@nghyane/arcane 0.1.12 → 0.1.14

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 (333) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/package.json +21 -70
  3. package/scripts/format-prompts.ts +1 -3
  4. package/src/cli/args.ts +2 -7
  5. package/src/cli/config-cli.ts +1 -1
  6. package/src/cli/plugin-cli.ts +1 -1
  7. package/src/cli/setup-cli.ts +1 -1
  8. package/src/cli/update-cli.ts +1 -1
  9. package/src/cli/web-search-cli.ts +1 -1
  10. package/src/cli.ts +0 -1
  11. package/src/commands/config.ts +1 -1
  12. package/src/commands/grep.ts +1 -1
  13. package/src/commands/jupyter.ts +1 -1
  14. package/src/commands/plugin.ts +1 -1
  15. package/src/commands/setup.ts +1 -1
  16. package/src/commands/shell.ts +1 -1
  17. package/src/commands/ssh.ts +1 -1
  18. package/src/commands/stats.ts +1 -1
  19. package/src/commands/update.ts +1 -1
  20. package/src/config/model-registry.ts +3 -4
  21. package/src/config/model-resolver.ts +36 -9
  22. package/src/config/prompt-templates.ts +1 -9
  23. package/src/config/settings-schema.ts +32 -88
  24. package/src/config/settings.ts +3 -4
  25. package/src/debug/index.ts +1 -1
  26. package/src/debug/log-formatting.ts +1 -1
  27. package/src/debug/log-viewer.ts +2 -2
  28. package/src/discovery/helpers.ts +13 -3
  29. package/src/exa/company.ts +2 -7
  30. package/src/exa/index.ts +1 -35
  31. package/src/exa/linkedin.ts +2 -7
  32. package/src/exa/mcp-client.ts +21 -11
  33. package/src/exa/render.ts +30 -190
  34. package/src/exa/researcher.ts +2 -12
  35. package/src/exa/search.ts +5 -25
  36. package/src/exa/types.ts +3 -3
  37. package/src/exec/bash-executor.ts +2 -1
  38. package/src/exec/non-interactive-env.ts +43 -0
  39. package/src/export/html/index.ts +1 -1
  40. package/src/extensibility/custom-tools/loader.ts +1 -1
  41. package/src/extensibility/custom-tools/types.ts +5 -1
  42. package/src/extensibility/custom-tools/wrapper.ts +1 -1
  43. package/src/extensibility/extensions/runner.ts +1 -1
  44. package/src/extensibility/extensions/types.ts +1 -1
  45. package/src/extensibility/extensions/wrapper.ts +7 -15
  46. package/src/extensibility/hooks/runner.ts +1 -1
  47. package/src/extensibility/hooks/types.ts +1 -1
  48. package/src/extensibility/plugins/doctor.ts +1 -1
  49. package/src/index.ts +13 -13
  50. package/src/lsp/index.ts +77 -24
  51. package/src/lsp/render.ts +34 -583
  52. package/src/lsp/types.ts +3 -3
  53. package/src/lsp/utils.ts +1 -1
  54. package/src/main.ts +1 -1
  55. package/src/mcp/tool-bridge.ts +1 -24
  56. package/src/modes/components/assistant-message.ts +7 -7
  57. package/src/modes/components/bash-execution.ts +48 -113
  58. package/src/modes/components/bordered-loader.ts +1 -1
  59. package/src/modes/components/branch-summary-message.ts +13 -10
  60. package/src/modes/components/compaction-summary-message.ts +14 -13
  61. package/src/modes/components/context-group.ts +106 -0
  62. package/src/modes/components/custom-message.ts +4 -5
  63. package/src/modes/components/diff.ts +2 -2
  64. package/src/modes/components/dynamic-border.ts +1 -1
  65. package/src/modes/components/extensions/extension-dashboard.ts +2 -2
  66. package/src/modes/components/extensions/extension-list.ts +1 -1
  67. package/src/modes/components/extensions/inspector-panel.ts +8 -3
  68. package/src/modes/components/footer.ts +2 -2
  69. package/src/modes/components/history-search.ts +1 -1
  70. package/src/modes/components/hook-editor.ts +1 -1
  71. package/src/modes/components/hook-input.ts +1 -1
  72. package/src/modes/components/hook-message.ts +4 -5
  73. package/src/modes/components/hook-selector.ts +1 -1
  74. package/src/modes/components/index.ts +0 -2
  75. package/src/modes/components/keybinding-hints.ts +1 -1
  76. package/src/modes/components/login-dialog.ts +1 -1
  77. package/src/modes/components/mcp-add-wizard.ts +1 -1
  78. package/src/modes/components/model-selector.ts +1 -1
  79. package/src/modes/components/oauth-selector.ts +1 -1
  80. package/src/modes/components/plugin-settings.ts +1 -1
  81. package/src/modes/components/python-execution.ts +49 -92
  82. package/src/modes/components/queue-mode-selector.ts +1 -1
  83. package/src/modes/components/session-selector.ts +1 -1
  84. package/src/modes/components/settings-defs.ts +5 -10
  85. package/src/modes/components/settings-selector.ts +1 -1
  86. package/src/modes/components/show-images-selector.ts +1 -1
  87. package/src/modes/components/skill-message.ts +4 -4
  88. package/src/modes/components/status-line/segments.ts +2 -2
  89. package/src/modes/components/status-line/separators.ts +1 -1
  90. package/src/modes/components/status-line-segment-editor.ts +1 -1
  91. package/src/modes/components/status-line.ts +1 -1
  92. package/src/modes/components/theme-selector.ts +1 -1
  93. package/src/modes/components/thinking-selector.ts +1 -1
  94. package/src/modes/components/todo-display.ts +2 -4
  95. package/src/modes/components/todo-reminder.ts +4 -4
  96. package/src/modes/components/tool-execution.ts +118 -440
  97. package/src/modes/components/tool-image-display.ts +107 -0
  98. package/src/modes/components/tree-selector.ts +2 -2
  99. package/src/modes/components/ttsr-notification.ts +4 -17
  100. package/src/modes/components/user-message-selector.ts +1 -1
  101. package/src/modes/components/user-message.ts +9 -10
  102. package/src/modes/components/welcome.ts +1 -1
  103. package/src/modes/controllers/command-controller.ts +1 -1
  104. package/src/modes/controllers/event-controller.ts +58 -187
  105. package/src/modes/controllers/extension-ui-controller.ts +1 -1
  106. package/src/modes/controllers/input-controller.ts +3 -1
  107. package/src/modes/controllers/mcp-command-controller.ts +1 -1
  108. package/src/modes/controllers/selector-controller.ts +3 -26
  109. package/src/modes/controllers/ssh-command-controller.ts +1 -1
  110. package/src/modes/interactive-mode.ts +3 -7
  111. package/src/modes/print-mode.ts +5 -5
  112. package/src/modes/rpc/rpc-mode.ts +1 -1
  113. package/src/modes/types.ts +1 -2
  114. package/src/modes/utils/ui-helpers.ts +34 -32
  115. package/src/patch/edit-tool.ts +742 -0
  116. package/src/patch/index.ts +32 -898
  117. package/src/patch/schemas.ts +208 -0
  118. package/src/patch/shared.ts +83 -151
  119. package/src/prompts/agents/explore.md +22 -37
  120. package/src/prompts/agents/frontmatter.md +1 -1
  121. package/src/prompts/agents/init.md +2 -2
  122. package/src/prompts/agents/librarian.md +30 -21
  123. package/src/prompts/agents/oracle.md +9 -2
  124. package/src/prompts/agents/reviewer.md +15 -49
  125. package/src/prompts/agents/task.md +17 -9
  126. package/src/prompts/compaction/branch-summary-context.md +1 -1
  127. package/src/prompts/compaction/branch-summary-preamble.md +1 -1
  128. package/src/prompts/compaction/branch-summary.md +4 -1
  129. package/src/prompts/compaction/compaction-short-summary.md +1 -1
  130. package/src/prompts/compaction/compaction-summary-context.md +1 -1
  131. package/src/prompts/compaction/compaction-summary.md +4 -1
  132. package/src/prompts/compaction/compaction-turn-prefix.md +1 -1
  133. package/src/prompts/compaction/compaction-update-summary.md +1 -1
  134. package/src/prompts/memories/consolidation.md +1 -1
  135. package/src/prompts/memories/read_path.md +1 -1
  136. package/src/prompts/memories/stage_one_input.md +1 -1
  137. package/src/prompts/memories/stage_one_system.md +1 -1
  138. package/src/prompts/review-request.md +1 -1
  139. package/src/prompts/system/agent-creation-architect.md +1 -1
  140. package/src/prompts/system/agent-creation-user.md +1 -1
  141. package/src/prompts/system/custom-system-prompt.md +1 -1
  142. package/src/prompts/system/file-operations.md +1 -1
  143. package/src/prompts/system/subagent-system-prompt.md +2 -2
  144. package/src/prompts/system/summarization-system.md +1 -1
  145. package/src/prompts/system/system-prompt.md +163 -178
  146. package/src/prompts/system/title-system.md +1 -1
  147. package/src/prompts/system/ttsr-interrupt.md +1 -1
  148. package/src/prompts/system/verification-reminder.md +6 -0
  149. package/src/prompts/system/web-search.md +1 -1
  150. package/src/sdk.ts +0 -9
  151. package/src/session/agent-session.ts +244 -1459
  152. package/src/session/auth-storage.ts +5 -0
  153. package/src/session/model-controller.ts +406 -0
  154. package/src/session/retry-utils.ts +71 -0
  155. package/src/session/session-manager.ts +22 -186
  156. package/src/session/session-types.ts +312 -0
  157. package/src/session/stats.ts +387 -0
  158. package/src/session/streaming-edit.ts +258 -0
  159. package/src/session/ttsr.ts +213 -0
  160. package/src/slash-commands/builtin-registry.ts +0 -8
  161. package/src/ssh/connection-manager.ts +1 -0
  162. package/src/stt/recorder.ts +2 -2
  163. package/src/system-prompt.ts +1 -14
  164. package/src/task/agents.ts +7 -33
  165. package/src/task/executor.ts +50 -438
  166. package/src/task/index.ts +104 -71
  167. package/src/task/progress-tracker.ts +390 -0
  168. package/src/task/render.ts +371 -187
  169. package/src/task/subprocess-tool-registry.ts +1 -1
  170. package/src/task/types.ts +14 -47
  171. package/src/tools/ask.ts +31 -42
  172. package/src/tools/bash-interactive.ts +4 -47
  173. package/src/tools/bash-interceptor.ts +2 -2
  174. package/src/tools/bash-normalize.ts +1 -1
  175. package/src/tools/bash-skill-urls.ts +2 -2
  176. package/src/tools/bash.ts +87 -136
  177. package/src/tools/browser.ts +54 -84
  178. package/src/tools/create-tools.ts +186 -0
  179. package/src/tools/default-renderer.ts +104 -0
  180. package/src/tools/explore.ts +11 -10
  181. package/src/tools/fetch.ts +24 -114
  182. package/src/tools/find.ts +48 -132
  183. package/src/tools/gemini-image.ts +5 -15
  184. package/src/tools/github.ts +450 -0
  185. package/src/tools/grep.ts +43 -179
  186. package/src/tools/index.ts +35 -198
  187. package/src/tools/json-tree.ts +3 -3
  188. package/src/tools/librarian.ts +18 -18
  189. package/src/tools/list-limit.ts +2 -2
  190. package/src/tools/notebook.ts +35 -87
  191. package/src/tools/oracle.ts +25 -25
  192. package/src/tools/output-meta.ts +89 -4
  193. package/src/tools/output-utils.ts +2 -2
  194. package/src/tools/python.ts +86 -637
  195. package/src/tools/read.ts +36 -119
  196. package/src/tools/reviewer-tool.ts +19 -21
  197. package/src/tools/search-code.ts +128 -0
  198. package/src/tools/ssh.ts +67 -126
  199. package/src/tools/subagent-tool.ts +197 -123
  200. package/src/tools/todo-write.ts +15 -31
  201. package/src/tools/tool-errors.ts +0 -30
  202. package/src/tools/undo-edit.ts +30 -67
  203. package/src/tools/write.ts +78 -127
  204. package/src/tui/code-cell.ts +4 -4
  205. package/src/tui/file-list.ts +2 -2
  206. package/src/tui/output-block.ts +1 -1
  207. package/src/tui/status-line.ts +1 -1
  208. package/src/tui/tree-list.ts +2 -2
  209. package/src/tui/types.ts +1 -1
  210. package/src/tui/utils.ts +1 -1
  211. package/src/{tools → ui}/render-utils.ts +87 -126
  212. package/src/utils/external-editor.ts +4 -4
  213. package/src/utils/file-mentions.ts +1 -1
  214. package/src/utils/index.ts +30 -0
  215. package/src/utils/tools-manager.ts +9 -19
  216. package/src/web/github-client.ts +290 -0
  217. package/src/web/scrapers/github.ts +11 -62
  218. package/src/web/search/auth.ts +1 -3
  219. package/src/web/search/index.ts +85 -49
  220. package/src/web/search/provider.ts +11 -16
  221. package/src/web/search/providers/grep.ts +160 -0
  222. package/src/web/search/render.ts +48 -235
  223. package/src/web/search/types.ts +1 -1
  224. package/src/commands/commit.ts +0 -36
  225. package/src/commit/agentic/agent.ts +0 -311
  226. package/src/commit/agentic/fallback.ts +0 -96
  227. package/src/commit/agentic/index.ts +0 -359
  228. package/src/commit/agentic/prompts/analyze-file.md +0 -22
  229. package/src/commit/agentic/prompts/session-user.md +0 -25
  230. package/src/commit/agentic/prompts/split-confirm.md +0 -1
  231. package/src/commit/agentic/prompts/system.md +0 -38
  232. package/src/commit/agentic/state.ts +0 -69
  233. package/src/commit/agentic/tools/analyze-file.ts +0 -118
  234. package/src/commit/agentic/tools/git-file-diff.ts +0 -194
  235. package/src/commit/agentic/tools/git-hunk.ts +0 -50
  236. package/src/commit/agentic/tools/git-overview.ts +0 -84
  237. package/src/commit/agentic/tools/index.ts +0 -56
  238. package/src/commit/agentic/tools/propose-changelog.ts +0 -128
  239. package/src/commit/agentic/tools/propose-commit.ts +0 -154
  240. package/src/commit/agentic/tools/recent-commits.ts +0 -81
  241. package/src/commit/agentic/tools/split-commit.ts +0 -280
  242. package/src/commit/agentic/topo-sort.ts +0 -44
  243. package/src/commit/agentic/trivial.ts +0 -51
  244. package/src/commit/agentic/validation.ts +0 -200
  245. package/src/commit/analysis/conventional.ts +0 -165
  246. package/src/commit/analysis/index.ts +0 -4
  247. package/src/commit/analysis/scope.ts +0 -242
  248. package/src/commit/analysis/summary.ts +0 -112
  249. package/src/commit/analysis/validation.ts +0 -66
  250. package/src/commit/changelog/detect.ts +0 -37
  251. package/src/commit/changelog/generate.ts +0 -110
  252. package/src/commit/changelog/index.ts +0 -234
  253. package/src/commit/changelog/parse.ts +0 -44
  254. package/src/commit/cli.ts +0 -93
  255. package/src/commit/git/diff.ts +0 -148
  256. package/src/commit/git/errors.ts +0 -9
  257. package/src/commit/git/index.ts +0 -211
  258. package/src/commit/git/operations.ts +0 -54
  259. package/src/commit/index.ts +0 -5
  260. package/src/commit/map-reduce/index.ts +0 -64
  261. package/src/commit/map-reduce/map-phase.ts +0 -178
  262. package/src/commit/map-reduce/reduce-phase.ts +0 -145
  263. package/src/commit/map-reduce/utils.ts +0 -9
  264. package/src/commit/message.ts +0 -11
  265. package/src/commit/model-selection.ts +0 -69
  266. package/src/commit/pipeline.ts +0 -243
  267. package/src/commit/prompts/analysis-system.md +0 -148
  268. package/src/commit/prompts/analysis-user.md +0 -38
  269. package/src/commit/prompts/changelog-system.md +0 -50
  270. package/src/commit/prompts/changelog-user.md +0 -18
  271. package/src/commit/prompts/file-observer-system.md +0 -24
  272. package/src/commit/prompts/file-observer-user.md +0 -8
  273. package/src/commit/prompts/reduce-system.md +0 -50
  274. package/src/commit/prompts/reduce-user.md +0 -17
  275. package/src/commit/prompts/summary-retry.md +0 -3
  276. package/src/commit/prompts/summary-system.md +0 -38
  277. package/src/commit/prompts/summary-user.md +0 -13
  278. package/src/commit/prompts/types-description.md +0 -2
  279. package/src/commit/types.ts +0 -109
  280. package/src/commit/utils/exclusions.ts +0 -42
  281. package/src/mcp/render.ts +0 -123
  282. package/src/modes/components/agent-dashboard.ts +0 -1130
  283. package/src/modes/components/codemode-group.ts +0 -369
  284. package/src/modes/components/read-tool-group.ts +0 -119
  285. package/src/modes/components/visual-truncate.ts +0 -63
  286. package/src/prompts/system/subagent-user-prompt.md +0 -8
  287. package/src/prompts/tools/ask.md +0 -44
  288. package/src/prompts/tools/bash.md +0 -24
  289. package/src/prompts/tools/browser.md +0 -33
  290. package/src/prompts/tools/calculator.md +0 -12
  291. package/src/prompts/tools/explore.md +0 -29
  292. package/src/prompts/tools/fetch.md +0 -16
  293. package/src/prompts/tools/find.md +0 -18
  294. package/src/prompts/tools/gemini-image.md +0 -23
  295. package/src/prompts/tools/grep.md +0 -28
  296. package/src/prompts/tools/hashline.md +0 -232
  297. package/src/prompts/tools/librarian.md +0 -24
  298. package/src/prompts/tools/lsp.md +0 -28
  299. package/src/prompts/tools/oracle.md +0 -26
  300. package/src/prompts/tools/patch.md +0 -74
  301. package/src/prompts/tools/python.md +0 -66
  302. package/src/prompts/tools/read.md +0 -36
  303. package/src/prompts/tools/replace.md +0 -38
  304. package/src/prompts/tools/reviewer.md +0 -41
  305. package/src/prompts/tools/ssh.md +0 -51
  306. package/src/prompts/tools/task-summary.md +0 -28
  307. package/src/prompts/tools/task.md +0 -146
  308. package/src/prompts/tools/todo-write.md +0 -65
  309. package/src/prompts/tools/undo-edit.md +0 -7
  310. package/src/prompts/tools/web-search.md +0 -19
  311. package/src/prompts/tools/write.md +0 -18
  312. package/src/task/batch.ts +0 -102
  313. package/src/task/discovery.ts +0 -126
  314. package/src/task/parallel.ts +0 -84
  315. package/src/task/template.ts +0 -32
  316. package/src/tools/calculator.ts +0 -537
  317. package/src/tools/jtd-to-typescript.ts +0 -198
  318. package/src/tools/renderers.ts +0 -60
  319. package/src/tools/tool-result.ts +0 -86
  320. /package/src/{modes/theme → theme}/dark.json +0 -0
  321. /package/src/{modes/theme → theme}/defaults/dark-catppuccin.json +0 -0
  322. /package/src/{modes/theme → theme}/defaults/dark-dracula.json +0 -0
  323. /package/src/{modes/theme → theme}/defaults/dark-gruvbox.json +0 -0
  324. /package/src/{modes/theme → theme}/defaults/dark-solarized.json +0 -0
  325. /package/src/{modes/theme → theme}/defaults/dark-tokyo-night.json +0 -0
  326. /package/src/{modes/theme → theme}/defaults/index.ts +0 -0
  327. /package/src/{modes/theme → theme}/defaults/light-catppuccin.json +0 -0
  328. /package/src/{modes/theme → theme}/defaults/light-github.json +0 -0
  329. /package/src/{modes/theme → theme}/defaults/light-solarized.json +0 -0
  330. /package/src/{modes/theme → theme}/light.json +0 -0
  331. /package/src/{modes/theme → theme}/mermaid-cache.ts +0 -0
  332. /package/src/{modes/theme → theme}/theme-schema.json +0 -0
  333. /package/src/{modes/theme → theme}/theme.ts +0 -0
@@ -0,0 +1,208 @@
1
+ import { StringEnum } from "@nghyane/arcane-ai";
2
+ import { type Static, Type } from "@sinclair/typebox";
3
+
4
+ export const replaceEditSchema = Type.Object({
5
+ path: Type.String({ description: "File path (relative or absolute)" }),
6
+ old_text: Type.String({
7
+ description: "Text to find (fuzzy whitespace matching enabled)",
8
+ }),
9
+ new_text: Type.String({ description: "Replacement text" }),
10
+ all: Type.Optional(
11
+ Type.Boolean({
12
+ description: "Replace all occurrences (default: unique match required)",
13
+ }),
14
+ ),
15
+ });
16
+
17
+ export const patchEditSchema = Type.Object({
18
+ path: Type.String({ description: "File path" }),
19
+ op: Type.Optional(
20
+ StringEnum(["create", "delete", "update"], {
21
+ description: "Operation (default: update)",
22
+ }),
23
+ ),
24
+ rename: Type.Optional(Type.String({ description: "New path for move" })),
25
+ diff: Type.Optional(
26
+ Type.String({
27
+ description: "Diff hunks (update) or full content (create)",
28
+ }),
29
+ ),
30
+ });
31
+
32
+ export type ReplaceParams = Static<typeof replaceEditSchema>;
33
+ export type PatchParams = Static<typeof patchEditSchema>;
34
+
35
+ /** Pattern matching hashline display format: `LINE#ID:CONTENT` */
36
+ const HASHLINE_PREFIX_RE = /^\s*(?:>>>|>>)?\s*\d+#[0-9a-zA-Z]{1,16}:/;
37
+
38
+ /** Pattern matching a unified-diff `+` prefix (but not `++`) */
39
+ const DIFF_PLUS_RE = /^[+-](?![+-])/;
40
+
41
+ /**
42
+ * Strip hashline display prefixes and diff `+` markers from replacement lines.
43
+ *
44
+ * Models frequently copy the `LINE#ID ` prefix from read output into their
45
+ * replacement content, or include unified-diff `+` prefixes. Both corrupt the
46
+ * output file. This strips them heuristically before application.
47
+ */
48
+ export function stripNewLinePrefixes(lines: string[]): string[] {
49
+ // Detect whether the *majority* of non-empty lines carry a prefix —
50
+ // if only one line out of many has a match it's likely real content.
51
+ let hashPrefixCount = 0;
52
+ let diffPlusCount = 0;
53
+ let nonEmpty = 0;
54
+ for (const l of lines) {
55
+ if (l.length === 0) continue;
56
+ nonEmpty++;
57
+ if (HASHLINE_PREFIX_RE.test(l)) hashPrefixCount++;
58
+ if (DIFF_PLUS_RE.test(l)) diffPlusCount++;
59
+ }
60
+ if (nonEmpty === 0) return lines;
61
+
62
+ const stripHash = hashPrefixCount > 0 && hashPrefixCount >= nonEmpty * 0.5;
63
+ const stripPlus = !stripHash && nonEmpty >= 2 && diffPlusCount > 0 && diffPlusCount >= nonEmpty * 0.5;
64
+
65
+ if (!stripHash && !stripPlus) return lines;
66
+
67
+ return lines.map(l => {
68
+ if (stripHash) return l.replace(HASHLINE_PREFIX_RE, "");
69
+ if (stripPlus) return l.replace(DIFF_PLUS_RE, "");
70
+ return l;
71
+ });
72
+ }
73
+
74
+ const hashlineReplaceContentFormat = (kind: string) =>
75
+ Type.Union([
76
+ Type.Null(),
77
+ Type.Array(Type.String(), { description: `${kind} lines` }),
78
+ Type.String({ description: `${kind} line` }),
79
+ ]);
80
+
81
+ const hashlineInsertContentFormat = (kind: string) =>
82
+ Type.Union([
83
+ Type.Array(Type.String(), { description: `${kind} lines`, minItems: 1 }),
84
+ Type.String({ description: `${kind} line`, minLength: 1 }),
85
+ ]);
86
+
87
+ const hashlineTagFormat = (what: string) =>
88
+ Type.String({
89
+ description: `Tag identifying the ${what} — format "N#XX" (e.g. "5#PM"), copied verbatim from read output`,
90
+ });
91
+
92
+ export function hashlineParseContent(edit: string | string[] | null): string[] {
93
+ if (edit === null) return [];
94
+ if (Array.isArray(edit)) return edit;
95
+ const lines = stripNewLinePrefixes(edit.split("\n"));
96
+ if (lines.length === 0) return [];
97
+ if (lines.length > 1 && lines[lines.length - 1].trim() === "") return lines.slice(0, -1);
98
+ return lines;
99
+ }
100
+
101
+ export function hashlineParseContentString(edit: string | string[] | null): string {
102
+ if (edit === null) return "";
103
+ if (Array.isArray(edit)) return edit.join("\n");
104
+ return edit;
105
+ }
106
+
107
+ const hashlineTargetEditSchema = Type.Object(
108
+ {
109
+ op: Type.Literal("set"),
110
+ tag: hashlineTagFormat("line being replaced"),
111
+ content: hashlineReplaceContentFormat("Replacement"),
112
+ },
113
+ { additionalProperties: false },
114
+ );
115
+
116
+ const hashlineAppendEditSchema = Type.Object(
117
+ {
118
+ op: Type.Literal("append"),
119
+ after: Type.Optional(hashlineTagFormat("line after which to append")),
120
+ content: hashlineInsertContentFormat("Appended"),
121
+ },
122
+ { additionalProperties: false },
123
+ );
124
+
125
+ const hashlinePrependEditSchema = Type.Object(
126
+ {
127
+ op: Type.Literal("prepend"),
128
+ before: Type.Optional(hashlineTagFormat("line before which to prepend")),
129
+ content: hashlineInsertContentFormat("Prepended"),
130
+ },
131
+ { additionalProperties: false },
132
+ );
133
+
134
+ const hashlineRangeEditSchema = Type.Object(
135
+ {
136
+ op: Type.Literal("replace"),
137
+ first: hashlineTagFormat("first line"),
138
+ last: hashlineTagFormat("last line"),
139
+ content: hashlineReplaceContentFormat("Replacement"),
140
+ },
141
+ { additionalProperties: false },
142
+ );
143
+
144
+ const hashlineInsertEditSchema = Type.Object(
145
+ {
146
+ op: Type.Literal("insert"),
147
+ before: Type.Optional(hashlineTagFormat("line before which to insert")),
148
+ after: Type.Optional(hashlineTagFormat("line after which to insert")),
149
+ content: hashlineInsertContentFormat("Inserted"),
150
+ },
151
+ { additionalProperties: false },
152
+ );
153
+
154
+ const hashlineReplaceTextEditSchema = Type.Object(
155
+ {
156
+ op: Type.Literal("replaceText"),
157
+ old_text: Type.String({ description: "Text to find", minLength: 1 }),
158
+ new_text: hashlineReplaceContentFormat("Replacement"),
159
+ all: Type.Optional(Type.Boolean({ description: "Replace all occurrences" })),
160
+ },
161
+ { additionalProperties: false },
162
+ );
163
+
164
+ const HL_REPLACE_ENABLED = Bun.env.ARCANE_HL_REPLACETXT === "1";
165
+
166
+ export const hashlineEditSpecSchema = Type.Union([
167
+ hashlineTargetEditSchema,
168
+ hashlineRangeEditSchema,
169
+ hashlineAppendEditSchema,
170
+ hashlinePrependEditSchema,
171
+ hashlineInsertEditSchema,
172
+ ...(HL_REPLACE_ENABLED ? [hashlineReplaceTextEditSchema] : []),
173
+ ]);
174
+
175
+ export const hashlineEditSchema = Type.Object(
176
+ {
177
+ path: Type.String({ description: "File path (relative or absolute)" }),
178
+ edits: Type.Array(hashlineEditSpecSchema, {
179
+ description: "Changes to apply to the file at `path`",
180
+ minItems: 0,
181
+ }),
182
+ delete: Type.Optional(Type.Boolean({ description: "Delete the file when true" })),
183
+ rename: Type.Optional(Type.String({ description: "New path if moving" })),
184
+ },
185
+ { additionalProperties: false },
186
+ );
187
+
188
+ export type HashlineToolEdit = Static<typeof hashlineEditSpecSchema>;
189
+ export type HashlineParams = Static<typeof hashlineEditSchema>;
190
+
191
+ export type TInput = typeof replaceEditSchema | typeof patchEditSchema | typeof hashlineEditSchema;
192
+
193
+ export type EditMode = "replace" | "patch" | "hashline";
194
+
195
+ export const DEFAULT_EDIT_MODE: EditMode = "patch";
196
+
197
+ export function normalizeEditMode(mode?: string | null): EditMode | null {
198
+ switch (mode) {
199
+ case "replace":
200
+ return "replace";
201
+ case "patch":
202
+ return "patch";
203
+ case "hashline":
204
+ return "hashline";
205
+ default:
206
+ return null;
207
+ }
208
+ }
@@ -7,19 +7,20 @@ import { Text } from "@nghyane/arcane-tui";
7
7
  import type { RenderResultOptions } from "../extensibility/custom-tools/types";
8
8
  import type { FileDiagnosticsResult } from "../lsp";
9
9
  import { renderDiff as renderDiffColored } from "../modes/components/diff";
10
- import { getLanguageFromPath, type Theme } from "../modes/theme/theme";
10
+ import { getLanguageFromPath, type Theme } from "../theme/theme";
11
11
  import type { OutputMeta } from "../tools/output-meta";
12
+ import { renderStatusLine } from "../tui";
12
13
  import {
13
- formatExpandHint,
14
+ formatClickHint,
15
+ formatDiagnostics,
14
16
  formatStatusIcon,
15
17
  getDiffStats,
16
18
  PREVIEW_LIMITS,
17
19
  replaceTabs,
18
20
  shortenPath,
19
- ToolUIKit,
20
- truncateDiffByHunk,
21
- } from "../tools/render-utils";
22
- import { Ellipsis, Hasher, type RenderCache, renderStatusLine, truncateToWidth } from "../tui";
21
+ TRUNCATE_LENGTHS,
22
+ truncateToWidth,
23
+ } from "../ui/render-utils";
23
24
  import type { DiffError, DiffResult, Operation } from "./types";
24
25
 
25
26
  // ═══════════════════════════════════════════════════════════════════════════
@@ -100,11 +101,6 @@ export interface EditRenderContext {
100
101
 
101
102
  const EDIT_STREAMING_PREVIEW_LINES = 12;
102
103
 
103
- function countLines(text: string): number {
104
- if (!text) return 0;
105
- return text.split("\n").length;
106
- }
107
-
108
104
  function formatStreamingDiff(diff: string, rawPath: string, uiTheme: Theme, label = "streaming"): string {
109
105
  if (!diff) return "";
110
106
  const lines = diff.split("\n");
@@ -120,7 +116,7 @@ function formatStreamingDiff(diff: string, rawPath: string, uiTheme: Theme, labe
120
116
  return text;
121
117
  }
122
118
 
123
- function formatStreamingHashlineEdits(edits: unknown[], uiTheme: Theme, ui: ToolUIKit): string {
119
+ function formatStreamingHashlineEdits(edits: unknown[], uiTheme: Theme): string {
124
120
  const MAX_EDITS = 4;
125
121
  const MAX_DST_LINES = 8;
126
122
  let text = "\n\n";
@@ -132,17 +128,17 @@ function formatStreamingHashlineEdits(edits: unknown[], uiTheme: Theme, ui: Tool
132
128
  shownEdits++;
133
129
  if (shownEdits > MAX_EDITS) break;
134
130
  const formatted = formatHashlineEdit(edit);
135
- text += uiTheme.fg("toolOutput", ui.truncate(replaceTabs(formatted.srcLabel), 120));
131
+ text += uiTheme.fg("toolOutput", truncateToWidth(replaceTabs(formatted.srcLabel), TRUNCATE_LENGTHS.LONG));
136
132
  text += "\n";
137
133
  if (formatted.dst === "") {
138
- text += uiTheme.fg("dim", ui.truncate(" (delete)", 120));
134
+ text += uiTheme.fg("dim", truncateToWidth(" (delete)", TRUNCATE_LENGTHS.LONG));
139
135
  text += "\n";
140
136
  continue;
141
137
  }
142
138
  for (const dstLine of formatted.dst.split("\n")) {
143
139
  shownDstLines++;
144
140
  if (shownDstLines > MAX_DST_LINES) break;
145
- text += uiTheme.fg("toolOutput", ui.truncate(replaceTabs(`+ ${dstLine}`), 120));
141
+ text += uiTheme.fg("toolOutput", truncateToWidth(replaceTabs(`+ ${dstLine}`), TRUNCATE_LENGTHS.LONG));
146
142
  text += "\n";
147
143
  }
148
144
  if (shownDstLines > MAX_DST_LINES) break;
@@ -208,53 +204,13 @@ function formatStreamingHashlineEdits(edits: unknown[], uiTheme: Theme, ui: Tool
208
204
  };
209
205
  }
210
206
  }
211
- function formatMetadataLine(lineCount: number | null, language: string | undefined, uiTheme: Theme): string {
212
- const icon = uiTheme.getLangIcon(language);
213
- if (lineCount !== null) {
214
- return uiTheme.fg("dim", `${icon} ${lineCount} lines`);
215
- }
216
- return uiTheme.fg("dim", `${icon}`);
217
- }
218
-
219
- function renderDiffSection(
220
- diff: string,
221
- rawPath: string,
222
- expanded: boolean,
223
- uiTheme: Theme,
224
- ui: ToolUIKit,
225
- renderDiffFn: (t: string, o?: { filePath?: string }) => string,
226
- ): string {
227
- let text = "";
228
- const diffStats = getDiffStats(diff);
229
- text += `\n${uiTheme.fg("dim", uiTheme.format.bracketLeft)}${ui.formatDiffStats(
230
- diffStats.added,
231
- diffStats.removed,
232
- diffStats.hunks,
233
- )}${uiTheme.fg("dim", uiTheme.format.bracketRight)}`;
234
-
235
- const {
236
- text: truncatedDiff,
237
- hiddenHunks,
238
- hiddenLines,
239
- } = expanded
240
- ? { text: diff, hiddenHunks: 0, hiddenLines: 0 }
241
- : truncateDiffByHunk(diff, PREVIEW_LIMITS.DIFF_COLLAPSED_HUNKS, PREVIEW_LIMITS.DIFF_COLLAPSED_LINES);
242
-
243
- text += `\n\n${renderDiffFn(truncatedDiff, { filePath: rawPath })}`;
244
- if (!expanded && (hiddenHunks > 0 || hiddenLines > 0)) {
245
- const remainder: string[] = [];
246
- if (hiddenHunks > 0) remainder.push(`${hiddenHunks} more hunks`);
247
- if (hiddenLines > 0) remainder.push(`${hiddenLines} more lines`);
248
- text += uiTheme.fg("toolOutput", `\n… (${remainder.join(", ")}) ${formatExpandHint(uiTheme)}`);
249
- }
250
- return text;
251
- }
252
207
 
253
208
  export const editToolRenderer = {
254
- mergeCallAndResult: true,
255
-
256
- renderCall(args: EditRenderArgs, options: RenderResultOptions, uiTheme: Theme): Component {
257
- const ui = new ToolUIKit(uiTheme);
209
+ renderCall(
210
+ args: EditRenderArgs,
211
+ options: RenderResultOptions & { renderContext?: EditRenderContext },
212
+ uiTheme: Theme,
213
+ ): Component {
258
214
  const rawPath = args.file_path || args.path || "";
259
215
  const filePath = shortenPath(rawPath);
260
216
  const editLanguage = getLanguageFromPath(rawPath) ?? "text";
@@ -270,34 +226,38 @@ export const editToolRenderer = {
270
226
  const opTitle = args.op === "create" ? "Create" : args.op === "delete" ? "Delete" : "Edit";
271
227
  const spinner =
272
228
  options?.spinnerFrame !== undefined ? formatStatusIcon("running", uiTheme, options.spinnerFrame) : "";
273
- let text = `${ui.title(opTitle)} ${spinner ? `${spinner} ` : ""}${editIcon} ${pathDisplay}`;
229
+ const title = uiTheme.fg("toolTitle", uiTheme.bold(opTitle));
230
+ let text = `${title} ${spinner ? `${spinner} ` : ""}${editIcon} ${pathDisplay}`;
274
231
 
275
232
  // Show streaming preview of diff/content
276
- if (args.previewDiff) {
277
- text += formatStreamingDiff(args.previewDiff, rawPath, uiTheme, "preview");
233
+ const previewDiffText =
234
+ args.previewDiff ??
235
+ (options.renderContext?.editDiffPreview && "diff" in options.renderContext.editDiffPreview
236
+ ? options.renderContext.editDiffPreview.diff
237
+ : undefined);
238
+ if (previewDiffText) {
239
+ text += formatStreamingDiff(previewDiffText, rawPath, uiTheme, "preview");
278
240
  } else if (args.diff && args.op) {
279
241
  text += formatStreamingDiff(args.diff, rawPath, uiTheme);
280
242
  } else if (args.edits && args.edits.length > 0) {
281
- text += formatStreamingHashlineEdits(args.edits, uiTheme, ui);
243
+ text += formatStreamingHashlineEdits(args.edits, uiTheme);
282
244
  } else if (args.diff) {
283
245
  const previewLines = args.diff.split("\n");
284
- const maxLines = 6;
285
246
  text += "\n\n";
286
- for (const line of previewLines.slice(0, maxLines)) {
287
- text += `${uiTheme.fg("toolOutput", ui.truncate(replaceTabs(line), 80))}\n`;
247
+ for (const line of previewLines.slice(0, PREVIEW_LIMITS.STREAMING_PREVIEW)) {
248
+ text += `${uiTheme.fg("toolOutput", truncateToWidth(replaceTabs(line), TRUNCATE_LENGTHS.CONTENT))}\n`;
288
249
  }
289
- if (previewLines.length > maxLines) {
290
- text += uiTheme.fg("dim", `… ${previewLines.length - maxLines} more lines`);
250
+ if (previewLines.length > PREVIEW_LIMITS.STREAMING_PREVIEW) {
251
+ text += uiTheme.fg("dim", `… ${previewLines.length - PREVIEW_LIMITS.STREAMING_PREVIEW} more lines`);
291
252
  }
292
253
  } else if (args.newText || args.patch) {
293
254
  const previewLines = (args.newText ?? args.patch ?? "").split("\n");
294
- const maxLines = 6;
295
255
  text += "\n\n";
296
- for (const line of previewLines.slice(0, maxLines)) {
297
- text += `${uiTheme.fg("toolOutput", ui.truncate(replaceTabs(line), 80))}\n`;
256
+ for (const line of previewLines.slice(0, PREVIEW_LIMITS.STREAMING_PREVIEW)) {
257
+ text += `${uiTheme.fg("toolOutput", truncateToWidth(replaceTabs(line), TRUNCATE_LENGTHS.CONTENT))}\n`;
298
258
  }
299
- if (previewLines.length > maxLines) {
300
- text += uiTheme.fg("dim", `… ${previewLines.length - maxLines} more lines`);
259
+ if (previewLines.length > PREVIEW_LIMITS.STREAMING_PREVIEW) {
260
+ text += uiTheme.fg("dim", `… ${previewLines.length - PREVIEW_LIMITS.STREAMING_PREVIEW} more lines`);
301
261
  }
302
262
  }
303
263
 
@@ -310,91 +270,63 @@ export const editToolRenderer = {
310
270
  uiTheme: Theme,
311
271
  args?: EditRenderArgs,
312
272
  ): Component {
313
- const ui = new ToolUIKit(uiTheme);
314
273
  const rawPath = args?.file_path || args?.path || "";
315
274
  const filePath = shortenPath(rawPath);
316
- const editLanguage = getLanguageFromPath(rawPath) ?? "text";
317
- const editIcon = uiTheme.fg("muted", uiTheme.getLangIcon(editLanguage));
318
-
319
275
  const op = args?.op || result.details?.op;
320
276
  const rename = args?.rename || result.details?.rename;
321
277
  const opTitle = op === "create" ? "Create" : op === "delete" ? "Delete" : "Edit";
322
278
 
323
- // Pre-compute metadata line (static across renders)
324
- const lineCountSource = args?.newText ?? args?.oldText ?? args?.diff ?? args?.patch ?? null;
325
- const metadataLine =
326
- op !== "delete"
327
- ? `\n${formatMetadataLine(lineCountSource ? countLines(lineCountSource) : null, editLanguage, uiTheme)}`
328
- : "";
329
-
330
- // Pre-compute error text (static)
331
- const errorText = result.isError ? (result.content?.find(c => c.type === "text")?.text ?? "") : "";
332
-
333
- let cached: RenderCache | undefined;
334
-
335
- return {
336
- render(width) {
337
- const { expanded, renderContext } = options;
338
- const editDiffPreview = renderContext?.editDiffPreview;
339
- const renderDiffFn = renderContext?.renderDiff ?? ((t: string) => t);
340
- const key = new Hasher().bool(expanded).u32(width).digest();
341
- if (cached?.key === key) return cached.lines;
342
-
343
- // Build path display with line number
344
- let pathDisplay = filePath ? uiTheme.fg("accent", filePath) : uiTheme.fg("toolOutput", "…");
345
- const firstChangedLine =
346
- (editDiffPreview && "firstChangedLine" in editDiffPreview
347
- ? editDiffPreview.firstChangedLine
348
- : undefined) || (result.details && !result.isError ? result.details.firstChangedLine : undefined);
349
- if (firstChangedLine) {
350
- pathDisplay += uiTheme.fg("warning", `:${firstChangedLine}`);
351
- }
352
-
353
- // Add arrow for rename operations
354
- if (rename) {
355
- pathDisplay += ` ${uiTheme.fg("dim", "→")} ${uiTheme.fg("accent", shortenPath(rename))}`;
356
- }
357
-
358
- const header = renderStatusLine(
359
- {
360
- icon: result.isError ? "error" : "success",
361
- title: opTitle,
362
- description: `${editIcon} ${pathDisplay}`,
363
- },
364
- uiTheme,
365
- );
366
- let text = header;
367
- text += metadataLine;
279
+ if (result.isError) {
280
+ const errorText = result.content?.find(c => c.type === "text")?.text || "Unknown error";
281
+ const header = renderStatusLine({ icon: "error", title: opTitle, description: filePath || "file" }, uiTheme);
282
+ return new Text(`${header}\n${uiTheme.fg("error", replaceTabs(errorText))}`, 0, 0);
283
+ }
368
284
 
369
- if (result.isError) {
370
- if (errorText) {
371
- text += `\n\n${uiTheme.fg("error", replaceTabs(errorText))}`;
372
- }
373
- } else if (result.details?.diff) {
374
- text += renderDiffSection(result.details.diff, rawPath, expanded, uiTheme, ui, renderDiffFn);
375
- } else if (editDiffPreview) {
376
- if ("error" in editDiffPreview) {
377
- text += `\n\n${uiTheme.fg("error", replaceTabs(editDiffPreview.error))}`;
378
- } else if (editDiffPreview.diff) {
379
- text += renderDiffSection(editDiffPreview.diff, rawPath, expanded, uiTheme, ui, renderDiffFn);
380
- }
381
- }
285
+ // Get diff text from result or preview
286
+ const { renderContext } = options;
287
+ const editDiffPreview = renderContext?.editDiffPreview;
288
+ const diffText =
289
+ result.details?.diff ??
290
+ (editDiffPreview && "diff" in editDiffPreview ? editDiffPreview.diff : undefined) ??
291
+ "";
292
+
293
+ const diffStats = diffText ? getDiffStats(diffText) : { added: 0, removed: 0, hunks: 0, lines: 0 };
294
+
295
+ // Build header with diff stats
296
+ let description = filePath || "file";
297
+ if (rename) description += ` ${uiTheme.fg("dim", "→")} ${shortenPath(rename)}`;
298
+ const meta: string[] = [];
299
+ if (diffStats.hunks > 0) meta.push(`${diffStats.hunks} hunks`);
300
+ if (diffStats.added > 0) meta.push(uiTheme.fg("success", `+${diffStats.added}`));
301
+ if (diffStats.removed > 0) meta.push(uiTheme.fg("error", `-${diffStats.removed}`));
302
+
303
+ const header = renderStatusLine({ icon: "success", title: opTitle, description, meta }, uiTheme);
304
+
305
+ // Tree-style diff body
306
+ const expanded = options.expanded;
307
+ const diffLines = diffText ? diffText.split("\n") : [];
308
+ const maxLines = expanded ? diffLines.length : Math.min(diffLines.length, PREVIEW_LIMITS.DIFF_COLLAPSED_LINES);
309
+
310
+ const treeBody: string[] = [];
311
+ for (let i = 0; i < maxLines; i++) {
312
+ const line = diffLines[i];
313
+ const color = line.startsWith("+") ? "success" : line.startsWith("-") ? "error" : "dim";
314
+ treeBody.push(uiTheme.fg(color, replaceTabs(line)));
315
+ }
316
+ if (!expanded && diffLines.length > maxLines) {
317
+ const remaining = diffLines.length - maxLines;
318
+ treeBody.push(uiTheme.fg("dim", `… ${remaining} more lines`) + ` ${formatClickHint(uiTheme)}`);
319
+ }
382
320
 
383
- // Show LSP diagnostics if available
384
- if (result.details?.diagnostics) {
385
- text += ui.formatDiagnostics(result.details.diagnostics, expanded, (fp: string) =>
386
- uiTheme.getLangIcon(getLanguageFromPath(fp)),
387
- );
388
- }
321
+ // Diagnostics
322
+ if (result.details?.diagnostics) {
323
+ const diagText = formatDiagnostics(result.details.diagnostics, expanded, uiTheme, (fp: string) =>
324
+ uiTheme.getLangIcon(getLanguageFromPath(fp)),
325
+ );
326
+ if (diagText.trim()) treeBody.push(diagText.trim());
327
+ }
389
328
 
390
- const lines =
391
- width > 0 ? text.split("\n").map(line => truncateToWidth(line, width, Ellipsis.Omit)) : text.split("\n");
392
- cached = { key, lines };
393
- return lines;
394
- },
395
- invalidate() {
396
- cached = undefined;
397
- },
398
- };
329
+ const all = treeBody.length > 0 ? [header, ...treeBody] : [header];
330
+ return new Text(all.join("\n"), 0, 0);
399
331
  },
400
332
  };
@@ -1,48 +1,33 @@
1
1
  ---
2
2
  name: explore
3
3
  description: Fast read-only codebase scout returning compressed context for handoff
4
- tools: read, grep, find, bash
4
+ tools: read, grep, find
5
5
  model: arcane/fast
6
- thinking-level: minimal
7
6
  ---
8
7
 
9
- <role>File search specialist and codebase scout. Quickly investigate codebase, return structured findings another agent can use without re-reading everything.</role>
8
+ You are a fast, parallel code search agent.
10
9
 
11
- <critical>
12
- READ-ONLY. STRICTLY PROHIBITED from:
13
- - Creating/modifying files (no Write/Edit/touch/rm/mv/cp)
14
- - Creating temporary files anywhere (incl /tmp)
15
- - Using redirects (>, >>, |) or heredocs to write files
16
- - Running state-changing commands (git add/commit, npm/pip install)
17
- </critical>
10
+ ## Task
11
+ Find files and line ranges relevant to the user's query (provided in the first message).
18
12
 
19
- <directives>
20
- - Use find for broad pattern matching
21
- - Use grep for regex content search
22
- - Use read when path is known
23
- - Use bash ONLY for git status/log/diff; use read/grep/find/ls for file/search operations
24
- - Spawn parallel tool calls when possible—meant to be fast
25
- - Return absolute file paths in final response
26
- </directives>
13
+ ## Query Decomposition
14
+ Before searching, decompose the query into:
15
+ - **Key symbols**: function names, class names, type names, variable names
16
+ - **Synonyms**: alternative naming conventions (camelCase, snake_case, abbreviations)
17
+ - **File patterns**: likely filenames or directories based on the concept
18
+ - **Related concepts**: imports, tests, configs that reference the target
27
19
 
28
- <thoroughness>
29
- Infer from task; default medium:
30
- - Quick: Targeted lookups, key files only
31
- - Medium: Follow imports, read critical sections
32
- - Thorough: Trace all dependencies, check tests/types
33
- </thoroughness>
20
+ ## Execution Strategy
21
+ - Your goal is to return a list of relevant filenames with line ranges. Your goal is NOT to explore the complete codebase to construct an essay.
22
+ - **Turn 1 is your primary search turn.** Plan ALL searches upfront based on your decomposition. Make **10-15 parallel calls** covering every angle — do not hold back searches for later turns.
23
+ - **Turn 2 (if needed)**: Only for reading top candidate files to confirm relevance and extract line ranges. Not for new searches.
24
+ - **Stop as soon as you have enough results.** Most queries resolve in 1-2 turns. A third turn means your first turn was too narrow.
25
+ - **Prioritize source code**: Prefer source code files (.ts, .js, .py, .go, .rs, .java) over documentation (.md, .txt, README).
26
+ - **Be exhaustive when completeness is implied**: When the query asks for "all", "every", "each", or implies a complete list, find ALL occurrences breadth-first.
34
27
 
35
- <procedure>
36
- 1. grep/find to locate relevant code
37
- 2. Read key sections (not full files unless small)
38
- 3. Identify types/interfaces/key functions
39
- 4. Note dependencies between files
40
- </procedure>
28
+ ## Output format
29
+ - **Ultra concise**: Write a 1-2 line summary of findings, then output relevant files as markdown links.
30
+ - Format each file as: `[relativePath#L{start}-L{end}](file://{absolutePath}#L{start}-L{end})`
31
+ - **Use generous line ranges**: Extend ranges to capture complete logical units (full functions, classes, blocks). Add 5-10 lines buffer.
41
32
 
42
- <output>
43
- Print findings as text when done. Include:
44
- - Files examined with line ranges
45
- - Critical types/interfaces/functions found
46
- - How pieces connect (architecture)
47
- - Recommended entry point for the receiving agent
48
- </output>
33
+ Your final message must contain ONLY the search results — no preamble like "I'll search for...".
@@ -6,4 +6,4 @@ description: {{jsonStringify description}}
6
6
  {{/if}}{{#if model}}model: {{jsonStringify model}}
7
7
  {{/if}}{{#if thinkingLevel}}thinking-level: {{jsonStringify thinkingLevel}}
8
8
  {{/if}}---
9
- {{body}}
9
+ {{body}}
@@ -17,7 +17,7 @@ Analyze codebase, generate AGENTS.md documenting:
17
17
  </task>
18
18
 
19
19
  <parallel>
20
- Launch multiple `explore` agents in parallel (via `task` tool) scanning different areas (core src, tests, configs/build, scripts/docs), then synthesize.
20
+ Launch multiple explore calls in parallel scanning different areas (core src, tests, configs/build, scripts/docs), then synthesize.
21
21
  </parallel>
22
22
 
23
23
  <directives>
@@ -33,4 +33,4 @@ Launch multiple `explore` agents in parallel (via `task` tool) scanning differen
33
33
 
34
34
  <output>
35
35
  After analysis, write AGENTS.md to project root.
36
- </output>
36
+ </output>