@astralyn/pi 1.0.5 → 1.1.0
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/CHANGELOG.md +37 -0
- package/dist/bundle/chunks/{anthropic-messages-YIOJIMVL.js → anthropic-messages-3K3DWVY6.js} +1 -1
- package/dist/bundle/chunks/anthropic.js +1 -1
- package/dist/bundle/chunks/{azure-openai-responses-LDW4FGAQ.js → azure-openai-responses-CH74HGP4.js} +1 -1
- package/dist/bundle/chunks/bedrock-converse-stream.js +2 -2
- package/dist/bundle/chunks/{chunk-UCXU7KLO.js → chunk-3MMB5I7J.js} +1 -1
- package/dist/bundle/chunks/{chunk-GIG5IHES.js → chunk-5KJH3GGH.js} +1 -1
- package/dist/bundle/chunks/chunk-6VYRLG5F.js +2 -0
- package/dist/bundle/chunks/{chunk-HDHRZ7GT.js → chunk-C2ARIVS3.js} +1 -1
- package/dist/bundle/chunks/{chunk-IE3Z7ESB.js → chunk-D3XW5X3Z.js} +371 -246
- package/dist/bundle/chunks/{chunk-IFELM7MW.js → chunk-EJEOEBSJ.js} +1 -1
- package/dist/bundle/chunks/chunk-H35KWBT5.js +11 -0
- package/dist/bundle/chunks/chunk-KAC2YPTW.js +2 -0
- package/dist/bundle/chunks/chunk-MAC4N3BW.js +2 -0
- package/dist/bundle/chunks/chunk-QLU3LESZ.js +2 -0
- package/dist/bundle/chunks/{chunk-A6ALEEY5.js → chunk-TEAAYBTS.js} +1 -1
- package/dist/bundle/chunks/cloudflare-workers-ai-system-one-XO45ZT3V.js +2 -0
- package/dist/bundle/chunks/codemode-worker.js +2 -2
- package/dist/bundle/chunks/github-copilot.js +1 -1
- package/dist/bundle/chunks/{google-generative-ai-S5A5IBU4.js → google-generative-ai-VVO64ZRQ.js} +1 -1
- package/dist/bundle/chunks/{google-vertex-UBRQFDB4.js → google-vertex-LKS5NUHA.js} +1 -1
- package/dist/bundle/chunks/image-resize-worker.js +1 -1
- package/dist/bundle/chunks/{llama-cpp-classify-R7DQLTQN.js → llama-cpp-classify-H3IZDR5O.js} +2 -2
- package/dist/bundle/chunks/{mistral-conversations-A2N5FSOV.js → mistral-conversations-NJUOG4ET.js} +2 -2
- package/dist/bundle/chunks/openai-chatgpt.js +1 -1
- package/dist/bundle/chunks/{openai-codex-responses-Q6JHCWLE.js → openai-codex-responses-TZWBTTYM.js} +2 -2
- package/dist/bundle/chunks/openai-codex.js +1 -1
- package/dist/bundle/chunks/{openai-completions-H4VMO7AU.js → openai-completions-7HTTU6FH.js} +1 -1
- package/dist/bundle/chunks/openai-decisions-776H4VDZ.js +5 -0
- package/dist/bundle/chunks/{openai-responses-G4PGNM2H.js → openai-responses-7A6BAQ5X.js} +1 -1
- package/dist/bundle/chunks/{openrouter-images-YP3YVB54.js → openrouter-images-TDLJV5N4.js} +1 -1
- package/dist/bundle/chunks/{pi-messages-HZZ7GEEW.js → pi-messages-ZXNERWJG.js} +1 -1
- package/dist/bundle/chunks/typesafe-system-one-2DQLG4R2.js +2 -0
- package/dist/bundle/chunks/{virtual-modules-46MSJGKO.js → virtual-modules-2NHGQRS6.js} +1 -1
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/cli/args.d.ts +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +13 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-session.d.ts +12 -6
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +146 -174
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +40 -45
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/context-snapshot.d.ts +4 -1
- package/dist/core/context-snapshot.d.ts.map +1 -1
- package/dist/core/context-snapshot.js +45 -0
- package/dist/core/context-snapshot.js.map +1 -1
- package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
- package/dist/core/export-html/tool-renderer.js +2 -0
- package/dist/core/export-html/tool-renderer.js.map +1 -1
- package/dist/core/extensions/types.d.ts +11 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +2 -1
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/nested-tool-calls.d.ts +1 -0
- package/dist/core/nested-tool-calls.d.ts.map +1 -1
- package/dist/core/nested-tool-calls.js +1 -0
- package/dist/core/nested-tool-calls.js.map +1 -1
- package/dist/core/sdk.d.ts +4 -0
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +17 -5
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-manager.d.ts +13 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +37 -13
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/tasks/session.d.ts +9 -0
- package/dist/core/tasks/session.d.ts.map +1 -1
- package/dist/core/tasks/session.js +21 -0
- package/dist/core/tasks/session.js.map +1 -1
- package/dist/core/tools/renderers/bash.d.ts.map +1 -1
- package/dist/core/tools/renderers/bash.js +8 -3
- package/dist/core/tools/renderers/bash.js.map +1 -1
- package/dist/core/tools/renderers/edit.js +1 -1
- package/dist/core/tools/renderers/edit.js.map +1 -1
- package/dist/extensions/codemode/execute.d.ts.map +1 -1
- package/dist/extensions/codemode/execute.js +63 -7
- package/dist/extensions/codemode/execute.js.map +1 -1
- package/dist/extensions/codemode/tool.js +2 -2
- package/dist/extensions/codemode/tool.js.map +1 -1
- package/dist/extensions/index.js +2 -2
- package/dist/extensions/index.js.map +1 -1
- package/dist/extensions/llama/provider.d.ts.map +1 -1
- package/dist/extensions/llama/provider.js +34 -11
- package/dist/extensions/llama/provider.js.map +1 -1
- package/dist/extensions/mcp/cli.js +17 -23
- package/dist/extensions/mcp/cli.js.map +1 -1
- package/dist/extensions/mcp/index.d.ts.map +1 -1
- package/dist/extensions/mcp/index.js +165 -64
- package/dist/extensions/mcp/index.js.map +1 -1
- package/dist/extensions/mcp/oauth.d.ts +5 -3
- package/dist/extensions/mcp/oauth.d.ts.map +1 -1
- package/dist/extensions/mcp/oauth.js +36 -10
- package/dist/extensions/mcp/oauth.js.map +1 -1
- package/dist/extensions/mcp/ui.d.ts +3 -3
- package/dist/extensions/mcp/ui.d.ts.map +1 -1
- package/dist/extensions/mcp/ui.js +10 -2
- package/dist/extensions/mcp/ui.js.map +1 -1
- package/dist/extensions/search/code-search.d.ts +29 -0
- package/dist/extensions/search/code-search.d.ts.map +1 -0
- package/dist/extensions/search/code-search.js +120 -0
- package/dist/extensions/search/code-search.js.map +1 -0
- package/dist/extensions/search/command.d.ts +5 -0
- package/dist/extensions/search/command.d.ts.map +1 -0
- package/dist/extensions/search/command.js +69 -0
- package/dist/extensions/search/command.js.map +1 -0
- package/dist/extensions/search/credential.d.ts +25 -0
- package/dist/extensions/search/credential.d.ts.map +1 -0
- package/dist/extensions/search/credential.js +117 -0
- package/dist/extensions/search/credential.js.map +1 -0
- package/dist/extensions/search/devin.d.ts +34 -0
- package/dist/extensions/search/devin.d.ts.map +1 -0
- package/dist/extensions/search/devin.js +210 -0
- package/dist/extensions/search/devin.js.map +1 -0
- package/dist/extensions/search/index.d.ts +5 -0
- package/dist/extensions/search/index.d.ts.map +1 -0
- package/dist/extensions/search/index.js +110 -0
- package/dist/extensions/search/index.js.map +1 -0
- package/dist/extensions/search/panel.d.ts +53 -0
- package/dist/extensions/search/panel.d.ts.map +1 -0
- package/dist/extensions/search/panel.js +157 -0
- package/dist/extensions/search/panel.js.map +1 -0
- package/dist/extensions/search/prompt.d.ts +14 -0
- package/dist/extensions/search/prompt.d.ts.map +1 -0
- package/dist/extensions/search/prompt.js +221 -0
- package/dist/extensions/search/prompt.js.map +1 -0
- package/dist/extensions/search/render.d.ts +28 -0
- package/dist/extensions/search/render.d.ts.map +1 -0
- package/dist/extensions/search/render.js +86 -0
- package/dist/extensions/search/render.js.map +1 -0
- package/dist/extensions/search/workspace.d.ts +38 -0
- package/dist/extensions/search/workspace.d.ts.map +1 -0
- package/dist/extensions/search/workspace.js +245 -0
- package/dist/extensions/search/workspace.js.map +1 -0
- package/dist/modes/interactive/components/bash-execution.d.ts +5 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +14 -14
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts +2 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +5 -2
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts +2 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +5 -2
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/custom-entry.d.ts +3 -1
- package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-entry.js +7 -2
- package/dist/modes/interactive/components/custom-entry.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +1 -0
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +1 -1
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts +2 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.js +5 -2
- package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +2 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +52 -59
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/program-status-reporter.d.ts +34 -0
- package/dist/modes/interactive/program-status-reporter.d.ts.map +1 -0
- package/dist/modes/interactive/program-status-reporter.js +107 -0
- package/dist/modes/interactive/program-status-reporter.js.map +1 -0
- package/dist/modes/interactive/tasks/host-hooks.d.ts +14 -0
- package/dist/modes/interactive/tasks/host-hooks.d.ts.map +1 -0
- package/dist/modes/interactive/tasks/host-hooks.js +31 -0
- package/dist/modes/interactive/tasks/host-hooks.js.map +1 -0
- package/dist/modes/interactive/tool-view/tool-execution.d.ts +5 -0
- package/dist/modes/interactive/tool-view/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/tool-view/tool-execution.js +7 -0
- package/dist/modes/interactive/tool-view/tool-execution.js.map +1 -1
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +24 -0
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/utils/ansi.d.ts +8 -0
- package/dist/utils/ansi.d.ts.map +1 -1
- package/dist/utils/ansi.js +30 -11
- package/dist/utils/ansi.js.map +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +12 -11
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/image-resize-core.d.ts +12 -0
- package/dist/utils/image-resize-core.d.ts.map +1 -1
- package/dist/utils/image-resize-core.js +5 -0
- package/dist/utils/image-resize-core.js.map +1 -1
- package/dist/utils/image-resize-worker.js +3 -2
- package/dist/utils/image-resize-worker.js.map +1 -1
- package/dist/utils/image-resize.d.ts.map +1 -1
- package/dist/utils/image-resize.js +9 -10
- package/dist/utils/image-resize.js.map +1 -1
- package/docs/bundled/README.md +1 -1
- package/docs/bundled/extensions/provider.md +1 -1
- package/docs/bundled/extensions/question.md +1 -1
- package/docs/bundled/extensions/search.md +50 -0
- package/docs/bundled/extensions/statusline.md +15 -41
- package/docs/codemode.md +23 -3
- package/docs/docs.json +0 -4
- package/docs/environment-variables.md +1 -0
- package/docs/extensions.md +5 -1
- package/docs/json.md +2 -2
- package/docs/llama-cpp.md +8 -1
- package/docs/models.md +4 -1
- package/docs/providers.md +17 -0
- package/docs/rpc.md +6 -3
- package/docs/session-format.md +1 -0
- package/docs/settings.md +3 -3
- package/docs/terminal-setup.md +14 -0
- package/docs/usage.md +5 -3
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +54 -54
- package/package.json +13 -11
- package/dist/bundle/chunks/chunk-57XI7YJH.js +0 -2
- package/dist/bundle/chunks/chunk-JI4WGISU.js +0 -2
- package/dist/bundle/chunks/chunk-TCQ4HHQD.js +0 -2
- package/dist/bundle/chunks/chunk-TXJO4AJ7.js +0 -11
- package/dist/bundle/chunks/cloudflare-workers-ai-system-one-OWU5SM6J.js +0 -2
- package/dist/bundle/chunks/typesafe-system-one-KYKKNU3E.js +0 -2
- package/dist/extensions/web-search/auth.d.ts +0 -12
- package/dist/extensions/web-search/auth.d.ts.map +0 -1
- package/dist/extensions/web-search/auth.js +0 -90
- package/dist/extensions/web-search/auth.js.map +0 -1
- package/dist/extensions/web-search/constants.d.ts +0 -13
- package/dist/extensions/web-search/constants.d.ts.map +0 -1
- package/dist/extensions/web-search/constants.js +0 -26
- package/dist/extensions/web-search/constants.js.map +0 -1
- package/dist/extensions/web-search/execute.d.ts +0 -9
- package/dist/extensions/web-search/execute.d.ts.map +0 -1
- package/dist/extensions/web-search/execute.js +0 -96
- package/dist/extensions/web-search/execute.js.map +0 -1
- package/dist/extensions/web-search/format.d.ts +0 -21
- package/dist/extensions/web-search/format.d.ts.map +0 -1
- package/dist/extensions/web-search/format.js +0 -117
- package/dist/extensions/web-search/format.js.map +0 -1
- package/dist/extensions/web-search/index.d.ts +0 -6
- package/dist/extensions/web-search/index.d.ts.map +0 -1
- package/dist/extensions/web-search/index.js +0 -50
- package/dist/extensions/web-search/index.js.map +0 -1
- package/dist/extensions/web-search/providers/deepseek.d.ts +0 -13
- package/dist/extensions/web-search/providers/deepseek.d.ts.map +0 -1
- package/dist/extensions/web-search/providers/deepseek.js +0 -110
- package/dist/extensions/web-search/providers/deepseek.js.map +0 -1
- package/dist/extensions/web-search/providers/http.d.ts +0 -4
- package/dist/extensions/web-search/providers/http.d.ts.map +0 -1
- package/dist/extensions/web-search/providers/http.js +0 -42
- package/dist/extensions/web-search/providers/http.js.map +0 -1
- package/dist/extensions/web-search/providers/minimax.d.ts +0 -12
- package/dist/extensions/web-search/providers/minimax.d.ts.map +0 -1
- package/dist/extensions/web-search/providers/minimax.js +0 -61
- package/dist/extensions/web-search/providers/minimax.js.map +0 -1
- package/dist/extensions/web-search/render.d.ts +0 -15
- package/dist/extensions/web-search/render.d.ts.map +0 -1
- package/dist/extensions/web-search/render.js +0 -142
- package/dist/extensions/web-search/render.js.map +0 -1
- package/dist/extensions/web-search/results.d.ts +0 -35
- package/dist/extensions/web-search/results.d.ts.map +0 -1
- package/dist/extensions/web-search/results.js +0 -167
- package/dist/extensions/web-search/results.js.map +0 -1
- package/dist/extensions/web-search/schema.d.ts +0 -10
- package/dist/extensions/web-search/schema.d.ts.map +0 -1
- package/dist/extensions/web-search/schema.js +0 -36
- package/dist/extensions/web-search/schema.js.map +0 -1
- package/dist/extensions/web-search/types.d.ts +0 -51
- package/dist/extensions/web-search/types.d.ts.map +0 -1
- package/dist/extensions/web-search/types.js +0 -5
- package/dist/extensions/web-search/types.js.map +0 -1
- package/docs/bundled/extensions/web-search.md +0 -46
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt.js","sourceRoot":"","sources":["../../../src/extensions/search/prompt.ts"],"names":[],"mappings":"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","sourcesContent":["/** Planning rounds before the final answer is forced, commands per round, and files per answer. */\nexport const MAX_TURNS = 3;\nexport const MAX_COMMANDS = 8;\nexport const MAX_RESULTS = 10;\n\n/**\n * The SWE-grep planner prompt, kept close to the Windsurf original the backend model was tuned on.\n * The budgets it states are the ones code-search.ts enforces.\n */\nexport const SYSTEM_PROMPT = `You are an expert software engineer, responsible for providing context \\\nto another engineer to solve a code issue in the current codebase. \\\nThe user will present you with a description of the issue, and it is \\\nyour job to provide a series of file paths with associated line ranges \\\nthat contain ALL the information relevant to understand and correctly \\\naddress the issue.\n\n# IMPORTANT:\n- A relevant file does not mean only the files that must be modified to \\\nsolve the task. It means any file that contains information relevant to \\\nplanning and implementing the fix, such as the definitions of classes \\\nand functions that are relevant to the pieces of code that will have to \\\nbe modified.\n- You should include enough context around the relevant lines to allow \\\nthe engineer to understand the task correctly. You must include ENTIRE \\\nsemantic blocks (functions, classes, definitions, etc). For example:\nIf addressing the issue requires modifying a method within a class, then \\\nyou should include the entire class definition, not just the lines around \\\nthe method we want to modify.\n- NEVER truncate these blocks unless they are very large (hundreds of \\\nlines or more, in which case providing only a relevant portion of the \\\nblock is acceptable).\n- Your job is to essentially alleviate the job of the other engineer by \\\ngiving them a clean starting context from which to start working. More \\\nprecisely, you should minimize the number of files the engineer has to \\\nread to understand and solve the task correctly (while not providing \\\nirrelevant code snippets).\n\n# ENVIRONMENT\n- Working directory: /codebase. Make sure to run commands in this \\\ndirectory, not \\`.\n- Tool access: use the restricted_exec tool ONLY\n- Allowed sub-commands (schema-enforced):\n - rg: Search for patterns in files using ripgrep\n - Required: pattern (string), path (string)\n - Optional: include (array of globs), exclude (array of globs)\n - readfile: Read contents of a file with optional line range\n - Required: file (string)\n - Optional: start_line (int), end_line (int) — 1-indexed, inclusive\n - tree: Display directory structure as a tree\n - Required: path (string)\n - Optional: levels (int)\n\n# THINKING RULES\n- Think step-by-step. Plan, reason, and reflect before each tool call.\n- Use tool calls liberally and purposefully to ground every conclusion \\\nin real code, not assumptions.\n- If a command fails, rethink and try something different; do not \\\ncomplain to the user.\n\n# FAST-SEARCH DEFAULTS (optimize rg/tree on large repos)\n- Start NARROW, then widen only if needed. Prefer searching likely code \\\nroots first (e.g., \\`src/\\`, \\`lib/\\`, \\`app/\\`, \\`packages/\\`, \\`services/\\`) \\\ninstead of \\`/codebase\\`.\n- Prefer fixed-string search for literals: escape patterns or keep regex \\\nsimple. Use smart case; avoid case-insensitive unless necessary.\n- Prefer file-type filters and globs (in include) over full-repo scans.\n- Default EXCLUDES for speed (apply via the exclude array): \\\nnode_modules, .git, dist, build, coverage, .venv, venv, target, out, \\\n.cache, __pycache__, vendor, deps, third_party, logs, data, *.min.*\n- Skip huge files where possible; when opening files, prefer reading \\\nonly relevant ranges with readfile.\n- Limit directory traversal with tree levels to quickly orient before \\\ndeeper inspection.\n\n# SOME EXAMPLES OF WORKFLOWS\n- MAP – Use \\`tree\\` with small levels; \\`rg\\` on likely roots to grasp \\\nstructure and hotspots.\n- ANCHOR – \\`rg\\` for problem keywords and anchor symbols; restrict by \\\nlanguage globs via include.\n- TRACE – Follow imports with targeted \\`rg\\` in narrowed roots; open \\\nfiles with \\`readfile\\` scoped to entire semantic blocks.\n- VERIFY – Confirm each candidate path exists by reading or additional \\\nsearches; drop false positives (tests, vendored, generated) unless they \\\nmust change.\n\n# TOOL USE GUIDELINES\n- You must use a SINGLE restricted_exec call in your answer, that lets \\\nyou execute at most ${MAX_COMMANDS} commands in a single turn. Each command must be \\\nan object with a \\`type\\` field of \\`rg\\`, \\`readfile\\`, or \\`tree\\` and the appropriate fields for that type.\n- Example restricted_exec usage:\n[TOOL_CALLS]restricted_exec[ARGS]{\n \"command1\": {\n \"type\": \"rg\",\n \"pattern\": \"Controller\",\n \"path\": \"/codebase/slime\",\n \"include\": [\"**/*.py\"],\n \"exclude\": [\"**/node_modules/**\", \"**/.git/**\", \"**/dist/**\", \\\n\"**/build/**\", \"**/.venv/**\", \"**/__pycache__/**\"]\n },\n \"command2\": {\n \"type\": \"readfile\",\n \"file\": \"/codebase/slime/train.py\",\n \"start_line\": 1,\n \"end_line\": 200\n },\n \"command3\": {\n \"type\": \"tree\",\n \"path\": \"/codebase/slime/\",\n \"levels\": 2\n }\n}\n- You have at most ${MAX_TURNS} turns to interact with the environment by calling \\\ntools, so issuing multiple commands at once is necessary and encouraged \\\nto speed up your research.\n- Each command result may be truncated to 40 lines; prefer multiple \\\ntargeted reads/searches to build complete context.\n- DO NOT EVER USE MORE THAN ${MAX_COMMANDS} commands in a single turn, or you will \\\nbe penalized.\n\n# ANSWER FORMAT (strict format, including tags)\n- You will output an XML structure with a root element \"ANSWER\" \\\ncontaining \"file\" elements. Each \"file\" element will have a \"path\" \\\nattribute and contain \"range\" elements.\n- You will output this as your final response.\n- The line ranges must be inclusive.\n\nOutput example inside the \"answer\" tool argument:\n<ANSWER>\n <file path=\"/codebase/info_theory/formulas/entropy.py\">\n <range>10-60</range>\n <range>150-210</range>\n </file>\n <file path=\"/codebase/info_theory/data_structures/bits.py\">\n <range>1-40</range>\n <range>110-170</range>\n </file>\n</ANSWER>\n\nRemember: Prefer narrow, fixed-string, and type-filtered searches with \\\naggressive excludes and size/depth limits. Widen scope only as needed. \\\nUse the restricted tools available to you, and output your answer in \\\nexactly the specified format.\n\n# NO RESULTS POLICY\nIf after thorough searching you are confident that NO relevant files exist \\\nfor the given query (e.g., the function/class/concept does not exist in the \\\ncodebase), you MUST return an empty ANSWER:\n<ANSWER></ANSWER>\nDo NOT return irrelevant files (such as entry points or config files) just \\\nto provide some output. An empty answer is always better than a misleading one.\n\n# RESULT COUNT\nAim to return at most ${MAX_RESULTS} files in your answer. Focus on the most \\\nrelevant files first. If fewer files are relevant, return fewer.\n`;\n\nexport const FORCE_ANSWER =\n\t\"You have no turns left. Now you MUST provide your final ANSWER, even if it's not complete.\";\n\nexport const RETRY_TOOL_CALL =\n\t\"Your last reply did not contain a valid tool call. Reply with exactly one restricted_exec or answer call.\";\n\nconst COMMAND_SCHEMA = {\n\ttype: \"object\",\n\tdescription: \"One command. Must be one of: rg, readfile, or tree.\",\n\toneOf: [\n\t\t{\n\t\t\tproperties: {\n\t\t\t\ttype: { type: \"string\", const: \"rg\", description: \"Search for patterns in files using ripgrep.\" },\n\t\t\t\tpattern: { type: \"string\", description: \"The regex pattern to search for.\" },\n\t\t\t\tpath: { type: \"string\", description: \"The path to search in.\" },\n\t\t\t\tinclude: { type: \"array\", items: { type: \"string\" }, description: \"File patterns to include.\" },\n\t\t\t\texclude: { type: \"array\", items: { type: \"string\" }, description: \"File patterns to exclude.\" },\n\t\t\t},\n\t\t\trequired: [\"type\", \"pattern\", \"path\"],\n\t\t},\n\t\t{\n\t\t\tproperties: {\n\t\t\t\ttype: {\n\t\t\t\t\ttype: \"string\",\n\t\t\t\t\tconst: \"readfile\",\n\t\t\t\t\tdescription: \"Read contents of a file with optional line range.\",\n\t\t\t\t},\n\t\t\t\tfile: { type: \"string\", description: \"Path to the file to read.\" },\n\t\t\t\tstart_line: { type: \"integer\", description: \"Starting line number (1-indexed).\" },\n\t\t\t\tend_line: { type: \"integer\", description: \"Ending line number (1-indexed).\" },\n\t\t\t},\n\t\t\trequired: [\"type\", \"file\"],\n\t\t},\n\t\t{\n\t\t\tproperties: {\n\t\t\t\ttype: { type: \"string\", const: \"tree\", description: \"Display directory structure as a tree.\" },\n\t\t\t\tpath: { type: \"string\", description: \"Path to the directory.\" },\n\t\t\t\tlevels: { type: \"integer\", description: \"Number of directory levels.\" },\n\t\t\t},\n\t\t\trequired: [\"type\", \"path\"],\n\t\t},\n\t],\n};\n\n/** The planner's two tools, in the OpenAI function format the backend expects. */\nexport const TOOL_DEFINITIONS = JSON.stringify([\n\t{\n\t\ttype: \"function\",\n\t\tfunction: {\n\t\t\tname: \"restricted_exec\",\n\t\t\tdescription: \"Execute restricted commands (rg, readfile, tree) in parallel.\",\n\t\t\tparameters: {\n\t\t\t\ttype: \"object\",\n\t\t\t\tproperties: Object.fromEntries(\n\t\t\t\t\tArray.from({ length: MAX_COMMANDS }, (_, i) => [`command${i + 1}`, COMMAND_SCHEMA]),\n\t\t\t\t),\n\t\t\t\trequired: [\"command1\"],\n\t\t\t},\n\t\t},\n\t},\n\t{\n\t\ttype: \"function\",\n\t\tfunction: {\n\t\t\tname: \"answer\",\n\t\t\tdescription: \"Final answer with relevant files and line ranges.\",\n\t\t\tparameters: {\n\t\t\t\ttype: \"object\",\n\t\t\t\tproperties: { answer: { type: \"string\", description: \"The final answer in XML format.\" } },\n\t\t\t\trequired: [\"answer\"],\n\t\t\t},\n\t\t},\n\t},\n]);\n"]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rows for code_search and web_search, in the shape of the built-in explore tools: a one-line
|
|
3
|
+
* header that carries progress and the result count, and a body only when expanded (or failed).
|
|
4
|
+
* The model-facing text is untouched; these read `details`.
|
|
5
|
+
*/
|
|
6
|
+
import { type Component } from "@earendil-works/pi-tui";
|
|
7
|
+
import type { AgentToolResult, ToolRenderContext, ToolRenderResultOptions } from "../../core/extensions/types.ts";
|
|
8
|
+
import type { Theme } from "../../modes/interactive/theme/theme.ts";
|
|
9
|
+
import type { CodeLocation } from "./code-search.ts";
|
|
10
|
+
import type { WebResult } from "./devin.ts";
|
|
11
|
+
export interface CodeSearchDetails {
|
|
12
|
+
locations: CodeLocation[];
|
|
13
|
+
}
|
|
14
|
+
export interface WebSearchDetails {
|
|
15
|
+
results: WebResult[];
|
|
16
|
+
}
|
|
17
|
+
export declare function renderCodeSearchCall(args: {
|
|
18
|
+
query?: string;
|
|
19
|
+
path?: string;
|
|
20
|
+
}, theme: Theme, context: ToolRenderContext<unknown, unknown, CodeSearchDetails>): Component;
|
|
21
|
+
export declare function renderCodeSearchResult(result: AgentToolResult<CodeSearchDetails>, options: ToolRenderResultOptions, theme: Theme, context: ToolRenderContext<unknown, {
|
|
22
|
+
path?: string;
|
|
23
|
+
}, CodeSearchDetails>): Component;
|
|
24
|
+
export declare function renderWebSearchCall(args: {
|
|
25
|
+
query?: string;
|
|
26
|
+
}, theme: Theme, context: ToolRenderContext<unknown, unknown, WebSearchDetails>): Component;
|
|
27
|
+
export declare function renderWebSearchResult(result: AgentToolResult<WebSearchDetails>, options: ToolRenderResultOptions, theme: Theme, context: ToolRenderContext<unknown, unknown, WebSearchDetails>): Component;
|
|
28
|
+
//# sourceMappingURL=render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/extensions/search/render.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,KAAK,SAAS,EAA6D,MAAM,wBAAwB,CAAC;AACnH,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAClH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wCAAwC,CAAC;AACpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,MAAM,WAAW,iBAAiB;IACjC,SAAS,EAAE,YAAY,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAChC,OAAO,EAAE,SAAS,EAAE,CAAC;CACrB;AAqDD,wBAAgB,oBAAoB,CACnC,IAAI,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EACvC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,iBAAiB,CAAC,GAC7D,SAAS,CAMX;AAED,wBAAgB,sBAAsB,CACrC,MAAM,EAAE,eAAe,CAAC,iBAAiB,CAAC,EAC1C,OAAO,EAAE,uBAAuB,EAChC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,CAAC,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,iBAAiB,CAAC,GACvE,SAAS,CAiBX;AAED,wBAAgB,mBAAmB,CAClC,IAAI,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,EACxB,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,gBAAgB,CAAC,GAC5D,SAAS,CAKX;AAED,wBAAgB,qBAAqB,CACpC,MAAM,EAAE,eAAe,CAAC,gBAAgB,CAAC,EACzC,OAAO,EAAE,uBAAuB,EAChC,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,gBAAgB,CAAC,GAC5D,SAAS,CAaX"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rows for code_search and web_search, in the shape of the built-in explore tools: a one-line
|
|
3
|
+
* header that carries progress and the result count, and a body only when expanded (or failed).
|
|
4
|
+
* The model-facing text is untouched; these read `details`.
|
|
5
|
+
*/
|
|
6
|
+
import { Container, hyperlink, Text, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
7
|
+
/** Columns beyond which a path or title stops pushing the second column right. */
|
|
8
|
+
const MAX_FIRST_COLUMN = 56;
|
|
9
|
+
function textOf(result) {
|
|
10
|
+
const block = result?.content.find((c) => c.type === "text");
|
|
11
|
+
return block && "text" in block ? block.text.trim() : "";
|
|
12
|
+
}
|
|
13
|
+
function plural(n, word) {
|
|
14
|
+
return `${n} ${word}${n === 1 ? "" : "s"}`;
|
|
15
|
+
}
|
|
16
|
+
/** `● name "query"<scope> · <status>`, where status is live progress, then the result count. */
|
|
17
|
+
function header(theme, name, query, scope, context, summary) {
|
|
18
|
+
let line = `${theme.fg("toolTitle", theme.bold(name))} ${theme.fg("accent", `"${query ?? ""}"`)}`;
|
|
19
|
+
if (scope)
|
|
20
|
+
line += theme.fg("toolOutput", scope);
|
|
21
|
+
const status = !context.result || context.isError ? "" : context.isPartial ? textOf(context.result) : summary();
|
|
22
|
+
if (status)
|
|
23
|
+
line += theme.fg("muted", ` · ${status}`);
|
|
24
|
+
return new Text(line, 0, 0);
|
|
25
|
+
}
|
|
26
|
+
/** Two aligned columns; the first is padded to the widest entry, up to MAX_FIRST_COLUMN. */
|
|
27
|
+
function columns(rows) {
|
|
28
|
+
const width = Math.min(MAX_FIRST_COLUMN, Math.max(...rows.map((r) => visibleWidth(r.first))));
|
|
29
|
+
const lines = rows.map(({ first, second }) => {
|
|
30
|
+
const cell = visibleWidth(first) > width ? truncateToWidth(first, width, "…") : first;
|
|
31
|
+
return `${cell}${" ".repeat(Math.max(0, width - visibleWidth(cell)))} ${second}`;
|
|
32
|
+
});
|
|
33
|
+
return new Text(lines.join("\n"), 0, 0);
|
|
34
|
+
}
|
|
35
|
+
/** Collapsed and still-running rows show nothing below the header; a failure always shows its message. */
|
|
36
|
+
function body(result, options, theme, context, expanded) {
|
|
37
|
+
if (context.isError)
|
|
38
|
+
return new Text(theme.fg("error", textOf(result).split("\n")[0] ?? ""), 0, 0);
|
|
39
|
+
if (!options.expanded || options.isPartial)
|
|
40
|
+
return new Container();
|
|
41
|
+
return expanded();
|
|
42
|
+
}
|
|
43
|
+
export function renderCodeSearchCall(args, theme, context) {
|
|
44
|
+
const scope = args.path && args.path !== "." ? ` in ${args.path.replace(/\\/g, "/")}` : "";
|
|
45
|
+
return header(theme, "code_search", args.query, scope, context, () => {
|
|
46
|
+
const n = context.result?.details?.locations.length ?? 0;
|
|
47
|
+
return n ? plural(n, "file") : "nothing found";
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
export function renderCodeSearchResult(result, options, theme, context) {
|
|
51
|
+
return body(result, options, theme, context, () => {
|
|
52
|
+
const locations = result.details?.locations ?? [];
|
|
53
|
+
if (!locations.length)
|
|
54
|
+
return new Text(theme.fg("muted", "No relevant code found."), 0, 0);
|
|
55
|
+
// Paths are relative to the session directory; show them relative to the searched path.
|
|
56
|
+
const scope = context.args.path?.replace(/\\/g, "/").replace(/^\.\/?|\/+$/g, "");
|
|
57
|
+
return columns(locations.map(({ path, ranges }) => {
|
|
58
|
+
const shown = scope && path.startsWith(`${scope}/`) ? path.slice(scope.length + 1) : path;
|
|
59
|
+
const slash = shown.lastIndexOf("/");
|
|
60
|
+
return {
|
|
61
|
+
first: theme.fg("muted", shown.slice(0, slash + 1)) + theme.fg("toolOutput", shown.slice(slash + 1)),
|
|
62
|
+
second: theme.fg("accent", ranges.map(([s, e]) => (s === e ? `${s}` : `${s}-${e}`)).join(" · ")),
|
|
63
|
+
};
|
|
64
|
+
}));
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
export function renderWebSearchCall(args, theme, context) {
|
|
68
|
+
return header(theme, "web_search", args.query, "", context, () => {
|
|
69
|
+
const n = context.result?.details?.results.length ?? 0;
|
|
70
|
+
return n ? plural(n, "result") : "no results";
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
export function renderWebSearchResult(result, options, theme, context) {
|
|
74
|
+
return body(result, options, theme, context, () => {
|
|
75
|
+
const results = result.details?.results ?? [];
|
|
76
|
+
if (!results.length)
|
|
77
|
+
return new Text(theme.fg("muted", "No results."), 0, 0);
|
|
78
|
+
return columns(results.map(({ url, title }) => {
|
|
79
|
+
const host = new URL(url).hostname.replace(/^www\./, "");
|
|
80
|
+
const label = title ?? url;
|
|
81
|
+
const cell = visibleWidth(label) > MAX_FIRST_COLUMN ? truncateToWidth(label, MAX_FIRST_COLUMN, "…") : label;
|
|
82
|
+
return { first: hyperlink(theme.fg("toolOutput", cell), url), second: theme.fg("muted", host) };
|
|
83
|
+
}));
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../../src/extensions/search/render.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Rows for code_search and web_search, in the shape of the built-in explore tools: a one-line\n * header that carries progress and the result count, and a body only when expanded (or failed).\n * The model-facing text is untouched; these read `details`.\n */\nimport { type Component, Container, hyperlink, Text, truncateToWidth, visibleWidth } from \"@earendil-works/pi-tui\";\nimport type { AgentToolResult, ToolRenderContext, ToolRenderResultOptions } from \"../../core/extensions/types.ts\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport type { CodeLocation } from \"./code-search.ts\";\nimport type { WebResult } from \"./devin.ts\";\n\nexport interface CodeSearchDetails {\n\tlocations: CodeLocation[];\n}\n\nexport interface WebSearchDetails {\n\tresults: WebResult[];\n}\n\n/** Columns beyond which a path or title stops pushing the second column right. */\nconst MAX_FIRST_COLUMN = 56;\n\nfunction textOf(result: AgentToolResult<unknown> | undefined): string {\n\tconst block = result?.content.find((c) => c.type === \"text\");\n\treturn block && \"text\" in block ? block.text.trim() : \"\";\n}\n\nfunction plural(n: number, word: string): string {\n\treturn `${n} ${word}${n === 1 ? \"\" : \"s\"}`;\n}\n\n/** `● name \"query\"<scope> · <status>`, where status is live progress, then the result count. */\nfunction header(\n\ttheme: Theme,\n\tname: string,\n\tquery: string | undefined,\n\tscope: string,\n\tcontext: ToolRenderContext,\n\tsummary: () => string,\n): Component {\n\tlet line = `${theme.fg(\"toolTitle\", theme.bold(name))} ${theme.fg(\"accent\", `\"${query ?? \"\"}\"`)}`;\n\tif (scope) line += theme.fg(\"toolOutput\", scope);\n\tconst status = !context.result || context.isError ? \"\" : context.isPartial ? textOf(context.result) : summary();\n\tif (status) line += theme.fg(\"muted\", ` · ${status}`);\n\treturn new Text(line, 0, 0);\n}\n\n/** Two aligned columns; the first is padded to the widest entry, up to MAX_FIRST_COLUMN. */\nfunction columns(rows: Array<{ first: string; second: string }>): Component {\n\tconst width = Math.min(MAX_FIRST_COLUMN, Math.max(...rows.map((r) => visibleWidth(r.first))));\n\tconst lines = rows.map(({ first, second }) => {\n\t\tconst cell = visibleWidth(first) > width ? truncateToWidth(first, width, \"…\") : first;\n\t\treturn `${cell}${\" \".repeat(Math.max(0, width - visibleWidth(cell)))} ${second}`;\n\t});\n\treturn new Text(lines.join(\"\\n\"), 0, 0);\n}\n\n/** Collapsed and still-running rows show nothing below the header; a failure always shows its message. */\nfunction body(\n\tresult: AgentToolResult<unknown>,\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tcontext: ToolRenderContext,\n\texpanded: () => Component,\n): Component {\n\tif (context.isError) return new Text(theme.fg(\"error\", textOf(result).split(\"\\n\")[0] ?? \"\"), 0, 0);\n\tif (!options.expanded || options.isPartial) return new Container();\n\treturn expanded();\n}\n\nexport function renderCodeSearchCall(\n\targs: { query?: string; path?: string },\n\ttheme: Theme,\n\tcontext: ToolRenderContext<unknown, unknown, CodeSearchDetails>,\n): Component {\n\tconst scope = args.path && args.path !== \".\" ? ` in ${args.path.replace(/\\\\/g, \"/\")}` : \"\";\n\treturn header(theme, \"code_search\", args.query, scope, context, () => {\n\t\tconst n = context.result?.details?.locations.length ?? 0;\n\t\treturn n ? plural(n, \"file\") : \"nothing found\";\n\t});\n}\n\nexport function renderCodeSearchResult(\n\tresult: AgentToolResult<CodeSearchDetails>,\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tcontext: ToolRenderContext<unknown, { path?: string }, CodeSearchDetails>,\n): Component {\n\treturn body(result, options, theme, context, () => {\n\t\tconst locations = result.details?.locations ?? [];\n\t\tif (!locations.length) return new Text(theme.fg(\"muted\", \"No relevant code found.\"), 0, 0);\n\t\t// Paths are relative to the session directory; show them relative to the searched path.\n\t\tconst scope = context.args.path?.replace(/\\\\/g, \"/\").replace(/^\\.\\/?|\\/+$/g, \"\");\n\t\treturn columns(\n\t\t\tlocations.map(({ path, ranges }) => {\n\t\t\t\tconst shown = scope && path.startsWith(`${scope}/`) ? path.slice(scope.length + 1) : path;\n\t\t\t\tconst slash = shown.lastIndexOf(\"/\");\n\t\t\t\treturn {\n\t\t\t\t\tfirst: theme.fg(\"muted\", shown.slice(0, slash + 1)) + theme.fg(\"toolOutput\", shown.slice(slash + 1)),\n\t\t\t\t\tsecond: theme.fg(\"accent\", ranges.map(([s, e]) => (s === e ? `${s}` : `${s}-${e}`)).join(\" · \")),\n\t\t\t\t};\n\t\t\t}),\n\t\t);\n\t});\n}\n\nexport function renderWebSearchCall(\n\targs: { query?: string },\n\ttheme: Theme,\n\tcontext: ToolRenderContext<unknown, unknown, WebSearchDetails>,\n): Component {\n\treturn header(theme, \"web_search\", args.query, \"\", context, () => {\n\t\tconst n = context.result?.details?.results.length ?? 0;\n\t\treturn n ? plural(n, \"result\") : \"no results\";\n\t});\n}\n\nexport function renderWebSearchResult(\n\tresult: AgentToolResult<WebSearchDetails>,\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tcontext: ToolRenderContext<unknown, unknown, WebSearchDetails>,\n): Component {\n\treturn body(result, options, theme, context, () => {\n\t\tconst results = result.details?.results ?? [];\n\t\tif (!results.length) return new Text(theme.fg(\"muted\", \"No results.\"), 0, 0);\n\t\treturn columns(\n\t\t\tresults.map(({ url, title }) => {\n\t\t\t\tconst host = new URL(url).hostname.replace(/^www\\./, \"\");\n\t\t\t\tconst label = title ?? url;\n\t\t\t\tconst cell = visibleWidth(label) > MAX_FIRST_COLUMN ? truncateToWidth(label, MAX_FIRST_COLUMN, \"…\") : label;\n\t\t\t\treturn { first: hyperlink(theme.fg(\"toolOutput\", cell), url), second: theme.fg(\"muted\", host) };\n\t\t\t}),\n\t\t);\n\t});\n}\n"]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export declare const VIRTUAL_ROOT = "/codebase";
|
|
2
|
+
/** `rg` backend: pattern, directory or file, optional glob → `path:line: text` lines. */
|
|
3
|
+
export type Grep = (pattern: string, path: string, glob: string | undefined, signal?: AbortSignal) => Promise<string>;
|
|
4
|
+
/** Pi's own grep tool: gitignore-aware, with its bundled ripgrep. It takes one glob, so only the first include applies. */
|
|
5
|
+
export declare function piGrep(root: string): Grep;
|
|
6
|
+
/** Whether `path` lies inside `root`, both as written and after following symlinks. */
|
|
7
|
+
export declare function isInside(root: string, path: string): boolean;
|
|
8
|
+
export interface Command {
|
|
9
|
+
type?: unknown;
|
|
10
|
+
pattern?: unknown;
|
|
11
|
+
path?: unknown;
|
|
12
|
+
include?: unknown;
|
|
13
|
+
file?: unknown;
|
|
14
|
+
start_line?: unknown;
|
|
15
|
+
end_line?: unknown;
|
|
16
|
+
levels?: unknown;
|
|
17
|
+
}
|
|
18
|
+
export declare class Workspace {
|
|
19
|
+
readonly root: string;
|
|
20
|
+
private readonly grep;
|
|
21
|
+
private readonly noise;
|
|
22
|
+
constructor(root: string, grep?: Grep);
|
|
23
|
+
contains(path: string): boolean;
|
|
24
|
+
/** `/codebase/src/a.ts` or `src/a.ts` → an absolute path inside the root, or null. */
|
|
25
|
+
toReal(virtual: unknown): string | null;
|
|
26
|
+
toVirtual(real: string): string;
|
|
27
|
+
/** The deepest tree of the root, up to three levels, that fits the map budget. */
|
|
28
|
+
repoMap(): {
|
|
29
|
+
depth: number;
|
|
30
|
+
tree: string;
|
|
31
|
+
};
|
|
32
|
+
run(command: Command, signal?: AbortSignal): Promise<string>;
|
|
33
|
+
private rg;
|
|
34
|
+
private readfile;
|
|
35
|
+
private tree;
|
|
36
|
+
private renderTree;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=workspace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../../src/extensions/search/workspace.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,YAAY,cAAc,CAAC;AA6BxC,yFAAyF;AACzF,MAAM,MAAM,IAAI,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAEtH,2HAA2H;AAC3H,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAWzC;AAwBD,uFAAuF;AACvF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAG5D;AAWD,MAAM,WAAW,OAAO;IACvB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,qBAAa,SAAS;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAO;IAC5B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAc;gBAExB,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,IAAmB;IAMnD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI/B,sFAAsF;IACtF,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI;IAgBvC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAK/B,kFAAkF;IAClF,OAAO,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE;IAQpC,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;YAapD,EAAE;IA2BhB,OAAO,CAAC,QAAQ;IAqBhB,OAAO,CAAC,IAAI;IAYZ,OAAO,CAAC,UAAU;CA0BlB"}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The local side of code_search: the planner runs remotely and names commands against a virtual
|
|
3
|
+
* `/codebase`; this module executes them read-only, confined to one directory.
|
|
4
|
+
*
|
|
5
|
+
* Security boundary: every model-supplied path must resolve inside the root, both lexically and
|
|
6
|
+
* after following symlinks. Only `rg`, `readfile`, and `tree` exist; there is no shell and no write.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync, readdirSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
9
|
+
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
10
|
+
import { createGrepToolDefinition } from "../../core/tools/grep.js";
|
|
11
|
+
export const VIRTUAL_ROOT = "/codebase";
|
|
12
|
+
/** Per-command result cap. Results are sent back to Devin, whose request limit is ~320KB. */
|
|
13
|
+
const RESULT_MAX_LINES = 40;
|
|
14
|
+
const LINE_MAX_CHARS = 200;
|
|
15
|
+
/** The repo map's share of that limit; deeper trees fall back to shallower ones until they fit. */
|
|
16
|
+
const MAP_MAX_BYTES = 64 * 1024;
|
|
17
|
+
const MAP_MAX_DEPTH = 3;
|
|
18
|
+
const NOISE_DIRS = [
|
|
19
|
+
".git",
|
|
20
|
+
"node_modules",
|
|
21
|
+
"dist",
|
|
22
|
+
"build",
|
|
23
|
+
"out",
|
|
24
|
+
"target",
|
|
25
|
+
"coverage",
|
|
26
|
+
".venv",
|
|
27
|
+
"venv",
|
|
28
|
+
"__pycache__",
|
|
29
|
+
".cache",
|
|
30
|
+
".next",
|
|
31
|
+
".nuxt",
|
|
32
|
+
".turbo",
|
|
33
|
+
".idea",
|
|
34
|
+
"vendor",
|
|
35
|
+
"third_party",
|
|
36
|
+
];
|
|
37
|
+
/** Pi's own grep tool: gitignore-aware, with its bundled ripgrep. It takes one glob, so only the first include applies. */
|
|
38
|
+
export function piGrep(root) {
|
|
39
|
+
const tool = createGrepToolDefinition(root);
|
|
40
|
+
const execute = tool.execute;
|
|
41
|
+
return async (pattern, path, glob, signal) => {
|
|
42
|
+
const result = await execute("code_search", { pattern, path, glob, limit: RESULT_MAX_LINES }, signal);
|
|
43
|
+
return result.content?.find((c) => c.type === "text")?.text ?? "";
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function within(base, path) {
|
|
47
|
+
const rel = relative(base, path);
|
|
48
|
+
return rel === "" || (!rel.startsWith(`..${sep}`) && rel !== ".." && !isAbsolute(rel));
|
|
49
|
+
}
|
|
50
|
+
/** realpath of the longest existing prefix, so a not-yet-existing path still resolves through symlinks. */
|
|
51
|
+
function realpathOf(path) {
|
|
52
|
+
let current = resolve(path);
|
|
53
|
+
const tail = [];
|
|
54
|
+
while (!existsSync(current)) {
|
|
55
|
+
const parent = dirname(current);
|
|
56
|
+
if (parent === current)
|
|
57
|
+
return resolve(path);
|
|
58
|
+
tail.unshift(basename(current));
|
|
59
|
+
current = parent;
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
return resolve(realpathSync(current), ...tail);
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return resolve(path);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/** Whether `path` lies inside `root`, both as written and after following symlinks. */
|
|
69
|
+
export function isInside(root, path) {
|
|
70
|
+
const abs = resolve(path);
|
|
71
|
+
return within(resolve(root), abs) && within(realpathOf(root), realpathOf(abs));
|
|
72
|
+
}
|
|
73
|
+
function capLines(text) {
|
|
74
|
+
const lines = text.split("\n");
|
|
75
|
+
const kept = lines
|
|
76
|
+
.slice(0, RESULT_MAX_LINES)
|
|
77
|
+
.map((l) => (l.length > LINE_MAX_CHARS ? l.slice(0, LINE_MAX_CHARS) : l));
|
|
78
|
+
if (lines.length > RESULT_MAX_LINES)
|
|
79
|
+
kept.push(`... (${lines.length - RESULT_MAX_LINES} more lines)`);
|
|
80
|
+
return kept.join("\n");
|
|
81
|
+
}
|
|
82
|
+
export class Workspace {
|
|
83
|
+
constructor(root, grep = piGrep(root)) {
|
|
84
|
+
this.root = resolve(root);
|
|
85
|
+
this.grep = grep;
|
|
86
|
+
this.noise = new Set([...NOISE_DIRS, ...gitignoredNames(this.root)]);
|
|
87
|
+
}
|
|
88
|
+
contains(path) {
|
|
89
|
+
return isInside(this.root, path);
|
|
90
|
+
}
|
|
91
|
+
/** `/codebase/src/a.ts` or `src/a.ts` → an absolute path inside the root, or null. */
|
|
92
|
+
toReal(virtual) {
|
|
93
|
+
if (typeof virtual !== "string" || !virtual)
|
|
94
|
+
return null;
|
|
95
|
+
const normalized = virtual.replace(/\\/g, "/");
|
|
96
|
+
let rel;
|
|
97
|
+
if (normalized === VIRTUAL_ROOT || normalized.startsWith(`${VIRTUAL_ROOT}/`)) {
|
|
98
|
+
rel = normalized.slice(VIRTUAL_ROOT.length);
|
|
99
|
+
}
|
|
100
|
+
else if (isAbsolute(virtual) || normalized.startsWith("/") || /^[a-zA-Z]:/.test(normalized)) {
|
|
101
|
+
// A drive-letter path is another drive on Windows and a stray filename elsewhere; refuse it everywhere.
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
rel = normalized;
|
|
106
|
+
}
|
|
107
|
+
const candidate = resolve(this.root, rel.replace(/^\/+/, ""));
|
|
108
|
+
return this.contains(candidate) ? candidate : null;
|
|
109
|
+
}
|
|
110
|
+
toVirtual(real) {
|
|
111
|
+
const rel = relative(this.root, real).split(sep).join("/");
|
|
112
|
+
return rel ? `${VIRTUAL_ROOT}/${rel}` : VIRTUAL_ROOT;
|
|
113
|
+
}
|
|
114
|
+
/** The deepest tree of the root, up to three levels, that fits the map budget. */
|
|
115
|
+
repoMap() {
|
|
116
|
+
for (let depth = MAP_MAX_DEPTH; depth > 1; depth--) {
|
|
117
|
+
const tree = this.renderTree(this.root, depth);
|
|
118
|
+
if (Buffer.byteLength(tree) <= MAP_MAX_BYTES)
|
|
119
|
+
return { depth, tree };
|
|
120
|
+
}
|
|
121
|
+
return { depth: 1, tree: this.renderTree(this.root, 1).slice(0, MAP_MAX_BYTES / 4) };
|
|
122
|
+
}
|
|
123
|
+
async run(command, signal) {
|
|
124
|
+
switch (command?.type) {
|
|
125
|
+
case "rg":
|
|
126
|
+
return this.rg(command, signal);
|
|
127
|
+
case "readfile":
|
|
128
|
+
return this.readfile(command);
|
|
129
|
+
case "tree":
|
|
130
|
+
return this.tree(command);
|
|
131
|
+
default:
|
|
132
|
+
return `Error: unknown command type '${String(command?.type)}'; use rg, readfile, or tree`;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
async rg(command, signal) {
|
|
136
|
+
if (typeof command.pattern !== "string" || !command.pattern)
|
|
137
|
+
return "Error: missing pattern";
|
|
138
|
+
const real = this.toReal(command.path ?? VIRTUAL_ROOT);
|
|
139
|
+
if (!real)
|
|
140
|
+
return `Error: path outside project root: ${String(command.path)}`;
|
|
141
|
+
if (!existsSync(real))
|
|
142
|
+
return `Error: path does not exist: ${String(command.path)}`;
|
|
143
|
+
const include = Array.isArray(command.include) && typeof command.include[0] === "string" ? command.include[0] : undefined;
|
|
144
|
+
let raw;
|
|
145
|
+
try {
|
|
146
|
+
raw = await this.grep(command.pattern, real, include, signal);
|
|
147
|
+
}
|
|
148
|
+
catch (e) {
|
|
149
|
+
return `Error: ${e instanceof Error ? e.message : String(e)}`;
|
|
150
|
+
}
|
|
151
|
+
// Pi's grep prints paths relative to the searched directory, or the bare file name for a file.
|
|
152
|
+
const isFile = statSync(real).isFile();
|
|
153
|
+
const base = this.toVirtual(real);
|
|
154
|
+
const remapped = raw
|
|
155
|
+
.split("\n")
|
|
156
|
+
.map((line) => {
|
|
157
|
+
const m = line.match(/^(.+?):(\d+):(.*)$/);
|
|
158
|
+
if (!m)
|
|
159
|
+
return line;
|
|
160
|
+
return `${isFile ? base : `${base}/${m[1].replace(/\\/g, "/")}`}:${m[2]}:${m[3]}`;
|
|
161
|
+
})
|
|
162
|
+
.join("\n");
|
|
163
|
+
return capLines(remapped.trim() || "(no matches)");
|
|
164
|
+
}
|
|
165
|
+
readfile(command) {
|
|
166
|
+
const real = this.toReal(command.file);
|
|
167
|
+
if (!real)
|
|
168
|
+
return `Error: path outside project root: ${String(command.file)}`;
|
|
169
|
+
let content;
|
|
170
|
+
try {
|
|
171
|
+
if (!statSync(real).isFile())
|
|
172
|
+
return `Error: not a file: ${String(command.file)}`;
|
|
173
|
+
content = readFileSync(real, "utf-8");
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
return `Error: file not found: ${String(command.file)}`;
|
|
177
|
+
}
|
|
178
|
+
const lines = content.split("\n");
|
|
179
|
+
const start = Math.max(1, Number(command.start_line) || 1);
|
|
180
|
+
const end = Math.min(lines.length, Number(command.end_line) || lines.length);
|
|
181
|
+
return capLines(lines
|
|
182
|
+
.slice(start - 1, end)
|
|
183
|
+
.map((line, i) => `${start + i}:${line}`)
|
|
184
|
+
.join("\n"));
|
|
185
|
+
}
|
|
186
|
+
tree(command) {
|
|
187
|
+
const real = this.toReal(command.path ?? VIRTUAL_ROOT);
|
|
188
|
+
if (!real)
|
|
189
|
+
return `Error: path outside project root: ${String(command.path)}`;
|
|
190
|
+
try {
|
|
191
|
+
if (!statSync(real).isDirectory())
|
|
192
|
+
return `Error: not a directory: ${String(command.path)}`;
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
return `Error: directory not found: ${String(command.path)}`;
|
|
196
|
+
}
|
|
197
|
+
const levels = Math.min(Math.max(Number(command.levels) || 2, 1), 4);
|
|
198
|
+
return capLines(this.renderTree(real, levels));
|
|
199
|
+
}
|
|
200
|
+
renderTree(dir, maxDepth) {
|
|
201
|
+
const lines = [this.toVirtual(dir)];
|
|
202
|
+
const walk = (current, depth, prefix) => {
|
|
203
|
+
if (depth >= maxDepth)
|
|
204
|
+
return;
|
|
205
|
+
let entries;
|
|
206
|
+
try {
|
|
207
|
+
entries = readdirSync(current)
|
|
208
|
+
.filter((name) => !this.noise.has(name))
|
|
209
|
+
.sort();
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
entries.forEach((name, i) => {
|
|
215
|
+
const last = i === entries.length - 1;
|
|
216
|
+
lines.push(`${prefix}${last ? "└── " : "├── "}${name}`);
|
|
217
|
+
const path = join(current, name);
|
|
218
|
+
let isDir = false;
|
|
219
|
+
try {
|
|
220
|
+
isDir = statSync(path).isDirectory() && this.contains(path);
|
|
221
|
+
}
|
|
222
|
+
catch { }
|
|
223
|
+
if (isDir)
|
|
224
|
+
walk(path, depth + 1, `${prefix}${last ? " " : "│ "}`);
|
|
225
|
+
});
|
|
226
|
+
};
|
|
227
|
+
walk(dir, 0, "");
|
|
228
|
+
return lines.join("\n");
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
/** Plain directory names from `.gitignore`; patterns with slashes or globs are left to grep. */
|
|
232
|
+
function gitignoredNames(root) {
|
|
233
|
+
let text;
|
|
234
|
+
try {
|
|
235
|
+
text = readFileSync(join(root, ".gitignore"), "utf-8");
|
|
236
|
+
}
|
|
237
|
+
catch {
|
|
238
|
+
return [];
|
|
239
|
+
}
|
|
240
|
+
return text
|
|
241
|
+
.split("\n")
|
|
242
|
+
.map((line) => line.trim().replace(/^\/+|\/+$/g, ""))
|
|
243
|
+
.filter((name) => name && !name.startsWith("#") && !name.startsWith("!") && !/[/*?[\]]/.test(name));
|
|
244
|
+
}
|
|
245
|
+
//# sourceMappingURL=workspace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../../src/extensions/search/workspace.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The local side of code_search: the planner runs remotely and names commands against a virtual\n * `/codebase`; this module executes them read-only, confined to one directory.\n *\n * Security boundary: every model-supplied path must resolve inside the root, both lexically and\n * after following symlinks. Only `rg`, `readfile`, and `tree` exist; there is no shell and no write.\n */\nimport { existsSync, readdirSync, readFileSync, realpathSync, statSync } from \"node:fs\";\nimport { basename, dirname, isAbsolute, join, relative, resolve, sep } from \"node:path\";\nimport { createGrepToolDefinition } from \"../../core/tools/grep.ts\";\n\nexport const VIRTUAL_ROOT = \"/codebase\";\n\n/** Per-command result cap. Results are sent back to Devin, whose request limit is ~320KB. */\nconst RESULT_MAX_LINES = 40;\nconst LINE_MAX_CHARS = 200;\n/** The repo map's share of that limit; deeper trees fall back to shallower ones until they fit. */\nconst MAP_MAX_BYTES = 64 * 1024;\nconst MAP_MAX_DEPTH = 3;\n\nconst NOISE_DIRS = [\n\t\".git\",\n\t\"node_modules\",\n\t\"dist\",\n\t\"build\",\n\t\"out\",\n\t\"target\",\n\t\"coverage\",\n\t\".venv\",\n\t\"venv\",\n\t\"__pycache__\",\n\t\".cache\",\n\t\".next\",\n\t\".nuxt\",\n\t\".turbo\",\n\t\".idea\",\n\t\"vendor\",\n\t\"third_party\",\n];\n\n/** `rg` backend: pattern, directory or file, optional glob → `path:line: text` lines. */\nexport type Grep = (pattern: string, path: string, glob: string | undefined, signal?: AbortSignal) => Promise<string>;\n\n/** Pi's own grep tool: gitignore-aware, with its bundled ripgrep. It takes one glob, so only the first include applies. */\nexport function piGrep(root: string): Grep {\n\tconst tool = createGrepToolDefinition(root);\n\tconst execute = tool.execute as unknown as (\n\t\tid: string,\n\t\tparams: { pattern: string; path: string; glob?: string; limit: number },\n\t\tsignal?: AbortSignal,\n\t) => Promise<{ content?: Array<{ type?: string; text?: string }> }>;\n\treturn async (pattern, path, glob, signal) => {\n\t\tconst result = await execute(\"code_search\", { pattern, path, glob, limit: RESULT_MAX_LINES }, signal);\n\t\treturn result.content?.find((c) => c.type === \"text\")?.text ?? \"\";\n\t};\n}\n\nfunction within(base: string, path: string): boolean {\n\tconst rel = relative(base, path);\n\treturn rel === \"\" || (!rel.startsWith(`..${sep}`) && rel !== \"..\" && !isAbsolute(rel));\n}\n\n/** realpath of the longest existing prefix, so a not-yet-existing path still resolves through symlinks. */\nfunction realpathOf(path: string): string {\n\tlet current = resolve(path);\n\tconst tail: string[] = [];\n\twhile (!existsSync(current)) {\n\t\tconst parent = dirname(current);\n\t\tif (parent === current) return resolve(path);\n\t\ttail.unshift(basename(current));\n\t\tcurrent = parent;\n\t}\n\ttry {\n\t\treturn resolve(realpathSync(current), ...tail);\n\t} catch {\n\t\treturn resolve(path);\n\t}\n}\n\n/** Whether `path` lies inside `root`, both as written and after following symlinks. */\nexport function isInside(root: string, path: string): boolean {\n\tconst abs = resolve(path);\n\treturn within(resolve(root), abs) && within(realpathOf(root), realpathOf(abs));\n}\n\nfunction capLines(text: string): string {\n\tconst lines = text.split(\"\\n\");\n\tconst kept = lines\n\t\t.slice(0, RESULT_MAX_LINES)\n\t\t.map((l) => (l.length > LINE_MAX_CHARS ? l.slice(0, LINE_MAX_CHARS) : l));\n\tif (lines.length > RESULT_MAX_LINES) kept.push(`... (${lines.length - RESULT_MAX_LINES} more lines)`);\n\treturn kept.join(\"\\n\");\n}\n\nexport interface Command {\n\ttype?: unknown;\n\tpattern?: unknown;\n\tpath?: unknown;\n\tinclude?: unknown;\n\tfile?: unknown;\n\tstart_line?: unknown;\n\tend_line?: unknown;\n\tlevels?: unknown;\n}\n\nexport class Workspace {\n\treadonly root: string;\n\tprivate readonly grep: Grep;\n\tprivate readonly noise: Set<string>;\n\n\tconstructor(root: string, grep: Grep = piGrep(root)) {\n\t\tthis.root = resolve(root);\n\t\tthis.grep = grep;\n\t\tthis.noise = new Set([...NOISE_DIRS, ...gitignoredNames(this.root)]);\n\t}\n\n\tcontains(path: string): boolean {\n\t\treturn isInside(this.root, path);\n\t}\n\n\t/** `/codebase/src/a.ts` or `src/a.ts` → an absolute path inside the root, or null. */\n\ttoReal(virtual: unknown): string | null {\n\t\tif (typeof virtual !== \"string\" || !virtual) return null;\n\t\tconst normalized = virtual.replace(/\\\\/g, \"/\");\n\t\tlet rel: string;\n\t\tif (normalized === VIRTUAL_ROOT || normalized.startsWith(`${VIRTUAL_ROOT}/`)) {\n\t\t\trel = normalized.slice(VIRTUAL_ROOT.length);\n\t\t} else if (isAbsolute(virtual) || normalized.startsWith(\"/\") || /^[a-zA-Z]:/.test(normalized)) {\n\t\t\t// A drive-letter path is another drive on Windows and a stray filename elsewhere; refuse it everywhere.\n\t\t\treturn null;\n\t\t} else {\n\t\t\trel = normalized;\n\t\t}\n\t\tconst candidate = resolve(this.root, rel.replace(/^\\/+/, \"\"));\n\t\treturn this.contains(candidate) ? candidate : null;\n\t}\n\n\ttoVirtual(real: string): string {\n\t\tconst rel = relative(this.root, real).split(sep).join(\"/\");\n\t\treturn rel ? `${VIRTUAL_ROOT}/${rel}` : VIRTUAL_ROOT;\n\t}\n\n\t/** The deepest tree of the root, up to three levels, that fits the map budget. */\n\trepoMap(): { depth: number; tree: string } {\n\t\tfor (let depth = MAP_MAX_DEPTH; depth > 1; depth--) {\n\t\t\tconst tree = this.renderTree(this.root, depth);\n\t\t\tif (Buffer.byteLength(tree) <= MAP_MAX_BYTES) return { depth, tree };\n\t\t}\n\t\treturn { depth: 1, tree: this.renderTree(this.root, 1).slice(0, MAP_MAX_BYTES / 4) };\n\t}\n\n\tasync run(command: Command, signal?: AbortSignal): Promise<string> {\n\t\tswitch (command?.type) {\n\t\t\tcase \"rg\":\n\t\t\t\treturn this.rg(command, signal);\n\t\t\tcase \"readfile\":\n\t\t\t\treturn this.readfile(command);\n\t\t\tcase \"tree\":\n\t\t\t\treturn this.tree(command);\n\t\t\tdefault:\n\t\t\t\treturn `Error: unknown command type '${String(command?.type)}'; use rg, readfile, or tree`;\n\t\t}\n\t}\n\n\tprivate async rg(command: Command, signal?: AbortSignal): Promise<string> {\n\t\tif (typeof command.pattern !== \"string\" || !command.pattern) return \"Error: missing pattern\";\n\t\tconst real = this.toReal(command.path ?? VIRTUAL_ROOT);\n\t\tif (!real) return `Error: path outside project root: ${String(command.path)}`;\n\t\tif (!existsSync(real)) return `Error: path does not exist: ${String(command.path)}`;\n\t\tconst include =\n\t\t\tArray.isArray(command.include) && typeof command.include[0] === \"string\" ? command.include[0] : undefined;\n\t\tlet raw: string;\n\t\ttry {\n\t\t\traw = await this.grep(command.pattern, real, include, signal);\n\t\t} catch (e) {\n\t\t\treturn `Error: ${e instanceof Error ? e.message : String(e)}`;\n\t\t}\n\t\t// Pi's grep prints paths relative to the searched directory, or the bare file name for a file.\n\t\tconst isFile = statSync(real).isFile();\n\t\tconst base = this.toVirtual(real);\n\t\tconst remapped = raw\n\t\t\t.split(\"\\n\")\n\t\t\t.map((line) => {\n\t\t\t\tconst m = line.match(/^(.+?):(\\d+):(.*)$/);\n\t\t\t\tif (!m) return line;\n\t\t\t\treturn `${isFile ? base : `${base}/${m[1]!.replace(/\\\\/g, \"/\")}`}:${m[2]}:${m[3]}`;\n\t\t\t})\n\t\t\t.join(\"\\n\");\n\t\treturn capLines(remapped.trim() || \"(no matches)\");\n\t}\n\n\tprivate readfile(command: Command): string {\n\t\tconst real = this.toReal(command.file);\n\t\tif (!real) return `Error: path outside project root: ${String(command.file)}`;\n\t\tlet content: string;\n\t\ttry {\n\t\t\tif (!statSync(real).isFile()) return `Error: not a file: ${String(command.file)}`;\n\t\t\tcontent = readFileSync(real, \"utf-8\");\n\t\t} catch {\n\t\t\treturn `Error: file not found: ${String(command.file)}`;\n\t\t}\n\t\tconst lines = content.split(\"\\n\");\n\t\tconst start = Math.max(1, Number(command.start_line) || 1);\n\t\tconst end = Math.min(lines.length, Number(command.end_line) || lines.length);\n\t\treturn capLines(\n\t\t\tlines\n\t\t\t\t.slice(start - 1, end)\n\t\t\t\t.map((line, i) => `${start + i}:${line}`)\n\t\t\t\t.join(\"\\n\"),\n\t\t);\n\t}\n\n\tprivate tree(command: Command): string {\n\t\tconst real = this.toReal(command.path ?? VIRTUAL_ROOT);\n\t\tif (!real) return `Error: path outside project root: ${String(command.path)}`;\n\t\ttry {\n\t\t\tif (!statSync(real).isDirectory()) return `Error: not a directory: ${String(command.path)}`;\n\t\t} catch {\n\t\t\treturn `Error: directory not found: ${String(command.path)}`;\n\t\t}\n\t\tconst levels = Math.min(Math.max(Number(command.levels) || 2, 1), 4);\n\t\treturn capLines(this.renderTree(real, levels));\n\t}\n\n\tprivate renderTree(dir: string, maxDepth: number): string {\n\t\tconst lines = [this.toVirtual(dir)];\n\t\tconst walk = (current: string, depth: number, prefix: string): void => {\n\t\t\tif (depth >= maxDepth) return;\n\t\t\tlet entries: string[];\n\t\t\ttry {\n\t\t\t\tentries = readdirSync(current)\n\t\t\t\t\t.filter((name) => !this.noise.has(name))\n\t\t\t\t\t.sort();\n\t\t\t} catch {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tentries.forEach((name, i) => {\n\t\t\t\tconst last = i === entries.length - 1;\n\t\t\t\tlines.push(`${prefix}${last ? \"└── \" : \"├── \"}${name}`);\n\t\t\t\tconst path = join(current, name);\n\t\t\t\tlet isDir = false;\n\t\t\t\ttry {\n\t\t\t\t\tisDir = statSync(path).isDirectory() && this.contains(path);\n\t\t\t\t} catch {}\n\t\t\t\tif (isDir) walk(path, depth + 1, `${prefix}${last ? \" \" : \"│ \"}`);\n\t\t\t});\n\t\t};\n\t\twalk(dir, 0, \"\");\n\t\treturn lines.join(\"\\n\");\n\t}\n}\n\n/** Plain directory names from `.gitignore`; patterns with slashes or globs are left to grep. */\nfunction gitignoredNames(root: string): string[] {\n\tlet text: string;\n\ttry {\n\t\ttext = readFileSync(join(root, \".gitignore\"), \"utf-8\");\n\t} catch {\n\t\treturn [];\n\t}\n\treturn text\n\t\t.split(\"\\n\")\n\t\t.map((line) => line.trim().replace(/^\\/+|\\/+$/g, \"\"))\n\t\t.filter((name) => name && !name.startsWith(\"#\") && !name.startsWith(\"!\") && !/[/*?[\\]]/.test(name));\n}\n"]}
|
|
@@ -13,11 +13,15 @@ export declare class BashExecutionComponent extends Container {
|
|
|
13
13
|
private fullOutputPath?;
|
|
14
14
|
private expanded;
|
|
15
15
|
private contentContainer;
|
|
16
|
-
|
|
16
|
+
/** `dim` marks `!!` commands, whose output is excluded from the model context. */
|
|
17
|
+
private readonly colorKey;
|
|
18
|
+
private outputPad;
|
|
19
|
+
constructor(command: string, ui: TUI, excludeFromContext?: boolean, outputPad?: number);
|
|
17
20
|
/**
|
|
18
21
|
* Set whether the output is expanded (shows full output) or collapsed (preview only).
|
|
19
22
|
*/
|
|
20
23
|
setExpanded(expanded: boolean): void;
|
|
24
|
+
setOutputPad(outputPad: number): void;
|
|
21
25
|
invalidate(): void;
|
|
22
26
|
appendOutput(chunk: string): void;
|
|
23
27
|
setComplete(exitCode: number | undefined, cancelled: boolean, truncationResult?: TruncationResult, fullOutputPath?: string): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bash-execution.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/bash-execution.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAwB,KAAK,GAAG,EAAE,MAAM,wBAAwB,CAAC;AACnF,OAAO,EAGN,KAAK,gBAAgB,EAErB,MAAM,iCAAiC,CAAC;AAUzC,qBAAa,sBAAuB,SAAQ,SAAS;IACpD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,MAAM,CAA6D;IAC3E,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,gBAAgB,CAAC,CAAmB;IAC5C,OAAO,CAAC,cAAc,CAAC,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,gBAAgB,CAAY;
|
|
1
|
+
{"version":3,"file":"bash-execution.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/bash-execution.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAwB,KAAK,GAAG,EAAE,MAAM,wBAAwB,CAAC;AACnF,OAAO,EAGN,KAAK,gBAAgB,EAErB,MAAM,iCAAiC,CAAC;AAUzC,qBAAa,sBAAuB,SAAQ,SAAS;IACpD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,MAAM,CAA6D;IAC3E,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,gBAAgB,CAAC,CAAmB;IAC5C,OAAO,CAAC,cAAc,CAAC,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,gBAAgB,CAAY;IACpC,kFAAkF;IAClF,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;IAC9C,OAAO,CAAC,SAAS,CAAS;gBAEd,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,kBAAkB,UAAQ,EAAE,SAAS,SAAI;IA8B/E;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;IAKpC,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAK5B,UAAU,IAAI,IAAI;IAK3B,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAkBjC,WAAW,CACV,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,SAAS,EAAE,OAAO,EAClB,gBAAgB,CAAC,EAAE,gBAAgB,EACnC,cAAc,CAAC,EAAE,MAAM,GACrB,IAAI;IAgBP,OAAO,CAAC,aAAa;IAwFrB;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,UAAU,IAAI,MAAM;CAGpB"}
|
|
@@ -11,16 +11,16 @@ import { truncateToVisualLines } from "./visual-truncate.js";
|
|
|
11
11
|
// Preview line limit when not expanded (matches tool execution behavior)
|
|
12
12
|
const PREVIEW_LINES = 20;
|
|
13
13
|
export class BashExecutionComponent extends Container {
|
|
14
|
-
constructor(command, ui, excludeFromContext = false) {
|
|
14
|
+
constructor(command, ui, excludeFromContext = false, outputPad = 1) {
|
|
15
15
|
super();
|
|
16
16
|
this.outputLines = [];
|
|
17
17
|
this.status = "running";
|
|
18
18
|
this.exitCode = undefined;
|
|
19
19
|
this.expanded = false;
|
|
20
20
|
this.command = command;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const borderColor = (str) => theme.fg(colorKey, str);
|
|
21
|
+
this.colorKey = excludeFromContext ? "dim" : "bashMode";
|
|
22
|
+
this.outputPad = outputPad;
|
|
23
|
+
const borderColor = (str) => theme.fg(this.colorKey, str);
|
|
24
24
|
// Add spacer
|
|
25
25
|
this.addChild(new Spacer(1));
|
|
26
26
|
// Top border
|
|
@@ -28,14 +28,10 @@ export class BashExecutionComponent extends Container {
|
|
|
28
28
|
// Content container (holds dynamic content between borders)
|
|
29
29
|
this.contentContainer = new Container();
|
|
30
30
|
this.addChild(this.contentContainer);
|
|
31
|
-
|
|
32
|
-
const header = new Text(theme.fg(colorKey, theme.bold(`$ ${command}`)), 1, 0);
|
|
33
|
-
this.contentContainer.addChild(header);
|
|
34
|
-
// Loader
|
|
35
|
-
this.loader = new Loader(ui, (spinner) => theme.fg(colorKey, spinner), (text) => theme.fg("muted", text), `Running... (${keyText("tui.select.cancel")} to cancel)`);
|
|
36
|
-
this.contentContainer.addChild(this.loader);
|
|
31
|
+
this.loader = new Loader(ui, (spinner) => theme.fg(this.colorKey, spinner), (text) => theme.fg("muted", text), `Running... (${keyText("tui.select.cancel")} to cancel)`);
|
|
37
32
|
// Bottom border
|
|
38
33
|
this.addChild(new DynamicBorder(borderColor));
|
|
34
|
+
this.updateDisplay();
|
|
39
35
|
}
|
|
40
36
|
/**
|
|
41
37
|
* Set whether the output is expanded (shows full output) or collapsed (preview only).
|
|
@@ -44,6 +40,10 @@ export class BashExecutionComponent extends Container {
|
|
|
44
40
|
this.expanded = expanded;
|
|
45
41
|
this.updateDisplay();
|
|
46
42
|
}
|
|
43
|
+
setOutputPad(outputPad) {
|
|
44
|
+
this.outputPad = outputPad;
|
|
45
|
+
this.updateDisplay();
|
|
46
|
+
}
|
|
47
47
|
invalidate() {
|
|
48
48
|
super.invalidate();
|
|
49
49
|
this.updateDisplay();
|
|
@@ -92,14 +92,14 @@ export class BashExecutionComponent extends Container {
|
|
|
92
92
|
// Rebuild content container
|
|
93
93
|
this.contentContainer.clear();
|
|
94
94
|
// Command header
|
|
95
|
-
const header = new Text(theme.fg(
|
|
95
|
+
const header = new Text(theme.fg(this.colorKey, theme.bold(`$ ${this.command}`)), this.outputPad, 0);
|
|
96
96
|
this.contentContainer.addChild(header);
|
|
97
97
|
// Output
|
|
98
98
|
if (availableLines.length > 0) {
|
|
99
99
|
if (this.expanded) {
|
|
100
100
|
// Show all lines
|
|
101
101
|
const displayText = availableLines.map((line) => theme.fg("muted", line)).join("\n");
|
|
102
|
-
this.contentContainer.addChild(new Text(`\n${displayText}`,
|
|
102
|
+
this.contentContainer.addChild(new Text(`\n${displayText}`, this.outputPad, 0));
|
|
103
103
|
}
|
|
104
104
|
else {
|
|
105
105
|
// Use shared visual truncation utility with width-aware caching
|
|
@@ -110,7 +110,7 @@ export class BashExecutionComponent extends Container {
|
|
|
110
110
|
this.contentContainer.addChild({
|
|
111
111
|
render: (width) => {
|
|
112
112
|
if (cachedLines === undefined || cachedWidth !== width) {
|
|
113
|
-
const result = truncateToVisualLines(styledInput, PREVIEW_LINES, width,
|
|
113
|
+
const result = truncateToVisualLines(styledInput, PREVIEW_LINES, width, this.outputPad);
|
|
114
114
|
cachedLines = result.visualLines;
|
|
115
115
|
cachedWidth = width;
|
|
116
116
|
}
|
|
@@ -150,7 +150,7 @@ export class BashExecutionComponent extends Container {
|
|
|
150
150
|
statusParts.push(theme.fg("warning", `Output truncated. Full output: ${this.fullOutputPath}`));
|
|
151
151
|
}
|
|
152
152
|
if (statusParts.length > 0) {
|
|
153
|
-
this.contentContainer.addChild(new Text(`\n${statusParts.join("\n")}`,
|
|
153
|
+
this.contentContainer.addChild(new Text(`\n${statusParts.join("\n")}`, this.outputPad, 0));
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
}
|