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,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* scope.ts — which glob-scoped rules this session has activated.
|
|
3
|
+
*
|
|
4
|
+
* A rule may carry `globs`, meaning "apply this once the work heads that way". The
|
|
5
|
+
* question is when that gets decided.
|
|
6
|
+
*
|
|
7
|
+
* It used to be decided AT RENDER: every model call rebuilt the set of every path the
|
|
8
|
+
* session had ever touched, relativized each one, and matched every scoped rule's globs
|
|
9
|
+
* against all of them. That is O(paths x rules) on every step of every turn, against a
|
|
10
|
+
* path set that only ever grew — so the cost of a rule the user set once climbed for as
|
|
11
|
+
* long as the session lasted.
|
|
12
|
+
*
|
|
13
|
+
* It is now decided AT ACCESS, which is the only shape that stays correct
|
|
14
|
+
* (`getManagedAndUserConditionalRules(targetPath, processedPaths)` resolves conditional
|
|
15
|
+
* rules for the ONE file being touched, with a processed-set for dedup). When a path is
|
|
16
|
+
* read or written we test it once, against only the rules that have not already fired,
|
|
17
|
+
* and remember the NAMES that matched. Rendering is then a set lookup per rule.
|
|
18
|
+
*
|
|
19
|
+
* Remembering the match rather than the path is what makes this durable. A compaction
|
|
20
|
+
* clears the read ledger because the contents it described are gone from the screen —
|
|
21
|
+
* but "this session has worked in src/api" is not a fact about the screen, and a name
|
|
22
|
+
* already in `matched` is never removed. The earlier fix for that bug carried a second
|
|
23
|
+
* copy of every path forward to re-derive the same answer; this needs no carry at all.
|
|
24
|
+
*/
|
|
25
|
+
import { relative } from "node:path";
|
|
26
|
+
import { anyPathMatches } from "./glob.js";
|
|
27
|
+
/**
|
|
28
|
+
* How many project-relative paths are kept for RE-EVALUATION.
|
|
29
|
+
*
|
|
30
|
+
* Only used when the rule set itself changes (the user edits a rule file, or the model
|
|
31
|
+
* writes a new one) and rules that never ran must be judged against work already done.
|
|
32
|
+
* Matching for rules that have already fired does not consult this at all — those names
|
|
33
|
+
* are sticky — so overflowing the cap can only mean a NEWLY ADDED scoped rule misses
|
|
34
|
+
* paths touched long ago. It still fires on the next matching path.
|
|
35
|
+
*
|
|
36
|
+
* Bounded because this is the one structure here that would otherwise grow with session
|
|
37
|
+
* length, which is exactly the property being removed.
|
|
38
|
+
*/
|
|
39
|
+
const MAX_REMEMBERED_PATHS = 2_000;
|
|
40
|
+
export function createRuleScope() {
|
|
41
|
+
return { matched: new Set(), paths: new Set() };
|
|
42
|
+
}
|
|
43
|
+
/** Project-relative POSIX form, computed ONCE per path instead of once per render. */
|
|
44
|
+
function relPosix(root, absPath) {
|
|
45
|
+
return relative(root, absPath).split("\\").join("/");
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Record that the session touched `absPath`, and fire any scoped rule it matches.
|
|
49
|
+
*
|
|
50
|
+
* Cheap by construction: a rule already in `matched` is skipped, so the work per path
|
|
51
|
+
* shrinks as rules fire, and a project with no scoped rules does no matching at all.
|
|
52
|
+
*/
|
|
53
|
+
export function noteScopePath(scope, rules, root, absPath) {
|
|
54
|
+
const rel = relPosix(root, absPath);
|
|
55
|
+
if (scope.paths.size < MAX_REMEMBERED_PATHS)
|
|
56
|
+
scope.paths.add(rel);
|
|
57
|
+
const one = [rel];
|
|
58
|
+
for (const rule of rules) {
|
|
59
|
+
if (!rule.globs || rule.globs.length === 0)
|
|
60
|
+
continue; // always-on: nothing to decide
|
|
61
|
+
if (scope.matched.has(rule.name))
|
|
62
|
+
continue; // already fired — never re-tested
|
|
63
|
+
if (anyPathMatches(one, rule.globs))
|
|
64
|
+
scope.matched.add(rule.name);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Re-judge every remembered path against the CURRENT rule set.
|
|
69
|
+
*
|
|
70
|
+
* Called when the rules themselves change — a reload from disk, or the model writing a
|
|
71
|
+
* new one — because a rule that did not exist when a path was touched never got its
|
|
72
|
+
* chance. This is the only O(paths x rules) pass left, and it runs on rule changes
|
|
73
|
+
* rather than on every model call.
|
|
74
|
+
*
|
|
75
|
+
* Additive: it never un-matches. A rule deleted from disk simply stops being rendered,
|
|
76
|
+
* because rendering filters by the live rule list, not by this set.
|
|
77
|
+
*/
|
|
78
|
+
export function rescope(scope, rules) {
|
|
79
|
+
const paths = [...scope.paths];
|
|
80
|
+
if (paths.length === 0)
|
|
81
|
+
return;
|
|
82
|
+
for (const rule of rules) {
|
|
83
|
+
if (!rule.globs || rule.globs.length === 0)
|
|
84
|
+
continue;
|
|
85
|
+
if (scope.matched.has(rule.name))
|
|
86
|
+
continue;
|
|
87
|
+
if (anyPathMatches(paths, rule.globs))
|
|
88
|
+
scope.matched.add(rule.name);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=scope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope.js","sourceRoot":"","sources":["../../src/governor/scope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAG3C;;;;;;;;;;;GAWG;AACH,MAAM,oBAAoB,GAAG,KAAK,CAAC;AAYnC,MAAM,UAAU,eAAe;IAC7B,OAAO,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC;AAClD,CAAC;AAED,sFAAsF;AACtF,SAAS,QAAQ,CAAC,IAAY,EAAE,OAAe;IAC7C,OAAO,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACvD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAC3B,KAAgB,EAChB,KAAsB,EACtB,IAAY,EACZ,OAAe;IAEf,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACpC,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,GAAG,oBAAoB;QAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAClE,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;IAClB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS,CAAC,+BAA+B;QACrF,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,SAAS,CAAC,kCAAkC;QAC9E,IAAI,cAAc,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC;YAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpE,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,OAAO,CAAC,KAAgB,EAAE,KAAsB;IAC9D,MAAM,KAAK,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;IAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QACrD,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,SAAS;QAC3C,IAAI,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC;YAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtE,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* skills.ts — reusable procedures the model can run on demand.
|
|
3
|
+
*
|
|
4
|
+
* A skill is a named playbook: `<project-state>/skills/<name>/SKILL.md`, with a
|
|
5
|
+
* `name` / `description` / `when_to_use` header and a markdown body of steps.
|
|
6
|
+
* The key design is **progressive disclosure**: only
|
|
7
|
+
* the lightweight catalog (name + description + when-to-use) ever sits in the
|
|
8
|
+
* prompt, so a project can have many skills at near-zero token cost; the full
|
|
9
|
+
* body is read only when the skill is actually invoked — by the user typing
|
|
10
|
+
* `/name`, or by the model calling the `use_skill` tool when a description fits.
|
|
11
|
+
*/
|
|
12
|
+
import { promises as fs } from "node:fs";
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
import { parseFrontmatter } from "./frontmatter.js";
|
|
15
|
+
import { parseGlobs } from "./rules.js";
|
|
16
|
+
import { anyPathMatches } from "./glob.js";
|
|
17
|
+
const SKILL_FILE = "SKILL.md";
|
|
18
|
+
/** Discover the project's skills, reading only each one's frontmatter (catalog). */
|
|
19
|
+
export async function loadSkillCatalog(stateDir) {
|
|
20
|
+
const dir = join(stateDir, "skills");
|
|
21
|
+
let entries;
|
|
22
|
+
try {
|
|
23
|
+
entries = await fs.readdir(dir, { withFileTypes: true });
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return []; // no skills dir yet
|
|
27
|
+
}
|
|
28
|
+
const skills = [];
|
|
29
|
+
for (const entry of entries) {
|
|
30
|
+
if (!entry.isDirectory())
|
|
31
|
+
continue; // skills are directories: <name>/SKILL.md
|
|
32
|
+
const skillDir = join(dir, entry.name);
|
|
33
|
+
try {
|
|
34
|
+
const raw = await fs.readFile(join(skillDir, SKILL_FILE), "utf8");
|
|
35
|
+
const { data } = parseFrontmatter(raw);
|
|
36
|
+
const globs = parseGlobs(data.globs || data.paths);
|
|
37
|
+
skills.push({
|
|
38
|
+
name: data.name || entry.name,
|
|
39
|
+
description: data.description || "",
|
|
40
|
+
whenToUse: data.when_to_use || data.whenToUse || "",
|
|
41
|
+
dir: skillDir,
|
|
42
|
+
...(data["argument-hint"] ? { argumentHint: data["argument-hint"] } : {}),
|
|
43
|
+
...(globs.length > 0 ? { globs } : {}),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// No SKILL.md (or unreadable) — not a skill directory; skip it.
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
skills.sort((a, b) => a.name.localeCompare(b.name));
|
|
51
|
+
return skills;
|
|
52
|
+
}
|
|
53
|
+
/** Load a skill's full body (the steps), read fresh on invocation. Null if gone. */
|
|
54
|
+
export async function loadSkillBody(skill) {
|
|
55
|
+
try {
|
|
56
|
+
const raw = await fs.readFile(join(skill.dir, SKILL_FILE), "utf8");
|
|
57
|
+
return parseFrontmatter(raw).body;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/** Find a skill by its invocation name (case-insensitive). */
|
|
64
|
+
export function findSkill(skills, name) {
|
|
65
|
+
const wanted = name.trim().toLowerCase().replace(/^\//, "");
|
|
66
|
+
return skills.find((s) => s.name.toLowerCase() === wanted);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The skills visible in the catalog this turn: every always-listed skill plus any
|
|
70
|
+
* glob-scoped skill whose patterns match the working set. (Scoped-out skills are
|
|
71
|
+
* still invokable by name — this only controls catalog noise.)
|
|
72
|
+
*/
|
|
73
|
+
export function activeSkills(skills, workingSet = []) {
|
|
74
|
+
return skills.filter((s) => !s.globs || s.globs.length === 0 || anyPathMatches(workingSet, s.globs));
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Render the catalog for the system prompt: one line per visible skill with its
|
|
78
|
+
* name (+ argument hint), description, and when-to-use. "" when none are visible.
|
|
79
|
+
* Content only — the engine frames it.
|
|
80
|
+
*/
|
|
81
|
+
/**
|
|
82
|
+
* Caps on the always-loaded skill catalog.
|
|
83
|
+
*
|
|
84
|
+
* This block renders into the CACHED system prefix on every session and only ever
|
|
85
|
+
* grows: every create_skill adds a line, permanently, and nothing trims it.
|
|
86
|
+
*
|
|
87
|
+
* The cap is on LENGTH PER ENTRY rather than on the number of entries, and that is a
|
|
88
|
+
* deliberate departure from "keep the most recent N". A skill is only reachable by
|
|
89
|
+
* NAME — use_skill takes one, and there is no tool that lists them — so an entry
|
|
90
|
+
* dropped from this catalog is a skill the model can no longer invoke at all. Trading
|
|
91
|
+
* a capability away to save tokens is the wrong trade. Clipping a rambling description
|
|
92
|
+
* costs nothing by comparison: the name still appears, the skill stays callable, and
|
|
93
|
+
* its full text is loaded on use anyway.
|
|
94
|
+
*
|
|
95
|
+
* The entry cap below is a backstop against the absurd case, set far above any real
|
|
96
|
+
* project, and it says so when it bites.
|
|
97
|
+
*/
|
|
98
|
+
const MAX_SKILL_LINE_CHARS = 200;
|
|
99
|
+
const MAX_SKILL_ENTRIES = 100;
|
|
100
|
+
/** Clip to `max` on a word boundary where possible, with an ellipsis. */
|
|
101
|
+
function clip(text, max) {
|
|
102
|
+
if (text.length <= max)
|
|
103
|
+
return text;
|
|
104
|
+
const cut = text.slice(0, max);
|
|
105
|
+
const space = cut.lastIndexOf(" ");
|
|
106
|
+
return `${(space > max * 0.6 ? cut.slice(0, space) : cut).trimEnd()}…`;
|
|
107
|
+
}
|
|
108
|
+
export function renderSkillCatalog(skills, workingSet) {
|
|
109
|
+
// OMITTING the working set means "list everything", not "list nothing". It used to
|
|
110
|
+
// default to `[]`, which quietly filtered every glob-scoped skill out — so a caller
|
|
111
|
+
// that had no working set to give showed an incomplete catalog, and a skill reachable
|
|
112
|
+
// only by name became uninvokable.
|
|
113
|
+
//
|
|
114
|
+
// The engine relies on this: the catalog renders into the CACHED system prompt, so it
|
|
115
|
+
// must be byte-identical all session. Filtering it by the working set made a
|
|
116
|
+
// glob-scoped skill appear the moment a matching file was read, changing the system
|
|
117
|
+
// prompt and invalidating the tools, system and message caches at once.
|
|
118
|
+
const visible = workingSet === undefined ? skills : activeSkills(skills, workingSet);
|
|
119
|
+
if (visible.length === 0)
|
|
120
|
+
return "";
|
|
121
|
+
const shown = visible.slice(0, MAX_SKILL_ENTRIES);
|
|
122
|
+
const lines = shown.map((s) => {
|
|
123
|
+
const hint = s.argumentHint ? ` ${s.argumentHint}` : "";
|
|
124
|
+
const desc = s.description ? `: ${s.description}` : "";
|
|
125
|
+
const when = s.whenToUse ? ` — use when: ${s.whenToUse}` : "";
|
|
126
|
+
// The name and its argument hint are never clipped — they are what makes the
|
|
127
|
+
// skill callable. Only the prose after them is.
|
|
128
|
+
return `- ${s.name}${hint}${clip(`${desc}${when}`, MAX_SKILL_LINE_CHARS)}`;
|
|
129
|
+
});
|
|
130
|
+
if (visible.length > shown.length) {
|
|
131
|
+
lines.push(`> WARNING: ${visible.length - shown.length} more skill(s) exist but are not listed here. ` +
|
|
132
|
+
`Keep the catalog under ${MAX_SKILL_ENTRIES} skills, or scope them with \`globs\` so they appear only when relevant.`);
|
|
133
|
+
}
|
|
134
|
+
return lines.join("\n");
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Substitute a skill's argument string into its body: `$ARGUMENTS` → the whole
|
|
138
|
+
* string, `$1`/`$2`/… → positional tokens. If the body has no such placeholder
|
|
139
|
+
* but arguments were given, they're appended as additional context — so both
|
|
140
|
+
* parameterized and plain skills handle args sensibly.
|
|
141
|
+
*/
|
|
142
|
+
export function substituteSkillArgs(body, argString) {
|
|
143
|
+
const args = argString.trim();
|
|
144
|
+
const positional = args.length > 0 ? args.split(/\s+/) : [];
|
|
145
|
+
const hasPlaceholder = /\$ARGUMENTS\b/.test(body) || POSITIONAL.test(body);
|
|
146
|
+
// ONE pass over the original body. Two chained replaces meant a `$1` inside the
|
|
147
|
+
// user's own argument string was then treated as a placeholder and substituted again.
|
|
148
|
+
const out = body.replace(SUBSTITUTION, (match, digit) => {
|
|
149
|
+
if (digit === undefined)
|
|
150
|
+
return args;
|
|
151
|
+
// Leave the placeholder visible when nothing was supplied for it. Blanking it makes
|
|
152
|
+
// a skill that expected an argument read as though it never wanted one.
|
|
153
|
+
return positional[Number(digit) - 1] ?? match;
|
|
154
|
+
});
|
|
155
|
+
if (!hasPlaceholder && args)
|
|
156
|
+
return `${out}\n\nAdditional context from the user: ${args}`;
|
|
157
|
+
return out;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* A positional placeholder: `$1`–`$9`, and NOT the start of a longer number.
|
|
161
|
+
*
|
|
162
|
+
* A skill body is a markdown playbook, so it very reasonably contains shell
|
|
163
|
+
* (`awk '{print $1}'`) and money (`$100`). The old pattern was `/\$(\d+)/`, which
|
|
164
|
+
* matched `$100` as positional argument one hundred, found nothing, and substituted
|
|
165
|
+
* the empty string — so `Budget is $100` silently became `Budget is `, and with no
|
|
166
|
+
* arguments at all EVERY `$n` in the body was deleted. The instructions the model was
|
|
167
|
+
* told to follow were quietly not the instructions on disk. Single digit matches the
|
|
168
|
+
* shell convention the syntax is borrowed from.
|
|
169
|
+
*/
|
|
170
|
+
const POSITIONAL_SRC = String.raw `\$([1-9])(?!\d)`;
|
|
171
|
+
/** Detects one, for deciding whether the skill declared any placeholder at all. */
|
|
172
|
+
const POSITIONAL = new RegExp(POSITIONAL_SRC);
|
|
173
|
+
/** Replaces every placeholder in one pass. Shares POSITIONAL's source so the two
|
|
174
|
+
* cannot drift into disagreeing about what counts as a placeholder. */
|
|
175
|
+
const SUBSTITUTION = new RegExp(String.raw `\$ARGUMENTS\b|` + POSITIONAL_SRC, "g");
|
|
176
|
+
//# sourceMappingURL=skills.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/governor/skills.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAG3C,MAAM,UAAU,GAAG,UAAU,CAAC;AAE9B,oFAAoF;AACpF,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,QAAgB;IACrD,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACrC,IAAI,OAAO,CAAC;IACZ,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC,CAAC,oBAAoB;IACjC,CAAC;IAED,MAAM,MAAM,GAAgB,EAAE,CAAC;IAC/B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE;YAAE,SAAS,CAAC,0CAA0C;QAC9E,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,CAAC;YAClE,MAAM,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;YACvC,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC;YACnD,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI;gBAC7B,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,EAAE;gBACnC,SAAS,EAAE,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,SAAS,IAAI,EAAE;gBACnD,GAAG,EAAE,QAAQ;gBACb,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACzE,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACvC,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YACP,gEAAgE;QAClE,CAAC;IACH,CAAC;IACD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACpD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,oFAAoF;AACpF,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAgB;IAClD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,CAAC;QACnE,OAAO,gBAAgB,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,SAAS,CAAC,MAAmB,EAAE,IAAY;IACzD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC5D,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,CAAC;AAC7D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,MAAmB,EAAE,aAAuB,EAAE;IACzE,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,cAAc,CAAC,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AACvG,CAAC;AAED;;;;GAIG;AACH;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,oBAAoB,GAAG,GAAG,CAAC;AACjC,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAE9B,yEAAyE;AACzE,SAAS,IAAI,CAAC,IAAY,EAAE,GAAW;IACrC,IAAI,IAAI,CAAC,MAAM,IAAI,GAAG;QAAE,OAAO,IAAI,CAAC;IACpC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC/B,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACnC,OAAO,GAAG,CAAC,KAAK,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC;AACzE,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAmB,EAAE,UAAqB;IAC3E,mFAAmF;IACnF,oFAAoF;IACpF,sFAAsF;IACtF,mCAAmC;IACnC,EAAE;IACF,sFAAsF;IACtF,6EAA6E;IAC7E,oFAAoF;IACpF,wEAAwE;IACxE,MAAM,OAAO,GAAG,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACrF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACpC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAC;IAClD,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QAC5B,MAAM,IAAI,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxD,MAAM,IAAI,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,MAAM,IAAI,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC9D,6EAA6E;QAC7E,gDAAgD;QAChD,OAAO,KAAK,CAAC,CAAC,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI,EAAE,EAAE,oBAAoB,CAAC,EAAE,CAAC;IAC7E,CAAC,CAAC,CAAC;IACH,IAAI,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CACR,cAAc,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,gDAAgD;YACzF,0BAA0B,iBAAiB,0EAA0E,CACxH,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,IAAY,EAAE,SAAiB;IACjE,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC;IAC9B,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC5D,MAAM,cAAc,GAAG,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAE3E,gFAAgF;IAChF,sFAAsF;IACtF,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,CAAC,KAAK,EAAE,KAAc,EAAE,EAAE;QAC/D,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC;QACrC,oFAAoF;QACpF,wEAAwE;QACxE,OAAO,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,cAAc,IAAI,IAAI;QAAE,OAAO,GAAG,GAAG,yCAAyC,IAAI,EAAE,CAAC;IAC1F,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,cAAc,GAAG,MAAM,CAAC,GAAG,CAAA,iBAAiB,CAAC;AAEnD,mFAAmF;AACnF,MAAM,UAAU,GAAG,IAAI,MAAM,CAAC,cAAc,CAAC,CAAC;AAE9C;wEACwE;AACxE,MAAM,YAAY,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAA,gBAAgB,GAAG,cAAc,EAAE,GAAG,CAAC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* types.ts — the governor's data contracts.
|
|
3
|
+
*
|
|
4
|
+
* The "governor" is the per-project control layer: the user's standing **rules**
|
|
5
|
+
* (always followed), reusable **skills** (procedures loaded on demand), and the
|
|
6
|
+
* **forbidden** list (paths/actions the tools must never touch). All of it is
|
|
7
|
+
* scoped to one project and stored under that project's state directory — the
|
|
8
|
+
* same `~/.mindweave/projects/<project>/` folder sessions already use.
|
|
9
|
+
*
|
|
10
|
+
* Everything here is plain JSON-friendly data on purpose. The forbidden config
|
|
11
|
+
* in particular rides on `ToolContext` (which deliberately holds only plain
|
|
12
|
+
* data), and the path/command checks are pure functions over it — exactly like
|
|
13
|
+
* the existing `guard.ts` deny-list, just user-defined instead of built-in.
|
|
14
|
+
*/
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/governor/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* write.ts — persist a new rule or forbidden path for a project.
|
|
3
|
+
*
|
|
4
|
+
* The governor owns the on-disk formats, so the act of "make this a rule" or
|
|
5
|
+
* "forbid this" lives here; the tools in src/tools are thin wrappers that call
|
|
6
|
+
* these and then mirror the change into the live session so it takes effect
|
|
7
|
+
* immediately. Files land under the project's state dir (the same per-project
|
|
8
|
+
* folder sessions use), so they persist for every future launch in this project.
|
|
9
|
+
*/
|
|
10
|
+
import { promises as fs } from "node:fs";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { projectDir } from "../memory/store.js";
|
|
13
|
+
import { parseForbidden, parseForbiddenCommands } from "./forbidden.js";
|
|
14
|
+
/** A filesystem-safe slug from a human name/phrase (kebab, ≤50 chars). */
|
|
15
|
+
export function slugify(text) {
|
|
16
|
+
return (text
|
|
17
|
+
.toLowerCase()
|
|
18
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
19
|
+
.replace(/^-+|-+$/g, "")
|
|
20
|
+
.slice(0, 50) || "rule");
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Flatten a value to a single line before it goes into frontmatter.
|
|
24
|
+
*
|
|
25
|
+
* These headers are a line-oriented `key: value` format, and every value here is
|
|
26
|
+
* model-supplied text. A newline inside one starts what the loader reads as a NEW
|
|
27
|
+
* key, so a rule whose name ended in "\nglobs: **" would come back scoped to
|
|
28
|
+
* everything, and a skill's description could rewrite its own `when_to_use`. The
|
|
29
|
+
* value is written, then read back and believed, so it has to stay one field.
|
|
30
|
+
*/
|
|
31
|
+
function oneLine(value) {
|
|
32
|
+
return value.replace(/[\r\n]+/g, " ").trim();
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Build a frontmatter header, flattening EVERY value on the way in.
|
|
36
|
+
*
|
|
37
|
+
* `oneLine` used to be applied field by field at each call site, and one field was
|
|
38
|
+
* missed: `globs` went in raw as `globs: ${globs.join(", ")}`. That is the field
|
|
39
|
+
* deciding when a rule fires, and a newline inside it writes whatever the model
|
|
40
|
+
* likes into the header — a second key, or a `---` that closes it early and turns
|
|
41
|
+
* the rest of the rule into body.
|
|
42
|
+
*
|
|
43
|
+
* Written as one place that flattens everything, so the next field added cannot
|
|
44
|
+
* repeat the mistake. Empty values are dropped rather than emitted blank.
|
|
45
|
+
*/
|
|
46
|
+
function frontmatter(fields) {
|
|
47
|
+
const lines = ["---"];
|
|
48
|
+
for (const [key, raw] of Object.entries(fields)) {
|
|
49
|
+
const value = oneLine(raw ?? "");
|
|
50
|
+
if (value)
|
|
51
|
+
lines.push(`${key}: ${value}`);
|
|
52
|
+
}
|
|
53
|
+
lines.push("---", "");
|
|
54
|
+
return lines.join("\n");
|
|
55
|
+
}
|
|
56
|
+
/** A short name derived from a rule's text (first few words) when none is given. */
|
|
57
|
+
export function deriveRuleName(body) {
|
|
58
|
+
return slugify(body.split(/\s+/).slice(0, 6).join(" "));
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Save a standing rule as `rules/<slug>.md` in the project's state dir and return
|
|
62
|
+
* it. Overwrites a rule file of the same slug (re-stating a rule updates it). Pass
|
|
63
|
+
* `globs` to SCOPE the rule (fires only when the work touches matching files);
|
|
64
|
+
* omit them for an always-on rule (the default).
|
|
65
|
+
*/
|
|
66
|
+
export async function writeRule(cwd, name, body, description = "", globs = []) {
|
|
67
|
+
const dir = join(projectDir(cwd), "rules");
|
|
68
|
+
await fs.mkdir(dir, { recursive: true });
|
|
69
|
+
const file = join(dir, `${slugify(name)}.md`);
|
|
70
|
+
const header = frontmatter({
|
|
71
|
+
name,
|
|
72
|
+
description,
|
|
73
|
+
globs: globs.join(", "),
|
|
74
|
+
});
|
|
75
|
+
await fs.writeFile(file, `${header}${body}\n`, "utf8");
|
|
76
|
+
return { name: oneLine(name), description: oneLine(description), body, ...(globs.length > 0 ? { globs } : {}) };
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Create (or overwrite) a skill at `skills/<slug>/SKILL.md` in the project's
|
|
80
|
+
* state dir and return its catalog metadata. The directory name is the skill's
|
|
81
|
+
* invocation name; the frontmatter carries description / when-to-use / hint /
|
|
82
|
+
* scope so it loads back identically.
|
|
83
|
+
*/
|
|
84
|
+
export async function writeSkill(cwd, skill) {
|
|
85
|
+
const name = slugify(skill.name);
|
|
86
|
+
const dir = join(projectDir(cwd), "skills", name);
|
|
87
|
+
await fs.mkdir(dir, { recursive: true });
|
|
88
|
+
const description = oneLine(skill.description);
|
|
89
|
+
const whenToUse = oneLine(skill.whenToUse ?? "");
|
|
90
|
+
const argumentHint = oneLine(skill.argumentHint ?? "");
|
|
91
|
+
const header = frontmatter({
|
|
92
|
+
name, // already the slug: no newline can survive slugify
|
|
93
|
+
description,
|
|
94
|
+
when_to_use: whenToUse,
|
|
95
|
+
"argument-hint": argumentHint,
|
|
96
|
+
globs: skill.globs?.join(", ") ?? "",
|
|
97
|
+
});
|
|
98
|
+
await fs.writeFile(join(dir, "SKILL.md"), `${header}${skill.body}\n`, "utf8");
|
|
99
|
+
return {
|
|
100
|
+
name,
|
|
101
|
+
description,
|
|
102
|
+
whenToUse,
|
|
103
|
+
dir,
|
|
104
|
+
...(argumentHint ? { argumentHint } : {}),
|
|
105
|
+
...(skill.globs && skill.globs.length > 0 ? { globs: skill.globs } : {}),
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Append a pattern to `forbidden.md` in the project's state dir. Idempotent —
|
|
110
|
+
* returns `{ added: false }` if it was already forbidden. The pattern is
|
|
111
|
+
* normalized the same way the loader normalizes (drop leading `./`, trailing `/`).
|
|
112
|
+
*/
|
|
113
|
+
export async function appendForbidden(cwd, pattern) {
|
|
114
|
+
const normalized = pattern.trim().replace(/^\.?\//, "").replace(/\/+$/, "");
|
|
115
|
+
if (!normalized)
|
|
116
|
+
return { added: false, pattern: normalized };
|
|
117
|
+
const base = projectDir(cwd);
|
|
118
|
+
const file = join(base, "forbidden.md");
|
|
119
|
+
let text = "";
|
|
120
|
+
try {
|
|
121
|
+
text = await fs.readFile(file, "utf8");
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
/* no forbidden.md yet */
|
|
125
|
+
}
|
|
126
|
+
if (parseForbidden(text).includes(normalized))
|
|
127
|
+
return { added: false, pattern: normalized };
|
|
128
|
+
await fs.mkdir(base, { recursive: true });
|
|
129
|
+
const separator = text && !text.endsWith("\n") ? "\n" : "";
|
|
130
|
+
await fs.writeFile(file, `${text}${separator}${normalized}\n`, "utf8");
|
|
131
|
+
return { added: true, pattern: normalized };
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Append an MCP tool name to `forbidden-mcp-tools.md`. Sibling of
|
|
135
|
+
* appendForbiddenCommand; tool names are identifiers, kept verbatim.
|
|
136
|
+
*/
|
|
137
|
+
export async function appendForbiddenMcpTool(cwd, name) {
|
|
138
|
+
const normalized = name.trim();
|
|
139
|
+
if (!normalized)
|
|
140
|
+
return { added: false, pattern: normalized };
|
|
141
|
+
const base = projectDir(cwd);
|
|
142
|
+
const file = join(base, "forbidden-mcp-tools.md");
|
|
143
|
+
let text = "";
|
|
144
|
+
try {
|
|
145
|
+
text = await fs.readFile(file, "utf8");
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
/* no forbidden-mcp-tools.md yet */
|
|
149
|
+
}
|
|
150
|
+
if (parseForbiddenCommands(text).includes(normalized))
|
|
151
|
+
return { added: false, pattern: normalized };
|
|
152
|
+
await fs.mkdir(base, { recursive: true });
|
|
153
|
+
const separator = text && !text.endsWith("\n") ? "\n" : "";
|
|
154
|
+
await fs.writeFile(file, `${text}${separator}${normalized}\n`, "utf8");
|
|
155
|
+
return { added: true, pattern: normalized };
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Append a command pattern to `forbidden-commands.md` in the project's state dir.
|
|
159
|
+
* Idempotent — `{ added: false }` if it was already forbidden. Sibling of
|
|
160
|
+
* appendForbidden; command patterns are kept verbatim (trimmed), not path-normalized.
|
|
161
|
+
*/
|
|
162
|
+
export async function appendForbiddenCommand(cwd, pattern) {
|
|
163
|
+
const normalized = pattern.trim();
|
|
164
|
+
if (!normalized)
|
|
165
|
+
return { added: false, pattern: normalized };
|
|
166
|
+
const base = projectDir(cwd);
|
|
167
|
+
const file = join(base, "forbidden-commands.md");
|
|
168
|
+
let text = "";
|
|
169
|
+
try {
|
|
170
|
+
text = await fs.readFile(file, "utf8");
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
/* no forbidden-commands.md yet */
|
|
174
|
+
}
|
|
175
|
+
if (parseForbiddenCommands(text).includes(normalized))
|
|
176
|
+
return { added: false, pattern: normalized };
|
|
177
|
+
await fs.mkdir(base, { recursive: true });
|
|
178
|
+
const separator = text && !text.endsWith("\n") ? "\n" : "";
|
|
179
|
+
await fs.writeFile(file, `${text}${separator}${normalized}\n`, "utf8");
|
|
180
|
+
return { added: true, pattern: normalized };
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=write.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/governor/write.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Mindweave — entry point.
|
|
4
|
+
*
|
|
5
|
+
* This file does one thing: start the terminal UI. It deliberately stays tiny.
|
|
6
|
+
* All real logic lives in its own lane (cli / dynamo / tools / memory / alternator)
|
|
7
|
+
* so the project stays easy to understand as it grows.
|
|
8
|
+
*
|
|
9
|
+
* The shebang above + the `bin` entry in package.json make this the `mindweave`
|
|
10
|
+
* command: install once (`npm link` / `npm i -g`), then `cd` into any project and
|
|
11
|
+
* type `mindweave`. The session roots at the current directory (process.cwd()), so it
|
|
12
|
+
* just works wherever you run it.
|
|
13
|
+
*/
|
|
14
|
+
import { render } from "ink";
|
|
15
|
+
import { createElement } from "react";
|
|
16
|
+
import { App } from "./cli/App.js";
|
|
17
|
+
import { loadConfig } from "./cli/bootstrap.js";
|
|
18
|
+
import { sweepTempInBackground } from "./tools/tempSweep.js";
|
|
19
|
+
import { parseStartupArgs, hasInteractiveInput, NO_TERMINAL_MESSAGE } from "./cli/startupArgs.js";
|
|
20
|
+
import { enterAltScreen } from "./cli/altScreen.js";
|
|
21
|
+
import { TERMINAL_RESTORE } from "./cli/terminalRestore.js";
|
|
22
|
+
import { instrumentStdout, flush as flushPerf, perf, perfEnabled } from "./cli/perfLog.js";
|
|
23
|
+
import { MAX_FPS } from "./cli/frameRate.js";
|
|
24
|
+
import { framebufferStdout } from "./cli/framebuffer/writer.js";
|
|
25
|
+
// --help / --version answer and exit, BEFORE anything reads config, sweeps a
|
|
26
|
+
// directory, or starts the UI. They used to fall through to the interactive app,
|
|
27
|
+
// which then hung forever with no TTY to render into — the one thing a packaging
|
|
28
|
+
// tool or a script does with a new CLI.
|
|
29
|
+
const startup = parseStartupArgs(process.argv.slice(2));
|
|
30
|
+
if (startup.kind === "print") {
|
|
31
|
+
process.stdout.write(startup.text + "\n");
|
|
32
|
+
process.exit(0);
|
|
33
|
+
}
|
|
34
|
+
// Nothing below this point can run without a terminal to read from, and the failure
|
|
35
|
+
// without one is a stack trace through React internals on a process that exits 0.
|
|
36
|
+
// --help, --version and --reset-terminal are answered above, so they still work
|
|
37
|
+
// wherever they are called from.
|
|
38
|
+
if (!hasInteractiveInput(process.stdin)) {
|
|
39
|
+
process.stderr.write(NO_TERMINAL_MESSAGE);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
if (startup.kind === "reset") {
|
|
43
|
+
// Repairing a terminal a dead run left in mouse-reporting mode. Nothing else may run
|
|
44
|
+
// first: this is typed when the terminal is already misbehaving, and loading config or
|
|
45
|
+
// sweeping temp would only add ways for it to fail before it writes the one thing it
|
|
46
|
+
// came to write. Escapes go out only to a real terminal, since into a pipe they would
|
|
47
|
+
// be corruption rather than repair.
|
|
48
|
+
if (process.stdout.isTTY) {
|
|
49
|
+
process.stdout.write(TERMINAL_RESTORE);
|
|
50
|
+
process.stdout.write("terminal restored\n");
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
process.stdout.write("not a terminal, nothing to restore\n");
|
|
54
|
+
}
|
|
55
|
+
process.exit(0);
|
|
56
|
+
}
|
|
57
|
+
// Load config (global ~/.mindweave/.env + project .env) so provider API keys are
|
|
58
|
+
// available no matter which project we're launched in.
|
|
59
|
+
loadConfig();
|
|
60
|
+
// Clear out the temp files and directories earlier runs left behind: screenshots past
|
|
61
|
+
// their retention window, and the scratch (cwd hand-off files, command wrappers, test
|
|
62
|
+
// fixtures) that every call site removes on its way out and nothing removes when a run
|
|
63
|
+
// ends badly. Startup rather than shutdown precisely because that catches what a crash
|
|
64
|
+
// left behind, and detached so a slow or unreadable temp directory cannot delay the UI.
|
|
65
|
+
sweepTempInBackground();
|
|
66
|
+
// Times every frame the renderer writes to the real terminal. No-op unless
|
|
67
|
+
// MINDWEAVE_PERF names a file — see cli/perfLog.ts for why this cannot be measured
|
|
68
|
+
// from a test probe.
|
|
69
|
+
instrumentStdout(process.stdout);
|
|
70
|
+
process.on("exit", flushPerf);
|
|
71
|
+
enterAltScreen();
|
|
72
|
+
// Ink renders into a FRAMEBUFFER rather than straight to the terminal: each frame is
|
|
73
|
+
// parsed into a cell grid, diffed against what is already on screen, and only the
|
|
74
|
+
// cells that actually differ are written. Measured on a transcript-shaped screen,
|
|
75
|
+
// that is ~13x fewer bytes per frame (2,345 -> 178). See `cli/framebuffer/`.
|
|
76
|
+
//
|
|
77
|
+
// `incrementalRendering` is deliberately NOT enabled alongside it, and this is load
|
|
78
|
+
// bearing rather than a preference: that mode makes Ink emit only the LINES it thinks
|
|
79
|
+
// changed, interleaved with its own cursor movements, instead of a complete frame.
|
|
80
|
+
// The framebuffer's parser expects a whole frame — a partial one would be read as a
|
|
81
|
+
// full screen and everything it omitted would be blanked. One diff or the other, and
|
|
82
|
+
// ours is per-cell where Ink's is per-line.
|
|
83
|
+
// The frame-rate cap is what sets typing latency — see `cli/frameRate.ts` for the
|
|
84
|
+
// measurements and for why it is a timer rather than a cost.
|
|
85
|
+
render(createElement(App), {
|
|
86
|
+
maxFps: MAX_FPS,
|
|
87
|
+
stdout: framebufferStdout(process.stdout, perfEnabled() ? (s) => perf(`frame in=${s.inBytes} out=${s.outBytes}`) : undefined),
|
|
88
|
+
});
|
|
89
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|