lsd-pi 1.1.9 → 1.2.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.
Files changed (144) hide show
  1. package/dist/resources/extensions/slash-commands/context.js +15 -8
  2. package/dist/resources/extensions/slash-commands/index.js +2 -0
  3. package/dist/resources/extensions/slash-commands/init.js +47 -0
  4. package/dist/resources/extensions/slash-commands/plan.js +241 -54
  5. package/dist/resources/extensions/slash-commands/tools.js +47 -21
  6. package/dist/resources/extensions/subagent/index.js +5 -10
  7. package/dist/startup-model-validation.d.ts +1 -1
  8. package/package.json +1 -1
  9. package/packages/pi-agent-core/dist/types.d.ts +2 -1
  10. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  11. package/packages/pi-agent-core/dist/types.js.map +1 -1
  12. package/packages/pi-agent-core/src/types.ts +2 -1
  13. package/packages/pi-ai/dist/providers/amazon-bedrock.js +10 -3
  14. package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
  15. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts +1 -1
  16. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  17. package/packages/pi-ai/dist/providers/anthropic-shared.js +4 -1
  18. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  19. package/packages/pi-ai/dist/providers/anthropic.d.ts +2 -2
  20. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  21. package/packages/pi-ai/dist/providers/anthropic.js +2 -2
  22. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  23. package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
  24. package/packages/pi-ai/dist/providers/azure-openai-responses.js +2 -1
  25. package/packages/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
  26. package/packages/pi-ai/dist/providers/google-gemini-cli.js +2 -0
  27. package/packages/pi-ai/dist/providers/google-gemini-cli.js.map +1 -1
  28. package/packages/pi-ai/dist/providers/google-vertex.js +2 -0
  29. package/packages/pi-ai/dist/providers/google-vertex.js.map +1 -1
  30. package/packages/pi-ai/dist/providers/google.js +2 -0
  31. package/packages/pi-ai/dist/providers/google.js.map +1 -1
  32. package/packages/pi-ai/dist/providers/openai-codex-responses.d.ts.map +1 -1
  33. package/packages/pi-ai/dist/providers/openai-codex-responses.js +2 -1
  34. package/packages/pi-ai/dist/providers/openai-codex-responses.js.map +1 -1
  35. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  36. package/packages/pi-ai/dist/providers/openai-completions.js +2 -1
  37. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  38. package/packages/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
  39. package/packages/pi-ai/dist/providers/openai-responses.js +2 -1
  40. package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
  41. package/packages/pi-ai/dist/providers/simple-options.d.ts +1 -1
  42. package/packages/pi-ai/dist/providers/simple-options.d.ts.map +1 -1
  43. package/packages/pi-ai/dist/providers/simple-options.js +6 -2
  44. package/packages/pi-ai/dist/providers/simple-options.js.map +1 -1
  45. package/packages/pi-ai/dist/types.d.ts +1 -1
  46. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  47. package/packages/pi-ai/dist/types.js.map +1 -1
  48. package/packages/pi-ai/src/providers/amazon-bedrock.ts +11 -4
  49. package/packages/pi-ai/src/providers/anthropic-shared.ts +5 -2
  50. package/packages/pi-ai/src/providers/anthropic.ts +2 -2
  51. package/packages/pi-ai/src/providers/azure-openai-responses.ts +2 -1
  52. package/packages/pi-ai/src/providers/google-gemini-cli.ts +3 -1
  53. package/packages/pi-ai/src/providers/google-vertex.ts +3 -1
  54. package/packages/pi-ai/src/providers/google.ts +3 -1
  55. package/packages/pi-ai/src/providers/openai-codex-responses.ts +2 -1
  56. package/packages/pi-ai/src/providers/openai-completions.ts +2 -1
  57. package/packages/pi-ai/src/providers/openai-responses.ts +2 -1
  58. package/packages/pi-ai/src/providers/simple-options.ts +5 -3
  59. package/packages/pi-ai/src/types.ts +1 -1
  60. package/packages/pi-coding-agent/dist/cli/args.js +1 -1
  61. package/packages/pi-coding-agent/dist/cli/args.js.map +1 -1
  62. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +10 -0
  63. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  64. package/packages/pi-coding-agent/dist/core/agent-session.js +57 -20
  65. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  66. package/packages/pi-coding-agent/dist/core/classifier-service.d.ts.map +1 -1
  67. package/packages/pi-coding-agent/dist/core/classifier-service.js +34 -61
  68. package/packages/pi-coding-agent/dist/core/classifier-service.js.map +1 -1
  69. package/packages/pi-coding-agent/dist/core/compaction/utils.d.ts +1 -1
  70. package/packages/pi-coding-agent/dist/core/compaction/utils.d.ts.map +1 -1
  71. package/packages/pi-coding-agent/dist/core/compaction/utils.js +3 -1
  72. package/packages/pi-coding-agent/dist/core/compaction/utils.js.map +1 -1
  73. package/packages/pi-coding-agent/dist/core/resource-loader-lsd-md.test.js +59 -7
  74. package/packages/pi-coding-agent/dist/core/resource-loader-lsd-md.test.js.map +1 -1
  75. package/packages/pi-coding-agent/dist/core/resource-loader.js +4 -4
  76. package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
  77. package/packages/pi-coding-agent/dist/core/sdk.d.ts +1 -1
  78. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  79. package/packages/pi-coding-agent/dist/core/sdk.js +19 -20
  80. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  81. package/packages/pi-coding-agent/dist/core/sdk.test.js +80 -0
  82. package/packages/pi-coding-agent/dist/core/sdk.test.js.map +1 -1
  83. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +15 -5
  84. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  85. package/packages/pi-coding-agent/dist/core/settings-manager.js +31 -5
  86. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  87. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +6 -1
  88. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  89. package/packages/pi-coding-agent/dist/core/system-prompt.js +28 -68
  90. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  91. package/packages/pi-coding-agent/dist/core/tools/bash-interceptor.js +1 -1
  92. package/packages/pi-coding-agent/dist/core/tools/bash-interceptor.js.map +1 -1
  93. package/packages/pi-coding-agent/dist/core/tools/bash-interceptor.test.js +5 -0
  94. package/packages/pi-coding-agent/dist/core/tools/bash-interceptor.test.js.map +1 -1
  95. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  96. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +28 -0
  97. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
  98. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +8 -0
  99. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  100. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +44 -1
  101. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  102. package/packages/pi-coding-agent/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  103. package/packages/pi-coding-agent/dist/modes/interactive/components/thinking-selector.js +1 -0
  104. package/packages/pi-coding-agent/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  105. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  106. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +36 -0
  107. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  108. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  109. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +41 -5
  110. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  111. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +1 -1
  112. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  113. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +2 -0
  114. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  115. package/packages/pi-coding-agent/package.json +1 -1
  116. package/packages/pi-coding-agent/src/cli/args.ts +1 -1
  117. package/packages/pi-coding-agent/src/core/agent-session.ts +62 -19
  118. package/packages/pi-coding-agent/src/core/classifier-service.ts +35 -63
  119. package/packages/pi-coding-agent/src/core/compaction/utils.ts +3 -1
  120. package/packages/pi-coding-agent/src/core/resource-loader-lsd-md.test.ts +67 -7
  121. package/packages/pi-coding-agent/src/core/resource-loader.ts +4 -4
  122. package/packages/pi-coding-agent/src/core/sdk.test.ts +100 -0
  123. package/packages/pi-coding-agent/src/core/sdk.ts +24 -21
  124. package/packages/pi-coding-agent/src/core/settings-manager.ts +42 -8
  125. package/packages/pi-coding-agent/src/core/system-prompt.ts +39 -82
  126. package/packages/pi-coding-agent/src/core/tools/bash-interceptor.test.ts +6 -0
  127. package/packages/pi-coding-agent/src/core/tools/bash-interceptor.ts +1 -1
  128. package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +26 -0
  129. package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +53 -1
  130. package/packages/pi-coding-agent/src/modes/interactive/components/thinking-selector.ts +1 -0
  131. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +41 -0
  132. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +50 -7
  133. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +3 -1
  134. package/pkg/dist/modes/interactive/theme/theme.d.ts +1 -1
  135. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  136. package/pkg/dist/modes/interactive/theme/theme.js +2 -0
  137. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  138. package/pkg/package.json +1 -1
  139. package/src/resources/extensions/slash-commands/context.ts +15 -8
  140. package/src/resources/extensions/slash-commands/index.ts +2 -0
  141. package/src/resources/extensions/slash-commands/init.ts +55 -0
  142. package/src/resources/extensions/slash-commands/plan.ts +277 -55
  143. package/src/resources/extensions/slash-commands/tools.ts +47 -21
  144. package/src/resources/extensions/subagent/index.ts +5 -10
@@ -1 +1 @@
1
- {"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport { getDocsPath, getExamplesPath, getReadmePath } from \"../config.js\";\nimport { toPosixPath } from \"../utils/path-display.js\";\nimport { formatSkillsForPrompt, type Skill } from \"./skills.js\";\n\n/** Tool descriptions for system prompt */\nconst toolDescriptions: Record<string, string> = {\n\tread: \"Read file contents\",\n\tbash: \"Execute bash commands (ls, grep, find, etc.)\",\n\tedit: \"Make surgical edits to files (find exact text and replace)\",\n\twrite: \"Create or overwrite files\",\n\tgrep: \"Search file contents for patterns (respects .gitignore). For symbol definitions, references, type info, or callers in code, use lsp instead\",\n\tfind: \"Find files by glob pattern (respects .gitignore)\",\n\tls: \"List directory contents\",\n\tlsp: \"Code intelligence via Language Server Protocol (go-to-definition, references, diagnostics, hover, rename, symbols)\",\n};\n\nexport interface BuildSystemPromptOptions {\n\t/** Custom system prompt (replaces default). */\n\tcustomPrompt?: string;\n\t/** Tools to include in prompt. Default: [read, bash, edit, write] */\n\tselectedTools?: string[];\n\t/** Optional one-line tool snippets keyed by tool name. */\n\ttoolSnippets?: Record<string, string>;\n\t/** Additional guideline bullets appended to the default system prompt guidelines. */\n\tpromptGuidelines?: string[];\n\t/** Text to append to system prompt. */\n\tappendSystemPrompt?: string;\n\t/** Working directory. Default: process.cwd() */\n\tcwd?: string;\n\t/** Pre-loaded context files. */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Pre-loaded skills. */\n\tskills?: Skill[];\n}\n\n/** Build the system prompt with tools, guidelines, and context */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions = {}): string {\n\tconst {\n\t\tcustomPrompt,\n\t\tselectedTools,\n\t\ttoolSnippets,\n\t\tpromptGuidelines,\n\t\tappendSystemPrompt,\n\t\tcwd,\n\t\tcontextFiles: providedContextFiles,\n\t\tskills: providedSkills,\n\t} = options;\n\tconst resolvedCwd = toPosixPath(cwd ?? process.cwd());\n\n\tconst now = new Date();\n\tconst dateTime = now.toLocaleString(\"en-US\", {\n\t\tweekday: \"long\",\n\t\tyear: \"numeric\",\n\t\tmonth: \"long\",\n\t\tday: \"numeric\",\n\t\thour: \"2-digit\",\n\t\tminute: \"2-digit\",\n\t\tsecond: \"2-digit\",\n\t\ttimeZoneName: \"short\",\n\t});\n\n\tconst appendSection = appendSystemPrompt ? `\\n\\n${appendSystemPrompt}` : \"\";\n\n\tconst contextFiles = providedContextFiles ?? [];\n\tconst skills = providedSkills ?? [];\n\n\tif (customPrompt) {\n\t\tlet prompt = customPrompt;\n\n\t\tif (appendSection) {\n\t\t\tprompt += appendSection;\n\t\t}\n\n\t\t// Append project context files\n\t\tif (contextFiles.length > 0) {\n\t\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t\t}\n\t\t}\n\n\t\t// Append skills section (if read or Skill tool is available)\n\t\tconst customPromptHasSkillAccess = !selectedTools || selectedTools.includes(\"read\") || selectedTools.includes(\"Skill\");\n\t\tif (customPromptHasSkillAccess && skills.length > 0) {\n\t\t\tprompt += formatSkillsForPrompt(skills);\n\t\t}\n\n\t\t// Add date/time and working directory last\n\t\tprompt += `\\nCurrent date and time: ${dateTime}`;\n\t\tprompt += `\\nCurrent working directory: ${resolvedCwd}`;\n\n\t\t// Append promptGuidelines from extension-registered tools.\n\t\t// Without this, tools registered via pi.registerTool() with promptGuidelines\n\t\t// have their definitions reach the API but the model has no guidance on when\n\t\t// to use them (#1184).\n\t\tif (promptGuidelines && promptGuidelines.length > 0) {\n\t\t\tprompt += \"\\n\\n\";\n\t\t\tfor (const guideline of promptGuidelines) {\n\t\t\t\tprompt += guideline + \"\\n\";\n\t\t\t}\n\t\t}\n\n\t\treturn prompt;\n\t}\n\n\t// Get absolute paths to documentation and examples\n\tconst readmePath = getReadmePath();\n\tconst docsPath = getDocsPath();\n\tconst examplesPath = getExamplesPath();\n\n\t// Build tools list based on selected tools.\n\t// Built-ins use toolDescriptions. Custom tools can provide one-line snippets.\n\tconst tools = selectedTools || [\"read\", \"bash\", \"edit\", \"write\"];\n\tconst toolsList =\n\t\ttools.length > 0\n\t\t\t? tools\n\t\t\t\t\t.map((name) => {\n\t\t\t\t\t\tconst snippet = toolSnippets?.[name] ?? toolDescriptions[name] ?? name;\n\t\t\t\t\t\treturn `- ${name}: ${snippet}`;\n\t\t\t\t\t})\n\t\t\t\t\t.join(\"\\n\")\n\t\t\t: \"(none)\";\n\n\t// Build guidelines based on which tools are actually available\n\tconst guidelinesList: string[] = [];\n\tconst guidelinesSet = new Set<string>();\n\tconst addGuideline = (guideline: string): void => {\n\t\tif (guidelinesSet.has(guideline)) {\n\t\t\treturn;\n\t\t}\n\t\tguidelinesSet.add(guideline);\n\t\tguidelinesList.push(guideline);\n\t};\n\n\tconst hasBash = tools.includes(\"bash\");\n\tconst hasEdit = tools.includes(\"edit\");\n\tconst hasWrite = tools.includes(\"write\");\n\tconst hasGrep = tools.includes(\"grep\");\n\tconst hasFind = tools.includes(\"find\");\n\tconst hasLs = tools.includes(\"ls\");\n\tconst hasRead = tools.includes(\"read\");\n\tconst hasLsp = tools.includes(\"lsp\");\n\n\t// LSP guideline — must come FIRST so it outranks grep/bash in the model's priority\n\tif (hasLsp) {\n\t\taddGuideline(\n\t\t\t`Use lsp as the primary tool for code navigation in typed codebases:\n- Navigation: definition, type_definition, implementation, references, incoming_calls, outgoing_calls\n- Understanding: hover (types + docs), signature (parameter info), symbols (file/workspace search)\n- Refactoring: rename (project-wide), code_actions (quick-fixes, imports, refactors), format (formatter)\n- Verification: diagnostics after edits to catch type errors immediately\n- Before choosing a code-navigation tool, classify your intent: symbol lookup (definition, references, type info, callers, rename, formatting, diagnostics) or text search. Symbols → lsp. Text patterns / non-code files → grep/find/ls\n- Tool selection — code navigation:\n • Find where a symbol is defined → lsp definition (not grep)\n • Find all usages of a symbol → lsp references (not grep)\n • Find implementations of an interface or method → lsp implementation (not grep)\n • Get type info or docs for a symbol → lsp hover/signature (not reading source first)\n • Find all callers of a function → lsp incoming_calls (not grep)\n • Search for a text pattern, TODO, log message, or non-code content → grep\n • Search for filenames or directory structure → find/ls\n • Rename a symbol across the codebase → lsp rename (not find-and-replace)\n • Check typed errors after edits → lsp diagnostics (not manual scans)\n • Format a file → lsp format when available (not shelling out)\n- When lsp is available, ALWAYS prefer it over grep/bash/find for: finding definitions, finding references, getting type info, renaming symbols, listing symbols in a file or workspace, checking diagnostics/errors, and formatting\n- Never grep for a symbol definition when lsp can resolve it semantically\n- Never shell out to a formatter when lsp format is available`,\n\t\t);\n\t}\n\n\t// If the request is primarily conceptual or product/design oriented, answer the design or strategy question first and inspect the codebase only after confirming implementation detail is needed.\n\taddGuideline(\n\t\t\"If the request is primarily conceptual, product, or UX/design oriented, answer the question first with concise recommendations and inspect the codebase only after confirming implementation detail is needed\",\n\t);\n\n\t// Use subagents for broad reconnaissance before spending expensive-model tokens on discovery\n\tif (tools.includes(\"subagent\")) {\n\t\taddGuideline(\n\t\t\t\"Use a scout subagent for broad repo reconnaissance when file ownership or architecture is unclear; keep the scout read-only, use a cheaper model when available, and ask it to return a high-signal handoff with exact files/symbols to inspect next\",\n\t\t);\n\t}\n\n\taddGuideline(\n\t\t\"Do not deep-dive backend schemas, migrations, or infrastructure for a conceptual/product request until you confirm that implementation constraints actually matter\",\n\t);\n\n\t// File exploration guidelines (only for tasks lsp cannot do: raw text search, non-code files, etc.)\n\tif (hasBash && !hasGrep && !hasFind && !hasLs) {\n\t\taddGuideline(\"Use bash for file operations like ls, rg, find\");\n\t} else if (hasBash && (hasGrep || hasFind || hasLs)) {\n\t\tif (hasLsp) {\n\t\t\taddGuideline(\"Prefer grep/find/ls tools over bash for file exploration (faster, respects .gitignore) — but prefer lsp over grep/find when navigating typed code\");\n\t\t} else {\n\t\t\taddGuideline(\"Prefer grep/find/ls tools over bash for file exploration (faster, respects .gitignore)\");\n\t\t}\n\t}\n\n\t// Read before edit guideline\n\tif (hasRead && hasEdit) {\n\t\taddGuideline(\"Use read to examine files before editing. You must use this tool instead of cat or sed.\");\n\t}\n\n\t// Edit guideline\n\tif (hasEdit) {\n\t\taddGuideline(\"Use edit for precise changes (old text must match exactly)\");\n\t}\n\n\t// Write guideline\n\tif (hasWrite) {\n\t\taddGuideline(\"Use write only for new files or complete rewrites\");\n\t}\n\n\t// Output guideline (only when actually writing or executing)\n\tif (hasEdit || hasWrite) {\n\t\taddGuideline(\n\t\t\t\"When summarizing your actions, output plain text directly - do NOT use cat or bash to display what you did\",\n\t\t);\n\t}\n\n\tfor (const guideline of promptGuidelines ?? []) {\n\t\tconst normalized = guideline.trim();\n\t\tif (normalized.length > 0) {\n\t\t\taddGuideline(normalized);\n\t\t}\n\t}\n\n\t// Always include these\n\taddGuideline(\"Be concise in your responses\");\n\taddGuideline(\"Show file paths clearly when working with files\");\n\n\tconst guidelines = guidelinesList.map((g) => `- ${g}`).join(\"\\n\");\n\n\tlet prompt = `You are an expert coding assistant operating inside pi, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.\n\nAvailable tools:\n${toolsList}\n\nIn addition to the tools above, you may have access to other custom tools depending on the project.\n\nGuidelines:\n${guidelines}\n\nPi documentation (read only when the user asks about pi itself, its SDK, extensions, themes, skills, or TUI):\n- Main documentation: ${readmePath}\n- Additional docs: ${docsPath}\n- Examples: ${examplesPath} (extensions, custom tools, SDK)\n- When asked about: extensions (docs/extensions.md, examples/extensions/), themes (docs/themes.md), skills (docs/skills.md), prompt templates (docs/prompt-templates.md), TUI components (docs/tui.md), keybindings (docs/keybindings.md), SDK integrations (docs/sdk.md), custom providers (docs/custom-provider.md), adding models (docs/models.md), pi packages (docs/packages.md)\n- When working on pi topics, read the docs and examples, and follow .md cross-references before implementing\n- Always read pi .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;\n\n\tif (appendSection) {\n\t\tprompt += appendSection;\n\t}\n\n\t// Append project context files\n\tif (contextFiles.length > 0) {\n\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t}\n\t}\n\n\t// Append skills section (if read or Skill tool is available)\n\tconst hasSkill = tools.includes(\"Skill\");\n\tif ((hasRead || hasSkill) && skills.length > 0) {\n\t\tprompt += formatSkillsForPrompt(skills);\n\t}\n\n\t// Add date/time and working directory last\n\tprompt += `\\nCurrent date and time: ${dateTime}`;\n\tprompt += `\\nCurrent working directory: ${resolvedCwd}`;\n\n\treturn prompt;\n}\n"]}
1
+ {"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport { existsSync } from \"node:fs\";\nimport { getDocsPath, getExamplesPath, getReadmePath } from \"../config.js\";\nimport { toPosixPath } from \"../utils/path-display.js\";\nimport { formatSkillsForPrompt, type Skill } from \"./skills.js\";\n\n/** Tool descriptions for system prompt */\nconst toolDescriptions: Record<string, string> = {\n\tread: \"Read file contents\",\n\tbash: \"Execute bash commands (ls, grep, find, etc.)\",\n\tedit: \"Make surgical edits to files (find exact text and replace)\",\n\twrite: \"Create or overwrite files\",\n\tgrep: \"Search file contents for patterns (respects .gitignore). For symbol definitions, references, type info, or callers in code, use lsp instead\",\n\tfind: \"Find files by glob pattern (respects .gitignore)\",\n\tls: \"List directory contents\",\n\tlsp: \"Code intelligence via Language Server Protocol (go-to-definition, references, diagnostics, hover, rename, symbols)\",\n};\n\nexport interface BuildSystemPromptOptions {\n\t/**\n\t * Custom system prompt that replaces the default role header, tool list,\n\t * and guidelines entirely. You are responsible for providing your own\n\t * tool-usage guidance. Project context, skills, extension promptGuidelines,\n\t * date/cwd, and appendSystemPrompt are still applied on top.\n\t */\n\tcustomPrompt?: string;\n\t/** Tools to include in prompt. Default: [read, bash, edit, write] */\n\tselectedTools?: string[];\n\t/** Optional one-line tool snippets keyed by tool name. */\n\ttoolSnippets?: Record<string, string>;\n\t/** Additional guideline bullets appended to the default system prompt guidelines. */\n\tpromptGuidelines?: string[];\n\t/** Text to append to system prompt. */\n\tappendSystemPrompt?: string;\n\t/** Working directory. Default: process.cwd() */\n\tcwd?: string;\n\t/** Pre-loaded context files. */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Pre-loaded skills. */\n\tskills?: Skill[];\n}\n\n/** Build the system prompt with tools, guidelines, and context */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions = {}): string {\n\tconst {\n\t\tcustomPrompt,\n\t\tselectedTools,\n\t\ttoolSnippets,\n\t\tpromptGuidelines,\n\t\tappendSystemPrompt,\n\t\tcwd,\n\t\tcontextFiles: providedContextFiles,\n\t\tskills: providedSkills,\n\t} = options;\n\tconst resolvedCwd = toPosixPath(cwd ?? process.cwd());\n\n\tconst now = new Date();\n\tconst dateTime = now.toLocaleString(\"en-US\", {\n\t\tweekday: \"long\",\n\t\tyear: \"numeric\",\n\t\tmonth: \"long\",\n\t\tday: \"numeric\",\n\t\thour: \"2-digit\",\n\t\tminute: \"2-digit\",\n\t\tsecond: \"2-digit\",\n\t\ttimeZoneName: \"short\",\n\t});\n\n\tconst appendSection = appendSystemPrompt ? `\\n\\n${appendSystemPrompt}` : \"\";\n\n\tconst contextFiles = providedContextFiles ?? [];\n\tconst skills = providedSkills ?? [];\n\n\tif (customPrompt) {\n\t\tlet prompt = customPrompt;\n\n\t\tif (appendSection) {\n\t\t\tprompt += appendSection;\n\t\t}\n\n\t\t// Append project context files\n\t\tif (contextFiles.length > 0) {\n\t\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t\t}\n\t\t}\n\n\t\t// Append skills section (if read or Skill tool is available)\n\t\tconst customPromptHasSkillAccess = !selectedTools || selectedTools.includes(\"read\") || selectedTools.includes(\"Skill\");\n\t\tif (customPromptHasSkillAccess && skills.length > 0) {\n\t\t\tprompt += formatSkillsForPrompt(skills);\n\t\t}\n\n\t\t// Append promptGuidelines from extension-registered tools.\n\t\t// Without this, tools registered via pi.registerTool() with promptGuidelines\n\t\t// have their definitions reach the API but the model has no guidance on when\n\t\t// to use them (#1184).\n\t\tif (promptGuidelines && promptGuidelines.length > 0) {\n\t\t\tprompt += \"\\n\\n\";\n\t\t\tfor (const guideline of promptGuidelines) {\n\t\t\t\tprompt += guideline + \"\\n\";\n\t\t\t}\n\t\t}\n\n\t\t// Add date/time and working directory last\n\t\tprompt += `\\nCurrent date and time: ${dateTime}`;\n\t\tprompt += `\\nCurrent working directory: ${resolvedCwd}`;\n\n\t\treturn prompt;\n\t}\n\n\t// Get absolute paths to documentation and examples\n\tconst readmePath = getReadmePath();\n\tconst docsPath = getDocsPath();\n\tconst examplesPath = getExamplesPath();\n\n\t// Build tools list based on selected tools.\n\t// Built-ins use toolDescriptions. Custom tools can provide one-line snippets.\n\tconst tools = selectedTools || [\"read\", \"bash\", \"edit\", \"write\"];\n\tconst toolsList =\n\t\ttools.length > 0\n\t\t\t? tools\n\t\t\t\t\t.map((name) => {\n\t\t\t\t\t\tconst snippet = toolSnippets?.[name] ?? toolDescriptions[name] ?? name;\n\t\t\t\t\t\treturn `- ${name}: ${snippet}`;\n\t\t\t\t\t})\n\t\t\t\t\t.join(\"\\n\")\n\t\t\t: \"(none)\";\n\n\t// Build guidelines based on which tools are actually available\n\tconst guidelinesList: string[] = [];\n\tconst guidelinesSet = new Set<string>();\n\tconst addGuideline = (guideline: string): void => {\n\t\tif (guidelinesSet.has(guideline)) {\n\t\t\treturn;\n\t\t}\n\t\tguidelinesSet.add(guideline);\n\t\tguidelinesList.push(guideline);\n\t};\n\n\tconst hasEdit = tools.includes(\"edit\");\n\tconst hasWrite = tools.includes(\"write\");\n\tconst hasRead = tools.includes(\"read\");\n\tconst hasLsp = tools.includes(\"lsp\");\n\n\t// Priority-ordered compact guidelines\n\taddGuideline(\"Be concise. Prefer short, direct answers over preamble.\");\n\taddGuideline(\"For conceptual, product, or UX questions, answer first; inspect code only if implementation detail is needed.\");\n\n\tif (hasLsp) {\n\t\taddGuideline(\n\t\t\t\"Code navigation in typed codebases: use lsp for symbols (definition, references, implementation, hover, diagnostics, rename, format). Use grep/find/ls for text patterns, filenames, and non-code files.\",\n\t\t);\n\t} else {\n\t\taddGuideline(\"Use grep/find/ls for code search and file exploration (faster than bash, respects .gitignore)\");\n\t}\n\n\tif (hasRead && hasEdit) {\n\t\taddGuideline(\"Read files before editing them. Never use cat or sed to inspect or modify files.\");\n\t}\n\n\tif (hasEdit) {\n\t\taddGuideline(\"edit requires exact text match; write is for new files or full rewrites.\");\n\t}\n\n\tif (hasWrite && !hasEdit) {\n\t\taddGuideline(\"write is for new files or full rewrites.\");\n\t}\n\n\tif (hasLsp && hasEdit) {\n\t\taddGuideline(\"Run lsp diagnostics after edits to catch type errors.\");\n\t}\n\n\tif (hasEdit || hasWrite) {\n\t\taddGuideline(\"Output plain text directly when summarizing your work — do not cat or echo to display what you did.\");\n\t}\n\n\taddGuideline(\"Show file paths clearly when referencing files.\");\n\n\tfor (const guideline of promptGuidelines ?? []) {\n\t\tconst normalized = guideline.trim();\n\t\tif (normalized.length > 0) {\n\t\t\taddGuideline(normalized);\n\t\t}\n\t}\n\n\tconst guidelines = guidelinesList.map((g) => `- ${g}`).join(\"\\n\");\n\n\tconst piDocsBlock = existsSync(readmePath)\n\t\t? `\\n\\nPi documentation (read only when the user asks about pi itself, its SDK, extensions, themes, skills, or TUI):\n- Main documentation: ${readmePath}\n- Additional docs: ${docsPath}\n- Examples: ${examplesPath} (extensions, custom tools, SDK)\n- When working on pi topics, read the docs and follow .md cross-references before implementing`\n\t\t: \"\";\n\n\tlet prompt = `You are an expert coding assistant operating inside pi, a coding agent harness.\n\nAvailable tools:\n${toolsList}\n\nIn addition to the tools above, you may have access to other custom tools depending on the project.\n\nGuidelines:\n${guidelines}${piDocsBlock}`;\n\n\tif (appendSection) {\n\t\tprompt += appendSection;\n\t}\n\n\t// Append project context files\n\tif (contextFiles.length > 0) {\n\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t}\n\t}\n\n\t// Append skills section (if read or Skill tool is available)\n\tconst hasSkill = tools.includes(\"Skill\");\n\tif ((hasRead || hasSkill) && skills.length > 0) {\n\t\tprompt += formatSkillsForPrompt(skills);\n\t}\n\n\t// Add date/time and working directory last\n\tprompt += `\\nCurrent date and time: ${dateTime}`;\n\tprompt += `\\nCurrent working directory: ${resolvedCwd}`;\n\n\treturn prompt;\n}\n"]}
@@ -67,7 +67,7 @@ export function compileInterceptor(rules) {
67
67
  if (regex.test(trimmed) && availableTools.includes(rule.tool)) {
68
68
  return {
69
69
  block: true,
70
- message: `Blocked: ${rule.message}\n\nOriginal command: ${command}`,
70
+ message: `Tool routing: ${rule.message}\n\nThis is a routing suggestion, not a permission block. Use the suggested tool to perform this action.\n\nOriginal command: ${command}`,
71
71
  suggestedTool: rule.tool,
72
72
  };
73
73
  }
@@ -1 +1 @@
1
- {"version":3,"file":"bash-interceptor.js","sourceRoot":"","sources":["../../../src/core/tools/bash-interceptor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,MAAM,CAAC,MAAM,8BAA8B,GAA0B;IACpE;QACC,oEAAoE;QACpE,OAAO,EAAE,8CAA8C;QACvD,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,oEAAoE;KAC7E;IACD;QACC,OAAO,EAAE,mCAAmC;QAC5C,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,0EAA0E;KACnF;IACD;QACC,OAAO,EAAE,8DAA8D;QACvE,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,8EAA8E;KACvF;IACD;QACC,OAAO,EAAE,6BAA6B;QACtC,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,mEAAmE;KAC5E;IACD;QACC,OAAO,EAAE,wBAAwB;QACjC,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,oEAAoE;KAC7E;IACD;QACC,OAAO,EAAE,6BAA6B;QACtC,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,mEAAmE;KAC5E;IACD;QACC,sFAAsF;QACtF,4EAA4E;QAC5E,OAAO,EAAE,6DAA6D;QACtE,IAAI,EAAE,OAAO;QACb,OAAO,EAAE,0EAA0E;KACnF;CACD,CAAC;AAYF;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAA4B;IAC9D,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QACvC,IAAI,CAAC;YACJ,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,EAAE,CAAC,CAAC,qBAAqB;QACjC,CAAC;IACF,CAAC,CAAC,CAAC;IAEH,OAAO;QACN,KAAK,CAAC,OAAe,EAAE,cAAwB;YAC9C,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;YAC/B,KAAK,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,QAAQ,EAAE,CAAC;gBACxC,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC/D,OAAO;wBACN,KAAK,EAAE,IAAI;wBACX,OAAO,EAAE,YAAY,IAAI,CAAC,OAAO,yBAAyB,OAAO,EAAE;wBACnE,aAAa,EAAE,IAAI,CAAC,IAAI;qBACxB,CAAC;gBACH,CAAC;YACF,CAAC;YACD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;QACzB,CAAC;KACD,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,qBAAqB,CACpC,OAAe,EACf,cAAwB,EACxB,KAA6B;IAE7B,MAAM,cAAc,GAAG,KAAK,IAAI,8BAA8B,CAAC;IAC/D,OAAO,kBAAkB,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;AAC1E,CAAC","sourcesContent":["/**\n * Bash command interceptor — blocks shell commands that duplicate dedicated tools.\n *\n * Each rule defines a regex pattern, a suggested replacement tool, and a message.\n * A command is only blocked when the suggested tool exists in the session's active tool list.\n */\n\nexport interface BashInterceptorRule {\n\tpattern: string;\n\tflags?: string;\n\ttool: string;\n\tmessage: string;\n}\n\nexport const DEFAULT_BASH_INTERCEPTOR_RULES: BashInterceptorRule[] = [\n\t{\n\t\t// cat/head/tail for file viewing — excludes heredoc syntax (cat <<)\n\t\tpattern: \"^\\\\s*(cat(?!\\\\s*<<)|head|tail|less|more)\\\\s+\",\n\t\ttool: \"read\",\n\t\tmessage: \"Use the read tool to view file contents instead of shell commands.\",\n\t},\n\t{\n\t\tpattern: \"^\\\\s*(grep|rg|ripgrep|ag|ack)\\\\s+\",\n\t\ttool: \"grep\",\n\t\tmessage: \"Use the grep tool for searching file contents instead of shell commands.\",\n\t},\n\t{\n\t\tpattern: \"^\\\\s*(find|fd|locate)\\\\s+.*(-name|-iname|-type|--type|-glob)\",\n\t\ttool: \"find\",\n\t\tmessage: \"Use the find tool for locating files by name/type instead of shell commands.\",\n\t},\n\t{\n\t\tpattern: \"^\\\\s*sed\\\\s+(-i|--in-place)\",\n\t\ttool: \"edit\",\n\t\tmessage: \"Use the edit tool for in-place file modifications instead of sed.\",\n\t},\n\t{\n\t\tpattern: \"^\\\\s*perl\\\\s+.*-[pn]?i\",\n\t\ttool: \"edit\",\n\t\tmessage: \"Use the edit tool for in-place file modifications instead of perl.\",\n\t},\n\t{\n\t\tpattern: \"^\\\\s*awk\\\\s+.*-i\\\\s+inplace\",\n\t\ttool: \"edit\",\n\t\tmessage: \"Use the edit tool for in-place file modifications instead of awk.\",\n\t},\n\t{\n\t\t// echo/printf/heredoc writing to a file via > (not >> append, not 2> stderr redirect)\n\t\t// Matches a single > not preceded by |, >, or a digit (fd redirect like 2>)\n\t\tpattern: \"^\\\\s*(echo|printf|cat\\\\s*<<)\\\\s+.*(?<![|>\\\\d])>(?!>)\\\\s*\\\\S\",\n\t\ttool: \"write\",\n\t\tmessage: \"Use the write tool to create/overwrite files instead of shell redirects.\",\n\t},\n];\n\nexport interface InterceptionResult {\n\tblock: boolean;\n\tmessage?: string;\n\tsuggestedTool?: string;\n}\n\nexport interface CompiledInterceptor {\n\tcheck: (command: string, availableTools: string[]) => InterceptionResult;\n}\n\n/**\n * Compile rules into an interceptor with pre-built regex objects.\n * Silently skips rules with invalid patterns.\n *\n * Pre-compiling at construction time avoids repeated `new RegExp()` calls\n * on every bash command invocation.\n */\nexport function compileInterceptor(rules: BashInterceptorRule[]): CompiledInterceptor {\n\tconst compiled = rules.flatMap((rule) => {\n\t\ttry {\n\t\t\treturn [{ regex: new RegExp(rule.pattern, rule.flags), rule }];\n\t\t} catch {\n\t\t\treturn []; // skip invalid regex\n\t\t}\n\t});\n\n\treturn {\n\t\tcheck(command: string, availableTools: string[]): InterceptionResult {\n\t\t\tconst trimmed = command.trim();\n\t\t\tfor (const { regex, rule } of compiled) {\n\t\t\t\tif (regex.test(trimmed) && availableTools.includes(rule.tool)) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tblock: true,\n\t\t\t\t\t\tmessage: `Blocked: ${rule.message}\\n\\nOriginal command: ${command}`,\n\t\t\t\t\t\tsuggestedTool: rule.tool,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { block: false };\n\t\t},\n\t};\n}\n\n/**\n * Check whether a bash command should be intercepted.\n *\n * Compiles rules on each call — prefer `compileInterceptor()` for repeated use.\n *\n * @param command - The shell command to check\n * @param availableTools - Tool names present in the current session\n * @param rules - Override the default rule set (optional)\n */\nexport function checkBashInterception(\n\tcommand: string,\n\tavailableTools: string[],\n\trules?: BashInterceptorRule[],\n): InterceptionResult {\n\tconst effectiveRules = rules ?? DEFAULT_BASH_INTERCEPTOR_RULES;\n\treturn compileInterceptor(effectiveRules).check(command, availableTools);\n}\n"]}
1
+ {"version":3,"file":"bash-interceptor.js","sourceRoot":"","sources":["../../../src/core/tools/bash-interceptor.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,MAAM,CAAC,MAAM,8BAA8B,GAA0B;IACpE;QACC,oEAAoE;QACpE,OAAO,EAAE,8CAA8C;QACvD,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,oEAAoE;KAC7E;IACD;QACC,OAAO,EAAE,mCAAmC;QAC5C,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,0EAA0E;KACnF;IACD;QACC,OAAO,EAAE,8DAA8D;QACvE,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,8EAA8E;KACvF;IACD;QACC,OAAO,EAAE,6BAA6B;QACtC,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,mEAAmE;KAC5E;IACD;QACC,OAAO,EAAE,wBAAwB;QACjC,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,oEAAoE;KAC7E;IACD;QACC,OAAO,EAAE,6BAA6B;QACtC,IAAI,EAAE,MAAM;QACZ,OAAO,EAAE,mEAAmE;KAC5E;IACD;QACC,sFAAsF;QACtF,4EAA4E;QAC5E,OAAO,EAAE,6DAA6D;QACtE,IAAI,EAAE,OAAO;QACb,OAAO,EAAE,0EAA0E;KACnF;CACD,CAAC;AAYF;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAA4B;IAC9D,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QACvC,IAAI,CAAC;YACJ,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,CAAC;QAAC,MAAM,CAAC;YACR,OAAO,EAAE,CAAC,CAAC,qBAAqB;QACjC,CAAC;IACF,CAAC,CAAC,CAAC;IAEH,OAAO;QACN,KAAK,CAAC,OAAe,EAAE,cAAwB;YAC9C,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;YAC/B,KAAK,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,QAAQ,EAAE,CAAC;gBACxC,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC/D,OAAO;wBACN,KAAK,EAAE,IAAI;wBACX,OAAO,EAAE,iBAAiB,IAAI,CAAC,OAAO,iIAAiI,OAAO,EAAE;wBAChL,aAAa,EAAE,IAAI,CAAC,IAAI;qBACxB,CAAC;gBACH,CAAC;YACF,CAAC;YACD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;QACzB,CAAC;KACD,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,qBAAqB,CACpC,OAAe,EACf,cAAwB,EACxB,KAA6B;IAE7B,MAAM,cAAc,GAAG,KAAK,IAAI,8BAA8B,CAAC;IAC/D,OAAO,kBAAkB,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;AAC1E,CAAC","sourcesContent":["/**\n * Bash command interceptor — blocks shell commands that duplicate dedicated tools.\n *\n * Each rule defines a regex pattern, a suggested replacement tool, and a message.\n * A command is only blocked when the suggested tool exists in the session's active tool list.\n */\n\nexport interface BashInterceptorRule {\n\tpattern: string;\n\tflags?: string;\n\ttool: string;\n\tmessage: string;\n}\n\nexport const DEFAULT_BASH_INTERCEPTOR_RULES: BashInterceptorRule[] = [\n\t{\n\t\t// cat/head/tail for file viewing — excludes heredoc syntax (cat <<)\n\t\tpattern: \"^\\\\s*(cat(?!\\\\s*<<)|head|tail|less|more)\\\\s+\",\n\t\ttool: \"read\",\n\t\tmessage: \"Use the read tool to view file contents instead of shell commands.\",\n\t},\n\t{\n\t\tpattern: \"^\\\\s*(grep|rg|ripgrep|ag|ack)\\\\s+\",\n\t\ttool: \"grep\",\n\t\tmessage: \"Use the grep tool for searching file contents instead of shell commands.\",\n\t},\n\t{\n\t\tpattern: \"^\\\\s*(find|fd|locate)\\\\s+.*(-name|-iname|-type|--type|-glob)\",\n\t\ttool: \"find\",\n\t\tmessage: \"Use the find tool for locating files by name/type instead of shell commands.\",\n\t},\n\t{\n\t\tpattern: \"^\\\\s*sed\\\\s+(-i|--in-place)\",\n\t\ttool: \"edit\",\n\t\tmessage: \"Use the edit tool for in-place file modifications instead of sed.\",\n\t},\n\t{\n\t\tpattern: \"^\\\\s*perl\\\\s+.*-[pn]?i\",\n\t\ttool: \"edit\",\n\t\tmessage: \"Use the edit tool for in-place file modifications instead of perl.\",\n\t},\n\t{\n\t\tpattern: \"^\\\\s*awk\\\\s+.*-i\\\\s+inplace\",\n\t\ttool: \"edit\",\n\t\tmessage: \"Use the edit tool for in-place file modifications instead of awk.\",\n\t},\n\t{\n\t\t// echo/printf/heredoc writing to a file via > (not >> append, not 2> stderr redirect)\n\t\t// Matches a single > not preceded by |, >, or a digit (fd redirect like 2>)\n\t\tpattern: \"^\\\\s*(echo|printf|cat\\\\s*<<)\\\\s+.*(?<![|>\\\\d])>(?!>)\\\\s*\\\\S\",\n\t\ttool: \"write\",\n\t\tmessage: \"Use the write tool to create/overwrite files instead of shell redirects.\",\n\t},\n];\n\nexport interface InterceptionResult {\n\tblock: boolean;\n\tmessage?: string;\n\tsuggestedTool?: string;\n}\n\nexport interface CompiledInterceptor {\n\tcheck: (command: string, availableTools: string[]) => InterceptionResult;\n}\n\n/**\n * Compile rules into an interceptor with pre-built regex objects.\n * Silently skips rules with invalid patterns.\n *\n * Pre-compiling at construction time avoids repeated `new RegExp()` calls\n * on every bash command invocation.\n */\nexport function compileInterceptor(rules: BashInterceptorRule[]): CompiledInterceptor {\n\tconst compiled = rules.flatMap((rule) => {\n\t\ttry {\n\t\t\treturn [{ regex: new RegExp(rule.pattern, rule.flags), rule }];\n\t\t} catch {\n\t\t\treturn []; // skip invalid regex\n\t\t}\n\t});\n\n\treturn {\n\t\tcheck(command: string, availableTools: string[]): InterceptionResult {\n\t\t\tconst trimmed = command.trim();\n\t\t\tfor (const { regex, rule } of compiled) {\n\t\t\t\tif (regex.test(trimmed) && availableTools.includes(rule.tool)) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tblock: true,\n\t\t\t\t\t\tmessage: `Tool routing: ${rule.message}\\n\\nThis is a routing suggestion, not a permission block. Use the suggested tool to perform this action.\\n\\nOriginal command: ${command}`,\n\t\t\t\t\t\tsuggestedTool: rule.tool,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { block: false };\n\t\t},\n\t};\n}\n\n/**\n * Check whether a bash command should be intercepted.\n *\n * Compiles rules on each call — prefer `compileInterceptor()` for repeated use.\n *\n * @param command - The shell command to check\n * @param availableTools - Tool names present in the current session\n * @param rules - Override the default rule set (optional)\n */\nexport function checkBashInterception(\n\tcommand: string,\n\tavailableTools: string[],\n\trules?: BashInterceptorRule[],\n): InterceptionResult {\n\tconst effectiveRules = rules ?? DEFAULT_BASH_INTERCEPTOR_RULES;\n\treturn compileInterceptor(effectiveRules).check(command, availableTools);\n}\n"]}
@@ -110,6 +110,11 @@ describe("checkBashInterception", () => {
110
110
  const r = checkBashInterception("cat README.md", ALL_TOOLS);
111
111
  assert.ok(r.message?.includes("cat README.md"), "message should contain original command");
112
112
  });
113
+ it("uses 'Tool routing:' prefix to distinguish from permission blocks", () => {
114
+ const r = checkBashInterception("cat README.md", ALL_TOOLS);
115
+ assert.ok(r.message?.startsWith("Tool routing:"), "message should start with 'Tool routing:'");
116
+ assert.ok(r.message?.includes("not a permission block"), "message should clarify it's not a permission block");
117
+ });
113
118
  it("returns block:false with no message when not blocked", () => {
114
119
  const r = checkBashInterception("npm install", ALL_TOOLS);
115
120
  assert.equal(r.block, false);
@@ -1 +1 @@
1
- {"version":3,"file":"bash-interceptor.test.js","sourceRoot":"","sources":["../../../src/core/tools/bash-interceptor.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport {\n\tcheckBashInterception,\n\tcompileInterceptor,\n\tDEFAULT_BASH_INTERCEPTOR_RULES,\n\ttype BashInterceptorRule,\n} from \"./bash-interceptor.js\";\n\nconst ALL_TOOLS = [\"read\", \"grep\", \"find\", \"edit\", \"write\"];\nconst NO_TOOLS: string[] = [];\n\ndescribe(\"checkBashInterception\", () => {\n\tdescribe(\"read rule (cat/head/tail/less/more)\", () => {\n\t\tit(\"blocks cat with a file argument\", () => {\n\t\t\tconst r = checkBashInterception(\"cat README.md\", ALL_TOOLS);\n\t\t\tassert.equal(r.block, true);\n\t\t\tassert.equal(r.suggestedTool, \"read\");\n\t\t});\n\n\t\tit(\"blocks head and tail\", () => {\n\t\t\tassert.equal(checkBashInterception(\"head -n 20 file.ts\", ALL_TOOLS).block, true);\n\t\t\tassert.equal(checkBashInterception(\"tail -f app.log\", ALL_TOOLS).block, true);\n\t\t});\n\n\t\tit(\"does NOT block cat used as heredoc (cat <<EOF)\", () => {\n\t\t\tconst r = checkBashInterception(\"cat <<EOF > file.txt\", ALL_TOOLS);\n\t\t\tassert.notEqual(r.suggestedTool, \"read\");\n\t\t});\n\n\t\tit(\"does NOT block when read tool is absent\", () => {\n\t\t\tassert.equal(checkBashInterception(\"cat README.md\", NO_TOOLS).block, false);\n\t\t\tassert.equal(checkBashInterception(\"cat README.md\", [\"grep\"]).block, false);\n\t\t});\n\t});\n\n\tdescribe(\"grep rule\", () => {\n\t\tit(\"blocks grep and rg\", () => {\n\t\t\tassert.equal(checkBashInterception(\"grep foo bar.ts\", ALL_TOOLS).block, true);\n\t\t\tassert.equal(checkBashInterception(\"rg -r pattern .\", ALL_TOOLS).block, true);\n\t\t});\n\n\t\tit(\"blocks grep with leading whitespace\", () => {\n\t\t\tassert.equal(checkBashInterception(\" grep -r foo .\", ALL_TOOLS).block, true);\n\t\t});\n\n\t\tit(\"does NOT block when grep tool is absent\", () => {\n\t\t\tassert.equal(checkBashInterception(\"grep foo bar\", [\"read\", \"edit\"]).block, false);\n\t\t});\n\t});\n\n\tdescribe(\"find rule\", () => {\n\t\tit(\"blocks find with -name flag\", () => {\n\t\t\tassert.equal(checkBashInterception('find . -name \"*.ts\"', ALL_TOOLS).block, true);\n\t\t});\n\n\t\tit(\"blocks find with -type flag\", () => {\n\t\t\tassert.equal(checkBashInterception(\"find /tmp -maxdepth 1 -type f\", ALL_TOOLS).block, true);\n\t\t});\n\n\t\tit(\"does NOT block find without name/type flags\", () => {\n\t\t\tassert.equal(checkBashInterception(\"find /tmp -maxdepth 1\", ALL_TOOLS).block, false);\n\t\t});\n\n\t\tit(\"does NOT block when find tool is absent\", () => {\n\t\t\tassert.equal(checkBashInterception('find . -name \"*.ts\"', [\"read\", \"grep\"]).block, false);\n\t\t});\n\t});\n\n\tdescribe(\"edit rule (sed/perl/awk)\", () => {\n\t\tit(\"blocks sed -i\", () => {\n\t\t\tassert.equal(checkBashInterception(\"sed -i 's/foo/bar/' file.ts\", ALL_TOOLS).block, true);\n\t\t\tassert.equal(checkBashInterception(\"sed --in-place 's/x/y/' f\", ALL_TOOLS).block, true);\n\t\t});\n\n\t\tit(\"does NOT block sed without -i (read-only)\", () => {\n\t\t\tassert.equal(checkBashInterception(\"sed 's/foo/bar/' file.ts\", ALL_TOOLS).block, false);\n\t\t});\n\n\t\tit(\"blocks perl -pi and perl -p -i\", () => {\n\t\t\tassert.equal(checkBashInterception(\"perl -pi -e 's/foo/bar/' file\", ALL_TOOLS).block, true);\n\t\t\tassert.equal(checkBashInterception(\"perl -p -i -e 's/x/y/' f\", ALL_TOOLS).block, true);\n\t\t});\n\n\t\tit(\"blocks awk -i inplace\", () => {\n\t\t\tassert.equal(checkBashInterception(\"awk -i inplace '{print}' file\", ALL_TOOLS).block, true);\n\t\t});\n\n\t\tit(\"does NOT block when edit tool is absent\", () => {\n\t\t\tassert.equal(checkBashInterception(\"sed -i 's/a/b/' f\", [\"read\", \"grep\"]).block, false);\n\t\t});\n\t});\n\n\tdescribe(\"write rule (echo/printf/heredoc redirect)\", () => {\n\t\tit(\"blocks echo with > redirect\", () => {\n\t\t\tassert.equal(checkBashInterception(\"echo hello > file.txt\", ALL_TOOLS).block, true);\n\t\t});\n\n\t\tit(\"blocks printf with > redirect\", () => {\n\t\t\tassert.equal(checkBashInterception('printf \"%s\" content > out.txt', ALL_TOOLS).block, true);\n\t\t});\n\n\t\tit(\"does NOT block echo without redirect\", () => {\n\t\t\tassert.equal(checkBashInterception(\"echo hello\", ALL_TOOLS).block, false);\n\t\t});\n\n\t\tit(\"does NOT block >> append redirect (write tool does not support appending)\", () => {\n\t\t\tassert.equal(checkBashInterception(\"echo hello >> file.txt\", ALL_TOOLS).block, false);\n\t\t});\n\n\t\tit(\"does NOT block stderr redirect (2>)\", () => {\n\t\t\tassert.equal(checkBashInterception(\"echo test 2> /dev/null\", ALL_TOOLS).block, false);\n\t\t});\n\n\t\tit(\"does NOT block pipe (echo foo | grep bar)\", () => {\n\t\t\tassert.equal(checkBashInterception(\"echo foo | grep bar\", ALL_TOOLS).block, false);\n\t\t});\n\n\t\tit(\"does NOT block when write tool is absent\", () => {\n\t\t\tassert.equal(checkBashInterception(\"echo hello > file.txt\", [\"read\", \"grep\"]).block, false);\n\t\t});\n\t});\n\n\tdescribe(\"pass-through commands\", () => {\n\t\tit(\"passes npm install\", () => {\n\t\t\tassert.equal(checkBashInterception(\"npm install\", ALL_TOOLS).block, false);\n\t\t});\n\n\t\tit(\"passes ls > output.txt (not an echo/printf/cat)\", () => {\n\t\t\tassert.equal(checkBashInterception(\"ls > output.txt\", ALL_TOOLS).block, false);\n\t\t});\n\n\t\tit(\"passes tee file.txt\", () => {\n\t\t\tassert.equal(checkBashInterception(\"tee file.txt\", ALL_TOOLS).block, false);\n\t\t});\n\n\t\tit(\"passes git log\", () => {\n\t\t\tassert.equal(checkBashInterception(\"git log --oneline\", ALL_TOOLS).block, false);\n\t\t});\n\t});\n\n\tdescribe(\"block message content\", () => {\n\t\tit(\"includes the original command in the block message\", () => {\n\t\t\tconst r = checkBashInterception(\"cat README.md\", ALL_TOOLS);\n\t\t\tassert.ok(r.message?.includes(\"cat README.md\"), \"message should contain original command\");\n\t\t});\n\n\t\tit(\"returns block:false with no message when not blocked\", () => {\n\t\t\tconst r = checkBashInterception(\"npm install\", ALL_TOOLS);\n\t\t\tassert.equal(r.block, false);\n\t\t\tassert.equal(r.message, undefined);\n\t\t});\n\t});\n});\n\ndescribe(\"compileInterceptor\", () => {\n\tit(\"produces same results as checkBashInterception\", () => {\n\t\tconst interceptor = compileInterceptor(DEFAULT_BASH_INTERCEPTOR_RULES);\n\t\tconst cases: [string, string[], boolean][] = [\n\t\t\t[\"cat README.md\", ALL_TOOLS, true],\n\t\t\t[\"npm install\", ALL_TOOLS, false],\n\t\t\t[\"grep foo bar\", ALL_TOOLS, true],\n\t\t\t[\"echo hello >> file\", ALL_TOOLS, false],\n\t\t\t[\"echo test 2> /dev/null\", ALL_TOOLS, false],\n\t\t];\n\t\tfor (const [cmd, tools, expected] of cases) {\n\t\t\tassert.equal(\n\t\t\t\tinterceptor.check(cmd, tools).block,\n\t\t\t\texpected,\n\t\t\t\t`pre-compiled: \"${cmd}\" expected block=${expected}`,\n\t\t\t);\n\t\t}\n\t});\n\n\tit(\"silently skips rules with invalid regex patterns\", () => {\n\t\tconst rules: BashInterceptorRule[] = [\n\t\t\t{ pattern: \"[invalid(\", tool: \"read\", message: \"broken\" },\n\t\t\t{ pattern: \"^\\\\s*cat\\\\s+\", tool: \"read\", message: \"valid\" },\n\t\t];\n\t\tconst interceptor = compileInterceptor(rules);\n\t\tassert.equal(interceptor.check(\"cat file.txt\", [\"read\"]).block, true);\n\t});\n\n\tit(\"returns block:false when available tools list is empty\", () => {\n\t\tconst interceptor = compileInterceptor(DEFAULT_BASH_INTERCEPTOR_RULES);\n\t\tassert.equal(interceptor.check(\"cat README.md\", []).block, false);\n\t});\n\n\tit(\"allows custom rule override\", () => {\n\t\tconst customRules: BashInterceptorRule[] = [\n\t\t\t{ pattern: \"^\\\\s*curl\\\\s+\", tool: \"fetch\", message: \"Use fetch tool instead.\" },\n\t\t];\n\t\tconst interceptor = compileInterceptor(customRules);\n\t\tassert.equal(interceptor.check(\"curl https://example.com\", [\"fetch\"]).block, true);\n\t\t// default rules not active\n\t\tassert.equal(interceptor.check(\"cat file.txt\", [\"read\"]).block, false);\n\t});\n});\n"]}
1
+ {"version":3,"file":"bash-interceptor.test.js","sourceRoot":"","sources":["../../../src/core/tools/bash-interceptor.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport {\n\tcheckBashInterception,\n\tcompileInterceptor,\n\tDEFAULT_BASH_INTERCEPTOR_RULES,\n\ttype BashInterceptorRule,\n} from \"./bash-interceptor.js\";\n\nconst ALL_TOOLS = [\"read\", \"grep\", \"find\", \"edit\", \"write\"];\nconst NO_TOOLS: string[] = [];\n\ndescribe(\"checkBashInterception\", () => {\n\tdescribe(\"read rule (cat/head/tail/less/more)\", () => {\n\t\tit(\"blocks cat with a file argument\", () => {\n\t\t\tconst r = checkBashInterception(\"cat README.md\", ALL_TOOLS);\n\t\t\tassert.equal(r.block, true);\n\t\t\tassert.equal(r.suggestedTool, \"read\");\n\t\t});\n\n\t\tit(\"blocks head and tail\", () => {\n\t\t\tassert.equal(checkBashInterception(\"head -n 20 file.ts\", ALL_TOOLS).block, true);\n\t\t\tassert.equal(checkBashInterception(\"tail -f app.log\", ALL_TOOLS).block, true);\n\t\t});\n\n\t\tit(\"does NOT block cat used as heredoc (cat <<EOF)\", () => {\n\t\t\tconst r = checkBashInterception(\"cat <<EOF > file.txt\", ALL_TOOLS);\n\t\t\tassert.notEqual(r.suggestedTool, \"read\");\n\t\t});\n\n\t\tit(\"does NOT block when read tool is absent\", () => {\n\t\t\tassert.equal(checkBashInterception(\"cat README.md\", NO_TOOLS).block, false);\n\t\t\tassert.equal(checkBashInterception(\"cat README.md\", [\"grep\"]).block, false);\n\t\t});\n\t});\n\n\tdescribe(\"grep rule\", () => {\n\t\tit(\"blocks grep and rg\", () => {\n\t\t\tassert.equal(checkBashInterception(\"grep foo bar.ts\", ALL_TOOLS).block, true);\n\t\t\tassert.equal(checkBashInterception(\"rg -r pattern .\", ALL_TOOLS).block, true);\n\t\t});\n\n\t\tit(\"blocks grep with leading whitespace\", () => {\n\t\t\tassert.equal(checkBashInterception(\" grep -r foo .\", ALL_TOOLS).block, true);\n\t\t});\n\n\t\tit(\"does NOT block when grep tool is absent\", () => {\n\t\t\tassert.equal(checkBashInterception(\"grep foo bar\", [\"read\", \"edit\"]).block, false);\n\t\t});\n\t});\n\n\tdescribe(\"find rule\", () => {\n\t\tit(\"blocks find with -name flag\", () => {\n\t\t\tassert.equal(checkBashInterception('find . -name \"*.ts\"', ALL_TOOLS).block, true);\n\t\t});\n\n\t\tit(\"blocks find with -type flag\", () => {\n\t\t\tassert.equal(checkBashInterception(\"find /tmp -maxdepth 1 -type f\", ALL_TOOLS).block, true);\n\t\t});\n\n\t\tit(\"does NOT block find without name/type flags\", () => {\n\t\t\tassert.equal(checkBashInterception(\"find /tmp -maxdepth 1\", ALL_TOOLS).block, false);\n\t\t});\n\n\t\tit(\"does NOT block when find tool is absent\", () => {\n\t\t\tassert.equal(checkBashInterception('find . -name \"*.ts\"', [\"read\", \"grep\"]).block, false);\n\t\t});\n\t});\n\n\tdescribe(\"edit rule (sed/perl/awk)\", () => {\n\t\tit(\"blocks sed -i\", () => {\n\t\t\tassert.equal(checkBashInterception(\"sed -i 's/foo/bar/' file.ts\", ALL_TOOLS).block, true);\n\t\t\tassert.equal(checkBashInterception(\"sed --in-place 's/x/y/' f\", ALL_TOOLS).block, true);\n\t\t});\n\n\t\tit(\"does NOT block sed without -i (read-only)\", () => {\n\t\t\tassert.equal(checkBashInterception(\"sed 's/foo/bar/' file.ts\", ALL_TOOLS).block, false);\n\t\t});\n\n\t\tit(\"blocks perl -pi and perl -p -i\", () => {\n\t\t\tassert.equal(checkBashInterception(\"perl -pi -e 's/foo/bar/' file\", ALL_TOOLS).block, true);\n\t\t\tassert.equal(checkBashInterception(\"perl -p -i -e 's/x/y/' f\", ALL_TOOLS).block, true);\n\t\t});\n\n\t\tit(\"blocks awk -i inplace\", () => {\n\t\t\tassert.equal(checkBashInterception(\"awk -i inplace '{print}' file\", ALL_TOOLS).block, true);\n\t\t});\n\n\t\tit(\"does NOT block when edit tool is absent\", () => {\n\t\t\tassert.equal(checkBashInterception(\"sed -i 's/a/b/' f\", [\"read\", \"grep\"]).block, false);\n\t\t});\n\t});\n\n\tdescribe(\"write rule (echo/printf/heredoc redirect)\", () => {\n\t\tit(\"blocks echo with > redirect\", () => {\n\t\t\tassert.equal(checkBashInterception(\"echo hello > file.txt\", ALL_TOOLS).block, true);\n\t\t});\n\n\t\tit(\"blocks printf with > redirect\", () => {\n\t\t\tassert.equal(checkBashInterception('printf \"%s\" content > out.txt', ALL_TOOLS).block, true);\n\t\t});\n\n\t\tit(\"does NOT block echo without redirect\", () => {\n\t\t\tassert.equal(checkBashInterception(\"echo hello\", ALL_TOOLS).block, false);\n\t\t});\n\n\t\tit(\"does NOT block >> append redirect (write tool does not support appending)\", () => {\n\t\t\tassert.equal(checkBashInterception(\"echo hello >> file.txt\", ALL_TOOLS).block, false);\n\t\t});\n\n\t\tit(\"does NOT block stderr redirect (2>)\", () => {\n\t\t\tassert.equal(checkBashInterception(\"echo test 2> /dev/null\", ALL_TOOLS).block, false);\n\t\t});\n\n\t\tit(\"does NOT block pipe (echo foo | grep bar)\", () => {\n\t\t\tassert.equal(checkBashInterception(\"echo foo | grep bar\", ALL_TOOLS).block, false);\n\t\t});\n\n\t\tit(\"does NOT block when write tool is absent\", () => {\n\t\t\tassert.equal(checkBashInterception(\"echo hello > file.txt\", [\"read\", \"grep\"]).block, false);\n\t\t});\n\t});\n\n\tdescribe(\"pass-through commands\", () => {\n\t\tit(\"passes npm install\", () => {\n\t\t\tassert.equal(checkBashInterception(\"npm install\", ALL_TOOLS).block, false);\n\t\t});\n\n\t\tit(\"passes ls > output.txt (not an echo/printf/cat)\", () => {\n\t\t\tassert.equal(checkBashInterception(\"ls > output.txt\", ALL_TOOLS).block, false);\n\t\t});\n\n\t\tit(\"passes tee file.txt\", () => {\n\t\t\tassert.equal(checkBashInterception(\"tee file.txt\", ALL_TOOLS).block, false);\n\t\t});\n\n\t\tit(\"passes git log\", () => {\n\t\t\tassert.equal(checkBashInterception(\"git log --oneline\", ALL_TOOLS).block, false);\n\t\t});\n\t});\n\n\tdescribe(\"block message content\", () => {\n\t\tit(\"includes the original command in the block message\", () => {\n\t\t\tconst r = checkBashInterception(\"cat README.md\", ALL_TOOLS);\n\t\t\tassert.ok(r.message?.includes(\"cat README.md\"), \"message should contain original command\");\n\t\t});\n\n\t\tit(\"uses 'Tool routing:' prefix to distinguish from permission blocks\", () => {\n\t\t\tconst r = checkBashInterception(\"cat README.md\", ALL_TOOLS);\n\t\t\tassert.ok(r.message?.startsWith(\"Tool routing:\"), \"message should start with 'Tool routing:'\");\n\t\t\tassert.ok(r.message?.includes(\"not a permission block\"), \"message should clarify it's not a permission block\");\n\t\t});\n\n\t\tit(\"returns block:false with no message when not blocked\", () => {\n\t\t\tconst r = checkBashInterception(\"npm install\", ALL_TOOLS);\n\t\t\tassert.equal(r.block, false);\n\t\t\tassert.equal(r.message, undefined);\n\t\t});\n\t});\n});\n\ndescribe(\"compileInterceptor\", () => {\n\tit(\"produces same results as checkBashInterception\", () => {\n\t\tconst interceptor = compileInterceptor(DEFAULT_BASH_INTERCEPTOR_RULES);\n\t\tconst cases: [string, string[], boolean][] = [\n\t\t\t[\"cat README.md\", ALL_TOOLS, true],\n\t\t\t[\"npm install\", ALL_TOOLS, false],\n\t\t\t[\"grep foo bar\", ALL_TOOLS, true],\n\t\t\t[\"echo hello >> file\", ALL_TOOLS, false],\n\t\t\t[\"echo test 2> /dev/null\", ALL_TOOLS, false],\n\t\t];\n\t\tfor (const [cmd, tools, expected] of cases) {\n\t\t\tassert.equal(\n\t\t\t\tinterceptor.check(cmd, tools).block,\n\t\t\t\texpected,\n\t\t\t\t`pre-compiled: \"${cmd}\" expected block=${expected}`,\n\t\t\t);\n\t\t}\n\t});\n\n\tit(\"silently skips rules with invalid regex patterns\", () => {\n\t\tconst rules: BashInterceptorRule[] = [\n\t\t\t{ pattern: \"[invalid(\", tool: \"read\", message: \"broken\" },\n\t\t\t{ pattern: \"^\\\\s*cat\\\\s+\", tool: \"read\", message: \"valid\" },\n\t\t];\n\t\tconst interceptor = compileInterceptor(rules);\n\t\tassert.equal(interceptor.check(\"cat file.txt\", [\"read\"]).block, true);\n\t});\n\n\tit(\"returns block:false when available tools list is empty\", () => {\n\t\tconst interceptor = compileInterceptor(DEFAULT_BASH_INTERCEPTOR_RULES);\n\t\tassert.equal(interceptor.check(\"cat README.md\", []).block, false);\n\t});\n\n\tit(\"allows custom rule override\", () => {\n\t\tconst customRules: BashInterceptorRule[] = [\n\t\t\t{ pattern: \"^\\\\s*curl\\\\s+\", tool: \"fetch\", message: \"Use fetch tool instead.\" },\n\t\t];\n\t\tconst interceptor = compileInterceptor(customRules);\n\t\tassert.equal(interceptor.check(\"curl https://example.com\", [\"fetch\"]).block, true);\n\t\t// default rules not active\n\t\tassert.equal(interceptor.check(\"cat file.txt\", [\"read\"]).block, false);\n\t});\n});\n"]}
@@ -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,EAAgB,KAAK,GAAG,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAGN,KAAK,gBAAgB,EAErB,MAAM,iCAAiC,CAAC;AASzC,KAAK,cAAc,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE3C,qBAAa,sBAAuB,SAAQ,SAAS;IACpD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,SAAS,CAAM;IACvB,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,UAAU,CAAiB;IACnC,OAAO,CAAC,gBAAgB,CAAY;IACpC,OAAO,CAAC,EAAE,CAAM;IAChB,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,SAAS,CAAU;IAE3B,OAAO,CAAC,UAAU,CAAO;gBAGxB,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,GAAG,EACP,kBAAkB,UAAQ,EAC1B,UAAU,GAAE,cAAyB,EACrC,UAAU,UAAQ,EAClB,SAAS,UAAQ;IA6BlB,kCAAkC;IAClC,OAAO,CAAC,eAAe;IAQvB;;;OAGG;IACH,OAAO,IAAI,IAAI;IAIf;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;IAKpC,aAAa,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAOhC,UAAU,IAAI,IAAI;IAK3B,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAOjC,WAAW,CACV,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,SAAS,EAAE,OAAO,EAClB,gBAAgB,CAAC,EAAE,gBAAgB,EACnC,cAAc,CAAC,EAAE,MAAM,EACvB,SAAS,CAAC,EAAE,OAAO,GACjB,IAAI;IAmBP,OAAO,CAAC,aAAa;IA2FrB;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,UAAU,IAAI,MAAM;CAGpB"}
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,EAAgB,KAAK,GAAG,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAGN,KAAK,gBAAgB,EAErB,MAAM,iCAAiC,CAAC;AA4BzC,KAAK,cAAc,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE3C,qBAAa,sBAAuB,SAAQ,SAAS;IACpD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,WAAW,CAAgB;IACnC,OAAO,CAAC,SAAS,CAAM;IACvB,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,UAAU,CAAiB;IACnC,OAAO,CAAC,gBAAgB,CAAY;IACpC,OAAO,CAAC,EAAE,CAAM;IAChB,OAAO,CAAC,QAAQ,CAAa;IAC7B,OAAO,CAAC,SAAS,CAAU;IAE3B,OAAO,CAAC,UAAU,CAAO;gBAGxB,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,GAAG,EACP,kBAAkB,UAAQ,EAC1B,UAAU,GAAE,cAAyB,EACrC,UAAU,UAAQ,EAClB,SAAS,UAAQ;IA6BlB,kCAAkC;IAClC,OAAO,CAAC,eAAe;IAQvB;;;OAGG;IACH,OAAO,IAAI,IAAI;IAIf;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;IAKpC,aAAa,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAOhC,UAAU,IAAI,IAAI;IAK3B,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAOjC,WAAW,CACV,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,SAAS,EAAE,OAAO,EAClB,gBAAgB,CAAC,EAAE,gBAAgB,EACnC,cAAc,CAAC,EAAE,MAAM,EACvB,SAAS,CAAC,EAAE,OAAO,GACjB,IAAI;IAmBP,OAAO,CAAC,aAAa;IAkGrB;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,UAAU,IAAI,MAAM;CAGpB"}
@@ -9,6 +9,30 @@ import { editorKey, keyHint } from "./keybinding-hints.js";
9
9
  import { truncateToVisualLines } from "./visual-truncate.js";
10
10
  // Preview line limit when not expanded (matches tool execution behavior)
11
11
  const PREVIEW_LINES = 20;
12
+ /**
13
+ * Returns true if the command failure looks like a privilege/sudo escalation
14
+ * error that the agent cannot resolve — distinct from an OS sandbox policy block.
15
+ */
16
+ function isPrivilegeError(output, command) {
17
+ // Already handled by sandbox-policy path
18
+ if (/sandbox blocked this operation/i.test(output))
19
+ return false;
20
+ // sudo explicitly rejected
21
+ if (/sudo.*operation not permitted/i.test(output))
22
+ return true;
23
+ if (/command exited with code 126/i.test(output) && /sudo/i.test(output))
24
+ return true;
25
+ // Agent process itself hit EPERM (e.g. npm cache owned by root)
26
+ if (/EPERM|operation not permitted/i.test(output) && /sudo/i.test(command))
27
+ return true;
28
+ // npm cache root-owned files pattern
29
+ if (/cache folder contains root-owned files/i.test(output))
30
+ return true;
31
+ // Generic privilege denial patterns
32
+ if (/permission denied/i.test(output) && /sudo/i.test(command))
33
+ return true;
34
+ return false;
35
+ }
12
36
  export class BashExecutionComponent extends Container {
13
37
  constructor(command, ui, excludeFromContext = false, renderMode = "normal", _rtkActive = false, sandboxed = false) {
14
38
  super();
@@ -151,6 +175,10 @@ export class BashExecutionComponent extends Container {
151
175
  if (this.sandboxed && /operation not permitted/i.test(fullOutput)) {
152
176
  statusParts.push(theme.fg("warning", "Sandbox blocked this operation. Run /sandbox to inspect the active policy and allowed paths."));
153
177
  }
178
+ else if (!this.sandboxed && isPrivilegeError(fullOutput, this.command)) {
179
+ statusParts.push(theme.fg("warning", "⚠ This command requires elevated privileges the agent cannot use."));
180
+ statusParts.push(theme.fg("muted", `Run it manually in your terminal:\n ${this.command}`));
181
+ }
154
182
  }
155
183
  // Add truncation warning (context truncation, not preview truncation)
156
184
  const wasTruncated = this.truncationResult?.truncated || contextTruncation.truncated;
@@ -1 +1 @@
1
- {"version":3,"file":"bash-execution.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/bash-execution.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Component for displaying bash command execution with streaming output.\n */\n\nimport { Container, Loader, Text, type TUI } from \"@gsd/pi-tui\";\nimport {\n\tDEFAULT_MAX_BYTES,\n\tDEFAULT_MAX_LINES,\n\ttype TruncationResult,\n\ttruncateTail,\n} from \"../../../core/tools/truncate.js\";\nimport { renderTerminalLines } from \"../../../utils/terminal-serializer.js\";\nimport { theme, type ThemeColor } from \"../theme/theme.js\";\nimport { editorKey, keyHint } from \"./keybinding-hints.js\";\nimport { truncateToVisualLines } from \"./visual-truncate.js\";\n\n// Preview line limit when not expanded (matches tool execution behavior)\nconst PREVIEW_LINES = 20;\n\ntype ToolOutputMode = \"minimal\" | \"normal\";\n\nexport class BashExecutionComponent extends Container {\n\tprivate command: string;\n\tprivate outputLines: string[] = [];\n\tprivate rawOutput = \"\";\n\tprivate status: \"running\" | \"complete\" | \"cancelled\" | \"error\" = \"running\";\n\tprivate exitCode: number | undefined = undefined;\n\tprivate loader: Loader;\n\tprivate truncationResult?: TruncationResult;\n\tprivate fullOutputPath?: string;\n\tprivate expanded = false;\n\tprivate renderMode: ToolOutputMode;\n\tprivate contentContainer: Container;\n\tprivate ui: TUI;\n\tprivate colorKey: ThemeColor;\n\tprivate sandboxed: boolean;\n\t// Dedicated header node\n\tprivate headerText: Text;\n\n\tconstructor(\n\t\tcommand: string,\n\t\tui: TUI,\n\t\texcludeFromContext = false,\n\t\trenderMode: ToolOutputMode = \"normal\",\n\t\t_rtkActive = false,\n\t\tsandboxed = false,\n\t) {\n\t\tsuper();\n\t\tthis.command = command;\n\t\tthis.ui = ui;\n\t\tthis.renderMode = renderMode;\n\t\tthis.sandboxed = sandboxed;\n\n\t\t// Use dim tone for excluded-from-context commands (!! prefix)\n\t\tthis.colorKey = (excludeFromContext ? \"dim\" : \"bashMode\") as ThemeColor;\n\n\t\t// Content container\n\t\tthis.contentContainer = new Container();\n\t\tthis.addChild(this.contentContainer);\n\n\t\t// Header Text node\n\t\tthis.headerText = new Text(this.buildHeaderText(), 1, 0);\n\t\tthis.contentContainer.addChild(this.headerText);\n\n\t\t// Loader\n\t\tthis.loader = new Loader(\n\t\t\tui,\n\t\t\t(spinner) => theme.fg(this.colorKey, spinner),\n\t\t\t(text) => theme.fg(\"muted\", text),\n\t\t\t`Running... (${editorKey(\"selectCancel\")} to cancel)`, // Plain text for loader\n\t\t);\n\t\tthis.contentContainer.addChild(this.loader);\n\t}\n\n\t/** Build the header line text. */\n\tprivate buildHeaderText(): string {\n\t\tlet text = `${theme.fg(\"toolTitle\", theme.bold(\"bash\"))} ${theme.fg(this.colorKey, theme.bold(`$ ${this.command}`))}`;\n\t\tif (this.sandboxed) {\n\t\t\ttext += ` ${theme.fg(\"success\", \"[sandboxed]\")}`;\n\t\t}\n\t\treturn text;\n\t}\n\n\t/**\n\t * Stop all timers and release resources. Call when removing the component\n\t * from the tree before setComplete() has been called (e.g. on clear/cancel).\n\t */\n\tdispose(): void {\n\t\tthis.loader.dispose();\n\t}\n\n\t/**\n\t * Set whether the output is expanded (shows full output) or collapsed (preview only).\n\t */\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetRenderMode(mode: ToolOutputMode): void {\n\t\tif (this.renderMode !== mode) {\n\t\t\tthis.renderMode = mode;\n\t\t\tthis.updateDisplay();\n\t\t}\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\tappendOutput(chunk: string): void {\n\t\t// Strip ANSI codes and preserve carriage-return semantics for display.\n\t\tthis.rawOutput += chunk;\n\t\tthis.outputLines = renderTerminalLines(this.rawOutput);\n\t\tthis.updateDisplay();\n\t}\n\n\tsetComplete(\n\t\texitCode: number | undefined,\n\t\tcancelled: boolean,\n\t\ttruncationResult?: TruncationResult,\n\t\tfullOutputPath?: string,\n\t\tsandboxed?: boolean,\n\t): void {\n\t\tthis.exitCode = exitCode;\n\t\tthis.status = cancelled\n\t\t\t? \"cancelled\"\n\t\t\t: exitCode !== 0 && exitCode !== undefined && exitCode !== null\n\t\t\t\t? \"error\"\n\t\t\t\t: \"complete\";\n\t\tthis.truncationResult = truncationResult;\n\t\tthis.fullOutputPath = fullOutputPath;\n\t\tif (sandboxed !== undefined) {\n\t\t\tthis.sandboxed = sandboxed;\n\t\t}\n\n\t\t// Stop loader\n\t\tthis.loader.stop();\n\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate updateDisplay(): void {\n\t\t// Apply truncation for LLM context limits (same limits as bash tool)\n\t\tconst fullOutput = this.outputLines.join(\"\\n\");\n\t\tconst contextTruncation = truncateTail(fullOutput, {\n\t\t\tmaxLines: DEFAULT_MAX_LINES,\n\t\t\tmaxBytes: DEFAULT_MAX_BYTES,\n\t\t});\n\n\t\t// Get the lines to potentially display (after context truncation)\n\t\tconst availableLines = contextTruncation.content ? contextTruncation.content.split(\"\\n\") : [];\n\n\t\t// Apply preview truncation based on expanded state\n\t\tconst previewLogicalLines = availableLines.slice(-PREVIEW_LINES);\n\t\tconst hiddenLineCount = availableLines.length - previewLogicalLines.length;\n\n\t\t// Rebuild content container\n\t\tthis.contentContainer.clear();\n\n\t\t// Header — re-add the dedicated node (clear() removed it, setText keeps its current value)\n\t\tthis.contentContainer.addChild(this.headerText);\n\n\t\t// Output\n\t\tif (availableLines.length > 0) {\n\t\t\tif (this.expanded) {\n\t\t\t\t// Show all lines\n\t\t\t\tconst displayText = availableLines.map((line) => theme.fg(\"muted\", line)).join(\"\\n\");\n\t\t\t\tthis.contentContainer.addChild(new Text(`\\n${displayText}`, 1, 0));\n\t\t\t} else if (this.renderMode === \"minimal\") {\n\t\t\t\t// collapsed — no inline hint needed (shown in editor bottom border)\n\t\t\t} else {\n\t\t\t\t// Use shared visual truncation utility\n\t\t\t\tconst styledOutput = previewLogicalLines.map((line) => theme.fg(\"muted\", line)).join(\"\\n\");\n\t\t\t\tconst { visualLines } = truncateToVisualLines(\n\t\t\t\t\t`\\n${styledOutput}`,\n\t\t\t\t\tPREVIEW_LINES,\n\t\t\t\t\tthis.ui.terminal.columns,\n\t\t\t\t\t1, // padding\n\t\t\t\t);\n\t\t\t\tthis.contentContainer.addChild({ render: () => visualLines, invalidate: () => {} });\n\t\t\t}\n\t\t}\n\n\t\t// Loader or status\n\t\tif (this.status === \"running\") {\n\t\t\tthis.contentContainer.addChild(this.loader);\n\t\t} else {\n\t\t\tconst statusParts: string[] = [];\n\n\t\t\t// Show expand/collapse hint whenever there is output\n\t\t\tif (availableLines.length > 0) {\n\t\t\t\tif (this.expanded) {\n\t\t\t\t\tstatusParts.push(`(${keyHint(\"expandTools\", \"to collapse\")})`);\n\t\t\t\t} else if (this.renderMode === \"minimal\") {\n\t\t\t\t\tstatusParts.push(`(${keyHint(\"expandTools\", \"to expand\")})`);\n\t\t\t\t} else if (hiddenLineCount > 0) {\n\t\t\t\t\t// Normal mode: show line count + hint\n\t\t\t\t\tstatusParts.push(\n\t\t\t\t\t\t`${theme.fg(\"muted\", `... ${hiddenLineCount} more lines`)} (${keyHint(\"expandTools\", \"to expand\")})`,\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\t// Normal mode: all preview lines visible, still offer expand\n\t\t\t\t\tstatusParts.push(`(${keyHint(\"expandTools\", \"to expand\")})`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (this.status === \"cancelled\") {\n\t\t\t\tstatusParts.push(theme.fg(\"warning\", \"(cancelled)\"));\n\t\t\t} else if (this.status === \"error\") {\n\t\t\t\tstatusParts.push(theme.fg(\"error\", `(exit ${this.exitCode})`));\n\t\t\t\tif (this.sandboxed && /operation not permitted/i.test(fullOutput)) {\n\t\t\t\t\tstatusParts.push(\n\t\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t\t\"Sandbox blocked this operation. Run /sandbox to inspect the active policy and allowed paths.\",\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add truncation warning (context truncation, not preview truncation)\n\t\t\tconst wasTruncated = this.truncationResult?.truncated || contextTruncation.truncated;\n\t\t\tif (wasTruncated && this.fullOutputPath) {\n\t\t\t\tstatusParts.push(theme.fg(\"warning\", `Output truncated. Full output: ${this.fullOutputPath}`));\n\t\t\t}\n\n\t\t\tif (statusParts.length > 0) {\n\t\t\t\tthis.contentContainer.addChild(new Text(`\\n${statusParts.join(\"\\n\")}`, 1, 0));\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Get the raw output for creating BashExecutionMessage.\n\t */\n\tgetOutput(): string {\n\t\treturn this.outputLines.join(\"\\n\");\n\t}\n\n\t/**\n\t * Get the command that was executed.\n\t */\n\tgetCommand(): string {\n\t\treturn this.command;\n\t}\n}\n"]}
1
+ {"version":3,"file":"bash-execution.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/bash-execution.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Component for displaying bash command execution with streaming output.\n */\n\nimport { Container, Loader, Text, type TUI } from \"@gsd/pi-tui\";\nimport {\n\tDEFAULT_MAX_BYTES,\n\tDEFAULT_MAX_LINES,\n\ttype TruncationResult,\n\ttruncateTail,\n} from \"../../../core/tools/truncate.js\";\nimport { renderTerminalLines } from \"../../../utils/terminal-serializer.js\";\nimport { theme, type ThemeColor } from \"../theme/theme.js\";\nimport { editorKey, keyHint } from \"./keybinding-hints.js\";\nimport { truncateToVisualLines } from \"./visual-truncate.js\";\n\n// Preview line limit when not expanded (matches tool execution behavior)\nconst PREVIEW_LINES = 20;\n\n/**\n * Returns true if the command failure looks like a privilege/sudo escalation\n * error that the agent cannot resolve — distinct from an OS sandbox policy block.\n */\nfunction isPrivilegeError(output: string, command: string): boolean {\n\t// Already handled by sandbox-policy path\n\tif (/sandbox blocked this operation/i.test(output)) return false;\n\t// sudo explicitly rejected\n\tif (/sudo.*operation not permitted/i.test(output)) return true;\n\tif (/command exited with code 126/i.test(output) && /sudo/i.test(output)) return true;\n\t// Agent process itself hit EPERM (e.g. npm cache owned by root)\n\tif (/EPERM|operation not permitted/i.test(output) && /sudo/i.test(command)) return true;\n\t// npm cache root-owned files pattern\n\tif (/cache folder contains root-owned files/i.test(output)) return true;\n\t// Generic privilege denial patterns\n\tif (/permission denied/i.test(output) && /sudo/i.test(command)) return true;\n\treturn false;\n}\n\ntype ToolOutputMode = \"minimal\" | \"normal\";\n\nexport class BashExecutionComponent extends Container {\n\tprivate command: string;\n\tprivate outputLines: string[] = [];\n\tprivate rawOutput = \"\";\n\tprivate status: \"running\" | \"complete\" | \"cancelled\" | \"error\" = \"running\";\n\tprivate exitCode: number | undefined = undefined;\n\tprivate loader: Loader;\n\tprivate truncationResult?: TruncationResult;\n\tprivate fullOutputPath?: string;\n\tprivate expanded = false;\n\tprivate renderMode: ToolOutputMode;\n\tprivate contentContainer: Container;\n\tprivate ui: TUI;\n\tprivate colorKey: ThemeColor;\n\tprivate sandboxed: boolean;\n\t// Dedicated header node\n\tprivate headerText: Text;\n\n\tconstructor(\n\t\tcommand: string,\n\t\tui: TUI,\n\t\texcludeFromContext = false,\n\t\trenderMode: ToolOutputMode = \"normal\",\n\t\t_rtkActive = false,\n\t\tsandboxed = false,\n\t) {\n\t\tsuper();\n\t\tthis.command = command;\n\t\tthis.ui = ui;\n\t\tthis.renderMode = renderMode;\n\t\tthis.sandboxed = sandboxed;\n\n\t\t// Use dim tone for excluded-from-context commands (!! prefix)\n\t\tthis.colorKey = (excludeFromContext ? \"dim\" : \"bashMode\") as ThemeColor;\n\n\t\t// Content container\n\t\tthis.contentContainer = new Container();\n\t\tthis.addChild(this.contentContainer);\n\n\t\t// Header Text node\n\t\tthis.headerText = new Text(this.buildHeaderText(), 1, 0);\n\t\tthis.contentContainer.addChild(this.headerText);\n\n\t\t// Loader\n\t\tthis.loader = new Loader(\n\t\t\tui,\n\t\t\t(spinner) => theme.fg(this.colorKey, spinner),\n\t\t\t(text) => theme.fg(\"muted\", text),\n\t\t\t`Running... (${editorKey(\"selectCancel\")} to cancel)`, // Plain text for loader\n\t\t);\n\t\tthis.contentContainer.addChild(this.loader);\n\t}\n\n\t/** Build the header line text. */\n\tprivate buildHeaderText(): string {\n\t\tlet text = `${theme.fg(\"toolTitle\", theme.bold(\"bash\"))} ${theme.fg(this.colorKey, theme.bold(`$ ${this.command}`))}`;\n\t\tif (this.sandboxed) {\n\t\t\ttext += ` ${theme.fg(\"success\", \"[sandboxed]\")}`;\n\t\t}\n\t\treturn text;\n\t}\n\n\t/**\n\t * Stop all timers and release resources. Call when removing the component\n\t * from the tree before setComplete() has been called (e.g. on clear/cancel).\n\t */\n\tdispose(): void {\n\t\tthis.loader.dispose();\n\t}\n\n\t/**\n\t * Set whether the output is expanded (shows full output) or collapsed (preview only).\n\t */\n\tsetExpanded(expanded: boolean): void {\n\t\tthis.expanded = expanded;\n\t\tthis.updateDisplay();\n\t}\n\n\tsetRenderMode(mode: ToolOutputMode): void {\n\t\tif (this.renderMode !== mode) {\n\t\t\tthis.renderMode = mode;\n\t\t\tthis.updateDisplay();\n\t\t}\n\t}\n\n\toverride invalidate(): void {\n\t\tsuper.invalidate();\n\t\tthis.updateDisplay();\n\t}\n\n\tappendOutput(chunk: string): void {\n\t\t// Strip ANSI codes and preserve carriage-return semantics for display.\n\t\tthis.rawOutput += chunk;\n\t\tthis.outputLines = renderTerminalLines(this.rawOutput);\n\t\tthis.updateDisplay();\n\t}\n\n\tsetComplete(\n\t\texitCode: number | undefined,\n\t\tcancelled: boolean,\n\t\ttruncationResult?: TruncationResult,\n\t\tfullOutputPath?: string,\n\t\tsandboxed?: boolean,\n\t): void {\n\t\tthis.exitCode = exitCode;\n\t\tthis.status = cancelled\n\t\t\t? \"cancelled\"\n\t\t\t: exitCode !== 0 && exitCode !== undefined && exitCode !== null\n\t\t\t\t? \"error\"\n\t\t\t\t: \"complete\";\n\t\tthis.truncationResult = truncationResult;\n\t\tthis.fullOutputPath = fullOutputPath;\n\t\tif (sandboxed !== undefined) {\n\t\t\tthis.sandboxed = sandboxed;\n\t\t}\n\n\t\t// Stop loader\n\t\tthis.loader.stop();\n\n\t\tthis.updateDisplay();\n\t}\n\n\tprivate updateDisplay(): void {\n\t\t// Apply truncation for LLM context limits (same limits as bash tool)\n\t\tconst fullOutput = this.outputLines.join(\"\\n\");\n\t\tconst contextTruncation = truncateTail(fullOutput, {\n\t\t\tmaxLines: DEFAULT_MAX_LINES,\n\t\t\tmaxBytes: DEFAULT_MAX_BYTES,\n\t\t});\n\n\t\t// Get the lines to potentially display (after context truncation)\n\t\tconst availableLines = contextTruncation.content ? contextTruncation.content.split(\"\\n\") : [];\n\n\t\t// Apply preview truncation based on expanded state\n\t\tconst previewLogicalLines = availableLines.slice(-PREVIEW_LINES);\n\t\tconst hiddenLineCount = availableLines.length - previewLogicalLines.length;\n\n\t\t// Rebuild content container\n\t\tthis.contentContainer.clear();\n\n\t\t// Header — re-add the dedicated node (clear() removed it, setText keeps its current value)\n\t\tthis.contentContainer.addChild(this.headerText);\n\n\t\t// Output\n\t\tif (availableLines.length > 0) {\n\t\t\tif (this.expanded) {\n\t\t\t\t// Show all lines\n\t\t\t\tconst displayText = availableLines.map((line) => theme.fg(\"muted\", line)).join(\"\\n\");\n\t\t\t\tthis.contentContainer.addChild(new Text(`\\n${displayText}`, 1, 0));\n\t\t\t} else if (this.renderMode === \"minimal\") {\n\t\t\t\t// collapsed — no inline hint needed (shown in editor bottom border)\n\t\t\t} else {\n\t\t\t\t// Use shared visual truncation utility\n\t\t\t\tconst styledOutput = previewLogicalLines.map((line) => theme.fg(\"muted\", line)).join(\"\\n\");\n\t\t\t\tconst { visualLines } = truncateToVisualLines(\n\t\t\t\t\t`\\n${styledOutput}`,\n\t\t\t\t\tPREVIEW_LINES,\n\t\t\t\t\tthis.ui.terminal.columns,\n\t\t\t\t\t1, // padding\n\t\t\t\t);\n\t\t\t\tthis.contentContainer.addChild({ render: () => visualLines, invalidate: () => {} });\n\t\t\t}\n\t\t}\n\n\t\t// Loader or status\n\t\tif (this.status === \"running\") {\n\t\t\tthis.contentContainer.addChild(this.loader);\n\t\t} else {\n\t\t\tconst statusParts: string[] = [];\n\n\t\t\t// Show expand/collapse hint whenever there is output\n\t\t\tif (availableLines.length > 0) {\n\t\t\t\tif (this.expanded) {\n\t\t\t\t\tstatusParts.push(`(${keyHint(\"expandTools\", \"to collapse\")})`);\n\t\t\t\t} else if (this.renderMode === \"minimal\") {\n\t\t\t\t\tstatusParts.push(`(${keyHint(\"expandTools\", \"to expand\")})`);\n\t\t\t\t} else if (hiddenLineCount > 0) {\n\t\t\t\t\t// Normal mode: show line count + hint\n\t\t\t\t\tstatusParts.push(\n\t\t\t\t\t\t`${theme.fg(\"muted\", `... ${hiddenLineCount} more lines`)} (${keyHint(\"expandTools\", \"to expand\")})`,\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\t// Normal mode: all preview lines visible, still offer expand\n\t\t\t\t\tstatusParts.push(`(${keyHint(\"expandTools\", \"to expand\")})`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (this.status === \"cancelled\") {\n\t\t\t\tstatusParts.push(theme.fg(\"warning\", \"(cancelled)\"));\n\t\t\t} else if (this.status === \"error\") {\n\t\t\t\tstatusParts.push(theme.fg(\"error\", `(exit ${this.exitCode})`));\n\t\t\t\tif (this.sandboxed && /operation not permitted/i.test(fullOutput)) {\n\t\t\t\t\tstatusParts.push(\n\t\t\t\t\t\ttheme.fg(\n\t\t\t\t\t\t\t\"warning\",\n\t\t\t\t\t\t\t\"Sandbox blocked this operation. Run /sandbox to inspect the active policy and allowed paths.\",\n\t\t\t\t\t\t),\n\t\t\t\t\t);\n\t\t\t\t} else if (!this.sandboxed && isPrivilegeError(fullOutput, this.command)) {\n\t\t\t\t\tstatusParts.push(\n\t\t\t\t\t\ttheme.fg(\"warning\", \"⚠ This command requires elevated privileges the agent cannot use.\"),\n\t\t\t\t\t);\n\t\t\t\t\tstatusParts.push(\n\t\t\t\t\t\ttheme.fg(\"muted\", `Run it manually in your terminal:\\n ${this.command}`),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add truncation warning (context truncation, not preview truncation)\n\t\t\tconst wasTruncated = this.truncationResult?.truncated || contextTruncation.truncated;\n\t\t\tif (wasTruncated && this.fullOutputPath) {\n\t\t\t\tstatusParts.push(theme.fg(\"warning\", `Output truncated. Full output: ${this.fullOutputPath}`));\n\t\t\t}\n\n\t\t\tif (statusParts.length > 0) {\n\t\t\t\tthis.contentContainer.addChild(new Text(`\\n${statusParts.join(\"\\n\")}`, 1, 0));\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Get the raw output for creating BashExecutionMessage.\n\t */\n\tgetOutput(): string {\n\t\treturn this.outputLines.join(\"\\n\");\n\t}\n\n\t/**\n\t * Get the command that was executed.\n\t */\n\tgetCommand(): string {\n\t\treturn this.command;\n\t}\n}\n"]}
@@ -11,10 +11,13 @@ export interface SettingsConfig {
11
11
  planModeReasoningModel: string;
12
12
  planModeReviewModel: string;
13
13
  planModeCodingModel: string;
14
+ autoSuggestPlanMode: boolean;
15
+ autoSwitchPlanModel: boolean;
14
16
  showImages: boolean;
15
17
  autoResizeImages: boolean;
16
18
  blockImages: boolean;
17
19
  enableSkillCommands: boolean;
20
+ toolProfile: "balanced" | "full";
18
21
  codexRotate: boolean;
19
22
  cacheTimer: boolean;
20
23
  pinLastPrompt: boolean;
@@ -22,6 +25,7 @@ export interface SettingsConfig {
22
25
  followUpMode: "all" | "one-at-a-time";
23
26
  transport: Transport;
24
27
  thinkingLevel: ThinkingLevel;
28
+ anthropicAdaptiveByDefault: boolean;
25
29
  availableThinkingLevels: ThinkingLevel[];
26
30
  currentTheme: string;
27
31
  availableThemes: string[];
@@ -62,6 +66,8 @@ export interface SettingsCallbacks {
62
66
  onPlanModeReasoningModelChange: (modelRef: string) => void;
63
67
  onPlanModeReviewModelChange: (modelRef: string) => void;
64
68
  onPlanModeCodingModelChange: (modelRef: string) => void;
69
+ onAutoSuggestPlanModeChange: (enabled: boolean) => void;
70
+ onAutoSwitchPlanModelChange: (enabled: boolean) => void;
65
71
  onAutoDreamChange: (enabled: boolean) => void;
66
72
  onAutoMemoryChange: (enabled: boolean) => void;
67
73
  onTelegramLiveRelayAutoConnectChange: (enabled: boolean) => void;
@@ -71,6 +77,7 @@ export interface SettingsCallbacks {
71
77
  onAutoResizeImagesChange: (enabled: boolean) => void;
72
78
  onBlockImagesChange: (blocked: boolean) => void;
73
79
  onEnableSkillCommandsChange: (enabled: boolean) => void;
80
+ onToolProfileChange: (profile: "balanced" | "full") => void;
74
81
  onCodexRotateChange: (enabled: boolean) => void;
75
82
  onCacheTimerChange: (enabled: boolean) => void;
76
83
  onPinLastPromptChange: (enabled: boolean) => void;
@@ -78,6 +85,7 @@ export interface SettingsCallbacks {
78
85
  onFollowUpModeChange: (mode: "all" | "one-at-a-time") => void;
79
86
  onTransportChange: (transport: Transport) => void;
80
87
  onThinkingLevelChange: (level: ThinkingLevel) => void;
88
+ onAnthropicAdaptiveByDefaultChange: (enabled: boolean) => void;
81
89
  onThemeChange: (theme: string) => void;
82
90
  onThemePreview?: (theme: string) => void;
83
91
  onThemeAccentChange: (accent: string) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"settings-selector.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/settings-selector.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"settings-selector.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/settings-selector.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,7 @@ import { getSelectListTheme, getSettingsListTheme, getThemeAccentInfo, getThemeA
3
3
  import { DynamicBorder } from "./dynamic-border.js";
4
4
  export const THINKING_DESCRIPTIONS = {
5
5
  off: "No reasoning",
6
+ adaptive: "Claude decides when and how much to think (Claude 4.6+ only)",
6
7
  minimal: "Very brief reasoning (~1k tokens)",
7
8
  low: "Light reasoning (~2k tokens)",
8
9
  medium: "Moderate reasoning (~8k tokens)",
@@ -113,6 +114,20 @@ export class SettingsSelectorComponent extends Container {
113
114
  currentValue: config.planModeCodingModel,
114
115
  submenu: config.planModeCodingModelSubmenu,
115
116
  },
117
+ {
118
+ id: "auto-suggest-plan-mode",
119
+ label: "Auto-suggest plan mode",
120
+ description: "Ask the LLM to suggest plan mode for large/complex tasks",
121
+ currentValue: config.autoSuggestPlanMode ? "true" : "false",
122
+ values: ["true", "false"],
123
+ },
124
+ {
125
+ id: "auto-switch-plan-model",
126
+ label: "OpusPlan mode",
127
+ description: "On plan entry: auto-switch to Plan reasoning model (must be set). On approval: offer new session with Plan coding model + worker agent",
128
+ currentValue: config.autoSwitchPlanModel ? "true" : "false",
129
+ values: ["true", "false"],
130
+ },
116
131
  {
117
132
  id: "steering-mode",
118
133
  label: "Steering mode",
@@ -204,6 +219,13 @@ export class SettingsSelectorComponent extends Container {
204
219
  done(value);
205
220
  }, () => done()),
206
221
  },
222
+ {
223
+ id: "anthropic-adaptive-default",
224
+ label: "Anthropic adaptive",
225
+ description: "Default to adaptive thinking for supported Anthropic models",
226
+ currentValue: config.anthropicAdaptiveByDefault ? "true" : "false",
227
+ values: ["true", "false"],
228
+ },
207
229
  {
208
230
  id: "theme",
209
231
  label: "Theme",
@@ -276,9 +298,18 @@ export class SettingsSelectorComponent extends Container {
276
298
  currentValue: config.enableSkillCommands ? "true" : "false",
277
299
  values: ["true", "false"],
278
300
  });
279
- // Hardware cursor toggle (insert after skill-commands)
301
+ // Tool profile selector (insert after skill-commands)
280
302
  const skillCommandsIndex = items.findIndex((item) => item.id === "skill-commands");
281
303
  items.splice(skillCommandsIndex + 1, 0, {
304
+ id: "tool-profile",
305
+ label: "Tool profile",
306
+ description: "Choose the default active tool set: balanced for day-to-day coding, full to enable all available tools",
307
+ currentValue: config.toolProfile,
308
+ values: ["balanced", "full"],
309
+ });
310
+ // Codex rotate toggle (insert after tool-profile)
311
+ const toolProfileIndex = items.findIndex((item) => item.id === "tool-profile");
312
+ items.splice(toolProfileIndex + 1, 0, {
282
313
  id: "codex-rotate",
283
314
  label: "Codex rotate",
284
315
  description: "Enable automatic Codex account rotation extension",
@@ -430,6 +461,12 @@ export class SettingsSelectorComponent extends Container {
430
461
  case "plan-mode-coding-model":
431
462
  callbacks.onPlanModeCodingModelChange(newValue);
432
463
  break;
464
+ case "auto-suggest-plan-mode":
465
+ callbacks.onAutoSuggestPlanModeChange(newValue === "true");
466
+ break;
467
+ case "auto-switch-plan-model":
468
+ callbacks.onAutoSwitchPlanModelChange(newValue === "true");
469
+ break;
433
470
  case "show-images":
434
471
  callbacks.onShowImagesChange(newValue === "true");
435
472
  break;
@@ -442,6 +479,9 @@ export class SettingsSelectorComponent extends Container {
442
479
  case "skill-commands":
443
480
  callbacks.onEnableSkillCommandsChange(newValue === "true");
444
481
  break;
482
+ case "tool-profile":
483
+ callbacks.onToolProfileChange(newValue);
484
+ break;
445
485
  case "codex-rotate":
446
486
  callbacks.onCodexRotateChange(newValue === "true");
447
487
  break;
@@ -472,6 +512,9 @@ export class SettingsSelectorComponent extends Container {
472
512
  case "transport":
473
513
  callbacks.onTransportChange(newValue);
474
514
  break;
515
+ case "anthropic-adaptive-default":
516
+ callbacks.onAnthropicAdaptiveByDefaultChange(newValue === "true");
517
+ break;
475
518
  case "hide-thinking":
476
519
  callbacks.onHideThinkingBlockChange(newValue === "true");
477
520
  break;