@nxuss/lemma 1.18.0 → 1.18.2
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/dist/cjs/mcp/cognitiveMap.d.ts +27 -0
- package/dist/cjs/mcp/cognitiveMap.d.ts.map +1 -0
- package/dist/cjs/mcp/cognitiveMap.js +47 -0
- package/dist/cjs/mcp/cognitiveMap.js.map +1 -0
- package/dist/cjs/mcp/toolTypes.d.ts +39 -0
- package/dist/cjs/mcp/toolTypes.d.ts.map +1 -0
- package/dist/cjs/mcp/toolTypes.js +8 -0
- package/dist/cjs/mcp/toolTypes.js.map +1 -0
- package/dist/cjs/mcp/tools/analysis.d.ts +11 -0
- package/dist/cjs/mcp/tools/analysis.d.ts.map +1 -0
- package/dist/cjs/mcp/tools/analysis.js +933 -0
- package/dist/cjs/mcp/tools/analysis.js.map +1 -0
- package/dist/cjs/mcp/tools/codenav.d.ts +9 -0
- package/dist/cjs/mcp/tools/codenav.d.ts.map +1 -0
- package/dist/cjs/mcp/tools/codenav.js +524 -0
- package/dist/cjs/mcp/tools/codenav.js.map +1 -0
- package/dist/cjs/mcp/tools/context-tools.d.ts +20 -0
- package/dist/cjs/mcp/tools/context-tools.d.ts.map +1 -0
- package/dist/cjs/mcp/tools/context-tools.js +543 -0
- package/dist/cjs/mcp/tools/context-tools.js.map +1 -0
- package/dist/cjs/mcp/tools/depgraph.d.ts +8 -0
- package/dist/cjs/mcp/tools/depgraph.d.ts.map +1 -0
- package/dist/cjs/mcp/tools/depgraph.js +321 -0
- package/dist/cjs/mcp/tools/depgraph.js.map +1 -0
- package/dist/cjs/mcp/tools/dev-utils.d.ts +11 -0
- package/dist/cjs/mcp/tools/dev-utils.d.ts.map +1 -0
- package/dist/cjs/mcp/tools/dev-utils.js +519 -0
- package/dist/cjs/mcp/tools/dev-utils.js.map +1 -0
- package/dist/cjs/mcp/tools/devtools.d.ts +9 -0
- package/dist/cjs/mcp/tools/devtools.d.ts.map +1 -0
- package/dist/cjs/mcp/tools/devtools.js +445 -0
- package/dist/cjs/mcp/tools/devtools.js.map +1 -0
- package/dist/cjs/mcp/tools/memory.d.ts +10 -0
- package/dist/cjs/mcp/tools/memory.d.ts.map +1 -0
- package/dist/cjs/mcp/tools/memory.js +539 -0
- package/dist/cjs/mcp/tools/memory.js.map +1 -0
- package/dist/cjs/mcp/tools/misc.d.ts +10 -0
- package/dist/cjs/mcp/tools/misc.d.ts.map +1 -0
- package/dist/cjs/mcp/tools/misc.js +423 -0
- package/dist/cjs/mcp/tools/misc.js.map +1 -0
- package/dist/cjs/mcp/tools/refactor.d.ts +8 -0
- package/dist/cjs/mcp/tools/refactor.d.ts.map +1 -0
- package/dist/cjs/mcp/tools/refactor.js +335 -0
- package/dist/cjs/mcp/tools/refactor.js.map +1 -0
- package/dist/cjs/mcp/tools/review.d.ts +10 -0
- package/dist/cjs/mcp/tools/review.d.ts.map +1 -0
- package/dist/cjs/mcp/tools/review.js +283 -0
- package/dist/cjs/mcp/tools/review.js.map +1 -0
- package/dist/cjs/mcp/tools/squeeze-cache.d.ts +14 -0
- package/dist/cjs/mcp/tools/squeeze-cache.d.ts.map +1 -0
- package/dist/cjs/mcp/tools/squeeze-cache.js +418 -0
- package/dist/cjs/mcp/tools/squeeze-cache.js.map +1 -0
- package/dist/cjs/mcp/tools/text-ops.d.ts +14 -0
- package/dist/cjs/mcp/tools/text-ops.d.ts.map +1 -0
- package/dist/cjs/mcp/tools/text-ops.js +155 -0
- package/dist/cjs/mcp/tools/text-ops.js.map +1 -0
- package/dist/cjs/mcp/tools/workspace.d.ts +10 -0
- package/dist/cjs/mcp/tools/workspace.d.ts.map +1 -0
- package/dist/cjs/mcp/tools/workspace.js +675 -0
- package/dist/cjs/mcp/tools/workspace.js.map +1 -0
- package/dist/cjs/mcp/tools.d.ts.map +1 -1
- package/dist/cjs/mcp/tools.js +636 -6388
- package/dist/cjs/mcp/tools.js.map +1 -1
- package/dist/cjs/mcp/utils.d.ts +55 -2
- package/dist/cjs/mcp/utils.d.ts.map +1 -1
- package/dist/cjs/mcp/utils.js +194 -10
- package/dist/cjs/mcp/utils.js.map +1 -1
- package/dist/cjs/mcp/workspaceShared.d.ts +19 -0
- package/dist/cjs/mcp/workspaceShared.d.ts.map +1 -0
- package/dist/cjs/mcp/workspaceShared.js +101 -0
- package/dist/cjs/mcp/workspaceShared.js.map +1 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/utils/ExecAuditLog.d.ts +27 -0
- package/dist/cjs/utils/ExecAuditLog.d.ts.map +1 -0
- package/dist/cjs/utils/ExecAuditLog.js +53 -0
- package/dist/cjs/utils/ExecAuditLog.js.map +1 -0
- package/dist/esm/api/dashboardRoutes.d.ts +3 -3
- package/dist/esm/api/dashboardRoutes.js +1 -1
- package/dist/esm/api/server.d.ts +4 -4
- package/dist/esm/api/server.js +3 -3
- package/dist/esm/autopilot/AutopilotWatcher.js +3 -3
- package/dist/esm/autopilot/Notifier.d.ts +1 -1
- package/dist/esm/cli/lemma-proxy.js +15 -15
- package/dist/esm/cli/stack.d.ts +4 -4
- package/dist/esm/cli/stack.js +5 -5
- package/dist/esm/cloud/KeyManager.d.ts +1 -1
- package/dist/esm/cloud/KeyManager.js +1 -1
- package/dist/esm/cloud/TenantCache.d.ts +1 -1
- package/dist/esm/cloud/identity/ApiKey.d.ts +1 -1
- package/dist/esm/cloud/identity/TenantResolver.d.ts +1 -1
- package/dist/esm/cloud/identity/TenantResolver.js +1 -1
- package/dist/esm/cloud/identity/authenticateV2.d.ts +3 -3
- package/dist/esm/cloud/identity/authenticateV2.js +3 -3
- package/dist/esm/cloud/identity/identityStore.d.ts +2 -2
- package/dist/esm/cloud/identity/index.d.ts +6 -6
- package/dist/esm/cloud/identity/index.js +6 -6
- package/dist/esm/cloud/index.d.ts +3 -3
- package/dist/esm/cloud/index.js +3 -3
- package/dist/esm/cloud/metering/UsageLedger.d.ts +1 -1
- package/dist/esm/cloud/metering/index.d.ts +2 -2
- package/dist/esm/cloud/metering/index.js +2 -2
- package/dist/esm/cloud/scrub/StatelessScrubber.d.ts +1 -1
- package/dist/esm/cloud/scrub/index.d.ts +1 -1
- package/dist/esm/cloud/scrub/index.js +1 -1
- package/dist/esm/cloud/server.d.ts +3 -3
- package/dist/esm/cloud/server.js +5 -5
- package/dist/esm/cloud/store/FileBrainStore.d.ts +1 -1
- package/dist/esm/cloud/store/FileBrainStore.js +1 -1
- package/dist/esm/cloud/store/PostgresBrainStore.d.ts +1 -1
- package/dist/esm/cloud/store/PostgresBrainStore.js +2 -2
- package/dist/esm/cloud/store/index.d.ts +2 -2
- package/dist/esm/cloud/store/index.js +2 -2
- package/dist/esm/cloud/v2/app.d.ts +1 -1
- package/dist/esm/cloud/v2/app.js +3 -3
- package/dist/esm/cloud/v2/routes/index.d.ts +5 -5
- package/dist/esm/cloud/v2/routes/index.js +7 -7
- package/dist/esm/cloud/v2/routes/memories.d.ts +4 -4
- package/dist/esm/cloud/v2/routes/memories.js +2 -2
- package/dist/esm/cloud/v2/routes/recall.d.ts +1 -1
- package/dist/esm/cloud/v2/routes/recall.js +1 -1
- package/dist/esm/cloud/v2/routes/scrub.d.ts +2 -2
- package/dist/esm/cloud/v2/routes/scrub.js +2 -2
- package/dist/esm/cloud/v2/routes/usage.d.ts +1 -1
- package/dist/esm/cloud/v2/routes/verify.d.ts +1 -1
- package/dist/esm/cloud/v2/routes/verify.js +1 -1
- package/dist/esm/cloud/v2/server.js +4 -4
- package/dist/esm/config/index.d.ts +1 -1
- package/dist/esm/config/index.js +1 -1
- package/dist/esm/consensus/index.d.ts +2 -2
- package/dist/esm/consensus/index.js +2 -2
- package/dist/esm/contracts/api-v2.types.d.ts +1 -1
- package/dist/esm/contracts/index.d.ts +4 -4
- package/dist/esm/contracts/index.js +4 -4
- package/dist/esm/core/AgentRegistry.d.ts +1 -1
- package/dist/esm/core/AgentRegistry.js +1 -1
- package/dist/esm/core/DashboardBroadcaster.d.ts +3 -3
- package/dist/esm/core/DashboardBroadcaster.js +2 -2
- package/dist/esm/core/DashboardWebSocketServer.d.ts +1 -1
- package/dist/esm/core/DashboardWebSocketServer.js +1 -1
- package/dist/esm/core/GhostAlchemist.js +1 -1
- package/dist/esm/core/GhostListener.js +2 -2
- package/dist/esm/core/OrchestrationEngine.d.ts +3 -3
- package/dist/esm/core/OrchestrationEngine.js +2 -2
- package/dist/esm/core/SubconsciousEngine.d.ts +1 -1
- package/dist/esm/core/SubconsciousEngine.js +2 -2
- package/dist/esm/core/WebSocketServer.d.ts +2 -2
- package/dist/esm/core/WebSocketServer.js +1 -1
- package/dist/esm/core/index.d.ts +6 -6
- package/dist/esm/core/index.js +6 -6
- package/dist/esm/core/router.d.ts +3 -3
- package/dist/esm/core/router.js +1 -1
- package/dist/esm/db/database.js +1 -1
- package/dist/esm/embed.d.ts +2 -2
- package/dist/esm/embed.js +2 -2
- package/dist/esm/examples/basic-usage.js +1 -1
- package/dist/esm/index.d.ts +14 -14
- package/dist/esm/index.js +14 -14
- package/dist/esm/infra/analyzers/DriftDetector.d.ts +1 -1
- package/dist/esm/infra/analyzers/InfraAnalyzer.d.ts +1 -1
- package/dist/esm/infra/analyzers/MonolithAnalyzer.d.ts +1 -1
- package/dist/esm/infra/analyzers/index.d.ts +3 -3
- package/dist/esm/infra/analyzers/index.js +3 -3
- package/dist/esm/infra/cli.js +2 -2
- package/dist/esm/infra/config.d.ts +1 -1
- package/dist/esm/infra/index.d.ts +5 -5
- package/dist/esm/infra/index.js +5 -5
- package/dist/esm/infra/mcp-tools.js +5 -5
- package/dist/esm/infra/providers/InfraProvider.d.ts +1 -1
- package/dist/esm/infra/providers/JenkinsProvider.d.ts +2 -2
- package/dist/esm/infra/providers/OKDProvider.d.ts +2 -2
- package/dist/esm/infra/providers/TerraformProvider.d.ts +2 -2
- package/dist/esm/infra/providers/index.d.ts +5 -5
- package/dist/esm/infra/providers/index.js +3 -3
- package/dist/esm/mcp/cognitiveMap.d.ts +27 -0
- package/dist/esm/mcp/cognitiveMap.d.ts.map +1 -0
- package/dist/esm/mcp/cognitiveMap.js +40 -0
- package/dist/esm/mcp/cognitiveMap.js.map +1 -0
- package/dist/esm/mcp/index.js +5 -5
- package/dist/esm/mcp/prompts.js +1 -1
- package/dist/esm/mcp/resources.js +2 -2
- package/dist/esm/mcp/tasks.js +1 -1
- package/dist/esm/mcp/tool-profiles.js +1 -1
- package/dist/esm/mcp/toolTypes.d.ts +39 -0
- package/dist/esm/mcp/toolTypes.d.ts.map +1 -0
- package/dist/esm/mcp/toolTypes.js +7 -0
- package/dist/esm/mcp/toolTypes.js.map +1 -0
- package/dist/esm/mcp/tools/analysis.d.ts +11 -0
- package/dist/esm/mcp/tools/analysis.d.ts.map +1 -0
- package/dist/esm/mcp/tools/analysis.js +894 -0
- package/dist/esm/mcp/tools/analysis.js.map +1 -0
- package/dist/esm/mcp/tools/codenav.d.ts +9 -0
- package/dist/esm/mcp/tools/codenav.d.ts.map +1 -0
- package/dist/esm/mcp/tools/codenav.js +485 -0
- package/dist/esm/mcp/tools/codenav.js.map +1 -0
- package/dist/esm/mcp/tools/context-tools.d.ts +20 -0
- package/dist/esm/mcp/tools/context-tools.d.ts.map +1 -0
- package/dist/esm/mcp/tools/context-tools.js +503 -0
- package/dist/esm/mcp/tools/context-tools.js.map +1 -0
- package/dist/esm/mcp/tools/depgraph.d.ts +8 -0
- package/dist/esm/mcp/tools/depgraph.d.ts.map +1 -0
- package/dist/esm/mcp/tools/depgraph.js +315 -0
- package/dist/esm/mcp/tools/depgraph.js.map +1 -0
- package/dist/esm/mcp/tools/dev-utils.d.ts +11 -0
- package/dist/esm/mcp/tools/dev-utils.d.ts.map +1 -0
- package/dist/esm/mcp/tools/dev-utils.js +516 -0
- package/dist/esm/mcp/tools/dev-utils.js.map +1 -0
- package/dist/esm/mcp/tools/devtools.d.ts +9 -0
- package/dist/esm/mcp/tools/devtools.d.ts.map +1 -0
- package/dist/esm/mcp/tools/devtools.js +406 -0
- package/dist/esm/mcp/tools/devtools.js.map +1 -0
- package/dist/esm/mcp/tools/memory.d.ts +10 -0
- package/dist/esm/mcp/tools/memory.d.ts.map +1 -0
- package/dist/esm/mcp/tools/memory.js +533 -0
- package/dist/esm/mcp/tools/memory.js.map +1 -0
- package/dist/esm/mcp/tools/misc.d.ts +10 -0
- package/dist/esm/mcp/tools/misc.d.ts.map +1 -0
- package/dist/esm/mcp/tools/misc.js +417 -0
- package/dist/esm/mcp/tools/misc.js.map +1 -0
- package/dist/esm/mcp/tools/refactor.d.ts +8 -0
- package/dist/esm/mcp/tools/refactor.d.ts.map +1 -0
- package/dist/esm/mcp/tools/refactor.js +296 -0
- package/dist/esm/mcp/tools/refactor.js.map +1 -0
- package/dist/esm/mcp/tools/review.d.ts +10 -0
- package/dist/esm/mcp/tools/review.d.ts.map +1 -0
- package/dist/esm/mcp/tools/review.js +277 -0
- package/dist/esm/mcp/tools/review.js.map +1 -0
- package/dist/esm/mcp/tools/squeeze-cache.d.ts +14 -0
- package/dist/esm/mcp/tools/squeeze-cache.d.ts.map +1 -0
- package/dist/esm/mcp/tools/squeeze-cache.js +382 -0
- package/dist/esm/mcp/tools/squeeze-cache.js.map +1 -0
- package/dist/esm/mcp/tools/text-ops.d.ts +14 -0
- package/dist/esm/mcp/tools/text-ops.d.ts.map +1 -0
- package/dist/esm/mcp/tools/text-ops.js +152 -0
- package/dist/esm/mcp/tools/text-ops.js.map +1 -0
- package/dist/esm/mcp/tools/workspace.d.ts +10 -0
- package/dist/esm/mcp/tools/workspace.d.ts.map +1 -0
- package/dist/esm/mcp/tools/workspace.js +669 -0
- package/dist/esm/mcp/tools/workspace.js.map +1 -0
- package/dist/esm/mcp/tools.d.ts +1 -1
- package/dist/esm/mcp/tools.d.ts.map +1 -1
- package/dist/esm/mcp/tools.js +652 -6404
- package/dist/esm/mcp/tools.js.map +1 -1
- package/dist/esm/mcp/utils.d.ts +55 -2
- package/dist/esm/mcp/utils.d.ts.map +1 -1
- package/dist/esm/mcp/utils.js +189 -10
- package/dist/esm/mcp/utils.js.map +1 -1
- package/dist/esm/mcp/workspaceShared.d.ts +19 -0
- package/dist/esm/mcp/workspaceShared.d.ts.map +1 -0
- package/dist/esm/mcp/workspaceShared.js +93 -0
- package/dist/esm/mcp/workspaceShared.js.map +1 -0
- package/dist/esm/observability/IdeContextSync.d.ts +1 -1
- package/dist/esm/observability/IdeContextSync.js +5 -5
- package/dist/esm/package.json +3 -0
- package/dist/esm/pr-review/PRReviewEngine.d.ts +1 -1
- package/dist/esm/pr-review/PRReviewEngine.js +4 -4
- package/dist/esm/pr-review/ReviewStore.d.ts +1 -1
- package/dist/esm/pr-review/adapters/AzureDevOpsAdapter.d.ts +2 -2
- package/dist/esm/pr-review/adapters/AzureDevOpsAdapter.js +1 -1
- package/dist/esm/pr-review/adapters/GitHubAdapter.d.ts +2 -2
- package/dist/esm/pr-review/adapters/GitHubAdapter.js +1 -1
- package/dist/esm/pr-review/adapters/GitLabAdapter.d.ts +2 -2
- package/dist/esm/pr-review/adapters/GitLabAdapter.js +1 -1
- package/dist/esm/pr-review/adapters/GitPlatformAdapter.d.ts +1 -1
- package/dist/esm/pr-review/adapters/index.d.ts +4 -4
- package/dist/esm/pr-review/adapters/index.js +3 -3
- package/dist/esm/pr-review/analyzers/QualityGrader.d.ts +1 -1
- package/dist/esm/pr-review/analyzers/RegressionDetector.d.ts +1 -1
- package/dist/esm/pr-review/analyzers/SecurityScanner.d.ts +1 -1
- package/dist/esm/pr-review/analyzers/StaticAnalyzer.d.ts +1 -1
- package/dist/esm/pr-review/analyzers/index.d.ts +8 -8
- package/dist/esm/pr-review/analyzers/index.js +4 -4
- package/dist/esm/pr-review/bridge/BrainBridge.d.ts +1 -1
- package/dist/esm/pr-review/bridge/BrainBridge.js +1 -1
- package/dist/esm/pr-review/bridge/index.d.ts +1 -1
- package/dist/esm/pr-review/bridge/index.js +1 -1
- package/dist/esm/pr-review/index.d.ts +4 -4
- package/dist/esm/pr-review/index.js +2 -2
- package/dist/esm/pr-review/reviewRunner.d.ts +2 -2
- package/dist/esm/pr-review/reviewRunner.js +6 -6
- package/dist/esm/pr-review/webhook/WebhookServer.js +1 -1
- package/dist/esm/pr-review/webhook/index.d.ts +1 -1
- package/dist/esm/pr-review/webhook/index.js +1 -1
- package/dist/esm/protocol/flows.d.ts +1 -1
- package/dist/esm/protocol/flows.js +1 -1
- package/dist/esm/protocol/index.d.ts +4 -4
- package/dist/esm/protocol/index.js +4 -4
- package/dist/esm/protocol/utils.d.ts +1 -1
- package/dist/esm/protocol/utils.js +2 -2
- package/dist/esm/protocol/validators.d.ts +1 -1
- package/dist/esm/protocol/validators.js +1 -1
- package/dist/esm/proxy/ContextInjector.d.ts +1 -1
- package/dist/esm/proxy/Gatekeeper.d.ts +1 -1
- package/dist/esm/security/SecurityMiddleware.d.ts +1 -1
- package/dist/esm/security/SecurityMiddleware.js +3 -3
- package/dist/esm/security/index.d.ts +4 -4
- package/dist/esm/security/index.js +4 -4
- package/dist/esm/speculative/SpeculativeCache.d.ts +2 -2
- package/dist/esm/speculative/SpeculativeEngine.d.ts +2 -2
- package/dist/esm/speculative/SpeculativeEngine.js +3 -3
- package/dist/esm/speculative/WorkerPool.d.ts +1 -1
- package/dist/esm/speculative/index.d.ts +4 -4
- package/dist/esm/speculative/index.js +4 -4
- package/dist/esm/subconscious/GitIngest.d.ts +1 -1
- package/dist/esm/subconscious/GitIngest.js +1 -1
- package/dist/esm/subconscious/SemanticCache.d.ts +2 -2
- package/dist/esm/subconscious/SemanticCache.js +2 -2
- package/dist/esm/subconscious/SubconsciousEngine.d.ts +1 -1
- package/dist/esm/subconscious/SubconsciousEngine.js +3 -3
- package/dist/esm/subconscious/TheBrainV2.d.ts +1 -1
- package/dist/esm/subconscious/TheBrainV2.js +2 -2
- package/dist/esm/subconscious/freshness/LocalFsResolver.d.ts +1 -1
- package/dist/esm/subconscious/freshness/LocalFsResolver.js +1 -1
- package/dist/esm/subconscious/freshness/SuppliedEvidenceResolver.d.ts +1 -1
- package/dist/esm/subconscious/freshness/index.d.ts +2 -2
- package/dist/esm/subconscious/freshness/index.js +2 -2
- package/dist/esm/subconscious/index.d.ts +4 -4
- package/dist/esm/subconscious/index.js +4 -4
- package/dist/esm/utils/AffectedTests.js +1 -1
- package/dist/esm/utils/AutoContextBundle.d.ts +1 -1
- package/dist/esm/utils/AutoContextBundle.js +4 -4
- package/dist/esm/utils/BulkFileDigest.js +2 -2
- package/dist/esm/utils/ClipboardWatcher.js +2 -2
- package/dist/esm/utils/ContextCollapser.js +1 -1
- package/dist/esm/utils/ConversationCheckpoint.js +1 -1
- package/dist/esm/utils/ExecAuditLog.d.ts +27 -0
- package/dist/esm/utils/ExecAuditLog.d.ts.map +1 -0
- package/dist/esm/utils/ExecAuditLog.js +45 -0
- package/dist/esm/utils/ExecAuditLog.js.map +1 -0
- package/dist/esm/utils/ExecutiveReport.js +1 -1
- package/dist/esm/utils/OutputLedger.js +2 -2
- package/dist/esm/utils/ReadWorkspaceCache.js +1 -1
- package/dist/esm/utils/SpeculativeWarmer.d.ts +1 -1
- package/dist/esm/utils/SpeculativeWarmer.js +2 -2
- package/dist/esm/utils/StateHashCache.js +1 -1
- package/dist/esm/utils/StructuralSearch.d.ts +1 -1
- package/dist/esm/utils/SurgicalASTInsert.js +1 -1
- package/dist/esm/utils/SymbolSurgicalContext.js +1 -1
- package/dist/esm/utils/TestAutofixInterceptor.js +1 -1
- package/dist/esm/utils/WorkspaceSearch.js +0 -0
- package/dist/esm/utils/logger.js +1 -1
- package/dist/esm/utils/reportSavings.js +1 -1
- package/package.json +3 -1
- package/sdks/crewai/dist/crewai/src/index.d.ts +131 -0
- package/sdks/crewai/dist/crewai/src/index.js +325 -0
- package/sdks/crewai/dist/crewai/src/memory.d.ts +36 -0
- package/sdks/crewai/dist/crewai/src/memory.js +61 -0
- package/sdks/crewai/dist/ts/src/client.d.ts +39 -0
- package/sdks/crewai/dist/ts/src/client.js +124 -0
- package/sdks/crewai/dist/ts/src/errors.d.ts +19 -0
- package/sdks/crewai/dist/ts/src/errors.js +18 -0
- package/sdks/crewai/dist/ts/src/evidence.d.ts +30 -0
- package/sdks/crewai/dist/ts/src/evidence.js +175 -0
- package/sdks/crewai/dist/ts/src/index.d.ts +4 -0
- package/sdks/crewai/dist/ts/src/index.js +27 -0
- package/sdks/crewai/dist/ts/src/types.d.ts +112 -0
- package/sdks/crewai/dist/ts/src/types.js +11 -0
|
@@ -0,0 +1,675 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Workspace file/dir CRUD and command execution: read_workspace_file,
|
|
4
|
+
* write_workspace_file, create_workspace_file, apply_workspace_patch,
|
|
5
|
+
* run_workspace_command, output_region, list_workspace_dir. Split out of ../tools.ts
|
|
6
|
+
* (see that file's history for why) — pure relocation, no behavior change.
|
|
7
|
+
*/
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.WORKSPACE_TOOL_HANDLERS = exports.WORKSPACE_TOOL_DEFINITIONS = void 0;
|
|
13
|
+
const fs_1 = __importDefault(require("fs"));
|
|
14
|
+
const path_1 = __importDefault(require("path"));
|
|
15
|
+
const child_process_1 = require("child_process");
|
|
16
|
+
const SemanticScrubber_1 = require("../../security/SemanticScrubber");
|
|
17
|
+
const TheBrainV2_1 = require("../../subconscious/TheBrainV2");
|
|
18
|
+
const ContextSqueezer_1 = require("../../utils/ContextSqueezer");
|
|
19
|
+
const reportSavings_1 = require("../../utils/reportSavings");
|
|
20
|
+
const utils_1 = require("../utils");
|
|
21
|
+
const TokenReceipt_1 = require("../../utils/TokenReceipt");
|
|
22
|
+
const ExecAuditLog_1 = require("../../utils/ExecAuditLog");
|
|
23
|
+
const CommandOutputDistiller_1 = require("../../utils/CommandOutputDistiller");
|
|
24
|
+
const PatchMatcher_1 = require("../../utils/PatchMatcher");
|
|
25
|
+
const ReadWorkspaceCache_1 = require("../../utils/ReadWorkspaceCache");
|
|
26
|
+
const OutputDelta_1 = require("../../utils/OutputDelta");
|
|
27
|
+
const OutputLedger_1 = require("../../utils/OutputLedger");
|
|
28
|
+
const SpeculativeWarmer_1 = require("../../utils/SpeculativeWarmer");
|
|
29
|
+
const LineNumberMap_1 = require("../../utils/LineNumberMap");
|
|
30
|
+
const FileOutline_1 = require("../../utils/FileOutline");
|
|
31
|
+
const workspaceShared_1 = require("../workspaceShared");
|
|
32
|
+
exports.WORKSPACE_TOOL_DEFINITIONS = [
|
|
33
|
+
{
|
|
34
|
+
name: "read_workspace_file",
|
|
35
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
36
|
+
description: "Read a file inside the workspace. Compresses comments/whitespace and scrubs API keys. Every line carries its REAL line number in the original file (compression removes lines, it never renumbers them), so you can cite file:line and patch precisely without re-reading. The header lists which imports were compressed away. Use offset/limit to read a line range of a large file. If this exact view was already read this session and hasn't changed on disk, returns an UNCHANGED marker plus a symbol outline. If it changed only slightly, returns a CHANGED marker with a unified diff to apply to the copy you already hold. Either way, pass force:true to get the full file when it is no longer in your context.",
|
|
37
|
+
inputSchema: {
|
|
38
|
+
type: "object",
|
|
39
|
+
properties: {
|
|
40
|
+
filePath: { type: "string", description: "Path relative to the project root" },
|
|
41
|
+
compact: { type: "boolean", description: "Whether to compress comments and whitespace", default: true },
|
|
42
|
+
force: { type: "boolean", description: "Bypass the unchanged-file short-circuit and always return full content", default: false },
|
|
43
|
+
lineNumbers: { type: "boolean", description: "Prefix each line with its real line number in the original file", default: true },
|
|
44
|
+
offset: { type: "number", description: "First line to read (1-indexed). Omit to start at the beginning." },
|
|
45
|
+
limit: { type: "number", description: "How many lines to read from offset. Omit to read to the end." },
|
|
46
|
+
},
|
|
47
|
+
required: ["filePath"],
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: "write_workspace_file",
|
|
52
|
+
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: false },
|
|
53
|
+
description: "Write full contents to a file inside the workspace. Creates parent directories automatically.",
|
|
54
|
+
inputSchema: {
|
|
55
|
+
type: "object",
|
|
56
|
+
properties: {
|
|
57
|
+
filePath: { type: "string", description: "Path relative to the project root" },
|
|
58
|
+
content: { type: "string", description: "The complete content to write" },
|
|
59
|
+
},
|
|
60
|
+
required: ["filePath", "content"],
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: "create_workspace_file",
|
|
65
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
|
|
66
|
+
description: "Create a NEW file in the workspace. Fails immediately if the file already exists — use write_workspace_file or apply_workspace_patch to modify existing files. Creates parent directories automatically. Returns a minimal token-free ACK: no file content is echoed back, saving provider output tokens.",
|
|
67
|
+
inputSchema: {
|
|
68
|
+
type: "object",
|
|
69
|
+
properties: {
|
|
70
|
+
filePath: { type: "string", description: "Path relative to the project root for the new file" },
|
|
71
|
+
content: { type: "string", description: "The complete initial content for the new file" },
|
|
72
|
+
},
|
|
73
|
+
required: ["filePath", "content"],
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: "apply_workspace_patch",
|
|
78
|
+
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false },
|
|
79
|
+
description: "Apply a smart search-and-replace patch to an existing file. Falls back through whitespace-normalized, indent-anchored, and fuzzy matching if the exact block isn't found — so a searchContent built from a compacted read still applies. Safe against duplicate matches. On total failure, the error includes a diff against the closest candidate block.",
|
|
80
|
+
inputSchema: {
|
|
81
|
+
type: "object",
|
|
82
|
+
properties: {
|
|
83
|
+
filePath: { type: "string", description: "Path relative to the project root" },
|
|
84
|
+
searchContent: { type: "string", description: "The exact search block to find" },
|
|
85
|
+
replaceContent: { type: "string", description: "The replacement block" },
|
|
86
|
+
},
|
|
87
|
+
required: ["filePath", "searchContent", "replaceContent"],
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: "run_workspace_command",
|
|
92
|
+
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true },
|
|
93
|
+
execution: { taskSupport: "optional" },
|
|
94
|
+
description: "Execute a bash command in the workspace root. Default timeout 120s — raise it with timeoutMs for a full test or build run (max 600s). Captures both stdout and stderr, and returns whatever was produced even if the command times out. Long test/build/lint output is distilled deterministically — for jest, vitest and tsc it returns the failing tests or diagnostics with their locations and reasons, dropping code frames and node_modules stack frames; anything else falls back to head/tail plus error-matching lines. The complete output is always stored first and the reply carries a handle: nothing is lost, use output_region to retrieve any part verbatim. Pass raw:true to skip distillation.",
|
|
95
|
+
inputSchema: {
|
|
96
|
+
type: "object",
|
|
97
|
+
properties: {
|
|
98
|
+
command: { type: "string", description: "The bash command to run" },
|
|
99
|
+
raw: {
|
|
100
|
+
type: "boolean",
|
|
101
|
+
description: "Return the complete untouched output instead of the distilled view",
|
|
102
|
+
default: false,
|
|
103
|
+
},
|
|
104
|
+
timeoutMs: {
|
|
105
|
+
type: "number",
|
|
106
|
+
description: "Milliseconds before the command is killed (default 120000, max 600000)",
|
|
107
|
+
default: 120000,
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
required: ["command"],
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
name: "output_region",
|
|
115
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
116
|
+
description: "Retrieve any part of a command output previously stored by run_workspace_command, verbatim. This is what makes distillation lossless — use it when the distilled view isn't enough. Pass all:true for the whole output, section for one named block (a failing test title or a file path, as listed in the distilled view), or startLine/endLine for a range.",
|
|
117
|
+
inputSchema: {
|
|
118
|
+
type: "object",
|
|
119
|
+
properties: {
|
|
120
|
+
handle: { type: "string", description: "The handle reported by run_workspace_command" },
|
|
121
|
+
section: { type: "string", description: "Name of a section to retrieve (failing test title or file path)" },
|
|
122
|
+
startLine: { type: "number", description: "First line to return (1-indexed, inclusive)" },
|
|
123
|
+
endLine: { type: "number", description: "Last line to return (1-indexed, inclusive)" },
|
|
124
|
+
all: { type: "boolean", description: "Return the complete stored output", default: false },
|
|
125
|
+
},
|
|
126
|
+
required: ["handle"],
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
name: "list_workspace_dir",
|
|
131
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
132
|
+
description: "List files and subdirectories recursively to navigate the repository structure.",
|
|
133
|
+
inputSchema: {
|
|
134
|
+
type: "object",
|
|
135
|
+
properties: {
|
|
136
|
+
dirPath: { type: "string", description: "Directory relative to project root", default: "" },
|
|
137
|
+
maxDepth: { type: "number", description: "Maximum recursion depth", default: 3 },
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
];
|
|
142
|
+
async function handleReadWorkspaceFile(args) {
|
|
143
|
+
const filePath = args?.filePath;
|
|
144
|
+
const compact = args?.compact !== false;
|
|
145
|
+
const force = !!args?.force;
|
|
146
|
+
const lineNumbers = args?.lineNumbers !== false;
|
|
147
|
+
const offset = typeof args?.offset === "number" && args.offset > 0 ? Math.floor(args.offset) : undefined;
|
|
148
|
+
const limit = typeof args?.limit === "number" && args.limit > 0 ? Math.floor(args.limit) : undefined;
|
|
149
|
+
if (!filePath)
|
|
150
|
+
throw new Error("filePath is required");
|
|
151
|
+
const workspaceRoot = process.cwd();
|
|
152
|
+
try {
|
|
153
|
+
const { resolved } = (0, utils_1.safeResolvePath)(workspaceRoot, filePath);
|
|
154
|
+
const fullContent = fs_1.default.readFileSync(resolved, "utf8");
|
|
155
|
+
const view = { compact, lineNumbers, offset, limit };
|
|
156
|
+
// The range is applied to the original file, before any compression: `offset` means the
|
|
157
|
+
// line the user would see in an editor, not a position in the squeezed output.
|
|
158
|
+
const allLines = fullContent.split("\n");
|
|
159
|
+
const startIndex = offset ? Math.min(offset - 1, allLines.length) : 0;
|
|
160
|
+
const endIndex = limit ? Math.min(startIndex + limit, allLines.length) : allLines.length;
|
|
161
|
+
const ranged = offset || limit ? allLines.slice(startIndex, endIndex).join("\n") : fullContent;
|
|
162
|
+
const rangeHeader = offset || limit
|
|
163
|
+
? `[lines ${startIndex + 1}-${endIndex} of ${allLines.length} in ${filePath}]\n`
|
|
164
|
+
: "";
|
|
165
|
+
let content = ranged;
|
|
166
|
+
const originalSize = content.length;
|
|
167
|
+
const dedup = (0, ReadWorkspaceCache_1.checkAlreadySent)(resolved, view, content);
|
|
168
|
+
if (!force && dedup.unchanged) {
|
|
169
|
+
(0, reportSavings_1.reportSavings)({
|
|
170
|
+
source: "contextSqueeze",
|
|
171
|
+
charsBefore: originalSize,
|
|
172
|
+
charsAfter: 0,
|
|
173
|
+
toolName: "read_workspace_file",
|
|
174
|
+
filePath,
|
|
175
|
+
});
|
|
176
|
+
// A hash alone is not actionable: the model's context may have been compacted since,
|
|
177
|
+
// in which case it no longer holds the copy this marker tells it to reuse. The outline
|
|
178
|
+
// costs ~50 tokens and is enough to either locate what it needs or decide to re-fetch.
|
|
179
|
+
const outline = (0, FileOutline_1.formatOutline)((0, FileOutline_1.fileOutline)(content), allLines.length);
|
|
180
|
+
return {
|
|
181
|
+
content: [
|
|
182
|
+
{
|
|
183
|
+
type: "text",
|
|
184
|
+
text: [
|
|
185
|
+
`UNCHANGED: ${filePath} is identical to what you already read this session (hash ${dedup.hash.slice(0, 12)}) — reuse your existing copy.`,
|
|
186
|
+
`If it is no longer in your context, re-fetch with force:true. Structure:`,
|
|
187
|
+
outline,
|
|
188
|
+
].join("\n"),
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
// Line numbers are computed against the pre-squeeze text and carried through, so a
|
|
194
|
+
// compressed read still reports the position the code actually occupies on disk.
|
|
195
|
+
let numbers = null;
|
|
196
|
+
if (compact) {
|
|
197
|
+
const squeezed = (0, ContextSqueezer_1.squeezeCode)(content);
|
|
198
|
+
if (lineNumbers) {
|
|
199
|
+
numbers = (0, LineNumberMap_1.mapSqueezedToOriginal)(content, squeezed).map((n) => (n === null ? null : n + startIndex));
|
|
200
|
+
}
|
|
201
|
+
content = squeezed;
|
|
202
|
+
if (content.length < originalSize) {
|
|
203
|
+
(0, reportSavings_1.reportSavings)({
|
|
204
|
+
source: "contextSqueeze",
|
|
205
|
+
charsBefore: originalSize,
|
|
206
|
+
charsAfter: content.length,
|
|
207
|
+
toolName: "read_workspace_file",
|
|
208
|
+
filePath,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
else if (lineNumbers) {
|
|
213
|
+
numbers = (0, LineNumberMap_1.sequentialNumbers)(content, startIndex + 1);
|
|
214
|
+
}
|
|
215
|
+
try {
|
|
216
|
+
const scrubber = new SemanticScrubber_1.SemanticScrubber();
|
|
217
|
+
const { maskedPrompt } = scrubber.mask(content);
|
|
218
|
+
// Masking must not change the line count, or every number after a masked secret would
|
|
219
|
+
// be off. If it ever does, drop the gutter rather than print numbers that lie.
|
|
220
|
+
if (numbers && maskedPrompt.split("\n").length !== content.split("\n").length) {
|
|
221
|
+
numbers = null;
|
|
222
|
+
}
|
|
223
|
+
content = maskedPrompt;
|
|
224
|
+
}
|
|
225
|
+
catch (err) {
|
|
226
|
+
(0, utils_1.logWarn)("read_workspace_file", "SemanticScrubber failed, returning raw content");
|
|
227
|
+
}
|
|
228
|
+
if (numbers)
|
|
229
|
+
content = (0, LineNumberMap_1.withLineNumbers)(content, numbers);
|
|
230
|
+
// The file changed, but usually only slightly — the common case in an edit loop is a
|
|
231
|
+
// few lines moving in a file the model already holds in full. Re-sending everything
|
|
232
|
+
// charges for the whole file (and keeps charging, since tool results stay in the
|
|
233
|
+
// transcript). A diff against the exact text we last emitted covers the same ground
|
|
234
|
+
// for a fraction of the tokens; `shouldEmitDelta` declines whenever it wouldn't.
|
|
235
|
+
if (!force) {
|
|
236
|
+
const previousEmitted = (0, ReadWorkspaceCache_1.getLastEmitted)(resolved, view);
|
|
237
|
+
if (previousEmitted !== null) {
|
|
238
|
+
const delta = (0, OutputDelta_1.shouldEmitDelta)(previousEmitted, content);
|
|
239
|
+
if (delta.emit) {
|
|
240
|
+
(0, reportSavings_1.reportSavings)({
|
|
241
|
+
source: "contextSqueeze",
|
|
242
|
+
charsBefore: content.length,
|
|
243
|
+
charsAfter: delta.body.length,
|
|
244
|
+
toolName: "read_workspace_file",
|
|
245
|
+
filePath,
|
|
246
|
+
});
|
|
247
|
+
(0, ReadWorkspaceCache_1.recordSent)(resolved, view, dedup.hash, content);
|
|
248
|
+
(0, SpeculativeWarmer_1.warmNeighbors)(workspaceRoot, resolved);
|
|
249
|
+
return {
|
|
250
|
+
content: [
|
|
251
|
+
{
|
|
252
|
+
type: "text",
|
|
253
|
+
text: [
|
|
254
|
+
`CHANGED: ${filePath} — ${delta.hunkCount} hunk(s), +${delta.added}/-${delta.removed} since you last read it.`,
|
|
255
|
+
`Apply this diff to the copy you already have. Line numbers are real positions in the file on disk.`,
|
|
256
|
+
`If you no longer hold that copy, re-fetch with force:true.`,
|
|
257
|
+
``,
|
|
258
|
+
delta.body,
|
|
259
|
+
].join("\n") + (0, workspaceShared_1.formatRecallNote)(filePath),
|
|
260
|
+
},
|
|
261
|
+
],
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
(0, ReadWorkspaceCache_1.recordSent)(resolved, view, dedup.hash, content);
|
|
267
|
+
(0, SpeculativeWarmer_1.warmNeighbors)(workspaceRoot, resolved);
|
|
268
|
+
return { content: [{ type: "text", text: rangeHeader + content + (0, workspaceShared_1.formatRecallNote)(filePath) }] };
|
|
269
|
+
}
|
|
270
|
+
catch (err) {
|
|
271
|
+
(0, utils_1.logError)("read_workspace_file", err);
|
|
272
|
+
return { content: [{ type: "text", text: `Error reading file: ${err.message}` }] };
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
async function handleWriteWorkspaceFile(args) {
|
|
276
|
+
const filePath = args?.filePath;
|
|
277
|
+
const content = args?.content;
|
|
278
|
+
if (!filePath || content === undefined)
|
|
279
|
+
throw new Error("filePath and content are required");
|
|
280
|
+
const workspaceRoot = process.cwd();
|
|
281
|
+
try {
|
|
282
|
+
const { resolved } = (0, utils_1.safeResolvePath)(workspaceRoot, filePath);
|
|
283
|
+
const dir = path_1.default.dirname(resolved);
|
|
284
|
+
if (!fs_1.default.existsSync(dir)) {
|
|
285
|
+
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
286
|
+
}
|
|
287
|
+
fs_1.default.writeFileSync(resolved, content, "utf8");
|
|
288
|
+
(0, ExecAuditLog_1.recordExecAudit)({ tool: "write_workspace_file", detail: resolved, allowed: true });
|
|
289
|
+
const blastRadius = (0, workspaceShared_1.formatBlastRadiusNote)((0, TheBrainV2_1.getBrain)().findBlastRadius(filePath));
|
|
290
|
+
return { content: [{ type: "text", text: `Success: Written file to ${filePath}${blastRadius}` }] };
|
|
291
|
+
}
|
|
292
|
+
catch (err) {
|
|
293
|
+
(0, utils_1.logError)("write_workspace_file", err);
|
|
294
|
+
return { content: [{ type: "text", text: `Error writing file: ${err.message}` }] };
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
// ── Create Workspace File (zero-token ACK) ───────────────────────────
|
|
298
|
+
async function handleCreateWorkspaceFile(args) {
|
|
299
|
+
const filePath = args?.filePath;
|
|
300
|
+
const content = args?.content;
|
|
301
|
+
if (!filePath || content === undefined)
|
|
302
|
+
throw new Error("filePath and content are required");
|
|
303
|
+
const workspaceRoot = process.cwd();
|
|
304
|
+
try {
|
|
305
|
+
const { resolved } = (0, utils_1.safeResolvePath)(workspaceRoot, filePath);
|
|
306
|
+
if (fs_1.default.existsSync(resolved)) {
|
|
307
|
+
return { content: [{ type: "text", text: `Error: File already exists at ${filePath}. Use write_workspace_file or apply_workspace_patch to modify it.` }] };
|
|
308
|
+
}
|
|
309
|
+
const dir = path_1.default.dirname(resolved);
|
|
310
|
+
if (!fs_1.default.existsSync(dir)) {
|
|
311
|
+
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
312
|
+
}
|
|
313
|
+
fs_1.default.writeFileSync(resolved, content, "utf8");
|
|
314
|
+
(0, ExecAuditLog_1.recordExecAudit)({ tool: "create_workspace_file", detail: resolved, allowed: true });
|
|
315
|
+
// Minimal ACK — no content echoed back to save provider output tokens
|
|
316
|
+
return { content: [{ type: "text", text: `OK:created:${filePath}` }] };
|
|
317
|
+
}
|
|
318
|
+
catch (err) {
|
|
319
|
+
(0, utils_1.logError)("create_workspace_file", err);
|
|
320
|
+
return { content: [{ type: "text", text: `Error creating file: ${err.message}` }] };
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* `read_workspace_file` now returns a "123| code" gutter, which makes it easy to paste a block
|
|
325
|
+
* back into a patch with the numbers still attached. That block matches nothing on disk, so the
|
|
326
|
+
* patch fails for a reason that has nothing to do with the edit. Strip the gutter when *every*
|
|
327
|
+
* non-empty line carries one — a uniform prefix is a gutter; a lone "12| " inside real code is
|
|
328
|
+
* not, and must be left alone.
|
|
329
|
+
*/
|
|
330
|
+
function stripLineNumberGutter(text) {
|
|
331
|
+
const lines = text.split("\n");
|
|
332
|
+
const nonEmpty = lines.filter((l) => l.trim().length > 0);
|
|
333
|
+
if (nonEmpty.length === 0)
|
|
334
|
+
return text;
|
|
335
|
+
const GUTTER = /^\s*\d+\|\s?/;
|
|
336
|
+
if (!nonEmpty.every((l) => GUTTER.test(l)))
|
|
337
|
+
return text;
|
|
338
|
+
return lines.map((l) => l.replace(GUTTER, "")).join("\n");
|
|
339
|
+
}
|
|
340
|
+
// Splices one resolved match into the file and writes it. Shared by the normal
|
|
341
|
+
// single-match path and the ambiguous-match-resolved-via-elicitation path below.
|
|
342
|
+
async function applyMatch(match, filePath, resolved, originalContent, searchContent, replaceContent) {
|
|
343
|
+
let updatedContent;
|
|
344
|
+
if (match.strategy === "exact" && match.charStart !== undefined && match.charEnd !== undefined) {
|
|
345
|
+
// Splice by character offset — the search block may be a mid-line fragment, and
|
|
346
|
+
// a whole-line splice would discard everything else sharing that line.
|
|
347
|
+
updatedContent = originalContent.slice(0, match.charStart) + replaceContent + originalContent.slice(match.charEnd);
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
const contentLines = originalContent.split("\n");
|
|
351
|
+
const finalReplace = (0, PatchMatcher_1.reindentReplacement)(replaceContent, searchContent, contentLines[match.startLine]);
|
|
352
|
+
const updatedLines = [...contentLines.slice(0, match.startLine), ...finalReplace.split("\n"), ...contentLines.slice(match.endLine + 1)];
|
|
353
|
+
updatedContent = updatedLines.join("\n");
|
|
354
|
+
}
|
|
355
|
+
const elicited = await (0, utils_1.tryElicitConfirmation)(`Apply a patch to ${filePath}? This replaces ${searchContent.length} char(s) with ${replaceContent.length} char(s) ` +
|
|
356
|
+
`starting at line ${match.startLine + 1}.`);
|
|
357
|
+
if (elicited.supported && !elicited.confirmed) {
|
|
358
|
+
return { content: [{ type: "text", text: `Patch to ${filePath} was not applied: declined during confirmation.` }] };
|
|
359
|
+
}
|
|
360
|
+
fs_1.default.writeFileSync(resolved, updatedContent, "utf8");
|
|
361
|
+
(0, ExecAuditLog_1.recordExecAudit)({ tool: "apply_workspace_patch", detail: resolved, allowed: true });
|
|
362
|
+
const note = match.strategy === "exact" ? "" : ` (matched via ${match.strategy}, score ${match.score.toFixed(2)})`;
|
|
363
|
+
const blastRadius = (0, workspaceShared_1.formatBlastRadiusNote)((0, TheBrainV2_1.getBrain)().findBlastRadius(filePath));
|
|
364
|
+
return { content: [{ type: "text", text: `Success: Patch successfully applied to ${filePath}${note}${blastRadius}` }] };
|
|
365
|
+
}
|
|
366
|
+
async function handleApplyWorkspacePatch(args) {
|
|
367
|
+
const filePath = args?.filePath;
|
|
368
|
+
const rawSearch = args?.searchContent;
|
|
369
|
+
const rawReplace = args?.replaceContent;
|
|
370
|
+
if (!filePath || !rawSearch || rawReplace === undefined) {
|
|
371
|
+
throw new Error("filePath, searchContent, and replaceContent are required");
|
|
372
|
+
}
|
|
373
|
+
const searchContent = stripLineNumberGutter(rawSearch);
|
|
374
|
+
// Only strip the replacement's gutter when the search block had one too: that pairing means
|
|
375
|
+
// the model was working from a numbered read. Stripping unconditionally would mangle a
|
|
376
|
+
// replacement that legitimately contains "1| " (a table, a doc block).
|
|
377
|
+
const replaceContent = searchContent !== rawSearch ? stripLineNumberGutter(rawReplace) : rawReplace;
|
|
378
|
+
const workspaceRoot = process.cwd();
|
|
379
|
+
try {
|
|
380
|
+
const { resolved } = (0, utils_1.safeResolvePath)(workspaceRoot, filePath);
|
|
381
|
+
if (!fs_1.default.existsSync(resolved)) {
|
|
382
|
+
return { content: [{ type: "text", text: `Error: File ${filePath} does not exist.` }] };
|
|
383
|
+
}
|
|
384
|
+
const originalContent = fs_1.default.readFileSync(resolved, "utf8");
|
|
385
|
+
const matchResult = (0, PatchMatcher_1.findMatch)(originalContent, searchContent);
|
|
386
|
+
if (!Array.isArray(matchResult)) {
|
|
387
|
+
if (matchResult.reason === "ambiguous") {
|
|
388
|
+
const candidates = matchResult.candidates ?? [];
|
|
389
|
+
if (candidates.length > 0) {
|
|
390
|
+
const chosen = await (0, utils_1.tryElicitChoice)(`${candidates.length} equally good matches found for the search content in ${filePath}. Which one should be patched?`, candidates.map((c) => ({
|
|
391
|
+
title: `line ${c.startLine + 1}: ${c.matchedText.split("\n")[0].slice(0, 80)}`,
|
|
392
|
+
})));
|
|
393
|
+
if (chosen.index !== null) {
|
|
394
|
+
return applyMatch(candidates[chosen.index], filePath, resolved, originalContent, searchContent, replaceContent);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return {
|
|
398
|
+
content: [
|
|
399
|
+
{
|
|
400
|
+
type: "text",
|
|
401
|
+
text: `Error: Multiple matches found for the search content. Please provide a larger search block with unique surrounding context lines to make it unambiguous.`,
|
|
402
|
+
},
|
|
403
|
+
],
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
if (matchResult.candidateDiff) {
|
|
407
|
+
return {
|
|
408
|
+
content: [
|
|
409
|
+
{
|
|
410
|
+
type: "text",
|
|
411
|
+
text: `Error: No match found for the search content. Closest candidate starts at line ${matchResult.candidateStartLine} (- = your searchContent, + = actual file content):\n\n${matchResult.candidateDiff}`,
|
|
412
|
+
},
|
|
413
|
+
],
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
return {
|
|
417
|
+
content: [
|
|
418
|
+
{
|
|
419
|
+
type: "text",
|
|
420
|
+
text: `Error: Target search content not found in file, and no similar block was found to diff against.`,
|
|
421
|
+
},
|
|
422
|
+
],
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
return applyMatch(matchResult[0], filePath, resolved, originalContent, searchContent, replaceContent);
|
|
426
|
+
}
|
|
427
|
+
catch (err) {
|
|
428
|
+
(0, utils_1.logError)("apply_workspace_patch", err);
|
|
429
|
+
return { content: [{ type: "text", text: `Error applying patch: ${err.message}` }] };
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
// Async replacement for spawnSync: a blocking syscall inside a `tools/call` handler
|
|
433
|
+
// freezes the whole (single-threaded) MCP server for the run's entire duration — including
|
|
434
|
+
// task-status polls for THIS run once it's task-augmented (see runAsTask in tasks.ts), which
|
|
435
|
+
// would otherwise defeat the point of making the tool pollable. `spawn` keeps the event loop
|
|
436
|
+
// free while the command runs. Shape of the resolved value mirrors spawnSync's return value
|
|
437
|
+
// on the fields the caller actually reads, so the rest of handleRunWorkspaceCommand is unchanged.
|
|
438
|
+
function spawnCollect(command, cwd, timeoutMs) {
|
|
439
|
+
return new Promise((resolve) => {
|
|
440
|
+
const child = (0, child_process_1.spawn)(command, {
|
|
441
|
+
cwd,
|
|
442
|
+
shell: true,
|
|
443
|
+
env: { ...process.env },
|
|
444
|
+
// spawnSync closed stdin immediately (no `input` option given), so a command reading
|
|
445
|
+
// from stdin (e.g. `sed` with no file argument) saw EOF right away. Plain `spawn`
|
|
446
|
+
// leaves stdin as an open pipe by default — nothing ever writes to or closes it — so
|
|
447
|
+
// the same command hangs until the timeout kills it. "ignore" reproduces the old,
|
|
448
|
+
// immediate-EOF behavior.
|
|
449
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
450
|
+
});
|
|
451
|
+
let stdout = "";
|
|
452
|
+
let stderr = "";
|
|
453
|
+
let stdoutBytes = 0;
|
|
454
|
+
let stderrBytes = 0;
|
|
455
|
+
const MAX_BUFFER = 20 * 1024 * 1024;
|
|
456
|
+
let timedOut = false;
|
|
457
|
+
let settled = false;
|
|
458
|
+
const timer = setTimeout(() => {
|
|
459
|
+
timedOut = true;
|
|
460
|
+
child.kill("SIGTERM");
|
|
461
|
+
}, timeoutMs);
|
|
462
|
+
child.stdout?.on("data", (chunk) => {
|
|
463
|
+
if (stdoutBytes >= MAX_BUFFER)
|
|
464
|
+
return;
|
|
465
|
+
stdoutBytes += chunk.length;
|
|
466
|
+
stdout += chunk.toString("utf8");
|
|
467
|
+
});
|
|
468
|
+
child.stderr?.on("data", (chunk) => {
|
|
469
|
+
if (stderrBytes >= MAX_BUFFER)
|
|
470
|
+
return;
|
|
471
|
+
stderrBytes += chunk.length;
|
|
472
|
+
stderr += chunk.toString("utf8");
|
|
473
|
+
});
|
|
474
|
+
child.on("error", (err) => {
|
|
475
|
+
if (settled)
|
|
476
|
+
return;
|
|
477
|
+
settled = true;
|
|
478
|
+
clearTimeout(timer);
|
|
479
|
+
resolve({ stdout, stderr, status: null, timedOut, error: err });
|
|
480
|
+
});
|
|
481
|
+
child.on("close", (code) => {
|
|
482
|
+
if (settled)
|
|
483
|
+
return;
|
|
484
|
+
settled = true;
|
|
485
|
+
clearTimeout(timer);
|
|
486
|
+
resolve({ stdout, stderr, status: code, timedOut });
|
|
487
|
+
});
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
async function handleRunWorkspaceCommand(args) {
|
|
491
|
+
const command = args?.command;
|
|
492
|
+
if (!command)
|
|
493
|
+
throw new Error("command is required");
|
|
494
|
+
// ── Security: allowlist check ──────────────────────────────────────────────
|
|
495
|
+
const check = (0, utils_1.isCommandAllowed)(command);
|
|
496
|
+
if (!check.allowed) {
|
|
497
|
+
(0, ExecAuditLog_1.recordExecAudit)({ tool: "run_workspace_command", detail: command, allowed: false, reason: check.reason });
|
|
498
|
+
const allowed = (0, utils_1.loadAllowedCommands)().join(', ');
|
|
499
|
+
return {
|
|
500
|
+
content: [{
|
|
501
|
+
type: "text",
|
|
502
|
+
text: [
|
|
503
|
+
`❌ Command blocked by Lemma security policy.`,
|
|
504
|
+
``,
|
|
505
|
+
`Command: ${command}`,
|
|
506
|
+
`Reason: ${check.reason ?? "The base command is not in the allowed list."}`,
|
|
507
|
+
``,
|
|
508
|
+
`Allowed command prefixes:`,
|
|
509
|
+
` ${allowed}`,
|
|
510
|
+
``,
|
|
511
|
+
`To extend the allowlist, add to lemma.config.json:`,
|
|
512
|
+
` { "mcp": { "allowedCommandPrefixes": ["your-command"] } }`,
|
|
513
|
+
].join("\n"),
|
|
514
|
+
}],
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
// ── End allowlist check ────────────────────────────────────────────────
|
|
518
|
+
const workspaceRoot = process.cwd();
|
|
519
|
+
try {
|
|
520
|
+
// spawn (via spawnCollect above) rather than execSync: execSync leaves stderr attached to
|
|
521
|
+
// the parent unless stdio is overridden, which silently dropped the output of every tool
|
|
522
|
+
// that reports on stderr (jest and tsc both do) on a successful run. It also gives us
|
|
523
|
+
// stdout, stderr and the exit code through one code path instead of a throw-on-failure split.
|
|
524
|
+
// 15s was below the runtime of the commands this tool exists for: a real `npm test` or
|
|
525
|
+
// `tsc --noEmit` always tripped it, so the distillation pipeline never ran on the output
|
|
526
|
+
// it was built for and the call was pure overhead before falling back to a plain shell.
|
|
527
|
+
const DEFAULT_TIMEOUT_MS = 120000;
|
|
528
|
+
const MAX_TIMEOUT_MS = 600000;
|
|
529
|
+
const requested = typeof args?.timeoutMs === "number" && args.timeoutMs > 0 ? args.timeoutMs : DEFAULT_TIMEOUT_MS;
|
|
530
|
+
const timeoutMs = Math.min(Math.floor(requested), MAX_TIMEOUT_MS);
|
|
531
|
+
const elicited = await (0, utils_1.tryElicitConfirmation)(`Run this command in the workspace root?\n\n${command}`);
|
|
532
|
+
if (elicited.supported && !elicited.confirmed) {
|
|
533
|
+
return { content: [{ type: "text", text: `Command was not run: declined during confirmation.\n\nCommand: ${command}` }] };
|
|
534
|
+
}
|
|
535
|
+
const result = await spawnCollect(command, workspaceRoot, timeoutMs);
|
|
536
|
+
const timedOut = result.timedOut;
|
|
537
|
+
(0, ExecAuditLog_1.recordExecAudit)({
|
|
538
|
+
tool: "run_workspace_command",
|
|
539
|
+
detail: command,
|
|
540
|
+
allowed: true,
|
|
541
|
+
exitCode: result.status,
|
|
542
|
+
reason: timedOut ? "timed out" : undefined,
|
|
543
|
+
});
|
|
544
|
+
if (result.error && !timedOut) {
|
|
545
|
+
return {
|
|
546
|
+
content: [{ type: "text", text: `Command could not be executed: ${result.error.message}` }],
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
const stdout = result.stdout || "";
|
|
550
|
+
const stderr = result.stderr || "";
|
|
551
|
+
const combined = [stdout, stderr].filter((s) => s.trim().length > 0).join("\n");
|
|
552
|
+
const status = result.status ?? 0;
|
|
553
|
+
// A timed-out run still produced output, and that partial output is normally where the
|
|
554
|
+
// failure is. Discarding it forced the whole command to be re-run somewhere else.
|
|
555
|
+
const header = timedOut
|
|
556
|
+
? `Command timed out after ${Math.round(timeoutMs / 1000)}s (killed): ${command}\nOutput produced before the kill is below — it may be incomplete. Re-run with a higher timeoutMs if it was still making progress.`
|
|
557
|
+
: status === 0
|
|
558
|
+
? "Command completed successfully."
|
|
559
|
+
: `Command failed with exit code ${status}.`;
|
|
560
|
+
if (!combined.trim()) {
|
|
561
|
+
return { content: [{ type: "text", text: `${header}\n\n(no output)` }] };
|
|
562
|
+
}
|
|
563
|
+
const distilled = (0, CommandOutputDistiller_1.distillCommandOutput)(combined, { command, raw: args?.raw === true });
|
|
564
|
+
if (distilled.handle) {
|
|
565
|
+
(0, TokenReceipt_1.recordReceiptEvent)("tool_call", `run_workspace_command distilled (${distilled.format})`, {
|
|
566
|
+
command,
|
|
567
|
+
originalChars: distilled.originalChars,
|
|
568
|
+
distilledChars: distilled.distilledChars,
|
|
569
|
+
handle: distilled.handle,
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
// A debug loop runs the same command repeatedly and the output barely moves between
|
|
573
|
+
// runs. The header is part of the compared text on purpose: a pass/fail flip must never
|
|
574
|
+
// be reported as "identical", even in the rare case where the body alone matches.
|
|
575
|
+
// The footer is deliberately excluded and always re-appended — it carries this run's
|
|
576
|
+
// `output_region` handle, which is different every time and must stay usable.
|
|
577
|
+
const body = `${header}\n\nOutput:\n${distilled.text}`;
|
|
578
|
+
const footer = (0, CommandOutputDistiller_1.buildDistillFooter)(distilled);
|
|
579
|
+
const key = (0, OutputLedger_1.ledgerKey)("run_workspace_command", { command, cwd: workspaceRoot, raw: args?.raw === true });
|
|
580
|
+
const ledger = (0, OutputLedger_1.checkOutput)(key, body, {
|
|
581
|
+
label: `\`${command}\``,
|
|
582
|
+
rerunHint: "The command did run again — this reports its result, it does not skip execution.",
|
|
583
|
+
});
|
|
584
|
+
(0, OutputLedger_1.recordOutput)(key, body);
|
|
585
|
+
if (ledger.replacement) {
|
|
586
|
+
(0, reportSavings_1.reportSavings)({
|
|
587
|
+
source: "contextSqueeze",
|
|
588
|
+
charsBefore: body.length,
|
|
589
|
+
charsAfter: ledger.replacement.length,
|
|
590
|
+
toolName: "run_workspace_command",
|
|
591
|
+
});
|
|
592
|
+
(0, TokenReceipt_1.recordReceiptEvent)("tool_call", `run_workspace_command ${ledger.status} vs. earlier run`, {
|
|
593
|
+
command,
|
|
594
|
+
savedChars: ledger.savedChars,
|
|
595
|
+
});
|
|
596
|
+
return { content: [{ type: "text", text: ledger.replacement + footer }] };
|
|
597
|
+
}
|
|
598
|
+
return {
|
|
599
|
+
content: [
|
|
600
|
+
{ type: "text", text: body + footer },
|
|
601
|
+
],
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
catch (err) {
|
|
605
|
+
return {
|
|
606
|
+
content: [
|
|
607
|
+
{
|
|
608
|
+
type: "text",
|
|
609
|
+
text: `Command could not be executed: ${err?.message || String(err)}`,
|
|
610
|
+
},
|
|
611
|
+
],
|
|
612
|
+
};
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
async function handleOutputRegion(args) {
|
|
616
|
+
const handle = args?.handle;
|
|
617
|
+
if (!handle)
|
|
618
|
+
throw new Error("handle is required");
|
|
619
|
+
const region = (0, CommandOutputDistiller_1.readRegion)({
|
|
620
|
+
handle,
|
|
621
|
+
section: args?.section,
|
|
622
|
+
startLine: args?.startLine,
|
|
623
|
+
endLine: args?.endLine,
|
|
624
|
+
all: args?.all === true,
|
|
625
|
+
});
|
|
626
|
+
if (!region.found) {
|
|
627
|
+
const parts = [region.error ?? `Could not read region for handle "${handle}".`];
|
|
628
|
+
if (region.availableSections?.length) {
|
|
629
|
+
parts.push("", "Available sections:", ...region.availableSections.map((s) => ` ${s}`));
|
|
630
|
+
}
|
|
631
|
+
return { content: [{ type: "text", text: parts.join("\n") }] };
|
|
632
|
+
}
|
|
633
|
+
const scope = region.startLine === 1 && region.endLine === region.totalLines
|
|
634
|
+
? `complete output (${region.totalLines} lines)`
|
|
635
|
+
: `lines ${region.startLine}-${region.endLine} of ${region.totalLines}`;
|
|
636
|
+
return {
|
|
637
|
+
content: [
|
|
638
|
+
{
|
|
639
|
+
type: "text",
|
|
640
|
+
text: `Raw output for \`${region.command ?? "?"}\` — ${scope}, verbatim:\n\n${region.text}`,
|
|
641
|
+
},
|
|
642
|
+
],
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
async function handleListWorkspaceDir(args) {
|
|
646
|
+
const dirPath = args?.dirPath || "";
|
|
647
|
+
const maxDepth = args?.maxDepth || 3;
|
|
648
|
+
const workspaceRoot = process.cwd();
|
|
649
|
+
try {
|
|
650
|
+
const { resolved } = (0, utils_1.safeResolvePath)(workspaceRoot, dirPath);
|
|
651
|
+
const list = (0, workspaceShared_1.listDirRecursive)(resolved, dirPath, 1, maxDepth);
|
|
652
|
+
return {
|
|
653
|
+
content: [
|
|
654
|
+
{
|
|
655
|
+
type: "text",
|
|
656
|
+
text: list.length > 0 ? list.join("\n") : "(Directory is empty or inaccessible)",
|
|
657
|
+
},
|
|
658
|
+
],
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
catch (err) {
|
|
662
|
+
(0, utils_1.logError)("list_workspace_dir", err);
|
|
663
|
+
return { content: [{ type: "text", text: `Error listing directory: ${err.message}` }] };
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
exports.WORKSPACE_TOOL_HANDLERS = {
|
|
667
|
+
read_workspace_file: handleReadWorkspaceFile,
|
|
668
|
+
write_workspace_file: handleWriteWorkspaceFile,
|
|
669
|
+
create_workspace_file: handleCreateWorkspaceFile,
|
|
670
|
+
apply_workspace_patch: handleApplyWorkspacePatch,
|
|
671
|
+
run_workspace_command: handleRunWorkspaceCommand,
|
|
672
|
+
output_region: handleOutputRegion,
|
|
673
|
+
list_workspace_dir: handleListWorkspaceDir,
|
|
674
|
+
};
|
|
675
|
+
//# sourceMappingURL=workspace.js.map
|