@mastra/core 1.4.0 → 1.5.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +368 -0
- package/dist/agent/agent.d.ts +3 -2
- package/dist/agent/agent.d.ts.map +1 -1
- package/dist/agent/index.cjs +13 -13
- package/dist/agent/index.js +2 -2
- package/dist/agent/message-list/conversion/output-converter.d.ts.map +1 -1
- package/dist/agent/message-list/index.cjs +18 -18
- package/dist/agent/message-list/index.js +1 -1
- package/dist/agent/message-list/merge/MessageMerger.d.ts.map +1 -1
- package/dist/agent/message-list/message-list.d.ts.map +1 -1
- package/dist/agent/types.d.ts +2 -2
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/workflows/prepare-stream/index.d.ts +1 -0
- package/dist/agent/workflows/prepare-stream/index.d.ts.map +1 -1
- package/dist/agent/workflows/prepare-stream/prepare-tools-step.d.ts +1 -0
- package/dist/agent/workflows/prepare-stream/prepare-tools-step.d.ts.map +1 -1
- package/dist/agent/workflows/prepare-stream/schema.d.ts +8 -0
- package/dist/agent/workflows/prepare-stream/schema.d.ts.map +1 -1
- package/dist/{chunk-Y3TQ52UE.js → chunk-33TGTTTS.js} +4 -3
- package/dist/chunk-33TGTTTS.js.map +1 -0
- package/dist/{chunk-3X3CZUXI.js → chunk-3KJW4EMO.js} +660 -206
- package/dist/chunk-3KJW4EMO.js.map +1 -0
- package/dist/{chunk-YNNJLLFN.cjs → chunk-3YMDR4OL.cjs} +661 -207
- package/dist/chunk-3YMDR4OL.cjs.map +1 -0
- package/dist/{chunk-NJ7TL3LQ.js → chunk-5EOLBHHS.js} +26 -15
- package/dist/chunk-5EOLBHHS.js.map +1 -0
- package/dist/{chunk-RZ4CIIZR.js → chunk-6DUTLERJ.js} +4 -4
- package/dist/{chunk-RZ4CIIZR.js.map → chunk-6DUTLERJ.js.map} +1 -1
- package/dist/{chunk-VTE2OBKS.cjs → chunk-A6EWCOGA.cjs} +417 -77
- package/dist/chunk-A6EWCOGA.cjs.map +1 -0
- package/dist/{chunk-4XSAZPPS.js → chunk-A7V2NSY3.js} +313 -137
- package/dist/chunk-A7V2NSY3.js.map +1 -0
- package/dist/{chunk-FLPEGTEK.js → chunk-AIRMLZ43.js} +5 -5
- package/dist/{chunk-FLPEGTEK.js.map → chunk-AIRMLZ43.js.map} +1 -1
- package/dist/{chunk-DBSVT6AR.cjs → chunk-BKQAP27M.cjs} +9 -9
- package/dist/{chunk-DBSVT6AR.cjs.map → chunk-BKQAP27M.cjs.map} +1 -1
- package/dist/{chunk-RS6CZXGA.js → chunk-BQHWJLXU.js} +15 -4
- package/dist/chunk-BQHWJLXU.js.map +1 -0
- package/dist/{chunk-V2MLGA7T.js → chunk-CXVMDV2B.js} +417 -78
- package/dist/chunk-CXVMDV2B.js.map +1 -0
- package/dist/{chunk-NKYWDNCI.cjs → chunk-E2FHTXAI.cjs} +7 -7
- package/dist/{chunk-NKYWDNCI.cjs.map → chunk-E2FHTXAI.cjs.map} +1 -1
- package/dist/{chunk-7UWHFWST.cjs → chunk-EAZ6YDCQ.cjs} +15 -3
- package/dist/chunk-EAZ6YDCQ.cjs.map +1 -0
- package/dist/{chunk-64WGYTQK.cjs → chunk-FTBLAVTF.cjs} +55 -55
- package/dist/{chunk-64WGYTQK.cjs.map → chunk-FTBLAVTF.cjs.map} +1 -1
- package/dist/{chunk-4EHGOATH.js → chunk-FZ5DRHKE.js} +1337 -547
- package/dist/chunk-FZ5DRHKE.js.map +1 -0
- package/dist/{chunk-4TQ4EBYX.js → chunk-GEDGDKQ6.js} +9 -9
- package/dist/chunk-GEDGDKQ6.js.map +1 -0
- package/dist/{chunk-QTTWRCB5.js → chunk-I3AWF54W.js} +5 -5
- package/dist/{chunk-QTTWRCB5.js.map → chunk-I3AWF54W.js.map} +1 -1
- package/dist/{chunk-U2HKJZCI.js → chunk-IBNCZTNQ.js} +6 -6
- package/dist/{chunk-U2HKJZCI.js.map → chunk-IBNCZTNQ.js.map} +1 -1
- package/dist/{chunk-3JVFFAJX.cjs → chunk-IJIE3ZID.cjs} +27 -16
- package/dist/chunk-IJIE3ZID.cjs.map +1 -0
- package/dist/{chunk-NZG2JAKS.cjs → chunk-JWG272ZZ.cjs} +19 -19
- package/dist/chunk-JWG272ZZ.cjs.map +1 -0
- package/dist/{chunk-BP7VYTOP.cjs → chunk-JZ6TH4HQ.cjs} +954 -401
- package/dist/chunk-JZ6TH4HQ.cjs.map +1 -0
- package/dist/{chunk-SU5APAM6.cjs → chunk-KNXZ7KYL.cjs} +94 -6
- package/dist/chunk-KNXZ7KYL.cjs.map +1 -0
- package/dist/{chunk-CYUP7QWT.cjs → chunk-KRAGJ433.cjs} +4 -3
- package/dist/chunk-KRAGJ433.cjs.map +1 -0
- package/dist/{chunk-XDD5V446.cjs → chunk-MDC6VYA6.cjs} +6 -2
- package/dist/{chunk-XDD5V446.cjs.map → chunk-MDC6VYA6.cjs.map} +1 -1
- package/dist/{chunk-AXHBJ4GX.js → chunk-NN26FSKL.js} +10 -8
- package/dist/chunk-NN26FSKL.js.map +1 -0
- package/dist/{chunk-AY6DBRS3.js → chunk-OHLVZVIK.js} +36 -2
- package/dist/chunk-OHLVZVIK.js.map +1 -0
- package/dist/{chunk-5Q5Y34SS.js → chunk-PECKKR4C.js} +4 -4
- package/dist/{chunk-5Q5Y34SS.js.map → chunk-PECKKR4C.js.map} +1 -1
- package/dist/{chunk-HYRYTTMT.cjs → chunk-PHHJLGZU.cjs} +9 -9
- package/dist/{chunk-HYRYTTMT.cjs.map → chunk-PHHJLGZU.cjs.map} +1 -1
- package/dist/{chunk-65PHUUMF.cjs → chunk-QDH6MVJ7.cjs} +24 -22
- package/dist/chunk-QDH6MVJ7.cjs.map +1 -0
- package/dist/{chunk-VD5YA6RH.cjs → chunk-QSN5KQXZ.cjs} +18 -18
- package/dist/{chunk-VD5YA6RH.cjs.map → chunk-QSN5KQXZ.cjs.map} +1 -1
- package/dist/{chunk-4IJ4UDZX.cjs → chunk-RH2K66O2.cjs} +399 -223
- package/dist/chunk-RH2K66O2.cjs.map +1 -0
- package/dist/{chunk-4KFEMXTV.cjs → chunk-S4VVZI4E.cjs} +1361 -546
- package/dist/chunk-S4VVZI4E.cjs.map +1 -0
- package/dist/{chunk-ZATLLPIH.js → chunk-TPDMP7OD.js} +6 -2
- package/dist/chunk-TPDMP7OD.js.map +1 -0
- package/dist/{chunk-PS5ONCXY.js → chunk-UZFGMMKU.js} +82 -4
- package/dist/chunk-UZFGMMKU.js.map +1 -0
- package/dist/{chunk-7NKUSQEV.js → chunk-YIN5F7VO.js} +936 -389
- package/dist/chunk-YIN5F7VO.js.map +1 -0
- package/dist/{chunk-CZ4NQANZ.cjs → chunk-YW54RH77.cjs} +36 -2
- package/dist/chunk-YW54RH77.cjs.map +1 -0
- package/dist/datasets/experiment/executor.d.ts.map +1 -1
- package/dist/datasets/index.cjs +17 -17
- package/dist/datasets/index.js +2 -2
- package/dist/docs/SKILL.md +27 -1
- package/dist/docs/assets/SOURCE_MAP.json +463 -389
- package/dist/docs/references/docs-agents-processors.md +52 -0
- package/dist/docs/references/docs-observability-datasets-overview.md +188 -0
- package/dist/docs/references/docs-observability-datasets-running-experiments.md +266 -0
- package/dist/docs/references/docs-observability-tracing-exporters-cloud.md +7 -4
- package/dist/docs/references/reference-agents-generate.md +1 -1
- package/dist/docs/references/reference-configuration.md +3 -4
- package/dist/docs/references/reference-datasets-addItem.md +35 -0
- package/dist/docs/references/reference-datasets-addItems.md +33 -0
- package/dist/docs/references/reference-datasets-compareExperiments.md +48 -0
- package/dist/docs/references/reference-datasets-create.md +49 -0
- package/dist/docs/references/reference-datasets-dataset.md +78 -0
- package/dist/docs/references/reference-datasets-datasets-manager.md +84 -0
- package/dist/docs/references/reference-datasets-delete.md +23 -0
- package/dist/docs/references/reference-datasets-deleteExperiment.md +25 -0
- package/dist/docs/references/reference-datasets-deleteItem.md +25 -0
- package/dist/docs/references/reference-datasets-deleteItems.md +27 -0
- package/dist/docs/references/reference-datasets-get.md +29 -0
- package/dist/docs/references/reference-datasets-getDetails.md +45 -0
- package/dist/docs/references/reference-datasets-getExperiment.md +28 -0
- package/dist/docs/references/reference-datasets-getItem.md +31 -0
- package/dist/docs/references/reference-datasets-getItemHistory.md +29 -0
- package/dist/docs/references/reference-datasets-list.md +29 -0
- package/dist/docs/references/reference-datasets-listExperimentResults.md +37 -0
- package/dist/docs/references/reference-datasets-listExperiments.md +31 -0
- package/dist/docs/references/reference-datasets-listItems.md +44 -0
- package/dist/docs/references/reference-datasets-listVersions.md +31 -0
- package/dist/docs/references/reference-datasets-startExperiment.md +60 -0
- package/dist/docs/references/reference-datasets-startExperimentAsync.md +41 -0
- package/dist/docs/references/reference-datasets-update.md +46 -0
- package/dist/docs/references/reference-datasets-updateItem.md +36 -0
- package/dist/docs/references/reference-memory-observational-memory.md +36 -0
- package/dist/docs/references/reference-processors-processor-interface.md +4 -0
- package/dist/docs/references/reference-tools-create-tool.md +1 -1
- package/dist/docs/references/reference.md +24 -0
- package/dist/editor/index.d.ts +1 -1
- package/dist/editor/index.d.ts.map +1 -1
- package/dist/editor/types.d.ts +108 -2
- package/dist/editor/types.d.ts.map +1 -1
- package/dist/evals/index.cjs +20 -20
- package/dist/evals/index.js +3 -3
- package/dist/evals/scoreTraces/index.cjs +5 -5
- package/dist/evals/scoreTraces/index.js +2 -2
- package/dist/harness/harness.d.ts +281 -0
- package/dist/harness/harness.d.ts.map +1 -0
- package/dist/harness/index.cjs +1728 -0
- package/dist/harness/index.cjs.map +1 -0
- package/dist/harness/index.d.ts +4 -0
- package/dist/harness/index.d.ts.map +1 -0
- package/dist/harness/index.js +1723 -0
- package/dist/harness/index.js.map +1 -0
- package/dist/harness/tools.d.ts +65 -0
- package/dist/harness/tools.d.ts.map +1 -0
- package/dist/harness/types.d.ts +561 -0
- package/dist/harness/types.d.ts.map +1 -0
- package/dist/index.cjs +2 -2
- package/dist/index.js +1 -1
- package/dist/integration/index.cjs +2 -2
- package/dist/integration/index.js +1 -1
- package/dist/llm/index.cjs +20 -20
- package/dist/llm/index.js +3 -3
- package/dist/llm/model/gateways/constants.d.ts.map +1 -1
- package/dist/llm/model/gateways/models-dev.d.ts +2 -3
- package/dist/llm/model/gateways/models-dev.d.ts.map +1 -1
- package/dist/llm/model/provider-types.generated.d.ts +312 -93
- package/dist/loop/index.cjs +12 -12
- package/dist/loop/index.js +1 -1
- package/dist/loop/network/index.d.ts.map +1 -1
- package/dist/loop/test-utils/options.d.ts.map +1 -1
- package/dist/loop/test-utils/tools.d.ts.map +1 -1
- package/dist/loop/workflows/agentic-execution/llm-mapping-step.d.ts.map +1 -1
- package/dist/loop/workflows/agentic-execution/tool-call-step.d.ts.map +1 -1
- package/dist/loop/workflows/stream.d.ts.map +1 -1
- package/dist/mastra/index.cjs +2 -2
- package/dist/mastra/index.d.ts +3 -3
- package/dist/mastra/index.d.ts.map +1 -1
- package/dist/mastra/index.js +1 -1
- package/dist/memory/index.cjs +14 -14
- package/dist/memory/index.js +1 -1
- package/dist/memory/memory.d.ts +10 -0
- package/dist/memory/memory.d.ts.map +1 -1
- package/dist/memory/types.d.ts +24 -0
- package/dist/memory/types.d.ts.map +1 -1
- package/dist/models-dev-BW2GAM3K.cjs +12 -0
- package/dist/{models-dev-PPIXUUCU.cjs.map → models-dev-BW2GAM3K.cjs.map} +1 -1
- package/dist/models-dev-MDI5E2YA.js +3 -0
- package/dist/{models-dev-FQVUTQ7L.js.map → models-dev-MDI5E2YA.js.map} +1 -1
- package/dist/observability/index.cjs +11 -11
- package/dist/observability/index.js +1 -1
- package/dist/observability/utils.d.ts.map +1 -1
- package/dist/processors/index.cjs +41 -41
- package/dist/processors/index.js +1 -1
- package/dist/processors/processors/skills.d.ts +5 -0
- package/dist/processors/processors/skills.d.ts.map +1 -1
- package/dist/processors/runner.d.ts +2 -2
- package/dist/processors/runner.d.ts.map +1 -1
- package/dist/processors/step-schema.d.ts +218 -49453
- package/dist/processors/step-schema.d.ts.map +1 -1
- package/dist/provider-registry-4PH2JPIA.cjs +40 -0
- package/dist/{provider-registry-6LZAGQET.cjs.map → provider-registry-4PH2JPIA.cjs.map} +1 -1
- package/dist/provider-registry-VEJ3PN4S.js +3 -0
- package/dist/{provider-registry-QUNT7S55.js.map → provider-registry-VEJ3PN4S.js.map} +1 -1
- package/dist/provider-registry.json +657 -203
- package/dist/relevance/index.cjs +3 -3
- package/dist/relevance/index.js +1 -1
- package/dist/server/composite-auth.d.ts.map +1 -1
- package/dist/server/index.cjs +6 -1
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.js +6 -1
- package/dist/server/index.js.map +1 -1
- package/dist/storage/base.d.ts +4 -1
- package/dist/storage/base.d.ts.map +1 -1
- package/dist/storage/constants.cjs +82 -42
- package/dist/storage/constants.d.ts +11 -1
- package/dist/storage/constants.d.ts.map +1 -1
- package/dist/storage/constants.js +1 -1
- package/dist/storage/domains/agents/inmemory.d.ts.map +1 -1
- package/dist/storage/domains/blobs/base.d.ts +47 -0
- package/dist/storage/domains/blobs/base.d.ts.map +1 -0
- package/dist/storage/domains/blobs/index.d.ts +3 -0
- package/dist/storage/domains/blobs/index.d.ts.map +1 -0
- package/dist/storage/domains/blobs/inmemory.d.ts +17 -0
- package/dist/storage/domains/blobs/inmemory.d.ts.map +1 -0
- package/dist/storage/domains/datasets/inmemory.d.ts.map +1 -1
- package/dist/storage/domains/index.d.ts +3 -0
- package/dist/storage/domains/index.d.ts.map +1 -1
- package/dist/storage/domains/inmemory-db.d.ts +7 -1
- package/dist/storage/domains/inmemory-db.d.ts.map +1 -1
- package/dist/storage/domains/mcp-clients/inmemory.d.ts.map +1 -1
- package/dist/storage/domains/operations/inmemory.d.ts.map +1 -1
- package/dist/storage/domains/prompt-blocks/inmemory.d.ts.map +1 -1
- package/dist/storage/domains/scorer-definitions/inmemory.d.ts.map +1 -1
- package/dist/storage/domains/skills/base.d.ts +47 -0
- package/dist/storage/domains/skills/base.d.ts.map +1 -0
- package/dist/storage/domains/skills/index.d.ts +3 -0
- package/dist/storage/domains/skills/index.d.ts.map +1 -0
- package/dist/storage/domains/skills/inmemory.d.ts +31 -0
- package/dist/storage/domains/skills/inmemory.d.ts.map +1 -0
- package/dist/storage/domains/versioned.d.ts +12 -3
- package/dist/storage/domains/versioned.d.ts.map +1 -1
- package/dist/storage/domains/workspaces/base.d.ts +47 -0
- package/dist/storage/domains/workspaces/base.d.ts.map +1 -0
- package/dist/storage/domains/workspaces/index.d.ts +3 -0
- package/dist/storage/domains/workspaces/index.d.ts.map +1 -0
- package/dist/storage/domains/workspaces/inmemory.d.ts +31 -0
- package/dist/storage/domains/workspaces/inmemory.d.ts.map +1 -0
- package/dist/storage/index.cjs +202 -138
- package/dist/storage/index.js +2 -2
- package/dist/storage/mock.d.ts.map +1 -1
- package/dist/storage/types.d.ts +422 -12
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/stream/base/output.d.ts.map +1 -1
- package/dist/stream/index.cjs +11 -11
- package/dist/stream/index.js +2 -2
- package/dist/test-utils/llm-mock.cjs +4 -4
- package/dist/test-utils/llm-mock.js +1 -1
- package/dist/tool-loop-agent/index.cjs +4 -4
- package/dist/tool-loop-agent/index.js +1 -1
- package/dist/tools/index.cjs +8 -4
- package/dist/tools/index.js +1 -1
- package/dist/tools/is-vercel-tool.cjs +2 -2
- package/dist/tools/is-vercel-tool.js +1 -1
- package/dist/tools/tool-builder/builder.d.ts.map +1 -1
- package/dist/tools/tool.d.ts +13 -0
- package/dist/tools/tool.d.ts.map +1 -1
- package/dist/tools/toolchecks.d.ts.map +1 -1
- package/dist/tools/types.d.ts +24 -0
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/types/zod-compat.d.ts +27 -6
- package/dist/types/zod-compat.d.ts.map +1 -1
- package/dist/utils.cjs +23 -23
- package/dist/utils.js +1 -1
- package/dist/vector/index.cjs +12 -12
- package/dist/vector/index.js +2 -2
- package/dist/workflows/evented/index.cjs +10 -10
- package/dist/workflows/evented/index.js +1 -1
- package/dist/workflows/handlers/entry.d.ts.map +1 -1
- package/dist/workflows/index.cjs +25 -25
- package/dist/workflows/index.js +1 -1
- package/dist/workflows/workflow.d.ts +2 -2
- package/dist/workflows/workflow.d.ts.map +1 -1
- package/dist/workspace/constants/index.d.ts +1 -0
- package/dist/workspace/constants/index.d.ts.map +1 -1
- package/dist/workspace/errors.d.ts +3 -0
- package/dist/workspace/errors.d.ts.map +1 -1
- package/dist/workspace/filesystem/composite-filesystem.d.ts +75 -6
- package/dist/workspace/filesystem/composite-filesystem.d.ts.map +1 -1
- package/dist/workspace/filesystem/local-filesystem.d.ts +42 -0
- package/dist/workspace/filesystem/local-filesystem.d.ts.map +1 -1
- package/dist/workspace/glob.d.ts +61 -0
- package/dist/workspace/glob.d.ts.map +1 -0
- package/dist/workspace/index.cjs +133 -41
- package/dist/workspace/index.d.ts +8 -1
- package/dist/workspace/index.d.ts.map +1 -1
- package/dist/workspace/index.js +1 -1
- package/dist/workspace/sandbox/local-sandbox.d.ts.map +1 -1
- package/dist/workspace/skills/composite-versioned-skill-source.d.ts +44 -0
- package/dist/workspace/skills/composite-versioned-skill-source.d.ts.map +1 -0
- package/dist/workspace/skills/index.d.ts +3 -0
- package/dist/workspace/skills/index.d.ts.map +1 -1
- package/dist/workspace/skills/local-skill-source.d.ts.map +1 -1
- package/dist/workspace/skills/publish.d.ts +34 -0
- package/dist/workspace/skills/publish.d.ts.map +1 -0
- package/dist/workspace/skills/skill-source.d.ts +2 -0
- package/dist/workspace/skills/skill-source.d.ts.map +1 -1
- package/dist/workspace/skills/types.d.ts +16 -0
- package/dist/workspace/skills/types.d.ts.map +1 -1
- package/dist/workspace/skills/versioned-skill-source.d.ts +20 -0
- package/dist/workspace/skills/versioned-skill-source.d.ts.map +1 -0
- package/dist/workspace/skills/workspace-skills.d.ts +5 -0
- package/dist/workspace/skills/workspace-skills.d.ts.map +1 -1
- package/dist/workspace/tools/delete-file.d.ts +5 -0
- package/dist/workspace/tools/delete-file.d.ts.map +1 -0
- package/dist/workspace/tools/edit-file.d.ts +7 -0
- package/dist/workspace/tools/edit-file.d.ts.map +1 -0
- package/dist/workspace/tools/execute-command.d.ts +7 -0
- package/dist/workspace/tools/execute-command.d.ts.map +1 -0
- package/dist/workspace/tools/file-stat.d.ts +4 -0
- package/dist/workspace/tools/file-stat.d.ts.map +1 -0
- package/dist/workspace/tools/grep.d.ts +9 -0
- package/dist/workspace/tools/grep.d.ts.map +1 -0
- package/dist/workspace/tools/helpers.d.ts +36 -0
- package/dist/workspace/tools/helpers.d.ts.map +1 -0
- package/dist/workspace/tools/index-content.d.ts +6 -0
- package/dist/workspace/tools/index-content.d.ts.map +1 -0
- package/dist/workspace/tools/index.d.ts +13 -1
- package/dist/workspace/tools/index.d.ts.map +1 -1
- package/dist/workspace/tools/list-files.d.ts +10 -0
- package/dist/workspace/tools/list-files.d.ts.map +1 -0
- package/dist/workspace/tools/mkdir.d.ts +5 -0
- package/dist/workspace/tools/mkdir.d.ts.map +1 -0
- package/dist/workspace/tools/read-file.d.ts +8 -0
- package/dist/workspace/tools/read-file.d.ts.map +1 -0
- package/dist/workspace/tools/search.d.ts +7 -0
- package/dist/workspace/tools/search.d.ts.map +1 -0
- package/dist/workspace/tools/tools.d.ts +5 -7
- package/dist/workspace/tools/tools.d.ts.map +1 -1
- package/dist/workspace/tools/tree-formatter.d.ts +2 -0
- package/dist/workspace/tools/tree-formatter.d.ts.map +1 -1
- package/dist/workspace/tools/write-file.d.ts +6 -0
- package/dist/workspace/tools/write-file.d.ts.map +1 -0
- package/dist/workspace/workspace.d.ts +56 -10
- package/dist/workspace/workspace.d.ts.map +1 -1
- package/harness.d.ts +1 -0
- package/package.json +8 -6
- package/src/llm/model/provider-types.generated.d.ts +312 -93
- package/dist/chunk-3JVFFAJX.cjs.map +0 -1
- package/dist/chunk-3X3CZUXI.js.map +0 -1
- package/dist/chunk-4EHGOATH.js.map +0 -1
- package/dist/chunk-4IJ4UDZX.cjs.map +0 -1
- package/dist/chunk-4KFEMXTV.cjs.map +0 -1
- package/dist/chunk-4TQ4EBYX.js.map +0 -1
- package/dist/chunk-4XSAZPPS.js.map +0 -1
- package/dist/chunk-65PHUUMF.cjs.map +0 -1
- package/dist/chunk-7NKUSQEV.js.map +0 -1
- package/dist/chunk-7UWHFWST.cjs.map +0 -1
- package/dist/chunk-AXHBJ4GX.js.map +0 -1
- package/dist/chunk-AY6DBRS3.js.map +0 -1
- package/dist/chunk-BP7VYTOP.cjs.map +0 -1
- package/dist/chunk-CYUP7QWT.cjs.map +0 -1
- package/dist/chunk-CZ4NQANZ.cjs.map +0 -1
- package/dist/chunk-NJ7TL3LQ.js.map +0 -1
- package/dist/chunk-NZG2JAKS.cjs.map +0 -1
- package/dist/chunk-PS5ONCXY.js.map +0 -1
- package/dist/chunk-RS6CZXGA.js.map +0 -1
- package/dist/chunk-SU5APAM6.cjs.map +0 -1
- package/dist/chunk-V2MLGA7T.js.map +0 -1
- package/dist/chunk-VTE2OBKS.cjs.map +0 -1
- package/dist/chunk-Y3TQ52UE.js.map +0 -1
- package/dist/chunk-YNNJLLFN.cjs.map +0 -1
- package/dist/chunk-ZATLLPIH.js.map +0 -1
- package/dist/models-dev-FQVUTQ7L.js +0 -3
- package/dist/models-dev-PPIXUUCU.cjs +0 -12
- package/dist/provider-registry-6LZAGQET.cjs +0 -40
- package/dist/provider-registry-QUNT7S55.js +0 -3
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkEAZ6YDCQ_cjs = require('./chunk-EAZ6YDCQ.cjs');
|
|
4
4
|
var chunkRO47SMI7_cjs = require('./chunk-RO47SMI7.cjs');
|
|
5
5
|
var chunk7XAECHYL_cjs = require('./chunk-7XAECHYL.cjs');
|
|
6
|
+
var posixPath = require('path/posix');
|
|
6
7
|
var fs = require('fs');
|
|
7
8
|
var fs2 = require('fs/promises');
|
|
8
9
|
var nodePath = require('path');
|
|
10
|
+
var picomatch = require('picomatch');
|
|
9
11
|
var crypto = require('crypto');
|
|
10
12
|
var matter = require('gray-matter');
|
|
11
13
|
var childProcess = require('child_process');
|
|
@@ -32,8 +34,10 @@ function _interopNamespace(e) {
|
|
|
32
34
|
return Object.freeze(n);
|
|
33
35
|
}
|
|
34
36
|
|
|
37
|
+
var posixPath__default = /*#__PURE__*/_interopDefault(posixPath);
|
|
35
38
|
var fs2__namespace = /*#__PURE__*/_interopNamespace(fs2);
|
|
36
39
|
var nodePath__namespace = /*#__PURE__*/_interopNamespace(nodePath);
|
|
40
|
+
var picomatch__default = /*#__PURE__*/_interopDefault(picomatch);
|
|
37
41
|
var crypto__namespace = /*#__PURE__*/_interopNamespace(crypto);
|
|
38
42
|
var matter__default = /*#__PURE__*/_interopDefault(matter);
|
|
39
43
|
var childProcess__namespace = /*#__PURE__*/_interopNamespace(childProcess);
|
|
@@ -48,6 +52,12 @@ var WorkspaceError = class extends Error {
|
|
|
48
52
|
this.name = "WorkspaceError";
|
|
49
53
|
}
|
|
50
54
|
};
|
|
55
|
+
var WorkspaceNotAvailableError = class extends WorkspaceError {
|
|
56
|
+
constructor() {
|
|
57
|
+
super("Workspace not available. Ensure the agent has a workspace configured.", "NO_WORKSPACE");
|
|
58
|
+
this.name = "WorkspaceNotAvailableError";
|
|
59
|
+
}
|
|
60
|
+
};
|
|
51
61
|
var FilesystemNotAvailableError = class extends WorkspaceError {
|
|
52
62
|
constructor() {
|
|
53
63
|
super("Workspace does not have a filesystem configured", "NO_FILESYSTEM");
|
|
@@ -167,6 +177,7 @@ var CompositeFilesystem = class {
|
|
|
167
177
|
id;
|
|
168
178
|
name = "CompositeFilesystem";
|
|
169
179
|
provider = "composite";
|
|
180
|
+
readOnly;
|
|
170
181
|
status = "ready";
|
|
171
182
|
_mounts;
|
|
172
183
|
constructor(config) {
|
|
@@ -179,6 +190,7 @@ var CompositeFilesystem = class {
|
|
|
179
190
|
if (this._mounts.size === 0) {
|
|
180
191
|
throw new Error("CompositeFilesystem requires at least one mount");
|
|
181
192
|
}
|
|
193
|
+
this.readOnly = [...this._mounts.values()].every((fs5) => fs5.readOnly) || void 0;
|
|
182
194
|
const mountPaths = [...this._mounts.keys()];
|
|
183
195
|
for (const a of mountPaths) {
|
|
184
196
|
for (const b of mountPaths) {
|
|
@@ -196,10 +208,29 @@ var CompositeFilesystem = class {
|
|
|
196
208
|
}
|
|
197
209
|
/**
|
|
198
210
|
* Get the mounts map.
|
|
211
|
+
* Returns a typed map where `get()` preserves the concrete filesystem type per mount path.
|
|
199
212
|
*/
|
|
200
213
|
get mounts() {
|
|
201
214
|
return this._mounts;
|
|
202
215
|
}
|
|
216
|
+
/**
|
|
217
|
+
* Get status and metadata for this composite filesystem.
|
|
218
|
+
* Includes info from each mounted filesystem in `metadata.mounts`.
|
|
219
|
+
*/
|
|
220
|
+
async getInfo() {
|
|
221
|
+
const mounts = {};
|
|
222
|
+
for (const [mountPath, fs5] of this._mounts) {
|
|
223
|
+
mounts[mountPath] = await fs5.getInfo?.() ?? null;
|
|
224
|
+
}
|
|
225
|
+
return {
|
|
226
|
+
id: this.id,
|
|
227
|
+
name: this.name,
|
|
228
|
+
provider: this.provider,
|
|
229
|
+
status: this.status,
|
|
230
|
+
readOnly: this.readOnly,
|
|
231
|
+
metadata: { mounts }
|
|
232
|
+
};
|
|
233
|
+
}
|
|
203
234
|
/**
|
|
204
235
|
* Get the underlying filesystem for a given path.
|
|
205
236
|
* Returns undefined if the path doesn't resolve to any mount.
|
|
@@ -218,7 +249,8 @@ var CompositeFilesystem = class {
|
|
|
218
249
|
}
|
|
219
250
|
normalizePath(path4) {
|
|
220
251
|
if (!path4 || path4 === "/") return "/";
|
|
221
|
-
let n =
|
|
252
|
+
let n = posixPath__default.default.normalize(path4);
|
|
253
|
+
if (!n.startsWith("/")) n = `/${n}`;
|
|
222
254
|
if (n.length > 1 && n.endsWith("/")) n = n.slice(0, -1);
|
|
223
255
|
return n;
|
|
224
256
|
}
|
|
@@ -452,8 +484,7 @@ var CompositeFilesystem = class {
|
|
|
452
484
|
return `- ${mountPath}: ${name} ${access2}`;
|
|
453
485
|
}).join("\n");
|
|
454
486
|
return `Mounted filesystems:
|
|
455
|
-
${mountDescriptions}
|
|
456
|
-
Files written via workspace tools are accessible at the same paths in sandbox commands.`;
|
|
487
|
+
${mountDescriptions}`;
|
|
457
488
|
}
|
|
458
489
|
};
|
|
459
490
|
|
|
@@ -763,6 +794,7 @@ var LocalFilesystem = class extends MastraFilesystem {
|
|
|
763
794
|
status = "pending";
|
|
764
795
|
_basePath;
|
|
765
796
|
_contained;
|
|
797
|
+
_allowedPaths;
|
|
766
798
|
/**
|
|
767
799
|
* The absolute base path on disk where files are stored.
|
|
768
800
|
* Useful for understanding how workspace paths map to disk paths.
|
|
@@ -770,16 +802,51 @@ var LocalFilesystem = class extends MastraFilesystem {
|
|
|
770
802
|
get basePath() {
|
|
771
803
|
return this._basePath;
|
|
772
804
|
}
|
|
805
|
+
/**
|
|
806
|
+
* Current set of additional allowed paths (absolute, resolved).
|
|
807
|
+
* These paths are permitted beyond basePath when containment is enabled.
|
|
808
|
+
*/
|
|
809
|
+
get allowedPaths() {
|
|
810
|
+
return this._allowedPaths;
|
|
811
|
+
}
|
|
812
|
+
/**
|
|
813
|
+
* Update allowed paths. Accepts a direct array or an updater callback
|
|
814
|
+
* receiving the current paths (React setState pattern).
|
|
815
|
+
*
|
|
816
|
+
* @example
|
|
817
|
+
* ```typescript
|
|
818
|
+
* // Set directly
|
|
819
|
+
* fs.setAllowedPaths(['/home/user/.config']);
|
|
820
|
+
*
|
|
821
|
+
* // Update with callback
|
|
822
|
+
* fs.setAllowedPaths(prev => [...prev, '/home/user/.ssh']);
|
|
823
|
+
* ```
|
|
824
|
+
*/
|
|
825
|
+
setAllowedPaths(pathsOrUpdater) {
|
|
826
|
+
const newPaths = typeof pathsOrUpdater === "function" ? pathsOrUpdater(this._allowedPaths) : pathsOrUpdater;
|
|
827
|
+
this._allowedPaths = newPaths.map((p) => nodePath__namespace.resolve(p));
|
|
828
|
+
}
|
|
773
829
|
constructor(options) {
|
|
774
830
|
super({ ...options, name: "LocalFilesystem" });
|
|
775
831
|
this.id = options.id ?? this.generateId();
|
|
776
832
|
this._basePath = nodePath__namespace.resolve(options.basePath);
|
|
777
833
|
this._contained = options.contained ?? true;
|
|
778
834
|
this.readOnly = options.readOnly;
|
|
835
|
+
this._allowedPaths = (options.allowedPaths ?? []).map((p) => nodePath__namespace.resolve(p));
|
|
779
836
|
}
|
|
780
837
|
generateId() {
|
|
781
838
|
return `local-fs-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
782
839
|
}
|
|
840
|
+
/**
|
|
841
|
+
* Check if an absolute path falls within basePath or any allowed path.
|
|
842
|
+
*/
|
|
843
|
+
_isWithinAnyRoot(absolutePath) {
|
|
844
|
+
const roots = [this._basePath, ...this._allowedPaths];
|
|
845
|
+
return roots.some((root) => {
|
|
846
|
+
const relative2 = nodePath__namespace.relative(root, absolutePath);
|
|
847
|
+
return !relative2.startsWith("..") && !nodePath__namespace.isAbsolute(relative2);
|
|
848
|
+
});
|
|
849
|
+
}
|
|
783
850
|
toBuffer(content) {
|
|
784
851
|
if (Buffer.isBuffer(content)) return content;
|
|
785
852
|
if (content instanceof Uint8Array) return Buffer.from(content);
|
|
@@ -791,8 +858,7 @@ var LocalFilesystem = class extends MastraFilesystem {
|
|
|
791
858
|
absolutePath = nodePath__namespace.normalize(inputPath);
|
|
792
859
|
} else if (this._contained && nodePath__namespace.isAbsolute(inputPath)) {
|
|
793
860
|
const normalized = nodePath__namespace.normalize(inputPath);
|
|
794
|
-
|
|
795
|
-
if (!relative2.startsWith("..") && !nodePath__namespace.isAbsolute(relative2)) {
|
|
861
|
+
if (this._isWithinAnyRoot(normalized)) {
|
|
796
862
|
absolutePath = normalized;
|
|
797
863
|
} else {
|
|
798
864
|
const cleanedPath = inputPath.replace(/^\/+/, "");
|
|
@@ -803,8 +869,7 @@ var LocalFilesystem = class extends MastraFilesystem {
|
|
|
803
869
|
absolutePath = nodePath__namespace.resolve(this._basePath, nodePath__namespace.normalize(cleanedPath));
|
|
804
870
|
}
|
|
805
871
|
if (this._contained) {
|
|
806
|
-
|
|
807
|
-
if (relative2.startsWith("..") || nodePath__namespace.isAbsolute(relative2)) {
|
|
872
|
+
if (!this._isWithinAnyRoot(absolutePath)) {
|
|
808
873
|
throw new PermissionError(inputPath, "access");
|
|
809
874
|
}
|
|
810
875
|
}
|
|
@@ -824,14 +889,19 @@ var LocalFilesystem = class extends MastraFilesystem {
|
|
|
824
889
|
*/
|
|
825
890
|
async assertPathContained(absolutePath) {
|
|
826
891
|
if (!this._contained) return;
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
892
|
+
const rootReals = [];
|
|
893
|
+
for (const root of [this._basePath, ...this._allowedPaths]) {
|
|
894
|
+
try {
|
|
895
|
+
rootReals.push(await fs2__namespace.realpath(root));
|
|
896
|
+
} catch (error) {
|
|
897
|
+
if (isEnoentError(error)) {
|
|
898
|
+
continue;
|
|
899
|
+
}
|
|
900
|
+
throw error;
|
|
833
901
|
}
|
|
834
|
-
|
|
902
|
+
}
|
|
903
|
+
if (rootReals.length === 0) {
|
|
904
|
+
throw new DirectoryNotFoundError(this._basePath);
|
|
835
905
|
}
|
|
836
906
|
let targetReal;
|
|
837
907
|
try {
|
|
@@ -858,7 +928,10 @@ var LocalFilesystem = class extends MastraFilesystem {
|
|
|
858
928
|
throw error;
|
|
859
929
|
}
|
|
860
930
|
}
|
|
861
|
-
|
|
931
|
+
const isWithinRoot = rootReals.some(
|
|
932
|
+
(rootReal) => targetReal === rootReal || targetReal.startsWith(rootReal + nodePath__namespace.sep)
|
|
933
|
+
);
|
|
934
|
+
if (!isWithinRoot) {
|
|
862
935
|
throw new PermissionError(absolutePath, "access");
|
|
863
936
|
}
|
|
864
937
|
}
|
|
@@ -1217,15 +1290,17 @@ var LocalFilesystem = class extends MastraFilesystem {
|
|
|
1217
1290
|
error: this.error,
|
|
1218
1291
|
metadata: {
|
|
1219
1292
|
basePath: this.basePath,
|
|
1220
|
-
contained: this._contained
|
|
1293
|
+
contained: this._contained,
|
|
1294
|
+
...this._allowedPaths.length > 0 && { allowedPaths: [...this._allowedPaths] }
|
|
1221
1295
|
}
|
|
1222
1296
|
};
|
|
1223
1297
|
}
|
|
1224
1298
|
getInstructions() {
|
|
1299
|
+
const allowedNote = this._allowedPaths.length > 0 ? ` Additionally, the following paths outside basePath are accessible: ${this._allowedPaths.join(", ")}.` : "";
|
|
1225
1300
|
if (this._contained) {
|
|
1226
|
-
return `Local filesystem at "${this.basePath}". Files at workspace path "/foo" are stored at "${this.basePath}/foo" on disk
|
|
1301
|
+
return `Local filesystem at "${this.basePath}". Files at workspace path "/foo" are stored at "${this.basePath}/foo" on disk.${allowedNote}`;
|
|
1227
1302
|
}
|
|
1228
|
-
return `Local filesystem rooted at "${this.basePath}". Containment is disabled so absolute paths access the real filesystem. Use paths relative to "${this.basePath}" (e.g. "foo/bar.txt") for workspace files. Avoid unnecessary listing "/" as it would traverse the entire host filesystem
|
|
1303
|
+
return `Local filesystem rooted at "${this.basePath}". Containment is disabled so absolute paths access the real filesystem. Use paths relative to "${this.basePath}" (e.g. "foo/bar.txt") for workspace files. Avoid unnecessary listing "/" as it would traverse the entire host filesystem.${allowedNote}`;
|
|
1229
1304
|
}
|
|
1230
1305
|
};
|
|
1231
1306
|
var InMemoryFileReadTracker = class {
|
|
@@ -1268,6 +1343,38 @@ var InMemoryFileReadTracker = class {
|
|
|
1268
1343
|
return normalized.replace(/\/$/, "") || "/";
|
|
1269
1344
|
}
|
|
1270
1345
|
};
|
|
1346
|
+
var GLOB_CHARS = /[*?{}[\]]/;
|
|
1347
|
+
function isGlobPattern(input) {
|
|
1348
|
+
return GLOB_CHARS.test(input);
|
|
1349
|
+
}
|
|
1350
|
+
function extractGlobBase(pattern) {
|
|
1351
|
+
const firstMeta = pattern.search(GLOB_CHARS);
|
|
1352
|
+
if (firstMeta === -1) {
|
|
1353
|
+
return pattern;
|
|
1354
|
+
}
|
|
1355
|
+
const prefix = pattern.slice(0, firstMeta);
|
|
1356
|
+
const lastSlash = prefix.lastIndexOf("/");
|
|
1357
|
+
if (lastSlash <= 0) {
|
|
1358
|
+
return "/";
|
|
1359
|
+
}
|
|
1360
|
+
return prefix.slice(0, lastSlash);
|
|
1361
|
+
}
|
|
1362
|
+
function normalizeForMatch(input) {
|
|
1363
|
+
if (input.startsWith("./")) return input.slice(2);
|
|
1364
|
+
if (input.startsWith("/")) return input.slice(1);
|
|
1365
|
+
return input;
|
|
1366
|
+
}
|
|
1367
|
+
function createGlobMatcher(patterns, options) {
|
|
1368
|
+
const patternArray = (Array.isArray(patterns) ? patterns : [patterns]).map(normalizeForMatch);
|
|
1369
|
+
const matcher = picomatch__default.default(patternArray, {
|
|
1370
|
+
posix: true,
|
|
1371
|
+
dot: options?.dot ?? false
|
|
1372
|
+
});
|
|
1373
|
+
return (path4) => matcher(normalizeForMatch(path4));
|
|
1374
|
+
}
|
|
1375
|
+
function matchGlob(path4, pattern, options) {
|
|
1376
|
+
return createGlobMatcher(pattern, options)(path4);
|
|
1377
|
+
}
|
|
1271
1378
|
|
|
1272
1379
|
// src/workspace/sandbox/errors.ts
|
|
1273
1380
|
var SandboxError = class extends Error {
|
|
@@ -2721,11 +2828,211 @@ var LocalSkillSource = class {
|
|
|
2721
2828
|
const entries = await fs2__namespace.readdir(resolved, { withFileTypes: true });
|
|
2722
2829
|
return entries.map((entry) => ({
|
|
2723
2830
|
name: entry.name,
|
|
2724
|
-
type: entry.isDirectory() ? "directory" : "file"
|
|
2831
|
+
type: entry.isDirectory() ? "directory" : "file",
|
|
2832
|
+
isSymlink: entry.isSymbolicLink() || void 0
|
|
2725
2833
|
}));
|
|
2726
2834
|
}
|
|
2727
2835
|
};
|
|
2728
|
-
|
|
2836
|
+
|
|
2837
|
+
// src/workspace/skills/versioned-skill-source.ts
|
|
2838
|
+
var VersionedSkillSource = class {
|
|
2839
|
+
#tree;
|
|
2840
|
+
#blobStore;
|
|
2841
|
+
#versionCreatedAt;
|
|
2842
|
+
/** Computed set of directory paths from the tree entries */
|
|
2843
|
+
#directories;
|
|
2844
|
+
constructor(tree, blobStore, versionCreatedAt) {
|
|
2845
|
+
this.#tree = tree;
|
|
2846
|
+
this.#blobStore = blobStore;
|
|
2847
|
+
this.#versionCreatedAt = versionCreatedAt;
|
|
2848
|
+
this.#directories = this.#computeDirectories();
|
|
2849
|
+
}
|
|
2850
|
+
/**
|
|
2851
|
+
* Compute all directory paths implied by the file tree.
|
|
2852
|
+
* For a file at "references/api.md", this adds "" (root), "references".
|
|
2853
|
+
*/
|
|
2854
|
+
#computeDirectories() {
|
|
2855
|
+
const dirs = /* @__PURE__ */ new Set();
|
|
2856
|
+
dirs.add("");
|
|
2857
|
+
dirs.add(".");
|
|
2858
|
+
for (const filePath of Object.keys(this.#tree.entries)) {
|
|
2859
|
+
const parts = filePath.split("/");
|
|
2860
|
+
for (let i = 1; i < parts.length; i++) {
|
|
2861
|
+
dirs.add(parts.slice(0, i).join("/"));
|
|
2862
|
+
}
|
|
2863
|
+
}
|
|
2864
|
+
return dirs;
|
|
2865
|
+
}
|
|
2866
|
+
/**
|
|
2867
|
+
* Normalize a path by stripping leading/trailing slashes and dots.
|
|
2868
|
+
*/
|
|
2869
|
+
#normalizePath(path4) {
|
|
2870
|
+
let normalized = path4.replace(/^[./\\]+|[/\\]+$/g, "");
|
|
2871
|
+
if (normalized === "") return "";
|
|
2872
|
+
return normalized;
|
|
2873
|
+
}
|
|
2874
|
+
async exists(path4) {
|
|
2875
|
+
const normalized = this.#normalizePath(path4);
|
|
2876
|
+
if (this.#tree.entries[normalized]) return true;
|
|
2877
|
+
return this.#directories.has(normalized);
|
|
2878
|
+
}
|
|
2879
|
+
async stat(path4) {
|
|
2880
|
+
const normalized = this.#normalizePath(path4);
|
|
2881
|
+
const name = normalized.split("/").pop() || normalized || ".";
|
|
2882
|
+
const entry = this.#tree.entries[normalized];
|
|
2883
|
+
if (entry) {
|
|
2884
|
+
return {
|
|
2885
|
+
name,
|
|
2886
|
+
type: "file",
|
|
2887
|
+
size: entry.size,
|
|
2888
|
+
createdAt: this.#versionCreatedAt,
|
|
2889
|
+
modifiedAt: this.#versionCreatedAt,
|
|
2890
|
+
mimeType: entry.mimeType
|
|
2891
|
+
};
|
|
2892
|
+
}
|
|
2893
|
+
if (this.#directories.has(normalized)) {
|
|
2894
|
+
return {
|
|
2895
|
+
name,
|
|
2896
|
+
type: "directory",
|
|
2897
|
+
size: 0,
|
|
2898
|
+
createdAt: this.#versionCreatedAt,
|
|
2899
|
+
modifiedAt: this.#versionCreatedAt
|
|
2900
|
+
};
|
|
2901
|
+
}
|
|
2902
|
+
throw new Error(`Path not found in skill version tree: ${path4}`);
|
|
2903
|
+
}
|
|
2904
|
+
async readFile(path4) {
|
|
2905
|
+
const normalized = this.#normalizePath(path4);
|
|
2906
|
+
const entry = this.#tree.entries[normalized];
|
|
2907
|
+
if (!entry) {
|
|
2908
|
+
throw new Error(`File not found in skill version tree: ${path4}`);
|
|
2909
|
+
}
|
|
2910
|
+
const blob = await this.#blobStore.get(entry.blobHash);
|
|
2911
|
+
if (!blob) {
|
|
2912
|
+
throw new Error(`Blob not found for hash ${entry.blobHash} (file: ${path4})`);
|
|
2913
|
+
}
|
|
2914
|
+
if (entry.encoding === "base64") {
|
|
2915
|
+
return Buffer.from(blob.content, "base64");
|
|
2916
|
+
}
|
|
2917
|
+
return blob.content;
|
|
2918
|
+
}
|
|
2919
|
+
async readdir(path4) {
|
|
2920
|
+
const normalized = this.#normalizePath(path4);
|
|
2921
|
+
if (!this.#directories.has(normalized)) {
|
|
2922
|
+
throw new Error(`Directory not found in skill version tree: ${path4}`);
|
|
2923
|
+
}
|
|
2924
|
+
const prefix = normalized === "" ? "" : normalized + "/";
|
|
2925
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2926
|
+
const entries = [];
|
|
2927
|
+
for (const filePath of Object.keys(this.#tree.entries)) {
|
|
2928
|
+
if (!filePath.startsWith(prefix)) continue;
|
|
2929
|
+
const remaining = filePath.slice(prefix.length);
|
|
2930
|
+
const nextSegment = remaining.split("/")[0];
|
|
2931
|
+
if (!nextSegment || seen.has(nextSegment)) continue;
|
|
2932
|
+
seen.add(nextSegment);
|
|
2933
|
+
const isDirectory = remaining.includes("/");
|
|
2934
|
+
entries.push({
|
|
2935
|
+
name: nextSegment,
|
|
2936
|
+
type: isDirectory ? "directory" : "file"
|
|
2937
|
+
});
|
|
2938
|
+
}
|
|
2939
|
+
return entries;
|
|
2940
|
+
}
|
|
2941
|
+
};
|
|
2942
|
+
|
|
2943
|
+
// src/workspace/skills/composite-versioned-skill-source.ts
|
|
2944
|
+
var CompositeVersionedSkillSource = class {
|
|
2945
|
+
#sources = /* @__PURE__ */ new Map();
|
|
2946
|
+
#fallback;
|
|
2947
|
+
#fallbackSkills;
|
|
2948
|
+
constructor(entries, blobStore, options) {
|
|
2949
|
+
for (const entry of entries) {
|
|
2950
|
+
this.#sources.set(entry.dirName, new VersionedSkillSource(entry.tree, blobStore, entry.versionCreatedAt));
|
|
2951
|
+
}
|
|
2952
|
+
this.#fallback = options?.fallback;
|
|
2953
|
+
this.#fallbackSkills = new Set(options?.fallbackSkills ?? []);
|
|
2954
|
+
}
|
|
2955
|
+
#normalizePath(path4) {
|
|
2956
|
+
return path4.replace(/^[./\\]+|[/\\]+$/g, "");
|
|
2957
|
+
}
|
|
2958
|
+
/**
|
|
2959
|
+
* Route a path to the correct source.
|
|
2960
|
+
* Returns the source and the remaining path within that source.
|
|
2961
|
+
*/
|
|
2962
|
+
#routePath(path4) {
|
|
2963
|
+
const normalized = this.#normalizePath(path4);
|
|
2964
|
+
if (normalized === "") return null;
|
|
2965
|
+
const segments = normalized.split("/");
|
|
2966
|
+
const skillDir = segments[0];
|
|
2967
|
+
const subPath = segments.slice(1).join("/");
|
|
2968
|
+
if (this.#fallbackSkills.has(skillDir) && this.#fallback) {
|
|
2969
|
+
return { source: this.#fallback, subPath: normalized };
|
|
2970
|
+
}
|
|
2971
|
+
const versionedSource = this.#sources.get(skillDir);
|
|
2972
|
+
if (versionedSource) {
|
|
2973
|
+
return { source: versionedSource, subPath };
|
|
2974
|
+
}
|
|
2975
|
+
if (this.#fallback) {
|
|
2976
|
+
return { source: this.#fallback, subPath: normalized };
|
|
2977
|
+
}
|
|
2978
|
+
return null;
|
|
2979
|
+
}
|
|
2980
|
+
async exists(path4) {
|
|
2981
|
+
const normalized = this.#normalizePath(path4);
|
|
2982
|
+
if (normalized === "") return true;
|
|
2983
|
+
const route = this.#routePath(path4);
|
|
2984
|
+
if (!route) return false;
|
|
2985
|
+
return route.source.exists(route.subPath);
|
|
2986
|
+
}
|
|
2987
|
+
async stat(path4) {
|
|
2988
|
+
const normalized = this.#normalizePath(path4);
|
|
2989
|
+
if (normalized === "") {
|
|
2990
|
+
return {
|
|
2991
|
+
name: ".",
|
|
2992
|
+
type: "directory",
|
|
2993
|
+
size: 0,
|
|
2994
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
2995
|
+
modifiedAt: /* @__PURE__ */ new Date()
|
|
2996
|
+
};
|
|
2997
|
+
}
|
|
2998
|
+
const route = this.#routePath(path4);
|
|
2999
|
+
if (!route) {
|
|
3000
|
+
throw new Error(`Path not found in composite skill source: ${path4}`);
|
|
3001
|
+
}
|
|
3002
|
+
return route.source.stat(route.subPath);
|
|
3003
|
+
}
|
|
3004
|
+
async readFile(path4) {
|
|
3005
|
+
const route = this.#routePath(path4);
|
|
3006
|
+
if (!route) {
|
|
3007
|
+
throw new Error(`File not found in composite skill source: ${path4}`);
|
|
3008
|
+
}
|
|
3009
|
+
return route.source.readFile(route.subPath);
|
|
3010
|
+
}
|
|
3011
|
+
async readdir(path4) {
|
|
3012
|
+
const normalized = this.#normalizePath(path4);
|
|
3013
|
+
if (normalized === "") {
|
|
3014
|
+
const entries = [];
|
|
3015
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3016
|
+
for (const dirName of this.#sources.keys()) {
|
|
3017
|
+
entries.push({ name: dirName, type: "directory" });
|
|
3018
|
+
seen.add(dirName);
|
|
3019
|
+
}
|
|
3020
|
+
for (const dirName of this.#fallbackSkills) {
|
|
3021
|
+
if (!seen.has(dirName)) {
|
|
3022
|
+
entries.push({ name: dirName, type: "directory" });
|
|
3023
|
+
seen.add(dirName);
|
|
3024
|
+
}
|
|
3025
|
+
}
|
|
3026
|
+
return entries;
|
|
3027
|
+
}
|
|
3028
|
+
const route = this.#routePath(path4);
|
|
3029
|
+
if (!route) {
|
|
3030
|
+
throw new Error(`Directory not found in composite skill source: ${path4}`);
|
|
3031
|
+
}
|
|
3032
|
+
return route.source.readdir(route.subPath);
|
|
3033
|
+
}
|
|
3034
|
+
};
|
|
3035
|
+
var WorkspaceSkillsImpl = class _WorkspaceSkillsImpl {
|
|
2729
3036
|
#source;
|
|
2730
3037
|
#skillsResolver;
|
|
2731
3038
|
#searchEngine;
|
|
@@ -2740,6 +3047,13 @@ var WorkspaceSkillsImpl = class {
|
|
|
2740
3047
|
#lastDiscoveryTime = 0;
|
|
2741
3048
|
/** Currently resolved skills paths (used to detect changes) */
|
|
2742
3049
|
#resolvedPaths = [];
|
|
3050
|
+
/** Cached glob-resolved directories and per-pattern resolve timestamps */
|
|
3051
|
+
#globDirCache = /* @__PURE__ */ new Map();
|
|
3052
|
+
#globResolveTimes = /* @__PURE__ */ new Map();
|
|
3053
|
+
static GLOB_RESOLVE_INTERVAL = 5e3;
|
|
3054
|
+
// Re-walk glob dirs every 5s
|
|
3055
|
+
static STALENESS_CHECK_COOLDOWN = 2e3;
|
|
3056
|
+
// Skip staleness check for 2s after discovery
|
|
2743
3057
|
constructor(config) {
|
|
2744
3058
|
this.#source = config.source;
|
|
2745
3059
|
this.#skillsResolver = config.skills;
|
|
@@ -2792,6 +3106,35 @@ var WorkspaceSkillsImpl = class {
|
|
|
2792
3106
|
await this.refresh();
|
|
2793
3107
|
}
|
|
2794
3108
|
}
|
|
3109
|
+
async addSkill(skillPath) {
|
|
3110
|
+
await this.#ensureInitialized();
|
|
3111
|
+
let skillFilePath;
|
|
3112
|
+
let dirName;
|
|
3113
|
+
if (skillPath.endsWith("/SKILL.md") || skillPath === "SKILL.md") {
|
|
3114
|
+
skillFilePath = skillPath;
|
|
3115
|
+
dirName = this.#getParentPath(skillPath).split("/").pop() || "unknown";
|
|
3116
|
+
} else {
|
|
3117
|
+
skillFilePath = this.#joinPath(skillPath, "SKILL.md");
|
|
3118
|
+
dirName = skillPath.split("/").pop() || "unknown";
|
|
3119
|
+
}
|
|
3120
|
+
const source = this.#inferSource(skillPath);
|
|
3121
|
+
const skill = await this.#parseSkillFile(skillFilePath, dirName, source);
|
|
3122
|
+
const existing = this.#skills.get(skill.name);
|
|
3123
|
+
if (existing) {
|
|
3124
|
+
await this.#removeSkillFromIndex(existing);
|
|
3125
|
+
}
|
|
3126
|
+
this.#skills.set(skill.name, skill);
|
|
3127
|
+
await this.#indexSkill(skill);
|
|
3128
|
+
this.#lastDiscoveryTime = Date.now();
|
|
3129
|
+
}
|
|
3130
|
+
async removeSkill(skillName) {
|
|
3131
|
+
await this.#ensureInitialized();
|
|
3132
|
+
const skill = this.#skills.get(skillName);
|
|
3133
|
+
if (!skill) return;
|
|
3134
|
+
await this.#removeSkillFromIndex(skill);
|
|
3135
|
+
this.#skills.delete(skillName);
|
|
3136
|
+
this.#lastDiscoveryTime = Date.now();
|
|
3137
|
+
}
|
|
2795
3138
|
/**
|
|
2796
3139
|
* Resolve skills paths from the resolver (static array or function).
|
|
2797
3140
|
*/
|
|
@@ -2948,19 +3291,82 @@ var WorkspaceSkillsImpl = class {
|
|
|
2948
3291
|
/**
|
|
2949
3292
|
* Discover skills from all skills paths.
|
|
2950
3293
|
* Uses currently resolved paths (must be set before calling).
|
|
3294
|
+
*
|
|
3295
|
+
* Paths can be plain directories (e.g., '/skills') or glob patterns
|
|
3296
|
+
* (e.g., '**\/skills'). Glob patterns resolve to directories that match
|
|
3297
|
+
* the pattern, each of which is then scanned for skills.
|
|
2951
3298
|
*/
|
|
2952
3299
|
async #discoverSkills() {
|
|
3300
|
+
this.#globDirCache.clear();
|
|
3301
|
+
this.#globResolveTimes.clear();
|
|
2953
3302
|
for (const skillsPath of this.#resolvedPaths) {
|
|
2954
3303
|
const source = this.#determineSource(skillsPath);
|
|
2955
|
-
|
|
3304
|
+
if (isGlobPattern(skillsPath)) {
|
|
3305
|
+
const matchingDirs = await this.#resolveGlobToDirectories(skillsPath);
|
|
3306
|
+
this.#globDirCache.set(skillsPath, matchingDirs);
|
|
3307
|
+
this.#globResolveTimes.set(skillsPath, Date.now());
|
|
3308
|
+
for (const dir of matchingDirs) {
|
|
3309
|
+
await this.#discoverSkillsInPath(dir, source);
|
|
3310
|
+
}
|
|
3311
|
+
} else {
|
|
3312
|
+
const isDirect = await this.#discoverDirectSkill(skillsPath, source);
|
|
3313
|
+
if (!isDirect) {
|
|
3314
|
+
await this.#discoverSkillsInPath(skillsPath, source);
|
|
3315
|
+
}
|
|
3316
|
+
}
|
|
2956
3317
|
}
|
|
2957
3318
|
this.#lastDiscoveryTime = Date.now();
|
|
2958
3319
|
}
|
|
3320
|
+
/**
|
|
3321
|
+
* Resolve a glob pattern to a list of matching directories.
|
|
3322
|
+
* Walks from extractGlobBase() and tests each directory against the pattern.
|
|
3323
|
+
*
|
|
3324
|
+
* Note: Broad patterns like `/** /skills` resolve to a walk root of `/`,
|
|
3325
|
+
* scanning the entire workspace tree. This is cached per-pattern with a
|
|
3326
|
+
* TTL (GLOB_RESOLVE_INTERVAL) to limit I/O. For large workspaces, prefer
|
|
3327
|
+
* more specific patterns like `/src/** /skills` to narrow the walk root.
|
|
3328
|
+
*/
|
|
3329
|
+
async #resolveGlobToDirectories(pattern) {
|
|
3330
|
+
const walkRoot = extractGlobBase(pattern);
|
|
3331
|
+
const matcher = createGlobMatcher(pattern, { dot: true });
|
|
3332
|
+
const matchingDirs = [];
|
|
3333
|
+
await this.#walkForDirectories(walkRoot, (dirPath) => {
|
|
3334
|
+
if (matcher(dirPath)) {
|
|
3335
|
+
matchingDirs.push(dirPath);
|
|
3336
|
+
}
|
|
3337
|
+
});
|
|
3338
|
+
return matchingDirs;
|
|
3339
|
+
}
|
|
3340
|
+
/**
|
|
3341
|
+
* Walk a directory tree and call callback for each directory found.
|
|
3342
|
+
*/
|
|
3343
|
+
async #walkForDirectories(basePath, callback, depth = 0, maxDepth = 4) {
|
|
3344
|
+
if (depth >= maxDepth) return;
|
|
3345
|
+
try {
|
|
3346
|
+
const entries = await this.#source.readdir(basePath);
|
|
3347
|
+
for (const entry of entries) {
|
|
3348
|
+
if (entry.type !== "directory" || entry.isSymlink) continue;
|
|
3349
|
+
const entryPath = basePath === "/" ? `/${entry.name}` : `${basePath}/${entry.name}`;
|
|
3350
|
+
callback(entryPath);
|
|
3351
|
+
await this.#walkForDirectories(entryPath, callback, depth + 1, maxDepth);
|
|
3352
|
+
}
|
|
3353
|
+
} catch {
|
|
3354
|
+
}
|
|
3355
|
+
}
|
|
2959
3356
|
/**
|
|
2960
3357
|
* Discover skills in a single path
|
|
2961
3358
|
*/
|
|
2962
3359
|
async #discoverSkillsInPath(skillsPath, source) {
|
|
2963
|
-
|
|
3360
|
+
try {
|
|
3361
|
+
if (!await this.#source.exists(skillsPath)) {
|
|
3362
|
+
return;
|
|
3363
|
+
}
|
|
3364
|
+
} catch (error) {
|
|
3365
|
+
if (error instanceof Error) {
|
|
3366
|
+
console.warn(`[WorkspaceSkills] Cannot access skills path "${skillsPath}": ${error.message}`);
|
|
3367
|
+
} else {
|
|
3368
|
+
console.warn(`[WorkspaceSkills] Cannot access skills path "${skillsPath}": ${String(error)}`);
|
|
3369
|
+
}
|
|
2964
3370
|
return;
|
|
2965
3371
|
}
|
|
2966
3372
|
try {
|
|
@@ -2987,35 +3393,107 @@ var WorkspaceSkillsImpl = class {
|
|
|
2987
3393
|
}
|
|
2988
3394
|
}
|
|
2989
3395
|
}
|
|
3396
|
+
/**
|
|
3397
|
+
* Attempt to discover a skill from a direct path reference.
|
|
3398
|
+
*
|
|
3399
|
+
* Handles two cases:
|
|
3400
|
+
* - Path ends with `/SKILL.md` → parse directly, extract dirName from parent
|
|
3401
|
+
* - Path is a directory containing `SKILL.md` → parse it as a single skill
|
|
3402
|
+
*
|
|
3403
|
+
* Returns `true` if the path was a direct skill reference (skip subdirectory scan),
|
|
3404
|
+
* `false` to fall through to the normal subdirectory scan.
|
|
3405
|
+
*/
|
|
3406
|
+
async #discoverDirectSkill(skillsPath, source) {
|
|
3407
|
+
try {
|
|
3408
|
+
if (skillsPath.endsWith("/SKILL.md") || skillsPath === "SKILL.md") {
|
|
3409
|
+
if (!await this.#source.exists(skillsPath)) {
|
|
3410
|
+
return true;
|
|
3411
|
+
}
|
|
3412
|
+
const skillDir = this.#getParentPath(skillsPath);
|
|
3413
|
+
const dirName = skillDir.split("/").pop() || skillDir;
|
|
3414
|
+
try {
|
|
3415
|
+
const skill = await this.#parseSkillFile(skillsPath, dirName, source);
|
|
3416
|
+
this.#skills.set(skill.name, skill);
|
|
3417
|
+
await this.#indexSkill(skill);
|
|
3418
|
+
} catch (error) {
|
|
3419
|
+
if (error instanceof Error) {
|
|
3420
|
+
console.error(`[WorkspaceSkills] Failed to load skill from ${skillsPath}:`, error.message);
|
|
3421
|
+
}
|
|
3422
|
+
}
|
|
3423
|
+
return true;
|
|
3424
|
+
}
|
|
3425
|
+
if (await this.#source.exists(skillsPath)) {
|
|
3426
|
+
const skillFilePath = this.#joinPath(skillsPath, "SKILL.md");
|
|
3427
|
+
if (await this.#source.exists(skillFilePath)) {
|
|
3428
|
+
const dirName = skillsPath.split("/").pop() || skillsPath;
|
|
3429
|
+
try {
|
|
3430
|
+
const skill = await this.#parseSkillFile(skillFilePath, dirName, source);
|
|
3431
|
+
this.#skills.set(skill.name, skill);
|
|
3432
|
+
await this.#indexSkill(skill);
|
|
3433
|
+
} catch (error) {
|
|
3434
|
+
if (error instanceof Error) {
|
|
3435
|
+
console.error(`[WorkspaceSkills] Failed to load skill from ${skillFilePath}:`, error.message);
|
|
3436
|
+
}
|
|
3437
|
+
}
|
|
3438
|
+
return true;
|
|
3439
|
+
}
|
|
3440
|
+
}
|
|
3441
|
+
return false;
|
|
3442
|
+
} catch {
|
|
3443
|
+
return false;
|
|
3444
|
+
}
|
|
3445
|
+
}
|
|
2990
3446
|
/**
|
|
2991
3447
|
* Check if any skills path directory has been modified since last discovery.
|
|
2992
3448
|
* Compares directory mtime to lastDiscoveryTime.
|
|
3449
|
+
* For glob patterns, checks the walk root and expanded directories.
|
|
2993
3450
|
*/
|
|
2994
3451
|
async #isSkillsPathStale() {
|
|
2995
3452
|
if (this.#lastDiscoveryTime === 0) {
|
|
2996
3453
|
return true;
|
|
2997
3454
|
}
|
|
3455
|
+
if (Date.now() - this.#lastDiscoveryTime < _WorkspaceSkillsImpl.STALENESS_CHECK_COOLDOWN) {
|
|
3456
|
+
return false;
|
|
3457
|
+
}
|
|
2998
3458
|
for (const skillsPath of this.#resolvedPaths) {
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
const
|
|
3002
|
-
|
|
3003
|
-
|
|
3459
|
+
let pathsToCheck;
|
|
3460
|
+
if (isGlobPattern(skillsPath)) {
|
|
3461
|
+
const now = Date.now();
|
|
3462
|
+
const lastResolved = this.#globResolveTimes.get(skillsPath) ?? 0;
|
|
3463
|
+
if (now - lastResolved > _WorkspaceSkillsImpl.GLOB_RESOLVE_INTERVAL || !this.#globDirCache.has(skillsPath)) {
|
|
3464
|
+
const dirs = await this.#resolveGlobToDirectories(skillsPath);
|
|
3465
|
+
this.#globDirCache.set(skillsPath, dirs);
|
|
3466
|
+
this.#globResolveTimes.set(skillsPath, now);
|
|
3004
3467
|
}
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3468
|
+
pathsToCheck = this.#globDirCache.get(skillsPath) ?? [];
|
|
3469
|
+
} else {
|
|
3470
|
+
pathsToCheck = [skillsPath];
|
|
3471
|
+
}
|
|
3472
|
+
for (const pathToCheck of pathsToCheck) {
|
|
3473
|
+
try {
|
|
3474
|
+
const stat3 = await this.#source.stat(pathToCheck);
|
|
3475
|
+
const mtime = stat3.modifiedAt.getTime();
|
|
3476
|
+
if (mtime > this.#lastDiscoveryTime) {
|
|
3477
|
+
return true;
|
|
3478
|
+
}
|
|
3479
|
+
if (stat3.type !== "directory") {
|
|
3480
|
+
continue;
|
|
3481
|
+
}
|
|
3482
|
+
const entries = await this.#source.readdir(pathToCheck);
|
|
3483
|
+
for (const entry of entries) {
|
|
3484
|
+
if (entry.type !== "directory") continue;
|
|
3485
|
+
const entryPath = this.#joinPath(pathToCheck, entry.name);
|
|
3486
|
+
try {
|
|
3487
|
+
const entryStat = await this.#source.stat(entryPath);
|
|
3488
|
+
if (entryStat.modifiedAt.getTime() > this.#lastDiscoveryTime) {
|
|
3489
|
+
return true;
|
|
3490
|
+
}
|
|
3491
|
+
} catch {
|
|
3013
3492
|
}
|
|
3014
|
-
} catch {
|
|
3015
3493
|
}
|
|
3494
|
+
} catch {
|
|
3495
|
+
continue;
|
|
3016
3496
|
}
|
|
3017
|
-
} catch {
|
|
3018
|
-
continue;
|
|
3019
3497
|
}
|
|
3020
3498
|
}
|
|
3021
3499
|
return false;
|
|
@@ -3099,7 +3577,7 @@ ${validation.errors.join("\n")}`);
|
|
|
3099
3577
|
const entries = await this.#source.readdir(dirPath);
|
|
3100
3578
|
for (const entry of entries) {
|
|
3101
3579
|
const entryPath = this.#joinPath(dirPath, entry.name);
|
|
3102
|
-
if (entry.type === "directory") {
|
|
3580
|
+
if (entry.type === "directory" && !entry.isSymlink) {
|
|
3103
3581
|
await this.#walkDirectory(basePath, entryPath, callback, depth + 1, maxDepth);
|
|
3104
3582
|
} else {
|
|
3105
3583
|
const relativePath = entryPath.substring(basePath.length + 1);
|
|
@@ -3123,6 +3601,30 @@ ${validation.errors.join("\n")}`);
|
|
|
3123
3601
|
}
|
|
3124
3602
|
return parts.join("\n\n");
|
|
3125
3603
|
}
|
|
3604
|
+
/**
|
|
3605
|
+
* Remove a skill's entries from the search index.
|
|
3606
|
+
*/
|
|
3607
|
+
async #removeSkillFromIndex(skill) {
|
|
3608
|
+
if (!this.#searchEngine?.remove) return;
|
|
3609
|
+
const ids = [`skill:${skill.name}:SKILL.md`, ...skill.references.map((r) => `skill:${skill.name}:${r}`)];
|
|
3610
|
+
for (const id of ids) {
|
|
3611
|
+
try {
|
|
3612
|
+
await this.#searchEngine.remove(id);
|
|
3613
|
+
} catch {
|
|
3614
|
+
}
|
|
3615
|
+
}
|
|
3616
|
+
}
|
|
3617
|
+
/**
|
|
3618
|
+
* Infer the ContentSource for a skill path by matching against resolved paths.
|
|
3619
|
+
*/
|
|
3620
|
+
#inferSource(skillPath) {
|
|
3621
|
+
for (const rp of this.#resolvedPaths) {
|
|
3622
|
+
if (skillPath === rp || skillPath.startsWith(rp + "/")) {
|
|
3623
|
+
return this.#determineSource(rp);
|
|
3624
|
+
}
|
|
3625
|
+
}
|
|
3626
|
+
return this.#determineSource(skillPath);
|
|
3627
|
+
}
|
|
3126
3628
|
/**
|
|
3127
3629
|
* Index a skill for search
|
|
3128
3630
|
*/
|
|
@@ -3232,6 +3734,151 @@ ${validation.errors.join("\n")}`);
|
|
|
3232
3734
|
return lastSlash > 0 ? path4.substring(0, lastSlash) : "/";
|
|
3233
3735
|
}
|
|
3234
3736
|
};
|
|
3737
|
+
function hashContent(content) {
|
|
3738
|
+
if (Buffer.isBuffer(content)) {
|
|
3739
|
+
return crypto.createHash("sha256").update(content).digest("hex");
|
|
3740
|
+
}
|
|
3741
|
+
return crypto.createHash("sha256").update(content, "utf-8").digest("hex");
|
|
3742
|
+
}
|
|
3743
|
+
function detectMimeType(filename) {
|
|
3744
|
+
const ext = filename.slice(filename.lastIndexOf(".")).toLowerCase();
|
|
3745
|
+
const mimeTypes = {
|
|
3746
|
+
".md": "text/markdown",
|
|
3747
|
+
".txt": "text/plain",
|
|
3748
|
+
".json": "application/json",
|
|
3749
|
+
".yaml": "text/yaml",
|
|
3750
|
+
".yml": "text/yaml",
|
|
3751
|
+
".sh": "text/x-shellscript",
|
|
3752
|
+
".py": "text/x-python",
|
|
3753
|
+
".js": "text/javascript",
|
|
3754
|
+
".ts": "text/typescript",
|
|
3755
|
+
".html": "text/html",
|
|
3756
|
+
".css": "text/css",
|
|
3757
|
+
".png": "image/png",
|
|
3758
|
+
".jpg": "image/jpeg",
|
|
3759
|
+
".jpeg": "image/jpeg",
|
|
3760
|
+
".svg": "image/svg+xml"
|
|
3761
|
+
};
|
|
3762
|
+
return mimeTypes[ext];
|
|
3763
|
+
}
|
|
3764
|
+
function isBinaryMimeType(mimeType) {
|
|
3765
|
+
if (!mimeType) return false;
|
|
3766
|
+
if (mimeType.startsWith("text/")) return false;
|
|
3767
|
+
if (mimeType === "application/json") return false;
|
|
3768
|
+
if (mimeType === "image/svg+xml") return false;
|
|
3769
|
+
return true;
|
|
3770
|
+
}
|
|
3771
|
+
async function walkSkillDirectory(source, basePath, currentPath = basePath) {
|
|
3772
|
+
const entries = await source.readdir(currentPath);
|
|
3773
|
+
const files = [];
|
|
3774
|
+
for (const entry of entries) {
|
|
3775
|
+
const entryPath = joinPath(currentPath, entry.name);
|
|
3776
|
+
if (entry.type === "directory") {
|
|
3777
|
+
const subFiles = await walkSkillDirectory(source, basePath, entryPath);
|
|
3778
|
+
files.push(...subFiles);
|
|
3779
|
+
} else {
|
|
3780
|
+
const rawContent = await source.readFile(entryPath);
|
|
3781
|
+
const relativePath = entryPath.substring(basePath.length + 1);
|
|
3782
|
+
const mimeType = detectMimeType(entry.name);
|
|
3783
|
+
const isBinary = isBinaryMimeType(mimeType);
|
|
3784
|
+
if (isBinary) {
|
|
3785
|
+
const buf = Buffer.isBuffer(rawContent) ? rawContent : Buffer.from(rawContent, "utf-8");
|
|
3786
|
+
files.push({ path: relativePath, content: buf, isBinary: true });
|
|
3787
|
+
} else {
|
|
3788
|
+
const content = typeof rawContent === "string" ? rawContent : rawContent.toString("utf-8");
|
|
3789
|
+
files.push({ path: relativePath, content, isBinary: false });
|
|
3790
|
+
}
|
|
3791
|
+
}
|
|
3792
|
+
}
|
|
3793
|
+
return files;
|
|
3794
|
+
}
|
|
3795
|
+
function joinPath(...segments) {
|
|
3796
|
+
return segments.map((seg, i) => {
|
|
3797
|
+
if (i === 0) return seg.replace(/\/+$/, "");
|
|
3798
|
+
return seg.replace(/^\/+|\/+$/g, "");
|
|
3799
|
+
}).filter(Boolean).join("/");
|
|
3800
|
+
}
|
|
3801
|
+
function collectSubdirPaths(allPaths, subdir) {
|
|
3802
|
+
const prefix = subdir + "/";
|
|
3803
|
+
return allPaths.filter((p) => p.startsWith(prefix)).map((p) => p.substring(prefix.length));
|
|
3804
|
+
}
|
|
3805
|
+
async function collectSkillForPublish(source, skillPath) {
|
|
3806
|
+
const files = await walkSkillDirectory(source, skillPath);
|
|
3807
|
+
const treeEntries = {};
|
|
3808
|
+
const blobMap = /* @__PURE__ */ new Map();
|
|
3809
|
+
const now = /* @__PURE__ */ new Date();
|
|
3810
|
+
for (const file of files) {
|
|
3811
|
+
const hash = hashContent(file.content);
|
|
3812
|
+
const mimeType = detectMimeType(file.path);
|
|
3813
|
+
if (file.isBinary) {
|
|
3814
|
+
const buf = Buffer.isBuffer(file.content) ? file.content : Buffer.from(file.content);
|
|
3815
|
+
const size = buf.length;
|
|
3816
|
+
const base64Content = buf.toString("base64");
|
|
3817
|
+
treeEntries[file.path] = {
|
|
3818
|
+
blobHash: hash,
|
|
3819
|
+
size,
|
|
3820
|
+
mimeType,
|
|
3821
|
+
encoding: "base64"
|
|
3822
|
+
};
|
|
3823
|
+
if (!blobMap.has(hash)) {
|
|
3824
|
+
blobMap.set(hash, {
|
|
3825
|
+
hash,
|
|
3826
|
+
content: base64Content,
|
|
3827
|
+
size,
|
|
3828
|
+
mimeType,
|
|
3829
|
+
createdAt: now
|
|
3830
|
+
});
|
|
3831
|
+
}
|
|
3832
|
+
} else {
|
|
3833
|
+
const content = file.content;
|
|
3834
|
+
const size = Buffer.byteLength(content, "utf-8");
|
|
3835
|
+
treeEntries[file.path] = {
|
|
3836
|
+
blobHash: hash,
|
|
3837
|
+
size,
|
|
3838
|
+
mimeType
|
|
3839
|
+
};
|
|
3840
|
+
if (!blobMap.has(hash)) {
|
|
3841
|
+
blobMap.set(hash, {
|
|
3842
|
+
hash,
|
|
3843
|
+
content,
|
|
3844
|
+
size,
|
|
3845
|
+
mimeType,
|
|
3846
|
+
createdAt: now
|
|
3847
|
+
});
|
|
3848
|
+
}
|
|
3849
|
+
}
|
|
3850
|
+
}
|
|
3851
|
+
const tree = { entries: treeEntries };
|
|
3852
|
+
const blobs = Array.from(blobMap.values());
|
|
3853
|
+
const skillMdFile = files.find((f) => f.path === "SKILL.md");
|
|
3854
|
+
if (!skillMdFile) {
|
|
3855
|
+
throw new Error(`SKILL.md not found in ${skillPath}`);
|
|
3856
|
+
}
|
|
3857
|
+
const parsed = matter__default.default(skillMdFile.content);
|
|
3858
|
+
const frontmatter = parsed.data;
|
|
3859
|
+
const instructions = parsed.content.trim();
|
|
3860
|
+
const allPaths = files.map((f) => f.path);
|
|
3861
|
+
const references = collectSubdirPaths(allPaths, "references");
|
|
3862
|
+
const scripts = collectSubdirPaths(allPaths, "scripts");
|
|
3863
|
+
const assets = collectSubdirPaths(allPaths, "assets");
|
|
3864
|
+
const snapshot = {
|
|
3865
|
+
name: frontmatter.name,
|
|
3866
|
+
description: frontmatter.description,
|
|
3867
|
+
instructions,
|
|
3868
|
+
license: frontmatter.license,
|
|
3869
|
+
compatibility: frontmatter.compatibility,
|
|
3870
|
+
metadata: frontmatter.metadata,
|
|
3871
|
+
...references.length > 0 ? { references } : {},
|
|
3872
|
+
...scripts.length > 0 ? { scripts } : {},
|
|
3873
|
+
...assets.length > 0 ? { assets } : {}
|
|
3874
|
+
};
|
|
3875
|
+
return { snapshot, tree, blobs };
|
|
3876
|
+
}
|
|
3877
|
+
async function publishSkillFromSource(source, skillPath, blobStore) {
|
|
3878
|
+
const result = await collectSkillForPublish(source, skillPath);
|
|
3879
|
+
await blobStore.putMany(result.blobs);
|
|
3880
|
+
return result;
|
|
3881
|
+
}
|
|
3235
3882
|
|
|
3236
3883
|
// src/workspace/workspace.ts
|
|
3237
3884
|
var Workspace = class {
|
|
@@ -3316,12 +3963,18 @@ var Workspace = class {
|
|
|
3316
3963
|
}
|
|
3317
3964
|
/**
|
|
3318
3965
|
* The filesystem provider (if configured).
|
|
3966
|
+
*
|
|
3967
|
+
* Returns the concrete type you passed to the constructor.
|
|
3968
|
+
* When `mounts` is used instead of `filesystem`, returns `CompositeFilesystem`
|
|
3969
|
+
* parameterized with the concrete mount types.
|
|
3319
3970
|
*/
|
|
3320
3971
|
get filesystem() {
|
|
3321
3972
|
return this._fs;
|
|
3322
3973
|
}
|
|
3323
3974
|
/**
|
|
3324
3975
|
* The sandbox provider (if configured).
|
|
3976
|
+
*
|
|
3977
|
+
* Returns the concrete type you passed to the constructor.
|
|
3325
3978
|
*/
|
|
3326
3979
|
get sandbox() {
|
|
3327
3980
|
return this._sandbox;
|
|
@@ -3351,7 +4004,7 @@ var Workspace = class {
|
|
|
3351
4004
|
return void 0;
|
|
3352
4005
|
}
|
|
3353
4006
|
if (!this._skills) {
|
|
3354
|
-
const source = this._fs ?? new LocalSkillSource();
|
|
4007
|
+
const source = this._config.skillSource ?? this._fs ?? new LocalSkillSource();
|
|
3355
4008
|
this._skills = new WorkspaceSkillsImpl({
|
|
3356
4009
|
source,
|
|
3357
4010
|
skills: this._config.skills,
|
|
@@ -3429,31 +4082,51 @@ var Workspace = class {
|
|
|
3429
4082
|
/**
|
|
3430
4083
|
* Rebuild the search index from filesystem paths.
|
|
3431
4084
|
* Used internally for auto-indexing on init.
|
|
4085
|
+
*
|
|
4086
|
+
* Paths can be plain directories (e.g., '/docs') or glob patterns
|
|
4087
|
+
* (e.g., '/docs/**\/*.md'). Glob patterns are resolved to a walk root
|
|
4088
|
+
* via extractGlobBase, then files are filtered by the pattern.
|
|
3432
4089
|
*/
|
|
3433
4090
|
async rebuildSearchIndex(paths) {
|
|
3434
4091
|
if (!this._searchEngine || !this._fs || paths.length === 0) {
|
|
3435
4092
|
return;
|
|
3436
4093
|
}
|
|
3437
4094
|
this._searchEngine.clear();
|
|
3438
|
-
for (const
|
|
4095
|
+
for (const pathOrGlob of paths) {
|
|
3439
4096
|
try {
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
4097
|
+
if (isGlobPattern(pathOrGlob)) {
|
|
4098
|
+
const walkRoot = extractGlobBase(pathOrGlob);
|
|
4099
|
+
const matcher = createGlobMatcher(pathOrGlob);
|
|
4100
|
+
const files = await this.getAllFiles(walkRoot);
|
|
4101
|
+
for (const filePath of files) {
|
|
4102
|
+
if (!matcher(filePath)) continue;
|
|
4103
|
+
await this.indexFileForSearch(filePath);
|
|
4104
|
+
}
|
|
4105
|
+
} else {
|
|
4106
|
+
const files = await this.getAllFiles(pathOrGlob);
|
|
4107
|
+
for (const filePath of files) {
|
|
4108
|
+
await this.indexFileForSearch(filePath);
|
|
3449
4109
|
}
|
|
3450
4110
|
}
|
|
3451
4111
|
} catch {
|
|
3452
4112
|
}
|
|
3453
4113
|
}
|
|
3454
4114
|
}
|
|
3455
|
-
|
|
3456
|
-
|
|
4115
|
+
/**
|
|
4116
|
+
* Index a single file for search. Skips files that can't be read as text.
|
|
4117
|
+
*/
|
|
4118
|
+
async indexFileForSearch(filePath) {
|
|
4119
|
+
try {
|
|
4120
|
+
const content = await this._fs.readFile(filePath, { encoding: "utf-8" });
|
|
4121
|
+
await this._searchEngine.index({
|
|
4122
|
+
id: filePath,
|
|
4123
|
+
content
|
|
4124
|
+
});
|
|
4125
|
+
} catch {
|
|
4126
|
+
}
|
|
4127
|
+
}
|
|
4128
|
+
async getAllFiles(dir, depth = 0, maxDepth = 10) {
|
|
4129
|
+
if (!this._fs || depth >= maxDepth) return [];
|
|
3457
4130
|
const files = [];
|
|
3458
4131
|
const entries = await this._fs.readdir(dir);
|
|
3459
4132
|
for (const entry of entries) {
|
|
@@ -3461,7 +4134,7 @@ var Workspace = class {
|
|
|
3461
4134
|
if (entry.type === "file") {
|
|
3462
4135
|
files.push(fullPath);
|
|
3463
4136
|
} else if (entry.type === "directory" && !entry.isSymlink) {
|
|
3464
|
-
files.push(...await this.getAllFiles(fullPath));
|
|
4137
|
+
files.push(...await this.getAllFiles(fullPath, depth + 1, maxDepth));
|
|
3465
4138
|
}
|
|
3466
4139
|
}
|
|
3467
4140
|
return files;
|
|
@@ -3941,7 +4614,10 @@ var LocalSandbox = class extends MastraSandbox {
|
|
|
3941
4614
|
* Status management is handled by the base class.
|
|
3942
4615
|
*/
|
|
3943
4616
|
async start() {
|
|
3944
|
-
this.logger.debug("Starting sandbox", {
|
|
4617
|
+
this.logger.debug("[LocalSandbox] Starting sandbox", {
|
|
4618
|
+
workingDirectory: this._workingDirectory,
|
|
4619
|
+
isolation: this._isolation
|
|
4620
|
+
});
|
|
3945
4621
|
await fs2__namespace.mkdir(this.workingDirectory, { recursive: true });
|
|
3946
4622
|
if (this._isolation === "seatbelt") {
|
|
3947
4623
|
const userProvidedPath = this._nativeSandboxConfig.seatbeltProfilePath;
|
|
@@ -3967,14 +4643,14 @@ var LocalSandbox = class extends MastraSandbox {
|
|
|
3967
4643
|
await fs2__namespace.writeFile(this._seatbeltProfilePath, this._seatbeltProfile, "utf-8");
|
|
3968
4644
|
}
|
|
3969
4645
|
}
|
|
3970
|
-
this.logger.debug("Sandbox started", { workingDirectory: this._workingDirectory });
|
|
4646
|
+
this.logger.debug("[LocalSandbox] Sandbox started", { workingDirectory: this._workingDirectory });
|
|
3971
4647
|
}
|
|
3972
4648
|
/**
|
|
3973
4649
|
* Stop the local sandbox.
|
|
3974
4650
|
* Status management is handled by the base class.
|
|
3975
4651
|
*/
|
|
3976
4652
|
async stop() {
|
|
3977
|
-
this.logger.debug("Stopping sandbox", { workingDirectory: this._workingDirectory });
|
|
4653
|
+
this.logger.debug("[LocalSandbox] Stopping sandbox", { workingDirectory: this._workingDirectory });
|
|
3978
4654
|
}
|
|
3979
4655
|
/**
|
|
3980
4656
|
* Destroy the local sandbox and clean up resources.
|
|
@@ -3982,7 +4658,7 @@ var LocalSandbox = class extends MastraSandbox {
|
|
|
3982
4658
|
* Status management is handled by the base class.
|
|
3983
4659
|
*/
|
|
3984
4660
|
async destroy() {
|
|
3985
|
-
this.logger.debug("Destroying sandbox", { workingDirectory: this._workingDirectory });
|
|
4661
|
+
this.logger.debug("[LocalSandbox] Destroying sandbox", { workingDirectory: this._workingDirectory });
|
|
3986
4662
|
if (this._seatbeltProfilePath && !this._userProvidedProfilePath) {
|
|
3987
4663
|
try {
|
|
3988
4664
|
await fs2__namespace.unlink(this._seatbeltProfilePath);
|
|
@@ -4048,7 +4724,7 @@ var LocalSandbox = class extends MastraSandbox {
|
|
|
4048
4724
|
});
|
|
4049
4725
|
}
|
|
4050
4726
|
async executeCommand(command, args = [], options = {}) {
|
|
4051
|
-
this.logger.debug("Executing command", { command, args, cwd: options.cwd ?? this.workingDirectory });
|
|
4727
|
+
this.logger.debug("[LocalSandbox] Executing command", { command, args, cwd: options.cwd ?? this.workingDirectory });
|
|
4052
4728
|
await this.ensureRunning();
|
|
4053
4729
|
const startTime = Date.now();
|
|
4054
4730
|
const wrapped = this.wrapCommandForIsolation(command, args);
|
|
@@ -4067,7 +4743,7 @@ var LocalSandbox = class extends MastraSandbox {
|
|
|
4067
4743
|
exitCode: result.exitCode,
|
|
4068
4744
|
executionTimeMs: Date.now() - startTime
|
|
4069
4745
|
};
|
|
4070
|
-
this.logger.
|
|
4746
|
+
this.logger.debug("[LocalSandbox] Command completed", {
|
|
4071
4747
|
command,
|
|
4072
4748
|
exitCode: commandResult.exitCode,
|
|
4073
4749
|
executionTimeMs: commandResult.executionTimeMs
|
|
@@ -4075,7 +4751,7 @@ var LocalSandbox = class extends MastraSandbox {
|
|
|
4075
4751
|
return commandResult;
|
|
4076
4752
|
} catch (error) {
|
|
4077
4753
|
const executionTimeMs = Date.now() - startTime;
|
|
4078
|
-
this.logger.error("Command failed", { command, error, executionTimeMs });
|
|
4754
|
+
this.logger.error("[LocalSandbox] Command failed", { command, error, executionTimeMs });
|
|
4079
4755
|
return {
|
|
4080
4756
|
success: false,
|
|
4081
4757
|
stdout: "",
|
|
@@ -4097,7 +4773,8 @@ var WORKSPACE_TOOLS = {
|
|
|
4097
4773
|
LIST_FILES: `${WORKSPACE_TOOLS_PREFIX}_list_files`,
|
|
4098
4774
|
DELETE: `${WORKSPACE_TOOLS_PREFIX}_delete`,
|
|
4099
4775
|
FILE_STAT: `${WORKSPACE_TOOLS_PREFIX}_file_stat`,
|
|
4100
|
-
MKDIR: `${WORKSPACE_TOOLS_PREFIX}_mkdir
|
|
4776
|
+
MKDIR: `${WORKSPACE_TOOLS_PREFIX}_mkdir`,
|
|
4777
|
+
GREP: `${WORKSPACE_TOOLS_PREFIX}_grep`
|
|
4101
4778
|
},
|
|
4102
4779
|
SANDBOX: {
|
|
4103
4780
|
EXECUTE_COMMAND: `${WORKSPACE_TOOLS_PREFIX}_execute_command`
|
|
@@ -4108,6 +4785,357 @@ var WORKSPACE_TOOLS = {
|
|
|
4108
4785
|
}
|
|
4109
4786
|
};
|
|
4110
4787
|
|
|
4788
|
+
// src/workspace/tools/helpers.ts
|
|
4789
|
+
function requireWorkspace(context) {
|
|
4790
|
+
if (!context?.workspace) {
|
|
4791
|
+
throw new WorkspaceNotAvailableError();
|
|
4792
|
+
}
|
|
4793
|
+
return context.workspace;
|
|
4794
|
+
}
|
|
4795
|
+
function requireFilesystem(context) {
|
|
4796
|
+
const workspace = requireWorkspace(context);
|
|
4797
|
+
if (!workspace.filesystem) {
|
|
4798
|
+
throw new FilesystemNotAvailableError();
|
|
4799
|
+
}
|
|
4800
|
+
return { workspace, filesystem: workspace.filesystem };
|
|
4801
|
+
}
|
|
4802
|
+
function requireSandbox(context) {
|
|
4803
|
+
const workspace = requireWorkspace(context);
|
|
4804
|
+
if (!workspace.sandbox) {
|
|
4805
|
+
throw new SandboxNotAvailableError();
|
|
4806
|
+
}
|
|
4807
|
+
return { workspace, sandbox: workspace.sandbox };
|
|
4808
|
+
}
|
|
4809
|
+
async function emitWorkspaceMetadata(context, toolName) {
|
|
4810
|
+
const workspace = requireWorkspace(context);
|
|
4811
|
+
const info = await workspace.getInfo();
|
|
4812
|
+
const toolCallId = context?.agent?.toolCallId;
|
|
4813
|
+
await context?.writer?.custom({
|
|
4814
|
+
type: "data-workspace-metadata",
|
|
4815
|
+
data: { toolName, toolCallId, ...info }
|
|
4816
|
+
});
|
|
4817
|
+
}
|
|
4818
|
+
|
|
4819
|
+
// src/workspace/tools/delete-file.ts
|
|
4820
|
+
var deleteFileTool = chunkEAZ6YDCQ_cjs.createTool({
|
|
4821
|
+
id: WORKSPACE_TOOLS.FILESYSTEM.DELETE,
|
|
4822
|
+
description: "Delete a file or directory from the workspace filesystem",
|
|
4823
|
+
inputSchema: zod.z.object({
|
|
4824
|
+
path: zod.z.string().describe("The path to the file or directory to delete"),
|
|
4825
|
+
recursive: zod.z.boolean().optional().default(false).describe("If true, delete directories and their contents recursively. Required for non-empty directories.")
|
|
4826
|
+
}),
|
|
4827
|
+
execute: async ({ path: path4, recursive }, context) => {
|
|
4828
|
+
const { filesystem } = requireFilesystem(context);
|
|
4829
|
+
await emitWorkspaceMetadata(context, WORKSPACE_TOOLS.FILESYSTEM.DELETE);
|
|
4830
|
+
if (filesystem.readOnly) {
|
|
4831
|
+
throw new WorkspaceReadOnlyError("delete");
|
|
4832
|
+
}
|
|
4833
|
+
const stat3 = await filesystem.stat(path4);
|
|
4834
|
+
if (stat3.type === "directory") {
|
|
4835
|
+
await filesystem.rmdir(path4, { recursive, force: recursive });
|
|
4836
|
+
} else {
|
|
4837
|
+
await filesystem.deleteFile(path4);
|
|
4838
|
+
}
|
|
4839
|
+
return `Deleted ${path4}`;
|
|
4840
|
+
}
|
|
4841
|
+
});
|
|
4842
|
+
var editFileTool = chunkEAZ6YDCQ_cjs.createTool({
|
|
4843
|
+
id: WORKSPACE_TOOLS.FILESYSTEM.EDIT_FILE,
|
|
4844
|
+
description: `Edit a file by replacing specific text. The old_string must match exactly and be unique in the file.
|
|
4845
|
+
|
|
4846
|
+
Usage:
|
|
4847
|
+
- Read the file first to get the exact text to replace.
|
|
4848
|
+
- By default, ${WORKSPACE_TOOLS.FILESYSTEM.READ_FILE} output includes line number prefixes (e.g., " 1\u2192"). Ensure you preserve the exact indentation as it appears AFTER the arrow. Never include any part of the line number prefix in old_string or new_string.
|
|
4849
|
+
- Include enough surrounding context (multiple lines) to make old_string unique. If it still isn't unique, include more lines.
|
|
4850
|
+
- Use replace_all only when intentionally replacing all occurrences.`,
|
|
4851
|
+
inputSchema: zod.z.object({
|
|
4852
|
+
path: zod.z.string().describe("The path to the file to edit"),
|
|
4853
|
+
old_string: zod.z.string().describe("The exact text to find and replace. Must be unique in the file."),
|
|
4854
|
+
new_string: zod.z.string().describe("The text to replace old_string with"),
|
|
4855
|
+
replace_all: zod.z.boolean().optional().default(false).describe("If true, replace all occurrences. If false (default), old_string must be unique.")
|
|
4856
|
+
}),
|
|
4857
|
+
execute: async ({ path: path4, old_string, new_string, replace_all }, context) => {
|
|
4858
|
+
const { filesystem } = requireFilesystem(context);
|
|
4859
|
+
await emitWorkspaceMetadata(context, WORKSPACE_TOOLS.FILESYSTEM.EDIT_FILE);
|
|
4860
|
+
if (filesystem.readOnly) {
|
|
4861
|
+
throw new WorkspaceReadOnlyError("edit_file");
|
|
4862
|
+
}
|
|
4863
|
+
try {
|
|
4864
|
+
const content = await filesystem.readFile(path4, { encoding: "utf-8" });
|
|
4865
|
+
if (typeof content !== "string") {
|
|
4866
|
+
return `Cannot edit binary files. Use ${WORKSPACE_TOOLS.FILESYSTEM.WRITE_FILE} instead.`;
|
|
4867
|
+
}
|
|
4868
|
+
const result = replaceString(content, old_string, new_string, replace_all);
|
|
4869
|
+
await filesystem.writeFile(path4, result.content, { overwrite: true });
|
|
4870
|
+
return `Replaced ${result.replacements} occurrence${result.replacements !== 1 ? "s" : ""} in ${path4}`;
|
|
4871
|
+
} catch (error) {
|
|
4872
|
+
if (error instanceof StringNotFoundError) {
|
|
4873
|
+
return error.message;
|
|
4874
|
+
}
|
|
4875
|
+
if (error instanceof StringNotUniqueError) {
|
|
4876
|
+
return error.message;
|
|
4877
|
+
}
|
|
4878
|
+
throw error;
|
|
4879
|
+
}
|
|
4880
|
+
}
|
|
4881
|
+
});
|
|
4882
|
+
var executeCommandTool = chunkEAZ6YDCQ_cjs.createTool({
|
|
4883
|
+
id: WORKSPACE_TOOLS.SANDBOX.EXECUTE_COMMAND,
|
|
4884
|
+
description: `Execute a shell command in the workspace sandbox.
|
|
4885
|
+
|
|
4886
|
+
Usage:
|
|
4887
|
+
- Verify parent directories exist before running commands that create files or directories.
|
|
4888
|
+
- Always quote file paths that contain spaces (e.g., cd "/path/with spaces").
|
|
4889
|
+
- Use the timeout parameter to limit execution time. Behavior when omitted depends on the sandbox provider.
|
|
4890
|
+
- Optionally use cwd to override the working directory. Commands run from the sandbox default if omitted.`,
|
|
4891
|
+
inputSchema: zod.z.object({
|
|
4892
|
+
command: zod.z.string().describe('The command to execute (e.g., "ls", "npm", "python")'),
|
|
4893
|
+
args: zod.z.array(zod.z.string()).nullish().default([]).describe("Arguments to pass to the command"),
|
|
4894
|
+
timeout: zod.z.number().nullish().describe("Maximum execution time in milliseconds. Example: 60000 for 1 minute."),
|
|
4895
|
+
cwd: zod.z.string().nullish().describe("Working directory for the command")
|
|
4896
|
+
}),
|
|
4897
|
+
execute: async ({ command, args, timeout, cwd }, context) => {
|
|
4898
|
+
const { sandbox } = requireSandbox(context);
|
|
4899
|
+
if (!sandbox.executeCommand) {
|
|
4900
|
+
throw new SandboxFeatureNotSupportedError("executeCommand");
|
|
4901
|
+
}
|
|
4902
|
+
await emitWorkspaceMetadata(context, WORKSPACE_TOOLS.SANDBOX.EXECUTE_COMMAND);
|
|
4903
|
+
const toolCallId = context?.agent?.toolCallId;
|
|
4904
|
+
const startedAt = Date.now();
|
|
4905
|
+
let stdout = "";
|
|
4906
|
+
let stderr = "";
|
|
4907
|
+
try {
|
|
4908
|
+
const result = await sandbox.executeCommand(command, args ?? [], {
|
|
4909
|
+
timeout: timeout ?? void 0,
|
|
4910
|
+
cwd: cwd ?? void 0,
|
|
4911
|
+
onStdout: async (data) => {
|
|
4912
|
+
stdout += data;
|
|
4913
|
+
await context?.writer?.custom({
|
|
4914
|
+
type: "data-sandbox-stdout",
|
|
4915
|
+
data: { output: data, timestamp: Date.now(), toolCallId }
|
|
4916
|
+
});
|
|
4917
|
+
},
|
|
4918
|
+
onStderr: async (data) => {
|
|
4919
|
+
stderr += data;
|
|
4920
|
+
await context?.writer?.custom({
|
|
4921
|
+
type: "data-sandbox-stderr",
|
|
4922
|
+
data: { output: data, timestamp: Date.now(), toolCallId }
|
|
4923
|
+
});
|
|
4924
|
+
}
|
|
4925
|
+
});
|
|
4926
|
+
await context?.writer?.custom({
|
|
4927
|
+
type: "data-sandbox-exit",
|
|
4928
|
+
data: {
|
|
4929
|
+
exitCode: result.exitCode,
|
|
4930
|
+
success: result.success,
|
|
4931
|
+
executionTimeMs: result.executionTimeMs,
|
|
4932
|
+
toolCallId
|
|
4933
|
+
}
|
|
4934
|
+
});
|
|
4935
|
+
if (!result.success) {
|
|
4936
|
+
const parts = [result.stdout, result.stderr].filter(Boolean);
|
|
4937
|
+
parts.push(`Exit code: ${result.exitCode}`);
|
|
4938
|
+
return parts.join("\n");
|
|
4939
|
+
}
|
|
4940
|
+
return result.stdout || "(no output)";
|
|
4941
|
+
} catch (error) {
|
|
4942
|
+
await context?.writer?.custom({
|
|
4943
|
+
type: "data-sandbox-exit",
|
|
4944
|
+
data: {
|
|
4945
|
+
exitCode: -1,
|
|
4946
|
+
success: false,
|
|
4947
|
+
executionTimeMs: Date.now() - startedAt,
|
|
4948
|
+
toolCallId
|
|
4949
|
+
}
|
|
4950
|
+
});
|
|
4951
|
+
const parts = [stdout, stderr].filter(Boolean);
|
|
4952
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
4953
|
+
parts.push(`Error: ${errorMessage}`);
|
|
4954
|
+
return parts.join("\n");
|
|
4955
|
+
}
|
|
4956
|
+
}
|
|
4957
|
+
});
|
|
4958
|
+
var fileStatTool = chunkEAZ6YDCQ_cjs.createTool({
|
|
4959
|
+
id: WORKSPACE_TOOLS.FILESYSTEM.FILE_STAT,
|
|
4960
|
+
description: "Get file or directory metadata from the workspace. Returns existence, type, size, and modification time.",
|
|
4961
|
+
inputSchema: zod.z.object({
|
|
4962
|
+
path: zod.z.string().describe("The path to check")
|
|
4963
|
+
}),
|
|
4964
|
+
execute: async ({ path: path4 }, context) => {
|
|
4965
|
+
const { filesystem } = requireFilesystem(context);
|
|
4966
|
+
await emitWorkspaceMetadata(context, WORKSPACE_TOOLS.FILESYSTEM.FILE_STAT);
|
|
4967
|
+
try {
|
|
4968
|
+
const stat3 = await filesystem.stat(path4);
|
|
4969
|
+
const modifiedAt = stat3.modifiedAt.toISOString();
|
|
4970
|
+
const parts = [`${path4}`, `Type: ${stat3.type}`];
|
|
4971
|
+
if (stat3.size !== void 0) parts.push(`Size: ${stat3.size} bytes`);
|
|
4972
|
+
parts.push(`Modified: ${modifiedAt}`);
|
|
4973
|
+
return parts.join(" ");
|
|
4974
|
+
} catch (error) {
|
|
4975
|
+
if (error instanceof FileNotFoundError) {
|
|
4976
|
+
return `${path4}: not found`;
|
|
4977
|
+
}
|
|
4978
|
+
throw error;
|
|
4979
|
+
}
|
|
4980
|
+
}
|
|
4981
|
+
});
|
|
4982
|
+
var grepTool = chunkEAZ6YDCQ_cjs.createTool({
|
|
4983
|
+
id: WORKSPACE_TOOLS.FILESYSTEM.GREP,
|
|
4984
|
+
description: `Search file contents using a regex pattern. Walks the filesystem and returns matching lines with file paths and line numbers.
|
|
4985
|
+
|
|
4986
|
+
Usage:
|
|
4987
|
+
- Basic search: { pattern: "TODO" }
|
|
4988
|
+
- Regex: { pattern: "function\\s+\\w+\\(" }
|
|
4989
|
+
- Multiple terms: { pattern: "TODO|FIXME|HACK" }
|
|
4990
|
+
- Case-insensitive: { pattern: "error", caseSensitive: false }
|
|
4991
|
+
- Search in directory: { pattern: "import", path: "./src" }
|
|
4992
|
+
- Filter by glob: { pattern: "import", path: "**/*.ts" }
|
|
4993
|
+
- Combined path + glob: { pattern: "import", path: "src/**/*.ts" }
|
|
4994
|
+
- Multiple file types: { pattern: "import", path: "**/*.{ts,tsx,js}" }
|
|
4995
|
+
- Multiple directories: { pattern: "TODO", path: "{src,lib}/**/*.ts" }
|
|
4996
|
+
- With context: { pattern: "function", contextLines: 2 }`,
|
|
4997
|
+
inputSchema: zod.z.object({
|
|
4998
|
+
pattern: zod.z.string().describe("Regex pattern to search for"),
|
|
4999
|
+
path: zod.z.string().optional().default("./").describe(
|
|
5000
|
+
'File, directory, or glob pattern to search within (default: "./"). A plain path searches that file or directory. A glob pattern (e.g., "**/*.ts", "src/**/*.test.ts") filters which files to search.'
|
|
5001
|
+
),
|
|
5002
|
+
contextLines: zod.z.number().optional().default(0).describe("Number of lines of context to include before and after each match (default: 0)"),
|
|
5003
|
+
maxCount: zod.z.number().optional().describe(
|
|
5004
|
+
"Maximum matches per file. Moves on to the next file after this many matches. Similar to grep -m flag."
|
|
5005
|
+
),
|
|
5006
|
+
caseSensitive: zod.z.boolean().optional().default(true).describe("Whether the search is case-sensitive (default: true)"),
|
|
5007
|
+
includeHidden: zod.z.boolean().optional().default(false).describe('Include hidden files and directories (names starting with ".") in the search (default: false)')
|
|
5008
|
+
}),
|
|
5009
|
+
execute: async ({ pattern, path: inputPath = "./", contextLines = 0, maxCount, caseSensitive = true, includeHidden = false }, context) => {
|
|
5010
|
+
const { filesystem } = requireFilesystem(context);
|
|
5011
|
+
await emitWorkspaceMetadata(context, WORKSPACE_TOOLS.FILESYSTEM.GREP);
|
|
5012
|
+
const MAX_PATTERN_LENGTH = 1e3;
|
|
5013
|
+
if (pattern.length > MAX_PATTERN_LENGTH) {
|
|
5014
|
+
return `Error: Pattern too long (${pattern.length} chars, max ${MAX_PATTERN_LENGTH}). Use a shorter pattern.`;
|
|
5015
|
+
}
|
|
5016
|
+
let regex;
|
|
5017
|
+
try {
|
|
5018
|
+
regex = new RegExp(pattern, caseSensitive ? "g" : "gi");
|
|
5019
|
+
} catch (e) {
|
|
5020
|
+
return `Error: Invalid regex pattern: ${e.message}`;
|
|
5021
|
+
}
|
|
5022
|
+
let searchPath;
|
|
5023
|
+
let globMatcher;
|
|
5024
|
+
if (isGlobPattern(inputPath)) {
|
|
5025
|
+
searchPath = extractGlobBase(inputPath);
|
|
5026
|
+
globMatcher = createGlobMatcher(inputPath, { dot: includeHidden });
|
|
5027
|
+
} else {
|
|
5028
|
+
searchPath = inputPath;
|
|
5029
|
+
}
|
|
5030
|
+
let filePaths;
|
|
5031
|
+
try {
|
|
5032
|
+
const stat3 = await filesystem.stat(searchPath);
|
|
5033
|
+
if (stat3.type === "file") {
|
|
5034
|
+
filePaths = isTextFile(searchPath) ? [searchPath] : [];
|
|
5035
|
+
} else {
|
|
5036
|
+
const collectFiles = async (dir) => {
|
|
5037
|
+
const files = [];
|
|
5038
|
+
let entries;
|
|
5039
|
+
try {
|
|
5040
|
+
entries = await filesystem.readdir(dir);
|
|
5041
|
+
} catch {
|
|
5042
|
+
return files;
|
|
5043
|
+
}
|
|
5044
|
+
for (const entry of entries) {
|
|
5045
|
+
if (!includeHidden && entry.name.startsWith(".")) continue;
|
|
5046
|
+
const fullPath = dir.endsWith("/") ? `${dir}${entry.name}` : `${dir}/${entry.name}`;
|
|
5047
|
+
if (entry.type === "file") {
|
|
5048
|
+
if (!isTextFile(entry.name)) continue;
|
|
5049
|
+
if (globMatcher && !globMatcher(fullPath)) continue;
|
|
5050
|
+
files.push(fullPath);
|
|
5051
|
+
} else if (entry.type === "directory" && !entry.isSymlink) {
|
|
5052
|
+
files.push(...await collectFiles(fullPath));
|
|
5053
|
+
}
|
|
5054
|
+
}
|
|
5055
|
+
return files;
|
|
5056
|
+
};
|
|
5057
|
+
filePaths = await collectFiles(searchPath);
|
|
5058
|
+
}
|
|
5059
|
+
} catch {
|
|
5060
|
+
filePaths = [];
|
|
5061
|
+
}
|
|
5062
|
+
const outputLines = [];
|
|
5063
|
+
const filesWithMatches = /* @__PURE__ */ new Set();
|
|
5064
|
+
let totalMatchCount = 0;
|
|
5065
|
+
let truncated = false;
|
|
5066
|
+
const MAX_LINE_LENGTH = 500;
|
|
5067
|
+
const GLOBAL_CAP = 1e3;
|
|
5068
|
+
for (const filePath of filePaths) {
|
|
5069
|
+
if (truncated) break;
|
|
5070
|
+
let content;
|
|
5071
|
+
try {
|
|
5072
|
+
const raw = await filesystem.readFile(filePath, { encoding: "utf-8" });
|
|
5073
|
+
if (typeof raw !== "string") continue;
|
|
5074
|
+
content = raw;
|
|
5075
|
+
} catch {
|
|
5076
|
+
continue;
|
|
5077
|
+
}
|
|
5078
|
+
const lines = content.split("\n");
|
|
5079
|
+
let fileMatchCount = 0;
|
|
5080
|
+
for (let i = 0; i < lines.length; i++) {
|
|
5081
|
+
const currentLine = lines[i];
|
|
5082
|
+
regex.lastIndex = 0;
|
|
5083
|
+
const lineMatch = regex.exec(currentLine);
|
|
5084
|
+
if (!lineMatch) continue;
|
|
5085
|
+
filesWithMatches.add(filePath);
|
|
5086
|
+
let lineContent = currentLine;
|
|
5087
|
+
if (lineContent.length > MAX_LINE_LENGTH) {
|
|
5088
|
+
lineContent = lineContent.slice(0, MAX_LINE_LENGTH) + "...";
|
|
5089
|
+
}
|
|
5090
|
+
if (contextLines > 0) {
|
|
5091
|
+
const beforeStart = Math.max(0, i - contextLines);
|
|
5092
|
+
for (let b = beforeStart; b < i; b++) {
|
|
5093
|
+
outputLines.push(`${filePath}:${b + 1}- ${lines[b]}`);
|
|
5094
|
+
}
|
|
5095
|
+
}
|
|
5096
|
+
outputLines.push(`${filePath}:${i + 1}:${lineMatch.index + 1}: ${lineContent}`);
|
|
5097
|
+
if (contextLines > 0) {
|
|
5098
|
+
const afterEnd = Math.min(lines.length - 1, i + contextLines);
|
|
5099
|
+
for (let a = i + 1; a <= afterEnd; a++) {
|
|
5100
|
+
outputLines.push(`${filePath}:${a + 1}- ${lines[a]}`);
|
|
5101
|
+
}
|
|
5102
|
+
outputLines.push("--");
|
|
5103
|
+
}
|
|
5104
|
+
totalMatchCount++;
|
|
5105
|
+
fileMatchCount++;
|
|
5106
|
+
if (maxCount !== void 0 && fileMatchCount >= maxCount) break;
|
|
5107
|
+
if (totalMatchCount >= GLOBAL_CAP) {
|
|
5108
|
+
truncated = true;
|
|
5109
|
+
break;
|
|
5110
|
+
}
|
|
5111
|
+
}
|
|
5112
|
+
}
|
|
5113
|
+
outputLines.push("---");
|
|
5114
|
+
const parts = [`${totalMatchCount} match${totalMatchCount !== 1 ? "es" : ""}`];
|
|
5115
|
+
parts.push(`across ${filesWithMatches.size} file${filesWithMatches.size !== 1 ? "s" : ""}`);
|
|
5116
|
+
if (truncated) {
|
|
5117
|
+
parts.push(`(truncated at ${GLOBAL_CAP})`);
|
|
5118
|
+
}
|
|
5119
|
+
outputLines.push(parts.join(" "));
|
|
5120
|
+
return outputLines.join("\n");
|
|
5121
|
+
}
|
|
5122
|
+
});
|
|
5123
|
+
var indexContentTool = chunkEAZ6YDCQ_cjs.createTool({
|
|
5124
|
+
id: WORKSPACE_TOOLS.SEARCH.INDEX,
|
|
5125
|
+
description: "Index content for search. The path becomes the document ID in search results.",
|
|
5126
|
+
inputSchema: zod.z.object({
|
|
5127
|
+
path: zod.z.string().describe("The document ID/path for search results"),
|
|
5128
|
+
content: zod.z.string().describe("The text content to index"),
|
|
5129
|
+
metadata: zod.z.record(zod.z.unknown()).optional().describe("Optional metadata to store with the document")
|
|
5130
|
+
}),
|
|
5131
|
+
execute: async ({ path: path4, content, metadata }, context) => {
|
|
5132
|
+
const workspace = requireWorkspace(context);
|
|
5133
|
+
await emitWorkspaceMetadata(context, WORKSPACE_TOOLS.SEARCH.INDEX);
|
|
5134
|
+
await workspace.index(path4, content, { metadata });
|
|
5135
|
+
return `Indexed ${path4}`;
|
|
5136
|
+
}
|
|
5137
|
+
});
|
|
5138
|
+
|
|
4111
5139
|
// src/workspace/tools/tree-formatter.ts
|
|
4112
5140
|
var BRANCH = "\u251C\u2500\u2500 ";
|
|
4113
5141
|
var LAST_BRANCH = "\u2514\u2500\u2500 ";
|
|
@@ -4119,6 +5147,12 @@ async function formatAsTree(fs5, path4, options) {
|
|
|
4119
5147
|
const dirsOnly = options?.dirsOnly ?? false;
|
|
4120
5148
|
const exclude = options?.exclude;
|
|
4121
5149
|
const extension = options?.extension;
|
|
5150
|
+
const pattern = options?.pattern;
|
|
5151
|
+
let globMatcher;
|
|
5152
|
+
if (pattern) {
|
|
5153
|
+
const patterns = Array.isArray(pattern) ? pattern : [pattern];
|
|
5154
|
+
globMatcher = createGlobMatcher(patterns, { dot: showHidden });
|
|
5155
|
+
}
|
|
4122
5156
|
const lines = ["."];
|
|
4123
5157
|
let dirCount = 0;
|
|
4124
5158
|
let fileCount = 0;
|
|
@@ -4144,7 +5178,7 @@ async function formatAsTree(fs5, path4, options) {
|
|
|
4144
5178
|
if (exclude) {
|
|
4145
5179
|
const patterns = Array.isArray(exclude) ? exclude : [exclude];
|
|
4146
5180
|
filtered = filtered.filter((e) => {
|
|
4147
|
-
return !patterns.some((
|
|
5181
|
+
return !patterns.some((pattern2) => e.name.includes(pattern2));
|
|
4148
5182
|
});
|
|
4149
5183
|
}
|
|
4150
5184
|
if (dirsOnly) {
|
|
@@ -4160,6 +5194,20 @@ async function formatAsTree(fs5, path4, options) {
|
|
|
4160
5194
|
});
|
|
4161
5195
|
});
|
|
4162
5196
|
}
|
|
5197
|
+
if (globMatcher && !dirsOnly) {
|
|
5198
|
+
filtered = filtered.filter((e) => {
|
|
5199
|
+
if (e.type === "directory") return true;
|
|
5200
|
+
const entryPath = currentPath === path4 ? e.name : `${currentPath === "/" ? "" : currentPath}/${e.name}`;
|
|
5201
|
+
let relativePath;
|
|
5202
|
+
if (path4 === "/" || path4 === "") {
|
|
5203
|
+
relativePath = entryPath.startsWith("/") ? entryPath.slice(1) : entryPath;
|
|
5204
|
+
} else {
|
|
5205
|
+
relativePath = entryPath.startsWith(path4 + "/") ? entryPath.slice(path4.length + 1) : entryPath;
|
|
5206
|
+
if (!relativePath) relativePath = entryPath;
|
|
5207
|
+
}
|
|
5208
|
+
return globMatcher(relativePath);
|
|
5209
|
+
});
|
|
5210
|
+
}
|
|
4163
5211
|
filtered.sort((a, b) => {
|
|
4164
5212
|
if (a.type === "directory" && b.type !== "directory") return -1;
|
|
4165
5213
|
if (a.type !== "directory" && b.type === "directory") return 1;
|
|
@@ -4175,7 +5223,7 @@ async function formatAsTree(fs5, path4, options) {
|
|
|
4175
5223
|
if (entry.type === "directory") {
|
|
4176
5224
|
dirCount++;
|
|
4177
5225
|
if (!entry.isSymlink) {
|
|
4178
|
-
const childPath =
|
|
5226
|
+
const childPath = joinPath2(currentPath, entry.name);
|
|
4179
5227
|
await buildTree(childPath, childPrefix, depth + 1);
|
|
4180
5228
|
}
|
|
4181
5229
|
} else {
|
|
@@ -4198,13 +5246,159 @@ async function formatAsTree(fs5, path4, options) {
|
|
|
4198
5246
|
truncated
|
|
4199
5247
|
};
|
|
4200
5248
|
}
|
|
4201
|
-
function
|
|
5249
|
+
function joinPath2(base, name) {
|
|
4202
5250
|
if (base === "/" || base === "") {
|
|
4203
5251
|
return `/${name}`;
|
|
4204
5252
|
}
|
|
4205
5253
|
return `${base}/${name}`;
|
|
4206
5254
|
}
|
|
4207
5255
|
|
|
5256
|
+
// src/workspace/tools/list-files.ts
|
|
5257
|
+
var listFilesTool = chunkEAZ6YDCQ_cjs.createTool({
|
|
5258
|
+
id: WORKSPACE_TOOLS.FILESYSTEM.LIST_FILES,
|
|
5259
|
+
description: `List files and directories in the workspace filesystem.
|
|
5260
|
+
Returns a tree-style view (like the Unix "tree" command) for easy visualization.
|
|
5261
|
+
The output is displayed to the user as a tree-like structure in the tool result.
|
|
5262
|
+
Options mirror common tree command flags for familiarity.
|
|
5263
|
+
|
|
5264
|
+
Examples:
|
|
5265
|
+
- List root: { path: "./" }
|
|
5266
|
+
- Deep listing: { path: "./src", maxDepth: 5 }
|
|
5267
|
+
- Directories only: { path: "./", dirsOnly: true }
|
|
5268
|
+
- Exclude node_modules: { path: "./", exclude: "node_modules" }
|
|
5269
|
+
- Find TypeScript files: { path: "./src", pattern: "**/*.ts" }
|
|
5270
|
+
- Find config files: { path: "./", pattern: "*.config.{js,ts}" }
|
|
5271
|
+
- Multiple patterns: { path: "./", pattern: ["**/*.ts", "**/*.tsx"] }`,
|
|
5272
|
+
inputSchema: zod.z.object({
|
|
5273
|
+
path: zod.z.string().default("./").describe("Directory path to list"),
|
|
5274
|
+
maxDepth: zod.z.number().optional().default(3).describe("Maximum depth to descend (default: 3). Similar to tree -L flag."),
|
|
5275
|
+
showHidden: zod.z.boolean().optional().default(false).describe('Show hidden files starting with "." (default: false). Similar to tree -a flag.'),
|
|
5276
|
+
dirsOnly: zod.z.boolean().optional().default(false).describe("List directories only, no files (default: false). Similar to tree -d flag."),
|
|
5277
|
+
exclude: zod.z.string().optional().describe('Pattern to exclude (e.g., "node_modules"). Similar to tree -I flag.'),
|
|
5278
|
+
extension: zod.z.string().optional().describe('Filter by file extension (e.g., ".ts"). Similar to tree -P flag.'),
|
|
5279
|
+
pattern: zod.z.union([zod.z.string(), zod.z.array(zod.z.string())]).optional().describe(
|
|
5280
|
+
'Glob pattern(s) to filter files. Examples: "**/*.ts", "src/**/*.test.ts", "*.config.{js,ts}". Directories always pass through.'
|
|
5281
|
+
)
|
|
5282
|
+
}),
|
|
5283
|
+
execute: async ({ path: path4 = "./", maxDepth = 3, showHidden, dirsOnly, exclude, extension, pattern }, context) => {
|
|
5284
|
+
const { filesystem } = requireFilesystem(context);
|
|
5285
|
+
await emitWorkspaceMetadata(context, WORKSPACE_TOOLS.FILESYSTEM.LIST_FILES);
|
|
5286
|
+
const result = await formatAsTree(filesystem, path4, {
|
|
5287
|
+
maxDepth,
|
|
5288
|
+
showHidden,
|
|
5289
|
+
dirsOnly,
|
|
5290
|
+
exclude: exclude || void 0,
|
|
5291
|
+
extension: extension || void 0,
|
|
5292
|
+
pattern: pattern || void 0
|
|
5293
|
+
});
|
|
5294
|
+
return `${result.tree}
|
|
5295
|
+
|
|
5296
|
+
${result.summary}`;
|
|
5297
|
+
}
|
|
5298
|
+
});
|
|
5299
|
+
var mkdirTool = chunkEAZ6YDCQ_cjs.createTool({
|
|
5300
|
+
id: WORKSPACE_TOOLS.FILESYSTEM.MKDIR,
|
|
5301
|
+
description: "Create a directory in the workspace filesystem",
|
|
5302
|
+
inputSchema: zod.z.object({
|
|
5303
|
+
path: zod.z.string().describe("The path of the directory to create"),
|
|
5304
|
+
recursive: zod.z.boolean().optional().default(true).describe("Whether to create parent directories if they do not exist")
|
|
5305
|
+
}),
|
|
5306
|
+
execute: async ({ path: path4, recursive }, context) => {
|
|
5307
|
+
const { filesystem } = requireFilesystem(context);
|
|
5308
|
+
await emitWorkspaceMetadata(context, WORKSPACE_TOOLS.FILESYSTEM.MKDIR);
|
|
5309
|
+
if (filesystem.readOnly) {
|
|
5310
|
+
throw new WorkspaceReadOnlyError("mkdir");
|
|
5311
|
+
}
|
|
5312
|
+
await filesystem.mkdir(path4, { recursive });
|
|
5313
|
+
return `Created directory ${path4}`;
|
|
5314
|
+
}
|
|
5315
|
+
});
|
|
5316
|
+
var readFileTool = chunkEAZ6YDCQ_cjs.createTool({
|
|
5317
|
+
id: WORKSPACE_TOOLS.FILESYSTEM.READ_FILE,
|
|
5318
|
+
description: "Read the contents of a file from the workspace filesystem. Use offset/limit parameters to read specific line ranges for large files.",
|
|
5319
|
+
inputSchema: zod.z.object({
|
|
5320
|
+
path: zod.z.string().describe('The path to the file to read (e.g., "/data/config.json")'),
|
|
5321
|
+
encoding: zod.z.enum(["utf-8", "utf8", "base64", "hex", "binary"]).optional().describe("The encoding to use when reading the file. Defaults to utf-8 for text files."),
|
|
5322
|
+
offset: zod.z.number().optional().describe("Line number to start reading from (1-indexed). If omitted, starts from line 1."),
|
|
5323
|
+
limit: zod.z.number().optional().describe("Maximum number of lines to read. If omitted, reads to the end of the file."),
|
|
5324
|
+
showLineNumbers: zod.z.boolean().optional().default(true).describe("Whether to prefix each line with its line number (default: true)")
|
|
5325
|
+
}),
|
|
5326
|
+
execute: async ({ path: path4, encoding, offset, limit, showLineNumbers }, context) => {
|
|
5327
|
+
const { filesystem } = requireFilesystem(context);
|
|
5328
|
+
await emitWorkspaceMetadata(context, WORKSPACE_TOOLS.FILESYSTEM.READ_FILE);
|
|
5329
|
+
const effectiveEncoding = encoding ?? "utf-8";
|
|
5330
|
+
const fullContent = await filesystem.readFile(path4, { encoding: effectiveEncoding });
|
|
5331
|
+
const stat3 = await filesystem.stat(path4);
|
|
5332
|
+
const isTextEncoding = !encoding || encoding === "utf-8" || encoding === "utf8";
|
|
5333
|
+
if (!isTextEncoding) {
|
|
5334
|
+
return `${stat3.path} (${stat3.size} bytes, ${effectiveEncoding})
|
|
5335
|
+
${fullContent}`;
|
|
5336
|
+
}
|
|
5337
|
+
if (typeof fullContent !== "string") {
|
|
5338
|
+
return `${stat3.path} (${stat3.size} bytes, base64)
|
|
5339
|
+
${fullContent.toString("base64")}`;
|
|
5340
|
+
}
|
|
5341
|
+
const hasLineRange = offset !== void 0 || limit !== void 0;
|
|
5342
|
+
const result = extractLinesWithLimit(fullContent, offset, limit);
|
|
5343
|
+
const shouldShowLineNumbers = showLineNumbers !== false;
|
|
5344
|
+
const formattedContent = shouldShowLineNumbers ? formatWithLineNumbers(result.content, result.lines.start) : result.content;
|
|
5345
|
+
let header;
|
|
5346
|
+
if (hasLineRange) {
|
|
5347
|
+
header = `${stat3.path} (lines ${result.lines.start}-${result.lines.end} of ${result.totalLines}, ${stat3.size} bytes)`;
|
|
5348
|
+
} else {
|
|
5349
|
+
header = `${stat3.path} (${stat3.size} bytes)`;
|
|
5350
|
+
}
|
|
5351
|
+
return `${header}
|
|
5352
|
+
${formattedContent}`;
|
|
5353
|
+
}
|
|
5354
|
+
});
|
|
5355
|
+
var searchTool = chunkEAZ6YDCQ_cjs.createTool({
|
|
5356
|
+
id: WORKSPACE_TOOLS.SEARCH.SEARCH,
|
|
5357
|
+
description: "Search indexed content in the workspace. Supports keyword (BM25), semantic (vector), and hybrid search modes.",
|
|
5358
|
+
inputSchema: zod.z.object({
|
|
5359
|
+
query: zod.z.string().describe("The search query string"),
|
|
5360
|
+
topK: zod.z.number().optional().default(5).describe("Maximum number of results to return"),
|
|
5361
|
+
mode: zod.z.enum(["bm25", "vector", "hybrid"]).optional().describe("Search mode: bm25 for keyword search, vector for semantic search, hybrid for both combined"),
|
|
5362
|
+
minScore: zod.z.number().optional().describe("Minimum score threshold (0-1 for normalized scores)")
|
|
5363
|
+
}),
|
|
5364
|
+
execute: async ({ query, topK, mode, minScore }, context) => {
|
|
5365
|
+
const workspace = requireWorkspace(context);
|
|
5366
|
+
await emitWorkspaceMetadata(context, WORKSPACE_TOOLS.SEARCH.SEARCH);
|
|
5367
|
+
const results = await workspace.search(query, {
|
|
5368
|
+
topK,
|
|
5369
|
+
mode,
|
|
5370
|
+
minScore
|
|
5371
|
+
});
|
|
5372
|
+
const effectiveMode = mode ?? (workspace.canHybrid ? "hybrid" : workspace.canVector ? "vector" : "bm25");
|
|
5373
|
+
const lines = results.map((r) => {
|
|
5374
|
+
const lineInfo = r.lineRange ? `:${r.lineRange.start}-${r.lineRange.end}` : "";
|
|
5375
|
+
return `${r.id}${lineInfo}: ${r.content}`;
|
|
5376
|
+
});
|
|
5377
|
+
lines.push("---");
|
|
5378
|
+
lines.push(`${results.length} result${results.length !== 1 ? "s" : ""} (${effectiveMode} search)`);
|
|
5379
|
+
return lines.join("\n");
|
|
5380
|
+
}
|
|
5381
|
+
});
|
|
5382
|
+
var writeFileTool = chunkEAZ6YDCQ_cjs.createTool({
|
|
5383
|
+
id: WORKSPACE_TOOLS.FILESYSTEM.WRITE_FILE,
|
|
5384
|
+
description: "Write content to a file in the workspace filesystem. Creates parent directories if needed.",
|
|
5385
|
+
inputSchema: zod.z.object({
|
|
5386
|
+
path: zod.z.string().describe('The path where to write the file (e.g., "/data/output.txt")'),
|
|
5387
|
+
content: zod.z.string().describe("The content to write to the file"),
|
|
5388
|
+
overwrite: zod.z.boolean().optional().default(true).describe("Whether to overwrite the file if it already exists")
|
|
5389
|
+
}),
|
|
5390
|
+
execute: async ({ path: path4, content, overwrite }, context) => {
|
|
5391
|
+
const { filesystem } = requireFilesystem(context);
|
|
5392
|
+
await emitWorkspaceMetadata(context, WORKSPACE_TOOLS.FILESYSTEM.WRITE_FILE);
|
|
5393
|
+
if (filesystem.readOnly) {
|
|
5394
|
+
throw new WorkspaceReadOnlyError("write_file");
|
|
5395
|
+
}
|
|
5396
|
+
await filesystem.writeFile(path4, content, { overwrite });
|
|
5397
|
+
const size = Buffer.byteLength(content, "utf-8");
|
|
5398
|
+
return `Wrote ${size} bytes to ${path4}`;
|
|
5399
|
+
}
|
|
5400
|
+
});
|
|
5401
|
+
|
|
4208
5402
|
// src/workspace/tools/tools.ts
|
|
4209
5403
|
function resolveToolConfig(toolsConfig, toolName) {
|
|
4210
5404
|
let enabled = true;
|
|
@@ -4232,6 +5426,49 @@ function resolveToolConfig(toolsConfig, toolName) {
|
|
|
4232
5426
|
}
|
|
4233
5427
|
return { enabled, requireApproval, requireReadBeforeWrite };
|
|
4234
5428
|
}
|
|
5429
|
+
function wrapTool(tool, workspace, config) {
|
|
5430
|
+
return {
|
|
5431
|
+
...tool,
|
|
5432
|
+
requireApproval: config.requireApproval,
|
|
5433
|
+
execute: async (input, context = {}) => {
|
|
5434
|
+
const enrichedContext = { ...context, workspace: context?.workspace ?? workspace };
|
|
5435
|
+
return tool.execute(input, enrichedContext);
|
|
5436
|
+
}
|
|
5437
|
+
};
|
|
5438
|
+
}
|
|
5439
|
+
function wrapWithReadTracker(tool, workspace, readTracker, config, mode) {
|
|
5440
|
+
return {
|
|
5441
|
+
...tool,
|
|
5442
|
+
requireApproval: config.requireApproval,
|
|
5443
|
+
execute: async (input, context = {}) => {
|
|
5444
|
+
const enrichedContext = { ...context, workspace: context?.workspace ?? workspace };
|
|
5445
|
+
if (mode === "write" && config.requireReadBeforeWrite) {
|
|
5446
|
+
try {
|
|
5447
|
+
const stat3 = await workspace.filesystem.stat(input.path);
|
|
5448
|
+
const check = readTracker.needsReRead(input.path, stat3.modifiedAt);
|
|
5449
|
+
if (check.needsReRead) {
|
|
5450
|
+
throw new FileReadRequiredError(input.path, check.reason);
|
|
5451
|
+
}
|
|
5452
|
+
} catch (error) {
|
|
5453
|
+
if (!(error instanceof FileNotFoundError)) {
|
|
5454
|
+
throw error;
|
|
5455
|
+
}
|
|
5456
|
+
}
|
|
5457
|
+
}
|
|
5458
|
+
const result = await tool.execute(input, enrichedContext);
|
|
5459
|
+
if (mode === "read") {
|
|
5460
|
+
try {
|
|
5461
|
+
const stat3 = await workspace.filesystem.stat(input.path);
|
|
5462
|
+
readTracker.recordRead(input.path, stat3.modifiedAt);
|
|
5463
|
+
} catch {
|
|
5464
|
+
}
|
|
5465
|
+
} else if (mode === "write") {
|
|
5466
|
+
readTracker.clearReadRecord(input.path);
|
|
5467
|
+
}
|
|
5468
|
+
return result;
|
|
5469
|
+
}
|
|
5470
|
+
};
|
|
5471
|
+
}
|
|
4235
5472
|
function createWorkspaceTools(workspace) {
|
|
4236
5473
|
const tools = {};
|
|
4237
5474
|
const toolsConfig = workspace.getToolsConfig();
|
|
@@ -4242,493 +5479,48 @@ function createWorkspaceTools(workspace) {
|
|
|
4242
5479
|
if (writeFileConfig.requireReadBeforeWrite || editFileConfig.requireReadBeforeWrite) {
|
|
4243
5480
|
readTracker = new InMemoryFileReadTracker();
|
|
4244
5481
|
}
|
|
4245
|
-
|
|
4246
|
-
const
|
|
4247
|
-
if (
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
path: zod.z.string().describe('The path to the file to read (e.g., "/data/config.json")'),
|
|
4254
|
-
encoding: zod.z.enum(["utf-8", "utf8", "base64", "hex", "binary"]).optional().describe("The encoding to use when reading the file. Defaults to utf-8 for text files."),
|
|
4255
|
-
offset: zod.z.number().optional().describe("Line number to start reading from (1-indexed). If omitted, starts from line 1."),
|
|
4256
|
-
limit: zod.z.number().optional().describe("Maximum number of lines to read. If omitted, reads to the end of the file."),
|
|
4257
|
-
showLineNumbers: zod.z.boolean().optional().default(true).describe("Whether to prefix each line with its line number (default: true)")
|
|
4258
|
-
}),
|
|
4259
|
-
outputSchema: zod.z.object({
|
|
4260
|
-
content: zod.z.string().describe("The file contents (with optional line number prefixes)"),
|
|
4261
|
-
size: zod.z.number().describe("The file size in bytes"),
|
|
4262
|
-
path: zod.z.string().describe("The full path to the file"),
|
|
4263
|
-
lines: zod.z.object({
|
|
4264
|
-
start: zod.z.number().describe("First line number returned"),
|
|
4265
|
-
end: zod.z.number().describe("Last line number returned")
|
|
4266
|
-
}).optional().describe("Line range information (when offset/limit used)"),
|
|
4267
|
-
totalLines: zod.z.number().optional().describe("Total number of lines in the file")
|
|
4268
|
-
}),
|
|
4269
|
-
execute: async ({ path: path4, encoding, offset, limit, showLineNumbers }) => {
|
|
4270
|
-
const effectiveEncoding = encoding ?? "utf-8";
|
|
4271
|
-
const fullContent = await workspace.filesystem.readFile(path4, {
|
|
4272
|
-
encoding: effectiveEncoding
|
|
4273
|
-
});
|
|
4274
|
-
const stat3 = await workspace.filesystem.stat(path4);
|
|
4275
|
-
if (readTracker) {
|
|
4276
|
-
readTracker.recordRead(path4, stat3.modifiedAt);
|
|
4277
|
-
}
|
|
4278
|
-
const isTextEncoding = !encoding || encoding === "utf-8" || encoding === "utf8";
|
|
4279
|
-
if (!isTextEncoding) {
|
|
4280
|
-
return {
|
|
4281
|
-
content: fullContent,
|
|
4282
|
-
size: stat3.size,
|
|
4283
|
-
path: stat3.path
|
|
4284
|
-
};
|
|
4285
|
-
}
|
|
4286
|
-
if (typeof fullContent !== "string") {
|
|
4287
|
-
return {
|
|
4288
|
-
content: fullContent.toString("base64"),
|
|
4289
|
-
size: stat3.size,
|
|
4290
|
-
path: stat3.path
|
|
4291
|
-
};
|
|
4292
|
-
}
|
|
4293
|
-
const hasLineRange = offset !== void 0 || limit !== void 0;
|
|
4294
|
-
const result = extractLinesWithLimit(fullContent, offset, limit);
|
|
4295
|
-
const shouldShowLineNumbers = showLineNumbers !== false;
|
|
4296
|
-
const formattedContent = shouldShowLineNumbers ? formatWithLineNumbers(result.content, result.lines.start) : result.content;
|
|
4297
|
-
return {
|
|
4298
|
-
content: formattedContent,
|
|
4299
|
-
size: stat3.size,
|
|
4300
|
-
path: stat3.path,
|
|
4301
|
-
...hasLineRange && {
|
|
4302
|
-
lines: result.lines,
|
|
4303
|
-
totalLines: result.totalLines
|
|
4304
|
-
}
|
|
4305
|
-
};
|
|
4306
|
-
}
|
|
4307
|
-
});
|
|
4308
|
-
}
|
|
4309
|
-
if (!isReadOnly && writeFileConfig.enabled) {
|
|
4310
|
-
tools[WORKSPACE_TOOLS.FILESYSTEM.WRITE_FILE] = chunk7UWHFWST_cjs.createTool({
|
|
4311
|
-
id: WORKSPACE_TOOLS.FILESYSTEM.WRITE_FILE,
|
|
4312
|
-
description: "Write content to a file in the workspace filesystem. Creates parent directories if needed.",
|
|
4313
|
-
requireApproval: writeFileConfig.requireApproval,
|
|
4314
|
-
inputSchema: zod.z.object({
|
|
4315
|
-
path: zod.z.string().describe('The path where to write the file (e.g., "/data/output.txt")'),
|
|
4316
|
-
content: zod.z.string().describe("The content to write to the file"),
|
|
4317
|
-
overwrite: zod.z.boolean().optional().default(true).describe("Whether to overwrite the file if it already exists")
|
|
4318
|
-
}),
|
|
4319
|
-
outputSchema: zod.z.object({
|
|
4320
|
-
success: zod.z.boolean(),
|
|
4321
|
-
path: zod.z.string().describe("The path where the file was written"),
|
|
4322
|
-
size: zod.z.number().describe("The size of the written content in bytes")
|
|
4323
|
-
}),
|
|
4324
|
-
execute: async ({ path: path4, content, overwrite }) => {
|
|
4325
|
-
if (readTracker && writeFileConfig.requireReadBeforeWrite) {
|
|
4326
|
-
try {
|
|
4327
|
-
const stat3 = await workspace.filesystem.stat(path4);
|
|
4328
|
-
const check = readTracker.needsReRead(path4, stat3.modifiedAt);
|
|
4329
|
-
if (check.needsReRead) {
|
|
4330
|
-
throw new FileReadRequiredError(path4, check.reason);
|
|
4331
|
-
}
|
|
4332
|
-
} catch (error) {
|
|
4333
|
-
if (!(error instanceof FileNotFoundError)) {
|
|
4334
|
-
throw error;
|
|
4335
|
-
}
|
|
4336
|
-
}
|
|
4337
|
-
}
|
|
4338
|
-
await workspace.filesystem.writeFile(path4, content, { overwrite });
|
|
4339
|
-
if (readTracker) {
|
|
4340
|
-
readTracker.clearReadRecord(path4);
|
|
4341
|
-
}
|
|
4342
|
-
return {
|
|
4343
|
-
success: true,
|
|
4344
|
-
path: path4,
|
|
4345
|
-
size: Buffer.byteLength(content, "utf-8")
|
|
4346
|
-
};
|
|
4347
|
-
}
|
|
4348
|
-
});
|
|
4349
|
-
}
|
|
4350
|
-
if (!isReadOnly && editFileConfig.enabled) {
|
|
4351
|
-
tools[WORKSPACE_TOOLS.FILESYSTEM.EDIT_FILE] = chunk7UWHFWST_cjs.createTool({
|
|
4352
|
-
id: WORKSPACE_TOOLS.FILESYSTEM.EDIT_FILE,
|
|
4353
|
-
description: `Edit a file by replacing specific text. The old_string must match exactly and be unique in the file.
|
|
4354
|
-
|
|
4355
|
-
Usage:
|
|
4356
|
-
- Read the file first to get the exact text to replace.
|
|
4357
|
-
- By default, ${WORKSPACE_TOOLS.FILESYSTEM.READ_FILE} output includes line number prefixes (e.g., " 1\u2192"). Ensure you preserve the exact indentation as it appears AFTER the arrow. Never include any part of the line number prefix in old_string or new_string.
|
|
4358
|
-
- Include enough surrounding context (multiple lines) to make old_string unique. If it still isn't unique, include more lines.
|
|
4359
|
-
- Use replace_all only when intentionally replacing all occurrences.`,
|
|
4360
|
-
requireApproval: editFileConfig.requireApproval,
|
|
4361
|
-
inputSchema: zod.z.object({
|
|
4362
|
-
path: zod.z.string().describe("The path to the file to edit"),
|
|
4363
|
-
old_string: zod.z.string().describe("The exact text to find and replace. Must be unique in the file."),
|
|
4364
|
-
new_string: zod.z.string().describe("The text to replace old_string with"),
|
|
4365
|
-
replace_all: zod.z.boolean().optional().default(false).describe("If true, replace all occurrences. If false (default), old_string must be unique.")
|
|
4366
|
-
}),
|
|
4367
|
-
outputSchema: zod.z.object({
|
|
4368
|
-
success: zod.z.boolean(),
|
|
4369
|
-
path: zod.z.string().describe("The path to the edited file"),
|
|
4370
|
-
replacements: zod.z.number().describe("Number of replacements made"),
|
|
4371
|
-
error: zod.z.string().optional().describe("Error message if the edit failed")
|
|
4372
|
-
}),
|
|
4373
|
-
execute: async ({ path: path4, old_string, new_string, replace_all }) => {
|
|
4374
|
-
try {
|
|
4375
|
-
if (readTracker && editFileConfig.requireReadBeforeWrite) {
|
|
4376
|
-
const stat3 = await workspace.filesystem.stat(path4);
|
|
4377
|
-
const check = readTracker.needsReRead(path4, stat3.modifiedAt);
|
|
4378
|
-
if (check.needsReRead) {
|
|
4379
|
-
throw new FileReadRequiredError(path4, check.reason);
|
|
4380
|
-
}
|
|
4381
|
-
}
|
|
4382
|
-
const content = await workspace.filesystem.readFile(path4, { encoding: "utf-8" });
|
|
4383
|
-
if (typeof content !== "string") {
|
|
4384
|
-
return {
|
|
4385
|
-
success: false,
|
|
4386
|
-
path: path4,
|
|
4387
|
-
replacements: 0,
|
|
4388
|
-
error: "Cannot edit binary files. Use workspace_write_file instead."
|
|
4389
|
-
};
|
|
4390
|
-
}
|
|
4391
|
-
const result = replaceString(content, old_string, new_string, replace_all);
|
|
4392
|
-
await workspace.filesystem.writeFile(path4, result.content, { overwrite: true });
|
|
4393
|
-
if (readTracker) {
|
|
4394
|
-
readTracker.clearReadRecord(path4);
|
|
4395
|
-
}
|
|
4396
|
-
return {
|
|
4397
|
-
success: true,
|
|
4398
|
-
path: path4,
|
|
4399
|
-
replacements: result.replacements
|
|
4400
|
-
};
|
|
4401
|
-
} catch (error) {
|
|
4402
|
-
if (error instanceof FileReadRequiredError) {
|
|
4403
|
-
throw error;
|
|
4404
|
-
}
|
|
4405
|
-
if (error instanceof StringNotFoundError) {
|
|
4406
|
-
return {
|
|
4407
|
-
success: false,
|
|
4408
|
-
path: path4,
|
|
4409
|
-
replacements: 0,
|
|
4410
|
-
error: error.message
|
|
4411
|
-
};
|
|
4412
|
-
}
|
|
4413
|
-
if (error instanceof StringNotUniqueError) {
|
|
4414
|
-
return {
|
|
4415
|
-
success: false,
|
|
4416
|
-
path: path4,
|
|
4417
|
-
replacements: 0,
|
|
4418
|
-
error: error.message
|
|
4419
|
-
};
|
|
4420
|
-
}
|
|
4421
|
-
throw error;
|
|
4422
|
-
}
|
|
4423
|
-
}
|
|
4424
|
-
});
|
|
4425
|
-
}
|
|
4426
|
-
const listFilesConfig = resolveToolConfig(toolsConfig, WORKSPACE_TOOLS.FILESYSTEM.LIST_FILES);
|
|
4427
|
-
if (listFilesConfig.enabled) {
|
|
4428
|
-
tools[WORKSPACE_TOOLS.FILESYSTEM.LIST_FILES] = chunk7UWHFWST_cjs.createTool({
|
|
4429
|
-
id: WORKSPACE_TOOLS.FILESYSTEM.LIST_FILES,
|
|
4430
|
-
description: `List files and directories in the workspace filesystem.
|
|
4431
|
-
Returns a tree-style view (like the Unix "tree" command) for easy visualization.
|
|
4432
|
-
The output is displayed to the user as a tree-like structure in the tool result.
|
|
4433
|
-
Options mirror common tree command flags for familiarity.
|
|
4434
|
-
|
|
4435
|
-
Examples:
|
|
4436
|
-
- List root: { path: "/" }
|
|
4437
|
-
- Deep listing: { path: "/src", maxDepth: 5 }
|
|
4438
|
-
- Directories only: { path: "/", dirsOnly: true }
|
|
4439
|
-
- Exclude node_modules: { path: "/", exclude: "node_modules" }`,
|
|
4440
|
-
requireApproval: listFilesConfig.requireApproval,
|
|
4441
|
-
inputSchema: zod.z.object({
|
|
4442
|
-
path: zod.z.string().default("/").describe("Directory path to list"),
|
|
4443
|
-
maxDepth: zod.z.number().optional().default(3).describe("Maximum depth to descend (default: 3). Similar to tree -L flag."),
|
|
4444
|
-
showHidden: zod.z.boolean().optional().default(false).describe('Show hidden files starting with "." (default: false). Similar to tree -a flag.'),
|
|
4445
|
-
dirsOnly: zod.z.boolean().optional().default(false).describe("List directories only, no files (default: false). Similar to tree -d flag."),
|
|
4446
|
-
exclude: zod.z.string().optional().describe('Pattern to exclude (e.g., "node_modules"). Similar to tree -I flag.'),
|
|
4447
|
-
extension: zod.z.string().optional().describe('Filter by file extension (e.g., ".ts"). Similar to tree -P flag.')
|
|
4448
|
-
}),
|
|
4449
|
-
outputSchema: zod.z.object({
|
|
4450
|
-
tree: zod.z.string().describe("Tree-style directory listing"),
|
|
4451
|
-
summary: zod.z.string().describe('Summary of directories and files (e.g., "3 directories, 12 files")'),
|
|
4452
|
-
metadata: zod.z.object({
|
|
4453
|
-
workspace: zod.z.object({
|
|
4454
|
-
id: zod.z.string().optional(),
|
|
4455
|
-
name: zod.z.string().optional()
|
|
4456
|
-
}).optional(),
|
|
4457
|
-
filesystem: zod.z.object({
|
|
4458
|
-
id: zod.z.string().optional(),
|
|
4459
|
-
name: zod.z.string().optional(),
|
|
4460
|
-
provider: zod.z.string().optional()
|
|
4461
|
-
}).optional()
|
|
4462
|
-
}).optional().describe("Metadata about the workspace and filesystem")
|
|
4463
|
-
}),
|
|
4464
|
-
execute: async ({ path: path4 = "/", maxDepth = 3, showHidden, dirsOnly, exclude, extension }) => {
|
|
4465
|
-
const result = await formatAsTree(workspace.filesystem, path4, {
|
|
4466
|
-
maxDepth,
|
|
4467
|
-
showHidden,
|
|
4468
|
-
dirsOnly,
|
|
4469
|
-
exclude: exclude || void 0,
|
|
4470
|
-
extension: extension || void 0
|
|
4471
|
-
});
|
|
4472
|
-
const fs5 = workspace.filesystem;
|
|
4473
|
-
const metadata = {
|
|
4474
|
-
workspace: {
|
|
4475
|
-
id: workspace.id,
|
|
4476
|
-
name: workspace.name
|
|
4477
|
-
},
|
|
4478
|
-
filesystem: {
|
|
4479
|
-
id: fs5.id,
|
|
4480
|
-
name: fs5.name,
|
|
4481
|
-
provider: fs5.provider
|
|
4482
|
-
}
|
|
4483
|
-
};
|
|
4484
|
-
return {
|
|
4485
|
-
tree: result.tree,
|
|
4486
|
-
summary: result.summary,
|
|
4487
|
-
metadata
|
|
4488
|
-
};
|
|
4489
|
-
}
|
|
4490
|
-
});
|
|
4491
|
-
}
|
|
4492
|
-
const deleteConfig = resolveToolConfig(toolsConfig, WORKSPACE_TOOLS.FILESYSTEM.DELETE);
|
|
4493
|
-
if (!isReadOnly && deleteConfig.enabled) {
|
|
4494
|
-
tools[WORKSPACE_TOOLS.FILESYSTEM.DELETE] = chunk7UWHFWST_cjs.createTool({
|
|
4495
|
-
id: WORKSPACE_TOOLS.FILESYSTEM.DELETE,
|
|
4496
|
-
description: "Delete a file or directory from the workspace filesystem",
|
|
4497
|
-
requireApproval: deleteConfig.requireApproval,
|
|
4498
|
-
inputSchema: zod.z.object({
|
|
4499
|
-
path: zod.z.string().describe("The path to the file or directory to delete"),
|
|
4500
|
-
recursive: zod.z.boolean().optional().default(false).describe(
|
|
4501
|
-
"If true, delete directories and their contents recursively. Required for non-empty directories."
|
|
4502
|
-
)
|
|
4503
|
-
}),
|
|
4504
|
-
outputSchema: zod.z.object({
|
|
4505
|
-
success: zod.z.boolean(),
|
|
4506
|
-
path: zod.z.string()
|
|
4507
|
-
}),
|
|
4508
|
-
execute: async ({ path: path4, recursive }) => {
|
|
4509
|
-
const stat3 = await workspace.filesystem.stat(path4);
|
|
4510
|
-
if (stat3.type === "directory") {
|
|
4511
|
-
await workspace.filesystem.rmdir(path4, { recursive, force: recursive });
|
|
4512
|
-
} else {
|
|
4513
|
-
await workspace.filesystem.deleteFile(path4);
|
|
4514
|
-
}
|
|
4515
|
-
return { success: true, path: path4 };
|
|
4516
|
-
}
|
|
4517
|
-
});
|
|
4518
|
-
}
|
|
4519
|
-
const fileStatConfig = resolveToolConfig(toolsConfig, WORKSPACE_TOOLS.FILESYSTEM.FILE_STAT);
|
|
4520
|
-
if (fileStatConfig.enabled) {
|
|
4521
|
-
tools[WORKSPACE_TOOLS.FILESYSTEM.FILE_STAT] = chunk7UWHFWST_cjs.createTool({
|
|
4522
|
-
id: WORKSPACE_TOOLS.FILESYSTEM.FILE_STAT,
|
|
4523
|
-
description: "Get file or directory metadata from the workspace. Returns existence, type, size, and modification time.",
|
|
4524
|
-
requireApproval: fileStatConfig.requireApproval,
|
|
4525
|
-
inputSchema: zod.z.object({
|
|
4526
|
-
path: zod.z.string().describe("The path to check")
|
|
4527
|
-
}),
|
|
4528
|
-
outputSchema: zod.z.object({
|
|
4529
|
-
exists: zod.z.boolean().describe("Whether the path exists"),
|
|
4530
|
-
type: zod.z.enum(["file", "directory", "none"]).describe("The type of the path if it exists"),
|
|
4531
|
-
size: zod.z.number().optional().describe("Size in bytes (for files)"),
|
|
4532
|
-
modifiedAt: zod.z.string().optional().describe("Last modification time (ISO string)")
|
|
4533
|
-
}),
|
|
4534
|
-
execute: async ({ path: path4 }) => {
|
|
4535
|
-
try {
|
|
4536
|
-
const stat3 = await workspace.filesystem.stat(path4);
|
|
4537
|
-
return {
|
|
4538
|
-
exists: true,
|
|
4539
|
-
type: stat3.type,
|
|
4540
|
-
size: stat3.size,
|
|
4541
|
-
modifiedAt: stat3.modifiedAt.toISOString()
|
|
4542
|
-
};
|
|
4543
|
-
} catch (error) {
|
|
4544
|
-
if (error instanceof FileNotFoundError) {
|
|
4545
|
-
return { exists: false, type: "none" };
|
|
4546
|
-
}
|
|
4547
|
-
throw error;
|
|
4548
|
-
}
|
|
4549
|
-
}
|
|
4550
|
-
});
|
|
4551
|
-
}
|
|
4552
|
-
const mkdirConfig = resolveToolConfig(toolsConfig, WORKSPACE_TOOLS.FILESYSTEM.MKDIR);
|
|
4553
|
-
if (!isReadOnly && mkdirConfig.enabled) {
|
|
4554
|
-
tools[WORKSPACE_TOOLS.FILESYSTEM.MKDIR] = chunk7UWHFWST_cjs.createTool({
|
|
4555
|
-
id: WORKSPACE_TOOLS.FILESYSTEM.MKDIR,
|
|
4556
|
-
description: "Create a directory in the workspace filesystem",
|
|
4557
|
-
requireApproval: mkdirConfig.requireApproval,
|
|
4558
|
-
inputSchema: zod.z.object({
|
|
4559
|
-
path: zod.z.string().describe("The path of the directory to create"),
|
|
4560
|
-
recursive: zod.z.boolean().optional().default(true).describe("Whether to create parent directories if they do not exist")
|
|
4561
|
-
}),
|
|
4562
|
-
outputSchema: zod.z.object({
|
|
4563
|
-
success: zod.z.boolean(),
|
|
4564
|
-
path: zod.z.string()
|
|
4565
|
-
}),
|
|
4566
|
-
execute: async ({ path: path4, recursive }) => {
|
|
4567
|
-
await workspace.filesystem.mkdir(path4, { recursive });
|
|
4568
|
-
return { success: true, path: path4 };
|
|
4569
|
-
}
|
|
4570
|
-
});
|
|
5482
|
+
const addTool = (name, tool, opts) => {
|
|
5483
|
+
const config = resolveToolConfig(toolsConfig, name);
|
|
5484
|
+
if (!config.enabled) return;
|
|
5485
|
+
if (opts?.requireWrite && isReadOnly) return;
|
|
5486
|
+
if (readTracker && opts?.readTrackerMode) {
|
|
5487
|
+
tools[name] = wrapWithReadTracker(tool, workspace, readTracker, config, opts.readTrackerMode);
|
|
5488
|
+
} else {
|
|
5489
|
+
tools[name] = wrapTool(tool, workspace, config);
|
|
4571
5490
|
}
|
|
5491
|
+
};
|
|
5492
|
+
if (workspace.filesystem) {
|
|
5493
|
+
addTool(WORKSPACE_TOOLS.FILESYSTEM.READ_FILE, readFileTool, { readTrackerMode: "read" });
|
|
5494
|
+
addTool(WORKSPACE_TOOLS.FILESYSTEM.WRITE_FILE, writeFileTool, {
|
|
5495
|
+
requireWrite: true,
|
|
5496
|
+
readTrackerMode: "write"
|
|
5497
|
+
});
|
|
5498
|
+
addTool(WORKSPACE_TOOLS.FILESYSTEM.EDIT_FILE, editFileTool, {
|
|
5499
|
+
requireWrite: true,
|
|
5500
|
+
readTrackerMode: "write"
|
|
5501
|
+
});
|
|
5502
|
+
addTool(WORKSPACE_TOOLS.FILESYSTEM.LIST_FILES, listFilesTool);
|
|
5503
|
+
addTool(WORKSPACE_TOOLS.FILESYSTEM.DELETE, deleteFileTool, { requireWrite: true });
|
|
5504
|
+
addTool(WORKSPACE_TOOLS.FILESYSTEM.FILE_STAT, fileStatTool);
|
|
5505
|
+
addTool(WORKSPACE_TOOLS.FILESYSTEM.MKDIR, mkdirTool, { requireWrite: true });
|
|
5506
|
+
addTool(WORKSPACE_TOOLS.FILESYSTEM.GREP, grepTool);
|
|
4572
5507
|
}
|
|
4573
5508
|
if (workspace.canBM25 || workspace.canVector) {
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
tools[WORKSPACE_TOOLS.SEARCH.SEARCH] = chunk7UWHFWST_cjs.createTool({
|
|
4577
|
-
id: WORKSPACE_TOOLS.SEARCH.SEARCH,
|
|
4578
|
-
description: "Search indexed content in the workspace. Supports keyword (BM25), semantic (vector), and hybrid search modes.",
|
|
4579
|
-
requireApproval: searchConfig.requireApproval,
|
|
4580
|
-
inputSchema: zod.z.object({
|
|
4581
|
-
query: zod.z.string().describe("The search query string"),
|
|
4582
|
-
topK: zod.z.number().optional().default(5).describe("Maximum number of results to return"),
|
|
4583
|
-
mode: zod.z.enum(["bm25", "vector", "hybrid"]).optional().describe("Search mode: bm25 for keyword search, vector for semantic search, hybrid for both combined"),
|
|
4584
|
-
minScore: zod.z.number().optional().describe("Minimum score threshold (0-1 for normalized scores)")
|
|
4585
|
-
}),
|
|
4586
|
-
outputSchema: zod.z.object({
|
|
4587
|
-
results: zod.z.array(
|
|
4588
|
-
zod.z.object({
|
|
4589
|
-
id: zod.z.string().describe("Document/file path"),
|
|
4590
|
-
content: zod.z.string().describe("The matching content"),
|
|
4591
|
-
score: zod.z.number().describe("Relevance score"),
|
|
4592
|
-
lineRange: zod.z.object({
|
|
4593
|
-
start: zod.z.number(),
|
|
4594
|
-
end: zod.z.number()
|
|
4595
|
-
}).optional().describe("Line range where query terms were found")
|
|
4596
|
-
})
|
|
4597
|
-
),
|
|
4598
|
-
count: zod.z.number().describe("Number of results returned"),
|
|
4599
|
-
mode: zod.z.string().describe("The search mode that was used")
|
|
4600
|
-
}),
|
|
4601
|
-
execute: async ({ query, topK, mode, minScore }) => {
|
|
4602
|
-
const results = await workspace.search(query, {
|
|
4603
|
-
topK,
|
|
4604
|
-
mode,
|
|
4605
|
-
minScore
|
|
4606
|
-
});
|
|
4607
|
-
return {
|
|
4608
|
-
results: results.map((r) => ({
|
|
4609
|
-
id: r.id,
|
|
4610
|
-
content: r.content,
|
|
4611
|
-
score: r.score,
|
|
4612
|
-
lineRange: r.lineRange
|
|
4613
|
-
})),
|
|
4614
|
-
count: results.length,
|
|
4615
|
-
mode: mode ?? (workspace.canHybrid ? "hybrid" : workspace.canVector ? "vector" : "bm25")
|
|
4616
|
-
};
|
|
4617
|
-
}
|
|
4618
|
-
});
|
|
4619
|
-
}
|
|
4620
|
-
const indexConfig = resolveToolConfig(toolsConfig, WORKSPACE_TOOLS.SEARCH.INDEX);
|
|
4621
|
-
if (!isReadOnly && indexConfig.enabled) {
|
|
4622
|
-
tools[WORKSPACE_TOOLS.SEARCH.INDEX] = chunk7UWHFWST_cjs.createTool({
|
|
4623
|
-
id: WORKSPACE_TOOLS.SEARCH.INDEX,
|
|
4624
|
-
description: "Index content for search. The path becomes the document ID in search results.",
|
|
4625
|
-
requireApproval: indexConfig.requireApproval,
|
|
4626
|
-
inputSchema: zod.z.object({
|
|
4627
|
-
path: zod.z.string().describe("The document ID/path for search results"),
|
|
4628
|
-
content: zod.z.string().describe("The text content to index"),
|
|
4629
|
-
metadata: zod.z.record(zod.z.unknown()).optional().describe("Optional metadata to store with the document")
|
|
4630
|
-
}),
|
|
4631
|
-
outputSchema: zod.z.object({
|
|
4632
|
-
success: zod.z.boolean(),
|
|
4633
|
-
path: zod.z.string().describe("The indexed document ID")
|
|
4634
|
-
}),
|
|
4635
|
-
execute: async ({ path: path4, content, metadata }) => {
|
|
4636
|
-
await workspace.index(path4, content, { metadata });
|
|
4637
|
-
return { success: true, path: path4 };
|
|
4638
|
-
}
|
|
4639
|
-
});
|
|
4640
|
-
}
|
|
5509
|
+
addTool(WORKSPACE_TOOLS.SEARCH.SEARCH, searchTool);
|
|
5510
|
+
addTool(WORKSPACE_TOOLS.SEARCH.INDEX, indexContentTool, { requireWrite: true });
|
|
4641
5511
|
}
|
|
4642
5512
|
if (workspace.sandbox) {
|
|
4643
|
-
const pathContext = workspace.getPathContext();
|
|
4644
|
-
const pathInfo = pathContext.instructions ? ` ${pathContext.instructions}` : "";
|
|
4645
5513
|
const executeCommandConfig = resolveToolConfig(toolsConfig, WORKSPACE_TOOLS.SANDBOX.EXECUTE_COMMAND);
|
|
4646
5514
|
if (workspace.sandbox.executeCommand && executeCommandConfig.enabled) {
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
description: `Execute a shell command in the workspace sandbox.${pathInfo}
|
|
5515
|
+
const pathContext = workspace.getPathContext();
|
|
5516
|
+
const pathInfo = pathContext.instructions ? `
|
|
4650
5517
|
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
inputSchema: zod.z.object({
|
|
4658
|
-
command: zod.z.string().describe('The command to execute (e.g., "ls", "npm", "python")'),
|
|
4659
|
-
args: zod.z.array(zod.z.string()).nullish().default([]).describe("Arguments to pass to the command"),
|
|
4660
|
-
timeout: zod.z.number().nullish().describe("Maximum execution time in milliseconds. Example: 60000 for 1 minute."),
|
|
4661
|
-
cwd: zod.z.string().nullish().describe("Working directory for the command")
|
|
4662
|
-
}),
|
|
4663
|
-
outputSchema: zod.z.object({
|
|
4664
|
-
success: zod.z.boolean().describe("Whether the command executed successfully (exit code 0)"),
|
|
4665
|
-
stdout: zod.z.string().describe("Standard output from the command"),
|
|
4666
|
-
stderr: zod.z.string().describe("Standard error output"),
|
|
4667
|
-
exitCode: zod.z.number().describe("Exit code (0 = success)"),
|
|
4668
|
-
executionTimeMs: zod.z.number().describe("How long the execution took in milliseconds")
|
|
4669
|
-
}),
|
|
4670
|
-
execute: async ({ command, args, timeout, cwd }, context) => {
|
|
4671
|
-
const getExecutionMetadata = () => ({
|
|
4672
|
-
workspace: {
|
|
4673
|
-
id: workspace.id,
|
|
4674
|
-
name: workspace.name
|
|
4675
|
-
},
|
|
4676
|
-
sandbox: {
|
|
4677
|
-
id: workspace.sandbox?.id,
|
|
4678
|
-
name: workspace.sandbox?.name,
|
|
4679
|
-
provider: workspace.sandbox?.provider,
|
|
4680
|
-
status: workspace.sandbox?.status
|
|
4681
|
-
}
|
|
4682
|
-
});
|
|
4683
|
-
const startedAt = Date.now();
|
|
4684
|
-
try {
|
|
4685
|
-
const result = await workspace.sandbox.executeCommand(command, args ?? [], {
|
|
4686
|
-
timeout: timeout ?? void 0,
|
|
4687
|
-
cwd: cwd ?? void 0,
|
|
4688
|
-
// Stream stdout/stderr as tool-output chunks for proper UI integration
|
|
4689
|
-
onStdout: async (data) => {
|
|
4690
|
-
await context?.writer?.write({
|
|
4691
|
-
type: "sandbox-stdout",
|
|
4692
|
-
data,
|
|
4693
|
-
timestamp: Date.now(),
|
|
4694
|
-
metadata: getExecutionMetadata()
|
|
4695
|
-
});
|
|
4696
|
-
},
|
|
4697
|
-
onStderr: async (data) => {
|
|
4698
|
-
await context?.writer?.write({
|
|
4699
|
-
type: "sandbox-stderr",
|
|
4700
|
-
data,
|
|
4701
|
-
timestamp: Date.now(),
|
|
4702
|
-
metadata: getExecutionMetadata()
|
|
4703
|
-
});
|
|
4704
|
-
}
|
|
4705
|
-
});
|
|
4706
|
-
await context?.writer?.write({
|
|
4707
|
-
type: "sandbox-exit",
|
|
4708
|
-
exitCode: result.exitCode,
|
|
4709
|
-
success: result.success,
|
|
4710
|
-
executionTimeMs: result.executionTimeMs,
|
|
4711
|
-
metadata: getExecutionMetadata()
|
|
4712
|
-
});
|
|
4713
|
-
return {
|
|
4714
|
-
success: result.success,
|
|
4715
|
-
stdout: result.stdout,
|
|
4716
|
-
stderr: result.stderr,
|
|
4717
|
-
exitCode: result.exitCode,
|
|
4718
|
-
executionTimeMs: result.executionTimeMs
|
|
4719
|
-
};
|
|
4720
|
-
} catch (error) {
|
|
4721
|
-
await context?.writer?.write({
|
|
4722
|
-
type: "sandbox-exit",
|
|
4723
|
-
exitCode: -1,
|
|
4724
|
-
success: false,
|
|
4725
|
-
executionTimeMs: Date.now() - startedAt,
|
|
4726
|
-
metadata: getExecutionMetadata()
|
|
4727
|
-
});
|
|
4728
|
-
throw error;
|
|
4729
|
-
}
|
|
4730
|
-
}
|
|
4731
|
-
});
|
|
5518
|
+
${pathContext.instructions}` : "";
|
|
5519
|
+
const description = pathInfo ? `${executeCommandTool.description}${pathInfo}` : executeCommandTool.description;
|
|
5520
|
+
tools[WORKSPACE_TOOLS.SANDBOX.EXECUTE_COMMAND] = {
|
|
5521
|
+
...wrapTool(executeCommandTool, workspace, executeCommandConfig),
|
|
5522
|
+
description
|
|
5523
|
+
};
|
|
4732
5524
|
}
|
|
4733
5525
|
}
|
|
4734
5526
|
return tools;
|
|
@@ -4736,6 +5528,7 @@ Usage:
|
|
|
4736
5528
|
|
|
4737
5529
|
exports.BM25Index = BM25Index;
|
|
4738
5530
|
exports.CompositeFilesystem = CompositeFilesystem;
|
|
5531
|
+
exports.CompositeVersionedSkillSource = CompositeVersionedSkillSource;
|
|
4739
5532
|
exports.DirectoryNotEmptyError = DirectoryNotEmptyError;
|
|
4740
5533
|
exports.DirectoryNotFoundError = DirectoryNotFoundError;
|
|
4741
5534
|
exports.FileExistsError = FileExistsError;
|
|
@@ -4749,6 +5542,7 @@ exports.IsDirectoryError = IsDirectoryError;
|
|
|
4749
5542
|
exports.IsolationUnavailableError = IsolationUnavailableError;
|
|
4750
5543
|
exports.LocalFilesystem = LocalFilesystem;
|
|
4751
5544
|
exports.LocalSandbox = LocalSandbox;
|
|
5545
|
+
exports.LocalSkillSource = LocalSkillSource;
|
|
4752
5546
|
exports.MastraFilesystem = MastraFilesystem;
|
|
4753
5547
|
exports.MastraSandbox = MastraSandbox;
|
|
4754
5548
|
exports.MountError = MountError;
|
|
@@ -4763,18 +5557,39 @@ exports.SandboxNotAvailableError = SandboxNotAvailableError;
|
|
|
4763
5557
|
exports.SandboxNotReadyError = SandboxNotReadyError;
|
|
4764
5558
|
exports.SandboxTimeoutError = SandboxTimeoutError;
|
|
4765
5559
|
exports.SearchNotAvailableError = SearchNotAvailableError;
|
|
5560
|
+
exports.VersionedSkillSource = VersionedSkillSource;
|
|
4766
5561
|
exports.WORKSPACE_TOOLS = WORKSPACE_TOOLS;
|
|
4767
5562
|
exports.WORKSPACE_TOOLS_PREFIX = WORKSPACE_TOOLS_PREFIX;
|
|
4768
5563
|
exports.Workspace = Workspace;
|
|
4769
5564
|
exports.WorkspaceError = WorkspaceError;
|
|
5565
|
+
exports.WorkspaceNotAvailableError = WorkspaceNotAvailableError;
|
|
4770
5566
|
exports.WorkspaceNotReadyError = WorkspaceNotReadyError;
|
|
4771
5567
|
exports.WorkspaceReadOnlyError = WorkspaceReadOnlyError;
|
|
4772
5568
|
exports.callLifecycle = callLifecycle;
|
|
5569
|
+
exports.collectSkillForPublish = collectSkillForPublish;
|
|
5570
|
+
exports.createGlobMatcher = createGlobMatcher;
|
|
4773
5571
|
exports.createWorkspaceTools = createWorkspaceTools;
|
|
5572
|
+
exports.deleteFileTool = deleteFileTool;
|
|
4774
5573
|
exports.detectIsolation = detectIsolation;
|
|
5574
|
+
exports.editFileTool = editFileTool;
|
|
5575
|
+
exports.executeCommandTool = executeCommandTool;
|
|
5576
|
+
exports.extractGlobBase = extractGlobBase;
|
|
4775
5577
|
exports.extractLines = extractLines;
|
|
5578
|
+
exports.fileStatTool = fileStatTool;
|
|
4776
5579
|
exports.getRecommendedIsolation = getRecommendedIsolation;
|
|
5580
|
+
exports.indexContentTool = indexContentTool;
|
|
5581
|
+
exports.isGlobPattern = isGlobPattern;
|
|
4777
5582
|
exports.isIsolationAvailable = isIsolationAvailable;
|
|
5583
|
+
exports.listFilesTool = listFilesTool;
|
|
5584
|
+
exports.matchGlob = matchGlob;
|
|
5585
|
+
exports.mkdirTool = mkdirTool;
|
|
5586
|
+
exports.publishSkillFromSource = publishSkillFromSource;
|
|
5587
|
+
exports.readFileTool = readFileTool;
|
|
5588
|
+
exports.requireFilesystem = requireFilesystem;
|
|
5589
|
+
exports.requireSandbox = requireSandbox;
|
|
5590
|
+
exports.requireWorkspace = requireWorkspace;
|
|
4778
5591
|
exports.resolveToolConfig = resolveToolConfig;
|
|
4779
|
-
|
|
4780
|
-
|
|
5592
|
+
exports.searchTool = searchTool;
|
|
5593
|
+
exports.writeFileTool = writeFileTool;
|
|
5594
|
+
//# sourceMappingURL=chunk-S4VVZI4E.cjs.map
|
|
5595
|
+
//# sourceMappingURL=chunk-S4VVZI4E.cjs.map
|