@skaile/workspaces 4.11.0 → 4.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/dist/{asset-feeds-3TOP4ZKE.js → asset-feeds-AAQOGRLM.js} +14 -13
- package/dist/asset-feeds-AAQOGRLM.js.map +1 -0
- package/dist/asset-manager/catalog-deployer.js +10 -9
- package/dist/asset-manager/index.js +14 -13
- package/dist/asset-manager/installer.js +10 -9
- package/dist/bridge/drivers/claude-sdk.js +229 -26
- package/dist/bridge/drivers/claude-sdk.js.map +1 -1
- package/dist/bridge/drivers/codex.js +12 -11
- package/dist/bridge/drivers/codex.js.map +1 -1
- package/dist/bridge/drivers/continue.js +14 -12
- package/dist/bridge/drivers/continue.js.map +1 -1
- package/dist/bridge/drivers/echo.js +11 -8
- package/dist/bridge/drivers/echo.js.map +1 -1
- package/dist/bridge/drivers/gemini.js +10 -8
- package/dist/bridge/drivers/goose.js +13 -11
- package/dist/bridge/drivers/goose.js.map +1 -1
- package/dist/bridge/drivers/omp.js +8 -6
- package/dist/bridge/drivers/omp.js.map +1 -1
- package/dist/bridge/drivers/opencode.js +15 -12
- package/dist/bridge/drivers/opencode.js.map +1 -1
- package/dist/bridge/drivers/qwen.js +10 -8
- package/dist/bridge/drivers/qwen.js.map +1 -1
- package/dist/bridge/index.js +14 -13
- package/dist/bridge/src/cloud.d.ts.map +1 -1
- package/dist/bridge/src/drivers/claude-sdk.d.ts +18 -1
- package/dist/bridge/src/drivers/claude-sdk.d.ts.map +1 -1
- package/dist/bridge/src/drivers/echo.d.ts.map +1 -1
- package/dist/bridge/src/drivers/omp-models-yml.d.ts.map +1 -1
- package/dist/bridge/src/mcp-tool-schema-filter.d.ts +44 -0
- package/dist/bridge/src/mcp-tool-schema-filter.d.ts.map +1 -0
- package/dist/bridge/src/provider-materialize/continue-config-yaml.d.ts.map +1 -1
- package/dist/bridge/src/provider-materialize/env-drivers.d.ts +20 -5
- package/dist/bridge/src/provider-materialize/env-drivers.d.ts.map +1 -1
- package/dist/bridge/src/provider-materialize/opencode-config.d.ts.map +1 -1
- package/dist/bridge/src/types.d.ts +6 -2
- package/dist/bridge/src/types.d.ts.map +1 -1
- package/dist/{chunk-MKZOK4JU.js → chunk-2FBPAR2V.js} +3 -3
- package/dist/{chunk-MKZOK4JU.js.map → chunk-2FBPAR2V.js.map} +1 -1
- package/dist/{chunk-CJXSTOGW.js → chunk-4JGTXBQB.js} +4 -4
- package/dist/{chunk-CJXSTOGW.js.map → chunk-4JGTXBQB.js.map} +1 -1
- package/dist/{chunk-OUJVFZWJ.js → chunk-4SIMGJIU.js} +4 -9
- package/dist/chunk-4SIMGJIU.js.map +1 -0
- package/dist/{chunk-AT2TJEWG.js → chunk-65VAYFIJ.js} +11 -11
- package/dist/chunk-65VAYFIJ.js.map +1 -0
- package/dist/{chunk-JM2LRJ46.js → chunk-6Y3ICAPP.js} +3 -3
- package/dist/{chunk-JM2LRJ46.js.map → chunk-6Y3ICAPP.js.map} +1 -1
- package/dist/{chunk-7IRJ4K4F.js → chunk-7IH3RKKK.js} +3 -3
- package/dist/{chunk-7IRJ4K4F.js.map → chunk-7IH3RKKK.js.map} +1 -1
- package/dist/{chunk-JECDED7B.js → chunk-7NRF7BQB.js} +5 -5
- package/dist/{chunk-JECDED7B.js.map → chunk-7NRF7BQB.js.map} +1 -1
- package/dist/{chunk-O3DHAGBO.js → chunk-A2T4WIZL.js} +6 -5
- package/dist/chunk-A2T4WIZL.js.map +1 -0
- package/dist/chunk-ALLCAFHQ.js +365 -0
- package/dist/chunk-ALLCAFHQ.js.map +1 -0
- package/dist/chunk-BDFR5MHE.js +141 -0
- package/dist/chunk-BDFR5MHE.js.map +1 -0
- package/dist/{chunk-W4IPN3DD.js → chunk-BOFL7GIF.js} +62 -10
- package/dist/chunk-BOFL7GIF.js.map +1 -0
- package/dist/{chunk-WXB6YEHZ.js → chunk-BRNGJTHH.js} +3 -3
- package/dist/{chunk-WXB6YEHZ.js.map → chunk-BRNGJTHH.js.map} +1 -1
- package/dist/chunk-C3CAXQMA.js +8 -0
- package/dist/chunk-C3CAXQMA.js.map +1 -0
- package/dist/{chunk-35PMOWAD.js → chunk-CPIAQTYM.js} +4 -4
- package/dist/chunk-CPIAQTYM.js.map +1 -0
- package/dist/{chunk-REYJKU7T.js → chunk-DHMBE5J7.js} +12 -364
- package/dist/chunk-DHMBE5J7.js.map +1 -0
- package/dist/{chunk-KSIRR5PL.js → chunk-DPLIN2RA.js} +3 -3
- package/dist/{chunk-KSIRR5PL.js.map → chunk-DPLIN2RA.js.map} +1 -1
- package/dist/{chunk-PBCNRS7Q.js → chunk-EUHB2BD2.js} +6 -6
- package/dist/{chunk-PBCNRS7Q.js.map → chunk-EUHB2BD2.js.map} +1 -1
- package/dist/{chunk-6XKQEDF7.js → chunk-FKWGIDUG.js} +6 -5
- package/dist/chunk-FKWGIDUG.js.map +1 -0
- package/dist/{chunk-ILG4BXYE.js → chunk-GZZPKAV5.js} +27 -3
- package/dist/chunk-GZZPKAV5.js.map +1 -0
- package/dist/{chunk-M5H4DWIA.js → chunk-HGPSZXZP.js} +3 -3
- package/dist/{chunk-M5H4DWIA.js.map → chunk-HGPSZXZP.js.map} +1 -1
- package/dist/{chunk-L3PZINDD.js → chunk-HXTBOZL6.js} +8 -8
- package/dist/{chunk-L3PZINDD.js.map → chunk-HXTBOZL6.js.map} +1 -1
- package/dist/{chunk-IGGHUTOW.js → chunk-HZBRHZPI.js} +4 -4
- package/dist/{chunk-IGGHUTOW.js.map → chunk-HZBRHZPI.js.map} +1 -1
- package/dist/{chunk-VLXODO37.js → chunk-IQFSXFYG.js} +3 -3
- package/dist/{chunk-VLXODO37.js.map → chunk-IQFSXFYG.js.map} +1 -1
- package/dist/{chunk-3HKYCT2M.js → chunk-JMKB7IB4.js} +4 -6
- package/dist/chunk-JMKB7IB4.js.map +1 -0
- package/dist/{chunk-S2MT6SDZ.js → chunk-KTSV5TDX.js} +107 -48
- package/dist/chunk-KTSV5TDX.js.map +1 -0
- package/dist/{chunk-IECQMSQ5.js → chunk-KUH4EKQQ.js} +4 -129
- package/dist/chunk-KUH4EKQQ.js.map +1 -0
- package/dist/{chunk-3YTFHHMI.js → chunk-LCKZCLXA.js} +3 -3
- package/dist/{chunk-3YTFHHMI.js.map → chunk-LCKZCLXA.js.map} +1 -1
- package/dist/{chunk-GXACG5ZE.js → chunk-N6XJGVSK.js} +50 -41
- package/dist/chunk-N6XJGVSK.js.map +1 -0
- package/dist/{chunk-SIGVAFRJ.js → chunk-NC7YSNBP.js} +10 -10
- package/dist/{chunk-SIGVAFRJ.js.map → chunk-NC7YSNBP.js.map} +1 -1
- package/dist/{chunk-UXUDNBJM.js → chunk-NKRAHM7T.js} +3 -3
- package/dist/{chunk-UXUDNBJM.js.map → chunk-NKRAHM7T.js.map} +1 -1
- package/dist/{chunk-WILO77HE.js → chunk-NXTLDFLA.js} +4 -4
- package/dist/{chunk-WILO77HE.js.map → chunk-NXTLDFLA.js.map} +1 -1
- package/dist/{chunk-FAI2SMFE.js → chunk-P2DLXBZK.js} +4 -4
- package/dist/{chunk-FAI2SMFE.js.map → chunk-P2DLXBZK.js.map} +1 -1
- package/dist/{chunk-2HUQUTJ3.js → chunk-PE3A6FFW.js} +4 -4
- package/dist/{chunk-2HUQUTJ3.js.map → chunk-PE3A6FFW.js.map} +1 -1
- package/dist/{chunk-DMUY5C3X.js → chunk-PHURDPQO.js} +10 -8
- package/dist/chunk-PHURDPQO.js.map +1 -0
- package/dist/{chunk-3T5DRUNZ.js → chunk-PQF3NDQH.js} +5 -5
- package/dist/{chunk-3T5DRUNZ.js.map → chunk-PQF3NDQH.js.map} +1 -1
- package/dist/{chunk-7BUZQVRR.js → chunk-Q6NDQ6BH.js} +4 -4
- package/dist/{chunk-7BUZQVRR.js.map → chunk-Q6NDQ6BH.js.map} +1 -1
- package/dist/{chunk-HO4UO25I.js → chunk-QWGSKDD7.js} +91 -7
- package/dist/chunk-QWGSKDD7.js.map +1 -0
- package/dist/{chunk-2D5BYAL6.js → chunk-RQLL7L72.js} +3 -3
- package/dist/{chunk-2D5BYAL6.js.map → chunk-RQLL7L72.js.map} +1 -1
- package/dist/{chunk-3XXQPHGL.js → chunk-T3YUSWVK.js} +4 -4
- package/dist/{chunk-3XXQPHGL.js.map → chunk-T3YUSWVK.js.map} +1 -1
- package/dist/{chunk-MMLXSVQ3.js → chunk-UOJW2DOZ.js} +5 -5
- package/dist/{chunk-MMLXSVQ3.js.map → chunk-UOJW2DOZ.js.map} +1 -1
- package/dist/{chunk-ELPR5XBG.js → chunk-V4RGCKYC.js} +5 -3
- package/dist/chunk-V4RGCKYC.js.map +1 -0
- package/dist/{chunk-UKJMQZV6.js → chunk-VOEBLPXO.js} +2 -2
- package/dist/chunk-VOEBLPXO.js.map +1 -0
- package/dist/{chunk-7SNYWCQS.js → chunk-WIQDBNMF.js} +3 -3
- package/dist/{chunk-7SNYWCQS.js.map → chunk-WIQDBNMF.js.map} +1 -1
- package/dist/{chunk-A3X4LDOD.js → chunk-WQPLZUXU.js} +6 -6
- package/dist/{chunk-A3X4LDOD.js.map → chunk-WQPLZUXU.js.map} +1 -1
- package/dist/{chunk-7ZJXFQ42.js → chunk-WZQWZJYL.js} +3 -3
- package/dist/{chunk-7ZJXFQ42.js.map → chunk-WZQWZJYL.js.map} +1 -1
- package/dist/{chunk-BXV6RLF4.js → chunk-XKPFQ3JT.js} +4 -4
- package/dist/{chunk-BXV6RLF4.js.map → chunk-XKPFQ3JT.js.map} +1 -1
- package/dist/{chunk-KLMXMW6Z.js → chunk-XPDB4O4H.js} +3 -3
- package/dist/{chunk-KLMXMW6Z.js.map → chunk-XPDB4O4H.js.map} +1 -1
- package/dist/{chunk-GUZNTYHE.js → chunk-YXUVOWEU.js} +4 -4
- package/dist/{chunk-GUZNTYHE.js.map → chunk-YXUVOWEU.js.map} +1 -1
- package/dist/{chunk-I3UWSGEB.js → chunk-ZK7DQRB2.js} +3 -3
- package/dist/{chunk-I3UWSGEB.js.map → chunk-ZK7DQRB2.js.map} +1 -1
- package/dist/{chunk-KJM7Y2FW.js → chunk-ZUOZV7CS.js} +7 -7
- package/dist/{chunk-KJM7Y2FW.js.map → chunk-ZUOZV7CS.js.map} +1 -1
- package/dist/cli/index.js +76 -69
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/src/commands/migrate-legacy-entry.d.ts.map +1 -1
- package/dist/cli/src/commands/project.d.ts.map +1 -1
- package/dist/cli/src/store-auth.d.ts.map +1 -1
- package/dist/connectors/config.js +5 -13
- package/dist/connectors/index.js +22 -20
- package/dist/connectors/src/config.d.ts.map +1 -1
- package/dist/connectors/src/connector-manager.d.ts.map +1 -1
- package/dist/connectors/src/materialized-connectors.d.ts.map +1 -1
- package/dist/connectors/src/secrets.d.ts.map +1 -1
- package/dist/core/index.js +9 -8
- package/dist/core/logging.js +3 -2
- package/dist/core/manifest.js +2 -2
- package/dist/core/provider-registry-credentials.js +2 -2
- package/dist/core/provider-registry.js +1 -1
- package/dist/core/runtime-assets.js +5 -4
- package/dist/core/src/index.d.ts +3 -3
- package/dist/core/src/index.d.ts.map +1 -1
- package/dist/core/src/logging/create-logger.d.ts.map +1 -1
- package/dist/core/src/logging/index.d.ts +1 -0
- package/dist/core/src/logging/index.d.ts.map +1 -1
- package/dist/core/src/logging/redact.d.ts +33 -0
- package/dist/core/src/logging/redact.d.ts.map +1 -0
- package/dist/core/src/logging/retention-value.d.ts +7 -0
- package/dist/core/src/logging/retention-value.d.ts.map +1 -0
- package/dist/core/src/logging/retention.d.ts.map +1 -1
- package/dist/core/src/logging/sanitize.d.ts +11 -0
- package/dist/core/src/logging/sanitize.d.ts.map +1 -1
- package/dist/core/src/provider-registry.d.ts +22 -0
- package/dist/core/src/provider-registry.d.ts.map +1 -1
- package/dist/core/src/workspace-config.d.ts +51 -2
- package/dist/core/src/workspace-config.d.ts.map +1 -1
- package/dist/core/workspace-config.js +4 -3
- package/dist/deploy/index.js +9 -8
- package/dist/deploy/index.js.map +1 -1
- package/dist/discovery/index.js +3 -3
- package/dist/{ensure-sources-2OC2X3ZM.js → ensure-sources-PSWARJPK.js} +17 -16
- package/dist/ensure-sources-PSWARJPK.js.map +1 -0
- package/dist/factory-assets/connectors/box.js +22 -20
- package/dist/factory-assets/connectors/deploy.js +22 -20
- package/dist/factory-assets/connectors/devserver.js +22 -20
- package/dist/factory-assets/connectors/flow/CONNECTOR.md +4 -2
- package/dist/factory-assets/connectors/flow/adapter.js +22 -20
- package/dist/factory-assets/connectors/flow/contract/schema.d.ts +12 -0
- package/dist/factory-assets/connectors/flow/contract/schema.d.ts.map +1 -1
- package/dist/factory-assets/connectors/flow/contract.js +4 -3
- package/dist/factory-assets/connectors/flow/engine/node-shape.d.ts.map +1 -1
- package/dist/factory-assets/connectors/flow/engine.js +13 -11
- package/dist/factory-assets/connectors/flow/prompt-fragments.js +3 -2
- package/dist/factory-assets/connectors/flow/run-flow.js +24 -22
- package/dist/factory-assets/connectors/flow/subprompt-runner.d.ts.map +1 -1
- package/dist/factory-assets/connectors/flow.js +22 -20
- package/dist/factory-assets/connectors/git/driver.d.ts.map +1 -1
- package/dist/factory-assets/connectors/git.js +22 -20
- package/dist/factory-assets/connectors/gmail.js +22 -20
- package/dist/factory-assets/connectors/googledrive.js +22 -20
- package/dist/factory-assets/connectors/local.js +22 -20
- package/dist/factory-assets/connectors/mattermost.js +22 -20
- package/dist/factory-assets/connectors/memory.js +22 -20
- package/dist/factory-assets/connectors/minio.js +22 -20
- package/dist/factory-assets/connectors/postgres.js +22 -20
- package/dist/factory-assets/connectors/s3.js +22 -20
- package/dist/factory-assets/connectors/sharepoint.js +22 -20
- package/dist/factory-assets/connectors/sqlite.js +22 -20
- package/dist/factory-assets/connectors/static-server.js +22 -20
- package/dist/factory-assets/connectors/tunnel.js +22 -20
- package/dist/factory-assets/connectors/webdav.js +22 -20
- package/dist/factory-assets/connectors/xstate-store.js +22 -20
- package/dist/factory-assets/connectors/xstate.js +22 -20
- package/dist/flows-7EB63Q2Q.js +24 -0
- package/dist/{flows-H6FL4NZU.js.map → flows-7EB63Q2Q.js.map} +1 -1
- package/dist/{helpers-RPJUSSG3.js → helpers-LHHGL2NL.js} +17 -16
- package/dist/{helpers-RPJUSSG3.js.map → helpers-LHHGL2NL.js.map} +1 -1
- package/dist/library/index.js +12 -11
- package/dist/library/install.js +1 -15
- package/dist/library/src/install/install-from-manifest.d.ts.map +1 -1
- package/dist/{library-publish-AAD6GTIF.js → library-publish-4SBO437O.js} +24 -22
- package/dist/library-publish-4SBO437O.js.map +1 -0
- package/dist/open-library-SF2F7NDS.js +37 -0
- package/dist/{open-library-HDOM4MLS.js.map → open-library-SF2F7NDS.js.map} +1 -1
- package/dist/paths-IK6Y4OIU.js +20 -0
- package/dist/{paths-RL6NZW5X.js.map → paths-IK6Y4OIU.js.map} +1 -1
- package/dist/{plugin-store-ZTAJCMTY.js → plugin-store-LUJ4GXSO.js} +11 -10
- package/dist/plugin-store-LUJ4GXSO.js.map +1 -0
- package/dist/{project-2B52FKAY.js → project-ZHPOPJBE.js} +18 -17
- package/dist/{project-2B52FKAY.js.map → project-ZHPOPJBE.js.map} +1 -1
- package/dist/resolver/index.js +10 -9
- package/dist/run-group-engine/index.js.map +1 -1
- package/dist/run-group-engine/src/rollup.d.ts.map +1 -1
- package/dist/runner/index.js +33 -31
- package/dist/runner/src/capability-registry.d.ts +13 -1
- package/dist/runner/src/capability-registry.d.ts.map +1 -1
- package/dist/runner/src/codex-init.d.ts.map +1 -1
- package/dist/runner/src/compaction/orchestrator.d.ts.map +1 -1
- package/dist/runner/src/compaction/strategy.d.ts +8 -5
- package/dist/runner/src/compaction/strategy.d.ts.map +1 -1
- package/dist/runner/src/lifecycle-handler.d.ts.map +1 -1
- package/dist/runner/src/log-content.d.ts +22 -0
- package/dist/runner/src/log-content.d.ts.map +1 -0
- package/dist/runner/src/logging-bootstrap.d.ts +6 -1
- package/dist/runner/src/logging-bootstrap.d.ts.map +1 -1
- package/dist/runner/src/serve.d.ts.map +1 -1
- package/dist/runner/src/session-builder.d.ts.map +1 -1
- package/dist/sdk/asset-manager.js +14 -13
- package/dist/sdk/bridge.js +14 -13
- package/dist/sdk/core.js +9 -8
- package/dist/sdk/flow.js +13 -11
- package/dist/sdk/index.js +33 -31
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/resolver.js +10 -9
- package/dist/sdk/runner.js +33 -31
- package/dist/{setup-MVBITSVT.js → setup-3NXXR7SH.js} +23 -22
- package/dist/setup-3NXXR7SH.js.map +1 -0
- package/dist/skills-YB5RHUAT.js +24 -0
- package/dist/{skills-Y6MU2NRI.js.map → skills-YB5RHUAT.js.map} +1 -1
- package/dist/source-C2OYNI3T.js +38 -0
- package/dist/{source-53PY7DXF.js.map → source-C2OYNI3T.js.map} +1 -1
- package/dist/{source-manifest-publish-ALRZKEBO.js → source-manifest-publish-BKS763DB.js} +25 -23
- package/dist/source-manifest-publish-BKS763DB.js.map +1 -0
- package/dist/tui/index.js +33 -31
- package/dist/tui/index.js.map +1 -1
- package/dist/types/src/manifests/preset.d.ts +5 -5
- package/dist/workspace-plugin/adapters/mcp.js +15 -14
- package/dist/workspace-plugin/adapters/omp.js +7 -7
- package/dist/workspace-plugin/adapters/omp.js.map +1 -1
- package/dist/workspace-plugin/index.js +4 -3
- package/dist/workspace-plugin/src/adapters/omp.d.ts.map +1 -1
- package/package.json +3 -1
- package/dist/asset-feeds-3TOP4ZKE.js.map +0 -1
- package/dist/chunk-35PMOWAD.js.map +0 -1
- package/dist/chunk-3HKYCT2M.js.map +0 -1
- package/dist/chunk-6XKQEDF7.js.map +0 -1
- package/dist/chunk-AT2TJEWG.js.map +0 -1
- package/dist/chunk-DMUY5C3X.js.map +0 -1
- package/dist/chunk-ELPR5XBG.js.map +0 -1
- package/dist/chunk-GXACG5ZE.js.map +0 -1
- package/dist/chunk-HO4UO25I.js.map +0 -1
- package/dist/chunk-IECQMSQ5.js.map +0 -1
- package/dist/chunk-ILG4BXYE.js.map +0 -1
- package/dist/chunk-O3DHAGBO.js.map +0 -1
- package/dist/chunk-OUJVFZWJ.js.map +0 -1
- package/dist/chunk-REYJKU7T.js.map +0 -1
- package/dist/chunk-S2MT6SDZ.js.map +0 -1
- package/dist/chunk-UKJMQZV6.js.map +0 -1
- package/dist/chunk-W4IPN3DD.js.map +0 -1
- package/dist/ensure-sources-2OC2X3ZM.js.map +0 -1
- package/dist/flows-H6FL4NZU.js +0 -23
- package/dist/library-publish-AAD6GTIF.js.map +0 -1
- package/dist/open-library-HDOM4MLS.js +0 -35
- package/dist/paths-RL6NZW5X.js +0 -19
- package/dist/plugin-store-ZTAJCMTY.js.map +0 -1
- package/dist/setup-MVBITSVT.js.map +0 -1
- package/dist/skills-Y6MU2NRI.js +0 -23
- package/dist/source-53PY7DXF.js +0 -36
- package/dist/source-manifest-publish-ALRZKEBO.js.map +0 -1
|
@@ -162,23 +162,73 @@ function reportSinkFailure(err) {
|
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
+
// core/src/logging/redact.ts
|
|
166
|
+
var URL_USERINFO = /\/\/[^/?#\s"'<>]*@/g;
|
|
167
|
+
var SCHEMED_USERINFO = /(?<![a-z0-9+.-])([a-z][a-z0-9+.-]{0,31}:\/\/)[^\s/"'=]{0,512}@/gi;
|
|
168
|
+
var SCHEMELESS_USERINFO = /(^|[\s"'(<=,])[^\s/@:"'()<>,=]{1,256}:[^\s/"'()<>]{1,256}@/g;
|
|
169
|
+
var SECRET_NAMES = [
|
|
170
|
+
"access[_-]?token",
|
|
171
|
+
"refresh[_-]?token",
|
|
172
|
+
"id[_-]?token",
|
|
173
|
+
"session[_-]?token",
|
|
174
|
+
"security[_-]?token",
|
|
175
|
+
"bearer[_-]?token",
|
|
176
|
+
"token",
|
|
177
|
+
"api[_-]?key",
|
|
178
|
+
"apikey",
|
|
179
|
+
"client[_-]?secret",
|
|
180
|
+
"secret[_-]?access[_-]?key",
|
|
181
|
+
"secret",
|
|
182
|
+
"access[_-]?key[_-]?id",
|
|
183
|
+
"account[_-]?key",
|
|
184
|
+
"sas[_-]?url",
|
|
185
|
+
"key",
|
|
186
|
+
"password",
|
|
187
|
+
"passwd",
|
|
188
|
+
"pass",
|
|
189
|
+
"pwd",
|
|
190
|
+
"sig",
|
|
191
|
+
"signature",
|
|
192
|
+
"x-amz-signature",
|
|
193
|
+
"x-amz-credential",
|
|
194
|
+
"x-amz-security-token",
|
|
195
|
+
"auth"
|
|
196
|
+
].join("|");
|
|
197
|
+
var SECRET_FIELD = new RegExp(
|
|
198
|
+
`^(?:${SECRET_NAMES.split("|").filter((n) => n !== "key" && n !== "auth" && n !== "sig").join("|")})$`,
|
|
199
|
+
"i"
|
|
200
|
+
);
|
|
201
|
+
function isSecretFieldName(name) {
|
|
202
|
+
return SECRET_FIELD.test(name);
|
|
203
|
+
}
|
|
204
|
+
var QUERY_SECRET = new RegExp(`([?&#;][a-z0-9_-]{0,32}(?:${SECRET_NAMES})=)[^&#;\\s"']+`, "gi");
|
|
205
|
+
var RCLONE_SECRET = new RegExp(
|
|
206
|
+
`([:,][a-z0-9_-]{0,32}(?:${SECRET_NAMES})=)(?:"[^"]*"|'[^']*'|[^:,\\s"']+)`,
|
|
207
|
+
"gi"
|
|
208
|
+
);
|
|
209
|
+
var SECRET_FLAG = /(?<![\w-])(--[a-z0-9-]{0,64}(?:pass|password|token|secret)[a-z0-9-]{0,64}=)[^\s"',]+/gi;
|
|
210
|
+
function redactCredentials(text) {
|
|
211
|
+
if (!text.includes("@") && !text.includes("=")) return text;
|
|
212
|
+
return text.replace(URL_USERINFO, "//***@").replace(SCHEMED_USERINFO, "$1***@").replace(SCHEMELESS_USERINFO, "$1***@").replace(QUERY_SECRET, "$1***").replace(RCLONE_SECRET, "$1***").replace(SECRET_FLAG, "$1***");
|
|
213
|
+
}
|
|
214
|
+
|
|
165
215
|
// core/src/logging/sanitize.ts
|
|
166
216
|
function normalizeError(value) {
|
|
167
217
|
if (value === void 0 || value === null) return void 0;
|
|
168
218
|
if (value instanceof Error) {
|
|
169
219
|
return {
|
|
170
220
|
name: value.name,
|
|
171
|
-
message: value.message,
|
|
172
|
-
stack: value.stack
|
|
221
|
+
message: redactCredentials(value.message),
|
|
222
|
+
stack: value.stack === void 0 ? void 0 : redactCredentials(value.stack)
|
|
173
223
|
};
|
|
174
224
|
}
|
|
175
225
|
if (typeof value === "string") {
|
|
176
|
-
return { name: "Error", message: value };
|
|
226
|
+
return { name: "Error", message: redactCredentials(value) };
|
|
177
227
|
}
|
|
178
228
|
try {
|
|
179
|
-
return { name: "Error", message: JSON.stringify(value) };
|
|
229
|
+
return { name: "Error", message: redactCredentials(JSON.stringify(value)) };
|
|
180
230
|
} catch {
|
|
181
|
-
return { name: "Error", message: String(value) };
|
|
231
|
+
return { name: "Error", message: redactCredentials(String(value)) };
|
|
182
232
|
}
|
|
183
233
|
}
|
|
184
234
|
function sanitizeData(value) {
|
|
@@ -186,6 +236,7 @@ function sanitizeData(value) {
|
|
|
186
236
|
const seen = /* @__PURE__ */ new WeakSet();
|
|
187
237
|
const walk = (v) => {
|
|
188
238
|
if (v === null || v === void 0) return v;
|
|
239
|
+
if (typeof v === "string") return redactCredentials(v);
|
|
189
240
|
if (typeof v === "bigint") return v.toString();
|
|
190
241
|
if (typeof v === "function") return "[Function]";
|
|
191
242
|
if (typeof v === "symbol") return v.toString();
|
|
@@ -196,7 +247,8 @@ function sanitizeData(value) {
|
|
|
196
247
|
if (Array.isArray(v)) return v.map(walk);
|
|
197
248
|
const out = {};
|
|
198
249
|
for (const [k, child] of Object.entries(v)) {
|
|
199
|
-
|
|
250
|
+
const bare = typeof child === "string" || typeof child === "number";
|
|
251
|
+
out[k] = bare && isSecretFieldName(k) ? "***" : walk(child);
|
|
200
252
|
}
|
|
201
253
|
return out;
|
|
202
254
|
};
|
|
@@ -324,7 +376,7 @@ function makeLogger(source, store) {
|
|
|
324
376
|
store.record({
|
|
325
377
|
source,
|
|
326
378
|
level,
|
|
327
|
-
message,
|
|
379
|
+
message: redactCredentials(message),
|
|
328
380
|
data: sanitizeData(data),
|
|
329
381
|
error: normalizeError(err)
|
|
330
382
|
});
|
|
@@ -348,6 +400,6 @@ function makeLogger(source, store) {
|
|
|
348
400
|
};
|
|
349
401
|
}
|
|
350
402
|
|
|
351
|
-
export { LogStore, LogStoreDisabledError, NoOpSink, StdoutSink, __resetBrokenStreams, createLogger, getLogStore, isBrokenPipeError, isStreamOpen, isStreamUsable, isUnwritableStreamError, markStreamBroken, normalizeError, registerLogStore, resetLogStore, sanitizeData };
|
|
352
|
-
//# sourceMappingURL=chunk-
|
|
353
|
-
//# sourceMappingURL=chunk-
|
|
403
|
+
export { LogStore, LogStoreDisabledError, NoOpSink, StdoutSink, __resetBrokenStreams, createLogger, getLogStore, isBrokenPipeError, isStreamOpen, isStreamUsable, isUnwritableStreamError, markStreamBroken, normalizeError, redactCredentials, registerLogStore, resetLogStore, sanitizeData };
|
|
404
|
+
//# sourceMappingURL=chunk-BOFL7GIF.js.map
|
|
405
|
+
//# sourceMappingURL=chunk-BOFL7GIF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../core/src/logging/stream-health.ts","../core/src/logging/log-store.ts","../core/src/logging/redact.ts","../core/src/logging/sanitize.ts","../core/src/logging/sinks/types.ts","../core/src/logging/sinks/no-op-sink.ts","../core/src/logging/sinks/stdout-sink.ts","../core/src/logging/create-logger.ts"],"names":[],"mappings":"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","file":"chunk-BOFL7GIF.js","sourcesContent":["/**\n * Liveness checks for the stdio streams the logging layer writes to.\n *\n * Shared by `StdoutSink` (which stops writing to a dead stream) and the\n * runner's `watchOutputStream` (which stops the loop, and exits only when its\n * caller owns the process), so the two cannot disagree about what \"dead\" means.\n * See `_devlog/notes/2026-09-07-stdout-epipe-log-loop.md`.\n */\n\n/**\n * Structural subset of `process.stdout` these helpers need. Declared instead of\n * `NodeJS.WriteStream` so tests and embedders can pass an ordinary `Writable`.\n */\nexport type OutputStream = NodeJS.WritableStream & {\n isTTY?: boolean;\n destroyed?: boolean;\n writableEnded?: boolean;\n};\n\nfunction codeOf(err: unknown): string | undefined {\n if (typeof err !== \"object\" || err === null) return undefined;\n const code = (err as NodeJS.ErrnoException).code;\n return typeof code === \"string\" ? code : undefined;\n}\n\n/**\n * True only for `EPIPE` — the reader closed its end.\n *\n * Deliberately narrow, because callers act on it by killing the process: a\n * wider set would let an unrelated bad descriptor take a whole session down.\n * Use {@link isUnwritableStreamError} to decide whether to stop *writing*.\n */\nexport function isBrokenPipeError(err: unknown): boolean {\n return codeOf(err) === \"EPIPE\";\n}\n\n/**\n * Error codes meaning this stream will never accept another write. Broader\n * than {@link isBrokenPipeError} because latching a sink off is cheap and\n * reversible in a way that exiting the process is not.\n */\nconst UNWRITABLE_CODES = new Set([\n \"EPIPE\",\n \"EBADF\",\n \"ERR_STREAM_DESTROYED\",\n \"ERR_STREAM_WRITE_AFTER_END\",\n]);\n\n/** True when a further write to this stream can only fail the same way. */\nexport function isUnwritableStreamError(err: unknown): boolean {\n const code = codeOf(err);\n return code !== undefined && UNWRITABLE_CODES.has(code);\n}\n\n/** False once the stream has been destroyed or ended. */\nexport function isStreamOpen(stream: { destroyed?: boolean; writableEnded?: boolean }): boolean {\n return stream.destroyed !== true && stream.writableEnded !== true;\n}\n\n/**\n * Streams known to be unwritable. Sinks consult this and go quiet; nothing\n * here listens for `error`, because claiming that event suppresses Node's\n * default fatal-EPIPE exit — right for a long-lived server, wrong for a CLI\n * being piped into `head`. That listener belongs to whoever owns the process\n * lifecycle: see `watchOutputStream` in the runner.\n */\nlet brokenStreams = new WeakSet<object>();\n\n/** Record that a stream will never accept another write. Idempotent. */\nexport function markStreamBroken(stream: object): void {\n brokenStreams.add(stream);\n}\n\n/**\n * Forget every broken-stream mark. Test-only — the registry is process-wide by\n * design, so a suite that breaks a stream would otherwise leak that verdict.\n * @internal\n */\nexport function __resetBrokenStreams(): void {\n brokenStreams = new WeakSet();\n}\n\n/** True while a stream is worth writing to. */\nexport function isStreamUsable(stream: { destroyed?: boolean; writableEnded?: boolean }): boolean {\n return !brokenStreams.has(stream) && isStreamOpen(stream);\n}\n","import { EventEmitter } from \"node:events\";\nimport type {\n LogEntry,\n LogLevel,\n LogQuery,\n LogQueryResult,\n LogSource,\n} from \"@skaile/workspaces/types\";\nimport { ulid } from \"ulid\";\nimport { isStreamUsable, isUnwritableStreamError, markStreamBroken } from \"./stream-health.js\";\nimport type { LogSink } from \"./sinks/types.js\";\n\nexport interface LogStoreOptions {\n sessionId: string;\n level: LogLevel;\n sinks: LogSink[];\n flushIntervalMs?: number; // default 50\n flushBatchSize?: number; // default 100\n}\n\nexport interface RecordInput {\n source: LogSource;\n level: LogLevel;\n message: string;\n data?: Record<string, unknown>;\n error?: { name: string; message: string; stack?: string };\n}\n\nconst LEVEL_RANK: Record<LogLevel, number> = {\n debug: 10,\n info: 20,\n warn: 30,\n error: 40,\n};\n\n/**\n * In-memory log buffer with periodic flush to sinks.\n *\n * The LogStore buffers log entries and flushes them to registered sinks\n * either when the buffer reaches a certain size, after a time interval,\n * or when explicitly flushed. Supports subscribing to live log entries.\n *\n * @see {@link LogStoreOptions} for configuration\n * @see {@link LogEntry} for the log entry format\n * @category Logging\n * @since 2.0.0\n */\nexport class LogStore {\n private sessionId: string;\n private level: LogLevel;\n private sinks: LogSink[];\n private flushIntervalMs: number;\n private flushBatchSize: number;\n private buffer: LogEntry[] = [];\n private timer: NodeJS.Timeout | null = null;\n private emitter = new EventEmitter();\n private closed = false;\n\n constructor(opts: LogStoreOptions) {\n this.sessionId = opts.sessionId;\n this.level = opts.level;\n this.sinks = opts.sinks;\n this.flushIntervalMs = opts.flushIntervalMs ?? 50;\n this.flushBatchSize = opts.flushBatchSize ?? 100;\n this.emitter.setMaxListeners(0);\n }\n\n getLevel(): LogLevel {\n return this.level;\n }\n\n setLevel(level: LogLevel): void {\n this.level = level;\n }\n\n /** Append a sink after construction. Used by bridges (e.g. OnLogBridgeSink). */\n addSink(sink: LogSink): void {\n this.sinks.push(sink);\n }\n\n /** Returns true if the level is enabled. Used by createLogger to short-circuit. */\n isEnabled(level: LogLevel): boolean {\n return LEVEL_RANK[level] >= LEVEL_RANK[this.level];\n }\n\n record(input: RecordInput): void {\n if (this.closed) return;\n if (!this.isEnabled(input.level)) return;\n const entry: LogEntry = {\n id: ulid(),\n timestamp: new Date().toISOString(),\n sessionId: this.sessionId,\n source: input.source,\n level: input.level,\n message: input.message,\n data: input.data,\n error: input.error,\n };\n this.emitter.emit(\"entry\", entry);\n this.buffer.push(entry);\n if (this.buffer.length >= this.flushBatchSize) {\n this.flushSync();\n } else if (this.flushIntervalMs > 0 && this.timer === null) {\n this.timer = setTimeout(() => this.flushSync(), this.flushIntervalMs);\n } else if (this.flushIntervalMs === 0) {\n this.flushSync();\n }\n }\n\n /** Subscribe to live entries. Returns an unsubscribe function. */\n subscribe(handler: (entry: LogEntry) => void): () => void {\n this.emitter.on(\"entry\", handler);\n return () => this.emitter.off(\"entry\", handler);\n }\n\n /**\n * Query stored log entries.\n *\n * Queries the first sink that supports querying (typically SQLiteSink).\n * Returns empty result if no sink supports querying.\n *\n * @param q - Query parameters including filters and pagination\n * @returns Query result with matching entries\n */\n query(q: LogQuery): LogQueryResult {\n for (const sink of this.sinks) {\n if (sink.query) return sink.query(q);\n }\n return { entries: [] };\n }\n\n /** Force-flush. SQLite writes are synchronous, so this returns once writes complete. */\n flush(): void {\n this.flushSync();\n }\n\n /**\n * Close the log store and release resources.\n *\n * Flushes any pending entries, marks the store as closed, and closes\n * all registered sinks.\n */\n close(): void {\n if (this.closed) return;\n this.flushSync();\n this.closed = true;\n if (this.timer) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n for (const sink of this.sinks) sink.close();\n this.emitter.removeAllListeners();\n }\n\n private flushSync(): void {\n if (this.timer) {\n clearTimeout(this.timer);\n this.timer = null;\n }\n if (this.buffer.length === 0) return;\n const batch = this.buffer;\n this.buffer = [];\n for (const sink of this.sinks) {\n try {\n sink.writeBatch(batch);\n } catch (err) {\n // Never let a sink failure crash the producer. `reportSinkFailure` is\n // itself failure-tolerant: a throw here would escape to the process\n // handler, which logs it back through this same store.\n reportSinkFailure(err);\n }\n }\n }\n}\n\n/**\n * Last-resort report of a sink failure. Silent once stderr is unusable —\n * a dead stderr fails asynchronously just like stdout, so the try/catch alone\n * would never latch. `isStreamUsable` is the shared verdict; the `catch` only\n * covers the synchronous throws (write-after-end, destroyed).\n */\nfunction reportSinkFailure(err: unknown): void {\n if (!isStreamUsable(process.stderr)) return;\n try {\n process.stderr.write(`LogStore sink write failed: ${String(err)}\\n`);\n } catch (writeErr) {\n if (isUnwritableStreamError(writeErr)) markStreamBroken(process.stderr);\n }\n}\n","// Every repeat is bounded or stops at a character its prefix cannot contain:\n// this runs synchronously on every log call, so it must stay linear on large\n// strings.\nconst URL_USERINFO = /\\/\\/[^/?#\\s\"'<>]*@/g;\n\n// A second userinfo pass anchored right after the scheme, for a pasted\n// token or password that holds `?`, `#` or `<>`, where URL_USERINFO stops.\n// Excluding `=` keeps a query string such as `https://host?to=a@b.com` out.\nconst SCHEMED_USERINFO = /(?<![a-z0-9+.-])([a-z][a-z0-9+.-]{0,31}:\\/\\/)[^\\s/\"'=]{0,512}@/gi;\n\nconst SCHEMELESS_USERINFO = /(^|[\\s\"'(<=,])[^\\s/@:\"'()<>,=]{1,256}:[^\\s/\"'()<>]{1,256}@/g;\n\nconst SECRET_NAMES = [\n \"access[_-]?token\",\n \"refresh[_-]?token\",\n \"id[_-]?token\",\n \"session[_-]?token\",\n \"security[_-]?token\",\n \"bearer[_-]?token\",\n \"token\",\n \"api[_-]?key\",\n \"apikey\",\n \"client[_-]?secret\",\n \"secret[_-]?access[_-]?key\",\n \"secret\",\n \"access[_-]?key[_-]?id\",\n \"account[_-]?key\",\n \"sas[_-]?url\",\n \"key\",\n \"password\",\n \"passwd\",\n \"pass\",\n \"pwd\",\n \"sig\",\n \"signature\",\n \"x-amz-signature\",\n \"x-amz-credential\",\n \"x-amz-security-token\",\n \"auth\",\n].join(\"|\");\n\n/**\n * Field names whose whole value is a secret. The URL-parameter list minus the\n * bare `key`, `auth` and `sig`, which as log fields name an object key or an\n * auth mode, not a credential.\n */\nconst SECRET_FIELD = new RegExp(\n `^(?:${SECRET_NAMES.split(\"|\")\n .filter((n) => n !== \"key\" && n !== \"auth\" && n !== \"sig\")\n .join(\"|\")})$`,\n \"i\",\n);\n\n/** True when a log `data` field of this name holds a credential as its whole value. */\nexport function isSecretFieldName(name: string): boolean {\n return SECRET_FIELD.test(name);\n}\n\n/**\n * A URL query or fragment parameter. The bounded prefix also catches a secret\n * name with segments in front (`private_token`, `oauth_signature`); a suffix is\n * not allowed, as it would also catch `keyword` or `monkey`. The value may\n * contain `:`.\n */\nconst QUERY_SECRET = new RegExp(`([?&#;][a-z0-9_-]{0,32}(?:${SECRET_NAMES})=)[^&#;\\\\s\"']+`, \"gi\");\n\n/**\n * An rclone connection-string parameter, with the same prefix rule\n * (`key_file_pass`, `auth_token`). A value with `:` or `,` must be quoted.\n */\nconst RCLONE_SECRET = new RegExp(\n `([:,][a-z0-9_-]{0,32}(?:${SECRET_NAMES})=)(?:\"[^\"]*\"|'[^']*'|[^:,\\\\s\"']+)`,\n \"gi\",\n);\n\nconst SECRET_FLAG =\n /(?<![\\w-])(--[a-z0-9-]{0,64}(?:pass|password|token|secret)[a-z0-9-]{0,64}=)[^\\s\"',]+/gi;\n\n/**\n * Strip embedded credentials out of free text, keeping host and path readable.\n *\n * Applied to every string a logger records (see `sanitize.ts`), and reused\n * wherever a connector's free text leaves the process. A mount source is a\n * declaration value, so it can carry a token in any of these spellings:\n *\n * - URL userinfo: `https://<token>@host`, `https://user:<token>@host`,\n * `s3://<key>:<secret>@bucket`. Matching runs to the *last* `@` in the\n * authority, as git's own parse does, so a password containing `@` is\n * covered; `[^/\\s]*` cannot cross the `/` that ends the authority, so an `@`\n * in a path is left alone. `ssh://git@host` loses its username — not worth a\n * narrower pattern that could miss a secret.\n * - A secret-named field (`token`, `password`, `apiKey`, …) has its whole value\n * blanked by `sanitizeData` — see {@link isSecretFieldName}.\n * - Scheme-less `user:<secret>@host`, also to the last `@`. An scp-style\n * `git@host:org/repo` has no colon before its `@` and is left alone; a\n * `mailto:alice@host` is not, and loses its local part.\n * - Secret-named query / fragment parameters (`?access_token=`,\n * `X-Amz-Signature=`, …) and rclone connection-string parameters\n * (`:webdav,user=bob,pass=…:path`, `:s3,secret_access_key=…:bucket`).\n * - rclone backend flags (`--webdav-pass=…`).\n *\n * Known residuals: a raw userinfo holding both `=` and one of `? # < >`\n * (invalid per RFC 3986), and a secret name with a suffix (`key_pem=`).\n *\n * A regex over the text, never a URL parse: a parse throws on the scp-style\n * remotes and on the fragments of argv that git error messages carry.\n */\nexport function redactCredentials(text: string): string {\n // Every pattern below needs an `@` or an `=`; most log strings have neither.\n if (!text.includes(\"@\") && !text.includes(\"=\")) return text;\n return text\n .replace(URL_USERINFO, \"//***@\")\n .replace(SCHEMED_USERINFO, \"$1***@\")\n .replace(SCHEMELESS_USERINFO, \"$1***@\")\n .replace(QUERY_SECRET, \"$1***\")\n .replace(RCLONE_SECRET, \"$1***\")\n .replace(SECRET_FLAG, \"$1***\");\n}\n","import type { NormalizedError } from \"@skaile/workspaces/types\";\nimport { isSecretFieldName, redactCredentials } from \"./redact.js\";\n\n/** Error view for a log entry; message and stack pass through {@link redactCredentials}. */\nexport function normalizeError(value: unknown): NormalizedError | undefined {\n if (value === undefined || value === null) return undefined;\n if (value instanceof Error) {\n return {\n name: value.name,\n message: redactCredentials(value.message),\n stack: value.stack === undefined ? undefined : redactCredentials(value.stack),\n };\n }\n if (typeof value === \"string\") {\n return { name: \"Error\", message: redactCredentials(value) };\n }\n try {\n return { name: \"Error\", message: redactCredentials(JSON.stringify(value)) };\n } catch {\n return { name: \"Error\", message: redactCredentials(String(value)) };\n }\n}\n\n/**\n * JSON-safe copy of a log entry's `data`. Every string leaf passes through\n * {@link redactCredentials}, and a string or number value under a secret-named\n * field (`token`, `password`, …) is blanked; an object there is walked, so a\n * credential reference such as `{ ref: \"env:FOO\" }` keeps its shape. Emitters log declaration values (mount sources, endpoints)\n * as they are, so this is the one place a credential inside one is stopped\n * before any sink — SQLite, stdout, the gateway forward — sees it. A secret\n * under any other field name, outside a URL, connection string or flag, still\n * passes: do not log a credential field.\n */\nexport function sanitizeData(value: unknown): Record<string, unknown> | undefined {\n if (value === undefined || value === null) return undefined;\n const seen = new WeakSet<object>();\n const walk = (v: unknown): unknown => {\n if (v === null || v === undefined) return v;\n if (typeof v === \"string\") return redactCredentials(v);\n if (typeof v === \"bigint\") return v.toString();\n if (typeof v === \"function\") return \"[Function]\";\n if (typeof v === \"symbol\") return v.toString();\n if (v instanceof Error) return normalizeError(v);\n if (typeof v !== \"object\") return v;\n if (seen.has(v as object)) return \"[Circular]\";\n seen.add(v as object);\n if (Array.isArray(v)) return v.map(walk);\n const out: Record<string, unknown> = {};\n for (const [k, child] of Object.entries(v as Record<string, unknown>)) {\n const bare = typeof child === \"string\" || typeof child === \"number\";\n out[k] = bare && isSecretFieldName(k) ? \"***\" : walk(child);\n }\n return out;\n };\n const result = walk(value);\n if (typeof result !== \"object\" || result === null || Array.isArray(result)) {\n return { value: result };\n }\n return result as Record<string, unknown>;\n}\n","// LogSink interface lives in @skaile/workspaces/types so consumers can type-check\n// sink instances without depending on core. Runtime errors live here.\nexport type { LogSink } from \"@skaile/workspaces/types\";\n\nexport class LogStoreDisabledError extends Error {\n constructor() {\n super(\"LogStore is disabled (mode=off); query is unavailable\");\n this.name = \"LogStoreDisabledError\";\n }\n}\n","import type { LogEntry, LogQuery, LogQueryResult } from \"@skaile/workspaces/types\";\nimport { type LogSink, LogStoreDisabledError } from \"./types.js\";\n\nexport class NoOpSink implements LogSink {\n write(_entry: LogEntry): void {}\n writeBatch(_entries: LogEntry[]): void {}\n query(_q: LogQuery): LogQueryResult {\n throw new LogStoreDisabledError();\n }\n close(): void {}\n}\n","import type { LogEntry, LogSource } from \"@skaile/workspaces/types\";\nimport {\n isStreamUsable,\n isUnwritableStreamError,\n markStreamBroken,\n type OutputStream,\n} from \"../stream-health.js\";\nimport type { LogSink } from \"./types.js\";\n\nexport type StdoutFormat = \"pretty\" | \"json\";\n\n/** Which standard stream the sink writes to. */\nexport type StdoutStream = \"stdout\" | \"stderr\";\n\nexport type { OutputStream };\n\nexport interface StdoutSinkOptions {\n format?: StdoutFormat;\n /**\n * Standard stream to write to. Default: `\"stdout\"`. Set to `\"stderr\"` for\n * processes whose stdout is a reserved channel — e.g. a stdio MCP server,\n * where stdout carries JSON-RPC and any log line would corrupt the protocol.\n * An explicit stream object may be passed instead; used by tests.\n */\n stream?: StdoutStream | OutputStream;\n}\n\nfunction formatSource(source: LogSource): string {\n const parts = [source.kind, source.subkind];\n if (source.instance) parts.push(source.instance);\n return `[${parts.join(\":\")}]`;\n}\n\nfunction formatTime(iso: string): string {\n // HH:MM:SS.sss\n return iso.slice(11, 23);\n}\n\nconst LEVEL_LABEL = {\n debug: \"DEBUG\",\n info: \"INFO \",\n warn: \"WARN \",\n error: \"ERROR\",\n} as const;\n\nexport class StdoutSink implements LogSink {\n private format: StdoutFormat;\n private stream: OutputStream;\n\n constructor(opts: StdoutSinkOptions = {}) {\n this.stream = resolveStream(opts.stream);\n this.format = opts.format ?? (this.stream.isTTY ? \"pretty\" : \"json\");\n }\n\n write(entry: LogEntry): void {\n if (!this.writable()) return;\n try {\n this.stream.write(`${this.render(entry)}\\n`);\n } catch (err) {\n // Sync throws (write-after-end, destroyed) never reach the `error` event.\n if (isUnwritableStreamError(err)) markStreamBroken(this.stream);\n }\n }\n\n writeBatch(entries: LogEntry[]): void {\n // `write` re-checks per entry, so a batch stops at the first failure.\n for (const e of entries) this.write(e);\n }\n\n close(): void {}\n\n /** False once the far end is gone; the sink then drops entries silently. */\n private writable(): boolean {\n return isStreamUsable(this.stream);\n }\n\n private render(entry: LogEntry): string {\n if (this.format === \"json\") {\n return JSON.stringify(entry);\n }\n const head = `${formatTime(entry.timestamp)} ${LEVEL_LABEL[entry.level]} ${formatSource(entry.source)}`;\n const tail = entry.message;\n const detail = entry.data ? `\\n > ${JSON.stringify(entry.data)}` : \"\";\n const err = entry.error ? `\\n ! ${entry.error.name}: ${entry.error.message}` : \"\";\n return `${head} ${tail}${detail}${err}`;\n }\n}\n\nfunction resolveStream(stream: StdoutSinkOptions[\"stream\"]): OutputStream {\n if (stream === \"stderr\") return process.stderr;\n if (stream === undefined || stream === \"stdout\") return process.stdout;\n return stream;\n}\n","import type { Logger, LogSource } from \"@skaile/workspaces/types\";\nimport { LogStore } from \"./log-store.js\";\nimport { redactCredentials } from \"./redact.js\";\nimport { normalizeError, sanitizeData } from \"./sanitize.js\";\nimport { NoOpSink } from \"./sinks/no-op-sink.js\";\nimport { StdoutSink } from \"./sinks/stdout-sink.js\";\n\n/**\n * The active LogStore is a process-singleton. It is stored on `globalThis`\n * under a `Symbol.for` key so it survives module duplication — under vitest's\n * `skaile-src` aliasing and the runner's lazy `import(\"@skaile/workspaces/runner\")`,\n * `core/logging` can be evaluated as two distinct module instances. A plain\n * module-scoped `let` would give each instance its own store, so a logger\n * created on one instance would not see a store registered on the other.\n * The `globalThis` slot makes the singleton genuinely process-wide.\n */\nconst ACTIVE_STORE_KEY = Symbol.for(\"@skaile/workspaces:logging:activeStore\");\n\ntype GlobalWithStore = typeof globalThis & {\n [ACTIVE_STORE_KEY]?: LogStore | null;\n};\n\nconst globalStoreSlot = globalThis as GlobalWithStore;\n\nexport function registerLogStore(store: LogStore): void {\n globalStoreSlot[ACTIVE_STORE_KEY] = store;\n}\n\nexport function getLogStore(): LogStore | null {\n return globalStoreSlot[ACTIVE_STORE_KEY] ?? null;\n}\n\nexport function resetLogStore(): void {\n globalStoreSlot[ACTIVE_STORE_KEY] = null;\n}\n\nexport interface CreateLoggerOptions {\n /**\n * When true (default), create + register a lazy off-mode LogStore if none\n * is registered. When false, throw if no store has been registered.\n */\n fallback?: boolean;\n}\n\nfunction ensureLogStore(): LogStore {\n const existing = globalStoreSlot[ACTIVE_STORE_KEY];\n if (existing) return existing;\n // Lazy off-mode fallback: NoOp + Stdout, no SQLite, no sessionId.\n const fallback = new LogStore({\n sessionId: \"no-session\",\n level: \"info\",\n sinks: [new NoOpSink(), new StdoutSink()],\n });\n globalStoreSlot[ACTIVE_STORE_KEY] = fallback;\n return fallback;\n}\n\n/**\n * Creates a logger for the given source.\n *\n * If no LogStore is registered and fallback is enabled (default), a lazy\n * off-mode fallback store (NoOp + Stdout) is created.\n *\n * @param source - The log source (e.g., { kind: 'agent', name: 'my-agent' })\n * @param opts - Configuration options for logger creation\n * @param opts.fallback - When true (default), creates a fallback store if none registered\n * @returns A logger instance\n * @throws {Error} When no LogStore is registered and fallback is false\n *\n * @example\n * ```typescript\n * const logger = createLogger({ kind: 'agent', name: 'my-agent' });\n * logger.info('Agent started');\n * ```\n */\nexport function createLogger(source: LogSource, opts: CreateLoggerOptions = {}): Logger {\n const fallback = opts.fallback !== false;\n if (!getLogStore() && !fallback) {\n throw new Error(\"createLogger: no LogStore registered. Call registerLogStore() first.\");\n }\n const store = ensureLogStore();\n return makeLogger(source, store);\n}\n\nfunction makeLogger(source: LogSource, store: LogStore): Logger {\n const emit = (\n level: \"debug\" | \"info\" | \"warn\" | \"error\",\n message: string,\n data?: object,\n err?: unknown,\n ) => {\n if (!store.isEnabled(level)) return;\n store.record({\n source,\n level,\n message: redactCredentials(message),\n data: sanitizeData(data),\n error: normalizeError(err),\n });\n };\n return {\n debug(message, data) {\n emit(\"debug\", message, data);\n },\n info(message, data) {\n emit(\"info\", message, data);\n },\n warn(message, data) {\n emit(\"warn\", message, data);\n },\n error(message, err, data) {\n emit(\"error\", message, data, err);\n },\n child(partial) {\n return makeLogger({ ...source, ...partial }, store);\n },\n };\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { globalSettingsPath, mapLegacyFields } from './chunk-
|
|
1
|
+
import { globalSettingsPath, mapLegacyFields } from './chunk-7NRF7BQB.js';
|
|
2
2
|
import { rmSync, existsSync, readFileSync, mkdirSync, writeFileSync, chmodSync } from 'fs';
|
|
3
3
|
import { randomBytes, createHash } from 'crypto';
|
|
4
4
|
import { homedir } from 'os';
|
|
@@ -228,5 +228,5 @@ function isStoreAuthenticated() {
|
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
export { deviceLogin, getStoreConfig, getStoreIdentity, getStoreToken, hasStoredAuth, isStoreAuthenticated, loadStoreAuthConfig, logout, storeFetch };
|
|
231
|
-
//# sourceMappingURL=chunk-
|
|
232
|
-
//# sourceMappingURL=chunk-
|
|
231
|
+
//# sourceMappingURL=chunk-BRNGJTHH.js.map
|
|
232
|
+
//# sourceMappingURL=chunk-BRNGJTHH.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../cli/src/store-auth.ts","../cli/src/store-client.ts"],"names":["readFileSync"],"mappings":"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","file":"chunk-WXB6YEHZ.js","sourcesContent":["/**\n * Keycloak Device Authorization Grant (RFC 8628) for the store CLI: a public\n * device-flow client (`skaile-store-cli`) issues a plain realm JWT the store's\n * `AuthGuard` accepts — a CLI can't use the storefront's confidential browser\n * client. Tokens cache at `~/.skaile/auth.json` (0600, shared with `store/cli`);\n * `getAccessToken` refreshes transparently. All targets are env-overridable.\n *\n * @docLink cli/dev-guide#store-auth\n */\nimport { createHash, randomBytes } from \"node:crypto\";\nimport { chmodSync, mkdirSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\n/**\n * A PKCE (RFC 7636) `code_verifier` + its S256 `code_challenge`. Keycloak\n * enforces PKCE on the `skaile-store-cli` device flow (the device-authorization\n * request 400s with \"Missing parameter: code_challenge_method\" otherwise), so\n * every `deviceLogin` mints a fresh pair: the challenge goes on the device-auth\n * request, the verifier on the matching token poll. `base64url` (no padding)\n * per the spec.\n */\nfunction makePkcePair(): { verifier: string; challenge: string } {\n const verifier = randomBytes(32).toString(\"base64url\");\n const challenge = createHash(\"sha256\").update(verifier).digest(\"base64url\");\n return { verifier, challenge };\n}\n\n/** Resolved auth targets — every field has a prod default, all env-overridable. */\nexport interface StoreAuthConfig {\n keycloakUrl: string;\n realm: string;\n clientId: string;\n authFile: string;\n}\n\nfunction trimTrailingSlash(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\n/**\n * Load the auth config. Defaults target the production store\n * (`auth.skaile.ai`, realm `skaile-store`, public client `skaile-store-cli`);\n * override with `SKAILE_KEYCLOAK_URL` / `SKAILE_STORE_REALM` /\n * `SKAILE_STORE_CLI_CLIENT` / `SKAILE_AUTH_FILE` for dev or a preview deploy.\n */\nexport function loadStoreAuthConfig(): StoreAuthConfig {\n const home = process.env.SKAILE_HOME ?? join(homedir(), \".skaile\");\n return {\n keycloakUrl: trimTrailingSlash(process.env.SKAILE_KEYCLOAK_URL ?? \"https://auth.skaile.ai\"),\n realm: process.env.SKAILE_STORE_REALM ?? \"skaile-store\",\n clientId: process.env.SKAILE_STORE_CLI_CLIENT ?? \"skaile-store-cli\",\n authFile: process.env.SKAILE_AUTH_FILE ?? join(home, \"auth.json\"),\n };\n}\n\n/** Keycloak OIDC endpoints derived from the realm base. */\nfunction oidc(config: StoreAuthConfig): { deviceAuth: string; token: string } {\n const base = `${config.keycloakUrl}/realms/${config.realm}/protocol/openid-connect`;\n return { deviceAuth: `${base}/auth/device`, token: `${base}/token` };\n}\n\nexport interface StoredAuth {\n access_token: string;\n refresh_token?: string;\n /** Epoch ms when the access token expires (with a safety margin already applied). */\n expires_at: number;\n}\n\ninterface TokenResponse {\n access_token: string;\n refresh_token?: string;\n expires_in?: number;\n error?: string;\n error_description?: string;\n}\n\ninterface DeviceAuthResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete?: string;\n interval?: number;\n expires_in: number;\n}\n\n/** Refresh this many ms before real expiry so an in-flight call never 401s. */\nconst EXPIRY_MARGIN_MS = 30_000;\n\n/** Injectable seams so the poll loop is unit-testable without real time or network. */\nexport interface AuthDeps {\n fetchImpl?: typeof fetch;\n sleep?: (ms: number) => Promise<void>;\n /** Called once with the verification URL + user code (default: write to stderr). */\n onPrompt?: (url: string, userCode: string) => void;\n}\n\nfunction readAuth(config: StoreAuthConfig): StoredAuth | null {\n try {\n const parsed = JSON.parse(readFileSync(config.authFile, \"utf-8\"));\n // Reject a corrupt / hand-edited file rather than treat it as a session.\n if (parsed && typeof parsed.access_token === \"string\") return parsed as StoredAuth;\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * The caller's store identity, decoded LOCALLY from the cached token's JWT\n * payload (no network, no signature check — this is an author-side hint, not an\n * authorization decision). Returns `null` when not signed in or the token is\n * unreadable. `githubLogin` is the verified GitHub handle (the preferred\n * publisher namespace); `username` is the Keycloak `preferred_username`.\n */\nexport function getStoreIdentity(\n config: StoreAuthConfig = loadStoreAuthConfig(),\n): { username?: string; githubLogin?: string } | null {\n const auth = readAuth(config);\n if (!auth) return null;\n try {\n const payload = auth.access_token.split(\".\")[1];\n const json = JSON.parse(Buffer.from(payload, \"base64url\").toString(\"utf-8\"));\n const username = typeof json.preferred_username === \"string\" ? json.preferred_username : undefined;\n const githubLogin = typeof json.github_login === \"string\" ? json.github_login : undefined;\n return username || githubLogin ? { username, githubLogin } : null;\n } catch {\n return null;\n }\n}\n\nfunction writeAuth(config: StoreAuthConfig, auth: StoredAuth): void {\n mkdirSync(dirname(config.authFile), { recursive: true });\n writeFileSync(config.authFile, JSON.stringify(auth, null, 2), { mode: 0o600 });\n chmodSync(config.authFile, 0o600);\n}\n\n/** Remove the cached session (sign out). */\nexport function logout(config: StoreAuthConfig): void {\n try {\n rmSync(config.authFile);\n } catch {\n // already absent — nothing to do\n }\n}\n\n/** True when a cached, well-formed session exists (validity/refresh resolved on use). */\nexport function hasStoredAuth(config: StoreAuthConfig): boolean {\n return readAuth(config) !== null;\n}\n\nfunction tokenToStored(token: TokenResponse): StoredAuth {\n return {\n access_token: token.access_token,\n refresh_token: token.refresh_token,\n expires_at: Date.now() + (token.expires_in ?? 300) * 1000 - EXPIRY_MARGIN_MS,\n };\n}\n\nconst defaultSleep = (ms: number): Promise<void> => new Promise((r) => setTimeout(r, ms));\n\nfunction defaultPrompt(url: string, userCode: string): void {\n process.stderr.write(\n `\\nTo sign in, open:\\n\\n ${url}\\n\\nand enter the code: ${userCode}\\n\\nWaiting for approval…\\n`,\n );\n}\n\n/**\n * Run the device flow to completion, persisting tokens on success. Prints the\n * verification URL + user code for the operator to approve in a browser.\n */\nexport async function deviceLogin(\n config: StoreAuthConfig,\n deps: AuthDeps = {},\n): Promise<StoredAuth> {\n const fetchImpl = deps.fetchImpl ?? fetch;\n const sleep = deps.sleep ?? defaultSleep;\n const onPrompt = deps.onPrompt ?? defaultPrompt;\n const endpoints = oidc(config);\n const pkce = makePkcePair();\n\n const deviceRes = await fetchImpl(endpoints.deviceAuth, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n client_id: config.clientId,\n scope: \"openid profile\",\n code_challenge: pkce.challenge,\n code_challenge_method: \"S256\",\n }),\n });\n if (!deviceRes.ok) {\n throw new Error(\n `Device authorization request failed (${deviceRes.status}): ${await deviceRes.text()}`,\n );\n }\n const device = (await deviceRes.json()) as DeviceAuthResponse;\n\n onPrompt(device.verification_uri_complete ?? device.verification_uri, device.user_code);\n\n const intervalMs = (device.interval ?? 5) * 1000;\n const deadline = Date.now() + device.expires_in * 1000;\n let waitMs = intervalMs;\n\n while (Date.now() < deadline) {\n await sleep(waitMs);\n const tokenRes = await fetchImpl(endpoints.token, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n device_code: device.device_code,\n client_id: config.clientId,\n code_verifier: pkce.verifier,\n }),\n });\n const token = (await tokenRes.json()) as TokenResponse;\n if (tokenRes.ok) {\n const stored = tokenToStored(token);\n writeAuth(config, stored);\n return stored;\n }\n // RFC 8628 §3.5 pending / slow-down handling.\n if (token.error === \"authorization_pending\") continue;\n if (token.error === \"slow_down\") {\n waitMs += 5_000;\n continue;\n }\n throw new Error(`Sign-in failed: ${token.error_description ?? token.error ?? \"unknown error\"}`);\n }\n throw new Error(\"Sign-in timed out before approval.\");\n}\n\n/** Exchange a refresh token for a fresh access token; persist on success. */\nasync function refresh(\n config: StoreAuthConfig,\n refreshToken: string,\n fetchImpl: typeof fetch,\n): Promise<StoredAuth> {\n const res = await fetchImpl(oidc(config).token, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n client_id: config.clientId,\n }),\n });\n const token = (await res.json()) as TokenResponse;\n if (!res.ok) {\n throw new Error(\n `Token refresh failed: ${token.error_description ?? token.error ?? res.status}`,\n );\n }\n const stored = tokenToStored(token);\n writeAuth(config, stored);\n return stored;\n}\n\n/**\n * Return a valid access token, refreshing if it is expired (or about to). Throws\n * a clear \"run `skaile store login`\" error when there is no usable session.\n */\nexport async function getAccessToken(\n config: StoreAuthConfig,\n deps: AuthDeps = {},\n): Promise<string> {\n const fetchImpl = deps.fetchImpl ?? fetch;\n const auth = readAuth(config);\n if (!auth) throw new Error(\"Not signed in. Run `skaile store login` first.\");\n if (Date.now() < auth.expires_at) return auth.access_token;\n if (!auth.refresh_token) throw new Error(\"Session expired. Run `skaile store login` again.\");\n try {\n return (await refresh(config, auth.refresh_token, fetchImpl)).access_token;\n } catch {\n throw new Error(\"Session expired and refresh failed. Run `skaile store login` again.\");\n }\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { globalSettingsPath, mapLegacyFields } from \"@skaile/workspaces/core\";\nimport { type AuthDeps, getAccessToken, hasStoredAuth, loadStoreAuthConfig } from \"./store-auth.ts\";\n\n/**\n * Connection configuration for the AI Asset Store API. `jwt` is normally left\n * null here and filled per-call by the caller from {@link getStoreToken} (the\n * device-flow session); it stays on the type for the `{ ...config, jwt }` spread.\n *\n * @docLink cli/dev-guide#store-client\n */\nexport interface StoreConfig {\n url: string;\n jwt: string | null;\n}\n\n/**\n * Read the store API base URL (settings `storeUrl` → `SKAILE_STORE_URL` →\n * default). Auth is not read here — it lives in the device-flow session; see\n * {@link getStoreToken}.\n *\n * @docLink cli/dev-guide#store-client\n */\nexport function getStoreConfig(): StoreConfig {\n const settingsPath = globalSettingsPath();\n let settings: Record<string, any> = {};\n if (existsSync(settingsPath)) {\n try {\n settings = mapLegacyFields(JSON.parse(readFileSync(settingsPath, \"utf-8\")));\n } catch {\n settings = {};\n }\n }\n return {\n url: settings.storeUrl ?? process.env.SKAILE_STORE_URL ?? \"https://api.skaile.store\",\n jwt: null,\n };\n}\n\n/**\n * Return a valid store access token (Keycloak device-flow session, refreshed if\n * needed). Throws a \"run `skaile store login`\" error when there is no session.\n * This is the auth source for every `/api/v1/*` publisher call.\n */\nexport function getStoreToken(deps?: AuthDeps): Promise<string> {\n return getAccessToken(loadStoreAuthConfig(), deps);\n}\n\n/**\n * Make an authenticated HTTP request to the store REST API.\n *\n * @param config - Store connection config (URL + auth token).\n * @param path - API path (e.g. `/api/assets`).\n * @param opts - Optional method, body, query params, extra headers, and\n * `timeoutMs` (default 1500). Publisher calls pass a longer timeout because\n * they trigger server-side clone/sync work.\n * @returns Parsed JSON response body.\n * @docLink cli/dev-guide#store-client\n */\nexport async function storeFetch<T = any>(\n config: StoreConfig,\n path: string,\n opts?: {\n method?: string;\n body?: unknown;\n params?: Record<string, string>;\n headers?: Record<string, string>;\n timeoutMs?: number;\n },\n): Promise<T> {\n let url = `${config.url}${path}`;\n if (opts?.params) {\n const sp = new URLSearchParams(opts.params);\n url += `?${sp}`;\n }\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n ...(opts?.headers ?? {}),\n };\n if (config.jwt) {\n headers.Authorization = `Bearer ${config.jwt}`;\n }\n\n const fetchOpts: RequestInit = {\n method: opts?.method ?? \"GET\",\n headers,\n };\n if (opts?.body) {\n fetchOpts.body = JSON.stringify(opts.body);\n }\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), opts?.timeoutMs ?? 1_500);\n try {\n const res = await fetch(url, { ...fetchOpts, signal: controller.signal });\n if (!res.ok) {\n const body = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));\n // Prefer the store's human-readable `message` (e.g. \"Namespace '@x' is\n // reserved … Sign in with GitHub to claim it\") over the bare `error` code\n // (`UNPROCESSABLE_CONTENT`) — the message is the actionable part.\n const b = body as { message?: string; error?: string };\n throw new Error(b.message ?? b.error ?? `Store API error: ${res.status}`);\n }\n return res.json() as Promise<T>;\n } finally {\n clearTimeout(timeout);\n }\n}\n\n/**\n * Return `true` when a store session exists (a Keycloak device-flow token cached\n * at `~/.skaile/auth.json`). Validity/refresh is resolved on use via\n * {@link getStoreToken}.\n *\n * @docLink cli/dev-guide#store-client\n */\nexport function isStoreAuthenticated(): boolean {\n return hasStoredAuth(loadStoreAuthConfig());\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../cli/src/store-auth.ts","../cli/src/store-client.ts"],"names":["readFileSync"],"mappings":"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","file":"chunk-BRNGJTHH.js","sourcesContent":["/**\n * Keycloak Device Authorization Grant (RFC 8628) for the store CLI: a public\n * device-flow client (`skaile-store-cli`) issues a plain realm JWT the store's\n * `AuthGuard` accepts — a CLI can't use the storefront's confidential browser\n * client. Tokens cache at `~/.skaile/auth.json` (0600, shared with `store/cli`);\n * `getAccessToken` refreshes transparently. All targets are env-overridable.\n *\n * @docLink cli/dev-guide#store-auth\n */\nimport { createHash, randomBytes } from \"node:crypto\";\nimport { chmodSync, mkdirSync, readFileSync, rmSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\n/**\n * A PKCE (RFC 7636) `code_verifier` + its S256 `code_challenge`. Keycloak\n * enforces PKCE on the `skaile-store-cli` device flow (the device-authorization\n * request 400s with \"Missing parameter: code_challenge_method\" otherwise), so\n * every `deviceLogin` mints a fresh pair: the challenge goes on the device-auth\n * request, the verifier on the matching token poll. `base64url` (no padding)\n * per the spec.\n */\nfunction makePkcePair(): { verifier: string; challenge: string } {\n const verifier = randomBytes(32).toString(\"base64url\");\n const challenge = createHash(\"sha256\").update(verifier).digest(\"base64url\");\n return { verifier, challenge };\n}\n\n/** Resolved auth targets — every field has a prod default, all env-overridable. */\nexport interface StoreAuthConfig {\n keycloakUrl: string;\n realm: string;\n clientId: string;\n authFile: string;\n}\n\nfunction trimTrailingSlash(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\n/**\n * Load the auth config. Defaults target the production store\n * (`auth.skaile.ai`, realm `skaile-store`, public client `skaile-store-cli`);\n * override with `SKAILE_KEYCLOAK_URL` / `SKAILE_STORE_REALM` /\n * `SKAILE_STORE_CLI_CLIENT` / `SKAILE_AUTH_FILE` for dev or a preview deploy.\n */\nexport function loadStoreAuthConfig(): StoreAuthConfig {\n const home = process.env.SKAILE_HOME ?? join(homedir(), \".skaile\");\n return {\n keycloakUrl: trimTrailingSlash(process.env.SKAILE_KEYCLOAK_URL ?? \"https://auth.skaile.ai\"),\n realm: process.env.SKAILE_STORE_REALM ?? \"skaile-store\",\n clientId: process.env.SKAILE_STORE_CLI_CLIENT ?? \"skaile-store-cli\",\n authFile: process.env.SKAILE_AUTH_FILE ?? join(home, \"auth.json\"),\n };\n}\n\n/** Keycloak OIDC endpoints derived from the realm base. */\nfunction oidc(config: StoreAuthConfig): { deviceAuth: string; token: string } {\n const base = `${config.keycloakUrl}/realms/${config.realm}/protocol/openid-connect`;\n return { deviceAuth: `${base}/auth/device`, token: `${base}/token` };\n}\n\nexport interface StoredAuth {\n access_token: string;\n refresh_token?: string;\n /** Epoch ms when the access token expires (with a safety margin already applied). */\n expires_at: number;\n}\n\ninterface TokenResponse {\n access_token: string;\n refresh_token?: string;\n expires_in?: number;\n error?: string;\n error_description?: string;\n}\n\ninterface DeviceAuthResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete?: string;\n interval?: number;\n expires_in: number;\n}\n\n/** Refresh this many ms before real expiry so an in-flight call never 401s. */\nconst EXPIRY_MARGIN_MS = 30_000;\n\n/** Injectable seams so the poll loop is unit-testable without real time or network. */\nexport interface AuthDeps {\n fetchImpl?: typeof fetch;\n sleep?: (ms: number) => Promise<void>;\n /** Called once with the verification URL + user code (default: write to stderr). */\n onPrompt?: (url: string, userCode: string) => void;\n}\n\nfunction readAuth(config: StoreAuthConfig): StoredAuth | null {\n try {\n const parsed = JSON.parse(readFileSync(config.authFile, \"utf-8\"));\n // Reject a corrupt / hand-edited file rather than treat it as a session.\n if (parsed && typeof parsed.access_token === \"string\") return parsed as StoredAuth;\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * The caller's store identity, decoded LOCALLY from the cached token's JWT\n * payload (no network, no signature check — this is an author-side hint, not an\n * authorization decision). Returns `null` when not signed in or the token is\n * unreadable. `githubLogin` is the verified GitHub handle (the preferred\n * publisher namespace); `username` is the Keycloak `preferred_username`.\n */\nexport function getStoreIdentity(\n config: StoreAuthConfig = loadStoreAuthConfig(),\n): { username?: string; githubLogin?: string } | null {\n const auth = readAuth(config);\n if (!auth) return null;\n try {\n const payload = auth.access_token.split(\".\")[1];\n const json = JSON.parse(Buffer.from(payload, \"base64url\").toString(\"utf-8\"));\n const username =\n typeof json.preferred_username === \"string\" ? json.preferred_username : undefined;\n const githubLogin = typeof json.github_login === \"string\" ? json.github_login : undefined;\n return username || githubLogin ? { username, githubLogin } : null;\n } catch {\n return null;\n }\n}\n\nfunction writeAuth(config: StoreAuthConfig, auth: StoredAuth): void {\n mkdirSync(dirname(config.authFile), { recursive: true });\n writeFileSync(config.authFile, JSON.stringify(auth, null, 2), { mode: 0o600 });\n chmodSync(config.authFile, 0o600);\n}\n\n/** Remove the cached session (sign out). */\nexport function logout(config: StoreAuthConfig): void {\n try {\n rmSync(config.authFile);\n } catch {\n // already absent — nothing to do\n }\n}\n\n/** True when a cached, well-formed session exists (validity/refresh resolved on use). */\nexport function hasStoredAuth(config: StoreAuthConfig): boolean {\n return readAuth(config) !== null;\n}\n\nfunction tokenToStored(token: TokenResponse): StoredAuth {\n return {\n access_token: token.access_token,\n refresh_token: token.refresh_token,\n expires_at: Date.now() + (token.expires_in ?? 300) * 1000 - EXPIRY_MARGIN_MS,\n };\n}\n\nconst defaultSleep = (ms: number): Promise<void> => new Promise((r) => setTimeout(r, ms));\n\nfunction defaultPrompt(url: string, userCode: string): void {\n process.stderr.write(\n `\\nTo sign in, open:\\n\\n ${url}\\n\\nand enter the code: ${userCode}\\n\\nWaiting for approval…\\n`,\n );\n}\n\n/**\n * Run the device flow to completion, persisting tokens on success. Prints the\n * verification URL + user code for the operator to approve in a browser.\n */\nexport async function deviceLogin(\n config: StoreAuthConfig,\n deps: AuthDeps = {},\n): Promise<StoredAuth> {\n const fetchImpl = deps.fetchImpl ?? fetch;\n const sleep = deps.sleep ?? defaultSleep;\n const onPrompt = deps.onPrompt ?? defaultPrompt;\n const endpoints = oidc(config);\n const pkce = makePkcePair();\n\n const deviceRes = await fetchImpl(endpoints.deviceAuth, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n client_id: config.clientId,\n scope: \"openid profile\",\n code_challenge: pkce.challenge,\n code_challenge_method: \"S256\",\n }),\n });\n if (!deviceRes.ok) {\n throw new Error(\n `Device authorization request failed (${deviceRes.status}): ${await deviceRes.text()}`,\n );\n }\n const device = (await deviceRes.json()) as DeviceAuthResponse;\n\n onPrompt(device.verification_uri_complete ?? device.verification_uri, device.user_code);\n\n const intervalMs = (device.interval ?? 5) * 1000;\n const deadline = Date.now() + device.expires_in * 1000;\n let waitMs = intervalMs;\n\n while (Date.now() < deadline) {\n await sleep(waitMs);\n const tokenRes = await fetchImpl(endpoints.token, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: \"urn:ietf:params:oauth:grant-type:device_code\",\n device_code: device.device_code,\n client_id: config.clientId,\n code_verifier: pkce.verifier,\n }),\n });\n const token = (await tokenRes.json()) as TokenResponse;\n if (tokenRes.ok) {\n const stored = tokenToStored(token);\n writeAuth(config, stored);\n return stored;\n }\n // RFC 8628 §3.5 pending / slow-down handling.\n if (token.error === \"authorization_pending\") continue;\n if (token.error === \"slow_down\") {\n waitMs += 5_000;\n continue;\n }\n throw new Error(`Sign-in failed: ${token.error_description ?? token.error ?? \"unknown error\"}`);\n }\n throw new Error(\"Sign-in timed out before approval.\");\n}\n\n/** Exchange a refresh token for a fresh access token; persist on success. */\nasync function refresh(\n config: StoreAuthConfig,\n refreshToken: string,\n fetchImpl: typeof fetch,\n): Promise<StoredAuth> {\n const res = await fetchImpl(oidc(config).token, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n client_id: config.clientId,\n }),\n });\n const token = (await res.json()) as TokenResponse;\n if (!res.ok) {\n throw new Error(\n `Token refresh failed: ${token.error_description ?? token.error ?? res.status}`,\n );\n }\n const stored = tokenToStored(token);\n writeAuth(config, stored);\n return stored;\n}\n\n/**\n * Return a valid access token, refreshing if it is expired (or about to). Throws\n * a clear \"run `skaile store login`\" error when there is no usable session.\n */\nexport async function getAccessToken(\n config: StoreAuthConfig,\n deps: AuthDeps = {},\n): Promise<string> {\n const fetchImpl = deps.fetchImpl ?? fetch;\n const auth = readAuth(config);\n if (!auth) throw new Error(\"Not signed in. Run `skaile store login` first.\");\n if (Date.now() < auth.expires_at) return auth.access_token;\n if (!auth.refresh_token) throw new Error(\"Session expired. Run `skaile store login` again.\");\n try {\n return (await refresh(config, auth.refresh_token, fetchImpl)).access_token;\n } catch {\n throw new Error(\"Session expired and refresh failed. Run `skaile store login` again.\");\n }\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { globalSettingsPath, mapLegacyFields } from \"@skaile/workspaces/core\";\nimport { type AuthDeps, getAccessToken, hasStoredAuth, loadStoreAuthConfig } from \"./store-auth.ts\";\n\n/**\n * Connection configuration for the AI Asset Store API. `jwt` is normally left\n * null here and filled per-call by the caller from {@link getStoreToken} (the\n * device-flow session); it stays on the type for the `{ ...config, jwt }` spread.\n *\n * @docLink cli/dev-guide#store-client\n */\nexport interface StoreConfig {\n url: string;\n jwt: string | null;\n}\n\n/**\n * Read the store API base URL (settings `storeUrl` → `SKAILE_STORE_URL` →\n * default). Auth is not read here — it lives in the device-flow session; see\n * {@link getStoreToken}.\n *\n * @docLink cli/dev-guide#store-client\n */\nexport function getStoreConfig(): StoreConfig {\n const settingsPath = globalSettingsPath();\n let settings: Record<string, any> = {};\n if (existsSync(settingsPath)) {\n try {\n settings = mapLegacyFields(JSON.parse(readFileSync(settingsPath, \"utf-8\")));\n } catch {\n settings = {};\n }\n }\n return {\n url: settings.storeUrl ?? process.env.SKAILE_STORE_URL ?? \"https://api.skaile.store\",\n jwt: null,\n };\n}\n\n/**\n * Return a valid store access token (Keycloak device-flow session, refreshed if\n * needed). Throws a \"run `skaile store login`\" error when there is no session.\n * This is the auth source for every `/api/v1/*` publisher call.\n */\nexport function getStoreToken(deps?: AuthDeps): Promise<string> {\n return getAccessToken(loadStoreAuthConfig(), deps);\n}\n\n/**\n * Make an authenticated HTTP request to the store REST API.\n *\n * @param config - Store connection config (URL + auth token).\n * @param path - API path (e.g. `/api/assets`).\n * @param opts - Optional method, body, query params, extra headers, and\n * `timeoutMs` (default 1500). Publisher calls pass a longer timeout because\n * they trigger server-side clone/sync work.\n * @returns Parsed JSON response body.\n * @docLink cli/dev-guide#store-client\n */\nexport async function storeFetch<T = any>(\n config: StoreConfig,\n path: string,\n opts?: {\n method?: string;\n body?: unknown;\n params?: Record<string, string>;\n headers?: Record<string, string>;\n timeoutMs?: number;\n },\n): Promise<T> {\n let url = `${config.url}${path}`;\n if (opts?.params) {\n const sp = new URLSearchParams(opts.params);\n url += `?${sp}`;\n }\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n ...(opts?.headers ?? {}),\n };\n if (config.jwt) {\n headers.Authorization = `Bearer ${config.jwt}`;\n }\n\n const fetchOpts: RequestInit = {\n method: opts?.method ?? \"GET\",\n headers,\n };\n if (opts?.body) {\n fetchOpts.body = JSON.stringify(opts.body);\n }\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), opts?.timeoutMs ?? 1_500);\n try {\n const res = await fetch(url, { ...fetchOpts, signal: controller.signal });\n if (!res.ok) {\n const body = await res.json().catch(() => ({ error: `HTTP ${res.status}` }));\n // Prefer the store's human-readable `message` (e.g. \"Namespace '@x' is\n // reserved … Sign in with GitHub to claim it\") over the bare `error` code\n // (`UNPROCESSABLE_CONTENT`) — the message is the actionable part.\n const b = body as { message?: string; error?: string };\n throw new Error(b.message ?? b.error ?? `Store API error: ${res.status}`);\n }\n return res.json() as Promise<T>;\n } finally {\n clearTimeout(timeout);\n }\n}\n\n/**\n * Return `true` when a store session exists (a Keycloak device-flow token cached\n * at `~/.skaile/auth.json`). Validity/refresh is resolved on use via\n * {@link getStoreToken}.\n *\n * @docLink cli/dev-guide#store-client\n */\nexport function isStoreAuthenticated(): boolean {\n return hasStoredAuth(loadStoreAuthConfig());\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../core/src/logging/retention-value.ts"],"names":[],"mappings":";AAKO,SAAS,iBAAiB,CAAA,EAAyB;AACxD,EAAA,OAAO,OAAO,CAAA,KAAM,QAAA,IAAY,OAAO,QAAA,CAAS,CAAC,KAAK,CAAA,IAAK,CAAA;AAC7D","file":"chunk-C3CAXQMA.js","sourcesContent":["/**\n * The one rule for a `logging.retention` limit: a finite number of 0 or more\n * (`0` means \"delete every row\"). Kept free of the SQLite runtime so the\n * `skaile.yaml` decoder can share it with the trimmer.\n */\nexport function isRetentionValue(v: unknown): v is number {\n return typeof v === \"number\" && Number.isFinite(v) && v >= 0;\n}\n"]}
|
|
@@ -19,10 +19,10 @@ async function dispatchCapability(hooks, callId, name, input, onBackgroundError
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
if (cap?.fireAndForget) {
|
|
22
|
-
void hooks.invoke(name, input, signal).catch(onBackgroundError);
|
|
22
|
+
void hooks.invoke(name, input, signal, callId).catch(onBackgroundError);
|
|
23
23
|
return { result: {}, background: true };
|
|
24
24
|
}
|
|
25
|
-
const result = await hooks.invoke(name, input, signal);
|
|
25
|
+
const result = await hooks.invoke(name, input, signal, callId);
|
|
26
26
|
return { result, background: false };
|
|
27
27
|
}
|
|
28
28
|
function renderFallback(template, input) {
|
|
@@ -51,5 +51,5 @@ function filterRenderCapabilities(caps) {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
export { dispatchCapability, filterRenderCapabilities, renderFallback };
|
|
54
|
-
//# sourceMappingURL=chunk-
|
|
55
|
-
//# sourceMappingURL=chunk-
|
|
54
|
+
//# sourceMappingURL=chunk-CPIAQTYM.js.map
|
|
55
|
+
//# sourceMappingURL=chunk-CPIAQTYM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../bridge/src/capability-dispatch.ts"],"names":[],"mappings":";;;AAmEA,eAAsB,mBACpB,KAAA,EACA,MAAA,EACA,IAAA,EACA,KAAA,EACA,oBAA4C,MAAM;AAAC,CAAA,EACnD,MAAA,EACmC;AACnC,EAAA,MAAA,EAAQ,cAAA,EAAe;AACvB,EAAA,MAAM,GAAA,GAAM,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA;AAI9B,EAAA,IAAI,CAAC,qBAAA,CAAsB,GAAA,EAAK,WAAW,CAAA,EAAG,KAAA,GAAQ,mBAAmB,KAAK,CAAA;AAK9E,EAAA,IAAI,GAAA,EAAK,MAAA,IAAU,KAAA,CAAM,UAAA,EAAY;AACnC,IAAA,KAAA,CAAM,UAAA,CAAW;AAAA,MACf,IAAA,EAAM,gBAAA;AAAA,MACN,cAAA,EAAgB,IAAA;AAAA,MAChB,KAAA,EAAO,KAAA;AAAA,MACP;AAAA,KACD,CAAA;AACD,IAAA,IAAI,GAAA,CAAI,MAAA,CAAO,QAAA,IAAY,KAAA,CAAM,QAAA,EAAU;AACzC,MAAA,MAAM,QAAA,GAAW,cAAA,CAAe,GAAA,CAAI,MAAA,CAAO,UAAU,KAAK,CAAA;AAC1D,MAAA,KAAA,CAAM,SAAS,QAAQ,CAAA;AAAA,IACzB;AAAA,EACF;AAEA,EAAA,IAAI,KAAK,aAAA,EAAe;AAEtB,IAAA,KAAK,KAAA,CAAM,OAAO,IAAA,EAAM,KAAA,EAAO,QAAQ,MAAM,CAAA,CAAE,MAAM,iBAAiB,CAAA;AACtE,IAAA,OAAO,EAAE,MAAA,EAAQ,EAAC,EAAG,YAAY,IAAA,EAAK;AAAA,EACxC;AAEA,EAAA,MAAM,SAAS,MAAM,KAAA,CAAM,OAAO,IAAA,EAAM,KAAA,EAAO,QAAQ,MAAM,CAAA;AAC7D,EAAA,OAAO,EAAE,MAAA,EAAQ,UAAA,EAAY,KAAA,EAAM;AACrC;AAqBO,SAAS,cAAA,CAAe,UAAkB,KAAA,EAAwB;AACvE,EAAA,IAAI,CAAC,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,EAAU;AACvC,IAAA,OAAO,QAAA,CAAS,OAAA,CAAQ,wBAAA,EAA0B,EAAE,CAAA;AAAA,EACtD;AACA,EAAA,MAAM,KAAA,GAAQ,KAAA;AACd,EAAA,OAAO,QAAA,CAAS,OAAA,CAAQ,0BAAA,EAA4B,CAAC,QAAQ,IAAA,KAAiB;AAC5E,IAAA,MAAM,KAAA,GAAQ,QAAA,CAAS,KAAA,EAAO,IAAI,CAAA;AAClC,IAAA,OAAO,UAAU,MAAA,IAAa,KAAA,KAAU,IAAA,GAAO,EAAA,GAAK,OAAO,KAAK,CAAA;AAAA,EAClE,CAAC,CAAA;AACH;AAEA,SAAS,QAAA,CAAS,KAA8B,IAAA,EAAuB;AACrE,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AAC5B,EAAA,IAAI,OAAA,GAAmB,GAAA;AACvB,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,IAAA,IAAI,YAAY,IAAA,IAAQ,OAAA,KAAY,MAAA,IAAa,OAAO,YAAY,QAAA,EAAU;AAC5E,MAAA,OAAO,MAAA;AAAA,IACT;AACA,IAAA,OAAA,GAAW,QAAoC,IAAI,CAAA;AAAA,EACrD;AACA,EAAA,OAAO,OAAA;AACT;AAYO,SAAS,yBAAyB,IAAA,EAAkC;AACzE,EAAA,OAAO,KAAK,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,WAAW,MAAS,CAAA;AAClD","file":"chunk-CPIAQTYM.js","sourcesContent":["/**\n * Capability dispatch helpers for bridge drivers.\n *\n * The runner builds a {@link BridgeCapabilityHooks} bundle from its\n * `CapabilityRegistry` and threads it through `AgentConfig.capabilities`.\n * Drivers consume the bundle via these helpers without taking a runtime\n * dependency on `@skaile/workspaces/runner` (which would create a circular dep).\n *\n * Three behaviours are layered into a single dispatch path:\n *\n * 1. **Standard tool call** — the LLM invokes a capability; the bridge calls\n * `hooks.invoke()`, awaits the result, and returns it to the LLM.\n * 2. **Fire-and-forget** — when the resolved Capability has `fireAndForget`\n * set, the bridge resolves to `{}` immediately and runs the handler in\n * the background. Background errors are logged but never surfaced to the\n * LLM since the call is already settled.\n * 3. **Render capability** — when the resolved Capability has a non-undefined\n * `render`, the bridge emits `RenderInvokedEvent` to the runner via\n * `hooks.emitRender` and (when `render.fallback` is set) a parallel text\n * event via `hooks.emitText` with simple `{{prop}}` substitution. The\n * placeholder convention follows the v2 spec — top-level keys of `props`\n * only, with optional dotted-path traversal (`{{user.name}}`). The legacy\n * AAP `{{props.x}}` form was retired in Phase 6.\n *\n * @category Capabilities\n * @since 2.0.0\n */\nimport {\n type Capability,\n declaresActivityLabel,\n stripActivityLabel,\n} from \"@skaile/workspaces/types\";\nimport type { BridgeCapabilityHooks } from \"./types.js\";\n\n/**\n * Result of a capability dispatch returned by {@link dispatchCapability}.\n *\n * The bridge feeds `{ result }` back to the LLM tool-use response. For\n * fire-and-forget capabilities `result` is always `{}` and `background` is `true`.\n *\n * @docLink packages/bridge/concepts#capability-dispatch-result\n */\nexport interface CapabilityDispatchResult {\n /** Value returned to the LLM. `{}` for fire-and-forget capabilities. */\n result: unknown;\n /** True when the handler is still running in the background (fire-and-forget). */\n background: boolean;\n}\n\n/**\n * Run a capability invocation through the runner-provided hooks, applying\n * render-event emission and fire-and-forget short-circuit.\n *\n * The result is always shaped for direct return to the LLM. For\n * fire-and-forget capabilities the background promise is fired and any error\n * is logged through `onBackgroundError` (defaulting to a no-op). For all\n * other capabilities the handler is awaited; errors propagate as a rejection\n * so the driver can surface them as tool errors.\n *\n * @param hooks - Capability dispatch bundle from `AgentConfig.capabilities`.\n * @param callId - Correlation ID for the tool-use invocation (used in render events).\n * @param name - Registered capability name.\n * @param input - Raw tool input from the LLM.\n * @param onBackgroundError - Optional error handler for fire-and-forget failures.\n * @returns Resolved dispatch result with the LLM-facing value and background flag.\n * @docLink packages/bridge/concepts#dispatch-capability\n */\nexport async function dispatchCapability(\n hooks: BridgeCapabilityHooks,\n callId: string,\n name: string,\n input: unknown,\n onBackgroundError: (err: unknown) => void = () => {},\n signal?: AbortSignal,\n): Promise<CapabilityDispatchResult> {\n signal?.throwIfAborted();\n const cap = hooks.resolve(name);\n // The advertised `activity_label` is for the UI only. Strip it before render\n // props and the handler: strict inputs would reject it and external MCP\n // passthrough would forward it. Kept when the capability declares it itself.\n if (!declaresActivityLabel(cap?.inputSchema)) input = stripActivityLabel(input);\n\n // Render emission happens before invocation so clients see the props the\n // LLM passed in even if the handler errors. The runner's gateway forwards\n // the event over the transport.\n if (cap?.render && hooks.emitRender) {\n hooks.emitRender({\n type: \"render_invoked\",\n capabilityName: name,\n props: input,\n callId,\n });\n if (cap.render.fallback && hooks.emitText) {\n const fallback = renderFallback(cap.render.fallback, input);\n hooks.emitText(fallback);\n }\n }\n\n if (cap?.fireAndForget) {\n // Resolve immediately; run handler in background.\n void hooks.invoke(name, input, signal, callId).catch(onBackgroundError);\n return { result: {}, background: true };\n }\n\n const result = await hooks.invoke(name, input, signal, callId);\n return { result, background: false };\n}\n\n/**\n * Substitute `{{prop}}` placeholders inside a fallback template using the\n * input record. Top-level keys of `props` resolve directly\n * (`{{name}}` → `props.name`); dotted paths traverse nested records\n * (`{{user.name}}` → `props.user.name`). Missing keys collapse to an empty\n * string; non-record inputs collapse all placeholders.\n *\n * The convention is fixed by the v2 spec (§1, `RenderSpec.fallback`). The\n * legacy AAP form `{{props.x}}` is no longer accepted — author fallbacks\n * with bare keys.\n *\n * Intentionally minimal — full template engines belong in the platform's\n * render layer, not the bridge.\n *\n * @param template - Fallback string from `RenderSpec.fallback` with `{{key}}` placeholders.\n * @param input - LLM tool input object; non-object values collapse all placeholders.\n * @returns Template with all resolvable placeholders replaced.\n * @docLink packages/bridge/concepts#render-fallback\n */\nexport function renderFallback(template: string, input: unknown): string {\n if (!input || typeof input !== \"object\") {\n return template.replace(/\\{\\{\\s*[\\w$.]+\\s*\\}\\}/g, \"\");\n }\n const props = input as Record<string, unknown>;\n return template.replace(/\\{\\{\\s*([\\w$.]+)\\s*\\}\\}/g, (_match, path: string) => {\n const value = readPath(props, path);\n return value === undefined || value === null ? \"\" : String(value);\n });\n}\n\nfunction readPath(obj: Record<string, unknown>, path: string): unknown {\n const parts = path.split(\".\");\n let current: unknown = obj;\n for (const part of parts) {\n if (current === null || current === undefined || typeof current !== \"object\") {\n return undefined;\n }\n current = (current as Record<string, unknown>)[part];\n }\n return current;\n}\n\n/**\n * Filter a capability list to those marked as render-capable (having a `render` spec).\n *\n * Used by drivers that emit a separate render manifest at registration time.\n * Currently unused in production drivers; reserved for future phases.\n *\n * @param caps - Full capability list to filter.\n * @returns Subset of capabilities with a non-undefined `render` property.\n * @docLink packages/bridge/concepts#filter-render-capabilities\n */\nexport function filterRenderCapabilities(caps: Capability[]): Capability[] {\n return caps.filter((c) => c.render !== undefined);\n}\n"]}
|