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,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* viewport.ts — which transcript blocks are actually on screen.
|
|
3
|
+
*
|
|
4
|
+
* In the alternate screen there is no terminal scrollback to lean on: the app
|
|
5
|
+
* owns every row, so it must decide for itself what fits between the pinned
|
|
6
|
+
* header and the pinned footer.
|
|
7
|
+
*
|
|
8
|
+
* The obvious approach — hand every block to a fixed-height, `overflow: hidden`
|
|
9
|
+
* flex box and let the layout engine clip — DOES NOT WORK, and it fails in the
|
|
10
|
+
* worst possible direction. Measured against Ink 5.2.1 / Yoga 3.2.1:
|
|
11
|
+
*
|
|
12
|
+
* - Children default to `flexShrink: 1`, so an overfull column does not clip at
|
|
13
|
+
* all, it COMPRESSES: 30 one-line blocks in a 17-row box rendered as
|
|
14
|
+
* `block-00, block-02, block-04…` — a strided sample with rows silently
|
|
15
|
+
* dropped out of the middle.
|
|
16
|
+
* - With `flexShrink: 0` the blocks stay whole, but every layout tried
|
|
17
|
+
* (`column-reverse`, `column` + `justifyContent: flex-end`, plain `column`)
|
|
18
|
+
* clips the END of the layout — which is the NEWEST message. The reply you
|
|
19
|
+
* just received is the first thing to disappear off the bottom.
|
|
20
|
+
*
|
|
21
|
+
* So the slice is computed here instead, walking BACKWARD from the newest block
|
|
22
|
+
* and taking blocks until the next one would not fit. The heights are estimated
|
|
23
|
+
* rather than measured — Ink can only measure by rendering, and rendering to
|
|
24
|
+
* decide what to render is a loop — so the estimate deliberately errs HIGH:
|
|
25
|
+
* over-estimating leaves a blank row at the top (harmless), under-estimating
|
|
26
|
+
* would push the pinned footer off the bottom (the bug this file exists to
|
|
27
|
+
* prevent).
|
|
28
|
+
*/
|
|
29
|
+
import { renderMarkdown } from "./markdown.js";
|
|
30
|
+
import { collapseAdjacent } from "./toolItems.js";
|
|
31
|
+
import { GROUP_MAX_ROWS } from "./components/ToolGroup.js";
|
|
32
|
+
/**
|
|
33
|
+
* The newest blocks that fit in `maxRows`, oldest-first (render order).
|
|
34
|
+
*
|
|
35
|
+
* `scrollBack` skips that many blocks from the newest end, which is how paging
|
|
36
|
+
* up works: the window slides toward older history without the block list or
|
|
37
|
+
* the estimator needing to know anything about scrolling.
|
|
38
|
+
*/
|
|
39
|
+
export function visibleBlocks(all, columns, maxRows, scrollBack = 0) {
|
|
40
|
+
if (maxRows <= 0 || all.length === 0)
|
|
41
|
+
return { blocks: [], hiddenAbove: 0 };
|
|
42
|
+
// Anything scrolled past is simply not a candidate — the window's newest end.
|
|
43
|
+
const end = Math.max(0, all.length - clampScroll(all.length, scrollBack));
|
|
44
|
+
const taken = [];
|
|
45
|
+
let used = 0;
|
|
46
|
+
for (let i = end - 1; i >= 0; i--) {
|
|
47
|
+
const block = all[i];
|
|
48
|
+
const height = blockHeight(block, columns, isTight(all, i));
|
|
49
|
+
// Always take at least one block: a single block taller than the whole
|
|
50
|
+
// viewport must still render (clipped) rather than leaving a blank screen.
|
|
51
|
+
if (taken.length > 0 && used + height > maxRows)
|
|
52
|
+
break;
|
|
53
|
+
taken.push(block);
|
|
54
|
+
used += height;
|
|
55
|
+
}
|
|
56
|
+
taken.reverse();
|
|
57
|
+
return { blocks: taken, hiddenAbove: end - taken.length };
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Whether block `i` hugs the one above it (no blank line between).
|
|
61
|
+
*
|
|
62
|
+
* Exported because the height estimate and the actual render MUST agree: if the
|
|
63
|
+
* renderer hugs a row the estimate padded, the arithmetic drifts by a line per
|
|
64
|
+
* tool call and the footer walks off the bottom. One definition, used by both.
|
|
65
|
+
*/
|
|
66
|
+
export function isTight(all, i) {
|
|
67
|
+
const block = all[i];
|
|
68
|
+
const prev = i > 0 ? all[i - 1] : undefined;
|
|
69
|
+
return !!block && block.kind === "tool" && !!prev && prev.kind === "tool";
|
|
70
|
+
}
|
|
71
|
+
/** Clamp a scroll offset so paging can never run past either end of history. */
|
|
72
|
+
export function clampScroll(total, scrollBack) {
|
|
73
|
+
if (!Number.isFinite(scrollBack) || scrollBack <= 0)
|
|
74
|
+
return 0;
|
|
75
|
+
// One block must always remain visible, so the newest end can always be found.
|
|
76
|
+
return Math.min(Math.floor(scrollBack), Math.max(0, total - 1));
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Rows one block occupies, matching BlockView's structure (margins included).
|
|
80
|
+
*
|
|
81
|
+
* Kept deliberately close to BlockView: when a block type's rendering changes,
|
|
82
|
+
* this is the other half of that change. A drifted estimate degrades (a blank
|
|
83
|
+
* row, or a partially clipped top block) rather than breaking, which is why the
|
|
84
|
+
* coupling is acceptable — but it IS coupling, so the cases are in the same
|
|
85
|
+
* order as the switch in BlockView.tsx.
|
|
86
|
+
*/
|
|
87
|
+
export function blockHeight(block, columns, tight = false) {
|
|
88
|
+
const textWidth = Math.max(8, columns - 4);
|
|
89
|
+
const top = tight ? 0 : 1;
|
|
90
|
+
switch (block.kind) {
|
|
91
|
+
case "user":
|
|
92
|
+
return 1 + wrappedLines(block.text, textWidth);
|
|
93
|
+
case "assistant":
|
|
94
|
+
if (!block.text)
|
|
95
|
+
return 0; // BlockView renders null
|
|
96
|
+
return 1 + countLines(renderMarkdown(block.text, textWidth));
|
|
97
|
+
case "tool": {
|
|
98
|
+
const branch = block.status !== "running" ? branchLineCount(block) : 0;
|
|
99
|
+
return top + 1 + branch;
|
|
100
|
+
}
|
|
101
|
+
case "tools": {
|
|
102
|
+
// Header, plus (once done) the calls listed under it, capped — see ToolGroup.
|
|
103
|
+
if (!block.done)
|
|
104
|
+
return top + 1;
|
|
105
|
+
const listed = collapseAdjacent(block.items).length;
|
|
106
|
+
const shown = Math.min(listed, GROUP_MAX_ROWS);
|
|
107
|
+
return top + 1 + shown + (listed > shown ? 1 : 0);
|
|
108
|
+
}
|
|
109
|
+
case "subagent": {
|
|
110
|
+
const items = collapseAdjacent(block.items).length;
|
|
111
|
+
const summary = block.done && block.summary ? 1 : 0;
|
|
112
|
+
return top + 1 + items + summary;
|
|
113
|
+
}
|
|
114
|
+
case "error":
|
|
115
|
+
return 1 + wrappedLines(block.text, textWidth);
|
|
116
|
+
case "completion":
|
|
117
|
+
return 1 + 1; // marginTop + a single truncated line
|
|
118
|
+
case "note":
|
|
119
|
+
return wrappedLines(`· ${block.text}`, Math.max(8, columns));
|
|
120
|
+
case "context":
|
|
121
|
+
return 1 + 1 + 1; // marginTop + one truncated line + marginBottom
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/** The `⎿` branch rows under a resolved tool row (detail wins over summary). */
|
|
125
|
+
function branchLineCount(block) {
|
|
126
|
+
if (block.detail)
|
|
127
|
+
return countLines(block.detail);
|
|
128
|
+
return block.summary ? 1 : 0;
|
|
129
|
+
}
|
|
130
|
+
function countLines(s) {
|
|
131
|
+
return s === "" ? 0 : s.split("\n").length;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Rows a string takes when word-wrapped to `width` (pure).
|
|
135
|
+
*
|
|
136
|
+
* Greedy word wrapping, matching how Ink wraps `<Text wrap="wrap">`, because the
|
|
137
|
+
* cheap `ceil(length / width)` under-counts exactly when it matters: a line of
|
|
138
|
+
* long words breaks earlier than its character count suggests, and under-counting
|
|
139
|
+
* is the direction that pushes the footer off screen.
|
|
140
|
+
*/
|
|
141
|
+
export function wrappedLines(text, width) {
|
|
142
|
+
if (width <= 0)
|
|
143
|
+
return 1;
|
|
144
|
+
let rows = 0;
|
|
145
|
+
for (const line of text.split("\n")) {
|
|
146
|
+
if (line === "") {
|
|
147
|
+
rows += 1;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
let col = 0;
|
|
151
|
+
for (const word of line.split(/\s+/).filter(Boolean)) {
|
|
152
|
+
// A word longer than the line wraps across as many rows as it needs.
|
|
153
|
+
// `rows` counts only COMPLETED rows and `col` carries the row still being
|
|
154
|
+
// filled, so this takes the floor and lets the trailing check below close
|
|
155
|
+
// the partial row — taking the ceiling here counts that last row twice.
|
|
156
|
+
if (word.length > width) {
|
|
157
|
+
if (col > 0) {
|
|
158
|
+
rows += 1;
|
|
159
|
+
col = 0;
|
|
160
|
+
}
|
|
161
|
+
rows += Math.floor(word.length / width);
|
|
162
|
+
col = word.length % width;
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
const needed = col === 0 ? word.length : col + 1 + word.length;
|
|
166
|
+
if (needed > width) {
|
|
167
|
+
rows += 1;
|
|
168
|
+
col = word.length;
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
col = needed;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (col > 0 || rows === 0)
|
|
175
|
+
rows += 1;
|
|
176
|
+
}
|
|
177
|
+
return Math.max(1, rows);
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=viewport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewport.js","sourceRoot":"","sources":["../../src/cli/viewport.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* virtualWindow.ts — which transcript blocks are worth handing to the renderer.
|
|
3
|
+
*
|
|
4
|
+
* THE PROBLEM THIS SOLVES, measured before it existed: the transcript rendered in
|
|
5
|
+
* FULL inside a clipped viewport, so a 150-block conversation laid out ~2,100 rows
|
|
6
|
+
* on every frame in order to show about 30 of them. Cost tracks total rendered rows
|
|
7
|
+
* and goes superlinear — bare Ink, no Mindweave code involved:
|
|
8
|
+
*
|
|
9
|
+
* 700 rows -> 8.1 ms/frame
|
|
10
|
+
* 1000 rows -> 52.8 ms/frame
|
|
11
|
+
* 2100 rows -> 109.1 ms/frame
|
|
12
|
+
*
|
|
13
|
+
* Against Ink's 32ms frame throttle, that is the typing lag and the scroll stutter.
|
|
14
|
+
* Memoizing the block components removed the markdown work but not this: Yoga still
|
|
15
|
+
* lays out every node it is given, whether or not React re-rendered it.
|
|
16
|
+
*
|
|
17
|
+
* Gemini CLI hit the same wall and answered it the same way — for its alternate-buffer
|
|
18
|
+
* path it renders through a VirtualizedList that keeps a cumulative offsets array and
|
|
19
|
+
* draws only the slice covering the viewport. This is that idea, in the shape this
|
|
20
|
+
* codebase already has.
|
|
21
|
+
*
|
|
22
|
+
* WHY THIS IS SAFE, given that an earlier attempt at virtualization is exactly why the
|
|
23
|
+
* scroll mechanism was frozen. That attempt ESTIMATED each block's height and rendered
|
|
24
|
+
* only what it thought would fit, so any drift between the estimate and the real render
|
|
25
|
+
* made content shift around, and it scrolled a whole block per step so a long block
|
|
26
|
+
* jumped the view past its own contents.
|
|
27
|
+
*
|
|
28
|
+
* This one does neither:
|
|
29
|
+
*
|
|
30
|
+
* - It estimates NOTHING. It is given exact, already-measured row heights, and the
|
|
31
|
+
* caller renders nothing it has not measured (see App.tsx: a block is measured on
|
|
32
|
+
* the frame it first appears, which it always does at the bottom of the transcript
|
|
33
|
+
* before it can scroll anywhere).
|
|
34
|
+
* - It does not scroll. `scrollUp`, `chatLayout` and the negative-margin slide are
|
|
35
|
+
* untouched. The blocks outside the window are replaced by SPACERS of their exact
|
|
36
|
+
* summed height, so `contentHeight` is identical to what it was when every block
|
|
37
|
+
* was rendered in full, and therefore so is `marginTop`. The scroll mechanism
|
|
38
|
+
* cannot tell the difference; only Yoga's workload changes.
|
|
39
|
+
*/
|
|
40
|
+
/**
|
|
41
|
+
* How many blocks beyond each edge of the viewport to keep mounted.
|
|
42
|
+
*
|
|
43
|
+
* Not a performance knob — a correctness margin. A block is measured on the frame it
|
|
44
|
+
* is rendered, so keeping a couple in hand on each side means the ones about to come
|
|
45
|
+
* into view are already mounted and measured rather than appearing on the frame they
|
|
46
|
+
* are first needed. Two is enough because the caller never virtualizes a block it has
|
|
47
|
+
* not already measured.
|
|
48
|
+
*/
|
|
49
|
+
export const OVERSCAN_BLOCKS = 2;
|
|
50
|
+
/**
|
|
51
|
+
* The blocks covering rows `[shift, shift + rows)` of the transcript, plus overscan.
|
|
52
|
+
*
|
|
53
|
+
* @param heights exact rendered height of every block, in rows, in transcript order
|
|
54
|
+
* @param shift first visible content row (from `chatLayout`: `maxScroll - scrolled`)
|
|
55
|
+
* @param rows viewport height in rows
|
|
56
|
+
*/
|
|
57
|
+
export function virtualWindow(heights, shift, rows) {
|
|
58
|
+
if (heights.length === 0)
|
|
59
|
+
return { start: 0, end: 0, padTop: 0, padBottom: 0 };
|
|
60
|
+
// A viewport of no rows still has to name a block, or the caller renders an empty
|
|
61
|
+
// transcript and the screen goes blank with nothing to explain it. Same reasoning as
|
|
62
|
+
// chatLayout's own clamp, and the same failure it is avoiding.
|
|
63
|
+
const height = Math.max(1, rows);
|
|
64
|
+
const top = Math.max(0, shift);
|
|
65
|
+
const bottom = top + height;
|
|
66
|
+
// Walk once, accumulating offsets. A binary search over a prefix-sum array would be
|
|
67
|
+
// asymptotically better and is what a list of thousands would need; this list is
|
|
68
|
+
// capped at SCROLLBACK_BLOCKS (150), where one pass over a number array is far
|
|
69
|
+
// cheaper than the allocation the prefix-sum table would cost every frame.
|
|
70
|
+
let first = -1;
|
|
71
|
+
let last = -1;
|
|
72
|
+
let offset = 0;
|
|
73
|
+
for (let i = 0; i < heights.length; i++) {
|
|
74
|
+
const start = offset;
|
|
75
|
+
const end = offset + (heights[i] ?? 0);
|
|
76
|
+
// Overlap, not containment: a block taller than the whole viewport contains no
|
|
77
|
+
// visible edge and would be skipped by a containment test — leaving a hole exactly
|
|
78
|
+
// where the biggest thing on screen should be.
|
|
79
|
+
if (end > top && start < bottom) {
|
|
80
|
+
if (first === -1)
|
|
81
|
+
first = i;
|
|
82
|
+
last = i;
|
|
83
|
+
}
|
|
84
|
+
offset = end;
|
|
85
|
+
}
|
|
86
|
+
// Nothing overlaps: the offset is past the end of the content (a stale measurement
|
|
87
|
+
// during a resize can do this for a frame). Anchor to the last block rather than
|
|
88
|
+
// rendering nothing, so the newest output stays on screen while it settles.
|
|
89
|
+
if (first === -1) {
|
|
90
|
+
first = heights.length - 1;
|
|
91
|
+
last = heights.length - 1;
|
|
92
|
+
}
|
|
93
|
+
const start = Math.max(0, first - OVERSCAN_BLOCKS);
|
|
94
|
+
const end = Math.min(heights.length, last + 1 + OVERSCAN_BLOCKS);
|
|
95
|
+
let padTop = 0;
|
|
96
|
+
for (let i = 0; i < start; i++)
|
|
97
|
+
padTop += heights[i] ?? 0;
|
|
98
|
+
let padBottom = 0;
|
|
99
|
+
for (let i = end; i < heights.length; i++)
|
|
100
|
+
padBottom += heights[i] ?? 0;
|
|
101
|
+
return { start, end, padTop, padBottom };
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=virtualWindow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"virtualWindow.js","sourceRoot":"","sources":["../../src/cli/virtualWindow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAcH;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC;AAEjC;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,OAA0B,EAAE,KAAa,EAAE,IAAY;IACnF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;IAE/E,kFAAkF;IAClF,qFAAqF;IACrF,+DAA+D;IAC/D,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IACjC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC;IAE5B,oFAAoF;IACpF,iFAAiF;IACjF,+EAA+E;IAC/E,2EAA2E;IAC3E,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC;IACf,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC;IACd,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,MAAM,CAAC;QACrB,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACvC,+EAA+E;QAC/E,mFAAmF;QACnF,+CAA+C;QAC/C,IAAI,GAAG,GAAG,GAAG,IAAI,KAAK,GAAG,MAAM,EAAE,CAAC;YAChC,IAAI,KAAK,KAAK,CAAC,CAAC;gBAAE,KAAK,GAAG,CAAC,CAAC;YAC5B,IAAI,GAAG,CAAC,CAAC;QACX,CAAC;QACD,MAAM,GAAG,GAAG,CAAC;IACf,CAAC;IAED,mFAAmF;IACnF,iFAAiF;IACjF,4EAA4E;IAC5E,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;QACjB,KAAK,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;QAC3B,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IAC5B,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,eAAe,CAAC,CAAC;IACnD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,GAAG,CAAC,GAAG,eAAe,CAAC,CAAC;IAEjE,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE;QAAE,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC1D,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,KAAK,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,SAAS,IAAI,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAExE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;AAC3C,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* workingVerb.ts — the word the status line shows while a turn runs.
|
|
3
|
+
*
|
|
4
|
+
* `Working…` on every turn of every session is a label, not a signal: it says the
|
|
5
|
+
* thing the spinner already says. A word that differs per turn tells you at a glance
|
|
6
|
+
* that this is a NEW turn and not the last one still going — which is the one thing
|
|
7
|
+
* the line is there to answer.
|
|
8
|
+
*
|
|
9
|
+
* Held for the whole turn, derived from the turn's start time rather than stored, so
|
|
10
|
+
* the once-a-second re-render cannot make it flicker between words. Pure, so the
|
|
11
|
+
* choice is testable without a clock.
|
|
12
|
+
*/
|
|
13
|
+
/** Present participles only, and none that claim progress the harness cannot see
|
|
14
|
+
* ("Almost done", "Finishing") — those would be a guess dressed as a status. */
|
|
15
|
+
const VERBS = [
|
|
16
|
+
"Scampering",
|
|
17
|
+
"Tinkering",
|
|
18
|
+
"Rummaging",
|
|
19
|
+
"Untangling",
|
|
20
|
+
"Puzzling",
|
|
21
|
+
"Burrowing",
|
|
22
|
+
"Whirring",
|
|
23
|
+
"Pondering",
|
|
24
|
+
"Noodling",
|
|
25
|
+
"Sifting",
|
|
26
|
+
"Weaving",
|
|
27
|
+
"Chewing",
|
|
28
|
+
];
|
|
29
|
+
/** The verb for the turn that began at `startedAt`. Stable for that whole turn. */
|
|
30
|
+
export function workingVerb(startedAt) {
|
|
31
|
+
// Milliseconds, not seconds: two turns started in the same second still differ.
|
|
32
|
+
const i = Math.abs(Math.floor(startedAt)) % VERBS.length;
|
|
33
|
+
return VERBS[i];
|
|
34
|
+
}
|
|
35
|
+
/** Exposed for the test — the pool must stay free of progress claims. */
|
|
36
|
+
export const WORKING_VERBS = VERBS;
|
|
37
|
+
//# sourceMappingURL=workingVerb.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workingVerb.js","sourceRoot":"","sources":["../../src/cli/workingVerb.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;iFACiF;AACjF,MAAM,KAAK,GAAG;IACZ,YAAY;IACZ,WAAW;IACX,WAAW;IACX,YAAY;IACZ,UAAU;IACV,WAAW;IACX,UAAU;IACV,WAAW;IACX,UAAU;IACV,SAAS;IACT,SAAS;IACT,SAAS;CACV,CAAC;AAEF,mFAAmF;AACnF,MAAM,UAAU,WAAW,CAAC,SAAiB;IAC3C,gFAAgF;IAChF,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;IACzD,OAAO,KAAK,CAAC,CAAC,CAAE,CAAC;AACnB,CAAC;AAED,yEAAyE;AACzE,MAAM,CAAC,MAAM,aAAa,GAAsB,KAAK,CAAC"}
|
package/dist/cli/wrap.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* wrap.ts — word-wrap ANSI-styled text ourselves, because Ink's own `wrap="wrap"`
|
|
3
|
+
* has a real bug: some continuation lines come out indented by one stray space,
|
|
4
|
+
* others don't. Confirmed with a bare Ink render, no Mindweave code involved —
|
|
5
|
+
* `<Text wrap="wrap">` on a plain sentence at width 20 produced:
|
|
6
|
+
*
|
|
7
|
+
* sentence that should
|
|
8
|
+
* wrap cleanly across ← extra leading space
|
|
9
|
+
* two or three lines ← extra leading space
|
|
10
|
+
* without issue
|
|
11
|
+
*
|
|
12
|
+
* lines 2 and 5 clean, 3 and 4 not — same input, same call, inconsistent. That
|
|
13
|
+
* rules out anything in BlockView's own Box structure; it is Ink/wrap-ansi's
|
|
14
|
+
* wrapping itself. Rather than depend on the library IT happens to use
|
|
15
|
+
* internally (an undeclared transitive dependency that could vanish on the next
|
|
16
|
+
* `npm install`), this wraps the text before Ink ever sees it and renders each
|
|
17
|
+
* line as its own row — nothing left for Ink's wrapper to get inconsistent about.
|
|
18
|
+
*/
|
|
19
|
+
// Strips ANSI SGR codes (chalk's coloring) so width is measured on what's
|
|
20
|
+
// actually visible, not the escape bytes around it.
|
|
21
|
+
const ANSI_RE = /\x1b\[[0-9;]*m/g;
|
|
22
|
+
/**
|
|
23
|
+
* Text as at most `maxRows` RENDERED rows, saying so when it had to cut (pure).
|
|
24
|
+
*
|
|
25
|
+
* Rendered rows, not newlines: one 400-column line is several rows on screen, and
|
|
26
|
+
* counting newlines would call it short and let it blow the frame anyway.
|
|
27
|
+
*
|
|
28
|
+
* This exists because an unbounded prompt is not a cosmetic problem. Anything drawn in
|
|
29
|
+
* the footer that grows past the terminal's height makes Ink abandon its normal
|
|
30
|
+
* erase-and-redraw, after which the screen tears and the app is unusable — measured,
|
|
31
|
+
* from a 40-step plan passed as an overlay title.
|
|
32
|
+
*/
|
|
33
|
+
export function clipRows(text, width, maxRows) {
|
|
34
|
+
const rows = wrapAnsi(text, Math.max(8, width));
|
|
35
|
+
if (rows.length <= maxRows)
|
|
36
|
+
return rows;
|
|
37
|
+
// Say it was cut. A silently truncated question is one the user answers without
|
|
38
|
+
// having read it.
|
|
39
|
+
return [...rows.slice(0, Math.max(1, maxRows - 1)), `… (${rows.length - (maxRows - 1)} more lines above)`];
|
|
40
|
+
}
|
|
41
|
+
function visibleWidth(s) {
|
|
42
|
+
return s.replace(ANSI_RE, "").length;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Greedy word-wrap of ANSI-styled text to `width` columns (pure).
|
|
46
|
+
*
|
|
47
|
+
* Existing newlines are respected as hard breaks (a markdown reply's paragraph
|
|
48
|
+
* spacing survives). Splitting on whitespace in the ORIGINAL string is safe even
|
|
49
|
+
* with embedded ANSI: an escape sequence (`\x1b[...m`) is only digits and
|
|
50
|
+
* semicolons, so it can never contain the whitespace being split on, and a
|
|
51
|
+
* "word" that comes out of the split keeps whatever styling wraps it intact.
|
|
52
|
+
*
|
|
53
|
+
* A single word wider than `width` (an unbroken run with no spaces, or a long
|
|
54
|
+
* styled token) still has to break somewhere. It hard-breaks on the PLAIN text
|
|
55
|
+
* rather than carry ANSI codes through the cut, which could otherwise sever an
|
|
56
|
+
* escape sequence or leave a color open past the end of its own line — losing
|
|
57
|
+
* that one word's styling is a far smaller cost than corrupting the line after it.
|
|
58
|
+
*/
|
|
59
|
+
export function wrapAnsi(text, width) {
|
|
60
|
+
const w = Math.max(1, width);
|
|
61
|
+
const out = [];
|
|
62
|
+
for (const line of text.split("\n")) {
|
|
63
|
+
out.push(...wrapLine(line, w));
|
|
64
|
+
}
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* A list item's marker, as `markdown.ts` renders one: optional nesting indent, then
|
|
69
|
+
* `•` or `3.`, then a space. Deliberately NOT `-`/`*`/`+` — our own renderer emits
|
|
70
|
+
* the bullet character, and a raw `-` at the start of a line is far more often a diff
|
|
71
|
+
* removal or literal command output, where hanging text under it would be wrong.
|
|
72
|
+
*/
|
|
73
|
+
const LIST_MARKER_RE = /^\s*(?:•|\d+[.)])\s/;
|
|
74
|
+
/**
|
|
75
|
+
* How far a wrapped list item's continuation rows are indented, in columns.
|
|
76
|
+
*
|
|
77
|
+
* Without it the second row of an item starts in the bullet's own column, so
|
|
78
|
+
* "settings." under "• Font picker — let users choose…" reads as a new item rather
|
|
79
|
+
* than the rest of the previous one. Capped so a narrow terminal keeps usable room.
|
|
80
|
+
*/
|
|
81
|
+
function hangingIndent(line, width) {
|
|
82
|
+
const m = LIST_MARKER_RE.exec(line.replace(ANSI_RE, ""));
|
|
83
|
+
return m ? Math.min(m[0].length, Math.max(0, width - 8)) : 0;
|
|
84
|
+
}
|
|
85
|
+
function wrapLine(line, width) {
|
|
86
|
+
const hang = hangingIndent(line, width);
|
|
87
|
+
const pad = " ".repeat(hang);
|
|
88
|
+
const lines = [];
|
|
89
|
+
// The first row starts at the margin; every row after it hangs under the item's text.
|
|
90
|
+
const push = (s) => lines.push(lines.length === 0 ? s : pad + s);
|
|
91
|
+
const room = () => (lines.length === 0 ? width : width - hang);
|
|
92
|
+
const words = line.split(/(\s+)/).filter((w) => w !== "");
|
|
93
|
+
let cur = "";
|
|
94
|
+
let curWidth = 0;
|
|
95
|
+
for (const word of words) {
|
|
96
|
+
const isSpace = /^\s+$/.test(word);
|
|
97
|
+
const wWidth = visibleWidth(word);
|
|
98
|
+
if (isSpace) {
|
|
99
|
+
// A run of spaces mid-line is kept (markdown text rarely has one, but
|
|
100
|
+
// dropping it would be presumptuous); one that would start a wrapped
|
|
101
|
+
// line is dropped — the exact leading-space bug this file exists to avoid.
|
|
102
|
+
if (cur === "")
|
|
103
|
+
continue;
|
|
104
|
+
if (curWidth + wWidth > room()) {
|
|
105
|
+
push(cur);
|
|
106
|
+
cur = "";
|
|
107
|
+
curWidth = 0;
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
cur += word;
|
|
111
|
+
curWidth += wWidth;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (wWidth > room()) {
|
|
115
|
+
// Wider than a whole line by itself: flush what's pending, then hard-break
|
|
116
|
+
// the plain text (see the function comment for why styling is dropped here).
|
|
117
|
+
if (cur !== "") {
|
|
118
|
+
push(cur);
|
|
119
|
+
cur = "";
|
|
120
|
+
curWidth = 0;
|
|
121
|
+
}
|
|
122
|
+
const plain = word.replace(ANSI_RE, "");
|
|
123
|
+
let i = 0;
|
|
124
|
+
while (i < plain.length) {
|
|
125
|
+
const take = room();
|
|
126
|
+
push(plain.slice(i, i + take));
|
|
127
|
+
i += take;
|
|
128
|
+
}
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (curWidth + wWidth > room()) {
|
|
132
|
+
push(cur);
|
|
133
|
+
cur = word;
|
|
134
|
+
curWidth = wWidth;
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
cur += word;
|
|
138
|
+
curWidth += wWidth;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (cur !== "")
|
|
142
|
+
push(cur);
|
|
143
|
+
return lines.length > 0 ? lines : [""];
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=wrap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrap.js","sourceRoot":"","sources":["../../src/cli/wrap.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* cachePoints.ts — where to put Anthropic's cache breakpoints, and why more than one.
|
|
3
|
+
*
|
|
4
|
+
* A breakpoint does not scan the whole conversation for a prior cache entry. It walks
|
|
5
|
+
* backward at most **20 content blocks**, and if it finds nothing in that window it
|
|
6
|
+
* misses — silently, with no error and no signal in the response beyond a
|
|
7
|
+
* `cache_read_input_tokens` of zero that looks exactly like a cold start.
|
|
8
|
+
*
|
|
9
|
+
* That limit is a poor fit for an agentic loop specifically. A round with three
|
|
10
|
+
* parallel tool calls adds three `tool_use` blocks and three `tool_result` blocks; two
|
|
11
|
+
* such rounds and the next request's single breakpoint is already looking past its own
|
|
12
|
+
* window at the entry it needs. The conversation keeps growing, every request keeps
|
|
13
|
+
* paying full price for all of it, and nothing anywhere says so.
|
|
14
|
+
*
|
|
15
|
+
* So a single breakpoint at the stable prefix is not enough. This spreads the available
|
|
16
|
+
* budget backward through the conversation as a LADDER, close enough together that the
|
|
17
|
+
* next request always lands within a window of one of them.
|
|
18
|
+
*
|
|
19
|
+
* Pure and unit-tested, because the failure it prevents is invisible at runtime: there
|
|
20
|
+
* is no observation a live session can make that distinguishes "cache missed because of
|
|
21
|
+
* the lookback window" from "cache missed because this is a new conversation".
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Content blocks between consecutive breakpoints.
|
|
25
|
+
*
|
|
26
|
+
* 15 rather than 20: the limit is a hard 20, and the next request appends its own
|
|
27
|
+
* blocks before its breakpoint goes looking. Sitting exactly at the limit means any
|
|
28
|
+
* growth at all overshoots it, so the margin is the point.
|
|
29
|
+
*/
|
|
30
|
+
export const BLOCK_SPACING = 15;
|
|
31
|
+
/**
|
|
32
|
+
* Anthropic allows 4 `cache_control` breakpoints per request. One is spent on the
|
|
33
|
+
* system prompt (which also covers the tool definitions ahead of it), leaving three
|
|
34
|
+
* for the conversation.
|
|
35
|
+
*/
|
|
36
|
+
export const MAX_BREAKPOINTS = 4;
|
|
37
|
+
export const MESSAGE_BREAKPOINTS = MAX_BREAKPOINTS - 1;
|
|
38
|
+
/**
|
|
39
|
+
* Which message indexes should carry a breakpoint, given each message's block count.
|
|
40
|
+
*
|
|
41
|
+
* Returns indexes in ASCENDING order. The last message is always included: it is the
|
|
42
|
+
* stable-prefix boundary the whole request shape is built around, and the one entry the
|
|
43
|
+
* next request most wants to find.
|
|
44
|
+
*
|
|
45
|
+
* Walking BACKWARD from the end is deliberate. The recent end of the conversation is
|
|
46
|
+
* where the next request will look, so when the budget runs out it should run out at
|
|
47
|
+
* the far end — an unreachable breakpoint deep in history buys nothing.
|
|
48
|
+
*/
|
|
49
|
+
export function cacheBreakpoints(blockCounts, budget = MESSAGE_BREAKPOINTS) {
|
|
50
|
+
if (blockCounts.length === 0 || budget <= 0)
|
|
51
|
+
return [];
|
|
52
|
+
const picked = [blockCounts.length - 1];
|
|
53
|
+
let sinceLast = 0;
|
|
54
|
+
// From the message before the last one, backward. `sinceLast` counts the blocks
|
|
55
|
+
// BETWEEN the previous breakpoint and here, which is exactly the distance the next
|
|
56
|
+
// request's lookback has to cover.
|
|
57
|
+
for (let i = blockCounts.length - 2; i >= 0 && picked.length < budget; i--) {
|
|
58
|
+
sinceLast += Math.max(0, blockCounts[i] ?? 0);
|
|
59
|
+
if (sinceLast >= BLOCK_SPACING) {
|
|
60
|
+
picked.push(i);
|
|
61
|
+
sinceLast = 0;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return picked.reverse();
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Whether a conversation is long enough for the extra breakpoints to matter.
|
|
68
|
+
*
|
|
69
|
+
* Below the spacing there is only one place a breakpoint can usefully go, and spending
|
|
70
|
+
* the budget anyway would mark blocks a single window already reaches. Cheap to ask,
|
|
71
|
+
* and it keeps short sessions rendering exactly as they did before.
|
|
72
|
+
*/
|
|
73
|
+
export function needsLadder(blockCounts) {
|
|
74
|
+
const total = blockCounts.reduce((n, c) => n + Math.max(0, c), 0);
|
|
75
|
+
return total > BLOCK_SPACING;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=cachePoints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cachePoints.js","sourceRoot":"","sources":["../../../src/drivers/anthropic/cachePoints.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,EAAE,CAAC;AAEhC;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC;AACjC,MAAM,CAAC,MAAM,mBAAmB,GAAG,eAAe,GAAG,CAAC,CAAC;AAEvD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAAC,WAA8B,EAAE,MAAM,GAAG,mBAAmB;IAC3F,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IAEvD,MAAM,MAAM,GAAa,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAClD,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,gFAAgF;IAChF,mFAAmF;IACnF,mCAAmC;IACnC,KAAK,IAAI,CAAC,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3E,SAAS,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAC9C,IAAI,SAAS,IAAI,aAAa,EAAE,CAAC;YAC/B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACf,SAAS,GAAG,CAAC,CAAC;QAChB,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC,OAAO,EAAE,CAAC;AAC1B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,WAA8B;IACxD,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAClE,OAAO,KAAK,GAAG,aAAa,CAAC;AAC/B,CAAC"}
|