@skaile/workspaces 3.18.0 → 3.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/dist/{asset-feeds-LT4GI576.js → asset-feeds-OO3NIRVI.js} +4 -4
- package/dist/{asset-feeds-LT4GI576.js.map → asset-feeds-OO3NIRVI.js.map} +1 -1
- package/dist/asset-manager/index.js +1 -1
- package/dist/bridge/codex-app-server.js +1 -1
- package/dist/bridge/drivers/claude-sdk.js +1 -1
- package/dist/bridge/drivers/codex.js +147 -48
- package/dist/bridge/drivers/codex.js.map +1 -1
- package/dist/bridge/drivers/continue.js +2 -2
- package/dist/bridge/drivers/echo.js +1 -1
- package/dist/bridge/drivers/gemini.js +3 -3
- package/dist/bridge/drivers/goose.js +2 -2
- package/dist/bridge/drivers/omp.js +1 -1
- package/dist/bridge/drivers/opencode.js +2 -2
- package/dist/bridge/drivers/qwen.js +3 -3
- package/dist/bridge/index.js +2 -2
- package/dist/bridge/src/codex/managed-driver.d.ts +2 -0
- package/dist/bridge/src/codex/managed-driver.d.ts.map +1 -1
- package/dist/bridge/src/codex/native-mcp-approval.d.ts +13 -0
- package/dist/bridge/src/codex/native-mcp-approval.d.ts.map +1 -0
- package/dist/bridge/src/codex/native-protocol.generated.d.ts +5 -1
- package/dist/bridge/src/codex/native-protocol.generated.d.ts.map +1 -1
- package/dist/bridge/src/codex/questions.d.ts +2 -2
- package/dist/bridge/src/codex/questions.d.ts.map +1 -1
- package/dist/bridge/src/codex-app-server.d.ts +2 -0
- package/dist/bridge/src/codex-app-server.d.ts.map +1 -1
- package/dist/bridge/src/normalizer.d.ts.map +1 -1
- package/dist/bridge/src/types.d.ts +7 -1
- package/dist/bridge/src/types.d.ts.map +1 -1
- package/dist/{chunk-BJI7IGZF.js → chunk-34RUVLL6.js} +6 -6
- package/dist/{chunk-BJI7IGZF.js.map → chunk-34RUVLL6.js.map} +1 -1
- package/dist/{chunk-SH7GXS7V.js → chunk-3BOWST5G.js} +4 -4
- package/dist/{chunk-SH7GXS7V.js.map → chunk-3BOWST5G.js.map} +1 -1
- package/dist/{chunk-FYVDBIZV.js → chunk-5Y4RBNT2.js} +3 -3
- package/dist/{chunk-FYVDBIZV.js.map → chunk-5Y4RBNT2.js.map} +1 -1
- package/dist/{chunk-IT42ZT3T.js → chunk-7ECAUWFU.js} +6 -6
- package/dist/{chunk-IT42ZT3T.js.map → chunk-7ECAUWFU.js.map} +1 -1
- package/dist/{chunk-GRA4BWCV.js → chunk-7J4W54DV.js} +3 -3
- package/dist/{chunk-GRA4BWCV.js.map → chunk-7J4W54DV.js.map} +1 -1
- package/dist/{chunk-FBD5SOIH.js → chunk-HFL3PYJ7.js} +3 -3
- package/dist/{chunk-FBD5SOIH.js.map → chunk-HFL3PYJ7.js.map} +1 -1
- package/dist/{chunk-J7VSUGGH.js → chunk-KB2GC6YY.js} +2 -2
- package/dist/chunk-KB2GC6YY.js.map +1 -0
- package/dist/{chunk-X3LUB275.js → chunk-OLRKNOO2.js} +3 -3
- package/dist/{chunk-X3LUB275.js.map → chunk-OLRKNOO2.js.map} +1 -1
- package/dist/{chunk-XKSGEYZC.js → chunk-PHBYB4XT.js} +5 -2
- package/dist/chunk-PHBYB4XT.js.map +1 -0
- package/dist/{chunk-AI2PZX4H.js → chunk-PWBURVRH.js} +3 -3
- package/dist/{chunk-AI2PZX4H.js.map → chunk-PWBURVRH.js.map} +1 -1
- package/dist/{chunk-2IROGAS7.js → chunk-SBDTLR3Q.js} +2 -2
- package/dist/{chunk-2IROGAS7.js.map → chunk-SBDTLR3Q.js.map} +1 -1
- package/dist/{chunk-RJOGAEIY.js → chunk-SZ3HIMSX.js} +8 -7
- package/dist/chunk-SZ3HIMSX.js.map +1 -0
- package/dist/{chunk-CQY7XKRV.js → chunk-WB4EWSDR.js} +5 -4
- package/dist/chunk-WB4EWSDR.js.map +1 -0
- package/dist/{chunk-67KB2A77.js → chunk-YLSMYOHN.js} +2 -2
- package/dist/{chunk-67KB2A77.js.map → chunk-YLSMYOHN.js.map} +1 -1
- package/dist/{chunk-GMMACS5W.js → chunk-YWGL52GT.js} +4 -4
- package/dist/{chunk-GMMACS5W.js.map → chunk-YWGL52GT.js.map} +1 -1
- package/dist/cli/index.js +29 -29
- package/dist/connectors/index.js +3 -3
- package/dist/{ensure-sources-4BQ6GMYG.js → ensure-sources-PR7YN3HV.js} +4 -4
- package/dist/{ensure-sources-4BQ6GMYG.js.map → ensure-sources-PR7YN3HV.js.map} +1 -1
- package/dist/factory-assets/connectors/box.js +3 -3
- package/dist/factory-assets/connectors/deploy.js +3 -3
- package/dist/factory-assets/connectors/devserver.js +3 -3
- package/dist/factory-assets/connectors/flow/adapter.js +3 -3
- package/dist/factory-assets/connectors/flow/run-flow.js +4 -4
- package/dist/factory-assets/connectors/flow.js +3 -3
- package/dist/factory-assets/connectors/git.js +3 -3
- package/dist/factory-assets/connectors/gmail.js +3 -3
- package/dist/factory-assets/connectors/googledrive.js +3 -3
- package/dist/factory-assets/connectors/local.js +3 -3
- package/dist/factory-assets/connectors/mattermost.js +3 -3
- package/dist/factory-assets/connectors/memory.js +3 -3
- package/dist/factory-assets/connectors/minio.js +3 -3
- package/dist/factory-assets/connectors/postgres.js +3 -3
- package/dist/factory-assets/connectors/s3.js +3 -3
- package/dist/factory-assets/connectors/sharepoint.js +3 -3
- package/dist/factory-assets/connectors/sqlite.js +3 -3
- package/dist/factory-assets/connectors/static-server.js +3 -3
- package/dist/factory-assets/connectors/tunnel.js +3 -3
- package/dist/factory-assets/connectors/webdav.js +3 -3
- package/dist/factory-assets/connectors/xstate-store.js +3 -3
- package/dist/factory-assets/connectors/xstate.js +3 -3
- package/dist/{helpers-4UJMSN6T.js → helpers-TFSZSWT5.js} +4 -4
- package/dist/{helpers-4UJMSN6T.js.map → helpers-TFSZSWT5.js.map} +1 -1
- package/dist/{library-publish-QHQDN4IC.js → library-publish-WVIUUYG3.js} +6 -6
- package/dist/{library-publish-QHQDN4IC.js.map → library-publish-WVIUUYG3.js.map} +1 -1
- package/dist/{open-library-ZDM6DUKJ.js → open-library-2AWZGIWE.js} +5 -5
- package/dist/{open-library-ZDM6DUKJ.js.map → open-library-2AWZGIWE.js.map} +1 -1
- package/dist/{project-JJUAAI7N.js → project-XZDKNIRG.js} +5 -5
- package/dist/{project-JJUAAI7N.js.map → project-XZDKNIRG.js.map} +1 -1
- package/dist/runner/index.js +6 -6
- package/dist/runner/src/codex-tools.d.ts.map +1 -1
- package/dist/sdk/asset-manager.js +1 -1
- package/dist/sdk/bridge.js +2 -2
- package/dist/sdk/index.js +6 -6
- package/dist/sdk/runner.js +6 -6
- package/dist/{setup-PS6ZERZ5.js → setup-J34TR5IR.js} +4 -4
- package/dist/{setup-PS6ZERZ5.js.map → setup-J34TR5IR.js.map} +1 -1
- package/dist/{source-QLDIZCI3.js → source-QYINHHUP.js} +6 -6
- package/dist/{source-QLDIZCI3.js.map → source-QYINHHUP.js.map} +1 -1
- package/dist/{source-manifest-publish-J3AVCTLX.js → source-manifest-publish-3RBW5E2O.js} +7 -7
- package/dist/{source-manifest-publish-J3AVCTLX.js.map → source-manifest-publish-3RBW5E2O.js.map} +1 -1
- package/dist/tui/index.js +6 -6
- package/dist/types/src/events.d.ts +3 -3
- package/dist/types/src/events.d.ts.map +1 -1
- package/dist/workspace-plugin/index.js +1 -1
- package/package.json +2 -1
- package/dist/chunk-CQY7XKRV.js.map +0 -1
- package/dist/chunk-J7VSUGGH.js.map +0 -1
- package/dist/chunk-RJOGAEIY.js.map +0 -1
- package/dist/chunk-XKSGEYZC.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 3.19.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#674](https://github.com/skaile-ai/workspaces/pull/674) [`95ff13e`](https://github.com/skaile-ai/workspaces/commit/95ff13ef72e86c721b9107744ed4cc5614794e81) Thanks [@peteralbert](https://github.com/peteralbert)! - Add explicit approve-once/deny managed MCP consent using the original native callback and configured transport binding. Preserve the native elicitation envelope in the generated protocol; reject unsupported approval forms, stale replies and changed bindings through the final RPC write. Consent cards add the `mcp` kind with bounded durable presentation, without replacing capability or Platform authorization.
|
|
8
|
+
|
|
9
|
+
Update strict consent consumers as described in MIGRATION.md. Synthetic driver/runner regressions and a separately constrained allowed-only fixture harness do not establish native/provider readiness or production activation.
|
|
10
|
+
|
|
11
|
+
Sample final passive MCP counters after owned transport closure, so rejected post-terminal SDK entries cannot disappear from the final audit. Uncertain closure or a failed counter read does not claim a completed final sample.
|
|
12
|
+
|
|
3
13
|
## 3.18.0
|
|
4
14
|
|
|
5
15
|
### Minor Changes
|
|
@@ -65,7 +65,7 @@ async function libraryAssets() {
|
|
|
65
65
|
const domains = [];
|
|
66
66
|
try {
|
|
67
67
|
const [{ openLibraryManager }, { skaileHomeDir }, { getGlobalCacheDir }] = await Promise.all([
|
|
68
|
-
import('./open-library-
|
|
68
|
+
import('./open-library-2AWZGIWE.js'),
|
|
69
69
|
import('./library/index.js'),
|
|
70
70
|
import('./core/index.js')
|
|
71
71
|
]);
|
|
@@ -98,7 +98,7 @@ async function libraryAssets() {
|
|
|
98
98
|
async function storeAssets(projectDir) {
|
|
99
99
|
const notes = [];
|
|
100
100
|
try {
|
|
101
|
-
const { resolveCatalogSource } = await import('./open-library-
|
|
101
|
+
const { resolveCatalogSource } = await import('./open-library-2AWZGIWE.js');
|
|
102
102
|
const { source, close } = await resolveCatalogSource({ projectDir });
|
|
103
103
|
try {
|
|
104
104
|
const assets = await source.listAssets();
|
|
@@ -202,5 +202,5 @@ function dedupeBySlug(domains) {
|
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
export { gatherAssetFeeds };
|
|
205
|
-
//# sourceMappingURL=asset-feeds-
|
|
206
|
-
//# sourceMappingURL=asset-feeds-
|
|
205
|
+
//# sourceMappingURL=asset-feeds-OO3NIRVI.js.map
|
|
206
|
+
//# sourceMappingURL=asset-feeds-OO3NIRVI.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../cli/src/asset-feeds.ts"],"names":[],"mappings":"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","file":"asset-feeds-LT4GI576.js","sourcesContent":["/**\n * asset-feeds.ts — gather installable assets from every feed the manage TUI\n * surfaces.\n *\n * Four feeds, normalized into `CatalogEntry`:\n * - **Project sources** — `skaile.yaml` `sources:` entries (scanned via\n * `AssetManager.search()`; the new `sources:` field is merged into the\n * legacy repositories map in `AssetManager.loadConfig`).\n * - **Local libraries** — user authoring places from `LocalIndex` (filesystem\n * scan of each library's `path`).\n * - **Factory assets** — the bundled first-party `factory-assets` tree\n * (`factoryAssetRoots()`), scanned from disk. Always present; no network.\n * - **Remote store** — the configured catalog source when `catalog.url` is\n * not `local`. Failures are non-fatal — they surface as notes.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport * as path from \"node:path\";\nimport {\n type AssetKind,\n type CatalogDomain,\n type CatalogEntry,\n factoryAssetRoots,\n parseFrontmatter,\n scanRepo,\n walkDir,\n} from \"@skaile/workspaces/core\";\nimport {\n assignDomain,\n buildDomainIndex,\n DOMAIN_MD_FILENAME,\n type DomainMd,\n parseDomainMd,\n} from \"@skaile/workspaces/discovery\";\n\n/** One non-fatal note returned to the caller for surfacing in the UI. */\nexport interface FeedNote {\n feed: \"sources\" | \"libraries\" | \"store\" | \"factory\";\n message: string;\n}\n\n/**\n * Which feed an asset came from. This is the top-level grouping axis in the\n * manage TUI (\"where is this skill coming from?\") and is intentionally distinct\n * from `publisher` (asset-intrinsic identity): the same publisher can legitimately\n * appear under more than one origin (e.g. a github repo you added as a `source`\n * that is also listed in the remote `store`).\n */\nexport type AssetOrigin = \"source\" | \"library\" | \"factory\" | \"store\";\n\n/** A catalog entry tagged with the feed it was gathered from. */\nexport interface OriginEntry {\n origin: AssetOrigin;\n entry: CatalogEntry;\n /**\n * Second-level grouping label for the manage tree. Defaults (when unset) to the\n * entry's `publisher`; the source feed sets it to the source's short repo name\n * so the Sources band groups by source — \"which repo did this come from\" — not\n * by the asset-intrinsic publisher.\n */\n group?: string;\n}\n\nexport interface AssetFeedResult {\n entries: OriginEntry[];\n /**\n * Display-only domain metadata, keyed (by the consumer) on `slug`. Populated\n * from the store's `catalog.listDomains` when the connected catalog source\n * exposes it; empty otherwise. The manage TUI joins `entry.domainSlug` → a\n * domain for grouping headers, descriptions, and relation badges.\n */\n domains: CatalogDomain[];\n notes: FeedNote[];\n}\n\n// ── Domain stamping (on-disk feeds) ──────────────────────────────────────────\n//\n// `scanRepo` (the source / library / factory scan path) does not read the\n// `DOMAIN.md` sidecars, so its entries arrive with no `domainSlug` and render\n// flat under their publisher band. We re-derive the grouping here from the\n// root's `DOMAIN.md` files (the same sidecars the remote store computes\n// server-side), and fall back to the repo/source name for any entry no domain\n// claims so it still groups instead of landing in the synthetic \"no domain\" pile.\n\n/** Repo-relative POSIX path (DOMAIN.md slugs are matched whole-segment, `/`-joined). */\nfunction toPosix(p: string): string {\n return p.split(path.sep).join(\"/\");\n}\n\n/** Parse every `DOMAIN.md` sidecar under `root` into a {@link DomainMd}. */\nasync function loadDomainMds(root: string): Promise<DomainMd[]> {\n const out: DomainMd[] = [];\n for await (const { path: filePath, name } of walkDir(root)) {\n if (name !== DOMAIN_MD_FILENAME) continue;\n try {\n const { data } = parseFrontmatter(readFileSync(filePath, \"utf8\"));\n out.push(parseDomainMd(toPosix(path.relative(root, filePath)), data));\n } catch {}\n }\n return out;\n}\n\n/**\n * Stamp `domainSlug` onto every entry scanned from `root` using the root's\n * `DOMAIN.md` sidecars. Returns the `CatalogDomain` registry for the real\n * domains, plus a synthetic fallback domain when any entry used the fallback.\n * Mutates `entries` in place (sets `entry.domainSlug`).\n *\n * `synthesizeFallback` (default true): entries no domain claims fall back to\n * `fallbackSlug` (the repo/source name). Pass `false` when the caller already\n * groups these entries one level up (e.g. the source feed groups by source\n * node) — unmatched entries then get no domain (`\"\"`) and hang directly under\n * that parent, instead of nesting under a same-named fallback domain.\n */\nasync function stampDomains(\n root: string,\n fallbackSlug: string,\n entries: CatalogEntry[],\n synthesizeFallback = true,\n): Promise<CatalogDomain[]> {\n const domainMds = await loadDomainMds(root);\n const assignables = entries.map((entry) => ({\n entry,\n ref: `${entry.kind}:${entry.name}`,\n relativePath: toPosix(path.relative(root, entry.source)),\n }));\n\n let usedFallback = false;\n for (const a of assignables) {\n const slug = assignDomain(a.relativePath, domainMds);\n if (slug) a.entry.domainSlug = slug;\n else if (synthesizeFallback) {\n a.entry.domainSlug = fallbackSlug;\n usedFallback = true;\n } else a.entry.domainSlug = \"\";\n }\n\n const { index } = buildDomainIndex(assignables, domainMds);\n const catalog: CatalogDomain[] = Object.values(index).map((d) => ({\n slug: d.slug,\n title: d.title,\n ...(d.description ? { description: d.description } : {}),\n ...(d.relation ? { relation: d.relation } : {}),\n ...(d.order !== undefined ? { order: d.order } : {}),\n ...(d.recommended[0] ? { recommendedRef: d.recommended[0] } : {}),\n }));\n if (usedFallback) catalog.push({ slug: fallbackSlug, title: fallbackSlug });\n return catalog;\n}\n\n/**\n * Pull assets from local libraries (the authoring places under\n * `~/.skaile/libraries/<name>/`, not the `~/.skaile/cache/sources/` cache). Each\n * library's `path` is scanned with `scanRepo` and grouped under the bare library\n * name (`group: <name>`) so the manage TUI shows a clean `<name>` band — no\n * `library:` prefix and no redundant same-named fallback domain (mirrors the\n * source feed).\n */\nasync function libraryAssets(): Promise<{\n entries: OriginEntry[];\n domains: CatalogDomain[];\n notes: FeedNote[];\n}> {\n const notes: FeedNote[] = [];\n const domains: CatalogDomain[] = [];\n try {\n const [{ openLibraryManager }, { skaileHomeDir }, { getGlobalCacheDir }] = await Promise.all([\n import(\"./open-library.ts\"),\n import(\"@skaile/workspaces/library\"),\n import(\"@skaile/workspaces/core\"),\n ]);\n const { manager, close } = await openLibraryManager();\n try {\n // Authoring libraries are the rows that are NOT source clones. index.db\n // rows predating the cache migration still carry the legacy\n // ~/.skaile/sources path, so exclude both roots.\n const newRoot = getGlobalCacheDir();\n const legacyRoot = path.join(skaileHomeDir(), \"sources\");\n const libs = (await manager.listLibraries()).filter(\n (l) => !l.path.startsWith(newRoot) && !l.path.startsWith(legacyRoot),\n );\n const entries: OriginEntry[] = [];\n for (const lib of libs) {\n if (!existsSync(lib.path)) continue;\n // Scan + group under the bare library name. `synthesizeFallback: false`\n // (as the source feed does) keeps domainless assets directly under the\n // library band instead of a redundant same-named fallback domain.\n const libEntries = [...(await scanRepo(lib.path, lib.name))];\n domains.push(...(await stampDomains(lib.path, lib.name, libEntries, false)));\n for (const entry of libEntries) entries.push({ origin: \"library\", entry, group: lib.name });\n }\n return { entries, domains, notes };\n } finally {\n close();\n }\n } catch (err) {\n notes.push({\n feed: \"libraries\",\n message: err instanceof Error ? err.message : String(err),\n });\n return { entries: [], domains, notes };\n }\n}\n\n/**\n * Pull a (best-effort) snapshot of the connected remote store catalog.\n *\n * - Returns no entries when the resolved catalog is local-only or the host\n * is unreachable (the failure becomes a note, not an exception).\n * - Maps `CatalogAsset` → `CatalogEntry`, carrying `publisher`, `repo`, and\n * `category` straight through and using `source = \"store://<id>\"`; per-file\n * `source` paths are not available for remote assets so the canonical ref is\n * a stable placeholder.\n */\nasync function storeAssets(projectDir: string): Promise<{\n entries: CatalogEntry[];\n domains: CatalogDomain[];\n notes: FeedNote[];\n}> {\n const notes: FeedNote[] = [];\n try {\n const { resolveCatalogSource } = await import(\"./open-library.ts\");\n const { source, close } = await resolveCatalogSource({ projectDir });\n try {\n const assets = await source.listAssets();\n const entries: CatalogEntry[] = assets.map((a) => ({\n name: a.name,\n kind: (a.kind as AssetKind) ?? \"skill\",\n description: a.description ?? \"\",\n source: `store://${a.id}`,\n publisher: a.publisher,\n repo: a.repo,\n domainSlug: a.domainSlug,\n category: a.category,\n version: a.version,\n requires: [],\n dependencies: [],\n }));\n // Domains are optional on the catalog source — only the store backend\n // (post Part 4 `catalog.listDomains`) exposes them. Duck-type the call so\n // older sources and the local catalog degrade to no domains, not an error.\n const domains = await loadDomains(source);\n return { entries, domains, notes };\n } finally {\n close();\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n // Local-only catalog throws a recognizable message — silence it; absence\n // is the user's choice, not an error.\n if (!/local/i.test(msg)) {\n notes.push({ feed: \"store\", message: msg });\n }\n return { entries: [], domains: [], notes };\n }\n}\n\n/** Optional `listDomains` capability — returns `[]` when the source lacks it. */\nasync function loadDomains(source: unknown): Promise<CatalogDomain[]> {\n const fn = (source as { listDomains?: () => Promise<CatalogDomain[]> }).listDomains;\n if (typeof fn !== \"function\") return [];\n const domains = await fn.call(source);\n return Array.isArray(domains) ? domains : [];\n}\n\n/** The slice of `AssetManager` the source feed needs (kept narrow for tests). */\ninterface AssetManagerLike {\n search: () => Promise<CatalogEntry[]>;\n searchRepoRoots: () => { repoName: string; root: string }[];\n}\n\n/**\n * Project-source feed: leans on `AssetManager.search()`, which now merges\n * `skaile.yaml`'s `sources:` field into the repositories map, then stamps\n * `DOMAIN.md`-derived domain grouping onto the scanned entries via\n * `searchRepoRoots()`.\n */\nasync function sourceAssets(\n am: AssetManagerLike,\n): Promise<{ entries: OriginEntry[]; domains: CatalogDomain[] }> {\n // The bundled factory tree is injected into the repositories map as an implicit\n // source, so `am.search()` returns it too. It has its own `factory` origin band,\n // so drop it here — otherwise the same first-party skills list twice under Sources.\n const factoryPrefixes = factoryAssetRoots().map((r) => (r.endsWith(path.sep) ? r : r + path.sep));\n const isFactoryPath = (p: string) =>\n factoryPrefixes.some((fp) => p === fp.slice(0, -1) || p.startsWith(fp));\n\n const all = (await am.search()).filter((e) => !isFactoryPath(e.source));\n const entries: OriginEntry[] = [];\n const domains: CatalogDomain[] = [];\n // Group each source's entries under the source node (its short repo name), not\n // the publisher: under Sources the navigational question is \"which repo did\n // this come from\". Each entry's `source` (absolute manifest path) lives under\n // exactly one declared root, so group + stamp by prefix. The cache slug is\n // URL-keyed `github.com/<org>/<repo>` — take the trailing segment.\n for (const { repoName, root } of am.searchRepoRoots()) {\n if (isFactoryPath(root)) continue;\n const prefix = root.endsWith(path.sep) ? root : root + path.sep;\n const owned = all.filter((e) => e.source === root || e.source.startsWith(prefix));\n if (owned.length === 0) continue;\n const sourceName = repoName.split(\"/\").pop() || repoName;\n // No synthetic fallback domain — the source node already groups these, so a\n // same-named fallback would just nest the source under itself.\n domains.push(...(await stampDomains(root, sourceName, owned, false)));\n for (const entry of owned) entries.push({ origin: \"source\", entry, group: sourceName });\n }\n return { entries, domains };\n}\n\n/**\n * Factory-asset feed: scan the bundled first-party `factory-assets` tree(s)\n * resolved by `factoryAssetRoots()` (the `SKAILE_FACTORY_ASSETS_DIR` override\n * layer ahead of the bundled tree). Local disk only, no network — the entries are\n * the built-in skills / connectors / bundles that ship with `@skaile/workspaces`.\n * `factoryAssetRoots()` already dedupes, so the env override pointing at the\n * bundled dir collapses to one root.\n */\nasync function factoryAssets(): Promise<{\n entries: CatalogEntry[];\n domains: CatalogDomain[];\n notes: FeedNote[];\n}> {\n const notes: FeedNote[] = [];\n const domains: CatalogDomain[] = [];\n try {\n const entries: CatalogEntry[] = [];\n for (const root of factoryAssetRoots()) {\n const rootEntries = [...(await scanRepo(root, \"skaile-factory\"))];\n domains.push(...(await stampDomains(root, \"skaile-factory\", rootEntries)));\n entries.push(...rootEntries);\n }\n return { entries, domains, notes };\n } catch (err) {\n notes.push({\n feed: \"factory\",\n message: err instanceof Error ? err.message : String(err),\n });\n return { entries: [], domains, notes };\n }\n}\n\n/** Tag a flat entry list with a single origin. */\nfunction tag(origin: AssetOrigin, entries: CatalogEntry[]): OriginEntry[] {\n return entries.map((entry) => ({ origin, entry }));\n}\n\n/**\n * Run all feeds and return a single normalized result.\n *\n * Feeds run in parallel where possible — the store fetch is the slow one\n * (one HTTP call) and is fired alongside the local library walk. The factory\n * scan is local disk only, so it runs inline.\n */\nexport async function gatherAssetFeeds(\n am: AssetManagerLike,\n projectDir: string,\n): Promise<AssetFeedResult> {\n const [libs, store] = await Promise.all([libraryAssets(), storeAssets(projectDir)]);\n const factory = await factoryAssets();\n const src = await sourceAssets(am);\n return {\n entries: [\n ...src.entries,\n ...libs.entries,\n ...tag(\"factory\", factory.entries),\n ...tag(\"store\", store.entries),\n ],\n // Store domains first (server-curated), then the on-disk feeds; dedupe by\n // slug, first-wins, so a store-served domain shadows a same-slug local one.\n domains: dedupeBySlug([...store.domains, ...src.domains, ...libs.domains, ...factory.domains]),\n notes: [...libs.notes, ...store.notes, ...factory.notes],\n };\n}\n\n/** First-wins dedupe of a domain list by `slug`. */\nfunction dedupeBySlug(domains: CatalogDomain[]): CatalogDomain[] {\n const seen = new Set<string>();\n const out: CatalogDomain[] = [];\n for (const d of domains) {\n if (seen.has(d.slug)) continue;\n seen.add(d.slug);\n out.push(d);\n }\n return out;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../cli/src/asset-feeds.ts"],"names":[],"mappings":"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","file":"asset-feeds-OO3NIRVI.js","sourcesContent":["/**\n * asset-feeds.ts — gather installable assets from every feed the manage TUI\n * surfaces.\n *\n * Four feeds, normalized into `CatalogEntry`:\n * - **Project sources** — `skaile.yaml` `sources:` entries (scanned via\n * `AssetManager.search()`; the new `sources:` field is merged into the\n * legacy repositories map in `AssetManager.loadConfig`).\n * - **Local libraries** — user authoring places from `LocalIndex` (filesystem\n * scan of each library's `path`).\n * - **Factory assets** — the bundled first-party `factory-assets` tree\n * (`factoryAssetRoots()`), scanned from disk. Always present; no network.\n * - **Remote store** — the configured catalog source when `catalog.url` is\n * not `local`. Failures are non-fatal — they surface as notes.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport * as path from \"node:path\";\nimport {\n type AssetKind,\n type CatalogDomain,\n type CatalogEntry,\n factoryAssetRoots,\n parseFrontmatter,\n scanRepo,\n walkDir,\n} from \"@skaile/workspaces/core\";\nimport {\n assignDomain,\n buildDomainIndex,\n DOMAIN_MD_FILENAME,\n type DomainMd,\n parseDomainMd,\n} from \"@skaile/workspaces/discovery\";\n\n/** One non-fatal note returned to the caller for surfacing in the UI. */\nexport interface FeedNote {\n feed: \"sources\" | \"libraries\" | \"store\" | \"factory\";\n message: string;\n}\n\n/**\n * Which feed an asset came from. This is the top-level grouping axis in the\n * manage TUI (\"where is this skill coming from?\") and is intentionally distinct\n * from `publisher` (asset-intrinsic identity): the same publisher can legitimately\n * appear under more than one origin (e.g. a github repo you added as a `source`\n * that is also listed in the remote `store`).\n */\nexport type AssetOrigin = \"source\" | \"library\" | \"factory\" | \"store\";\n\n/** A catalog entry tagged with the feed it was gathered from. */\nexport interface OriginEntry {\n origin: AssetOrigin;\n entry: CatalogEntry;\n /**\n * Second-level grouping label for the manage tree. Defaults (when unset) to the\n * entry's `publisher`; the source feed sets it to the source's short repo name\n * so the Sources band groups by source — \"which repo did this come from\" — not\n * by the asset-intrinsic publisher.\n */\n group?: string;\n}\n\nexport interface AssetFeedResult {\n entries: OriginEntry[];\n /**\n * Display-only domain metadata, keyed (by the consumer) on `slug`. Populated\n * from the store's `catalog.listDomains` when the connected catalog source\n * exposes it; empty otherwise. The manage TUI joins `entry.domainSlug` → a\n * domain for grouping headers, descriptions, and relation badges.\n */\n domains: CatalogDomain[];\n notes: FeedNote[];\n}\n\n// ── Domain stamping (on-disk feeds) ──────────────────────────────────────────\n//\n// `scanRepo` (the source / library / factory scan path) does not read the\n// `DOMAIN.md` sidecars, so its entries arrive with no `domainSlug` and render\n// flat under their publisher band. We re-derive the grouping here from the\n// root's `DOMAIN.md` files (the same sidecars the remote store computes\n// server-side), and fall back to the repo/source name for any entry no domain\n// claims so it still groups instead of landing in the synthetic \"no domain\" pile.\n\n/** Repo-relative POSIX path (DOMAIN.md slugs are matched whole-segment, `/`-joined). */\nfunction toPosix(p: string): string {\n return p.split(path.sep).join(\"/\");\n}\n\n/** Parse every `DOMAIN.md` sidecar under `root` into a {@link DomainMd}. */\nasync function loadDomainMds(root: string): Promise<DomainMd[]> {\n const out: DomainMd[] = [];\n for await (const { path: filePath, name } of walkDir(root)) {\n if (name !== DOMAIN_MD_FILENAME) continue;\n try {\n const { data } = parseFrontmatter(readFileSync(filePath, \"utf8\"));\n out.push(parseDomainMd(toPosix(path.relative(root, filePath)), data));\n } catch {}\n }\n return out;\n}\n\n/**\n * Stamp `domainSlug` onto every entry scanned from `root` using the root's\n * `DOMAIN.md` sidecars. Returns the `CatalogDomain` registry for the real\n * domains, plus a synthetic fallback domain when any entry used the fallback.\n * Mutates `entries` in place (sets `entry.domainSlug`).\n *\n * `synthesizeFallback` (default true): entries no domain claims fall back to\n * `fallbackSlug` (the repo/source name). Pass `false` when the caller already\n * groups these entries one level up (e.g. the source feed groups by source\n * node) — unmatched entries then get no domain (`\"\"`) and hang directly under\n * that parent, instead of nesting under a same-named fallback domain.\n */\nasync function stampDomains(\n root: string,\n fallbackSlug: string,\n entries: CatalogEntry[],\n synthesizeFallback = true,\n): Promise<CatalogDomain[]> {\n const domainMds = await loadDomainMds(root);\n const assignables = entries.map((entry) => ({\n entry,\n ref: `${entry.kind}:${entry.name}`,\n relativePath: toPosix(path.relative(root, entry.source)),\n }));\n\n let usedFallback = false;\n for (const a of assignables) {\n const slug = assignDomain(a.relativePath, domainMds);\n if (slug) a.entry.domainSlug = slug;\n else if (synthesizeFallback) {\n a.entry.domainSlug = fallbackSlug;\n usedFallback = true;\n } else a.entry.domainSlug = \"\";\n }\n\n const { index } = buildDomainIndex(assignables, domainMds);\n const catalog: CatalogDomain[] = Object.values(index).map((d) => ({\n slug: d.slug,\n title: d.title,\n ...(d.description ? { description: d.description } : {}),\n ...(d.relation ? { relation: d.relation } : {}),\n ...(d.order !== undefined ? { order: d.order } : {}),\n ...(d.recommended[0] ? { recommendedRef: d.recommended[0] } : {}),\n }));\n if (usedFallback) catalog.push({ slug: fallbackSlug, title: fallbackSlug });\n return catalog;\n}\n\n/**\n * Pull assets from local libraries (the authoring places under\n * `~/.skaile/libraries/<name>/`, not the `~/.skaile/cache/sources/` cache). Each\n * library's `path` is scanned with `scanRepo` and grouped under the bare library\n * name (`group: <name>`) so the manage TUI shows a clean `<name>` band — no\n * `library:` prefix and no redundant same-named fallback domain (mirrors the\n * source feed).\n */\nasync function libraryAssets(): Promise<{\n entries: OriginEntry[];\n domains: CatalogDomain[];\n notes: FeedNote[];\n}> {\n const notes: FeedNote[] = [];\n const domains: CatalogDomain[] = [];\n try {\n const [{ openLibraryManager }, { skaileHomeDir }, { getGlobalCacheDir }] = await Promise.all([\n import(\"./open-library.ts\"),\n import(\"@skaile/workspaces/library\"),\n import(\"@skaile/workspaces/core\"),\n ]);\n const { manager, close } = await openLibraryManager();\n try {\n // Authoring libraries are the rows that are NOT source clones. index.db\n // rows predating the cache migration still carry the legacy\n // ~/.skaile/sources path, so exclude both roots.\n const newRoot = getGlobalCacheDir();\n const legacyRoot = path.join(skaileHomeDir(), \"sources\");\n const libs = (await manager.listLibraries()).filter(\n (l) => !l.path.startsWith(newRoot) && !l.path.startsWith(legacyRoot),\n );\n const entries: OriginEntry[] = [];\n for (const lib of libs) {\n if (!existsSync(lib.path)) continue;\n // Scan + group under the bare library name. `synthesizeFallback: false`\n // (as the source feed does) keeps domainless assets directly under the\n // library band instead of a redundant same-named fallback domain.\n const libEntries = [...(await scanRepo(lib.path, lib.name))];\n domains.push(...(await stampDomains(lib.path, lib.name, libEntries, false)));\n for (const entry of libEntries) entries.push({ origin: \"library\", entry, group: lib.name });\n }\n return { entries, domains, notes };\n } finally {\n close();\n }\n } catch (err) {\n notes.push({\n feed: \"libraries\",\n message: err instanceof Error ? err.message : String(err),\n });\n return { entries: [], domains, notes };\n }\n}\n\n/**\n * Pull a (best-effort) snapshot of the connected remote store catalog.\n *\n * - Returns no entries when the resolved catalog is local-only or the host\n * is unreachable (the failure becomes a note, not an exception).\n * - Maps `CatalogAsset` → `CatalogEntry`, carrying `publisher`, `repo`, and\n * `category` straight through and using `source = \"store://<id>\"`; per-file\n * `source` paths are not available for remote assets so the canonical ref is\n * a stable placeholder.\n */\nasync function storeAssets(projectDir: string): Promise<{\n entries: CatalogEntry[];\n domains: CatalogDomain[];\n notes: FeedNote[];\n}> {\n const notes: FeedNote[] = [];\n try {\n const { resolveCatalogSource } = await import(\"./open-library.ts\");\n const { source, close } = await resolveCatalogSource({ projectDir });\n try {\n const assets = await source.listAssets();\n const entries: CatalogEntry[] = assets.map((a) => ({\n name: a.name,\n kind: (a.kind as AssetKind) ?? \"skill\",\n description: a.description ?? \"\",\n source: `store://${a.id}`,\n publisher: a.publisher,\n repo: a.repo,\n domainSlug: a.domainSlug,\n category: a.category,\n version: a.version,\n requires: [],\n dependencies: [],\n }));\n // Domains are optional on the catalog source — only the store backend\n // (post Part 4 `catalog.listDomains`) exposes them. Duck-type the call so\n // older sources and the local catalog degrade to no domains, not an error.\n const domains = await loadDomains(source);\n return { entries, domains, notes };\n } finally {\n close();\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n // Local-only catalog throws a recognizable message — silence it; absence\n // is the user's choice, not an error.\n if (!/local/i.test(msg)) {\n notes.push({ feed: \"store\", message: msg });\n }\n return { entries: [], domains: [], notes };\n }\n}\n\n/** Optional `listDomains` capability — returns `[]` when the source lacks it. */\nasync function loadDomains(source: unknown): Promise<CatalogDomain[]> {\n const fn = (source as { listDomains?: () => Promise<CatalogDomain[]> }).listDomains;\n if (typeof fn !== \"function\") return [];\n const domains = await fn.call(source);\n return Array.isArray(domains) ? domains : [];\n}\n\n/** The slice of `AssetManager` the source feed needs (kept narrow for tests). */\ninterface AssetManagerLike {\n search: () => Promise<CatalogEntry[]>;\n searchRepoRoots: () => { repoName: string; root: string }[];\n}\n\n/**\n * Project-source feed: leans on `AssetManager.search()`, which now merges\n * `skaile.yaml`'s `sources:` field into the repositories map, then stamps\n * `DOMAIN.md`-derived domain grouping onto the scanned entries via\n * `searchRepoRoots()`.\n */\nasync function sourceAssets(\n am: AssetManagerLike,\n): Promise<{ entries: OriginEntry[]; domains: CatalogDomain[] }> {\n // The bundled factory tree is injected into the repositories map as an implicit\n // source, so `am.search()` returns it too. It has its own `factory` origin band,\n // so drop it here — otherwise the same first-party skills list twice under Sources.\n const factoryPrefixes = factoryAssetRoots().map((r) => (r.endsWith(path.sep) ? r : r + path.sep));\n const isFactoryPath = (p: string) =>\n factoryPrefixes.some((fp) => p === fp.slice(0, -1) || p.startsWith(fp));\n\n const all = (await am.search()).filter((e) => !isFactoryPath(e.source));\n const entries: OriginEntry[] = [];\n const domains: CatalogDomain[] = [];\n // Group each source's entries under the source node (its short repo name), not\n // the publisher: under Sources the navigational question is \"which repo did\n // this come from\". Each entry's `source` (absolute manifest path) lives under\n // exactly one declared root, so group + stamp by prefix. The cache slug is\n // URL-keyed `github.com/<org>/<repo>` — take the trailing segment.\n for (const { repoName, root } of am.searchRepoRoots()) {\n if (isFactoryPath(root)) continue;\n const prefix = root.endsWith(path.sep) ? root : root + path.sep;\n const owned = all.filter((e) => e.source === root || e.source.startsWith(prefix));\n if (owned.length === 0) continue;\n const sourceName = repoName.split(\"/\").pop() || repoName;\n // No synthetic fallback domain — the source node already groups these, so a\n // same-named fallback would just nest the source under itself.\n domains.push(...(await stampDomains(root, sourceName, owned, false)));\n for (const entry of owned) entries.push({ origin: \"source\", entry, group: sourceName });\n }\n return { entries, domains };\n}\n\n/**\n * Factory-asset feed: scan the bundled first-party `factory-assets` tree(s)\n * resolved by `factoryAssetRoots()` (the `SKAILE_FACTORY_ASSETS_DIR` override\n * layer ahead of the bundled tree). Local disk only, no network — the entries are\n * the built-in skills / connectors / bundles that ship with `@skaile/workspaces`.\n * `factoryAssetRoots()` already dedupes, so the env override pointing at the\n * bundled dir collapses to one root.\n */\nasync function factoryAssets(): Promise<{\n entries: CatalogEntry[];\n domains: CatalogDomain[];\n notes: FeedNote[];\n}> {\n const notes: FeedNote[] = [];\n const domains: CatalogDomain[] = [];\n try {\n const entries: CatalogEntry[] = [];\n for (const root of factoryAssetRoots()) {\n const rootEntries = [...(await scanRepo(root, \"skaile-factory\"))];\n domains.push(...(await stampDomains(root, \"skaile-factory\", rootEntries)));\n entries.push(...rootEntries);\n }\n return { entries, domains, notes };\n } catch (err) {\n notes.push({\n feed: \"factory\",\n message: err instanceof Error ? err.message : String(err),\n });\n return { entries: [], domains, notes };\n }\n}\n\n/** Tag a flat entry list with a single origin. */\nfunction tag(origin: AssetOrigin, entries: CatalogEntry[]): OriginEntry[] {\n return entries.map((entry) => ({ origin, entry }));\n}\n\n/**\n * Run all feeds and return a single normalized result.\n *\n * Feeds run in parallel where possible — the store fetch is the slow one\n * (one HTTP call) and is fired alongside the local library walk. The factory\n * scan is local disk only, so it runs inline.\n */\nexport async function gatherAssetFeeds(\n am: AssetManagerLike,\n projectDir: string,\n): Promise<AssetFeedResult> {\n const [libs, store] = await Promise.all([libraryAssets(), storeAssets(projectDir)]);\n const factory = await factoryAssets();\n const src = await sourceAssets(am);\n return {\n entries: [\n ...src.entries,\n ...libs.entries,\n ...tag(\"factory\", factory.entries),\n ...tag(\"store\", store.entries),\n ],\n // Store domains first (server-curated), then the on-disk feeds; dedupe by\n // slug, first-wins, so a store-served domain shadows a same-slug local one.\n domains: dedupeBySlug([...store.domains, ...src.domains, ...libs.domains, ...factory.domains]),\n notes: [...libs.notes, ...store.notes, ...factory.notes],\n };\n}\n\n/** First-wins dedupe of a domain list by `slug`. */\nfunction dedupeBySlug(domains: CatalogDomain[]): CatalogDomain[] {\n const seen = new Set<string>();\n const out: CatalogDomain[] = [];\n for (const d of domains) {\n if (seen.has(d.slug)) continue;\n seen.add(d.slug);\n out.push(d);\n }\n return out;\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { AssetManager, FACTORY_SOURCE_URL, MissingManifestError, NON_DEPLOYABLE_KINDS, normalizeRepoUrl, parseCanonicalLockKey, parseRefTolerant, renderMcpServerConfig, softDepName } from '../chunk-
|
|
1
|
+
export { AssetManager, FACTORY_SOURCE_URL, MissingManifestError, NON_DEPLOYABLE_KINDS, normalizeRepoUrl, parseCanonicalLockKey, parseRefTolerant, renderMcpServerConfig, softDepName } from '../chunk-YLSMYOHN.js';
|
|
2
2
|
import '../chunk-QG2ZXU5W.js';
|
|
3
3
|
import '../chunk-DZ4UZOFB.js';
|
|
4
4
|
import '../chunk-UKJMQZV6.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { CodexAppServerClient, CodexAppServerError } from '../chunk-
|
|
1
|
+
export { CodexAppServerClient, CodexAppServerError } from '../chunk-PHBYB4XT.js';
|
|
2
2
|
import '../chunk-LOO5CB5M.js';
|
|
3
3
|
import '../chunk-NSBPE2FW.js';
|
|
4
4
|
//# sourceMappingURL=codex-app-server.js.map
|
|
@@ -2,7 +2,7 @@ import { scrubPoisonedTranscript, resolveClaudeConfigDir, SUPPORTED_CLOUDS, buil
|
|
|
2
2
|
import { dispatchCapability } from '../../chunk-7ZO3MUP3.js';
|
|
3
3
|
import { fetchProviderModels } from '../../chunk-GURXUF2J.js';
|
|
4
4
|
import { AuthError, classifyClaudeSdkError, reclassifyAuthAsAccountUnavailable, AccountUnavailableError } from '../../chunk-GAH4YRCI.js';
|
|
5
|
-
import { BUILTIN_DRIVER_CATALOG, AgentDriver, getBridgeLogger } from '../../chunk-
|
|
5
|
+
import { BUILTIN_DRIVER_CATALOG, AgentDriver, getBridgeLogger } from '../../chunk-KB2GC6YY.js';
|
|
6
6
|
import '../../chunk-6E6PKKAD.js';
|
|
7
7
|
import '../../chunk-H662SXKS.js';
|
|
8
8
|
import '../../chunk-F3HNW354.js';
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { CodexAppServerClient } from '../../chunk-
|
|
2
|
-
import { parseCodexCredential, prepareNativePolicy, prepareCodexInstance, codexInstanceEnvironment, activateNativeApprovalPolicy, parseCodexRefreshResult,
|
|
1
|
+
import { CodexAppServerClient } from '../../chunk-PHBYB4XT.js';
|
|
2
|
+
import { parseCodexCredential, prepareNativePolicy, prepareCodexInstance, codexInstanceEnvironment, isNativeApprovalPolicyActive, activateNativeApprovalPolicy, parseCodexRefreshResult, allowsNativeApprovalPath } from '../../chunk-T3YLZQS4.js';
|
|
3
3
|
import { CodexNativeStateUnavailable } from '../../chunk-LOO5CB5M.js';
|
|
4
4
|
import { fetchProviderModels } from '../../chunk-GURXUF2J.js';
|
|
5
5
|
import { classifyGenericErrorMessage } from '../../chunk-GAH4YRCI.js';
|
|
6
|
-
import { BUILTIN_DRIVER_CATALOG, AgentDriver, getBridgeLogger } from '../../chunk-
|
|
6
|
+
import { BUILTIN_DRIVER_CATALOG, AgentDriver, getBridgeLogger } from '../../chunk-KB2GC6YY.js';
|
|
7
7
|
import '../../chunk-6E6PKKAD.js';
|
|
8
8
|
import '../../chunk-FTG7CRFD.js';
|
|
9
9
|
import '../../chunk-W4IPN3DD.js';
|
|
10
10
|
import '../../chunk-NSBPE2FW.js';
|
|
11
11
|
import { join, dirname, isAbsolute, relative } from 'path';
|
|
12
|
+
import { isDeepStrictEqual } from 'util';
|
|
12
13
|
import { existsSync, readFileSync, mkdirSync, writeFileSync, realpathSync, statSync } from 'fs';
|
|
13
14
|
import { randomUUID } from 'crypto';
|
|
14
15
|
import * as z from 'zod';
|
|
@@ -54,8 +55,8 @@ function codexPromptInput(input, cwd, skills) {
|
|
|
54
55
|
// bridge/src/codex/native-approvals.ts
|
|
55
56
|
function createCodexNativeApprovalHandlers(options) {
|
|
56
57
|
const active = (signal, threadId) => !signal.aborted && isNativeApprovalPolicyActive(options.getPolicy(), threadId);
|
|
57
|
-
const
|
|
58
|
-
const scoped = async (path, access, signal, threadId) => active(signal, threadId) &&
|
|
58
|
+
const text2 = (value) => typeof value === "string" && value.length > 0 && value.length <= 8192;
|
|
59
|
+
const scoped = async (path, access, signal, threadId) => active(signal, threadId) && text2(path) && allowsNativeApprovalPath(options.getPolicy(), path, access) && active(signal, threadId);
|
|
59
60
|
const permissions = async (value, signal, threadId) => {
|
|
60
61
|
if (value.network?.enabled || value.network != null && Object.keys(value.network).some((key) => key !== "enabled") || Object.keys(value).some((key) => !["network", "fileSystem"].includes(key)))
|
|
61
62
|
return false;
|
|
@@ -83,7 +84,7 @@ function createCodexNativeApprovalHandlers(options) {
|
|
|
83
84
|
return {
|
|
84
85
|
"item/commandExecution/requestApproval": async (input, signal) => {
|
|
85
86
|
const params = structuredClone(input);
|
|
86
|
-
const allowed = async () => active(signal, params.threadId) &&
|
|
87
|
+
const allowed = async () => active(signal, params.threadId) && text2(params.command) && (params.kind == null || params.kind === "command") && !params.environmentId && !params.networkApprovalContext && (params.availableDecisions == null || params.availableDecisions.includes("accept")) && await scoped(params.cwd, "read", signal, params.threadId) && (!params.additionalPermissions || await permissions(params.additionalPermissions, signal, params.threadId));
|
|
87
88
|
if (!await allowed()) return { decision: "decline" };
|
|
88
89
|
const details = [`Command: ${params.command}`, `Directory: ${params.cwd}`];
|
|
89
90
|
for (const access of ["read", "write"])
|
|
@@ -105,7 +106,7 @@ function createCodexNativeApprovalHandlers(options) {
|
|
|
105
106
|
if (params.grantRoot != null && !await scoped(params.grantRoot, "write", signal, params.threadId))
|
|
106
107
|
return false;
|
|
107
108
|
for (const change of changes) {
|
|
108
|
-
if (!
|
|
109
|
+
if (!text2(change.diff) || !await scoped(change.path, "write", signal, params.threadId))
|
|
109
110
|
return false;
|
|
110
111
|
if (!["add", "delete", "update"].includes(change.kind.type)) return false;
|
|
111
112
|
if (change.kind.type === "update" && change.kind.move_path != null && !await scoped(change.kind.move_path, "write", signal, params.threadId))
|
|
@@ -138,6 +139,48 @@ function createCodexNativeApprovalHandlers(options) {
|
|
|
138
139
|
}
|
|
139
140
|
};
|
|
140
141
|
}
|
|
142
|
+
|
|
143
|
+
// bridge/src/codex/native-mcp-approval.ts
|
|
144
|
+
var record = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
145
|
+
var text = (value) => typeof value === "string" && value.length > 0 && Buffer.byteLength(value) <= 8192;
|
|
146
|
+
function createCodexMcpApprovalHandler(options) {
|
|
147
|
+
return async (input, signal) => {
|
|
148
|
+
const decline = { action: "decline", content: null, _meta: null };
|
|
149
|
+
try {
|
|
150
|
+
const params = structuredClone(input);
|
|
151
|
+
const active = () => !signal.aborted && options.bindingActive() && isNativeApprovalPolicyActive(options.getPolicy(), params.threadId);
|
|
152
|
+
if (!active() || !text(options.serverName) || params.serverName !== options.serverName || !text(params.threadId) || !text(params.turnId) || params.mode !== "form" || !text(params.message) || Object.keys(params).some(
|
|
153
|
+
(key) => ![
|
|
154
|
+
"threadId",
|
|
155
|
+
"turnId",
|
|
156
|
+
"serverName",
|
|
157
|
+
"mode",
|
|
158
|
+
"message",
|
|
159
|
+
"requestedSchema",
|
|
160
|
+
"_meta"
|
|
161
|
+
].includes(key)
|
|
162
|
+
) || !record(params._meta) || params._meta.codex_approval_kind !== "mcp_tool_call" || !record(params.requestedSchema) || params.requestedSchema.type !== "object" || !record(params.requestedSchema.properties) || Object.keys(params.requestedSchema.properties).length !== 0 || Object.keys(params.requestedSchema).some(
|
|
163
|
+
(key) => !["type", "properties", "required"].includes(key)
|
|
164
|
+
) || params.requestedSchema.required !== void 0 && (!Array.isArray(params.requestedSchema.required) || params.requestedSchema.required.length !== 0) || Buffer.byteLength(JSON.stringify(params._meta)) > 65536)
|
|
165
|
+
return decline;
|
|
166
|
+
const accepted = await options.questions.requestApproval(
|
|
167
|
+
void 0,
|
|
168
|
+
{
|
|
169
|
+
kind: "mcp",
|
|
170
|
+
details: [
|
|
171
|
+
`Configured MCP server: ${options.serverName}`,
|
|
172
|
+
params.message,
|
|
173
|
+
"This is native request presentation, not an independently verified tool identity. Tool permissions are checked again when dispatched."
|
|
174
|
+
]
|
|
175
|
+
},
|
|
176
|
+
signal
|
|
177
|
+
);
|
|
178
|
+
return accepted && active() ? { action: "accept", content: null, _meta: null } : decline;
|
|
179
|
+
} catch {
|
|
180
|
+
return decline;
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
}
|
|
141
184
|
var CodexQuestions = class {
|
|
142
185
|
constructor(emit) {
|
|
143
186
|
this.emit = emit;
|
|
@@ -145,7 +188,7 @@ var CodexQuestions = class {
|
|
|
145
188
|
emit;
|
|
146
189
|
pending;
|
|
147
190
|
request = async (params, signal) => this.park(params, signal);
|
|
148
|
-
/** Park
|
|
191
|
+
/** Park native consent; MCP uses only local correlation because it supplies no native item ID. */
|
|
149
192
|
async requestApproval(identity, approval, signal) {
|
|
150
193
|
const result = await this.park(
|
|
151
194
|
{
|
|
@@ -155,7 +198,7 @@ var CodexQuestions = class {
|
|
|
155
198
|
{
|
|
156
199
|
id: "native-approval",
|
|
157
200
|
header: "Approval",
|
|
158
|
-
question: approval.kind === "permissions" ? "Allow these permissions for the current turn?" : "Allow this native action once?",
|
|
201
|
+
question: approval.kind === "permissions" ? "Allow these permissions for the current turn?" : approval.kind === "mcp" ? "Allow this native MCP request once?" : "Allow this native action once?",
|
|
159
202
|
options: [
|
|
160
203
|
{
|
|
161
204
|
label: "Approve once",
|
|
@@ -175,7 +218,10 @@ var CodexQuestions = class {
|
|
|
175
218
|
signal.throwIfAborted();
|
|
176
219
|
if (this.pending || !params.isBlocking || !Array.isArray(params.questions) || params.questions.length === 0 || params.questions.length > 16 || params.questions.some((q) => !q.id || !q.question || q.isSecret) || new Set(params.questions.map((q) => q.id)).size !== params.questions.length || new Set(params.questions.map((q) => q.question)).size !== params.questions.length)
|
|
177
220
|
throw new Error("CODEX_INPUT_UNSUPPORTED");
|
|
221
|
+
params = structuredClone(params);
|
|
222
|
+
approval = approval ? structuredClone(approval) : void 0;
|
|
178
223
|
const id = randomUUID();
|
|
224
|
+
const eventId = params.itemId ?? `local-consent:${id}`;
|
|
179
225
|
return new Promise((resolve, reject) => {
|
|
180
226
|
const abort = () => finish();
|
|
181
227
|
const finish = (result) => {
|
|
@@ -194,8 +240,8 @@ var CodexQuestions = class {
|
|
|
194
240
|
};
|
|
195
241
|
const input = {
|
|
196
242
|
requestId: id,
|
|
197
|
-
questions: params.questions,
|
|
198
|
-
...approval ? { approval } : {}
|
|
243
|
+
questions: structuredClone(params.questions),
|
|
244
|
+
...approval ? { approval: structuredClone(approval) } : {}
|
|
199
245
|
};
|
|
200
246
|
signal.addEventListener("abort", abort, { once: true });
|
|
201
247
|
if (signal.aborted) {
|
|
@@ -210,17 +256,18 @@ var CodexQuestions = class {
|
|
|
210
256
|
{
|
|
211
257
|
type: "tool_use",
|
|
212
258
|
name: "AskUserQuestion",
|
|
213
|
-
id:
|
|
259
|
+
id: eventId,
|
|
214
260
|
input
|
|
215
261
|
}
|
|
216
262
|
]
|
|
217
263
|
}
|
|
218
264
|
});
|
|
265
|
+
if (this.pending?.id !== id || signal.aborted) return;
|
|
219
266
|
this.emit({
|
|
220
267
|
type: "tool_call",
|
|
221
268
|
name: "AskUserQuestion",
|
|
222
269
|
tool: { name: "AskUserQuestion" },
|
|
223
|
-
toolCallId:
|
|
270
|
+
toolCallId: eventId,
|
|
224
271
|
input
|
|
225
272
|
});
|
|
226
273
|
});
|
|
@@ -243,7 +290,7 @@ var CodexQuestions = class {
|
|
|
243
290
|
};
|
|
244
291
|
|
|
245
292
|
// bridge/src/codex/managed-driver.ts
|
|
246
|
-
var
|
|
293
|
+
var record2 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
247
294
|
var failure = (code = "CODEX_RUNTIME_UNSUPPORTED") => new Error(code);
|
|
248
295
|
var nativeUsage = (value) => ({
|
|
249
296
|
...typeof value.inputTokens === "number" ? { inputTokens: value.inputTokens } : {},
|
|
@@ -415,6 +462,7 @@ var ManagedCodexDriver = class extends AgentDriver {
|
|
|
415
462
|
});
|
|
416
463
|
this.instance = prepareCodexInstance(this.config, options, this.credential);
|
|
417
464
|
const generation = ++this.generation;
|
|
465
|
+
const mcpReplies = /* @__PURE__ */ new WeakMap();
|
|
418
466
|
this.controller = new AbortController();
|
|
419
467
|
this.startupRefreshUsed = false;
|
|
420
468
|
this.startupAuthAttempted = false;
|
|
@@ -475,6 +523,10 @@ var ManagedCodexDriver = class extends AgentDriver {
|
|
|
475
523
|
requestTimeoutMs: timeout,
|
|
476
524
|
serverRequestTimeoutMs: Math.min(limit(options.interactionTimeoutMs, 3e5), 3e5),
|
|
477
525
|
onServerRequest: handlers,
|
|
526
|
+
canReplyToServerRequest: (method, params) => {
|
|
527
|
+
if (method !== "mcpServer/elicitation/request") return true;
|
|
528
|
+
return record2(params) && (mcpReplies.get(params)?.() ?? false);
|
|
529
|
+
},
|
|
478
530
|
onNotification: (method, params) => {
|
|
479
531
|
if (generation === this.generation) this.notification(method, params);
|
|
480
532
|
},
|
|
@@ -510,7 +562,7 @@ var ManagedCodexDriver = class extends AgentDriver {
|
|
|
510
562
|
} catch {
|
|
511
563
|
throw failure("CODEX_REQUIRED_TOOL_UNAVAILABLE");
|
|
512
564
|
}
|
|
513
|
-
if (!this.tools || !
|
|
565
|
+
if (!this.tools || !record2(this.tools.mcpServers) || typeof this.tools.dispose !== "function" || Object.keys(this.tools.mcpServers).length === 0 && Object.keys(this.tools.onServerRequest ?? {}).length === 0)
|
|
514
566
|
throw failure("CODEX_REQUIRED_TOOL_UNAVAILABLE");
|
|
515
567
|
if (this.tools.onServerRequest?.["item/tool/requestUserInput"])
|
|
516
568
|
throw failure("AI_PROFILE_INVALID");
|
|
@@ -525,21 +577,40 @@ var ManagedCodexDriver = class extends AgentDriver {
|
|
|
525
577
|
return snapshot ? JSON.parse(snapshot) : void 0;
|
|
526
578
|
}
|
|
527
579
|
});
|
|
580
|
+
const approvalTools = this.tools;
|
|
581
|
+
const approvalServerName = approvalTools.approvalServerName;
|
|
582
|
+
const approvalServer = approvalServerName ? approvalTools.mcpServers[approvalServerName] : void 0;
|
|
583
|
+
const approvalServerSnapshot = structuredClone(approvalServer);
|
|
584
|
+
const mcpBindingActive = () => this.tools === approvalTools && approvalTools.approvalServerName === approvalServerName && Boolean(approvalServerName) && Object.hasOwn(approvalTools.mcpServers, approvalServerName) && record2(approvalServer) && approvalTools.mcpServers[approvalServerName] === approvalServer && isDeepStrictEqual(approvalServer, approvalServerSnapshot);
|
|
585
|
+
const mcpPolicy = () => tuning.approvalPolicy === "never" ? void 0 : this.nativeApprovalPolicy;
|
|
586
|
+
const mcpApproval = createCodexMcpApprovalHandler({
|
|
587
|
+
serverName: approvalServerName,
|
|
588
|
+
questions: this.questions,
|
|
589
|
+
getPolicy: mcpPolicy,
|
|
590
|
+
bindingActive: mcpBindingActive
|
|
591
|
+
});
|
|
528
592
|
for (const [method, handler] of Object.entries({
|
|
529
593
|
...this.tools.onServerRequest,
|
|
530
594
|
...nativeApprovals,
|
|
531
|
-
"item/tool/requestUserInput": this.questions.request
|
|
595
|
+
"item/tool/requestUserInput": this.questions.request,
|
|
596
|
+
"mcpServer/elicitation/request": mcpApproval
|
|
532
597
|
})) {
|
|
533
598
|
if (method === "account/chatgptAuthTokens/refresh" || !handler)
|
|
534
599
|
throw failure("AI_PROFILE_INVALID");
|
|
535
600
|
handlers[method] = async (params, signal) => {
|
|
536
601
|
const active = this.active;
|
|
537
|
-
if (generation !== this.generation || !active || !
|
|
602
|
+
if (generation !== this.generation || !active || !record2(params)) throw failure();
|
|
538
603
|
await active.ready;
|
|
539
604
|
if (generation !== this.generation || this.active !== active || params.threadId !== this.threadId || params.turnId !== active.id)
|
|
540
605
|
throw failure();
|
|
541
606
|
const cancellation = AbortSignal.any([signal, active.controller.signal]);
|
|
542
607
|
if (cancellation.aborted) throw failure();
|
|
608
|
+
if (method === "mcpServer/elicitation/request") {
|
|
609
|
+
mcpReplies.set(
|
|
610
|
+
params,
|
|
611
|
+
() => generation === this.generation && this.active === active && !cancellation.aborted && params.threadId === this.threadId && params.turnId === active.id && mcpBindingActive() && isNativeApprovalPolicyActive(mcpPolicy(), this.threadId ?? "")
|
|
612
|
+
);
|
|
613
|
+
}
|
|
543
614
|
const result = await handler(params, cancellation);
|
|
544
615
|
if (generation !== this.generation || cancellation.aborted || this.active !== active)
|
|
545
616
|
throw failure();
|
|
@@ -571,14 +642,14 @@ var ManagedCodexDriver = class extends AgentDriver {
|
|
|
571
642
|
...threadParams,
|
|
572
643
|
allowProviderModelFallback: false
|
|
573
644
|
});
|
|
574
|
-
if (!
|
|
645
|
+
if (!record2(response) || response.model !== this.config.model)
|
|
575
646
|
throw failure("CODEX_MODEL_UNAVAILABLE");
|
|
576
|
-
if (!
|
|
647
|
+
if (!record2(response.thread) || typeof response.thread.id !== "string" || resuming && response.thread.id !== this.config.resumeSessionId || resuming && !Array.isArray(response.thread.turns) || response.reasoningEffort !== (this.config.effort ?? tuning.reasoningEffort) || response.modelProvider !== "openai" || response.approvalPolicy !== tuning.approvalPolicy)
|
|
577
648
|
throw failure("AI_PROFILE_INVALID");
|
|
578
649
|
if (generation !== this.generation || this.killed) throw failure();
|
|
579
650
|
this.resumeUsageTurnIds = new Set(
|
|
580
651
|
resuming && Array.isArray(response.thread.turns) ? response.thread.turns.flatMap(
|
|
581
|
-
(turn) =>
|
|
652
|
+
(turn) => record2(turn) && typeof turn.id === "string" ? [turn.id] : []
|
|
582
653
|
) : []
|
|
583
654
|
);
|
|
584
655
|
this.nativeApprovalPolicy = activateNativeApprovalPolicy(
|
|
@@ -623,7 +694,7 @@ var ManagedCodexDriver = class extends AgentDriver {
|
|
|
623
694
|
}
|
|
624
695
|
async refresh(params, signal) {
|
|
625
696
|
const credential = this.credential;
|
|
626
|
-
if (!
|
|
697
|
+
if (!record2(params) || params.reason !== "unauthorized" || !credential || credential.kind !== "codex-subscription" || params.previousAccountId != null && params.previousAccountId !== credential.chatgptAccountId || !this.options?.refreshCredential || (this.active ? this.active.refreshUsed : this.startupRefreshUsed))
|
|
627
698
|
throw failure("CODEX_AUTH_UNAVAILABLE");
|
|
628
699
|
if (this.active) this.active.refreshUsed = true;
|
|
629
700
|
else this.startupRefreshUsed = true;
|
|
@@ -741,7 +812,7 @@ var ManagedCodexDriver = class extends AgentDriver {
|
|
|
741
812
|
effort: this.config.effort ?? this.config.driverOptions.codex.reasoningEffort
|
|
742
813
|
});
|
|
743
814
|
if (this.active !== active) return;
|
|
744
|
-
if (!
|
|
815
|
+
if (!record2(response.turn) || typeof response.turn.id !== "string") throw failure();
|
|
745
816
|
active.id = response.turn.id;
|
|
746
817
|
active.readyNow();
|
|
747
818
|
for (const event of active.events.splice(0)) this.notification(event.method, event.params);
|
|
@@ -812,7 +883,8 @@ var ManagedCodexDriver = class extends AgentDriver {
|
|
|
812
883
|
this.pendingPatch = { ...this.pendingPatch, ...patch };
|
|
813
884
|
}
|
|
814
885
|
closeGeneration() {
|
|
815
|
-
++this.generation;
|
|
886
|
+
const generation = ++this.generation;
|
|
887
|
+
const finalMcp = { ...this.mcpDiagnostics };
|
|
816
888
|
this.mcpStartup = "unknown";
|
|
817
889
|
this.pendingMcpStartup = void 0;
|
|
818
890
|
this.controller.abort();
|
|
@@ -835,14 +907,19 @@ var ManagedCodexDriver = class extends AgentDriver {
|
|
|
835
907
|
if (pendingClient && pendingClient !== client) await pendingClient.dispose();
|
|
836
908
|
if (client && !client.terminationConfirmed || pendingClient && !pendingClient.terminationConfirmed)
|
|
837
909
|
this.cleanupUncertain = true;
|
|
838
|
-
if (tools)
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
910
|
+
if (tools) {
|
|
911
|
+
try {
|
|
912
|
+
await bounded(
|
|
913
|
+
Promise.resolve().then(() => tools.dispose()),
|
|
914
|
+
new AbortController().signal,
|
|
915
|
+
1e3
|
|
916
|
+
);
|
|
917
|
+
if (generation === this.generation && !this.cleanupUncertain)
|
|
918
|
+
this.observeClosedMcp(tools, finalMcp);
|
|
919
|
+
} catch {
|
|
844
920
|
this.cleanupUncertain = true;
|
|
845
|
-
}
|
|
921
|
+
}
|
|
922
|
+
}
|
|
846
923
|
} finally {
|
|
847
924
|
instance?.release();
|
|
848
925
|
}
|
|
@@ -852,7 +929,7 @@ var ManagedCodexDriver = class extends AgentDriver {
|
|
|
852
929
|
return this.closing;
|
|
853
930
|
}
|
|
854
931
|
notification(method, params) {
|
|
855
|
-
if (!
|
|
932
|
+
if (!record2(params)) return;
|
|
856
933
|
if (method === "mcpServer/startupStatus/updated") {
|
|
857
934
|
const serverName = this.tools?.diagnostics?.serverName;
|
|
858
935
|
if (!serverName || params.name !== serverName || typeof params.threadId !== "string" || params.threadId.length > 512 || typeof params.status !== "string" || !["starting", "ready", "failed", "cancelled"].includes(params.status))
|
|
@@ -869,7 +946,7 @@ var ManagedCodexDriver = class extends AgentDriver {
|
|
|
869
946
|
return;
|
|
870
947
|
}
|
|
871
948
|
const active = this.active;
|
|
872
|
-
if ((!active || !active.usageCursor && this.resumeUsageTurnIds.has(String(params.turnId))) && method === "thread/tokenUsage/updated" && params.threadId === (this.threadId ?? this.config.resumeSessionId) &&
|
|
949
|
+
if ((!active || !active.usageCursor && this.resumeUsageTurnIds.has(String(params.turnId))) && method === "thread/tokenUsage/updated" && params.threadId === (this.threadId ?? this.config.resumeSessionId) && record2(params.tokenUsage) && record2(params.tokenUsage.total)) {
|
|
873
950
|
this.threadUsageTotal = nativeUsage(params.tokenUsage.total);
|
|
874
951
|
if (active) active.usageBaseline = this.threadUsageTotal;
|
|
875
952
|
return;
|
|
@@ -883,12 +960,12 @@ var ManagedCodexDriver = class extends AgentDriver {
|
|
|
883
960
|
} else active.events.push({ method, params });
|
|
884
961
|
return;
|
|
885
962
|
}
|
|
886
|
-
const turnId =
|
|
963
|
+
const turnId = record2(params.turn) ? params.turn.id : params.turnId;
|
|
887
964
|
if (turnId !== active.id) return;
|
|
888
|
-
if (method === "thread/tokenUsage/updated" &&
|
|
965
|
+
if (method === "thread/tokenUsage/updated" && record2(params.tokenUsage)) {
|
|
889
966
|
const last = params.tokenUsage.last;
|
|
890
967
|
const total = params.tokenUsage.total;
|
|
891
|
-
const cumulativeUsage =
|
|
968
|
+
const cumulativeUsage = record2(total) ? nativeUsage(total) : void 0;
|
|
892
969
|
if (cumulativeUsage) {
|
|
893
970
|
active.usageBaseline ??= {};
|
|
894
971
|
this.resumeUsageTurnIds.clear();
|
|
@@ -900,7 +977,7 @@ var ManagedCodexDriver = class extends AgentDriver {
|
|
|
900
977
|
active.usageCursor = cumulativeUsage;
|
|
901
978
|
this.threadUsageTotal = cumulativeUsage;
|
|
902
979
|
}
|
|
903
|
-
if (
|
|
980
|
+
if (record2(last)) {
|
|
904
981
|
if (typeof last.totalTokens === "number") active.contextTokens = last.totalTokens;
|
|
905
982
|
}
|
|
906
983
|
if (typeof params.tokenUsage.modelContextWindow === "number")
|
|
@@ -908,7 +985,7 @@ var ManagedCodexDriver = class extends AgentDriver {
|
|
|
908
985
|
} else if (method === "model/rerouted") {
|
|
909
986
|
active.actualModel = typeof params.toModel === "string" ? params.toModel : active.actualModel;
|
|
910
987
|
active.failureCode = "CODEX_MODEL_UNAVAILABLE";
|
|
911
|
-
} else if (method === "turn/completed" &&
|
|
988
|
+
} else if (method === "turn/completed" && record2(params.turn)) this.complete(params.turn);
|
|
912
989
|
else if (method === "error" && params.willRetry !== true)
|
|
913
990
|
active.failureCode = this.nativeErrorCode(params.error);
|
|
914
991
|
else if (method === "item/agentMessage/delta" && typeof params.itemId === "string" && typeof params.delta === "string") {
|
|
@@ -918,14 +995,14 @@ var ManagedCodexDriver = class extends AgentDriver {
|
|
|
918
995
|
type: "message_start",
|
|
919
996
|
message: { role: "assistant", content: [{ type: "text", text: "" }] }
|
|
920
997
|
});
|
|
921
|
-
const
|
|
922
|
-
active.messages.set(params.itemId,
|
|
998
|
+
const text2 = (previous ?? "") + params.delta;
|
|
999
|
+
active.messages.set(params.itemId, text2);
|
|
923
1000
|
this.event({
|
|
924
1001
|
type: "message_update",
|
|
925
|
-
message: { role: "assistant", content: [{ type: "text", text }] },
|
|
1002
|
+
message: { role: "assistant", content: [{ type: "text", text: text2 }] },
|
|
926
1003
|
_textDelta: params.delta
|
|
927
1004
|
});
|
|
928
|
-
} else if ((method === "item/started" || method === "item/completed") &&
|
|
1005
|
+
} else if ((method === "item/started" || method === "item/completed") && record2(params.item) && typeof params.item.id === "string") {
|
|
929
1006
|
this.item(
|
|
930
1007
|
params.item,
|
|
931
1008
|
method === "item/completed"
|
|
@@ -1009,11 +1086,11 @@ var ManagedCodexDriver = class extends AgentDriver {
|
|
|
1009
1086
|
this.finishTurn(this.active?.failureCode ?? this.nativeErrorCode(turn.error));
|
|
1010
1087
|
}
|
|
1011
1088
|
nativeErrorCode(error) {
|
|
1012
|
-
const info =
|
|
1089
|
+
const info = record2(error) ? error.codexErrorInfo : void 0;
|
|
1013
1090
|
if (info === "unauthorized") return "CODEX_RECONNECT_REQUIRED";
|
|
1014
1091
|
if (info === "usageLimitExceeded" || info === "rateLimitExceeded" || info === "serverOverloaded")
|
|
1015
1092
|
return "CODEX_RATE_LIMITED";
|
|
1016
|
-
if (
|
|
1093
|
+
if (record2(info) && [
|
|
1017
1094
|
"httpConnectionFailed",
|
|
1018
1095
|
"responseStreamConnectionFailed",
|
|
1019
1096
|
"responseStreamDisconnected",
|
|
@@ -1039,9 +1116,31 @@ var ManagedCodexDriver = class extends AgentDriver {
|
|
|
1039
1116
|
this.mcpDiagnostics.startupAtEnd = this.mcpStartup;
|
|
1040
1117
|
this.mcpDiagnostics.toolsListTotal = Math.max(this.mcpDiagnostics.toolsListBeforeTurn, listed);
|
|
1041
1118
|
this.mcpDiagnostics.toolsCallTotal = beforeTurn ? called : Math.max(this.mcpDiagnostics.toolsCallTotal, called);
|
|
1119
|
+
this.publishMcp(this.mcpDiagnostics);
|
|
1120
|
+
}
|
|
1121
|
+
observeClosedMcp(tools, snapshot) {
|
|
1122
|
+
try {
|
|
1123
|
+
const counts = tools.diagnostics?.requestCounts();
|
|
1124
|
+
if (!counts || ![counts.toolsListTotal, counts.toolsCallTotal].every(
|
|
1125
|
+
(value) => Number.isSafeInteger(value) && value >= 0
|
|
1126
|
+
))
|
|
1127
|
+
return;
|
|
1128
|
+
snapshot.toolsListTotal = Math.max(
|
|
1129
|
+
snapshot.toolsListTotal,
|
|
1130
|
+
Math.min(512, counts.toolsListTotal)
|
|
1131
|
+
);
|
|
1132
|
+
snapshot.toolsCallTotal = Math.max(
|
|
1133
|
+
snapshot.toolsCallTotal,
|
|
1134
|
+
Math.min(512, counts.toolsCallTotal)
|
|
1135
|
+
);
|
|
1136
|
+
this.publishMcp(snapshot);
|
|
1137
|
+
} catch {
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
publishMcp(snapshot) {
|
|
1042
1141
|
try {
|
|
1043
1142
|
void Promise.resolve(
|
|
1044
|
-
this.options?.onNativeMcpDiagnostics?.(Object.freeze({ ...
|
|
1143
|
+
this.options?.onNativeMcpDiagnostics?.(Object.freeze({ ...snapshot }))
|
|
1045
1144
|
).catch(() => {
|
|
1046
1145
|
});
|
|
1047
1146
|
} catch {
|
|
@@ -1056,10 +1155,10 @@ var ManagedCodexDriver = class extends AgentDriver {
|
|
|
1056
1155
|
active.controller.abort();
|
|
1057
1156
|
active.fileChanges.clear();
|
|
1058
1157
|
active.readyNow();
|
|
1059
|
-
for (const
|
|
1158
|
+
for (const text2 of active.messages.values())
|
|
1060
1159
|
this.event({
|
|
1061
1160
|
type: "message_end",
|
|
1062
|
-
message: { role: "assistant", content: [{ type: "text", text }] }
|
|
1161
|
+
message: { role: "assistant", content: [{ type: "text", text: text2 }] }
|
|
1063
1162
|
});
|
|
1064
1163
|
this.event({ type: "turn_end", toolResults: active.toolResults });
|
|
1065
1164
|
const modelUsage = active.usage ? {
|
|
@@ -1546,10 +1645,10 @@ var CodexDriver = class extends AgentDriver {
|
|
|
1546
1645
|
});
|
|
1547
1646
|
this.pendingToolResults = [];
|
|
1548
1647
|
}
|
|
1549
|
-
buildAssistantMessage(
|
|
1648
|
+
buildAssistantMessage(text2) {
|
|
1550
1649
|
return {
|
|
1551
1650
|
role: "assistant",
|
|
1552
|
-
content: [{ type: "text", text }]
|
|
1651
|
+
content: [{ type: "text", text: text2 }]
|
|
1553
1652
|
};
|
|
1554
1653
|
}
|
|
1555
1654
|
toObject(value) {
|