mindweave 0.0.1 → 2.1.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/LICENSE +190 -0
- package/README.md +171 -14
- package/dist/alternator/chassis/cache.js +47 -0
- package/dist/alternator/chassis/cache.js.map +1 -0
- package/dist/alternator/chassis/domRefs.js +53 -0
- package/dist/alternator/chassis/domRefs.js.map +1 -0
- package/dist/alternator/chassis/extractWorker.js +65 -0
- package/dist/alternator/chassis/extractWorker.js.map +1 -0
- package/dist/alternator/chassis/graph.js +221 -0
- package/dist/alternator/chassis/graph.js.map +1 -0
- package/dist/alternator/chassis/index.js +463 -0
- package/dist/alternator/chassis/index.js.map +1 -0
- package/dist/alternator/chassis/isolation.js +336 -0
- package/dist/alternator/chassis/isolation.js.map +1 -0
- package/dist/alternator/chassis/langCases.js +69 -0
- package/dist/alternator/chassis/langCases.js.map +1 -0
- package/dist/alternator/chassis/lsp.js +469 -0
- package/dist/alternator/chassis/lsp.js.map +1 -0
- package/dist/alternator/chassis/markup.js +262 -0
- package/dist/alternator/chassis/markup.js.map +1 -0
- package/dist/alternator/chassis/provision.js +198 -0
- package/dist/alternator/chassis/provision.js.map +1 -0
- package/dist/alternator/chassis/rank.js +72 -0
- package/dist/alternator/chassis/rank.js.map +1 -0
- package/dist/alternator/chassis/servers.js +215 -0
- package/dist/alternator/chassis/servers.js.map +1 -0
- package/dist/alternator/chassis/treesitter.js +608 -0
- package/dist/alternator/chassis/treesitter.js.map +1 -0
- package/dist/alternator/chassis/types.js +24 -0
- package/dist/alternator/chassis/types.js.map +1 -0
- package/dist/alternator/lane.js +67 -0
- package/dist/alternator/lane.js.map +1 -0
- package/dist/cli/App.js +2586 -0
- package/dist/cli/App.js.map +1 -0
- package/dist/cli/altScreen.js +67 -0
- package/dist/cli/altScreen.js.map +1 -0
- package/dist/cli/approvalChannel.js +72 -0
- package/dist/cli/approvalChannel.js.map +1 -0
- package/dist/cli/attachments.js +188 -0
- package/dist/cli/attachments.js.map +1 -0
- package/dist/cli/bootstrap.js +279 -0
- package/dist/cli/bootstrap.js.map +1 -0
- package/dist/cli/chatAnchor.js +94 -0
- package/dist/cli/chatAnchor.js.map +1 -0
- package/dist/cli/commandArgs.js +79 -0
- package/dist/cli/commandArgs.js.map +1 -0
- package/dist/cli/commandRoute.js +78 -0
- package/dist/cli/commandRoute.js.map +1 -0
- package/dist/cli/compaction.js +69 -0
- package/dist/cli/compaction.js.map +1 -0
- package/dist/cli/components/ApprovalBox.js +100 -0
- package/dist/cli/components/ApprovalBox.js.map +1 -0
- package/dist/cli/components/BlockView.js +128 -0
- package/dist/cli/components/BlockView.js.map +1 -0
- package/dist/cli/components/FirstRunFrame.js +41 -0
- package/dist/cli/components/FirstRunFrame.js.map +1 -0
- package/dist/cli/components/KeyManager.js +197 -0
- package/dist/cli/components/KeyManager.js.map +1 -0
- package/dist/cli/components/KeySetup.js +125 -0
- package/dist/cli/components/KeySetup.js.map +1 -0
- package/dist/cli/components/MenuFrame.js +24 -0
- package/dist/cli/components/MenuFrame.js.map +1 -0
- package/dist/cli/components/Picker.js +82 -0
- package/dist/cli/components/Picker.js.map +1 -0
- package/dist/cli/components/PromptInput.js +509 -0
- package/dist/cli/components/PromptInput.js.map +1 -0
- package/dist/cli/components/SubagentView.js +86 -0
- package/dist/cli/components/SubagentView.js.map +1 -0
- package/dist/cli/components/ToolGroup.js +60 -0
- package/dist/cli/components/ToolGroup.js.map +1 -0
- package/dist/cli/components/ToolLine.js +123 -0
- package/dist/cli/components/ToolLine.js.map +1 -0
- package/dist/cli/components/TrustGate.js +37 -0
- package/dist/cli/components/TrustGate.js.map +1 -0
- package/dist/cli/costView.js +40 -0
- package/dist/cli/costView.js.map +1 -0
- package/dist/cli/frameRate.js +30 -0
- package/dist/cli/frameRate.js.map +1 -0
- package/dist/cli/framebuffer/paint.js +165 -0
- package/dist/cli/framebuffer/paint.js.map +1 -0
- package/dist/cli/framebuffer/parse.js +266 -0
- package/dist/cli/framebuffer/parse.js.map +1 -0
- package/dist/cli/framebuffer/screen.js +196 -0
- package/dist/cli/framebuffer/screen.js.map +1 -0
- package/dist/cli/framebuffer/writer.js +139 -0
- package/dist/cli/framebuffer/writer.js.map +1 -0
- package/dist/cli/groupReveal.js +51 -0
- package/dist/cli/groupReveal.js.map +1 -0
- package/dist/cli/help.js +55 -0
- package/dist/cli/help.js.map +1 -0
- package/dist/cli/inputView.js +105 -0
- package/dist/cli/inputView.js.map +1 -0
- package/dist/cli/keyManager.js +65 -0
- package/dist/cli/keyManager.js.map +1 -0
- package/dist/cli/keySetup.js +35 -0
- package/dist/cli/keySetup.js.map +1 -0
- package/dist/cli/keyStore.js +73 -0
- package/dist/cli/keyStore.js.map +1 -0
- package/dist/cli/markdown.js +460 -0
- package/dist/cli/markdown.js.map +1 -0
- package/dist/cli/messageQueue.js +96 -0
- package/dist/cli/messageQueue.js.map +1 -0
- package/dist/cli/modes.js +90 -0
- package/dist/cli/modes.js.map +1 -0
- package/dist/cli/mouse.js +78 -0
- package/dist/cli/mouse.js.map +1 -0
- package/dist/cli/pasteAssembler.js +44 -0
- package/dist/cli/pasteAssembler.js.map +1 -0
- package/dist/cli/pathComplete.js +39 -0
- package/dist/cli/pathComplete.js.map +1 -0
- package/dist/cli/perfLog.js +90 -0
- package/dist/cli/perfLog.js.map +1 -0
- package/dist/cli/reveal.js +32 -0
- package/dist/cli/reveal.js.map +1 -0
- package/dist/cli/revealPace.js +59 -0
- package/dist/cli/revealPace.js.map +1 -0
- package/dist/cli/sessionCarry.js +19 -0
- package/dist/cli/sessionCarry.js.map +1 -0
- package/dist/cli/smoothScroll.js +74 -0
- package/dist/cli/smoothScroll.js.map +1 -0
- package/dist/cli/startupArgs.js +96 -0
- package/dist/cli/startupArgs.js.map +1 -0
- package/dist/cli/terminalRestore.js +34 -0
- package/dist/cli/terminalRestore.js.map +1 -0
- package/dist/cli/toolDisplay.js +219 -0
- package/dist/cli/toolDisplay.js.map +1 -0
- package/dist/cli/toolItems.js +65 -0
- package/dist/cli/toolItems.js.map +1 -0
- package/dist/cli/transcript.js +351 -0
- package/dist/cli/transcript.js.map +1 -0
- package/dist/cli/trust.js +79 -0
- package/dist/cli/trust.js.map +1 -0
- package/dist/cli/updateCheck.js +107 -0
- package/dist/cli/updateCheck.js.map +1 -0
- package/dist/cli/version.js +39 -0
- package/dist/cli/version.js.map +1 -0
- package/dist/cli/viewport.js +179 -0
- package/dist/cli/viewport.js.map +1 -0
- package/dist/cli/virtualWindow.js +103 -0
- package/dist/cli/virtualWindow.js.map +1 -0
- package/dist/cli/workingVerb.js +37 -0
- package/dist/cli/workingVerb.js.map +1 -0
- package/dist/cli/wrap.js +145 -0
- package/dist/cli/wrap.js.map +1 -0
- package/dist/drivers/anthropic/cachePoints.js +77 -0
- package/dist/drivers/anthropic/cachePoints.js.map +1 -0
- package/dist/drivers/anthropic/client.js +432 -0
- package/dist/drivers/anthropic/client.js.map +1 -0
- package/dist/drivers/anthropic/index.js +10 -0
- package/dist/drivers/anthropic/index.js.map +1 -0
- package/dist/drivers/anthropic/manifest.js +221 -0
- package/dist/drivers/anthropic/manifest.js.map +1 -0
- package/dist/drivers/cerebras/client.js +69 -0
- package/dist/drivers/cerebras/client.js.map +1 -0
- package/dist/drivers/cerebras/index.js +5 -0
- package/dist/drivers/cerebras/index.js.map +1 -0
- package/dist/drivers/cerebras/manifest.js +140 -0
- package/dist/drivers/cerebras/manifest.js.map +1 -0
- package/dist/drivers/clientId.js +41 -0
- package/dist/drivers/clientId.js.map +1 -0
- package/dist/drivers/contextOverflow.js +77 -0
- package/dist/drivers/contextOverflow.js.map +1 -0
- package/dist/drivers/deepseek/client.js +168 -0
- package/dist/drivers/deepseek/client.js.map +1 -0
- package/dist/drivers/deepseek/index.js +16 -0
- package/dist/drivers/deepseek/index.js.map +1 -0
- package/dist/drivers/deepseek/inlineTools.js +46 -0
- package/dist/drivers/deepseek/inlineTools.js.map +1 -0
- package/dist/drivers/deepseek/manifest.js +166 -0
- package/dist/drivers/deepseek/manifest.js.map +1 -0
- package/dist/drivers/gemini/client.js +38 -0
- package/dist/drivers/gemini/client.js.map +1 -0
- package/dist/drivers/gemini/index.js +5 -0
- package/dist/drivers/gemini/index.js.map +1 -0
- package/dist/drivers/gemini/manifest.js +150 -0
- package/dist/drivers/gemini/manifest.js.map +1 -0
- package/dist/drivers/glm/client.js +90 -0
- package/dist/drivers/glm/client.js.map +1 -0
- package/dist/drivers/glm/index.js +9 -0
- package/dist/drivers/glm/index.js.map +1 -0
- package/dist/drivers/glm/manifest.js +183 -0
- package/dist/drivers/glm/manifest.js.map +1 -0
- package/dist/drivers/groq/client.js +80 -0
- package/dist/drivers/groq/client.js.map +1 -0
- package/dist/drivers/groq/index.js +5 -0
- package/dist/drivers/groq/index.js.map +1 -0
- package/dist/drivers/groq/manifest.js +160 -0
- package/dist/drivers/groq/manifest.js.map +1 -0
- package/dist/drivers/kimi/client.js +82 -0
- package/dist/drivers/kimi/client.js.map +1 -0
- package/dist/drivers/kimi/index.js +9 -0
- package/dist/drivers/kimi/index.js.map +1 -0
- package/dist/drivers/kimi/manifest.js +168 -0
- package/dist/drivers/kimi/manifest.js.map +1 -0
- package/dist/drivers/meta/client.js +30 -0
- package/dist/drivers/meta/client.js.map +1 -0
- package/dist/drivers/meta/index.js +5 -0
- package/dist/drivers/meta/index.js.map +1 -0
- package/dist/drivers/meta/manifest.js +101 -0
- package/dist/drivers/meta/manifest.js.map +1 -0
- package/dist/drivers/minimax/client.js +36 -0
- package/dist/drivers/minimax/client.js.map +1 -0
- package/dist/drivers/minimax/index.js +5 -0
- package/dist/drivers/minimax/index.js.map +1 -0
- package/dist/drivers/minimax/manifest.js +120 -0
- package/dist/drivers/minimax/manifest.js.map +1 -0
- package/dist/drivers/mistral/client.js +54 -0
- package/dist/drivers/mistral/client.js.map +1 -0
- package/dist/drivers/mistral/index.js +5 -0
- package/dist/drivers/mistral/index.js.map +1 -0
- package/dist/drivers/mistral/manifest.js +118 -0
- package/dist/drivers/mistral/manifest.js.map +1 -0
- package/dist/drivers/openai/client.js +290 -0
- package/dist/drivers/openai/client.js.map +1 -0
- package/dist/drivers/openai/index.js +9 -0
- package/dist/drivers/openai/index.js.map +1 -0
- package/dist/drivers/openai/manifest.js +133 -0
- package/dist/drivers/openai/manifest.js.map +1 -0
- package/dist/drivers/openaiCompat/wire.js +493 -0
- package/dist/drivers/openaiCompat/wire.js.map +1 -0
- package/dist/drivers/partialTurn.js +23 -0
- package/dist/drivers/partialTurn.js.map +1 -0
- package/dist/drivers/providerError.js +181 -0
- package/dist/drivers/providerError.js.map +1 -0
- package/dist/drivers/qwen/client.js +93 -0
- package/dist/drivers/qwen/client.js.map +1 -0
- package/dist/drivers/qwen/index.js +9 -0
- package/dist/drivers/qwen/index.js.map +1 -0
- package/dist/drivers/qwen/manifest.js +146 -0
- package/dist/drivers/qwen/manifest.js.map +1 -0
- package/dist/drivers/registry.js +177 -0
- package/dist/drivers/registry.js.map +1 -0
- package/dist/drivers/retryPolicy.js +129 -0
- package/dist/drivers/retryPolicy.js.map +1 -0
- package/dist/drivers/searchBlocks.js +61 -0
- package/dist/drivers/searchBlocks.js.map +1 -0
- package/dist/drivers/types.js +2 -0
- package/dist/drivers/types.js.map +1 -0
- package/dist/drivers/xai/client.js +63 -0
- package/dist/drivers/xai/client.js.map +1 -0
- package/dist/drivers/xai/index.js +5 -0
- package/dist/drivers/xai/index.js.map +1 -0
- package/dist/drivers/xai/manifest.js +137 -0
- package/dist/drivers/xai/manifest.js.map +1 -0
- package/dist/dynamo/_probe.tmp.js +20 -0
- package/dist/dynamo/_probe.tmp.js.map +1 -0
- package/dist/dynamo/cacheBreak.js +88 -0
- package/dist/dynamo/cacheBreak.js.map +1 -0
- package/dist/dynamo/contextWindow.js +243 -0
- package/dist/dynamo/contextWindow.js.map +1 -0
- package/dist/dynamo/engine.js +2011 -0
- package/dist/dynamo/engine.js.map +1 -0
- package/dist/dynamo/guard.js +132 -0
- package/dist/dynamo/guard.js.map +1 -0
- package/dist/dynamo/liveMeter.js +58 -0
- package/dist/dynamo/liveMeter.js.map +1 -0
- package/dist/dynamo/model.js +172 -0
- package/dist/dynamo/model.js.map +1 -0
- package/dist/dynamo/planArtifact.js +125 -0
- package/dist/dynamo/planArtifact.js.map +1 -0
- package/dist/dynamo/pricing.js +140 -0
- package/dist/dynamo/pricing.js.map +1 -0
- package/dist/dynamo/prompt.js +264 -0
- package/dist/dynamo/prompt.js.map +1 -0
- package/dist/dynamo/spend.js +45 -0
- package/dist/dynamo/spend.js.map +1 -0
- package/dist/dynamo/verify.js +483 -0
- package/dist/dynamo/verify.js.map +1 -0
- package/dist/governor/forbidden.js +181 -0
- package/dist/governor/forbidden.js.map +1 -0
- package/dist/governor/freshness.js +83 -0
- package/dist/governor/freshness.js.map +1 -0
- package/dist/governor/frontmatter.js +38 -0
- package/dist/governor/frontmatter.js.map +1 -0
- package/dist/governor/glob.js +75 -0
- package/dist/governor/glob.js.map +1 -0
- package/dist/governor/index.js +87 -0
- package/dist/governor/index.js.map +1 -0
- package/dist/governor/rules.js +80 -0
- package/dist/governor/rules.js.map +1 -0
- package/dist/governor/scope.js +91 -0
- package/dist/governor/scope.js.map +1 -0
- package/dist/governor/skills.js +176 -0
- package/dist/governor/skills.js.map +1 -0
- package/dist/governor/types.js +16 -0
- package/dist/governor/types.js.map +1 -0
- package/dist/governor/write.js +182 -0
- package/dist/governor/write.js.map +1 -0
- package/dist/index.js +89 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/catalog.js +232 -0
- package/dist/mcp/catalog.js.map +1 -0
- package/dist/mcp/config.js +116 -0
- package/dist/mcp/config.js.map +1 -0
- package/dist/mcp/configWrite.js +254 -0
- package/dist/mcp/configWrite.js.map +1 -0
- package/dist/mcp/connection.js +504 -0
- package/dist/mcp/connection.js.map +1 -0
- package/dist/mcp/deferred.js +104 -0
- package/dist/mcp/deferred.js.map +1 -0
- package/dist/mcp/discover.js +128 -0
- package/dist/mcp/discover.js.map +1 -0
- package/dist/mcp/manager.js +679 -0
- package/dist/mcp/manager.js.map +1 -0
- package/dist/mcp/paramHeaders.js +163 -0
- package/dist/mcp/paramHeaders.js.map +1 -0
- package/dist/mcp/prompts.js +136 -0
- package/dist/mcp/prompts.js.map +1 -0
- package/dist/mcp/protocol.js +171 -0
- package/dist/mcp/protocol.js.map +1 -0
- package/dist/mcp/resources.js +119 -0
- package/dist/mcp/resources.js.map +1 -0
- package/dist/mcp/resultStore.js +180 -0
- package/dist/mcp/resultStore.js.map +1 -0
- package/dist/mcp/subscriptions.js +74 -0
- package/dist/mcp/subscriptions.js.map +1 -0
- package/dist/mcp/transport/headerValue.js +40 -0
- package/dist/mcp/transport/headerValue.js.map +1 -0
- package/dist/mcp/transport/http.js +321 -0
- package/dist/mcp/transport/http.js.map +1 -0
- package/dist/mcp/transport/stdio.js +234 -0
- package/dist/mcp/transport/stdio.js.map +1 -0
- package/dist/mcp/transport/types.js +27 -0
- package/dist/mcp/transport/types.js.map +1 -0
- package/dist/mcp/trust.js +98 -0
- package/dist/mcp/trust.js.map +1 -0
- package/dist/mcp/trustStore.js +55 -0
- package/dist/mcp/trustStore.js.map +1 -0
- package/dist/memory/autoMemory.js +340 -0
- package/dist/memory/autoMemory.js.map +1 -0
- package/dist/memory/compaction.js +513 -0
- package/dist/memory/compaction.js.map +1 -0
- package/dist/memory/images.js +173 -0
- package/dist/memory/images.js.map +1 -0
- package/dist/memory/presence.js +59 -0
- package/dist/memory/presence.js.map +1 -0
- package/dist/memory/projectNotes.js +247 -0
- package/dist/memory/projectNotes.js.map +1 -0
- package/dist/memory/restore.js +72 -0
- package/dist/memory/restore.js.map +1 -0
- package/dist/memory/session.js +472 -0
- package/dist/memory/session.js.map +1 -0
- package/dist/memory/sessionMemory.js +142 -0
- package/dist/memory/sessionMemory.js.map +1 -0
- package/dist/memory/sessionMemoryCompact.js +136 -0
- package/dist/memory/sessionMemoryCompact.js.map +1 -0
- package/dist/memory/store.js +217 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/memory/types.js +14 -0
- package/dist/memory/types.js.map +1 -0
- package/dist/memory/workingSet.js +383 -0
- package/dist/memory/workingSet.js.map +1 -0
- package/dist/project/context.js +425 -0
- package/dist/project/context.js.map +1 -0
- package/dist/tools/approval.js +189 -0
- package/dist/tools/approval.js.map +1 -0
- package/dist/tools/askUser.js +103 -0
- package/dist/tools/askUser.js.map +1 -0
- package/dist/tools/atomicWrite.js +151 -0
- package/dist/tools/atomicWrite.js.map +1 -0
- package/dist/tools/backgroundShells.js +468 -0
- package/dist/tools/backgroundShells.js.map +1 -0
- package/dist/tools/captureSweep.js +77 -0
- package/dist/tools/captureSweep.js.map +1 -0
- package/dist/tools/chassisMux.js +92 -0
- package/dist/tools/chassisMux.js.map +1 -0
- package/dist/tools/checkpoints.js +328 -0
- package/dist/tools/checkpoints.js.map +1 -0
- package/dist/tools/codeIntel.js +267 -0
- package/dist/tools/codeIntel.js.map +1 -0
- package/dist/tools/deferredNative.js +121 -0
- package/dist/tools/deferredNative.js.map +1 -0
- package/dist/tools/detail.js +135 -0
- package/dist/tools/detail.js.map +1 -0
- package/dist/tools/diagnostics.js +174 -0
- package/dist/tools/diagnostics.js.map +1 -0
- package/dist/tools/edit.js +167 -0
- package/dist/tools/edit.js.map +1 -0
- package/dist/tools/editCore.js +283 -0
- package/dist/tools/editCore.js.map +1 -0
- package/dist/tools/editFile.js +183 -0
- package/dist/tools/editFile.js.map +1 -0
- package/dist/tools/editRipple.js +126 -0
- package/dist/tools/editRipple.js.map +1 -0
- package/dist/tools/editTarget.js +131 -0
- package/dist/tools/editTarget.js.map +1 -0
- package/dist/tools/editWindow.js +49 -0
- package/dist/tools/editWindow.js.map +1 -0
- package/dist/tools/eol.js +56 -0
- package/dist/tools/eol.js.map +1 -0
- package/dist/tools/exitPlan.js +175 -0
- package/dist/tools/exitPlan.js.map +1 -0
- package/dist/tools/focus.js +42 -0
- package/dist/tools/focus.js.map +1 -0
- package/dist/tools/gitignore.js +148 -0
- package/dist/tools/gitignore.js.map +1 -0
- package/dist/tools/glob.js +134 -0
- package/dist/tools/glob.js.map +1 -0
- package/dist/tools/governorTools.js +258 -0
- package/dist/tools/governorTools.js.map +1 -0
- package/dist/tools/grep.js +450 -0
- package/dist/tools/grep.js.map +1 -0
- package/dist/tools/guard.js +220 -0
- package/dist/tools/guard.js.map +1 -0
- package/dist/tools/killTree.js +215 -0
- package/dist/tools/killTree.js.map +1 -0
- package/dist/tools/listDir.js +143 -0
- package/dist/tools/listDir.js.map +1 -0
- package/dist/tools/mcpAdd.js +176 -0
- package/dist/tools/mcpAdd.js.map +1 -0
- package/dist/tools/mcpResources.js +116 -0
- package/dist/tools/mcpResources.js.map +1 -0
- package/dist/tools/mcpSearch.js +123 -0
- package/dist/tools/mcpSearch.js.map +1 -0
- package/dist/tools/multiEdit.js +168 -0
- package/dist/tools/multiEdit.js.map +1 -0
- package/dist/tools/paths.js +225 -0
- package/dist/tools/paths.js.map +1 -0
- package/dist/tools/posixShell.js +123 -0
- package/dist/tools/posixShell.js.map +1 -0
- package/dist/tools/readFile.js +371 -0
- package/dist/tools/readFile.js.map +1 -0
- package/dist/tools/readSymbol.js +145 -0
- package/dist/tools/readSymbol.js.map +1 -0
- package/dist/tools/registry.js +120 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/replaceSymbol.js +141 -0
- package/dist/tools/replaceSymbol.js.map +1 -0
- package/dist/tools/results.js +15 -0
- package/dist/tools/results.js.map +1 -0
- package/dist/tools/ripgrep.js +145 -0
- package/dist/tools/ripgrep.js.map +1 -0
- package/dist/tools/runCommand.js +633 -0
- package/dist/tools/runCommand.js.map +1 -0
- package/dist/tools/saveMemory.js +102 -0
- package/dist/tools/saveMemory.js.map +1 -0
- package/dist/tools/screenshot.js +200 -0
- package/dist/tools/screenshot.js.map +1 -0
- package/dist/tools/screenshotWin.js +227 -0
- package/dist/tools/screenshotWin.js.map +1 -0
- package/dist/tools/search.js +121 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/sessionTools.js +187 -0
- package/dist/tools/sessionTools.js.map +1 -0
- package/dist/tools/shellCheckpoint.js +123 -0
- package/dist/tools/shellCheckpoint.js.map +1 -0
- package/dist/tools/shellLint.js +102 -0
- package/dist/tools/shellLint.js.map +1 -0
- package/dist/tools/shellTools.js +203 -0
- package/dist/tools/shellTools.js.map +1 -0
- package/dist/tools/spanCore.js +78 -0
- package/dist/tools/spanCore.js.map +1 -0
- package/dist/tools/subagent.js +224 -0
- package/dist/tools/subagent.js.map +1 -0
- package/dist/tools/subagentReport.js +114 -0
- package/dist/tools/subagentReport.js.map +1 -0
- package/dist/tools/tempSweep.js +118 -0
- package/dist/tools/tempSweep.js.map +1 -0
- package/dist/tools/todo.js +117 -0
- package/dist/tools/todo.js.map +1 -0
- package/dist/tools/types.js +2 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/untrusted.js +46 -0
- package/dist/tools/untrusted.js.map +1 -0
- package/dist/tools/useSkill.js +62 -0
- package/dist/tools/useSkill.js.map +1 -0
- package/dist/tools/walk.js +152 -0
- package/dist/tools/walk.js.map +1 -0
- package/dist/tools/web.js +61 -0
- package/dist/tools/web.js.map +1 -0
- package/dist/tools/webFetch.js +444 -0
- package/dist/tools/webFetch.js.map +1 -0
- package/dist/tools/webSearch.js +130 -0
- package/dist/tools/webSearch.js.map +1 -0
- package/dist/tools/workspace.js +212 -0
- package/dist/tools/workspace.js.map +1 -0
- package/dist/tools/workspaceDiscover.js +216 -0
- package/dist/tools/workspaceDiscover.js.map +1 -0
- package/dist/tools/writeFile.js +162 -0
- package/dist/tools/writeFile.js.map +1 -0
- package/package.json +74 -28
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* backgroundShells.ts — long-running commands that outlive a turn.
|
|
3
|
+
*
|
|
4
|
+
* When a command crosses its timeout (or the model asks for `run_in_background`),
|
|
5
|
+
* run_command hands the LIVE process to this manager instead of killing it. The
|
|
6
|
+
* manager owns the registry of background shells per session, buffers their output
|
|
7
|
+
* (capped, so a chatty dev server never floods memory or the model's context), and
|
|
8
|
+
* exposes:
|
|
9
|
+
*
|
|
10
|
+
* - `read(id)` — only the NEW output since the last read (incremental).
|
|
11
|
+
* - `kill(id)` — whole-tree kill.
|
|
12
|
+
* - `list()` — running + finished shells (for the UI and /shells).
|
|
13
|
+
*
|
|
14
|
+
* Two ONE-SHOT, self-cleaning event channels keep notifications from leaking
|
|
15
|
+
* (avoiding the common footgun where finished jobs re-inject into the model forever):
|
|
16
|
+
* - `takeUiEvents()` — shells that came up or stopped, not yet shown in the chat.
|
|
17
|
+
* - `drainEvents()` — the same for the MODEL, each with a tail of output, so it is
|
|
18
|
+
* told once and then never again.
|
|
19
|
+
*
|
|
20
|
+
* Every event is delivered. What varies is whether it INTERRUPTS the session: a stop
|
|
21
|
+
* the user caused arrives as background fact on the next turn rather than waking the
|
|
22
|
+
* model, which is what stops it reopening an app somebody just closed.
|
|
23
|
+
*
|
|
24
|
+
* Client-side, like the alternator lanes: it holds live process handles, never
|
|
25
|
+
* crosses the engine↔brain wire. All children are killed on process exit.
|
|
26
|
+
*/
|
|
27
|
+
import { promises as fs } from "node:fs";
|
|
28
|
+
import { killTree, killTreeSync } from "./killTree.js";
|
|
29
|
+
const MAX_BUFFER_CHARS = 5_000_000; // cap one shell's retained output (runaway server)
|
|
30
|
+
export const MAX_READ_CHARS = 30_000; // cap a single `shells` read
|
|
31
|
+
const TAIL_CHARS = 2_000; // how much trailing output rides on a completion note
|
|
32
|
+
/**
|
|
33
|
+
* How long a server has to stay up before we treat its death as "someone stopped it"
|
|
34
|
+
* rather than "it failed to start".
|
|
35
|
+
*
|
|
36
|
+
* This is the one honest way to tell the two apart, because the exit status cannot:
|
|
37
|
+
* measured on Windows, a user closing an app reports `code 1`, and so does a server
|
|
38
|
+
* that crashed because its port was taken. Duration separates them cleanly — a port
|
|
39
|
+
* conflict dies in under a second, a session you close has been up for minutes.
|
|
40
|
+
*
|
|
41
|
+
* Borrowed from process supervisors, which hit this decades ago: supervisord counts a
|
|
42
|
+
* program as failed-to-start if it exits before `startsecs` (default 1s) regardless of
|
|
43
|
+
* its exit code. 10s is deliberately generous, since a dev server can take several
|
|
44
|
+
* seconds to bind a port and fail.
|
|
45
|
+
*/
|
|
46
|
+
const STARTUP_GRACE_MS = 10_000;
|
|
47
|
+
/**
|
|
48
|
+
* How long to wait after `exit` for `close` before finalizing anyway.
|
|
49
|
+
*
|
|
50
|
+
* `close` fires only once every stdio stream is closed, and a surviving grandchild can
|
|
51
|
+
* hold the pipe open forever, which strands the entry as permanently "running".
|
|
52
|
+
* `exit` fires when the process itself goes, so it is the backstop; the delay lets
|
|
53
|
+
* `close` win normally so buffered output is not lost.
|
|
54
|
+
*/
|
|
55
|
+
const EXIT_GRACE_MS = 2_000;
|
|
56
|
+
/**
|
|
57
|
+
* Guess a notify policy from the command, for callers that did not declare one.
|
|
58
|
+
*
|
|
59
|
+
* This is a FALLBACK, not the decision. The policy is declared at call time; this only
|
|
60
|
+
* picks a default when nothing was said, so a caller that forgets does not regress to
|
|
61
|
+
* "reopen the app the user just closed". Being a list of names, it is wrong for
|
|
62
|
+
* everything nobody thought of (`cargo run`, `docker compose up`, `flask run`, a plain
|
|
63
|
+
* path to a binary) — which is exactly why it is no longer the authority.
|
|
64
|
+
*/
|
|
65
|
+
export function guessNotifyPolicy(command) {
|
|
66
|
+
return isInteractiveServerCommand(command) ? "on_failure" : "on_finish";
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Is this command a dev server / interactive app — something that runs until stopped,
|
|
70
|
+
* where "it exited" means the USER closed it, NOT that a task finished? (pure/tested)
|
|
71
|
+
*
|
|
72
|
+
* Only used now to pick a default (see `guessNotifyPolicy`). A finite task (build,
|
|
73
|
+
* test, lint) that finishes IS a result worth surfacing, but a dev server exiting is
|
|
74
|
+
* just the user closing their app, and reacting to it makes the model reopen the thing
|
|
75
|
+
* they just closed. `build` variants are finite tasks, so they're excluded even though
|
|
76
|
+
* they share a runner name.
|
|
77
|
+
*/
|
|
78
|
+
export function isInteractiveServerCommand(command) {
|
|
79
|
+
const c = command.toLowerCase();
|
|
80
|
+
if (/\bbuild\b/.test(c))
|
|
81
|
+
return false; // `next build`, `tauri build`, `vite build` — finite
|
|
82
|
+
// Package-runner dev/serve/start/preview scripts: `npm run dev`, `pnpm start`, `yarn serve`.
|
|
83
|
+
if (/\b(npm|pnpm|yarn|bun)\b[^\n]*\b(dev|serve|start|preview)\b/.test(c))
|
|
84
|
+
return true;
|
|
85
|
+
// Dev servers / desktop-app runners invoked directly.
|
|
86
|
+
return /\b(tauri|vite|next|nuxt|remix|astro|nodemon|electron|expo|ng|http-server|live-server|serve|webpack-dev-server|watchexec)\b/.test(c);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Should a finished shell INTERRUPT the user with a turn? (pure/tested)
|
|
90
|
+
*
|
|
91
|
+
* Note the narrow question. This does NOT decide whether the model is told: it is
|
|
92
|
+
* always told (see `drainEvents`). Swallowing the event was the real defect — the
|
|
93
|
+
* model could not say "your app stopped", and if asked why the app was down it had
|
|
94
|
+
* nothing. This decides only whether the stop is worth breaking into the session for.
|
|
95
|
+
*
|
|
96
|
+
* The rule, in the user's words: don't reopen something they closed, unless it
|
|
97
|
+
* crashed before they ever got to see it.
|
|
98
|
+
*
|
|
99
|
+
* - `never` → nothing is ever worth interrupting for
|
|
100
|
+
* - somebody killed it → the agent or the user did that on purpose, so they know
|
|
101
|
+
* - `on_finish` → the result is the point, always interrupt
|
|
102
|
+
* - a signal ended it → someone stopped it deliberately
|
|
103
|
+
* - otherwise → interrupt ONLY if it never came up, because then the user never saw
|
|
104
|
+
* it running and cannot know it failed
|
|
105
|
+
*
|
|
106
|
+
* Deliberately NOT consulted: the exit code and the duration. Exit status cannot tell
|
|
107
|
+
* these cases apart — measured on Windows, a closed app and a port conflict both report
|
|
108
|
+
* code 1, and a signalled process reports none at all. `cameUp` is the fact that
|
|
109
|
+
* actually separates them, and it is established in ONE place (the readiness timer)
|
|
110
|
+
* rather than recomputed here from a second set of numbers.
|
|
111
|
+
*/
|
|
112
|
+
export function shouldWakeOnEnd(end) {
|
|
113
|
+
if (end.notify === "never")
|
|
114
|
+
return false;
|
|
115
|
+
if (end.killed)
|
|
116
|
+
return false;
|
|
117
|
+
if (end.notify === "on_finish")
|
|
118
|
+
return true;
|
|
119
|
+
if (end.signal)
|
|
120
|
+
return false;
|
|
121
|
+
return !end.cameUp;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Is `command` already running as one of these shells? (pure/tested) Matches on the
|
|
125
|
+
* normalized command string, so launching the very same server a second time is caught
|
|
126
|
+
* — the failure where the model fires `npm run tauri dev` twice, the copies collide on
|
|
127
|
+
* the port, and it then fights the conflict it created. Distinct servers (a frontend and
|
|
128
|
+
* a backend) don't match each other, so running both is still fine.
|
|
129
|
+
*/
|
|
130
|
+
export function findRunningDuplicate(running, command) {
|
|
131
|
+
const norm = (s) => s.toLowerCase().replace(/\s+/g, " ").trim();
|
|
132
|
+
const target = norm(command);
|
|
133
|
+
return running.find((s) => norm(s.command) === target);
|
|
134
|
+
}
|
|
135
|
+
/** How long after a user closes an app a re-launch of the same command is refused. Long
|
|
136
|
+
* enough to break the close→reopen loop that plays out over a turn or two; short enough
|
|
137
|
+
* that a restart the user genuinely asks for a while later is not held back. */
|
|
138
|
+
export const REOPEN_COOLDOWN_MS = 2 * 60 * 1000;
|
|
139
|
+
/**
|
|
140
|
+
* Was `command` an app the USER just closed? (pure/tested)
|
|
141
|
+
*
|
|
142
|
+
* The loop this breaks: the user closes their app, an agent that ignores the "do not
|
|
143
|
+
* reopen" note fires run_command again, the user closes it again, and round it goes. A
|
|
144
|
+
* match here lets the tool refuse the re-launch instead of reopening what the user shut.
|
|
145
|
+
*
|
|
146
|
+
* The signal is "it came up, then ended, and the AGENT did not kill it" — `ready` and
|
|
147
|
+
* `stoppedBy !== "agent"`. That is deliberately the same fact `shouldWakeOnEnd` treats as
|
|
148
|
+
* the user stopping their own app. It leaves the agent's OWN restart flow (kill_shell then
|
|
149
|
+
* relaunch) untouched, because that ending is `stoppedBy: "agent"`; and it never blocks a
|
|
150
|
+
* server that failed to start (`ready` is false), which the agent should be free to fix.
|
|
151
|
+
* Matched on the normalized command within a cooldown, so a later, deliberate restart is
|
|
152
|
+
* not held back.
|
|
153
|
+
*/
|
|
154
|
+
export function findRecentUserClose(shells, command, now, windowMs = REOPEN_COOLDOWN_MS) {
|
|
155
|
+
const norm = (s) => s.toLowerCase().replace(/\s+/g, " ").trim();
|
|
156
|
+
const target = norm(command);
|
|
157
|
+
return shells.find((s) => s.status !== "running" &&
|
|
158
|
+
s.ready &&
|
|
159
|
+
s.stoppedBy !== "agent" &&
|
|
160
|
+
s.finishedAt !== null &&
|
|
161
|
+
now - s.finishedAt < windowMs &&
|
|
162
|
+
norm(s.command) === target);
|
|
163
|
+
}
|
|
164
|
+
const active = new Set();
|
|
165
|
+
let cleanupRegistered = false;
|
|
166
|
+
export class BackgroundShells {
|
|
167
|
+
startupGraceMs;
|
|
168
|
+
exitGraceMs;
|
|
169
|
+
seq = 0;
|
|
170
|
+
shells = new Map();
|
|
171
|
+
onChange = null;
|
|
172
|
+
/**
|
|
173
|
+
* The two grace periods, injectable ONLY so tests can exercise the mechanism
|
|
174
|
+
* without waiting out real seconds. The defaults are the shipped behaviour and no
|
|
175
|
+
* production caller passes anything: a suite that waits out a 10s startup grace
|
|
176
|
+
* per case was 73% of the whole run's wall time, and that cost lands again on
|
|
177
|
+
* every contributor and every CI job.
|
|
178
|
+
*/
|
|
179
|
+
constructor(startupGraceMs = STARTUP_GRACE_MS, exitGraceMs = EXIT_GRACE_MS) {
|
|
180
|
+
this.startupGraceMs = startupGraceMs;
|
|
181
|
+
this.exitGraceMs = exitGraceMs;
|
|
182
|
+
active.add(this);
|
|
183
|
+
registerCleanup();
|
|
184
|
+
}
|
|
185
|
+
/** Subscribe to state changes (start / finish / kill) — the UI re-renders. */
|
|
186
|
+
setOnChange(cb) {
|
|
187
|
+
this.onChange = cb;
|
|
188
|
+
}
|
|
189
|
+
/** Take ownership of a live child process and start buffering its output. */
|
|
190
|
+
adopt(child, opts) {
|
|
191
|
+
const id = ++this.seq;
|
|
192
|
+
const entry = {
|
|
193
|
+
id,
|
|
194
|
+
command: opts.command,
|
|
195
|
+
cwd: opts.cwd,
|
|
196
|
+
status: "running",
|
|
197
|
+
exitCode: null,
|
|
198
|
+
startedAt: Date.now(),
|
|
199
|
+
finishedAt: null,
|
|
200
|
+
child,
|
|
201
|
+
buffer: "",
|
|
202
|
+
readOffset: 0,
|
|
203
|
+
truncated: false,
|
|
204
|
+
notify: opts.notify ?? guessNotifyPolicy(opts.command),
|
|
205
|
+
ready: false,
|
|
206
|
+
reported: false,
|
|
207
|
+
uiNotified: false,
|
|
208
|
+
wakeOnEnd: false,
|
|
209
|
+
readyReported: false,
|
|
210
|
+
readyUiNotified: false,
|
|
211
|
+
readyTimer: null,
|
|
212
|
+
cwdFile: opts.cwdFile,
|
|
213
|
+
tempFile: opts.tempFile,
|
|
214
|
+
};
|
|
215
|
+
this.shells.set(id, entry);
|
|
216
|
+
if (opts.initial)
|
|
217
|
+
this.append(entry, opts.initial);
|
|
218
|
+
// The readiness signal. A server that is still alive after the startup grace has
|
|
219
|
+
// come up, and that is the one positive event worth reporting for something that
|
|
220
|
+
// never "finishes". Without it the model was told to promise a report it could not
|
|
221
|
+
// give: the only event it could ever receive was the end, which for a server is
|
|
222
|
+
// deliberately suppressed. Tasks don't need it — their event is completion.
|
|
223
|
+
if (entry.notify === "on_failure") {
|
|
224
|
+
entry.readyTimer = setTimeout(() => {
|
|
225
|
+
entry.readyTimer = null;
|
|
226
|
+
if (entry.status !== "running")
|
|
227
|
+
return;
|
|
228
|
+
entry.ready = true;
|
|
229
|
+
this.emit();
|
|
230
|
+
}, this.startupGraceMs);
|
|
231
|
+
entry.readyTimer.unref?.();
|
|
232
|
+
}
|
|
233
|
+
const collect = (chunk) => this.append(entry, chunk.toString("utf8"));
|
|
234
|
+
child.stdout?.on("data", collect);
|
|
235
|
+
child.stderr?.on("data", collect);
|
|
236
|
+
// `signal` is captured, not dropped: a process ended by SIGTERM/SIGINT reports
|
|
237
|
+
// `code === null`, and without the signal there is no way to tell that from a
|
|
238
|
+
// crash.
|
|
239
|
+
child.on("close", (code, signal) => this.onClose(entry, code, signal, false));
|
|
240
|
+
child.on("error", () => this.onClose(entry, null, null, false));
|
|
241
|
+
// Backstop for a `close` that never arrives because a surviving grandchild still
|
|
242
|
+
// holds the stdio pipe. Without this the entry stays "running" for the rest of the
|
|
243
|
+
// session: the UI shows a dead shell, and `runningCount()` is permanently wrong.
|
|
244
|
+
child.on("exit", (code, signal) => {
|
|
245
|
+
const timer = setTimeout(() => this.onClose(entry, code, signal, false), this.exitGraceMs);
|
|
246
|
+
timer.unref?.();
|
|
247
|
+
});
|
|
248
|
+
this.emit();
|
|
249
|
+
return view(entry);
|
|
250
|
+
}
|
|
251
|
+
append(entry, text) {
|
|
252
|
+
entry.buffer += text;
|
|
253
|
+
if (entry.buffer.length > MAX_BUFFER_CHARS) {
|
|
254
|
+
// Keep the tail — the recent output is what matters for tests/errors.
|
|
255
|
+
entry.buffer = entry.buffer.slice(entry.buffer.length - MAX_BUFFER_CHARS);
|
|
256
|
+
entry.readOffset = Math.min(entry.readOffset, entry.buffer.length);
|
|
257
|
+
entry.truncated = true;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
onClose(entry, code, signal, killed, by) {
|
|
261
|
+
if (entry.status !== "running")
|
|
262
|
+
return;
|
|
263
|
+
entry.status = killed ? "killed" : "exited";
|
|
264
|
+
entry.exitCode = code;
|
|
265
|
+
if (signal)
|
|
266
|
+
entry.signal = signal;
|
|
267
|
+
entry.finishedAt = Date.now();
|
|
268
|
+
entry.child = null;
|
|
269
|
+
if (by)
|
|
270
|
+
entry.stoppedBy = by;
|
|
271
|
+
if (entry.readyTimer) {
|
|
272
|
+
clearTimeout(entry.readyTimer);
|
|
273
|
+
entry.readyTimer = null;
|
|
274
|
+
}
|
|
275
|
+
// A pending "it's up" must not fire after the thing has already stopped. Note this
|
|
276
|
+
// clears the PENDING notice, not `entry.ready`: whether it ever came up is the fact
|
|
277
|
+
// the wake decision below is built on, and it has to survive.
|
|
278
|
+
entry.readyReported = true;
|
|
279
|
+
entry.readyUiNotified = true;
|
|
280
|
+
// Whether this ending is worth interrupting for. It is NOT marked reported here:
|
|
281
|
+
// the model is always told (drainEvents), it just isn't always interrupted. Marking
|
|
282
|
+
// it reported is what used to delete the event outright, leaving the model unable
|
|
283
|
+
// to say the app had stopped at all.
|
|
284
|
+
entry.wakeOnEnd = shouldWakeOnEnd({
|
|
285
|
+
notify: entry.notify,
|
|
286
|
+
killed,
|
|
287
|
+
signal,
|
|
288
|
+
cameUp: entry.ready,
|
|
289
|
+
});
|
|
290
|
+
if (entry.cwdFile)
|
|
291
|
+
void fs.rm(entry.cwdFile, { force: true }).catch(() => { });
|
|
292
|
+
if (entry.tempFile)
|
|
293
|
+
void fs.rm(entry.tempFile, { force: true }).catch(() => { });
|
|
294
|
+
this.emit();
|
|
295
|
+
}
|
|
296
|
+
/** New output since the last read of this shell, plus its current status. */
|
|
297
|
+
async read(id) {
|
|
298
|
+
const entry = this.shells.get(id);
|
|
299
|
+
if (!entry)
|
|
300
|
+
return null;
|
|
301
|
+
let chunk = entry.buffer.slice(entry.readOffset);
|
|
302
|
+
entry.readOffset = entry.buffer.length;
|
|
303
|
+
if (chunk.length > MAX_READ_CHARS) {
|
|
304
|
+
chunk = `… (earlier output omitted)\n${chunk.slice(chunk.length - MAX_READ_CHARS)}`;
|
|
305
|
+
}
|
|
306
|
+
return { info: view(entry), chunk };
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Kill a running shell (whole tree). Returns false if it isn't running.
|
|
310
|
+
*
|
|
311
|
+
* `by` records WHO stopped it. Neither actor is woken about it, since both already
|
|
312
|
+
* know, but the difference is kept so the model can say "you stopped it" rather than
|
|
313
|
+
* guessing that it crashed.
|
|
314
|
+
*/
|
|
315
|
+
kill(id, by = "agent") {
|
|
316
|
+
const entry = this.shells.get(id);
|
|
317
|
+
if (!entry || entry.status !== "running" || !entry.child)
|
|
318
|
+
return false;
|
|
319
|
+
killTree(entry.child.pid);
|
|
320
|
+
this.onClose(entry, null, null, true, by);
|
|
321
|
+
return true;
|
|
322
|
+
}
|
|
323
|
+
list() {
|
|
324
|
+
return [...this.shells.values()].map(view);
|
|
325
|
+
}
|
|
326
|
+
running() {
|
|
327
|
+
return this.list().filter((s) => s.status === "running");
|
|
328
|
+
}
|
|
329
|
+
runningCount() {
|
|
330
|
+
return this.running().length;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Events worth INTERRUPTING for: a shell that just came up, or one that ended in a
|
|
334
|
+
* way the user cannot already know about.
|
|
335
|
+
*
|
|
336
|
+
* This is deliberately narrower than "events not yet told". A stop the user caused
|
|
337
|
+
* still gets delivered on the next turn (see `drainEvents`); it just doesn't break
|
|
338
|
+
* into the session, which is what stops the agent reopening a closed app.
|
|
339
|
+
*/
|
|
340
|
+
pendingCount() {
|
|
341
|
+
return [...this.shells.values()].filter((e) => (e.status !== "running" && !e.reported && e.wakeOnEnd) || (e.ready && !e.readyReported)).length;
|
|
342
|
+
}
|
|
343
|
+
/** One-shot for the UI: shells that came up or stopped and aren't in the chat yet. */
|
|
344
|
+
takeUiEvents() {
|
|
345
|
+
const out = [];
|
|
346
|
+
for (const entry of this.shells.values()) {
|
|
347
|
+
if (entry.ready && !entry.readyUiNotified) {
|
|
348
|
+
entry.readyUiNotified = true;
|
|
349
|
+
out.push({ info: view(entry), kind: "ready" });
|
|
350
|
+
}
|
|
351
|
+
if (entry.status !== "running" && !entry.uiNotified) {
|
|
352
|
+
entry.uiNotified = true;
|
|
353
|
+
out.push({ info: view(entry), kind: "ended" });
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
return out;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* One-shot for the MODEL: EVERYTHING it hasn't been told, each with a tail of output.
|
|
360
|
+
*
|
|
361
|
+
* Every ending is delivered, including the ones not worth interrupting for. Those
|
|
362
|
+
* used to be deleted, which left the model unable to say an app had stopped, or to
|
|
363
|
+
* answer why it was down. `wake` carries whether this was the interrupting kind, so
|
|
364
|
+
* the caller can word it as news or as background fact.
|
|
365
|
+
*
|
|
366
|
+
* Both kinds go through this single channel, and both mark themselves so nothing is
|
|
367
|
+
* ever injected twice. That one-shot property is the whole reason background jobs
|
|
368
|
+
* don't slowly eat the context window, and it must survive any change here.
|
|
369
|
+
*/
|
|
370
|
+
async drainEvents() {
|
|
371
|
+
const out = [];
|
|
372
|
+
const tailOf = (entry) => entry.buffer.slice(Math.max(0, entry.buffer.length - TAIL_CHARS));
|
|
373
|
+
for (const entry of this.shells.values()) {
|
|
374
|
+
if (entry.ready && !entry.readyReported) {
|
|
375
|
+
entry.readyReported = true;
|
|
376
|
+
out.push({ info: view(entry), kind: "ready", tail: tailOf(entry), wake: true });
|
|
377
|
+
}
|
|
378
|
+
if (entry.status !== "running" && !entry.reported) {
|
|
379
|
+
entry.reported = true;
|
|
380
|
+
out.push({ info: view(entry), kind: "ended", tail: tailOf(entry), wake: entry.wakeOnEnd });
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
return out;
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Kill every running shell and drop the registry (session swap / exit).
|
|
387
|
+
*
|
|
388
|
+
* `sync` is required when disposing from a process-exit handler: the default
|
|
389
|
+
* kill spawns `taskkill` asynchronously, and Node runs no async work during
|
|
390
|
+
* exit, so the shells would outlive us. Measured, not assumed.
|
|
391
|
+
*/
|
|
392
|
+
dispose(sync = false) {
|
|
393
|
+
for (const entry of this.shells.values()) {
|
|
394
|
+
// Kill by CHILD PRESENT, not by recorded status. A shell we have marked
|
|
395
|
+
// "ended" only means its WRAPPER exited, and on POSIX that says nothing about
|
|
396
|
+
// its descendants: kill the `sh -c` and the program it started is orphaned and
|
|
397
|
+
// keeps running, still holding the stdio pipes. MEASURED on Linux, where the
|
|
398
|
+
// orphan outlived the whole test process and stopped it from ever exiting.
|
|
399
|
+
// The group kill still reaches it, because a process group survives its leader
|
|
400
|
+
// as long as it has members. Signalling an already-dead pid is a harmless
|
|
401
|
+
// no-op, so there is nothing to lose by not consulting the status first.
|
|
402
|
+
if (entry.child) {
|
|
403
|
+
if (sync)
|
|
404
|
+
killTreeSync(entry.child.pid);
|
|
405
|
+
else
|
|
406
|
+
killTree(entry.child.pid);
|
|
407
|
+
}
|
|
408
|
+
if (entry.cwdFile)
|
|
409
|
+
void fs.rm(entry.cwdFile, { force: true }).catch(() => { });
|
|
410
|
+
if (entry.tempFile)
|
|
411
|
+
void fs.rm(entry.tempFile, { force: true }).catch(() => { });
|
|
412
|
+
}
|
|
413
|
+
this.shells.clear();
|
|
414
|
+
active.delete(this);
|
|
415
|
+
}
|
|
416
|
+
emit() {
|
|
417
|
+
this.onChange?.();
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
function view(e) {
|
|
421
|
+
return {
|
|
422
|
+
id: e.id,
|
|
423
|
+
command: e.command,
|
|
424
|
+
cwd: e.cwd,
|
|
425
|
+
status: e.status,
|
|
426
|
+
exitCode: e.exitCode,
|
|
427
|
+
startedAt: e.startedAt,
|
|
428
|
+
finishedAt: e.finishedAt,
|
|
429
|
+
notify: e.notify,
|
|
430
|
+
ready: e.ready,
|
|
431
|
+
...(e.signal ? { signal: e.signal } : {}),
|
|
432
|
+
...(e.stoppedBy ? { stoppedBy: e.stoppedBy } : {}),
|
|
433
|
+
...(e.truncated ? { truncated: true } : {}),
|
|
434
|
+
...(detectPort(e.buffer) !== undefined ? { port: detectPort(e.buffer) } : {}),
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
/** Kill any background processes still running when the process exits. */
|
|
438
|
+
function registerCleanup() {
|
|
439
|
+
if (cleanupRegistered)
|
|
440
|
+
return;
|
|
441
|
+
cleanupRegistered = true;
|
|
442
|
+
process.once("exit", () => {
|
|
443
|
+
// Synchronous kill: an async one never reaches the OS from here.
|
|
444
|
+
for (const mgr of active)
|
|
445
|
+
mgr.dispose(true);
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* The port a process announced in its own output.
|
|
450
|
+
*
|
|
451
|
+
* A backgrounded dev server is only useful if you know where it is listening, and the
|
|
452
|
+
* one thing that knows is the server itself — it prints the URL on startup. So this
|
|
453
|
+
* reads the buffer rather than inspecting sockets: no privileges, no platform-specific
|
|
454
|
+
* netstat parsing, and it cannot report a port belonging to some other process.
|
|
455
|
+
*
|
|
456
|
+
* The FIRST announcement wins. A framework often prints a local URL and then a network
|
|
457
|
+
* one for the same port, and some print a proxy target afterwards; the first line is
|
|
458
|
+
* the one describing the server that just came up.
|
|
459
|
+
*/
|
|
460
|
+
export function detectPort(output) {
|
|
461
|
+
const m = /(?:https?:\/\/)(?:localhost|127\.0\.0\.1|0\.0\.0\.0|\[::1\]):(\d{2,5})/i.exec(output) ??
|
|
462
|
+
/\b(?:listening|running|started|ready)\b[^\n]*?\bport\b\s*:?\s*(\d{2,5})/i.exec(output);
|
|
463
|
+
if (!m)
|
|
464
|
+
return undefined;
|
|
465
|
+
const port = Number(m[1]);
|
|
466
|
+
return port >= 1 && port <= 65535 ? port : undefined;
|
|
467
|
+
}
|
|
468
|
+
//# sourceMappingURL=backgroundShells.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backgroundShells.js","sourceRoot":"","sources":["../../src/tools/backgroundShells.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* captureSweep.ts — clear out screenshots that have outlived their usefulness.
|
|
3
|
+
*
|
|
4
|
+
* `screenshot` writes each capture to its own temp directory so the model can be
|
|
5
|
+
* handed the file and compaction can drop and restore the reference. Nothing removed
|
|
6
|
+
* them, so every window ever photographed stayed on disk indefinitely — and unlike
|
|
7
|
+
* the rest of the agent's temp files, a capture holds whatever happened to be on
|
|
8
|
+
* screen at the time.
|
|
9
|
+
*
|
|
10
|
+
* Deleting immediately after sending was considered and rejected: the reference
|
|
11
|
+
* survives in the transcript, compaction can bring an image back, and a capture the
|
|
12
|
+
* model may still be asked about should not be a dangling path. So they live for a
|
|
13
|
+
* few days and are swept by age at startup, which also catches anything left behind
|
|
14
|
+
* by a crash — the case a shutdown hook would miss.
|
|
15
|
+
*
|
|
16
|
+
* Best-effort throughout. A sweep that cannot read the temp directory, or that races
|
|
17
|
+
* another Mindweave deleting the same folder, must never keep the CLI from starting.
|
|
18
|
+
*/
|
|
19
|
+
import { readdir, rm, stat } from "node:fs/promises";
|
|
20
|
+
import { tmpdir } from "node:os";
|
|
21
|
+
import { join } from "node:path";
|
|
22
|
+
/** How long a capture is kept. One edit changes the policy. */
|
|
23
|
+
export const CAPTURE_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
24
|
+
/** Temp directory prefixes this sweep owns. Must match what creates them. */
|
|
25
|
+
export const SWEPT_PREFIXES = ["mindweave-shot-"];
|
|
26
|
+
/** Does this directory name belong to us? (pure) */
|
|
27
|
+
export function isSweptName(name) {
|
|
28
|
+
return SWEPT_PREFIXES.some((p) => name.startsWith(p));
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Should an entry be removed, given its age? (pure)
|
|
32
|
+
*
|
|
33
|
+
* Split out from the I/O so the policy can be tested without fabricating timestamps
|
|
34
|
+
* on a real filesystem, and so "how old is too old" is one comparison in one place.
|
|
35
|
+
*/
|
|
36
|
+
export function isExpired(mtimeMs, now, maxAgeMs = CAPTURE_MAX_AGE_MS) {
|
|
37
|
+
return now - mtimeMs > maxAgeMs;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Remove expired capture directories. Returns how many went.
|
|
41
|
+
*
|
|
42
|
+
* `dir` and `now` are parameters so tests drive a fabricated tree rather than the
|
|
43
|
+
* real temp directory, where a stray match would delete a developer's actual files.
|
|
44
|
+
*/
|
|
45
|
+
export async function sweepCaptures(dir = tmpdir(), now = Date.now(), maxAgeMs = CAPTURE_MAX_AGE_MS) {
|
|
46
|
+
let removed = 0;
|
|
47
|
+
let names;
|
|
48
|
+
try {
|
|
49
|
+
names = await readdir(dir);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return 0; // unreadable temp directory is not our problem to solve
|
|
53
|
+
}
|
|
54
|
+
for (const name of names) {
|
|
55
|
+
if (!isSweptName(name))
|
|
56
|
+
continue;
|
|
57
|
+
const full = join(dir, name);
|
|
58
|
+
try {
|
|
59
|
+
const info = await stat(full);
|
|
60
|
+
if (!info.isDirectory())
|
|
61
|
+
continue;
|
|
62
|
+
if (!isExpired(info.mtimeMs, now, maxAgeMs))
|
|
63
|
+
continue;
|
|
64
|
+
await rm(full, { recursive: true, force: true });
|
|
65
|
+
removed++;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// Vanished under us, locked, or not ours to delete. Skip it.
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return removed;
|
|
72
|
+
}
|
|
73
|
+
/** Fire-and-forget sweep for startup: never awaited, never throws, never logs. */
|
|
74
|
+
export function sweepCapturesInBackground() {
|
|
75
|
+
void sweepCaptures().catch(() => { });
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=captureSweep.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"captureSweep.js","sourceRoot":"","sources":["../../src/tools/captureSweep.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,+DAA+D;AAC/D,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,SAAS;AAEpE,6EAA6E;AAC7E,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,iBAAiB,CAAU,CAAC;AAE3D,oDAAoD;AACpD,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AACxD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CAAC,OAAe,EAAE,GAAW,EAAE,QAAQ,GAAG,kBAAkB;IACnF,OAAO,GAAG,GAAG,OAAO,GAAG,QAAQ,CAAC;AAClC,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAc,MAAM,EAAE,EACtB,MAAc,IAAI,CAAC,GAAG,EAAE,EACxB,WAAmB,kBAAkB;IAErC,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,IAAI,KAAe,CAAC;IACpB,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAC,CAAC,wDAAwD;IACpE,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;YAAE,SAAS;QACjC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;YAC9B,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;gBAAE,SAAS;YAClC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,QAAQ,CAAC;gBAAE,SAAS;YACtD,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACjD,OAAO,EAAE,CAAC;QACZ,CAAC;QAAC,MAAM,CAAC;YACP,6DAA6D;QAC/D,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,yBAAyB;IACvC,KAAK,aAAa,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* chassisMux.ts — query the right code map(s) in a multi-root workspace.
|
|
3
|
+
*
|
|
4
|
+
* Each session root has its own chassis (a code map only knows its own files). The
|
|
5
|
+
* code-intelligence tools route through here so they stay correct across roots:
|
|
6
|
+
* - path queries (outline) hit the chassis that OWNS the file;
|
|
7
|
+
* - name queries (definition/references) MERGE across every root;
|
|
8
|
+
* - relevance ranks within each root, then merges by score.
|
|
9
|
+
* Single-root sessions fall straight through to the one chassis — no overhead.
|
|
10
|
+
*/
|
|
11
|
+
import { isAbsolute, relative } from "node:path";
|
|
12
|
+
import { CodeGraph } from "../alternator/chassis/graph.js";
|
|
13
|
+
/** Every chassis in play (per-root set, or just the primary). */
|
|
14
|
+
export function allChassis(ctx) {
|
|
15
|
+
if (ctx.chassisByRoot && ctx.chassisByRoot.size > 0)
|
|
16
|
+
return [...ctx.chassisByRoot.values()];
|
|
17
|
+
return ctx.chassis ? [ctx.chassis] : [];
|
|
18
|
+
}
|
|
19
|
+
/** The chassis whose root contains `abs`, or the primary as a fallback. */
|
|
20
|
+
export function chassisForPath(ctx, abs) {
|
|
21
|
+
if (ctx.chassisByRoot) {
|
|
22
|
+
for (const [root, chassis] of ctx.chassisByRoot) {
|
|
23
|
+
const rel = relative(root, abs);
|
|
24
|
+
if (rel === "" || (!rel.startsWith("..") && !isAbsolute(rel)))
|
|
25
|
+
return chassis;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return ctx.chassis;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Confidence for a MERGED list, which is the confidence of its weakest part.
|
|
32
|
+
*
|
|
33
|
+
* The merged list is one list to the reader, and the caveat printed from this value
|
|
34
|
+
* governs all of it. So a root running a language server must not vouch for a root
|
|
35
|
+
* that is on the tree-sitter tier: taking the best there marks name-level entries
|
|
36
|
+
* `resolved` purely by association, and `resolved` is exactly what suppresses the
|
|
37
|
+
* "verify with grep" note those entries need. Each `Ref` still carries its own
|
|
38
|
+
* per-entry confidence for anyone who wants the finer answer.
|
|
39
|
+
*/
|
|
40
|
+
function mergedConfidence(values) {
|
|
41
|
+
return values.every((c) => c === "resolved") && values.length > 0 ? "resolved" : "name-level";
|
|
42
|
+
}
|
|
43
|
+
/** Where a symbol is defined, merged across every root. */
|
|
44
|
+
export async function mergedDefinition(ctx, name) {
|
|
45
|
+
const list = allChassis(ctx);
|
|
46
|
+
if (list.length === 1)
|
|
47
|
+
return list[0].definition(name);
|
|
48
|
+
const symbols = [];
|
|
49
|
+
const confidences = [];
|
|
50
|
+
for (const ch of list) {
|
|
51
|
+
const r = await ch.definition(name);
|
|
52
|
+
symbols.push(...r.symbols);
|
|
53
|
+
if (r.symbols.length)
|
|
54
|
+
confidences.push(r.confidence);
|
|
55
|
+
}
|
|
56
|
+
return { symbols, confidence: mergedConfidence(confidences) };
|
|
57
|
+
}
|
|
58
|
+
/** Who references a symbol, merged across every root. */
|
|
59
|
+
export async function mergedReferences(ctx, name) {
|
|
60
|
+
const list = allChassis(ctx);
|
|
61
|
+
if (list.length === 1)
|
|
62
|
+
return list[0].references(name);
|
|
63
|
+
const refs = [];
|
|
64
|
+
const confidences = [];
|
|
65
|
+
for (const ch of list) {
|
|
66
|
+
const r = await ch.references(name);
|
|
67
|
+
refs.push(...r.refs);
|
|
68
|
+
if (r.refs.length)
|
|
69
|
+
confidences.push(r.confidence);
|
|
70
|
+
}
|
|
71
|
+
return { refs, confidence: mergedConfidence(confidences) };
|
|
72
|
+
}
|
|
73
|
+
/** The span(s) of a named symbol's definition, across every root. A `path` is only
|
|
74
|
+
* ever inside one root, so passing it naturally narrows the result to that root. */
|
|
75
|
+
export async function symbolSpans(ctx, name, opts = {}) {
|
|
76
|
+
const list = allChassis(ctx);
|
|
77
|
+
if (list.length === 0)
|
|
78
|
+
return [];
|
|
79
|
+
if (list.length === 1)
|
|
80
|
+
return list[0].span(name, opts);
|
|
81
|
+
const spans = [];
|
|
82
|
+
for (const ch of list)
|
|
83
|
+
spans.push(...(await ch.span(name, opts)));
|
|
84
|
+
return spans;
|
|
85
|
+
}
|
|
86
|
+
/** A chassis's underlying code graph, if it exposes one (CodeChassis does; the
|
|
87
|
+
* null/test chassis may not). */
|
|
88
|
+
function graphOf(chassis) {
|
|
89
|
+
const g = chassis.graphRef?.();
|
|
90
|
+
return g instanceof CodeGraph ? g : null;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=chassisMux.js.map
|