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,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* editTarget.ts — the shared pre-edit gauntlet for the edit tool.
|
|
3
|
+
*
|
|
4
|
+
* Both tools must clear the exact same gates before touching a file: path guards
|
|
5
|
+
* (protected + forbidden-with-lift), the file must exist and be a file, and it
|
|
6
|
+
* must have been READ this session (the anti-confabulation rule). Factoring it
|
|
7
|
+
* here keeps that policy in one place so the two tools can never drift apart on
|
|
8
|
+
* safety. Returns the file's content + detected EOL on success, or a ready-made
|
|
9
|
+
* failure ToolResult to hand straight back.
|
|
10
|
+
*/
|
|
11
|
+
import { promises as fs } from "node:fs";
|
|
12
|
+
import { foreignAgentReason, protectedPathReason } from "./guard.js";
|
|
13
|
+
import { forbiddenPathReason } from "../governor/forbidden.js";
|
|
14
|
+
import { requestAgentDataAccess, requestForbiddenLift, requestOutsideWorkspaceWrite } from "./approval.js";
|
|
15
|
+
import { resolvePath } from "./paths.js";
|
|
16
|
+
import { detectEol } from "./eol.js";
|
|
17
|
+
import { fail, failQuietly } from "./results.js";
|
|
18
|
+
// Re-exported because the edit tools reach for these alongside the gauntlet itself.
|
|
19
|
+
export { fail, failQuietly } from "./results.js";
|
|
20
|
+
/** Run the shared pre-edit checks for `rawPath`. `verb` names the action in
|
|
21
|
+
* messages (e.g. "editing"). */
|
|
22
|
+
export async function prepareEditTarget(ctx, rawPath, verb) {
|
|
23
|
+
const filePath = resolvePath(ctx, rawPath);
|
|
24
|
+
const blocked = protectedPathReason(filePath);
|
|
25
|
+
if (blocked)
|
|
26
|
+
return { ok: false, error: fail(`Refusing to edit ${rawPath}: it is ${blocked}.`) };
|
|
27
|
+
// Another tool's data. Writing to it is worse than reading it — we'd be editing
|
|
28
|
+
// a history we were never part of — so it goes through the same ask-first gate.
|
|
29
|
+
const otherTool = foreignAgentReason(filePath);
|
|
30
|
+
if (otherTool) {
|
|
31
|
+
const denied = await requestAgentDataAccess(ctx, otherTool, `${verb} ${rawPath}`);
|
|
32
|
+
if (denied)
|
|
33
|
+
return { ok: false, error: denied };
|
|
34
|
+
}
|
|
35
|
+
const forbidden = forbiddenPathReason(ctx.governance?.forbidden, filePath, ctx.roots ?? []);
|
|
36
|
+
if (forbidden) {
|
|
37
|
+
const lift = await requestForbiddenLift(ctx, forbidden, `${verb} ${rawPath}`, `the user has forbidden touching '${forbidden}'.`);
|
|
38
|
+
if (lift)
|
|
39
|
+
return { ok: false, error: lift }; // refused/deferred; an allow returns null → falls through
|
|
40
|
+
}
|
|
41
|
+
// The workspace boundary. Everything above is about WHICH file; this is about whether
|
|
42
|
+
// the agent should be writing there at all.
|
|
43
|
+
const outside = await requestOutsideWorkspaceWrite(ctx, filePath, `${verb} ${rawPath}`);
|
|
44
|
+
if (outside)
|
|
45
|
+
return { ok: false, error: outside };
|
|
46
|
+
let stat;
|
|
47
|
+
try {
|
|
48
|
+
stat = await fs.stat(filePath);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return { ok: false, error: fail(`file ${rawPath} not found. Use write_file to create a new file.`) };
|
|
52
|
+
}
|
|
53
|
+
if (stat.isDirectory())
|
|
54
|
+
return { ok: false, error: fail(`${rawPath} is a directory, not a file.`) };
|
|
55
|
+
// Read-before-edit: the anti-confabulation gate.
|
|
56
|
+
//
|
|
57
|
+
// It used to refuse here, outright, for any file not in the ledger. That cost far more
|
|
58
|
+
// than it protected. Measured on a real session: the model batched one identical
|
|
59
|
+
// navigation edit across five pages, four were refused, and it then read four whole
|
|
60
|
+
// files (~9,000 tokens each) and re-issued the same four edits — which all applied
|
|
61
|
+
// cleanly, first try. Twelve calls where five would have done, and every byte of those
|
|
62
|
+
// reads was spent proving something the edit was about to prove anyway.
|
|
63
|
+
//
|
|
64
|
+
// Because that is what an edit already does: `old_string` is matched against the
|
|
65
|
+
// file's CURRENT bytes (see the freshness note below, which says as much). A unique
|
|
66
|
+
// match IS evidence the model knows what is there — you cannot quote a line you have
|
|
67
|
+
// not seen. So an unread file is no longer refused; it is made to earn the edit by
|
|
68
|
+
// matching exactly. If it cannot, the caller returns the same "read it first" message
|
|
69
|
+
// it always did, and the read happens then — when it is actually needed.
|
|
70
|
+
// A search-sourced entry does not count as having seen the file: grep shows matching
|
|
71
|
+
// lines, never the file, so the edit still has to earn itself by matching exactly.
|
|
72
|
+
const record = ctx.reads.get(filePath);
|
|
73
|
+
const seen = record && !record.viaSearch ? record : undefined;
|
|
74
|
+
let content;
|
|
75
|
+
try {
|
|
76
|
+
content = await fs.readFile(filePath, "utf8");
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
return { ok: false, error: fail(`could not read ${rawPath}: ${errText(error)}`) };
|
|
80
|
+
}
|
|
81
|
+
// Freshness: has the file moved since it was read?
|
|
82
|
+
//
|
|
83
|
+
// Without this the situation is still SAFE — the edit is matched against the file's
|
|
84
|
+
// current bytes, so a stale `old_string` simply fails to match — but it is diagnosed
|
|
85
|
+
// WRONGLY. The model is told "old_string not found, re-read and copy the target text
|
|
86
|
+
// precisely", which reads as "you mistyped", so it retries the same doomed string
|
|
87
|
+
// instead of re-reading. The cause has to be named for the recovery to be the right one.
|
|
88
|
+
//
|
|
89
|
+
// And the quieter case is worse: if the change landed somewhere the model is not
|
|
90
|
+
// editing, its edit applies cleanly against content nobody has looked at. That is the
|
|
91
|
+
// only path here where a confident edit is made on stale understanding, so it is worth
|
|
92
|
+
// one comparison of two numbers we already hold.
|
|
93
|
+
if (seen && changedSinceRead(seen, stat)) {
|
|
94
|
+
return {
|
|
95
|
+
ok: false,
|
|
96
|
+
error: failQuietly(`${rawPath} changed on disk since you read it (a command, a formatter, or the user). ` +
|
|
97
|
+
`Your view of this file is out of date, so an edit based on it could be wrong even where it matches. ` +
|
|
98
|
+
`Read it again, then redo the edit against what it says now.`),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
return { ok: true, filePath, content, eol: detectEol(content), unread: seen === undefined };
|
|
102
|
+
}
|
|
103
|
+
/** The refusal an unread file earns only when its edits do NOT match exactly. Same
|
|
104
|
+
* message the gate always gave; it is just paid for when it is actually true. */
|
|
105
|
+
export function unreadError(rawPath) {
|
|
106
|
+
return fail(`${rawPath} has not been read this session, and your edit did not match it exactly. ` +
|
|
107
|
+
`Read it first so your edit matches the real content.`);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Did the file change between the read that put it in the ledger and now (pure)?
|
|
111
|
+
*
|
|
112
|
+
* Both signals are checked because either alone misses real cases: mtime resolution is
|
|
113
|
+
* coarse enough on some filesystems that a fast rewrite keeps the same stamp, and a size
|
|
114
|
+
* comparison alone misses any edit that happens to preserve length — a renamed symbol, a
|
|
115
|
+
* flipped boolean, a changed constant. Neither is exotic in a codebase.
|
|
116
|
+
*
|
|
117
|
+
* A file the ledger has no size for (an older record, or one seeded rather than read) is
|
|
118
|
+
* treated as unchanged: refusing on missing bookkeeping would block edits over our own
|
|
119
|
+
* gap rather than over anything the user did.
|
|
120
|
+
*/
|
|
121
|
+
export function changedSinceRead(seen, now) {
|
|
122
|
+
if (typeof seen.size === "number" && seen.size !== now.size)
|
|
123
|
+
return true;
|
|
124
|
+
if (typeof seen.mtimeMs === "number" && seen.mtimeMs > 0 && Math.abs(seen.mtimeMs - now.mtimeMs) > 1)
|
|
125
|
+
return true;
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
export function errText(error) {
|
|
129
|
+
return error instanceof Error ? error.message : String(error);
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=editTarget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editTarget.js","sourceRoot":"","sources":["../../src/tools/editTarget.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* editWindow.ts — showing the model what its edit actually produced.
|
|
3
|
+
*
|
|
4
|
+
* After a change lands, the tool hands back the changed region with line numbers
|
|
5
|
+
* rather than making the model re-read the whole file to see the result. That one
|
|
6
|
+
* habit is the difference between an edit costing one call and costing two, and
|
|
7
|
+
* re-reads were measured as a large share of wasted context.
|
|
8
|
+
*
|
|
9
|
+
* These live apart from the edit tool itself because `replace_symbol_body` needs
|
|
10
|
+
* the same rendering and has nothing else in common with it. Pure functions over
|
|
11
|
+
* normalized (LF) text: no filesystem, no EOL concerns, trivially testable.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* Render the lines spanning [startChar, endChar] in `text`, plus `pad` lines of
|
|
15
|
+
* context on each side, with 1-based right-aligned line numbers. Pure and indexed
|
|
16
|
+
* on the normalized (LF) text, so it's independent of the file's real EOL. Bounded
|
|
17
|
+
* by `maxLines` so a sweeping replace can't flood the result.
|
|
18
|
+
*/
|
|
19
|
+
export function numberedWindow(text, startChar, endChar, pad = 4, maxLines = 30) {
|
|
20
|
+
const lines = text.split("\n");
|
|
21
|
+
const startLine = charToLine(text, startChar);
|
|
22
|
+
const endLine = charToLine(text, endChar);
|
|
23
|
+
const from = Math.max(0, startLine - pad);
|
|
24
|
+
let to = Math.min(lines.length - 1, endLine + pad);
|
|
25
|
+
let truncated = false;
|
|
26
|
+
if (to - from + 1 > maxLines) {
|
|
27
|
+
to = from + maxLines - 1;
|
|
28
|
+
truncated = true;
|
|
29
|
+
}
|
|
30
|
+
const width = String(to + 1).length;
|
|
31
|
+
const out = [];
|
|
32
|
+
for (let i = from; i <= to; i++) {
|
|
33
|
+
out.push(`${String(i + 1).padStart(width)} ${lines[i] ?? ""}`);
|
|
34
|
+
}
|
|
35
|
+
if (truncated)
|
|
36
|
+
out.push(" … (region continues; re-read the file if you need the rest)");
|
|
37
|
+
return out.join("\n");
|
|
38
|
+
}
|
|
39
|
+
/** The 0-based line a character offset falls on (count of newlines before it). */
|
|
40
|
+
export function charToLine(text, charIndex) {
|
|
41
|
+
let line = 0;
|
|
42
|
+
const limit = Math.min(charIndex, text.length);
|
|
43
|
+
for (let i = 0; i < limit; i++) {
|
|
44
|
+
if (text[i] === "\n")
|
|
45
|
+
line++;
|
|
46
|
+
}
|
|
47
|
+
return line;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=editWindow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"editWindow.js","sourceRoot":"","sources":["../../src/tools/editWindow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAC5B,IAAY,EACZ,SAAiB,EACjB,OAAe,EACf,GAAG,GAAG,CAAC,EACP,QAAQ,GAAG,EAAE;IAEb,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC,CAAC;IAC1C,IAAI,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,OAAO,GAAG,GAAG,CAAC,CAAC;IACnD,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,IAAI,EAAE,GAAG,IAAI,GAAG,CAAC,GAAG,QAAQ,EAAE,CAAC;QAC7B,EAAE,GAAG,IAAI,GAAG,QAAQ,GAAG,CAAC,CAAC;QACzB,SAAS,GAAG,IAAI,CAAC;IACnB,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;IACpC,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;QAChC,GAAG,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAClE,CAAC;IACD,IAAI,SAAS;QAAE,GAAG,CAAC,IAAI,CAAC,iEAAiE,CAAC,CAAC;IAC3F,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACxB,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,UAAU,CAAC,IAAY,EAAE,SAAiB;IACxD,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC/C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/B,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI;YAAE,IAAI,EAAE,CAAC;IAC/B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* eol.ts — line-ending helpers so Mindweave's write tools respect a file's (or a
|
|
3
|
+
* project's) existing style instead of imposing LF.
|
|
4
|
+
*
|
|
5
|
+
* The model always emits LF in tool arguments (it can't see a CR). Left alone,
|
|
6
|
+
* write_file would turn a Windows (CRLF) project into a mix of CRLF and LF files,
|
|
7
|
+
* and a multi-line `old_string` would fail to match raw CRLF bytes. These
|
|
8
|
+
* helpers keep the bytes on disk consistent with what's already there.
|
|
9
|
+
*/
|
|
10
|
+
import { promises as fs } from "node:fs";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
/** The dominant line ending of a text blob: CRLF if any CRLF is present, else LF. */
|
|
13
|
+
export function detectEol(sample) {
|
|
14
|
+
return sample.includes("\r\n") ? "\r\n" : "\n";
|
|
15
|
+
}
|
|
16
|
+
/** Re-encode content to `eol` (normalize to LF first so it's idempotent). */
|
|
17
|
+
export function applyEol(content, eol) {
|
|
18
|
+
const lf = content.replace(/\r\n/g, "\n");
|
|
19
|
+
return eol === "\r\n" ? lf.replace(/\n/g, "\r\n") : lf;
|
|
20
|
+
}
|
|
21
|
+
/** The line ending an EXISTING file uses (reads it; LF if unreadable/unknown). */
|
|
22
|
+
export async function fileEol(path) {
|
|
23
|
+
try {
|
|
24
|
+
return detectEol(await fs.readFile(path, "utf8"));
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return "\n";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Best-effort line ending for a NEW file: match a sibling text file in the same
|
|
32
|
+
* directory, else LF. Bounded and fail-safe so it never blocks or slows a write.
|
|
33
|
+
*/
|
|
34
|
+
export async function dirEol(dir) {
|
|
35
|
+
try {
|
|
36
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
37
|
+
for (const e of entries.slice(0, 20)) {
|
|
38
|
+
if (!e.isFile())
|
|
39
|
+
continue;
|
|
40
|
+
try {
|
|
41
|
+
const buf = await fs.readFile(join(dir, e.name));
|
|
42
|
+
const head = buf.subarray(0, 8192).toString("utf8");
|
|
43
|
+
if (head.includes("\n"))
|
|
44
|
+
return detectEol(head);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Unreadable sibling — try the next one.
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// No directory yet (or unreadable) — fall through to the default.
|
|
53
|
+
}
|
|
54
|
+
return "\n";
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=eol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eol.js","sourceRoot":"","sources":["../../src/tools/eol.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAIjC,qFAAqF;AACrF,MAAM,UAAU,SAAS,CAAC,MAAc;IACtC,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACjD,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,QAAQ,CAAC,OAAe,EAAE,GAAQ;IAChD,MAAM,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC1C,OAAO,GAAG,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACzD,CAAC;AAED,kFAAkF;AAClF,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAY;IACxC,IAAI,CAAC;QACH,OAAO,SAAS,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,GAAW;IACtC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/D,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;YACrC,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE;gBAAE,SAAS;YAC1B,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;gBACjD,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;gBACpD,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;oBAAE,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC;YAClD,CAAC;YAAC,MAAM,CAAC;gBACP,yCAAyC;YAC3C,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,kEAAkE;IACpE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { savePlanArtifact } from "../dynamo/planArtifact.js";
|
|
2
|
+
import { fail, failQuietly } from "./results.js";
|
|
3
|
+
import { readFreeText } from "./approval.js";
|
|
4
|
+
/**
|
|
5
|
+
* What the user chose at the approval prompt. Order is the display order.
|
|
6
|
+
*
|
|
7
|
+
* The "fresh context" pair is the one worth explaining. Planning spends a lot of the
|
|
8
|
+
* window on exploration — files opened to understand the shape of the problem, searches
|
|
9
|
+
* that led nowhere — and none of that is needed to CARRY OUT the plan. Choosing fresh
|
|
10
|
+
* starts the work with the plan as the instruction and nothing else, which is both
|
|
11
|
+
* cheaper and cleaner than implementing underneath a transcript of the investigation.
|
|
12
|
+
* Nothing is lost: the session file is still on disk and the model is told where.
|
|
13
|
+
*/
|
|
14
|
+
export const PLAN_CHOICES = [
|
|
15
|
+
"Approve — Lightning (auto-accept)",
|
|
16
|
+
"Approve — Lightning, fresh context",
|
|
17
|
+
"Approve — Sentinel (ask each action)",
|
|
18
|
+
"Approve — Sentinel, fresh context",
|
|
19
|
+
"Reject",
|
|
20
|
+
];
|
|
21
|
+
/** The typed answer offered alongside them, for saying what to change. */
|
|
22
|
+
export const PLAN_FEEDBACK = { label: "Change something", placeholder: "say what to change" };
|
|
23
|
+
/**
|
|
24
|
+
* Read a verdict out of the chosen option (pure).
|
|
25
|
+
*
|
|
26
|
+
* Matched by POSITION-INDEPENDENT content rather than exact string equality: the
|
|
27
|
+
* approval channel can hand back a trimmed or re-cased answer, and an unrecognised
|
|
28
|
+
* reply must never be read as approval. Anything unknown is a refusal, because the
|
|
29
|
+
* failure that matters here is acting when nobody said yes.
|
|
30
|
+
*/
|
|
31
|
+
export function readVerdict(choice) {
|
|
32
|
+
return readDecision(choice).verdict;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The full decision behind an answer (pure).
|
|
36
|
+
*
|
|
37
|
+
* A TYPED answer is always a revision request carrying its text — the user telling the
|
|
38
|
+
* agent what to change is the one thing the old four-option prompt could not express,
|
|
39
|
+
* so "Change something" meant "stop and wait for them to say it in a new message",
|
|
40
|
+
* which cost a whole round trip to learn one sentence.
|
|
41
|
+
*/
|
|
42
|
+
export function readDecision(choice) {
|
|
43
|
+
const typed = readFreeText(choice);
|
|
44
|
+
if (typed !== null)
|
|
45
|
+
return { verdict: "revise", fresh: false, feedback: typed.trim() };
|
|
46
|
+
const c = choice.trim().toLowerCase();
|
|
47
|
+
if (c.startsWith("approve")) {
|
|
48
|
+
return { verdict: c.includes("sentinel") ? "sentinel" : "lightning", fresh: c.includes("fresh") };
|
|
49
|
+
}
|
|
50
|
+
if (c.startsWith("change"))
|
|
51
|
+
return { verdict: "revise", fresh: false };
|
|
52
|
+
return { verdict: "reject", fresh: false };
|
|
53
|
+
}
|
|
54
|
+
export const exitPlan = {
|
|
55
|
+
name: "exit_plan",
|
|
56
|
+
// It writes nothing, but it is not offered outside planning: there is nothing to
|
|
57
|
+
// exit from in an ordinary turn.
|
|
58
|
+
readOnly: true,
|
|
59
|
+
planOnly: true,
|
|
60
|
+
description: "Present your finished plan to the user and ask them to approve it. Call this when " +
|
|
61
|
+
"you have researched enough to say exactly what you would change and why — it is how " +
|
|
62
|
+
"planning ends. " +
|
|
63
|
+
"Put the WHOLE plan in `plan`: the user reads it here and nowhere else, so it must " +
|
|
64
|
+
"stand on its own, in the order you would carry it out, naming the files you would " +
|
|
65
|
+
"touch. Do not summarise it in your reply as well. " +
|
|
66
|
+
"If the user approves, you begin immediately in the same turn, so write the plan as " +
|
|
67
|
+
"the instruction you are about to follow. If they decline, stop and wait.",
|
|
68
|
+
parameters: {
|
|
69
|
+
type: "object",
|
|
70
|
+
additionalProperties: false,
|
|
71
|
+
required: ["plan"],
|
|
72
|
+
properties: {
|
|
73
|
+
plan: {
|
|
74
|
+
type: "string",
|
|
75
|
+
description: "The complete plan, in markdown. Steps in the order you would do them, the " +
|
|
76
|
+
"files each one touches, and anything you would need the user to decide.",
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
async execute(args, ctx) {
|
|
81
|
+
const plan = typeof args.plan === "string" ? args.plan.trim() : "";
|
|
82
|
+
if (!plan)
|
|
83
|
+
return failQuietly("`plan` is required — put the whole plan in it.");
|
|
84
|
+
if (!ctx.requestApproval) {
|
|
85
|
+
return fail("Cannot ask for approval from here, so the plan cannot be started. Present the " +
|
|
86
|
+
"plan in your reply instead and let the user decide.");
|
|
87
|
+
}
|
|
88
|
+
// The plan travels as DETAIL, not as the question. It is the longest thing any
|
|
89
|
+
// tool asks about, and putting it in the prompt made the frame taller than the
|
|
90
|
+
// terminal — the screen tore and the app looked hung with no way to answer. As
|
|
91
|
+
// detail it prints into the transcript, which scrolls, and the prompt stays one
|
|
92
|
+
// line. Nothing is summarised: the user still reads the whole plan.
|
|
93
|
+
const choice = await ctx.requestApproval(PLAN_QUESTION, [...PLAN_CHOICES], plan, undefined, PLAN_FEEDBACK);
|
|
94
|
+
const { verdict, fresh, feedback } = readDecision(choice);
|
|
95
|
+
if (verdict === "reject") {
|
|
96
|
+
return {
|
|
97
|
+
output: "The user rejected the plan. Stop here and do not start any of it. Do not " +
|
|
98
|
+
"propose a new plan until they say what they want changed.",
|
|
99
|
+
summary: "plan rejected",
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
if (verdict === "revise") {
|
|
103
|
+
// With their words, this is a working instruction and the model can revise now.
|
|
104
|
+
// Without them it is still a full stop, because guessing at what someone meant by
|
|
105
|
+
// "change something" is how an agent produces a second plan nobody asked for.
|
|
106
|
+
return feedback
|
|
107
|
+
? {
|
|
108
|
+
output: `The user did not approve the plan. They want this changed:
|
|
109
|
+
|
|
110
|
+
${feedback}
|
|
111
|
+
|
|
112
|
+
` +
|
|
113
|
+
"Revise the plan accordingly and present it again with exit_plan. Do not " +
|
|
114
|
+
"start any of the work yet.",
|
|
115
|
+
summary: "plan sent back with notes",
|
|
116
|
+
}
|
|
117
|
+
: {
|
|
118
|
+
output: "The user wants the plan changed but has not said how yet. Stop and wait for " +
|
|
119
|
+
"them to tell you. Do not guess at a revision or start any part of the plan.",
|
|
120
|
+
summary: "plan sent back",
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
// Approved. The plan is now the agreed scope of the work, so it becomes a
|
|
124
|
+
// durable artifact: written to .mindweave/plan.md (user-visible, user-editable,
|
|
125
|
+
// survives compaction BY CONSTRUCTION because the engine re-renders it from
|
|
126
|
+
// here every request instead of trusting the transcript) and carried on the
|
|
127
|
+
// context for this session. A failure to write must not un-approve the plan —
|
|
128
|
+
// the in-memory copy still governs this session; only persistence is lost.
|
|
129
|
+
ctx.activePlan = plan;
|
|
130
|
+
ctx.activePlanApprovedAt = new Date().toISOString();
|
|
131
|
+
try {
|
|
132
|
+
await savePlanArtifact(ctx.roots?.[0] ?? ctx.cwd, plan, verdict === "sentinel" ? "sentinel" : "lightning");
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
// Read-only filesystem or similar: session-local plan still applies.
|
|
136
|
+
}
|
|
137
|
+
// Approving ENDS the planning session, and the mode the user picked at the prompt
|
|
138
|
+
// is the mode they are now in. It used to be lifted for one turn and then forced
|
|
139
|
+
// back to planning, which had two costs: work that did not finish in a single turn
|
|
140
|
+
// came back with the editing tools withheld AND the plan no longer in context, so
|
|
141
|
+
// it needed approving again; and a user who had been in Sentinel before planning
|
|
142
|
+
// was silently returned to a different mode from the one they chose here.
|
|
143
|
+
ctx.planMode = false;
|
|
144
|
+
// Asked for, not done here. Replacing the conversation from inside a tool would
|
|
145
|
+
// strand the call that is still running: the provider requires every tool_call to
|
|
146
|
+
// be answered, so the engine performs it once this result has been recorded, and
|
|
147
|
+
// drops the call and its answer together.
|
|
148
|
+
if (fresh)
|
|
149
|
+
ctx.planFreshStart = plan;
|
|
150
|
+
ctx.guarded = verdict === "sentinel";
|
|
151
|
+
// A fresh Sentinel pass starts vigilant: an "allow all" from some earlier point in
|
|
152
|
+
// the session must not silently cover work the user has only just agreed to.
|
|
153
|
+
if (ctx.guarded)
|
|
154
|
+
ctx.guardAllowed = undefined;
|
|
155
|
+
ctx.onModeChange?.();
|
|
156
|
+
return {
|
|
157
|
+
output: `The user approved the plan${verdict === "sentinel" ? " and asked to confirm each action" : ""}. ` +
|
|
158
|
+
`Start now, in this turn, and follow the plan you just presented. ` +
|
|
159
|
+
`Begin by putting its steps on your task list if there is more than one. ` +
|
|
160
|
+
(fresh
|
|
161
|
+
? "The conversation from planning has been cleared, so work from the plan itself. " +
|
|
162
|
+
"It is repeated in full above. "
|
|
163
|
+
: "") +
|
|
164
|
+
(verdict === "sentinel"
|
|
165
|
+
? "Each change is confirmed with them before it happens, so work in small clear steps. "
|
|
166
|
+
: "") +
|
|
167
|
+
`Do not restate the plan — they have read it.`,
|
|
168
|
+
summary: verdict === "sentinel" ? "plan approved (Sentinel)" : "plan approved (Lightning)",
|
|
169
|
+
};
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
/** The prompt itself — one line, because it renders in the height-bounded footer.
|
|
173
|
+
* The plan is passed alongside it as detail and printed into the transcript. */
|
|
174
|
+
export const PLAN_QUESTION = "Start on this?";
|
|
175
|
+
//# sourceMappingURL=exitPlan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exitPlan.js","sourceRoot":"","sources":["../../src/tools/exitPlan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* focus.ts — pure helpers for a file's "focus spans": the line ranges the model has
|
|
3
|
+
* recently read or edited. When a file is too big to keep whole in the working set,
|
|
4
|
+
* these spans are what we show (its focused regions) instead of the entire file.
|
|
5
|
+
*
|
|
6
|
+
* Kept dependency-free so both the path/ledger layer (paths.ts) and the working-set
|
|
7
|
+
* renderer (workingSet.ts) can share it without an import cycle.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Add a span to a file's focus list, merging overlapping/adjacent ranges and keeping
|
|
11
|
+
* at most `max` (the most recent). Returns a new array (or undefined when nothing to
|
|
12
|
+
* track). Pure.
|
|
13
|
+
*/
|
|
14
|
+
export function addFocus(existing, span, max = 4) {
|
|
15
|
+
if (!span)
|
|
16
|
+
return existing;
|
|
17
|
+
const all = [...(existing ?? []), { start: Math.max(1, span.start), end: Math.max(span.start, span.end) }].sort((a, b) => a.start - b.start);
|
|
18
|
+
const merged = [];
|
|
19
|
+
for (const s of all) {
|
|
20
|
+
const last = merged[merged.length - 1];
|
|
21
|
+
if (last && s.start <= last.end + 1)
|
|
22
|
+
last.end = Math.max(last.end, s.end);
|
|
23
|
+
else
|
|
24
|
+
merged.push({ ...s });
|
|
25
|
+
}
|
|
26
|
+
// Keep the most recent (highest-line) spans when over the cap.
|
|
27
|
+
return merged.slice(-max);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Is [start..end] wholly inside a span the model is already being shown?
|
|
31
|
+
*
|
|
32
|
+
* NOTE: the working set that used to render a large file's focus regions every turn is
|
|
33
|
+
* gone, so nothing populates the span map any more and this answers "no" in the engine's
|
|
34
|
+
* own path. Kept because the reasoning is still correct wherever a caller genuinely knows
|
|
35
|
+
* what is on screen: checked against the focus recorded BEFORE this read, and only ever
|
|
36
|
+
* used together with an unchanged-file check — a stale region is worse than a duplicated
|
|
37
|
+
* one. A span map with no producer must never be allowed to suppress content.
|
|
38
|
+
*/
|
|
39
|
+
export function coversSpan(focus, start, end) {
|
|
40
|
+
return (focus ?? []).some((f) => f.start <= start && f.end >= end);
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=focus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"focus.js","sourceRoot":"","sources":["../../src/tools/focus.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CACtB,QAAiC,EACjC,IAA2B,EAC3B,GAAG,GAAG,CAAC;IAEP,IAAI,CAAC,IAAI;QAAE,OAAO,QAAQ,CAAC;IAC3B,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,IAAI,CAC7G,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAC5B,CAAC;IACF,MAAM,MAAM,GAAgB,EAAE,CAAC;IAC/B,KAAK,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC;QACpB,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACvC,IAAI,IAAI,IAAI,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,GAAG,CAAC;YAAE,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;;YACrE,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IAC7B,CAAC;IACD,+DAA+D;IAC/D,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,UAAU,CAAC,KAA8B,EAAE,KAAa,EAAE,GAAW;IACnF,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,KAAK,IAAI,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC;AACrE,CAAC"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* gitignore.ts — honour .gitignore in the pure-Node walk.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS EXISTS: search has two engines. ripgrep walks the tree itself and is
|
|
5
|
+
* .gitignore-aware; the Node fallback in walk.ts was not. So the same query
|
|
6
|
+
* returned different results depending on whether `rg` happened to be installed,
|
|
7
|
+
* and both tool descriptions stated the gitignore behaviour as universal — true on
|
|
8
|
+
* one engine, false on the other. Two engines that disagree about what exists is
|
|
9
|
+
* worse than either behaviour on its own, because nothing in the answer says which
|
|
10
|
+
* one you got.
|
|
11
|
+
*
|
|
12
|
+
* WHAT IS SUPPORTED (the common subset, which is what real .gitignore files use):
|
|
13
|
+
* - comments (`#`), blank lines, trailing-space trimming
|
|
14
|
+
* - negation (`!pattern`), last match wins, deeper files override shallower ones
|
|
15
|
+
* - directory-only rules (`build/`)
|
|
16
|
+
* - anchoring: a `/` anywhere but the end anchors to the .gitignore's own
|
|
17
|
+
* directory; otherwise the rule matches a basename at any depth
|
|
18
|
+
* - `*`, `?`, `**`, and backslash escapes
|
|
19
|
+
*
|
|
20
|
+
* NOT supported, deliberately: character classes (`[a-z]`). They are rare in real
|
|
21
|
+
* ignore files, and a half-right implementation of them would silently hide files,
|
|
22
|
+
* which is the one failure mode worth avoiding here — an unsupported rule is
|
|
23
|
+
* treated as matching nothing, so the walk errs toward SHOWING a file rather than
|
|
24
|
+
* hiding it. Over-showing is visible and correctable; over-hiding looks like the
|
|
25
|
+
* file does not exist.
|
|
26
|
+
*/
|
|
27
|
+
import { promises as fs } from "node:fs";
|
|
28
|
+
import { join } from "node:path";
|
|
29
|
+
/** Parse .gitignore text into rules. Exported for testing. */
|
|
30
|
+
export function parseGitignore(text) {
|
|
31
|
+
const rules = [];
|
|
32
|
+
for (const raw of text.split(/\r?\n/)) {
|
|
33
|
+
let line = raw;
|
|
34
|
+
// A comment only counts at the start; `foo#bar` is a real pattern.
|
|
35
|
+
if (line.startsWith("#"))
|
|
36
|
+
continue;
|
|
37
|
+
// Trailing whitespace is stripped unless escaped with a backslash.
|
|
38
|
+
line = line.replace(/(?<!\\)\s+$/, "");
|
|
39
|
+
if (line === "")
|
|
40
|
+
continue;
|
|
41
|
+
let negated = false;
|
|
42
|
+
if (line.startsWith("!")) {
|
|
43
|
+
negated = true;
|
|
44
|
+
line = line.slice(1);
|
|
45
|
+
}
|
|
46
|
+
else if (line.startsWith("\\!")) {
|
|
47
|
+
line = line.slice(1); // an escaped literal "!"
|
|
48
|
+
}
|
|
49
|
+
if (line === "")
|
|
50
|
+
continue;
|
|
51
|
+
let dirOnly = false;
|
|
52
|
+
if (line.endsWith("/")) {
|
|
53
|
+
dirOnly = true;
|
|
54
|
+
line = line.slice(0, -1);
|
|
55
|
+
}
|
|
56
|
+
if (line === "")
|
|
57
|
+
continue;
|
|
58
|
+
// A slash anywhere except the very end anchors the rule to this .gitignore's
|
|
59
|
+
// directory. Otherwise it matches a basename at any depth.
|
|
60
|
+
const anchored = line.includes("/");
|
|
61
|
+
if (line.startsWith("/"))
|
|
62
|
+
line = line.slice(1);
|
|
63
|
+
const body = globBody(line);
|
|
64
|
+
if (body === null)
|
|
65
|
+
continue; // unsupported syntax — match nothing (see header)
|
|
66
|
+
const prefix = anchored ? "" : "(?:.*/)?";
|
|
67
|
+
rules.push({ re: new RegExp(`^${prefix}${body}$`), negated, dirOnly });
|
|
68
|
+
}
|
|
69
|
+
return rules;
|
|
70
|
+
}
|
|
71
|
+
/** Translate one gitignore pattern into a regex body, or null if unsupported. */
|
|
72
|
+
function globBody(pattern) {
|
|
73
|
+
let out = "";
|
|
74
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
75
|
+
const c = pattern[i];
|
|
76
|
+
if (c === "\\") {
|
|
77
|
+
const next = pattern[i + 1];
|
|
78
|
+
if (next === undefined)
|
|
79
|
+
return null; // dangling escape
|
|
80
|
+
out += escapeRe(next);
|
|
81
|
+
i++;
|
|
82
|
+
}
|
|
83
|
+
else if (c === "[") {
|
|
84
|
+
return null; // character class — deliberately unsupported, see header
|
|
85
|
+
}
|
|
86
|
+
else if (c === "*") {
|
|
87
|
+
if (pattern[i + 1] === "*") {
|
|
88
|
+
// `**/` spans zero or more whole segments; a trailing `**` matches the rest.
|
|
89
|
+
if (pattern[i + 2] === "/") {
|
|
90
|
+
out += "(?:.*/)?";
|
|
91
|
+
i += 2;
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
out += ".*";
|
|
95
|
+
i += 1;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
out += "[^/]*";
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
else if (c === "?") {
|
|
103
|
+
out += "[^/]";
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
out += escapeRe(c);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return out;
|
|
110
|
+
}
|
|
111
|
+
function escapeRe(s) {
|
|
112
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
113
|
+
}
|
|
114
|
+
/** Read a directory's .gitignore into a layer, or null when it has none. */
|
|
115
|
+
export async function loadIgnoreLayer(dir) {
|
|
116
|
+
let text;
|
|
117
|
+
try {
|
|
118
|
+
text = await fs.readFile(join(dir, ".gitignore"), "utf8");
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
const rules = parseGitignore(text);
|
|
124
|
+
return rules.length ? { base: dir, rules } : null;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Is `relPath` (posix, relative to the layer's base) ignored by these layers?
|
|
128
|
+
*
|
|
129
|
+
* Git's precedence: a deeper .gitignore overrides a shallower one, and within one
|
|
130
|
+
* file the LAST matching rule wins. So we walk layers deepest-first and return the
|
|
131
|
+
* first layer that has an opinion.
|
|
132
|
+
*/
|
|
133
|
+
export function isIgnored(layers, isDir) {
|
|
134
|
+
for (let i = layers.length - 1; i >= 0; i--) {
|
|
135
|
+
const { layer, rel } = layers[i];
|
|
136
|
+
let decision = null;
|
|
137
|
+
for (const rule of layer.rules) {
|
|
138
|
+
if (rule.dirOnly && !isDir)
|
|
139
|
+
continue;
|
|
140
|
+
if (rule.re.test(rel))
|
|
141
|
+
decision = !rule.negated;
|
|
142
|
+
}
|
|
143
|
+
if (decision !== null)
|
|
144
|
+
return decision;
|
|
145
|
+
}
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=gitignore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitignore.js","sourceRoot":"","sources":["../../src/tools/gitignore.ts"],"names":[],"mappings":"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"}
|