iosm-cli 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/CHANGELOG.md +3 -1
  2. package/README.md +218 -547
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +11 -3
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/core/agent-profiles.d.ts.map +1 -1
  7. package/dist/core/agent-profiles.js +20 -5
  8. package/dist/core/agent-profiles.js.map +1 -1
  9. package/dist/core/sdk.d.ts +2 -2
  10. package/dist/core/sdk.d.ts.map +1 -1
  11. package/dist/core/sdk.js +3 -3
  12. package/dist/core/sdk.js.map +1 -1
  13. package/dist/core/slash-commands.d.ts.map +1 -1
  14. package/dist/core/slash-commands.js +4 -1
  15. package/dist/core/slash-commands.js.map +1 -1
  16. package/dist/core/system-prompt.d.ts.map +1 -1
  17. package/dist/core/system-prompt.js +34 -3
  18. package/dist/core/system-prompt.js.map +1 -1
  19. package/dist/core/tools/ast-grep.d.ts +12 -0
  20. package/dist/core/tools/ast-grep.d.ts.map +1 -0
  21. package/dist/core/tools/ast-grep.js +12 -0
  22. package/dist/core/tools/ast-grep.js.map +1 -0
  23. package/dist/core/tools/comby.d.ts +12 -0
  24. package/dist/core/tools/comby.d.ts.map +1 -0
  25. package/dist/core/tools/comby.js +14 -0
  26. package/dist/core/tools/comby.js.map +1 -0
  27. package/dist/core/tools/external-cli.d.ts +33 -0
  28. package/dist/core/tools/external-cli.d.ts.map +1 -0
  29. package/dist/core/tools/external-cli.js +201 -0
  30. package/dist/core/tools/external-cli.js.map +1 -0
  31. package/dist/core/tools/fd.d.ts +12 -0
  32. package/dist/core/tools/fd.d.ts.map +1 -0
  33. package/dist/core/tools/fd.js +15 -0
  34. package/dist/core/tools/fd.js.map +1 -0
  35. package/dist/core/tools/index.d.ts +57 -0
  36. package/dist/core/tools/index.d.ts.map +1 -1
  37. package/dist/core/tools/index.js +61 -2
  38. package/dist/core/tools/index.js.map +1 -1
  39. package/dist/core/tools/jq.d.ts +12 -0
  40. package/dist/core/tools/jq.d.ts.map +1 -0
  41. package/dist/core/tools/jq.js +12 -0
  42. package/dist/core/tools/jq.js.map +1 -0
  43. package/dist/core/tools/rg.d.ts +12 -0
  44. package/dist/core/tools/rg.d.ts.map +1 -0
  45. package/dist/core/tools/rg.js +15 -0
  46. package/dist/core/tools/rg.js.map +1 -0
  47. package/dist/core/tools/sed.d.ts +12 -0
  48. package/dist/core/tools/sed.d.ts.map +1 -0
  49. package/dist/core/tools/sed.js +14 -0
  50. package/dist/core/tools/sed.js.map +1 -0
  51. package/dist/core/tools/semgrep.d.ts +12 -0
  52. package/dist/core/tools/semgrep.d.ts.map +1 -0
  53. package/dist/core/tools/semgrep.js +13 -0
  54. package/dist/core/tools/semgrep.js.map +1 -0
  55. package/dist/core/tools/yq.d.ts +12 -0
  56. package/dist/core/tools/yq.d.ts.map +1 -0
  57. package/dist/core/tools/yq.js +12 -0
  58. package/dist/core/tools/yq.js.map +1 -0
  59. package/dist/index.d.ts +2 -2
  60. package/dist/index.d.ts.map +1 -1
  61. package/dist/index.js +2 -2
  62. package/dist/index.js.map +1 -1
  63. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  64. package/dist/modes/interactive/interactive-mode.js +136 -3
  65. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  66. package/docs/assets/preview.jpg +0 -0
  67. package/docs/cli-reference.md +12 -4
  68. package/docs/configuration.md +4 -4
  69. package/docs/development-and-testing.md +1 -1
  70. package/docs/extensions-packages-themes.md +1 -1
  71. package/docs/getting-started.md +3 -3
  72. package/docs/interactive-mode.md +1 -1
  73. package/docs/rpc-json-sdk.md +1 -1
  74. package/package.json +6 -2
@@ -1 +1 @@
1
- {"version":3,"file":"slash-commands.js","sourceRoot":"","sources":["../../src/core/slash-commands.ts"],"names":[],"mappings":"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","sourcesContent":["export type SlashCommandSource = \"extension\" | \"prompt\" | \"skill\";\n\nexport type SlashCommandLocation = \"user\" | \"project\" | \"path\";\n\nexport interface SlashCommandInfo {\n\tname: string;\n\tdescription?: string;\n\tsource: SlashCommandSource;\n\tlocation?: SlashCommandLocation;\n\tpath?: string;\n}\n\nexport interface BuiltinSlashCommand {\n\tname: string;\n\tdescription: string;\n}\n\nexport const BUILTIN_SLASH_COMMANDS: ReadonlyArray<BuiltinSlashCommand> = [\n\t{ name: \"init\", description: \"Initialize iosm.yaml and .iosm scaffold in current (or target) directory\" },\n\t{\n\t\tname: \"iosm\",\n\t\tdescription: \"Run IOSM auto-improvement loop: /iosm [target-index] [--max-iterations N] [--force-init]\",\n\t},\n\t{\n\t\tname: \"orchestrate\",\n\t\tdescription:\n\t\t\t\"Run orchestrated subagents: /orchestrate (--parallel|--sequential) --agents N [--max-parallel N] [--profile <name>|--profiles p1,p2] [--cwd p1,p2] [--locks l1,l2] [--worktree] [--depends 2>1,3>2] <task>\",\n\t},\n\t{\n\t\tname: \"agents\",\n\t\tdescription:\n\t\t\t\"Interactive agent menu: browse/use/create/edit/delete custom agents and inspect source precedence from .iosm/agents\",\n\t},\n\t{ name: \"subagent-runs\", description: \"List recent subagent runs from .iosm/subagents/runs\" },\n\t{\n\t\tname: \"subagent-resume\",\n\t\tdescription: \"Resume from prior subagent output: /subagent-resume [run-id] [extra instructions] (picker when omitted)\",\n\t},\n\t{ name: \"team-runs\", description: \"List recent team orchestration runs from .iosm/subagents/teams\" },\n\t{ name: \"team-status\", description: \"Show a team run status: /team-status [team-run-id] (picker when omitted)\" },\n\t{ name: \"cycle-list\", description: \"List IOSM cycles\" },\n\t{ name: \"cycle-plan\", description: \"Plan a new IOSM cycle: /cycle-plan [--id <id>] [--force] <goal...>\" },\n\t{ name: \"cycle-status\", description: \"Show IOSM cycle completeness and gates: /cycle-status [cycle-id]\" },\n\t{ name: \"cycle-report\", description: \"Show IOSM cycle report JSON: /cycle-report [cycle-id]\" },\n\t{\n\t\tname: \"mcp\",\n\t\tdescription:\n\t\t\t\"MCP server manager: /mcp (interactive UI), /mcp add <name> ..., /mcp list, /mcp tools [name], /mcp enable|disable|remove <name>\",\n\t},\n\t{\n\t\tname: \"memory\",\n\t\tdescription:\n\t\t\t\"Memory manager: /memory (interactive), /memory <text>, /memory edit <index> <text>, /memory rm <index>\",\n\t},\n\t{ name: \"settings\", description: \"Open settings menu\" },\n\t{\n\t\tname: \"permissions\",\n\t\tdescription:\n\t\t\t\"Permission controls: /permissions (interactive menu) or /permissions [ask|auto|yolo|status|hooks] and /permissions [allow|deny] [list|add|remove] <tool:match>\",\n\t},\n\t{ name: \"yolo\", description: \"Toggle permission prompts: /yolo [on|off|status]\" },\n\t{ name: \"model\", description: \"Select model (provider-first selector UI)\" },\n\t{ name: \"scoped-models\", description: \"Enable/disable models for Ctrl+P cycling\" },\n\t{ name: \"export\", description: \"Export session to HTML file: /export [output-path] (wizard when omitted)\" },\n\t{ name: \"share\", description: \"Share session as a secret GitHub gist\" },\n\t{ name: \"copy\", description: \"Copy last agent message to clipboard\" },\n\t{ name: \"name\", description: \"Set session display name\" },\n\t{ name: \"session\", description: \"Show session info and stats\" },\n\t{ name: \"doctor\", description: \"Run runtime diagnostics (model/auth/MCP/hooks/paths) with optional interactive fixes\" },\n\t{ name: \"checkpoint\", description: \"Create/list checkpoints for safe rollback\" },\n\t{ name: \"rollback\", description: \"Rollback session tree to a checkpoint (picker when omitted)\" },\n\t{ name: \"changelog\", description: \"Show changelog entries\" },\n\t{ name: \"hotkeys\", description: \"Show all keyboard shortcuts\" },\n\t{ name: \"fork\", description: \"Create a new fork from a previous message\" },\n\t{ name: \"tree\", description: \"Navigate session tree (switch branches)\" },\n\t{ name: \"login\", description: \"Authenticate with provider (OAuth incl. Qwen + OpenRouter API key)\" },\n\t{ name: \"auth\", description: \"Alias for /login\" },\n\t{ name: \"logout\", description: \"Remove saved provider credentials (OAuth/API key)\" },\n\t{ name: \"new\", description: \"Start a new session\" },\n\t{ name: \"clear\", description: \"Alias for /new\" },\n\t{ name: \"compact\", description: \"Manually compact the session context\" },\n\t{ name: \"resume\", description: \"Resume a different session\" },\n\t{ name: \"reload\", description: \"Reload extensions, skills, prompts, and themes\" },\n\t{ name: \"quit\", description: \"Quit iosm\" },\n];\n"]}
1
+ {"version":3,"file":"slash-commands.js","sourceRoot":"","sources":["../../src/core/slash-commands.ts"],"names":[],"mappings":"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","sourcesContent":["export type SlashCommandSource = \"extension\" | \"prompt\" | \"skill\";\n\nexport type SlashCommandLocation = \"user\" | \"project\" | \"path\";\n\nexport interface SlashCommandInfo {\n\tname: string;\n\tdescription?: string;\n\tsource: SlashCommandSource;\n\tlocation?: SlashCommandLocation;\n\tpath?: string;\n}\n\nexport interface BuiltinSlashCommand {\n\tname: string;\n\tdescription: string;\n}\n\nexport const BUILTIN_SLASH_COMMANDS: ReadonlyArray<BuiltinSlashCommand> = [\n\t{ name: \"init\", description: \"Initialize iosm.yaml and .iosm scaffold in current (or target) directory\" },\n\t{\n\t\tname: \"iosm\",\n\t\tdescription: \"Run IOSM auto-improvement loop: /iosm [target-index] [--max-iterations N] [--force-init]\",\n\t},\n\t{\n\t\tname: \"orchestrate\",\n\t\tdescription:\n\t\t\t\"Run orchestrated subagents: /orchestrate (--parallel|--sequential) --agents N [--max-parallel N] [--profile <name>|--profiles p1,p2] [--cwd p1,p2] [--locks l1,l2] [--worktree] [--depends 2>1,3>2] <task>\",\n\t},\n\t{\n\t\tname: \"agents\",\n\t\tdescription:\n\t\t\t\"Interactive agent menu: browse/use/create/edit/delete custom agents and inspect source precedence from .iosm/agents\",\n\t},\n\t{ name: \"subagent-runs\", description: \"List recent subagent runs from .iosm/subagents/runs\" },\n\t{\n\t\tname: \"subagent-resume\",\n\t\tdescription: \"Resume from prior subagent output: /subagent-resume [run-id] [extra instructions] (picker when omitted)\",\n\t},\n\t{ name: \"team-runs\", description: \"List recent team orchestration runs from .iosm/subagents/teams\" },\n\t{ name: \"team-status\", description: \"Show a team run status: /team-status [team-run-id] (picker when omitted)\" },\n\t{ name: \"cycle-list\", description: \"List IOSM cycles\" },\n\t{ name: \"cycle-plan\", description: \"Plan a new IOSM cycle: /cycle-plan [--id <id>] [--force] <goal...>\" },\n\t{ name: \"cycle-status\", description: \"Show IOSM cycle completeness and gates: /cycle-status [cycle-id]\" },\n\t{ name: \"cycle-report\", description: \"Show IOSM cycle report JSON: /cycle-report [cycle-id]\" },\n\t{\n\t\tname: \"mcp\",\n\t\tdescription:\n\t\t\t\"MCP server manager: /mcp (interactive UI), /mcp add <name> ..., /mcp list, /mcp tools [name], /mcp enable|disable|remove <name>\",\n\t},\n\t{\n\t\tname: \"memory\",\n\t\tdescription:\n\t\t\t\"Memory manager: /memory (interactive), /memory <text>, /memory edit <index> <text>, /memory rm <index>\",\n\t},\n\t{ name: \"settings\", description: \"Open settings menu\" },\n\t{\n\t\tname: \"permissions\",\n\t\tdescription:\n\t\t\t\"Permission controls: /permissions (interactive menu) or /permissions [ask|auto|yolo|status|hooks] and /permissions [allow|deny] [list|add|remove] <tool:match>\",\n\t},\n\t{ name: \"yolo\", description: \"Toggle permission prompts: /yolo [on|off|status]\" },\n\t{ name: \"model\", description: \"Select model (provider-first selector UI)\" },\n\t{ name: \"scoped-models\", description: \"Enable/disable models for Ctrl+P cycling\" },\n\t{ name: \"export\", description: \"Export session to HTML file: /export [output-path] (wizard when omitted)\" },\n\t{ name: \"share\", description: \"Share session as a secret GitHub gist\" },\n\t{ name: \"copy\", description: \"Copy last agent message to clipboard\" },\n\t{ name: \"name\", description: \"Set session display name\" },\n\t{ name: \"session\", description: \"Show session info and stats\" },\n\t{\n\t\tname: \"doctor\",\n\t\tdescription: \"Run runtime diagnostics (model/auth/MCP/CLI tools/hooks/paths) with optional interactive fixes\",\n\t},\n\t{ name: \"checkpoint\", description: \"Create/list checkpoints for safe rollback\" },\n\t{ name: \"rollback\", description: \"Rollback session tree to a checkpoint (picker when omitted)\" },\n\t{ name: \"changelog\", description: \"Show changelog entries\" },\n\t{ name: \"hotkeys\", description: \"Show all keyboard shortcuts\" },\n\t{ name: \"fork\", description: \"Create a new fork from a previous message\" },\n\t{ name: \"tree\", description: \"Navigate session tree (switch branches)\" },\n\t{ name: \"login\", description: \"Authenticate with provider (OAuth incl. Qwen + OpenRouter API key)\" },\n\t{ name: \"auth\", description: \"Alias for /login\" },\n\t{ name: \"logout\", description: \"Remove saved provider credentials (OAuth/API key)\" },\n\t{ name: \"new\", description: \"Start a new session\" },\n\t{ name: \"clear\", description: \"Alias for /new\" },\n\t{ name: \"compact\", description: \"Manually compact the session context\" },\n\t{ name: \"resume\", description: \"Resume a different session\" },\n\t{ name: \"reload\", description: \"Reload extensions, skills, prompts, and themes\" },\n\t{ name: \"quit\", description: \"Quit iosm\" },\n];\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAyB,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAchE,MAAM,WAAW,wBAAwB;IACxC,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,qFAAqF;IACrF,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,uCAAuC;IACvC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gDAAgD;IAChD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,yBAAyB;IACzB,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;CACjB;AAED,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,wBAA6B,GAAG,MAAM,CAwNhF"}
1
+ {"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAyB,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAsBhE,MAAM,WAAW,wBAAwB;IACxC,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,qFAAqF;IACrF,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,uCAAuC;IACvC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gDAAgD;IAChD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,yBAAyB;IACzB,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;CACjB;AAED,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,wBAA6B,GAAG,MAAM,CAoPhF"}
@@ -12,6 +12,14 @@ const toolDescriptions = {
12
12
  grep: "Search file contents for patterns (respects .gitignore)",
13
13
  find: "Find files by glob pattern (respects .gitignore)",
14
14
  ls: "List directory contents",
15
+ rg: "Run ripgrep directly for advanced regex search",
16
+ fd: "Run fd directly for fast file discovery",
17
+ ast_grep: "Run ast-grep for AST/syntax-aware structural code search",
18
+ comby: "Run comby for structural pattern search/rewrite previews (no in-place edits)",
19
+ jq: "Run jq for JSON querying/transformation",
20
+ yq: "Run yq for YAML/JSON/TOML querying/transformation",
21
+ semgrep: "Run semgrep for structural/static security checks",
22
+ sed: "Run sed for stream editing/extraction previews (no in-place edits)",
15
23
  task: "Run a specialized subagent (supports profile, cwd, lock_key for optional write serialization, run_id/task_id, model override, background mode for detached runs, and agent=<custom name from .iosm/agents>)",
16
24
  };
17
25
  /** Build the system prompt with tools, guidelines, and context */
@@ -86,13 +94,36 @@ export function buildSystemPrompt(options = {}) {
86
94
  const hasGrep = tools.includes("grep");
87
95
  const hasFind = tools.includes("find");
88
96
  const hasLs = tools.includes("ls");
97
+ const hasRg = tools.includes("rg");
98
+ const hasFd = tools.includes("fd");
99
+ const hasAstGrep = tools.includes("ast_grep");
100
+ const hasComby = tools.includes("comby");
101
+ const hasJq = tools.includes("jq");
102
+ const hasYq = tools.includes("yq");
103
+ const hasSemgrep = tools.includes("semgrep");
104
+ const hasSed = tools.includes("sed");
89
105
  const hasRead = tools.includes("read");
90
106
  // File exploration guidelines
91
- if (hasBash && !hasGrep && !hasFind && !hasLs) {
107
+ if (hasBash && !hasGrep && !hasFind && !hasLs && !hasRg && !hasFd) {
92
108
  addGuideline("Use bash for file operations like ls, rg, find; prefer rg for targeted search when available");
93
109
  }
94
- else if (hasBash && (hasGrep || hasFind || hasLs)) {
95
- addGuideline("Prefer grep/find/ls tools over bash for file exploration (faster, respects .gitignore)");
110
+ else if (hasBash && (hasGrep || hasFind || hasLs || hasRg || hasFd)) {
111
+ addGuideline("Prefer grep/find/ls/rg/fd tools over bash for codebase exploration (faster and less noisy)");
112
+ }
113
+ if (hasAstGrep || hasComby) {
114
+ addGuideline("Use ast_grep/comby for syntax-aware structural queries before falling back to broad regex");
115
+ }
116
+ if (hasComby) {
117
+ addGuideline("Use comby to preview structural rewrite matches first, then apply final changes via edit/write");
118
+ }
119
+ if (hasJq || hasYq) {
120
+ addGuideline("Prefer jq/yq over ad-hoc shell parsing when extracting or transforming JSON/YAML/TOML");
121
+ }
122
+ if (hasSemgrep) {
123
+ addGuideline("Use semgrep for rule-based risk scans and structural security checks when relevant");
124
+ }
125
+ if (hasSed) {
126
+ addGuideline("Use sed for preview/extraction workflows only; perform final file edits with edit/write");
96
127
  }
97
128
  // Read before edit guideline
98
129
  if (hasRead && hasEdit) {
@@ -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 { 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)\",\n\tfind: \"Find files by glob pattern (respects .gitignore)\",\n\tls: \"List directory contents\",\n\ttask: \"Run a specialized subagent (supports profile, cwd, lock_key for optional write serialization, run_id/task_id, model override, background mode for detached runs, and agent=<custom name from .iosm/agents>)\",\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 = 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 (only if read tool is available)\n\t\tconst customPromptHasRead = !selectedTools || selectedTools.includes(\"read\");\n\t\tif (customPromptHasRead && 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\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\n\t// File exploration guidelines\n\tif (hasBash && !hasGrep && !hasFind && !hasLs) {\n\t\taddGuideline(\"Use bash for file operations like ls, rg, find; prefer rg for targeted search when available\");\n\t} else if (hasBash && (hasGrep || hasFind || hasLs)) {\n\t\taddGuideline(\"Prefer grep/find/ls tools over bash for file exploration (faster, respects .gitignore)\");\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\taddGuideline(\"Inspect the relevant files before editing and keep exploration bounded to the task\");\n\taddGuideline(\"Make reasonable assumptions and continue unless a risky ambiguity blocks the work\");\n\taddGuideline(\"Classify requests as simple vs complex: execute simple work immediately, use a step plan for complex work\");\n\taddGuideline(\"For complex work, publish a short step plan before edits and keep step statuses current while executing\");\n\taddGuideline(\"If a meaningful architecture or product fork changes implementation, ask a concise clarification before editing\");\n\taddGuideline(\"After changes, run the smallest relevant verification and report the concrete result\");\n\taddGuideline(\"Do not claim success without evidence; if you could not verify, say so explicitly\");\n\taddGuideline(\"Complete the requested task end-to-end when possible instead of stopping at analysis\");\n\taddGuideline(\"For code review requests, lead with findings and risks before summaries\");\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 a professional software engineering agent operating inside iosm-cli. Help users inspect systems, change code, run commands, maintain project artifacts when needed, and explain results clearly.\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\nOperating defaults:\n- Summarize work in standard engineering language first: what you inspected, what you changed, what you verified, and any remaining risk or blocker.\n- Do NOT start by reading documentation unless the user asks for documentation help, asks about harness internals, or implementation is blocked without it.\n- Start implementation turns with a quick repository scan of the files most likely to matter before proposing or editing.\n- Prefer targeted reads and searches over broad dumps; keep command output bounded and focused.\n- For complex tasks, include a machine-readable plan block before edits and update it when statuses change:\n <task_plan complexity=\"complex\">\n - [in_progress] Current step\n - [pending] Next step\n </task_plan>\n- Skip plan blocks for simple one-shot tasks.\n- When a material architecture fork exists, pause and ask one concise clarification (or use ask_user when available) before implementation.\n- Treat verification as mandatory after edits: tests, type checks, linters, or a precise explanation of why verification was not possible.\n- For complex requests, execute plan steps in order, close each step explicitly, and finish the full plan unless blocked.\n- If the user explicitly asks for subagents/agents orchestration, you MUST use the task tool rather than doing all work in the main agent.\n- For explicit subagent/orchestration requests, execute at least one task tool call before giving a final prose-only answer.\n- Do not expose internal orchestration scaffolding to the user (for example: [ORCHESTRATION_DIRECTIVE], pseudo tool-call JSON, or raw task arguments).\n- When invoking tools, call them directly without preambles like \"I will now call tool X\"; only report outcomes that matter to the user.\n- Respect orchestration constraints from the user exactly: count, parallel vs sequential execution, per-agent profile, and per-agent working directory (cwd) when provided.\n- For explicit parallel orchestration requests, issue multiple independent task tool calls to match the requested agent count; do not collapse to a single subagent unless the user asks for one.\n- For explicit parallel orchestration requests, emit independent task calls in a single assistant turn whenever possible so they can be launched together.\n- Runtime note: when parallel orchestration is requested, emit independent task calls in one assistant turn so they can run concurrently; avoid background mode unless the user explicitly asks for detached async runs.\n- If orchestration constraints are ambiguous or conflict, ask one concise clarification (or use ask_user when available) before launching subagents.\n- When the user provides an <orchestrate ...>...</orchestrate> block, treat it as an execution contract and follow its mode/agents/profile/cwd assignments strictly.\n- When orchestration assignments include run_id/task_id/lock_key or depends_on, enforce them in task calls (run_id/task_id for team tracking, lock_key for serialization domains, depends_on for ordering).\n- For write-heavy parallel orchestration, prefer isolation=worktree to reduce cross-agent interference when the repository is git-backed.\n- If the user message includes @<custom-agent-name>, treat it as an explicit agent selection and call task with agent set to that custom agent name.\n\niosm-cli reference docs (use when needed):\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), package composition (docs/packages.md)\n- When working on harness internals, read the relevant docs/examples before implementing`;\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 (only if read tool is available)\n\tif (hasRead && 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 { getDocsPath, getExamplesPath, getReadmePath } from \"../config.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)\",\n\tfind: \"Find files by glob pattern (respects .gitignore)\",\n\tls: \"List directory contents\",\n\trg: \"Run ripgrep directly for advanced regex search\",\n\tfd: \"Run fd directly for fast file discovery\",\n\tast_grep: \"Run ast-grep for AST/syntax-aware structural code search\",\n\tcomby: \"Run comby for structural pattern search/rewrite previews (no in-place edits)\",\n\tjq: \"Run jq for JSON querying/transformation\",\n\tyq: \"Run yq for YAML/JSON/TOML querying/transformation\",\n\tsemgrep: \"Run semgrep for structural/static security checks\",\n\tsed: \"Run sed for stream editing/extraction previews (no in-place edits)\",\n\ttask: \"Run a specialized subagent (supports profile, cwd, lock_key for optional write serialization, run_id/task_id, model override, background mode for detached runs, and agent=<custom name from .iosm/agents>)\",\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 = 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 (only if read tool is available)\n\t\tconst customPromptHasRead = !selectedTools || selectedTools.includes(\"read\");\n\t\tif (customPromptHasRead && 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\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 hasRg = tools.includes(\"rg\");\n\tconst hasFd = tools.includes(\"fd\");\n\tconst hasAstGrep = tools.includes(\"ast_grep\");\n\tconst hasComby = tools.includes(\"comby\");\n\tconst hasJq = tools.includes(\"jq\");\n\tconst hasYq = tools.includes(\"yq\");\n\tconst hasSemgrep = tools.includes(\"semgrep\");\n\tconst hasSed = tools.includes(\"sed\");\n\tconst hasRead = tools.includes(\"read\");\n\n\t// File exploration guidelines\n\tif (hasBash && !hasGrep && !hasFind && !hasLs && !hasRg && !hasFd) {\n\t\taddGuideline(\"Use bash for file operations like ls, rg, find; prefer rg for targeted search when available\");\n\t} else if (hasBash && (hasGrep || hasFind || hasLs || hasRg || hasFd)) {\n\t\taddGuideline(\"Prefer grep/find/ls/rg/fd tools over bash for codebase exploration (faster and less noisy)\");\n\t}\n\n\tif (hasAstGrep || hasComby) {\n\t\taddGuideline(\"Use ast_grep/comby for syntax-aware structural queries before falling back to broad regex\");\n\t}\n\n\tif (hasComby) {\n\t\taddGuideline(\"Use comby to preview structural rewrite matches first, then apply final changes via edit/write\");\n\t}\n\n\tif (hasJq || hasYq) {\n\t\taddGuideline(\"Prefer jq/yq over ad-hoc shell parsing when extracting or transforming JSON/YAML/TOML\");\n\t}\n\n\tif (hasSemgrep) {\n\t\taddGuideline(\"Use semgrep for rule-based risk scans and structural security checks when relevant\");\n\t}\n\n\tif (hasSed) {\n\t\taddGuideline(\"Use sed for preview/extraction workflows only; perform final file edits with edit/write\");\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\taddGuideline(\"Inspect the relevant files before editing and keep exploration bounded to the task\");\n\taddGuideline(\"Make reasonable assumptions and continue unless a risky ambiguity blocks the work\");\n\taddGuideline(\"Classify requests as simple vs complex: execute simple work immediately, use a step plan for complex work\");\n\taddGuideline(\"For complex work, publish a short step plan before edits and keep step statuses current while executing\");\n\taddGuideline(\"If a meaningful architecture or product fork changes implementation, ask a concise clarification before editing\");\n\taddGuideline(\"After changes, run the smallest relevant verification and report the concrete result\");\n\taddGuideline(\"Do not claim success without evidence; if you could not verify, say so explicitly\");\n\taddGuideline(\"Complete the requested task end-to-end when possible instead of stopping at analysis\");\n\taddGuideline(\"For code review requests, lead with findings and risks before summaries\");\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 a professional software engineering agent operating inside iosm-cli. Help users inspect systems, change code, run commands, maintain project artifacts when needed, and explain results clearly.\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\nOperating defaults:\n- Summarize work in standard engineering language first: what you inspected, what you changed, what you verified, and any remaining risk or blocker.\n- Do NOT start by reading documentation unless the user asks for documentation help, asks about harness internals, or implementation is blocked without it.\n- Start implementation turns with a quick repository scan of the files most likely to matter before proposing or editing.\n- Prefer targeted reads and searches over broad dumps; keep command output bounded and focused.\n- For complex tasks, include a machine-readable plan block before edits and update it when statuses change:\n <task_plan complexity=\"complex\">\n - [in_progress] Current step\n - [pending] Next step\n </task_plan>\n- Skip plan blocks for simple one-shot tasks.\n- When a material architecture fork exists, pause and ask one concise clarification (or use ask_user when available) before implementation.\n- Treat verification as mandatory after edits: tests, type checks, linters, or a precise explanation of why verification was not possible.\n- For complex requests, execute plan steps in order, close each step explicitly, and finish the full plan unless blocked.\n- If the user explicitly asks for subagents/agents orchestration, you MUST use the task tool rather than doing all work in the main agent.\n- For explicit subagent/orchestration requests, execute at least one task tool call before giving a final prose-only answer.\n- Do not expose internal orchestration scaffolding to the user (for example: [ORCHESTRATION_DIRECTIVE], pseudo tool-call JSON, or raw task arguments).\n- When invoking tools, call them directly without preambles like \"I will now call tool X\"; only report outcomes that matter to the user.\n- Respect orchestration constraints from the user exactly: count, parallel vs sequential execution, per-agent profile, and per-agent working directory (cwd) when provided.\n- For explicit parallel orchestration requests, issue multiple independent task tool calls to match the requested agent count; do not collapse to a single subagent unless the user asks for one.\n- For explicit parallel orchestration requests, emit independent task calls in a single assistant turn whenever possible so they can be launched together.\n- Runtime note: when parallel orchestration is requested, emit independent task calls in one assistant turn so they can run concurrently; avoid background mode unless the user explicitly asks for detached async runs.\n- If orchestration constraints are ambiguous or conflict, ask one concise clarification (or use ask_user when available) before launching subagents.\n- When the user provides an <orchestrate ...>...</orchestrate> block, treat it as an execution contract and follow its mode/agents/profile/cwd assignments strictly.\n- When orchestration assignments include run_id/task_id/lock_key or depends_on, enforce them in task calls (run_id/task_id for team tracking, lock_key for serialization domains, depends_on for ordering).\n- For write-heavy parallel orchestration, prefer isolation=worktree to reduce cross-agent interference when the repository is git-backed.\n- If the user message includes @<custom-agent-name>, treat it as an explicit agent selection and call task with agent set to that custom agent name.\n\niosm-cli reference docs (use when needed):\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), package composition (docs/packages.md)\n- When working on harness internals, read the relevant docs/examples before implementing`;\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 (only if read tool is available)\n\tif (hasRead && 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"]}
@@ -0,0 +1,12 @@
1
+ import type { AgentTool } from "@mariozechner/pi-agent-core";
2
+ import type { Static } from "@sinclair/typebox";
3
+ import { externalCliSchema } from "./external-cli.js";
4
+ export type AstGrepToolInput = Static<typeof externalCliSchema>;
5
+ export declare function createAstGrepTool(cwd: string): AgentTool<typeof externalCliSchema>;
6
+ export declare const astGrepTool: AgentTool<import("@sinclair/typebox").TObject<{
7
+ args: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
8
+ path: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
9
+ stdin: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
10
+ timeout: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
11
+ }>, any>;
12
+ //# sourceMappingURL=ast-grep.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast-grep.d.ts","sourceRoot":"","sources":["../../../src/core/tools/ast-grep.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAyB,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE7E,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAEhE,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC,OAAO,iBAAiB,CAAC,CASlF;AAED,eAAO,MAAM,WAAW;;;;;QAAmC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { createExternalCliTool } from "./external-cli.js";
2
+ export function createAstGrepTool(cwd) {
3
+ return createExternalCliTool(cwd, {
4
+ name: "ast_grep",
5
+ label: "ast-grep",
6
+ description: "Run ast-grep (sg) for syntax-aware code queries. Pass CLI arguments directly (for example: [\"scan\",\"--pattern\",\"console.log($A)\",\"src\"]).",
7
+ commandCandidates: ["ast-grep", "sg"],
8
+ missingInstallHint: "Install ast-grep (brew install ast-grep or npm i -g @ast-grep/cli).",
9
+ });
10
+ }
11
+ export const astGrepTool = createAstGrepTool(process.cwd());
12
+ //# sourceMappingURL=ast-grep.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ast-grep.js","sourceRoot":"","sources":["../../../src/core/tools/ast-grep.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAqB,MAAM,mBAAmB,CAAC;AAI7E,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC5C,OAAO,qBAAqB,CAAC,GAAG,EAAE;QACjC,IAAI,EAAE,UAAU;QAChB,KAAK,EAAE,UAAU;QACjB,WAAW,EACV,mJAAmJ;QACpJ,iBAAiB,EAAE,CAAC,UAAU,EAAE,IAAI,CAAC;QACrC,kBAAkB,EAAE,qEAAqE;KACzF,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,iBAAiB,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC","sourcesContent":["import type { AgentTool } from \"@mariozechner/pi-agent-core\";\nimport type { Static } from \"@sinclair/typebox\";\nimport { createExternalCliTool, externalCliSchema } from \"./external-cli.js\";\n\nexport type AstGrepToolInput = Static<typeof externalCliSchema>;\n\nexport function createAstGrepTool(cwd: string): AgentTool<typeof externalCliSchema> {\n\treturn createExternalCliTool(cwd, {\n\t\tname: \"ast_grep\",\n\t\tlabel: \"ast-grep\",\n\t\tdescription:\n\t\t\t\"Run ast-grep (sg) for syntax-aware code queries. Pass CLI arguments directly (for example: [\\\"scan\\\",\\\"--pattern\\\",\\\"console.log($A)\\\",\\\"src\\\"]).\",\n\t\tcommandCandidates: [\"ast-grep\", \"sg\"],\n\t\tmissingInstallHint: \"Install ast-grep (brew install ast-grep or npm i -g @ast-grep/cli).\",\n\t});\n}\n\nexport const astGrepTool = createAstGrepTool(process.cwd());\n"]}
@@ -0,0 +1,12 @@
1
+ import type { AgentTool } from "@mariozechner/pi-agent-core";
2
+ import type { Static } from "@sinclair/typebox";
3
+ import { externalCliSchema } from "./external-cli.js";
4
+ export type CombyToolInput = Static<typeof externalCliSchema>;
5
+ export declare function createCombyTool(cwd: string): AgentTool<typeof externalCliSchema>;
6
+ export declare const combyTool: AgentTool<import("@sinclair/typebox").TObject<{
7
+ args: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
8
+ path: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
9
+ stdin: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
10
+ timeout: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
11
+ }>, any>;
12
+ //# sourceMappingURL=comby.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comby.d.ts","sourceRoot":"","sources":["../../../src/core/tools/comby.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAyB,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE7E,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE9D,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC,OAAO,iBAAiB,CAAC,CAWhF;AAED,eAAO,MAAM,SAAS;;;;;QAAiC,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { createExternalCliTool } from "./external-cli.js";
2
+ export function createCombyTool(cwd) {
3
+ return createExternalCliTool(cwd, {
4
+ name: "comby",
5
+ label: "comby",
6
+ description: "Run comby for structural search/rewrite previews. In-place flags are blocked; use edit/write tools for actual file mutations.",
7
+ commandCandidates: ["comby"],
8
+ missingInstallHint: "Install comby (brew install comby).",
9
+ forbiddenArgs: ["-i", "--in-place", "-in-place"],
10
+ forbiddenArgPrefixes: ["-i="],
11
+ });
12
+ }
13
+ export const combyTool = createCombyTool(process.cwd());
14
+ //# sourceMappingURL=comby.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comby.js","sourceRoot":"","sources":["../../../src/core/tools/comby.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAqB,MAAM,mBAAmB,CAAC;AAI7E,MAAM,UAAU,eAAe,CAAC,GAAW;IAC1C,OAAO,qBAAqB,CAAC,GAAG,EAAE;QACjC,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,OAAO;QACd,WAAW,EACV,+HAA+H;QAChI,iBAAiB,EAAE,CAAC,OAAO,CAAC;QAC5B,kBAAkB,EAAE,qCAAqC;QACzD,aAAa,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,WAAW,CAAC;QAChD,oBAAoB,EAAE,CAAC,KAAK,CAAC;KAC7B,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,eAAe,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC","sourcesContent":["import type { AgentTool } from \"@mariozechner/pi-agent-core\";\nimport type { Static } from \"@sinclair/typebox\";\nimport { createExternalCliTool, externalCliSchema } from \"./external-cli.js\";\n\nexport type CombyToolInput = Static<typeof externalCliSchema>;\n\nexport function createCombyTool(cwd: string): AgentTool<typeof externalCliSchema> {\n\treturn createExternalCliTool(cwd, {\n\t\tname: \"comby\",\n\t\tlabel: \"comby\",\n\t\tdescription:\n\t\t\t\"Run comby for structural search/rewrite previews. In-place flags are blocked; use edit/write tools for actual file mutations.\",\n\t\tcommandCandidates: [\"comby\"],\n\t\tmissingInstallHint: \"Install comby (brew install comby).\",\n\t\tforbiddenArgs: [\"-i\", \"--in-place\", \"-in-place\"],\n\t\tforbiddenArgPrefixes: [\"-i=\"],\n\t});\n}\n\nexport const combyTool = createCombyTool(process.cwd());\n"]}
@@ -0,0 +1,33 @@
1
+ import type { AgentTool } from "@mariozechner/pi-agent-core";
2
+ import { type Static } from "@sinclair/typebox";
3
+ import { type TruncationResult } from "./truncate.js";
4
+ declare const externalCliSchema: import("@sinclair/typebox").TObject<{
5
+ args: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
6
+ path: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
7
+ stdin: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
8
+ timeout: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
9
+ }>;
10
+ export type ExternalCliToolInput = Static<typeof externalCliSchema>;
11
+ export interface ExternalCliToolDetails {
12
+ command: string;
13
+ args: string[];
14
+ cwd: string;
15
+ exitCode: number;
16
+ truncation?: TruncationResult;
17
+ captureTruncated?: boolean;
18
+ }
19
+ export interface ExternalCliToolOptions {
20
+ name: string;
21
+ label?: string;
22
+ description: string;
23
+ commandCandidates: string[];
24
+ ensureManagedTool?: "fd" | "rg";
25
+ allowExitCodes?: number[];
26
+ emptyOutputMessage?: string;
27
+ missingInstallHint?: string;
28
+ forbiddenArgs?: string[];
29
+ forbiddenArgPrefixes?: string[];
30
+ }
31
+ export declare function createExternalCliTool(cwd: string, options: ExternalCliToolOptions): AgentTool<typeof externalCliSchema>;
32
+ export { externalCliSchema };
33
+ //# sourceMappingURL=external-cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"external-cli.d.ts","sourceRoot":"","sources":["../../../src/core/tools/external-cli.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,KAAK,MAAM,EAAQ,MAAM,mBAAmB,CAAC;AAGtD,OAAO,EAIN,KAAK,gBAAgB,EAErB,MAAM,eAAe,CAAC;AAEvB,QAAA,MAAM,iBAAiB;;;;;EASrB,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAYpE,MAAM,WAAW,sBAAsB;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,sBAAsB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,iBAAiB,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAChC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CAChC;AA8JD,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAsB,GAAG,SAAS,CAAC,OAAO,iBAAiB,CAAC,CAwEvH;AAED,OAAO,EAAE,iBAAiB,EAAE,CAAC"}
@@ -0,0 +1,201 @@
1
+ import { spawn, spawnSync } from "node:child_process";
2
+ import { Type } from "@sinclair/typebox";
3
+ import { ensureTool } from "../../utils/tools-manager.js";
4
+ import { resolveToCwd } from "./path-utils.js";
5
+ import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, truncateHead, } from "./truncate.js";
6
+ const externalCliSchema = Type.Object({
7
+ args: Type.Optional(Type.Array(Type.String(), {
8
+ description: "Arguments passed directly to the command (no shell interpolation)",
9
+ })),
10
+ path: Type.Optional(Type.String({ description: "Working directory for the command (default: current directory)" })),
11
+ stdin: Type.Optional(Type.String({ description: "Optional text piped to the command stdin" })),
12
+ timeout: Type.Optional(Type.Number({ description: "Timeout in seconds (default: 30)" })),
13
+ });
14
+ const DEFAULT_TIMEOUT_MS = 30_000;
15
+ const MAX_CAPTURE_BYTES = 512 * 1024;
16
+ function commandExists(command) {
17
+ try {
18
+ const result = spawnSync(command, ["--version"], { stdio: "pipe" });
19
+ const err = result.error;
20
+ return !err || err.code !== "ENOENT";
21
+ }
22
+ catch {
23
+ return false;
24
+ }
25
+ }
26
+ function includesForbiddenArg(args, exact, prefixes) {
27
+ for (const arg of args) {
28
+ if (exact.has(arg)) {
29
+ return arg;
30
+ }
31
+ for (const prefix of prefixes) {
32
+ if (arg === prefix || arg.startsWith(prefix)) {
33
+ return arg;
34
+ }
35
+ }
36
+ }
37
+ return undefined;
38
+ }
39
+ async function resolveCommand(options) {
40
+ if (options.ensureManagedTool) {
41
+ const managed = await ensureTool(options.ensureManagedTool, true);
42
+ if (managed) {
43
+ return managed;
44
+ }
45
+ }
46
+ for (const candidate of options.commandCandidates) {
47
+ if (commandExists(candidate)) {
48
+ return candidate;
49
+ }
50
+ }
51
+ return undefined;
52
+ }
53
+ function runCommand(command, args, cwd, stdin, timeoutMs, signal) {
54
+ return new Promise((resolve, reject) => {
55
+ if (signal?.aborted) {
56
+ reject(new Error("Operation aborted"));
57
+ return;
58
+ }
59
+ const child = spawn(command, args, {
60
+ cwd,
61
+ stdio: ["pipe", "pipe", "pipe"],
62
+ });
63
+ let stdoutChunks = [];
64
+ let stderrChunks = [];
65
+ let stdoutBytes = 0;
66
+ let stderrBytes = 0;
67
+ let captureTruncated = false;
68
+ let timedOut = false;
69
+ let aborted = false;
70
+ let settled = false;
71
+ const settle = (fn) => {
72
+ if (!settled) {
73
+ settled = true;
74
+ fn();
75
+ }
76
+ };
77
+ const captureChunk = (chunk, chunks, currentBytes) => {
78
+ if (currentBytes >= MAX_CAPTURE_BYTES) {
79
+ return { nextBytes: currentBytes, truncated: true };
80
+ }
81
+ const remaining = MAX_CAPTURE_BYTES - currentBytes;
82
+ if (chunk.length <= remaining) {
83
+ chunks.push(chunk);
84
+ return { nextBytes: currentBytes + chunk.length, truncated: false };
85
+ }
86
+ chunks.push(chunk.subarray(0, remaining));
87
+ return { nextBytes: MAX_CAPTURE_BYTES, truncated: true };
88
+ };
89
+ const timeoutHandle = setTimeout(() => {
90
+ timedOut = true;
91
+ child.kill("SIGTERM");
92
+ }, Math.max(1_000, timeoutMs));
93
+ const cleanup = () => {
94
+ clearTimeout(timeoutHandle);
95
+ signal?.removeEventListener("abort", onAbort);
96
+ };
97
+ const onAbort = () => {
98
+ aborted = true;
99
+ child.kill("SIGTERM");
100
+ };
101
+ signal?.addEventListener("abort", onAbort, { once: true });
102
+ child.stdout.on("data", (chunk) => {
103
+ const captured = captureChunk(chunk, stdoutChunks, stdoutBytes);
104
+ stdoutBytes = captured.nextBytes;
105
+ captureTruncated = captureTruncated || captured.truncated;
106
+ });
107
+ child.stderr.on("data", (chunk) => {
108
+ const captured = captureChunk(chunk, stderrChunks, stderrBytes);
109
+ stderrBytes = captured.nextBytes;
110
+ captureTruncated = captureTruncated || captured.truncated;
111
+ });
112
+ if (stdin !== undefined) {
113
+ child.stdin.write(stdin);
114
+ }
115
+ child.stdin.end();
116
+ child.on("error", (error) => {
117
+ cleanup();
118
+ settle(() => reject(new Error(`Failed to run ${command}: ${error.message}`)));
119
+ });
120
+ child.on("close", (code) => {
121
+ cleanup();
122
+ if (aborted) {
123
+ settle(() => reject(new Error("Operation aborted")));
124
+ return;
125
+ }
126
+ if (timedOut) {
127
+ settle(() => reject(new Error(`Command timed out after ${Math.round(timeoutMs / 1000)}s`)));
128
+ return;
129
+ }
130
+ settle(() => resolve({
131
+ stdout: Buffer.concat(stdoutChunks).toString("utf-8"),
132
+ stderr: Buffer.concat(stderrChunks).toString("utf-8"),
133
+ exitCode: code ?? -1,
134
+ captureTruncated,
135
+ }));
136
+ });
137
+ });
138
+ }
139
+ export function createExternalCliTool(cwd, options) {
140
+ const allowExitCodes = new Set(options.allowExitCodes ?? [0]);
141
+ const forbiddenArgs = new Set(options.forbiddenArgs ?? []);
142
+ const forbiddenPrefixes = options.forbiddenArgPrefixes ?? [];
143
+ return {
144
+ name: options.name,
145
+ label: options.label ?? options.name,
146
+ description: options.description,
147
+ parameters: externalCliSchema,
148
+ execute: async (_toolCallId, { args, path, stdin, timeout }, signal) => {
149
+ const normalizedArgs = (args ?? []).map((arg) => String(arg));
150
+ const blockedArg = includesForbiddenArg(normalizedArgs, forbiddenArgs, forbiddenPrefixes);
151
+ if (blockedArg) {
152
+ throw new Error(`Argument "${blockedArg}" is not allowed for ${options.name}.`);
153
+ }
154
+ const command = await resolveCommand(options);
155
+ if (!command) {
156
+ const hint = options.missingInstallHint ? ` ${options.missingInstallHint}` : "";
157
+ throw new Error(`${options.name} command is not available.${hint}`);
158
+ }
159
+ const executionCwd = resolveToCwd(path || ".", cwd);
160
+ const timeoutMs = Math.round((timeout ?? 30) * 1000);
161
+ const result = await runCommand(command, normalizedArgs, executionCwd, stdin, timeoutMs, signal);
162
+ if (!allowExitCodes.has(result.exitCode)) {
163
+ const errorText = result.stderr.trim() || result.stdout.trim() || `${options.name} exited with code ${result.exitCode}`;
164
+ throw new Error(errorText);
165
+ }
166
+ let output = result.stdout.trimEnd();
167
+ if (!output && result.stderr.trim().length > 0) {
168
+ output = result.stderr.trimEnd();
169
+ }
170
+ if (!output) {
171
+ output = options.emptyOutputMessage ?? "No output";
172
+ }
173
+ const truncation = truncateHead(output);
174
+ let finalOutput = truncation.content;
175
+ const details = {
176
+ command,
177
+ args: normalizedArgs,
178
+ cwd: executionCwd,
179
+ exitCode: result.exitCode,
180
+ };
181
+ const notices = [];
182
+ if (truncation.truncated) {
183
+ details.truncation = truncation;
184
+ notices.push(`${formatSize(DEFAULT_MAX_BYTES)} output limit reached`);
185
+ }
186
+ if (result.captureTruncated) {
187
+ details.captureTruncated = true;
188
+ notices.push(`capture limit reached (${formatSize(MAX_CAPTURE_BYTES)})`);
189
+ }
190
+ if (notices.length > 0) {
191
+ finalOutput += `\n\n[${notices.join(". ")} · showing up to ${DEFAULT_MAX_LINES} lines]`;
192
+ }
193
+ return {
194
+ content: [{ type: "text", text: finalOutput }],
195
+ details,
196
+ };
197
+ },
198
+ };
199
+ }
200
+ export { externalCliSchema };
201
+ //# sourceMappingURL=external-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"external-cli.js","sourceRoot":"","sources":["../../../src/core/tools/external-cli.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn, spawnSync } from \"node:child_process\";\nimport type { AgentTool } from \"@mariozechner/pi-agent-core\";\nimport { type Static, Type } from \"@sinclair/typebox\";\nimport { ensureTool } from \"../../utils/tools-manager.js\";\nimport { resolveToCwd } from \"./path-utils.js\";\nimport {\n\tDEFAULT_MAX_BYTES,\n\tDEFAULT_MAX_LINES,\n\tformatSize,\n\ttype TruncationResult,\n\ttruncateHead,\n} from \"./truncate.js\";\n\nconst externalCliSchema = Type.Object({\n\targs: Type.Optional(\n\t\tType.Array(Type.String(), {\n\t\t\tdescription: \"Arguments passed directly to the command (no shell interpolation)\",\n\t\t}),\n\t),\n\tpath: Type.Optional(Type.String({ description: \"Working directory for the command (default: current directory)\" })),\n\tstdin: Type.Optional(Type.String({ description: \"Optional text piped to the command stdin\" })),\n\ttimeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (default: 30)\" })),\n});\n\nexport type ExternalCliToolInput = Static<typeof externalCliSchema>;\n\nconst DEFAULT_TIMEOUT_MS = 30_000;\nconst MAX_CAPTURE_BYTES = 512 * 1024;\n\ninterface RunCommandResult {\n\tstdout: string;\n\tstderr: string;\n\texitCode: number;\n\tcaptureTruncated: boolean;\n}\n\nexport interface ExternalCliToolDetails {\n\tcommand: string;\n\targs: string[];\n\tcwd: string;\n\texitCode: number;\n\ttruncation?: TruncationResult;\n\tcaptureTruncated?: boolean;\n}\n\nexport interface ExternalCliToolOptions {\n\tname: string;\n\tlabel?: string;\n\tdescription: string;\n\tcommandCandidates: string[];\n\tensureManagedTool?: \"fd\" | \"rg\";\n\tallowExitCodes?: number[];\n\temptyOutputMessage?: string;\n\tmissingInstallHint?: string;\n\tforbiddenArgs?: string[];\n\tforbiddenArgPrefixes?: string[];\n}\n\nfunction commandExists(command: string): boolean {\n\ttry {\n\t\tconst result = spawnSync(command, [\"--version\"], { stdio: \"pipe\" });\n\t\tconst err = result.error as NodeJS.ErrnoException | undefined;\n\t\treturn !err || err.code !== \"ENOENT\";\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction includesForbiddenArg(args: string[], exact: Set<string>, prefixes: string[]): string | undefined {\n\tfor (const arg of args) {\n\t\tif (exact.has(arg)) {\n\t\t\treturn arg;\n\t\t}\n\t\tfor (const prefix of prefixes) {\n\t\t\tif (arg === prefix || arg.startsWith(prefix)) {\n\t\t\t\treturn arg;\n\t\t\t}\n\t\t}\n\t}\n\treturn undefined;\n}\n\nasync function resolveCommand(options: ExternalCliToolOptions): Promise<string | undefined> {\n\tif (options.ensureManagedTool) {\n\t\tconst managed = await ensureTool(options.ensureManagedTool, true);\n\t\tif (managed) {\n\t\t\treturn managed;\n\t\t}\n\t}\n\n\tfor (const candidate of options.commandCandidates) {\n\t\tif (commandExists(candidate)) {\n\t\t\treturn candidate;\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\nfunction runCommand(\n\tcommand: string,\n\targs: string[],\n\tcwd: string,\n\tstdin: string | undefined,\n\ttimeoutMs: number,\n\tsignal?: AbortSignal,\n): Promise<RunCommandResult> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (signal?.aborted) {\n\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\treturn;\n\t\t}\n\n\t\tconst child = spawn(command, args, {\n\t\t\tcwd,\n\t\t\tstdio: [\"pipe\", \"pipe\", \"pipe\"],\n\t\t});\n\n\t\tlet stdoutChunks: Buffer[] = [];\n\t\tlet stderrChunks: Buffer[] = [];\n\t\tlet stdoutBytes = 0;\n\t\tlet stderrBytes = 0;\n\t\tlet captureTruncated = false;\n\t\tlet timedOut = false;\n\t\tlet aborted = false;\n\t\tlet settled = false;\n\n\t\tconst settle = (fn: () => void) => {\n\t\t\tif (!settled) {\n\t\t\t\tsettled = true;\n\t\t\t\tfn();\n\t\t\t}\n\t\t};\n\n\t\tconst captureChunk = (\n\t\t\tchunk: Buffer,\n\t\t\tchunks: Buffer[],\n\t\t\tcurrentBytes: number,\n\t\t): { nextBytes: number; truncated: boolean } => {\n\t\t\tif (currentBytes >= MAX_CAPTURE_BYTES) {\n\t\t\t\treturn { nextBytes: currentBytes, truncated: true };\n\t\t\t}\n\t\t\tconst remaining = MAX_CAPTURE_BYTES - currentBytes;\n\t\t\tif (chunk.length <= remaining) {\n\t\t\t\tchunks.push(chunk);\n\t\t\t\treturn { nextBytes: currentBytes + chunk.length, truncated: false };\n\t\t\t}\n\t\t\tchunks.push(chunk.subarray(0, remaining));\n\t\t\treturn { nextBytes: MAX_CAPTURE_BYTES, truncated: true };\n\t\t};\n\n\t\tconst timeoutHandle = setTimeout(() => {\n\t\t\ttimedOut = true;\n\t\t\tchild.kill(\"SIGTERM\");\n\t\t}, Math.max(1_000, timeoutMs));\n\n\t\tconst cleanup = () => {\n\t\t\tclearTimeout(timeoutHandle);\n\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t};\n\n\t\tconst onAbort = () => {\n\t\t\taborted = true;\n\t\t\tchild.kill(\"SIGTERM\");\n\t\t};\n\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\n\t\tchild.stdout.on(\"data\", (chunk: Buffer) => {\n\t\t\tconst captured = captureChunk(chunk, stdoutChunks, stdoutBytes);\n\t\t\tstdoutBytes = captured.nextBytes;\n\t\t\tcaptureTruncated = captureTruncated || captured.truncated;\n\t\t});\n\n\t\tchild.stderr.on(\"data\", (chunk: Buffer) => {\n\t\t\tconst captured = captureChunk(chunk, stderrChunks, stderrBytes);\n\t\t\tstderrBytes = captured.nextBytes;\n\t\t\tcaptureTruncated = captureTruncated || captured.truncated;\n\t\t});\n\n\t\tif (stdin !== undefined) {\n\t\t\tchild.stdin.write(stdin);\n\t\t}\n\t\tchild.stdin.end();\n\n\t\tchild.on(\"error\", (error) => {\n\t\t\tcleanup();\n\t\t\tsettle(() => reject(new Error(`Failed to run ${command}: ${error.message}`)));\n\t\t});\n\n\t\tchild.on(\"close\", (code) => {\n\t\t\tcleanup();\n\n\t\t\tif (aborted) {\n\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (timedOut) {\n\t\t\t\tsettle(() => reject(new Error(`Command timed out after ${Math.round(timeoutMs / 1000)}s`)));\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tsettle(() =>\n\t\t\t\tresolve({\n\t\t\t\t\tstdout: Buffer.concat(stdoutChunks).toString(\"utf-8\"),\n\t\t\t\t\tstderr: Buffer.concat(stderrChunks).toString(\"utf-8\"),\n\t\t\t\t\texitCode: code ?? -1,\n\t\t\t\t\tcaptureTruncated,\n\t\t\t\t}),\n\t\t\t);\n\t\t});\n\t});\n}\n\nexport function createExternalCliTool(cwd: string, options: ExternalCliToolOptions): AgentTool<typeof externalCliSchema> {\n\tconst allowExitCodes = new Set(options.allowExitCodes ?? [0]);\n\tconst forbiddenArgs = new Set(options.forbiddenArgs ?? []);\n\tconst forbiddenPrefixes = options.forbiddenArgPrefixes ?? [];\n\n\treturn {\n\t\tname: options.name,\n\t\tlabel: options.label ?? options.name,\n\t\tdescription: options.description,\n\t\tparameters: externalCliSchema,\n\t\texecute: async (\n\t\t\t_toolCallId: string,\n\t\t\t{ args, path, stdin, timeout }: { args?: string[]; path?: string; stdin?: string; timeout?: number },\n\t\t\tsignal?: AbortSignal,\n\t\t) => {\n\t\t\tconst normalizedArgs = (args ?? []).map((arg) => String(arg));\n\t\t\tconst blockedArg = includesForbiddenArg(normalizedArgs, forbiddenArgs, forbiddenPrefixes);\n\t\t\tif (blockedArg) {\n\t\t\t\tthrow new Error(`Argument \"${blockedArg}\" is not allowed for ${options.name}.`);\n\t\t\t}\n\n\t\t\tconst command = await resolveCommand(options);\n\t\t\tif (!command) {\n\t\t\t\tconst hint = options.missingInstallHint ? ` ${options.missingInstallHint}` : \"\";\n\t\t\t\tthrow new Error(`${options.name} command is not available.${hint}`);\n\t\t\t}\n\n\t\t\tconst executionCwd = resolveToCwd(path || \".\", cwd);\n\t\t\tconst timeoutMs = Math.round((timeout ?? 30) * 1000);\n\t\t\tconst result = await runCommand(command, normalizedArgs, executionCwd, stdin, timeoutMs, signal);\n\n\t\t\tif (!allowExitCodes.has(result.exitCode)) {\n\t\t\t\tconst errorText = result.stderr.trim() || result.stdout.trim() || `${options.name} exited with code ${result.exitCode}`;\n\t\t\t\tthrow new Error(errorText);\n\t\t\t}\n\n\t\t\tlet output = result.stdout.trimEnd();\n\t\t\tif (!output && result.stderr.trim().length > 0) {\n\t\t\t\toutput = result.stderr.trimEnd();\n\t\t\t}\n\t\t\tif (!output) {\n\t\t\t\toutput = options.emptyOutputMessage ?? \"No output\";\n\t\t\t}\n\n\t\t\tconst truncation = truncateHead(output);\n\t\t\tlet finalOutput = truncation.content;\n\t\t\tconst details: ExternalCliToolDetails = {\n\t\t\t\tcommand,\n\t\t\t\targs: normalizedArgs,\n\t\t\t\tcwd: executionCwd,\n\t\t\t\texitCode: result.exitCode,\n\t\t\t};\n\t\t\tconst notices: string[] = [];\n\n\t\t\tif (truncation.truncated) {\n\t\t\t\tdetails.truncation = truncation;\n\t\t\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} output limit reached`);\n\t\t\t}\n\t\t\tif (result.captureTruncated) {\n\t\t\t\tdetails.captureTruncated = true;\n\t\t\t\tnotices.push(`capture limit reached (${formatSize(MAX_CAPTURE_BYTES)})`);\n\t\t\t}\n\t\t\tif (notices.length > 0) {\n\t\t\t\tfinalOutput += `\\n\\n[${notices.join(\". \")} · showing up to ${DEFAULT_MAX_LINES} lines]`;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: finalOutput }],\n\t\t\t\tdetails,\n\t\t\t};\n\t\t},\n\t};\n}\n\nexport { externalCliSchema };\n"]}
@@ -0,0 +1,12 @@
1
+ import type { AgentTool } from "@mariozechner/pi-agent-core";
2
+ import type { Static } from "@sinclair/typebox";
3
+ import { externalCliSchema } from "./external-cli.js";
4
+ export type FdToolInput = Static<typeof externalCliSchema>;
5
+ export declare function createFdTool(cwd: string): AgentTool<typeof externalCliSchema>;
6
+ export declare const fdTool: AgentTool<import("@sinclair/typebox").TObject<{
7
+ args: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TArray<import("@sinclair/typebox").TString>>;
8
+ path: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
9
+ stdin: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TString>;
10
+ timeout: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
11
+ }>, any>;
12
+ //# sourceMappingURL=fd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fd.d.ts","sourceRoot":"","sources":["../../../src/core/tools/fd.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAyB,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAE7E,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE3D,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAC,OAAO,iBAAiB,CAAC,CAY7E;AAED,eAAO,MAAM,MAAM;;;;;QAA8B,CAAC"}
@@ -0,0 +1,15 @@
1
+ import { createExternalCliTool } from "./external-cli.js";
2
+ export function createFdTool(cwd) {
3
+ return createExternalCliTool(cwd, {
4
+ name: "fd",
5
+ label: "fd",
6
+ description: "Run fd directly for fast file discovery. Args are passed directly to fd (no shell interpolation). Exit code 1 (no results) is treated as success.",
7
+ commandCandidates: ["fd"],
8
+ ensureManagedTool: "fd",
9
+ allowExitCodes: [0, 1],
10
+ emptyOutputMessage: "No files found",
11
+ missingInstallHint: "Install fd or allow iosm-cli to download managed binaries.",
12
+ });
13
+ }
14
+ export const fdTool = createFdTool(process.cwd());
15
+ //# sourceMappingURL=fd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fd.js","sourceRoot":"","sources":["../../../src/core/tools/fd.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,qBAAqB,EAAqB,MAAM,mBAAmB,CAAC;AAI7E,MAAM,UAAU,YAAY,CAAC,GAAW;IACvC,OAAO,qBAAqB,CAAC,GAAG,EAAE;QACjC,IAAI,EAAE,IAAI;QACV,KAAK,EAAE,IAAI;QACX,WAAW,EACV,mJAAmJ;QACpJ,iBAAiB,EAAE,CAAC,IAAI,CAAC;QACzB,iBAAiB,EAAE,IAAI;QACvB,cAAc,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;QACtB,kBAAkB,EAAE,gBAAgB;QACpC,kBAAkB,EAAE,4DAA4D;KAChF,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC","sourcesContent":["import type { AgentTool } from \"@mariozechner/pi-agent-core\";\nimport type { Static } from \"@sinclair/typebox\";\nimport { createExternalCliTool, externalCliSchema } from \"./external-cli.js\";\n\nexport type FdToolInput = Static<typeof externalCliSchema>;\n\nexport function createFdTool(cwd: string): AgentTool<typeof externalCliSchema> {\n\treturn createExternalCliTool(cwd, {\n\t\tname: \"fd\",\n\t\tlabel: \"fd\",\n\t\tdescription:\n\t\t\t\"Run fd directly for fast file discovery. Args are passed directly to fd (no shell interpolation). Exit code 1 (no results) is treated as success.\",\n\t\tcommandCandidates: [\"fd\"],\n\t\tensureManagedTool: \"fd\",\n\t\tallowExitCodes: [0, 1],\n\t\temptyOutputMessage: \"No files found\",\n\t\tmissingInstallHint: \"Install fd or allow iosm-cli to download managed binaries.\",\n\t});\n}\n\nexport const fdTool = createFdTool(process.cwd());\n"]}