diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index f51723deb..caaac6842 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -31,6 +31,10 @@ - Fixed remote MCP OAuth refresh failures leaving stale credentials in `agent.db`: when the token endpoint returns a definitive failure (`invalid_grant`, `invalid_token`, `revoked`, plain 401/403 not classified as transient), `MCPManager#resolveAuthConfig` now drops the credential via `AuthStorage.remove(credentialId)` and skips re-attaching the dead `Authorization: Bearer …` header. Previously a revoked refresh token kept producing `401 invalid_token` on every MCP request and survived restarts, so users had to hand-clear the credential row to recover; the next connect now surfaces a clean auth error and `/mcp reauth ` (or `/mcp unauth`) recovers without restarting. Transient refresh failures (network/`fetch failed`/`ECONNREFUSED`) still fall back to the existing access token ([#1908](https://github.com/can1357/oh-my-pi/issues/1908)). +### Fixed + +- Fixed `omp://docs` and `omp://docs/...` internal documentation URLs in the distributed package to resolve through the embedded documentation index instead of failing with `Documentation file not found` ([#1898](https://github.com/can1357/oh-my-pi/issues/1898)). + ## [15.9.1] - 2026-06-04 ### Added diff --git a/packages/coding-agent/src/internal-urls/omp-protocol.ts b/packages/coding-agent/src/internal-urls/omp-protocol.ts index a36c29edf..ee5e13534 100644 --- a/packages/coding-agent/src/internal-urls/omp-protocol.ts +++ b/packages/coding-agent/src/internal-urls/omp-protocol.ts @@ -64,9 +64,15 @@ export class OmpProtocolHandler implements ProtocolHandler { throw new Error("Path traversal (..) is not allowed in omp:// URLs"); } - const content = EMBEDDED_DOCS[normalized]; + const docPath = + normalized === "docs" ? "" : normalized.startsWith("docs/") ? normalized.slice("docs/".length) : normalized; + if (!docPath) { + return this.#listDocs(url); + } + + const content = EMBEDDED_DOCS[docPath]; if (content === undefined) { - const lookup = normalized.replace(/\.md$/, ""); + const lookup = docPath.replace(/\.md$/, ""); const suggestions = EMBEDDED_DOC_FILENAMES.filter( f => f.includes(lookup) || lookup.includes(f.replace(/\.md$/, "")), ).slice(0, 5); diff --git a/packages/coding-agent/src/tools/search.ts b/packages/coding-agent/src/tools/search.ts index d36f04fcc..221b10797 100644 --- a/packages/coding-agent/src/tools/search.ts +++ b/packages/coding-agent/src/tools/search.ts @@ -259,7 +259,7 @@ interface IndexedContentLines { } const INTERNAL_URL_DISPLAY_RE = /^[a-z][a-z0-9+.-]*:\/\//i; -const OMP_ROOT_URL_RE = /^omp:\/\/\/?$/i; +const OMP_ROOT_URL_RE = /^omp:\/\/(?:\/?|docs\/?)$/i; function normalizeSearchLine(line: string): string { return line.endsWith("\r") ? line.slice(0, -1) : line; diff --git a/packages/coding-agent/test/internal-urls/omp-protocol.test.ts b/packages/coding-agent/test/internal-urls/omp-protocol.test.ts new file mode 100644 index 000000000..d779bf393 --- /dev/null +++ b/packages/coding-agent/test/internal-urls/omp-protocol.test.ts @@ -0,0 +1,20 @@ +import { describe, expect, it } from "bun:test"; +import { InternalUrlRouter } from "@oh-my-pi/pi-coding-agent/internal-urls"; + +describe("OmpProtocolHandler", () => { + it("treats omp://docs as the documentation root", async () => { + const resource = await InternalUrlRouter.instance().resolve("omp://docs"); + + expect(resource.content).toContain("# Documentation"); + expect(resource.content).toContain("tools/read.md"); + }); + + it("resolves docs-prefixed documentation paths", async () => { + const router = InternalUrlRouter.instance(); + const direct = await router.resolve("omp://tools/read.md"); + const prefixed = await router.resolve("omp://docs/tools/read.md"); + + expect(prefixed.content).toBe(direct.content); + expect(prefixed.content).toContain("# read"); + }); +}); diff --git a/packages/coding-agent/test/tools/search-internal-urls.test.ts b/packages/coding-agent/test/tools/search-internal-urls.test.ts index a3383faee..52edda3b5 100644 --- a/packages/coding-agent/test/tools/search-internal-urls.test.ts +++ b/packages/coding-agent/test/tools/search-internal-urls.test.ts @@ -183,6 +183,20 @@ describe("SearchTool internal URL resolution", () => { expect(text).toContain("Search file contents with a regex across files"); }); + it("expands omp://docs to grep embedded documentation files", async () => { + const session = createSession(); + const tool = new SearchTool(session); + + const result = await tool.execute("test-call", { + pattern: "Read files, directories, archives", + paths: ["omp://docs"], + }); + + const text = getResultText(result); + expect(text).toContain("# omp://tools/read.md"); + expect(text).toContain("Read files, directories, archives"); + }); + it("throws when internal URL has no sourcePath", async () => { const session = createSession(); const tool = new SearchTool(session);