@oh-my-pi/pi-coding-agent 14.2.1 → 14.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/CHANGELOG.md +143 -1
  2. package/package.json +19 -19
  3. package/src/autoresearch/prompt.md +1 -1
  4. package/src/cli/args.ts +10 -1
  5. package/src/cli/shell-cli.ts +15 -3
  6. package/src/commit/agentic/prompts/analyze-file.md +1 -1
  7. package/src/config/model-registry.ts +67 -15
  8. package/src/config/prompt-templates.ts +5 -5
  9. package/src/config/settings-schema.ts +63 -4
  10. package/src/cursor.ts +3 -8
  11. package/src/debug/system-info.ts +6 -2
  12. package/src/discovery/claude.ts +58 -36
  13. package/src/discovery/helpers.ts +3 -3
  14. package/src/discovery/opencode.ts +20 -2
  15. package/src/edit/diff.ts +50 -47
  16. package/src/edit/index.ts +87 -57
  17. package/src/edit/line-hash.ts +735 -19
  18. package/src/edit/modes/apply-patch.ts +0 -9
  19. package/src/edit/modes/atom.ts +658 -0
  20. package/src/edit/modes/chunk.ts +144 -78
  21. package/src/edit/modes/hashline.ts +223 -146
  22. package/src/edit/modes/patch.ts +5 -9
  23. package/src/edit/modes/replace.ts +6 -11
  24. package/src/edit/renderer.ts +112 -143
  25. package/src/edit/streaming.ts +385 -0
  26. package/src/exec/bash-executor.ts +58 -5
  27. package/src/export/html/template.generated.ts +1 -1
  28. package/src/export/html/template.js +4 -12
  29. package/src/extensibility/custom-tools/types.ts +2 -0
  30. package/src/extensibility/custom-tools/wrapper.ts +2 -1
  31. package/src/internal-urls/docs-index.generated.ts +7 -7
  32. package/src/internal-urls/pi-protocol.ts +0 -2
  33. package/src/lsp/client.ts +8 -1
  34. package/src/lsp/defaults.json +2 -1
  35. package/src/lsp/index.ts +1 -1
  36. package/src/mcp/render.ts +1 -8
  37. package/src/modes/acp/acp-agent.ts +76 -2
  38. package/src/modes/components/assistant-message.ts +5 -34
  39. package/src/modes/components/diff.ts +23 -14
  40. package/src/modes/components/footer.ts +21 -16
  41. package/src/modes/components/hook-editor.ts +1 -1
  42. package/src/modes/components/settings-defs.ts +6 -1
  43. package/src/modes/components/todo-reminder.ts +1 -8
  44. package/src/modes/components/tool-execution.ts +112 -105
  45. package/src/modes/controllers/input-controller.ts +1 -1
  46. package/src/modes/controllers/selector-controller.ts +1 -1
  47. package/src/modes/interactive-mode.ts +0 -2
  48. package/src/modes/print-mode.ts +8 -0
  49. package/src/modes/theme/mermaid-cache.ts +13 -52
  50. package/src/modes/theme/theme.ts +2 -2
  51. package/src/prompts/agents/librarian.md +1 -1
  52. package/src/prompts/agents/reviewer.md +4 -4
  53. package/src/prompts/ci-green-request.md +1 -1
  54. package/src/prompts/review-request.md +1 -1
  55. package/src/prompts/system/subagent-system-prompt.md +3 -3
  56. package/src/prompts/system/subagent-yield-reminder.md +11 -0
  57. package/src/prompts/system/system-prompt.md +4 -1
  58. package/src/prompts/tools/ask.md +3 -2
  59. package/src/prompts/tools/ast-edit.md +15 -19
  60. package/src/prompts/tools/ast-grep.md +18 -24
  61. package/src/prompts/tools/atom.md +96 -0
  62. package/src/prompts/tools/browser.md +1 -0
  63. package/src/prompts/tools/chunk-edit.md +58 -179
  64. package/src/prompts/tools/debug.md +4 -5
  65. package/src/prompts/tools/exit-plan-mode.md +4 -5
  66. package/src/prompts/tools/find.md +4 -8
  67. package/src/prompts/tools/github.md +18 -0
  68. package/src/prompts/tools/grep.md +8 -8
  69. package/src/prompts/tools/hashline.md +22 -89
  70. package/src/prompts/tools/{gemini-image.md → image-gen.md} +1 -1
  71. package/src/prompts/tools/inspect-image.md +6 -6
  72. package/src/prompts/tools/lsp.md +6 -0
  73. package/src/prompts/tools/patch.md +12 -19
  74. package/src/prompts/tools/python.md +3 -2
  75. package/src/prompts/tools/read-chunk.md +46 -8
  76. package/src/prompts/tools/read.md +9 -6
  77. package/src/prompts/tools/ssh.md +8 -17
  78. package/src/prompts/tools/todo-write.md +54 -41
  79. package/src/sdk.ts +22 -14
  80. package/src/session/agent-session.ts +61 -22
  81. package/src/session/session-manager.ts +228 -57
  82. package/src/session/streaming-output.ts +11 -0
  83. package/src/system-prompt.ts +7 -2
  84. package/src/task/executor.ts +44 -48
  85. package/src/task/render.ts +11 -13
  86. package/src/tools/ask.ts +7 -7
  87. package/src/tools/ast-edit.ts +45 -41
  88. package/src/tools/ast-grep.ts +77 -85
  89. package/src/tools/bash.ts +21 -9
  90. package/src/tools/browser.ts +32 -30
  91. package/src/tools/calculator.ts +4 -4
  92. package/src/tools/cancel-job.ts +1 -1
  93. package/src/tools/checkpoint.ts +2 -2
  94. package/src/tools/debug.ts +41 -37
  95. package/src/tools/exit-plan-mode.ts +1 -1
  96. package/src/tools/find.ts +4 -4
  97. package/src/tools/gh-renderer.ts +12 -4
  98. package/src/tools/gh.ts +514 -712
  99. package/src/tools/grep.ts +115 -130
  100. package/src/tools/{gemini-image.ts → image-gen.ts} +459 -60
  101. package/src/tools/index.ts +14 -32
  102. package/src/tools/inspect-image.ts +3 -3
  103. package/src/tools/json-tree.ts +114 -114
  104. package/src/tools/match-line-format.ts +9 -8
  105. package/src/tools/notebook.ts +8 -7
  106. package/src/tools/poll-tool.ts +2 -1
  107. package/src/tools/python.ts +9 -23
  108. package/src/tools/read.ts +32 -21
  109. package/src/tools/render-mermaid.ts +1 -1
  110. package/src/tools/render-utils.ts +18 -0
  111. package/src/tools/renderers.ts +2 -2
  112. package/src/tools/report-tool-issue.ts +3 -2
  113. package/src/tools/resolve.ts +1 -1
  114. package/src/tools/review.ts +12 -10
  115. package/src/tools/search-tool-bm25.ts +2 -4
  116. package/src/tools/sqlite-reader.ts +116 -3
  117. package/src/tools/ssh.ts +4 -4
  118. package/src/tools/todo-write.ts +172 -147
  119. package/src/tools/vim.ts +14 -15
  120. package/src/tools/write.ts +4 -4
  121. package/src/tools/{submit-result.ts → yield.ts} +11 -13
  122. package/src/utils/edit-mode.ts +2 -1
  123. package/src/utils/file-display-mode.ts +10 -5
  124. package/src/utils/git.ts +9 -5
  125. package/src/utils/shell-snapshot.ts +2 -3
  126. package/src/vim/render.ts +4 -4
  127. package/src/web/search/providers/codex.ts +129 -6
  128. package/src/prompts/system/subagent-submit-reminder.md +0 -11
  129. package/src/prompts/tools/gh-issue-view.md +0 -11
  130. package/src/prompts/tools/gh-pr-checkout.md +0 -12
  131. package/src/prompts/tools/gh-pr-diff.md +0 -12
  132. package/src/prompts/tools/gh-pr-push.md +0 -11
  133. package/src/prompts/tools/gh-pr-view.md +0 -11
  134. package/src/prompts/tools/gh-repo-view.md +0 -11
  135. package/src/prompts/tools/gh-run-watch.md +0 -12
  136. package/src/prompts/tools/gh-search-issues.md +0 -11
  137. package/src/prompts/tools/gh-search-prs.md +0 -11
@@ -8,14 +8,10 @@ Finds files using fast pattern matching that works with any codebase size.
8
8
  Matching file paths sorted by modification time (most recent first). Truncated at 1000 entries or 50KB (configurable via `limit`).
9
9
  </output>
10
10
 
11
- <example name="find files">
12
- ```
13
- {
14
- "pattern": "src/**/*.ts",
15
- "limit": 1000
16
- }
17
- ```
18
- </example>
11
+ <examples>
12
+ # Find files
13
+ `{"pattern": "src/**/*.ts", "limit": 1000}`
14
+ </examples>
19
15
 
20
16
  <avoid>
21
17
  For open-ended searches requiring multiple rounds of globbing and grepping, you **MUST** use Task tool instead.
@@ -0,0 +1,18 @@
1
+ GitHub CLI tool with a single op-based dispatch. Wraps `gh` for repository, issue, pull request, search, checkout, push, and Actions watch workflows.
2
+
3
+ <instruction>
4
+ Pick the operation via `op`. Each op uses a subset of the parameters:
5
+ - `repo_view` — Read repository metadata. Optional `repo` (owner/repo) and `branch`. Falls back to the current checkout or default `gh` repo.
6
+ - `issue_view` — Read an issue. Required `issue` (number or URL). Optional `repo`. Set `comments: false` to skip discussion.
7
+ - `pr_view` — Read a pull request, including reviews and inline review comments. Optional `pr` (number, URL, or branch); omitting it targets the current branch's PR. Optional `repo`. Set `comments: false` for a lighter summary.
8
+ - `pr_diff` — Read a pull request diff. Optional `pr`, `repo`. Set `nameOnly: true` for changed file names. Use `exclude` to drop generated paths from the diff.
9
+ - `pr_checkout` — Check a pull request out into a dedicated git worktree. Optional `pr`, `repo`, `branch` (local), `worktree` (path), `force` (reset existing local branch).
10
+ - `pr_push` — Push a checked-out PR branch back to its source branch. Requires the branch to have been checked out via `op: pr_checkout` (carries push metadata). Optional `branch`; defaults to the current checked-out git branch. Optional `forceWithLease`.
11
+ - `search_issues` — Search issues using normal GitHub issue search syntax. Required `query`. Optional `repo`, `limit`.
12
+ - `search_prs` — Search pull requests using normal GitHub PR search syntax. Required `query`. Optional `repo`, `limit`.
13
+ - `run_watch` — Watch a GitHub Actions workflow run. Optional `run` (id or URL). Omitting `run` watches all workflow runs for the current HEAD commit; `branch` falls back to the current branch. Optional `tail` (log lines per failed job). Streams snapshots, fast-fails on the first detected job failure (with a brief grace period to capture concurrent failures), then fetches tailed logs for the failed jobs. The full failed-job logs are saved as a session artifact for on-demand reads.
14
+ </instruction>
15
+
16
+ <output>
17
+ Returns a concise readable summary tailored to the chosen op (repo/issue/PR metadata, diff text, search results, checkout info, push target, or workflow run snapshot). For `run_watch`, the full failed-job logs are saved as a session artifact when failures occur.
18
+ </output>
@@ -2,26 +2,26 @@ Searches files using powerful regex matching.
2
2
 
3
3
  <instruction>
4
4
  - Supports full regex syntax (e.g., `log.*Error`, `function\\s+\\w+`); literal braces need escaping (`interface\\{\\}` for `interface{}` in Go)
5
- - `path` also accepts comma-separated path lists; pair with `glob` when you need a relative file filter in addition to `type`
6
- - For cross-line patterns like `struct \\{[\\s\\S]*?field`, set `multiline: true`
7
- - If the pattern contains a literal `\n`, `multiline` defaults to true automatically
5
+ - `path` is required and accepts a file, directory, glob, comma-separated path list, or internal URL
6
+ - Cross-line patterns are detected from literal `\n` or escaped `\\n` in `pattern`
8
7
  </instruction>
9
8
 
10
9
  <output>
11
10
  {{#if IS_HASHLINE_MODE}}
12
- - Text output is CID prefixed: `LINE#ID:content`
11
+ - Text output is anchor-prefixed: `123th:content` (match) or `123th-content` (context). The 2-letter ID is a content fingerprint.
13
12
  {{else}}
14
13
  {{#if IS_LINE_NUMBER_MODE}}
15
14
  - Text output is line-number-prefixed
16
15
  {{/if}}
17
16
  {{/if}}
18
17
  {{#if IS_CHUNK_MODE}}
19
- - Text output is chunk-path-prefixed: `path:selector>LINE|content`
18
+ - Text output is chunk-path-prefixed: `path:sel>123th:content`
20
19
  {{/if}}
21
20
  </output>
22
21
 
23
22
  <critical>
24
- - You **MUST** use Grep when searching for content.
25
- - You **MUST NOT** invoke `grep` or `rg` via Bash.
26
- - If the search is open-ended, requiring multiple rounds, you **MUST** use Task tool with explore subagent instead.
23
+ - You **MUST** use the built-in Grep tool for any content search. Do **NOT** shell out to `grep`, `rg`, `ripgrep`, `ag`, `ack`, `git grep`, `awk`, `sed`-for-search, or any other CLI search via Bash — even for a single match, even "just to check quickly", even piped through other commands.
24
+ - Bash `grep`/`rg` returns raw text without chunk paths, loses `.gitignore` semantics, bypasses result limits, and wastes tokens. The Grep tool is faster, structured, and already wired into the workspace — there is no scenario where Bash search is preferable.
25
+ - If you catch yourself typing `grep`, `rg`, or `| grep` in a Bash command, stop and re-issue the search through the Grep tool instead.
26
+ - If the search is open-ended, requiring multiple rounds, you **MUST** use the Task tool with the explore subagent instead of chaining Grep calls yourself.
27
27
  </critical>
@@ -1,22 +1,21 @@
1
- Applies precise file edits using `LINE#ID` anchors from `read` output.
1
+ Applies precise file edits using full anchors from `read` output (for example `160sr`).
2
2
 
3
- Read the file first. Copy anchors exactly from the latest `read` output. After any successful edit, re-read before editing that file again.
3
+ Read the file first. Copy the full anchors exactly as shown by `read`.
4
4
 
5
5
  <operations>
6
6
  **Top level**
7
7
  - `edits` — array of edit entries
8
+ - `path` (optional) — default file path used when an entry omits its own `path`. Lets you share the path across many edits in one request.
8
9
 
9
- **Edit entry**: `{ path, loc, content }` or `{ path, delete: true }` or `{ path, move: "new/path" }`
10
- - `path` — file path
10
+ **Edit entry**: `{ path?, loc, content }`
11
+ - `path` — file path (omit to fall back to the request-level `path`)
11
12
  - `loc` — where to apply the edit (see below)
12
- - `content` — replacement/inserted lines (array of strings preferred, `null` to delete)
13
- - `delete` — delete the file
14
- - `move` — move/rename the file
13
+ - `content` — replacement/inserted lines (`string[]`, one element per line; `null` to delete)
15
14
 
16
15
  **`loc` values**
17
16
  - `"append"` / `"prepend"` — insert at end/start of file
18
- - `{ append: "N#ID" }` / `{ prepend: "N#ID" }` — insert after/before anchored line
19
- - `{ range: { pos: "N#ID", end: "N#ID" } }` — replace inclusive range `pos..end` with new content (set `pos == end` for single-line replace)
17
+ - `{ append: "123th" }` / `{ prepend: "123th" }` — insert after/before anchored line
18
+ - `{ range: { pos: "123th", end: "123th" } }` — replace inclusive range `pos..end` with new content (set `pos == end` for single-line replace)
20
19
  </operations>
21
20
 
22
21
  <examples>
@@ -43,92 +42,26 @@ All examples below reference the same file:
43
42
  {{hline 18 "}"}}
44
43
  ```
45
44
 
46
- <example name="replace a block body">
45
+ # Replace a block body
47
46
  Replace only the catch body. Do not target the shared boundary line `} catch (err) {`.
48
-
49
- ```
50
- {
51
- edits: [{
52
- path: "a.ts",
53
- loc: { range: { pos: {{href 15 "\t\tconsole.error(err);"}}, end: {{href 16 "\t\treturn null;"}} } },
54
- content: [
55
- "\t\tif (isEnoent(err)) return null;",
56
- "\t\tthrow err;"
57
- ]
58
- }]
59
- }
60
- ```
61
- </example>
62
-
63
- <example name="replace whole block including closing brace">
64
- Replace the entire body of `alpha`, including its closing `}`. `end` **MUST** be {{href 7 "}"}} because `content` includes `}`.
65
-
66
- ```
67
- {
68
- edits: [{
69
- path: "a.ts",
70
- loc: { range: { pos: {{href 6 "\tlog();"}}, end: {{href 7 "}"}} } },
71
- content: [
72
- "\tvalidate();",
73
- "\tlog();",
74
- "}"
75
- ]
76
- }]
77
- }
78
- ```
79
-
80
- **Wrong**: `end: {{href 6 "\tlog();"}}` with the same content — line 7 (`}`) survives AND content emits `}`, producing two closing braces.
81
- </example>
82
-
83
- <example name="replace one line">
47
+ `{edits:[{path:"a.ts",loc:{range:{pos:{{href 15 "\t\tconsole.error(err);"}},end:{{href 16 "\t\treturn null;"}}}},content:["\t\tif (isEnoent(err)) return null;","\t\tthrow err;"]}]}`
48
+ # Replace whole block including closing brace
49
+ Replace `alpha`'s entire body including the closing `}`. `end` **MUST** be {{href 7 "}"}} because `content` includes `}`.
50
+ `{edits:[{path:"a.ts",loc:{range:{pos:{{href 6 "\tlog();"}},end:{{href 7 "}"}}}},content:["\tvalidate();","\tlog();","}"]}]}`
51
+ **Wrong**: `end: {{href 6 "\tlog();"}}` — line 7 (`}`) survives AND content emits `}`, producing two closing braces.
52
+ # Replace one line
84
53
  Single-line replace uses `pos == end`.
85
-
86
- ```
87
- {
88
- edits: [{
89
- path: "a.ts",
90
- loc: { range: { pos: {{href 2 "const timeout = 5000;"}}, end: {{href 2 "const timeout = 5000;"}} } },
91
- content: ["const timeout = 30_000;"]
92
- }]
93
- }
94
- ```
95
- </example>
96
-
97
- <example name="delete a range">
98
- ```
99
- {
100
- edits: [{
101
- path: "a.ts",
102
- loc: { range: { pos: {{href 10 "\t// TODO: remove after migration"}}, end: {{href 11 "\tlegacy();"}} } },
103
- content: null
104
- }]
105
- }
106
- ```
107
- </example>
108
-
109
- <example name="insert before sibling">
54
+ `{edits:[{path:"a.ts",loc:{range:{pos:{{href 2 "const timeout = 5000;"}},end:{{href 2 "const timeout = 5000;"}}}},content:["const timeout = 30_000;"]}]}`
55
+ # Delete a range
56
+ `{edits:[{path:"a.ts",loc:{range:{pos:{{href 10 "\t// TODO: remove after migration"}},end:{{href 11 "\tlegacy();"}}}},content:null}]}`
57
+ # Insert before a sibling
110
58
  When adding a sibling declaration, prefer `prepend` on the next declaration.
111
-
112
- ```
113
- {
114
- edits: [{
115
- path: "a.ts",
116
- loc: { prepend: {{href 9 "function beta() {"}} },
117
- content: [
118
- "function gamma() {",
119
- "\tvalidate();",
120
- "}",
121
- ""
122
- ]
123
- }]
124
- }
125
- ```
126
- </example>
59
+ `{edits:[{path:"a.ts",loc:{prepend:{{href 9 "function beta() {"}}},content:["function gamma() {","\tvalidate();","}",""]}]}`
127
60
  </examples>
128
61
 
129
62
  <critical>
130
- - Make the minimum exact edit. Do not rewrite nearby code unless the range requires it.
131
- - Copy anchors exactly as `N#ID` from the latest `read` output.
63
+ - Make the minimum exact edit.
64
+ - Copy the full anchors exactly as shown by `read/grep` (for example `160sr`, not just `sr`).
132
65
  - `range` requires both `pos` and `end`.
133
66
  - **Closing-delimiter check**: when your replacement `content` ends with a closing delimiter (`}`, `*/`, `)`, `]`), compare it against the line immediately after `end` in the file. If they match, extend `end` to include that line — otherwise the original delimiter survives and `content` adds a second copy.
134
67
  - For a range, replace only the body or the whole range — don't split range boundaries.
@@ -1,4 +1,4 @@
1
- Generates or edits images using Gemini image models.
1
+ Generates or edits images using the configured image provider.
2
2
 
3
3
  <instructions>
4
4
  - You **MUST** provide a single detailed `subject` prompt for image generation or editing.
@@ -12,12 +12,12 @@ Inspects an image file with a vision-capable model and returns compact text anal
12
12
  </instruction>
13
13
 
14
14
  <examples>
15
- - OCR with strict formatting:
16
- - `{"path":"screenshots/error.png","question":"Extract all visible text verbatim. Return as bullet list in reading order."}`
17
- - Screenshot debugging:
18
- - `{"path":"screenshots/settings.png","question":"Identify the likely cause of the disabled Save button. Return: (1) observations, (2) likely cause, (3) confidence."}`
19
- - Scene/object question:
20
- - `{"path":"photos/shelf.jpg","question":"List all clearly visible product labels and their shelf positions (top/middle/bottom). If unreadable, say unreadable."}`
15
+ # OCR with strict formatting
16
+ `{"path":"screenshots/error.png","question":"Extract all visible text verbatim. Return as bullet list in reading order."}`
17
+ # Screenshot debugging
18
+ `{"path":"screenshots/settings.png","question":"Identify the likely cause of the disabled Save button. Return: (1) observations, (2) likely cause, (3) confidence."}`
19
+ # Scene/object question
20
+ `{"path":"photos/shelf.jpg","question":"List all clearly visible product labels and their shelf positions (top/middle/bottom). If unreadable, say unreadable."}`
21
21
  </examples>
22
22
 
23
23
  <output>
@@ -31,3 +31,9 @@ Interacts with Language Server Protocol servers for code intelligence.
31
31
  - Glob expansion samples up to 20 files per request; use `file: "*"` for broader coverage
32
32
  - When `symbol` is provided for position-based actions, missing symbols or out-of-bounds `occurrence` values return an explicit error instead of silently falling back
33
33
  </caution>
34
+
35
+ <critical>
36
+ - You **MUST** use `lsp` for symbol-aware operations (rename, find references, go to definition/implementation, code actions) whenever a language server is available — it is safer and more accurate than text-based alternatives.
37
+ - You **MUST NOT** perform cross-file renames with `ast_edit`, `sed`, `rsed`, or manual edits when `lsp` `rename` can do it. Text-based renames miss shadowing, re-exports, and usages in other files.
38
+ - Prefer `lsp` `code_actions` for imports, quick-fixes, and refactors the language server already knows how to apply.
39
+ </critical>
@@ -50,25 +50,18 @@ Returns success/failure; on failure, error message indicates:
50
50
  - **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.
51
51
  </critical>
52
52
 
53
- <example name="create">
54
- edit {"edits":[{"path":"hello.txt","op":"create","diff":"Hello\n"}]}
55
- </example>
56
-
57
- <example name="update">
58
- edit {"edits":[{"path":"src/app.py","op":"update","diff":"@@ def greet():\n def greet():\n-print('Hi')\n+print('Hello')\n"}]}
59
- </example>
60
-
61
- <example name="rename">
62
- edit {"edits":[{"path":"src/app.py","op":"update","rename":"src/main.py","diff":"@@\n …\n"}]}
63
- </example>
64
-
65
- <example name="delete">
66
- edit {"edits":[{"path":"obsolete.txt","op":"delete"}]}
67
- </example>
68
-
69
- <example name="multi-file">
70
- edit {"edits":[{"path":"src/types.ts","op":"update","diff":"@@\n-old\n+new\n"},{"path":"src/index.ts","op":"update","diff":"@@\n-old\n+new\n"}]}
71
- </example>
53
+ <examples>
54
+ # Create
55
+ `edit {"edits":[{"path":"hello.txt","op":"create","diff":"Hello\n"}]}`
56
+ # Update
57
+ `edit {"edits":[{"path":"src/app.py","op":"update","diff":"@@ def greet():\n def greet():\n-print('Hi')\n+print('Hello')\n"}]}`
58
+ # Rename
59
+ `edit {"edits":[{"path":"src/app.py","op":"update","rename":"src/main.py","diff":"@@\n …\n"}]}`
60
+ # Delete
61
+ `edit {"edits":[{"path":"obsolete.txt","op":"delete"}]}`
62
+ # Multi-file
63
+ `edit {"edits":[{"path":"src/types.ts","op":"update","diff":"@@\n-old\n+new\n"},{"path":"src/index.ts","op":"update","diff":"@@\n-old\n+new\n"}]}`
64
+ </examples>
72
65
 
73
66
  <avoid>
74
67
  - Generic anchors: `import`, `export`, `describe`, `function`, `const`
@@ -44,7 +44,8 @@ User sees output like Jupyter notebook; rich displays render fully:
44
44
  - You **MUST** use `run()` for shell commands; you **MUST NOT** use raw `subprocess`
45
45
  </critical>
46
46
 
47
- <example name="multiple small cells">
47
+ <examples>
48
+ # Multiple small cells
48
49
  ```python
49
50
  cells: [
50
51
  {"title": "imports", "code": "import json\nfrom pathlib import Path"},
@@ -53,4 +54,4 @@ cells: [
53
54
  {"title": "use helper", "code": "configs = [parse_config(p) for p in Path('.').glob('*.json')]"}
54
55
  ]
55
56
  ```
56
- </example>
57
+ </examples>
@@ -1,23 +1,53 @@
1
- Reads files using syntax-aware chunks.
1
+ Reads files using syntax-aware chunks. Also inspects directories, archives, SQLite databases, images, documents (PDF/DOCX/PPTX/XLSX/RTF/EPUB/ipynb), **and URLs**.
2
2
 
3
3
  <instruction>
4
- - `path` file path or URL; may include `:selector` suffix
5
- - `sel` optional selector: `class_Foo`, `class_Foo.fn_bar#ABCD~`, `?`, `L50`, `L50-L120`, or `raw`
4
+ The chunk-aware `read` variant returns AST-scoped chunks with current checksum IDs for structural editing, and otherwise behaves like `open` for non-code content.
5
+ - You **MUST** parallelize calls when exploring related files
6
+ - For URLs, `read` fetches the page and returns clean extracted text/markdown by default (reader-mode). It handles HTML pages, GitHub issues/PRs, Stack Overflow, Wikipedia, Reddit, NPM, arXiv, RSS/Atom, JSON endpoints, PDFs, etc. You **SHOULD** reach for `read` — not a browser/puppeteer tool — for fetching and inspecting web content.
7
+
8
+ ## Parameters
9
+ - `path` — file path or URL; may include `:selector` suffix (required)
10
+ - `sel` — optional selector for chunks, line ranges, listing, or raw mode
6
11
  - `timeout` — seconds, for URLs only
7
12
 
8
- Each anchor `@full.chunk.path#CCCC` (with `-` prefixes for nesting depth) in the output identifies a chunk. Use `full.chunk.path#CCCC` as-is to read truncated chunks.
9
- If you need a canonical target list, run `read(path="file", sel="?")`. That listing shows chunk paths with IDs.
10
- Line numbers in the gutter are absolute file line numbers.
13
+ ## Selectors
14
+
15
+ |`sel` value|Behavior|
16
+ |---|---|
17
+ |*(omitted)*|Read full file as chunks (up to {{DEFAULT_LIMIT}} lines)|
18
+ |`class_Foo`|Read a specific chunk|
19
+ |`class_Foo.fn_bar#thth~`|Read a chunk region (body `~` / head `^`) by ID|
20
+ |`?`|List all chunk paths with IDs|
21
+ |`L50`|Read from line 50 onward (shorthand for L50 to EOF)|
22
+ |`L50-L120`|Read lines 50 through 120|
23
+ |`L20-L20`|Read exactly one line|
24
+ |`raw`|Raw content without transformations (for URLs: untouched HTML)|
11
25
 
12
- `L20` (single line, no explicit end) is shorthand for `L20` to end-of-file. Use `L20-L20` for a one-line window.
26
+ Max {{DEFAULT_MAX_LINES}} lines per call.
27
+
28
+ # Chunks
29
+ Each anchor `@full.chunk.path#thth` (with `-` prefixes for nesting depth) in the output identifies a chunk. Use `full.chunk.path#thth` as-is to read truncated chunks.
30
+ If you need a canonical target list, run `read(path="file", sel="?")`. That listing shows chunk paths with IDs and is the safest structural discovery mode. Summary lines in this listing are orientation hints; follow a selector with `read(path="file", sel="chunk#ID")` or use `raw` when you need exact source.
31
+ Line numbers in the gutter are absolute file line numbers.
13
32
 
14
33
  {{#if chunkAutoIndent}}
15
34
  Chunk reads normalize leading indentation so copied content round-trips cleanly into chunk edits.
16
35
  {{else}}
17
36
  Chunk reads preserve literal leading tabs/spaces from the file. When editing, keep the same whitespace characters you see here.
18
37
  {{/if}}
38
+ `raw` shows the file's literal whitespace. Structured chunk views may normalize or display indentation for edit round-tripping, so use `raw` when exact tabs/spaces matter, especially inside markdown fenced code blocks.
39
+
40
+ IDs change after every edit. Use the new IDs from the edit response or refresh with `sel="?"` before the next `write`/`delete`. `insert` selectors may omit IDs, but still prefer fresh paths after structural edits.
41
+
42
+ Parser boundaries vary by language: TypeScript/JavaScript decorators and JSDoc above decorated methods may appear as sibling `chunk#ID` entries, Python decorators are part of the function/class head, Python docstrings are body lines, and Python enum members or nested closures may remain opaque inside their parent chunk. Decorated Python `^` writes and Python `^` deletes are rejected for safety.
43
+ Markdown sections, lists, and tables are structural chunks. Recognized pipe tables expose `row_N` children for row-level edits; list items and table cells are not independently addressable. Fenced code blocks with a declared language are parsed again when possible, so functions inside a markdown fence can appear as addressable nested chunks.
19
44
 
20
45
  Chunk trees: JS, TS, TSX, Python, Rust, Go. Others use blank-line fallback.
46
+ # Inspection
47
+ Extracts text from PDF, Word, PowerPoint, Excel, RTF, EPUB, and Jupyter notebook files. Can inspect images.
48
+
49
+ # Directories & Archives
50
+ Directories and archive roots return a list of entries. Supports `.tar`, `.tar.gz`, `.tgz`, `.zip`. Use `archive.ext:path/inside/archive` to read contents.
21
51
 
22
52
  # SQLite Databases
23
53
  When used against a SQLite database (`.sqlite`, `.sqlite3`, `.db`, `.db3`), returns structured database content.
@@ -27,9 +57,17 @@ When used against a SQLite database (`.sqlite`, `.sqlite3`, `.db`, `.db3`), retu
27
57
  - `file.db:table?limit=50&offset=100` — paginated rows
28
58
  - `file.db:table?where=status='active'&order=created:desc` — filtered rows
29
59
  - `file.db?q=SELECT …` — read-only SELECT query
60
+
61
+ # URLs
62
+ Extracts content from web pages, GitHub issues/PRs, Stack Overflow, Wikipedia, Reddit, NPM, arXiv, RSS/Atom feeds, JSON endpoints, PDFs at URLs, and similar text-based resources. Returns clean reader-mode text/markdown — no browser required. Use `sel="raw"` for untouched HTML; `timeout` to override the default request timeout. You **SHOULD** prefer `read` over a browser/puppeteer tool for fetching URL content; only use a browser when the page requires JS execution, authentication, or interactive actions (clicks, forms, scrolling).
30
63
  </instruction>
31
64
 
32
65
  <critical>
33
- - **MUST** `read` before editing — never invent chunk names or IDs.
66
+ - You **MUST** `read` before editing — never invent chunk names or IDs.
34
67
  - Chunk names are truncated (e.g., `handleRequest` becomes `fn_handleRequ`). Always copy chunk paths from `read` or `?` output — never construct them from source identifiers.
68
+ - You **MUST** use `read` (never bash `cat`/`head`/`tail`/`less`/`more`/`ls`/`tar`/`unzip`/`curl`/`wget`) for all file, directory, archive, and URL reads.
69
+ - You **MUST NOT** reach for a browser/puppeteer tool to fetch static web content — `read` handles HTML, PDFs, JSON, feeds, and docs directly. Reserve browser tools for JS-heavy pages or interactive flows.
70
+ - You **MUST** always include the `path` parameter; never call with `{}`.
71
+ - For specific line ranges, use `sel`: `read(path="file", sel="L50-L150")` — not `cat -n file | sed`.
72
+ - You **MAY** use `sel` with URL reads; the tool paginates cached fetched output.
35
73
  </critical>
@@ -1,8 +1,9 @@
1
1
  Reads the content at the specified path or URL.
2
2
 
3
3
  <instruction>
4
- The `read` tool is multi-purpose — inspects files, directories, archives, SQLite databases, and URLs.
4
+ The `read` tool is multi-purpose and more capable than it looks — inspects files, directories, archives, SQLite databases, images, documents (PDF/DOCX/PPTX/XLSX/RTF/EPUB/ipynb), **and URLs**.
5
5
  - You **MUST** parallelize reads when exploring related files
6
+ - For URLs, `read` fetches the page and returns clean extracted text/markdown by default (reader-mode). It handles HTML pages, GitHub issues/PRs, Stack Overflow, Wikipedia, Reddit, NPM, arXiv, RSS/Atom, JSON endpoints, PDFs, etc. You **SHOULD** reach for `read` — not a browser/puppeteer tool — for fetching and inspecting web content.
6
7
 
7
8
  ## Parameters
8
9
  - `path` — file path or URL (required)
@@ -14,15 +15,16 @@ The `read` tool is multi-purpose — inspects files, directories, archives, SQLi
14
15
  |`sel` value|Behavior|
15
16
  |---|---|
16
17
  |*(omitted)*|Read full file (up to {{DEFAULT_LIMIT}} lines)|
17
- |`L50`|Read from line 50 onward|
18
+ |`L50`|Read from line 50 onward (shorthand for L50 to EOF)|
18
19
  |`L50-L120`|Read lines 50 through 120|
19
- |`raw`|Raw content without transformations (for URLs: untouched HTML)|
20
+ |`L20-L20`|Read exactly one line|
21
+ |`raw`|Skip line-numbering / hashline / chunking; return file content as plain text. For URLs: untouched HTML.|
20
22
 
21
23
  Max {{DEFAULT_MAX_LINES}} lines per call.
22
24
 
23
25
  # Filesystem
24
26
  {{#if IS_HASHLINE_MODE}}
25
- - Reading from FS returns lines prefixed with anchors: `41#ZZ:def alpha():`
27
+ - Reading from FS returns lines prefixed with anchors: `41th:def alpha():` (line number, 2-letter ID, colon, then content)
26
28
  {{else}}
27
29
  {{#if IS_LINE_NUMBER_MODE}}
28
30
  - Reading from FS returns lines prefixed with line numbers: `41:def alpha():`
@@ -45,11 +47,12 @@ For `.sqlite`, `.sqlite3`, `.db`, `.db3`:
45
47
  - `file.db?q=SELECT …` — read-only SELECT query
46
48
 
47
49
  # URLs
48
- Extracts content from web pages, GitHub issues/PRs, Stack Overflow, Wikipedia, Reddit, NPM, arXiv, RSS/Atom feeds, JSON endpoints, and similar text-based resources. Use `sel="raw"` for untouched HTML; `timeout` to override the default request timeout.
50
+ Extracts content from web pages, GitHub issues/PRs, Stack Overflow, Wikipedia, Reddit, NPM, arXiv, RSS/Atom feeds, JSON endpoints, PDFs at URLs, and similar text-based resources. Returns clean reader-mode text/markdown — no browser required. Use `sel="raw"` for untouched HTML; `timeout` to override the default request timeout. You **SHOULD** prefer `read` over a browser/puppeteer tool for fetching URL content; only use a browser when the page requires JS execution, authentication, or interactive actions (clicks, forms, scrolling).
49
51
  </instruction>
50
52
 
51
53
  <critical>
52
- - You **MUST** use `read` (never bash `cat`/`head`/`tail`/`less`/`more`/`ls`/`tar`/`unzip`) for all file, directory, and archive reads.
54
+ - You **MUST** use `read` (never bash `cat`/`head`/`tail`/`less`/`more`/`ls`/`tar`/`unzip`/`curl`/`wget`) for all file, directory, archive, and URL reads.
55
+ - You **MUST NOT** reach for a browser/puppeteer tool to fetch static web content — `read` handles HTML, PDFs, JSON, feeds, and docs directly. Reserve browser tools for JS-heavy pages or interactive flows.
53
56
  - You **MUST** always include the `path` parameter; never call with `{}`.
54
57
  - For specific line ranges, use `sel`: `read(path="file", sel="L50-L150")` — not `cat -n file | sed`.
55
58
  - You **MAY** use `sel` with URL reads; the tool paginates cached fetched output.
@@ -25,20 +25,11 @@ You **MUST** build commands from the reference below
25
25
  You **MUST** verify the shell type from "Available hosts" and use matching commands.
26
26
  </critical>
27
27
 
28
- <example name="linux">
29
- Task: List /home/user files on "server1"
30
- Host: server1 (10.0.0.1) | linux/bash
31
- Command: `ls -la /home/user`
32
- </example>
33
-
34
- <example name="windows-cmd">
35
- Task: Show running processes on "winbox"
36
- Host: winbox (192.168.1.5) | windows/cmd
37
- Command: `tasklist /v`
38
- </example>
39
-
40
- <example name="macos">
41
- Task: Get system info on "macbook"
42
- Host: macbook (10.0.0.20) | macos/zsh
43
- Command: `uname -a && sw_vers`
44
- </example>
28
+ <examples>
29
+ # List files: Linux
30
+ Host: server1 (10.0.0.1) | linux/bash. Command: `ls -la /home/user`
31
+ # Show running processes: Windows cmd
32
+ Host: winbox (192.168.1.5) | windows/cmd. Command: `tasklist /v`
33
+ # Get system info: macOS
34
+ Host: macbook (10.0.0.20) | macos/zsh. Command: `uname -a && sw_vers`
35
+ </examples>
@@ -1,28 +1,53 @@
1
- Manages a phased task list. Each field is a verb set the ones you need in a single call.
1
+ Manages a phased task list through an `ops` array of flat operations.
2
2
  The next pending task is auto-promoted to `in_progress` after completing the current one.
3
3
 
4
4
  <protocol>
5
- ## Fields
5
+ ## Shape
6
+
7
+ Pass an object with an `ops` array:
8
+
9
+ ```ts
10
+ {
11
+ ops: [
12
+ { op: "replace", phases: [...] },
13
+ { op: "start", task: "task-3" },
14
+ { op: "done", phase: "Implementation" },
15
+ { op: "rm" },
16
+ { op: "drop", task: "task-9" },
17
+ { op: "append", phase: "Implementation", items: [{ id: "task-10", label: "Run tests" }] },
18
+ ],
19
+ }
20
+ ```
21
+
22
+ ## Operation fields
6
23
 
7
24
  |Field|Type|When to use|
8
25
  |---|---|---|
9
- |`phases`|Phase[]|Initial setup, or full restructure when the plan changes significantly|
10
- |`complete`|string[]|Mark tasks done|
11
- |`start`|string|Jump to a specific task out of order|
12
- |`abandon`|string[]|Drop tasks intentionally|
13
- |`remove`|string[]|Remove tasks that are no longer relevant|
14
- |`add_notes`|{id, notes}[]|Append runtime observations to tasks|
15
- |`add_tasks`|{phase, content, details?}[]|Add tasks to a phase (by name or ID)|
16
- |`add_phase`|{name, tasks?}|Add a new phase of work discovered mid-task|
26
+ |`op`|string|Required. One of `replace`, `start`, `done`, `rm`, `drop`, `append`|
27
+ |`task`|string|Task id for `start`, or a task target for `done` / `rm` / `drop`|
28
+ |`phase`|string|Phase target for `done` / `rm` / `drop`, or append destination for `append`|
29
+ |`items`|{id, label}[]|Required for `append`. If the phase does not exist, it is created at the end|
30
+ |`phases`|Phase[]|Only for `replace`. Keeps initial phased setup available for harness bootstrap and full restructures|
31
+
32
+ ## Semantics
33
+ - `start`: requires `task`; sets that task to `in_progress`
34
+ - `done`: marks one task, one phase, or all tasks completed
35
+ - `rm`: removes one task, one phase's tasks, or all tasks
36
+ - `drop`: marks one task, one phase, or all tasks abandoned
37
+ - `append`: appends `items` to `phase`; creates the phase if missing
38
+ - `replace`: replaces the full todo list
39
+
40
+ If `done`, `rm`, or `drop` omits both `task` and `phase`, it applies to all tasks.
17
41
 
18
42
  ## Task Anatomy
19
- - `content`: Short label (5-10 words). What is being done, not how.
20
- - `details`: File paths, implementation steps, edge cases. Shown only when the task is active.
43
+ - `label`: Short label (5-10 words). What is being done, not how.
44
+ - `replace` task `content` should stay short and specific.
21
45
 
22
46
  ## Rules
23
- - Mark tasks completed immediately after finishing — never defer
24
- - Complete phases in order — do not skip ahead while earlier ones are pending
25
- - On blockers: add a new task describing the blocker
47
+ - Mark tasks done immediately after finishing — never defer.
48
+ - Complete phases in order — do not skip ahead while earlier ones are pending.
49
+ - On blockers, append a new task to the active phase.
50
+ - Keep ids stable once introduced.
26
51
  </protocol>
27
52
 
28
53
  <conditions>
@@ -33,32 +58,20 @@ Create a todo list when:
33
58
  4. New instructions arrive mid-task — capture before proceeding
34
59
  </conditions>
35
60
 
36
- <example name="initial-setup">
37
- {phases: [
38
- {name: "Investigation", tasks: [{content: "Read source"}, {content: "Map callsites"}]},
39
- {name: "Implementation", tasks: [{content: "Apply fix", details: "Update parser.ts to handle edge case in line 42"}, {content: "Run tests"}]}
40
- ]}
41
- </example>
42
-
43
- <example name="complete">
44
- {complete: ["task-2", "task-3"]}
45
- </example>
46
-
47
- <example name="add-notes">
48
- {add_notes: [{id: "task-3", notes: "Found edge case in parser — needs null check"}]}
49
- </example>
50
-
51
- <example name="add-task">
52
- {add_tasks: [{phase: "Implementation", content: "Handle retries", details: "Cap exponential backoff in retry.ts"}]}
53
- </example>
54
-
55
- <example name="add-phase">
56
- {add_phase: {name: "Cleanup", tasks: [{content: "Remove dead code"}]}}
57
- </example>
58
-
59
- <example name="combined">
60
- {complete: ["task-2"], add_notes: [{id: "task-3", notes: "Needs extra validation"}]}
61
- </example>
61
+ <examples>
62
+ # Initial setup
63
+ `{"ops":[{"op":"replace","phases":[{"name":"Investigation","tasks":[{"content":"Read source"},{"content":"Map callsites"}]},{"name":"Implementation","tasks":[{"content":"Apply fix"},{"content":"Run tests"}]}]}]}`
64
+ # Complete one task
65
+ `{"ops":[{"op":"done","task":"task-2"}]}`
66
+ # Complete a whole phase
67
+ `{"ops":[{"op":"done","phase":"Implementation"}]}`
68
+ # Remove all tasks
69
+ `{"ops":[{"op":"rm"}]}`
70
+ # Drop one task
71
+ `{"ops":[{"op":"drop","task":"task-7"}]}`
72
+ # Append tasks to a phase
73
+ `{"ops":[{"op":"append","phase":"Implementation","items":[{"id":"task-8","label":"Handle retries"},{"id":"task-9","label":"Run tests"}]}]}`
74
+ </examples>
62
75
 
63
76
  <avoid>
64
77
  - Single-step tasks — act directly