@skaile/workspaces 4.20.0 → 4.21.1
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 +14 -0
- package/dist/app-sdk/index.js +1 -1
- package/dist/{asset-feeds-HQJGP42P.js → asset-feeds-HKPNPO7N.js} +4 -4
- package/dist/{asset-feeds-HQJGP42P.js.map → asset-feeds-HKPNPO7N.js.map} +1 -1
- package/dist/asset-manager/index.js +1 -1
- package/dist/bridge/drivers/claude-sdk.js +160 -5
- package/dist/bridge/drivers/claude-sdk.js.map +1 -1
- package/dist/bridge/drivers/codex.js +2 -2
- package/dist/bridge/drivers/continue.js +3 -3
- package/dist/bridge/drivers/echo.js +3 -3
- package/dist/bridge/drivers/gemini.js +5 -5
- package/dist/bridge/drivers/goose.js +3 -3
- package/dist/bridge/drivers/omp.js +20 -4
- package/dist/bridge/drivers/omp.js.map +1 -1
- package/dist/bridge/drivers/opencode.js +3 -3
- package/dist/bridge/drivers/qwen.js +5 -5
- package/dist/bridge/index.js +5 -5
- package/dist/bridge/src/drivers/claude-context-usage.d.ts +104 -0
- package/dist/bridge/src/drivers/claude-context-usage.d.ts.map +1 -0
- package/dist/bridge/src/drivers/claude-sdk.d.ts +13 -1
- package/dist/bridge/src/drivers/claude-sdk.d.ts.map +1 -1
- package/dist/bridge/src/drivers/omp.d.ts +8 -1
- package/dist/bridge/src/drivers/omp.d.ts.map +1 -1
- package/dist/bridge/src/types.d.ts +16 -1
- package/dist/bridge/src/types.d.ts.map +1 -1
- package/dist/{chunk-IDPHRLYV.js → chunk-5FMWNSAQ.js} +3 -3
- package/dist/{chunk-IDPHRLYV.js.map → chunk-5FMWNSAQ.js.map} +1 -1
- package/dist/{chunk-666BKSSR.js → chunk-5YDCUHJI.js} +3 -3
- package/dist/{chunk-666BKSSR.js.map → chunk-5YDCUHJI.js.map} +1 -1
- package/dist/{chunk-D3LQY3MT.js → chunk-AEOHSR27.js} +3 -3
- package/dist/{chunk-D3LQY3MT.js.map → chunk-AEOHSR27.js.map} +1 -1
- package/dist/{chunk-EMWWU6RR.js → chunk-ES4E6RDZ.js} +3 -3
- package/dist/{chunk-EMWWU6RR.js.map → chunk-ES4E6RDZ.js.map} +1 -1
- package/dist/{chunk-XJTD6KWX.js → chunk-EUGEEYGD.js} +2 -2
- package/dist/{chunk-XJTD6KWX.js.map → chunk-EUGEEYGD.js.map} +1 -1
- package/dist/{chunk-RJ67DIJI.js → chunk-FELWDKLQ.js} +3 -3
- package/dist/{chunk-RJ67DIJI.js.map → chunk-FELWDKLQ.js.map} +1 -1
- package/dist/{chunk-3FGGVQDU.js → chunk-HA674IQL.js} +6 -6
- package/dist/{chunk-3FGGVQDU.js.map → chunk-HA674IQL.js.map} +1 -1
- package/dist/{chunk-VFUY5O4T.js → chunk-I4VIRPHS.js} +3 -3
- package/dist/{chunk-VFUY5O4T.js.map → chunk-I4VIRPHS.js.map} +1 -1
- package/dist/{chunk-RZNASEEJ.js → chunk-IZAN5MHL.js} +3 -3
- package/dist/{chunk-RZNASEEJ.js.map → chunk-IZAN5MHL.js.map} +1 -1
- package/dist/{chunk-OFC725VA.js → chunk-N5XNEKHC.js} +771 -19
- package/dist/chunk-N5XNEKHC.js.map +1 -0
- package/dist/{chunk-DMDZTEL4.js → chunk-ODIJJXXB.js} +6 -6
- package/dist/{chunk-DMDZTEL4.js.map → chunk-ODIJJXXB.js.map} +1 -1
- package/dist/{chunk-P6L3CMKN.js → chunk-OPSKLUB4.js} +2 -2
- package/dist/{chunk-P6L3CMKN.js.map → chunk-OPSKLUB4.js.map} +1 -1
- package/dist/{chunk-CHGN5BTN.js → chunk-R3EU2FFW.js} +4 -4
- package/dist/{chunk-CHGN5BTN.js.map → chunk-R3EU2FFW.js.map} +1 -1
- package/dist/{chunk-OR7C7PTE.js → chunk-RBTVXXD5.js} +3 -3
- package/dist/{chunk-OR7C7PTE.js.map → chunk-RBTVXXD5.js.map} +1 -1
- package/dist/{chunk-56UHERYI.js → chunk-RLACUE4X.js} +3 -3
- package/dist/{chunk-56UHERYI.js.map → chunk-RLACUE4X.js.map} +1 -1
- package/dist/{chunk-TLOP6FLY.js → chunk-RTD5KAM4.js} +17 -2
- package/dist/chunk-RTD5KAM4.js.map +1 -0
- package/dist/{chunk-TFCZYDOE.js → chunk-RZ2YIFT6.js} +6 -6
- package/dist/{chunk-TFCZYDOE.js.map → chunk-RZ2YIFT6.js.map} +1 -1
- package/dist/{chunk-PGQDBXS7.js → chunk-S5A5MVJN.js} +4 -4
- package/dist/chunk-S5A5MVJN.js.map +1 -0
- package/dist/{chunk-QNC7VEBL.js → chunk-SY2HSULI.js} +3 -3
- package/dist/{chunk-QNC7VEBL.js.map → chunk-SY2HSULI.js.map} +1 -1
- package/dist/{chunk-4WBZC7UF.js → chunk-XBMCUMZT.js} +4 -4
- package/dist/{chunk-4WBZC7UF.js.map → chunk-XBMCUMZT.js.map} +1 -1
- package/dist/{chunk-2KTI5R4T.js → chunk-YEQ3BXOY.js} +3 -3
- package/dist/{chunk-2KTI5R4T.js.map → chunk-YEQ3BXOY.js.map} +1 -1
- package/dist/{chunk-EC24QFGP.js → chunk-ZDSZGV5F.js} +7 -7
- package/dist/{chunk-EC24QFGP.js.map → chunk-ZDSZGV5F.js.map} +1 -1
- package/dist/cli/index.js +35 -35
- package/dist/connectors/index.js +7 -7
- package/dist/connectors-shared/index.js +2 -2
- package/dist/{ensure-sources-LQNEZUFT.js → ensure-sources-MUS622KB.js} +4 -4
- package/dist/{ensure-sources-LQNEZUFT.js.map → ensure-sources-MUS622KB.js.map} +1 -1
- package/dist/factory-assets/connectors/box.js +7 -7
- package/dist/factory-assets/connectors/deploy.js +7 -7
- package/dist/factory-assets/connectors/devserver.js +7 -7
- package/dist/factory-assets/connectors/flow/adapter.js +7 -7
- package/dist/factory-assets/connectors/flow/run-flow.js +8 -8
- package/dist/factory-assets/connectors/flow.js +7 -7
- package/dist/factory-assets/connectors/git.js +7 -7
- package/dist/factory-assets/connectors/gmail.js +7 -7
- package/dist/factory-assets/connectors/googledrive.js +7 -7
- package/dist/factory-assets/connectors/local.js +7 -7
- package/dist/factory-assets/connectors/mattermost.js +7 -7
- package/dist/factory-assets/connectors/memory.js +7 -7
- package/dist/factory-assets/connectors/minio.js +7 -7
- package/dist/factory-assets/connectors/postgres.js +7 -7
- package/dist/factory-assets/connectors/s3.js +7 -7
- package/dist/factory-assets/connectors/sharepoint.js +7 -7
- package/dist/factory-assets/connectors/sqlite.js +7 -7
- package/dist/factory-assets/connectors/static-server.js +7 -7
- package/dist/factory-assets/connectors/tunnel.js +7 -7
- package/dist/factory-assets/connectors/webdav.js +7 -7
- package/dist/factory-assets/connectors/xstate-store.js +7 -7
- package/dist/factory-assets/connectors/xstate.js +7 -7
- package/dist/{helpers-73M3SDDE.js → helpers-V3IJWB75.js} +4 -4
- package/dist/{helpers-73M3SDDE.js.map → helpers-V3IJWB75.js.map} +1 -1
- package/dist/{library-publish-NLA2EBV7.js → library-publish-TXJM76SD.js} +6 -6
- package/dist/{library-publish-NLA2EBV7.js.map → library-publish-TXJM76SD.js.map} +1 -1
- package/dist/{open-library-FHPRGIP6.js → open-library-ORTV2RUE.js} +5 -5
- package/dist/{open-library-FHPRGIP6.js.map → open-library-ORTV2RUE.js.map} +1 -1
- package/dist/{project-OKV7M4BV.js → project-GI2A75UN.js} +5 -5
- package/dist/{project-OKV7M4BV.js.map → project-GI2A75UN.js.map} +1 -1
- package/dist/runner/index.js +11 -11
- package/dist/runner/src/ai-credential-retry.d.ts +14 -0
- package/dist/runner/src/ai-credential-retry.d.ts.map +1 -1
- package/dist/runner/src/capability-roundtrip.d.ts +18 -0
- package/dist/runner/src/capability-roundtrip.d.ts.map +1 -1
- package/dist/runner/src/compaction/orchestrator.d.ts +12 -0
- package/dist/runner/src/compaction/orchestrator.d.ts.map +1 -1
- package/dist/runner/src/context-usage/collector.d.ts +83 -0
- package/dist/runner/src/context-usage/collector.d.ts.map +1 -0
- package/dist/runner/src/context-usage/compose.d.ts +51 -0
- package/dist/runner/src/context-usage/compose.d.ts.map +1 -0
- package/dist/runner/src/context-usage/estimator.d.ts +13 -0
- package/dist/runner/src/context-usage/estimator.d.ts.map +1 -0
- package/dist/runner/src/context-usage/index.d.ts +6 -0
- package/dist/runner/src/context-usage/index.d.ts.map +1 -0
- package/dist/runner/src/context-usage/skill-listings.d.ts +8 -0
- package/dist/runner/src/context-usage/skill-listings.d.ts.map +1 -0
- package/dist/runner/src/context-usage/transcript-tracker.d.ts +35 -0
- package/dist/runner/src/context-usage/transcript-tracker.d.ts.map +1 -0
- package/dist/runner/src/event-gap-buffer.d.ts +77 -0
- package/dist/runner/src/event-gap-buffer.d.ts.map +1 -0
- package/dist/runner/src/serve.d.ts.map +1 -1
- package/dist/sdk/asset-manager.js +1 -1
- package/dist/sdk/bridge.js +5 -5
- package/dist/sdk/index.js +11 -11
- package/dist/sdk/runner.js +11 -11
- package/dist/sdk/session.js +2 -2
- package/dist/sdk/types.js +1 -1
- package/dist/session/index.js +2 -2
- package/dist/{setup-VBXJH72H.js → setup-GLCLE36X.js} +10 -10
- package/dist/{setup-VBXJH72H.js.map → setup-GLCLE36X.js.map} +1 -1
- package/dist/{source-6KKMQU67.js → source-N6EKFFH5.js} +6 -6
- package/dist/{source-6KKMQU67.js.map → source-N6EKFFH5.js.map} +1 -1
- package/dist/{source-manifest-publish-EPIP6RQ3.js → source-manifest-publish-BDMY4B4B.js} +7 -7
- package/dist/{source-manifest-publish-EPIP6RQ3.js.map → source-manifest-publish-BDMY4B4B.js.map} +1 -1
- package/dist/tui/index.js +11 -11
- package/dist/types/index.js +1 -1
- package/dist/types/src/context-usage.d.ts +142 -0
- package/dist/types/src/context-usage.d.ts.map +1 -0
- package/dist/types/src/events.d.ts +26 -1
- package/dist/types/src/events.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +3 -2
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/protocol.d.ts +21 -1
- package/dist/types/src/protocol.d.ts.map +1 -1
- package/dist/types/src/version.d.ts +7 -1
- package/dist/types/src/version.d.ts.map +1 -1
- package/dist/workspace-plugin/adapters/mcp.js +2 -2
- package/dist/workspace-plugin/index.js +1 -1
- package/package.json +3 -3
- package/dist/chunk-OFC725VA.js.map +0 -1
- package/dist/chunk-PGQDBXS7.js.map +0 -1
- package/dist/chunk-TLOP6FLY.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 4.21.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#861](https://github.com/skaile-ai/workspaces/pull/861) [`0716bcf`](https://github.com/skaile-ai/workspaces/commit/0716bcf9c61a1238e1170aa1586974502a97857e) Thanks [@peteralbert](https://github.com/peteralbert)! - runner: a container that outlives a platform backend restart now comes through the gap intact. Agent events produced while no platform is connected are buffered (at most 10,000 events / 16 MiB, oldest dropped first) and flushed on reconnect between the replayed `session_init_ack` and the turn-status snapshot. A configured runner that tries to mint an AI credential while disconnected now fails transiently (`backend-error`) instead of terminally (`not-configured`), and each reconnect re-arms the proactive refresh scheduler. Capability calls in flight when the connection drops are rejected at once instead of waiting out their timeout. Today's platform needs no change.
|
|
8
|
+
|
|
9
|
+
## 4.21.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [#856](https://github.com/skaile-ai/workspaces/pull/856) [`752cc74`](https://github.com/skaile-ai/workspaces/commit/752cc74414c14e8b3828f2052a9138397d3f2e0b) Thanks [@peteralbert](https://github.com/peteralbert)! - The runner reports what fills a session's context window, like Claude Code's `/context`, for every driver (protocol 4.7.0). A `context_usage` event carries a `ContextUsageSnapshot`: fixed buckets (`provider-system`, `skaile-system`, `agent-prompt`, `memory`, `skills`, `mcp-tools`, `builtin-tools`, `subagents`, `content`, `free`, `compaction-buffer`), each marked `measured`, `estimated`, `derived` or `unknown`, plus the window and the runner's auto-compaction trigger. It is emitted after every turn and after a compaction, and in answer to the new `get_context_usage { requestId, detail? }` command, exactly once per `requestId`. A failed measurement still gets its answer, with estimates and an `error`. Drivers can implement `AgentDriver.getContextUsageReport({ detail })`: `full` may call the provider, `summary` must stay local. claude-sdk maps the SDK's `getContextUsage({ detail })` on each row's `kind`. A `full` report costs `count_tokens` requests, including one that uploads the whole conversation, so it runs only when a measured breakdown is requested. The per-turn snapshot uses the local `summary`, so its per-category figures are marked `estimated`. omp reports its `get_state` fill and window. Other drivers get runner estimates and the exact fill. A 4.6 runner ignores the command, so a host must treat a missing answer as unsupported.
|
|
14
|
+
|
|
15
|
+
The Claude Agent SDK peer and dev dependency moves from `^0.3.150` to `^0.3.289`. The SDK bundles zod 4.5.4, so a host that pins zod to the SDK's bundled copy must move with it. Two SDK default changes are held back so sessions behave as before. The system prompt is sent with `snapshot: false`, because the new default would replay the first prompt on resume and ignore a changed append until the next compaction. `CLAUDE_CODE_ENABLE_TODO_TOOLS` defaults to `1`, because the new preset drops TodoWrite and the Task tools on Opus 4.8+ and Sonnet 5+. Set it to `0` in `config.env` to opt out.
|
|
16
|
+
|
|
3
17
|
## 4.20.0
|
|
4
18
|
|
|
5
19
|
### Minor Changes
|
package/dist/app-sdk/index.js
CHANGED
|
@@ -69,7 +69,7 @@ async function libraryAssets() {
|
|
|
69
69
|
const domains = [];
|
|
70
70
|
try {
|
|
71
71
|
const [{ openLibraryManager }, { skaileHomeDir }, { getGlobalCacheDir }] = await Promise.all([
|
|
72
|
-
import('./open-library-
|
|
72
|
+
import('./open-library-ORTV2RUE.js'),
|
|
73
73
|
import('./library/index.js'),
|
|
74
74
|
import('./core/index.js')
|
|
75
75
|
]);
|
|
@@ -102,7 +102,7 @@ async function libraryAssets() {
|
|
|
102
102
|
async function storeAssets(projectDir) {
|
|
103
103
|
const notes = [];
|
|
104
104
|
try {
|
|
105
|
-
const { resolveCatalogSource } = await import('./open-library-
|
|
105
|
+
const { resolveCatalogSource } = await import('./open-library-ORTV2RUE.js');
|
|
106
106
|
const { source, close } = await resolveCatalogSource({ projectDir });
|
|
107
107
|
try {
|
|
108
108
|
const assets = await source.listAssets();
|
|
@@ -206,5 +206,5 @@ function dedupeBySlug(domains) {
|
|
|
206
206
|
}
|
|
207
207
|
|
|
208
208
|
export { gatherAssetFeeds };
|
|
209
|
-
//# sourceMappingURL=asset-feeds-
|
|
210
|
-
//# sourceMappingURL=asset-feeds-
|
|
209
|
+
//# sourceMappingURL=asset-feeds-HKPNPO7N.js.map
|
|
210
|
+
//# sourceMappingURL=asset-feeds-HKPNPO7N.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../cli/src/asset-feeds.ts"],"names":[],"mappings":"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","file":"asset-feeds-HQJGP42P.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-HKPNPO7N.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-EUGEEYGD.js';
|
|
2
2
|
import '../chunk-UFWADBG6.js';
|
|
3
3
|
import '../chunk-HGPSZXZP.js';
|
|
4
4
|
import '../chunk-VOEBLPXO.js';
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { formatDroppedToolsNotice, filterInProcessMcpServerTools, checkToolPropertyKeys } from '../../chunk-X5O56UO4.js';
|
|
2
2
|
import { scrubPoisonedTranscript, transcriptStoreForRuntime, resolveClaudeConfigDir, claudeEndpointMode, buildClaudeEndpointEnv } from '../../chunk-6S5KL76M.js';
|
|
3
|
-
import { dispatchCapability } from '../../chunk-
|
|
4
|
-
import { fetchProviderModels } from '../../chunk-
|
|
3
|
+
import { dispatchCapability } from '../../chunk-RLACUE4X.js';
|
|
4
|
+
import { fetchProviderModels } from '../../chunk-RBTVXXD5.js';
|
|
5
5
|
import { AuthError, stripRunnerPrivateEnv, classifyClaudeSdkError, reclassifyAuthAsAccountUnavailable, AccountUnavailableError } from '../../chunk-BGY4KTU6.js';
|
|
6
6
|
import { agentExecRequested, wrapAgentCommand, resolveAgentExec } from '../../chunk-YROR332M.js';
|
|
7
|
-
import { BUILTIN_DRIVER_CATALOG, AgentDriver, getBridgeLogger, entryCredentialValue, registryDriverConfig } from '../../chunk-
|
|
7
|
+
import { BUILTIN_DRIVER_CATALOG, AgentDriver, getBridgeLogger, entryCredentialValue, registryDriverConfig } from '../../chunk-RTD5KAM4.js';
|
|
8
8
|
import '../../chunk-6E6PKKAD.js';
|
|
9
|
-
import { withActivityLabelShape } from '../../chunk-
|
|
9
|
+
import { withActivityLabelShape } from '../../chunk-S5A5MVJN.js';
|
|
10
10
|
import '../../chunk-UWU572Q6.js';
|
|
11
11
|
import '../../chunk-4GY63JU6.js';
|
|
12
12
|
import '../../chunk-5RHPNNWP.js';
|
|
@@ -30,6 +30,136 @@ import { readFileSync, existsSync } from 'fs';
|
|
|
30
30
|
import { createRequire } from 'module';
|
|
31
31
|
import * as zNS from 'zod';
|
|
32
32
|
|
|
33
|
+
// bridge/src/drivers/claude-context-usage.ts
|
|
34
|
+
var USED_ROW = {
|
|
35
|
+
systemPrompt: "System prompt",
|
|
36
|
+
systemTools: "System tools",
|
|
37
|
+
mcpTools: "MCP tools",
|
|
38
|
+
mcpInstructions: "MCP server instructions",
|
|
39
|
+
messages: "Messages"
|
|
40
|
+
};
|
|
41
|
+
function claudeSystemPromptSectionName(text) {
|
|
42
|
+
const heading = text.match(/^#+\s+(.+)$/m);
|
|
43
|
+
if (heading?.[1]) return heading[1].trim();
|
|
44
|
+
const line = text.split("\n").find((l) => l.trim().length > 0) ?? "";
|
|
45
|
+
return line.length > 40 ? `${line.slice(0, 40)}\u2026` : line;
|
|
46
|
+
}
|
|
47
|
+
function mapClaudeContextUsage(resp, opts = {}) {
|
|
48
|
+
const used = resp.categories.filter((c) => c.kind === "used");
|
|
49
|
+
const usedRow = (name) => used.find((c) => c.name === name)?.tokens;
|
|
50
|
+
const summary = opts.detail === "summary";
|
|
51
|
+
const report = {
|
|
52
|
+
contextWindow: resp.maxTokens > 0 ? resp.maxTokens : null
|
|
53
|
+
};
|
|
54
|
+
if (summary) report.breakdownFidelity = "estimated";
|
|
55
|
+
if (!summary || resp.apiUsage) report.usedTokens = resp.totalTokens;
|
|
56
|
+
if (resp.autoCompactThreshold !== void 0) {
|
|
57
|
+
report.harnessAutoCompactAt = resp.autoCompactThreshold;
|
|
58
|
+
}
|
|
59
|
+
const systemPromptTokens = usedRow(USED_ROW.systemPrompt);
|
|
60
|
+
if (systemPromptTokens !== void 0) report.systemPromptTokens = systemPromptTokens;
|
|
61
|
+
if (resp.systemPromptSections?.length) {
|
|
62
|
+
const sections = [...resp.systemPromptSections];
|
|
63
|
+
const appendedName = opts.appendedSystemPrompt ? claudeSystemPromptSectionName(opts.appendedSystemPrompt) : void 0;
|
|
64
|
+
const appendedIndex = appendedName !== void 0 ? sections.map((s) => s.name).lastIndexOf(appendedName) : -1;
|
|
65
|
+
if (appendedIndex >= 0) {
|
|
66
|
+
report.appendedSystemPromptTokens = sections[appendedIndex]?.tokens ?? 0;
|
|
67
|
+
sections.splice(appendedIndex, 1);
|
|
68
|
+
}
|
|
69
|
+
report.systemPromptSections = sections.map((s) => ({ name: s.name, tokens: s.tokens }));
|
|
70
|
+
}
|
|
71
|
+
if (resp.memoryFiles?.length) {
|
|
72
|
+
report.memory = sumBucket(
|
|
73
|
+
resp.memoryFiles.map((f) => ({ name: f.path, tokens: f.tokens, group: f.type }))
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
if (resp.skills) {
|
|
77
|
+
report.skills = {
|
|
78
|
+
tokens: resp.skills.tokens,
|
|
79
|
+
items: resp.skills.skillFrontmatter.map((s) => ({
|
|
80
|
+
name: s.name,
|
|
81
|
+
tokens: s.tokens,
|
|
82
|
+
source: s.source
|
|
83
|
+
}))
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
const deferredTotal = sumTokens(resp.categories.filter((c) => c.kind === "deferred"));
|
|
87
|
+
const mcpItems = (resp.mcpTools ?? []).map((t) => ({
|
|
88
|
+
name: t.name,
|
|
89
|
+
tokens: t.tokens,
|
|
90
|
+
group: t.serverName,
|
|
91
|
+
...t.isLoaded === false ? { deferred: true } : {}
|
|
92
|
+
}));
|
|
93
|
+
const mcpDeferred = sumTokens(mcpItems.filter((i) => i.deferred));
|
|
94
|
+
const mcpRow = usedRow(USED_ROW.mcpTools);
|
|
95
|
+
const mcpInstructions = usedRow(USED_ROW.mcpInstructions);
|
|
96
|
+
if (mcpItems.length > 0 || mcpRow !== void 0 || mcpInstructions !== void 0) {
|
|
97
|
+
const instructionItems = mcpInstructions ? [{ name: "Server instructions", tokens: mcpInstructions, group: "instructions" }] : [];
|
|
98
|
+
const items = [...mcpItems, ...instructionItems];
|
|
99
|
+
report.mcpTools = {
|
|
100
|
+
tokens: (mcpRow ?? sumTokens(mcpItems.filter((i) => !i.deferred))) + (mcpInstructions ?? 0),
|
|
101
|
+
...items.length > 0 ? { items } : {},
|
|
102
|
+
...mcpDeferred > 0 ? { deferredTokens: mcpDeferred } : {}
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
const builtinItems = [
|
|
106
|
+
...(resp.systemTools ?? []).map((t) => ({ name: t.name, tokens: t.tokens })),
|
|
107
|
+
...(resp.deferredBuiltinTools ?? []).map((t) => ({
|
|
108
|
+
name: t.name,
|
|
109
|
+
tokens: t.tokens,
|
|
110
|
+
...t.isLoaded ? {} : { deferred: true }
|
|
111
|
+
}))
|
|
112
|
+
];
|
|
113
|
+
const builtinRow = usedRow(USED_ROW.systemTools);
|
|
114
|
+
const builtinDeferred = Math.max(0, deferredTotal - mcpDeferred);
|
|
115
|
+
if (builtinItems.length > 0 || builtinRow !== void 0) {
|
|
116
|
+
report.builtinTools = {
|
|
117
|
+
tokens: builtinRow ?? sumTokens(builtinItems.filter((i) => !i.deferred)),
|
|
118
|
+
...builtinItems.length > 0 ? { items: builtinItems } : {},
|
|
119
|
+
...builtinDeferred > 0 ? { deferredTokens: builtinDeferred } : {}
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
if (resp.agents?.length) {
|
|
123
|
+
report.subagents = {
|
|
124
|
+
tokens: sumTokens(resp.agents),
|
|
125
|
+
items: resp.agents.map((a) => ({ name: a.agentType, tokens: a.tokens, source: a.source }))
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
const messages = usedRow(USED_ROW.messages);
|
|
129
|
+
if (messages !== void 0 || resp.messageBreakdown) {
|
|
130
|
+
report.content = {
|
|
131
|
+
tokens: messages ?? 0,
|
|
132
|
+
...resp.messageBreakdown ? { items: messageItems(resp.messageBreakdown) } : {}
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
return report;
|
|
136
|
+
}
|
|
137
|
+
function messageItems(b) {
|
|
138
|
+
const items = [
|
|
139
|
+
{ name: "User messages", tokens: b.userMessageTokens, group: "messages" },
|
|
140
|
+
{ name: "Assistant messages", tokens: b.assistantMessageTokens, group: "messages" }
|
|
141
|
+
];
|
|
142
|
+
for (const t of b.toolCallsByType) {
|
|
143
|
+
items.push({ name: t.name, tokens: t.callTokens + t.resultTokens, group: "tools" });
|
|
144
|
+
}
|
|
145
|
+
for (const a of b.attachmentsByType) {
|
|
146
|
+
items.push({ name: a.name, tokens: a.tokens, group: "attachments" });
|
|
147
|
+
}
|
|
148
|
+
if (b.redirectedContextTokens > 0) {
|
|
149
|
+
items.push({ name: "Redirected context", tokens: b.redirectedContextTokens, group: "other" });
|
|
150
|
+
}
|
|
151
|
+
if (b.unattributedTokens > 0) {
|
|
152
|
+
items.push({ name: "Unattributed", tokens: b.unattributedTokens, group: "other" });
|
|
153
|
+
}
|
|
154
|
+
return items.filter((i) => i.tokens > 0);
|
|
155
|
+
}
|
|
156
|
+
function sumTokens(items) {
|
|
157
|
+
return items.reduce((sum, i) => sum + i.tokens, 0);
|
|
158
|
+
}
|
|
159
|
+
function sumBucket(items) {
|
|
160
|
+
return { tokens: sumTokens(items), items };
|
|
161
|
+
}
|
|
162
|
+
|
|
33
163
|
// bridge/src/drivers/sanitize-assistant-text.ts
|
|
34
164
|
var NS = "(?:[a-z][a-z0-9]*:)?";
|
|
35
165
|
var FUNCTION_CALL_BLOCK = new RegExp(
|
|
@@ -343,6 +473,8 @@ var ClaudeSdkDriver = class extends AgentDriver {
|
|
|
343
473
|
lastApiErrorRender = null;
|
|
344
474
|
/** Active query — stays alive between turns (streaming input mode). */
|
|
345
475
|
query = null;
|
|
476
|
+
/** The block appended to the preset on the live query; finds it in a context report. */
|
|
477
|
+
appendedSystemPrompt = "";
|
|
346
478
|
/**
|
|
347
479
|
* The live query's prompt stream. Created in {@link startQuery}, fed one user
|
|
348
480
|
* message per turn, and ended wherever the query is dropped — an ended stream
|
|
@@ -1285,6 +1417,7 @@ var ClaudeSdkDriver = class extends AgentDriver {
|
|
|
1285
1417
|
const onStderr = (data) => this.log.warn("claude stderr", { line: data.trim() });
|
|
1286
1418
|
const { patch: mcpServersPatch, dropped: droppedMcpTools } = await this.buildEffectiveMcpServers();
|
|
1287
1419
|
const systemPromptAppend = [this.config.systemPrompt, formatDroppedToolsNotice(droppedMcpTools)].filter((part) => !!part).join("\n\n");
|
|
1420
|
+
this.appendedSystemPrompt = systemPromptAppend;
|
|
1288
1421
|
const options = {
|
|
1289
1422
|
cwd: this.config.cwd,
|
|
1290
1423
|
// Load project + user settings so .claude/skills/ are discovered
|
|
@@ -1346,7 +1479,11 @@ var ClaudeSdkDriver = class extends AgentDriver {
|
|
|
1346
1479
|
systemPrompt: {
|
|
1347
1480
|
type: "preset",
|
|
1348
1481
|
preset: "claude_code",
|
|
1349
|
-
...systemPromptAppend ? { append: systemPromptAppend } : {}
|
|
1482
|
+
...systemPromptAppend ? { append: systemPromptAppend } : {},
|
|
1483
|
+
// A recorded prompt ignores a different `append` on resume until the
|
|
1484
|
+
// next compaction; the runner rebuilds the append per launch (agent
|
|
1485
|
+
// edits, dropped-tool notices), so it must take effect immediately.
|
|
1486
|
+
snapshot: false
|
|
1350
1487
|
},
|
|
1351
1488
|
// ── Session continuity ────────────────────────────────────────────────
|
|
1352
1489
|
// Three-level fallback ensures the right session is always resumed:
|
|
@@ -1398,6 +1535,7 @@ var ClaudeSdkDriver = class extends AgentDriver {
|
|
|
1398
1535
|
{ ...endpoint.baseEnv, ...endpoint.configEnv }
|
|
1399
1536
|
);
|
|
1400
1537
|
childEnv.ENABLE_CLAUDEAI_MCP_SERVERS = "false";
|
|
1538
|
+
childEnv.CLAUDE_CODE_ENABLE_TODO_TOOLS ??= "1";
|
|
1401
1539
|
if (agentExecRequested()) childEnv.CLAUDE_CONFIG_DIR = this.resolveClaudeConfigDir();
|
|
1402
1540
|
options.env = stripRunnerPrivateEnv(childEnv);
|
|
1403
1541
|
const { query } = this.sdk;
|
|
@@ -2487,6 +2625,23 @@ var ClaudeSdkDriver = class extends AgentDriver {
|
|
|
2487
2625
|
getContextWindow() {
|
|
2488
2626
|
return this._contextWindow;
|
|
2489
2627
|
}
|
|
2628
|
+
/**
|
|
2629
|
+
* The SDK's `/context` breakdown, mapped to the neutral report. `full` costs
|
|
2630
|
+
* `count_tokens` requests (the transcript count uploads the conversation and
|
|
2631
|
+
* is never cached; static counts are memoized per CLI process); `summary`
|
|
2632
|
+
* answers locally from the last API usage plus character estimates. `null`
|
|
2633
|
+
* before the first query exists: there is nothing live to measure.
|
|
2634
|
+
*/
|
|
2635
|
+
async getContextUsageReport(opts = {}) {
|
|
2636
|
+
const query = this.query;
|
|
2637
|
+
if (!query) return null;
|
|
2638
|
+
const detail = opts.detail ?? "full";
|
|
2639
|
+
const resp = await query.getContextUsage({ detail });
|
|
2640
|
+
return mapClaudeContextUsage(resp, {
|
|
2641
|
+
appendedSystemPrompt: this.appendedSystemPrompt,
|
|
2642
|
+
detail
|
|
2643
|
+
});
|
|
2644
|
+
}
|
|
2490
2645
|
async resetSession() {
|
|
2491
2646
|
this.denyPendingQuestion("session reset before the question was answered");
|
|
2492
2647
|
const descendants = this.snapshotDescendantPids();
|