@oh-my-pi/pi-coding-agent 13.2.0 → 13.2.1

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 (228) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/package.json +7 -7
  3. package/scripts/format-prompts.ts +33 -14
  4. package/src/capability/index.ts +1 -2
  5. package/src/cli/args.ts +1 -2
  6. package/src/cli/config-cli.ts +1 -1
  7. package/src/cli/file-processor.ts +1 -2
  8. package/src/cli/grep-cli.ts +1 -1
  9. package/src/cli/jupyter-cli.ts +1 -1
  10. package/src/cli/plugin-cli.ts +1 -1
  11. package/src/cli/setup-cli.ts +1 -1
  12. package/src/cli/shell-cli.ts +1 -1
  13. package/src/cli/ssh-cli.ts +1 -1
  14. package/src/cli/stats-cli.ts +1 -2
  15. package/src/cli/update-cli.ts +1 -2
  16. package/src/cli/web-search-cli.ts +1 -1
  17. package/src/cli.ts +1 -1
  18. package/src/commands/launch.ts +2 -1
  19. package/src/commit/agentic/agent.ts +2 -1
  20. package/src/commit/agentic/index.ts +1 -2
  21. package/src/commit/agentic/prompts/system.md +3 -3
  22. package/src/commit/agentic/tools/propose-changelog.ts +30 -19
  23. package/src/commit/changelog/generate.ts +16 -6
  24. package/src/commit/changelog/index.ts +2 -1
  25. package/src/commit/pipeline.ts +1 -2
  26. package/src/commit/prompts/reduce-system.md +1 -1
  27. package/src/commit/types.ts +10 -1
  28. package/src/config/keybindings.ts +1 -2
  29. package/src/config/model-registry.ts +1 -1
  30. package/src/config/prompt-templates.ts +14 -2
  31. package/src/config/settings.ts +9 -2
  32. package/src/config.ts +1 -2
  33. package/src/debug/index.ts +1 -1
  34. package/src/debug/report-bundle.ts +1 -2
  35. package/src/debug/system-info.ts +1 -2
  36. package/src/discovery/agents.ts +2 -2
  37. package/src/discovery/builtin.ts +8 -9
  38. package/src/discovery/claude-plugins.ts +2 -2
  39. package/src/discovery/claude.ts +7 -7
  40. package/src/discovery/codex.ts +3 -3
  41. package/src/discovery/cursor.ts +5 -4
  42. package/src/discovery/gemini.ts +5 -5
  43. package/src/discovery/helpers.ts +47 -69
  44. package/src/discovery/mcp-json.ts +3 -3
  45. package/src/discovery/opencode.ts +7 -8
  46. package/src/discovery/ssh.ts +3 -3
  47. package/src/discovery/vscode.ts +3 -2
  48. package/src/discovery/windsurf.ts +3 -2
  49. package/src/exa/company.ts +1 -1
  50. package/src/exa/factory.ts +1 -6
  51. package/src/exa/linkedin.ts +1 -1
  52. package/src/exa/mcp-client.ts +19 -8
  53. package/src/exa/search.ts +2 -2
  54. package/src/exa/types.ts +3 -3
  55. package/src/exec/bash-executor.ts +2 -1
  56. package/src/exec/non-interactive-env.ts +43 -0
  57. package/src/export/custom-share.ts +1 -1
  58. package/src/export/html/index.ts +1 -2
  59. package/src/extensibility/custom-commands/loader.ts +1 -2
  60. package/src/extensibility/plugins/installer.ts +1 -2
  61. package/src/extensibility/plugins/loader.ts +1 -2
  62. package/src/extensibility/plugins/manager.ts +3 -2
  63. package/src/extensibility/skills.ts +59 -115
  64. package/src/index.ts +1 -3
  65. package/src/internal-urls/docs-index.generated.ts +1 -1
  66. package/src/ipy/executor.ts +1 -2
  67. package/src/ipy/gateway-coordinator.ts +1 -2
  68. package/src/ipy/modules.ts +1 -1
  69. package/src/ipy/runtime.ts +1 -3
  70. package/src/main.ts +1 -2
  71. package/src/mcp/config.ts +1 -1
  72. package/src/mcp/transports/stdio.ts +1 -2
  73. package/src/memories/index.ts +1 -2
  74. package/src/modes/components/extensions/extension-dashboard.ts +1 -1
  75. package/src/modes/components/extensions/inspector-panel.ts +8 -2
  76. package/src/modes/components/footer.ts +1 -2
  77. package/src/modes/components/status-line/segments.ts +1 -2
  78. package/src/modes/components/tool-execution.ts +3 -10
  79. package/src/modes/components/welcome.ts +1 -1
  80. package/src/modes/controllers/command-controller.ts +1 -2
  81. package/src/modes/controllers/mcp-command-controller.ts +1 -1
  82. package/src/modes/controllers/selector-controller.ts +1 -1
  83. package/src/modes/controllers/ssh-command-controller.ts +1 -1
  84. package/src/modes/interactive-mode.ts +2 -3
  85. package/src/modes/shared.ts +1 -2
  86. package/src/modes/theme/theme.ts +1 -2
  87. package/src/patch/index.ts +1 -25
  88. package/src/prompts/agents/designer.md +7 -10
  89. package/src/prompts/agents/explore.md +15 -23
  90. package/src/prompts/agents/init.md +23 -23
  91. package/src/prompts/agents/plan.md +14 -77
  92. package/src/prompts/agents/reviewer.md +6 -5
  93. package/src/prompts/agents/task.md +13 -11
  94. package/src/prompts/compaction/branch-summary.md +3 -3
  95. package/src/prompts/compaction/compaction-short-summary.md +7 -7
  96. package/src/prompts/compaction/compaction-summary-context.md +1 -1
  97. package/src/prompts/compaction/compaction-summary.md +5 -5
  98. package/src/prompts/compaction/compaction-turn-prefix.md +3 -3
  99. package/src/prompts/compaction/compaction-update-summary.md +11 -11
  100. package/src/prompts/memories/consolidation.md +5 -5
  101. package/src/prompts/memories/read-path.md +6 -6
  102. package/src/prompts/memories/stage_one_input.md +1 -1
  103. package/src/prompts/memories/stage_one_system.md +5 -5
  104. package/src/prompts/review-request.md +4 -4
  105. package/src/prompts/system/agent-creation-architect.md +17 -17
  106. package/src/prompts/system/agent-creation-user.md +2 -2
  107. package/src/prompts/system/custom-system-prompt.md +4 -4
  108. package/src/prompts/system/plan-mode-active.md +20 -20
  109. package/src/prompts/system/plan-mode-approved.md +7 -7
  110. package/src/prompts/system/plan-mode-reference.md +2 -2
  111. package/src/prompts/system/plan-mode-subagent.md +8 -8
  112. package/src/prompts/system/subagent-submit-reminder.md +5 -5
  113. package/src/prompts/system/subagent-system-prompt.md +29 -22
  114. package/src/prompts/system/subagent-user-prompt.md +7 -3
  115. package/src/prompts/system/summarization-system.md +1 -1
  116. package/src/prompts/system/system-prompt.md +201 -226
  117. package/src/prompts/system/title-system.md +2 -2
  118. package/src/prompts/system/ttsr-interrupt.md +1 -1
  119. package/src/prompts/system/web-search.md +16 -16
  120. package/src/prompts/tools/ask.md +1 -3
  121. package/src/prompts/tools/await.md +2 -4
  122. package/src/prompts/tools/bash.md +5 -7
  123. package/src/prompts/tools/browser.md +4 -6
  124. package/src/prompts/tools/calculator.md +1 -3
  125. package/src/prompts/tools/cancel-job.md +2 -4
  126. package/src/prompts/tools/exit-plan-mode.md +7 -7
  127. package/src/prompts/tools/fetch.md +0 -2
  128. package/src/prompts/tools/find.md +3 -5
  129. package/src/prompts/tools/gemini-image.md +6 -22
  130. package/src/prompts/tools/grep.md +4 -6
  131. package/src/prompts/tools/hashline.md +12 -15
  132. package/src/prompts/tools/lsp.md +1 -3
  133. package/src/prompts/tools/patch.md +7 -9
  134. package/src/prompts/tools/python.md +10 -14
  135. package/src/prompts/tools/read.md +0 -2
  136. package/src/prompts/tools/replace.md +5 -7
  137. package/src/prompts/tools/ssh.md +3 -5
  138. package/src/prompts/tools/task.md +6 -8
  139. package/src/prompts/tools/todo-write.md +7 -9
  140. package/src/prompts/tools/web-search.md +3 -5
  141. package/src/prompts/tools/write.md +3 -5
  142. package/src/sdk.ts +1 -2
  143. package/src/session/agent-session.ts +10 -26
  144. package/src/session/agent-storage.ts +1 -2
  145. package/src/session/history-storage.ts +1 -2
  146. package/src/session/session-manager.ts +10 -2
  147. package/src/ssh/connection-manager.ts +11 -2
  148. package/src/ssh/sshfs-mount.ts +7 -1
  149. package/src/system-prompt.ts +25 -103
  150. package/src/task/agents.ts +1 -1
  151. package/src/task/worktree.ts +1 -2
  152. package/src/tools/ask.ts +0 -1
  153. package/src/tools/bash-interactive.ts +2 -45
  154. package/src/tools/bash.ts +5 -5
  155. package/src/tools/browser.ts +1 -2
  156. package/src/tools/gemini-image.ts +8 -28
  157. package/src/tools/json-tree.ts +2 -1
  158. package/src/tools/python.ts +1 -1
  159. package/src/tools/read.ts +1 -2
  160. package/src/utils/tools-manager.ts +1 -2
  161. package/src/web/scrapers/artifacthub.ts +2 -1
  162. package/src/web/scrapers/aur.ts +2 -1
  163. package/src/web/scrapers/biorxiv.ts +2 -1
  164. package/src/web/scrapers/bluesky.ts +2 -1
  165. package/src/web/scrapers/chocolatey.ts +2 -1
  166. package/src/web/scrapers/cisa-kev.ts +2 -1
  167. package/src/web/scrapers/clojars.ts +2 -1
  168. package/src/web/scrapers/coingecko.ts +2 -1
  169. package/src/web/scrapers/crates-io.ts +2 -1
  170. package/src/web/scrapers/crossref.ts +2 -1
  171. package/src/web/scrapers/discogs.ts +3 -1
  172. package/src/web/scrapers/discourse.ts +2 -1
  173. package/src/web/scrapers/dockerhub.ts +2 -1
  174. package/src/web/scrapers/fdroid.ts +2 -1
  175. package/src/web/scrapers/firefox-addons.ts +2 -1
  176. package/src/web/scrapers/flathub.ts +2 -1
  177. package/src/web/scrapers/gitlab.ts +1 -1
  178. package/src/web/scrapers/go-pkg.ts +2 -1
  179. package/src/web/scrapers/hackage.ts +2 -1
  180. package/src/web/scrapers/hackernews.ts +2 -1
  181. package/src/web/scrapers/hex.ts +2 -1
  182. package/src/web/scrapers/huggingface.ts +2 -1
  183. package/src/web/scrapers/jetbrains-marketplace.ts +2 -1
  184. package/src/web/scrapers/lemmy.ts +2 -1
  185. package/src/web/scrapers/lobsters.ts +2 -1
  186. package/src/web/scrapers/mastodon.ts +2 -1
  187. package/src/web/scrapers/maven.ts +2 -1
  188. package/src/web/scrapers/mdn.ts +2 -1
  189. package/src/web/scrapers/metacpan.ts +2 -1
  190. package/src/web/scrapers/musicbrainz.ts +3 -1
  191. package/src/web/scrapers/npm.ts +2 -1
  192. package/src/web/scrapers/nuget.ts +2 -1
  193. package/src/web/scrapers/nvd.ts +2 -1
  194. package/src/web/scrapers/ollama.ts +2 -1
  195. package/src/web/scrapers/open-vsx.ts +2 -1
  196. package/src/web/scrapers/opencorporates.ts +2 -1
  197. package/src/web/scrapers/openlibrary.ts +2 -1
  198. package/src/web/scrapers/orcid.ts +3 -1
  199. package/src/web/scrapers/osv.ts +2 -1
  200. package/src/web/scrapers/packagist.ts +2 -1
  201. package/src/web/scrapers/pub-dev.ts +2 -1
  202. package/src/web/scrapers/pubmed.ts +2 -1
  203. package/src/web/scrapers/pypi.ts +2 -1
  204. package/src/web/scrapers/rawg.ts +2 -8
  205. package/src/web/scrapers/reddit.ts +2 -1
  206. package/src/web/scrapers/repology.ts +2 -1
  207. package/src/web/scrapers/rfc.ts +2 -1
  208. package/src/web/scrapers/rubygems.ts +2 -1
  209. package/src/web/scrapers/searchcode.ts +2 -1
  210. package/src/web/scrapers/sec-edgar.ts +2 -1
  211. package/src/web/scrapers/semantic-scholar.ts +2 -1
  212. package/src/web/scrapers/snapcraft.ts +2 -1
  213. package/src/web/scrapers/sourcegraph.ts +2 -1
  214. package/src/web/scrapers/spdx.ts +2 -1
  215. package/src/web/scrapers/stackoverflow.ts +2 -1
  216. package/src/web/scrapers/terraform.ts +2 -1
  217. package/src/web/scrapers/types.ts +0 -11
  218. package/src/web/scrapers/vimeo.ts +2 -1
  219. package/src/web/scrapers/vscode-marketplace.ts +2 -1
  220. package/src/web/scrapers/w3c.ts +2 -1
  221. package/src/web/scrapers/wikidata.ts +2 -1
  222. package/src/web/search/index.ts +10 -14
  223. package/src/web/search/provider.ts +2 -2
  224. package/src/web/search/providers/codex.ts +1 -2
  225. package/src/web/search/providers/exa.ts +1 -6
  226. package/src/web/search/providers/gemini.ts +1 -1
  227. package/src/web/search/providers/perplexity.ts +1 -2
  228. package/src/web/search/providers/utils.ts +1 -1
@@ -1,6 +1,4 @@
1
- # Browser
2
-
3
- Navigate, click, type, scroll, drag, query DOM content, and capture screenshots.
1
+ Navigates, clicks, types, scrolls, drags, queries DOM content, and captures screenshots.
4
2
 
5
3
  <instruction>
6
4
  - `"open"` starts a headless session (or implicitly on first action); `"goto"` navigates to `url`; `"close"` releases the browser
@@ -15,10 +13,10 @@ Navigate, click, type, scroll, drag, query DOM content, and capture screenshots.
15
13
  </instruction>
16
14
 
17
15
  <critical>
18
- **You MUST default to `observe`, not `screenshot`.**
16
+ **You **MUST** default to `observe`, not `screenshot`.**
19
17
  - `observe` is cheaper, faster, and returns structured data — use it to understand page state, find elements, and plan interactions.
20
- - You SHOULD only use `screenshot` when visual appearance matters (verifying layout, debugging CSS, capturing a visual artifact for the user).
21
- - You MUST NOT screenshot just to "see what's on the page" — `observe` gives you that with element IDs you can act on immediately.
18
+ - You **SHOULD** only use `screenshot` when visual appearance matters (verifying layout, debugging CSS, capturing a visual artifact for the user).
19
+ - You **MUST NOT** screenshot just to "see what's on the page" — `observe` gives you that with element IDs you can act on immediately.
22
20
  </critical>
23
21
 
24
22
  <output>
@@ -1,6 +1,4 @@
1
- # Calculator
2
-
3
- Basic calculations.
1
+ Performs basic calculations.
4
2
 
5
3
  <instruction>
6
4
  - Supports +, -, *, /, %, ** and parentheses
@@ -1,7 +1,5 @@
1
- # Cancel Job
2
-
3
1
  Cancels a running background job started via async tool execution.
4
2
 
5
- You SHOULD use this when a background `bash` or `task` job is no longer needed or is stuck.
3
+ You **SHOULD** use this when a background `bash` or `task` job is no longer needed or is stuck.
6
4
 
7
- You MAY inspect jobs first with `read jobs://` or `read jobs://<job-id>`.
5
+ You **MAY** inspect jobs first with `read jobs://` or `read jobs://<job-id>`.
@@ -8,9 +8,9 @@ Use when:
8
8
  </conditions>
9
9
 
10
10
  <instruction>
11
- - You MUST write plan to plan file BEFORE calling this tool
11
+ - You **MUST** write plan to plan file BEFORE calling this tool
12
12
  - Tool reads plan from file—does not take plan content as parameter
13
- - You MUST provide a `title` argument for the final plan artifact (example: `WP_MIGRATION_PLAN`)
13
+ - You **MUST** provide a `title` argument for the final plan artifact (example: `WP_MIGRATION_PLAN`)
14
14
  - `.md` is optional in `title`; it is appended automatically when omitted
15
15
  - User sees plan contents when reviewing
16
16
  </instruction>
@@ -30,12 +30,12 @@ Unsure about auth method (OAuth vs JWT).
30
30
  </example>
31
31
 
32
32
  <avoid>
33
- - MUST NOT call before plan is written to file
34
- - MUST NOT omit `title`
35
- - MUST NOT use `ask` to request plan approval (this tool does that)
36
- - MUST NOT call after pure research tasks (no implementation planned)
33
+ - **MUST NOT** call before plan is written to file
34
+ - **MUST NOT** omit `title`
35
+ - **MUST NOT** use `ask` to request plan approval (this tool does that)
36
+ - **MUST NOT** call after pure research tasks (no implementation planned)
37
37
  </avoid>
38
38
 
39
39
  <critical>
40
- You MUST only use when planning implementation steps. Research tasks (searching, reading, understanding) do not need this tool.
40
+ You **MUST** only use when planning implementation steps. Research tasks (searching, reading, understanding) do not need this tool.
41
41
  </critical>
@@ -1,5 +1,3 @@
1
- # Fetch
2
-
3
1
  Retrieves content from a URL and returns it in a clean, readable format.
4
2
 
5
3
  <instruction>
@@ -1,12 +1,10 @@
1
- # Find
2
-
3
- Fast file pattern matching that works with any codebase size.
1
+ Finds files using fast pattern matching that works with any codebase size.
4
2
 
5
3
  <instruction>
6
4
  - Pattern includes the search path: `src/**/*.ts`, `lib/*.json`, `**/*.md`
7
5
  - Simple patterns like `*.ts` automatically search recursively from cwd
8
6
  - Includes hidden files by default (use `hidden: false` to exclude)
9
- - You SHOULD perform multiple searches in parallel when potentially useful
7
+ - You **SHOULD** perform multiple searches in parallel when potentially useful
10
8
  </instruction>
11
9
 
12
10
  <output>
@@ -23,5 +21,5 @@ Matching file paths sorted by modification time (most recent first). Truncated a
23
21
  </example>
24
22
 
25
23
  <avoid>
26
- For open-ended searches requiring multiple rounds of globbing and grepping, you MUST use Task tool instead.
24
+ For open-ended searches requiring multiple rounds of globbing and grepping, you **MUST** use Task tool instead.
27
25
  </avoid>
@@ -1,23 +1,7 @@
1
- # Gemini Image
1
+ Generates or edits images using Gemini image models.
2
2
 
3
- Generate or edit images using Gemini image models.
4
-
5
- <instruction>
6
- You SHOULD provide structured parameters for best results. Tool assembles into optimized prompt.
7
-
8
- When using multiple `input_images`, you MUST describe each image's role in `subject` or `scene` field:
9
- - "Use Image 1 for the character's face and outfit, Image 2 for the pose, Image 3 for the background environment"
10
- - "Match the color palette from Image 1, apply the lighting style from Image 2"
11
- </instruction>
12
-
13
- <output>
14
- Returns generated image saved to disk. Response includes file path where image was written.
15
- </output>
16
-
17
- <caution>
18
- - For photoreal: you SHOULD add "ultra-detailed, realistic, natural skin texture" to style
19
- - For posters/cards: you SHOULD use 9:16 aspect ratio with negative space for text placement
20
- - For iteration: you SHOULD use `changes` for targeted adjustments rather than regenerating from scratch
21
- - For text: you SHOULD add "sharp, legible, correctly spelled" for important text; keep text short
22
- - For diagrams: you SHOULD include "scientifically accurate" in style and provide facts explicitly
23
- </caution>
3
+ <instructions>
4
+ - You **MUST** provide a single detailed `subject` prompt for image generation or editing.
5
+ - When using multiple `input`, you **SHOULD** describe each image's role directly in `subject`, e.g. `Image 1` for composition reference, `Image 2` for lighting reference, `Image 3` for background.
6
+ - For text: you **SHOULD** add "sharp, legible, correctly spelled" for important text; keep text short
7
+ </instructions>
@@ -1,6 +1,4 @@
1
- # Grep
2
-
3
- Powerful search tool built on ripgrep.
1
+ Searches files using powerful regex matching built on ripgrep.
4
2
 
5
3
  <instruction>
6
4
  - Supports full regex syntax (e.g., `log.*Error`, `function\\s+\\w+`); literal braces need escaping (`interface\\{\\}` for `interface{}` in Go)
@@ -20,7 +18,7 @@ Powerful search tool built on ripgrep.
20
18
  </output>
21
19
 
22
20
  <critical>
23
- - You MUST use Grep when searching for content.
24
- - You MUST NOT invoke `grep` or `rg` via Bash.
25
- - If the search is open-ended, requiring multiple rounds, you MUST use Task tool with explore subagent instead.
21
+ - You **MUST** use Grep when searching for content.
22
+ - You **MUST NOT** invoke `grep` or `rg` via Bash.
23
+ - If the search is open-ended, requiring multiple rounds, you **MUST** use Task tool with explore subagent instead.
26
24
  </critical>
@@ -1,11 +1,9 @@
1
- # Edit
2
-
3
- Apply precise file edits using `LINE#ID` tags from `read` output.
1
+ Applies precise file edits using `LINE#ID` tags from `read` output.
4
2
 
5
3
  <workflow>
6
- 1. You SHOULD issue a `read` call before editing if you have no tagged context for a file.
7
- 2. You MUST pick the smallest operation per change site.
8
- 3. You MUST submit one `edit` call per file with all operations, think your changes through before submitting.
4
+ 1. You **SHOULD** issue a `read` call before editing if you have no tagged context for a file.
5
+ 2. You **MUST** pick the smallest operation per change site.
6
+ 3. You **MUST** submit one `edit` call per file with all operations, think your changes through before submitting.
9
7
  </workflow>
10
8
 
11
9
  <operations>
@@ -40,16 +38,14 @@ Every edit has `op`, `pos`, and `lines`. Range replaces also have `end`. Both `p
40
38
  </operations>
41
39
 
42
40
  <rules>
43
- 1. **Minimize scope:** You MUST use one logical mutation per operation.
44
- 2. **No no-ops:** replacement MUST differ from current.
45
- 3. **Prefer insertion over neighbor rewrites:** You SHOULD anchor on structural boundaries (`}`, `]`, `},`), not interior lines.
46
- 4. **For swaps/moves:** You SHOULD prefer one range op over multiple single-line ops.
47
- 5. **Range end tag:** When replacing a block (e.g., an `if` body), the `end` tag MUST include the block's closing brace/bracket — not just the last interior line. Verify the `end` tag covers all lines being logically removed, including trailing `}`, `]`, or `)`. An off-by-one on `end` orphans a brace and breaks syntax.
41
+ 1. **Minimize scope:** You **MUST** use one logical mutation per operation.
42
+ 2. **Prefer insertion over neighbor rewrites:** You **SHOULD** anchor on structural boundaries (`}`, `]`, `},`), not interior lines.
43
+ 3. **Range end tag:** When replacing a block (e.g., an `if` body), the `end` tag **MUST** include the block's closing brace/bracket — not just the last interior line. Verify the `end` tag covers all lines being logically removed, including trailing `}`, `]`, or `)`. An off-by-one on `end` orphans a brace and breaks syntax.
48
44
  </rules>
49
45
 
50
46
  <recovery>
51
- **Tag mismatch (`>>>`):** You MUST retry using fresh tags from the error snippet. Re-read only if snippet lacks context.
52
- **No-op (`identical`):** You MUST NOT resubmit. Re-read target lines and adjust the edit.
47
+ **Tag mismatch (`>>>`):** You **MUST** retry using fresh tags from the error snippet. If snippet lacks context, or if you repeatedly fail, you **MUST** re-read the file and issue less ambitious edits, i.e. single op.
48
+ **No-op (`identical`):** You **MUST NOT** resubmit. Re-read target lines and adjust the edit.
53
49
  </recovery>
54
50
 
55
51
  <example name="single-line replace">
@@ -186,6 +182,7 @@ Good — anchors to structural line:
186
182
 
187
183
  <critical>
188
184
  - Edit payload: `{ path, edits[] }`. Each entry: `op`, `lines`, optional `pos`/`end`. No extra keys.
189
- - Every tag MUST be copied exactly from fresh tool result as `N#ID`.
190
- - You MUST re-read after each edit call before issuing another on same file.
185
+ - Every tag **MUST** be copied exactly from fresh tool result as `N#ID`.
186
+ - You **MUST** re-read after each edit call before issuing another on same file.
187
+ - Formatting is a batch operation. You **MUST** never use this tool for formatting.
191
188
  </critical>
@@ -1,6 +1,4 @@
1
- # LSP
2
-
3
- Interact with Language Server Protocol servers for code intelligence.
1
+ Interacts with Language Server Protocol servers for code intelligence.
4
2
 
5
3
  <operations>
6
4
  - `definition`: Go to symbol definition → file path + position
@@ -1,6 +1,4 @@
1
- # Edit (Patch)
2
-
3
- Patch operations on file given diff. Primary tool for existing-file edits.
1
+ Patches files given diff hunks. Primary tool for existing-file edits.
4
2
 
5
3
  <instruction>
6
4
  **Hunk Headers:**
@@ -43,12 +41,12 @@ Returns success/failure; on failure, error message indicates:
43
41
  </output>
44
42
 
45
43
  <critical>
46
- - You MUST read the target file before editing
47
- - You MUST copy anchors and context lines verbatim (including whitespace)
48
- - You MUST NOT use anchors as comments (no line numbers, location labels, placeholders like `@@ @@`)
49
- - You MUST NOT place new lines outside the intended block
50
- - If edit fails or breaks structure, you MUST re-read the file and produce a new patch from current content — you MUST NOT retry the same diff
51
- - **NEVER** use edit to fix indentation, whitespace, or reformat code. Formatting is a single command run once at the end (`bun fmt`, `cargo fmt`, `prettier --write`, etc.)—not N individual edits. If you see inconsistent indentation after an edit, leave it; the formatter will fix all of it in one pass.
44
+ - You **MUST** read the target file before editing
45
+ - You **MUST** copy anchors and context lines verbatim (including whitespace)
46
+ - You **MUST NOT** use anchors as comments (no line numbers, location labels, placeholders like `@@ @@`)
47
+ - You **MUST NOT** place new lines outside the intended block
48
+ - If edit fails or breaks structure, you **MUST** re-read the file and produce a new patch from current content — you **MUST NOT** retry the same diff
49
+ - **NEVER** use edit to fix indentation, whitespace, or reformat code. Formatting is a single command run once at the end (`bun fmt`, `cargo fmt`, `prettier write`, etc.)—not N individual edits. If you see inconsistent indentation after an edit, leave it; the formatter will fix all of it in one pass.
52
50
  </critical>
53
51
 
54
52
  <example name="create">
@@ -1,23 +1,21 @@
1
- # Python
2
-
3
1
  Runs Python cells sequentially in persistent IPython kernel.
4
2
 
5
3
  <instruction>
6
4
  Kernel persists across calls and cells; **imports, variables, and functions survive—use this.**
7
5
  **Work incrementally:**
8
- - You SHOULD use one logical step per cell (imports, define function, test it, use it)
9
- - You SHOULD pass multiple small cells in one call
10
- - You SHOULD define small functions you can reuse and debug individually
11
- - You MUST put explanations in assistant message or cell title, MUST NOT put them in code
6
+ - You **SHOULD** use one logical step per cell (imports, define function, test it, use it)
7
+ - You **SHOULD** pass multiple small cells in one call
8
+ - You **SHOULD** define small functions you can reuse and debug individually
9
+ - You **MUST** put explanations in assistant message or cell title, **MUST NOT** put them in code
12
10
  **When something fails:**
13
11
  - Errors tell you which cell failed (e.g., "Cell 3 failed")
14
- - You SHOULD resubmit only the fixed cell (or fixed cell + remaining cells)
12
+ - You **SHOULD** resubmit only the fixed cell (or fixed cell + remaining cells)
15
13
  </instruction>
16
14
 
15
+ {{#if categories.length}}
17
16
  <prelude>
18
17
  All helpers auto-print results and return values for chaining.
19
18
 
20
- {{#if categories.length}}
21
19
  {{#each categories}}
22
20
  ### {{name}}
23
21
 
@@ -28,10 +26,8 @@ All helpers auto-print results and return values for chaining.
28
26
  {{/each}}
29
27
  ```
30
28
  {{/each}}
31
- {{else}}
32
- (Documentation unavailable — Python kernel failed to start)
33
- {{/if}}
34
29
  </prelude>
30
+ {{/if}}
35
31
 
36
32
  <output>
37
33
  User sees output like Jupyter notebook; rich displays render fully:
@@ -39,16 +35,16 @@ User sees output like Jupyter notebook; rich displays render fully:
39
35
  - `display(HTML(…))` → rendered HTML
40
36
  - `display(Markdown(…))` → formatted markdown
41
37
  - `plt.show()` → inline figures
42
- **You will see object repr** (e.g., `<IPython.core.display.JSON object>`). Trust `display()`; you MUST NOT assume user sees only repr.
38
+ **You will see object repr** (e.g., `<IPython.core.display.JSON object>`). Trust `display()`; you **MUST NOT** assume user sees only repr.
43
39
  </output>
44
40
 
45
41
  <caution>
46
42
  - Per-call mode uses fresh kernel each call
47
- - You MUST use `reset: true` to clear state when session mode active
43
+ - You **MUST** use `reset: true` to clear state when session mode active
48
44
  </caution>
49
45
 
50
46
  <critical>
51
- - You MUST use `run()` for shell commands; you MUST NOT use raw `subprocess`
47
+ - You **MUST** use `run()` for shell commands; you **MUST NOT** use raw `subprocess`
52
48
  </critical>
53
49
 
54
50
  <example name="good">
@@ -1,5 +1,3 @@
1
- # Read
2
-
3
1
  Reads files from local filesystem or internal URLs.
4
2
 
5
3
  <instruction>
@@ -1,12 +1,10 @@
1
- # Edit (Replace)
2
-
3
- String replacements in files with fuzzy whitespace matching.
1
+ Performs string replacements in files with fuzzy whitespace matching.
4
2
 
5
3
  <instruction>
6
- - You MUST use the smallest edit that uniquely identifies the change
7
- - If `old_text` not unique, you MUST expand to include more context or use `all: true` to replace all occurrences
4
+ - You **MUST** use the smallest edit that uniquely identifies the change
5
+ - If `old_text` not unique, you **MUST** expand to include more context or use `all: true` to replace all occurrences
8
6
  - Fuzzy matching handles minor whitespace/indentation differences automatically
9
- - You SHOULD prefer editing existing files over creating new ones
7
+ - You **SHOULD** prefer editing existing files over creating new ones
10
8
  </instruction>
11
9
 
12
10
  <output>
@@ -14,7 +12,7 @@ Returns success/failure status. On success, file modified in place with replacem
14
12
  </output>
15
13
 
16
14
  <critical>
17
- - You MUST read the file at least once in the conversation before editing. Tool errors if you attempt edit without reading file first.
15
+ - You **MUST** read the file at least once in the conversation before editing. Tool errors if you attempt edit without reading file first.
18
16
  </critical>
19
17
 
20
18
  <bash-alternatives>
@@ -1,9 +1,7 @@
1
- # SSH
2
-
3
- Run commands on remote hosts.
1
+ Runs commands on remote hosts.
4
2
 
5
3
  <instruction>
6
- You MUST build commands from the reference below
4
+ You **MUST** build commands from the reference below
7
5
  </instruction>
8
6
 
9
7
  <commands>
@@ -24,7 +22,7 @@ You MUST build commands from the reference below
24
22
  </commands>
25
23
 
26
24
  <critical>
27
- You MUST verify the shell type from "Available hosts" and use matching commands.
25
+ You **MUST** verify the shell type from "Available hosts" and use matching commands.
28
26
  </critical>
29
27
 
30
28
  <example name="linux">
@@ -1,13 +1,11 @@
1
- # Task
2
-
3
1
  Launches subagents to parallelize workflows.
4
2
 
5
3
  {{#if asyncEnabled}}
6
4
  - Use `read jobs://` to inspect state; `read jobs://<job_id>` for detail.
7
- - Use the `await` tool to wait until completion. You MUST NOT poll `read jobs://` in a loop.
5
+ - Use the `await` tool to wait until completion. You **MUST NOT** poll `read jobs://` in a loop.
8
6
  {{/if}}
9
7
 
10
- Subagents lack your conversation history. Every decision, file content, and user requirement they need MUST be explicit in `context` or `assignment`.
8
+ Subagents lack your conversation history. Every decision, file content, and user requirement they need **MUST** be explicit in `context` or `assignment`.
11
9
 
12
10
  <parameters>
13
11
  - `agent`: Agent type for all tasks.
@@ -16,15 +14,15 @@ Subagents lack your conversation history. Every decision, file content, and user
16
14
  - `.assignment`: Complete self-contained instructions. One-liners PROHIBITED; missing acceptance criteria = too vague.
17
15
  - `.skills`: Skill names to preload
18
16
  - `context`: Shared background prepended to every assignment. Session-specific info only.
19
- - `schema`: JTD schema for expected output. Format lives here — MUST NOT be duplicated in assignments.
17
+ - `schema`: JTD schema for expected output. Format lives here — **MUST NOT** be duplicated in assignments.
20
18
  - `tasks`: Tasks to execute in parallel.
21
19
  - `isolated`: Run in isolated git worktree; returns patches. Use when tasks edit overlapping files.
22
20
  </parameters>
23
21
 
24
22
  <critical>
25
- - MUST NOT include AGENTS.md rules, coding conventions, or style guidelines — subagents already have them.
26
- - MUST NOT duplicate shared constraints across assignments — put them in `context` once.
27
- - MUST NOT tell tasks to run project-wide build/test/lint. Parallel agents share the working tree; each task edits, stops. Caller verifies after all complete.
23
+ - **MUST NOT** include AGENTS.md rules, coding conventions, or style guidelines — subagents already have them.
24
+ - **MUST NOT** duplicate shared constraints across assignments — put them in `context` once.
25
+ - **MUST NOT** tell tasks to run project-wide build/test/lint. Parallel agents share the working tree; each task edits, stops. Caller verifies after all complete.
28
26
  - For large payloads (traces, JSON blobs), write to `local://<path>` and pass the path in context.
29
27
  - If scope is unclear, run a **Discovery task** first to enumerate files and callsites, then fan out.
30
28
  </critical>
@@ -1,14 +1,12 @@
1
- # Todo Write
2
-
3
- Manage a phased task list. Submit an `ops` array — each op mutates state incrementally.
1
+ Manages a phased task list. Submit an `ops` array — each op mutates state incrementally.
4
2
  **Primary op: `update`.** Use it to mark tasks `in_progress` or `completed`. Only reach for other ops when the structure itself needs to change.
5
3
 
6
4
  <critical>
7
- You MUST call this tool twice per task:
5
+ You **MUST** call this tool twice per task:
8
6
  1. Before beginning — `{op: "update", id: "task-N", status: "in_progress"}`
9
7
  2. Immediately after finishing — `{op: "update", id: "task-N", status: "completed"}`
10
8
 
11
- You MUST keep exactly one task `in_progress` at all times. Mark `completed` immediately — no batching.
9
+ You **MUST** keep exactly one task `in_progress` at all times. Mark `completed` immediately — no batching.
12
10
  </critical>
13
11
 
14
12
  <conditions>
@@ -40,10 +38,10 @@ Create a todo list when:
40
38
  |`abandoned`|Dropped intentionally|
41
39
 
42
40
  ## Rules
43
- - You MUST mark `in_progress` **before** starting work, not after
44
- - You MUST mark `completed` **immediately** — never defer
45
- - You MUST keep exactly **one** task `in_progress`
46
- - You MUST complete phases in order — do not mark later tasks `completed` while earlier ones are `pending`
41
+ - You **MUST** mark `in_progress` **before** starting work, not after
42
+ - You **MUST** mark `completed` **immediately** — never defer
43
+ - You **MUST** keep exactly **one** task `in_progress`
44
+ - You **MUST** complete phases in order — do not mark later tasks `completed` while earlier ones are `pending`
47
45
  - On blockers: keep `in_progress`, add a new task describing the blocker
48
46
  - Multiple ops can be batched in one call (e.g., complete current + start next)
49
47
  </protocol>
@@ -1,10 +1,8 @@
1
- # Web Search
2
-
3
- Search the web for up-to-date information beyond Claude's knowledge cutoff.
1
+ Searches the web for up-to-date information beyond Claude's knowledge cutoff.
4
2
 
5
3
  <instruction>
6
- - You SHOULD prefer primary sources (papers, official docs) and corroborate key claims with multiple sources
7
- - You MUST include links for cited sources in the final response
4
+ - You **SHOULD** prefer primary sources (papers, official docs) and corroborate key claims with multiple sources
5
+ - You **MUST** include links for cited sources in the final response
8
6
  </instruction>
9
7
 
10
8
  <caution>
@@ -1,5 +1,3 @@
1
- # Write
2
-
3
1
  Creates or overwrites file at specified path.
4
2
 
5
3
  <conditions>
@@ -8,7 +6,7 @@ Creates or overwrites file at specified path.
8
6
  </conditions>
9
7
 
10
8
  <critical>
11
- - You SHOULD use Edit tool for modifying existing files (more precise, preserves formatting)
12
- - You MUST NOT create documentation files (*.md, README) unless explicitly requested
13
- - You MUST NOT use emojis unless requested
9
+ - You **SHOULD** use Edit tool for modifying existing files (more precise, preserves formatting)
10
+ - You **MUST NOT** create documentation files (*.md, README) unless explicitly requested
11
+ - You **MUST NOT** use emojis unless requested
14
12
  </critical>
package/src/sdk.ts CHANGED
@@ -9,8 +9,7 @@ import {
9
9
  import { type Message, type Model, supportsXhigh } from "@oh-my-pi/pi-ai";
10
10
  import { prewarmOpenAICodexResponses } from "@oh-my-pi/pi-ai/providers/openai-codex-responses";
11
11
  import type { Component } from "@oh-my-pi/pi-tui";
12
- import { $env, logger, postmortem } from "@oh-my-pi/pi-utils";
13
- import { getAgentDbPath, getAgentDir, getProjectDir } from "@oh-my-pi/pi-utils/dirs";
12
+ import { $env, getAgentDbPath, getAgentDir, getProjectDir, logger, postmortem } from "@oh-my-pi/pi-utils";
14
13
  import chalk from "chalk";
15
14
  import { AsyncJobManager } from "./async";
16
15
  import { loadCapability } from "./capability";
@@ -23,6 +23,7 @@ import {
23
23
  type AgentMessage,
24
24
  type AgentState,
25
25
  type AgentTool,
26
+ INTENT_FIELD,
26
27
  type ThinkingLevel,
27
28
  } from "@oh-my-pi/pi-agent-core";
28
29
  import type {
@@ -38,8 +39,7 @@ import type {
38
39
  UsageReport,
39
40
  } from "@oh-my-pi/pi-ai";
40
41
  import { isContextOverflow, modelsAreEqual, supportsXhigh } from "@oh-my-pi/pi-ai";
41
- import { abortableSleep, isEnoent, logger } from "@oh-my-pi/pi-utils";
42
- import { getAgentDbPath } from "@oh-my-pi/pi-utils/dirs";
42
+ import { abortableSleep, getAgentDbPath, isEnoent, logger } from "@oh-my-pi/pi-utils";
43
43
  import type { AsyncJob, AsyncJobManager } from "../async";
44
44
  import type { Rule } from "../capability/rule";
45
45
  import { MODEL_ROLE_IDS, type ModelRegistry, type ModelRole } from "../config/model-registry";
@@ -84,8 +84,6 @@ import planModeActivePrompt from "../prompts/system/plan-mode-active.md" with {
84
84
  import planModeReferencePrompt from "../prompts/system/plan-mode-reference.md" with { type: "text" };
85
85
  import ttsrInterruptTemplate from "../prompts/system/ttsr-interrupt.md" with { type: "text" };
86
86
  import type { SecretObfuscator } from "../secrets/obfuscator";
87
- import { closeAllConnections } from "../ssh/connection-manager";
88
- import { unmountAll } from "../ssh/sshfs-mount";
89
87
  import { outputMeta } from "../tools/output-meta";
90
88
  import { resolveToCwd } from "../tools/path-utils";
91
89
  import { getLatestTodoPhasesFromEntries, type TodoItem, type TodoPhase } from "../tools/todo-write";
@@ -273,15 +271,6 @@ const noOpUIContext: ExtensionUIContext = {
273
271
  setToolsExpanded: () => {},
274
272
  };
275
273
 
276
- async function cleanupSshResources(): Promise<void> {
277
- const results = await Promise.allSettled([closeAllConnections(), unmountAll()]);
278
- for (const result of results) {
279
- if (result.status === "rejected") {
280
- logger.warn("SSH cleanup failed", { error: String(result.reason) });
281
- }
282
- }
283
- }
284
-
285
274
  // ============================================================================
286
275
  // AgentSession Class
287
276
  // ============================================================================
@@ -1275,13 +1264,19 @@ export class AgentSession {
1275
1264
  * Call this when completely done with the session.
1276
1265
  */
1277
1266
  async dispose(): Promise<void> {
1267
+ try {
1268
+ if (this.#extensionRunner?.hasHandlers("session_shutdown")) {
1269
+ await this.#extensionRunner.emit({ type: "session_shutdown" });
1270
+ }
1271
+ } catch (error) {
1272
+ logger.warn("Failed to emit session_shutdown event", { error: String(error) });
1273
+ }
1278
1274
  const drained = await this.#asyncJobManager?.dispose({ timeoutMs: 3_000 });
1279
1275
  const deliveryState = this.#asyncJobManager?.getDeliveryState();
1280
1276
  if (drained === false && deliveryState) {
1281
1277
  logger.warn("Async job completion deliveries still pending during dispose", { ...deliveryState });
1282
1278
  }
1283
1279
  await this.sessionManager.flush();
1284
- await cleanupSshResources();
1285
1280
  for (const state of this.#providerSessionState.values()) {
1286
1281
  state.close();
1287
1282
  }
@@ -4615,7 +4610,7 @@ Be thorough - include exact file paths, function names, error messages, and tech
4615
4610
  function formatArgsAsXml(args: Record<string, unknown>, indent = "\t"): string {
4616
4611
  const parts: string[] = [];
4617
4612
  for (const [key, value] of Object.entries(args)) {
4618
- if (key === "agent__intent") continue;
4613
+ if (key === INTENT_FIELD) continue;
4619
4614
  const text = typeof value === "string" ? value : JSON.stringify(value);
4620
4615
  parts.push(`${indent}<parameter name="${key}">${text}</parameter>`);
4621
4616
  }
@@ -4861,15 +4856,4 @@ Be thorough - include exact file paths, function names, error messages, and tech
4861
4856
  get extensionRunner(): ExtensionRunner | undefined {
4862
4857
  return this.#extensionRunner;
4863
4858
  }
4864
-
4865
- /**
4866
- * Emit a custom tool session event (backwards compatibility for older callers).
4867
- */
4868
- async emitCustomToolSessionEvent(reason: "start" | "switch" | "branch" | "tree" | "shutdown"): Promise<void> {
4869
- if (reason !== "shutdown") return;
4870
- if (this.#extensionRunner?.hasHandlers("session_shutdown")) {
4871
- await this.#extensionRunner.emit({ type: "session_shutdown" });
4872
- }
4873
- await cleanupSshResources();
4874
- }
4875
4859
  }
@@ -2,8 +2,7 @@ import { Database, type Statement } from "bun:sqlite";
2
2
  import * as fs from "node:fs";
3
3
  import * as path from "node:path";
4
4
  import { type AuthCredential, AuthCredentialStore, type StoredAuthCredential } from "@oh-my-pi/pi-ai";
5
- import { isRecord, logger } from "@oh-my-pi/pi-utils";
6
- import { getAgentDbPath } from "@oh-my-pi/pi-utils/dirs";
5
+ import { getAgentDbPath, isRecord, logger } from "@oh-my-pi/pi-utils";
7
6
  import type { RawSettings as Settings } from "../config/settings";
8
7
 
9
8
  /** Row shape for settings table queries */
@@ -1,8 +1,7 @@
1
1
  import { Database, type Statement } from "bun:sqlite";
2
2
  import * as fs from "node:fs";
3
3
  import * as path from "node:path";
4
- import { logger } from "@oh-my-pi/pi-utils";
5
- import { getAgentDir } from "@oh-my-pi/pi-utils/dirs";
4
+ import { getAgentDir, logger } from "@oh-my-pi/pi-utils";
6
5
 
7
6
  export interface HistoryEntry {
8
7
  id: number;
@@ -4,8 +4,16 @@ import * as path from "node:path";
4
4
  import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
5
5
  import type { ImageContent, Message, TextContent, Usage } from "@oh-my-pi/pi-ai";
6
6
  import { getTerminalId } from "@oh-my-pi/pi-tui";
7
- import { isEnoent, logger, parseJsonlLenient, Snowflake, toError } from "@oh-my-pi/pi-utils";
8
- import { getBlobsDir, getAgentDir as getDefaultAgentDir, getProjectDir } from "@oh-my-pi/pi-utils/dirs";
7
+ import {
8
+ getBlobsDir,
9
+ getAgentDir as getDefaultAgentDir,
10
+ getProjectDir,
11
+ isEnoent,
12
+ logger,
13
+ parseJsonlLenient,
14
+ Snowflake,
15
+ toError,
16
+ } from "@oh-my-pi/pi-utils";
9
17
  import { ArtifactManager } from "./artifacts";
10
18
  import { type BlobPutResult, BlobStore, externalizeImageData, isBlobRef, resolveImageData } from "./blob-store";
11
19
  import {
@@ -1,7 +1,6 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
- import { isEnoent, logger } from "@oh-my-pi/pi-utils";
4
- import { getRemoteHostDir, getSshControlDir } from "@oh-my-pi/pi-utils/dirs";
3
+ import { getRemoteHostDir, getSshControlDir, isEnoent, logger, postmortem } from "@oh-my-pi/pi-utils";
5
4
  import { $ } from "bun";
6
5
  import { buildSshTarget, sanitizeHostName } from "./utils";
7
6
 
@@ -69,6 +68,7 @@ async function validateKeyPermissions(keyPath?: string): Promise<void> {
69
68
 
70
69
  function buildCommonArgs(host: SSHConnectionTarget): string[] {
71
70
  const args = [
71
+ "-n",
72
72
  "-o",
73
73
  "ControlMaster=auto",
74
74
  "-o",
@@ -362,6 +362,8 @@ export async function buildRemoteCommand(host: SSHConnectionTarget, command: str
362
362
  return [...buildCommonArgs(host), buildSshTarget(host.username, host.host), command];
363
363
  }
364
364
 
365
+ let registered = false;
366
+
365
367
  export async function ensureConnection(host: SSHConnectionTarget): Promise<void> {
366
368
  const key = host.name;
367
369
  const pending = pendingConnections.get(key);
@@ -375,6 +377,13 @@ export async function ensureConnection(host: SSHConnectionTarget): Promise<void>
375
377
  ensureControlDir();
376
378
  await validateKeyPermissions(host.keyPath);
377
379
 
380
+ if (!registered) {
381
+ registered = true;
382
+ postmortem.register("ssh-cleanup", async () => {
383
+ await closeAllConnections();
384
+ });
385
+ }
386
+
378
387
  const target = buildSshTarget(host.username, host.host);
379
388
  const check = await runSshSync(["-O", "check", ...buildCommonArgs(host), target]);
380
389
  if (check.exitCode === 0) {