@skaile/workspaces 0.8.5
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 +135 -0
- package/LICENSE +201 -0
- package/README.md +82 -0
- package/dist/asset-manager/catalog-deployer.js +4 -0
- package/dist/asset-manager/catalog-deployer.js.map +1 -0
- package/dist/asset-manager/contrib.js +4 -0
- package/dist/asset-manager/contrib.js.map +1 -0
- package/dist/asset-manager/fragments.js +4 -0
- package/dist/asset-manager/fragments.js.map +1 -0
- package/dist/asset-manager/history.js +4 -0
- package/dist/asset-manager/history.js.map +1 -0
- package/dist/asset-manager/index.js +22 -0
- package/dist/asset-manager/index.js.map +1 -0
- package/dist/asset-manager/installer.js +18 -0
- package/dist/asset-manager/installer.js.map +1 -0
- package/dist/asset-manager/renderers.js +5 -0
- package/dist/asset-manager/renderers.js.map +1 -0
- package/dist/asset-manager/scaffold.js +18 -0
- package/dist/asset-manager/scaffold.js.map +1 -0
- package/dist/asset-manager/src/catalog-deployer.d.ts +144 -0
- package/dist/asset-manager/src/catalog-deployer.d.ts.map +1 -0
- package/dist/asset-manager/src/contrib.d.ts +133 -0
- package/dist/asset-manager/src/contrib.d.ts.map +1 -0
- package/dist/asset-manager/src/fragments.d.ts +111 -0
- package/dist/asset-manager/src/fragments.d.ts.map +1 -0
- package/dist/asset-manager/src/history.d.ts +52 -0
- package/dist/asset-manager/src/history.d.ts.map +1 -0
- package/dist/asset-manager/src/index.d.ts +459 -0
- package/dist/asset-manager/src/index.d.ts.map +1 -0
- package/dist/asset-manager/src/installer.d.ts +85 -0
- package/dist/asset-manager/src/installer.d.ts.map +1 -0
- package/dist/asset-manager/src/renderers.d.ts +125 -0
- package/dist/asset-manager/src/renderers.d.ts.map +1 -0
- package/dist/asset-manager/src/scaffold/index.d.ts +19 -0
- package/dist/asset-manager/src/scaffold/index.d.ts.map +1 -0
- package/dist/asset-manager/src/scaffold/layers/agents.d.ts +67 -0
- package/dist/asset-manager/src/scaffold/layers/agents.d.ts.map +1 -0
- package/dist/asset-manager/src/scaffold/layers/base.d.ts +17 -0
- package/dist/asset-manager/src/scaffold/layers/base.d.ts.map +1 -0
- package/dist/asset-manager/src/scaffold/layers/connectors.d.ts +18 -0
- package/dist/asset-manager/src/scaffold/layers/connectors.d.ts.map +1 -0
- package/dist/asset-manager/src/scaffold/layers/container.d.ts +16 -0
- package/dist/asset-manager/src/scaffold/layers/container.d.ts.map +1 -0
- package/dist/asset-manager/src/scaffold/layers/driver-target.d.ts +17 -0
- package/dist/asset-manager/src/scaffold/layers/driver-target.d.ts.map +1 -0
- package/dist/asset-manager/src/scaffold/layers/hooks.d.ts +22 -0
- package/dist/asset-manager/src/scaffold/layers/hooks.d.ts.map +1 -0
- package/dist/asset-manager/src/scaffold/layers/skills.d.ts +31 -0
- package/dist/asset-manager/src/scaffold/layers/skills.d.ts.map +1 -0
- package/dist/asset-manager/src/scaffold/layers/template.d.ts +16 -0
- package/dist/asset-manager/src/scaffold/layers/template.d.ts.map +1 -0
- package/dist/asset-manager/src/scaffold/scaffolder.d.ts +77 -0
- package/dist/asset-manager/src/scaffold/scaffolder.d.ts.map +1 -0
- package/dist/asset-manager/src/scaffold/types.d.ts +241 -0
- package/dist/asset-manager/src/scaffold/types.d.ts.map +1 -0
- package/dist/base-assets/connectors/deploy/adapter.d.ts +37 -0
- package/dist/base-assets/connectors/deploy/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/deploy.js +20 -0
- package/dist/base-assets/connectors/deploy.js.map +1 -0
- package/dist/base-assets/connectors/devserver/adapter.d.ts +43 -0
- package/dist/base-assets/connectors/devserver/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/devserver.js +20 -0
- package/dist/base-assets/connectors/devserver.js.map +1 -0
- package/dist/base-assets/connectors/flow/adapter.d.ts +200 -0
- package/dist/base-assets/connectors/flow/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/flow/adapter.js +20 -0
- package/dist/base-assets/connectors/flow/adapter.js.map +1 -0
- package/dist/base-assets/connectors/flow/engine/engine.d.ts +107 -0
- package/dist/base-assets/connectors/flow/engine/engine.d.ts.map +1 -0
- package/dist/base-assets/connectors/flow/engine/flow-kind-provider.d.ts +16 -0
- package/dist/base-assets/connectors/flow/engine/flow-kind-provider.d.ts.map +1 -0
- package/dist/base-assets/connectors/flow/engine/flow-manifest.d.ts +215 -0
- package/dist/base-assets/connectors/flow/engine/flow-manifest.d.ts.map +1 -0
- package/dist/base-assets/connectors/flow/engine/index.d.ts +7 -0
- package/dist/base-assets/connectors/flow/engine/index.d.ts.map +1 -0
- package/dist/base-assets/connectors/flow/engine/loader.d.ts +43 -0
- package/dist/base-assets/connectors/flow/engine/loader.d.ts.map +1 -0
- package/dist/base-assets/connectors/flow/engine/types.d.ts +298 -0
- package/dist/base-assets/connectors/flow/engine/types.d.ts.map +1 -0
- package/dist/base-assets/connectors/flow/engine.js +4 -0
- package/dist/base-assets/connectors/flow/engine.js.map +1 -0
- package/dist/base-assets/connectors/flow/index.d.ts +3 -0
- package/dist/base-assets/connectors/flow/index.d.ts.map +1 -0
- package/dist/base-assets/connectors/flow/prompt-fragments.d.ts +90 -0
- package/dist/base-assets/connectors/flow/prompt-fragments.d.ts.map +1 -0
- package/dist/base-assets/connectors/flow/prompt-fragments.js +4 -0
- package/dist/base-assets/connectors/flow/prompt-fragments.js.map +1 -0
- package/dist/base-assets/connectors/flow/run-flow.d.ts +159 -0
- package/dist/base-assets/connectors/flow/run-flow.d.ts.map +1 -0
- package/dist/base-assets/connectors/flow/run-flow.js +23 -0
- package/dist/base-assets/connectors/flow/run-flow.js.map +1 -0
- package/dist/base-assets/connectors/flow/stimulus-driver.d.ts +42 -0
- package/dist/base-assets/connectors/flow/stimulus-driver.d.ts.map +1 -0
- package/dist/base-assets/connectors/flow/stimulus-driver.js +4 -0
- package/dist/base-assets/connectors/flow/stimulus-driver.js.map +1 -0
- package/dist/base-assets/connectors/flow.js +20 -0
- package/dist/base-assets/connectors/flow.js.map +1 -0
- package/dist/base-assets/connectors/gmail/adapter.d.ts +31 -0
- package/dist/base-assets/connectors/gmail/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/gmail.js +20 -0
- package/dist/base-assets/connectors/gmail.js.map +1 -0
- package/dist/base-assets/connectors/mattermost/adapter.d.ts +38 -0
- package/dist/base-assets/connectors/mattermost/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/mattermost.js +20 -0
- package/dist/base-assets/connectors/mattermost.js.map +1 -0
- package/dist/base-assets/connectors/memory/adapter.d.ts +32 -0
- package/dist/base-assets/connectors/memory/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/memory.js +20 -0
- package/dist/base-assets/connectors/memory.js.map +1 -0
- package/dist/base-assets/connectors/minio/adapter.d.ts +32 -0
- package/dist/base-assets/connectors/minio/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/minio.js +20 -0
- package/dist/base-assets/connectors/minio.js.map +1 -0
- package/dist/base-assets/connectors/postgres/adapter.d.ts +40 -0
- package/dist/base-assets/connectors/postgres/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/postgres.js +20 -0
- package/dist/base-assets/connectors/postgres.js.map +1 -0
- package/dist/base-assets/connectors/redis/adapter.d.ts +39 -0
- package/dist/base-assets/connectors/redis/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/redis.js +20 -0
- package/dist/base-assets/connectors/redis.js.map +1 -0
- package/dist/base-assets/connectors/sqlite/adapter.d.ts +42 -0
- package/dist/base-assets/connectors/sqlite/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/sqlite.js +20 -0
- package/dist/base-assets/connectors/sqlite.js.map +1 -0
- package/dist/base-assets/connectors/static-server/adapter.d.ts +28 -0
- package/dist/base-assets/connectors/static-server/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/static-server.js +20 -0
- package/dist/base-assets/connectors/static-server.js.map +1 -0
- package/dist/base-assets/connectors/tunnel/adapter.d.ts +28 -0
- package/dist/base-assets/connectors/tunnel/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/tunnel.js +20 -0
- package/dist/base-assets/connectors/tunnel.js.map +1 -0
- package/dist/base-assets/connectors/xstate/adapter.d.ts +51 -0
- package/dist/base-assets/connectors/xstate/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/xstate-store/adapter.d.ts +40 -0
- package/dist/base-assets/connectors/xstate-store/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/xstate-store.js +20 -0
- package/dist/base-assets/connectors/xstate-store.js.map +1 -0
- package/dist/base-assets/connectors/xstate.js +20 -0
- package/dist/base-assets/connectors/xstate.js.map +1 -0
- package/dist/base-assets/connectors/yjs/adapter.d.ts +49 -0
- package/dist/base-assets/connectors/yjs/adapter.d.ts.map +1 -0
- package/dist/base-assets/connectors/yjs.js +20 -0
- package/dist/base-assets/connectors/yjs.js.map +1 -0
- package/dist/base-assets/index.d.ts +8 -0
- package/dist/base-assets/index.d.ts.map +1 -0
- package/dist/base-assets/index.js +9 -0
- package/dist/base-assets/index.js.map +1 -0
- package/dist/base-assets/mounts/git/driver.d.ts +183 -0
- package/dist/base-assets/mounts/git/driver.d.ts.map +1 -0
- package/dist/base-assets/mounts/git.js +20 -0
- package/dist/base-assets/mounts/git.js.map +1 -0
- package/dist/base-assets/mounts/local/driver.d.ts +27 -0
- package/dist/base-assets/mounts/local/driver.d.ts.map +1 -0
- package/dist/base-assets/mounts/local.js +20 -0
- package/dist/base-assets/mounts/local.js.map +1 -0
- package/dist/base-assets/mounts/s3/driver.d.ts +27 -0
- package/dist/base-assets/mounts/s3/driver.d.ts.map +1 -0
- package/dist/base-assets/mounts/s3.js +20 -0
- package/dist/base-assets/mounts/s3.js.map +1 -0
- package/dist/base-assets/mounts/sharepoint/driver.d.ts +31 -0
- package/dist/base-assets/mounts/sharepoint/driver.d.ts.map +1 -0
- package/dist/base-assets/mounts/sharepoint.js +20 -0
- package/dist/base-assets/mounts/sharepoint.js.map +1 -0
- package/dist/base-assets/mounts/webdav/driver.d.ts +32 -0
- package/dist/base-assets/mounts/webdav/driver.d.ts.map +1 -0
- package/dist/base-assets/mounts/webdav.js +20 -0
- package/dist/base-assets/mounts/webdav.js.map +1 -0
- package/dist/bridge/drivers/claude-sdk.js +836 -0
- package/dist/bridge/drivers/claude-sdk.js.map +1 -0
- package/dist/bridge/drivers/codex.js +478 -0
- package/dist/bridge/drivers/codex.js.map +1 -0
- package/dist/bridge/drivers/echo.js +219 -0
- package/dist/bridge/drivers/echo.js.map +1 -0
- package/dist/bridge/drivers/omp.js +431 -0
- package/dist/bridge/drivers/omp.js.map +1 -0
- package/dist/bridge/index.js +9 -0
- package/dist/bridge/index.js.map +1 -0
- package/dist/bridge/src/capability-dispatch.d.ts +94 -0
- package/dist/bridge/src/capability-dispatch.d.ts.map +1 -0
- package/dist/bridge/src/drivers/claude-sdk.d.ts +224 -0
- package/dist/bridge/src/drivers/claude-sdk.d.ts.map +1 -0
- package/dist/bridge/src/drivers/codex.d.ts +66 -0
- package/dist/bridge/src/drivers/codex.d.ts.map +1 -0
- package/dist/bridge/src/drivers/echo.d.ts +59 -0
- package/dist/bridge/src/drivers/echo.d.ts.map +1 -0
- package/dist/bridge/src/drivers/omp.d.ts +101 -0
- package/dist/bridge/src/drivers/omp.d.ts.map +1 -0
- package/dist/bridge/src/error-classifier.d.ts +90 -0
- package/dist/bridge/src/error-classifier.d.ts.map +1 -0
- package/dist/bridge/src/index.d.ts +10 -0
- package/dist/bridge/src/index.d.ts.map +1 -0
- package/dist/bridge/src/logger.d.ts +22 -0
- package/dist/bridge/src/logger.d.ts.map +1 -0
- package/dist/bridge/src/models.d.ts +90 -0
- package/dist/bridge/src/models.d.ts.map +1 -0
- package/dist/bridge/src/normalizer.d.ts +91 -0
- package/dist/bridge/src/normalizer.d.ts.map +1 -0
- package/dist/bridge/src/registry.d.ts +90 -0
- package/dist/bridge/src/registry.d.ts.map +1 -0
- package/dist/bridge/src/runtime.d.ts +42 -0
- package/dist/bridge/src/runtime.d.ts.map +1 -0
- package/dist/bridge/src/types.d.ts +564 -0
- package/dist/bridge/src/types.d.ts.map +1 -0
- package/dist/bridge/src/validation.d.ts +27 -0
- package/dist/bridge/src/validation.d.ts.map +1 -0
- package/dist/chunk-2M3XTMOL.js +23 -0
- package/dist/chunk-2M3XTMOL.js.map +1 -0
- package/dist/chunk-3W7Z74ZP.js +7678 -0
- package/dist/chunk-3W7Z74ZP.js.map +1 -0
- package/dist/chunk-44ZICIN4.js +418 -0
- package/dist/chunk-44ZICIN4.js.map +1 -0
- package/dist/chunk-46T37EBP.js +1517 -0
- package/dist/chunk-46T37EBP.js.map +1 -0
- package/dist/chunk-4NDWKA64.js +71 -0
- package/dist/chunk-4NDWKA64.js.map +1 -0
- package/dist/chunk-5CSE3QL2.js +546 -0
- package/dist/chunk-5CSE3QL2.js.map +1 -0
- package/dist/chunk-65CYXYUW.js +537 -0
- package/dist/chunk-65CYXYUW.js.map +1 -0
- package/dist/chunk-6UQ66R46.js +72 -0
- package/dist/chunk-6UQ66R46.js.map +1 -0
- package/dist/chunk-77CUYYO3.js +101 -0
- package/dist/chunk-77CUYYO3.js.map +1 -0
- package/dist/chunk-7H7EOIRH.js +393 -0
- package/dist/chunk-7H7EOIRH.js.map +1 -0
- package/dist/chunk-7HCGI2GW.js +385 -0
- package/dist/chunk-7HCGI2GW.js.map +1 -0
- package/dist/chunk-7HLNUSNE.js +212 -0
- package/dist/chunk-7HLNUSNE.js.map +1 -0
- package/dist/chunk-7PTP3SQJ.js +151 -0
- package/dist/chunk-7PTP3SQJ.js.map +1 -0
- package/dist/chunk-AIGWF3TJ.js +73 -0
- package/dist/chunk-AIGWF3TJ.js.map +1 -0
- package/dist/chunk-BVHFSUFM.js +343 -0
- package/dist/chunk-BVHFSUFM.js.map +1 -0
- package/dist/chunk-CCKGX5AS.js +481 -0
- package/dist/chunk-CCKGX5AS.js.map +1 -0
- package/dist/chunk-CGYEHQOX.js +117 -0
- package/dist/chunk-CGYEHQOX.js.map +1 -0
- package/dist/chunk-CSUBFKAN.js +747 -0
- package/dist/chunk-CSUBFKAN.js.map +1 -0
- package/dist/chunk-D5IH3QMH.js +112 -0
- package/dist/chunk-D5IH3QMH.js.map +1 -0
- package/dist/chunk-DOMCYP7D.js +3229 -0
- package/dist/chunk-DOMCYP7D.js.map +1 -0
- package/dist/chunk-EE3XTJ62.js +840 -0
- package/dist/chunk-EE3XTJ62.js.map +1 -0
- package/dist/chunk-EWP5HZBV.js +226 -0
- package/dist/chunk-EWP5HZBV.js.map +1 -0
- package/dist/chunk-FQHHCICT.js +591 -0
- package/dist/chunk-FQHHCICT.js.map +1 -0
- package/dist/chunk-FVTV7M76.js +30 -0
- package/dist/chunk-FVTV7M76.js.map +1 -0
- package/dist/chunk-GCRKAFH7.js +40 -0
- package/dist/chunk-GCRKAFH7.js.map +1 -0
- package/dist/chunk-GVOLEJG5.js +93 -0
- package/dist/chunk-GVOLEJG5.js.map +1 -0
- package/dist/chunk-GZWJGNNN.js +122 -0
- package/dist/chunk-GZWJGNNN.js.map +1 -0
- package/dist/chunk-HK5FRWG6.js +44 -0
- package/dist/chunk-HK5FRWG6.js.map +1 -0
- package/dist/chunk-IPUYL6TD.js +279 -0
- package/dist/chunk-IPUYL6TD.js.map +1 -0
- package/dist/chunk-JDX54X4Y.js +535 -0
- package/dist/chunk-JDX54X4Y.js.map +1 -0
- package/dist/chunk-JKNWJ64A.js +31 -0
- package/dist/chunk-JKNWJ64A.js.map +1 -0
- package/dist/chunk-JLPC4YWT.js +124 -0
- package/dist/chunk-JLPC4YWT.js.map +1 -0
- package/dist/chunk-K5GBV4SA.js +31 -0
- package/dist/chunk-K5GBV4SA.js.map +1 -0
- package/dist/chunk-KLNL7QHN.js +56 -0
- package/dist/chunk-KLNL7QHN.js.map +1 -0
- package/dist/chunk-KOVLSBXK.js +227 -0
- package/dist/chunk-KOVLSBXK.js.map +1 -0
- package/dist/chunk-KTBKW2FI.js +46 -0
- package/dist/chunk-KTBKW2FI.js.map +1 -0
- package/dist/chunk-LSGAYQ2E.js +166 -0
- package/dist/chunk-LSGAYQ2E.js.map +1 -0
- package/dist/chunk-LV2HPH3C.js +73 -0
- package/dist/chunk-LV2HPH3C.js.map +1 -0
- package/dist/chunk-MBBTBKAS.js +201 -0
- package/dist/chunk-MBBTBKAS.js.map +1 -0
- package/dist/chunk-MJHLQRJJ.js +325 -0
- package/dist/chunk-MJHLQRJJ.js.map +1 -0
- package/dist/chunk-NSBPE2FW.js +15 -0
- package/dist/chunk-NSBPE2FW.js.map +1 -0
- package/dist/chunk-NYJKXVG6.js +4166 -0
- package/dist/chunk-NYJKXVG6.js.map +1 -0
- package/dist/chunk-O4JH3KUE.js +56 -0
- package/dist/chunk-O4JH3KUE.js.map +1 -0
- package/dist/chunk-O5AE4QDX.js +67 -0
- package/dist/chunk-O5AE4QDX.js.map +1 -0
- package/dist/chunk-O7SG5PC2.js +3 -0
- package/dist/chunk-O7SG5PC2.js.map +1 -0
- package/dist/chunk-OKRUTSG7.js +87 -0
- package/dist/chunk-OKRUTSG7.js.map +1 -0
- package/dist/chunk-Q5URN24L.js +310 -0
- package/dist/chunk-Q5URN24L.js.map +1 -0
- package/dist/chunk-QT2KQHDT.js +49 -0
- package/dist/chunk-QT2KQHDT.js.map +1 -0
- package/dist/chunk-RRVQAE5D.js +51 -0
- package/dist/chunk-RRVQAE5D.js.map +1 -0
- package/dist/chunk-SZ3SIVZQ.js +78 -0
- package/dist/chunk-SZ3SIVZQ.js.map +1 -0
- package/dist/chunk-TS6VCR4W.js +195 -0
- package/dist/chunk-TS6VCR4W.js.map +1 -0
- package/dist/chunk-UMMBL7SW.js +210 -0
- package/dist/chunk-UMMBL7SW.js.map +1 -0
- package/dist/chunk-UQ6LFBPZ.js +122 -0
- package/dist/chunk-UQ6LFBPZ.js.map +1 -0
- package/dist/chunk-V37HONL7.js +526 -0
- package/dist/chunk-V37HONL7.js.map +1 -0
- package/dist/chunk-W2O5LWYU.js +3 -0
- package/dist/chunk-W2O5LWYU.js.map +1 -0
- package/dist/chunk-X5YPJV4N.js +14 -0
- package/dist/chunk-X5YPJV4N.js.map +1 -0
- package/dist/chunk-XCBG2KDC.js +23 -0
- package/dist/chunk-XCBG2KDC.js.map +1 -0
- package/dist/chunk-XEGHWFAX.js +174 -0
- package/dist/chunk-XEGHWFAX.js.map +1 -0
- package/dist/chunk-XOSBNBB6.js +155 -0
- package/dist/chunk-XOSBNBB6.js.map +1 -0
- package/dist/chunk-Y46TBPLI.js +97 -0
- package/dist/chunk-Y46TBPLI.js.map +1 -0
- package/dist/chunk-Z3RER6YZ.js +343 -0
- package/dist/chunk-Z3RER6YZ.js.map +1 -0
- package/dist/chunk-ZUQIXLRJ.js +284 -0
- package/dist/chunk-ZUQIXLRJ.js.map +1 -0
- package/dist/cli/index.js +5685 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/src/commands/asset-cmd.d.ts +15 -0
- package/dist/cli/src/commands/asset-cmd.d.ts.map +1 -0
- package/dist/cli/src/commands/auth.d.ts +16 -0
- package/dist/cli/src/commands/auth.d.ts.map +1 -0
- package/dist/cli/src/commands/catalog-cmd.d.ts +23 -0
- package/dist/cli/src/commands/catalog-cmd.d.ts.map +1 -0
- package/dist/cli/src/commands/catalog.d.ts +92 -0
- package/dist/cli/src/commands/catalog.d.ts.map +1 -0
- package/dist/cli/src/commands/complete-resolvers.d.ts +35 -0
- package/dist/cli/src/commands/complete-resolvers.d.ts.map +1 -0
- package/dist/cli/src/commands/complete.d.ts +14 -0
- package/dist/cli/src/commands/complete.d.ts.map +1 -0
- package/dist/cli/src/commands/config.d.ts +17 -0
- package/dist/cli/src/commands/config.d.ts.map +1 -0
- package/dist/cli/src/commands/connect.d.ts +13 -0
- package/dist/cli/src/commands/connect.d.ts.map +1 -0
- package/dist/cli/src/commands/connector.d.ts +30 -0
- package/dist/cli/src/commands/connector.d.ts.map +1 -0
- package/dist/cli/src/commands/debug.d.ts +13 -0
- package/dist/cli/src/commands/debug.d.ts.map +1 -0
- package/dist/cli/src/commands/diff.d.ts +12 -0
- package/dist/cli/src/commands/diff.d.ts.map +1 -0
- package/dist/cli/src/commands/flow.d.ts +14 -0
- package/dist/cli/src/commands/flow.d.ts.map +1 -0
- package/dist/cli/src/commands/history.d.ts +12 -0
- package/dist/cli/src/commands/history.d.ts.map +1 -0
- package/dist/cli/src/commands/library-cmd.d.ts +12 -0
- package/dist/cli/src/commands/library-cmd.d.ts.map +1 -0
- package/dist/cli/src/commands/library-status.d.ts +19 -0
- package/dist/cli/src/commands/library-status.d.ts.map +1 -0
- package/dist/cli/src/commands/logs.d.ts +13 -0
- package/dist/cli/src/commands/logs.d.ts.map +1 -0
- package/dist/cli/src/commands/manage.d.ts +62 -0
- package/dist/cli/src/commands/manage.d.ts.map +1 -0
- package/dist/cli/src/commands/mcp-server.d.ts +15 -0
- package/dist/cli/src/commands/mcp-server.d.ts.map +1 -0
- package/dist/cli/src/commands/mount.d.ts +22 -0
- package/dist/cli/src/commands/mount.d.ts.map +1 -0
- package/dist/cli/src/commands/npx.d.ts +14 -0
- package/dist/cli/src/commands/npx.d.ts.map +1 -0
- package/dist/cli/src/commands/outdated.d.ts +12 -0
- package/dist/cli/src/commands/outdated.d.ts.map +1 -0
- package/dist/cli/src/commands/patch.d.ts +14 -0
- package/dist/cli/src/commands/patch.d.ts.map +1 -0
- package/dist/cli/src/commands/plugin/claude-code.d.ts +17 -0
- package/dist/cli/src/commands/plugin/claude-code.d.ts.map +1 -0
- package/dist/cli/src/commands/plugin/codex.d.ts +5 -0
- package/dist/cli/src/commands/plugin/codex.d.ts.map +1 -0
- package/dist/cli/src/commands/plugin/omp.d.ts +12 -0
- package/dist/cli/src/commands/plugin/omp.d.ts.map +1 -0
- package/dist/cli/src/commands/plugin/types.d.ts +65 -0
- package/dist/cli/src/commands/plugin/types.d.ts.map +1 -0
- package/dist/cli/src/commands/plugin.d.ts +14 -0
- package/dist/cli/src/commands/plugin.d.ts.map +1 -0
- package/dist/cli/src/commands/preset-cmd.d.ts +19 -0
- package/dist/cli/src/commands/preset-cmd.d.ts.map +1 -0
- package/dist/cli/src/commands/project.d.ts +34 -0
- package/dist/cli/src/commands/project.d.ts.map +1 -0
- package/dist/cli/src/commands/rebuild.d.ts +21 -0
- package/dist/cli/src/commands/rebuild.d.ts.map +1 -0
- package/dist/cli/src/commands/run.d.ts +68 -0
- package/dist/cli/src/commands/run.d.ts.map +1 -0
- package/dist/cli/src/commands/serve.d.ts +13 -0
- package/dist/cli/src/commands/serve.d.ts.map +1 -0
- package/dist/cli/src/commands/session-logs/format.d.ts +21 -0
- package/dist/cli/src/commands/session-logs/format.d.ts.map +1 -0
- package/dist/cli/src/commands/session-logs/index.d.ts +18 -0
- package/dist/cli/src/commands/session-logs/index.d.ts.map +1 -0
- package/dist/cli/src/commands/session-logs/local-query.d.ts +19 -0
- package/dist/cli/src/commands/session-logs/local-query.d.ts.map +1 -0
- package/dist/cli/src/commands/session-logs/local-tail.d.ts +29 -0
- package/dist/cli/src/commands/session-logs/local-tail.d.ts.map +1 -0
- package/dist/cli/src/commands/session-logs/parse-time.d.ts +11 -0
- package/dist/cli/src/commands/session-logs/parse-time.d.ts.map +1 -0
- package/dist/cli/src/commands/session-logs/remote-query.d.ts +26 -0
- package/dist/cli/src/commands/session-logs/remote-query.d.ts.map +1 -0
- package/dist/cli/src/commands/session-logs/remote-tail.d.ts +22 -0
- package/dist/cli/src/commands/session-logs/remote-tail.d.ts.map +1 -0
- package/dist/cli/src/commands/session-logs/resolve-mode.d.ts +27 -0
- package/dist/cli/src/commands/session-logs/resolve-mode.d.ts.map +1 -0
- package/dist/cli/src/commands/session-logs/sqlite-row.d.ts +51 -0
- package/dist/cli/src/commands/session-logs/sqlite-row.d.ts.map +1 -0
- package/dist/cli/src/commands/session.d.ts +15 -0
- package/dist/cli/src/commands/session.d.ts.map +1 -0
- package/dist/cli/src/commands/show.d.ts +13 -0
- package/dist/cli/src/commands/show.d.ts.map +1 -0
- package/dist/cli/src/commands/source-sidecar.d.ts +6 -0
- package/dist/cli/src/commands/source-sidecar.d.ts.map +1 -0
- package/dist/cli/src/commands/source.d.ts +8 -0
- package/dist/cli/src/commands/source.d.ts.map +1 -0
- package/dist/cli/src/commands/store.d.ts +13 -0
- package/dist/cli/src/commands/store.d.ts.map +1 -0
- package/dist/cli/src/commands/tree.d.ts +12 -0
- package/dist/cli/src/commands/tree.d.ts.map +1 -0
- package/dist/cli/src/commands/update.d.ts +22 -0
- package/dist/cli/src/commands/update.d.ts.map +1 -0
- package/dist/cli/src/commands/validate.d.ts +17 -0
- package/dist/cli/src/commands/validate.d.ts.map +1 -0
- package/dist/cli/src/commands/verify.d.ts +13 -0
- package/dist/cli/src/commands/verify.d.ts.map +1 -0
- package/dist/cli/src/commands/why.d.ts +12 -0
- package/dist/cli/src/commands/why.d.ts.map +1 -0
- package/dist/cli/src/completion.d.ts +19 -0
- package/dist/cli/src/completion.d.ts.map +1 -0
- package/dist/cli/src/helpers.d.ts +54 -0
- package/dist/cli/src/helpers.d.ts.map +1 -0
- package/dist/cli/src/hooks/pre-commit-version.d.ts +10 -0
- package/dist/cli/src/hooks/pre-commit-version.d.ts.map +1 -0
- package/dist/cli/src/index.d.ts +8 -0
- package/dist/cli/src/index.d.ts.map +1 -0
- package/dist/cli/src/open-library.d.ts +101 -0
- package/dist/cli/src/open-library.d.ts.map +1 -0
- package/dist/cli/src/open-registry.d.ts +24 -0
- package/dist/cli/src/open-registry.d.ts.map +1 -0
- package/dist/cli/src/paths.d.ts +27 -0
- package/dist/cli/src/paths.d.ts.map +1 -0
- package/dist/cli/src/setup.d.ts +19 -0
- package/dist/cli/src/setup.d.ts.map +1 -0
- package/dist/cli/src/skill-walker.d.ts +31 -0
- package/dist/cli/src/skill-walker.d.ts.map +1 -0
- package/dist/cli/src/store-client.d.ts +55 -0
- package/dist/cli/src/store-client.d.ts.map +1 -0
- package/dist/client/index.js +4 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/src/client.d.ts +67 -0
- package/dist/client/src/client.d.ts.map +1 -0
- package/dist/client/src/index.d.ts +2 -0
- package/dist/client/src/index.d.ts.map +1 -0
- package/dist/connectors/config.js +14 -0
- package/dist/connectors/config.js.map +1 -0
- package/dist/connectors/index.js +20 -0
- package/dist/connectors/index.js.map +1 -0
- package/dist/connectors/rclone-config.js +4 -0
- package/dist/connectors/rclone-config.js.map +1 -0
- package/dist/connectors/rclone.js +4 -0
- package/dist/connectors/rclone.js.map +1 -0
- package/dist/connectors/src/adapters/base.d.ts +66 -0
- package/dist/connectors/src/adapters/base.d.ts.map +1 -0
- package/dist/connectors/src/cli.d.ts +16 -0
- package/dist/connectors/src/cli.d.ts.map +1 -0
- package/dist/connectors/src/config.d.ts +125 -0
- package/dist/connectors/src/config.d.ts.map +1 -0
- package/dist/connectors/src/connector-manager.d.ts +147 -0
- package/dist/connectors/src/connector-manager.d.ts.map +1 -0
- package/dist/connectors/src/connector-registry.d.ts +59 -0
- package/dist/connectors/src/connector-registry.d.ts.map +1 -0
- package/dist/connectors/src/connector-tools.d.ts +61 -0
- package/dist/connectors/src/connector-tools.d.ts.map +1 -0
- package/dist/connectors/src/connector-types.d.ts +220 -0
- package/dist/connectors/src/connector-types.d.ts.map +1 -0
- package/dist/connectors/src/credential-helper-script.d.ts +87 -0
- package/dist/connectors/src/credential-helper-script.d.ts.map +1 -0
- package/dist/connectors/src/drivers/base.d.ts +44 -0
- package/dist/connectors/src/drivers/base.d.ts.map +1 -0
- package/dist/connectors/src/index.d.ts +51 -0
- package/dist/connectors/src/index.d.ts.map +1 -0
- package/dist/connectors/src/log-buffer.d.ts +21 -0
- package/dist/connectors/src/log-buffer.d.ts.map +1 -0
- package/dist/connectors/src/managed-gitconfig.d.ts +122 -0
- package/dist/connectors/src/managed-gitconfig.d.ts.map +1 -0
- package/dist/connectors/src/mount-manager.d.ts +147 -0
- package/dist/connectors/src/mount-manager.d.ts.map +1 -0
- package/dist/connectors/src/mount-prompt.d.ts +13 -0
- package/dist/connectors/src/mount-prompt.d.ts.map +1 -0
- package/dist/connectors/src/mount-registry.d.ts +61 -0
- package/dist/connectors/src/mount-registry.d.ts.map +1 -0
- package/dist/connectors/src/mount-types.d.ts +222 -0
- package/dist/connectors/src/mount-types.d.ts.map +1 -0
- package/dist/connectors/src/npm-installer.d.ts +69 -0
- package/dist/connectors/src/npm-installer.d.ts.map +1 -0
- package/dist/connectors/src/port-pool.d.ts +25 -0
- package/dist/connectors/src/port-pool.d.ts.map +1 -0
- package/dist/connectors/src/rclone-config/index.d.ts +8 -0
- package/dist/connectors/src/rclone-config/index.d.ts.map +1 -0
- package/dist/connectors/src/rclone-config/onedrive.d.ts +47 -0
- package/dist/connectors/src/rclone-config/onedrive.d.ts.map +1 -0
- package/dist/connectors/src/rclone-config/webdav.d.ts +49 -0
- package/dist/connectors/src/rclone-config/webdav.d.ts.map +1 -0
- package/dist/connectors/src/rclone-process-manager.d.ts +104 -0
- package/dist/connectors/src/rclone-process-manager.d.ts.map +1 -0
- package/dist/connectors/src/secrets.d.ts +264 -0
- package/dist/connectors/src/secrets.d.ts.map +1 -0
- package/dist/connectors/src/shared-types.d.ts +171 -0
- package/dist/connectors/src/shared-types.d.ts.map +1 -0
- package/dist/connectors/src/watcher.d.ts +23 -0
- package/dist/connectors/src/watcher.d.ts.map +1 -0
- package/dist/connectors/src/worktree.d.ts +78 -0
- package/dist/connectors/src/worktree.d.ts.map +1 -0
- package/dist/connectors-7WS2KOSZ.js +5 -0
- package/dist/connectors-7WS2KOSZ.js.map +1 -0
- package/dist/core/discovery.js +4 -0
- package/dist/core/discovery.js.map +1 -0
- package/dist/core/driver-targets.js +4 -0
- package/dist/core/driver-targets.js.map +1 -0
- package/dist/core/framework.js +4 -0
- package/dist/core/framework.js.map +1 -0
- package/dist/core/index.js +13 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/logging.js +4 -0
- package/dist/core/logging.js.map +1 -0
- package/dist/core/manifest.js +5 -0
- package/dist/core/manifest.js.map +1 -0
- package/dist/core/models.js +4 -0
- package/dist/core/models.js.map +1 -0
- package/dist/core/runtime-assets.js +7 -0
- package/dist/core/runtime-assets.js.map +1 -0
- package/dist/core/src/discovery.d.ts +40 -0
- package/dist/core/src/discovery.d.ts.map +1 -0
- package/dist/core/src/driver-targets.d.ts +54 -0
- package/dist/core/src/driver-targets.d.ts.map +1 -0
- package/dist/core/src/framework.d.ts +46 -0
- package/dist/core/src/framework.d.ts.map +1 -0
- package/dist/core/src/index.d.ts +36 -0
- package/dist/core/src/index.d.ts.map +1 -0
- package/dist/core/src/lock.d.ts +69 -0
- package/dist/core/src/lock.d.ts.map +1 -0
- package/dist/core/src/logging/config.d.ts +17 -0
- package/dist/core/src/logging/config.d.ts.map +1 -0
- package/dist/core/src/logging/create-logger.d.ts +32 -0
- package/dist/core/src/logging/create-logger.d.ts.map +1 -0
- package/dist/core/src/logging/index.d.ts +16 -0
- package/dist/core/src/logging/index.d.ts.map +1 -0
- package/dist/core/src/logging/log-store.d.ts +74 -0
- package/dist/core/src/logging/log-store.d.ts.map +1 -0
- package/dist/core/src/logging/sanitize.d.ts +4 -0
- package/dist/core/src/logging/sanitize.d.ts.map +1 -0
- package/dist/core/src/logging/sinks/no-op-sink.d.ts +9 -0
- package/dist/core/src/logging/sinks/no-op-sink.d.ts.map +1 -0
- package/dist/core/src/logging/sinks/on-log-bridge-sink.d.ts +16 -0
- package/dist/core/src/logging/sinks/on-log-bridge-sink.d.ts.map +1 -0
- package/dist/core/src/logging/sinks/sqlite-sink.d.ts +18 -0
- package/dist/core/src/logging/sinks/sqlite-sink.d.ts.map +1 -0
- package/dist/core/src/logging/sinks/stdout-sink.d.ts +24 -0
- package/dist/core/src/logging/sinks/stdout-sink.d.ts.map +1 -0
- package/dist/core/src/logging/sinks/types.d.ts +5 -0
- package/dist/core/src/logging/sinks/types.d.ts.map +1 -0
- package/dist/core/src/logging/sinks/ws-log-sink.d.ts +24 -0
- package/dist/core/src/logging/sinks/ws-log-sink.d.ts.map +1 -0
- package/dist/core/src/manifest.d.ts +228 -0
- package/dist/core/src/manifest.d.ts.map +1 -0
- package/dist/core/src/models.d.ts +304 -0
- package/dist/core/src/models.d.ts.map +1 -0
- package/dist/core/src/patch.d.ts +59 -0
- package/dist/core/src/patch.d.ts.map +1 -0
- package/dist/core/src/repo-manager.d.ts +232 -0
- package/dist/core/src/repo-manager.d.ts.map +1 -0
- package/dist/core/src/runtime-assets.d.ts +125 -0
- package/dist/core/src/runtime-assets.d.ts.map +1 -0
- package/dist/core/src/settings.d.ts +188 -0
- package/dist/core/src/settings.d.ts.map +1 -0
- package/dist/core/src/store.d.ts +48 -0
- package/dist/core/src/store.d.ts.map +1 -0
- package/dist/core/src/workspace-config.d.ts +744 -0
- package/dist/core/src/workspace-config.d.ts.map +1 -0
- package/dist/core/src/workspace-yaml-editor.d.ts +74 -0
- package/dist/core/src/workspace-yaml-editor.d.ts.map +1 -0
- package/dist/core/store.js +5 -0
- package/dist/core/store.js.map +1 -0
- package/dist/core/workspace-config.js +6 -0
- package/dist/core/workspace-config.js.map +1 -0
- package/dist/discovery/index.js +8 -0
- package/dist/discovery/index.js.map +1 -0
- package/dist/discovery/src/asset-kind-registry.d.ts +35 -0
- package/dist/discovery/src/asset-kind-registry.d.ts.map +1 -0
- package/dist/discovery/src/builtin-providers.d.ts +37 -0
- package/dist/discovery/src/builtin-providers.d.ts.map +1 -0
- package/dist/discovery/src/discover-manifest.d.ts +41 -0
- package/dist/discovery/src/discover-manifest.d.ts.map +1 -0
- package/dist/discovery/src/discover.d.ts +92 -0
- package/dist/discovery/src/discover.d.ts.map +1 -0
- package/dist/discovery/src/hash.d.ts +45 -0
- package/dist/discovery/src/hash.d.ts.map +1 -0
- package/dist/discovery/src/index.d.ts +19 -0
- package/dist/discovery/src/index.d.ts.map +1 -0
- package/dist/discovery/src/requires-graph.d.ts +70 -0
- package/dist/discovery/src/requires-graph.d.ts.map +1 -0
- package/dist/discovery/src/source-config.d.ts +456 -0
- package/dist/discovery/src/source-config.d.ts.map +1 -0
- package/dist/discovery/src/tree-entries.d.ts +98 -0
- package/dist/discovery/src/tree-entries.d.ts.map +1 -0
- package/dist/flows-ZULSVHX5.js +7 -0
- package/dist/flows-ZULSVHX5.js.map +1 -0
- package/dist/helpers-I3SREIC3.js +4 -0
- package/dist/helpers-I3SREIC3.js.map +1 -0
- package/dist/library/index.js +9 -0
- package/dist/library/index.js.map +1 -0
- package/dist/library/src/config.d.ts +238 -0
- package/dist/library/src/config.d.ts.map +1 -0
- package/dist/library/src/index.d.ts +32 -0
- package/dist/library/src/index.d.ts.map +1 -0
- package/dist/library/src/knowledge/index.d.ts +9 -0
- package/dist/library/src/knowledge/index.d.ts.map +1 -0
- package/dist/library/src/knowledge/knowledge-kind-provider.d.ts +16 -0
- package/dist/library/src/knowledge/knowledge-kind-provider.d.ts.map +1 -0
- package/dist/library/src/knowledge/knowledge-manifest.d.ts +52 -0
- package/dist/library/src/knowledge/knowledge-manifest.d.ts.map +1 -0
- package/dist/library/src/library.d.ts +344 -0
- package/dist/library/src/library.d.ts.map +1 -0
- package/dist/library/src/local/db.d.ts +29 -0
- package/dist/library/src/local/db.d.ts.map +1 -0
- package/dist/library/src/local/library.d.ts +85 -0
- package/dist/library/src/local/library.d.ts.map +1 -0
- package/dist/library/src/local/local-catalog-source.d.ts +66 -0
- package/dist/library/src/local/local-catalog-source.d.ts.map +1 -0
- package/dist/library/src/local/schema.d.ts +783 -0
- package/dist/library/src/local/schema.d.ts.map +1 -0
- package/dist/library/src/local/sidecar-git.d.ts +104 -0
- package/dist/library/src/local/sidecar-git.d.ts.map +1 -0
- package/dist/library/src/local/sidecar-paths.d.ts +87 -0
- package/dist/library/src/local/sidecar-paths.d.ts.map +1 -0
- package/dist/library/src/local/user-library-manager.d.ts +41 -0
- package/dist/library/src/local/user-library-manager.d.ts.map +1 -0
- package/dist/library/src/migration.d.ts +38 -0
- package/dist/library/src/migration.d.ts.map +1 -0
- package/dist/library/src/pin-resolver.d.ts +45 -0
- package/dist/library/src/pin-resolver.d.ts.map +1 -0
- package/dist/library/src/preset/apply.d.ts +105 -0
- package/dist/library/src/preset/apply.d.ts.map +1 -0
- package/dist/library/src/preset/index.d.ts +13 -0
- package/dist/library/src/preset/index.d.ts.map +1 -0
- package/dist/library/src/preset/interpolate.d.ts +109 -0
- package/dist/library/src/preset/interpolate.d.ts.map +1 -0
- package/dist/library/src/preset/parse.d.ts +65 -0
- package/dist/library/src/preset/parse.d.ts.map +1 -0
- package/dist/library/src/preset/placeholders.d.ts +103 -0
- package/dist/library/src/preset/placeholders.d.ts.map +1 -0
- package/dist/library/src/preset/resolve-item.d.ts +119 -0
- package/dist/library/src/preset/resolve-item.d.ts.map +1 -0
- package/dist/library/src/preset/upgrade.d.ts +96 -0
- package/dist/library/src/preset/upgrade.d.ts.map +1 -0
- package/dist/library/src/remote/cache.d.ts +150 -0
- package/dist/library/src/remote/cache.d.ts.map +1 -0
- package/dist/library/src/remote/index.d.ts +13 -0
- package/dist/library/src/remote/index.d.ts.map +1 -0
- package/dist/library/src/remote/remote-catalog-source.d.ts +199 -0
- package/dist/library/src/remote/remote-catalog-source.d.ts.map +1 -0
- package/dist/library/src/remote/rest-catalog-source.d.ts +135 -0
- package/dist/library/src/remote/rest-catalog-source.d.ts.map +1 -0
- package/dist/library/src/sync/driver.d.ts +19 -0
- package/dist/library/src/sync/driver.d.ts.map +1 -0
- package/dist/library/src/sync/git-driver.d.ts +21 -0
- package/dist/library/src/sync/git-driver.d.ts.map +1 -0
- package/dist/library/src/sync/local-driver.d.ts +19 -0
- package/dist/library/src/sync/local-driver.d.ts.map +1 -0
- package/dist/library/src/sync/manifest-writeback.d.ts +23 -0
- package/dist/library/src/sync/manifest-writeback.d.ts.map +1 -0
- package/dist/library/src/sync/store-driver.d.ts +21 -0
- package/dist/library/src/sync/store-driver.d.ts.map +1 -0
- package/dist/library/src/user-library.d.ts +149 -0
- package/dist/library/src/user-library.d.ts.map +1 -0
- package/dist/library/src/workspace-config.d.ts +451 -0
- package/dist/library/src/workspace-config.d.ts.map +1 -0
- package/dist/mounts-PQLFYD2C.js +5 -0
- package/dist/mounts-PQLFYD2C.js.map +1 -0
- package/dist/open-library-N5T5HRTS.js +12 -0
- package/dist/open-library-N5T5HRTS.js.map +1 -0
- package/dist/paths-FKKGS6BA.js +4 -0
- package/dist/paths-FKKGS6BA.js.map +1 -0
- package/dist/plugins/index.js +4 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/src/asset-kind-provider.d.ts +99 -0
- package/dist/plugins/src/asset-kind-provider.d.ts.map +1 -0
- package/dist/plugins/src/asset-kind-registry.d.ts +106 -0
- package/dist/plugins/src/asset-kind-registry.d.ts.map +1 -0
- package/dist/plugins/src/catalog-source.d.ts +87 -0
- package/dist/plugins/src/catalog-source.d.ts.map +1 -0
- package/dist/plugins/src/index.d.ts +8 -0
- package/dist/plugins/src/index.d.ts.map +1 -0
- package/dist/plugins/src/secrets-provider.d.ts +143 -0
- package/dist/plugins/src/secrets-provider.d.ts.map +1 -0
- package/dist/provider-QXKEDXWJ.js +174 -0
- package/dist/provider-QXKEDXWJ.js.map +1 -0
- package/dist/resolver/index.js +4 -0
- package/dist/resolver/index.js.map +1 -0
- package/dist/resolver/src/index.d.ts +6 -0
- package/dist/resolver/src/index.d.ts.map +1 -0
- package/dist/resolver/src/parser.d.ts +47 -0
- package/dist/resolver/src/parser.d.ts.map +1 -0
- package/dist/resolver/src/preamble.d.ts +32 -0
- package/dist/resolver/src/preamble.d.ts.map +1 -0
- package/dist/resolver/src/types.d.ts +279 -0
- package/dist/resolver/src/types.d.ts.map +1 -0
- package/dist/resolver/src/validator.d.ts +55 -0
- package/dist/resolver/src/validator.d.ts.map +1 -0
- package/dist/resolver/src/version.d.ts +50 -0
- package/dist/resolver/src/version.d.ts.map +1 -0
- package/dist/runner/index.js +34 -0
- package/dist/runner/index.js.map +1 -0
- package/dist/runner/src/agent.d.ts +52 -0
- package/dist/runner/src/agent.d.ts.map +1 -0
- package/dist/runner/src/builtin-capabilities.d.ts +23 -0
- package/dist/runner/src/builtin-capabilities.d.ts.map +1 -0
- package/dist/runner/src/capability-registry.d.ts +212 -0
- package/dist/runner/src/capability-registry.d.ts.map +1 -0
- package/dist/runner/src/capability-roundtrip.d.ts +90 -0
- package/dist/runner/src/capability-roundtrip.d.ts.map +1 -0
- package/dist/runner/src/compaction/index.d.ts +6 -0
- package/dist/runner/src/compaction/index.d.ts.map +1 -0
- package/dist/runner/src/compaction/orchestrator.d.ts +99 -0
- package/dist/runner/src/compaction/orchestrator.d.ts.map +1 -0
- package/dist/runner/src/compaction/prompt.d.ts +15 -0
- package/dist/runner/src/compaction/prompt.d.ts.map +1 -0
- package/dist/runner/src/compaction/strategy.d.ts +41 -0
- package/dist/runner/src/compaction/strategy.d.ts.map +1 -0
- package/dist/runner/src/composition/bootstrap.d.ts +73 -0
- package/dist/runner/src/composition/bootstrap.d.ts.map +1 -0
- package/dist/runner/src/composition/compile.d.ts +84 -0
- package/dist/runner/src/composition/compile.d.ts.map +1 -0
- package/dist/runner/src/composition/index.d.ts +14 -0
- package/dist/runner/src/composition/index.d.ts.map +1 -0
- package/dist/runner/src/composition/resolve.d.ts +53 -0
- package/dist/runner/src/composition/resolve.d.ts.map +1 -0
- package/dist/runner/src/composition/types.d.ts +103 -0
- package/dist/runner/src/composition/types.d.ts.map +1 -0
- package/dist/runner/src/config.d.ts +11 -0
- package/dist/runner/src/config.d.ts.map +1 -0
- package/dist/runner/src/context.d.ts +16 -0
- package/dist/runner/src/context.d.ts.map +1 -0
- package/dist/runner/src/define-capability.d.ts +153 -0
- package/dist/runner/src/define-capability.d.ts.map +1 -0
- package/dist/runner/src/environment.d.ts +21 -0
- package/dist/runner/src/environment.d.ts.map +1 -0
- package/dist/runner/src/file-changed-rewriter.d.ts +35 -0
- package/dist/runner/src/file-changed-rewriter.d.ts.map +1 -0
- package/dist/runner/src/index.d.ts +22 -0
- package/dist/runner/src/index.d.ts.map +1 -0
- package/dist/runner/src/logging-bootstrap.d.ts +92 -0
- package/dist/runner/src/logging-bootstrap.d.ts.map +1 -0
- package/dist/runner/src/manifest.d.ts +33 -0
- package/dist/runner/src/manifest.d.ts.map +1 -0
- package/dist/runner/src/markdown-stream.d.ts +22 -0
- package/dist/runner/src/markdown-stream.d.ts.map +1 -0
- package/dist/runner/src/mixin-resolver.d.ts +61 -0
- package/dist/runner/src/mixin-resolver.d.ts.map +1 -0
- package/dist/runner/src/prompt-assembly.d.ts +42 -0
- package/dist/runner/src/prompt-assembly.d.ts.map +1 -0
- package/dist/runner/src/recipe-resolver.d.ts +18 -0
- package/dist/runner/src/recipe-resolver.d.ts.map +1 -0
- package/dist/runner/src/recipe-templating.d.ts +20 -0
- package/dist/runner/src/recipe-templating.d.ts.map +1 -0
- package/dist/runner/src/refresh-flag-dispatcher.d.ts +54 -0
- package/dist/runner/src/refresh-flag-dispatcher.d.ts.map +1 -0
- package/dist/runner/src/resource-handler.d.ts +22 -0
- package/dist/runner/src/resource-handler.d.ts.map +1 -0
- package/dist/runner/src/resources.d.ts +102 -0
- package/dist/runner/src/resources.d.ts.map +1 -0
- package/dist/runner/src/runner-capabilities.d.ts +120 -0
- package/dist/runner/src/runner-capabilities.d.ts.map +1 -0
- package/dist/runner/src/serve-credentials.d.ts +50 -0
- package/dist/runner/src/serve-credentials.d.ts.map +1 -0
- package/dist/runner/src/serve.d.ts +154 -0
- package/dist/runner/src/serve.d.ts.map +1 -0
- package/dist/runner/src/session-builder.d.ts +213 -0
- package/dist/runner/src/session-builder.d.ts.map +1 -0
- package/dist/runner/src/session-stimulus.d.ts +79 -0
- package/dist/runner/src/session-stimulus.d.ts.map +1 -0
- package/dist/runner/src/session.d.ts +139 -0
- package/dist/runner/src/session.d.ts.map +1 -0
- package/dist/runner/src/workspace-migration.d.ts +54 -0
- package/dist/runner/src/workspace-migration.d.ts.map +1 -0
- package/dist/sdk/asset-manager.js +22 -0
- package/dist/sdk/asset-manager.js.map +1 -0
- package/dist/sdk/bridge.js +9 -0
- package/dist/sdk/bridge.js.map +1 -0
- package/dist/sdk/client.js +4 -0
- package/dist/sdk/client.js.map +1 -0
- package/dist/sdk/core.js +13 -0
- package/dist/sdk/core.js.map +1 -0
- package/dist/sdk/flow.js +4 -0
- package/dist/sdk/flow.js.map +1 -0
- package/dist/sdk/index.js +339 -0
- package/dist/sdk/index.js.map +1 -0
- package/dist/sdk/resolver.js +4 -0
- package/dist/sdk/resolver.js.map +1 -0
- package/dist/sdk/runner.js +34 -0
- package/dist/sdk/runner.js.map +1 -0
- package/dist/sdk/session.js +5 -0
- package/dist/sdk/session.js.map +1 -0
- package/dist/sdk/src/agent-session.d.ts +67 -0
- package/dist/sdk/src/agent-session.d.ts.map +1 -0
- package/dist/sdk/src/asset-manager/index.d.ts +2 -0
- package/dist/sdk/src/asset-manager/index.d.ts.map +1 -0
- package/dist/sdk/src/bridge/index.d.ts +2 -0
- package/dist/sdk/src/bridge/index.d.ts.map +1 -0
- package/dist/sdk/src/client/index.d.ts +2 -0
- package/dist/sdk/src/client/index.d.ts.map +1 -0
- package/dist/sdk/src/core/index.d.ts +2 -0
- package/dist/sdk/src/core/index.d.ts.map +1 -0
- package/dist/sdk/src/factory.d.ts +19 -0
- package/dist/sdk/src/factory.d.ts.map +1 -0
- package/dist/sdk/src/flow/index.d.ts +2 -0
- package/dist/sdk/src/flow/index.d.ts.map +1 -0
- package/dist/sdk/src/index.d.ts +7 -0
- package/dist/sdk/src/index.d.ts.map +1 -0
- package/dist/sdk/src/local-runtime.d.ts +51 -0
- package/dist/sdk/src/local-runtime.d.ts.map +1 -0
- package/dist/sdk/src/resolver/index.d.ts +2 -0
- package/dist/sdk/src/resolver/index.d.ts.map +1 -0
- package/dist/sdk/src/runner/index.d.ts +2 -0
- package/dist/sdk/src/runner/index.d.ts.map +1 -0
- package/dist/sdk/src/session/index.d.ts +2 -0
- package/dist/sdk/src/session/index.d.ts.map +1 -0
- package/dist/sdk/src/store/index.d.ts +2 -0
- package/dist/sdk/src/store/index.d.ts.map +1 -0
- package/dist/sdk/src/telemetry/index.d.ts +2 -0
- package/dist/sdk/src/telemetry/index.d.ts.map +1 -0
- package/dist/sdk/src/transport/index.d.ts +2 -0
- package/dist/sdk/src/transport/index.d.ts.map +1 -0
- package/dist/sdk/src/transport/ws/client.d.ts +2 -0
- package/dist/sdk/src/transport/ws/client.d.ts.map +1 -0
- package/dist/sdk/src/transport/ws/index.d.ts +2 -0
- package/dist/sdk/src/transport/ws/index.d.ts.map +1 -0
- package/dist/sdk/src/transport/ws/server.d.ts +2 -0
- package/dist/sdk/src/transport/ws/server.d.ts.map +1 -0
- package/dist/sdk/src/transport.d.ts +31 -0
- package/dist/sdk/src/transport.d.ts.map +1 -0
- package/dist/sdk/src/types/index.d.ts +2 -0
- package/dist/sdk/src/types/index.d.ts.map +1 -0
- package/dist/sdk/src/types.d.ts +140 -0
- package/dist/sdk/src/types.d.ts.map +1 -0
- package/dist/sdk/src/workspace.d.ts +32 -0
- package/dist/sdk/src/workspace.d.ts.map +1 -0
- package/dist/sdk/store.js +4 -0
- package/dist/sdk/store.js.map +1 -0
- package/dist/sdk/telemetry.js +4 -0
- package/dist/sdk/telemetry.js.map +1 -0
- package/dist/sdk/transport/ws/client.js +4 -0
- package/dist/sdk/transport/ws/client.js.map +1 -0
- package/dist/sdk/transport/ws/server.js +4 -0
- package/dist/sdk/transport/ws/server.js.map +1 -0
- package/dist/sdk/transport/ws.js +6 -0
- package/dist/sdk/transport/ws.js.map +1 -0
- package/dist/sdk/transport.js +7 -0
- package/dist/sdk/transport.js.map +1 -0
- package/dist/sdk/types.js +4 -0
- package/dist/sdk/types.js.map +1 -0
- package/dist/secrets/index.js +5 -0
- package/dist/secrets/index.js.map +1 -0
- package/dist/secrets/src/index.d.ts +12 -0
- package/dist/secrets/src/index.d.ts.map +1 -0
- package/dist/secrets/src/lifecycle.d.ts +51 -0
- package/dist/secrets/src/lifecycle.d.ts.map +1 -0
- package/dist/secrets/src/providers/env.d.ts +26 -0
- package/dist/secrets/src/providers/env.d.ts.map +1 -0
- package/dist/secrets/src/providers/local.d.ts +63 -0
- package/dist/secrets/src/providers/local.d.ts.map +1 -0
- package/dist/secrets/src/router.d.ts +91 -0
- package/dist/secrets/src/router.d.ts.map +1 -0
- package/dist/session/index.js +5 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/src/dispatcher.d.ts +246 -0
- package/dist/session/src/dispatcher.d.ts.map +1 -0
- package/dist/session/src/index.d.ts +6 -0
- package/dist/session/src/index.d.ts.map +1 -0
- package/dist/session/src/mentions.d.ts +80 -0
- package/dist/session/src/mentions.d.ts.map +1 -0
- package/dist/session/src/types.d.ts +109 -0
- package/dist/session/src/types.d.ts.map +1 -0
- package/dist/sessions-2IUX4P3P.js +5 -0
- package/dist/sessions-2IUX4P3P.js.map +1 -0
- package/dist/setup-BMTC562F.js +488 -0
- package/dist/setup-BMTC562F.js.map +1 -0
- package/dist/skills-CRL3VJNN.js +7 -0
- package/dist/skills-CRL3VJNN.js.map +1 -0
- package/dist/store/index.js +4 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/react.js +40 -0
- package/dist/store/react.js.map +1 -0
- package/dist/store/src/index.d.ts +4 -0
- package/dist/store/src/index.d.ts.map +1 -0
- package/dist/store/src/react.d.ts +75 -0
- package/dist/store/src/react.d.ts.map +1 -0
- package/dist/store/src/resource-client.d.ts +128 -0
- package/dist/store/src/resource-client.d.ts.map +1 -0
- package/dist/store/src/store.d.ts +172 -0
- package/dist/store/src/store.d.ts.map +1 -0
- package/dist/store/src/types.d.ts +248 -0
- package/dist/store/src/types.d.ts.map +1 -0
- package/dist/store/src/vue.d.ts +52 -0
- package/dist/store/src/vue.d.ts.map +1 -0
- package/dist/store/vue.js +23 -0
- package/dist/store/vue.js.map +1 -0
- package/dist/store-client-X7Y7D5QX.js +14 -0
- package/dist/store-client-X7Y7D5QX.js.map +1 -0
- package/dist/telemetry/index.js +4 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/telemetry/src/config.d.ts +28 -0
- package/dist/telemetry/src/config.d.ts.map +1 -0
- package/dist/telemetry/src/context.d.ts +36 -0
- package/dist/telemetry/src/context.d.ts.map +1 -0
- package/dist/telemetry/src/index.d.ts +5 -0
- package/dist/telemetry/src/index.d.ts.map +1 -0
- package/dist/telemetry/src/noop.d.ts +25 -0
- package/dist/telemetry/src/noop.d.ts.map +1 -0
- package/dist/telemetry/src/otel/exporter.d.ts +17 -0
- package/dist/telemetry/src/otel/exporter.d.ts.map +1 -0
- package/dist/telemetry/src/otel/gen-ai.d.ts +17 -0
- package/dist/telemetry/src/otel/gen-ai.d.ts.map +1 -0
- package/dist/telemetry/src/otel/provider.d.ts +34 -0
- package/dist/telemetry/src/otel/provider.d.ts.map +1 -0
- package/dist/telemetry/src/types.d.ts +182 -0
- package/dist/telemetry/src/types.d.ts.map +1 -0
- package/dist/transport/index.js +7 -0
- package/dist/transport/index.js.map +1 -0
- package/dist/transport/src/index.d.ts +2 -0
- package/dist/transport/src/index.d.ts.map +1 -0
- package/dist/transport/src/ws/client.d.ts +72 -0
- package/dist/transport/src/ws/client.d.ts.map +1 -0
- package/dist/transport/src/ws/index.d.ts +3 -0
- package/dist/transport/src/ws/index.d.ts.map +1 -0
- package/dist/transport/src/ws/server.d.ts +67 -0
- package/dist/transport/src/ws/server.d.ts.map +1 -0
- package/dist/transport/ws/client.js +4 -0
- package/dist/transport/ws/client.js.map +1 -0
- package/dist/transport/ws/server.js +4 -0
- package/dist/transport/ws/server.js.map +1 -0
- package/dist/transport/ws.js +6 -0
- package/dist/transport/ws.js.map +1 -0
- package/dist/tui/index.js +471 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/tui/src/index.d.ts +4 -0
- package/dist/tui/src/index.d.ts.map +1 -0
- package/dist/tui/src/repl-renderer.d.ts +31 -0
- package/dist/tui/src/repl-renderer.d.ts.map +1 -0
- package/dist/tui/src/repl-session.d.ts +69 -0
- package/dist/tui/src/repl-session.d.ts.map +1 -0
- package/dist/tui/src/repl.d.ts +49 -0
- package/dist/tui/src/repl.d.ts.map +1 -0
- package/dist/tui/src/telemetry.d.ts +88 -0
- package/dist/tui/src/telemetry.d.ts.map +1 -0
- package/dist/types/index.js +4 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/manifests.js +4 -0
- package/dist/types/manifests.js.map +1 -0
- package/dist/types/src/capabilities.d.ts +398 -0
- package/dist/types/src/capabilities.d.ts.map +1 -0
- package/dist/types/src/envelope.d.ts +120 -0
- package/dist/types/src/envelope.d.ts.map +1 -0
- package/dist/types/src/events.d.ts +1075 -0
- package/dist/types/src/events.d.ts.map +1 -0
- package/dist/types/src/flow.d.ts +312 -0
- package/dist/types/src/flow.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +57 -0
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/src/lifecycle.d.ts +269 -0
- package/dist/types/src/lifecycle.d.ts.map +1 -0
- package/dist/types/src/logging.d.ts +161 -0
- package/dist/types/src/logging.d.ts.map +1 -0
- package/dist/types/src/manifests/_shared.d.ts +162 -0
- package/dist/types/src/manifests/_shared.d.ts.map +1 -0
- package/dist/types/src/manifests/agent.d.ts +343 -0
- package/dist/types/src/manifests/agent.d.ts.map +1 -0
- package/dist/types/src/manifests/connector.d.ts +126 -0
- package/dist/types/src/manifests/connector.d.ts.map +1 -0
- package/dist/types/src/manifests/contract.d.ts +90 -0
- package/dist/types/src/manifests/contract.d.ts.map +1 -0
- package/dist/types/src/manifests/index.d.ts +40 -0
- package/dist/types/src/manifests/index.d.ts.map +1 -0
- package/dist/types/src/manifests/mcp-server.d.ts +42 -0
- package/dist/types/src/manifests/mcp-server.d.ts.map +1 -0
- package/dist/types/src/manifests/mount.d.ts +93 -0
- package/dist/types/src/manifests/mount.d.ts.map +1 -0
- package/dist/types/src/manifests/persona.d.ts +90 -0
- package/dist/types/src/manifests/persona.d.ts.map +1 -0
- package/dist/types/src/manifests/preset.d.ts +704 -0
- package/dist/types/src/manifests/preset.d.ts.map +1 -0
- package/dist/types/src/manifests/prompt.d.ts +90 -0
- package/dist/types/src/manifests/prompt.d.ts.map +1 -0
- package/dist/types/src/manifests/ruleset.d.ts +90 -0
- package/dist/types/src/manifests/ruleset.d.ts.map +1 -0
- package/dist/types/src/manifests/skill.d.ts +2391 -0
- package/dist/types/src/manifests/skill.d.ts.map +1 -0
- package/dist/types/src/mentions.d.ts +49 -0
- package/dist/types/src/mentions.d.ts.map +1 -0
- package/dist/types/src/messaging.d.ts +105 -0
- package/dist/types/src/messaging.d.ts.map +1 -0
- package/dist/types/src/protocol.d.ts +201 -0
- package/dist/types/src/protocol.d.ts.map +1 -0
- package/dist/types/src/reactions.d.ts +34 -0
- package/dist/types/src/reactions.d.ts.map +1 -0
- package/dist/types/src/runtime.d.ts +219 -0
- package/dist/types/src/runtime.d.ts.map +1 -0
- package/dist/types/src/transport.d.ts +64 -0
- package/dist/types/src/transport.d.ts.map +1 -0
- package/dist/types/src/version.d.ts +129 -0
- package/dist/types/src/version.d.ts.map +1 -0
- package/dist/validator-764EQNM3.js +5 -0
- package/dist/validator-764EQNM3.js.map +1 -0
- package/dist/workspace-plugin/adapters/mcp.js +259 -0
- package/dist/workspace-plugin/adapters/mcp.js.map +1 -0
- package/dist/workspace-plugin/adapters/omp.js +251 -0
- package/dist/workspace-plugin/adapters/omp.js.map +1 -0
- package/dist/workspace-plugin/index.js +6 -0
- package/dist/workspace-plugin/index.js.map +1 -0
- package/dist/workspace-plugin/src/adapters/claude-code.d.ts +17 -0
- package/dist/workspace-plugin/src/adapters/claude-code.d.ts.map +1 -0
- package/dist/workspace-plugin/src/adapters/mcp.d.ts +78 -0
- package/dist/workspace-plugin/src/adapters/mcp.d.ts.map +1 -0
- package/dist/workspace-plugin/src/adapters/omp.d.ts +60 -0
- package/dist/workspace-plugin/src/adapters/omp.d.ts.map +1 -0
- package/dist/workspace-plugin/src/index.d.ts +8 -0
- package/dist/workspace-plugin/src/index.d.ts.map +1 -0
- package/dist/workspace-plugin/src/plugin.d.ts +83 -0
- package/dist/workspace-plugin/src/plugin.d.ts.map +1 -0
- package/dist/workspace-plugin/src/store.d.ts +36 -0
- package/dist/workspace-plugin/src/store.d.ts.map +1 -0
- package/dist/workspace-plugin/src/tools/connectors.d.ts +94 -0
- package/dist/workspace-plugin/src/tools/connectors.d.ts.map +1 -0
- package/dist/workspace-plugin/src/tools/flows.d.ts +54 -0
- package/dist/workspace-plugin/src/tools/flows.d.ts.map +1 -0
- package/dist/workspace-plugin/src/tools/mounts.d.ts +51 -0
- package/dist/workspace-plugin/src/tools/mounts.d.ts.map +1 -0
- package/dist/workspace-plugin/src/tools/sessions.d.ts +35 -0
- package/dist/workspace-plugin/src/tools/sessions.d.ts.map +1 -0
- package/dist/workspace-plugin/src/tools/skills.d.ts +75 -0
- package/dist/workspace-plugin/src/tools/skills.d.ts.map +1 -0
- package/dist/workspace-plugin/src/tools/validator.d.ts +64 -0
- package/dist/workspace-plugin/src/tools/validator.d.ts.map +1 -0
- package/dist/workspace-plugin/src/types.d.ts +73 -0
- package/dist/workspace-plugin/src/types.d.ts.map +1 -0
- package/dist/workspace-plugin/src/utils/ai-assets.d.ts +16 -0
- package/dist/workspace-plugin/src/utils/ai-assets.d.ts.map +1 -0
- package/dist/workspace-plugin/src/utils/project-dir.d.ts +23 -0
- package/dist/workspace-plugin/src/utils/project-dir.d.ts.map +1 -0
- package/package.json +646 -0
|
@@ -0,0 +1,4166 @@
|
|
|
1
|
+
import { WorkspacePlugin } from './chunk-MJHLQRJJ.js';
|
|
2
|
+
import { PROTOCOL_VERSION } from './chunk-O5AE4QDX.js';
|
|
3
|
+
import { WebSocketServerTransport } from './chunk-XOSBNBB6.js';
|
|
4
|
+
import { EventNormalizer } from './chunk-CCKGX5AS.js';
|
|
5
|
+
import { classifyClaudeSdkError } from './chunk-EWP5HZBV.js';
|
|
6
|
+
import { createDriver } from './chunk-MBBTBKAS.js';
|
|
7
|
+
import { deployCatalogEntry, undeployCatalogEntry } from './chunk-LV2HPH3C.js';
|
|
8
|
+
import { registerBuiltinConnectorAdapters, registerBuiltinMountDrivers, findMissingPackages, installNpmPackages, MountManager, MountStartupError, ConnectorManager, buildMountPromptSection, buildConnectorPromptSection, buildSdkConnectorTools } from './chunk-3W7Z74ZP.js';
|
|
9
|
+
import { loadMountDeclarations, loadConnectorDeclarations, PreMintedSecretProvider, InMemorySecretProvider } from './chunk-Q5URN24L.js';
|
|
10
|
+
import { renderStimulusPrompt, buildOrchestratorPrompt } from './chunk-GZWJGNNN.js';
|
|
11
|
+
import { resolveSettings, resolveApiKey, providerEnvKey } from './chunk-65CYXYUW.js';
|
|
12
|
+
import { resolveRuntimeAssets } from './chunk-XEGHWFAX.js';
|
|
13
|
+
import { loadMcpServerDeclarations, resolveSkWorkspaceConfig, resolveAgentDir, validateAssetRecipeAttr, COMPACTION_DEFAULTS } from './chunk-CSUBFKAN.js';
|
|
14
|
+
import { getLogStore, resolveLogStoreConfig, createLogStoreFromConfig, OnLogBridgeSink, WsLogSink, registerLogStore, resetLogStore, createLogger } from './chunk-V37HONL7.js';
|
|
15
|
+
import { __require } from './chunk-NSBPE2FW.js';
|
|
16
|
+
import pc from 'picocolors';
|
|
17
|
+
import { Marked } from 'marked';
|
|
18
|
+
import { markedTerminal } from 'marked-terminal';
|
|
19
|
+
import { readdirSync, existsSync, readFileSync, unlinkSync, writeFileSync, statSync, mkdirSync, watch, openSync, readSync, closeSync } from 'fs';
|
|
20
|
+
import path4, { join, resolve, basename, dirname, relative } from 'path';
|
|
21
|
+
import { homedir } from 'os';
|
|
22
|
+
import * as z4 from 'zod';
|
|
23
|
+
import { z } from 'zod';
|
|
24
|
+
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
25
|
+
import fs4, { mkdir, writeFile, rename } from 'fs/promises';
|
|
26
|
+
import { createHash, randomUUID } from 'crypto';
|
|
27
|
+
import { execFile, spawnSync } from 'child_process';
|
|
28
|
+
import { promisify } from 'util';
|
|
29
|
+
import { parse } from 'yaml';
|
|
30
|
+
import mime from 'mime';
|
|
31
|
+
|
|
32
|
+
// runner/src/logging-bootstrap.ts
|
|
33
|
+
var PreInitRingSink = class {
|
|
34
|
+
ring = [];
|
|
35
|
+
cap;
|
|
36
|
+
constructor(cap = 200) {
|
|
37
|
+
this.cap = cap;
|
|
38
|
+
}
|
|
39
|
+
write(entry) {
|
|
40
|
+
process.stdout.write(formatForStdout(entry));
|
|
41
|
+
this.ring.push(entry);
|
|
42
|
+
if (this.ring.length > this.cap) this.ring.shift();
|
|
43
|
+
}
|
|
44
|
+
writeBatch(entries) {
|
|
45
|
+
for (const entry of entries) this.write(entry);
|
|
46
|
+
}
|
|
47
|
+
/** Optional query (no-op) — satisfies the LogSink contract. */
|
|
48
|
+
query(_q) {
|
|
49
|
+
return { entries: this.ring.slice() };
|
|
50
|
+
}
|
|
51
|
+
/** Close hook — clears the ring so subsequent writes are dropped. */
|
|
52
|
+
close() {
|
|
53
|
+
this.ring.length = 0;
|
|
54
|
+
}
|
|
55
|
+
/** Number of entries currently buffered (capped at {@link cap}). */
|
|
56
|
+
size() {
|
|
57
|
+
return this.ring.length;
|
|
58
|
+
}
|
|
59
|
+
/** Snapshot of the currently-buffered entries. Used for diagnostics. */
|
|
60
|
+
entries() {
|
|
61
|
+
return this.ring.slice();
|
|
62
|
+
}
|
|
63
|
+
/** Discard all buffered entries. Called by `bootstrapRunnerLogStore`. */
|
|
64
|
+
clear() {
|
|
65
|
+
this.ring.length = 0;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
function formatForStdout(entry) {
|
|
69
|
+
const ts = entry.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
70
|
+
const where = [entry.source?.kind, entry.source?.subkind, entry.source?.instance].filter(Boolean).join(":");
|
|
71
|
+
const dataStr = entry.data ? ` ${JSON.stringify(entry.data)}` : "";
|
|
72
|
+
return `[${ts}] [${entry.level}] [${where}] ${entry.message}${dataStr}
|
|
73
|
+
`;
|
|
74
|
+
}
|
|
75
|
+
var activePreInitSink = null;
|
|
76
|
+
function installPreInitRingSink(cap = 200) {
|
|
77
|
+
if (activePreInitSink) return activePreInitSink;
|
|
78
|
+
activePreInitSink = new PreInitRingSink(cap);
|
|
79
|
+
return activePreInitSink;
|
|
80
|
+
}
|
|
81
|
+
function getPreInitRingSink() {
|
|
82
|
+
return activePreInitSink;
|
|
83
|
+
}
|
|
84
|
+
function clearPreInitRingSink() {
|
|
85
|
+
activePreInitSink = null;
|
|
86
|
+
}
|
|
87
|
+
var currentSessionId = null;
|
|
88
|
+
function bootstrapRunnerLogStore(opts) {
|
|
89
|
+
const existing = getLogStore();
|
|
90
|
+
if (existing && currentSessionId === opts.sessionId) {
|
|
91
|
+
return { store: existing, dispose: () => disposeStore(existing) };
|
|
92
|
+
}
|
|
93
|
+
const cfg = resolveLogStoreConfig({
|
|
94
|
+
sessionId: opts.sessionId,
|
|
95
|
+
workspacePath: opts.projectDir,
|
|
96
|
+
// The skaile.yaml `logging:` block is loosely typed at the workspace-config
|
|
97
|
+
// layer; the resolver validates `mode` / `level` strings at runtime.
|
|
98
|
+
yamlBlock: opts.yamlBlock
|
|
99
|
+
});
|
|
100
|
+
const store = createLogStoreFromConfig(cfg);
|
|
101
|
+
if (opts.onLog) {
|
|
102
|
+
store.addSink(new OnLogBridgeSink(opts.onLog));
|
|
103
|
+
}
|
|
104
|
+
if (opts.transportSend) {
|
|
105
|
+
store.addSink(new WsLogSink({ send: opts.transportSend }));
|
|
106
|
+
}
|
|
107
|
+
if (existing) disposeStore(existing);
|
|
108
|
+
registerLogStore(store);
|
|
109
|
+
currentSessionId = opts.sessionId;
|
|
110
|
+
const preInit = getPreInitRingSink();
|
|
111
|
+
if (preInit) preInit.clear();
|
|
112
|
+
return {
|
|
113
|
+
store,
|
|
114
|
+
dispose: () => {
|
|
115
|
+
disposeStore(store);
|
|
116
|
+
currentSessionId = null;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function resetRunnerLogStore() {
|
|
121
|
+
const s = getLogStore();
|
|
122
|
+
if (s) disposeStore(s);
|
|
123
|
+
resetLogStore();
|
|
124
|
+
currentSessionId = null;
|
|
125
|
+
}
|
|
126
|
+
function disposeStore(store) {
|
|
127
|
+
try {
|
|
128
|
+
store.flush();
|
|
129
|
+
store.close();
|
|
130
|
+
} catch {
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
var marked = new Marked(markedTerminal());
|
|
134
|
+
var MarkdownStreamer = class {
|
|
135
|
+
buffer = "";
|
|
136
|
+
committedSource = "";
|
|
137
|
+
// biome-ignore lint/correctness/noUnusedPrivateClassMembers: write-only accumulator kept for future diff-based rendering
|
|
138
|
+
committedRender = "";
|
|
139
|
+
output;
|
|
140
|
+
constructor(output = process.stdout) {
|
|
141
|
+
this.output = output;
|
|
142
|
+
}
|
|
143
|
+
write(chunk) {
|
|
144
|
+
this.buffer += chunk;
|
|
145
|
+
this.flush();
|
|
146
|
+
}
|
|
147
|
+
/** Render any remaining content and reset state. */
|
|
148
|
+
end() {
|
|
149
|
+
if (this.buffer.length > this.committedSource.length) {
|
|
150
|
+
const tail = this.buffer.slice(this.committedSource.length);
|
|
151
|
+
if (tail.trim()) {
|
|
152
|
+
const rendered = this.render(tail);
|
|
153
|
+
this.output.write(rendered);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
this.buffer = "";
|
|
157
|
+
this.committedRender = "";
|
|
158
|
+
this.committedSource = "";
|
|
159
|
+
}
|
|
160
|
+
flush() {
|
|
161
|
+
const uncommitted = this.buffer.slice(this.committedSource.length);
|
|
162
|
+
const boundary = uncommitted.lastIndexOf("\n\n");
|
|
163
|
+
if (boundary === -1) return;
|
|
164
|
+
const complete = uncommitted.slice(0, boundary + 2);
|
|
165
|
+
const rendered = this.render(complete);
|
|
166
|
+
this.output.write(rendered);
|
|
167
|
+
this.committedSource += complete;
|
|
168
|
+
this.committedRender += rendered;
|
|
169
|
+
}
|
|
170
|
+
render(src) {
|
|
171
|
+
try {
|
|
172
|
+
const result = marked.parse(src);
|
|
173
|
+
if (typeof result === "string") return result;
|
|
174
|
+
return String(result);
|
|
175
|
+
} catch {
|
|
176
|
+
return src;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
// runner/src/context.ts
|
|
182
|
+
var PLATFORM_DESCRIPTIONS = {
|
|
183
|
+
skaile: "You are an AI assistant operating within the Skaile platform, an enterprise AI workspace. Users interact with you through a chat interface in their browser."
|
|
184
|
+
};
|
|
185
|
+
function buildContextSection(context) {
|
|
186
|
+
if (!context) return void 0;
|
|
187
|
+
const hasAny = context.platform !== void 0 || context.multi_user !== void 0 || context.session_model !== void 0;
|
|
188
|
+
if (!hasAny) return void 0;
|
|
189
|
+
const lines = ["## Platform", ""];
|
|
190
|
+
if (context.platform) {
|
|
191
|
+
const description = PLATFORM_DESCRIPTIONS[context.platform];
|
|
192
|
+
if (description) {
|
|
193
|
+
lines.push(description);
|
|
194
|
+
} else {
|
|
195
|
+
lines.push(`You are running inside the ${context.platform} platform.`);
|
|
196
|
+
}
|
|
197
|
+
lines.push("");
|
|
198
|
+
}
|
|
199
|
+
if (context.multi_user === true) {
|
|
200
|
+
lines.push(
|
|
201
|
+
"Multiple users may participate in the same session. Be aware that messages in this conversation may come from different users."
|
|
202
|
+
);
|
|
203
|
+
lines.push("");
|
|
204
|
+
} else if (context.multi_user === false) {
|
|
205
|
+
lines.push("This is a single-user session.");
|
|
206
|
+
lines.push("");
|
|
207
|
+
}
|
|
208
|
+
if (context.session_model === "persistent") {
|
|
209
|
+
lines.push(
|
|
210
|
+
"Your work persists across interactions. Files you create or modify in the workspace are saved and available in future sessions."
|
|
211
|
+
);
|
|
212
|
+
lines.push("");
|
|
213
|
+
} else if (context.session_model === "ephemeral") {
|
|
214
|
+
lines.push(
|
|
215
|
+
"This session is ephemeral. Work you do does not persist beyond the current interaction."
|
|
216
|
+
);
|
|
217
|
+
lines.push("");
|
|
218
|
+
}
|
|
219
|
+
while (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
|
|
220
|
+
return lines.join("\n");
|
|
221
|
+
}
|
|
222
|
+
function defineCapability(args) {
|
|
223
|
+
const inputSchema = zodToJsonSchema(args.input, { $refStrategy: "none" });
|
|
224
|
+
const outputSchema = args.output ? zodToJsonSchema(args.output, { $refStrategy: "none" }) : void 0;
|
|
225
|
+
return {
|
|
226
|
+
name: args.name,
|
|
227
|
+
displayName: args.displayName,
|
|
228
|
+
description: args.description,
|
|
229
|
+
inputSchema,
|
|
230
|
+
outputSchema,
|
|
231
|
+
side: args.side,
|
|
232
|
+
origin: args.origin,
|
|
233
|
+
scope: args.scope,
|
|
234
|
+
fireAndForget: args.fireAndForget,
|
|
235
|
+
requiresApproval: args.requiresApproval,
|
|
236
|
+
kind: args.kind,
|
|
237
|
+
userInvokable: args.userInvokable,
|
|
238
|
+
audience: args.audience,
|
|
239
|
+
promptFragment: args.promptFragment,
|
|
240
|
+
render: args.render,
|
|
241
|
+
inputZod: args.input,
|
|
242
|
+
outputZod: args.output,
|
|
243
|
+
handler: args.handler
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
async function resolveMixin(ref, defaultKind, agentDir, repos) {
|
|
247
|
+
if (ref.startsWith(".") || ref.startsWith("/")) {
|
|
248
|
+
const absPath = ref.startsWith("/") ? ref : path4.join(agentDir, ref);
|
|
249
|
+
if (defaultKind === "knowledge") {
|
|
250
|
+
return loadKnowledgeDir(absPath);
|
|
251
|
+
}
|
|
252
|
+
const content = await readFileSafe(absPath);
|
|
253
|
+
if (!content) return null;
|
|
254
|
+
return { content: stripFrontmatter(content).trim(), source: absPath };
|
|
255
|
+
}
|
|
256
|
+
const { kind, name, repoQualifier } = parseRef(ref, defaultKind);
|
|
257
|
+
const entry = findInRepos(repos, kind, name, repoQualifier);
|
|
258
|
+
if (!entry) return null;
|
|
259
|
+
if (entry.kind === "knowledge") {
|
|
260
|
+
return loadKnowledgeDir(path4.dirname(entry.source));
|
|
261
|
+
}
|
|
262
|
+
const raw = await readFileSafe(entry.source);
|
|
263
|
+
if (!raw) return null;
|
|
264
|
+
return { content: stripFrontmatter(raw).trim(), source: entry.source };
|
|
265
|
+
}
|
|
266
|
+
async function resolveAgentMixins(manifest, agentDir, repos) {
|
|
267
|
+
const resolve3 = (refs, kind) => Promise.all((refs ?? []).map((r) => resolveMixin(r, kind, agentDir, repos)));
|
|
268
|
+
const [personaResults, rulesResults, knowledgeResults] = await Promise.all([
|
|
269
|
+
resolve3(manifest.persona, "persona"),
|
|
270
|
+
resolve3(manifest.rules, "ruleset"),
|
|
271
|
+
resolve3(manifest.knowledge, "knowledge")
|
|
272
|
+
]);
|
|
273
|
+
return {
|
|
274
|
+
personas: personaResults.filter((r) => r !== null),
|
|
275
|
+
rules: rulesResults.filter((r) => r !== null),
|
|
276
|
+
knowledge: knowledgeResults.filter((r) => r !== null)
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
async function readFileSafe(filePath) {
|
|
280
|
+
try {
|
|
281
|
+
return await fs4.readFile(filePath, "utf-8");
|
|
282
|
+
} catch {
|
|
283
|
+
return "";
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
function stripFrontmatter(text) {
|
|
287
|
+
return text.replace(/^---\s*\n[\s\S]*?\n---\s*\n?/, "");
|
|
288
|
+
}
|
|
289
|
+
function parseRef(ref, defaultKind) {
|
|
290
|
+
let rest = ref.trim();
|
|
291
|
+
let kind = defaultKind;
|
|
292
|
+
const colonIdx = rest.indexOf(":");
|
|
293
|
+
if (colonIdx !== -1) {
|
|
294
|
+
kind = rest.slice(0, colonIdx).trim();
|
|
295
|
+
rest = rest.slice(colonIdx + 1).trim();
|
|
296
|
+
}
|
|
297
|
+
const hashIdx = rest.indexOf("#");
|
|
298
|
+
if (hashIdx !== -1) rest = rest.slice(0, hashIdx).trim();
|
|
299
|
+
let repoQualifier;
|
|
300
|
+
const atIdx = rest.indexOf("@");
|
|
301
|
+
if (atIdx !== -1) {
|
|
302
|
+
repoQualifier = rest.slice(atIdx + 1).trim() || void 0;
|
|
303
|
+
rest = rest.slice(0, atIdx).trim();
|
|
304
|
+
}
|
|
305
|
+
return { kind, name: rest, repoQualifier };
|
|
306
|
+
}
|
|
307
|
+
function findInRepos(repos, kind, name, repoQualifier) {
|
|
308
|
+
const searchRepos = repoQualifier ? repos[repoQualifier] ? [repos[repoQualifier]] : [] : Object.values(repos);
|
|
309
|
+
for (const entries of searchRepos) {
|
|
310
|
+
const found = entries.find((e) => e.kind === kind && e.name === name);
|
|
311
|
+
if (found) return found;
|
|
312
|
+
}
|
|
313
|
+
return void 0;
|
|
314
|
+
}
|
|
315
|
+
async function loadKnowledgeDir(dir) {
|
|
316
|
+
let entries;
|
|
317
|
+
try {
|
|
318
|
+
entries = readdirSync(dir).filter((e) => e.endsWith(".md"));
|
|
319
|
+
} catch {
|
|
320
|
+
return null;
|
|
321
|
+
}
|
|
322
|
+
const priorityMap = {};
|
|
323
|
+
const indexContent = await readFileSafe(path4.join(dir, "index.yaml"));
|
|
324
|
+
if (indexContent) {
|
|
325
|
+
const pathMatches = [...indexContent.matchAll(/path:\s*(\S+)/g)];
|
|
326
|
+
const priorityMatches = [...indexContent.matchAll(/priority:\s*(\d+)/g)];
|
|
327
|
+
pathMatches.forEach((m, i) => {
|
|
328
|
+
const filename = m[1];
|
|
329
|
+
if (!filename) return;
|
|
330
|
+
const priority = priorityMatches[i] ? parseInt(priorityMatches[i][1] ?? "99", 10) : 99;
|
|
331
|
+
priorityMap[filename] = priority;
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
const docs = await Promise.all(
|
|
335
|
+
entries.map(async (filename) => ({
|
|
336
|
+
filename,
|
|
337
|
+
priority: priorityMap[filename] ?? 99,
|
|
338
|
+
content: (await readFileSafe(path4.join(dir, filename))).trim()
|
|
339
|
+
}))
|
|
340
|
+
);
|
|
341
|
+
const sorted = docs.filter((d) => d.content).sort((a, b) => a.priority - b.priority || a.filename.localeCompare(b.filename));
|
|
342
|
+
if (sorted.length === 0) return null;
|
|
343
|
+
return {
|
|
344
|
+
content: sorted.map((d) => d.content).join("\n\n---\n\n"),
|
|
345
|
+
source: dir
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// runner/src/composition/types.ts
|
|
350
|
+
var KIND_BINDING_DEFAULTS = {
|
|
351
|
+
soul: "inline-snapshot",
|
|
352
|
+
persona: "inline-snapshot",
|
|
353
|
+
ruleset: "inline-live",
|
|
354
|
+
skill: "discoverable",
|
|
355
|
+
knowledge: "discoverable",
|
|
356
|
+
connector: "discoverable",
|
|
357
|
+
mount: "discoverable",
|
|
358
|
+
prompt: "inline-live",
|
|
359
|
+
flow: "discoverable",
|
|
360
|
+
"mcp-server": "discoverable",
|
|
361
|
+
contract: "inline-live"
|
|
362
|
+
};
|
|
363
|
+
function resolveBinding(item) {
|
|
364
|
+
if (item.binding) return item.binding;
|
|
365
|
+
return KIND_BINDING_DEFAULTS[item.kind] ?? "discoverable";
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// runner/src/composition/compile.ts
|
|
369
|
+
var COMPILE_MANIFEST_FILENAME = "compile_manifest.json";
|
|
370
|
+
async function compileComposition(opts) {
|
|
371
|
+
const { agentDir, items, loadContent, resolveVersion } = opts;
|
|
372
|
+
const manifestPath = path4.join(agentDir, COMPILE_MANIFEST_FILENAME);
|
|
373
|
+
const warnings = [];
|
|
374
|
+
const existing = await loadCompileManifest(manifestPath);
|
|
375
|
+
const nextVersion = (existing?.prompt_version ?? 0) + 1;
|
|
376
|
+
const entries = [];
|
|
377
|
+
for (const item of items) {
|
|
378
|
+
const binding = resolveBinding(item);
|
|
379
|
+
const content = await loadContent(item.ref, item.kind);
|
|
380
|
+
if (!content) {
|
|
381
|
+
warnings.push(`"${item.ref}" (${item.kind}): content not found \u2014 skipped`);
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
const hash = createHash("sha256").update(content).digest("hex");
|
|
385
|
+
const version = resolveVersion ? await resolveVersion(item.ref) : null;
|
|
386
|
+
entries.push({
|
|
387
|
+
asset_ref: item.ref,
|
|
388
|
+
version,
|
|
389
|
+
hash,
|
|
390
|
+
binding,
|
|
391
|
+
resolved_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
const manifest = {
|
|
395
|
+
schema_version: 1,
|
|
396
|
+
prompt_version: nextVersion,
|
|
397
|
+
entries,
|
|
398
|
+
compiled_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
399
|
+
};
|
|
400
|
+
const tmpPath = `${manifestPath}.tmp`;
|
|
401
|
+
await fs4.writeFile(tmpPath, `${JSON.stringify(manifest, null, 2)}
|
|
402
|
+
`, "utf-8");
|
|
403
|
+
await fs4.rename(tmpPath, manifestPath);
|
|
404
|
+
return {
|
|
405
|
+
manifest,
|
|
406
|
+
manifestPath,
|
|
407
|
+
resolvedCount: entries.length,
|
|
408
|
+
warnings
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
async function loadCompileManifest(manifestPath) {
|
|
412
|
+
try {
|
|
413
|
+
const raw = await fs4.readFile(manifestPath, "utf-8");
|
|
414
|
+
const parsed = JSON.parse(raw);
|
|
415
|
+
if (parsed?.schema_version === 1 && typeof parsed.prompt_version === "number") {
|
|
416
|
+
return parsed;
|
|
417
|
+
}
|
|
418
|
+
return void 0;
|
|
419
|
+
} catch {
|
|
420
|
+
return void 0;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
async function loadCompileManifestFromDir(agentDir) {
|
|
424
|
+
return loadCompileManifest(path4.join(agentDir, COMPILE_MANIFEST_FILENAME));
|
|
425
|
+
}
|
|
426
|
+
async function resolveComposition(opts) {
|
|
427
|
+
const { items, library, compileManifest, loadContent } = opts;
|
|
428
|
+
const result = {
|
|
429
|
+
inlineBlocks: [],
|
|
430
|
+
discoverableEntries: [],
|
|
431
|
+
warnings: []
|
|
432
|
+
};
|
|
433
|
+
for (const item of items) {
|
|
434
|
+
const binding = resolveBinding(item);
|
|
435
|
+
try {
|
|
436
|
+
switch (binding) {
|
|
437
|
+
case "inline-snapshot":
|
|
438
|
+
await resolveInlineSnapshot(item, binding, compileManifest, loadContent, result);
|
|
439
|
+
break;
|
|
440
|
+
case "inline-live":
|
|
441
|
+
await resolveInlineLive(item, binding, loadContent, result);
|
|
442
|
+
break;
|
|
443
|
+
case "discoverable":
|
|
444
|
+
await resolveDiscoverable(item, library, loadContent, result);
|
|
445
|
+
break;
|
|
446
|
+
}
|
|
447
|
+
} catch (err) {
|
|
448
|
+
result.warnings.push(
|
|
449
|
+
`Failed to resolve "${item.ref}" (${item.kind}): ${err instanceof Error ? err.message : String(err)}`
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return result;
|
|
454
|
+
}
|
|
455
|
+
async function resolveInlineSnapshot(item, binding, compileManifest, loadContent, result) {
|
|
456
|
+
if (compileManifest) {
|
|
457
|
+
const entry = compileManifest.entries.find(
|
|
458
|
+
(e) => e.asset_ref === item.ref && e.binding === "inline-snapshot"
|
|
459
|
+
);
|
|
460
|
+
if (entry) {
|
|
461
|
+
const content2 = await loadContent(item.ref, item.kind);
|
|
462
|
+
if (content2) {
|
|
463
|
+
const hash = createHash("sha256").update(content2).digest("hex");
|
|
464
|
+
if (hash !== entry.hash) {
|
|
465
|
+
result.warnings.push(
|
|
466
|
+
`"${item.ref}" (${item.kind}) content has changed since last rebuild (expected ${entry.hash.slice(0, 8)}\u2026, got ${hash.slice(0, 8)}\u2026). Run "skaile rebuild" to update the snapshot.`
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
result.inlineBlocks.push({ ref: item.ref, kind: item.kind, content: content2, binding });
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
const content = await loadContent(item.ref, item.kind);
|
|
475
|
+
if (content) {
|
|
476
|
+
result.warnings.push(
|
|
477
|
+
`"${item.ref}" (${item.kind}) is binding=inline-snapshot but no compile_manifest.json found \u2014 using live content. Run "skaile rebuild" to freeze.`
|
|
478
|
+
);
|
|
479
|
+
result.inlineBlocks.push({ ref: item.ref, kind: item.kind, content, binding });
|
|
480
|
+
} else {
|
|
481
|
+
result.warnings.push(`"${item.ref}" (${item.kind}): content not found`);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
async function resolveInlineLive(item, binding, loadContent, result) {
|
|
485
|
+
const content = await loadContent(item.ref, item.kind);
|
|
486
|
+
if (content) {
|
|
487
|
+
result.inlineBlocks.push({ ref: item.ref, kind: item.kind, content, binding });
|
|
488
|
+
} else {
|
|
489
|
+
result.warnings.push(`"${item.ref}" (${item.kind}): content not found`);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
async function resolveDiscoverable(item, library, loadContent, result) {
|
|
493
|
+
const assetDef = await library.getAssetDef(item.ref);
|
|
494
|
+
const name = buildToolName(item);
|
|
495
|
+
const description = assetDef?.description ?? `${item.kind}: ${item.ref}`;
|
|
496
|
+
const content = await loadContent(item.ref, item.kind);
|
|
497
|
+
if (content) {
|
|
498
|
+
result.discoverableEntries.push({
|
|
499
|
+
ref: item.ref,
|
|
500
|
+
kind: item.kind,
|
|
501
|
+
name,
|
|
502
|
+
description,
|
|
503
|
+
content
|
|
504
|
+
});
|
|
505
|
+
} else {
|
|
506
|
+
result.warnings.push(`"${item.ref}" (${item.kind}): content not found for discoverable entry`);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
function buildToolName(item) {
|
|
510
|
+
const lastSlash = item.ref.lastIndexOf("/");
|
|
511
|
+
let refNoVersion;
|
|
512
|
+
if (lastSlash !== -1) {
|
|
513
|
+
const afterSlash = item.ref.slice(lastSlash + 1);
|
|
514
|
+
const versionAt = afterSlash.indexOf("@");
|
|
515
|
+
refNoVersion = versionAt !== -1 ? item.ref.slice(0, lastSlash + 1 + versionAt) : item.ref;
|
|
516
|
+
} else {
|
|
517
|
+
const versionAt = item.ref.indexOf("@");
|
|
518
|
+
refNoVersion = versionAt !== -1 ? item.ref.slice(0, versionAt) : item.ref;
|
|
519
|
+
}
|
|
520
|
+
const cleaned = refNoVersion.replace(/^@/, "");
|
|
521
|
+
return cleaned.replace(/\//g, "__");
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// runner/src/composition/bootstrap.ts
|
|
525
|
+
async function resolveAgentComposition(opts) {
|
|
526
|
+
const { agentDir, manifest, repos = {}, log } = opts;
|
|
527
|
+
const items = manifest.composes;
|
|
528
|
+
if (!items || items.length === 0) return null;
|
|
529
|
+
const compileManifest = await loadCompileManifestFromDir(agentDir);
|
|
530
|
+
const loadContent = async (ref, kind) => {
|
|
531
|
+
try {
|
|
532
|
+
const resolved = await resolveMixin(ref, kind, agentDir, repos);
|
|
533
|
+
return resolved?.content ?? null;
|
|
534
|
+
} catch {
|
|
535
|
+
return null;
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
const library = await openLocalLibraryIfAvailable(log);
|
|
539
|
+
const result = await resolveComposition({
|
|
540
|
+
items,
|
|
541
|
+
library,
|
|
542
|
+
compileManifest,
|
|
543
|
+
loadContent
|
|
544
|
+
});
|
|
545
|
+
if (log && result.warnings.length > 0) {
|
|
546
|
+
for (const warning of result.warnings) {
|
|
547
|
+
log.warn(warning);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
return result;
|
|
551
|
+
}
|
|
552
|
+
function registerCompositionCapabilities(registry, entries) {
|
|
553
|
+
for (const entry of entries) {
|
|
554
|
+
const cap = defineCapability({
|
|
555
|
+
name: entry.name,
|
|
556
|
+
displayName: `${entry.kind}: ${entry.ref}`,
|
|
557
|
+
description: entry.description,
|
|
558
|
+
side: "agent",
|
|
559
|
+
origin: { kind: "skill", skillId: entry.ref },
|
|
560
|
+
scope: "session",
|
|
561
|
+
kind: "query",
|
|
562
|
+
userInvokable: false,
|
|
563
|
+
input: z4.object({}).strict(),
|
|
564
|
+
handler: async (_args, ctx) => {
|
|
565
|
+
ctx.log.info("loading composed asset content", {
|
|
566
|
+
ref: entry.ref,
|
|
567
|
+
kind: entry.kind
|
|
568
|
+
});
|
|
569
|
+
return { content: entry.content, ref: entry.ref, kind: entry.kind };
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
registry.register(cap, "agent");
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
var STUB_LIBRARY = {
|
|
576
|
+
getAssetDef: async () => null,
|
|
577
|
+
listAssetDefs: async () => [],
|
|
578
|
+
createInstance: async () => ({}),
|
|
579
|
+
getInstance: async () => null,
|
|
580
|
+
listInstances: async () => [],
|
|
581
|
+
updateInstance: async () => ({}),
|
|
582
|
+
deleteInstance: async () => {
|
|
583
|
+
},
|
|
584
|
+
subscribe: async () => ({}),
|
|
585
|
+
unsubscribe: async () => {
|
|
586
|
+
},
|
|
587
|
+
listSubscriptions: async () => [],
|
|
588
|
+
getConsumptionGraph: async () => []
|
|
589
|
+
};
|
|
590
|
+
async function openLocalLibraryIfAvailable(log) {
|
|
591
|
+
const libraryDir = process.env.SKAILE_LIBRARY_DIR ?? join(homedir(), ".skaile", "library");
|
|
592
|
+
const dbPath = join(libraryDir, "lib.db");
|
|
593
|
+
if (!existsSync(dbPath)) {
|
|
594
|
+
return STUB_LIBRARY;
|
|
595
|
+
}
|
|
596
|
+
try {
|
|
597
|
+
const { LocalLibrary } = await import('./library/index.js');
|
|
598
|
+
return new LocalLibrary(libraryDir);
|
|
599
|
+
} catch (err) {
|
|
600
|
+
log?.debug(`Could not open LocalLibrary at ${libraryDir}: ${err.message}`);
|
|
601
|
+
return STUB_LIBRARY;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
var execFileAsync = promisify(execFile);
|
|
605
|
+
var PROBE_TIMEOUT_MS = 1500;
|
|
606
|
+
var VERSION_PROBES = [
|
|
607
|
+
{ label: "Python", bin: "python3", args: ["--version"] },
|
|
608
|
+
{ label: "Node.js", bin: "node", args: ["--version"] },
|
|
609
|
+
{ label: "Bun", bin: "bun", args: ["--version"] },
|
|
610
|
+
{ label: "Git", bin: "git", args: ["--version"] },
|
|
611
|
+
{ label: "npm", bin: "npm", args: ["--version"] },
|
|
612
|
+
{
|
|
613
|
+
label: "pip",
|
|
614
|
+
bin: "pip",
|
|
615
|
+
args: ["--version"],
|
|
616
|
+
extract: (out) => out.split(" ").slice(0, 2).join(" ")
|
|
617
|
+
}
|
|
618
|
+
];
|
|
619
|
+
var PRESENCE_PROBES = ["curl", "jq", "ssh", "wget", "rg"];
|
|
620
|
+
async function runProbe(bin, args) {
|
|
621
|
+
try {
|
|
622
|
+
const { stdout } = await execFileAsync(bin, args, { timeout: PROBE_TIMEOUT_MS });
|
|
623
|
+
return stdout.trim().split("\n")[0] ?? null;
|
|
624
|
+
} catch {
|
|
625
|
+
return null;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
async function checkPresence(bin) {
|
|
629
|
+
try {
|
|
630
|
+
await execFileAsync("which", [bin], { timeout: PROBE_TIMEOUT_MS });
|
|
631
|
+
return true;
|
|
632
|
+
} catch {
|
|
633
|
+
return false;
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
async function buildEnvironmentSection(projectDir) {
|
|
637
|
+
const versionResults = await Promise.allSettled(
|
|
638
|
+
VERSION_PROBES.map(async (probe) => {
|
|
639
|
+
const raw = await runProbe(probe.bin, probe.args);
|
|
640
|
+
if (!raw) return null;
|
|
641
|
+
const version = probe.extract ? probe.extract(raw) : raw;
|
|
642
|
+
return { label: probe.label, version };
|
|
643
|
+
})
|
|
644
|
+
);
|
|
645
|
+
const presenceResults = await Promise.allSettled(PRESENCE_PROBES.map(checkPresence));
|
|
646
|
+
const runtimes = [];
|
|
647
|
+
for (const result of versionResults) {
|
|
648
|
+
if (result.status === "fulfilled" && result.value) {
|
|
649
|
+
runtimes.push(`${result.value.label} (${result.value.version})`);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
const tools = [];
|
|
653
|
+
for (let i = 0; i < PRESENCE_PROBES.length; i++) {
|
|
654
|
+
const result = presenceResults[i];
|
|
655
|
+
if (result?.status === "fulfilled" && result.value) {
|
|
656
|
+
tools.push(PRESENCE_PROBES[i]);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
if (runtimes.length === 0 && tools.length === 0) return void 0;
|
|
660
|
+
const lines = [
|
|
661
|
+
"## Environment",
|
|
662
|
+
"",
|
|
663
|
+
"You are running inside an isolated container with the following tools available:",
|
|
664
|
+
""
|
|
665
|
+
];
|
|
666
|
+
if (runtimes.length > 0) {
|
|
667
|
+
lines.push("**Runtimes:**");
|
|
668
|
+
for (const r of runtimes) lines.push(`- ${r}`);
|
|
669
|
+
lines.push("");
|
|
670
|
+
}
|
|
671
|
+
if (tools.length > 0) {
|
|
672
|
+
lines.push(`**Tools:** ${tools.join(", ")}`);
|
|
673
|
+
lines.push("");
|
|
674
|
+
}
|
|
675
|
+
const shell = process.env.SHELL ?? "sh";
|
|
676
|
+
lines.push(`**Shell:** ${shell}`);
|
|
677
|
+
lines.push(`**Working directory:** ${projectDir}`);
|
|
678
|
+
return lines.join("\n");
|
|
679
|
+
}
|
|
680
|
+
async function agentDefinitionExists(agentDir) {
|
|
681
|
+
try {
|
|
682
|
+
await fs4.access(path4.join(agentDir, "agent.yaml"));
|
|
683
|
+
return true;
|
|
684
|
+
} catch {
|
|
685
|
+
return false;
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
async function loadAgentManifest(agentDir) {
|
|
689
|
+
const agentYamlPath = path4.join(agentDir, "agent.yaml");
|
|
690
|
+
let content;
|
|
691
|
+
try {
|
|
692
|
+
content = await fs4.readFile(agentYamlPath, "utf-8");
|
|
693
|
+
} catch {
|
|
694
|
+
return void 0;
|
|
695
|
+
}
|
|
696
|
+
if (!content.trim()) return void 0;
|
|
697
|
+
try {
|
|
698
|
+
return parse(content);
|
|
699
|
+
} catch {
|
|
700
|
+
return void 0;
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// runner/src/prompt-assembly.ts
|
|
705
|
+
function assembleSystemPrompt(parts) {
|
|
706
|
+
const filtered = parts.filter((p) => !!p);
|
|
707
|
+
if (filtered.length === 0) return void 0;
|
|
708
|
+
return filtered.join("\n\n---\n\n");
|
|
709
|
+
}
|
|
710
|
+
function buildCapabilitiesPromptSection(registry) {
|
|
711
|
+
const body = registry.composePromptSection();
|
|
712
|
+
if (!body) return void 0;
|
|
713
|
+
return `<CAPABILITIES>
|
|
714
|
+
${body}
|
|
715
|
+
</CAPABILITIES>`;
|
|
716
|
+
}
|
|
717
|
+
var RecipeUnavailableError = class extends Error {
|
|
718
|
+
constructor(flakeRef, attr, cause) {
|
|
719
|
+
super(
|
|
720
|
+
`Recipe unavailable: ${flakeRef}#${attr}${cause instanceof Error ? ` - ${cause.message}` : ""}`
|
|
721
|
+
);
|
|
722
|
+
this.flakeRef = flakeRef;
|
|
723
|
+
this.attr = attr;
|
|
724
|
+
this.name = "RecipeUnavailableError";
|
|
725
|
+
}
|
|
726
|
+
flakeRef;
|
|
727
|
+
attr;
|
|
728
|
+
};
|
|
729
|
+
function createRecipeCache() {
|
|
730
|
+
return /* @__PURE__ */ new Map();
|
|
731
|
+
}
|
|
732
|
+
function resolveRecipePath(flakeRef, attr, cache) {
|
|
733
|
+
const key = `${flakeRef}#${attr}`;
|
|
734
|
+
const cached = cache.get(key);
|
|
735
|
+
if (cached) return cached;
|
|
736
|
+
try {
|
|
737
|
+
validateAssetRecipeAttr(attr);
|
|
738
|
+
} catch (err) {
|
|
739
|
+
throw new RecipeUnavailableError(
|
|
740
|
+
flakeRef,
|
|
741
|
+
attr,
|
|
742
|
+
err instanceof Error ? err : new Error(String(err))
|
|
743
|
+
);
|
|
744
|
+
}
|
|
745
|
+
const log = createLogger({ kind: "mcp", subkind: "recipe-resolve" });
|
|
746
|
+
log.debug("resolving recipe", { flakeRef, attr });
|
|
747
|
+
const result = spawnSync("nix", ["path-info", "--offline", `${flakeRef}#${attr}`], {
|
|
748
|
+
encoding: "utf8"
|
|
749
|
+
});
|
|
750
|
+
if (result.error) throw new RecipeUnavailableError(flakeRef, attr, result.error);
|
|
751
|
+
if (result.status !== 0) {
|
|
752
|
+
throw new RecipeUnavailableError(
|
|
753
|
+
flakeRef,
|
|
754
|
+
attr,
|
|
755
|
+
new Error(`nix path-info exited ${result.status}: ${result.stderr.trim()}`)
|
|
756
|
+
);
|
|
757
|
+
}
|
|
758
|
+
const outPath = result.stdout.trim().split("\n")[0];
|
|
759
|
+
if (!outPath?.startsWith("/nix/store/")) {
|
|
760
|
+
throw new RecipeUnavailableError(
|
|
761
|
+
flakeRef,
|
|
762
|
+
attr,
|
|
763
|
+
new Error(`Unexpected output: ${result.stdout}`)
|
|
764
|
+
);
|
|
765
|
+
}
|
|
766
|
+
cache.set(key, outPath);
|
|
767
|
+
log.info("resolved recipe", { flakeRef, attr, outPath });
|
|
768
|
+
return outPath;
|
|
769
|
+
}
|
|
770
|
+
var RECIPE_MARKER = /\$\{recipe:([a-z0-9_-]+)(?::([a-z0-9_/.-]+))?\}/g;
|
|
771
|
+
function substituteRecipeTemplating(value, recipeOutPaths) {
|
|
772
|
+
return value.replace(RECIPE_MARKER, (_match, id, sub) => {
|
|
773
|
+
const outPath = recipeOutPaths.get(id);
|
|
774
|
+
if (!outPath) {
|
|
775
|
+
return _match;
|
|
776
|
+
}
|
|
777
|
+
if (!sub) return `${outPath}/bin`;
|
|
778
|
+
return `${outPath}/${sub}`;
|
|
779
|
+
});
|
|
780
|
+
}
|
|
781
|
+
function substituteRecipeMap(obj, recipeOutPaths) {
|
|
782
|
+
if (!obj) return obj;
|
|
783
|
+
const out = {};
|
|
784
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
785
|
+
out[k] = substituteRecipeTemplating(v, recipeOutPaths);
|
|
786
|
+
}
|
|
787
|
+
return out;
|
|
788
|
+
}
|
|
789
|
+
function validateSubstitutedPaths(command, args) {
|
|
790
|
+
const missing = [];
|
|
791
|
+
if (command?.startsWith("/nix/store/") && !existsSync(command)) {
|
|
792
|
+
missing.push({
|
|
793
|
+
field: "command",
|
|
794
|
+
path: command,
|
|
795
|
+
error: `resolved path does not exist: ${command}`
|
|
796
|
+
});
|
|
797
|
+
}
|
|
798
|
+
const firstArg = args?.[0];
|
|
799
|
+
if (firstArg?.startsWith("/nix/store/") && !existsSync(firstArg)) {
|
|
800
|
+
missing.push({
|
|
801
|
+
field: "args[0]",
|
|
802
|
+
path: firstArg,
|
|
803
|
+
error: `resolved path does not exist: ${firstArg}`
|
|
804
|
+
});
|
|
805
|
+
}
|
|
806
|
+
return missing;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
// runner/src/resources.ts
|
|
810
|
+
async function buildAgentResources(projectDir, driverType, _onLog, watch, secretProvider, sessionMeta, tokenMediator, preMintedSecrets) {
|
|
811
|
+
const resLog = createLogger({
|
|
812
|
+
kind: "runner",
|
|
813
|
+
subkind: "resources",
|
|
814
|
+
instance: sessionMeta?.sessionId ?? "no-session"
|
|
815
|
+
});
|
|
816
|
+
const noopResult = {
|
|
817
|
+
resourceManager: null,
|
|
818
|
+
mountManager: null,
|
|
819
|
+
resourcePromptSection: "",
|
|
820
|
+
mcpServers: void 0,
|
|
821
|
+
runtimeAssets: null,
|
|
822
|
+
dispose: async () => {
|
|
823
|
+
},
|
|
824
|
+
startWatching: () => {
|
|
825
|
+
}
|
|
826
|
+
};
|
|
827
|
+
try {
|
|
828
|
+
registerBuiltinConnectorAdapters();
|
|
829
|
+
registerBuiltinMountDrivers();
|
|
830
|
+
const runtimeAssets = await resolveRuntimeAssets(projectDir);
|
|
831
|
+
for (const w of runtimeAssets.warnings) {
|
|
832
|
+
resLog.warn("runtime asset warning", { code: w.code, message: w.message });
|
|
833
|
+
}
|
|
834
|
+
if (process.env.SKAILE_AUTO_INSTALL_DEPS === "true") {
|
|
835
|
+
const required = runtimeAssets.requiredNpmDeps.required;
|
|
836
|
+
if (required.length > 0) {
|
|
837
|
+
const missing = findMissingPackages(required, projectDir);
|
|
838
|
+
if (missing.length > 0) {
|
|
839
|
+
resLog.info("installing missing npm peer deps", { packages: missing });
|
|
840
|
+
const r = await installNpmPackages(missing, projectDir);
|
|
841
|
+
if (!r.success) resLog.error("npm install failed", void 0, { output: r.output });
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
const mountDeclarations = loadMountDeclarations(projectDir);
|
|
846
|
+
let mountMgr = null;
|
|
847
|
+
if (mountDeclarations.length > 0) {
|
|
848
|
+
mountMgr = new MountManager(projectDir, {
|
|
849
|
+
secrets: secretProvider,
|
|
850
|
+
catalogEntries: runtimeAssets.catalogEntries,
|
|
851
|
+
tokenMediator,
|
|
852
|
+
preMintedSecrets
|
|
853
|
+
});
|
|
854
|
+
try {
|
|
855
|
+
const mountReport = await mountMgr.mountAll(mountDeclarations, {
|
|
856
|
+
failOnReadWriteError: true
|
|
857
|
+
});
|
|
858
|
+
for (const r of mountReport.results) {
|
|
859
|
+
if (r.mounted) {
|
|
860
|
+
resLog.info("mount ok", { id: r.id, mountPath: r.mountPath });
|
|
861
|
+
} else {
|
|
862
|
+
resLog.error("mount failed", void 0, { id: r.id, error: r.error });
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
} catch (err) {
|
|
866
|
+
if (err instanceof MountStartupError) {
|
|
867
|
+
for (const r of err.report.results) {
|
|
868
|
+
if (r.mounted) {
|
|
869
|
+
resLog.info("mount ok", { id: r.id, mountPath: r.mountPath });
|
|
870
|
+
} else {
|
|
871
|
+
resLog.error("mount failed", void 0, { id: r.id, error: r.error });
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
throw err;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
const connectorDeclarations = loadConnectorDeclarations(projectDir);
|
|
879
|
+
let resourceManager = null;
|
|
880
|
+
if (connectorDeclarations.length > 0) {
|
|
881
|
+
resourceManager = new ConnectorManager(secretProvider, {
|
|
882
|
+
catalogEntries: runtimeAssets.catalogEntries
|
|
883
|
+
});
|
|
884
|
+
const report = await resourceManager.connectAll(connectorDeclarations);
|
|
885
|
+
for (const r of report.results) {
|
|
886
|
+
if (r.connected) {
|
|
887
|
+
resLog.info("connector ok", { id: r.id });
|
|
888
|
+
} else {
|
|
889
|
+
resLog.error("connector failed", void 0, { id: r.id, error: r.error });
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
const promptParts = [];
|
|
894
|
+
if (mountMgr) {
|
|
895
|
+
promptParts.push(buildMountPromptSection(mountMgr));
|
|
896
|
+
}
|
|
897
|
+
if (resourceManager) {
|
|
898
|
+
promptParts.push(buildConnectorPromptSection(resourceManager, driverType));
|
|
899
|
+
}
|
|
900
|
+
const resourcePromptSection = promptParts.filter(Boolean).join("\n\n");
|
|
901
|
+
const mcpLog = createLogger({
|
|
902
|
+
kind: "mcp",
|
|
903
|
+
subkind: "wiring",
|
|
904
|
+
instance: sessionMeta?.sessionId ?? "no-session"
|
|
905
|
+
});
|
|
906
|
+
let mcpServers;
|
|
907
|
+
let workspacePluginToShutdown = null;
|
|
908
|
+
if (driverType === "claude-sdk") {
|
|
909
|
+
if (resourceManager) {
|
|
910
|
+
const connectorsLog = createLogger({ kind: "mcp", subkind: "skaile-connectors" });
|
|
911
|
+
try {
|
|
912
|
+
const server = await buildSdkConnectorTools(resourceManager, { z: z });
|
|
913
|
+
if (server) {
|
|
914
|
+
mcpServers = { "skaile-connectors": server };
|
|
915
|
+
connectorsLog.info("server constructed", {
|
|
916
|
+
connectorCount: resourceManager.listConnectors().length
|
|
917
|
+
});
|
|
918
|
+
} else {
|
|
919
|
+
connectorsLog.debug("server skipped (no tools to expose)");
|
|
920
|
+
}
|
|
921
|
+
} catch (err) {
|
|
922
|
+
connectorsLog.error("server construction failed", err);
|
|
923
|
+
throw err;
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
const workspacePlugin = new WorkspacePlugin({
|
|
927
|
+
projectDir,
|
|
928
|
+
mountManager: mountMgr ?? void 0,
|
|
929
|
+
connectorManager: resourceManager ?? void 0,
|
|
930
|
+
driver: driverType,
|
|
931
|
+
provider: sessionMeta?.provider,
|
|
932
|
+
model: sessionMeta?.model
|
|
933
|
+
});
|
|
934
|
+
const wsServer = await workspacePlugin.buildWorkspaceMcpServer();
|
|
935
|
+
if (wsServer) {
|
|
936
|
+
mcpServers = { ...mcpServers ?? {}, "skaile-workspace": wsServer };
|
|
937
|
+
}
|
|
938
|
+
workspacePluginToShutdown = workspacePlugin;
|
|
939
|
+
const mcpDeclarations = loadMcpServerDeclarations(projectDir);
|
|
940
|
+
mcpLog.debug("loaded MCP declarations", { count: mcpDeclarations.length });
|
|
941
|
+
const recipeCache = createRecipeCache();
|
|
942
|
+
const nixFlakeRef = process.env.SKAILE_NIX_FLAKE_REF ?? "/etc/skaile/flake";
|
|
943
|
+
for (const decl of mcpDeclarations) {
|
|
944
|
+
if (RESERVED_MCP_SERVER_IDS.has(decl.id)) {
|
|
945
|
+
mcpLog.warn("MCP server skipped: reserved id", { id: decl.id });
|
|
946
|
+
continue;
|
|
947
|
+
}
|
|
948
|
+
let resolvedDecl = decl;
|
|
949
|
+
if (decl.recipe) {
|
|
950
|
+
try {
|
|
951
|
+
const outPath = resolveRecipePath(nixFlakeRef, decl.recipe.attr, recipeCache);
|
|
952
|
+
const outPaths = /* @__PURE__ */ new Map([[decl.id, outPath]]);
|
|
953
|
+
const resolvedCommand = decl.command ? substituteRecipeTemplating(decl.command, outPaths) : decl.command;
|
|
954
|
+
const resolvedArgs = decl.args?.map((a) => substituteRecipeTemplating(a, outPaths));
|
|
955
|
+
const resolvedEnv = substituteRecipeMap(decl.env, outPaths);
|
|
956
|
+
resolvedDecl = {
|
|
957
|
+
...decl,
|
|
958
|
+
command: resolvedCommand,
|
|
959
|
+
args: resolvedArgs,
|
|
960
|
+
env: resolvedEnv
|
|
961
|
+
};
|
|
962
|
+
const allResolved = [
|
|
963
|
+
resolvedCommand ?? "",
|
|
964
|
+
...resolvedArgs ?? [],
|
|
965
|
+
...Object.values(resolvedEnv ?? {})
|
|
966
|
+
];
|
|
967
|
+
for (const v of allResolved) {
|
|
968
|
+
if (v.includes("${recipe:")) {
|
|
969
|
+
const recipeLog2 = createLogger({
|
|
970
|
+
kind: "mcp",
|
|
971
|
+
subkind: decl.id,
|
|
972
|
+
instance: "recipe-resolve"
|
|
973
|
+
});
|
|
974
|
+
recipeLog2.warn("unresolved recipe marker after substitution", {
|
|
975
|
+
value: v,
|
|
976
|
+
declId: decl.id
|
|
977
|
+
});
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
const missingPaths = validateSubstitutedPaths(resolvedCommand, resolvedArgs);
|
|
981
|
+
if (missingPaths.length > 0) {
|
|
982
|
+
const recipeLog2 = createLogger({
|
|
983
|
+
kind: "mcp",
|
|
984
|
+
subkind: decl.id,
|
|
985
|
+
instance: "recipe-resolve"
|
|
986
|
+
});
|
|
987
|
+
recipeLog2.error("MCP server skipped: substituted path does not exist", void 0, {
|
|
988
|
+
id: decl.id,
|
|
989
|
+
attr: decl.recipe.attr,
|
|
990
|
+
missing: missingPaths
|
|
991
|
+
});
|
|
992
|
+
continue;
|
|
993
|
+
}
|
|
994
|
+
const recipeLog = createLogger({
|
|
995
|
+
kind: "mcp",
|
|
996
|
+
subkind: decl.id,
|
|
997
|
+
instance: "recipe-resolve"
|
|
998
|
+
});
|
|
999
|
+
recipeLog.info("recipe substitution complete", {
|
|
1000
|
+
attr: decl.recipe.attr,
|
|
1001
|
+
outPath
|
|
1002
|
+
});
|
|
1003
|
+
} catch (err) {
|
|
1004
|
+
const recipeLog = createLogger({
|
|
1005
|
+
kind: "mcp",
|
|
1006
|
+
subkind: decl.id,
|
|
1007
|
+
instance: "recipe-resolve"
|
|
1008
|
+
});
|
|
1009
|
+
recipeLog.error("MCP server skipped: recipe resolution failed", err, {
|
|
1010
|
+
id: decl.id,
|
|
1011
|
+
attr: decl.recipe.attr,
|
|
1012
|
+
flakeRef: nixFlakeRef
|
|
1013
|
+
});
|
|
1014
|
+
continue;
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
const serverConfig = toSdkMcpServerConfig(
|
|
1018
|
+
resolvedDecl,
|
|
1019
|
+
secretProvider
|
|
1020
|
+
);
|
|
1021
|
+
if (serverConfig) {
|
|
1022
|
+
mcpServers = { ...mcpServers ?? {}, [decl.id]: serverConfig };
|
|
1023
|
+
const declLog = createLogger({ kind: "mcp", subkind: decl.id });
|
|
1024
|
+
declLog.info("MCP server registered", {
|
|
1025
|
+
transport: decl.transport ?? "stdio",
|
|
1026
|
+
...decl.transport === "stdio" || !decl.transport ? { command: resolvedDecl.command, args: resolvedDecl.args } : { url: decl.url }
|
|
1027
|
+
});
|
|
1028
|
+
} else {
|
|
1029
|
+
mcpLog.error("MCP server config invalid (translation returned null)", void 0, {
|
|
1030
|
+
id: decl.id,
|
|
1031
|
+
transport: decl.transport
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
if (!mountMgr && !resourceManager && driverType !== "claude-sdk") return noopResult;
|
|
1037
|
+
const startWatching = () => {
|
|
1038
|
+
if (mountMgr && watch?.onMountChanged) {
|
|
1039
|
+
mountMgr.watchAll((mountId, event) => {
|
|
1040
|
+
watch.onMountChanged(mountId, event);
|
|
1041
|
+
});
|
|
1042
|
+
}
|
|
1043
|
+
if (resourceManager && watch?.onFileChanged) {
|
|
1044
|
+
const dedupTtlMs = watch.dedupTtlMs ?? 500;
|
|
1045
|
+
const recentlyEmitted = /* @__PURE__ */ new Map();
|
|
1046
|
+
resourceManager.watchAll((connectorId, event) => {
|
|
1047
|
+
const dedupKey = `${connectorId}:${event.path}`;
|
|
1048
|
+
const now = Date.now();
|
|
1049
|
+
const lastEmit = recentlyEmitted.get(dedupKey);
|
|
1050
|
+
if (lastEmit && now - lastEmit < dedupTtlMs) return;
|
|
1051
|
+
recentlyEmitted.set(dedupKey, now);
|
|
1052
|
+
if (recentlyEmitted.size > 200) {
|
|
1053
|
+
for (const [key, ts] of recentlyEmitted) {
|
|
1054
|
+
if (now - ts > dedupTtlMs) recentlyEmitted.delete(key);
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
watch.onFileChanged(connectorId, event);
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
1060
|
+
};
|
|
1061
|
+
const dispose = async () => {
|
|
1062
|
+
if (workspacePluginToShutdown) {
|
|
1063
|
+
try {
|
|
1064
|
+
await workspacePluginToShutdown.shutdown();
|
|
1065
|
+
} catch {
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
try {
|
|
1069
|
+
await mountMgr?.unmountAll();
|
|
1070
|
+
} catch {
|
|
1071
|
+
}
|
|
1072
|
+
try {
|
|
1073
|
+
await resourceManager?.disconnectAll();
|
|
1074
|
+
} catch {
|
|
1075
|
+
}
|
|
1076
|
+
};
|
|
1077
|
+
return {
|
|
1078
|
+
resourceManager,
|
|
1079
|
+
mountManager: mountMgr,
|
|
1080
|
+
resourcePromptSection,
|
|
1081
|
+
mcpServers,
|
|
1082
|
+
runtimeAssets,
|
|
1083
|
+
dispose,
|
|
1084
|
+
startWatching
|
|
1085
|
+
};
|
|
1086
|
+
} catch {
|
|
1087
|
+
return noopResult;
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
var RESERVED_MCP_SERVER_IDS = /* @__PURE__ */ new Set(["skaile-connectors", "skaile-workspace"]);
|
|
1091
|
+
function resolveRecordSecrets(record, secrets) {
|
|
1092
|
+
if (!secrets) return record;
|
|
1093
|
+
const resolved = {};
|
|
1094
|
+
for (const [k, v] of Object.entries(record)) {
|
|
1095
|
+
resolved[k] = secrets.resolve(v) ?? v;
|
|
1096
|
+
}
|
|
1097
|
+
return resolved;
|
|
1098
|
+
}
|
|
1099
|
+
function toSdkMcpServerConfig(decl, secrets) {
|
|
1100
|
+
const transport = decl.transport ?? "stdio";
|
|
1101
|
+
if (transport === "stdio") {
|
|
1102
|
+
if (!decl.command) return null;
|
|
1103
|
+
const cfg = { type: "stdio", command: decl.command };
|
|
1104
|
+
if (decl.args?.length) cfg.args = decl.args;
|
|
1105
|
+
if (decl.env && Object.keys(decl.env).length > 0) {
|
|
1106
|
+
cfg.env = resolveRecordSecrets(decl.env, secrets);
|
|
1107
|
+
}
|
|
1108
|
+
return cfg;
|
|
1109
|
+
}
|
|
1110
|
+
if (transport === "sse" || transport === "http") {
|
|
1111
|
+
if (!decl.url) return null;
|
|
1112
|
+
const cfg = { type: transport, url: decl.url };
|
|
1113
|
+
if (decl.headers && Object.keys(decl.headers).length > 0) {
|
|
1114
|
+
cfg.headers = resolveRecordSecrets(decl.headers, secrets);
|
|
1115
|
+
}
|
|
1116
|
+
return cfg;
|
|
1117
|
+
}
|
|
1118
|
+
return null;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
// runner/src/session-builder.ts
|
|
1122
|
+
async function createAgentSession(config) {
|
|
1123
|
+
const {
|
|
1124
|
+
projectDir,
|
|
1125
|
+
cwd: cwdOverride,
|
|
1126
|
+
agentDir,
|
|
1127
|
+
driver: driverOverride,
|
|
1128
|
+
model: modelOverride,
|
|
1129
|
+
provider: providerOverride,
|
|
1130
|
+
sessionId,
|
|
1131
|
+
resumeSessionId,
|
|
1132
|
+
externalPromptFile,
|
|
1133
|
+
wsConfig: wsConfigOverride,
|
|
1134
|
+
maxTurns: maxTurnsOverride,
|
|
1135
|
+
watch,
|
|
1136
|
+
secretProvider,
|
|
1137
|
+
onLog,
|
|
1138
|
+
telemetry,
|
|
1139
|
+
trace
|
|
1140
|
+
} = config;
|
|
1141
|
+
const agentCwd = cwdOverride ?? projectDir;
|
|
1142
|
+
const sessionLog = createLogger({
|
|
1143
|
+
kind: "runner",
|
|
1144
|
+
subkind: "session",
|
|
1145
|
+
instance: sessionId ?? "no-session"
|
|
1146
|
+
});
|
|
1147
|
+
const settings = await resolveSettings(projectDir, {
|
|
1148
|
+
driver: driverOverride,
|
|
1149
|
+
provider: providerOverride,
|
|
1150
|
+
model: modelOverride
|
|
1151
|
+
});
|
|
1152
|
+
const driverType = settings.driver ?? "omp";
|
|
1153
|
+
const provider = settings.provider;
|
|
1154
|
+
const model = settings.model;
|
|
1155
|
+
const apiKey = config.apiKey ?? resolveApiKey(provider ?? "anthropic", settings);
|
|
1156
|
+
const manifest = agentDir ? await loadAgentManifest(agentDir) : void 0;
|
|
1157
|
+
const {
|
|
1158
|
+
resourceManager,
|
|
1159
|
+
mountManager,
|
|
1160
|
+
resourcePromptSection,
|
|
1161
|
+
mcpServers,
|
|
1162
|
+
runtimeAssets,
|
|
1163
|
+
dispose,
|
|
1164
|
+
startWatching
|
|
1165
|
+
} = await buildAgentResources(
|
|
1166
|
+
projectDir,
|
|
1167
|
+
driverType,
|
|
1168
|
+
onLog,
|
|
1169
|
+
watch,
|
|
1170
|
+
secretProvider,
|
|
1171
|
+
{
|
|
1172
|
+
provider,
|
|
1173
|
+
model,
|
|
1174
|
+
sessionId
|
|
1175
|
+
},
|
|
1176
|
+
config.tokenMediator,
|
|
1177
|
+
config.preMintedSecrets
|
|
1178
|
+
);
|
|
1179
|
+
const wsConfig = wsConfigOverride ?? resolveSkWorkspaceConfig(projectDir);
|
|
1180
|
+
const contextSection = buildContextSection(wsConfig.agent?.context);
|
|
1181
|
+
const userPromptSection = wsConfig.agent?.prompt?.trim();
|
|
1182
|
+
const environmentSection = await buildEnvironmentSection(projectDir);
|
|
1183
|
+
const promptExtensions = loadPromptExtensions(
|
|
1184
|
+
wsConfig.agent?.["prompt-extensions"],
|
|
1185
|
+
projectDir,
|
|
1186
|
+
sessionLog
|
|
1187
|
+
);
|
|
1188
|
+
if (externalPromptFile) {
|
|
1189
|
+
sessionLog.warn(
|
|
1190
|
+
"externalPromptFile is deprecated and no longer injected; use agent.prompt-extensions in skaile.yaml instead"
|
|
1191
|
+
);
|
|
1192
|
+
}
|
|
1193
|
+
let composition = null;
|
|
1194
|
+
if (agentDir && manifest?.composes?.length) {
|
|
1195
|
+
composition = await resolveAgentComposition({
|
|
1196
|
+
agentDir,
|
|
1197
|
+
manifest,
|
|
1198
|
+
log: sessionLog
|
|
1199
|
+
});
|
|
1200
|
+
} else if (manifest?.composes?.length && !agentDir) {
|
|
1201
|
+
sessionLog.debug("skipping composition resolution \u2014 no agentDir available");
|
|
1202
|
+
}
|
|
1203
|
+
const compositionBlocks = composition?.inlineBlocks ?? [];
|
|
1204
|
+
const additionalSections = config.additionalPromptSections ?? [];
|
|
1205
|
+
const systemPromptSections = [];
|
|
1206
|
+
if (contextSection) systemPromptSections.push({ label: "context", value: contextSection });
|
|
1207
|
+
if (userPromptSection) systemPromptSections.push({ label: "prompt", value: userPromptSection });
|
|
1208
|
+
if (environmentSection)
|
|
1209
|
+
systemPromptSections.push({ label: "environment", value: environmentSection });
|
|
1210
|
+
if (resourcePromptSection)
|
|
1211
|
+
systemPromptSections.push({ label: "resources", value: resourcePromptSection });
|
|
1212
|
+
for (const ext of promptExtensions) {
|
|
1213
|
+
systemPromptSections.push({
|
|
1214
|
+
label: "prompt-extensions",
|
|
1215
|
+
value: ext.value,
|
|
1216
|
+
source: ext.source
|
|
1217
|
+
});
|
|
1218
|
+
}
|
|
1219
|
+
for (const block of compositionBlocks) {
|
|
1220
|
+
systemPromptSections.push({
|
|
1221
|
+
label: "composition",
|
|
1222
|
+
value: block.content,
|
|
1223
|
+
source: block.ref
|
|
1224
|
+
});
|
|
1225
|
+
}
|
|
1226
|
+
additionalSections.forEach((value, idx) => {
|
|
1227
|
+
systemPromptSections.push({
|
|
1228
|
+
label: "additional",
|
|
1229
|
+
value,
|
|
1230
|
+
source: `additional[${idx}]`
|
|
1231
|
+
});
|
|
1232
|
+
});
|
|
1233
|
+
const systemPrompt = assembleSystemPrompt([
|
|
1234
|
+
contextSection,
|
|
1235
|
+
userPromptSection,
|
|
1236
|
+
environmentSection,
|
|
1237
|
+
resourcePromptSection,
|
|
1238
|
+
...promptExtensions.map((e) => e.value),
|
|
1239
|
+
...compositionBlocks.map((b) => b.content),
|
|
1240
|
+
...additionalSections
|
|
1241
|
+
]);
|
|
1242
|
+
if (process.env.SKAILE_LOG_SYSTEM_PROMPT !== "0") {
|
|
1243
|
+
const length = systemPrompt?.length ?? 0;
|
|
1244
|
+
sessionLog.debug("assembled system prompt", { length });
|
|
1245
|
+
sessionLog.debug("system prompt content", { content: systemPrompt ?? "(empty)" });
|
|
1246
|
+
}
|
|
1247
|
+
const thinking = config.thinking ?? wsConfig.agent_config?.default?.thinking;
|
|
1248
|
+
const effort = config.effort ?? wsConfig.agent_config?.default?.effort;
|
|
1249
|
+
const maxTurns = maxTurnsOverride ?? manifest?.runtime?.max_turns;
|
|
1250
|
+
const driver = await createDriver(driverType, {
|
|
1251
|
+
cwd: agentCwd,
|
|
1252
|
+
provider,
|
|
1253
|
+
model: model ?? manifest?.model?.preferred,
|
|
1254
|
+
maxTurns,
|
|
1255
|
+
apiKeys: apiKey ? { [provider ?? "anthropic"]: apiKey } : void 0,
|
|
1256
|
+
systemPrompt,
|
|
1257
|
+
tools: manifest?.tools,
|
|
1258
|
+
...thinking ? { thinking } : {},
|
|
1259
|
+
...effort ? { effort } : {},
|
|
1260
|
+
...sessionId ? { sessionId } : {},
|
|
1261
|
+
...resumeSessionId ? { resumeSessionId } : {},
|
|
1262
|
+
...mcpServers ? { mcpServers } : {},
|
|
1263
|
+
// Protocol v2 capability dispatch hooks. When provided, the driver builds
|
|
1264
|
+
// a synthetic `skaile-capabilities` MCP server alongside any existing
|
|
1265
|
+
// mcpServers so capability invocations route through the registry's
|
|
1266
|
+
// `invoke()` (which logs + validates + handles fire-and-forget / render).
|
|
1267
|
+
...config.capabilities ? { capabilities: config.capabilities } : {},
|
|
1268
|
+
...config.aiProviderConfigId ? { aiProviderConfigId: config.aiProviderConfigId } : {},
|
|
1269
|
+
...config.onAuthError ? { onAuthError: config.onAuthError } : {},
|
|
1270
|
+
// Always forward agentDir/agentName for native identity handling
|
|
1271
|
+
...agentDir ? { agentDir, agentName: manifest?.name } : {}
|
|
1272
|
+
});
|
|
1273
|
+
if (telemetry && trace) {
|
|
1274
|
+
driver.setTelemetry(telemetry, trace);
|
|
1275
|
+
}
|
|
1276
|
+
return {
|
|
1277
|
+
driver,
|
|
1278
|
+
resourceManager,
|
|
1279
|
+
mountManager,
|
|
1280
|
+
runtimeAssets,
|
|
1281
|
+
composition,
|
|
1282
|
+
manifest,
|
|
1283
|
+
driverType,
|
|
1284
|
+
provider,
|
|
1285
|
+
model,
|
|
1286
|
+
dispose,
|
|
1287
|
+
startWatching,
|
|
1288
|
+
telemetry,
|
|
1289
|
+
systemPromptSections
|
|
1290
|
+
};
|
|
1291
|
+
}
|
|
1292
|
+
function loadPromptExtensions(paths, projectDir, log) {
|
|
1293
|
+
if (!paths?.length) return [];
|
|
1294
|
+
const result = [];
|
|
1295
|
+
for (const relPath of paths) {
|
|
1296
|
+
const absPath = resolve(projectDir, relPath);
|
|
1297
|
+
if (!existsSync(absPath)) {
|
|
1298
|
+
log.warn("prompt-extension file not found", { relPath });
|
|
1299
|
+
continue;
|
|
1300
|
+
}
|
|
1301
|
+
try {
|
|
1302
|
+
const content = readFileSync(absPath, "utf-8").trim();
|
|
1303
|
+
if (content.length > 0) result.push({ value: content, source: relPath });
|
|
1304
|
+
} catch (err) {
|
|
1305
|
+
log.warn("could not read prompt-extension", {
|
|
1306
|
+
relPath,
|
|
1307
|
+
error: err.message
|
|
1308
|
+
});
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
return result;
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
// runner/src/agent.ts
|
|
1315
|
+
var PROMPT_AGENT = `${pc.magenta(pc.bold("agent"))} ${pc.dim("\u25B6")} `;
|
|
1316
|
+
async function runAgentChat(opts) {
|
|
1317
|
+
const sessionId = `chat-${Date.now().toString(36)}`;
|
|
1318
|
+
const { dispose: disposeLogStore } = bootstrapRunnerLogStore({
|
|
1319
|
+
sessionId,
|
|
1320
|
+
projectDir: opts.projectDir,
|
|
1321
|
+
onLog: opts.onLog
|
|
1322
|
+
});
|
|
1323
|
+
const chatLog = createLogger({
|
|
1324
|
+
kind: "runner",
|
|
1325
|
+
subkind: "session",
|
|
1326
|
+
instance: sessionId
|
|
1327
|
+
});
|
|
1328
|
+
const agentSession = await buildDriver(opts);
|
|
1329
|
+
const driver = agentSession.driver;
|
|
1330
|
+
await driver.start();
|
|
1331
|
+
let firstChunk = true;
|
|
1332
|
+
const mdStream = new MarkdownStreamer();
|
|
1333
|
+
driver.on("agent-event", (event) => {
|
|
1334
|
+
opts.onEvent?.(event);
|
|
1335
|
+
if (event.type === "message_update") {
|
|
1336
|
+
const delta = event._textDelta;
|
|
1337
|
+
if (delta) {
|
|
1338
|
+
if (firstChunk) {
|
|
1339
|
+
process.stdout.write(PROMPT_AGENT);
|
|
1340
|
+
firstChunk = false;
|
|
1341
|
+
}
|
|
1342
|
+
mdStream.write(delta);
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
});
|
|
1346
|
+
let message = opts.message;
|
|
1347
|
+
if (opts.skill) {
|
|
1348
|
+
message = `Skill: ${opts.skill}
|
|
1349
|
+
|
|
1350
|
+
${message}`;
|
|
1351
|
+
}
|
|
1352
|
+
try {
|
|
1353
|
+
await new Promise((resolve3, reject) => {
|
|
1354
|
+
const onEvent = (event) => {
|
|
1355
|
+
if (event.type === "agent_end") {
|
|
1356
|
+
driver.off("agent-event", onEvent);
|
|
1357
|
+
mdStream.end();
|
|
1358
|
+
process.stdout.write("\n");
|
|
1359
|
+
driver.kill();
|
|
1360
|
+
resolve3();
|
|
1361
|
+
} else if (event.type === "error") {
|
|
1362
|
+
driver.off("agent-event", onEvent);
|
|
1363
|
+
const err = new Error(String(event.error));
|
|
1364
|
+
chatLog.error("agent emitted error event", err);
|
|
1365
|
+
driver.kill();
|
|
1366
|
+
reject(err);
|
|
1367
|
+
}
|
|
1368
|
+
};
|
|
1369
|
+
driver.on("agent-event", onEvent);
|
|
1370
|
+
driver.prompt(message).catch((err) => {
|
|
1371
|
+
driver.off("agent-event", onEvent);
|
|
1372
|
+
chatLog.error("prompt failed", err);
|
|
1373
|
+
driver.kill();
|
|
1374
|
+
reject(err);
|
|
1375
|
+
});
|
|
1376
|
+
});
|
|
1377
|
+
} finally {
|
|
1378
|
+
await agentSession.dispose();
|
|
1379
|
+
disposeLogStore();
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
async function buildDriver(opts) {
|
|
1383
|
+
const agentDir = opts.agentDir ?? resolveAgentDir(opts.projectDir);
|
|
1384
|
+
return createAgentSession({
|
|
1385
|
+
projectDir: opts.projectDir,
|
|
1386
|
+
agentDir,
|
|
1387
|
+
driver: opts.driver,
|
|
1388
|
+
model: opts.model,
|
|
1389
|
+
provider: opts.provider,
|
|
1390
|
+
promptsDir: opts.promptsDir,
|
|
1391
|
+
onLog: opts.onLog
|
|
1392
|
+
});
|
|
1393
|
+
}
|
|
1394
|
+
async function handleResourceRequest(command, manager, emit) {
|
|
1395
|
+
const { requestId, connectorId, operation, path: path5, options, content } = command;
|
|
1396
|
+
try {
|
|
1397
|
+
let data;
|
|
1398
|
+
switch (operation) {
|
|
1399
|
+
case "list":
|
|
1400
|
+
data = await manager.list(
|
|
1401
|
+
connectorId,
|
|
1402
|
+
path5,
|
|
1403
|
+
options
|
|
1404
|
+
);
|
|
1405
|
+
break;
|
|
1406
|
+
case "read":
|
|
1407
|
+
data = await manager.read(connectorId, path5);
|
|
1408
|
+
break;
|
|
1409
|
+
case "write":
|
|
1410
|
+
await manager.write(connectorId, path5, content);
|
|
1411
|
+
data = true;
|
|
1412
|
+
break;
|
|
1413
|
+
case "delete":
|
|
1414
|
+
data = await manager.delete(connectorId, path5);
|
|
1415
|
+
break;
|
|
1416
|
+
case "search":
|
|
1417
|
+
data = await manager.search(
|
|
1418
|
+
connectorId,
|
|
1419
|
+
path5,
|
|
1420
|
+
options
|
|
1421
|
+
);
|
|
1422
|
+
break;
|
|
1423
|
+
}
|
|
1424
|
+
emit({ type: "resource_response", requestId, resourceId: connectorId, operation, data });
|
|
1425
|
+
} catch (err) {
|
|
1426
|
+
emit({
|
|
1427
|
+
type: "resource_response",
|
|
1428
|
+
requestId,
|
|
1429
|
+
resourceId: connectorId,
|
|
1430
|
+
operation,
|
|
1431
|
+
error: err instanceof Error ? err.message : String(err)
|
|
1432
|
+
});
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
function getMimeType(filename) {
|
|
1436
|
+
return mime.getType(filename) ?? "application/octet-stream";
|
|
1437
|
+
}
|
|
1438
|
+
function isBinaryFile(filePath) {
|
|
1439
|
+
try {
|
|
1440
|
+
const fd = openSync(filePath, "r");
|
|
1441
|
+
const buf = Buffer.alloc(8192);
|
|
1442
|
+
const bytesRead = readSync(fd, buf, 0, 8192, 0);
|
|
1443
|
+
closeSync(fd);
|
|
1444
|
+
for (let i = 0; i < bytesRead; i++) {
|
|
1445
|
+
if (buf[i] === 0) return true;
|
|
1446
|
+
}
|
|
1447
|
+
return false;
|
|
1448
|
+
} catch {
|
|
1449
|
+
return false;
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
function handleMountResourceRequest(command, volManager, emit) {
|
|
1453
|
+
const { requestId, connectorId: mountId, operation, path: reqPath, content, options } = command;
|
|
1454
|
+
if (options?._customOp === "resolveWebUrl") {
|
|
1455
|
+
void (async () => {
|
|
1456
|
+
try {
|
|
1457
|
+
const vol = volManager.get(mountId);
|
|
1458
|
+
const driver = vol.driver;
|
|
1459
|
+
const url = typeof driver.resolveWebUrl === "function" ? await driver.resolveWebUrl(vol.handle, reqPath ?? "") : null;
|
|
1460
|
+
emit({ type: "resource_response", requestId, resourceId: mountId, operation, data: url });
|
|
1461
|
+
} catch (err) {
|
|
1462
|
+
emit({
|
|
1463
|
+
type: "resource_response",
|
|
1464
|
+
requestId,
|
|
1465
|
+
resourceId: mountId,
|
|
1466
|
+
operation,
|
|
1467
|
+
error: err instanceof Error ? err.message : String(err)
|
|
1468
|
+
});
|
|
1469
|
+
}
|
|
1470
|
+
})();
|
|
1471
|
+
return;
|
|
1472
|
+
}
|
|
1473
|
+
try {
|
|
1474
|
+
const vol = volManager.get(mountId);
|
|
1475
|
+
const mountPath = vol.handle.mountPath;
|
|
1476
|
+
const targetPath = reqPath ? resolve(mountPath, reqPath) : mountPath;
|
|
1477
|
+
if (!targetPath.startsWith(mountPath)) {
|
|
1478
|
+
throw new Error("Path traversal outside mount");
|
|
1479
|
+
}
|
|
1480
|
+
let data;
|
|
1481
|
+
switch (operation) {
|
|
1482
|
+
case "list": {
|
|
1483
|
+
const entries = readdirSync(targetPath, { withFileTypes: true });
|
|
1484
|
+
data = entries.filter((e) => !e.name.startsWith(".")).map((e) => {
|
|
1485
|
+
const entryPath = reqPath ? join(reqPath, e.name) : e.name;
|
|
1486
|
+
const result = {
|
|
1487
|
+
name: e.name,
|
|
1488
|
+
path: entryPath,
|
|
1489
|
+
type: e.isDirectory() ? "directory" : "file"
|
|
1490
|
+
};
|
|
1491
|
+
if (!e.isDirectory()) {
|
|
1492
|
+
try {
|
|
1493
|
+
result.size = statSync(join(targetPath, e.name)).size;
|
|
1494
|
+
} catch {
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
return result;
|
|
1498
|
+
});
|
|
1499
|
+
break;
|
|
1500
|
+
}
|
|
1501
|
+
case "read": {
|
|
1502
|
+
const contentType = getMimeType(basename(targetPath));
|
|
1503
|
+
if (isBinaryFile(targetPath)) {
|
|
1504
|
+
const buf = readFileSync(targetPath);
|
|
1505
|
+
data = {
|
|
1506
|
+
data: buf.toString("base64"),
|
|
1507
|
+
contentType,
|
|
1508
|
+
encoding: "binary"
|
|
1509
|
+
};
|
|
1510
|
+
} else {
|
|
1511
|
+
data = {
|
|
1512
|
+
data: readFileSync(targetPath, "utf-8"),
|
|
1513
|
+
contentType,
|
|
1514
|
+
encoding: "utf-8"
|
|
1515
|
+
};
|
|
1516
|
+
}
|
|
1517
|
+
break;
|
|
1518
|
+
}
|
|
1519
|
+
case "write": {
|
|
1520
|
+
const writeContent = typeof content === "string" ? content : content?.data ?? "";
|
|
1521
|
+
writeFileSync(targetPath, writeContent, "utf-8");
|
|
1522
|
+
data = true;
|
|
1523
|
+
break;
|
|
1524
|
+
}
|
|
1525
|
+
case "delete": {
|
|
1526
|
+
unlinkSync(targetPath);
|
|
1527
|
+
data = true;
|
|
1528
|
+
break;
|
|
1529
|
+
}
|
|
1530
|
+
default:
|
|
1531
|
+
throw new Error(`Unsupported operation for mount: ${operation}`);
|
|
1532
|
+
}
|
|
1533
|
+
emit({ type: "resource_response", requestId, resourceId: mountId, operation, data });
|
|
1534
|
+
} catch (err) {
|
|
1535
|
+
emit({
|
|
1536
|
+
type: "resource_response",
|
|
1537
|
+
requestId,
|
|
1538
|
+
resourceId: mountId,
|
|
1539
|
+
operation,
|
|
1540
|
+
error: err instanceof Error ? err.message : String(err)
|
|
1541
|
+
});
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
// runner/src/refresh-flag-dispatcher.ts
|
|
1546
|
+
async function dispatchRefreshToExposedGitMounts(mountManager, log) {
|
|
1547
|
+
if (!mountManager) return;
|
|
1548
|
+
let gitMounts;
|
|
1549
|
+
try {
|
|
1550
|
+
gitMounts = mountManager.listGitMounts();
|
|
1551
|
+
} catch (err) {
|
|
1552
|
+
log.warn("listGitMounts failed during refresh-flag dispatch", {
|
|
1553
|
+
error: err instanceof Error ? err.message : String(err)
|
|
1554
|
+
});
|
|
1555
|
+
return;
|
|
1556
|
+
}
|
|
1557
|
+
const eligible = gitMounts.filter((m) => m.exposeAccessToken === true && m.auth === "backend");
|
|
1558
|
+
if (eligible.length === 0) {
|
|
1559
|
+
log.debug("refresh-flag fired but no eligible git mounts (Tier-2 backend) found");
|
|
1560
|
+
return;
|
|
1561
|
+
}
|
|
1562
|
+
log.info("refresh-flag fired -- dispatching backend mediation", {
|
|
1563
|
+
mountIds: eligible.map((m) => m.id)
|
|
1564
|
+
});
|
|
1565
|
+
await Promise.all(
|
|
1566
|
+
eligible.map(async (m) => {
|
|
1567
|
+
try {
|
|
1568
|
+
const entry = mountManager.get(m.id);
|
|
1569
|
+
if (typeof entry.driver.refreshExposedCredential !== "function") {
|
|
1570
|
+
log.debug("driver lacks refreshExposedCredential -- skipping", {
|
|
1571
|
+
mountId: m.id
|
|
1572
|
+
});
|
|
1573
|
+
return;
|
|
1574
|
+
}
|
|
1575
|
+
await entry.driver.refreshExposedCredential(m.id, entry.handle);
|
|
1576
|
+
} catch (err) {
|
|
1577
|
+
log.warn("refresh-flag dispatch failed for mount", {
|
|
1578
|
+
mountId: m.id,
|
|
1579
|
+
error: err instanceof Error ? err.message : String(err)
|
|
1580
|
+
});
|
|
1581
|
+
}
|
|
1582
|
+
})
|
|
1583
|
+
);
|
|
1584
|
+
}
|
|
1585
|
+
function keywordSearch(capabilities, query, limit) {
|
|
1586
|
+
const tokens = query.toLowerCase().split(/\s+/).filter((t) => t.length > 0);
|
|
1587
|
+
if (tokens.length === 0) return capabilities.slice(0, limit);
|
|
1588
|
+
const scored = capabilities.map((cap) => {
|
|
1589
|
+
const haystack = [cap.name, cap.description, cap.promptFragment ?? ""].join(" ").toLowerCase();
|
|
1590
|
+
let score = 0;
|
|
1591
|
+
for (const token of tokens) {
|
|
1592
|
+
if (haystack.includes(token)) score += 1;
|
|
1593
|
+
}
|
|
1594
|
+
return { cap, score };
|
|
1595
|
+
}).filter((x) => x.score > 0).sort((a, b) => b.score - a.score);
|
|
1596
|
+
return scored.slice(0, limit).map((x) => x.cap);
|
|
1597
|
+
}
|
|
1598
|
+
function builtinCapabilities(registry) {
|
|
1599
|
+
const listFilterSchema = z4.object({
|
|
1600
|
+
side: z4.enum(["client", "agent"]).optional(),
|
|
1601
|
+
originKind: z4.enum(["framework", "client", "agent", "flow", "skill", "mcp", "connector", "mount"]).optional(),
|
|
1602
|
+
scope: z4.enum(["session", "turn"]).optional()
|
|
1603
|
+
}).strict();
|
|
1604
|
+
return [
|
|
1605
|
+
defineCapability({
|
|
1606
|
+
name: "__capabilities.list",
|
|
1607
|
+
displayName: "List capabilities",
|
|
1608
|
+
description: "List available capabilities in this session. Optionally filter by side, origin kind, or scope.",
|
|
1609
|
+
side: "agent",
|
|
1610
|
+
origin: { kind: "framework" },
|
|
1611
|
+
kind: "query",
|
|
1612
|
+
userInvokable: false,
|
|
1613
|
+
input: listFilterSchema,
|
|
1614
|
+
handler: async (args) => registry.list({
|
|
1615
|
+
side: args.side,
|
|
1616
|
+
origin: args.originKind,
|
|
1617
|
+
scope: args.scope
|
|
1618
|
+
})
|
|
1619
|
+
}),
|
|
1620
|
+
defineCapability({
|
|
1621
|
+
name: "__capabilities.search",
|
|
1622
|
+
displayName: "Search capabilities",
|
|
1623
|
+
description: "Keyword search across capability names, descriptions, and prompt fragments. Returns the top matches by score (substring match count).",
|
|
1624
|
+
side: "agent",
|
|
1625
|
+
origin: { kind: "framework" },
|
|
1626
|
+
kind: "query",
|
|
1627
|
+
userInvokable: false,
|
|
1628
|
+
input: z4.object({
|
|
1629
|
+
query: z4.string(),
|
|
1630
|
+
limit: z4.number().int().positive().optional()
|
|
1631
|
+
}).strict(),
|
|
1632
|
+
handler: async ({ query, limit }) => keywordSearch(registry.list(), query, limit ?? 10)
|
|
1633
|
+
}),
|
|
1634
|
+
defineCapability({
|
|
1635
|
+
name: "__capabilities.describe",
|
|
1636
|
+
displayName: "Describe capability",
|
|
1637
|
+
description: "Return the full Capability descriptor for a single capability by name.",
|
|
1638
|
+
side: "agent",
|
|
1639
|
+
origin: { kind: "framework" },
|
|
1640
|
+
kind: "query",
|
|
1641
|
+
userInvokable: false,
|
|
1642
|
+
input: z4.object({ name: z4.string() }).strict(),
|
|
1643
|
+
handler: async ({ name }) => {
|
|
1644
|
+
const cap = registry.resolve(name);
|
|
1645
|
+
if (!cap) return null;
|
|
1646
|
+
const wire = registry.list().find((c) => c.name === name);
|
|
1647
|
+
return wire ?? null;
|
|
1648
|
+
}
|
|
1649
|
+
})
|
|
1650
|
+
];
|
|
1651
|
+
}
|
|
1652
|
+
function bootstrapCapabilityRegistry(registry) {
|
|
1653
|
+
for (const cap of builtinCapabilities(registry)) {
|
|
1654
|
+
registry.register(cap, "agent");
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
var CLAUDE_CODE_CREDENTIALS_KEY = "CLAUDE_CODE_CREDENTIALS_JSON";
|
|
1658
|
+
async function writeClaudeCodeCredentialsFile(home, json) {
|
|
1659
|
+
const claudeDir = join(home, ".claude");
|
|
1660
|
+
await mkdir(claudeDir, { recursive: true, mode: 448 });
|
|
1661
|
+
const finalPath = join(claudeDir, ".credentials.json");
|
|
1662
|
+
const tmpPath = `${finalPath}.tmp.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
1663
|
+
await writeFile(tmpPath, json, { mode: 384 });
|
|
1664
|
+
await rename(tmpPath, finalPath);
|
|
1665
|
+
return finalPath;
|
|
1666
|
+
}
|
|
1667
|
+
async function mergeAndRewriteCredentialsFile(home, accessToken, expiresAt) {
|
|
1668
|
+
const credPath = join(home, ".claude", ".credentials.json");
|
|
1669
|
+
let merged = {};
|
|
1670
|
+
if (existsSync(credPath)) {
|
|
1671
|
+
try {
|
|
1672
|
+
merged = JSON.parse(readFileSync(credPath, "utf-8"));
|
|
1673
|
+
} catch {
|
|
1674
|
+
merged = {};
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
const oauthBlock = merged.claudeAiOauth ?? {};
|
|
1678
|
+
oauthBlock.accessToken = accessToken;
|
|
1679
|
+
if (expiresAt) oauthBlock.expiresAt = expiresAt;
|
|
1680
|
+
merged.claudeAiOauth = oauthBlock;
|
|
1681
|
+
merged.accessToken = accessToken;
|
|
1682
|
+
return writeClaudeCodeCredentialsFile(home, JSON.stringify(merged));
|
|
1683
|
+
}
|
|
1684
|
+
var DEFAULT_AUDIENCE = ["llm", "user"];
|
|
1685
|
+
function audienceOf(cap) {
|
|
1686
|
+
return cap.audience ?? DEFAULT_AUDIENCE;
|
|
1687
|
+
}
|
|
1688
|
+
function hasAudience(cap, target) {
|
|
1689
|
+
return audienceOf(cap).includes(target);
|
|
1690
|
+
}
|
|
1691
|
+
var ORIGIN_PROMPT_ORDER = [
|
|
1692
|
+
"framework",
|
|
1693
|
+
"client",
|
|
1694
|
+
"agent",
|
|
1695
|
+
"flow",
|
|
1696
|
+
"skill",
|
|
1697
|
+
"mcp",
|
|
1698
|
+
"connector",
|
|
1699
|
+
"mount"
|
|
1700
|
+
];
|
|
1701
|
+
var CapabilityRegistry = class {
|
|
1702
|
+
byName = /* @__PURE__ */ new Map();
|
|
1703
|
+
logger;
|
|
1704
|
+
remoteInvoker;
|
|
1705
|
+
constructor(logger) {
|
|
1706
|
+
this.logger = logger ?? createLogger({ kind: "runner", subkind: "capability-registry" });
|
|
1707
|
+
}
|
|
1708
|
+
/**
|
|
1709
|
+
* Install the platform-bound invoker used by {@link invokeRemote}.
|
|
1710
|
+
*
|
|
1711
|
+
* The runner wires this up after the transport is connected and the
|
|
1712
|
+
* per-session pending-call map is in place. Idempotent — repeated calls
|
|
1713
|
+
* replace the prior invoker.
|
|
1714
|
+
*
|
|
1715
|
+
* @category Runtime
|
|
1716
|
+
* @since 3.0.0
|
|
1717
|
+
*/
|
|
1718
|
+
setRemoteInvoker(invoker) {
|
|
1719
|
+
this.remoteInvoker = invoker;
|
|
1720
|
+
}
|
|
1721
|
+
/**
|
|
1722
|
+
* Invoke a `host.*` (or other peer-side) capability on the platform.
|
|
1723
|
+
*
|
|
1724
|
+
* Composes a `capability_invoked` event under the hood and resolves with
|
|
1725
|
+
* the matching `capability_result` payload. Infrastructure failures
|
|
1726
|
+
* (timeout, schema mismatch, transport disconnect) reject with `Error`;
|
|
1727
|
+
* domain failures (e.g. `{ ok: false, code }` for credential mints) ride
|
|
1728
|
+
* in the resolved payload.
|
|
1729
|
+
*
|
|
1730
|
+
* @category Runtime
|
|
1731
|
+
* @since 3.0.0
|
|
1732
|
+
*/
|
|
1733
|
+
async invokeRemote(name, input) {
|
|
1734
|
+
if (!this.remoteInvoker) {
|
|
1735
|
+
throw new Error(
|
|
1736
|
+
`Capability '${name}' invoked remotely but no remote invoker is wired. Call CapabilityRegistry.setRemoteInvoker(...) before dispatch.`
|
|
1737
|
+
);
|
|
1738
|
+
}
|
|
1739
|
+
return this.remoteInvoker(name, input);
|
|
1740
|
+
}
|
|
1741
|
+
/**
|
|
1742
|
+
* Register a capability. Validates that the registering `source` is
|
|
1743
|
+
* permitted to declare the capability's `origin.kind`; mismatches are
|
|
1744
|
+
* dropped with a warning so untrusted callers cannot impersonate other
|
|
1745
|
+
* registration sources.
|
|
1746
|
+
*
|
|
1747
|
+
* Allowed combinations:
|
|
1748
|
+
* - source `'agent'`: origins `framework | agent | flow | skill | mcp | connector | mount`
|
|
1749
|
+
* - source `'client'`: origin `client` only
|
|
1750
|
+
*
|
|
1751
|
+
* @param cap - capability to register (typically built via {@link defineCapability})
|
|
1752
|
+
* @param source - which side is doing the registration
|
|
1753
|
+
*/
|
|
1754
|
+
register(cap, source) {
|
|
1755
|
+
if (!this.isOriginAllowed(source, cap.origin)) {
|
|
1756
|
+
this.logger.warn("capability registration rejected (origin mismatch)", {
|
|
1757
|
+
name: cap.name,
|
|
1758
|
+
source,
|
|
1759
|
+
originKind: cap.origin.kind
|
|
1760
|
+
});
|
|
1761
|
+
return;
|
|
1762
|
+
}
|
|
1763
|
+
this.byName.set(cap.name, cap);
|
|
1764
|
+
this.logger.info("capability registered", {
|
|
1765
|
+
name: cap.name,
|
|
1766
|
+
side: cap.side,
|
|
1767
|
+
originKind: cap.origin.kind
|
|
1768
|
+
});
|
|
1769
|
+
}
|
|
1770
|
+
/**
|
|
1771
|
+
* Remove a capability by name. No-op when the name is unknown.
|
|
1772
|
+
*
|
|
1773
|
+
* @param name - capability name
|
|
1774
|
+
*/
|
|
1775
|
+
deregister(name) {
|
|
1776
|
+
if (this.byName.delete(name)) {
|
|
1777
|
+
this.logger.info("capability deregistered", { name });
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
/**
|
|
1781
|
+
* List capabilities, optionally filtering by `side`, `origin` kind, or
|
|
1782
|
+
* `scope`. Returns the wire-format {@link Capability} shape (no internal
|
|
1783
|
+
* Zod schemas or handlers).
|
|
1784
|
+
*/
|
|
1785
|
+
list(filter) {
|
|
1786
|
+
const all = Array.from(this.byName.values());
|
|
1787
|
+
const matching = filter ? all.filter(
|
|
1788
|
+
(c) => (filter.side === void 0 || c.side === filter.side) && (filter.origin === void 0 || c.origin.kind === filter.origin) && (filter.scope === void 0 || c.scope === filter.scope)
|
|
1789
|
+
) : all;
|
|
1790
|
+
return matching.map((c) => this.toWire(c));
|
|
1791
|
+
}
|
|
1792
|
+
/**
|
|
1793
|
+
* Resolve a capability by name. Returns the full {@link DefinedCapability}
|
|
1794
|
+
* (including the original Zod schemas + handler) for use by the bridge.
|
|
1795
|
+
*
|
|
1796
|
+
* @returns the capability or `null` when the name is not registered
|
|
1797
|
+
*/
|
|
1798
|
+
resolve(name) {
|
|
1799
|
+
return this.byName.get(name) ?? null;
|
|
1800
|
+
}
|
|
1801
|
+
/**
|
|
1802
|
+
* Build LLM tool descriptors for every registered capability whose
|
|
1803
|
+
* audience includes `'llm'` (the default when {@link Capability.audience}
|
|
1804
|
+
* is omitted). Bridge drivers consume this output directly when
|
|
1805
|
+
* assembling the tool list passed to the underlying LLM SDK.
|
|
1806
|
+
*
|
|
1807
|
+
* Capabilities scoped to `'runtime'` only (e.g. `host.refresh_credential`,
|
|
1808
|
+
* `runner.add_mount`) are filtered out so they never reach the model.
|
|
1809
|
+
*/
|
|
1810
|
+
composeLLMTools() {
|
|
1811
|
+
return Array.from(this.byName.values()).filter((c) => hasAudience(c, "llm")).map((c) => ({
|
|
1812
|
+
name: c.name,
|
|
1813
|
+
description: c.description,
|
|
1814
|
+
parameters: c.inputSchema
|
|
1815
|
+
}));
|
|
1816
|
+
}
|
|
1817
|
+
/**
|
|
1818
|
+
* Compose a deterministic prompt section from every registered
|
|
1819
|
+
* capability whose audience includes `'llm'`. Ordering matches
|
|
1820
|
+
* `ORIGIN_PROMPT_ORDER` (framework first, then client, then agent-side
|
|
1821
|
+
* surfaces) so the agent sees a stable layout. Capabilities without a
|
|
1822
|
+
* `promptFragment` are skipped.
|
|
1823
|
+
*/
|
|
1824
|
+
composePromptSection() {
|
|
1825
|
+
const groups = /* @__PURE__ */ new Map();
|
|
1826
|
+
for (const cap of this.byName.values()) {
|
|
1827
|
+
if (!cap.promptFragment) continue;
|
|
1828
|
+
if (!hasAudience(cap, "llm")) continue;
|
|
1829
|
+
const arr = groups.get(cap.origin.kind) ?? [];
|
|
1830
|
+
arr.push(cap.promptFragment);
|
|
1831
|
+
groups.set(cap.origin.kind, arr);
|
|
1832
|
+
}
|
|
1833
|
+
const lines = [];
|
|
1834
|
+
for (const kind of ORIGIN_PROMPT_ORDER) {
|
|
1835
|
+
const fragments = groups.get(kind);
|
|
1836
|
+
if (!fragments?.length) continue;
|
|
1837
|
+
for (const fragment of fragments) {
|
|
1838
|
+
lines.push(fragment);
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
return lines.join("\n\n");
|
|
1842
|
+
}
|
|
1843
|
+
/**
|
|
1844
|
+
* Serialize the registry to wire-format capabilities for hibernation. The
|
|
1845
|
+
* runtime fields (`inputZod`, `outputZod`, `handler`) are dropped; only
|
|
1846
|
+
* the wire shape is kept.
|
|
1847
|
+
*/
|
|
1848
|
+
serialize() {
|
|
1849
|
+
return Array.from(this.byName.values()).map((c) => this.toWire(c));
|
|
1850
|
+
}
|
|
1851
|
+
/**
|
|
1852
|
+
* Replay a wire snapshot taken via {@link serialize}. Wire-only capabilities
|
|
1853
|
+
* (no handler) are stored so {@link list} / {@link composeLLMTools} return
|
|
1854
|
+
* a complete picture; agent-side surfaces are expected to re-register
|
|
1855
|
+
* fully (with handlers) from their original sources on wake.
|
|
1856
|
+
*
|
|
1857
|
+
* Per the v2 design, only `client`-side capabilities are persisted across
|
|
1858
|
+
* hibernation by this method — agent-side ones come back via the
|
|
1859
|
+
* skill / flow / connector / mount adapters. Snapshot entries from other
|
|
1860
|
+
* origins are skipped on hydrate.
|
|
1861
|
+
*/
|
|
1862
|
+
hydrate(snapshot) {
|
|
1863
|
+
for (const cap of snapshot) {
|
|
1864
|
+
if (cap.origin.kind !== "client") continue;
|
|
1865
|
+
const stub = {
|
|
1866
|
+
...cap,
|
|
1867
|
+
inputZod: HYDRATED_PASSTHROUGH_ZOD,
|
|
1868
|
+
outputZod: void 0,
|
|
1869
|
+
handler: HYDRATED_REJECT_HANDLER
|
|
1870
|
+
};
|
|
1871
|
+
this.byName.set(cap.name, stub);
|
|
1872
|
+
}
|
|
1873
|
+
this.logger.info("capability registry hydrated", { count: snapshot.length });
|
|
1874
|
+
}
|
|
1875
|
+
/**
|
|
1876
|
+
* Invoke a registered capability. Validates the input against the Zod
|
|
1877
|
+
* schema, builds the per-handler logger, and runs the handler. Logs
|
|
1878
|
+
* `info "invoking"` and `info "ok"` (or `error "failed"`) under the
|
|
1879
|
+
* `capability:<origin>:<name>` slice for every call.
|
|
1880
|
+
*
|
|
1881
|
+
* @throws when the capability is unknown or the input fails validation
|
|
1882
|
+
*/
|
|
1883
|
+
async invoke(name, input, baseCtx) {
|
|
1884
|
+
const cap = this.resolve(name);
|
|
1885
|
+
if (!cap) {
|
|
1886
|
+
throw new Error(`Unknown capability: ${name}`);
|
|
1887
|
+
}
|
|
1888
|
+
const log = createLogger({
|
|
1889
|
+
kind: "capability",
|
|
1890
|
+
subkind: cap.origin.kind,
|
|
1891
|
+
instance: cap.name
|
|
1892
|
+
});
|
|
1893
|
+
log.info("invoking", { input });
|
|
1894
|
+
try {
|
|
1895
|
+
const validated = cap.inputZod.parse(input);
|
|
1896
|
+
const result = await cap.handler(validated, { ...baseCtx, log });
|
|
1897
|
+
log.info("ok", { output: result });
|
|
1898
|
+
return result;
|
|
1899
|
+
} catch (err) {
|
|
1900
|
+
log.error("failed", err);
|
|
1901
|
+
throw err;
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
/** True when `source` is allowed to register the given `origin`. */
|
|
1905
|
+
isOriginAllowed(source, origin) {
|
|
1906
|
+
if (source === "client") {
|
|
1907
|
+
return origin.kind === "client";
|
|
1908
|
+
}
|
|
1909
|
+
return origin.kind !== "client";
|
|
1910
|
+
}
|
|
1911
|
+
/** Strip the runtime-only fields from a {@link DefinedCapability}. */
|
|
1912
|
+
toWire(cap) {
|
|
1913
|
+
return {
|
|
1914
|
+
name: cap.name,
|
|
1915
|
+
displayName: cap.displayName,
|
|
1916
|
+
description: cap.description,
|
|
1917
|
+
inputSchema: cap.inputSchema,
|
|
1918
|
+
outputSchema: cap.outputSchema,
|
|
1919
|
+
side: cap.side,
|
|
1920
|
+
origin: cap.origin,
|
|
1921
|
+
scope: cap.scope,
|
|
1922
|
+
fireAndForget: cap.fireAndForget,
|
|
1923
|
+
requiresApproval: cap.requiresApproval,
|
|
1924
|
+
kind: cap.kind,
|
|
1925
|
+
userInvokable: cap.userInvokable,
|
|
1926
|
+
audience: cap.audience,
|
|
1927
|
+
promptFragment: cap.promptFragment,
|
|
1928
|
+
render: cap.render
|
|
1929
|
+
};
|
|
1930
|
+
}
|
|
1931
|
+
};
|
|
1932
|
+
function computeCapabilitySignature(caps) {
|
|
1933
|
+
const canonical = caps.slice().sort((a, b) => a.name.localeCompare(b.name)).map((c) => ({
|
|
1934
|
+
name: c.name,
|
|
1935
|
+
origin: c.origin.kind,
|
|
1936
|
+
schemaSha256: sha256(JSON.stringify(c.inputSchema ?? {}))
|
|
1937
|
+
}));
|
|
1938
|
+
return sha256(JSON.stringify(canonical));
|
|
1939
|
+
}
|
|
1940
|
+
function sha256(input) {
|
|
1941
|
+
return createHash("sha256").update(input).digest("hex");
|
|
1942
|
+
}
|
|
1943
|
+
var HYDRATED_PASSTHROUGH_ZOD = {
|
|
1944
|
+
parse: (v) => v
|
|
1945
|
+
// The full Zod surface is not required here — `parse` is the only method
|
|
1946
|
+
// used by `invoke`, and hydrated stubs are not expected to be invoked
|
|
1947
|
+
// before the platform resends the live capability via configure.
|
|
1948
|
+
};
|
|
1949
|
+
var HYDRATED_REJECT_HANDLER = async () => {
|
|
1950
|
+
throw new Error(
|
|
1951
|
+
"Hydrated capability stub cannot be invoked \u2014 re-register via ConfigureCommand on wake."
|
|
1952
|
+
);
|
|
1953
|
+
};
|
|
1954
|
+
|
|
1955
|
+
// runner/src/capability-roundtrip.ts
|
|
1956
|
+
var DEFAULT_CAPABILITY_CALL_TIMEOUT_MS = 6e4;
|
|
1957
|
+
function buildClientCapabilityHandler(args) {
|
|
1958
|
+
const timeoutMs = args.timeoutMs ?? DEFAULT_CAPABILITY_CALL_TIMEOUT_MS;
|
|
1959
|
+
const gen = args.generateCallId ?? (() => `cap-${Date.now()}-${Math.floor(Math.random() * 1e9)}`);
|
|
1960
|
+
return async (input) => {
|
|
1961
|
+
const callId = gen();
|
|
1962
|
+
if (args.wire.fireAndForget) {
|
|
1963
|
+
args.emit({
|
|
1964
|
+
type: "capability_invoked",
|
|
1965
|
+
callId,
|
|
1966
|
+
name: args.wire.name,
|
|
1967
|
+
input,
|
|
1968
|
+
invokedBy: "agent"
|
|
1969
|
+
});
|
|
1970
|
+
return {};
|
|
1971
|
+
}
|
|
1972
|
+
return new Promise((resolve3, reject) => {
|
|
1973
|
+
const timer = setTimeout(() => {
|
|
1974
|
+
args.pending.delete(callId);
|
|
1975
|
+
reject(
|
|
1976
|
+
new Error(
|
|
1977
|
+
`Capability ${args.wire.name} (callId=${callId}) timed out after ${timeoutMs}ms`
|
|
1978
|
+
)
|
|
1979
|
+
);
|
|
1980
|
+
}, timeoutMs);
|
|
1981
|
+
args.pending.set(callId, { resolve: resolve3, reject, timer });
|
|
1982
|
+
args.emit({
|
|
1983
|
+
type: "capability_invoked",
|
|
1984
|
+
callId,
|
|
1985
|
+
name: args.wire.name,
|
|
1986
|
+
input,
|
|
1987
|
+
invokedBy: "agent"
|
|
1988
|
+
});
|
|
1989
|
+
});
|
|
1990
|
+
};
|
|
1991
|
+
}
|
|
1992
|
+
function resolveCapabilityResult(pending, cmd) {
|
|
1993
|
+
const entry = pending.get(cmd.callId);
|
|
1994
|
+
if (!entry) return false;
|
|
1995
|
+
clearTimeout(entry.timer);
|
|
1996
|
+
pending.delete(cmd.callId);
|
|
1997
|
+
const result = cmd.result;
|
|
1998
|
+
if (result && typeof result === "object" && "error" in result) {
|
|
1999
|
+
entry.reject(new Error(String(result.error)));
|
|
2000
|
+
} else {
|
|
2001
|
+
entry.resolve(result);
|
|
2002
|
+
}
|
|
2003
|
+
return true;
|
|
2004
|
+
}
|
|
2005
|
+
function rejectCapabilityOnApprovalDeny(pending, callId, feedback) {
|
|
2006
|
+
const entry = pending.get(callId);
|
|
2007
|
+
if (!entry) return false;
|
|
2008
|
+
clearTimeout(entry.timer);
|
|
2009
|
+
pending.delete(callId);
|
|
2010
|
+
entry.reject(new Error(feedback ?? "declined by user"));
|
|
2011
|
+
return true;
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
// runner/src/compaction/strategy.ts
|
|
2015
|
+
var TokenThresholdStrategy = class {
|
|
2016
|
+
thresholdPercent;
|
|
2017
|
+
minCooldownMs;
|
|
2018
|
+
constructor(opts) {
|
|
2019
|
+
this.thresholdPercent = opts.thresholdPercent;
|
|
2020
|
+
this.minCooldownMs = opts.minCooldownMs;
|
|
2021
|
+
}
|
|
2022
|
+
shouldCompact(context) {
|
|
2023
|
+
const fillPercent = context.estimatedTokens / context.contextWindow * 100;
|
|
2024
|
+
if (fillPercent < this.thresholdPercent) return false;
|
|
2025
|
+
if (context.timeSinceLastCompaction !== null && context.timeSinceLastCompaction < this.minCooldownMs) {
|
|
2026
|
+
return false;
|
|
2027
|
+
}
|
|
2028
|
+
return true;
|
|
2029
|
+
}
|
|
2030
|
+
};
|
|
2031
|
+
|
|
2032
|
+
// runner/src/compaction/prompt.ts
|
|
2033
|
+
var DEFAULT_COMPACTION_PROMPT = `You are being asked to compact this conversation into a structured summary.
|
|
2034
|
+
This summary will replace the full conversation history when the session
|
|
2035
|
+
is restored. Produce a summary that lets you continue working effectively
|
|
2036
|
+
without access to the original messages.
|
|
2037
|
+
|
|
2038
|
+
## Rules
|
|
2039
|
+
|
|
2040
|
+
PRESERVE (include verbatim):
|
|
2041
|
+
- Current task/goal and its status
|
|
2042
|
+
- All file paths that were read, created, or modified
|
|
2043
|
+
- Function/class/variable names that are relevant to ongoing work
|
|
2044
|
+
- Key decisions made and the reasoning behind them
|
|
2045
|
+
- Errors encountered and how they were resolved
|
|
2046
|
+
- Active flow node and state (if any)
|
|
2047
|
+
- Unresolved questions or pending user input
|
|
2048
|
+
- User names and who said/requested what (multi-user sessions)
|
|
2049
|
+
- Test commands and verification criteria
|
|
2050
|
+
- Any explicit user instructions about preferences or constraints
|
|
2051
|
+
|
|
2052
|
+
COMPRESS (summarize in one line each):
|
|
2053
|
+
- Tool call / tool result pairs
|
|
2054
|
+
- Intermediate reasoning steps
|
|
2055
|
+
- Exploration paths that informed a decision
|
|
2056
|
+
|
|
2057
|
+
DROP (omit entirely):
|
|
2058
|
+
- Full file contents (can be re-read from disk)
|
|
2059
|
+
- Verbose command output (build logs, test suite output)
|
|
2060
|
+
- Exploration that led nowhere and didn't inform decisions
|
|
2061
|
+
- Redundant back-and-forth (corrections already applied)
|
|
2062
|
+
- Transient UI state
|
|
2063
|
+
|
|
2064
|
+
## Format
|
|
2065
|
+
|
|
2066
|
+
Write a structured summary using these sections. Omit any section that
|
|
2067
|
+
has no content.
|
|
2068
|
+
|
|
2069
|
+
### Goal
|
|
2070
|
+
What the user is trying to accomplish.
|
|
2071
|
+
|
|
2072
|
+
### Progress
|
|
2073
|
+
What has been done so far, organized by sub-task.
|
|
2074
|
+
|
|
2075
|
+
### Key Decisions
|
|
2076
|
+
Decisions made and why, as a bulleted list.
|
|
2077
|
+
|
|
2078
|
+
### Active State
|
|
2079
|
+
Current work in progress -- what was happening when compaction triggered.
|
|
2080
|
+
|
|
2081
|
+
### Files
|
|
2082
|
+
All relevant file paths with a one-line note on each.
|
|
2083
|
+
|
|
2084
|
+
### Pending
|
|
2085
|
+
What still needs to be done or is waiting on user input.
|
|
2086
|
+
|
|
2087
|
+
### Context
|
|
2088
|
+
User preferences, constraints, or instructions that must carry forward.`;
|
|
2089
|
+
function buildCompactionPrompt(opts) {
|
|
2090
|
+
const base = opts.agentPrompt ?? DEFAULT_COMPACTION_PROMPT;
|
|
2091
|
+
const parts = [base];
|
|
2092
|
+
const allDirectives = [...opts.skillDirectives ?? [], ...opts.mcpDirectives ?? []];
|
|
2093
|
+
if (allDirectives.length > 0) {
|
|
2094
|
+
parts.push(
|
|
2095
|
+
`
|
|
2096
|
+
|
|
2097
|
+
## Additional Compaction Directives
|
|
2098
|
+
${allDirectives.map((d) => `- ${d}`).join("\n")}`
|
|
2099
|
+
);
|
|
2100
|
+
}
|
|
2101
|
+
if (opts.focus) {
|
|
2102
|
+
parts.push(`
|
|
2103
|
+
|
|
2104
|
+
## Focus
|
|
2105
|
+
${opts.focus}`);
|
|
2106
|
+
}
|
|
2107
|
+
return parts.join("");
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
// runner/src/compaction/orchestrator.ts
|
|
2111
|
+
var MIN_SUMMARY_CHARS = 200;
|
|
2112
|
+
var MAX_COMPRESSION_RATIO = 0.9;
|
|
2113
|
+
var RATE_LIMIT_TEXT_MAX_CHARS = 1500;
|
|
2114
|
+
var RATE_LIMIT_TEXT_PATTERNS = [
|
|
2115
|
+
/you('?| ha)ve hit your (rate |usage )?limit/i,
|
|
2116
|
+
/you('?| ha)ve reached your (usage |rate )?limit/i,
|
|
2117
|
+
/you('?| ha)ve been rate[\s-]?limited/i,
|
|
2118
|
+
/rate limit (exceeded|reached|hit)/i,
|
|
2119
|
+
/usage limit (exceeded|reached)/i,
|
|
2120
|
+
/quota (exceeded|reached)/i,
|
|
2121
|
+
/claude (ai )?usage limit reached/i
|
|
2122
|
+
];
|
|
2123
|
+
function detectRateLimitInSummary(text) {
|
|
2124
|
+
if (text.length > RATE_LIMIT_TEXT_MAX_CHARS) return false;
|
|
2125
|
+
return RATE_LIMIT_TEXT_PATTERNS.some((p) => p.test(text));
|
|
2126
|
+
}
|
|
2127
|
+
function validateCompactionOutput(text, tokensBefore, tokensAfter) {
|
|
2128
|
+
if (!text.trim()) return { ok: false, errorCode: "empty" };
|
|
2129
|
+
if (detectRateLimitInSummary(text)) return { ok: false, errorCode: "rate_limit" };
|
|
2130
|
+
if (text.length < MIN_SUMMARY_CHARS) return { ok: false, errorCode: "too_short" };
|
|
2131
|
+
if (tokensBefore > 0 && tokensAfter / tokensBefore > MAX_COMPRESSION_RATIO) {
|
|
2132
|
+
return { ok: false, errorCode: "poor_ratio" };
|
|
2133
|
+
}
|
|
2134
|
+
return { ok: true };
|
|
2135
|
+
}
|
|
2136
|
+
var CompactionOrchestrator = class {
|
|
2137
|
+
driver;
|
|
2138
|
+
strategy;
|
|
2139
|
+
config;
|
|
2140
|
+
opts;
|
|
2141
|
+
_isCompacting = false;
|
|
2142
|
+
lastCompactionSeq = null;
|
|
2143
|
+
lastCompactionTime = null;
|
|
2144
|
+
currentSeq = 0;
|
|
2145
|
+
messagesSinceCompaction = 0;
|
|
2146
|
+
constructor(opts) {
|
|
2147
|
+
this.driver = opts.driver;
|
|
2148
|
+
this.opts = opts;
|
|
2149
|
+
this.config = { ...COMPACTION_DEFAULTS, ...opts.config };
|
|
2150
|
+
this.strategy = new TokenThresholdStrategy({
|
|
2151
|
+
thresholdPercent: this.config.thresholdPercent,
|
|
2152
|
+
minCooldownMs: this.config.minCooldownMs
|
|
2153
|
+
});
|
|
2154
|
+
}
|
|
2155
|
+
get hasNewMessagesSinceCompaction() {
|
|
2156
|
+
return this.messagesSinceCompaction > 0;
|
|
2157
|
+
}
|
|
2158
|
+
trackMessage(seq) {
|
|
2159
|
+
this.currentSeq = seq;
|
|
2160
|
+
this.messagesSinceCompaction++;
|
|
2161
|
+
}
|
|
2162
|
+
shouldCompact() {
|
|
2163
|
+
if (!this.config.enabled) return false;
|
|
2164
|
+
const usage = this.driver.getTokenUsage();
|
|
2165
|
+
const contextWindow = this.driver.getContextWindow();
|
|
2166
|
+
if (!usage || !contextWindow || usage.inputTokens === void 0) return false;
|
|
2167
|
+
return this.strategy.shouldCompact({
|
|
2168
|
+
estimatedTokens: usage.inputTokens,
|
|
2169
|
+
contextWindow,
|
|
2170
|
+
messageCount: this.messagesSinceCompaction,
|
|
2171
|
+
lastCompactionSeq: this.lastCompactionSeq,
|
|
2172
|
+
timeSinceLastCompaction: this.lastCompactionTime !== null ? Date.now() - this.lastCompactionTime : null
|
|
2173
|
+
});
|
|
2174
|
+
}
|
|
2175
|
+
async compact(trigger, focus) {
|
|
2176
|
+
if (this._isCompacting) return null;
|
|
2177
|
+
this._isCompacting = true;
|
|
2178
|
+
try {
|
|
2179
|
+
return await this._doCompact(trigger, focus);
|
|
2180
|
+
} finally {
|
|
2181
|
+
this._isCompacting = false;
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
async _doCompact(trigger, focus) {
|
|
2185
|
+
const tokensBefore = this.driver.getTokenUsage()?.inputTokens ?? 0;
|
|
2186
|
+
const driverSessionId = this.driver.runtimeSessionId ?? null;
|
|
2187
|
+
const driverModel = this.driver.getModel() ?? null;
|
|
2188
|
+
const driverProvider = this.driver.driverInfo?.id ?? null;
|
|
2189
|
+
const coversFromSeq = this.lastCompactionSeq ?? 0;
|
|
2190
|
+
const capabilitySignatureAtCompaction = this.opts.getCurrentCapabilitySignature?.() ?? null;
|
|
2191
|
+
this.opts.onCompactionStart?.(trigger);
|
|
2192
|
+
this.opts.onLog?.(`[compaction] Starting (trigger=${trigger}, tokens=${tokensBefore})`);
|
|
2193
|
+
const prompt = buildCompactionPrompt({
|
|
2194
|
+
agentPrompt: this.opts.agentCompactionPrompt,
|
|
2195
|
+
skillDirectives: this.opts.skillDirectives,
|
|
2196
|
+
mcpDirectives: this.opts.mcpDirectives,
|
|
2197
|
+
focus
|
|
2198
|
+
});
|
|
2199
|
+
let summaryText = "";
|
|
2200
|
+
const captureHandler = (raw) => {
|
|
2201
|
+
const event = raw;
|
|
2202
|
+
if (event.type === "text") {
|
|
2203
|
+
summaryText += event.content ?? "";
|
|
2204
|
+
return;
|
|
2205
|
+
}
|
|
2206
|
+
if (event.type === "message_update") {
|
|
2207
|
+
const delta = event._textDelta;
|
|
2208
|
+
if (delta) summaryText += delta;
|
|
2209
|
+
return;
|
|
2210
|
+
}
|
|
2211
|
+
if (event.type === "message_start" || event.type === "message_end") {
|
|
2212
|
+
const msg = event.message;
|
|
2213
|
+
if (!msg?.content) return;
|
|
2214
|
+
const blocks = Array.isArray(msg.content) ? msg.content : [];
|
|
2215
|
+
for (const b of blocks) {
|
|
2216
|
+
if (b.type === "text" && b.text) summaryText += b.text;
|
|
2217
|
+
}
|
|
2218
|
+
}
|
|
2219
|
+
};
|
|
2220
|
+
let promptError = null;
|
|
2221
|
+
try {
|
|
2222
|
+
this.driver.on("agent-event", captureHandler);
|
|
2223
|
+
await this.driver.prompt(prompt);
|
|
2224
|
+
} catch (err) {
|
|
2225
|
+
promptError = err;
|
|
2226
|
+
} finally {
|
|
2227
|
+
this.driver.removeListener("agent-event", captureHandler);
|
|
2228
|
+
}
|
|
2229
|
+
if (promptError !== null) {
|
|
2230
|
+
const classified = classifyClaudeSdkError(
|
|
2231
|
+
promptError instanceof Error ? promptError.message : String(promptError)
|
|
2232
|
+
);
|
|
2233
|
+
const errorCode = classified.category === "rate_limit" ? "rate_limit" : classified.category === "auth" ? "auth" : classified.category === "network" ? "timeout" : classified.category === "validation" ? "parse_error" : classified.category;
|
|
2234
|
+
this.opts.onLog?.(`[compaction] Failed: ${classified.message} (${errorCode})`);
|
|
2235
|
+
this.opts.onCompactionAttempt?.({
|
|
2236
|
+
type: "compaction_attempt",
|
|
2237
|
+
status: "failed",
|
|
2238
|
+
errorCode,
|
|
2239
|
+
trigger,
|
|
2240
|
+
summary: "",
|
|
2241
|
+
model: driverModel,
|
|
2242
|
+
provider: driverProvider,
|
|
2243
|
+
inputTokens: tokensBefore,
|
|
2244
|
+
outputTokens: 0,
|
|
2245
|
+
coversFromSeq,
|
|
2246
|
+
coversToSeq: this.currentSeq,
|
|
2247
|
+
driverSessionIdAtCompaction: driverSessionId,
|
|
2248
|
+
modelAtCompaction: driverModel,
|
|
2249
|
+
capabilitySignatureAtCompaction,
|
|
2250
|
+
validatedAt: null
|
|
2251
|
+
});
|
|
2252
|
+
this.opts.onCompactionEnd?.();
|
|
2253
|
+
return null;
|
|
2254
|
+
}
|
|
2255
|
+
const actualUsage = this.driver.getTokenUsage();
|
|
2256
|
+
const tokensAfter = actualUsage?.outputTokens ?? Math.ceil(summaryText.length / 4);
|
|
2257
|
+
const validation = validateCompactionOutput(summaryText, tokensBefore, tokensAfter);
|
|
2258
|
+
if (!validation.ok) {
|
|
2259
|
+
this.opts.onLog?.(
|
|
2260
|
+
`[compaction] Output failed validation (${validation.errorCode}); recording failed attempt`
|
|
2261
|
+
);
|
|
2262
|
+
this.opts.onCompactionAttempt?.({
|
|
2263
|
+
type: "compaction_attempt",
|
|
2264
|
+
status: "failed",
|
|
2265
|
+
errorCode: validation.errorCode,
|
|
2266
|
+
trigger,
|
|
2267
|
+
summary: "",
|
|
2268
|
+
model: driverModel,
|
|
2269
|
+
provider: driverProvider,
|
|
2270
|
+
inputTokens: tokensBefore,
|
|
2271
|
+
outputTokens: tokensAfter,
|
|
2272
|
+
coversFromSeq,
|
|
2273
|
+
coversToSeq: this.currentSeq,
|
|
2274
|
+
driverSessionIdAtCompaction: driverSessionId,
|
|
2275
|
+
modelAtCompaction: driverModel,
|
|
2276
|
+
capabilitySignatureAtCompaction,
|
|
2277
|
+
validatedAt: null
|
|
2278
|
+
});
|
|
2279
|
+
this.opts.onCompactionEnd?.();
|
|
2280
|
+
return null;
|
|
2281
|
+
}
|
|
2282
|
+
const validatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2283
|
+
const snapshot = {
|
|
2284
|
+
type: "snapshot",
|
|
2285
|
+
summary: summaryText,
|
|
2286
|
+
trigger,
|
|
2287
|
+
coversFromSeq,
|
|
2288
|
+
coversToSeq: this.currentSeq,
|
|
2289
|
+
tokensBefore,
|
|
2290
|
+
tokensAfter
|
|
2291
|
+
};
|
|
2292
|
+
this.opts.onCompactionAttempt?.({
|
|
2293
|
+
type: "compaction_attempt",
|
|
2294
|
+
status: "success",
|
|
2295
|
+
errorCode: null,
|
|
2296
|
+
trigger,
|
|
2297
|
+
summary: summaryText,
|
|
2298
|
+
model: driverModel,
|
|
2299
|
+
provider: driverProvider,
|
|
2300
|
+
inputTokens: tokensBefore,
|
|
2301
|
+
outputTokens: tokensAfter,
|
|
2302
|
+
coversFromSeq,
|
|
2303
|
+
coversToSeq: this.currentSeq,
|
|
2304
|
+
driverSessionIdAtCompaction: driverSessionId,
|
|
2305
|
+
modelAtCompaction: driverModel,
|
|
2306
|
+
capabilitySignatureAtCompaction,
|
|
2307
|
+
validatedAt
|
|
2308
|
+
});
|
|
2309
|
+
this.opts.onSnapshot?.(snapshot);
|
|
2310
|
+
this.lastCompactionSeq = this.currentSeq + 1;
|
|
2311
|
+
this.lastCompactionTime = Date.now();
|
|
2312
|
+
this.messagesSinceCompaction = 0;
|
|
2313
|
+
this.opts.onCompactionEnd?.();
|
|
2314
|
+
if (trigger !== "hibernate") {
|
|
2315
|
+
this.opts.onLog?.("[compaction] Resetting driver session");
|
|
2316
|
+
await this.driver.resetSession();
|
|
2317
|
+
await this.driver.prompt(
|
|
2318
|
+
`<session_snapshot>
|
|
2319
|
+
${summaryText}
|
|
2320
|
+
</session_snapshot>
|
|
2321
|
+
|
|
2322
|
+
The conversation has been compacted. The above snapshot contains the full context of our work so far. Continue from where we left off.`
|
|
2323
|
+
);
|
|
2324
|
+
}
|
|
2325
|
+
this.opts.onLog?.(
|
|
2326
|
+
`[compaction] Complete (${tokensBefore} -> ${tokensAfter} tokens, ratio=${(tokensAfter / Math.max(tokensBefore, 1) * 100).toFixed(1)}%)`
|
|
2327
|
+
);
|
|
2328
|
+
return snapshot;
|
|
2329
|
+
}
|
|
2330
|
+
initFromSnapshot(lastSnapshotSeq, lastSnapshotTime) {
|
|
2331
|
+
this.lastCompactionSeq = lastSnapshotSeq;
|
|
2332
|
+
this.lastCompactionTime = lastSnapshotTime;
|
|
2333
|
+
this.messagesSinceCompaction = 0;
|
|
2334
|
+
}
|
|
2335
|
+
};
|
|
2336
|
+
function rewriteFileChangedPath(event, cwd, mounts) {
|
|
2337
|
+
if (event.type !== "file_changed") return event;
|
|
2338
|
+
if (event.mountId) return event;
|
|
2339
|
+
const rawPath = event.path;
|
|
2340
|
+
if (!rawPath) return event;
|
|
2341
|
+
const absPath = resolve(cwd, rawPath);
|
|
2342
|
+
for (const mount of mounts) {
|
|
2343
|
+
const rel = relative(mount.mountPath, absPath);
|
|
2344
|
+
if (rel === "" || rel.startsWith("..") || rel.startsWith("/")) continue;
|
|
2345
|
+
return { ...event, path: rel, mountId: mount.id };
|
|
2346
|
+
}
|
|
2347
|
+
return event;
|
|
2348
|
+
}
|
|
2349
|
+
var RUNNER_CAP_ORIGIN = { kind: "framework" };
|
|
2350
|
+
function notImplemented(name) {
|
|
2351
|
+
return {
|
|
2352
|
+
ok: false,
|
|
2353
|
+
code: "not_implemented",
|
|
2354
|
+
message: `${name} handler not configured`
|
|
2355
|
+
};
|
|
2356
|
+
}
|
|
2357
|
+
var requiredUnknown = z4.unknown().refine(() => true);
|
|
2358
|
+
var preMintedTokenSchema = z4.object({
|
|
2359
|
+
token: z4.string(),
|
|
2360
|
+
expiresAt: z4.string().nullable().optional()
|
|
2361
|
+
}).optional();
|
|
2362
|
+
var mountDeclarationInput = z4.object({
|
|
2363
|
+
declaration: requiredUnknown,
|
|
2364
|
+
preMintedToken: preMintedTokenSchema
|
|
2365
|
+
}).strict();
|
|
2366
|
+
var connectorDeclarationInput = z4.object({
|
|
2367
|
+
declaration: requiredUnknown,
|
|
2368
|
+
preMintedToken: preMintedTokenSchema
|
|
2369
|
+
}).strict();
|
|
2370
|
+
var removeResourceInput = z4.object({
|
|
2371
|
+
id: z4.string()
|
|
2372
|
+
}).strict();
|
|
2373
|
+
var updateCredentialInput = z4.object({
|
|
2374
|
+
kind: z4.enum(["mount", "connector"]),
|
|
2375
|
+
id: z4.string(),
|
|
2376
|
+
// `CredentialMint` is a discriminated union from `@skaile/workspaces/types`.
|
|
2377
|
+
// We accept it as `z.unknown()` here because Zod can't easily mirror
|
|
2378
|
+
// a discriminated TypeScript union without duplicating the schema —
|
|
2379
|
+
// the platform side has already validated the shape before sending.
|
|
2380
|
+
mint: requiredUnknown
|
|
2381
|
+
}).strict();
|
|
2382
|
+
var setLogLevelInput = z4.object({
|
|
2383
|
+
level: z4.enum(["silent", "error", "warn", "info", "debug", "trace"])
|
|
2384
|
+
}).strict();
|
|
2385
|
+
var setStateInput = z4.object({
|
|
2386
|
+
store: z4.string(),
|
|
2387
|
+
key: z4.string(),
|
|
2388
|
+
value: requiredUnknown
|
|
2389
|
+
}).strict();
|
|
2390
|
+
var lifecycleInput = z4.object({
|
|
2391
|
+
action: z4.enum(["hibernate", "close", "shutdown"])
|
|
2392
|
+
}).strict();
|
|
2393
|
+
var VALID_LOG_STORE_LEVELS = /* @__PURE__ */ new Set(["debug", "info", "warn", "error"]);
|
|
2394
|
+
function buildRunnerCapabilities(handlers) {
|
|
2395
|
+
return [
|
|
2396
|
+
defineCapability({
|
|
2397
|
+
name: "runner.add_mount",
|
|
2398
|
+
displayName: "Add mount",
|
|
2399
|
+
description: "Mount a volume into the live session. Used by the platform to attach data sources mid-session.",
|
|
2400
|
+
side: "agent",
|
|
2401
|
+
origin: RUNNER_CAP_ORIGIN,
|
|
2402
|
+
audience: ["runtime"],
|
|
2403
|
+
kind: "effect",
|
|
2404
|
+
input: mountDeclarationInput,
|
|
2405
|
+
handler: async (input) => {
|
|
2406
|
+
if (!handlers.addMount) return notImplemented("runner.add_mount");
|
|
2407
|
+
return handlers.addMount({
|
|
2408
|
+
declaration: input.declaration,
|
|
2409
|
+
preMintedToken: input.preMintedToken
|
|
2410
|
+
});
|
|
2411
|
+
}
|
|
2412
|
+
}),
|
|
2413
|
+
defineCapability({
|
|
2414
|
+
name: "runner.add_connector",
|
|
2415
|
+
displayName: "Add connector",
|
|
2416
|
+
description: "Connect a tool-providing connector into the live session. Used by the platform to attach databases, APIs, etc. mid-session.",
|
|
2417
|
+
side: "agent",
|
|
2418
|
+
origin: RUNNER_CAP_ORIGIN,
|
|
2419
|
+
audience: ["runtime"],
|
|
2420
|
+
kind: "effect",
|
|
2421
|
+
input: connectorDeclarationInput,
|
|
2422
|
+
handler: async (input) => {
|
|
2423
|
+
if (!handlers.addConnector) return notImplemented("runner.add_connector");
|
|
2424
|
+
return handlers.addConnector({
|
|
2425
|
+
declaration: input.declaration,
|
|
2426
|
+
preMintedToken: input.preMintedToken
|
|
2427
|
+
});
|
|
2428
|
+
}
|
|
2429
|
+
}),
|
|
2430
|
+
defineCapability({
|
|
2431
|
+
name: "runner.remove_resource",
|
|
2432
|
+
displayName: "Remove resource",
|
|
2433
|
+
description: "Detach a mount or connector by id. The id namespace is shared across both kinds.",
|
|
2434
|
+
side: "agent",
|
|
2435
|
+
origin: RUNNER_CAP_ORIGIN,
|
|
2436
|
+
audience: ["runtime"],
|
|
2437
|
+
kind: "effect",
|
|
2438
|
+
input: removeResourceInput,
|
|
2439
|
+
handler: async (input) => {
|
|
2440
|
+
if (!handlers.removeResource) return notImplemented("runner.remove_resource");
|
|
2441
|
+
return handlers.removeResource(input);
|
|
2442
|
+
}
|
|
2443
|
+
}),
|
|
2444
|
+
defineCapability({
|
|
2445
|
+
name: "runner.update_credential",
|
|
2446
|
+
displayName: "Update credential",
|
|
2447
|
+
description: "Replace the pre-minted credential on an existing mount or connector. Used for proactive rotation before TTL expiry.",
|
|
2448
|
+
side: "agent",
|
|
2449
|
+
origin: RUNNER_CAP_ORIGIN,
|
|
2450
|
+
audience: ["runtime"],
|
|
2451
|
+
kind: "effect",
|
|
2452
|
+
input: updateCredentialInput,
|
|
2453
|
+
handler: async (input) => {
|
|
2454
|
+
if (!handlers.updateCredential) return notImplemented("runner.update_credential");
|
|
2455
|
+
return handlers.updateCredential({
|
|
2456
|
+
kind: input.kind,
|
|
2457
|
+
id: input.id,
|
|
2458
|
+
mint: input.mint
|
|
2459
|
+
});
|
|
2460
|
+
}
|
|
2461
|
+
}),
|
|
2462
|
+
defineCapability({
|
|
2463
|
+
name: "runner.set_log_level",
|
|
2464
|
+
displayName: "Set log level",
|
|
2465
|
+
description: "Live-update the in-container LogStore minimum level without restarting the session.",
|
|
2466
|
+
side: "agent",
|
|
2467
|
+
origin: RUNNER_CAP_ORIGIN,
|
|
2468
|
+
audience: ["runtime"],
|
|
2469
|
+
kind: "effect",
|
|
2470
|
+
input: setLogLevelInput,
|
|
2471
|
+
handler: async (input) => {
|
|
2472
|
+
if (handlers.setLogLevel) {
|
|
2473
|
+
return handlers.setLogLevel(input);
|
|
2474
|
+
}
|
|
2475
|
+
const candidate = input.level;
|
|
2476
|
+
if (VALID_LOG_STORE_LEVELS.has(candidate)) {
|
|
2477
|
+
getLogStore()?.setLevel(candidate);
|
|
2478
|
+
}
|
|
2479
|
+
return { ok: true };
|
|
2480
|
+
}
|
|
2481
|
+
}),
|
|
2482
|
+
defineCapability({
|
|
2483
|
+
name: "runner.set_state",
|
|
2484
|
+
displayName: "Set state",
|
|
2485
|
+
description: "Write into the session shared state store. Shape matches the legacy state_action command body.",
|
|
2486
|
+
side: "agent",
|
|
2487
|
+
origin: RUNNER_CAP_ORIGIN,
|
|
2488
|
+
audience: ["runtime"],
|
|
2489
|
+
kind: "effect",
|
|
2490
|
+
input: setStateInput,
|
|
2491
|
+
handler: async (input) => {
|
|
2492
|
+
if (!handlers.setState) {
|
|
2493
|
+
return notImplemented("runner.set_state");
|
|
2494
|
+
}
|
|
2495
|
+
return handlers.setState({
|
|
2496
|
+
store: input.store,
|
|
2497
|
+
key: input.key,
|
|
2498
|
+
value: input.value
|
|
2499
|
+
});
|
|
2500
|
+
}
|
|
2501
|
+
}),
|
|
2502
|
+
defineCapability({
|
|
2503
|
+
name: "runner.lifecycle",
|
|
2504
|
+
displayName: "Session lifecycle",
|
|
2505
|
+
description: "Transition the session lifecycle: hibernate to disk, close the active flow, or shut down the runner.",
|
|
2506
|
+
side: "agent",
|
|
2507
|
+
origin: RUNNER_CAP_ORIGIN,
|
|
2508
|
+
audience: ["runtime"],
|
|
2509
|
+
kind: "effect",
|
|
2510
|
+
input: lifecycleInput,
|
|
2511
|
+
handler: async (input) => {
|
|
2512
|
+
if (!handlers.lifecycle) {
|
|
2513
|
+
return notImplemented("runner.lifecycle");
|
|
2514
|
+
}
|
|
2515
|
+
return handlers.lifecycle(input);
|
|
2516
|
+
}
|
|
2517
|
+
})
|
|
2518
|
+
];
|
|
2519
|
+
}
|
|
2520
|
+
|
|
2521
|
+
// runner/src/session-stimulus.ts
|
|
2522
|
+
var DEFAULT_COALESCE_MS = 50;
|
|
2523
|
+
function createSessionStimulusBus(opts) {
|
|
2524
|
+
const { driveTurn, defaultCoalesceMs = DEFAULT_COALESCE_MS, log } = opts;
|
|
2525
|
+
const queues = /* @__PURE__ */ new Map();
|
|
2526
|
+
function getQueue(connectorId) {
|
|
2527
|
+
let q = queues.get(connectorId);
|
|
2528
|
+
if (!q) {
|
|
2529
|
+
q = { pending: [], timer: null, inFlight: false };
|
|
2530
|
+
queues.set(connectorId, q);
|
|
2531
|
+
}
|
|
2532
|
+
return q;
|
|
2533
|
+
}
|
|
2534
|
+
function startTimerIfNeeded(connectorId, q, coalesceMs) {
|
|
2535
|
+
if (q.timer != null) return;
|
|
2536
|
+
if (q.inFlight) return;
|
|
2537
|
+
q.timer = setTimeout(() => {
|
|
2538
|
+
q.timer = null;
|
|
2539
|
+
void flushQueue(connectorId, q);
|
|
2540
|
+
}, coalesceMs);
|
|
2541
|
+
}
|
|
2542
|
+
async function flushQueue(connectorId, q) {
|
|
2543
|
+
if (q.pending.length === 0) return;
|
|
2544
|
+
const batch = q.pending;
|
|
2545
|
+
q.pending = [];
|
|
2546
|
+
q.inFlight = true;
|
|
2547
|
+
const fragments = batch.map((e) => e.signal.promptFragment);
|
|
2548
|
+
const metas = batch.map((e) => e.signal.meta).filter((m) => m !== void 0);
|
|
2549
|
+
const joined = fragments.join("\n\n");
|
|
2550
|
+
log?.debug("turn driving", {
|
|
2551
|
+
connectorId,
|
|
2552
|
+
count: batch.length,
|
|
2553
|
+
fragmentLength: joined.length
|
|
2554
|
+
});
|
|
2555
|
+
try {
|
|
2556
|
+
await driveTurn(joined, metas);
|
|
2557
|
+
log?.debug("turn drained", {
|
|
2558
|
+
connectorId,
|
|
2559
|
+
count: batch.length,
|
|
2560
|
+
fragmentLength: joined.length
|
|
2561
|
+
});
|
|
2562
|
+
for (const entry of batch) entry.resolve();
|
|
2563
|
+
} catch (err) {
|
|
2564
|
+
log?.debug("turn failed", {
|
|
2565
|
+
connectorId,
|
|
2566
|
+
count: batch.length,
|
|
2567
|
+
fragmentLength: joined.length,
|
|
2568
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2569
|
+
});
|
|
2570
|
+
for (const entry of batch) entry.reject(err);
|
|
2571
|
+
} finally {
|
|
2572
|
+
q.inFlight = false;
|
|
2573
|
+
if (q.pending.length > 0) {
|
|
2574
|
+
const nextWindow = q.pending[q.pending.length - 1]?.signal.coalesceMs ?? defaultCoalesceMs;
|
|
2575
|
+
startTimerIfNeeded(connectorId, q, nextWindow);
|
|
2576
|
+
}
|
|
2577
|
+
}
|
|
2578
|
+
}
|
|
2579
|
+
return {
|
|
2580
|
+
signal(connectorId, sig) {
|
|
2581
|
+
const coalesceMs = sig.coalesceMs ?? defaultCoalesceMs;
|
|
2582
|
+
log?.debug("stimulus signaled", {
|
|
2583
|
+
connectorId,
|
|
2584
|
+
fragmentLength: sig.promptFragment.length
|
|
2585
|
+
});
|
|
2586
|
+
return new Promise((resolve3, reject) => {
|
|
2587
|
+
const q = getQueue(connectorId);
|
|
2588
|
+
q.pending.push({ signal: sig, resolve: resolve3, reject });
|
|
2589
|
+
startTimerIfNeeded(connectorId, q, coalesceMs);
|
|
2590
|
+
});
|
|
2591
|
+
}
|
|
2592
|
+
};
|
|
2593
|
+
}
|
|
2594
|
+
|
|
2595
|
+
// runner/src/serve.ts
|
|
2596
|
+
function getSessionCatalogEntries(session) {
|
|
2597
|
+
return session?.runtimeAssets?.catalogEntries ?? [];
|
|
2598
|
+
}
|
|
2599
|
+
function emitSystemPromptComposed(agentSession, sendEvent) {
|
|
2600
|
+
sendEvent({
|
|
2601
|
+
type: "system_prompt_composed",
|
|
2602
|
+
sections: agentSession.systemPromptSections,
|
|
2603
|
+
composedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2604
|
+
});
|
|
2605
|
+
}
|
|
2606
|
+
var FRAMEWORK_PACKAGES = [
|
|
2607
|
+
"@skaile/workspaces/runner",
|
|
2608
|
+
"@skaile/workspaces/bridge",
|
|
2609
|
+
"@skaile/workspaces/core",
|
|
2610
|
+
"@skaile/workspaces/types",
|
|
2611
|
+
"@skaile/workspaces/base-assets",
|
|
2612
|
+
"@skaile/workspaces/connectors",
|
|
2613
|
+
"@skaile/workspaces/resolver",
|
|
2614
|
+
"@skaile/workspaces/transport",
|
|
2615
|
+
"@skaile/workspaces/workspace-plugin"
|
|
2616
|
+
];
|
|
2617
|
+
var _frameworkVersions = null;
|
|
2618
|
+
function getFrameworkVersions() {
|
|
2619
|
+
if (_frameworkVersions) return _frameworkVersions;
|
|
2620
|
+
const versions = {};
|
|
2621
|
+
for (const pkg of FRAMEWORK_PACKAGES) {
|
|
2622
|
+
try {
|
|
2623
|
+
const pjPath = __require.resolve(`${pkg}/package.json`);
|
|
2624
|
+
const pj = JSON.parse(readFileSync(pjPath, "utf-8"));
|
|
2625
|
+
versions[pkg.replace("@skaile/", "")] = pj.version;
|
|
2626
|
+
} catch {
|
|
2627
|
+
}
|
|
2628
|
+
}
|
|
2629
|
+
_frameworkVersions = versions;
|
|
2630
|
+
return versions;
|
|
2631
|
+
}
|
|
2632
|
+
function findAiAssetsRoot(startDir) {
|
|
2633
|
+
let dir = startDir;
|
|
2634
|
+
for (let i = 0; i < 6; i++) {
|
|
2635
|
+
const candidate = join(dir, "ai-assets");
|
|
2636
|
+
if (existsSync(candidate)) return candidate;
|
|
2637
|
+
dir = join(dir, "..");
|
|
2638
|
+
}
|
|
2639
|
+
return null;
|
|
2640
|
+
}
|
|
2641
|
+
function ensureGitConfigInclude(managedGitconfigPath) {
|
|
2642
|
+
const home = process.env.HOME ?? homedir();
|
|
2643
|
+
if (!home) return;
|
|
2644
|
+
const gitconfigPath = join(home, ".gitconfig");
|
|
2645
|
+
let existing = "";
|
|
2646
|
+
try {
|
|
2647
|
+
existing = readFileSync(gitconfigPath, "utf-8");
|
|
2648
|
+
} catch {
|
|
2649
|
+
}
|
|
2650
|
+
const sectionRe = /^\s*\[([^\]\s]+)(?:\s+"[^"]*")?\]\s*$/;
|
|
2651
|
+
const pathKeyRe = /^\s*path\s*=\s*(.+?)\s*$/;
|
|
2652
|
+
let currentSection = null;
|
|
2653
|
+
for (const line of existing.split(/\r?\n/)) {
|
|
2654
|
+
const sectionMatch = line.match(sectionRe);
|
|
2655
|
+
if (sectionMatch) {
|
|
2656
|
+
currentSection = sectionMatch[1]?.toLowerCase() ?? null;
|
|
2657
|
+
continue;
|
|
2658
|
+
}
|
|
2659
|
+
if (currentSection !== "include" && currentSection !== "includeif") continue;
|
|
2660
|
+
const pathMatch = line.match(pathKeyRe);
|
|
2661
|
+
if (pathMatch?.[1] === managedGitconfigPath) return;
|
|
2662
|
+
}
|
|
2663
|
+
if (!existsSync(dirname(gitconfigPath))) {
|
|
2664
|
+
mkdirSync(dirname(gitconfigPath), { recursive: true });
|
|
2665
|
+
}
|
|
2666
|
+
const block = `${existing.trimEnd()}
|
|
2667
|
+
# skaile-runner: managed-gitconfig include
|
|
2668
|
+
[include]
|
|
2669
|
+
path = ${managedGitconfigPath}
|
|
2670
|
+
`;
|
|
2671
|
+
writeFileSync(gitconfigPath, block, { mode: 420 });
|
|
2672
|
+
}
|
|
2673
|
+
async function startAgentServer(opts) {
|
|
2674
|
+
const port = opts.port ?? 8080;
|
|
2675
|
+
const sessionId = opts.sessionId ?? process.env.SKAILE_SESSION_ID ?? "session-unknown";
|
|
2676
|
+
const resumeSessionId = opts.resumeSessionId ?? process.env.SKAILE_RESUME_SESSION_ID;
|
|
2677
|
+
const wsConfig = resolveSkWorkspaceConfig(opts.projectDir);
|
|
2678
|
+
const { store: logStore, dispose: disposeLogStore } = bootstrapRunnerLogStore({
|
|
2679
|
+
sessionId,
|
|
2680
|
+
projectDir: opts.projectDir,
|
|
2681
|
+
yamlBlock: wsConfig.logging,
|
|
2682
|
+
onLog: opts.onLog
|
|
2683
|
+
});
|
|
2684
|
+
const serverLog = createLogger({
|
|
2685
|
+
kind: "runner",
|
|
2686
|
+
subkind: "session",
|
|
2687
|
+
instance: sessionId
|
|
2688
|
+
});
|
|
2689
|
+
const log = (line) => serverLog.info(line);
|
|
2690
|
+
const profile = wsConfig.agent_config?.default;
|
|
2691
|
+
const maxTurns = wsConfig.agent?.permissions?.max_turns ?? profile?.max_turns;
|
|
2692
|
+
const managedGitconfigPath = join(opts.projectDir, ".skaile", "managed-gitconfig");
|
|
2693
|
+
process.env.GIT_CONFIG_GLOBAL = managedGitconfigPath;
|
|
2694
|
+
try {
|
|
2695
|
+
ensureGitConfigInclude(managedGitconfigPath);
|
|
2696
|
+
} catch (err) {
|
|
2697
|
+
serverLog.warn("failed to write ~/.gitconfig include \u2014 relying on env only", {
|
|
2698
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2699
|
+
});
|
|
2700
|
+
}
|
|
2701
|
+
const agentDir = opts.agentDir ?? resolveAgentDir(opts.projectDir);
|
|
2702
|
+
if (agentDir) {
|
|
2703
|
+
serverLog.info("agent dir resolved", { agentDir });
|
|
2704
|
+
} else {
|
|
2705
|
+
serverLog.warn("no agent definition found in skaile.yaml");
|
|
2706
|
+
}
|
|
2707
|
+
const transport = opts.transport ?? new WebSocketServerTransport({ port, onLog: log });
|
|
2708
|
+
logStore.addSink(
|
|
2709
|
+
new WsLogSink({
|
|
2710
|
+
send: (event) => {
|
|
2711
|
+
if (transport.connected) transport.send(event);
|
|
2712
|
+
}
|
|
2713
|
+
})
|
|
2714
|
+
);
|
|
2715
|
+
function sendEvent(event) {
|
|
2716
|
+
if (transport.connected) {
|
|
2717
|
+
transport.send(event);
|
|
2718
|
+
}
|
|
2719
|
+
}
|
|
2720
|
+
const capabilityRegistry = new CapabilityRegistry(
|
|
2721
|
+
createLogger({
|
|
2722
|
+
kind: "runner",
|
|
2723
|
+
subkind: "capability-registry",
|
|
2724
|
+
instance: sessionId
|
|
2725
|
+
})
|
|
2726
|
+
);
|
|
2727
|
+
bootstrapCapabilityRegistry(capabilityRegistry);
|
|
2728
|
+
const pendingCapabilityCalls = /* @__PURE__ */ new Map();
|
|
2729
|
+
const remoteCapabilityInvoker = (name, input) => {
|
|
2730
|
+
const callId = typeof crypto?.randomUUID === "function" ? crypto.randomUUID() : `rcap-${Date.now()}-${Math.floor(Math.random() * 1e9)}`;
|
|
2731
|
+
return new Promise((resolve3, reject) => {
|
|
2732
|
+
if (!transport.connected) {
|
|
2733
|
+
reject(new Error(`Transport disconnected; cannot invoke remote capability ${name}`));
|
|
2734
|
+
return;
|
|
2735
|
+
}
|
|
2736
|
+
const timer = setTimeout(() => {
|
|
2737
|
+
pendingCapabilityCalls.delete(callId);
|
|
2738
|
+
reject(new Error(`Remote capability ${name} (callId=${callId}) timed out`));
|
|
2739
|
+
}, DEFAULT_CAPABILITY_CALL_TIMEOUT_MS);
|
|
2740
|
+
pendingCapabilityCalls.set(callId, { resolve: resolve3, reject, timer });
|
|
2741
|
+
transport.send({
|
|
2742
|
+
type: "capability_invoked",
|
|
2743
|
+
callId,
|
|
2744
|
+
name,
|
|
2745
|
+
input,
|
|
2746
|
+
invokedBy: "agent"
|
|
2747
|
+
});
|
|
2748
|
+
});
|
|
2749
|
+
};
|
|
2750
|
+
let aiProviderConfigId;
|
|
2751
|
+
const onAuthError = async (args) => {
|
|
2752
|
+
if (!transport.connected || aiProviderConfigId === void 0) {
|
|
2753
|
+
log("[serve] auth error: no transport or no aiProviderConfigId; surfacing");
|
|
2754
|
+
return {
|
|
2755
|
+
ok: false,
|
|
2756
|
+
code: "not-configured",
|
|
2757
|
+
message: "no transport or aiProviderConfigId; standalone runner cannot mediate refresh"
|
|
2758
|
+
};
|
|
2759
|
+
}
|
|
2760
|
+
const targetConfigId = args.configId || aiProviderConfigId;
|
|
2761
|
+
log("[serve] auth error: invoking host.refresh_credential capability");
|
|
2762
|
+
try {
|
|
2763
|
+
const result = await capabilityRegistry.invokeRemote("host.refresh_credential", {
|
|
2764
|
+
kind: "ai-credentials",
|
|
2765
|
+
id: targetConfigId,
|
|
2766
|
+
reason: "retry-401"
|
|
2767
|
+
});
|
|
2768
|
+
if (!result?.ok) {
|
|
2769
|
+
log(`[serve] auth error: mint failed (code=${result?.code ?? "backend-error"}); surfacing`);
|
|
2770
|
+
return result ?? { ok: false, code: "backend-error", message: "no result from host" };
|
|
2771
|
+
}
|
|
2772
|
+
const home = process.env.HOME ?? homedir();
|
|
2773
|
+
if (!home) {
|
|
2774
|
+
log("[serve] auth error: HOME unset; cannot rewrite credentials file");
|
|
2775
|
+
return {
|
|
2776
|
+
ok: false,
|
|
2777
|
+
code: "backend-error",
|
|
2778
|
+
message: "HOME env var unset; cannot rewrite credentials file"
|
|
2779
|
+
};
|
|
2780
|
+
}
|
|
2781
|
+
await mergeAndRewriteCredentialsFile(home, result.token, result.expiresAt ?? null);
|
|
2782
|
+
log("[serve] auth error: rewrote .credentials.json with mediated accessToken");
|
|
2783
|
+
return result;
|
|
2784
|
+
} catch (err) {
|
|
2785
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
2786
|
+
log(`[serve] auth error: host.refresh_credential threw: ${errMsg}`);
|
|
2787
|
+
return { ok: false, code: "backend-error", message: errMsg };
|
|
2788
|
+
}
|
|
2789
|
+
};
|
|
2790
|
+
const APPROVAL_REQUIRED_CAPABILITY_TIMEOUT_MS = 15 * 60 * 1e3;
|
|
2791
|
+
function buildClientCapabilityHandler2(wire) {
|
|
2792
|
+
return buildClientCapabilityHandler({
|
|
2793
|
+
wire,
|
|
2794
|
+
pending: pendingCapabilityCalls,
|
|
2795
|
+
emit: (event) => sendEvent(event),
|
|
2796
|
+
timeoutMs: wire.requiresApproval ? APPROVAL_REQUIRED_CAPABILITY_TIMEOUT_MS : DEFAULT_CAPABILITY_CALL_TIMEOUT_MS
|
|
2797
|
+
});
|
|
2798
|
+
}
|
|
2799
|
+
function buildCapabilityHooks() {
|
|
2800
|
+
return {
|
|
2801
|
+
sessionId,
|
|
2802
|
+
composeTools: () => capabilityRegistry.composeLLMTools(),
|
|
2803
|
+
resolve: (name) => {
|
|
2804
|
+
const cap = capabilityRegistry.resolve(name);
|
|
2805
|
+
if (!cap) return null;
|
|
2806
|
+
return capabilityRegistry.list().find((c) => c.name === name) ?? null;
|
|
2807
|
+
},
|
|
2808
|
+
invoke: (name, input) => capabilityRegistry.invoke(name, input, { sessionId }),
|
|
2809
|
+
emitRender: (event) => sendEvent(event),
|
|
2810
|
+
emitText: (text) => sendEvent({
|
|
2811
|
+
type: "text",
|
|
2812
|
+
content: text
|
|
2813
|
+
})
|
|
2814
|
+
};
|
|
2815
|
+
}
|
|
2816
|
+
function registerSessionComposition(session) {
|
|
2817
|
+
if (session.composition?.discoverableEntries.length) {
|
|
2818
|
+
registerCompositionCapabilities(capabilityRegistry, session.composition.discoverableEntries);
|
|
2819
|
+
log(
|
|
2820
|
+
`[serve] registered ${session.composition.discoverableEntries.length} composition capabilities`
|
|
2821
|
+
);
|
|
2822
|
+
}
|
|
2823
|
+
}
|
|
2824
|
+
const secretsMode = wsConfig.secrets?.provider ?? "env";
|
|
2825
|
+
wsConfig.secrets?.timeoutMs ?? 3e4;
|
|
2826
|
+
function buildSessionConfig(secretProvider2, apiKey) {
|
|
2827
|
+
return {
|
|
2828
|
+
projectDir: opts.projectDir,
|
|
2829
|
+
agentDir,
|
|
2830
|
+
driver: opts.driver,
|
|
2831
|
+
model: opts.model,
|
|
2832
|
+
provider: opts.provider,
|
|
2833
|
+
promptsDir: opts.promptsDir,
|
|
2834
|
+
sessionId,
|
|
2835
|
+
resumeSessionId,
|
|
2836
|
+
maxTurns,
|
|
2837
|
+
wsConfig,
|
|
2838
|
+
externalPromptFile: process.env.SKAILE_SYSTEM_PROMPT_FILE,
|
|
2839
|
+
secretProvider: secretProvider2,
|
|
2840
|
+
onAuthError,
|
|
2841
|
+
...apiKey ? { apiKey } : {},
|
|
2842
|
+
// Protocol v2 `<CAPABILITIES>` block — joins each registered capability's
|
|
2843
|
+
// `promptFragment` (framework first, then client, then agent-side
|
|
2844
|
+
// surfaces). Built lazily inside `buildSessionConfig` so newly registered
|
|
2845
|
+
// capabilities (e.g. via mid-session `capability_register` commands) are
|
|
2846
|
+
// reflected on the next session rebuild.
|
|
2847
|
+
additionalPromptSections: (() => {
|
|
2848
|
+
const sections = [];
|
|
2849
|
+
const capSection = buildCapabilitiesPromptSection(capabilityRegistry);
|
|
2850
|
+
if (capSection) sections.push(capSection);
|
|
2851
|
+
return sections.length > 0 ? sections : void 0;
|
|
2852
|
+
})(),
|
|
2853
|
+
watch: {
|
|
2854
|
+
onSyncStatus: (mountId, status) => {
|
|
2855
|
+
sendEvent({
|
|
2856
|
+
type: "sync_status",
|
|
2857
|
+
mountId,
|
|
2858
|
+
...status,
|
|
2859
|
+
phase: status.phase
|
|
2860
|
+
});
|
|
2861
|
+
if (status.phase === "stubs_ready") {
|
|
2862
|
+
log(
|
|
2863
|
+
`[serve] ${mountId}: file tree ready (${status.totalFiles} files, ${status.stubFiles} stubs)`
|
|
2864
|
+
);
|
|
2865
|
+
} else if (status.phase === "initial_sync_complete") {
|
|
2866
|
+
log(
|
|
2867
|
+
`[serve] ${mountId}: sync complete (${status.downloadedFiles}/${status.totalFiles} downloaded)`
|
|
2868
|
+
);
|
|
2869
|
+
}
|
|
2870
|
+
},
|
|
2871
|
+
onFileChanged: (_connectorId, event) => {
|
|
2872
|
+
sendEvent({
|
|
2873
|
+
type: "file_changed",
|
|
2874
|
+
path: event.path,
|
|
2875
|
+
action: event.action
|
|
2876
|
+
});
|
|
2877
|
+
},
|
|
2878
|
+
onMountChanged: (volId, event) => {
|
|
2879
|
+
sendEvent({
|
|
2880
|
+
type: "file_changed",
|
|
2881
|
+
path: event.path,
|
|
2882
|
+
action: event.action,
|
|
2883
|
+
mountId: volId
|
|
2884
|
+
});
|
|
2885
|
+
}
|
|
2886
|
+
},
|
|
2887
|
+
onLog: (line) => log(`[serve] ${line}`),
|
|
2888
|
+
capabilities: buildCapabilityHooks(),
|
|
2889
|
+
// v3: pre-minted credentials replace the tokenMediator for initial mints.
|
|
2890
|
+
// Refresh routes through `host.refresh_credential` (invoked from the
|
|
2891
|
+
// bridge driver's onAuthError callback). The legacy `tokenMediator`
|
|
2892
|
+
// wire is gone.
|
|
2893
|
+
...preMintedSecrets ? { preMintedSecrets } : {},
|
|
2894
|
+
...aiProviderConfigId ? { aiProviderConfigId } : {}
|
|
2895
|
+
};
|
|
2896
|
+
}
|
|
2897
|
+
let resolveSessionReady;
|
|
2898
|
+
let rejectSessionReady;
|
|
2899
|
+
const sessionReady = new Promise((resolve3, reject) => {
|
|
2900
|
+
resolveSessionReady = resolve3;
|
|
2901
|
+
rejectSessionReady = reject;
|
|
2902
|
+
});
|
|
2903
|
+
let sessionConfig;
|
|
2904
|
+
let agentSession;
|
|
2905
|
+
let secretProvider;
|
|
2906
|
+
let runtimeIdentity;
|
|
2907
|
+
let preMintedSecrets;
|
|
2908
|
+
if (secretsMode === "provisioned") {
|
|
2909
|
+
log("[serve] secrets mode: provisioned \u2014 waiting for provision_secrets command");
|
|
2910
|
+
} else {
|
|
2911
|
+
sessionConfig = buildSessionConfig();
|
|
2912
|
+
agentSession = await createAgentSession(sessionConfig);
|
|
2913
|
+
emitSystemPromptComposed(agentSession, sendEvent);
|
|
2914
|
+
registerSessionComposition(agentSession);
|
|
2915
|
+
resolveSessionReady();
|
|
2916
|
+
}
|
|
2917
|
+
let resourceManager = secretsMode === "env" ? agentSession.resourceManager : null;
|
|
2918
|
+
let mountManager = secretsMode === "env" ? agentSession.mountManager : null;
|
|
2919
|
+
if (secretsMode === "env") {
|
|
2920
|
+
if (!agentSession.provider) {
|
|
2921
|
+
log(
|
|
2922
|
+
`[serve] WARNING: no API key found for ${agentSession.provider ?? "anthropic"} \u2014 agent calls will fail`
|
|
2923
|
+
);
|
|
2924
|
+
log(`[serve] Pass via env var (e.g. ANTHROPIC_API_KEY) or .skaile/settings.json`);
|
|
2925
|
+
}
|
|
2926
|
+
if (resourceManager) {
|
|
2927
|
+
const watched = resourceManager.watchedResources ?? [];
|
|
2928
|
+
if (watched.length > 0) {
|
|
2929
|
+
log(`[serve] watching ${watched.length} resource(s): ${watched.join(", ")}`);
|
|
2930
|
+
}
|
|
2931
|
+
}
|
|
2932
|
+
}
|
|
2933
|
+
if (secretsMode === "env" && agentSession.runtimeAssets) {
|
|
2934
|
+
for (const w of agentSession.runtimeAssets.warnings) {
|
|
2935
|
+
const asset = w.code === "missing_driver" && w.declarationId ? `${w.declarationId} \u2192 ${w.name ?? "unknown"}` : w.name ?? w.code;
|
|
2936
|
+
log(`[serve] validation_warning: ${w.code}: ${w.message}`);
|
|
2937
|
+
sendEvent({
|
|
2938
|
+
type: "validation_warning",
|
|
2939
|
+
asset,
|
|
2940
|
+
reason: w.code,
|
|
2941
|
+
suggestion: w.message
|
|
2942
|
+
});
|
|
2943
|
+
}
|
|
2944
|
+
}
|
|
2945
|
+
try {
|
|
2946
|
+
const wsConfig2 = resolveSkWorkspaceConfig(opts.projectDir);
|
|
2947
|
+
const aiResources = wsConfig2.ai_resources;
|
|
2948
|
+
if (aiResources) {
|
|
2949
|
+
for (const res of Array.isArray(aiResources) ? aiResources : [aiResources]) {
|
|
2950
|
+
const deps = res.dependencies;
|
|
2951
|
+
if (Array.isArray(deps)) {
|
|
2952
|
+
for (const dep of deps) {
|
|
2953
|
+
const ref = typeof dep === "string" ? dep : dep?.ref ?? dep?.name;
|
|
2954
|
+
if (ref) {
|
|
2955
|
+
const skillDir = join(
|
|
2956
|
+
opts.projectDir,
|
|
2957
|
+
".claude",
|
|
2958
|
+
"skills",
|
|
2959
|
+
ref.replace(/^skill:/, "")
|
|
2960
|
+
);
|
|
2961
|
+
if (!existsSync(skillDir)) {
|
|
2962
|
+
log(
|
|
2963
|
+
`[serve] validation_warning: dependency "${ref}" not found \u2014 continuing without it`
|
|
2964
|
+
);
|
|
2965
|
+
sendEvent({
|
|
2966
|
+
type: "validation_warning",
|
|
2967
|
+
asset: ref,
|
|
2968
|
+
reason: "not_found",
|
|
2969
|
+
suggestion: "Sync the catalog and re-add this asset"
|
|
2970
|
+
});
|
|
2971
|
+
}
|
|
2972
|
+
}
|
|
2973
|
+
}
|
|
2974
|
+
}
|
|
2975
|
+
}
|
|
2976
|
+
}
|
|
2977
|
+
} catch {
|
|
2978
|
+
}
|
|
2979
|
+
const normalizer = new EventNormalizer();
|
|
2980
|
+
function forwardNormalizedEvent(event) {
|
|
2981
|
+
if (compacting) return;
|
|
2982
|
+
const isTransient = event.type === "status" || event.type === "sync_status" || event.type === "resources_available" || event.type === "resource_response" || event.type === "commands_available";
|
|
2983
|
+
if (!isTransient) {
|
|
2984
|
+
eventSeq++;
|
|
2985
|
+
compactionOrchestrator?.trackMessage(eventSeq);
|
|
2986
|
+
}
|
|
2987
|
+
if (event.type === "finished") {
|
|
2988
|
+
if (!compacting && compactionOrchestrator?.shouldCompact()) {
|
|
2989
|
+
compactionOrchestrator.compact("threshold").catch((err) => {
|
|
2990
|
+
log(
|
|
2991
|
+
`[serve] auto-compaction failed: ${err instanceof Error ? err.message : String(err)}`
|
|
2992
|
+
);
|
|
2993
|
+
});
|
|
2994
|
+
}
|
|
2995
|
+
}
|
|
2996
|
+
if (!mountManager) {
|
|
2997
|
+
sendEvent(event);
|
|
2998
|
+
return;
|
|
2999
|
+
}
|
|
3000
|
+
const mounts = mountManager.listMounts().map(
|
|
3001
|
+
(info) => ({
|
|
3002
|
+
id: info.id,
|
|
3003
|
+
mountPath: mountManager.get(info.id).handle.mountPath
|
|
3004
|
+
})
|
|
3005
|
+
);
|
|
3006
|
+
sendEvent(rewriteFileChangedPath(event, opts.projectDir, mounts));
|
|
3007
|
+
}
|
|
3008
|
+
let driverStarted = false;
|
|
3009
|
+
let driver = secretsMode === "env" ? agentSession.driver : void 0;
|
|
3010
|
+
let secretsProvisioned = secretsMode === "env";
|
|
3011
|
+
let eventSeq = 0;
|
|
3012
|
+
let compacting = false;
|
|
3013
|
+
let compactionOrchestrator = null;
|
|
3014
|
+
const compactionConfig = wsConfig.compaction;
|
|
3015
|
+
function rebuildCompactionOrchestrator() {
|
|
3016
|
+
if (!driver) return;
|
|
3017
|
+
compactionOrchestrator = new CompactionOrchestrator({
|
|
3018
|
+
driver,
|
|
3019
|
+
config: compactionConfig,
|
|
3020
|
+
onCompactionStart: (trigger) => {
|
|
3021
|
+
compacting = true;
|
|
3022
|
+
sendEvent({ type: "status", phase: "compacting" });
|
|
3023
|
+
log(`[serve] compaction started (trigger=${trigger})`);
|
|
3024
|
+
},
|
|
3025
|
+
onSnapshot: (snapshot) => {
|
|
3026
|
+
sendEvent(snapshot);
|
|
3027
|
+
},
|
|
3028
|
+
onCompactionAttempt: (event) => {
|
|
3029
|
+
sendEvent(event);
|
|
3030
|
+
},
|
|
3031
|
+
onCompactionEnd: () => {
|
|
3032
|
+
compacting = false;
|
|
3033
|
+
sendEvent({ type: "status", phase: "idle" });
|
|
3034
|
+
},
|
|
3035
|
+
onLog: (line) => log(`[serve] ${line}`),
|
|
3036
|
+
// Phase 3: stamp every CompactionAttemptEvent with the registry's
|
|
3037
|
+
// current signature so wake-time tier-1 selection has the input it
|
|
3038
|
+
// needs. The registry exists for the entire serve lifetime, so this
|
|
3039
|
+
// closure is safe across orchestrator rebuilds.
|
|
3040
|
+
getCurrentCapabilitySignature: () => computeCapabilitySignature(capabilityRegistry.list())
|
|
3041
|
+
});
|
|
3042
|
+
}
|
|
3043
|
+
if (secretsMode === "env" && driver) {
|
|
3044
|
+
rebuildCompactionOrchestrator();
|
|
3045
|
+
}
|
|
3046
|
+
const activeFlows = /* @__PURE__ */ new Map();
|
|
3047
|
+
let stimulusBus = null;
|
|
3048
|
+
const FLOW_TURN_TIMEOUT_MS = 4 * 60 * 60 * 1e3;
|
|
3049
|
+
function getOnlyActiveFlow() {
|
|
3050
|
+
const iter = activeFlows.values().next();
|
|
3051
|
+
return iter.done ? null : iter.value;
|
|
3052
|
+
}
|
|
3053
|
+
function getOrCreateStimulusBus() {
|
|
3054
|
+
if (stimulusBus) return stimulusBus;
|
|
3055
|
+
stimulusBus = createSessionStimulusBus({
|
|
3056
|
+
driveTurn: async (promptFragment, metas) => {
|
|
3057
|
+
const lastMeta = metas[metas.length - 1] ?? {};
|
|
3058
|
+
const runId = typeof lastMeta.runId === "string" ? lastMeta.runId : null;
|
|
3059
|
+
const entry = runId ? activeFlows.get(runId) : getOnlyActiveFlow();
|
|
3060
|
+
if (!entry) {
|
|
3061
|
+
serverLog.warn("driveTurn fired with no active flow", { runId });
|
|
3062
|
+
return;
|
|
3063
|
+
}
|
|
3064
|
+
const lastKind = lastMeta.kind;
|
|
3065
|
+
let stimulus;
|
|
3066
|
+
if (lastKind === "flow_started") {
|
|
3067
|
+
stimulus = { kind: "flow_started" };
|
|
3068
|
+
} else if (lastKind === "user_message" && typeof lastMeta.text === "string") {
|
|
3069
|
+
stimulus = {
|
|
3070
|
+
kind: "user_message",
|
|
3071
|
+
text: String(lastMeta.text),
|
|
3072
|
+
senderId: String(lastMeta.senderId ?? "user")
|
|
3073
|
+
};
|
|
3074
|
+
} else {
|
|
3075
|
+
stimulus = { kind: "state_changed" };
|
|
3076
|
+
}
|
|
3077
|
+
const fullPrompt = buildOrchestratorPrompt(
|
|
3078
|
+
entry.flowDef,
|
|
3079
|
+
entry.adapter.getExecution(entry.handle),
|
|
3080
|
+
stimulus
|
|
3081
|
+
);
|
|
3082
|
+
if (!driverStarted) {
|
|
3083
|
+
await driver.start();
|
|
3084
|
+
driverStarted = true;
|
|
3085
|
+
driver.on("agent-event", (event) => {
|
|
3086
|
+
const normalized = normalizer.normalize(event);
|
|
3087
|
+
for (const e of normalized) forwardNormalizedEvent(e);
|
|
3088
|
+
});
|
|
3089
|
+
driver.on("error", (err) => {
|
|
3090
|
+
log(`[serve] driver error: ${err.message}`);
|
|
3091
|
+
sendEvent({ type: "error", message: err.message, fatal: true });
|
|
3092
|
+
});
|
|
3093
|
+
}
|
|
3094
|
+
await awaitFlowAgentEnd(fullPrompt, FLOW_TURN_TIMEOUT_MS);
|
|
3095
|
+
},
|
|
3096
|
+
log: serverLog
|
|
3097
|
+
});
|
|
3098
|
+
return stimulusBus;
|
|
3099
|
+
}
|
|
3100
|
+
function awaitFlowAgentEnd(prompt, timeoutMs) {
|
|
3101
|
+
return new Promise((resolve3, reject) => {
|
|
3102
|
+
let settled = false;
|
|
3103
|
+
const onEvent = (event) => {
|
|
3104
|
+
if (event.type === "agent_end") done();
|
|
3105
|
+
else if (event.type === "error") {
|
|
3106
|
+
const msg = event.error ?? event.message ?? "Agent error";
|
|
3107
|
+
done(new Error(msg));
|
|
3108
|
+
}
|
|
3109
|
+
};
|
|
3110
|
+
const done = (err) => {
|
|
3111
|
+
if (settled) return;
|
|
3112
|
+
settled = true;
|
|
3113
|
+
clearTimeout(timer);
|
|
3114
|
+
driver.off?.(
|
|
3115
|
+
"agent-event",
|
|
3116
|
+
onEvent
|
|
3117
|
+
) ?? driver.removeListener("agent-event", onEvent);
|
|
3118
|
+
if (err) reject(err);
|
|
3119
|
+
else resolve3();
|
|
3120
|
+
};
|
|
3121
|
+
const timer = setTimeout(
|
|
3122
|
+
() => done(new Error(`Flow turn timed out after ${timeoutMs / 1e3}s`)),
|
|
3123
|
+
timeoutMs
|
|
3124
|
+
);
|
|
3125
|
+
driver.on("agent-event", onEvent);
|
|
3126
|
+
driver.prompt(prompt).catch(done);
|
|
3127
|
+
});
|
|
3128
|
+
}
|
|
3129
|
+
async function createActiveFlow(flowDef, seedOrExecution) {
|
|
3130
|
+
if (!resourceManager) {
|
|
3131
|
+
registerBuiltinConnectorAdapters();
|
|
3132
|
+
resourceManager = new ConnectorManager(void 0, {
|
|
3133
|
+
catalogEntries: getSessionCatalogEntries(agentSession)
|
|
3134
|
+
});
|
|
3135
|
+
log("[serve] created ConnectorManager for flow execution (no other connectors declared)");
|
|
3136
|
+
}
|
|
3137
|
+
const bus = getOrCreateStimulusBus();
|
|
3138
|
+
const baseOptions = {
|
|
3139
|
+
stimulusBus: bus,
|
|
3140
|
+
useBusForStimulus: true
|
|
3141
|
+
};
|
|
3142
|
+
const options = "execution" in seedOrExecution ? { flow: flowDef, execution: seedOrExecution.execution, ...baseOptions } : { flow: flowDef, seed: seedOrExecution.seed, ...baseOptions };
|
|
3143
|
+
const seedRunId = "execution" in seedOrExecution ? seedOrExecution.execution.runId : seedOrExecution.seed.runId;
|
|
3144
|
+
const connectorId = `flow:${seedRunId}`;
|
|
3145
|
+
const handle = await resourceManager.connect({
|
|
3146
|
+
id: connectorId,
|
|
3147
|
+
driver: "flow",
|
|
3148
|
+
access: "read-write",
|
|
3149
|
+
options
|
|
3150
|
+
});
|
|
3151
|
+
const adapter = resourceManager.get(connectorId).adapter;
|
|
3152
|
+
const runId = adapter.getExecution(handle).runId;
|
|
3153
|
+
adapter.onStateChange(handle, (state) => {
|
|
3154
|
+
sendEvent({
|
|
3155
|
+
type: "state_changed",
|
|
3156
|
+
store: `flow:${state.runId}`,
|
|
3157
|
+
state
|
|
3158
|
+
});
|
|
3159
|
+
});
|
|
3160
|
+
if (agentSession?.driverType === "claude-sdk") {
|
|
3161
|
+
try {
|
|
3162
|
+
const server = await buildSdkConnectorTools(resourceManager, { z: z });
|
|
3163
|
+
if (server) {
|
|
3164
|
+
if (driverStarted) {
|
|
3165
|
+
const prevSessionId = driver.runtimeSessionId;
|
|
3166
|
+
log(
|
|
3167
|
+
`[serve] restarting driver to register flow connector tools (resume=${prevSessionId ?? "none"})`
|
|
3168
|
+
);
|
|
3169
|
+
await agentSession.dispose();
|
|
3170
|
+
agentSession = await createAgentSession({
|
|
3171
|
+
...sessionConfig,
|
|
3172
|
+
resumeSessionId: prevSessionId
|
|
3173
|
+
});
|
|
3174
|
+
emitSystemPromptComposed(agentSession, sendEvent);
|
|
3175
|
+
driver = agentSession.driver;
|
|
3176
|
+
normalizer.reset();
|
|
3177
|
+
driverStarted = false;
|
|
3178
|
+
rebuildCompactionOrchestrator();
|
|
3179
|
+
}
|
|
3180
|
+
driver.config.mcpServers = { "skaile-connectors": server };
|
|
3181
|
+
log(`[serve] rebuilt MCP connector tools for flow ${connectorId}`);
|
|
3182
|
+
} else {
|
|
3183
|
+
log(`[serve] buildSdkConnectorTools returned null for flow ${connectorId}`);
|
|
3184
|
+
}
|
|
3185
|
+
} catch (err) {
|
|
3186
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
3187
|
+
log(`[serve] failed to rebuild MCP tools for flow: ${errMsg}`);
|
|
3188
|
+
}
|
|
3189
|
+
}
|
|
3190
|
+
const entry = { runId, flowDef, adapter, handle, connectorId };
|
|
3191
|
+
activeFlows.set(runId, entry);
|
|
3192
|
+
return entry;
|
|
3193
|
+
}
|
|
3194
|
+
const refreshFlagPath = join(opts.projectDir, ".skaile", "refresh-request");
|
|
3195
|
+
try {
|
|
3196
|
+
mkdirSync(join(opts.projectDir, ".skaile"), { recursive: true });
|
|
3197
|
+
if (!existsSync(refreshFlagPath)) {
|
|
3198
|
+
writeFileSync(refreshFlagPath, "", { mode: 432, flag: "a" });
|
|
3199
|
+
}
|
|
3200
|
+
} catch (err) {
|
|
3201
|
+
serverLog.warn("failed to pre-create refresh-flag \u2014 wake-mid-401 disabled", {
|
|
3202
|
+
error: err instanceof Error ? err.message : String(err)
|
|
3203
|
+
});
|
|
3204
|
+
}
|
|
3205
|
+
let lastRefreshAt = 0;
|
|
3206
|
+
const REFRESH_DEBOUNCE_MS = 2e3;
|
|
3207
|
+
let refreshFlagWatcher = null;
|
|
3208
|
+
try {
|
|
3209
|
+
refreshFlagWatcher = watch(refreshFlagPath, (event) => {
|
|
3210
|
+
if (event !== "change") return;
|
|
3211
|
+
const now = Date.now();
|
|
3212
|
+
if (now - lastRefreshAt < REFRESH_DEBOUNCE_MS) return;
|
|
3213
|
+
lastRefreshAt = now;
|
|
3214
|
+
void dispatchRefreshToExposedGitMounts(mountManager, serverLog);
|
|
3215
|
+
});
|
|
3216
|
+
} catch (err) {
|
|
3217
|
+
serverLog.warn("fs.watch on refresh-flag failed \u2014 wake-mid-401 disabled", {
|
|
3218
|
+
error: err instanceof Error ? err.message : String(err)
|
|
3219
|
+
});
|
|
3220
|
+
}
|
|
3221
|
+
async function cleanup() {
|
|
3222
|
+
try {
|
|
3223
|
+
await Promise.race([
|
|
3224
|
+
sessionReady,
|
|
3225
|
+
new Promise((resolve3) => {
|
|
3226
|
+
const t = setTimeout(resolve3, 2e3);
|
|
3227
|
+
t.unref?.();
|
|
3228
|
+
})
|
|
3229
|
+
]);
|
|
3230
|
+
} catch {
|
|
3231
|
+
}
|
|
3232
|
+
try {
|
|
3233
|
+
driver?.kill();
|
|
3234
|
+
} catch {
|
|
3235
|
+
}
|
|
3236
|
+
for (const [callId, pending] of pendingCapabilityCalls) {
|
|
3237
|
+
clearTimeout(pending.timer);
|
|
3238
|
+
pending.reject(new Error(`Session terminated before capability_result (callId=${callId})`));
|
|
3239
|
+
}
|
|
3240
|
+
pendingCapabilityCalls.clear();
|
|
3241
|
+
try {
|
|
3242
|
+
refreshFlagWatcher?.close();
|
|
3243
|
+
} catch {
|
|
3244
|
+
}
|
|
3245
|
+
refreshFlagWatcher = null;
|
|
3246
|
+
if (agentSession) {
|
|
3247
|
+
try {
|
|
3248
|
+
await agentSession.dispose();
|
|
3249
|
+
} catch {
|
|
3250
|
+
}
|
|
3251
|
+
}
|
|
3252
|
+
}
|
|
3253
|
+
async function handleCommand(cmd) {
|
|
3254
|
+
switch (cmd.type) {
|
|
3255
|
+
case "session_init": {
|
|
3256
|
+
if (cmd.protocolVersion.major !== PROTOCOL_VERSION.major) {
|
|
3257
|
+
log(
|
|
3258
|
+
`[serve] incompatible protocol: agent=${PROTOCOL_VERSION.major} platform=${cmd.protocolVersion.major}`
|
|
3259
|
+
);
|
|
3260
|
+
sendEvent({
|
|
3261
|
+
type: "incompatible_protocol",
|
|
3262
|
+
agentVersion: PROTOCOL_VERSION,
|
|
3263
|
+
platformVersion: cmd.protocolVersion
|
|
3264
|
+
});
|
|
3265
|
+
await cleanup();
|
|
3266
|
+
disposeLogStore();
|
|
3267
|
+
return;
|
|
3268
|
+
}
|
|
3269
|
+
if (runtimeIdentity && runtimeIdentity.containerId !== cmd.identity.containerId) {
|
|
3270
|
+
log(
|
|
3271
|
+
`[serve] session_init_mismatch: expected=${runtimeIdentity.containerId} received=${cmd.identity.containerId}`
|
|
3272
|
+
);
|
|
3273
|
+
sendEvent({
|
|
3274
|
+
type: "session_init_mismatch",
|
|
3275
|
+
expectedContainerId: runtimeIdentity.containerId,
|
|
3276
|
+
receivedContainerId: cmd.identity.containerId
|
|
3277
|
+
});
|
|
3278
|
+
await cleanup();
|
|
3279
|
+
disposeLogStore();
|
|
3280
|
+
return;
|
|
3281
|
+
}
|
|
3282
|
+
runtimeIdentity = cmd.identity;
|
|
3283
|
+
const incoming = cmd.capabilities ?? [];
|
|
3284
|
+
for (const wire of incoming) {
|
|
3285
|
+
if (wire.audience && !wire.audience.includes("llm") && !wire.audience.includes("user")) {
|
|
3286
|
+
continue;
|
|
3287
|
+
}
|
|
3288
|
+
const stub = {
|
|
3289
|
+
...wire,
|
|
3290
|
+
inputZod: { parse: (v) => v },
|
|
3291
|
+
outputZod: void 0,
|
|
3292
|
+
handler: buildClientCapabilityHandler2(wire)
|
|
3293
|
+
};
|
|
3294
|
+
capabilityRegistry.register(stub, "client");
|
|
3295
|
+
}
|
|
3296
|
+
sendEvent({ type: "protocol_info", version: PROTOCOL_VERSION });
|
|
3297
|
+
preMintedSecrets = new PreMintedSecretProvider(cmd.credentials);
|
|
3298
|
+
if (cmd.secrets) {
|
|
3299
|
+
const ccdValue = cmd.secrets[CLAUDE_CODE_CREDENTIALS_KEY];
|
|
3300
|
+
if (ccdValue) {
|
|
3301
|
+
const home = process.env.HOME ?? homedir();
|
|
3302
|
+
if (home) {
|
|
3303
|
+
try {
|
|
3304
|
+
await writeClaudeCodeCredentialsFile(home, ccdValue);
|
|
3305
|
+
log(
|
|
3306
|
+
`[serve] wrote Claude Code credentials file to ${home}/.claude/.credentials.json (mode 0600)`
|
|
3307
|
+
);
|
|
3308
|
+
} catch (err) {
|
|
3309
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
3310
|
+
log(`[serve] failed to write Claude Code credentials file: ${errMsg}`);
|
|
3311
|
+
}
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3314
|
+
const otherSecrets = Object.fromEntries(
|
|
3315
|
+
Object.entries(cmd.secrets).filter(([k]) => k !== CLAUDE_CODE_CREDENTIALS_KEY)
|
|
3316
|
+
);
|
|
3317
|
+
const provider = new InMemorySecretProvider();
|
|
3318
|
+
provider.provision(otherSecrets);
|
|
3319
|
+
secretProvider = provider;
|
|
3320
|
+
secretsProvisioned = true;
|
|
3321
|
+
}
|
|
3322
|
+
try {
|
|
3323
|
+
const effectiveProvider = opts.provider ?? "anthropic";
|
|
3324
|
+
const envKey = providerEnvKey(effectiveProvider);
|
|
3325
|
+
const apiKeyFromSecrets = cmd.secrets?.[envKey];
|
|
3326
|
+
sessionConfig = buildSessionConfig(secretProvider, apiKeyFromSecrets);
|
|
3327
|
+
if (!agentSession) {
|
|
3328
|
+
agentSession = await createAgentSession(sessionConfig);
|
|
3329
|
+
emitSystemPromptComposed(agentSession, sendEvent);
|
|
3330
|
+
resourceManager = agentSession.resourceManager;
|
|
3331
|
+
mountManager = agentSession.mountManager;
|
|
3332
|
+
driver = agentSession.driver;
|
|
3333
|
+
rebuildCompactionOrchestrator();
|
|
3334
|
+
registerSessionComposition(agentSession);
|
|
3335
|
+
const mountList = mountManager?.listMounts?.() ?? [];
|
|
3336
|
+
const connectorList = resourceManager?.listConnectors?.() ?? [];
|
|
3337
|
+
sendEvent({
|
|
3338
|
+
type: "resources_available",
|
|
3339
|
+
mounts: mountList,
|
|
3340
|
+
connectors: connectorList
|
|
3341
|
+
});
|
|
3342
|
+
agentSession.startWatching();
|
|
3343
|
+
capabilityRegistry.setRemoteInvoker(remoteCapabilityInvoker);
|
|
3344
|
+
const runnerCaps = buildRunnerCapabilities({
|
|
3345
|
+
// setLogLevel is left undefined — the cap's built-in fallback
|
|
3346
|
+
// calls `getLogStore()?.setLevel(...)` directly, which matches
|
|
3347
|
+
// the legacy `set_log_level` AgentCommand body 1:1.
|
|
3348
|
+
// Other handlers (addMount / addConnector / removeResource /
|
|
3349
|
+
// updateCredential / setState / lifecycle) remain stubs;
|
|
3350
|
+
// wiring is tracked under AF-PV3 / F-RUNNER-CAPS.
|
|
3351
|
+
});
|
|
3352
|
+
for (const cap of runnerCaps) {
|
|
3353
|
+
capabilityRegistry.register(cap, "agent");
|
|
3354
|
+
}
|
|
3355
|
+
resolveSessionReady();
|
|
3356
|
+
log("[serve] session built from session_init envelope");
|
|
3357
|
+
}
|
|
3358
|
+
} catch (err) {
|
|
3359
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
3360
|
+
log(`[serve] session_init failed to build session: ${errMsg}`);
|
|
3361
|
+
sendEvent({ type: "error", message: errMsg, fatal: true });
|
|
3362
|
+
rejectSessionReady(err instanceof Error ? err : new Error(errMsg));
|
|
3363
|
+
}
|
|
3364
|
+
if (cmd.resolvedConfig.aiProviderConfigId) {
|
|
3365
|
+
aiProviderConfigId = cmd.resolvedConfig.aiProviderConfigId;
|
|
3366
|
+
log(`[serve] stashed aiProviderConfigId=${aiProviderConfigId}`);
|
|
3367
|
+
}
|
|
3368
|
+
const cfg = {
|
|
3369
|
+
aiResources: cmd.resolvedConfig.aiResources,
|
|
3370
|
+
subagents: cmd.resolvedConfig.subagents,
|
|
3371
|
+
sharedState: cmd.sharedState,
|
|
3372
|
+
resumeSessionId: cmd.resume?.sessionId,
|
|
3373
|
+
expectedCapabilitySignature: cmd.resume?.expectedCapabilitySignature,
|
|
3374
|
+
aiProviderConfigId: cmd.resolvedConfig.aiProviderConfigId
|
|
3375
|
+
};
|
|
3376
|
+
log(
|
|
3377
|
+
`[serve] configure cfg keys=${Object.keys(cfg).join(",")} sharedState=${cfg.sharedState ? cfg.sharedState.length : "undefined"} resourceManager=${resourceManager ? "set" : "null"}`
|
|
3378
|
+
);
|
|
3379
|
+
if (cfg.aiProviderConfigId) {
|
|
3380
|
+
aiProviderConfigId = cfg.aiProviderConfigId;
|
|
3381
|
+
log(`[serve] stashed aiProviderConfigId=${aiProviderConfigId}`);
|
|
3382
|
+
}
|
|
3383
|
+
let pendingResumeSessionId;
|
|
3384
|
+
const cfgResumeSessionId = cfg.resumeSessionId;
|
|
3385
|
+
const cfgExpectedSig = cfg.expectedCapabilitySignature;
|
|
3386
|
+
if (cfgResumeSessionId) {
|
|
3387
|
+
const currentSig = computeCapabilitySignature(capabilityRegistry.list());
|
|
3388
|
+
if (cfgExpectedSig && cfgExpectedSig !== currentSig) {
|
|
3389
|
+
log(
|
|
3390
|
+
`[serve] tier-1 resume rejected: signature mismatch (expected=${cfgExpectedSig.slice(0, 12)} current=${currentSig.slice(0, 12)})`
|
|
3391
|
+
);
|
|
3392
|
+
sendEvent({
|
|
3393
|
+
type: "resume_failed",
|
|
3394
|
+
resumeSessionId: cfgResumeSessionId,
|
|
3395
|
+
reason: "signature_mismatch"
|
|
3396
|
+
});
|
|
3397
|
+
} else {
|
|
3398
|
+
log(`[serve] tier-1 resume attempted: resumeSessionId=${cfgResumeSessionId}`);
|
|
3399
|
+
sendEvent({
|
|
3400
|
+
type: "resume_attempted",
|
|
3401
|
+
resumeSessionId: cfgResumeSessionId,
|
|
3402
|
+
capabilitySignature: currentSig
|
|
3403
|
+
});
|
|
3404
|
+
pendingResumeSessionId = cfgResumeSessionId;
|
|
3405
|
+
}
|
|
3406
|
+
}
|
|
3407
|
+
if (pendingResumeSessionId || cfg.subagents) {
|
|
3408
|
+
await agentSession.dispose();
|
|
3409
|
+
agentSession = await createAgentSession({
|
|
3410
|
+
...sessionConfig,
|
|
3411
|
+
...aiProviderConfigId ? { aiProviderConfigId } : {},
|
|
3412
|
+
...pendingResumeSessionId ? { resumeSessionId: pendingResumeSessionId } : {}
|
|
3413
|
+
});
|
|
3414
|
+
emitSystemPromptComposed(agentSession, sendEvent);
|
|
3415
|
+
driver = agentSession.driver;
|
|
3416
|
+
normalizer.reset();
|
|
3417
|
+
driverStarted = false;
|
|
3418
|
+
rebuildCompactionOrchestrator();
|
|
3419
|
+
}
|
|
3420
|
+
if (cfg.sharedState) {
|
|
3421
|
+
if (!resourceManager) {
|
|
3422
|
+
try {
|
|
3423
|
+
registerBuiltinConnectorAdapters();
|
|
3424
|
+
resourceManager = new ConnectorManager(void 0, {
|
|
3425
|
+
catalogEntries: getSessionCatalogEntries(agentSession)
|
|
3426
|
+
});
|
|
3427
|
+
log("[serve] created ConnectorManager for sharedState (no connectors were declared)");
|
|
3428
|
+
} catch (err) {
|
|
3429
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
3430
|
+
log(`[serve] failed to create ConnectorManager: ${errMsg}`);
|
|
3431
|
+
sendEvent({ type: "configured" });
|
|
3432
|
+
break;
|
|
3433
|
+
}
|
|
3434
|
+
}
|
|
3435
|
+
let storesRegistered = 0;
|
|
3436
|
+
for (const stateConfig of cfg.sharedState) {
|
|
3437
|
+
try {
|
|
3438
|
+
if (resourceManager.has(stateConfig.id)) {
|
|
3439
|
+
try {
|
|
3440
|
+
const snapshot = await resourceManager.executeOp(stateConfig.id, "get", {});
|
|
3441
|
+
const state = snapshot ? JSON.parse(snapshot) : {};
|
|
3442
|
+
sendEvent({
|
|
3443
|
+
type: "state_changed",
|
|
3444
|
+
store: stateConfig.id,
|
|
3445
|
+
state
|
|
3446
|
+
});
|
|
3447
|
+
log(
|
|
3448
|
+
`[serve] sharedState ${stateConfig.id} already registered \u2014 re-emitted current state`
|
|
3449
|
+
);
|
|
3450
|
+
} catch {
|
|
3451
|
+
log(
|
|
3452
|
+
`[serve] sharedState ${stateConfig.id} already registered \u2014 skipping (could not read state)`
|
|
3453
|
+
);
|
|
3454
|
+
}
|
|
3455
|
+
continue;
|
|
3456
|
+
}
|
|
3457
|
+
const handle = await resourceManager.connect({
|
|
3458
|
+
id: stateConfig.id,
|
|
3459
|
+
driver: stateConfig.adapter,
|
|
3460
|
+
access: "read-write",
|
|
3461
|
+
options: {
|
|
3462
|
+
...stateConfig.definition ?? {},
|
|
3463
|
+
initial: stateConfig.initialState ?? {}
|
|
3464
|
+
}
|
|
3465
|
+
});
|
|
3466
|
+
const entry = resourceManager.get(stateConfig.id);
|
|
3467
|
+
if (typeof entry.adapter.onStoreChange === "function") {
|
|
3468
|
+
entry.adapter.onStoreChange(handle, (snapshot) => {
|
|
3469
|
+
sendEvent({
|
|
3470
|
+
type: "state_changed",
|
|
3471
|
+
store: stateConfig.id,
|
|
3472
|
+
state: snapshot
|
|
3473
|
+
});
|
|
3474
|
+
});
|
|
3475
|
+
}
|
|
3476
|
+
log(`[serve] sharedState registered: ${stateConfig.id} (${stateConfig.adapter})`);
|
|
3477
|
+
storesRegistered++;
|
|
3478
|
+
sendEvent({
|
|
3479
|
+
type: "state_changed",
|
|
3480
|
+
store: stateConfig.id,
|
|
3481
|
+
state: stateConfig.initialState ?? {}
|
|
3482
|
+
});
|
|
3483
|
+
} catch (err) {
|
|
3484
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
3485
|
+
log(`[serve] sharedState registration failed for ${stateConfig.id}: ${errMsg}`);
|
|
3486
|
+
sendEvent({
|
|
3487
|
+
type: "error",
|
|
3488
|
+
message: `sharedState ${stateConfig.id}: ${errMsg}`,
|
|
3489
|
+
fatal: false
|
|
3490
|
+
});
|
|
3491
|
+
}
|
|
3492
|
+
}
|
|
3493
|
+
if (storesRegistered > 0 && !driverStarted && agentSession?.driverType === "claude-sdk") {
|
|
3494
|
+
try {
|
|
3495
|
+
const server = await buildSdkConnectorTools(resourceManager, { z: z });
|
|
3496
|
+
if (server) {
|
|
3497
|
+
driver.config.mcpServers = { "skaile-connectors": server };
|
|
3498
|
+
log(`[serve] rebuilt MCP connector tools (${storesRegistered} new store(s))`);
|
|
3499
|
+
} else {
|
|
3500
|
+
log(`[serve] buildSdkConnectorTools returned null`);
|
|
3501
|
+
}
|
|
3502
|
+
} catch (err) {
|
|
3503
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
3504
|
+
log(`[serve] failed to rebuild MCP tools: ${errMsg}`);
|
|
3505
|
+
}
|
|
3506
|
+
}
|
|
3507
|
+
}
|
|
3508
|
+
if (cfg.aiResources) {
|
|
3509
|
+
const catalogActions = cfg.aiResources.filter((a) => a.action);
|
|
3510
|
+
if (catalogActions.length > 0) {
|
|
3511
|
+
log(`[serve] aiResources catalog actions: ${catalogActions.length}`);
|
|
3512
|
+
try {
|
|
3513
|
+
const skillsDir = join(
|
|
3514
|
+
sessionConfig.projectDir ?? process.cwd(),
|
|
3515
|
+
".claude",
|
|
3516
|
+
"skills"
|
|
3517
|
+
);
|
|
3518
|
+
const assetsRoot = process.env.SKAILE_ASSETS_ROOT ?? findAiAssetsRoot(sessionConfig.projectDir ?? process.cwd()) ?? "/app/ai-assets";
|
|
3519
|
+
for (const res of catalogActions) {
|
|
3520
|
+
if (res.action === "add" && res.entry) {
|
|
3521
|
+
const entry = res.entry;
|
|
3522
|
+
const result = deployCatalogEntry(entry, {
|
|
3523
|
+
assetsRoot,
|
|
3524
|
+
skillsDir,
|
|
3525
|
+
context: res.context
|
|
3526
|
+
});
|
|
3527
|
+
if (result.success) {
|
|
3528
|
+
log(`[serve] deployed skill: ${entry.name ?? res.name}`);
|
|
3529
|
+
} else {
|
|
3530
|
+
log(
|
|
3531
|
+
`[serve] failed to deploy skill ${entry.name ?? res.name}: ${result.error}`
|
|
3532
|
+
);
|
|
3533
|
+
}
|
|
3534
|
+
} else if (res.action === "remove") {
|
|
3535
|
+
const removed = undeployCatalogEntry(res.name, skillsDir);
|
|
3536
|
+
log(`[serve] ${removed ? "removed" : "not found"} skill: ${res.name}`);
|
|
3537
|
+
}
|
|
3538
|
+
}
|
|
3539
|
+
if (driverStarted) {
|
|
3540
|
+
const prevSessionId = driver.runtimeSessionId;
|
|
3541
|
+
log(
|
|
3542
|
+
`[serve] restarting driver to pick up skill changes (resume=${prevSessionId ?? "none"})`
|
|
3543
|
+
);
|
|
3544
|
+
await agentSession.dispose();
|
|
3545
|
+
agentSession = await createAgentSession({
|
|
3546
|
+
...sessionConfig,
|
|
3547
|
+
resumeSessionId: prevSessionId
|
|
3548
|
+
});
|
|
3549
|
+
emitSystemPromptComposed(agentSession, sendEvent);
|
|
3550
|
+
driver = agentSession.driver;
|
|
3551
|
+
normalizer.reset();
|
|
3552
|
+
driverStarted = false;
|
|
3553
|
+
rebuildCompactionOrchestrator();
|
|
3554
|
+
sendEvent({
|
|
3555
|
+
type: "skills_changed",
|
|
3556
|
+
skills: catalogActions.map((a) => ({
|
|
3557
|
+
name: a.entry?.name ?? a.name,
|
|
3558
|
+
action: a.action ?? "add"
|
|
3559
|
+
}))
|
|
3560
|
+
});
|
|
3561
|
+
} else {
|
|
3562
|
+
log(
|
|
3563
|
+
"[serve] aiResources applied before driver start \u2014 skills discovered on first prompt"
|
|
3564
|
+
);
|
|
3565
|
+
}
|
|
3566
|
+
} catch (err) {
|
|
3567
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
3568
|
+
log(`[serve] aiResources handling failed: ${errMsg}`);
|
|
3569
|
+
sendEvent({
|
|
3570
|
+
type: "error",
|
|
3571
|
+
message: `aiResources: ${errMsg}`,
|
|
3572
|
+
fatal: false
|
|
3573
|
+
});
|
|
3574
|
+
}
|
|
3575
|
+
}
|
|
3576
|
+
}
|
|
3577
|
+
sendEvent({
|
|
3578
|
+
type: "session_init_ack",
|
|
3579
|
+
capabilitySignature: computeCapabilitySignature(capabilityRegistry.list())
|
|
3580
|
+
});
|
|
3581
|
+
break;
|
|
3582
|
+
}
|
|
3583
|
+
case "prompt": {
|
|
3584
|
+
try {
|
|
3585
|
+
await sessionReady;
|
|
3586
|
+
} catch (err) {
|
|
3587
|
+
sendEvent({
|
|
3588
|
+
type: "error",
|
|
3589
|
+
message: `Session not available: ${err.message}`,
|
|
3590
|
+
fatal: true
|
|
3591
|
+
});
|
|
3592
|
+
break;
|
|
3593
|
+
}
|
|
3594
|
+
if (!secretsProvisioned) {
|
|
3595
|
+
log("[serve] prompt received before secrets provisioned \u2014 rejecting");
|
|
3596
|
+
sendEvent({
|
|
3597
|
+
type: "error",
|
|
3598
|
+
message: "Secrets not yet provisioned \u2014 send provision_secrets first",
|
|
3599
|
+
fatal: false
|
|
3600
|
+
});
|
|
3601
|
+
break;
|
|
3602
|
+
}
|
|
3603
|
+
log(`[serve] prompt: ${cmd.prompt.slice(0, 80)}...`);
|
|
3604
|
+
const activeFlow = getOnlyActiveFlow();
|
|
3605
|
+
if (activeFlow) {
|
|
3606
|
+
sendEvent({ type: "status", phase: "thinking" });
|
|
3607
|
+
try {
|
|
3608
|
+
const bus = getOrCreateStimulusBus();
|
|
3609
|
+
const userStimulus = {
|
|
3610
|
+
kind: "user_message",
|
|
3611
|
+
text: cmd.prompt,
|
|
3612
|
+
senderId: "user"
|
|
3613
|
+
};
|
|
3614
|
+
await bus.signal(activeFlow.connectorId, {
|
|
3615
|
+
promptFragment: renderStimulusPrompt(userStimulus),
|
|
3616
|
+
meta: {
|
|
3617
|
+
kind: "user_message",
|
|
3618
|
+
runId: activeFlow.runId,
|
|
3619
|
+
text: cmd.prompt,
|
|
3620
|
+
senderId: "user"
|
|
3621
|
+
}
|
|
3622
|
+
});
|
|
3623
|
+
} catch (err) {
|
|
3624
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
3625
|
+
log(`[serve] flow user-message turn failed: ${errMsg}`);
|
|
3626
|
+
sendEvent({ type: "error", message: `Flow turn failed: ${errMsg}`, fatal: false });
|
|
3627
|
+
}
|
|
3628
|
+
break;
|
|
3629
|
+
}
|
|
3630
|
+
if (!driverStarted) {
|
|
3631
|
+
try {
|
|
3632
|
+
await driver.start();
|
|
3633
|
+
driverStarted = true;
|
|
3634
|
+
} catch (err) {
|
|
3635
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
3636
|
+
log(`[serve] driver start failed: ${errMsg}`);
|
|
3637
|
+
sendEvent({ type: "error", message: `Driver start failed: ${errMsg}`, fatal: true });
|
|
3638
|
+
break;
|
|
3639
|
+
}
|
|
3640
|
+
driver.on("agent-event", (event) => {
|
|
3641
|
+
const normalized = normalizer.normalize(event);
|
|
3642
|
+
for (const e of normalized) {
|
|
3643
|
+
forwardNormalizedEvent(e);
|
|
3644
|
+
}
|
|
3645
|
+
});
|
|
3646
|
+
driver.on("error", (err) => {
|
|
3647
|
+
log(`[serve] driver error: ${err.message}`);
|
|
3648
|
+
sendEvent({ type: "error", message: err.message, fatal: true });
|
|
3649
|
+
});
|
|
3650
|
+
}
|
|
3651
|
+
sendEvent({ type: "status", phase: "thinking" });
|
|
3652
|
+
try {
|
|
3653
|
+
await driver.prompt(cmd.prompt);
|
|
3654
|
+
} catch (err) {
|
|
3655
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
3656
|
+
log(`[serve] prompt failed: ${errMsg}`);
|
|
3657
|
+
sendEvent({ type: "error", message: `Prompt failed: ${errMsg}`, fatal: true });
|
|
3658
|
+
}
|
|
3659
|
+
break;
|
|
3660
|
+
}
|
|
3661
|
+
case "reply": {
|
|
3662
|
+
try {
|
|
3663
|
+
await sessionReady;
|
|
3664
|
+
} catch (err) {
|
|
3665
|
+
sendEvent({
|
|
3666
|
+
type: "error",
|
|
3667
|
+
message: `Session not available: ${err.message}`,
|
|
3668
|
+
fatal: true
|
|
3669
|
+
});
|
|
3670
|
+
break;
|
|
3671
|
+
}
|
|
3672
|
+
log(`[serve] reply: ${cmd.answer.slice(0, 80)}...`);
|
|
3673
|
+
try {
|
|
3674
|
+
await driver.prompt(cmd.answer);
|
|
3675
|
+
} catch (err) {
|
|
3676
|
+
sendEvent({
|
|
3677
|
+
type: "error",
|
|
3678
|
+
message: `Reply failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
3679
|
+
fatal: false
|
|
3680
|
+
});
|
|
3681
|
+
}
|
|
3682
|
+
break;
|
|
3683
|
+
}
|
|
3684
|
+
case "cancel": {
|
|
3685
|
+
try {
|
|
3686
|
+
await sessionReady;
|
|
3687
|
+
} catch (err) {
|
|
3688
|
+
sendEvent({
|
|
3689
|
+
type: "error",
|
|
3690
|
+
message: `Session not available: ${err.message}`,
|
|
3691
|
+
fatal: true
|
|
3692
|
+
});
|
|
3693
|
+
break;
|
|
3694
|
+
}
|
|
3695
|
+
log("[serve] cancel");
|
|
3696
|
+
try {
|
|
3697
|
+
await driver.abort();
|
|
3698
|
+
} catch (err) {
|
|
3699
|
+
log(`[serve] cancel failed: ${err}`);
|
|
3700
|
+
}
|
|
3701
|
+
break;
|
|
3702
|
+
}
|
|
3703
|
+
// v3: compact + lifecycle removed — reachable via runner.lifecycle capability
|
|
3704
|
+
// (the v3 `runner.lifecycle` cap takes `{ phase: 'hibernate' | 'close' | 'compact' }`).
|
|
3705
|
+
case "resource_request": {
|
|
3706
|
+
try {
|
|
3707
|
+
await sessionReady;
|
|
3708
|
+
} catch (err) {
|
|
3709
|
+
sendEvent({
|
|
3710
|
+
type: "error",
|
|
3711
|
+
message: `Session not available: ${err.message}`,
|
|
3712
|
+
fatal: true
|
|
3713
|
+
});
|
|
3714
|
+
break;
|
|
3715
|
+
}
|
|
3716
|
+
if (mountManager?.has(cmd.connectorId)) {
|
|
3717
|
+
handleMountResourceRequest(cmd, mountManager, sendEvent);
|
|
3718
|
+
break;
|
|
3719
|
+
}
|
|
3720
|
+
if (!resourceManager) {
|
|
3721
|
+
sendEvent({
|
|
3722
|
+
type: "resource_response",
|
|
3723
|
+
requestId: cmd.requestId,
|
|
3724
|
+
resourceId: cmd.connectorId,
|
|
3725
|
+
operation: cmd.operation,
|
|
3726
|
+
error: "No resources available \u2014 no mounts or connectors configured"
|
|
3727
|
+
});
|
|
3728
|
+
break;
|
|
3729
|
+
}
|
|
3730
|
+
void handleResourceRequest(cmd, resourceManager, sendEvent);
|
|
3731
|
+
break;
|
|
3732
|
+
}
|
|
3733
|
+
// v3: state_action removed — reachable via the runner.set_state capability.
|
|
3734
|
+
// ── Generic connector dispatch (Protocol 2.2) ──────────────────────
|
|
3735
|
+
// The 6 typed flow commands (`start_flow`, `approve_flow_node`,
|
|
3736
|
+
// `provide_flow_input`, `cancel_flow`, `set_flow_autonomous_mode`,
|
|
3737
|
+
// `retry_flow_node`) were removed in Phase 4 of the flow-connector
|
|
3738
|
+
// extraction. Hosts now drive flow execution exclusively through
|
|
3739
|
+
// `connector_mutate` against the `flow` connector. See
|
|
3740
|
+
// `MIGRATION-flow-connector.md` for the per-op mapping table.
|
|
3741
|
+
case "connector_mutate": {
|
|
3742
|
+
try {
|
|
3743
|
+
if (!resourceManager) throw new Error("connector_mutate before resources ready");
|
|
3744
|
+
const targetEntry = resourceManager.has?.(cmd.id) ? resourceManager.get(cmd.id) : null;
|
|
3745
|
+
const isExistingFlow = targetEntry?.adapter?.name === "flow";
|
|
3746
|
+
const isBareFlowId = cmd.id === "flow";
|
|
3747
|
+
if (cmd.op === "start") {
|
|
3748
|
+
if (isExistingFlow || isBareFlowId) {
|
|
3749
|
+
const payload = cmd.payload ?? {};
|
|
3750
|
+
const flowDef = payload.flow;
|
|
3751
|
+
const seed = payload.seed;
|
|
3752
|
+
if (flowDef?.id && seed?.runId && seed?.startedBy) {
|
|
3753
|
+
if (activeFlows.size > 0) {
|
|
3754
|
+
serverLog.warn("connector_mutate flow.start: another flow already active", {
|
|
3755
|
+
activeRunIds: Array.from(activeFlows.keys())
|
|
3756
|
+
});
|
|
3757
|
+
break;
|
|
3758
|
+
}
|
|
3759
|
+
const entry = await createActiveFlow(flowDef, { seed });
|
|
3760
|
+
serverLog.info("connector_mutate flow.start", {
|
|
3761
|
+
runId: entry.runId,
|
|
3762
|
+
flowId: flowDef.id
|
|
3763
|
+
});
|
|
3764
|
+
break;
|
|
3765
|
+
}
|
|
3766
|
+
}
|
|
3767
|
+
}
|
|
3768
|
+
let dispatchId = cmd.id;
|
|
3769
|
+
if (!targetEntry && isBareFlowId) {
|
|
3770
|
+
const onlyActive = getOnlyActiveFlow();
|
|
3771
|
+
if (onlyActive) {
|
|
3772
|
+
dispatchId = onlyActive.connectorId;
|
|
3773
|
+
}
|
|
3774
|
+
}
|
|
3775
|
+
await resourceManager.executeOp(dispatchId, cmd.op, cmd.payload ?? {});
|
|
3776
|
+
} catch (err) {
|
|
3777
|
+
serverLog.warn("connector_mutate failed", {
|
|
3778
|
+
id: cmd.id,
|
|
3779
|
+
op: cmd.op,
|
|
3780
|
+
error: err instanceof Error ? err.message : String(err)
|
|
3781
|
+
});
|
|
3782
|
+
}
|
|
3783
|
+
break;
|
|
3784
|
+
}
|
|
3785
|
+
case "connector_query": {
|
|
3786
|
+
let ok = true;
|
|
3787
|
+
let result;
|
|
3788
|
+
let error;
|
|
3789
|
+
try {
|
|
3790
|
+
if (!resourceManager) throw new Error("connector_query before resources ready");
|
|
3791
|
+
let dispatchId = cmd.id;
|
|
3792
|
+
if (!resourceManager.has?.(cmd.id) && cmd.id === "flow") {
|
|
3793
|
+
const onlyActive = getOnlyActiveFlow();
|
|
3794
|
+
if (onlyActive) {
|
|
3795
|
+
dispatchId = onlyActive.connectorId;
|
|
3796
|
+
}
|
|
3797
|
+
}
|
|
3798
|
+
result = await resourceManager.executeOp(dispatchId, cmd.op, cmd.payload ?? {});
|
|
3799
|
+
} catch (err) {
|
|
3800
|
+
ok = false;
|
|
3801
|
+
error = err instanceof Error ? err.message : String(err);
|
|
3802
|
+
}
|
|
3803
|
+
sendEvent({
|
|
3804
|
+
type: "connector_query_response",
|
|
3805
|
+
requestId: cmd.requestId,
|
|
3806
|
+
ok,
|
|
3807
|
+
...result !== void 0 ? { result } : {},
|
|
3808
|
+
...error !== void 0 ? { error } : {}
|
|
3809
|
+
});
|
|
3810
|
+
break;
|
|
3811
|
+
}
|
|
3812
|
+
case "debug": {
|
|
3813
|
+
try {
|
|
3814
|
+
await sessionReady;
|
|
3815
|
+
} catch (err) {
|
|
3816
|
+
sendEvent({
|
|
3817
|
+
type: "error",
|
|
3818
|
+
message: `Session not available: ${err.message}`,
|
|
3819
|
+
fatal: true
|
|
3820
|
+
});
|
|
3821
|
+
break;
|
|
3822
|
+
}
|
|
3823
|
+
log(`[serve] debug query=${cmd.query}`);
|
|
3824
|
+
let result;
|
|
3825
|
+
try {
|
|
3826
|
+
switch (cmd.query) {
|
|
3827
|
+
case "tools": {
|
|
3828
|
+
const mcpServers = Object.keys(driver?.config?.mcpServers ?? {});
|
|
3829
|
+
const allowedTools = driver?.config?.allowedTools ?? null;
|
|
3830
|
+
result = { mcpServers, allowedTools, driverStarted };
|
|
3831
|
+
break;
|
|
3832
|
+
}
|
|
3833
|
+
case "connectors": {
|
|
3834
|
+
result = resourceManager?.listConnectors?.() ?? [];
|
|
3835
|
+
break;
|
|
3836
|
+
}
|
|
3837
|
+
case "mcp": {
|
|
3838
|
+
const servers = Object.entries(driver?.config?.mcpServers ?? {}).map(
|
|
3839
|
+
([name]) => ({ name })
|
|
3840
|
+
);
|
|
3841
|
+
result = { servers };
|
|
3842
|
+
break;
|
|
3843
|
+
}
|
|
3844
|
+
case "config": {
|
|
3845
|
+
const liveModel = driver?.getModel() ?? agentSession?.model;
|
|
3846
|
+
result = {
|
|
3847
|
+
driver: agentSession?.driverType,
|
|
3848
|
+
model: liveModel,
|
|
3849
|
+
provider: agentSession?.provider,
|
|
3850
|
+
maxTurns,
|
|
3851
|
+
secretsMode,
|
|
3852
|
+
driverStarted,
|
|
3853
|
+
projectDir: opts.projectDir,
|
|
3854
|
+
versions: getFrameworkVersions()
|
|
3855
|
+
};
|
|
3856
|
+
break;
|
|
3857
|
+
}
|
|
3858
|
+
case "state": {
|
|
3859
|
+
const storeId = cmd.args?.store;
|
|
3860
|
+
if (storeId) {
|
|
3861
|
+
try {
|
|
3862
|
+
const snapshot = await resourceManager?.executeOp(storeId, "get", {});
|
|
3863
|
+
result = snapshot ? JSON.parse(snapshot) : null;
|
|
3864
|
+
} catch (err) {
|
|
3865
|
+
result = { error: err instanceof Error ? err.message : String(err) };
|
|
3866
|
+
}
|
|
3867
|
+
} else {
|
|
3868
|
+
const all = resourceManager?.listConnectors?.() ?? [];
|
|
3869
|
+
result = { stores: all.map((c) => c.id) };
|
|
3870
|
+
}
|
|
3871
|
+
break;
|
|
3872
|
+
}
|
|
3873
|
+
case "commands": {
|
|
3874
|
+
const commands = driver?.getSlashCommands?.() ?? [];
|
|
3875
|
+
result = { commands, driverType: agentSession?.driverType };
|
|
3876
|
+
break;
|
|
3877
|
+
}
|
|
3878
|
+
default:
|
|
3879
|
+
result = { error: `Unknown debug query: ${cmd.query}` };
|
|
3880
|
+
}
|
|
3881
|
+
} catch (err) {
|
|
3882
|
+
result = { error: err instanceof Error ? err.message : String(err) };
|
|
3883
|
+
}
|
|
3884
|
+
sendEvent({ type: "debug_result", query: cmd.query, data: result });
|
|
3885
|
+
break;
|
|
3886
|
+
}
|
|
3887
|
+
// -----------------------------------------------------------------------
|
|
3888
|
+
// -----------------------------------------------------------------------
|
|
3889
|
+
// v3: add_resource, remove_resource, remount_mount, set_log_level,
|
|
3890
|
+
// reconfigure_agent removed from AgentCommand union.
|
|
3891
|
+
// Reachable now via the `runner.set_log_level` and `runner.reconfigure`
|
|
3892
|
+
// capability invocations (audience: ['runtime']) — the platform calls
|
|
3893
|
+
// them through invokeRunnerCapability on the gateway. Handler bodies
|
|
3894
|
+
// live in the runner.* capability registrations.
|
|
3895
|
+
case "shutdown": {
|
|
3896
|
+
log("[serve] shutdown requested");
|
|
3897
|
+
await cleanup();
|
|
3898
|
+
if (transport instanceof WebSocketServerTransport) {
|
|
3899
|
+
await transport.close();
|
|
3900
|
+
}
|
|
3901
|
+
disposeLogStore();
|
|
3902
|
+
process.exit(0);
|
|
3903
|
+
}
|
|
3904
|
+
// Protocol v2 — capability round-trip results from the platform.
|
|
3905
|
+
case "capability_result": {
|
|
3906
|
+
const matched = resolveCapabilityResult(pendingCapabilityCalls, cmd);
|
|
3907
|
+
if (!matched) {
|
|
3908
|
+
log(
|
|
3909
|
+
`[serve] capability_result for unknown callId=${cmd.callId} (timed out or already resolved); dropping`
|
|
3910
|
+
);
|
|
3911
|
+
}
|
|
3912
|
+
break;
|
|
3913
|
+
}
|
|
3914
|
+
// Protocol v2 — additional capability lifecycle commands. The platform
|
|
3915
|
+
// can register / deregister capabilities mid-session (e.g. when a user
|
|
3916
|
+
// installs an extension after `configure`). Approval routing is reserved
|
|
3917
|
+
// for a later phase; we accept the command shape for forward
|
|
3918
|
+
// compatibility and log it.
|
|
3919
|
+
case "capability_register": {
|
|
3920
|
+
for (const raw of cmd.capabilities) {
|
|
3921
|
+
const wire = raw;
|
|
3922
|
+
capabilityRegistry.register(
|
|
3923
|
+
{
|
|
3924
|
+
...wire,
|
|
3925
|
+
inputZod: { parse: (v) => v },
|
|
3926
|
+
outputZod: void 0,
|
|
3927
|
+
handler: buildClientCapabilityHandler2(wire)
|
|
3928
|
+
},
|
|
3929
|
+
"client"
|
|
3930
|
+
);
|
|
3931
|
+
}
|
|
3932
|
+
break;
|
|
3933
|
+
}
|
|
3934
|
+
case "capability_deregister": {
|
|
3935
|
+
for (const name of cmd.names) {
|
|
3936
|
+
capabilityRegistry.deregister(name);
|
|
3937
|
+
}
|
|
3938
|
+
break;
|
|
3939
|
+
}
|
|
3940
|
+
case "capability_approve": {
|
|
3941
|
+
if (cmd.decision === "rejected") {
|
|
3942
|
+
const matched = rejectCapabilityOnApprovalDeny(
|
|
3943
|
+
pendingCapabilityCalls,
|
|
3944
|
+
cmd.callId,
|
|
3945
|
+
cmd.feedback
|
|
3946
|
+
);
|
|
3947
|
+
if (!matched) {
|
|
3948
|
+
log(
|
|
3949
|
+
`[serve] capability_approve(rejected) for unknown callId=${cmd.callId} (already resolved or timed out); dropping`
|
|
3950
|
+
);
|
|
3951
|
+
} else {
|
|
3952
|
+
log(
|
|
3953
|
+
`[serve] capability_approve(rejected) callId=${cmd.callId} decidedBy=${cmd.decidedBy}${cmd.feedback ? ` feedback=${JSON.stringify(cmd.feedback)}` : ""}`
|
|
3954
|
+
);
|
|
3955
|
+
}
|
|
3956
|
+
} else {
|
|
3957
|
+
log(
|
|
3958
|
+
`[serve] capability_approve(approved) callId=${cmd.callId} decidedBy=${cmd.decidedBy} (awaiting capability_result)`
|
|
3959
|
+
);
|
|
3960
|
+
}
|
|
3961
|
+
break;
|
|
3962
|
+
}
|
|
3963
|
+
}
|
|
3964
|
+
}
|
|
3965
|
+
transport.onCommand((cmd) => {
|
|
3966
|
+
void handleCommand(cmd);
|
|
3967
|
+
});
|
|
3968
|
+
if (transport instanceof WebSocketServerTransport) {
|
|
3969
|
+
await transport.listen();
|
|
3970
|
+
}
|
|
3971
|
+
if (secretsMode === "env" && agentSession) {
|
|
3972
|
+
agentSession.startWatching();
|
|
3973
|
+
}
|
|
3974
|
+
if (transport instanceof WebSocketServerTransport) {
|
|
3975
|
+
transport.onConnect(() => {
|
|
3976
|
+
if (resourceManager || mountManager) {
|
|
3977
|
+
const mountList = mountManager?.listMounts?.() ?? [];
|
|
3978
|
+
const connectorList = resourceManager?.listConnectors?.() ?? [];
|
|
3979
|
+
log(
|
|
3980
|
+
`[serve] emitting resources_available: ${mountList.length} mounts(s), ${connectorList.length} connector(s)`
|
|
3981
|
+
);
|
|
3982
|
+
sendEvent({
|
|
3983
|
+
type: "resources_available",
|
|
3984
|
+
mounts: mountList,
|
|
3985
|
+
connectors: connectorList
|
|
3986
|
+
});
|
|
3987
|
+
}
|
|
3988
|
+
const commands = driver?.getSlashCommands?.() ?? [];
|
|
3989
|
+
if (commands.length > 0) {
|
|
3990
|
+
log(`[serve] emitting commands_available: ${commands.length} command(s)`);
|
|
3991
|
+
sendEvent({ type: "commands_available", commands });
|
|
3992
|
+
}
|
|
3993
|
+
});
|
|
3994
|
+
}
|
|
3995
|
+
if (secretsMode === "env") {
|
|
3996
|
+
log(
|
|
3997
|
+
`[serve] driver=${agentSession.driverType} model=${agentSession.model ?? "(default)"} provider=${agentSession.provider ?? "(default)"} maxTurns=${maxTurns ?? "(default)"}`
|
|
3998
|
+
);
|
|
3999
|
+
} else {
|
|
4000
|
+
log(`[serve] secrets=provisioned \u2014 session will initialize after provision_secrets`);
|
|
4001
|
+
}
|
|
4002
|
+
log(`[serve] project=${opts.projectDir}`);
|
|
4003
|
+
process.on("uncaughtException", (err) => {
|
|
4004
|
+
log(
|
|
4005
|
+
`[serve] uncaughtException (non-fatal): ${err instanceof Error ? err.stack ?? err.message : String(err)}`
|
|
4006
|
+
);
|
|
4007
|
+
});
|
|
4008
|
+
process.on("unhandledRejection", (reason) => {
|
|
4009
|
+
log(
|
|
4010
|
+
`[serve] unhandledRejection (non-fatal): ${reason instanceof Error ? reason.stack ?? reason.message : String(reason)}`
|
|
4011
|
+
);
|
|
4012
|
+
});
|
|
4013
|
+
const GRACEFUL_SHUTDOWN_TIMEOUT_MS = 5e3;
|
|
4014
|
+
let shuttingDown = false;
|
|
4015
|
+
async function initiateShutdown(signal) {
|
|
4016
|
+
if (shuttingDown) {
|
|
4017
|
+
log(`[serve] ${signal} received again \u2014 forcing exit`);
|
|
4018
|
+
process.exit(130);
|
|
4019
|
+
}
|
|
4020
|
+
shuttingDown = true;
|
|
4021
|
+
log(`[serve] ${signal} received \u2014 shutting down (press Ctrl-C again to force)`);
|
|
4022
|
+
const forceExitTimer = setTimeout(() => {
|
|
4023
|
+
log(`[serve] graceful shutdown exceeded ${GRACEFUL_SHUTDOWN_TIMEOUT_MS}ms \u2014 forcing exit`);
|
|
4024
|
+
process.exit(130);
|
|
4025
|
+
}, GRACEFUL_SHUTDOWN_TIMEOUT_MS);
|
|
4026
|
+
forceExitTimer.unref?.();
|
|
4027
|
+
try {
|
|
4028
|
+
await cleanup();
|
|
4029
|
+
} catch (err) {
|
|
4030
|
+
log(`[serve] cleanup error: ${err.message}`);
|
|
4031
|
+
}
|
|
4032
|
+
try {
|
|
4033
|
+
if (transport instanceof WebSocketServerTransport) {
|
|
4034
|
+
await transport.close();
|
|
4035
|
+
}
|
|
4036
|
+
} catch (err) {
|
|
4037
|
+
log(`[serve] transport close error: ${err.message}`);
|
|
4038
|
+
}
|
|
4039
|
+
clearTimeout(forceExitTimer);
|
|
4040
|
+
log("[serve] shutdown complete");
|
|
4041
|
+
disposeLogStore();
|
|
4042
|
+
process.exit(0);
|
|
4043
|
+
}
|
|
4044
|
+
process.on("SIGTERM", () => {
|
|
4045
|
+
void initiateShutdown("SIGTERM");
|
|
4046
|
+
});
|
|
4047
|
+
process.on("SIGINT", () => {
|
|
4048
|
+
void initiateShutdown("SIGINT");
|
|
4049
|
+
});
|
|
4050
|
+
}
|
|
4051
|
+
var SESSION_DIR = ".skaile";
|
|
4052
|
+
var SESSIONS_SUBDIR = "sessions";
|
|
4053
|
+
var CURRENT_FILE = "current";
|
|
4054
|
+
var LEGACY_FILE = "session.json";
|
|
4055
|
+
function sessionsDir(projectDir) {
|
|
4056
|
+
return path4.join(projectDir, SESSION_DIR, SESSIONS_SUBDIR);
|
|
4057
|
+
}
|
|
4058
|
+
function sessionFilePath(projectDir, runId) {
|
|
4059
|
+
return path4.join(sessionsDir(projectDir), `${runId}.json`);
|
|
4060
|
+
}
|
|
4061
|
+
function currentPointerPath(projectDir) {
|
|
4062
|
+
return path4.join(projectDir, SESSION_DIR, CURRENT_FILE);
|
|
4063
|
+
}
|
|
4064
|
+
function legacySessionPath(projectDir) {
|
|
4065
|
+
return path4.join(projectDir, SESSION_DIR, LEGACY_FILE);
|
|
4066
|
+
}
|
|
4067
|
+
async function migrateLegacySession(projectDir) {
|
|
4068
|
+
const legacyPath = legacySessionPath(projectDir);
|
|
4069
|
+
try {
|
|
4070
|
+
const raw = await fs4.readFile(legacyPath, "utf-8");
|
|
4071
|
+
const state = JSON.parse(raw);
|
|
4072
|
+
await fs4.mkdir(sessionsDir(projectDir), { recursive: true });
|
|
4073
|
+
await fs4.writeFile(
|
|
4074
|
+
sessionFilePath(projectDir, state.runId),
|
|
4075
|
+
JSON.stringify(state, null, 2),
|
|
4076
|
+
"utf-8"
|
|
4077
|
+
);
|
|
4078
|
+
await fs4.writeFile(currentPointerPath(projectDir), state.runId, "utf-8");
|
|
4079
|
+
await fs4.rm(legacyPath);
|
|
4080
|
+
} catch {
|
|
4081
|
+
}
|
|
4082
|
+
}
|
|
4083
|
+
async function loadSession(projectDir) {
|
|
4084
|
+
await migrateLegacySession(projectDir);
|
|
4085
|
+
try {
|
|
4086
|
+
const runId = (await fs4.readFile(currentPointerPath(projectDir), "utf-8")).trim();
|
|
4087
|
+
if (!runId) return null;
|
|
4088
|
+
return await loadSessionById(projectDir, runId);
|
|
4089
|
+
} catch {
|
|
4090
|
+
return null;
|
|
4091
|
+
}
|
|
4092
|
+
}
|
|
4093
|
+
async function loadSessionById(projectDir, runId) {
|
|
4094
|
+
try {
|
|
4095
|
+
const raw = await fs4.readFile(sessionFilePath(projectDir, runId), "utf-8");
|
|
4096
|
+
return JSON.parse(raw);
|
|
4097
|
+
} catch {
|
|
4098
|
+
return null;
|
|
4099
|
+
}
|
|
4100
|
+
}
|
|
4101
|
+
async function listSessions(projectDir) {
|
|
4102
|
+
await migrateLegacySession(projectDir);
|
|
4103
|
+
const dir = sessionsDir(projectDir);
|
|
4104
|
+
try {
|
|
4105
|
+
const files = await fs4.readdir(dir);
|
|
4106
|
+
const sessions = [];
|
|
4107
|
+
for (const file of files) {
|
|
4108
|
+
if (!file.endsWith(".json")) continue;
|
|
4109
|
+
try {
|
|
4110
|
+
const raw = await fs4.readFile(path4.join(dir, file), "utf-8");
|
|
4111
|
+
sessions.push(JSON.parse(raw));
|
|
4112
|
+
} catch {
|
|
4113
|
+
}
|
|
4114
|
+
}
|
|
4115
|
+
return sessions.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
4116
|
+
} catch {
|
|
4117
|
+
return [];
|
|
4118
|
+
}
|
|
4119
|
+
}
|
|
4120
|
+
async function saveSession(projectDir, state, setCurrent = true) {
|
|
4121
|
+
await fs4.mkdir(sessionsDir(projectDir), { recursive: true });
|
|
4122
|
+
await fs4.writeFile(
|
|
4123
|
+
sessionFilePath(projectDir, state.runId),
|
|
4124
|
+
JSON.stringify(state, null, 2),
|
|
4125
|
+
"utf-8"
|
|
4126
|
+
);
|
|
4127
|
+
if (setCurrent) {
|
|
4128
|
+
await fs4.writeFile(currentPointerPath(projectDir), state.runId, "utf-8");
|
|
4129
|
+
}
|
|
4130
|
+
}
|
|
4131
|
+
async function setCurrentSession(projectDir, runId) {
|
|
4132
|
+
const exists = await loadSessionById(projectDir, runId);
|
|
4133
|
+
if (!exists) throw new Error(`Session not found: ${runId}`);
|
|
4134
|
+
await fs4.mkdir(path4.join(projectDir, SESSION_DIR), { recursive: true });
|
|
4135
|
+
await fs4.writeFile(currentPointerPath(projectDir), runId, "utf-8");
|
|
4136
|
+
}
|
|
4137
|
+
async function deleteSession(projectDir, runId) {
|
|
4138
|
+
try {
|
|
4139
|
+
await fs4.rm(sessionFilePath(projectDir, runId));
|
|
4140
|
+
} catch {
|
|
4141
|
+
}
|
|
4142
|
+
try {
|
|
4143
|
+
const current = (await fs4.readFile(currentPointerPath(projectDir), "utf-8")).trim();
|
|
4144
|
+
if (current === runId) {
|
|
4145
|
+
await fs4.rm(currentPointerPath(projectDir));
|
|
4146
|
+
}
|
|
4147
|
+
} catch {
|
|
4148
|
+
}
|
|
4149
|
+
}
|
|
4150
|
+
async function clearSession(projectDir) {
|
|
4151
|
+
try {
|
|
4152
|
+
await fs4.rm(currentPointerPath(projectDir));
|
|
4153
|
+
} catch {
|
|
4154
|
+
}
|
|
4155
|
+
}
|
|
4156
|
+
function newSession(opts) {
|
|
4157
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
4158
|
+
return { ...opts, runId: randomUUID(), startedAt: now, updatedAt: now, status: "running" };
|
|
4159
|
+
}
|
|
4160
|
+
function touchSession(state) {
|
|
4161
|
+
return { ...state, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
4162
|
+
}
|
|
4163
|
+
|
|
4164
|
+
export { CLAUDE_CODE_CREDENTIALS_KEY, COMPILE_MANIFEST_FILENAME, CapabilityRegistry, DEFAULT_CAPABILITY_CALL_TIMEOUT_MS, DEFAULT_COALESCE_MS, MarkdownStreamer, PreInitRingSink, agentDefinitionExists, assembleSystemPrompt, bootstrapCapabilityRegistry, bootstrapRunnerLogStore, buildAgentResources, buildCapabilitiesPromptSection, buildClientCapabilityHandler, buildContextSection, buildEnvironmentSection, builtinCapabilities, clearPreInitRingSink, clearSession, compileComposition, computeCapabilitySignature, createAgentSession, createSessionStimulusBus, defineCapability, deleteSession, emitSystemPromptComposed, ensureGitConfigInclude, getPreInitRingSink, handleMountResourceRequest, handleResourceRequest, installPreInitRingSink, listSessions, loadAgentManifest, loadCompileManifest, loadCompileManifestFromDir, loadSession, loadSessionById, newSession, registerCompositionCapabilities, rejectCapabilityOnApprovalDeny, resetRunnerLogStore, resolveAgentComposition, resolveAgentMixins, resolveBinding, resolveCapabilityResult, resolveComposition, resolveMixin, runAgentChat, saveSession, setCurrentSession, startAgentServer, touchSession, writeClaudeCodeCredentialsFile };
|
|
4165
|
+
//# sourceMappingURL=chunk-NYJKXVG6.js.map
|
|
4166
|
+
//# sourceMappingURL=chunk-NYJKXVG6.js.map
|