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,472 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* session.ts — create a fresh session or resume a saved one.
|
|
3
|
+
*
|
|
4
|
+
* A `Session` bundles the transcript, the tool context (live cwd + read ledger),
|
|
5
|
+
* and the project memory. This is the client-side init that does the disk reads
|
|
6
|
+
* (MINDWEAVE.md, a saved transcript); the engine receives a ready Session and never
|
|
7
|
+
* touches the filesystem itself.
|
|
8
|
+
*/
|
|
9
|
+
import { promises as fs, existsSync } from "node:fs";
|
|
10
|
+
import { randomUUID } from "node:crypto";
|
|
11
|
+
import { resolvePath, nextTouch, canonicalRoot } from "../tools/paths.js";
|
|
12
|
+
import { latestSession, listSessions, loadMeta, loadTranscript, loadSessionNotes } from "./store.js";
|
|
13
|
+
import { startChassis } from "../alternator/lane.js";
|
|
14
|
+
import { BackgroundShells } from "../tools/backgroundShells.js";
|
|
15
|
+
import { Checkpoints } from "../tools/checkpoints.js";
|
|
16
|
+
import { projectContextText } from "../project/context.js";
|
|
17
|
+
import { loadGovernance, governanceStamp } from "../governor/index.js";
|
|
18
|
+
import { createRuleScope } from "../governor/scope.js";
|
|
19
|
+
import { loadModelConfig } from "../dynamo/model.js";
|
|
20
|
+
import { ensureMemoryDir, loadMemoryIndex, memoryDir } from "./autoMemory.js";
|
|
21
|
+
import { loadMcpConfig } from "../mcp/config.js";
|
|
22
|
+
import { McpManager } from "../mcp/manager.js";
|
|
23
|
+
import { assembleNotes } from "./projectNotes.js";
|
|
24
|
+
/**
|
|
25
|
+
* Read the project's notes: MINDWEAVE.md, the user's own, and everything they import.
|
|
26
|
+
*
|
|
27
|
+
* The layers and their rules live in projectNotes.ts. This is only the seam the
|
|
28
|
+
* session uses, kept as a single string because that is what the cached prefix takes.
|
|
29
|
+
*/
|
|
30
|
+
async function loadProjectMemory(cwd) {
|
|
31
|
+
return (await assembleNotes(cwd)).text;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Re-read MINDWEAVE.md into the live session, but only when it is FREE to do so.
|
|
35
|
+
*
|
|
36
|
+
* The model maintains MINDWEAVE.md, so it edits the file mid-session; `projectMemory`
|
|
37
|
+
* is frozen into the cached system prompt at session start. Re-reading it every turn
|
|
38
|
+
* kept the two in step, at a price that turned out to be the single most expensive
|
|
39
|
+
* line in prompt assembly: changing the system prompt string invalidates the WHOLE
|
|
40
|
+
* cached prefix — base prompt, tool schemas, project snapshot, governance — and the
|
|
41
|
+
* next request pays a full cache rewrite at 1.25x normal input rate. One edit to a
|
|
42
|
+
* small markdown file re-billed everything.
|
|
43
|
+
*
|
|
44
|
+
* The codebase already knew this hazard: standing rules were deliberately moved OUT of
|
|
45
|
+
* the cached prefix precisely so a mid-session remember_rule could not bust it. This
|
|
46
|
+
* does the same thing for the same reason.
|
|
47
|
+
*
|
|
48
|
+
* Serving the frozen copy is safe because of where the fresh copy already is. The model
|
|
49
|
+
* that just edited MINDWEAVE.md has the new content in its own transcript — it wrote it
|
|
50
|
+
* — so nothing is hidden from it. The frozen prefix is only how the NEXT session starts,
|
|
51
|
+
* and it refreshes at points where the cache is being thrown away regardless: after a
|
|
52
|
+
* compaction (which rewrites the transcript, taking the edit with it), and at session
|
|
53
|
+
* start.
|
|
54
|
+
*/
|
|
55
|
+
export async function reloadProjectMemory(session, opts = {}) {
|
|
56
|
+
if (!opts.force && !session.projectMemoryStale)
|
|
57
|
+
return;
|
|
58
|
+
session.projectMemory = await loadProjectMemory(session.cwd);
|
|
59
|
+
session.projectMemoryStale = false;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Attach the MCP server pool to a session.
|
|
63
|
+
*
|
|
64
|
+
* Deliberately NOT awaited. Servers are third-party processes and a slow one would sit
|
|
65
|
+
* between the user pressing enter and the first paint, so the pool comes up in the
|
|
66
|
+
* background and its tools appear once they are ready. Failures are already states
|
|
67
|
+
* rather than exceptions, so nothing here can reject; the `catch` is belt and braces.
|
|
68
|
+
*
|
|
69
|
+
* The cost of not awaiting is that a server landing mid-session changes the tool list
|
|
70
|
+
* and invalidates the cached prompt prefix. That cost is real and it is NOT designed
|
|
71
|
+
* away: tool schemas are a structural API field rendered before every provider's cache
|
|
72
|
+
* breakpoint, so there is no volatile tail to move them into (docs/mcp-plan.md §6, which
|
|
73
|
+
* corrects an earlier claim that there was). What Phase 3 actually bought is a stable
|
|
74
|
+
* catalog and one frozen snapshot per turn, so the cost lands once per real change
|
|
75
|
+
* instead of once per turn — which is cheap enough that the fast start is worth keeping.
|
|
76
|
+
*/
|
|
77
|
+
function attachMcp(ctx, cwd) {
|
|
78
|
+
const manager = new McpManager();
|
|
79
|
+
ctx.mcp = manager;
|
|
80
|
+
// Before anything connects: a tool can be dispatched as soon as its server is up, and
|
|
81
|
+
// spilled results have to land in this project's state dir rather than wherever the
|
|
82
|
+
// process happened to start.
|
|
83
|
+
manager.setProjectRoot(cwd);
|
|
84
|
+
void loadMcpConfig(cwd)
|
|
85
|
+
.then(async (configs) => {
|
|
86
|
+
await manager.start(configs);
|
|
87
|
+
// Governance is applied AFTER connecting, because both gates are about the tools
|
|
88
|
+
// a server actually turned out to advertise: a forbidden name only matters once
|
|
89
|
+
// it exists, and a changed description can only be noticed against a live one.
|
|
90
|
+
manager.setForbidden(ctx.governance?.forbidden.mcpTools ?? []);
|
|
91
|
+
// Rug-pull check. `requestApproval` may not be attached yet (the CLI wires it
|
|
92
|
+
// just after session creation), in which case `verifyTrust` fails closed and
|
|
93
|
+
// changed tools stay blocked until the next session — the safe direction.
|
|
94
|
+
await manager.verifyTrust(cwd, ctx.requestApproval);
|
|
95
|
+
})
|
|
96
|
+
.catch(() => { });
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Seed the read-ledger with MINDWEAVE.md when it exists on disk, so the model can UPDATE
|
|
100
|
+
* the project's own memory file without a redundant read_file first. MINDWEAVE.md's content
|
|
101
|
+
* is already loaded into the system prompt (projectMemory), so the read-before-edit gate
|
|
102
|
+
* would otherwise trip on a file the model effectively already has — surfacing the
|
|
103
|
+
* confusing "MINDWEAVE.md has not been read this session" error on routine housekeeping.
|
|
104
|
+
* Keyed via resolvePath so it matches exactly what the edit gate looks up. Recorded
|
|
105
|
+
* full:false (the model works from a window, never a held whole-file copy) so it can
|
|
106
|
+
* never wrongly short-circuit a genuine read_file. Best-effort; no MINDWEAVE.md => no-op.
|
|
107
|
+
*/
|
|
108
|
+
async function seedProjectMemoryRead(ctx, projectMemory) {
|
|
109
|
+
if (!projectMemory)
|
|
110
|
+
return;
|
|
111
|
+
const abs = resolvePath(ctx, "MINDWEAVE.md");
|
|
112
|
+
try {
|
|
113
|
+
const st = await fs.stat(abs);
|
|
114
|
+
ctx.reads.set(abs, { mtimeMs: st.mtimeMs, size: st.size, full: false, touchedAt: nextTouch() });
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// No MINDWEAVE.md on disk — nothing to seed.
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/** Ensure the memory dir exists (so the model never mkdirs) and read its index. */
|
|
121
|
+
async function loadMemory(cwd) {
|
|
122
|
+
await ensureMemoryDir(cwd);
|
|
123
|
+
return loadMemoryIndex(cwd);
|
|
124
|
+
}
|
|
125
|
+
function freshToolContext(cwd, governance, roots) {
|
|
126
|
+
// Start the alternator: one code map per root warms up in the background while
|
|
127
|
+
// the session is already usable. The forbidden config + skill catalog come from
|
|
128
|
+
// the governor so the tools can enforce/invoke them.
|
|
129
|
+
const chassisByRoot = new Map(roots.map((root) => [root, startChassis(root)]));
|
|
130
|
+
return {
|
|
131
|
+
cwd,
|
|
132
|
+
roots,
|
|
133
|
+
reads: new Map(),
|
|
134
|
+
chassis: chassisByRoot.get(cwd), // the primary root's map (drives the auto-map)
|
|
135
|
+
chassisByRoot,
|
|
136
|
+
backgroundShells: new BackgroundShells(),
|
|
137
|
+
checkpoints: new Checkpoints(),
|
|
138
|
+
todos: [],
|
|
139
|
+
// Deferred tools the model has surfaced via find_tools become callable from then on
|
|
140
|
+
// (registry.toolSchemas). Empty at start; grows as the model searches; restored from
|
|
141
|
+
// meta on resume.
|
|
142
|
+
activatedTools: new Set(),
|
|
143
|
+
// Same governance object as Session.governance — shared so mid-session edits
|
|
144
|
+
// (a new rule, a new forbidden path) are visible to both the tools and the
|
|
145
|
+
// engine's prompt without a reload.
|
|
146
|
+
governance,
|
|
147
|
+
// Which glob-scoped rules this session has activated. Filled as paths are touched
|
|
148
|
+
// (governor/scope.ts) rather than re-derived on every model call.
|
|
149
|
+
ruleScope: createRuleScope(),
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
/** The framing prepended to a sub-agent's task — it works alone and reports back. */
|
|
153
|
+
const SUBAGENT_PREAMBLE = "You are a focused sub-agent spawned by the main Mindweave agent to complete ONE task and report back. " +
|
|
154
|
+
"Work autonomously with your tools — you cannot ask the user questions, and you do not see the main " +
|
|
155
|
+
"conversation, so rely only on the task below. Do EXACTLY what it asks and stay inside its boundaries — " +
|
|
156
|
+
"don't widen the scope, and don't change files the task didn't name. Stop as soon as the objective is met " +
|
|
157
|
+
"rather than exploring further. When finished, reply with a DISTILLED result — the answer the main agent " +
|
|
158
|
+
"needs, with concrete file:line references, and nothing else (no play-by-play). If the task specifies an " +
|
|
159
|
+
"output format, follow it exactly. Keep it tight (aim for well under a page): the main agent sees only " +
|
|
160
|
+
"your final message, not your intermediate steps.\n\nTask:\n";
|
|
161
|
+
/**
|
|
162
|
+
* A scoped child session for a sub-agent. It gets its OWN transcript (seeded with
|
|
163
|
+
* the task) and its OWN read ledger + todo list, so its work is isolated and never
|
|
164
|
+
* pollutes the parent's working set. It SHARES the parent's code map, checkpoints
|
|
165
|
+
* (so its edits are undoable too) and governance by reference — everything the parent
|
|
166
|
+
* already stood up. What it does NOT get is anything the user granted in person: the
|
|
167
|
+
* approval channel, session permission grants, and the parent's approved plan all stop
|
|
168
|
+
* here. Only the child's final reply crosses back to the parent, through the spawn tool.
|
|
169
|
+
*/
|
|
170
|
+
export function forkSession(parent, task, opts = {}) {
|
|
171
|
+
const p = parent.toolContext;
|
|
172
|
+
const id = randomUUID();
|
|
173
|
+
const childContext = {
|
|
174
|
+
...p,
|
|
175
|
+
reads: new Map(),
|
|
176
|
+
todos: [],
|
|
177
|
+
// Its OWN activation set, seeded with the parent's so it can call what is already
|
|
178
|
+
// active. Without the copy the spread would share the parent's Set by reference, and a
|
|
179
|
+
// sub-agent's find_tools would silently change the parent's advertised list.
|
|
180
|
+
activatedTools: new Set(p.activatedTools),
|
|
181
|
+
// Its own id, not the parent's. The spread carries `sessionId`, so a child asking
|
|
182
|
+
// "which conversation am I?" answered with the parent's — harmless while nothing
|
|
183
|
+
// writes session-scoped state from a child, and wrong the moment something does.
|
|
184
|
+
sessionId: id,
|
|
185
|
+
subagentDepth: (p.subagentDepth ?? 0) + 1,
|
|
186
|
+
readOnlyTools: opts.readOnly === true ? true : p.readOnlyTools,
|
|
187
|
+
// CLEARED, not inherited. This line used to copy the parent's value under a
|
|
188
|
+
// comment claiming it cleared it, and the engine's gate is
|
|
189
|
+
// `guarded && !guardAllowed.has(tool)` — so an inherited grant skipped the check
|
|
190
|
+
// outright. Combined with the missing approval channel below, a sub-agent the user
|
|
191
|
+
// never saw start could edit files with no prompt at all, while SECURITY.md
|
|
192
|
+
// promised Sentinel "covers every tool including sub-agent edits".
|
|
193
|
+
//
|
|
194
|
+
// "Allow all" is a judgement the user made about work they could see. It does not
|
|
195
|
+
// transfer to an agent they did not know would run. A guarded child has no channel
|
|
196
|
+
// to ask through, so its mutating tools are refused and it reports back instead —
|
|
197
|
+
// which is the failing direction to pick.
|
|
198
|
+
guardAllowed: undefined,
|
|
199
|
+
// Cleared for the same reason, and it was missed when this one was added: a folder
|
|
200
|
+
// the user allowed writing to is a judgement about work they were watching. Claude
|
|
201
|
+
// Code draws the identical line when it scopes a child — it keeps the permissions
|
|
202
|
+
// given on the command line and clears the SESSION ones, "to prevent unintended
|
|
203
|
+
// leakage".
|
|
204
|
+
allowedOutsideDirs: undefined,
|
|
205
|
+
// The parent's approved plan is NOT the child's work. Two things go wrong when it
|
|
206
|
+
// rides along: the child is handed a binding instruction to follow a plan it was not
|
|
207
|
+
// spawned for, on top of the one task it was given — and because a child runs the
|
|
208
|
+
// same turn loop, its turn ending settles that plan, marking the artifact DONE on
|
|
209
|
+
// disk while the parent is still in the middle of carrying it out.
|
|
210
|
+
//
|
|
211
|
+
// Empty string, not undefined: undefined means "not looked for yet" and would send
|
|
212
|
+
// the child to load the plan straight back off disk.
|
|
213
|
+
activePlan: "",
|
|
214
|
+
activePlanApprovedAt: undefined,
|
|
215
|
+
// A child CANNOT reach the user. The spread above inherited the parent's approval
|
|
216
|
+
// channel, so `ask_user` (which is read-only, and therefore offered even to a
|
|
217
|
+
// read-only child) put a question on screen from an agent the user never saw start
|
|
218
|
+
// — and a parallel fan-out could stack several, none of them attributable. It also
|
|
219
|
+
// made spawn_subagent's own briefing advice false: "write a COMPLETE, standalone
|
|
220
|
+
// task" only holds if the child truly cannot come back and ask.
|
|
221
|
+
// Every consumer of this channel already degrades correctly without it: ask_user
|
|
222
|
+
// tells the child to assume a sensible default and state it, and the guards fail
|
|
223
|
+
// closed. The child's findings reach the user through its result, where the parent
|
|
224
|
+
// can weigh them.
|
|
225
|
+
requestApproval: undefined,
|
|
226
|
+
};
|
|
227
|
+
return {
|
|
228
|
+
...parent,
|
|
229
|
+
id,
|
|
230
|
+
createdAt: Date.now(),
|
|
231
|
+
transcript: [{ role: "user", content: SUBAGENT_PREAMBLE + task }],
|
|
232
|
+
toolContext: childContext,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
/** A brand-new session rooted at `cwd` (defaults to the process cwd). */
|
|
236
|
+
/**
|
|
237
|
+
* A brand-new session.
|
|
238
|
+
*
|
|
239
|
+
* `carryRoots` is for starting over WITHOUT losing the workspace: `/clear` builds a
|
|
240
|
+
* fresh session in the same folder, and the folders someone added with `/include` or
|
|
241
|
+
* `/link` belong to the folder they are working in, not to the conversation they just
|
|
242
|
+
* ended. Dropping them was silent — every tool quietly narrowed to one root and
|
|
243
|
+
* nothing said so. Missing folders are filtered and the primary is de-duplicated, the
|
|
244
|
+
* same way `resumeSession` treats the roots it restores.
|
|
245
|
+
*/
|
|
246
|
+
export async function createSession(rawCwd = process.cwd(), carryRoots = []) {
|
|
247
|
+
// Canonicalise the root ONCE, here, before anything derives from it. run_command
|
|
248
|
+
// reports where it ended up as a physical path, and on macOS a great deal sits
|
|
249
|
+
// behind symlinks (/tmp, and all of os.tmpdir()), so a session opened at a logical
|
|
250
|
+
// path would compare unequal to its own cwd after the first command. See
|
|
251
|
+
// canonicalRoot. Doing it at the single point of entry is what keeps every root,
|
|
252
|
+
// every recorded cwd, and every relativized path speaking the same form.
|
|
253
|
+
const cwd = await canonicalRoot(rawCwd);
|
|
254
|
+
const [projectMemory, memoryIndex, projectContext, governance, stamp, modelConfig, earlier] = await Promise.all([
|
|
255
|
+
loadProjectMemory(cwd),
|
|
256
|
+
loadMemory(cwd),
|
|
257
|
+
projectContextText(cwd),
|
|
258
|
+
loadGovernance(cwd),
|
|
259
|
+
governanceStamp(cwd),
|
|
260
|
+
loadModelConfig(cwd),
|
|
261
|
+
listSessions(cwd),
|
|
262
|
+
]);
|
|
263
|
+
const id = randomUUID();
|
|
264
|
+
// Canonicalised BEFORE comparing. `cwd` has already been through canonicalRoot, so a
|
|
265
|
+
// raw string comparison misses the primary root arriving in another spelling — an 8.3
|
|
266
|
+
// short path, a symlinked temp directory, different drive-letter case — and adds it a
|
|
267
|
+
// second time. CI caught exactly that: its temp directory canonicalises differently
|
|
268
|
+
// from the path handed in, so the workspace came back with the same folder twice.
|
|
269
|
+
const carried = await Promise.all(carryRoots.map((r) => canonicalRoot(r)));
|
|
270
|
+
const seenRoot = new Set([cwd]);
|
|
271
|
+
const extra = carried.filter((r) => {
|
|
272
|
+
if (seenRoot.has(r) || !existsSync(r))
|
|
273
|
+
return false;
|
|
274
|
+
seenRoot.add(r);
|
|
275
|
+
return true;
|
|
276
|
+
});
|
|
277
|
+
const toolContext = freshToolContext(cwd, governance, [cwd, ...extra]);
|
|
278
|
+
// So the session tools can exclude this conversation from "your past sessions".
|
|
279
|
+
toolContext.sessionId = id;
|
|
280
|
+
attachMcp(toolContext, cwd);
|
|
281
|
+
await seedProjectMemoryRead(toolContext, projectMemory);
|
|
282
|
+
return {
|
|
283
|
+
id,
|
|
284
|
+
cwd,
|
|
285
|
+
createdAt: Date.now(),
|
|
286
|
+
transcript: [],
|
|
287
|
+
toolContext,
|
|
288
|
+
projectMemory,
|
|
289
|
+
memoryDir: memoryDir(cwd),
|
|
290
|
+
memoryIndex,
|
|
291
|
+
// Everything already saved predates this brand-new session.
|
|
292
|
+
priorSessions: earlier.length,
|
|
293
|
+
projectContext,
|
|
294
|
+
governance,
|
|
295
|
+
// Stamped at load so the first turn's freshness check settles instead of reloading
|
|
296
|
+
// what was just read. See governor/freshness.ts.
|
|
297
|
+
governanceStamp: stamp,
|
|
298
|
+
modelConfig,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Resume the most recent saved session for `cwd` (or a specific `id`), returning
|
|
303
|
+
* a live Session with its transcript loaded. Returns null when there's nothing
|
|
304
|
+
* to resume. The tool context starts fresh — the model re-reads files before it
|
|
305
|
+
* edits them (that's the read-before-edit contract), so a resumed session simply
|
|
306
|
+
* re-reads as needed rather than trusting a stale ledger.
|
|
307
|
+
*/
|
|
308
|
+
/**
|
|
309
|
+
* Repair a transcript that was cut off mid-tool. If the session was closed between the
|
|
310
|
+
* model issuing tool calls and their results being recorded (PC shutdown, force-kill,
|
|
311
|
+
* crash), some `tool_calls` have no matching `tool` result — which the provider rejects
|
|
312
|
+
* (breaking /continue) and which hides that the tool never finished. For every
|
|
313
|
+
* unanswered call we insert a synthetic result, right after its assistant message so the
|
|
314
|
+
* tool group stays contiguous, marking it interrupted so the model re-checks the real
|
|
315
|
+
* state before trusting or repeating it. Pure; returns a new array (unchanged if nothing
|
|
316
|
+
* was dangling). Exported for tests.
|
|
317
|
+
*/
|
|
318
|
+
/**
|
|
319
|
+
* Move anything that got wedged BETWEEN a `tool_calls` message and its results back
|
|
320
|
+
* out to after them. Pure; returns a new array (unchanged when nothing is stranded).
|
|
321
|
+
*
|
|
322
|
+
* Providers require a message carrying `tool_calls` to be followed immediately by one
|
|
323
|
+
* `tool` message per call. A build of Mindweave briefly appended its narration nudge
|
|
324
|
+
* the moment it judged the fault — right after the assistant message and before any
|
|
325
|
+
* result — so sessions written in that window hold a permanently invalid order and
|
|
326
|
+
* every resume of one dies on the first request:
|
|
327
|
+
*
|
|
328
|
+
* assistant(tool_calls) → user(nudge) → tool → tool ← rejected
|
|
329
|
+
* assistant(tool_calls) → tool → tool → user(nudge) ← what it should be
|
|
330
|
+
*
|
|
331
|
+
* The engine no longer produces this, but a fix that only stops NEW corruption leaves
|
|
332
|
+
* the already-saved sessions unopenable, and those hold the user's actual work. The
|
|
333
|
+
* stranded message is MOVED rather than dropped: it may be something the person typed,
|
|
334
|
+
* and repair is not a licence to lose it.
|
|
335
|
+
*/
|
|
336
|
+
export function repairToolCallOrder(transcript) {
|
|
337
|
+
const out = [];
|
|
338
|
+
let moved = false;
|
|
339
|
+
let i = 0;
|
|
340
|
+
while (i < transcript.length) {
|
|
341
|
+
const entry = transcript[i];
|
|
342
|
+
out.push(entry);
|
|
343
|
+
i++;
|
|
344
|
+
if (entry.role !== "assistant" || !entry.toolCalls?.length)
|
|
345
|
+
continue;
|
|
346
|
+
const owed = new Set(entry.toolCalls.map((c) => c.id));
|
|
347
|
+
const results = [];
|
|
348
|
+
const stranded = [];
|
|
349
|
+
// Walk forward while results are still outstanding, keeping them in order and
|
|
350
|
+
// setting aside anything that does not belong inside the group. A new assistant
|
|
351
|
+
// message means the group was abandoned — stop and let reconcile fill the gaps.
|
|
352
|
+
while (i < transcript.length && owed.size > 0) {
|
|
353
|
+
const next = transcript[i];
|
|
354
|
+
if (next.role === "assistant")
|
|
355
|
+
break;
|
|
356
|
+
if (next.role === "tool" && owed.has(next.toolCallId)) {
|
|
357
|
+
owed.delete(next.toolCallId);
|
|
358
|
+
results.push(next);
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
stranded.push(next);
|
|
362
|
+
moved = true;
|
|
363
|
+
}
|
|
364
|
+
i++;
|
|
365
|
+
}
|
|
366
|
+
out.push(...results, ...stranded);
|
|
367
|
+
}
|
|
368
|
+
return moved ? out : transcript;
|
|
369
|
+
}
|
|
370
|
+
export function reconcileInterruptedTools(transcript) {
|
|
371
|
+
const answered = new Set();
|
|
372
|
+
for (const e of transcript)
|
|
373
|
+
if (e.role === "tool")
|
|
374
|
+
answered.add(e.toolCallId);
|
|
375
|
+
let repaired = false;
|
|
376
|
+
const out = [];
|
|
377
|
+
for (const e of transcript) {
|
|
378
|
+
out.push(e);
|
|
379
|
+
if (e.role === "assistant" && e.toolCalls?.length) {
|
|
380
|
+
for (const call of e.toolCalls) {
|
|
381
|
+
if (answered.has(call.id))
|
|
382
|
+
continue;
|
|
383
|
+
answered.add(call.id); // guard against a (malformed) duplicate id
|
|
384
|
+
repaired = true;
|
|
385
|
+
out.push({
|
|
386
|
+
role: "tool",
|
|
387
|
+
toolCallId: call.id,
|
|
388
|
+
content: `[interrupted] '${call.name}' did not finish — the session was closed before this tool ` +
|
|
389
|
+
`returned, so its effect on disk/state is unknown. Re-check the current state (files, ` +
|
|
390
|
+
`processes, installs) before relying on it or running it again.`,
|
|
391
|
+
summary: `${call.name} — interrupted (session closed)`,
|
|
392
|
+
isError: true,
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return repaired ? out : transcript;
|
|
398
|
+
}
|
|
399
|
+
export async function resumeSession(cwd = process.cwd(), id) {
|
|
400
|
+
const meta = id ? await loadMeta(cwd, id) : await latestSession(cwd);
|
|
401
|
+
if (!meta)
|
|
402
|
+
return null;
|
|
403
|
+
const loaded = await loadTranscript(cwd, meta.id);
|
|
404
|
+
if (!loaded || loaded.length === 0)
|
|
405
|
+
return null;
|
|
406
|
+
// A session closed mid-tool (PC shutdown, force-kill) leaves the model's tool_calls
|
|
407
|
+
// with no results — invalid to replay and silent about what didn't finish. Repair it
|
|
408
|
+
// so /continue resumes cleanly and the model re-checks the interrupted step.
|
|
409
|
+
// Order first, then fill gaps: reconcile inserts results right after their assistant
|
|
410
|
+
// message, so it must see a group that is already contiguous.
|
|
411
|
+
const transcript = reconcileInterruptedTools(repairToolCallOrder(loaded));
|
|
412
|
+
const [projectMemory, memoryIndex, projectContext, governance, stamp, modelConfig, sessionMemory, saved] = await Promise.all([
|
|
413
|
+
loadProjectMemory(cwd),
|
|
414
|
+
loadMemory(cwd),
|
|
415
|
+
projectContextText(cwd),
|
|
416
|
+
loadGovernance(cwd),
|
|
417
|
+
governanceStamp(cwd),
|
|
418
|
+
loadModelConfig(cwd),
|
|
419
|
+
loadSessionNotes(cwd, meta.id),
|
|
420
|
+
listSessions(cwd),
|
|
421
|
+
]);
|
|
422
|
+
// Restore any added roots that still exist on disk (primary first).
|
|
423
|
+
const extra = (meta.extraRoots ?? []).filter((r) => existsSync(r));
|
|
424
|
+
const roots = [cwd, ...extra];
|
|
425
|
+
const toolContext = freshToolContext(cwd, governance, roots);
|
|
426
|
+
// Undo history is in-memory, so a resumed session starts with none even though the
|
|
427
|
+
// earlier turns really did change files. Marking it lets /undo explain that rather
|
|
428
|
+
// than claim nothing has happened.
|
|
429
|
+
toolContext.checkpoints?.noteResumed();
|
|
430
|
+
toolContext.sessionId = meta.id;
|
|
431
|
+
// Re-advertise the deferred tools this session had already surfaced, so a continued
|
|
432
|
+
// session keeps them callable instead of stripping a tool the model was mid-use of.
|
|
433
|
+
if (meta.activatedTools && meta.activatedTools.length > 0) {
|
|
434
|
+
toolContext.activatedTools = new Set(meta.activatedTools);
|
|
435
|
+
}
|
|
436
|
+
attachMcp(toolContext, cwd);
|
|
437
|
+
await seedProjectMemoryRead(toolContext, projectMemory);
|
|
438
|
+
return {
|
|
439
|
+
id: meta.id,
|
|
440
|
+
cwd,
|
|
441
|
+
createdAt: meta.createdAt ?? Date.now(),
|
|
442
|
+
transcript,
|
|
443
|
+
toolContext,
|
|
444
|
+
projectMemory,
|
|
445
|
+
memoryDir: memoryDir(cwd),
|
|
446
|
+
memoryIndex,
|
|
447
|
+
// The session being resumed is not "prior" to itself.
|
|
448
|
+
priorSessions: Math.max(0, saved.filter((m) => m.id !== meta.id).length),
|
|
449
|
+
projectContext,
|
|
450
|
+
governance,
|
|
451
|
+
// Stamped at load so the first turn's freshness check settles instead of reloading
|
|
452
|
+
// what was just read. See governor/freshness.ts.
|
|
453
|
+
governanceStamp: stamp,
|
|
454
|
+
modelConfig,
|
|
455
|
+
// The maintained session notes survive a resume, so a continued session keeps its
|
|
456
|
+
// crisp running state. The watermark starts fresh; it'll refresh as it grows again.
|
|
457
|
+
...(sessionMemory ? { sessionMemory, sessionMemoryInit: true } : {}),
|
|
458
|
+
// What the session has already cost, and the per-call detail behind it.
|
|
459
|
+
//
|
|
460
|
+
// Restored, not restarted. Leaving these out did not merely forget the earlier
|
|
461
|
+
// turns — the next save OVERWRITES the meta file, so a resumed session replaced a
|
|
462
|
+
// true running total with a smaller one and the earlier spend was gone for good. A
|
|
463
|
+
// session's cost is the cost of the whole session; `/continue` is not a new session.
|
|
464
|
+
//
|
|
465
|
+
// Deliberately unlike `prefixPrint`, which is NOT restored: that one asserts the
|
|
466
|
+
// provider still holds a cache, and after a resume it does not. These are records of
|
|
467
|
+
// what happened, and what happened does not stop being true.
|
|
468
|
+
...(meta.spend ? { spend: meta.spend } : {}),
|
|
469
|
+
...(meta.callLog ? { callLog: meta.callLog } : {}),
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/memory/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { estimateEntriesTokens, estimateTokens, formatTranscriptForSummary } from "./compaction.js";
|
|
2
|
+
import { activeDriver } from "../drivers/registry.js";
|
|
3
|
+
const env = (name, fallback) => {
|
|
4
|
+
const v = Number(process.env[name]);
|
|
5
|
+
return Number.isFinite(v) && v > 0 ? v : fallback;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* First update once the transcript passes this (let a session warm up first).
|
|
9
|
+
*
|
|
10
|
+
* Deliberately LOW. At 10K a session could do a whole piece of real work and end
|
|
11
|
+
* having never written a note, so a later `read_session` found nothing and fell back
|
|
12
|
+
* to the raw transcript — a worse answer, for more tokens, after an extra round trip.
|
|
13
|
+
* The bar only exists so a two-message session doesn't pay for a model call; 4K is
|
|
14
|
+
* enough warm-up for that and cheap enough that ordinary sessions get real notes.
|
|
15
|
+
*/
|
|
16
|
+
const INIT_THRESHOLD = env("MINDWEAVE_SESSION_MEMORY_INIT", 4_000);
|
|
17
|
+
/** Refresh the notes after this much further growth (token-gated). */
|
|
18
|
+
const UPDATE_THRESHOLD = env("MINDWEAVE_SESSION_MEMORY_UPDATE", 12_000);
|
|
19
|
+
/** How many recent transcript entries feed an update (the notes carry the older state). */
|
|
20
|
+
const RECENT_ENTRIES = env("MINDWEAVE_SESSION_MEMORY_RECENT", 40);
|
|
21
|
+
/** Hard cap on the notes so they can't themselves bloat context (~12K tokens total,
|
|
22
|
+
* ~2K per section). */
|
|
23
|
+
export const SESSION_MEMORY_MAX_TOKENS = env("MINDWEAVE_SESSION_MEMORY_MAX_TOKENS", 12_000);
|
|
24
|
+
/** Per-section soft budget — condense a section past this (~2K/section). */
|
|
25
|
+
export const SESSION_MEMORY_SECTION_TOKENS = env("MINDWEAVE_SESSION_MEMORY_SECTION_TOKENS", 2_000);
|
|
26
|
+
/** The structured skeleton the model fills in and keeps current. The
|
|
27
|
+
* italic _descriptions_ are template instructions (kept intact); the model only fills
|
|
28
|
+
* the content beneath each. "Current State" is first-class: it's what lets the model
|
|
29
|
+
* pick up cleanly after a compaction. */
|
|
30
|
+
export const SESSION_MEMORY_TEMPLATE = `# Session Title
|
|
31
|
+
_A short and distinctive 5-10 word descriptive title for the session. Super info dense, no filler_
|
|
32
|
+
|
|
33
|
+
# Current State
|
|
34
|
+
_What is actively being worked on right now? Pending tasks not yet completed. Immediate next steps._
|
|
35
|
+
|
|
36
|
+
# Task specification
|
|
37
|
+
_What did the user ask to build? Any design decisions or other explanatory context_
|
|
38
|
+
|
|
39
|
+
# Files and Functions
|
|
40
|
+
_What are the important files? In short, what do they contain and why are they relevant?_
|
|
41
|
+
|
|
42
|
+
# Workflow
|
|
43
|
+
_What commands are usually run and in what order? How to interpret their output if not obvious?_
|
|
44
|
+
|
|
45
|
+
# Errors & Corrections
|
|
46
|
+
_Errors encountered and how they were fixed. What did the user correct? What approaches failed and should not be tried again?_
|
|
47
|
+
|
|
48
|
+
# Codebase and System Documentation
|
|
49
|
+
_What are the important system components? How do they work/fit together?_
|
|
50
|
+
|
|
51
|
+
# Learnings
|
|
52
|
+
_What has worked well? What has not? What to avoid? Do not duplicate items from other sections_
|
|
53
|
+
|
|
54
|
+
# Key results
|
|
55
|
+
_If the user asked a specific output such as an answer to a question, a table, or other document, repeat the exact result here_
|
|
56
|
+
|
|
57
|
+
# Worklog
|
|
58
|
+
_Step by step, what was attempted, done? Very terse summary for each step_`;
|
|
59
|
+
const UPDATE_SYSTEM = "You maintain a running notes document that captures the live state of a software " +
|
|
60
|
+
"engineering session, so work can continue seamlessly across context compaction. You " +
|
|
61
|
+
"will be given the CURRENT notes and the RECENT conversation. Return the COMPLETE updated " +
|
|
62
|
+
"notes document. Rules:\n" +
|
|
63
|
+
"- Keep EVERY section header exactly, and keep the italic _description_ line under each " +
|
|
64
|
+
"header intact (those are template instructions, not content) — only update the content " +
|
|
65
|
+
"beneath them.\n" +
|
|
66
|
+
"- Fold new activity into the right sections; write DENSE, specific content (file paths, " +
|
|
67
|
+
"function names, exact commands, error messages, decisions).\n" +
|
|
68
|
+
`- Keep each section under ~${SESSION_MEMORY_SECTION_TOKENS} tokens: when one grows past that, ` +
|
|
69
|
+
"CYCLE OUT the least important details while preserving the most critical.\n" +
|
|
70
|
+
"- Leave a section unchanged if there's nothing substantial to add (no filler like 'N/A').\n" +
|
|
71
|
+
"- ALWAYS keep 'Current State' accurate to the latest turn — it's what continues the work " +
|
|
72
|
+
"after compaction.\n" +
|
|
73
|
+
"Output ONLY the notes document — no preamble, no commentary, no code fences.";
|
|
74
|
+
const UPDATE_REQUEST = "Update the notes with anything new from the recent conversation, then output the full " +
|
|
75
|
+
"updated notes document (same section headers and italic descriptions, dense, concise).";
|
|
76
|
+
/**
|
|
77
|
+
* Whether to refresh the notes now (pure). The token threshold is ALWAYS the gate,
|
|
78
|
+
* so updates don't fire too often; before the first update we wait for the
|
|
79
|
+
* session to warm past the init bar.
|
|
80
|
+
*/
|
|
81
|
+
export function shouldUpdateSessionMemory(currentTokens, lastUpdateTokens, initialized) {
|
|
82
|
+
if (!initialized)
|
|
83
|
+
return currentTokens >= INIT_THRESHOLD;
|
|
84
|
+
return currentTokens - lastUpdateTokens >= UPDATE_THRESHOLD;
|
|
85
|
+
}
|
|
86
|
+
/** The injected block (volatile tail — it changes as it's refreshed, so it must NOT
|
|
87
|
+
* sit in the cached prefix). "" when there are no notes yet. */
|
|
88
|
+
export function renderSessionMemory(notes) {
|
|
89
|
+
const trimmed = notes.trim();
|
|
90
|
+
if (!trimmed)
|
|
91
|
+
return "";
|
|
92
|
+
return ("Your maintained notes on THIS session's state (kept current across compaction — " +
|
|
93
|
+
"trust these for what's done, what's in flight, and what already failed):\n" +
|
|
94
|
+
`<session_memory>\n${trimmed}\n</session_memory>`);
|
|
95
|
+
}
|
|
96
|
+
/** Keep the notes under budget: if the model over-produces, trim to the cap (pure). */
|
|
97
|
+
export function boundSessionMemory(notes, maxTokens = SESSION_MEMORY_MAX_TOKENS) {
|
|
98
|
+
if (estimateTokens(notes) <= maxTokens)
|
|
99
|
+
return notes;
|
|
100
|
+
const maxChars = Math.floor(maxTokens * 3.5);
|
|
101
|
+
return notes.slice(0, maxChars).trimEnd() + "\n\n(notes truncated to stay within budget)";
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Refresh the session notes from the recent transcript (one cheap model call, thinking
|
|
105
|
+
* off). Mutates `session.sessionMemory` + the token watermark IN MEMORY only — the CLI
|
|
106
|
+
* persists the notes file, keeping the engine filesystem-pure. Degrade-safe: on any
|
|
107
|
+
* failure the previous notes are kept untouched.
|
|
108
|
+
*/
|
|
109
|
+
export async function updateSessionMemory(session) {
|
|
110
|
+
const recent = session.transcript.slice(-RECENT_ENTRIES);
|
|
111
|
+
if (recent.length === 0)
|
|
112
|
+
return false;
|
|
113
|
+
const current = session.sessionMemory?.trim() || SESSION_MEMORY_TEMPLATE;
|
|
114
|
+
try {
|
|
115
|
+
const { content } = await activeDriver().toolTurn({
|
|
116
|
+
system: UPDATE_SYSTEM,
|
|
117
|
+
messages: [
|
|
118
|
+
{
|
|
119
|
+
role: "user",
|
|
120
|
+
content: `CURRENT NOTES:\n${current}\n\n` +
|
|
121
|
+
`RECENT CONVERSATION:\n${formatTranscriptForSummary(recent)}\n\n${UPDATE_REQUEST}`,
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
model: { ...session.modelConfig, thinking: false },
|
|
125
|
+
});
|
|
126
|
+
const notes = content.trim();
|
|
127
|
+
if (!notes)
|
|
128
|
+
return false;
|
|
129
|
+
session.sessionMemory = boundSessionMemory(notes);
|
|
130
|
+
session.sessionMemoryTokens = estimateEntriesTokens(session.transcript);
|
|
131
|
+
// The boundary compaction-from-notes splits on: everything up to here is written
|
|
132
|
+
// down, everything after it has to be kept verbatim. Recorded at the same moment
|
|
133
|
+
// as the notes so the two can never describe different transcripts.
|
|
134
|
+
session.sessionMemoryEntries = session.transcript.length;
|
|
135
|
+
session.sessionMemoryInit = true;
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return false; // keep the last good notes
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=sessionMemory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionMemory.js","sourceRoot":"","sources":["../../src/memory/sessionMemory.ts"],"names":[],"mappings":"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"}
|