@skaile/workspaces 3.3.0 → 3.4.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 +108 -0
- package/dist/{asset-feeds-AGAH5OHC.js → asset-feeds-SILUSNAL.js} +11 -11
- package/dist/{asset-feeds-AGAH5OHC.js.map → asset-feeds-SILUSNAL.js.map} +1 -1
- package/dist/asset-manager/catalog-deployer.js +7 -7
- package/dist/asset-manager/index.js +10 -10
- package/dist/asset-manager/installer.js +7 -7
- package/dist/bridge/drivers/claude-sdk.js +8 -8
- package/dist/bridge/drivers/codex.js +3 -3
- package/dist/bridge/drivers/continue.js +4 -4
- package/dist/bridge/drivers/echo.js +3 -3
- package/dist/bridge/drivers/gemini.js +5 -5
- package/dist/bridge/drivers/goose.js +4 -4
- package/dist/bridge/drivers/omp.js +3 -3
- package/dist/bridge/drivers/opencode.js +4 -4
- package/dist/bridge/drivers/qwen.js +5 -5
- package/dist/bridge/index.js +9 -9
- package/dist/{chunk-4GJLRYMB.js → chunk-33ZEIMFJ.js} +3 -3
- package/dist/{chunk-4GJLRYMB.js.map → chunk-33ZEIMFJ.js.map} +1 -1
- package/dist/{chunk-7GOCNYUV.js → chunk-3A5IKBHQ.js} +47 -47
- package/dist/{chunk-7GOCNYUV.js.map → chunk-3A5IKBHQ.js.map} +1 -1
- package/dist/{chunk-ZNIHTT22.js → chunk-3UU3D2Q3.js} +5 -5
- package/dist/{chunk-ZNIHTT22.js.map → chunk-3UU3D2Q3.js.map} +1 -1
- package/dist/{chunk-E5S2WGTS.js → chunk-4GYL5TCP.js} +103 -33
- package/dist/chunk-4GYL5TCP.js.map +1 -0
- package/dist/{chunk-CZZRDYT4.js → chunk-4VTBZ2MF.js} +4 -4
- package/dist/{chunk-CZZRDYT4.js.map → chunk-4VTBZ2MF.js.map} +1 -1
- package/dist/{chunk-VT6HDD2L.js → chunk-4YYJV6TW.js} +3 -3
- package/dist/{chunk-VT6HDD2L.js.map → chunk-4YYJV6TW.js.map} +1 -1
- package/dist/{chunk-S6GKHEMN.js → chunk-5JP7ZF5I.js} +10 -10
- package/dist/{chunk-S6GKHEMN.js.map → chunk-5JP7ZF5I.js.map} +1 -1
- package/dist/{chunk-U5POE4BA.js → chunk-5Q7HA4JP.js} +3 -3
- package/dist/{chunk-U5POE4BA.js.map → chunk-5Q7HA4JP.js.map} +1 -1
- package/dist/{chunk-I7MKEZ6J.js → chunk-7EUW3BBR.js} +3 -3
- package/dist/{chunk-I7MKEZ6J.js.map → chunk-7EUW3BBR.js.map} +1 -1
- package/dist/{chunk-P43HBWKK.js → chunk-AZPXCHDK.js} +36 -7
- package/dist/chunk-AZPXCHDK.js.map +1 -0
- package/dist/{chunk-PKEAYYEJ.js → chunk-BCXI27BH.js} +219 -4
- package/dist/chunk-BCXI27BH.js.map +1 -0
- package/dist/{chunk-PRKLFKNC.js → chunk-BSPOMUA7.js} +4 -4
- package/dist/{chunk-PRKLFKNC.js.map → chunk-BSPOMUA7.js.map} +1 -1
- package/dist/{chunk-MWFYXUFK.js → chunk-G2CXWUO5.js} +4 -4
- package/dist/{chunk-MWFYXUFK.js.map → chunk-G2CXWUO5.js.map} +1 -1
- package/dist/{chunk-BEAIJRVF.js → chunk-GHWJHOYX.js} +4 -4
- package/dist/{chunk-BEAIJRVF.js.map → chunk-GHWJHOYX.js.map} +1 -1
- package/dist/{chunk-5FLEP4X6.js → chunk-HBF7A7JB.js} +45 -5
- package/dist/chunk-HBF7A7JB.js.map +1 -0
- package/dist/{chunk-MJ77WSJC.js → chunk-HIFLMPNV.js} +6 -6
- package/dist/{chunk-MJ77WSJC.js.map → chunk-HIFLMPNV.js.map} +1 -1
- package/dist/{chunk-KPZZI2KG.js → chunk-HV3ZCE4M.js} +3 -3
- package/dist/{chunk-KPZZI2KG.js.map → chunk-HV3ZCE4M.js.map} +1 -1
- package/dist/{chunk-Q26C5GLO.js → chunk-IP3GXHOB.js} +3 -4
- package/dist/chunk-IP3GXHOB.js.map +1 -0
- package/dist/{chunk-RRCNMURJ.js → chunk-J7HJUX4W.js} +29 -21
- package/dist/chunk-J7HJUX4W.js.map +1 -0
- package/dist/{chunk-BK3WL3QK.js → chunk-JAHHMZWG.js} +3 -3
- package/dist/{chunk-BK3WL3QK.js.map → chunk-JAHHMZWG.js.map} +1 -1
- package/dist/{chunk-BOH6AG6Q.js → chunk-KHLEQB4F.js} +47 -37
- package/dist/chunk-KHLEQB4F.js.map +1 -0
- package/dist/chunk-M5D2QNTY.js +23 -0
- package/dist/chunk-M5D2QNTY.js.map +1 -0
- package/dist/{chunk-2OCYS5EP.js → chunk-O7WKKINT.js} +4 -4
- package/dist/{chunk-2OCYS5EP.js.map → chunk-O7WKKINT.js.map} +1 -1
- package/dist/{chunk-3HVASHBF.js → chunk-OCLCDB7G.js} +6 -15
- package/dist/chunk-OCLCDB7G.js.map +1 -0
- package/dist/{chunk-NU4E7C5I.js → chunk-PW4SJE3X.js} +3 -3
- package/dist/{chunk-NU4E7C5I.js.map → chunk-PW4SJE3X.js.map} +1 -1
- package/dist/{chunk-O6B3ZZ5S.js → chunk-QAH2DYIP.js} +4 -4
- package/dist/{chunk-O6B3ZZ5S.js.map → chunk-QAH2DYIP.js.map} +1 -1
- package/dist/{chunk-33GWB3RB.js → chunk-QEQ5I47S.js} +3 -3
- package/dist/{chunk-33GWB3RB.js.map → chunk-QEQ5I47S.js.map} +1 -1
- package/dist/{chunk-EP7VBFMN.js → chunk-R4BUI5BU.js} +7 -7
- package/dist/{chunk-EP7VBFMN.js.map → chunk-R4BUI5BU.js.map} +1 -1
- package/dist/{chunk-46LE3GNY.js → chunk-RUFTB7QN.js} +3 -3
- package/dist/{chunk-46LE3GNY.js.map → chunk-RUFTB7QN.js.map} +1 -1
- package/dist/{chunk-UFY2HFLO.js → chunk-SH572OBN.js} +4 -4
- package/dist/{chunk-UFY2HFLO.js.map → chunk-SH572OBN.js.map} +1 -1
- package/dist/{chunk-OD3ABXUO.js → chunk-UEH5XAQR.js} +8 -8
- package/dist/{chunk-OD3ABXUO.js.map → chunk-UEH5XAQR.js.map} +1 -1
- package/dist/{chunk-DYMWJAL4.js → chunk-VQ4P7UYE.js} +3 -3
- package/dist/{chunk-DYMWJAL4.js.map → chunk-VQ4P7UYE.js.map} +1 -1
- package/dist/{chunk-AM5LFRXJ.js → chunk-WAFHQDLK.js} +3 -3
- package/dist/{chunk-AM5LFRXJ.js.map → chunk-WAFHQDLK.js.map} +1 -1
- package/dist/{chunk-3KEJ2HJY.js → chunk-WC7Q6GMC.js} +3 -3
- package/dist/{chunk-3KEJ2HJY.js.map → chunk-WC7Q6GMC.js.map} +1 -1
- package/dist/cli/index.js +145 -170
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/src/commands/run.d.ts.map +1 -1
- package/dist/cli/src/flow-discovery.d.ts +9 -9
- package/dist/cli/src/flow-discovery.d.ts.map +1 -1
- package/dist/cli/src/paths.d.ts +9 -33
- package/dist/cli/src/paths.d.ts.map +1 -1
- package/dist/connectors/config.js +7 -7
- package/dist/connectors/index.js +12 -12
- package/dist/core/index.js +6 -6
- package/dist/core/logging.js +2 -2
- package/dist/core/manifest.js +2 -2
- package/dist/core/runtime-assets.js +4 -4
- package/dist/core/src/asset-roots.d.ts +74 -0
- package/dist/core/src/asset-roots.d.ts.map +1 -0
- package/dist/core/src/index.d.ts +1 -0
- package/dist/core/src/index.d.ts.map +1 -1
- package/dist/core/src/workspace-config.d.ts +0 -2
- package/dist/core/src/workspace-config.d.ts.map +1 -1
- package/dist/core/workspace-config.js +3 -3
- package/dist/deploy/index.js +6 -6
- package/dist/discovery/index.js +3 -3
- package/dist/{ensure-sources-L2276FYP.js → ensure-sources-SZABN3WG.js} +13 -13
- package/dist/{ensure-sources-L2276FYP.js.map → ensure-sources-SZABN3WG.js.map} +1 -1
- package/dist/factory-assets/connectors/box.js +12 -12
- package/dist/factory-assets/connectors/deploy.js +12 -12
- package/dist/factory-assets/connectors/devserver.js +12 -12
- package/dist/factory-assets/connectors/flow/CONNECTOR.md +22 -2
- package/dist/factory-assets/connectors/flow/adapter.d.ts +1 -1
- package/dist/factory-assets/connectors/flow/adapter.d.ts.map +1 -1
- package/dist/factory-assets/connectors/flow/adapter.js +12 -12
- package/dist/factory-assets/connectors/flow/engine/index.d.ts +1 -0
- package/dist/factory-assets/connectors/flow/engine/index.d.ts.map +1 -1
- package/dist/factory-assets/connectors/flow/engine/locate.d.ts +75 -0
- package/dist/factory-assets/connectors/flow/engine/locate.d.ts.map +1 -0
- package/dist/factory-assets/connectors/flow/engine.js +7 -7
- package/dist/factory-assets/connectors/flow/index.d.ts +1 -1
- package/dist/factory-assets/connectors/flow/index.d.ts.map +1 -1
- package/dist/factory-assets/connectors/flow/node-executor.d.ts +23 -3
- package/dist/factory-assets/connectors/flow/node-executor.d.ts.map +1 -1
- package/dist/factory-assets/connectors/flow/run-flow.d.ts +9 -1
- package/dist/factory-assets/connectors/flow/run-flow.d.ts.map +1 -1
- package/dist/factory-assets/connectors/flow/run-flow.js +14 -14
- package/dist/factory-assets/connectors/flow.js +12 -12
- package/dist/factory-assets/connectors/git.js +12 -12
- package/dist/factory-assets/connectors/gmail.js +12 -12
- package/dist/factory-assets/connectors/googledrive.js +12 -12
- package/dist/factory-assets/connectors/local.js +12 -12
- package/dist/factory-assets/connectors/mattermost.js +12 -12
- package/dist/factory-assets/connectors/memory.js +12 -12
- package/dist/factory-assets/connectors/minio.js +12 -12
- package/dist/factory-assets/connectors/postgres.js +12 -12
- package/dist/factory-assets/connectors/s3.js +12 -12
- package/dist/factory-assets/connectors/sharepoint.js +12 -12
- package/dist/factory-assets/connectors/sqlite.js +12 -12
- package/dist/factory-assets/connectors/static-server.js +12 -12
- package/dist/factory-assets/connectors/tunnel.js +12 -12
- package/dist/factory-assets/connectors/webdav.js +12 -12
- package/dist/factory-assets/connectors/xstate-store.js +12 -12
- package/dist/factory-assets/connectors/xstate.js +12 -12
- package/dist/flows-4PIPK2S6.js +20 -0
- package/dist/{flows-7CZKSC64.js.map → flows-4PIPK2S6.js.map} +1 -1
- package/dist/{helpers-ZWHB5JHQ.js → helpers-XDIMXDTI.js} +13 -13
- package/dist/{helpers-ZWHB5JHQ.js.map → helpers-XDIMXDTI.js.map} +1 -1
- package/dist/library/index.js +8 -8
- package/dist/library/install.js +6 -6
- package/dist/library/src/config.d.ts +6 -6
- package/dist/library/src/config.d.ts.map +1 -1
- package/dist/{library-publish-CVYFMVGR.js → library-publish-HDYBQF46.js} +17 -17
- package/dist/{library-publish-CVYFMVGR.js.map → library-publish-HDYBQF46.js.map} +1 -1
- package/dist/{open-library-XB65LU3M.js → open-library-LAUJOTYJ.js} +15 -15
- package/dist/{open-library-XB65LU3M.js.map → open-library-LAUJOTYJ.js.map} +1 -1
- package/dist/paths-S7UESJKT.js +16 -0
- package/dist/{paths-B52KTS7N.js.map → paths-S7UESJKT.js.map} +1 -1
- package/dist/{plugin-store-EOP3S7OU.js → plugin-store-5SJX2PRR.js} +8 -8
- package/dist/{plugin-store-EOP3S7OU.js.map → plugin-store-5SJX2PRR.js.map} +1 -1
- package/dist/{project-E5LKCE7R.js → project-6IW2N3MX.js} +14 -14
- package/dist/{project-E5LKCE7R.js.map → project-6IW2N3MX.js.map} +1 -1
- package/dist/resolver/index.js +7 -7
- package/dist/runner/index.js +17 -17
- package/dist/runner/src/compaction/orchestrator.d.ts +14 -2
- package/dist/runner/src/compaction/orchestrator.d.ts.map +1 -1
- package/dist/sdk/asset-manager.js +10 -10
- package/dist/sdk/bridge.js +9 -9
- package/dist/sdk/core.js +6 -6
- package/dist/sdk/flow.js +7 -7
- package/dist/sdk/index.js +17 -17
- package/dist/sdk/resolver.js +7 -7
- package/dist/sdk/runner.js +17 -17
- package/dist/sdk/session.js +1 -1
- package/dist/session/index.js +1 -1
- package/dist/session/src/dispatcher.d.ts +15 -0
- package/dist/session/src/dispatcher.d.ts.map +1 -1
- package/dist/session/src/workspace-change-digest.d.ts +34 -0
- package/dist/session/src/workspace-change-digest.d.ts.map +1 -0
- package/dist/{setup-XI7TCIGF.js → setup-YA2QHQ2N.js} +11 -11
- package/dist/{setup-XI7TCIGF.js.map → setup-YA2QHQ2N.js.map} +1 -1
- package/dist/skills-OBJX3VYG.js +20 -0
- package/dist/{skills-5PJ6YVM7.js.map → skills-OBJX3VYG.js.map} +1 -1
- package/dist/{source-7BNREKGK.js → source-FIE5KQS2.js} +16 -16
- package/dist/{source-7BNREKGK.js.map → source-FIE5KQS2.js.map} +1 -1
- package/dist/{source-manifest-publish-JGMHNADH.js → source-manifest-publish-64PTOEP2.js} +18 -18
- package/dist/{source-manifest-publish-JGMHNADH.js.map → source-manifest-publish-64PTOEP2.js.map} +1 -1
- package/dist/tui/index.js +17 -17
- package/dist/types/src/events.d.ts +1 -1
- package/dist/types/src/events.d.ts.map +1 -1
- package/dist/workspace-plugin/adapters/mcp.js +11 -11
- package/dist/workspace-plugin/adapters/omp.js +7 -7
- package/dist/workspace-plugin/index.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-3HVASHBF.js.map +0 -1
- package/dist/chunk-5FLEP4X6.js.map +0 -1
- package/dist/chunk-6OMKIPIE.js +0 -42
- package/dist/chunk-6OMKIPIE.js.map +0 -1
- package/dist/chunk-BOH6AG6Q.js.map +0 -1
- package/dist/chunk-E5S2WGTS.js.map +0 -1
- package/dist/chunk-P43HBWKK.js.map +0 -1
- package/dist/chunk-PKEAYYEJ.js.map +0 -1
- package/dist/chunk-Q26C5GLO.js.map +0 -1
- package/dist/chunk-RRCNMURJ.js.map +0 -1
- package/dist/flows-7CZKSC64.js +0 -20
- package/dist/paths-B52KTS7N.js +0 -22
- package/dist/skills-5PJ6YVM7.js +0 -20
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../bridge/src/cloud.ts","../bridge/src/drivers/scrub-transcript.ts","../bridge/src/drivers/resume-probe.ts"],"names":["join"],"mappings":"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","file":"chunk-46LE3GNY.js","sourcesContent":["/**\n * AI cloud-provider transport dimension for the `claude-sdk` driver.\n *\n * `cloud` is a config axis orthogonal to `provider` (model vendor) and\n * `driver` (agent runtime). Under `driver: claude-sdk` each non-default value\n * maps to one of the Claude Agent SDK's native env-var transports:\n * Amazon Bedrock, Google Vertex AI, Azure AI Foundry, or a generic\n * `ANTHROPIC_BASE_URL` gateway (LiteLLM / corporate proxy).\n *\n * Cross-repo contract: env key names and semantics here are load-bearing —\n * the platform resolves credential bundles against the same key set.\n */\n\n/**\n * Canonical list of supported cloud transports. `\"default\"` (or an absent\n * `cloud` field) means the provider's native API — today's behavior, unchanged.\n *\n * The codec in `core/workspace-config.ts` keeps a local copy (`KNOWN_CLOUDS`)\n * to avoid an import cycle; a drift test asserts parity.\n *\n * @since 1.3.0\n */\nexport const SUPPORTED_CLOUDS = [\"default\", \"bedrock\", \"vertex\", \"azure\", \"gateway\"] as const;\n\n/** One of the supported cloud transport identifiers. */\nexport type CloudId = (typeof SUPPORTED_CLOUDS)[number];\n\n/**\n * Non-secret transport settings for a cloud. Sourced from skaile.yaml\n * `cloud_config` (snake_case on the wire, camelCase in-process — converted\n * exactly once at the settings/serve boundary).\n *\n * Must stay field-identical with core's `CloudTransportConfig` and the inline\n * `AgentSessionConfig.cloudConfig` shape (kept separate to avoid a core↔bridge\n * import cycle) — a field added here must be added there too.\n *\n * @since 1.3.0\n */\nexport interface CloudConfig {\n /** bedrock: AWS region (`AWS_REGION`); vertex: `CLOUD_ML_REGION`. */\n region?: string;\n /** vertex only: GCP project (`ANTHROPIC_VERTEX_PROJECT_ID`). */\n projectId?: string;\n /** azure only: Foundry resource name (`ANTHROPIC_FOUNDRY_RESOURCE`). */\n resource?: string;\n /** azure (alternative to `resource`) / gateway (required): endpoint base URL. */\n baseUrl?: string;\n}\n\n/**\n * Secret env keys that make up the credential bundle for each non-default\n * cloud. The platform delivers these env-keyed in the `session_init` secrets\n * map; the runner picks them out via `resolveCloudSecretBundle`.\n *\n * Vertex note: `GOOGLE_APPLICATION_CREDENTIALS_JSON` is our convention for the\n * raw service-account JSON blob. The runner materializes it to a 0600 file and\n * hands the driver `GOOGLE_APPLICATION_CREDENTIALS` (a path) instead — the\n * driver never sees the raw JSON.\n *\n * @since 1.3.0\n */\nexport const CLOUD_SECRET_ENV_KEYS: Record<Exclude<CloudId, \"default\">, readonly string[]> = {\n bedrock: [\n \"AWS_ACCESS_KEY_ID\",\n \"AWS_SECRET_ACCESS_KEY\",\n \"AWS_SESSION_TOKEN\",\n \"AWS_BEARER_TOKEN_BEDROCK\",\n ],\n vertex: [\"GOOGLE_APPLICATION_CREDENTIALS_JSON\"],\n azure: [\"ANTHROPIC_FOUNDRY_API_KEY\"],\n gateway: [\"ANTHROPIC_AUTH_TOKEN\", \"ANTHROPIC_API_KEY\"],\n};\n\n/**\n * Env vars scrubbed from the inherited environment before a non-default cloud\n * transport is assembled. Ambient first-party credentials or a stale\n * `CLAUDE_CODE_USE_*` flag must never leak into a Bedrock/Vertex/Foundry/\n * gateway session (the gateway branch re-adds its own carriers explicitly).\n *\n * Deliberately NOT exhaustive across clouds: ambient cloud-specific vars\n * (AWS_*, GOOGLE_*, ANTHROPIC_VERTEX_PROJECT_ID, ANTHROPIC_FOUNDRY_*) survive\n * so a standalone CLI inherits its own cloud's environment; the SDK ignores\n * vars whose transport flag is unset.\n */\nconst SCRUBBED_ENV_KEYS = [\"ANTHROPIC_API_KEY\", \"ANTHROPIC_AUTH_TOKEN\", \"ANTHROPIC_BASE_URL\"];\n\n/**\n * Assemble the Claude Agent SDK child env for a non-default cloud transport.\n *\n * Pure function (no external state touched; the returned `env` is a fresh\n * object — inputs are never mutated): starts from `baseEnv` (caller passes a\n * copy of `process.env` with undefined stripped) merged with `configEnv`,\n * scrubs inherited Anthropic\n * credential/routing vars and every `CLAUDE_CODE_USE_*` flag, then sets exactly\n * one `CLAUDE_CODE_USE_*` flag (none for gateway) plus the cloud's credential\n * bundle and derived non-secret vars. AWS_* / GOOGLE_* ambient values are NOT\n * scrubbed, so a standalone CLI inherits ambient cloud credentials when no\n * explicit `cloudSecrets` bundle is provided. Gateway is the mirror case: its\n * carriers ARE the scrubbed Anthropic vars, so the gateway branch restores\n * them from `cloudSecrets` → `fallbackApiKey` (resolved `apiKeys.anthropic`)\n * → the pre-scrub config/ambient value — otherwise a standalone gateway\n * session would have no reachable auth carrier at all.\n *\n * Never returns `undefined` values; absent settings are simply omitted.\n *\n * @since 1.3.0\n */\nexport function buildClaudeCloudEnv(args: {\n cloud: Exclude<CloudId, \"default\">;\n cloudConfig?: CloudConfig;\n cloudSecrets?: Record<string, string>;\n baseEnv: Record<string, string>;\n configEnv?: Record<string, string>;\n /** Resolved API key (e.g. `apiKeys.anthropic`) — gateway auth fallback only. */\n fallbackApiKey?: string;\n}): Record<string, string> {\n const { cloud, cloudConfig, cloudSecrets, baseEnv, configEnv, fallbackApiKey } = args;\n const env: Record<string, string> = { ...baseEnv, ...(configEnv ?? {}) };\n\n // Captured before the scrub — gateway falls back to these carriers.\n const ambient = {\n authToken: env.ANTHROPIC_AUTH_TOKEN,\n apiKey: env.ANTHROPIC_API_KEY,\n baseUrl: env.ANTHROPIC_BASE_URL,\n };\n\n for (const key of Object.keys(env)) {\n if (SCRUBBED_ENV_KEYS.includes(key) || key.startsWith(\"CLAUDE_CODE_USE_\")) {\n delete env[key];\n }\n }\n\n const set = (key: string, value: string | undefined) => {\n // Falsy check is deliberate: an empty-string credential/setting is never\n // valid env — dropping it beats shipping a key the SDK treats as set.\n if (value) env[key] = value;\n };\n\n switch (cloud) {\n case \"bedrock\": {\n env.CLAUDE_CODE_USE_BEDROCK = \"1\";\n // Explicit bundle values override ambient AWS_* (which survive the scrub\n // so a standalone CLI keeps its ambient credentials).\n for (const key of CLOUD_SECRET_ENV_KEYS.bedrock) set(key, cloudSecrets?.[key]);\n set(\"AWS_REGION\", cloudConfig?.region);\n break;\n }\n case \"vertex\": {\n env.CLAUDE_CODE_USE_VERTEX = \"1\";\n // Runner-materialized SA file path; ambient GOOGLE_APPLICATION_CREDENTIALS\n // is kept when no bundle value is provided.\n set(\"GOOGLE_APPLICATION_CREDENTIALS\", cloudSecrets?.GOOGLE_APPLICATION_CREDENTIALS);\n set(\"ANTHROPIC_VERTEX_PROJECT_ID\", cloudConfig?.projectId);\n set(\"CLOUD_ML_REGION\", cloudConfig?.region);\n break;\n }\n case \"azure\": {\n env.CLAUDE_CODE_USE_FOUNDRY = \"1\";\n set(\"ANTHROPIC_FOUNDRY_API_KEY\", cloudSecrets?.ANTHROPIC_FOUNDRY_API_KEY);\n // Resource wins over base_url when both are configured.\n if (cloudConfig?.resource) {\n env.ANTHROPIC_FOUNDRY_RESOURCE = cloudConfig.resource;\n } else {\n set(\"ANTHROPIC_FOUNDRY_BASE_URL\", cloudConfig?.baseUrl);\n }\n break;\n }\n case \"gateway\": {\n // No CLAUDE_CODE_USE_* flag — the gateway is addressed purely via\n // ANTHROPIC_BASE_URL plus an auth carrier. Explicit bundle wins;\n // standalone sessions fall back to the resolved key / ambient carriers.\n set(\"ANTHROPIC_BASE_URL\", cloudConfig?.baseUrl ?? ambient.baseUrl);\n const authToken = cloudSecrets?.ANTHROPIC_AUTH_TOKEN ?? ambient.authToken;\n if (authToken) {\n env.ANTHROPIC_AUTH_TOKEN = authToken;\n } else {\n set(\n \"ANTHROPIC_API_KEY\",\n cloudSecrets?.ANTHROPIC_API_KEY ?? fallbackApiKey ?? ambient.apiKey,\n );\n }\n break;\n }\n }\n\n return env;\n}\n","/**\n * Poisoned-transcript repair for the Claude Agent SDK driver.\n *\n * The Anthropic Messages API can permanently reject a conversation once its\n * persisted history contains a malformed content block. Because the bad block\n * lives in the SDK's on-disk JSONL transcript, every replayed turn fails with\n * the same `400 invalid_request_error` and the session is bricked with no\n * in-band recovery.\n *\n * This module repairs the transcript in place, covering three known poison\n * classes:\n *\n * 1. **Image `media_type` mismatch / omission.** An image block whose declared\n * `media_type` does not match — or is missing for — the actual bytes:\n * `... The image was specified using the image/png media type, but the\n * image appears to be a image/jpeg image`. Produced by the Claude Code\n * `Read` tool's format fallback (anthropics/claude-code#55338, #30124,\n * #33179). Repaired by sniffing the base64 magic bytes and correcting\n * `media_type`.\n * 2. **Oversized image.** An image whose decoded payload exceeds the API's\n * 5 MB per-image limit (anthropics/claude-code#34566). Replaced with a\n * text stub — the byte budget cannot be recovered any other way.\n * 3. **`cache_control` on an empty text block.** A text block carrying a\n * `cache_control` marker with empty/whitespace `text`\n * (anthropics/claude-code#59626). The `cache_control` field is stripped.\n *\n * Genuinely unidentifiable image blocks are also replaced with a text stub.\n *\n * Recovering by content scan (rather than parsing the API's `messages.N`\n * index) is deliberate: the index addresses the assembled API request, not a\n * JSONL line, and reproducing the SDK's message-assembly is fragile. A full\n * scan is index-free and repairs every poisoned block in one pass.\n *\n * **Async and line-streaming since #454.** A Claude Code transcript is routinely\n * multi-megabyte (base64 images inline in `tool_result` blocks), and this runs on\n * a failed turn *and before every resume* — inside the single-threaded `skaile\n * serve` loop. The previous `readFileSync` + `writeFileSync` + `renameSync` held\n * the loop for the whole file and materialised it twice over as one string. Both\n * passes now stream line by line off a `createReadStream`, so the loop is yielded\n * between lines and peak memory is one JSONL line rather than the whole file, and\n * every I/O phase is deadline-bounded.\n *\n * Streaming was chosen over a worker thread: the work is I/O-bound rather than\n * CPU-bound (per-line `JSON.parse` on a yielded loop is not what stalls a turn),\n * and a worker would add a structured-clone of the same multi-MB payload plus a\n * thread lifecycle to a path that must never block a turn.\n *\n * @module\n */\n\nimport { createReadStream, createWriteStream } from \"node:fs\";\nimport { readdir, rename, stat, unlink } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { pipeline } from \"node:stream/promises\";\nimport { fsDeadlineMs, tryWithFsDeadline, withFsDeadline } from \"@skaile/workspaces/core\";\n\n/**\n * Minimal logger shape accepted by {@link scrubPoisonedTranscript}. Compatible\n * with the bridge `Logger`, but narrowed so the helper stays unit-testable\n * without a real logger instance.\n *\n * @category Transcript repair\n */\nexport interface ScrubLogger {\n info(message: string, data?: Record<string, unknown>): void;\n warn(message: string, data?: Record<string, unknown>): void;\n}\n\n/**\n * Options for {@link scrubPoisonedTranscript}.\n *\n * @category Transcript repair\n */\nexport interface ScrubTranscriptOptions {\n /**\n * Claude Code config directory — the parent of `projects/`. Resolve from\n * `CLAUDE_CONFIG_DIR`, falling back to `~/.claude`.\n */\n configDir: string;\n /** SDK session id whose transcript JSONL should be repaired. */\n sessionId: string;\n /** Optional logger for diagnostics. */\n log?: ScrubLogger;\n}\n\n/**\n * Outcome of a {@link scrubPoisonedTranscript} pass.\n *\n * @category Transcript repair\n */\nexport interface ScrubTranscriptResult {\n /** The located JSONL transcript path, or `null` when not found. */\n filePath: string | null;\n /** Image blocks whose `media_type` was corrected (or filled in) to match the bytes. */\n corrected: number;\n /**\n * Image blocks replaced with a text stub — either unidentifiable bytes or a\n * payload over the API's 5 MB per-image limit.\n */\n stubbed: number;\n /** Empty text blocks from which a rejected `cache_control` marker was stripped. */\n cacheStripped: number;\n /**\n * `true` when the transcript was located, contained at least one poisoned\n * block, and was rewritten. `false` means nothing needed repair (or the\n * file was not found) — the caller should not retry the resume.\n */\n changed: boolean;\n}\n\n/** Text inserted in place of an image block whose format cannot be identified. */\nconst STUB_TEXT = \"[image removed: unprocessable image data]\";\n\n/** Text inserted in place of an image block that exceeds the API size limit. */\nconst STUB_TEXT_OVERSIZED = \"[image removed: image too large]\";\n\n/**\n * The Anthropic Messages API rejects any single image whose decoded payload\n * exceeds 5 MB. An image at or under this is left alone; a larger one is\n * stubbed (its byte budget cannot be recovered).\n */\nconst MAX_IMAGE_BYTES = 5 * 1024 * 1024;\n\n/**\n * Identify an image's media type from the leading bytes of its base64 payload.\n *\n * Recognises the four formats the Anthropic API accepts. Returns `null` when\n * the magic bytes match no known format — the caller treats that as a\n * genuinely corrupt block and stubs it.\n *\n * @param base64 - Base64-encoded image data (only the prefix is inspected).\n * @returns An `image/*` media type, or `null` when unrecognised.\n * @category Transcript repair\n */\nexport function sniffImageMediaType(base64: string): string | null {\n let buf: Buffer;\n try {\n // 32 base64 chars decode to 24 bytes — enough for the WebP check at 12.\n buf = Buffer.from(base64.slice(0, 32), \"base64\");\n } catch {\n return null;\n }\n if (buf.length < 4) {\n return null;\n }\n // JPEG — SOI marker `FF D8`. Third byte varies (and may be corrupt), so a\n // two-byte check is intentional: it still matches malformed JPEGs, which is\n // exactly the poison case the API flags as \"appears to be image/jpeg\".\n if (buf[0] === 0xff && buf[1] === 0xd8) {\n return \"image/jpeg\";\n }\n // PNG — `89 50 4E 47`.\n if (buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4e && buf[3] === 0x47) {\n return \"image/png\";\n }\n // GIF — `47 49 46 38` (\"GIF8\").\n if (buf[0] === 0x47 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x38) {\n return \"image/gif\";\n }\n // WebP — `RIFF` at 0..3 and `WEBP` at 8..11.\n if (\n buf.length >= 12 &&\n buf[0] === 0x52 &&\n buf[1] === 0x49 &&\n buf[2] === 0x46 &&\n buf[3] === 0x46 &&\n buf[8] === 0x57 &&\n buf[9] === 0x45 &&\n buf[10] === 0x42 &&\n buf[11] === 0x50\n ) {\n return \"image/webp\";\n }\n return null;\n}\n\n/** A base64 image source on a content block (shape is SDK-defined). */\ninterface Base64ImageSource {\n type?: string;\n media_type?: string;\n data?: string;\n}\n\n/** Loosely-typed content block from a transcript message. */\ninterface ContentBlockLike {\n type?: string;\n source?: Base64ImageSource;\n content?: unknown;\n [k: string]: unknown;\n}\n\n/** Mutable counters threaded through one scrub pass. */\ninterface ScrubCounters {\n corrected: number;\n stubbed: number;\n cacheStripped: number;\n}\n\n/** Total repairs recorded in a counter set — used to detect per-line changes. */\nfunction totalChanges(c: ScrubCounters): number {\n return c.corrected + c.stubbed + c.cacheStripped;\n}\n\n/**\n * Repair a single content block. Returns the (possibly replaced) block.\n *\n * - A `tool_result` block recurses into its `content` array.\n * - A text block carrying a `cache_control` marker whose `text` is empty or\n * whitespace has the marker stripped (the API rejects `cache_control` on\n * empty text blocks).\n * - An image block whose decoded payload exceeds the API's 5 MB limit is\n * replaced with a text stub.\n * - An image block whose bytes match no known format is replaced with a text\n * stub (an image cannot simply be dropped — a `tool_result` must keep at\n * least one content entry, and a bare `image` block is replaced 1:1).\n * - An image block whose declared `media_type` mismatches (or is missing for)\n * the sniffed type is corrected in place.\n * - Every other block is returned untouched.\n */\nfunction scrubBlock(block: ContentBlockLike, counters: ScrubCounters): ContentBlockLike {\n if (block.type === \"tool_result\" && Array.isArray(block.content)) {\n return {\n ...block,\n content: (block.content as ContentBlockLike[]).map((inner) => scrubBlock(inner, counters)),\n };\n }\n\n // A `cache_control` marker on a text block whose text is empty or whitespace\n // is rejected by the API (\"cache_control cannot be set for empty text\n // blocks\"). Strip the marker — the empty block itself is harmless.\n if (block.type === \"text\" && block.cache_control != null) {\n const text = typeof block.text === \"string\" ? block.text : \"\";\n if (text.trim() === \"\") {\n counters.cacheStripped++;\n const clone = { ...block };\n delete clone.cache_control;\n return clone;\n }\n }\n\n if (\n block.type === \"image\" &&\n block.source?.type === \"base64\" &&\n typeof block.source.data === \"string\"\n ) {\n const data = block.source.data;\n // The API rejects any image whose decoded payload exceeds 5 MB. The byte\n // budget cannot be salvaged, so the whole block becomes a text stub.\n // base64 encodes 3 bytes per 4 chars, so decoded length ≈ len * 3 / 4.\n if (Math.floor((data.length * 3) / 4) > MAX_IMAGE_BYTES) {\n counters.stubbed++;\n return { type: \"text\", text: STUB_TEXT_OVERSIZED };\n }\n const sniffed = sniffImageMediaType(data);\n if (sniffed === null) {\n counters.stubbed++;\n return { type: \"text\", text: STUB_TEXT };\n }\n if (sniffed !== block.source.media_type) {\n counters.corrected++;\n return { ...block, source: { ...block.source, media_type: sniffed } };\n }\n }\n\n return block;\n}\n\n/**\n * Locate the JSONL transcript for `sessionId` under `<configDir>/projects/`.\n *\n * Claude Code encodes the project directory into the `projects/` subfolder\n * name; rather than reproduce that encoding, this scans every subfolder for\n * `<sessionId>.jsonl` (the session id is a UUID — globally unique).\n *\n * Async and deadline-bounded since #454. The `existsSync(projectsDir)` probe is\n * gone: `readdir` already fails on a missing directory, so the probe was a\n * second stat on the same path for no information.\n *\n * `timeoutMs` defaults to {@link fsDeadlineMs} so callers that only need the\n * path (the resume probe) can omit it.\n *\n * @category Transcript repair\n */\nexport async function locateTranscriptPath(\n configDir: string,\n sessionId: string,\n timeoutMs: number = fsDeadlineMs(),\n): Promise<string | null> {\n const projectsDir = join(configDir, \"projects\");\n const entries = await tryWithFsDeadline(\n `readdir ${projectsDir}`,\n () => readdir(projectsDir),\n null,\n timeoutMs,\n );\n if (!entries) return null;\n for (const entry of entries) {\n const candidate = join(projectsDir, entry, `${sessionId}.jsonl`);\n const found = await tryWithFsDeadline(\n `stat ${candidate}`,\n async () => (await stat(candidate)).isFile(),\n false,\n timeoutMs,\n );\n if (found) return candidate;\n }\n return null;\n}\n\n/**\n * Yield a file's contents line by line, reproducing `readFileSync(...).split(\"\\n\")`\n * exactly — including the final (possibly empty) segment, so a trailing newline\n * survives a rewrite byte for byte.\n *\n * Splits on `\\n` alone, so a line out of a CRLF transcript arrives with its\n * `\\r` still attached. That carrier byte is part of the line here, and\n * {@link repairLine} re-attaches it to a line it rewrites — the file keeps the\n * terminator style it arrived with. Deliberately not `node:readline`:\n * `crlfDelay` strips the `\\r` outright (rewriting a CRLF transcript to LF) and\n * the interface swallows the trailing-newline distinction, either of which\n * would make the \"clean transcript is left byte-for-byte untouched\" guarantee\n * false. Only one line is held in memory at a time, so a multi-MB transcript\n * never materialises as a single string.\n */\nasync function* streamLines(filePath: string): AsyncGenerator<string> {\n const stream = createReadStream(filePath, { encoding: \"utf8\" });\n let pending = \"\";\n try {\n for await (const chunk of stream) {\n pending += chunk as string;\n let idx = pending.indexOf(\"\\n\");\n while (idx !== -1) {\n yield pending.slice(0, idx);\n pending = pending.slice(idx + 1);\n idx = pending.indexOf(\"\\n\");\n }\n }\n yield pending;\n } finally {\n stream.destroy();\n }\n}\n\n/**\n * Repair one JSONL line, returning the (possibly rewritten) line and mutating\n * `counters`. A non-JSON, blank, or content-less line is returned untouched.\n *\n * The reader splits on `\\n` only, so a line from a CRLF transcript still carries\n * its trailing `\\r`. An untouched line is returned verbatim and keeps it; a\n * rewritten one is rebuilt by `JSON.stringify`, which would drop it — leaving a\n * repaired CRLF transcript with mixed line endings. So the terminator is split\n * off before the parse and re-appended to the rewritten line.\n */\nfunction repairLine(line: string, counters: ScrubCounters): string {\n if (line.trim() === \"\") return line;\n const eol = line.endsWith(\"\\r\") ? \"\\r\" : \"\";\n const body = eol === \"\" ? line : line.slice(0, -1);\n let entry: { message?: { content?: unknown } };\n try {\n entry = JSON.parse(body);\n } catch {\n return line; // Not JSON — leave untouched.\n }\n const content = entry.message?.content;\n if (!Array.isArray(content)) return line;\n const before = totalChanges(counters);\n const scrubbed = (content as ContentBlockLike[]).map((block) => scrubBlock(block, counters));\n if (totalChanges(counters) === before) return line; // Nothing changed on this line.\n return `${JSON.stringify({ ...entry, message: { ...entry.message, content: scrubbed } })}${eol}`;\n}\n\n/**\n * Scan a Claude Code SDK transcript for image content blocks whose declared\n * `media_type` does not match the actual bytes, repair them, and atomically\n * rewrite the file.\n *\n * Safe to call after a turn has failed: the SDK query is dead at that point,\n * and the next resume re-reads the transcript from disk.\n *\n * **Async since #454.** Two streaming passes rather than one whole-file read:\n * pass 1 counts repairs without writing anything, and pass 2 runs only when\n * pass 1 found something. The common case — the preventive scrub of a clean\n * transcript before every resume — is therefore one streaming read and zero\n * writes, and a clean transcript is still left byte-for-byte untouched.\n *\n * @param opts - Config directory, session id, and an optional logger.\n * @returns A {@link ScrubTranscriptResult}. When `changed` is `true` the\n * caller may retry the resume with the same session id.\n * @category Transcript repair\n */\nexport async function scrubPoisonedTranscript(\n opts: ScrubTranscriptOptions,\n): Promise<ScrubTranscriptResult> {\n const { configDir, sessionId, log } = opts;\n const timeoutMs = fsDeadlineMs();\n const result: ScrubTranscriptResult = {\n filePath: null,\n corrected: 0,\n stubbed: 0,\n cacheStripped: 0,\n changed: false,\n };\n\n const filePath = await locateTranscriptPath(configDir, sessionId, timeoutMs);\n if (!filePath) {\n log?.warn(\"scrub-transcript: no transcript found\", { configDir, sessionId });\n return result;\n }\n result.filePath = filePath;\n\n // ── Pass 1: detect. Streams the transcript, counting repairs, writing nothing.\n const counters: ScrubCounters = { corrected: 0, stubbed: 0, cacheStripped: 0 };\n try {\n await withFsDeadline(\n `scan transcript ${filePath}`,\n async () => {\n for await (const line of streamLines(filePath)) repairLine(line, counters);\n },\n timeoutMs,\n );\n } catch (err) {\n log?.warn(\"scrub-transcript: failed to read transcript\", {\n filePath,\n error: err instanceof Error ? err.message : String(err),\n });\n return result;\n }\n\n result.corrected = counters.corrected;\n result.stubbed = counters.stubbed;\n result.cacheStripped = counters.cacheStripped;\n\n if (totalChanges(counters) === 0) {\n return result;\n }\n\n // ── Pass 2: rewrite. Atomic: stream a sibling temp file, then rename over the\n // original. Line separators are re-emitted exactly as pass 1 split them, so a\n // trailing newline and any blank lines survive verbatim.\n const tmpPath = `${filePath}.scrub-tmp`;\n try {\n await withFsDeadline(\n `rewrite transcript ${filePath}`,\n async () => {\n const discard: ScrubCounters = { corrected: 0, stubbed: 0, cacheStripped: 0 };\n await pipeline(\n (async function* () {\n let first = true;\n for await (const line of streamLines(filePath)) {\n yield first ? repairLine(line, discard) : `\\n${repairLine(line, discard)}`;\n first = false;\n }\n })(),\n createWriteStream(tmpPath, { encoding: \"utf8\" }),\n );\n await rename(tmpPath, filePath);\n },\n timeoutMs,\n );\n } catch (err) {\n log?.warn(\"scrub-transcript: failed to rewrite transcript\", {\n filePath,\n error: err instanceof Error ? err.message : String(err),\n });\n // Never leave a half-written sibling behind — the next scrub would rewrite\n // it anyway, but a stray `.scrub-tmp` in the SDK's projects dir is noise.\n await tryWithFsDeadline(`unlink ${tmpPath}`, () => unlink(tmpPath), undefined, timeoutMs);\n return result;\n }\n\n result.changed = true;\n log?.info(\"scrub-transcript: repaired poisoned transcript\", {\n filePath,\n corrected: result.corrected,\n stubbed: result.stubbed,\n cacheStripped: result.cacheStripped,\n });\n return result;\n}\n","/**\n * Pre-first-turn resume probe for the Claude Agent SDK driver.\n *\n * A tier-1 native resume only hands its session id to the SDK inside the first\n * real turn, so the `jsonl_lost` outcome (\"No conversation found\") is invisible\n * until a turn is consumed. The runner shares the container filesystem with the\n * SDK, so a cheap `stat` of the on-disk JSONL transcript is an authoritative,\n * side-effect-free signal of whether the resume will find its history — no\n * probe query, no spurious model turn.\n *\n * @module\n */\n\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { withFsDeadline } from \"@skaile/workspaces/core\";\nimport { locateTranscriptPath } from \"./scrub-transcript.js\";\n\n/**\n * Overall wall-clock budget for the probe. Deliberately a small fraction of the\n * platform's `session_init_ack` timeout (`DEFAULT_INIT_ACK_TIMEOUT_MS`, 15s):\n * the probe runs synchronously on the pre-ack path, so a wedged\n * `CLAUDE_CONFIG_DIR` mount must never push the ack past its deadline.\n */\nconst RESUME_PROBE_TIMEOUT_MS = 2_000;\n\n/**\n * Outcome of {@link probeResumeTranscript}: whether the SDK transcript for a\n * requested tier-1 resume exists on disk.\n *\n * @category Resume probe\n */\nexport type ResumeProbeOutcome = \"transcript_found\" | \"jsonl_lost\";\n\n/**\n * Resolve the Claude Code config directory — the parent of `projects/` — from\n * an explicit env map, the process environment, or the `~/.claude` default.\n *\n * The runner's probe and the claude-sdk driver share this one resolver, so they\n * agree as long as they see the same `CLAUDE_CONFIG_DIR`. Today they do:\n * `CLAUDE_CONFIG_DIR` is container-scoped and neither side threads a per-session\n * override through `config.env`, so both fall through to `process.env`. If a\n * future change ever set the driver's `config.env.CLAUDE_CONFIG_DIR` to a\n * divergent path, the reactive `resume_failed { jsonl_lost }` turn remains the\n * safety net.\n *\n * @category Resume probe\n */\nexport function resolveClaudeConfigDir(env?: Record<string, string | undefined>): string {\n return env?.CLAUDE_CONFIG_DIR || process.env.CLAUDE_CONFIG_DIR || join(homedir(), \".claude\");\n}\n\n/**\n * Probe whether the SDK JSONL transcript for `sessionId` exists on disk.\n *\n * Non-null locator result → `transcript_found`; null → `jsonl_lost`;\n * `undefined` → outcome unknown (the probe exceeded its budget or errored). The\n * caller leaves the ack field ABSENT on `undefined` so the reactive\n * `resume_failed { jsonl_lost }` turn stays the safety net — a timed-out probe\n * must never masquerade as a genuine `jsonl_lost` and force a needless downgrade.\n *\n * `opts.timeoutMs` overrides {@link RESUME_PROBE_TIMEOUT_MS}; `opts.locate`\n * overrides the transcript locator (used by tests / alternate stores).\n *\n * @category Resume probe\n */\nexport async function probeResumeTranscript(\n sessionId: string,\n opts?: {\n env?: Record<string, string | undefined>;\n timeoutMs?: number;\n locate?: (configDir: string, sessionId: string) => Promise<string | null>;\n },\n): Promise<ResumeProbeOutcome | undefined> {\n const configDir = resolveClaudeConfigDir(opts?.env);\n const timeoutMs = opts?.timeoutMs ?? RESUME_PROBE_TIMEOUT_MS;\n const locate = opts?.locate ?? locateTranscriptPath;\n try {\n // Bound the whole probe on wall-clock and THROW on expiry: the inner per-op\n // deadline swallows a timeout into a null path (a false `jsonl_lost`), so a\n // wedged mount must yield \"unknown\" here rather than a spurious downgrade.\n const filePath = await withFsDeadline(\n `resume-probe ${sessionId}`,\n () => locate(configDir, sessionId),\n timeoutMs,\n );\n return filePath ? \"transcript_found\" : \"jsonl_lost\";\n } catch {\n return undefined;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../bridge/src/cloud.ts","../bridge/src/drivers/scrub-transcript.ts","../bridge/src/drivers/resume-probe.ts"],"names":["join"],"mappings":";;;;;;;;AAsBO,IAAM,mBAAmB,CAAC,SAAA,EAAW,SAAA,EAAW,QAAA,EAAU,SAAS,SAAS;AAuC5E,IAAM,qBAAA,GAAgF;AAAA,EAC3F,OAAA,EAAS;AAAA,IACP,mBAAA;AAAA,IACA,uBAAA;AAAA,IACA,mBAAA;AAAA,IACA;AAAA,GACF;AAAA,EACA,MAAA,EAAQ,CAAC,qCAAqC,CAAA;AAAA,EAC9C,KAAA,EAAO,CAAC,2BAA2B,CAAA;AAAA,EACnC,OAAA,EAAS,CAAC,sBAAA,EAAwB,mBAAmB;AACvD;AAaA,IAAM,iBAAA,GAAoB,CAAC,mBAAA,EAAqB,sBAAA,EAAwB,oBAAoB,CAAA;AAuBrF,SAAS,oBAAoB,IAAA,EAQT;AACzB,EAAA,MAAM,EAAE,KAAA,EAAO,WAAA,EAAa,cAAc,OAAA,EAAS,SAAA,EAAW,gBAAe,GAAI,IAAA;AACjF,EAAA,MAAM,MAA8B,EAAE,GAAG,SAAS,GAAI,SAAA,IAAa,EAAC,EAAG;AAGvE,EAAA,MAAM,OAAA,GAAU;AAAA,IACd,WAAW,GAAA,CAAI,oBAAA;AAAA,IACf,QAAQ,GAAA,CAAI,iBAAA;AAAA,IACZ,SAAS,GAAA,CAAI;AAAA,GACf;AAEA,EAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,GAAG,CAAA,EAAG;AAClC,IAAA,IAAI,kBAAkB,QAAA,CAAS,GAAG,KAAK,GAAA,CAAI,UAAA,CAAW,kBAAkB,CAAA,EAAG;AACzE,MAAA,OAAO,IAAI,GAAG,CAAA;AAAA,IAChB;AAAA,EACF;AAEA,EAAA,MAAM,GAAA,GAAM,CAAC,GAAA,EAAa,KAAA,KAA8B;AAGtD,IAAA,IAAI,KAAA,EAAO,GAAA,CAAI,GAAG,CAAA,GAAI,KAAA;AAAA,EACxB,CAAA;AAEA,EAAA,QAAQ,KAAA;AAAO,IACb,KAAK,SAAA,EAAW;AACd,MAAA,GAAA,CAAI,uBAAA,GAA0B,GAAA;AAG9B,MAAA,KAAA,MAAW,OAAO,qBAAA,CAAsB,OAAA,MAAa,GAAA,EAAK,YAAA,GAAe,GAAG,CAAC,CAAA;AAC7E,MAAA,GAAA,CAAI,YAAA,EAAc,aAAa,MAAM,CAAA;AACrC,MAAA;AAAA,IACF;AAAA,IACA,KAAK,QAAA,EAAU;AACb,MAAA,GAAA,CAAI,sBAAA,GAAyB,GAAA;AAG7B,MAAA,GAAA,CAAI,gCAAA,EAAkC,cAAc,8BAA8B,CAAA;AAClF,MAAA,GAAA,CAAI,6BAAA,EAA+B,aAAa,SAAS,CAAA;AACzD,MAAA,GAAA,CAAI,iBAAA,EAAmB,aAAa,MAAM,CAAA;AAC1C,MAAA;AAAA,IACF;AAAA,IACA,KAAK,OAAA,EAAS;AACZ,MAAA,GAAA,CAAI,uBAAA,GAA0B,GAAA;AAC9B,MAAA,GAAA,CAAI,2BAAA,EAA6B,cAAc,yBAAyB,CAAA;AAExE,MAAA,IAAI,aAAa,QAAA,EAAU;AACzB,QAAA,GAAA,CAAI,6BAA6B,WAAA,CAAY,QAAA;AAAA,MAC/C,CAAA,MAAO;AACL,QAAA,GAAA,CAAI,4BAAA,EAA8B,aAAa,OAAO,CAAA;AAAA,MACxD;AACA,MAAA;AAAA,IACF;AAAA,IACA,KAAK,SAAA,EAAW;AAId,MAAA,GAAA,CAAI,oBAAA,EAAsB,WAAA,EAAa,OAAA,IAAW,OAAA,CAAQ,OAAO,CAAA;AACjE,MAAA,MAAM,SAAA,GAAY,YAAA,EAAc,oBAAA,IAAwB,OAAA,CAAQ,SAAA;AAChE,MAAA,IAAI,SAAA,EAAW;AACb,QAAA,GAAA,CAAI,oBAAA,GAAuB,SAAA;AAAA,MAC7B,CAAA,MAAO;AACL,QAAA,GAAA;AAAA,UACE,mBAAA;AAAA,UACA,YAAA,EAAc,iBAAA,IAAqB,cAAA,IAAkB,OAAA,CAAQ;AAAA,SAC/D;AAAA,MACF;AACA,MAAA;AAAA,IACF;AAAA;AAGF,EAAA,OAAO,GAAA;AACT;AC3EA,IAAM,SAAA,GAAY,2CAAA;AAGlB,IAAM,mBAAA,GAAsB,kCAAA;AAO5B,IAAM,eAAA,GAAkB,IAAI,IAAA,GAAO,IAAA;AAa5B,SAAS,oBAAoB,MAAA,EAA+B;AACjE,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AAEF,IAAA,GAAA,GAAM,OAAO,IAAA,CAAK,MAAA,CAAO,MAAM,CAAA,EAAG,EAAE,GAAG,QAAQ,CAAA;AAAA,EACjD,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI,GAAA,CAAI,SAAS,CAAA,EAAG;AAClB,IAAA,OAAO,IAAA;AAAA,EACT;AAIA,EAAA,IAAI,IAAI,CAAC,CAAA,KAAM,OAAQ,GAAA,CAAI,CAAC,MAAM,GAAA,EAAM;AACtC,IAAA,OAAO,YAAA;AAAA,EACT;AAEA,EAAA,IAAI,GAAA,CAAI,CAAC,CAAA,KAAM,GAAA,IAAQ,IAAI,CAAC,CAAA,KAAM,EAAA,IAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,EAAA,IAAQ,GAAA,CAAI,CAAC,MAAM,EAAA,EAAM;AAC5E,IAAA,OAAO,WAAA;AAAA,EACT;AAEA,EAAA,IAAI,GAAA,CAAI,CAAC,CAAA,KAAM,EAAA,IAAQ,IAAI,CAAC,CAAA,KAAM,EAAA,IAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,EAAA,IAAQ,GAAA,CAAI,CAAC,MAAM,EAAA,EAAM;AAC5E,IAAA,OAAO,WAAA;AAAA,EACT;AAEA,EAAA,IACE,GAAA,CAAI,MAAA,IAAU,EAAA,IACd,GAAA,CAAI,CAAC,CAAA,KAAM,EAAA,IACX,GAAA,CAAI,CAAC,MAAM,EAAA,IACX,GAAA,CAAI,CAAC,CAAA,KAAM,MACX,GAAA,CAAI,CAAC,CAAA,KAAM,EAAA,IACX,GAAA,CAAI,CAAC,CAAA,KAAM,EAAA,IACX,IAAI,CAAC,CAAA,KAAM,EAAA,IACX,GAAA,CAAI,EAAE,CAAA,KAAM,EAAA,IACZ,GAAA,CAAI,EAAE,MAAM,EAAA,EACZ;AACA,IAAA,OAAO,YAAA;AAAA,EACT;AACA,EAAA,OAAO,IAAA;AACT;AAyBA,SAAS,aAAa,CAAA,EAA0B;AAC9C,EAAA,OAAO,CAAA,CAAE,SAAA,GAAY,CAAA,CAAE,OAAA,GAAU,CAAA,CAAE,aAAA;AACrC;AAkBA,SAAS,UAAA,CAAW,OAAyB,QAAA,EAA2C;AACtF,EAAA,IAAI,MAAM,IAAA,KAAS,aAAA,IAAiB,MAAM,OAAA,CAAQ,KAAA,CAAM,OAAO,CAAA,EAAG;AAChE,IAAA,OAAO;AAAA,MACL,GAAG,KAAA;AAAA,MACH,OAAA,EAAU,MAAM,OAAA,CAA+B,GAAA,CAAI,CAAC,KAAA,KAAU,UAAA,CAAW,KAAA,EAAO,QAAQ,CAAC;AAAA,KAC3F;AAAA,EACF;AAKA,EAAA,IAAI,KAAA,CAAM,IAAA,KAAS,MAAA,IAAU,KAAA,CAAM,iBAAiB,IAAA,EAAM;AACxD,IAAA,MAAM,OAAO,OAAO,KAAA,CAAM,IAAA,KAAS,QAAA,GAAW,MAAM,IAAA,GAAO,EAAA;AAC3D,IAAA,IAAI,IAAA,CAAK,IAAA,EAAK,KAAM,EAAA,EAAI;AACtB,MAAA,QAAA,CAAS,aAAA,EAAA;AACT,MAAA,MAAM,KAAA,GAAQ,EAAE,GAAG,KAAA,EAAM;AACzB,MAAA,OAAO,KAAA,CAAM,aAAA;AACb,MAAA,OAAO,KAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,IACE,KAAA,CAAM,IAAA,KAAS,OAAA,IACf,KAAA,CAAM,MAAA,EAAQ,IAAA,KAAS,QAAA,IACvB,OAAO,KAAA,CAAM,MAAA,CAAO,IAAA,KAAS,QAAA,EAC7B;AACA,IAAA,MAAM,IAAA,GAAO,MAAM,MAAA,CAAO,IAAA;AAI1B,IAAA,IAAI,KAAK,KAAA,CAAO,IAAA,CAAK,SAAS,CAAA,GAAK,CAAC,IAAI,eAAA,EAAiB;AACvD,MAAA,QAAA,CAAS,OAAA,EAAA;AACT,MAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,mBAAA,EAAoB;AAAA,IACnD;AACA,IAAA,MAAM,OAAA,GAAU,oBAAoB,IAAI,CAAA;AACxC,IAAA,IAAI,YAAY,IAAA,EAAM;AACpB,MAAA,QAAA,CAAS,OAAA,EAAA;AACT,MAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,SAAA,EAAU;AAAA,IACzC;AACA,IAAA,IAAI,OAAA,KAAY,KAAA,CAAM,MAAA,CAAO,UAAA,EAAY;AACvC,MAAA,QAAA,CAAS,SAAA,EAAA;AACT,MAAA,OAAO,EAAE,GAAG,KAAA,EAAO,MAAA,EAAQ,EAAE,GAAG,KAAA,CAAM,MAAA,EAAQ,UAAA,EAAY,OAAA,EAAQ,EAAE;AAAA,IACtE;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT;AAkBA,eAAsB,oBAAA,CACpB,SAAA,EACA,SAAA,EACA,SAAA,GAAoB,cAAa,EACT;AACxB,EAAA,MAAM,WAAA,GAAc,IAAA,CAAK,SAAA,EAAW,UAAU,CAAA;AAC9C,EAAA,MAAM,UAAU,MAAM,iBAAA;AAAA,IACpB,WAAW,WAAW,CAAA,CAAA;AAAA,IACtB,MAAM,QAAQ,WAAW,CAAA;AAAA,IACzB,IAAA;AAAA,IACA;AAAA,GACF;AACA,EAAA,IAAI,CAAC,SAAS,OAAO,IAAA;AACrB,EAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAC3B,IAAA,MAAM,YAAY,IAAA,CAAK,WAAA,EAAa,KAAA,EAAO,CAAA,EAAG,SAAS,CAAA,MAAA,CAAQ,CAAA;AAC/D,IAAA,MAAM,QAAQ,MAAM,iBAAA;AAAA,MAClB,QAAQ,SAAS,CAAA,CAAA;AAAA,MACjB,YAAA,CAAa,MAAM,IAAA,CAAK,SAAS,GAAG,MAAA,EAAO;AAAA,MAC3C,KAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,IAAI,OAAO,OAAO,SAAA;AAAA,EACpB;AACA,EAAA,OAAO,IAAA;AACT;AAiBA,gBAAgB,YAAY,QAAA,EAA0C;AACpE,EAAA,MAAM,SAAS,gBAAA,CAAiB,QAAA,EAAU,EAAE,QAAA,EAAU,QAAQ,CAAA;AAC9D,EAAA,IAAI,OAAA,GAAU,EAAA;AACd,EAAA,IAAI;AACF,IAAA,WAAA,MAAiB,SAAS,MAAA,EAAQ;AAChC,MAAA,OAAA,IAAW,KAAA;AACX,MAAA,IAAI,GAAA,GAAM,OAAA,CAAQ,OAAA,CAAQ,IAAI,CAAA;AAC9B,MAAA,OAAO,QAAQ,CAAA,CAAA,EAAI;AACjB,QAAA,MAAM,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,GAAG,CAAA;AAC1B,QAAA,OAAA,GAAU,OAAA,CAAQ,KAAA,CAAM,GAAA,GAAM,CAAC,CAAA;AAC/B,QAAA,GAAA,GAAM,OAAA,CAAQ,QAAQ,IAAI,CAAA;AAAA,MAC5B;AAAA,IACF;AACA,IAAA,MAAM,OAAA;AAAA,EACR,CAAA,SAAE;AACA,IAAA,MAAA,CAAO,OAAA,EAAQ;AAAA,EACjB;AACF;AAYA,SAAS,UAAA,CAAW,MAAc,QAAA,EAAiC;AACjE,EAAA,IAAI,IAAA,CAAK,IAAA,EAAK,KAAM,EAAA,EAAI,OAAO,IAAA;AAC/B,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,QAAA,CAAS,IAAI,IAAI,IAAA,GAAO,EAAA;AACzC,EAAA,MAAM,OAAO,GAAA,KAAQ,EAAA,GAAK,OAAO,IAAA,CAAK,KAAA,CAAM,GAAG,EAAE,CAAA;AACjD,EAAA,IAAI,KAAA;AACJ,EAAA,IAAI;AACF,IAAA,KAAA,GAAQ,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,EACzB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,MAAM,OAAA,GAAU,MAAM,OAAA,EAAS,OAAA;AAC/B,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,OAAO,GAAG,OAAO,IAAA;AACpC,EAAA,MAAM,MAAA,GAAS,aAAa,QAAQ,CAAA;AACpC,EAAA,MAAM,QAAA,GAAY,QAA+B,GAAA,CAAI,CAAC,UAAU,UAAA,CAAW,KAAA,EAAO,QAAQ,CAAC,CAAA;AAC3F,EAAA,IAAI,YAAA,CAAa,QAAQ,CAAA,KAAM,MAAA,EAAQ,OAAO,IAAA;AAC9C,EAAA,OAAO,GAAG,IAAA,CAAK,SAAA,CAAU,EAAE,GAAG,OAAO,OAAA,EAAS,EAAE,GAAG,KAAA,CAAM,SAAS,OAAA,EAAS,QAAA,IAAY,CAAC,GAAG,GAAG,CAAA,CAAA;AAChG;AAqBA,eAAsB,wBACpB,IAAA,EACgC;AAChC,EAAA,MAAM,EAAE,SAAA,EAAW,SAAA,EAAW,GAAA,EAAI,GAAI,IAAA;AACtC,EAAA,MAAM,YAAY,YAAA,EAAa;AAC/B,EAAA,MAAM,MAAA,GAAgC;AAAA,IACpC,QAAA,EAAU,IAAA;AAAA,IACV,SAAA,EAAW,CAAA;AAAA,IACX,OAAA,EAAS,CAAA;AAAA,IACT,aAAA,EAAe,CAAA;AAAA,IACf,OAAA,EAAS;AAAA,GACX;AAEA,EAAA,MAAM,QAAA,GAAW,MAAM,oBAAA,CAAqB,SAAA,EAAW,WAAW,SAAS,CAAA;AAC3E,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,GAAA,EAAK,IAAA,CAAK,uCAAA,EAAyC,EAAE,SAAA,EAAW,WAAW,CAAA;AAC3E,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,MAAA,CAAO,QAAA,GAAW,QAAA;AAGlB,EAAA,MAAM,WAA0B,EAAE,SAAA,EAAW,GAAG,OAAA,EAAS,CAAA,EAAG,eAAe,CAAA,EAAE;AAC7E,EAAA,IAAI;AACF,IAAA,MAAM,cAAA;AAAA,MACJ,mBAAmB,QAAQ,CAAA,CAAA;AAAA,MAC3B,YAAY;AACV,QAAA,WAAA,MAAiB,QAAQ,WAAA,CAAY,QAAQ,CAAA,EAAG,UAAA,CAAW,MAAM,QAAQ,CAAA;AAAA,MAC3E,CAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF,SAAS,GAAA,EAAK;AACZ,IAAA,GAAA,EAAK,KAAK,6CAAA,EAA+C;AAAA,MACvD,QAAA;AAAA,MACA,OAAO,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG;AAAA,KACvD,CAAA;AACD,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,MAAA,CAAO,YAAY,QAAA,CAAS,SAAA;AAC5B,EAAA,MAAA,CAAO,UAAU,QAAA,CAAS,OAAA;AAC1B,EAAA,MAAA,CAAO,gBAAgB,QAAA,CAAS,aAAA;AAEhC,EAAA,IAAI,YAAA,CAAa,QAAQ,CAAA,KAAM,CAAA,EAAG;AAChC,IAAA,OAAO,MAAA;AAAA,EACT;AAKA,EAAA,MAAM,OAAA,GAAU,GAAG,QAAQ,CAAA,UAAA,CAAA;AAC3B,EAAA,IAAI;AACF,IAAA,MAAM,cAAA;AAAA,MACJ,sBAAsB,QAAQ,CAAA,CAAA;AAAA,MAC9B,YAAY;AACV,QAAA,MAAM,UAAyB,EAAE,SAAA,EAAW,GAAG,OAAA,EAAS,CAAA,EAAG,eAAe,CAAA,EAAE;AAC5E,QAAA,MAAM,QAAA;AAAA,UAAA,CACH,mBAAmB;AAClB,YAAA,IAAI,KAAA,GAAQ,IAAA;AACZ,YAAA,WAAA,MAAiB,IAAA,IAAQ,WAAA,CAAY,QAAQ,CAAA,EAAG;AAC9C,cAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,IAAA,EAAM,OAAO,CAAA,GAAI;AAAA,EAAK,UAAA,CAAW,IAAA,EAAM,OAAO,CAAC,CAAA,CAAA;AACxE,cAAA,KAAA,GAAQ,KAAA;AAAA,YACV;AAAA,UACF,CAAA,GAAG;AAAA,UACH,iBAAA,CAAkB,OAAA,EAAS,EAAE,QAAA,EAAU,QAAQ;AAAA,SACjD;AACA,QAAA,MAAM,MAAA,CAAO,SAAS,QAAQ,CAAA;AAAA,MAChC,CAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF,SAAS,GAAA,EAAK;AACZ,IAAA,GAAA,EAAK,KAAK,gDAAA,EAAkD;AAAA,MAC1D,QAAA;AAAA,MACA,OAAO,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG;AAAA,KACvD,CAAA;AAGD,IAAA,MAAM,iBAAA,CAAkB,UAAU,OAAO,CAAA,CAAA,EAAI,MAAM,MAAA,CAAO,OAAO,CAAA,EAAG,MAAA,EAAW,SAAS,CAAA;AACxF,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,MAAA,CAAO,OAAA,GAAU,IAAA;AACjB,EAAA,GAAA,EAAK,KAAK,gDAAA,EAAkD;AAAA,IAC1D,QAAA;AAAA,IACA,WAAW,MAAA,CAAO,SAAA;AAAA,IAClB,SAAS,MAAA,CAAO,OAAA;AAAA,IAChB,eAAe,MAAA,CAAO;AAAA,GACvB,CAAA;AACD,EAAA,OAAO,MAAA;AACT;ACtcA,IAAM,uBAAA,GAA0B,GAAA;AAwBzB,SAAS,uBAAuB,GAAA,EAAkD;AACvF,EAAA,OAAO,GAAA,EAAK,qBAAqB,OAAA,CAAQ,GAAA,CAAI,qBAAqBA,IAAAA,CAAK,OAAA,IAAW,SAAS,CAAA;AAC7F;AAgBA,eAAsB,qBAAA,CACpB,WACA,IAAA,EAKyC;AACzC,EAAA,MAAM,SAAA,GAAY,sBAAA,CAAuB,IAAA,EAAM,GAAG,CAAA;AAClD,EAAA,MAAM,SAAA,GAAY,MAAM,SAAA,IAAa,uBAAA;AACrC,EAAA,MAAM,MAAA,GAAS,MAAM,MAAA,IAAU,oBAAA;AAC/B,EAAA,IAAI;AAIF,IAAA,MAAM,WAAW,MAAM,cAAA;AAAA,MACrB,gBAAgB,SAAS,CAAA,CAAA;AAAA,MACzB,MAAM,MAAA,CAAO,SAAA,EAAW,SAAS,CAAA;AAAA,MACjC;AAAA,KACF;AACA,IAAA,OAAO,WAAW,kBAAA,GAAqB,YAAA;AAAA,EACzC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF","file":"chunk-RUFTB7QN.js","sourcesContent":["/**\n * AI cloud-provider transport dimension for the `claude-sdk` driver.\n *\n * `cloud` is a config axis orthogonal to `provider` (model vendor) and\n * `driver` (agent runtime). Under `driver: claude-sdk` each non-default value\n * maps to one of the Claude Agent SDK's native env-var transports:\n * Amazon Bedrock, Google Vertex AI, Azure AI Foundry, or a generic\n * `ANTHROPIC_BASE_URL` gateway (LiteLLM / corporate proxy).\n *\n * Cross-repo contract: env key names and semantics here are load-bearing —\n * the platform resolves credential bundles against the same key set.\n */\n\n/**\n * Canonical list of supported cloud transports. `\"default\"` (or an absent\n * `cloud` field) means the provider's native API — today's behavior, unchanged.\n *\n * The codec in `core/workspace-config.ts` keeps a local copy (`KNOWN_CLOUDS`)\n * to avoid an import cycle; a drift test asserts parity.\n *\n * @since 1.3.0\n */\nexport const SUPPORTED_CLOUDS = [\"default\", \"bedrock\", \"vertex\", \"azure\", \"gateway\"] as const;\n\n/** One of the supported cloud transport identifiers. */\nexport type CloudId = (typeof SUPPORTED_CLOUDS)[number];\n\n/**\n * Non-secret transport settings for a cloud. Sourced from skaile.yaml\n * `cloud_config` (snake_case on the wire, camelCase in-process — converted\n * exactly once at the settings/serve boundary).\n *\n * Must stay field-identical with core's `CloudTransportConfig` and the inline\n * `AgentSessionConfig.cloudConfig` shape (kept separate to avoid a core↔bridge\n * import cycle) — a field added here must be added there too.\n *\n * @since 1.3.0\n */\nexport interface CloudConfig {\n /** bedrock: AWS region (`AWS_REGION`); vertex: `CLOUD_ML_REGION`. */\n region?: string;\n /** vertex only: GCP project (`ANTHROPIC_VERTEX_PROJECT_ID`). */\n projectId?: string;\n /** azure only: Foundry resource name (`ANTHROPIC_FOUNDRY_RESOURCE`). */\n resource?: string;\n /** azure (alternative to `resource`) / gateway (required): endpoint base URL. */\n baseUrl?: string;\n}\n\n/**\n * Secret env keys that make up the credential bundle for each non-default\n * cloud. The platform delivers these env-keyed in the `session_init` secrets\n * map; the runner picks them out via `resolveCloudSecretBundle`.\n *\n * Vertex note: `GOOGLE_APPLICATION_CREDENTIALS_JSON` is our convention for the\n * raw service-account JSON blob. The runner materializes it to a 0600 file and\n * hands the driver `GOOGLE_APPLICATION_CREDENTIALS` (a path) instead — the\n * driver never sees the raw JSON.\n *\n * @since 1.3.0\n */\nexport const CLOUD_SECRET_ENV_KEYS: Record<Exclude<CloudId, \"default\">, readonly string[]> = {\n bedrock: [\n \"AWS_ACCESS_KEY_ID\",\n \"AWS_SECRET_ACCESS_KEY\",\n \"AWS_SESSION_TOKEN\",\n \"AWS_BEARER_TOKEN_BEDROCK\",\n ],\n vertex: [\"GOOGLE_APPLICATION_CREDENTIALS_JSON\"],\n azure: [\"ANTHROPIC_FOUNDRY_API_KEY\"],\n gateway: [\"ANTHROPIC_AUTH_TOKEN\", \"ANTHROPIC_API_KEY\"],\n};\n\n/**\n * Env vars scrubbed from the inherited environment before a non-default cloud\n * transport is assembled. Ambient first-party credentials or a stale\n * `CLAUDE_CODE_USE_*` flag must never leak into a Bedrock/Vertex/Foundry/\n * gateway session (the gateway branch re-adds its own carriers explicitly).\n *\n * Deliberately NOT exhaustive across clouds: ambient cloud-specific vars\n * (AWS_*, GOOGLE_*, ANTHROPIC_VERTEX_PROJECT_ID, ANTHROPIC_FOUNDRY_*) survive\n * so a standalone CLI inherits its own cloud's environment; the SDK ignores\n * vars whose transport flag is unset.\n */\nconst SCRUBBED_ENV_KEYS = [\"ANTHROPIC_API_KEY\", \"ANTHROPIC_AUTH_TOKEN\", \"ANTHROPIC_BASE_URL\"];\n\n/**\n * Assemble the Claude Agent SDK child env for a non-default cloud transport.\n *\n * Pure function (no external state touched; the returned `env` is a fresh\n * object — inputs are never mutated): starts from `baseEnv` (caller passes a\n * copy of `process.env` with undefined stripped) merged with `configEnv`,\n * scrubs inherited Anthropic\n * credential/routing vars and every `CLAUDE_CODE_USE_*` flag, then sets exactly\n * one `CLAUDE_CODE_USE_*` flag (none for gateway) plus the cloud's credential\n * bundle and derived non-secret vars. AWS_* / GOOGLE_* ambient values are NOT\n * scrubbed, so a standalone CLI inherits ambient cloud credentials when no\n * explicit `cloudSecrets` bundle is provided. Gateway is the mirror case: its\n * carriers ARE the scrubbed Anthropic vars, so the gateway branch restores\n * them from `cloudSecrets` → `fallbackApiKey` (resolved `apiKeys.anthropic`)\n * → the pre-scrub config/ambient value — otherwise a standalone gateway\n * session would have no reachable auth carrier at all.\n *\n * Never returns `undefined` values; absent settings are simply omitted.\n *\n * @since 1.3.0\n */\nexport function buildClaudeCloudEnv(args: {\n cloud: Exclude<CloudId, \"default\">;\n cloudConfig?: CloudConfig;\n cloudSecrets?: Record<string, string>;\n baseEnv: Record<string, string>;\n configEnv?: Record<string, string>;\n /** Resolved API key (e.g. `apiKeys.anthropic`) — gateway auth fallback only. */\n fallbackApiKey?: string;\n}): Record<string, string> {\n const { cloud, cloudConfig, cloudSecrets, baseEnv, configEnv, fallbackApiKey } = args;\n const env: Record<string, string> = { ...baseEnv, ...(configEnv ?? {}) };\n\n // Captured before the scrub — gateway falls back to these carriers.\n const ambient = {\n authToken: env.ANTHROPIC_AUTH_TOKEN,\n apiKey: env.ANTHROPIC_API_KEY,\n baseUrl: env.ANTHROPIC_BASE_URL,\n };\n\n for (const key of Object.keys(env)) {\n if (SCRUBBED_ENV_KEYS.includes(key) || key.startsWith(\"CLAUDE_CODE_USE_\")) {\n delete env[key];\n }\n }\n\n const set = (key: string, value: string | undefined) => {\n // Falsy check is deliberate: an empty-string credential/setting is never\n // valid env — dropping it beats shipping a key the SDK treats as set.\n if (value) env[key] = value;\n };\n\n switch (cloud) {\n case \"bedrock\": {\n env.CLAUDE_CODE_USE_BEDROCK = \"1\";\n // Explicit bundle values override ambient AWS_* (which survive the scrub\n // so a standalone CLI keeps its ambient credentials).\n for (const key of CLOUD_SECRET_ENV_KEYS.bedrock) set(key, cloudSecrets?.[key]);\n set(\"AWS_REGION\", cloudConfig?.region);\n break;\n }\n case \"vertex\": {\n env.CLAUDE_CODE_USE_VERTEX = \"1\";\n // Runner-materialized SA file path; ambient GOOGLE_APPLICATION_CREDENTIALS\n // is kept when no bundle value is provided.\n set(\"GOOGLE_APPLICATION_CREDENTIALS\", cloudSecrets?.GOOGLE_APPLICATION_CREDENTIALS);\n set(\"ANTHROPIC_VERTEX_PROJECT_ID\", cloudConfig?.projectId);\n set(\"CLOUD_ML_REGION\", cloudConfig?.region);\n break;\n }\n case \"azure\": {\n env.CLAUDE_CODE_USE_FOUNDRY = \"1\";\n set(\"ANTHROPIC_FOUNDRY_API_KEY\", cloudSecrets?.ANTHROPIC_FOUNDRY_API_KEY);\n // Resource wins over base_url when both are configured.\n if (cloudConfig?.resource) {\n env.ANTHROPIC_FOUNDRY_RESOURCE = cloudConfig.resource;\n } else {\n set(\"ANTHROPIC_FOUNDRY_BASE_URL\", cloudConfig?.baseUrl);\n }\n break;\n }\n case \"gateway\": {\n // No CLAUDE_CODE_USE_* flag — the gateway is addressed purely via\n // ANTHROPIC_BASE_URL plus an auth carrier. Explicit bundle wins;\n // standalone sessions fall back to the resolved key / ambient carriers.\n set(\"ANTHROPIC_BASE_URL\", cloudConfig?.baseUrl ?? ambient.baseUrl);\n const authToken = cloudSecrets?.ANTHROPIC_AUTH_TOKEN ?? ambient.authToken;\n if (authToken) {\n env.ANTHROPIC_AUTH_TOKEN = authToken;\n } else {\n set(\n \"ANTHROPIC_API_KEY\",\n cloudSecrets?.ANTHROPIC_API_KEY ?? fallbackApiKey ?? ambient.apiKey,\n );\n }\n break;\n }\n }\n\n return env;\n}\n","/**\n * Poisoned-transcript repair for the Claude Agent SDK driver.\n *\n * The Anthropic Messages API can permanently reject a conversation once its\n * persisted history contains a malformed content block. Because the bad block\n * lives in the SDK's on-disk JSONL transcript, every replayed turn fails with\n * the same `400 invalid_request_error` and the session is bricked with no\n * in-band recovery.\n *\n * This module repairs the transcript in place, covering three known poison\n * classes:\n *\n * 1. **Image `media_type` mismatch / omission.** An image block whose declared\n * `media_type` does not match — or is missing for — the actual bytes:\n * `... The image was specified using the image/png media type, but the\n * image appears to be a image/jpeg image`. Produced by the Claude Code\n * `Read` tool's format fallback (anthropics/claude-code#55338, #30124,\n * #33179). Repaired by sniffing the base64 magic bytes and correcting\n * `media_type`.\n * 2. **Oversized image.** An image whose decoded payload exceeds the API's\n * 5 MB per-image limit (anthropics/claude-code#34566). Replaced with a\n * text stub — the byte budget cannot be recovered any other way.\n * 3. **`cache_control` on an empty text block.** A text block carrying a\n * `cache_control` marker with empty/whitespace `text`\n * (anthropics/claude-code#59626). The `cache_control` field is stripped.\n *\n * Genuinely unidentifiable image blocks are also replaced with a text stub.\n *\n * Recovering by content scan (rather than parsing the API's `messages.N`\n * index) is deliberate: the index addresses the assembled API request, not a\n * JSONL line, and reproducing the SDK's message-assembly is fragile. A full\n * scan is index-free and repairs every poisoned block in one pass.\n *\n * **Async and line-streaming since #454.** A Claude Code transcript is routinely\n * multi-megabyte (base64 images inline in `tool_result` blocks), and this runs on\n * a failed turn *and before every resume* — inside the single-threaded `skaile\n * serve` loop. The previous `readFileSync` + `writeFileSync` + `renameSync` held\n * the loop for the whole file and materialised it twice over as one string. Both\n * passes now stream line by line off a `createReadStream`, so the loop is yielded\n * between lines and peak memory is one JSONL line rather than the whole file, and\n * every I/O phase is deadline-bounded.\n *\n * Streaming was chosen over a worker thread: the work is I/O-bound rather than\n * CPU-bound (per-line `JSON.parse` on a yielded loop is not what stalls a turn),\n * and a worker would add a structured-clone of the same multi-MB payload plus a\n * thread lifecycle to a path that must never block a turn.\n *\n * @module\n */\n\nimport { createReadStream, createWriteStream } from \"node:fs\";\nimport { readdir, rename, stat, unlink } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { pipeline } from \"node:stream/promises\";\nimport { fsDeadlineMs, tryWithFsDeadline, withFsDeadline } from \"@skaile/workspaces/core\";\n\n/**\n * Minimal logger shape accepted by {@link scrubPoisonedTranscript}. Compatible\n * with the bridge `Logger`, but narrowed so the helper stays unit-testable\n * without a real logger instance.\n *\n * @category Transcript repair\n */\nexport interface ScrubLogger {\n info(message: string, data?: Record<string, unknown>): void;\n warn(message: string, data?: Record<string, unknown>): void;\n}\n\n/**\n * Options for {@link scrubPoisonedTranscript}.\n *\n * @category Transcript repair\n */\nexport interface ScrubTranscriptOptions {\n /**\n * Claude Code config directory — the parent of `projects/`. Resolve from\n * `CLAUDE_CONFIG_DIR`, falling back to `~/.claude`.\n */\n configDir: string;\n /** SDK session id whose transcript JSONL should be repaired. */\n sessionId: string;\n /** Optional logger for diagnostics. */\n log?: ScrubLogger;\n}\n\n/**\n * Outcome of a {@link scrubPoisonedTranscript} pass.\n *\n * @category Transcript repair\n */\nexport interface ScrubTranscriptResult {\n /** The located JSONL transcript path, or `null` when not found. */\n filePath: string | null;\n /** Image blocks whose `media_type` was corrected (or filled in) to match the bytes. */\n corrected: number;\n /**\n * Image blocks replaced with a text stub — either unidentifiable bytes or a\n * payload over the API's 5 MB per-image limit.\n */\n stubbed: number;\n /** Empty text blocks from which a rejected `cache_control` marker was stripped. */\n cacheStripped: number;\n /**\n * `true` when the transcript was located, contained at least one poisoned\n * block, and was rewritten. `false` means nothing needed repair (or the\n * file was not found) — the caller should not retry the resume.\n */\n changed: boolean;\n}\n\n/** Text inserted in place of an image block whose format cannot be identified. */\nconst STUB_TEXT = \"[image removed: unprocessable image data]\";\n\n/** Text inserted in place of an image block that exceeds the API size limit. */\nconst STUB_TEXT_OVERSIZED = \"[image removed: image too large]\";\n\n/**\n * The Anthropic Messages API rejects any single image whose decoded payload\n * exceeds 5 MB. An image at or under this is left alone; a larger one is\n * stubbed (its byte budget cannot be recovered).\n */\nconst MAX_IMAGE_BYTES = 5 * 1024 * 1024;\n\n/**\n * Identify an image's media type from the leading bytes of its base64 payload.\n *\n * Recognises the four formats the Anthropic API accepts. Returns `null` when\n * the magic bytes match no known format — the caller treats that as a\n * genuinely corrupt block and stubs it.\n *\n * @param base64 - Base64-encoded image data (only the prefix is inspected).\n * @returns An `image/*` media type, or `null` when unrecognised.\n * @category Transcript repair\n */\nexport function sniffImageMediaType(base64: string): string | null {\n let buf: Buffer;\n try {\n // 32 base64 chars decode to 24 bytes — enough for the WebP check at 12.\n buf = Buffer.from(base64.slice(0, 32), \"base64\");\n } catch {\n return null;\n }\n if (buf.length < 4) {\n return null;\n }\n // JPEG — SOI marker `FF D8`. Third byte varies (and may be corrupt), so a\n // two-byte check is intentional: it still matches malformed JPEGs, which is\n // exactly the poison case the API flags as \"appears to be image/jpeg\".\n if (buf[0] === 0xff && buf[1] === 0xd8) {\n return \"image/jpeg\";\n }\n // PNG — `89 50 4E 47`.\n if (buf[0] === 0x89 && buf[1] === 0x50 && buf[2] === 0x4e && buf[3] === 0x47) {\n return \"image/png\";\n }\n // GIF — `47 49 46 38` (\"GIF8\").\n if (buf[0] === 0x47 && buf[1] === 0x49 && buf[2] === 0x46 && buf[3] === 0x38) {\n return \"image/gif\";\n }\n // WebP — `RIFF` at 0..3 and `WEBP` at 8..11.\n if (\n buf.length >= 12 &&\n buf[0] === 0x52 &&\n buf[1] === 0x49 &&\n buf[2] === 0x46 &&\n buf[3] === 0x46 &&\n buf[8] === 0x57 &&\n buf[9] === 0x45 &&\n buf[10] === 0x42 &&\n buf[11] === 0x50\n ) {\n return \"image/webp\";\n }\n return null;\n}\n\n/** A base64 image source on a content block (shape is SDK-defined). */\ninterface Base64ImageSource {\n type?: string;\n media_type?: string;\n data?: string;\n}\n\n/** Loosely-typed content block from a transcript message. */\ninterface ContentBlockLike {\n type?: string;\n source?: Base64ImageSource;\n content?: unknown;\n [k: string]: unknown;\n}\n\n/** Mutable counters threaded through one scrub pass. */\ninterface ScrubCounters {\n corrected: number;\n stubbed: number;\n cacheStripped: number;\n}\n\n/** Total repairs recorded in a counter set — used to detect per-line changes. */\nfunction totalChanges(c: ScrubCounters): number {\n return c.corrected + c.stubbed + c.cacheStripped;\n}\n\n/**\n * Repair a single content block. Returns the (possibly replaced) block.\n *\n * - A `tool_result` block recurses into its `content` array.\n * - A text block carrying a `cache_control` marker whose `text` is empty or\n * whitespace has the marker stripped (the API rejects `cache_control` on\n * empty text blocks).\n * - An image block whose decoded payload exceeds the API's 5 MB limit is\n * replaced with a text stub.\n * - An image block whose bytes match no known format is replaced with a text\n * stub (an image cannot simply be dropped — a `tool_result` must keep at\n * least one content entry, and a bare `image` block is replaced 1:1).\n * - An image block whose declared `media_type` mismatches (or is missing for)\n * the sniffed type is corrected in place.\n * - Every other block is returned untouched.\n */\nfunction scrubBlock(block: ContentBlockLike, counters: ScrubCounters): ContentBlockLike {\n if (block.type === \"tool_result\" && Array.isArray(block.content)) {\n return {\n ...block,\n content: (block.content as ContentBlockLike[]).map((inner) => scrubBlock(inner, counters)),\n };\n }\n\n // A `cache_control` marker on a text block whose text is empty or whitespace\n // is rejected by the API (\"cache_control cannot be set for empty text\n // blocks\"). Strip the marker — the empty block itself is harmless.\n if (block.type === \"text\" && block.cache_control != null) {\n const text = typeof block.text === \"string\" ? block.text : \"\";\n if (text.trim() === \"\") {\n counters.cacheStripped++;\n const clone = { ...block };\n delete clone.cache_control;\n return clone;\n }\n }\n\n if (\n block.type === \"image\" &&\n block.source?.type === \"base64\" &&\n typeof block.source.data === \"string\"\n ) {\n const data = block.source.data;\n // The API rejects any image whose decoded payload exceeds 5 MB. The byte\n // budget cannot be salvaged, so the whole block becomes a text stub.\n // base64 encodes 3 bytes per 4 chars, so decoded length ≈ len * 3 / 4.\n if (Math.floor((data.length * 3) / 4) > MAX_IMAGE_BYTES) {\n counters.stubbed++;\n return { type: \"text\", text: STUB_TEXT_OVERSIZED };\n }\n const sniffed = sniffImageMediaType(data);\n if (sniffed === null) {\n counters.stubbed++;\n return { type: \"text\", text: STUB_TEXT };\n }\n if (sniffed !== block.source.media_type) {\n counters.corrected++;\n return { ...block, source: { ...block.source, media_type: sniffed } };\n }\n }\n\n return block;\n}\n\n/**\n * Locate the JSONL transcript for `sessionId` under `<configDir>/projects/`.\n *\n * Claude Code encodes the project directory into the `projects/` subfolder\n * name; rather than reproduce that encoding, this scans every subfolder for\n * `<sessionId>.jsonl` (the session id is a UUID — globally unique).\n *\n * Async and deadline-bounded since #454. The `existsSync(projectsDir)` probe is\n * gone: `readdir` already fails on a missing directory, so the probe was a\n * second stat on the same path for no information.\n *\n * `timeoutMs` defaults to {@link fsDeadlineMs} so callers that only need the\n * path (the resume probe) can omit it.\n *\n * @category Transcript repair\n */\nexport async function locateTranscriptPath(\n configDir: string,\n sessionId: string,\n timeoutMs: number = fsDeadlineMs(),\n): Promise<string | null> {\n const projectsDir = join(configDir, \"projects\");\n const entries = await tryWithFsDeadline(\n `readdir ${projectsDir}`,\n () => readdir(projectsDir),\n null,\n timeoutMs,\n );\n if (!entries) return null;\n for (const entry of entries) {\n const candidate = join(projectsDir, entry, `${sessionId}.jsonl`);\n const found = await tryWithFsDeadline(\n `stat ${candidate}`,\n async () => (await stat(candidate)).isFile(),\n false,\n timeoutMs,\n );\n if (found) return candidate;\n }\n return null;\n}\n\n/**\n * Yield a file's contents line by line, reproducing `readFileSync(...).split(\"\\n\")`\n * exactly — including the final (possibly empty) segment, so a trailing newline\n * survives a rewrite byte for byte.\n *\n * Splits on `\\n` alone, so a line out of a CRLF transcript arrives with its\n * `\\r` still attached. That carrier byte is part of the line here, and\n * {@link repairLine} re-attaches it to a line it rewrites — the file keeps the\n * terminator style it arrived with. Deliberately not `node:readline`:\n * `crlfDelay` strips the `\\r` outright (rewriting a CRLF transcript to LF) and\n * the interface swallows the trailing-newline distinction, either of which\n * would make the \"clean transcript is left byte-for-byte untouched\" guarantee\n * false. Only one line is held in memory at a time, so a multi-MB transcript\n * never materialises as a single string.\n */\nasync function* streamLines(filePath: string): AsyncGenerator<string> {\n const stream = createReadStream(filePath, { encoding: \"utf8\" });\n let pending = \"\";\n try {\n for await (const chunk of stream) {\n pending += chunk as string;\n let idx = pending.indexOf(\"\\n\");\n while (idx !== -1) {\n yield pending.slice(0, idx);\n pending = pending.slice(idx + 1);\n idx = pending.indexOf(\"\\n\");\n }\n }\n yield pending;\n } finally {\n stream.destroy();\n }\n}\n\n/**\n * Repair one JSONL line, returning the (possibly rewritten) line and mutating\n * `counters`. A non-JSON, blank, or content-less line is returned untouched.\n *\n * The reader splits on `\\n` only, so a line from a CRLF transcript still carries\n * its trailing `\\r`. An untouched line is returned verbatim and keeps it; a\n * rewritten one is rebuilt by `JSON.stringify`, which would drop it — leaving a\n * repaired CRLF transcript with mixed line endings. So the terminator is split\n * off before the parse and re-appended to the rewritten line.\n */\nfunction repairLine(line: string, counters: ScrubCounters): string {\n if (line.trim() === \"\") return line;\n const eol = line.endsWith(\"\\r\") ? \"\\r\" : \"\";\n const body = eol === \"\" ? line : line.slice(0, -1);\n let entry: { message?: { content?: unknown } };\n try {\n entry = JSON.parse(body);\n } catch {\n return line; // Not JSON — leave untouched.\n }\n const content = entry.message?.content;\n if (!Array.isArray(content)) return line;\n const before = totalChanges(counters);\n const scrubbed = (content as ContentBlockLike[]).map((block) => scrubBlock(block, counters));\n if (totalChanges(counters) === before) return line; // Nothing changed on this line.\n return `${JSON.stringify({ ...entry, message: { ...entry.message, content: scrubbed } })}${eol}`;\n}\n\n/**\n * Scan a Claude Code SDK transcript for image content blocks whose declared\n * `media_type` does not match the actual bytes, repair them, and atomically\n * rewrite the file.\n *\n * Safe to call after a turn has failed: the SDK query is dead at that point,\n * and the next resume re-reads the transcript from disk.\n *\n * **Async since #454.** Two streaming passes rather than one whole-file read:\n * pass 1 counts repairs without writing anything, and pass 2 runs only when\n * pass 1 found something. The common case — the preventive scrub of a clean\n * transcript before every resume — is therefore one streaming read and zero\n * writes, and a clean transcript is still left byte-for-byte untouched.\n *\n * @param opts - Config directory, session id, and an optional logger.\n * @returns A {@link ScrubTranscriptResult}. When `changed` is `true` the\n * caller may retry the resume with the same session id.\n * @category Transcript repair\n */\nexport async function scrubPoisonedTranscript(\n opts: ScrubTranscriptOptions,\n): Promise<ScrubTranscriptResult> {\n const { configDir, sessionId, log } = opts;\n const timeoutMs = fsDeadlineMs();\n const result: ScrubTranscriptResult = {\n filePath: null,\n corrected: 0,\n stubbed: 0,\n cacheStripped: 0,\n changed: false,\n };\n\n const filePath = await locateTranscriptPath(configDir, sessionId, timeoutMs);\n if (!filePath) {\n log?.warn(\"scrub-transcript: no transcript found\", { configDir, sessionId });\n return result;\n }\n result.filePath = filePath;\n\n // ── Pass 1: detect. Streams the transcript, counting repairs, writing nothing.\n const counters: ScrubCounters = { corrected: 0, stubbed: 0, cacheStripped: 0 };\n try {\n await withFsDeadline(\n `scan transcript ${filePath}`,\n async () => {\n for await (const line of streamLines(filePath)) repairLine(line, counters);\n },\n timeoutMs,\n );\n } catch (err) {\n log?.warn(\"scrub-transcript: failed to read transcript\", {\n filePath,\n error: err instanceof Error ? err.message : String(err),\n });\n return result;\n }\n\n result.corrected = counters.corrected;\n result.stubbed = counters.stubbed;\n result.cacheStripped = counters.cacheStripped;\n\n if (totalChanges(counters) === 0) {\n return result;\n }\n\n // ── Pass 2: rewrite. Atomic: stream a sibling temp file, then rename over the\n // original. Line separators are re-emitted exactly as pass 1 split them, so a\n // trailing newline and any blank lines survive verbatim.\n const tmpPath = `${filePath}.scrub-tmp`;\n try {\n await withFsDeadline(\n `rewrite transcript ${filePath}`,\n async () => {\n const discard: ScrubCounters = { corrected: 0, stubbed: 0, cacheStripped: 0 };\n await pipeline(\n (async function* () {\n let first = true;\n for await (const line of streamLines(filePath)) {\n yield first ? repairLine(line, discard) : `\\n${repairLine(line, discard)}`;\n first = false;\n }\n })(),\n createWriteStream(tmpPath, { encoding: \"utf8\" }),\n );\n await rename(tmpPath, filePath);\n },\n timeoutMs,\n );\n } catch (err) {\n log?.warn(\"scrub-transcript: failed to rewrite transcript\", {\n filePath,\n error: err instanceof Error ? err.message : String(err),\n });\n // Never leave a half-written sibling behind — the next scrub would rewrite\n // it anyway, but a stray `.scrub-tmp` in the SDK's projects dir is noise.\n await tryWithFsDeadline(`unlink ${tmpPath}`, () => unlink(tmpPath), undefined, timeoutMs);\n return result;\n }\n\n result.changed = true;\n log?.info(\"scrub-transcript: repaired poisoned transcript\", {\n filePath,\n corrected: result.corrected,\n stubbed: result.stubbed,\n cacheStripped: result.cacheStripped,\n });\n return result;\n}\n","/**\n * Pre-first-turn resume probe for the Claude Agent SDK driver.\n *\n * A tier-1 native resume only hands its session id to the SDK inside the first\n * real turn, so the `jsonl_lost` outcome (\"No conversation found\") is invisible\n * until a turn is consumed. The runner shares the container filesystem with the\n * SDK, so a cheap `stat` of the on-disk JSONL transcript is an authoritative,\n * side-effect-free signal of whether the resume will find its history — no\n * probe query, no spurious model turn.\n *\n * @module\n */\n\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { withFsDeadline } from \"@skaile/workspaces/core\";\nimport { locateTranscriptPath } from \"./scrub-transcript.js\";\n\n/**\n * Overall wall-clock budget for the probe. Deliberately a small fraction of the\n * platform's `session_init_ack` timeout (`DEFAULT_INIT_ACK_TIMEOUT_MS`, 15s):\n * the probe runs synchronously on the pre-ack path, so a wedged\n * `CLAUDE_CONFIG_DIR` mount must never push the ack past its deadline.\n */\nconst RESUME_PROBE_TIMEOUT_MS = 2_000;\n\n/**\n * Outcome of {@link probeResumeTranscript}: whether the SDK transcript for a\n * requested tier-1 resume exists on disk.\n *\n * @category Resume probe\n */\nexport type ResumeProbeOutcome = \"transcript_found\" | \"jsonl_lost\";\n\n/**\n * Resolve the Claude Code config directory — the parent of `projects/` — from\n * an explicit env map, the process environment, or the `~/.claude` default.\n *\n * The runner's probe and the claude-sdk driver share this one resolver, so they\n * agree as long as they see the same `CLAUDE_CONFIG_DIR`. Today they do:\n * `CLAUDE_CONFIG_DIR` is container-scoped and neither side threads a per-session\n * override through `config.env`, so both fall through to `process.env`. If a\n * future change ever set the driver's `config.env.CLAUDE_CONFIG_DIR` to a\n * divergent path, the reactive `resume_failed { jsonl_lost }` turn remains the\n * safety net.\n *\n * @category Resume probe\n */\nexport function resolveClaudeConfigDir(env?: Record<string, string | undefined>): string {\n return env?.CLAUDE_CONFIG_DIR || process.env.CLAUDE_CONFIG_DIR || join(homedir(), \".claude\");\n}\n\n/**\n * Probe whether the SDK JSONL transcript for `sessionId` exists on disk.\n *\n * Non-null locator result → `transcript_found`; null → `jsonl_lost`;\n * `undefined` → outcome unknown (the probe exceeded its budget or errored). The\n * caller leaves the ack field ABSENT on `undefined` so the reactive\n * `resume_failed { jsonl_lost }` turn stays the safety net — a timed-out probe\n * must never masquerade as a genuine `jsonl_lost` and force a needless downgrade.\n *\n * `opts.timeoutMs` overrides {@link RESUME_PROBE_TIMEOUT_MS}; `opts.locate`\n * overrides the transcript locator (used by tests / alternate stores).\n *\n * @category Resume probe\n */\nexport async function probeResumeTranscript(\n sessionId: string,\n opts?: {\n env?: Record<string, string | undefined>;\n timeoutMs?: number;\n locate?: (configDir: string, sessionId: string) => Promise<string | null>;\n },\n): Promise<ResumeProbeOutcome | undefined> {\n const configDir = resolveClaudeConfigDir(opts?.env);\n const timeoutMs = opts?.timeoutMs ?? RESUME_PROBE_TIMEOUT_MS;\n const locate = opts?.locate ?? locateTranscriptPath;\n try {\n // Bound the whole probe on wall-clock and THROW on expiry: the inner per-op\n // deadline swallows a timeout into a null path (a false `jsonl_lost`), so a\n // wedged mount must yield \"unknown\" here rather than a spurious downgrade.\n const filePath = await withFsDeadline(\n `resume-probe ${sessionId}`,\n () => locate(configDir, sessionId),\n timeoutMs,\n );\n return filePath ? \"transcript_found\" : \"jsonl_lost\";\n } catch {\n return undefined;\n }\n}\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { resolveSkWorkspaceConfig, readLinks, getGlobalCacheDir, sourceCacheKey } from './chunk-
|
|
2
|
-
import { scanDirectory, tryWithFsDeadline } from './chunk-
|
|
1
|
+
import { resolveSkWorkspaceConfig, readLinks, getGlobalCacheDir, sourceCacheKey } from './chunk-IP3GXHOB.js';
|
|
2
|
+
import { scanDirectory, tryWithFsDeadline } from './chunk-VQ4P7UYE.js';
|
|
3
3
|
import { existsSync, readFileSync } from 'fs';
|
|
4
4
|
import { lstat, stat } from 'fs/promises';
|
|
5
5
|
import { createRequire } from 'module';
|
|
@@ -219,5 +219,5 @@ function findCatalogEntry(entries, query) {
|
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
export { FACTORY_ASSETS_REPO_NAME, factoryAssetRoots, resolveFactoryAssetsRoot, resolveFactoryAssetsRootOrNull, resolvePackagedAssetsDir, resolveRuntimeAssets, resolveWorkspacesPackageRoot };
|
|
222
|
-
//# sourceMappingURL=chunk-
|
|
223
|
-
//# sourceMappingURL=chunk-
|
|
222
|
+
//# sourceMappingURL=chunk-SH572OBN.js.map
|
|
223
|
+
//# sourceMappingURL=chunk-SH572OBN.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../core/src/runtime-assets.ts"],"names":["resolvePath","require"],"mappings":";;;;;;;;AAsDA,SAAS,sBACP,OAAA,EACmC;AACnC,EAAA,MAAM,aAAa,iBAAA,EAAkB;AACrC,EAAA,MAAM,MAAyC,EAAC;AAChD,EAAA,KAAA,MAAW,CAAA,IAAK,OAAA,IAAW,EAAC,EAAG;AAC7B,IAAA,MAAM,GAAA,GAAM,cAAA,CAAe,CAAA,CAAE,GAAG,CAAA;AAChC,IAAA,IAAI,GAAA,CAAI,GAAG,CAAA,EAAG;AACd,IAAA,GAAA,CAAI,GAAG,CAAA,GAAI,EAAE,IAAA,EAAM,IAAA,CAAK,UAAA,EAAY,GAAG,CAAA,EAAG,GAAA,EAAK,CAAA,CAAE,GAAA,EAAK,MAAA,EAAQ,EAAE,GAAA,EAAI;AAAA,EACtE;AACA,EAAA,OAAO,GAAA;AACT;AAqDO,IAAM,wBAAA,GAA2B;AAMxC,IAAM,iCAAA,GAAoC,yBAAA;AAsC1C,eAAsB,qBAAqB,UAAA,EAAkD;AAC3F,EAAA,MAAM,MAAA,GAA8B;AAAA,IAClC,gBAAgB,EAAC;AAAA,IACjB,cAAc,EAAC;AAAA,IACf,iBAAiB,EAAE,QAAA,EAAU,EAAC,EAAG,QAAA,EAAU,EAAC,EAAE;AAAA,IAC9C,UAAU,EAAC;AAAA,IACX,SAAS,YAAY;AACnB,MAAA,MAAM,QAAA,CAAS,YAAY,MAAM,CAAA;AAAA,IACnC,CAAA;AAAA,IACA,WAAW,CAAC,KAAA,KAAU,gBAAA,CAAiB,MAAA,CAAO,gBAAgB,KAAK;AAAA,GACrE;AAEA,EAAA,MAAM,QAAA,CAAS,YAAY,MAAM,CAAA;AACjC,EAAA,OAAO,MAAA;AACT;AAmBO,SAAS,iBAAA,GAA8B;AAC5C,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,GAAA,CAAI,yBAAA,IAA6B,QAAQ,GAAA,CAAI,sBAAA;AAOpE,EAAA,IAAI,MAAA,IAAU,WAAW,MAAM,CAAA,QAAS,IAAA,CAAKA,OAAA,CAAY,MAAM,CAAC,CAAA;AAChE,EAAA,MAAM,OAAA,GAAU,yBAAyB,gBAAgB,CAAA;AACzD,EAAA,IAAI,OAAA,EAAS,KAAA,CAAM,IAAA,CAAK,OAAO,CAAA;AAC/B,EAAA,OAAO,CAAC,GAAG,IAAI,GAAA,CAAI,KAAK,CAAC,CAAA;AAC3B;AAYO,SAAS,wBAAA,GAAmC;AACjD,EAAA,MAAM,MAAM,8BAAA,EAA+B;AAC3C,EAAA,IAAI,KAAK,OAAO,GAAA;AAEhB,EAAA,MAAM,IAAI,KAAA;AAAA,IACR,CAAA,+LAAA;AAAA,GAIF;AACF;AAUO,SAAS,8BAAA,GAAgD;AAC9D,EAAA,OAAO,iBAAA,EAAkB,CAAE,CAAC,CAAA,IAAK,IAAA;AACnC;AAoBA,IAAI,0BAAA;AAEG,SAAS,4BAAA,GAA8C;AAC5D,EAAA,IAAI,0BAAA,KAA+B,QAAW,OAAO,0BAAA;AACrD,EAAA,0BAAA,GAA6B,4BAAA,EAA6B;AAC1D,EAAA,OAAO,0BAAA;AACT;AAEA,SAAS,4BAAA,GAA8C;AACrD,EAAA,IAAI;AACF,IAAA,MAAMC,QAAAA,GAAU,aAAA,CAAc,MAAA,CAAA,IAAA,CAAY,GAAG,CAAA;AAC7C,IAAA,OAAO,OAAA,CAAQA,QAAAA,CAAQ,OAAA,CAAQ,iCAAiC,CAAC,CAAA;AAAA,EACnE,CAAA,CAAA,MAAQ;AAAA,EAER;AACA,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACF,IAAA,GAAA,GAAM,OAAA,CAAQ,aAAA,CAAc,MAAA,CAAA,IAAA,CAAY,GAAG,CAAC,CAAA;AAAA,EAC9C,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA,EAAK;AAC1B,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,GAAA,EAAK,cAAc,CAAA;AACxC,IAAA,IAAI,UAAA,CAAW,OAAO,CAAA,EAAG;AACvB,MAAA,IAAI;AACF,QAAA,MAAM,MAAM,IAAA,CAAK,KAAA,CAAM,YAAA,CAAa,OAAA,EAAS,OAAO,CAAC,CAAA;AACrD,QAAA,IAAI,GAAA,CAAI,IAAA,KAAS,oBAAA,EAAsB,OAAO,GAAA;AAAA,MAChD,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF;AACA,IAAA,MAAM,MAAA,GAAS,QAAQ,GAAG,CAAA;AAC1B,IAAA,IAAI,WAAW,GAAA,EAAK;AACpB,IAAA,GAAA,GAAM,MAAA;AAAA,EACR;AACA,EAAA,OAAO,IAAA;AACT;AAiBO,SAAS,yBAAyB,MAAA,EAA+B;AACtE,EAAA,MAAM,OAAO,4BAAA,EAA6B;AAC1C,EAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,EAAA,KAAA,MAAW,IAAA,IAAQ,CAAC,IAAA,CAAK,IAAA,EAAM,MAAM,CAAA,EAAG,IAAA,CAAK,IAAA,EAAM,MAAA,EAAQ,MAAM,CAAC,CAAA,EAAG;AACnE,IAAA,IAAI,UAAA,CAAW,IAAI,CAAA,EAAG,OAAO,IAAA;AAAA,EAC/B;AACA,EAAA,OAAO,IAAA;AACT;AAIA,eAAe,QAAA,CAAS,YAAoB,MAAA,EAA4C;AACtF,EAAA,MAAA,CAAO,iBAAiB,EAAC;AACzB,EAAA,MAAA,CAAO,eAAe,EAAC;AACvB,EAAA,MAAA,CAAO,kBAAkB,EAAE,QAAA,EAAU,EAAC,EAAG,QAAA,EAAU,EAAC,EAAE;AACtD,EAAA,MAAA,CAAO,WAAW,EAAC;AAEnB,EAAA,MAAM,MAAA,GAAS,yBAAyB,UAAU,CAAA;AAGlD,EAAA,MAAM,YAAA,GAAe,0BAAA,CAA2B,qBAAA,CAAsB,MAAA,CAAO,OAAO,CAAC,CAAA;AACrF,EAAA,MAAM,KAAA,GAAQ,UAAU,UAAU,CAAA;AAGlC,EAAA,KAAA,MAAW,CAAC,IAAA,EAAM,IAAI,KAAK,MAAA,CAAO,OAAA,CAAQ,YAAY,CAAA,EAAG;AACvD,IAAA,MAAM,UAAU,MAAM,cAAA,CAAe,IAAA,EAAM,IAAA,EAAM,YAAY,KAAK,CAAA;AAClE,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,MAAA,CAAO,SAAS,IAAA,CAAK;AAAA,QACnB,IAAA,EAAM,kBAAA;AAAA,QACN,IAAA;AAAA,QACA,OAAA,EAAS,sBAAA,CAAuB,IAAA,EAAM,IAAI;AAAA,OAC3C,CAAA;AACD,MAAA;AAAA,IACF;AACA,IAAA,IAAI;AAGF,MAAA,MAAM,QAAA,GAAW,IAAA,KAAS,iCAAA,GAAoC,wBAAA,GAA2B,IAAA;AACzF,MAAA,MAAM,OAAA,GAAU,MAAM,aAAA,CAAc,OAAA,EAAS,QAAQ,CAAA;AACrD,MAAA,MAAM,UAAU,OAAA,CAAQ,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,WAAW,CAAA;AAC5D,MAAA,MAAA,CAAO,cAAA,CAAe,IAAA,CAAK,GAAG,OAAO,CAAA;AAAA,IACvC,SAAS,GAAA,EAAK;AACZ,MAAA,MAAA,CAAO,SAAS,IAAA,CAAK;AAAA,QACnB,IAAA,EAAM,kBAAA;AAAA,QACN,IAAA;AAAA,QACA,OAAA,EAAS,CAAA,2BAAA,EAA8B,IAAI,CAAA,KAAA,EAAQ,OAAO,CAAA,EAAA,EACxD,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,MAAA,CAAO,GAAG,CACjD,CAAA;AAAA,OACD,CAAA;AAAA,IACH;AAAA,EACF;AAMA,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAY;AAC7B,EAAA,MAAA,CAAO,cAAA,GAAiB,MAAA,CAAO,cAAA,CAAe,MAAA,CAAO,CAAC,CAAA,KAAM;AAC1D,IAAA,MAAM,MAAM,CAAA,EAAG,CAAA,CAAE,IAAI,CAAA,CAAA,EAAI,EAAE,IAAI,CAAA,CAAA;AAC/B,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA,EAAG,OAAO,KAAA;AAC1B,IAAA,IAAA,CAAK,IAAI,GAAG,CAAA;AACZ,IAAA,OAAO,IAAA;AAAA,EACT,CAAC,CAAA;AAGD,EAAA,KAAA,MAAW,CAAA,IAAK,MAAA,CAAO,UAAA,IAAc,EAAC,EAAG;AACvC,IAAA,MAAA,CAAO,YAAA,CAAa,IAAA,CAAK,EAAE,IAAA,EAAM,WAAA,EAAa,IAAA,EAAM,CAAA,CAAE,MAAA,EAAQ,aAAA,EAAe,CAAA,CAAE,EAAA,EAAI,CAAA;AAAA,EACrF;AAGA,EAAA,MAAM,WAAA,uBAAkB,GAAA,EAAY;AACpC,EAAA,MAAM,WAAA,uBAAkB,GAAA,EAAY;AACpC,EAAA,KAAA,MAAW,GAAA,IAAO,OAAO,YAAA,EAAc;AACrC,IAAA,MAAM,KAAA,GAAQ,gBAAA,CAAiB,MAAA,CAAO,cAAA,EAAgB,GAAG,CAAA;AACzD,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA,MAAA,CAAO,SAAS,IAAA,CAAK;AAAA,QACnB,IAAA,EAAM,gBAAA;AAAA,QACN,eAAe,GAAA,CAAI,aAAA;AAAA,QACnB,MAAM,GAAA,CAAI,IAAA;AAAA,QACV,OAAA,EACE,CAAA,QAAA,EAAW,GAAA,CAAI,IAAI,YAAY,GAAA,CAAI,IAAI,CAAA,gBAAA,EAAmB,GAAA,CAAI,IAAI,CAAA,EAAA,EAAK,GAAA,CAAI,aAAa,CAAA,gBAAA,EACxE,IAAI,IAAI,CAAA,sGAAA;AAAA,OAE3B,CAAA;AACD,MAAA;AAAA,IACF;AACA,IAAA,MAAM,GAAA,GAAO,KAAA,CAAM,QAAA,EAAU,QAAA,IAAY,EAAC;AAC1C,IAAA,KAAA,MAAW,KAAK,GAAA,CAAI,QAAA,IAAY,EAAC,EAAG,WAAA,CAAY,IAAI,CAAC,CAAA;AACrD,IAAA,KAAA,MAAW,KAAK,GAAA,CAAI,QAAA,IAAY,EAAC,EAAG,WAAA,CAAY,IAAI,CAAC,CAAA;AAAA,EACvD;AACA,EAAA,MAAA,CAAO,eAAA,CAAgB,QAAA,GAAW,CAAC,GAAG,WAAW,CAAA;AACjD,EAAA,MAAA,CAAO,eAAA,CAAgB,QAAA,GAAW,CAAC,GAAG,WAAW,CAAA;AACnD;AAUA,SAAS,2BACP,QAAA,EACmC;AACnC,EAAA,MAAM,MAAA,GAA4C,EAAE,GAAI,QAAA,IAAY,EAAC,EAAG;AACxE,EAAA,MAAM,QAAQ,iBAAA,EAAkB;AAChC,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AAItB,IAAA,IAAI,CAAC,OAAO,wBAAwB,CAAA,SAAU,wBAAwB,CAAA,GAAI,EAAE,IAAA,EAAM,EAAA,EAAG;AACrF,IAAA,OAAO,MAAA;AAAA,EACT;AAGA,EAAA,MAAM,IAAA,GACJ,MAAM,MAAA,GAAS,CAAA,GACX,CAAC,iCAAA,EAAmC,wBAAwB,CAAA,GAC5D,CAAC,wBAAwB,CAAA;AAC/B,EAAA,KAAA,CAAM,OAAA,CAAQ,CAAC,GAAA,EAAK,CAAA,KAAM;AACxB,IAAA,MAAM,MAAM,IAAA,CAAK,CAAC,KAAK,CAAA,EAAG,wBAAwB,IAAI,CAAC,CAAA,CAAA;AACvD,IAAA,IAAI,CAAC,OAAO,GAAG,CAAA,SAAU,GAAG,CAAA,GAAI,EAAE,IAAA,EAAM,GAAA,EAAI;AAAA,EAC9C,CAAC,CAAA;AACD,EAAA,OAAO,MAAA;AACT;AAoBA,eAAe,cAAA,CACb,IAAA,EACA,IAAA,EACA,UAAA,EACA,KAAA,EACwB;AAExB,EAAA,MAAM,MAAA,GAAS,MAAM,IAAI,CAAA;AACzB,EAAA,IAAI,MAAA,IAAW,MAAM,UAAA,CAAW,MAAM,GAAI,OAAO,MAAA;AAGjD,EAAA,IAAI,KAAK,IAAA,EAAM;AACb,IAAA,MAAM,QAAA,GAAWD,OAAA,CAAY,UAAA,EAAY,IAAA,CAAK,IAAI,CAAA;AAClD,IAAA,OAAQ,MAAM,UAAA,CAAW,QAAQ,CAAA,GAAK,QAAA,GAAW,IAAA;AAAA,EACnD;AAKA,EAAA,IAAI,KAAK,GAAA,EAAK;AACZ,IAAA,MAAM,cAAc,IAAA,CAAK,UAAA,EAAY,SAAA,EAAW,OAAA,EAAS,WAAW,IAAI,CAAA;AAIxE,IAAA,MAAM,QAAQ,MAAM,iBAAA;AAAA,MAClB,SAAS,WAAW,CAAA,CAAA;AAAA,MACpB,YAAY;AACV,QAAA,MAAM,MAAM,WAAW,CAAA;AACvB,QAAA,OAAO,IAAA;AAAA,MACT,CAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,OAAO,QAAQ,WAAA,GAAc,IAAA;AAAA,EAC/B;AAEA,EAAA,OAAO,IAAA;AACT;AAGA,SAAS,WAAW,IAAA,EAAgC;AAClD,EAAA,OAAO,iBAAA;AAAA,IACL,QAAQ,IAAI,CAAA,CAAA;AAAA,IACZ,YAAY;AACV,MAAA,MAAM,KAAK,IAAI,CAAA;AACf,MAAA,OAAO,IAAA;AAAA,IACT,CAAA;AAAA,IACA;AAAA,GACF;AACF;AAEA,SAAS,sBAAA,CAAuB,MAAc,IAAA,EAAiC;AAC7E,EAAA,IAAI,SAAS,wBAAA,IAA4B,CAAC,KAAK,IAAA,IAAQ,CAAC,KAAK,GAAA,EAAK;AAChE,IAAA,OACE,CAAA,oHAAA,CAAA;AAAA,EAGJ;AACA,EAAA,IAAI,KAAK,GAAA,EAAK;AACZ,IAAA,OAAO,CAAA,YAAA,EAAe,IAAI,CAAA,GAAA,EAAM,IAAA,CAAK,GAAG,CAAA,8EAAA,CAAA;AAAA,EAC1C;AACA,EAAA,IAAI,KAAK,IAAA,EAAM;AACb,IAAA,OAAO,CAAA,YAAA,EAAe,IAAI,CAAA,kBAAA,EAAqB,IAAA,CAAK,IAAI,CAAA,CAAA;AAAA,EAC1D;AACA,EAAA,OAAO,eAAe,IAAI,CAAA,2BAAA,CAAA;AAC5B;AAEA,SAAS,gBAAA,CACP,SACA,KAAA,EACiC;AACjC,EAAA,IAAI,MAAM,IAAA,EAAM;AACd,IAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,KAAS,KAAA,CAAM,IAAA,IAAQ,CAAA,CAAE,IAAA,KAAS,KAAA,CAAM,IAAI,CAAA;AAAA,EAC3E;AACA,EAAA,MAAM,OAAA,GAAU,QAAQ,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,IAAA,KAAS,MAAM,IAAI,CAAA;AAC3D,EAAA,IAAI,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG,OAAO,QAAQ,CAAC,CAAA;AAE1C,EAAA,OAAO,MAAA;AACT","file":"chunk-UFY2HFLO.js","sourcesContent":["/**\n * Runtime asset resolution — read `skaile.yaml`, scan all declared repositories\n * (including the built-in `factory-assets/` directory as an implicit default),\n * and produce a unified view of connector catalog entries plus the implicit refs\n * that the `skaile.yaml` `connectors:` section adds to the dependency graph.\n *\n * This module is the single source of truth for \"which connectors does this\n * project see at runtime, and where do their implementations live on disk\".\n * Both the runner (serve, REPL, flow) and the platform's mid-session\n * `add_resource` flow consume `RuntimeAssetsResult.catalogEntries` and pass\n * it into `ConnectorManager` for catalog-based resolution.\n *\n * `factory-assets/` is the single first-party content tree (built-in connectors\n * + first-party skills + bundles) shipped inside the `@skaile/workspaces`\n * package — not a standalone package.\n *\n * It resolves to an **ordered list of roots** ({@link factoryAssetRoots}), not a\n * single dir. The bundled tree is always the baseline; an optional\n * `SKAILE_FACTORY_ASSETS_DIR` (legacy: `SKAILE_BASE_ASSETS_DIR`) is layered\n * **in front** as an additive override source — the agent container points it at\n * `/app/factory-assets/` (or a bind-mounted host dir) to ship updated skills /\n * flows / bundles / connector manifests without rebuilding the image. The two\n * roots resolve uniformly across every consumer (connector catalog scan, skill /\n * flow / completion discovery, the asset-manager factory source):\n * 1. `SKAILE_FACTORY_ASSETS_DIR` env dir, when set and existing (override layer).\n * 2. the bundled tree via {@link resolvePackagedAssetsDir} — the in-repo source\n * `packages/workspaces/factory-assets/` during dev, else the published\n * `dist/factory-assets/` after install (always-present baseline).\n *\n * Override semantics are **env-first**: on a name conflict the env root wins and\n * the bundled root fills the rest. Connector *code* still loads via the package's\n * static `exports` map, so the env root can override/add skills, flows, bundles,\n * and connector **manifests/metadata**, but cannot ship a new executable\n * connector — its `.js` is not on the package's import graph.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { lstat, stat } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport { dirname, join, resolve as resolvePath } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { tryWithFsDeadline } from \"./fs-deadline.js\";\nimport { scanDirectory } from \"./manifest.js\";\nimport type { CatalogEntry } from \"./models.js\";\nimport { getGlobalCacheDir, readLinks, sourceCacheKey } from \"./repo-manager.js\";\nimport type { SourceDeclaration, SourceEntry } from \"./workspace-config.js\";\nimport { resolveSkWorkspaceConfig } from \"./workspace-config.js\";\n\n/**\n * Map declared `sources[]` to internal `SourceDeclaration`s keyed by the\n * collision-free {@link sourceCacheKey} (`<host>/<owner>/<repo>`), pointing at\n * the unified machine-cache clone path (`getGlobalCacheDir()/<key>/`). Keyed by\n * the same function every other cache writer/reader uses so the path resolves.\n */\nfunction sourcesToDeclarations(\n sources: SourceEntry[] | undefined,\n): Record<string, SourceDeclaration> {\n const sourcesDir = getGlobalCacheDir();\n const out: Record<string, SourceDeclaration> = {};\n for (const s of sources ?? []) {\n const key = sourceCacheKey(s.url);\n if (out[key]) continue;\n out[key] = { path: join(sourcesDir, key), url: s.url, branch: s.pin };\n }\n return out;\n}\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\n/**\n * Catalog entry filtered to mount/connector kinds. Same shape as `CatalogEntry`.\n * @docLink packages/core/concepts#runtime-catalog-entry\n */\nexport type RuntimeCatalogEntry = CatalogEntry;\n\n/**\n * Implicit catalog reference derived from a `connectors:` declaration in `skaile.yaml`.\n * Each connector driver becomes an implicit ref that must be resolved in the catalog.\n * @docLink packages/core/concepts#runtime-asset-ref\n */\nexport interface RuntimeAssetRef {\n kind: \"connector\";\n /** Driver name — matches `RuntimeCatalogEntry.name`. */\n name: string;\n /** Source declaration id from `skaile.yaml`. */\n declarationId: string;\n}\n\n/**\n * Aggregated npm packages required by all resolved mount/connector adapters.\n * Populated from `metadata.npm_deps` in each matched catalog entry.\n * @docLink packages/core/concepts#runtime-npm-deps\n */\nexport interface RuntimeNpmDeps {\n required: string[];\n optional: string[];\n}\n\n/**\n * Non-fatal warning emitted during `resolveRuntimeAssets` when a repo is unavailable\n * or a driver is not found in any catalog.\n * @docLink packages/core/concepts#runtime-asset-warning\n */\nexport interface RuntimeAssetWarning {\n /** Stable code for filtering / structured logging. */\n code: \"missing_driver\" | \"repo_unavailable\" | \"invalid_repo_decl\";\n message: string;\n /** Declaration id when applicable. */\n declarationId?: string;\n /** Driver / repository name when applicable. */\n name?: string;\n}\n\n/**\n * Repository name used for the implicit built-in `factory-assets` catalog entry\n * (the in-package connector tree).\n * @docLink packages/core/concepts#factory-assets-repo-name\n */\nexport const FACTORY_ASSETS_REPO_NAME = \"factory-assets\";\n\n/**\n * Repository name for the optional `SKAILE_FACTORY_ASSETS_DIR` override layer,\n * scanned ahead of (and overriding) the bundled {@link FACTORY_ASSETS_REPO_NAME}.\n */\nconst FACTORY_ASSETS_OVERRIDE_REPO_NAME = \"factory-assets:override\";\n\n/**\n * Result of `resolveRuntimeAssets`.\n * The same object is mutated in place by `refresh()`, allowing callers to hold\n * a stable reference and observe updates after a new repository is cloned or\n * a driver is installed mid-session.\n * @docLink packages/core/concepts#runtime-assets-result\n */\nexport interface RuntimeAssetsResult {\n catalogEntries: RuntimeCatalogEntry[];\n implicitRefs: RuntimeAssetRef[];\n requiredNpmDeps: RuntimeNpmDeps;\n warnings: RuntimeAssetWarning[];\n /** Re-scan repositories and re-derive implicit refs. Mutates in place. */\n refresh(): Promise<void>;\n /**\n * Catalog lookup. When `kind` is omitted and multiple entries share the\n * `name`, returns `undefined` (caller must disambiguate).\n */\n findEntry(query: { kind?: \"connector\"; name: string }): RuntimeCatalogEntry | undefined;\n}\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Resolve all runtime assets visible to a project by scanning declared repositories.\n *\n * Reads `skaile.yaml`, scans every declared repository (plus the implicit\n * built-in `factory-assets` repo), and derives implicit refs from `mounts:` /\n * `connectors:` declarations. Does not clone or install anything — purely a\n * read-only scan of what is already on disk. URL-only repositories that have\n * not been cloned yet are reported as `repo_unavailable` warnings.\n *\n * @param projectDir - Absolute path to the project workspace root\n * @returns `RuntimeAssetsResult` with catalog entries, implicit refs, npm deps, and warnings\n * @docLink packages/core/concepts#resolve-runtime-assets\n */\nexport async function resolveRuntimeAssets(projectDir: string): Promise<RuntimeAssetsResult> {\n const result: RuntimeAssetsResult = {\n catalogEntries: [],\n implicitRefs: [],\n requiredNpmDeps: { required: [], optional: [] },\n warnings: [],\n refresh: async () => {\n await populate(projectDir, result);\n },\n findEntry: (query) => findCatalogEntry(result.catalogEntries, query),\n };\n\n await populate(projectDir, result);\n return result;\n}\n\n/**\n * Resolve the ordered list of on-disk roots for the built-in `factory-assets`\n * tree (built-in connectors + first-party skills + bundles). This is the single\n * shared resolver every consumer goes through, so the env override and the\n * bundled baseline are honoured uniformly.\n *\n * Order (env-first = override-wins):\n * 1. `SKAILE_FACTORY_ASSETS_DIR` env dir (legacy: `SKAILE_BASE_ASSETS_DIR`),\n * when set and existing — an additive override layer.\n * 2. {@link resolvePackagedAssetsDir} — the bundled tree (in-repo source in dev,\n * `dist/factory-assets/` after install). Always-present baseline.\n *\n * Returns `[]` only when the package cannot be located at all. De-duplicated, so\n * pointing the env var at the bundled dir collapses to one root.\n *\n * @docLink packages/core/concepts#resolve-factory-assets-root\n */\nexport function factoryAssetRoots(): string[] {\n const roots: string[] = [];\n const envDir = process.env.SKAILE_FACTORY_ASSETS_DIR ?? process.env.SKAILE_BASE_ASSETS_DIR;\n // Deliberately still synchronous after #454: both candidates are\n // container-local (the image's `/app/factory-assets/`, or the installed\n // package tree resolved by `resolvePackagedAssetsDir`), never the FUSE\n // workspace mount. The mount-reachable probes on this module's scan path —\n // the project-relative `sources[].path` candidates in `resolveRepoDir` — are\n // async and deadline-bounded.\n if (envDir && existsSync(envDir)) roots.push(resolvePath(envDir));\n const bundled = resolvePackagedAssetsDir(\"factory-assets\");\n if (bundled) roots.push(bundled);\n return [...new Set(roots)];\n}\n\n/**\n * Resolve the primary on-disk root of the `factory-assets` tree — the first of\n * {@link factoryAssetRoots} (the env override when set, else the bundled tree).\n * Prefer {@link factoryAssetRoots} when you need to scan every layer; this\n * single-dir form is for callers that want one canonical path.\n *\n * @returns Absolute path to the highest-precedence `factory-assets` directory\n * @throws When no root can be located\n * @docLink packages/core/concepts#resolve-factory-assets-root\n */\nexport function resolveFactoryAssetsRoot(): string {\n const hit = resolveFactoryAssetsRootOrNull();\n if (hit) return hit;\n\n throw new Error(\n `Cannot resolve the factory-assets directory. ` +\n `Set SKAILE_FACTORY_ASSETS_DIR to the on-disk path, ` +\n `ensure @skaile/workspaces is installed, ` +\n `or run from within the @skaile/workspaces package tree.`,\n );\n}\n\n/**\n * Non-throwing variant of {@link resolveFactoryAssetsRoot}: the same\n * env-then-packaged resolution tiers, returning `null` instead of throwing when\n * none locate the directory. Callers that treat a missing factory tree as a\n * soft \"not present\" (e.g. the asset-manager's implicit-source injection) MUST\n * use this so they honour the `SKAILE_FACTORY_ASSETS_DIR` container override\n * identically to the runtime path.\n */\nexport function resolveFactoryAssetsRootOrNull(): string | null {\n return factoryAssetRoots()[0] ?? null;\n}\n\n/**\n * Resolve the `@skaile/workspaces` package root — the directory containing its\n * `package.json`. Tries `require.resolve` first (works when installed as a\n * dependency *and* in-repo via the self-reference), then walks upward from this\n * module looking for a `package.json` whose `name` is `@skaile/workspaces`\n * (bounded to 8 levels). Returns `null` when neither locates it.\n *\n * The single source of truth for finding content shipped inside the package —\n * the unified `factory-assets/` tree (built-in connectors + first-party skills\n * + bundles) resolves through {@link resolvePackagedAssetsDir} on top of this.\n *\n * Memoized: the package location is immutable for the process lifetime, but\n * this sits on the CLI hot path (every `findSkills` / flow / completion call\n * funnels through here), so the `require.resolve` + upward `package.json` walk\n * runs once. `undefined` = not yet computed.\n *\n * @docLink packages/core/concepts#resolve-factory-assets-root\n */\nlet workspacesPackageRootCache: string | null | undefined;\n\nexport function resolveWorkspacesPackageRoot(): string | null {\n if (workspacesPackageRootCache !== undefined) return workspacesPackageRootCache;\n workspacesPackageRootCache = computeWorkspacesPackageRoot();\n return workspacesPackageRootCache;\n}\n\nfunction computeWorkspacesPackageRoot(): string | null {\n try {\n const require = createRequire(import.meta.url);\n return dirname(require.resolve(\"@skaile/workspaces/package.json\"));\n } catch {\n // Fall through to the workspace walk.\n }\n let dir: string;\n try {\n dir = dirname(fileURLToPath(import.meta.url));\n } catch {\n return null;\n }\n for (let i = 0; i < 8; i++) {\n const pkgPath = join(dir, \"package.json\");\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as { name?: string };\n if (pkg.name === \"@skaile/workspaces\") return dir;\n } catch {\n // Ignore malformed package.json and keep walking.\n }\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\n/**\n * Locate a content-asset directory inside the package. Prefers the in-repo\n * **source** dir `<pkgRoot>/<subdir>` when present — in a dev checkout it is the\n * full tree (e.g. `factory-assets/` keeps the connector `.ts` entry files that\n * `dist/` does not) — then the published `dist/<subdir>` copy (what\n * `files: [\"dist\"]` ships, the only one present after `npm i`). Returns `null`\n * when neither exists.\n *\n * `factory-assets/` resolves to the source tree in dev (code + skills + bundles)\n * and to `dist/factory-assets` post-install (compiled connectors + copied\n * manifests/skills/bundles).\n *\n * @param subdir - `\"factory-assets\"` | …\n * @docLink packages/core/concepts#resolve-factory-assets-root\n */\nexport function resolvePackagedAssetsDir(subdir: string): string | null {\n const root = resolveWorkspacesPackageRoot();\n if (!root) return null;\n for (const cand of [join(root, subdir), join(root, \"dist\", subdir)]) {\n if (existsSync(cand)) return cand;\n }\n return null;\n}\n\n// ─── Internals ────────────────────────────────────────────────────────────────\n\nasync function populate(projectDir: string, target: RuntimeAssetsResult): Promise<void> {\n target.catalogEntries = [];\n target.implicitRefs = [];\n target.requiredNpmDeps = { required: [], optional: [] };\n target.warnings = [];\n\n const config = resolveSkWorkspaceConfig(projectDir);\n // Connector catalog scan runs over the project's declared sources[] (resolved\n // to their machine-cache clone paths) plus the implicit factory-assets repo.\n const repositories = buildEffectiveRepositories(sourcesToDeclarations(config.sources));\n const links = readLinks(projectDir);\n\n // Scan each repository for connector entries.\n for (const [name, decl] of Object.entries(repositories)) {\n const repoDir = await resolveRepoDir(name, decl, projectDir, links);\n if (!repoDir) {\n target.warnings.push({\n code: \"repo_unavailable\",\n name,\n message: repoUnavailableMessage(name, decl),\n });\n continue;\n }\n try {\n // Both factory layers carry the same `factory-assets` provenance — the\n // override repo is an internal scan-order device, not a distinct source.\n const repoName = name === FACTORY_ASSETS_OVERRIDE_REPO_NAME ? FACTORY_ASSETS_REPO_NAME : name;\n const scanned = await scanDirectory(repoDir, repoName);\n const entries = scanned.filter((e) => e.kind === \"connector\");\n target.catalogEntries.push(...entries);\n } catch (err) {\n target.warnings.push({\n code: \"repo_unavailable\",\n name,\n message: `Failed to scan repository \"${name}\" at ${repoDir}: ${\n err instanceof Error ? err.message : String(err)\n }`,\n });\n }\n }\n\n // De-duplicate by (kind, name), keeping the first occurrence. Scan order is\n // declared sources → env override → bundled baseline, so an env-supplied\n // connector manifest overrides the bundled one and the bundled one fills the\n // rest (the override layer can refresh built-in manifests in place).\n const seen = new Set<string>();\n target.catalogEntries = target.catalogEntries.filter((e) => {\n const key = `${e.kind}:${e.name}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n\n // Derive implicit refs from skaile.yaml connectors.\n for (const c of config.connectors ?? []) {\n target.implicitRefs.push({ kind: \"connector\", name: c.driver, declarationId: c.id });\n }\n\n // Validate refs and aggregate npm deps.\n const requiredSet = new Set<string>();\n const optionalSet = new Set<string>();\n for (const ref of target.implicitRefs) {\n const entry = findCatalogEntry(target.catalogEntries, ref);\n if (!entry) {\n target.warnings.push({\n code: \"missing_driver\",\n declarationId: ref.declarationId,\n name: ref.name,\n message:\n `Unknown ${ref.kind} driver \"${ref.name}\" referenced by ${ref.kind} \"${ref.declarationId}\". ` +\n `Run \\`skaile ${ref.kind} catalog\\` to see available drivers, ` +\n `or declare a repository in skaile.yaml that provides this driver.`,\n });\n continue;\n }\n const npm = (entry.metadata?.npm_deps ?? {}) as { required?: string[]; optional?: string[] };\n for (const p of npm.required ?? []) requiredSet.add(p);\n for (const p of npm.optional ?? []) optionalSet.add(p);\n }\n target.requiredNpmDeps.required = [...requiredSet];\n target.requiredNpmDeps.optional = [...optionalSet];\n}\n\n/**\n * Build the effective `repositories` map: caller's declarations first, then the\n * implicit built-in `factory-assets` repos. Each {@link factoryAssetRoots} layer\n * becomes its own repo, the env override inserted **before** the bundled\n * baseline so its connector entries win on the first-match dedup downstream.\n * When the package cannot be located at all, a path-less sentinel under\n * {@link FACTORY_ASSETS_REPO_NAME} drives the `repo_unavailable` warning.\n */\nfunction buildEffectiveRepositories(\n declared: Record<string, SourceDeclaration> | undefined,\n): Record<string, SourceDeclaration> {\n const result: Record<string, SourceDeclaration> = { ...(declared ?? {}) };\n const roots = factoryAssetRoots();\n if (roots.length === 0) {\n // Surface as a warning during scan rather than throwing here — let the\n // caller decide whether factory-assets is required. resolveRepoDir() /\n // repoUnavailableMessage re-discover the failure and emit it.\n if (!result[FACTORY_ASSETS_REPO_NAME]) result[FACTORY_ASSETS_REPO_NAME] = { path: \"\" };\n return result;\n }\n // override-first when both layers exist, so the env root's entries are scanned\n // (and matched) ahead of the bundled baseline.\n const keys =\n roots.length > 1\n ? [FACTORY_ASSETS_OVERRIDE_REPO_NAME, FACTORY_ASSETS_REPO_NAME]\n : [FACTORY_ASSETS_REPO_NAME];\n roots.forEach((dir, i) => {\n const key = keys[i] ?? `${FACTORY_ASSETS_REPO_NAME}:${i}`;\n if (!result[key]) result[key] = { path: dir };\n });\n return result;\n}\n\n/**\n * Resolve a repository declaration to an on-disk directory. Order:\n * 1. Linked override (`.skaile/links.yaml`).\n * 2. Local `path` — relative to `projectDir`.\n * 3. Cloned URL repo at `.skaile/cache/sources/<name>/` (must already exist).\n *\n * Returns `null` when none of these resolve. Does not clone.\n *\n * **Async and deadline-bounded since #454.** Every candidate here is a\n * project-relative or operator-supplied path, so a `sources[].path` of\n * `workspace/my-assets` resolves onto the rclone FUSE mount — the same tree the\n * scan that follows walks. Probing it with `existsSync`/`lstatSync` would park\n * the `skaile serve` event loop *before* the (now async) scan ever ran, which\n * would leave the H2 fix meaningless on the very declaration that triggers it.\n * A probe that misses its deadline reads as \"unavailable\", which is what the\n * caller already does with an absent path — it becomes a `repo_unavailable`\n * warning rather than a stall.\n */\nasync function resolveRepoDir(\n name: string,\n decl: SourceDeclaration,\n projectDir: string,\n links: Record<string, string>,\n): Promise<string | null> {\n // 1. Linked override\n const linked = links[name];\n if (linked && (await pathExists(linked))) return linked;\n\n // 2. Local path\n if (decl.path) {\n const resolved = resolvePath(projectDir, decl.path);\n return (await pathExists(resolved)) ? resolved : null;\n }\n\n // 3. URL repo cloned to project's .skaile/cache/sources/<name> — the\n // project-local clone dir (often a symlink into the global cache, which\n // lives at getGlobalCacheDir()); NOT the global clone root itself.\n if (decl.url) {\n const projectDest = join(projectDir, \".skaile\", \"cache\", \"sources\", name);\n // One `lstat` answers both questions the pre-#454 `existsSync` + `lstatSync`\n // pair asked, and `lstat` (not `stat`) keeps the \"a symlink into the global\n // cache counts\" behaviour intact.\n const found = await tryWithFsDeadline(\n `lstat ${projectDest}`,\n async () => {\n await lstat(projectDest);\n return true;\n },\n false,\n );\n return found ? projectDest : null;\n }\n\n return null;\n}\n\n/** Deadline-bounded `existsSync` replacement — a wedged mount reads as absent. */\nfunction pathExists(path: string): Promise<boolean> {\n return tryWithFsDeadline(\n `stat ${path}`,\n async () => {\n await stat(path);\n return true;\n },\n false,\n );\n}\n\nfunction repoUnavailableMessage(name: string, decl: SourceDeclaration): string {\n if (name === FACTORY_ASSETS_REPO_NAME && !decl.path && !decl.url) {\n return (\n `Cannot resolve the built-in factory-assets. ` +\n `Set SKAILE_FACTORY_ASSETS_DIR or ensure @skaile/workspaces is installed.`\n );\n }\n if (decl.url) {\n return `Repository \"${name}\" (${decl.url}) is not available. Register it as a Library Source via \\`skaile source add\\`.`;\n }\n if (decl.path) {\n return `Repository \"${name}\" path not found: ${decl.path}`;\n }\n return `Repository \"${name}\" has neither url nor path.`;\n}\n\nfunction findCatalogEntry(\n entries: RuntimeCatalogEntry[],\n query: { kind?: \"connector\"; name: string },\n): RuntimeCatalogEntry | undefined {\n if (query.kind) {\n return entries.find((e) => e.kind === query.kind && e.name === query.name);\n }\n const matches = entries.filter((e) => e.name === query.name);\n if (matches.length === 1) return matches[0];\n // 0 or >1 with no kind — caller must disambiguate.\n return undefined;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../core/src/runtime-assets.ts"],"names":["resolvePath","require"],"mappings":";;;;;;;;AAsDA,SAAS,sBACP,OAAA,EACmC;AACnC,EAAA,MAAM,aAAa,iBAAA,EAAkB;AACrC,EAAA,MAAM,MAAyC,EAAC;AAChD,EAAA,KAAA,MAAW,CAAA,IAAK,OAAA,IAAW,EAAC,EAAG;AAC7B,IAAA,MAAM,GAAA,GAAM,cAAA,CAAe,CAAA,CAAE,GAAG,CAAA;AAChC,IAAA,IAAI,GAAA,CAAI,GAAG,CAAA,EAAG;AACd,IAAA,GAAA,CAAI,GAAG,CAAA,GAAI,EAAE,IAAA,EAAM,IAAA,CAAK,UAAA,EAAY,GAAG,CAAA,EAAG,GAAA,EAAK,CAAA,CAAE,GAAA,EAAK,MAAA,EAAQ,EAAE,GAAA,EAAI;AAAA,EACtE;AACA,EAAA,OAAO,GAAA;AACT;AAqDO,IAAM,wBAAA,GAA2B;AAMxC,IAAM,iCAAA,GAAoC,yBAAA;AAsC1C,eAAsB,qBAAqB,UAAA,EAAkD;AAC3F,EAAA,MAAM,MAAA,GAA8B;AAAA,IAClC,gBAAgB,EAAC;AAAA,IACjB,cAAc,EAAC;AAAA,IACf,iBAAiB,EAAE,QAAA,EAAU,EAAC,EAAG,QAAA,EAAU,EAAC,EAAE;AAAA,IAC9C,UAAU,EAAC;AAAA,IACX,SAAS,YAAY;AACnB,MAAA,MAAM,QAAA,CAAS,YAAY,MAAM,CAAA;AAAA,IACnC,CAAA;AAAA,IACA,WAAW,CAAC,KAAA,KAAU,gBAAA,CAAiB,MAAA,CAAO,gBAAgB,KAAK;AAAA,GACrE;AAEA,EAAA,MAAM,QAAA,CAAS,YAAY,MAAM,CAAA;AACjC,EAAA,OAAO,MAAA;AACT;AAmBO,SAAS,iBAAA,GAA8B;AAC5C,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,GAAA,CAAI,yBAAA,IAA6B,QAAQ,GAAA,CAAI,sBAAA;AAOpE,EAAA,IAAI,MAAA,IAAU,WAAW,MAAM,CAAA,QAAS,IAAA,CAAKA,OAAA,CAAY,MAAM,CAAC,CAAA;AAChE,EAAA,MAAM,OAAA,GAAU,yBAAyB,gBAAgB,CAAA;AACzD,EAAA,IAAI,OAAA,EAAS,KAAA,CAAM,IAAA,CAAK,OAAO,CAAA;AAC/B,EAAA,OAAO,CAAC,GAAG,IAAI,GAAA,CAAI,KAAK,CAAC,CAAA;AAC3B;AAYO,SAAS,wBAAA,GAAmC;AACjD,EAAA,MAAM,MAAM,8BAAA,EAA+B;AAC3C,EAAA,IAAI,KAAK,OAAO,GAAA;AAEhB,EAAA,MAAM,IAAI,KAAA;AAAA,IACR,CAAA,+LAAA;AAAA,GAIF;AACF;AAUO,SAAS,8BAAA,GAAgD;AAC9D,EAAA,OAAO,iBAAA,EAAkB,CAAE,CAAC,CAAA,IAAK,IAAA;AACnC;AAoBA,IAAI,0BAAA;AAEG,SAAS,4BAAA,GAA8C;AAC5D,EAAA,IAAI,0BAAA,KAA+B,QAAW,OAAO,0BAAA;AACrD,EAAA,0BAAA,GAA6B,4BAAA,EAA6B;AAC1D,EAAA,OAAO,0BAAA;AACT;AAEA,SAAS,4BAAA,GAA8C;AACrD,EAAA,IAAI;AACF,IAAA,MAAMC,QAAAA,GAAU,aAAA,CAAc,MAAA,CAAA,IAAA,CAAY,GAAG,CAAA;AAC7C,IAAA,OAAO,OAAA,CAAQA,QAAAA,CAAQ,OAAA,CAAQ,iCAAiC,CAAC,CAAA;AAAA,EACnE,CAAA,CAAA,MAAQ;AAAA,EAER;AACA,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACF,IAAA,GAAA,GAAM,OAAA,CAAQ,aAAA,CAAc,MAAA,CAAA,IAAA,CAAY,GAAG,CAAC,CAAA;AAAA,EAC9C,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,EAAG,CAAA,EAAA,EAAK;AAC1B,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,GAAA,EAAK,cAAc,CAAA;AACxC,IAAA,IAAI,UAAA,CAAW,OAAO,CAAA,EAAG;AACvB,MAAA,IAAI;AACF,QAAA,MAAM,MAAM,IAAA,CAAK,KAAA,CAAM,YAAA,CAAa,OAAA,EAAS,OAAO,CAAC,CAAA;AACrD,QAAA,IAAI,GAAA,CAAI,IAAA,KAAS,oBAAA,EAAsB,OAAO,GAAA;AAAA,MAChD,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF;AACA,IAAA,MAAM,MAAA,GAAS,QAAQ,GAAG,CAAA;AAC1B,IAAA,IAAI,WAAW,GAAA,EAAK;AACpB,IAAA,GAAA,GAAM,MAAA;AAAA,EACR;AACA,EAAA,OAAO,IAAA;AACT;AAiBO,SAAS,yBAAyB,MAAA,EAA+B;AACtE,EAAA,MAAM,OAAO,4BAAA,EAA6B;AAC1C,EAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,EAAA,KAAA,MAAW,IAAA,IAAQ,CAAC,IAAA,CAAK,IAAA,EAAM,MAAM,CAAA,EAAG,IAAA,CAAK,IAAA,EAAM,MAAA,EAAQ,MAAM,CAAC,CAAA,EAAG;AACnE,IAAA,IAAI,UAAA,CAAW,IAAI,CAAA,EAAG,OAAO,IAAA;AAAA,EAC/B;AACA,EAAA,OAAO,IAAA;AACT;AAIA,eAAe,QAAA,CAAS,YAAoB,MAAA,EAA4C;AACtF,EAAA,MAAA,CAAO,iBAAiB,EAAC;AACzB,EAAA,MAAA,CAAO,eAAe,EAAC;AACvB,EAAA,MAAA,CAAO,kBAAkB,EAAE,QAAA,EAAU,EAAC,EAAG,QAAA,EAAU,EAAC,EAAE;AACtD,EAAA,MAAA,CAAO,WAAW,EAAC;AAEnB,EAAA,MAAM,MAAA,GAAS,yBAAyB,UAAU,CAAA;AAGlD,EAAA,MAAM,YAAA,GAAe,0BAAA,CAA2B,qBAAA,CAAsB,MAAA,CAAO,OAAO,CAAC,CAAA;AACrF,EAAA,MAAM,KAAA,GAAQ,UAAU,UAAU,CAAA;AAGlC,EAAA,KAAA,MAAW,CAAC,IAAA,EAAM,IAAI,KAAK,MAAA,CAAO,OAAA,CAAQ,YAAY,CAAA,EAAG;AACvD,IAAA,MAAM,UAAU,MAAM,cAAA,CAAe,IAAA,EAAM,IAAA,EAAM,YAAY,KAAK,CAAA;AAClE,IAAA,IAAI,CAAC,OAAA,EAAS;AACZ,MAAA,MAAA,CAAO,SAAS,IAAA,CAAK;AAAA,QACnB,IAAA,EAAM,kBAAA;AAAA,QACN,IAAA;AAAA,QACA,OAAA,EAAS,sBAAA,CAAuB,IAAA,EAAM,IAAI;AAAA,OAC3C,CAAA;AACD,MAAA;AAAA,IACF;AACA,IAAA,IAAI;AAGF,MAAA,MAAM,QAAA,GAAW,IAAA,KAAS,iCAAA,GAAoC,wBAAA,GAA2B,IAAA;AACzF,MAAA,MAAM,OAAA,GAAU,MAAM,aAAA,CAAc,OAAA,EAAS,QAAQ,CAAA;AACrD,MAAA,MAAM,UAAU,OAAA,CAAQ,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,SAAS,WAAW,CAAA;AAC5D,MAAA,MAAA,CAAO,cAAA,CAAe,IAAA,CAAK,GAAG,OAAO,CAAA;AAAA,IACvC,SAAS,GAAA,EAAK;AACZ,MAAA,MAAA,CAAO,SAAS,IAAA,CAAK;AAAA,QACnB,IAAA,EAAM,kBAAA;AAAA,QACN,IAAA;AAAA,QACA,OAAA,EAAS,CAAA,2BAAA,EAA8B,IAAI,CAAA,KAAA,EAAQ,OAAO,CAAA,EAAA,EACxD,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,MAAA,CAAO,GAAG,CACjD,CAAA;AAAA,OACD,CAAA;AAAA,IACH;AAAA,EACF;AAMA,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAY;AAC7B,EAAA,MAAA,CAAO,cAAA,GAAiB,MAAA,CAAO,cAAA,CAAe,MAAA,CAAO,CAAC,CAAA,KAAM;AAC1D,IAAA,MAAM,MAAM,CAAA,EAAG,CAAA,CAAE,IAAI,CAAA,CAAA,EAAI,EAAE,IAAI,CAAA,CAAA;AAC/B,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA,EAAG,OAAO,KAAA;AAC1B,IAAA,IAAA,CAAK,IAAI,GAAG,CAAA;AACZ,IAAA,OAAO,IAAA;AAAA,EACT,CAAC,CAAA;AAGD,EAAA,KAAA,MAAW,CAAA,IAAK,MAAA,CAAO,UAAA,IAAc,EAAC,EAAG;AACvC,IAAA,MAAA,CAAO,YAAA,CAAa,IAAA,CAAK,EAAE,IAAA,EAAM,WAAA,EAAa,IAAA,EAAM,CAAA,CAAE,MAAA,EAAQ,aAAA,EAAe,CAAA,CAAE,EAAA,EAAI,CAAA;AAAA,EACrF;AAGA,EAAA,MAAM,WAAA,uBAAkB,GAAA,EAAY;AACpC,EAAA,MAAM,WAAA,uBAAkB,GAAA,EAAY;AACpC,EAAA,KAAA,MAAW,GAAA,IAAO,OAAO,YAAA,EAAc;AACrC,IAAA,MAAM,KAAA,GAAQ,gBAAA,CAAiB,MAAA,CAAO,cAAA,EAAgB,GAAG,CAAA;AACzD,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA,MAAA,CAAO,SAAS,IAAA,CAAK;AAAA,QACnB,IAAA,EAAM,gBAAA;AAAA,QACN,eAAe,GAAA,CAAI,aAAA;AAAA,QACnB,MAAM,GAAA,CAAI,IAAA;AAAA,QACV,OAAA,EACE,CAAA,QAAA,EAAW,GAAA,CAAI,IAAI,YAAY,GAAA,CAAI,IAAI,CAAA,gBAAA,EAAmB,GAAA,CAAI,IAAI,CAAA,EAAA,EAAK,GAAA,CAAI,aAAa,CAAA,gBAAA,EACxE,IAAI,IAAI,CAAA,sGAAA;AAAA,OAE3B,CAAA;AACD,MAAA;AAAA,IACF;AACA,IAAA,MAAM,GAAA,GAAO,KAAA,CAAM,QAAA,EAAU,QAAA,IAAY,EAAC;AAC1C,IAAA,KAAA,MAAW,KAAK,GAAA,CAAI,QAAA,IAAY,EAAC,EAAG,WAAA,CAAY,IAAI,CAAC,CAAA;AACrD,IAAA,KAAA,MAAW,KAAK,GAAA,CAAI,QAAA,IAAY,EAAC,EAAG,WAAA,CAAY,IAAI,CAAC,CAAA;AAAA,EACvD;AACA,EAAA,MAAA,CAAO,eAAA,CAAgB,QAAA,GAAW,CAAC,GAAG,WAAW,CAAA;AACjD,EAAA,MAAA,CAAO,eAAA,CAAgB,QAAA,GAAW,CAAC,GAAG,WAAW,CAAA;AACnD;AAUA,SAAS,2BACP,QAAA,EACmC;AACnC,EAAA,MAAM,MAAA,GAA4C,EAAE,GAAI,QAAA,IAAY,EAAC,EAAG;AACxE,EAAA,MAAM,QAAQ,iBAAA,EAAkB;AAChC,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AAItB,IAAA,IAAI,CAAC,OAAO,wBAAwB,CAAA,SAAU,wBAAwB,CAAA,GAAI,EAAE,IAAA,EAAM,EAAA,EAAG;AACrF,IAAA,OAAO,MAAA;AAAA,EACT;AAGA,EAAA,MAAM,IAAA,GACJ,MAAM,MAAA,GAAS,CAAA,GACX,CAAC,iCAAA,EAAmC,wBAAwB,CAAA,GAC5D,CAAC,wBAAwB,CAAA;AAC/B,EAAA,KAAA,CAAM,OAAA,CAAQ,CAAC,GAAA,EAAK,CAAA,KAAM;AACxB,IAAA,MAAM,MAAM,IAAA,CAAK,CAAC,KAAK,CAAA,EAAG,wBAAwB,IAAI,CAAC,CAAA,CAAA;AACvD,IAAA,IAAI,CAAC,OAAO,GAAG,CAAA,SAAU,GAAG,CAAA,GAAI,EAAE,IAAA,EAAM,GAAA,EAAI;AAAA,EAC9C,CAAC,CAAA;AACD,EAAA,OAAO,MAAA;AACT;AAoBA,eAAe,cAAA,CACb,IAAA,EACA,IAAA,EACA,UAAA,EACA,KAAA,EACwB;AAExB,EAAA,MAAM,MAAA,GAAS,MAAM,IAAI,CAAA;AACzB,EAAA,IAAI,MAAA,IAAW,MAAM,UAAA,CAAW,MAAM,GAAI,OAAO,MAAA;AAGjD,EAAA,IAAI,KAAK,IAAA,EAAM;AACb,IAAA,MAAM,QAAA,GAAWD,OAAA,CAAY,UAAA,EAAY,IAAA,CAAK,IAAI,CAAA;AAClD,IAAA,OAAQ,MAAM,UAAA,CAAW,QAAQ,CAAA,GAAK,QAAA,GAAW,IAAA;AAAA,EACnD;AAKA,EAAA,IAAI,KAAK,GAAA,EAAK;AACZ,IAAA,MAAM,cAAc,IAAA,CAAK,UAAA,EAAY,SAAA,EAAW,OAAA,EAAS,WAAW,IAAI,CAAA;AAIxE,IAAA,MAAM,QAAQ,MAAM,iBAAA;AAAA,MAClB,SAAS,WAAW,CAAA,CAAA;AAAA,MACpB,YAAY;AACV,QAAA,MAAM,MAAM,WAAW,CAAA;AACvB,QAAA,OAAO,IAAA;AAAA,MACT,CAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,OAAO,QAAQ,WAAA,GAAc,IAAA;AAAA,EAC/B;AAEA,EAAA,OAAO,IAAA;AACT;AAGA,SAAS,WAAW,IAAA,EAAgC;AAClD,EAAA,OAAO,iBAAA;AAAA,IACL,QAAQ,IAAI,CAAA,CAAA;AAAA,IACZ,YAAY;AACV,MAAA,MAAM,KAAK,IAAI,CAAA;AACf,MAAA,OAAO,IAAA;AAAA,IACT,CAAA;AAAA,IACA;AAAA,GACF;AACF;AAEA,SAAS,sBAAA,CAAuB,MAAc,IAAA,EAAiC;AAC7E,EAAA,IAAI,SAAS,wBAAA,IAA4B,CAAC,KAAK,IAAA,IAAQ,CAAC,KAAK,GAAA,EAAK;AAChE,IAAA,OACE,CAAA,oHAAA,CAAA;AAAA,EAGJ;AACA,EAAA,IAAI,KAAK,GAAA,EAAK;AACZ,IAAA,OAAO,CAAA,YAAA,EAAe,IAAI,CAAA,GAAA,EAAM,IAAA,CAAK,GAAG,CAAA,8EAAA,CAAA;AAAA,EAC1C;AACA,EAAA,IAAI,KAAK,IAAA,EAAM;AACb,IAAA,OAAO,CAAA,YAAA,EAAe,IAAI,CAAA,kBAAA,EAAqB,IAAA,CAAK,IAAI,CAAA,CAAA;AAAA,EAC1D;AACA,EAAA,OAAO,eAAe,IAAI,CAAA,2BAAA,CAAA;AAC5B;AAEA,SAAS,gBAAA,CACP,SACA,KAAA,EACiC;AACjC,EAAA,IAAI,MAAM,IAAA,EAAM;AACd,IAAA,OAAO,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,KAAS,KAAA,CAAM,IAAA,IAAQ,CAAA,CAAE,IAAA,KAAS,KAAA,CAAM,IAAI,CAAA;AAAA,EAC3E;AACA,EAAA,MAAM,OAAA,GAAU,QAAQ,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,IAAA,KAAS,MAAM,IAAI,CAAA;AAC3D,EAAA,IAAI,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG,OAAO,QAAQ,CAAC,CAAA;AAE1C,EAAA,OAAO,MAAA;AACT","file":"chunk-SH572OBN.js","sourcesContent":["/**\n * Runtime asset resolution — read `skaile.yaml`, scan all declared repositories\n * (including the built-in `factory-assets/` directory as an implicit default),\n * and produce a unified view of connector catalog entries plus the implicit refs\n * that the `skaile.yaml` `connectors:` section adds to the dependency graph.\n *\n * This module is the single source of truth for \"which connectors does this\n * project see at runtime, and where do their implementations live on disk\".\n * Both the runner (serve, REPL, flow) and the platform's mid-session\n * `add_resource` flow consume `RuntimeAssetsResult.catalogEntries` and pass\n * it into `ConnectorManager` for catalog-based resolution.\n *\n * `factory-assets/` is the single first-party content tree (built-in connectors\n * + first-party skills + bundles) shipped inside the `@skaile/workspaces`\n * package — not a standalone package.\n *\n * It resolves to an **ordered list of roots** ({@link factoryAssetRoots}), not a\n * single dir. The bundled tree is always the baseline; an optional\n * `SKAILE_FACTORY_ASSETS_DIR` (legacy: `SKAILE_BASE_ASSETS_DIR`) is layered\n * **in front** as an additive override source — the agent container points it at\n * `/app/factory-assets/` (or a bind-mounted host dir) to ship updated skills /\n * flows / bundles / connector manifests without rebuilding the image. The two\n * roots resolve uniformly across every consumer (connector catalog scan, skill /\n * flow / completion discovery, the asset-manager factory source):\n * 1. `SKAILE_FACTORY_ASSETS_DIR` env dir, when set and existing (override layer).\n * 2. the bundled tree via {@link resolvePackagedAssetsDir} — the in-repo source\n * `packages/workspaces/factory-assets/` during dev, else the published\n * `dist/factory-assets/` after install (always-present baseline).\n *\n * Override semantics are **env-first**: on a name conflict the env root wins and\n * the bundled root fills the rest. Connector *code* still loads via the package's\n * static `exports` map, so the env root can override/add skills, flows, bundles,\n * and connector **manifests/metadata**, but cannot ship a new executable\n * connector — its `.js` is not on the package's import graph.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { lstat, stat } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport { dirname, join, resolve as resolvePath } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { tryWithFsDeadline } from \"./fs-deadline.js\";\nimport { scanDirectory } from \"./manifest.js\";\nimport type { CatalogEntry } from \"./models.js\";\nimport { getGlobalCacheDir, readLinks, sourceCacheKey } from \"./repo-manager.js\";\nimport type { SourceDeclaration, SourceEntry } from \"./workspace-config.js\";\nimport { resolveSkWorkspaceConfig } from \"./workspace-config.js\";\n\n/**\n * Map declared `sources[]` to internal `SourceDeclaration`s keyed by the\n * collision-free {@link sourceCacheKey} (`<host>/<owner>/<repo>`), pointing at\n * the unified machine-cache clone path (`getGlobalCacheDir()/<key>/`). Keyed by\n * the same function every other cache writer/reader uses so the path resolves.\n */\nfunction sourcesToDeclarations(\n sources: SourceEntry[] | undefined,\n): Record<string, SourceDeclaration> {\n const sourcesDir = getGlobalCacheDir();\n const out: Record<string, SourceDeclaration> = {};\n for (const s of sources ?? []) {\n const key = sourceCacheKey(s.url);\n if (out[key]) continue;\n out[key] = { path: join(sourcesDir, key), url: s.url, branch: s.pin };\n }\n return out;\n}\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\n/**\n * Catalog entry filtered to mount/connector kinds. Same shape as `CatalogEntry`.\n * @docLink packages/core/concepts#runtime-catalog-entry\n */\nexport type RuntimeCatalogEntry = CatalogEntry;\n\n/**\n * Implicit catalog reference derived from a `connectors:` declaration in `skaile.yaml`.\n * Each connector driver becomes an implicit ref that must be resolved in the catalog.\n * @docLink packages/core/concepts#runtime-asset-ref\n */\nexport interface RuntimeAssetRef {\n kind: \"connector\";\n /** Driver name — matches `RuntimeCatalogEntry.name`. */\n name: string;\n /** Source declaration id from `skaile.yaml`. */\n declarationId: string;\n}\n\n/**\n * Aggregated npm packages required by all resolved mount/connector adapters.\n * Populated from `metadata.npm_deps` in each matched catalog entry.\n * @docLink packages/core/concepts#runtime-npm-deps\n */\nexport interface RuntimeNpmDeps {\n required: string[];\n optional: string[];\n}\n\n/**\n * Non-fatal warning emitted during `resolveRuntimeAssets` when a repo is unavailable\n * or a driver is not found in any catalog.\n * @docLink packages/core/concepts#runtime-asset-warning\n */\nexport interface RuntimeAssetWarning {\n /** Stable code for filtering / structured logging. */\n code: \"missing_driver\" | \"repo_unavailable\" | \"invalid_repo_decl\";\n message: string;\n /** Declaration id when applicable. */\n declarationId?: string;\n /** Driver / repository name when applicable. */\n name?: string;\n}\n\n/**\n * Repository name used for the implicit built-in `factory-assets` catalog entry\n * (the in-package connector tree).\n * @docLink packages/core/concepts#factory-assets-repo-name\n */\nexport const FACTORY_ASSETS_REPO_NAME = \"factory-assets\";\n\n/**\n * Repository name for the optional `SKAILE_FACTORY_ASSETS_DIR` override layer,\n * scanned ahead of (and overriding) the bundled {@link FACTORY_ASSETS_REPO_NAME}.\n */\nconst FACTORY_ASSETS_OVERRIDE_REPO_NAME = \"factory-assets:override\";\n\n/**\n * Result of `resolveRuntimeAssets`.\n * The same object is mutated in place by `refresh()`, allowing callers to hold\n * a stable reference and observe updates after a new repository is cloned or\n * a driver is installed mid-session.\n * @docLink packages/core/concepts#runtime-assets-result\n */\nexport interface RuntimeAssetsResult {\n catalogEntries: RuntimeCatalogEntry[];\n implicitRefs: RuntimeAssetRef[];\n requiredNpmDeps: RuntimeNpmDeps;\n warnings: RuntimeAssetWarning[];\n /** Re-scan repositories and re-derive implicit refs. Mutates in place. */\n refresh(): Promise<void>;\n /**\n * Catalog lookup. When `kind` is omitted and multiple entries share the\n * `name`, returns `undefined` (caller must disambiguate).\n */\n findEntry(query: { kind?: \"connector\"; name: string }): RuntimeCatalogEntry | undefined;\n}\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Resolve all runtime assets visible to a project by scanning declared repositories.\n *\n * Reads `skaile.yaml`, scans every declared repository (plus the implicit\n * built-in `factory-assets` repo), and derives implicit refs from `mounts:` /\n * `connectors:` declarations. Does not clone or install anything — purely a\n * read-only scan of what is already on disk. URL-only repositories that have\n * not been cloned yet are reported as `repo_unavailable` warnings.\n *\n * @param projectDir - Absolute path to the project workspace root\n * @returns `RuntimeAssetsResult` with catalog entries, implicit refs, npm deps, and warnings\n * @docLink packages/core/concepts#resolve-runtime-assets\n */\nexport async function resolveRuntimeAssets(projectDir: string): Promise<RuntimeAssetsResult> {\n const result: RuntimeAssetsResult = {\n catalogEntries: [],\n implicitRefs: [],\n requiredNpmDeps: { required: [], optional: [] },\n warnings: [],\n refresh: async () => {\n await populate(projectDir, result);\n },\n findEntry: (query) => findCatalogEntry(result.catalogEntries, query),\n };\n\n await populate(projectDir, result);\n return result;\n}\n\n/**\n * Resolve the ordered list of on-disk roots for the built-in `factory-assets`\n * tree (built-in connectors + first-party skills + bundles). This is the single\n * shared resolver every consumer goes through, so the env override and the\n * bundled baseline are honoured uniformly.\n *\n * Order (env-first = override-wins):\n * 1. `SKAILE_FACTORY_ASSETS_DIR` env dir (legacy: `SKAILE_BASE_ASSETS_DIR`),\n * when set and existing — an additive override layer.\n * 2. {@link resolvePackagedAssetsDir} — the bundled tree (in-repo source in dev,\n * `dist/factory-assets/` after install). Always-present baseline.\n *\n * Returns `[]` only when the package cannot be located at all. De-duplicated, so\n * pointing the env var at the bundled dir collapses to one root.\n *\n * @docLink packages/core/concepts#resolve-factory-assets-root\n */\nexport function factoryAssetRoots(): string[] {\n const roots: string[] = [];\n const envDir = process.env.SKAILE_FACTORY_ASSETS_DIR ?? process.env.SKAILE_BASE_ASSETS_DIR;\n // Deliberately still synchronous after #454: both candidates are\n // container-local (the image's `/app/factory-assets/`, or the installed\n // package tree resolved by `resolvePackagedAssetsDir`), never the FUSE\n // workspace mount. The mount-reachable probes on this module's scan path —\n // the project-relative `sources[].path` candidates in `resolveRepoDir` — are\n // async and deadline-bounded.\n if (envDir && existsSync(envDir)) roots.push(resolvePath(envDir));\n const bundled = resolvePackagedAssetsDir(\"factory-assets\");\n if (bundled) roots.push(bundled);\n return [...new Set(roots)];\n}\n\n/**\n * Resolve the primary on-disk root of the `factory-assets` tree — the first of\n * {@link factoryAssetRoots} (the env override when set, else the bundled tree).\n * Prefer {@link factoryAssetRoots} when you need to scan every layer; this\n * single-dir form is for callers that want one canonical path.\n *\n * @returns Absolute path to the highest-precedence `factory-assets` directory\n * @throws When no root can be located\n * @docLink packages/core/concepts#resolve-factory-assets-root\n */\nexport function resolveFactoryAssetsRoot(): string {\n const hit = resolveFactoryAssetsRootOrNull();\n if (hit) return hit;\n\n throw new Error(\n `Cannot resolve the factory-assets directory. ` +\n `Set SKAILE_FACTORY_ASSETS_DIR to the on-disk path, ` +\n `ensure @skaile/workspaces is installed, ` +\n `or run from within the @skaile/workspaces package tree.`,\n );\n}\n\n/**\n * Non-throwing variant of {@link resolveFactoryAssetsRoot}: the same\n * env-then-packaged resolution tiers, returning `null` instead of throwing when\n * none locate the directory. Callers that treat a missing factory tree as a\n * soft \"not present\" (e.g. the asset-manager's implicit-source injection) MUST\n * use this so they honour the `SKAILE_FACTORY_ASSETS_DIR` container override\n * identically to the runtime path.\n */\nexport function resolveFactoryAssetsRootOrNull(): string | null {\n return factoryAssetRoots()[0] ?? null;\n}\n\n/**\n * Resolve the `@skaile/workspaces` package root — the directory containing its\n * `package.json`. Tries `require.resolve` first (works when installed as a\n * dependency *and* in-repo via the self-reference), then walks upward from this\n * module looking for a `package.json` whose `name` is `@skaile/workspaces`\n * (bounded to 8 levels). Returns `null` when neither locates it.\n *\n * The single source of truth for finding content shipped inside the package —\n * the unified `factory-assets/` tree (built-in connectors + first-party skills\n * + bundles) resolves through {@link resolvePackagedAssetsDir} on top of this.\n *\n * Memoized: the package location is immutable for the process lifetime, but\n * this sits on the CLI hot path (every `findSkills` / flow / completion call\n * funnels through here), so the `require.resolve` + upward `package.json` walk\n * runs once. `undefined` = not yet computed.\n *\n * @docLink packages/core/concepts#resolve-factory-assets-root\n */\nlet workspacesPackageRootCache: string | null | undefined;\n\nexport function resolveWorkspacesPackageRoot(): string | null {\n if (workspacesPackageRootCache !== undefined) return workspacesPackageRootCache;\n workspacesPackageRootCache = computeWorkspacesPackageRoot();\n return workspacesPackageRootCache;\n}\n\nfunction computeWorkspacesPackageRoot(): string | null {\n try {\n const require = createRequire(import.meta.url);\n return dirname(require.resolve(\"@skaile/workspaces/package.json\"));\n } catch {\n // Fall through to the workspace walk.\n }\n let dir: string;\n try {\n dir = dirname(fileURLToPath(import.meta.url));\n } catch {\n return null;\n }\n for (let i = 0; i < 8; i++) {\n const pkgPath = join(dir, \"package.json\");\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as { name?: string };\n if (pkg.name === \"@skaile/workspaces\") return dir;\n } catch {\n // Ignore malformed package.json and keep walking.\n }\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\n/**\n * Locate a content-asset directory inside the package. Prefers the in-repo\n * **source** dir `<pkgRoot>/<subdir>` when present — in a dev checkout it is the\n * full tree (e.g. `factory-assets/` keeps the connector `.ts` entry files that\n * `dist/` does not) — then the published `dist/<subdir>` copy (what\n * `files: [\"dist\"]` ships, the only one present after `npm i`). Returns `null`\n * when neither exists.\n *\n * `factory-assets/` resolves to the source tree in dev (code + skills + bundles)\n * and to `dist/factory-assets` post-install (compiled connectors + copied\n * manifests/skills/bundles).\n *\n * @param subdir - `\"factory-assets\"` | …\n * @docLink packages/core/concepts#resolve-factory-assets-root\n */\nexport function resolvePackagedAssetsDir(subdir: string): string | null {\n const root = resolveWorkspacesPackageRoot();\n if (!root) return null;\n for (const cand of [join(root, subdir), join(root, \"dist\", subdir)]) {\n if (existsSync(cand)) return cand;\n }\n return null;\n}\n\n// ─── Internals ────────────────────────────────────────────────────────────────\n\nasync function populate(projectDir: string, target: RuntimeAssetsResult): Promise<void> {\n target.catalogEntries = [];\n target.implicitRefs = [];\n target.requiredNpmDeps = { required: [], optional: [] };\n target.warnings = [];\n\n const config = resolveSkWorkspaceConfig(projectDir);\n // Connector catalog scan runs over the project's declared sources[] (resolved\n // to their machine-cache clone paths) plus the implicit factory-assets repo.\n const repositories = buildEffectiveRepositories(sourcesToDeclarations(config.sources));\n const links = readLinks(projectDir);\n\n // Scan each repository for connector entries.\n for (const [name, decl] of Object.entries(repositories)) {\n const repoDir = await resolveRepoDir(name, decl, projectDir, links);\n if (!repoDir) {\n target.warnings.push({\n code: \"repo_unavailable\",\n name,\n message: repoUnavailableMessage(name, decl),\n });\n continue;\n }\n try {\n // Both factory layers carry the same `factory-assets` provenance — the\n // override repo is an internal scan-order device, not a distinct source.\n const repoName = name === FACTORY_ASSETS_OVERRIDE_REPO_NAME ? FACTORY_ASSETS_REPO_NAME : name;\n const scanned = await scanDirectory(repoDir, repoName);\n const entries = scanned.filter((e) => e.kind === \"connector\");\n target.catalogEntries.push(...entries);\n } catch (err) {\n target.warnings.push({\n code: \"repo_unavailable\",\n name,\n message: `Failed to scan repository \"${name}\" at ${repoDir}: ${\n err instanceof Error ? err.message : String(err)\n }`,\n });\n }\n }\n\n // De-duplicate by (kind, name), keeping the first occurrence. Scan order is\n // declared sources → env override → bundled baseline, so an env-supplied\n // connector manifest overrides the bundled one and the bundled one fills the\n // rest (the override layer can refresh built-in manifests in place).\n const seen = new Set<string>();\n target.catalogEntries = target.catalogEntries.filter((e) => {\n const key = `${e.kind}:${e.name}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n\n // Derive implicit refs from skaile.yaml connectors.\n for (const c of config.connectors ?? []) {\n target.implicitRefs.push({ kind: \"connector\", name: c.driver, declarationId: c.id });\n }\n\n // Validate refs and aggregate npm deps.\n const requiredSet = new Set<string>();\n const optionalSet = new Set<string>();\n for (const ref of target.implicitRefs) {\n const entry = findCatalogEntry(target.catalogEntries, ref);\n if (!entry) {\n target.warnings.push({\n code: \"missing_driver\",\n declarationId: ref.declarationId,\n name: ref.name,\n message:\n `Unknown ${ref.kind} driver \"${ref.name}\" referenced by ${ref.kind} \"${ref.declarationId}\". ` +\n `Run \\`skaile ${ref.kind} catalog\\` to see available drivers, ` +\n `or declare a repository in skaile.yaml that provides this driver.`,\n });\n continue;\n }\n const npm = (entry.metadata?.npm_deps ?? {}) as { required?: string[]; optional?: string[] };\n for (const p of npm.required ?? []) requiredSet.add(p);\n for (const p of npm.optional ?? []) optionalSet.add(p);\n }\n target.requiredNpmDeps.required = [...requiredSet];\n target.requiredNpmDeps.optional = [...optionalSet];\n}\n\n/**\n * Build the effective `repositories` map: caller's declarations first, then the\n * implicit built-in `factory-assets` repos. Each {@link factoryAssetRoots} layer\n * becomes its own repo, the env override inserted **before** the bundled\n * baseline so its connector entries win on the first-match dedup downstream.\n * When the package cannot be located at all, a path-less sentinel under\n * {@link FACTORY_ASSETS_REPO_NAME} drives the `repo_unavailable` warning.\n */\nfunction buildEffectiveRepositories(\n declared: Record<string, SourceDeclaration> | undefined,\n): Record<string, SourceDeclaration> {\n const result: Record<string, SourceDeclaration> = { ...(declared ?? {}) };\n const roots = factoryAssetRoots();\n if (roots.length === 0) {\n // Surface as a warning during scan rather than throwing here — let the\n // caller decide whether factory-assets is required. resolveRepoDir() /\n // repoUnavailableMessage re-discover the failure and emit it.\n if (!result[FACTORY_ASSETS_REPO_NAME]) result[FACTORY_ASSETS_REPO_NAME] = { path: \"\" };\n return result;\n }\n // override-first when both layers exist, so the env root's entries are scanned\n // (and matched) ahead of the bundled baseline.\n const keys =\n roots.length > 1\n ? [FACTORY_ASSETS_OVERRIDE_REPO_NAME, FACTORY_ASSETS_REPO_NAME]\n : [FACTORY_ASSETS_REPO_NAME];\n roots.forEach((dir, i) => {\n const key = keys[i] ?? `${FACTORY_ASSETS_REPO_NAME}:${i}`;\n if (!result[key]) result[key] = { path: dir };\n });\n return result;\n}\n\n/**\n * Resolve a repository declaration to an on-disk directory. Order:\n * 1. Linked override (`.skaile/links.yaml`).\n * 2. Local `path` — relative to `projectDir`.\n * 3. Cloned URL repo at `.skaile/cache/sources/<name>/` (must already exist).\n *\n * Returns `null` when none of these resolve. Does not clone.\n *\n * **Async and deadline-bounded since #454.** Every candidate here is a\n * project-relative or operator-supplied path, so a `sources[].path` of\n * `workspace/my-assets` resolves onto the rclone FUSE mount — the same tree the\n * scan that follows walks. Probing it with `existsSync`/`lstatSync` would park\n * the `skaile serve` event loop *before* the (now async) scan ever ran, which\n * would leave the H2 fix meaningless on the very declaration that triggers it.\n * A probe that misses its deadline reads as \"unavailable\", which is what the\n * caller already does with an absent path — it becomes a `repo_unavailable`\n * warning rather than a stall.\n */\nasync function resolveRepoDir(\n name: string,\n decl: SourceDeclaration,\n projectDir: string,\n links: Record<string, string>,\n): Promise<string | null> {\n // 1. Linked override\n const linked = links[name];\n if (linked && (await pathExists(linked))) return linked;\n\n // 2. Local path\n if (decl.path) {\n const resolved = resolvePath(projectDir, decl.path);\n return (await pathExists(resolved)) ? resolved : null;\n }\n\n // 3. URL repo cloned to project's .skaile/cache/sources/<name> — the\n // project-local clone dir (often a symlink into the global cache, which\n // lives at getGlobalCacheDir()); NOT the global clone root itself.\n if (decl.url) {\n const projectDest = join(projectDir, \".skaile\", \"cache\", \"sources\", name);\n // One `lstat` answers both questions the pre-#454 `existsSync` + `lstatSync`\n // pair asked, and `lstat` (not `stat`) keeps the \"a symlink into the global\n // cache counts\" behaviour intact.\n const found = await tryWithFsDeadline(\n `lstat ${projectDest}`,\n async () => {\n await lstat(projectDest);\n return true;\n },\n false,\n );\n return found ? projectDest : null;\n }\n\n return null;\n}\n\n/** Deadline-bounded `existsSync` replacement — a wedged mount reads as absent. */\nfunction pathExists(path: string): Promise<boolean> {\n return tryWithFsDeadline(\n `stat ${path}`,\n async () => {\n await stat(path);\n return true;\n },\n false,\n );\n}\n\nfunction repoUnavailableMessage(name: string, decl: SourceDeclaration): string {\n if (name === FACTORY_ASSETS_REPO_NAME && !decl.path && !decl.url) {\n return (\n `Cannot resolve the built-in factory-assets. ` +\n `Set SKAILE_FACTORY_ASSETS_DIR or ensure @skaile/workspaces is installed.`\n );\n }\n if (decl.url) {\n return `Repository \"${name}\" (${decl.url}) is not available. Register it as a Library Source via \\`skaile source add\\`.`;\n }\n if (decl.path) {\n return `Repository \"${name}\" path not found: ${decl.path}`;\n }\n return `Repository \"${name}\" has neither url nor path.`;\n}\n\nfunction findCatalogEntry(\n entries: RuntimeCatalogEntry[],\n query: { kind?: \"connector\"; name: string },\n): RuntimeCatalogEntry | undefined {\n if (query.kind) {\n return entries.find((e) => e.kind === query.kind && e.name === query.name);\n }\n const matches = entries.filter((e) => e.name === query.name);\n if (matches.length === 1) return matches[0];\n // 0 or >1 with no kind — caller must disambiguate.\n return undefined;\n}\n"]}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { deployAll, removeAsset, createScaffold } from './chunk-
|
|
3
|
-
import { writeLock, buildLockFile, readLock, verifyLock, extractForPatch, generatePatch, savePatch, applyPatch } from './chunk-
|
|
1
|
+
import { getStoreManifestsDir } from './chunk-OCLCDB7G.js';
|
|
2
|
+
import { deployAll, removeAsset, createScaffold } from './chunk-O7WKKINT.js';
|
|
3
|
+
import { resolveLibraryDir, writeLock, buildLockFile, readLock, verifyLock, extractForPatch, generatePatch, savePatch, applyPatch } from './chunk-AZPXCHDK.js';
|
|
4
4
|
import { deployedBase, isDeployed, deployedDir } from './chunk-F3HNW354.js';
|
|
5
|
-
import { resolveRuntimeAssets, factoryAssetRoots } from './chunk-
|
|
6
|
-
import { loadMcpServerDeclarations, globalSkaileDir, resolveGlobalBackends, globalCacheRoot, migrateLegacyDir, resolveGlobalSkWorkspaceConfig, resolveSkWorkspaceConfig, getGlobalCacheDir, sourceCacheKey, getRepoCommit, coerceVersion, matchPin, resolveAll, buildProvenanceIndex, ensureRepo, sourceShortName, scanRepo, SKAILE_YAML_DEFAULT, checkRepoStatus, resolveAsset, readLinks, storeManifestSlug } from './chunk-
|
|
7
|
-
import { scanDirectory, parseRequires } from './chunk-
|
|
5
|
+
import { resolveRuntimeAssets, factoryAssetRoots } from './chunk-SH572OBN.js';
|
|
6
|
+
import { loadMcpServerDeclarations, globalSkaileDir, resolveGlobalBackends, globalCacheRoot, migrateLegacyDir, resolveGlobalSkWorkspaceConfig, resolveSkWorkspaceConfig, getGlobalCacheDir, sourceCacheKey, getRepoCommit, coerceVersion, matchPin, resolveAll, buildProvenanceIndex, ensureRepo, sourceShortName, scanRepo, SKAILE_YAML_DEFAULT, checkRepoStatus, resolveAsset, readLinks, storeManifestSlug } from './chunk-IP3GXHOB.js';
|
|
7
|
+
import { scanDirectory, parseRequires } from './chunk-VQ4P7UYE.js';
|
|
8
8
|
import { parseAssetRef, slugifyAssetName, assetRefToStr } from './chunk-GEEW6SY2.js';
|
|
9
9
|
import { appendHistory, getRecentHistory, clearHistory } from './chunk-KTBKW2FI.js';
|
|
10
10
|
import { commitChanges } from './chunk-UQ6LFBPZ.js';
|
|
@@ -2085,5 +2085,5 @@ var AssetManager = class {
|
|
|
2085
2085
|
};
|
|
2086
2086
|
|
|
2087
2087
|
export { AssetManager, FACTORY_SOURCE_URL, MissingManifestError, NON_DEPLOYABLE_KINDS, normalizeRepoUrl, parseCanonicalLockKey, parseRefTolerant, renderMcpServerConfig, softDepName };
|
|
2088
|
-
//# sourceMappingURL=chunk-
|
|
2089
|
-
//# sourceMappingURL=chunk-
|
|
2088
|
+
//# sourceMappingURL=chunk-UEH5XAQR.js.map
|
|
2089
|
+
//# sourceMappingURL=chunk-UEH5XAQR.js.map
|