@nghyane/arcane 0.1.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 (738) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/README.md +12 -0
  3. package/examples/README.md +21 -0
  4. package/examples/custom-tools/README.md +109 -0
  5. package/examples/custom-tools/hello/index.ts +20 -0
  6. package/examples/custom-tools/todo/index.ts +206 -0
  7. package/examples/extensions/README.md +143 -0
  8. package/examples/extensions/api-demo.ts +89 -0
  9. package/examples/extensions/chalk-logger.ts +25 -0
  10. package/examples/extensions/hello.ts +32 -0
  11. package/examples/extensions/pirate.ts +43 -0
  12. package/examples/extensions/plan-mode.ts +550 -0
  13. package/examples/extensions/reload-runtime.ts +37 -0
  14. package/examples/extensions/todo.ts +296 -0
  15. package/examples/extensions/tools.ts +144 -0
  16. package/examples/extensions/with-deps/index.ts +35 -0
  17. package/examples/extensions/with-deps/package-lock.json +31 -0
  18. package/examples/extensions/with-deps/package.json +16 -0
  19. package/examples/hooks/README.md +56 -0
  20. package/examples/hooks/auto-commit-on-exit.ts +48 -0
  21. package/examples/hooks/confirm-destructive.ts +58 -0
  22. package/examples/hooks/custom-compaction.ts +116 -0
  23. package/examples/hooks/dirty-repo-guard.ts +51 -0
  24. package/examples/hooks/file-trigger.ts +40 -0
  25. package/examples/hooks/git-checkpoint.ts +52 -0
  26. package/examples/hooks/handoff.ts +150 -0
  27. package/examples/hooks/permission-gate.ts +33 -0
  28. package/examples/hooks/protected-paths.ts +29 -0
  29. package/examples/hooks/qna.ts +119 -0
  30. package/examples/hooks/status-line.ts +39 -0
  31. package/examples/sdk/01-minimal.ts +21 -0
  32. package/examples/sdk/02-custom-model.ts +49 -0
  33. package/examples/sdk/03-custom-prompt.ts +43 -0
  34. package/examples/sdk/04-skills.ts +43 -0
  35. package/examples/sdk/06-extensions.ts +80 -0
  36. package/examples/sdk/06-hooks.ts +61 -0
  37. package/examples/sdk/07-context-files.ts +35 -0
  38. package/examples/sdk/08-prompt-templates.ts +36 -0
  39. package/examples/sdk/08-slash-commands.ts +41 -0
  40. package/examples/sdk/09-api-keys-and-oauth.ts +54 -0
  41. package/examples/sdk/11-sessions.ts +47 -0
  42. package/examples/sdk/README.md +150 -0
  43. package/package.json +464 -0
  44. package/scripts/format-prompts.ts +184 -0
  45. package/scripts/generate-docs-index.ts +40 -0
  46. package/scripts/generate-template.ts +32 -0
  47. package/src/bun-imports.d.ts +22 -0
  48. package/src/capability/context-file.ts +39 -0
  49. package/src/capability/extension-module.ts +33 -0
  50. package/src/capability/extension.ts +47 -0
  51. package/src/capability/fs.ts +89 -0
  52. package/src/capability/hook.ts +39 -0
  53. package/src/capability/index.ts +432 -0
  54. package/src/capability/instruction.ts +36 -0
  55. package/src/capability/mcp.ts +60 -0
  56. package/src/capability/prompt.ts +34 -0
  57. package/src/capability/rule.ts +223 -0
  58. package/src/capability/settings.ts +34 -0
  59. package/src/capability/skill.ts +48 -0
  60. package/src/capability/slash-command.ts +39 -0
  61. package/src/capability/ssh.ts +41 -0
  62. package/src/capability/system-prompt.ts +34 -0
  63. package/src/capability/tool.ts +37 -0
  64. package/src/capability/types.ts +156 -0
  65. package/src/cli/args.ts +259 -0
  66. package/src/cli/config-cli.ts +357 -0
  67. package/src/cli/file-processor.ts +124 -0
  68. package/src/cli/grep-cli.ts +152 -0
  69. package/src/cli/jupyter-cli.ts +106 -0
  70. package/src/cli/list-models.ts +103 -0
  71. package/src/cli/plugin-cli.ts +661 -0
  72. package/src/cli/session-picker.ts +42 -0
  73. package/src/cli/setup-cli.ts +376 -0
  74. package/src/cli/shell-cli.ts +174 -0
  75. package/src/cli/ssh-cli.ts +179 -0
  76. package/src/cli/stats-cli.ts +197 -0
  77. package/src/cli/update-cli.ts +286 -0
  78. package/src/cli/web-search-cli.ts +143 -0
  79. package/src/cli.ts +65 -0
  80. package/src/commands/commit.ts +36 -0
  81. package/src/commands/config.ts +51 -0
  82. package/src/commands/grep.ts +41 -0
  83. package/src/commands/jupyter.ts +32 -0
  84. package/src/commands/launch.ts +139 -0
  85. package/src/commands/plugin.ts +70 -0
  86. package/src/commands/setup.ts +42 -0
  87. package/src/commands/shell.ts +29 -0
  88. package/src/commands/ssh.ts +60 -0
  89. package/src/commands/stats.ts +29 -0
  90. package/src/commands/update.ts +21 -0
  91. package/src/commands/web-search.ts +42 -0
  92. package/src/commit/agentic/agent.ts +311 -0
  93. package/src/commit/agentic/fallback.ts +96 -0
  94. package/src/commit/agentic/index.ts +359 -0
  95. package/src/commit/agentic/prompts/analyze-file.md +22 -0
  96. package/src/commit/agentic/prompts/session-user.md +25 -0
  97. package/src/commit/agentic/prompts/split-confirm.md +1 -0
  98. package/src/commit/agentic/prompts/system.md +38 -0
  99. package/src/commit/agentic/state.ts +69 -0
  100. package/src/commit/agentic/tools/analyze-file.ts +118 -0
  101. package/src/commit/agentic/tools/git-file-diff.ts +194 -0
  102. package/src/commit/agentic/tools/git-hunk.ts +50 -0
  103. package/src/commit/agentic/tools/git-overview.ts +84 -0
  104. package/src/commit/agentic/tools/index.ts +56 -0
  105. package/src/commit/agentic/tools/propose-changelog.ts +128 -0
  106. package/src/commit/agentic/tools/propose-commit.ts +154 -0
  107. package/src/commit/agentic/tools/recent-commits.ts +81 -0
  108. package/src/commit/agentic/tools/split-commit.ts +280 -0
  109. package/src/commit/agentic/topo-sort.ts +44 -0
  110. package/src/commit/agentic/trivial.ts +51 -0
  111. package/src/commit/agentic/validation.ts +200 -0
  112. package/src/commit/analysis/conventional.ts +165 -0
  113. package/src/commit/analysis/index.ts +4 -0
  114. package/src/commit/analysis/scope.ts +242 -0
  115. package/src/commit/analysis/summary.ts +112 -0
  116. package/src/commit/analysis/validation.ts +66 -0
  117. package/src/commit/changelog/detect.ts +37 -0
  118. package/src/commit/changelog/generate.ts +110 -0
  119. package/src/commit/changelog/index.ts +234 -0
  120. package/src/commit/changelog/parse.ts +44 -0
  121. package/src/commit/cli.ts +93 -0
  122. package/src/commit/git/diff.ts +148 -0
  123. package/src/commit/git/errors.ts +9 -0
  124. package/src/commit/git/index.ts +211 -0
  125. package/src/commit/git/operations.ts +54 -0
  126. package/src/commit/index.ts +5 -0
  127. package/src/commit/map-reduce/index.ts +64 -0
  128. package/src/commit/map-reduce/map-phase.ts +178 -0
  129. package/src/commit/map-reduce/reduce-phase.ts +145 -0
  130. package/src/commit/map-reduce/utils.ts +9 -0
  131. package/src/commit/message.ts +11 -0
  132. package/src/commit/model-selection.ts +69 -0
  133. package/src/commit/pipeline.ts +243 -0
  134. package/src/commit/prompts/analysis-system.md +148 -0
  135. package/src/commit/prompts/analysis-user.md +38 -0
  136. package/src/commit/prompts/changelog-system.md +50 -0
  137. package/src/commit/prompts/changelog-user.md +18 -0
  138. package/src/commit/prompts/file-observer-system.md +24 -0
  139. package/src/commit/prompts/file-observer-user.md +8 -0
  140. package/src/commit/prompts/reduce-system.md +50 -0
  141. package/src/commit/prompts/reduce-user.md +17 -0
  142. package/src/commit/prompts/summary-retry.md +3 -0
  143. package/src/commit/prompts/summary-system.md +38 -0
  144. package/src/commit/prompts/summary-user.md +13 -0
  145. package/src/commit/prompts/types-description.md +2 -0
  146. package/src/commit/types.ts +109 -0
  147. package/src/commit/utils/exclusions.ts +42 -0
  148. package/src/config/file-lock.ts +121 -0
  149. package/src/config/keybindings.ts +280 -0
  150. package/src/config/model-registry.ts +1140 -0
  151. package/src/config/model-resolver.ts +812 -0
  152. package/src/config/prompt-templates.ts +526 -0
  153. package/src/config/resolve-config-value.ts +92 -0
  154. package/src/config/settings-schema.ts +1236 -0
  155. package/src/config/settings.ts +706 -0
  156. package/src/config.ts +414 -0
  157. package/src/cursor.ts +239 -0
  158. package/src/debug/index.ts +431 -0
  159. package/src/debug/log-formatting.ts +60 -0
  160. package/src/debug/log-viewer.ts +903 -0
  161. package/src/debug/profiler.ts +158 -0
  162. package/src/debug/report-bundle.ts +366 -0
  163. package/src/debug/system-info.ts +112 -0
  164. package/src/discovery/agents-md.ts +68 -0
  165. package/src/discovery/agents.ts +199 -0
  166. package/src/discovery/builtin.ts +815 -0
  167. package/src/discovery/claude-plugins.ts +205 -0
  168. package/src/discovery/claude.ts +506 -0
  169. package/src/discovery/cline.ts +83 -0
  170. package/src/discovery/codex.ts +532 -0
  171. package/src/discovery/cursor.ts +218 -0
  172. package/src/discovery/gemini.ts +395 -0
  173. package/src/discovery/github.ts +117 -0
  174. package/src/discovery/helpers.ts +698 -0
  175. package/src/discovery/index.ts +89 -0
  176. package/src/discovery/mcp-json.ts +156 -0
  177. package/src/discovery/opencode.ts +394 -0
  178. package/src/discovery/ssh.ts +160 -0
  179. package/src/discovery/vscode.ts +103 -0
  180. package/src/discovery/windsurf.ts +145 -0
  181. package/src/exa/company.ts +57 -0
  182. package/src/exa/index.ts +62 -0
  183. package/src/exa/linkedin.ts +57 -0
  184. package/src/exa/mcp-client.ts +289 -0
  185. package/src/exa/render.ts +244 -0
  186. package/src/exa/researcher.ts +89 -0
  187. package/src/exa/search.ts +330 -0
  188. package/src/exa/types.ts +166 -0
  189. package/src/exa/websets.ts +247 -0
  190. package/src/exec/bash-executor.ts +184 -0
  191. package/src/exec/exec.ts +53 -0
  192. package/src/export/custom-share.ts +65 -0
  193. package/src/export/html/index.ts +162 -0
  194. package/src/export/html/template.css +889 -0
  195. package/src/export/html/template.generated.ts +2 -0
  196. package/src/export/html/template.html +45 -0
  197. package/src/export/html/template.js +1329 -0
  198. package/src/export/html/template.macro.ts +24 -0
  199. package/src/export/html/vendor/highlight.min.js +1213 -0
  200. package/src/export/html/vendor/marked.min.js +6 -0
  201. package/src/export/ttsr.ts +434 -0
  202. package/src/extensibility/custom-commands/bundled/review/index.ts +433 -0
  203. package/src/extensibility/custom-commands/index.ts +15 -0
  204. package/src/extensibility/custom-commands/loader.ts +231 -0
  205. package/src/extensibility/custom-commands/types.ts +111 -0
  206. package/src/extensibility/custom-tools/index.ts +22 -0
  207. package/src/extensibility/custom-tools/loader.ts +235 -0
  208. package/src/extensibility/custom-tools/types.ts +226 -0
  209. package/src/extensibility/custom-tools/wrapper.ts +45 -0
  210. package/src/extensibility/extensions/index.ts +136 -0
  211. package/src/extensibility/extensions/loader.ts +520 -0
  212. package/src/extensibility/extensions/runner.ts +774 -0
  213. package/src/extensibility/extensions/types.ts +1293 -0
  214. package/src/extensibility/extensions/wrapper.ts +188 -0
  215. package/src/extensibility/hooks/index.ts +16 -0
  216. package/src/extensibility/hooks/loader.ts +273 -0
  217. package/src/extensibility/hooks/runner.ts +441 -0
  218. package/src/extensibility/hooks/tool-wrapper.ts +106 -0
  219. package/src/extensibility/hooks/types.ts +817 -0
  220. package/src/extensibility/plugins/doctor.ts +65 -0
  221. package/src/extensibility/plugins/git-url.ts +281 -0
  222. package/src/extensibility/plugins/index.ts +33 -0
  223. package/src/extensibility/plugins/installer.ts +192 -0
  224. package/src/extensibility/plugins/loader.ts +338 -0
  225. package/src/extensibility/plugins/manager.ts +716 -0
  226. package/src/extensibility/plugins/parser.ts +105 -0
  227. package/src/extensibility/plugins/types.ts +190 -0
  228. package/src/extensibility/skills.ts +385 -0
  229. package/src/extensibility/slash-commands.ts +287 -0
  230. package/src/extensibility/tool-proxy.ts +25 -0
  231. package/src/index.ts +275 -0
  232. package/src/internal-urls/agent-protocol.ts +136 -0
  233. package/src/internal-urls/artifact-protocol.ts +97 -0
  234. package/src/internal-urls/docs-index.generated.ts +54 -0
  235. package/src/internal-urls/docs-protocol.ts +84 -0
  236. package/src/internal-urls/index.ts +31 -0
  237. package/src/internal-urls/json-query.ts +126 -0
  238. package/src/internal-urls/memory-protocol.ts +133 -0
  239. package/src/internal-urls/router.ts +70 -0
  240. package/src/internal-urls/rule-protocol.ts +55 -0
  241. package/src/internal-urls/skill-protocol.ts +111 -0
  242. package/src/internal-urls/types.ts +52 -0
  243. package/src/ipy/executor.ts +556 -0
  244. package/src/ipy/gateway-coordinator.ts +426 -0
  245. package/src/ipy/kernel.ts +892 -0
  246. package/src/ipy/modules.ts +109 -0
  247. package/src/ipy/prelude.py +831 -0
  248. package/src/ipy/prelude.ts +3 -0
  249. package/src/ipy/runtime.ts +222 -0
  250. package/src/lsp/client.ts +867 -0
  251. package/src/lsp/clients/biome-client.ts +202 -0
  252. package/src/lsp/clients/index.ts +50 -0
  253. package/src/lsp/clients/lsp-linter-client.ts +93 -0
  254. package/src/lsp/clients/swiftlint-client.ts +120 -0
  255. package/src/lsp/config.ts +397 -0
  256. package/src/lsp/defaults.json +464 -0
  257. package/src/lsp/edits.ts +109 -0
  258. package/src/lsp/index.ts +1268 -0
  259. package/src/lsp/lspmux.ts +250 -0
  260. package/src/lsp/render.ts +689 -0
  261. package/src/lsp/types.ts +414 -0
  262. package/src/lsp/utils.ts +549 -0
  263. package/src/main.ts +773 -0
  264. package/src/mcp/client.ts +239 -0
  265. package/src/mcp/config-writer.ts +215 -0
  266. package/src/mcp/config.ts +363 -0
  267. package/src/mcp/index.ts +55 -0
  268. package/src/mcp/json-rpc.ts +84 -0
  269. package/src/mcp/loader.ts +124 -0
  270. package/src/mcp/manager.ts +490 -0
  271. package/src/mcp/oauth-discovery.ts +274 -0
  272. package/src/mcp/oauth-flow.ts +229 -0
  273. package/src/mcp/render.ts +123 -0
  274. package/src/mcp/tool-bridge.ts +372 -0
  275. package/src/mcp/tool-cache.ts +121 -0
  276. package/src/mcp/transports/http.ts +332 -0
  277. package/src/mcp/transports/index.ts +6 -0
  278. package/src/mcp/transports/stdio.ts +281 -0
  279. package/src/mcp/types.ts +248 -0
  280. package/src/memories/index.ts +1099 -0
  281. package/src/memories/storage.ts +563 -0
  282. package/src/modes/components/agent-dashboard.ts +1130 -0
  283. package/src/modes/components/assistant-message.ts +144 -0
  284. package/src/modes/components/bash-execution.ts +218 -0
  285. package/src/modes/components/bordered-loader.ts +41 -0
  286. package/src/modes/components/branch-summary-message.ts +45 -0
  287. package/src/modes/components/codemode-group.ts +369 -0
  288. package/src/modes/components/compaction-summary-message.ts +51 -0
  289. package/src/modes/components/countdown-timer.ts +46 -0
  290. package/src/modes/components/custom-editor.ts +181 -0
  291. package/src/modes/components/custom-message.ts +91 -0
  292. package/src/modes/components/diff.ts +186 -0
  293. package/src/modes/components/dynamic-border.ts +25 -0
  294. package/src/modes/components/extensions/extension-dashboard.ts +325 -0
  295. package/src/modes/components/extensions/extension-list.ts +484 -0
  296. package/src/modes/components/extensions/index.ts +9 -0
  297. package/src/modes/components/extensions/inspector-panel.ts +321 -0
  298. package/src/modes/components/extensions/state-manager.ts +586 -0
  299. package/src/modes/components/extensions/types.ts +191 -0
  300. package/src/modes/components/footer.ts +315 -0
  301. package/src/modes/components/history-search.ts +157 -0
  302. package/src/modes/components/hook-editor.ts +101 -0
  303. package/src/modes/components/hook-input.ts +72 -0
  304. package/src/modes/components/hook-message.ts +100 -0
  305. package/src/modes/components/hook-selector.ts +155 -0
  306. package/src/modes/components/index.ts +41 -0
  307. package/src/modes/components/keybinding-hints.ts +65 -0
  308. package/src/modes/components/login-dialog.ts +164 -0
  309. package/src/modes/components/mcp-add-wizard.ts +1295 -0
  310. package/src/modes/components/model-selector.ts +625 -0
  311. package/src/modes/components/oauth-selector.ts +210 -0
  312. package/src/modes/components/plugin-settings.ts +477 -0
  313. package/src/modes/components/python-execution.ts +196 -0
  314. package/src/modes/components/queue-mode-selector.ts +56 -0
  315. package/src/modes/components/read-tool-group.ts +119 -0
  316. package/src/modes/components/session-selector.ts +242 -0
  317. package/src/modes/components/settings-defs.ts +340 -0
  318. package/src/modes/components/settings-selector.ts +529 -0
  319. package/src/modes/components/show-images-selector.ts +45 -0
  320. package/src/modes/components/skill-message.ts +90 -0
  321. package/src/modes/components/status-line/index.ts +4 -0
  322. package/src/modes/components/status-line/presets.ts +94 -0
  323. package/src/modes/components/status-line/segments.ts +352 -0
  324. package/src/modes/components/status-line/separators.ts +55 -0
  325. package/src/modes/components/status-line/types.ts +75 -0
  326. package/src/modes/components/status-line-segment-editor.ts +354 -0
  327. package/src/modes/components/status-line.ts +421 -0
  328. package/src/modes/components/theme-selector.ts +63 -0
  329. package/src/modes/components/thinking-selector.ts +64 -0
  330. package/src/modes/components/todo-display.ts +115 -0
  331. package/src/modes/components/todo-reminder.ts +40 -0
  332. package/src/modes/components/tool-execution.ts +703 -0
  333. package/src/modes/components/tree-selector.ts +904 -0
  334. package/src/modes/components/ttsr-notification.ts +80 -0
  335. package/src/modes/components/user-message-selector.ts +146 -0
  336. package/src/modes/components/user-message.ts +22 -0
  337. package/src/modes/components/visual-truncate.ts +63 -0
  338. package/src/modes/components/welcome.ts +247 -0
  339. package/src/modes/controllers/command-controller.ts +1120 -0
  340. package/src/modes/controllers/event-controller.ts +479 -0
  341. package/src/modes/controllers/extension-ui-controller.ts +778 -0
  342. package/src/modes/controllers/input-controller.ts +671 -0
  343. package/src/modes/controllers/mcp-command-controller.ts +1315 -0
  344. package/src/modes/controllers/selector-controller.ts +712 -0
  345. package/src/modes/controllers/ssh-command-controller.ts +452 -0
  346. package/src/modes/index.ts +15 -0
  347. package/src/modes/interactive-mode.ts +1027 -0
  348. package/src/modes/print-mode.ts +191 -0
  349. package/src/modes/rpc/rpc-client.ts +583 -0
  350. package/src/modes/rpc/rpc-mode.ts +700 -0
  351. package/src/modes/rpc/rpc-types.ts +236 -0
  352. package/src/modes/theme/dark.json +95 -0
  353. package/src/modes/theme/defaults/alabaster.json +93 -0
  354. package/src/modes/theme/defaults/amethyst.json +96 -0
  355. package/src/modes/theme/defaults/anthracite.json +93 -0
  356. package/src/modes/theme/defaults/basalt.json +91 -0
  357. package/src/modes/theme/defaults/birch.json +95 -0
  358. package/src/modes/theme/defaults/dark-abyss.json +91 -0
  359. package/src/modes/theme/defaults/dark-arctic.json +104 -0
  360. package/src/modes/theme/defaults/dark-aurora.json +95 -0
  361. package/src/modes/theme/defaults/dark-catppuccin.json +107 -0
  362. package/src/modes/theme/defaults/dark-cavern.json +91 -0
  363. package/src/modes/theme/defaults/dark-copper.json +95 -0
  364. package/src/modes/theme/defaults/dark-cosmos.json +90 -0
  365. package/src/modes/theme/defaults/dark-cyberpunk.json +102 -0
  366. package/src/modes/theme/defaults/dark-dracula.json +98 -0
  367. package/src/modes/theme/defaults/dark-eclipse.json +91 -0
  368. package/src/modes/theme/defaults/dark-ember.json +95 -0
  369. package/src/modes/theme/defaults/dark-equinox.json +90 -0
  370. package/src/modes/theme/defaults/dark-forest.json +96 -0
  371. package/src/modes/theme/defaults/dark-github.json +105 -0
  372. package/src/modes/theme/defaults/dark-gruvbox.json +112 -0
  373. package/src/modes/theme/defaults/dark-lavender.json +95 -0
  374. package/src/modes/theme/defaults/dark-lunar.json +89 -0
  375. package/src/modes/theme/defaults/dark-midnight.json +95 -0
  376. package/src/modes/theme/defaults/dark-monochrome.json +94 -0
  377. package/src/modes/theme/defaults/dark-monokai.json +98 -0
  378. package/src/modes/theme/defaults/dark-nebula.json +90 -0
  379. package/src/modes/theme/defaults/dark-nord.json +97 -0
  380. package/src/modes/theme/defaults/dark-ocean.json +101 -0
  381. package/src/modes/theme/defaults/dark-one.json +100 -0
  382. package/src/modes/theme/defaults/dark-rainforest.json +91 -0
  383. package/src/modes/theme/defaults/dark-reef.json +91 -0
  384. package/src/modes/theme/defaults/dark-retro.json +92 -0
  385. package/src/modes/theme/defaults/dark-rose-pine.json +96 -0
  386. package/src/modes/theme/defaults/dark-sakura.json +95 -0
  387. package/src/modes/theme/defaults/dark-slate.json +95 -0
  388. package/src/modes/theme/defaults/dark-solarized.json +97 -0
  389. package/src/modes/theme/defaults/dark-solstice.json +90 -0
  390. package/src/modes/theme/defaults/dark-starfall.json +91 -0
  391. package/src/modes/theme/defaults/dark-sunset.json +99 -0
  392. package/src/modes/theme/defaults/dark-swamp.json +90 -0
  393. package/src/modes/theme/defaults/dark-synthwave.json +103 -0
  394. package/src/modes/theme/defaults/dark-taiga.json +91 -0
  395. package/src/modes/theme/defaults/dark-terminal.json +95 -0
  396. package/src/modes/theme/defaults/dark-tokyo-night.json +101 -0
  397. package/src/modes/theme/defaults/dark-tundra.json +91 -0
  398. package/src/modes/theme/defaults/dark-twilight.json +91 -0
  399. package/src/modes/theme/defaults/dark-volcanic.json +91 -0
  400. package/src/modes/theme/defaults/graphite.json +92 -0
  401. package/src/modes/theme/defaults/index.ts +195 -0
  402. package/src/modes/theme/defaults/light-arctic.json +107 -0
  403. package/src/modes/theme/defaults/light-aurora-day.json +91 -0
  404. package/src/modes/theme/defaults/light-canyon.json +91 -0
  405. package/src/modes/theme/defaults/light-catppuccin.json +106 -0
  406. package/src/modes/theme/defaults/light-cirrus.json +90 -0
  407. package/src/modes/theme/defaults/light-coral.json +95 -0
  408. package/src/modes/theme/defaults/light-cyberpunk.json +96 -0
  409. package/src/modes/theme/defaults/light-dawn.json +90 -0
  410. package/src/modes/theme/defaults/light-dunes.json +91 -0
  411. package/src/modes/theme/defaults/light-eucalyptus.json +95 -0
  412. package/src/modes/theme/defaults/light-forest.json +100 -0
  413. package/src/modes/theme/defaults/light-frost.json +95 -0
  414. package/src/modes/theme/defaults/light-github.json +115 -0
  415. package/src/modes/theme/defaults/light-glacier.json +91 -0
  416. package/src/modes/theme/defaults/light-gruvbox.json +108 -0
  417. package/src/modes/theme/defaults/light-haze.json +90 -0
  418. package/src/modes/theme/defaults/light-honeycomb.json +95 -0
  419. package/src/modes/theme/defaults/light-lagoon.json +91 -0
  420. package/src/modes/theme/defaults/light-lavender.json +95 -0
  421. package/src/modes/theme/defaults/light-meadow.json +91 -0
  422. package/src/modes/theme/defaults/light-mint.json +95 -0
  423. package/src/modes/theme/defaults/light-monochrome.json +101 -0
  424. package/src/modes/theme/defaults/light-ocean.json +99 -0
  425. package/src/modes/theme/defaults/light-one.json +99 -0
  426. package/src/modes/theme/defaults/light-opal.json +91 -0
  427. package/src/modes/theme/defaults/light-orchard.json +91 -0
  428. package/src/modes/theme/defaults/light-paper.json +95 -0
  429. package/src/modes/theme/defaults/light-prism.json +90 -0
  430. package/src/modes/theme/defaults/light-retro.json +98 -0
  431. package/src/modes/theme/defaults/light-sand.json +95 -0
  432. package/src/modes/theme/defaults/light-savanna.json +91 -0
  433. package/src/modes/theme/defaults/light-solarized.json +102 -0
  434. package/src/modes/theme/defaults/light-soleil.json +90 -0
  435. package/src/modes/theme/defaults/light-sunset.json +99 -0
  436. package/src/modes/theme/defaults/light-synthwave.json +98 -0
  437. package/src/modes/theme/defaults/light-tokyo-night.json +111 -0
  438. package/src/modes/theme/defaults/light-wetland.json +91 -0
  439. package/src/modes/theme/defaults/light-zenith.json +89 -0
  440. package/src/modes/theme/defaults/limestone.json +94 -0
  441. package/src/modes/theme/defaults/mahogany.json +97 -0
  442. package/src/modes/theme/defaults/marble.json +93 -0
  443. package/src/modes/theme/defaults/obsidian.json +91 -0
  444. package/src/modes/theme/defaults/onyx.json +91 -0
  445. package/src/modes/theme/defaults/pearl.json +93 -0
  446. package/src/modes/theme/defaults/porcelain.json +91 -0
  447. package/src/modes/theme/defaults/quartz.json +96 -0
  448. package/src/modes/theme/defaults/sandstone.json +95 -0
  449. package/src/modes/theme/defaults/titanium.json +90 -0
  450. package/src/modes/theme/light.json +93 -0
  451. package/src/modes/theme/mermaid-cache.ts +111 -0
  452. package/src/modes/theme/theme-schema.json +429 -0
  453. package/src/modes/theme/theme.ts +2333 -0
  454. package/src/modes/types.ts +216 -0
  455. package/src/modes/utils/ui-helpers.ts +529 -0
  456. package/src/patch/applicator.ts +1482 -0
  457. package/src/patch/diff.ts +425 -0
  458. package/src/patch/fuzzy.ts +784 -0
  459. package/src/patch/hashline.ts +972 -0
  460. package/src/patch/index.ts +964 -0
  461. package/src/patch/normalize.ts +397 -0
  462. package/src/patch/normative.ts +72 -0
  463. package/src/patch/parser.ts +532 -0
  464. package/src/patch/shared.ts +400 -0
  465. package/src/patch/types.ts +292 -0
  466. package/src/priority.json +35 -0
  467. package/src/prompts/agents/explore.md +48 -0
  468. package/src/prompts/agents/frontmatter.md +9 -0
  469. package/src/prompts/agents/init.md +36 -0
  470. package/src/prompts/agents/librarian.md +53 -0
  471. package/src/prompts/agents/oracle.md +51 -0
  472. package/src/prompts/agents/reviewer.md +70 -0
  473. package/src/prompts/agents/task.md +14 -0
  474. package/src/prompts/compaction/branch-summary-context.md +5 -0
  475. package/src/prompts/compaction/branch-summary-preamble.md +2 -0
  476. package/src/prompts/compaction/branch-summary.md +30 -0
  477. package/src/prompts/compaction/compaction-short-summary.md +9 -0
  478. package/src/prompts/compaction/compaction-summary-context.md +5 -0
  479. package/src/prompts/compaction/compaction-summary.md +38 -0
  480. package/src/prompts/compaction/compaction-turn-prefix.md +17 -0
  481. package/src/prompts/compaction/compaction-update-summary.md +45 -0
  482. package/src/prompts/memories/consolidation.md +30 -0
  483. package/src/prompts/memories/read_path.md +11 -0
  484. package/src/prompts/memories/stage_one_input.md +6 -0
  485. package/src/prompts/memories/stage_one_system.md +21 -0
  486. package/src/prompts/review-request.md +64 -0
  487. package/src/prompts/system/agent-creation-architect.md +65 -0
  488. package/src/prompts/system/agent-creation-user.md +6 -0
  489. package/src/prompts/system/custom-system-prompt.md +68 -0
  490. package/src/prompts/system/file-operations.md +10 -0
  491. package/src/prompts/system/subagent-submit-reminder.md +11 -0
  492. package/src/prompts/system/subagent-system-prompt.md +31 -0
  493. package/src/prompts/system/subagent-user-prompt.md +8 -0
  494. package/src/prompts/system/summarization-system.md +3 -0
  495. package/src/prompts/system/system-prompt.md +300 -0
  496. package/src/prompts/system/title-system.md +2 -0
  497. package/src/prompts/system/ttsr-interrupt.md +7 -0
  498. package/src/prompts/system/web-search.md +28 -0
  499. package/src/prompts/tools/ask.md +44 -0
  500. package/src/prompts/tools/bash.md +24 -0
  501. package/src/prompts/tools/browser.md +33 -0
  502. package/src/prompts/tools/calculator.md +12 -0
  503. package/src/prompts/tools/explore.md +29 -0
  504. package/src/prompts/tools/fetch.md +16 -0
  505. package/src/prompts/tools/find.md +18 -0
  506. package/src/prompts/tools/gemini-image.md +23 -0
  507. package/src/prompts/tools/grep.md +28 -0
  508. package/src/prompts/tools/hashline.md +232 -0
  509. package/src/prompts/tools/librarian.md +24 -0
  510. package/src/prompts/tools/lsp.md +28 -0
  511. package/src/prompts/tools/oracle.md +26 -0
  512. package/src/prompts/tools/patch.md +74 -0
  513. package/src/prompts/tools/python.md +66 -0
  514. package/src/prompts/tools/read.md +36 -0
  515. package/src/prompts/tools/replace.md +38 -0
  516. package/src/prompts/tools/reviewer.md +41 -0
  517. package/src/prompts/tools/ssh.md +51 -0
  518. package/src/prompts/tools/task-summary.md +28 -0
  519. package/src/prompts/tools/task.md +275 -0
  520. package/src/prompts/tools/todo-write.md +65 -0
  521. package/src/prompts/tools/undo-edit.md +7 -0
  522. package/src/prompts/tools/web-search.md +19 -0
  523. package/src/prompts/tools/write.md +18 -0
  524. package/src/sdk.ts +1287 -0
  525. package/src/secrets/index.ts +116 -0
  526. package/src/secrets/obfuscator.ts +269 -0
  527. package/src/secrets/regex.ts +21 -0
  528. package/src/session/agent-session.ts +4669 -0
  529. package/src/session/agent-storage.ts +621 -0
  530. package/src/session/artifacts.ts +132 -0
  531. package/src/session/auth-storage.ts +1433 -0
  532. package/src/session/blob-store.ts +103 -0
  533. package/src/session/compaction/branch-summarization.ts +315 -0
  534. package/src/session/compaction/compaction.ts +864 -0
  535. package/src/session/compaction/index.ts +7 -0
  536. package/src/session/compaction/pruning.ts +91 -0
  537. package/src/session/compaction/utils.ts +171 -0
  538. package/src/session/history-storage.ts +170 -0
  539. package/src/session/messages.ts +317 -0
  540. package/src/session/session-manager.ts +2276 -0
  541. package/src/session/session-storage.ts +342 -0
  542. package/src/session/streaming-output.ts +565 -0
  543. package/src/slash-commands/builtin-registry.ts +439 -0
  544. package/src/ssh/config-writer.ts +183 -0
  545. package/src/ssh/connection-manager.ts +444 -0
  546. package/src/ssh/ssh-executor.ts +127 -0
  547. package/src/ssh/sshfs-mount.ts +135 -0
  548. package/src/stt/downloader.ts +71 -0
  549. package/src/stt/index.ts +3 -0
  550. package/src/stt/recorder.ts +351 -0
  551. package/src/stt/setup.ts +52 -0
  552. package/src/stt/stt-controller.ts +160 -0
  553. package/src/stt/transcribe.py +70 -0
  554. package/src/stt/transcriber.ts +91 -0
  555. package/src/system-prompt.ts +685 -0
  556. package/src/task/agents.ts +155 -0
  557. package/src/task/batch.ts +102 -0
  558. package/src/task/commands.ts +134 -0
  559. package/src/task/discovery.ts +126 -0
  560. package/src/task/executor.ts +908 -0
  561. package/src/task/index.ts +223 -0
  562. package/src/task/output-manager.ts +107 -0
  563. package/src/task/parallel.ts +84 -0
  564. package/src/task/render.ts +326 -0
  565. package/src/task/subprocess-tool-registry.ts +88 -0
  566. package/src/task/template.ts +32 -0
  567. package/src/task/types.ts +144 -0
  568. package/src/tools/ask.ts +523 -0
  569. package/src/tools/bash-interactive.ts +419 -0
  570. package/src/tools/bash-interceptor.ts +105 -0
  571. package/src/tools/bash-normalize.ts +107 -0
  572. package/src/tools/bash-skill-urls.ts +177 -0
  573. package/src/tools/bash.ts +347 -0
  574. package/src/tools/browser.ts +1374 -0
  575. package/src/tools/calculator.ts +537 -0
  576. package/src/tools/context.ts +39 -0
  577. package/src/tools/explore.ts +23 -0
  578. package/src/tools/fetch.ts +1091 -0
  579. package/src/tools/find.ts +540 -0
  580. package/src/tools/fs-cache-invalidation.ts +28 -0
  581. package/src/tools/gemini-image.ts +907 -0
  582. package/src/tools/grep.ts +489 -0
  583. package/src/tools/index.ts +337 -0
  584. package/src/tools/json-tree.ts +231 -0
  585. package/src/tools/jtd-to-json-schema.ts +247 -0
  586. package/src/tools/jtd-to-typescript.ts +198 -0
  587. package/src/tools/librarian.ts +33 -0
  588. package/src/tools/list-limit.ts +40 -0
  589. package/src/tools/notebook.ts +287 -0
  590. package/src/tools/oracle.ts +40 -0
  591. package/src/tools/output-meta.ts +459 -0
  592. package/src/tools/output-utils.ts +63 -0
  593. package/src/tools/path-utils.ts +116 -0
  594. package/src/tools/puppeteer/00_stealth_tampering.txt +63 -0
  595. package/src/tools/puppeteer/01_stealth_activity.txt +20 -0
  596. package/src/tools/puppeteer/02_stealth_hairline.txt +11 -0
  597. package/src/tools/puppeteer/03_stealth_botd.txt +384 -0
  598. package/src/tools/puppeteer/04_stealth_iframe.txt +81 -0
  599. package/src/tools/puppeteer/05_stealth_webgl.txt +75 -0
  600. package/src/tools/puppeteer/06_stealth_screen.txt +72 -0
  601. package/src/tools/puppeteer/07_stealth_fonts.txt +97 -0
  602. package/src/tools/puppeteer/08_stealth_audio.txt +51 -0
  603. package/src/tools/puppeteer/09_stealth_locale.txt +46 -0
  604. package/src/tools/puppeteer/10_stealth_plugins.txt +206 -0
  605. package/src/tools/puppeteer/11_stealth_hardware.txt +8 -0
  606. package/src/tools/puppeteer/12_stealth_codecs.txt +40 -0
  607. package/src/tools/puppeteer/13_stealth_worker.txt +74 -0
  608. package/src/tools/python.ts +1118 -0
  609. package/src/tools/read.ts +1193 -0
  610. package/src/tools/render-utils.ts +680 -0
  611. package/src/tools/renderers.ts +60 -0
  612. package/src/tools/reviewer-tool.ts +41 -0
  613. package/src/tools/ssh.ts +326 -0
  614. package/src/tools/subagent-tool.ts +169 -0
  615. package/src/tools/submit-result.ts +152 -0
  616. package/src/tools/todo-write.ts +255 -0
  617. package/src/tools/tool-errors.ts +92 -0
  618. package/src/tools/tool-result.ts +86 -0
  619. package/src/tools/undo-edit.ts +145 -0
  620. package/src/tools/undo-history.ts +22 -0
  621. package/src/tools/write.ts +274 -0
  622. package/src/tui/code-cell.ts +108 -0
  623. package/src/tui/file-list.ts +47 -0
  624. package/src/tui/index.ts +11 -0
  625. package/src/tui/output-block.ts +144 -0
  626. package/src/tui/status-line.ts +39 -0
  627. package/src/tui/tree-list.ts +53 -0
  628. package/src/tui/types.ts +16 -0
  629. package/src/tui/utils.ts +116 -0
  630. package/src/utils/changelog.ts +98 -0
  631. package/src/utils/event-bus.ts +33 -0
  632. package/src/utils/external-editor.ts +59 -0
  633. package/src/utils/file-display-mode.ts +36 -0
  634. package/src/utils/file-mentions.ts +384 -0
  635. package/src/utils/frontmatter.ts +101 -0
  636. package/src/utils/fuzzy.ts +108 -0
  637. package/src/utils/ignore-files.ts +119 -0
  638. package/src/utils/image-convert.ts +27 -0
  639. package/src/utils/image-resize.ts +236 -0
  640. package/src/utils/mime.ts +30 -0
  641. package/src/utils/open.ts +20 -0
  642. package/src/utils/shell-snapshot.ts +199 -0
  643. package/src/utils/timings.ts +26 -0
  644. package/src/utils/title-generator.ts +167 -0
  645. package/src/utils/tools-manager.ts +362 -0
  646. package/src/web/scrapers/artifacthub.ts +215 -0
  647. package/src/web/scrapers/arxiv.ts +88 -0
  648. package/src/web/scrapers/aur.ts +175 -0
  649. package/src/web/scrapers/biorxiv.ts +141 -0
  650. package/src/web/scrapers/bluesky.ts +284 -0
  651. package/src/web/scrapers/brew.ts +177 -0
  652. package/src/web/scrapers/cheatsh.ts +78 -0
  653. package/src/web/scrapers/chocolatey.ts +158 -0
  654. package/src/web/scrapers/choosealicense.ts +110 -0
  655. package/src/web/scrapers/cisa-kev.ts +100 -0
  656. package/src/web/scrapers/clojars.ts +180 -0
  657. package/src/web/scrapers/coingecko.ts +184 -0
  658. package/src/web/scrapers/crates-io.ts +128 -0
  659. package/src/web/scrapers/crossref.ts +149 -0
  660. package/src/web/scrapers/devto.ts +177 -0
  661. package/src/web/scrapers/discogs.ts +307 -0
  662. package/src/web/scrapers/discourse.ts +221 -0
  663. package/src/web/scrapers/dockerhub.ts +160 -0
  664. package/src/web/scrapers/fdroid.ts +158 -0
  665. package/src/web/scrapers/firefox-addons.ts +214 -0
  666. package/src/web/scrapers/flathub.ts +239 -0
  667. package/src/web/scrapers/github-gist.ts +68 -0
  668. package/src/web/scrapers/github.ts +490 -0
  669. package/src/web/scrapers/gitlab.ts +456 -0
  670. package/src/web/scrapers/go-pkg.ts +275 -0
  671. package/src/web/scrapers/hackage.ts +94 -0
  672. package/src/web/scrapers/hackernews.ts +208 -0
  673. package/src/web/scrapers/hex.ts +121 -0
  674. package/src/web/scrapers/huggingface.ts +385 -0
  675. package/src/web/scrapers/iacr.ts +86 -0
  676. package/src/web/scrapers/index.ts +249 -0
  677. package/src/web/scrapers/jetbrains-marketplace.ts +169 -0
  678. package/src/web/scrapers/lemmy.ts +220 -0
  679. package/src/web/scrapers/lobsters.ts +186 -0
  680. package/src/web/scrapers/mastodon.ts +310 -0
  681. package/src/web/scrapers/maven.ts +152 -0
  682. package/src/web/scrapers/mdn.ts +172 -0
  683. package/src/web/scrapers/metacpan.ts +253 -0
  684. package/src/web/scrapers/musicbrainz.ts +272 -0
  685. package/src/web/scrapers/npm.ts +114 -0
  686. package/src/web/scrapers/nuget.ts +205 -0
  687. package/src/web/scrapers/nvd.ts +243 -0
  688. package/src/web/scrapers/ollama.ts +265 -0
  689. package/src/web/scrapers/open-vsx.ts +119 -0
  690. package/src/web/scrapers/opencorporates.ts +275 -0
  691. package/src/web/scrapers/openlibrary.ts +319 -0
  692. package/src/web/scrapers/orcid.ts +298 -0
  693. package/src/web/scrapers/osv.ts +192 -0
  694. package/src/web/scrapers/packagist.ts +174 -0
  695. package/src/web/scrapers/pub-dev.ts +185 -0
  696. package/src/web/scrapers/pubmed.ts +177 -0
  697. package/src/web/scrapers/pypi.ts +129 -0
  698. package/src/web/scrapers/rawg.ts +124 -0
  699. package/src/web/scrapers/readthedocs.ts +125 -0
  700. package/src/web/scrapers/reddit.ts +104 -0
  701. package/src/web/scrapers/repology.ts +262 -0
  702. package/src/web/scrapers/rfc.ts +209 -0
  703. package/src/web/scrapers/rubygems.ts +117 -0
  704. package/src/web/scrapers/searchcode.ts +217 -0
  705. package/src/web/scrapers/sec-edgar.ts +274 -0
  706. package/src/web/scrapers/semantic-scholar.ts +190 -0
  707. package/src/web/scrapers/snapcraft.ts +200 -0
  708. package/src/web/scrapers/sourcegraph.ts +373 -0
  709. package/src/web/scrapers/spdx.ts +121 -0
  710. package/src/web/scrapers/spotify.ts +217 -0
  711. package/src/web/scrapers/stackoverflow.ts +124 -0
  712. package/src/web/scrapers/terraform.ts +304 -0
  713. package/src/web/scrapers/tldr.ts +51 -0
  714. package/src/web/scrapers/twitter.ts +97 -0
  715. package/src/web/scrapers/types.ts +200 -0
  716. package/src/web/scrapers/utils.ts +142 -0
  717. package/src/web/scrapers/vimeo.ts +152 -0
  718. package/src/web/scrapers/vscode-marketplace.ts +195 -0
  719. package/src/web/scrapers/w3c.ts +163 -0
  720. package/src/web/scrapers/wikidata.ts +357 -0
  721. package/src/web/scrapers/wikipedia.ts +95 -0
  722. package/src/web/scrapers/youtube.ts +312 -0
  723. package/src/web/search/auth.ts +178 -0
  724. package/src/web/search/index.ts +598 -0
  725. package/src/web/search/provider.ts +77 -0
  726. package/src/web/search/providers/anthropic.ts +284 -0
  727. package/src/web/search/providers/base.ts +22 -0
  728. package/src/web/search/providers/brave.ts +165 -0
  729. package/src/web/search/providers/codex.ts +377 -0
  730. package/src/web/search/providers/exa.ts +158 -0
  731. package/src/web/search/providers/gemini.ts +437 -0
  732. package/src/web/search/providers/jina.ts +99 -0
  733. package/src/web/search/providers/kimi.ts +196 -0
  734. package/src/web/search/providers/perplexity.ts +546 -0
  735. package/src/web/search/providers/synthetic.ts +136 -0
  736. package/src/web/search/providers/zai.ts +352 -0
  737. package/src/web/search/render.ts +299 -0
  738. package/src/web/search/types.ts +437 -0
@@ -0,0 +1,526 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { logger } from "@nghyane/arcane-utils";
4
+ import { getProjectDir, getProjectPromptsDir, getPromptsDir } from "@nghyane/arcane-utils/dirs";
5
+ import Handlebars from "handlebars";
6
+ import { computeLineHash } from "../patch/hashline";
7
+ import { jtdToTypeScript } from "../tools/jtd-to-typescript";
8
+ import { parseFrontmatter } from "../utils/frontmatter";
9
+
10
+ /**
11
+ * Represents a prompt template loaded from a markdown file
12
+ */
13
+ export interface PromptTemplate {
14
+ name: string;
15
+ description: string;
16
+ content: string;
17
+ source: string; // e.g., "(user)", "(project)", "(project:frontend)"
18
+ }
19
+
20
+ export interface TemplateContext extends Record<string, unknown> {
21
+ args?: string[];
22
+ ARGUMENTS?: string;
23
+ arguments?: string;
24
+ }
25
+
26
+ const handlebars = Handlebars.create();
27
+
28
+ handlebars.registerHelper("arg", function (this: TemplateContext, index: number | string): string {
29
+ const args = this.args ?? [];
30
+ const parsedIndex = typeof index === "number" ? index : Number.parseInt(index, 10);
31
+ if (!Number.isFinite(parsedIndex)) return "";
32
+ const zeroBased = parsedIndex - 1;
33
+ if (zeroBased < 0) return "";
34
+ return args[zeroBased] ?? "";
35
+ });
36
+
37
+ /**
38
+ * {{#list items prefix="- " suffix="" join="\n"}}{{this}}{{/list}}
39
+ * Renders an array with customizable prefix, suffix, and join separator.
40
+ * Note: Use \n in join for newlines (will be unescaped automatically).
41
+ */
42
+ handlebars.registerHelper(
43
+ "list",
44
+ function (this: unknown, context: unknown[], options: Handlebars.HelperOptions): string {
45
+ if (!Array.isArray(context) || context.length === 0) return "";
46
+ const prefix = (options.hash.prefix as string) ?? "";
47
+ const suffix = (options.hash.suffix as string) ?? "";
48
+ const rawSeparator = (options.hash.join as string) ?? "\n";
49
+ const separator = rawSeparator.replace(/\\n/g, "\n").replace(/\\t/g, "\t");
50
+ return context.map(item => `${prefix}${options.fn(item)}${suffix}`).join(separator);
51
+ },
52
+ );
53
+
54
+ /**
55
+ * {{join array ", "}}
56
+ * Joins an array with a separator (default: ", ").
57
+ */
58
+ handlebars.registerHelper("join", (context: unknown[], separator?: unknown): string => {
59
+ if (!Array.isArray(context)) return "";
60
+ const sep = typeof separator === "string" ? separator : ", ";
61
+ return context.join(sep);
62
+ });
63
+
64
+ /**
65
+ * {{default value "fallback"}}
66
+ * Returns the value if truthy, otherwise returns the fallback.
67
+ */
68
+ handlebars.registerHelper("default", (value: unknown, defaultValue: unknown): unknown => value || defaultValue);
69
+
70
+ /**
71
+ * {{pluralize count "item" "items"}}
72
+ * Returns "1 item" or "5 items" based on count.
73
+ */
74
+ handlebars.registerHelper(
75
+ "pluralize",
76
+ (count: number, singular: string, plural: string): string => `${count} ${count === 1 ? singular : plural}`,
77
+ );
78
+
79
+ /**
80
+ * {{#when value "==" compare}}...{{else}}...{{/when}}
81
+ * Conditional block with comparison operators: ==, ===, !=, !==, >, <, >=, <=
82
+ */
83
+ handlebars.registerHelper(
84
+ "when",
85
+ function (this: unknown, lhs: unknown, operator: string, rhs: unknown, options: Handlebars.HelperOptions): string {
86
+ const ops: Record<string, (a: unknown, b: unknown) => boolean> = {
87
+ "==": (a, b) => a === b,
88
+ "===": (a, b) => a === b,
89
+ "!=": (a, b) => a !== b,
90
+ "!==": (a, b) => a !== b,
91
+ ">": (a, b) => (a as number) > (b as number),
92
+ "<": (a, b) => (a as number) < (b as number),
93
+ ">=": (a, b) => (a as number) >= (b as number),
94
+ "<=": (a, b) => (a as number) <= (b as number),
95
+ };
96
+ const fn = ops[operator];
97
+ if (!fn) return options.inverse(this);
98
+ return fn(lhs, rhs) ? options.fn(this) : options.inverse(this);
99
+ },
100
+ );
101
+
102
+ /**
103
+ * {{#ifAny a b c}}...{{else}}...{{/ifAny}}
104
+ * True if any argument is truthy.
105
+ */
106
+ handlebars.registerHelper("ifAny", function (this: unknown, ...args: unknown[]): string {
107
+ const options = args.pop() as Handlebars.HelperOptions;
108
+ return args.some(Boolean) ? options.fn(this) : options.inverse(this);
109
+ });
110
+
111
+ /**
112
+ * {{#ifAll a b c}}...{{else}}...{{/ifAll}}
113
+ * True if all arguments are truthy.
114
+ */
115
+ handlebars.registerHelper("ifAll", function (this: unknown, ...args: unknown[]): string {
116
+ const options = args.pop() as Handlebars.HelperOptions;
117
+ return args.every(Boolean) ? options.fn(this) : options.inverse(this);
118
+ });
119
+
120
+ /**
121
+ * {{#table rows headers="Col1|Col2"}}{{col1}}|{{col2}}{{/table}}
122
+ * Generates a markdown table from an array of objects.
123
+ */
124
+ handlebars.registerHelper(
125
+ "table",
126
+ function (this: unknown, context: unknown[], options: Handlebars.HelperOptions): string {
127
+ if (!Array.isArray(context) || context.length === 0) return "";
128
+ const headersStr = options.hash.headers as string | undefined;
129
+ const headers = headersStr?.split("|") ?? [];
130
+ const separator = headers.map(() => "---").join(" | ");
131
+ const headerRow = headers.length > 0 ? `| ${headers.join(" | ")} |\n| ${separator} |\n` : "";
132
+ const rows = context.map(item => `| ${options.fn(item).trim()} |`).join("\n");
133
+ return headerRow + rows;
134
+ },
135
+ );
136
+
137
+ /**
138
+ * {{#codeblock lang="diff"}}...{{/codeblock}}
139
+ * Wraps content in a fenced code block.
140
+ */
141
+ handlebars.registerHelper("codeblock", function (this: unknown, options: Handlebars.HelperOptions): string {
142
+ const lang = (options.hash.lang as string) ?? "";
143
+ const content = options.fn(this).trim();
144
+ return `\`\`\`${lang}\n${content}\n\`\`\``;
145
+ });
146
+
147
+ /**
148
+ * {{#xml "tag"}}content{{/xml}}
149
+ * Wraps content in XML-style tags. Returns empty string if content is empty.
150
+ */
151
+ handlebars.registerHelper("xml", function (this: unknown, tag: string, options: Handlebars.HelperOptions): string {
152
+ const content = options.fn(this).trim();
153
+ if (!content) return "";
154
+ return `<${tag}>\n${content}\n</${tag}>`;
155
+ });
156
+
157
+ /**
158
+ * {{escapeXml value}}
159
+ * Escapes XML special characters: & < > "
160
+ */
161
+ handlebars.registerHelper("escapeXml", (value: unknown): string => {
162
+ if (value == null) return "";
163
+ return String(value).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
164
+ });
165
+
166
+ /**
167
+ * {{len array}}
168
+ * Returns the length of an array or string.
169
+ */
170
+ handlebars.registerHelper("len", (value: unknown): number => {
171
+ if (Array.isArray(value)) return value.length;
172
+ if (typeof value === "string") return value.length;
173
+ return 0;
174
+ });
175
+
176
+ /**
177
+ * {{add a b}}
178
+ * Adds two numbers.
179
+ */
180
+ handlebars.registerHelper("add", (a: number, b: number): number => (a ?? 0) + (b ?? 0));
181
+
182
+ /**
183
+ * {{sub a b}}
184
+ * Subtracts b from a.
185
+ */
186
+ handlebars.registerHelper("sub", (a: number, b: number): number => (a ?? 0) - (b ?? 0));
187
+
188
+ /**
189
+ * {{#has collection item}}...{{else}}...{{/has}}
190
+ * Checks if an array includes an item or if a Set/Map has a key.
191
+ */
192
+ handlebars.registerHelper(
193
+ "has",
194
+ function (this: unknown, collection: unknown, item: unknown, options: Handlebars.HelperOptions): string {
195
+ let found = false;
196
+ if (Array.isArray(collection)) {
197
+ found = collection.includes(item);
198
+ } else if (collection instanceof Set) {
199
+ found = collection.has(item);
200
+ } else if (collection instanceof Map) {
201
+ found = collection.has(item);
202
+ } else if (collection && typeof collection === "object") {
203
+ if (typeof item === "string" || typeof item === "number" || typeof item === "symbol") {
204
+ found = item in collection;
205
+ }
206
+ }
207
+ return found ? options.fn(this) : options.inverse(this);
208
+ },
209
+ );
210
+
211
+ /**
212
+ * {{includes array item}}
213
+ * Returns true if array includes item. For use in other helpers.
214
+ */
215
+ handlebars.registerHelper("includes", (collection: unknown, item: unknown): boolean => {
216
+ if (Array.isArray(collection)) return collection.includes(item);
217
+ if (collection instanceof Set) return collection.has(item);
218
+ if (collection instanceof Map) return collection.has(item);
219
+ return false;
220
+ });
221
+
222
+ /**
223
+ * {{not value}}
224
+ * Returns logical NOT of value. For use in subexpressions.
225
+ */
226
+ handlebars.registerHelper("not", (value: unknown): boolean => !value);
227
+
228
+ handlebars.registerHelper("jtdToTypeScript", (schema: unknown): string => jtdToTypeScript(schema));
229
+
230
+ handlebars.registerHelper("jsonStringify", (value: unknown): string => JSON.stringify(value));
231
+
232
+ /**
233
+ * {{hlineref lineNum "content"}} — compute a real hashline ref for prompt examples.
234
+ * Returns `"lineNum#hash"` using the actual hash algorithm.
235
+ */
236
+ function formatHashlineRef(lineNum: unknown, content: unknown): { num: number; text: string; ref: string } {
237
+ const num = typeof lineNum === "number" ? lineNum : Number.parseInt(String(lineNum), 10);
238
+ const text = typeof content === "string" ? content : String(content ?? "");
239
+ const ref = `${num}#${computeLineHash(num, text)}`;
240
+ return { num, text, ref };
241
+ }
242
+
243
+ handlebars.registerHelper("hlineref", (lineNum: unknown, content: unknown): string => {
244
+ const { ref } = formatHashlineRef(lineNum, content);
245
+ return ref;
246
+ });
247
+
248
+ /**
249
+ * {{hlinefull lineNum "content"}} — format a full read-style line with prefix.
250
+ * Returns `"lineNum#hash:content"`.
251
+ */
252
+ handlebars.registerHelper("hlinefull", (lineNum: unknown, content: unknown): string => {
253
+ const { ref, text } = formatHashlineRef(lineNum, content);
254
+ return `${ref}:${text}`;
255
+ });
256
+
257
+ export function renderPromptTemplate(template: string, context: TemplateContext = {}): string {
258
+ const compiled = handlebars.compile(template, { noEscape: true, strict: false });
259
+ const rendered = compiled(context ?? {});
260
+ return optimizePromptLayout(rendered);
261
+ }
262
+
263
+ function optimizePromptLayout(input: string): string {
264
+ // 1) strip CR / normalize line endings
265
+ let s = input.replace(/\r\n?/g, "\n");
266
+
267
+ // normalize NBSP -> space
268
+ s = s.replace(/\u00A0/g, " ");
269
+
270
+ const lines = s.split("\n").map(line => {
271
+ // 2) remove trailing whitespace (spaces/tabs) per line
272
+ let l = line.replace(/[ \t]+$/g, "");
273
+
274
+ // 3) lines with only whitespace -> empty line
275
+ if (/^[ \t]*$/.test(l)) return "";
276
+
277
+ // 4) normalize leading indentation: every 2 spaces -> \t (preserve leftover 1 space)
278
+ // NOTE: This is intentionally *only* leading indentation to avoid mangling prose.
279
+ const m = l.match(/^[ \t]+/);
280
+ if (m) {
281
+ const indent = m[0];
282
+ const rest = l.slice(indent.length);
283
+
284
+ let out = "";
285
+ let spaces = 0;
286
+
287
+ for (const ch of indent) {
288
+ if (ch === "\t") {
289
+ // flush pending spaces before existing tab
290
+ out += "\t".repeat(Math.floor(spaces / 2));
291
+ if (spaces % 2) out += " ";
292
+ spaces = 0;
293
+ out += "\t";
294
+ } else {
295
+ spaces++;
296
+ }
297
+ }
298
+
299
+ out += "\t".repeat(Math.floor(spaces / 2));
300
+ if (spaces % 2) out += " ";
301
+
302
+ l = out + rest;
303
+ }
304
+
305
+ return l;
306
+ });
307
+
308
+ s = lines.join("\n");
309
+
310
+ // 5) collapse excessive blank lines
311
+ s = s.replace(/\n{3,}/g, "\n\n");
312
+
313
+ return s.trim();
314
+ }
315
+
316
+ /**
317
+ * Parse command arguments respecting quoted strings (bash-style)
318
+ * Returns array of arguments
319
+ */
320
+ export function parseCommandArgs(argsString: string): string[] {
321
+ const args: string[] = [];
322
+ let current = "";
323
+ let inQuote: string | null = null;
324
+
325
+ for (let i = 0; i < argsString.length; i++) {
326
+ const char = argsString[i];
327
+
328
+ if (inQuote) {
329
+ if (char === inQuote) {
330
+ inQuote = null;
331
+ } else {
332
+ current += char;
333
+ }
334
+ } else if (char === '"' || char === "'") {
335
+ inQuote = char;
336
+ } else if (char === " " || char === "\t") {
337
+ if (current) {
338
+ args.push(current);
339
+ current = "";
340
+ }
341
+ } else {
342
+ current += char;
343
+ }
344
+ }
345
+
346
+ if (current) {
347
+ args.push(current);
348
+ }
349
+
350
+ return args;
351
+ }
352
+
353
+ /**
354
+ * Substitute argument placeholders in template content
355
+ * Supports $1, $2, ... for positional args, $@ and $ARGUMENTS for all args
356
+ *
357
+ * Note: Replacement happens on the template string only. Argument values
358
+ * containing patterns like $1, $@, or $ARGUMENTS are NOT recursively substituted.
359
+ */
360
+ export function substituteArgs(content: string, args: string[]): string {
361
+ let result = content;
362
+
363
+ // Replace $1, $2, etc. with positional args FIRST (before wildcards)
364
+ // This prevents wildcard replacement values containing $<digit> patterns from being re-substituted
365
+ result = result.replace(/\$(\d+)/g, (_, num) => {
366
+ const index = parseInt(num, 10) - 1;
367
+ return args[index] ?? "";
368
+ });
369
+
370
+ result = result.replace(/\$@\[(\d+)(?::(\d*)?)?\]/g, (_, startRaw: string, lengthRaw?: string) => {
371
+ const start = Number.parseInt(startRaw, 10);
372
+ if (!Number.isFinite(start) || start < 1) return "";
373
+ const startIndex = start - 1;
374
+ if (startIndex >= args.length) return "";
375
+
376
+ if (lengthRaw === undefined || lengthRaw === "") {
377
+ return args.slice(startIndex).join(" ");
378
+ }
379
+
380
+ const length = Number.parseInt(lengthRaw, 10);
381
+ if (!Number.isFinite(length) || length <= 0) return "";
382
+ return args.slice(startIndex, startIndex + length).join(" ");
383
+ });
384
+
385
+ // Pre-compute all args joined (optimization)
386
+ const allArgs = args.join(" ");
387
+
388
+ // Replace $ARGUMENTS with all args joined (new syntax, aligns with Claude, Codex, OpenCode)
389
+ result = result.replace(/\$ARGUMENTS/g, allArgs);
390
+
391
+ // Replace $@ with all args joined (existing syntax)
392
+ result = result.replace(/\$@/g, allArgs);
393
+
394
+ return result;
395
+ }
396
+
397
+ /**
398
+ * Recursively scan a directory for .md files (and symlinks to .md files) and load them as prompt templates
399
+ */
400
+ async function loadTemplatesFromDir(
401
+ dir: string,
402
+ source: "user" | "project",
403
+ subdir: string = "",
404
+ ): Promise<PromptTemplate[]> {
405
+ const templates: PromptTemplate[] = [];
406
+ try {
407
+ const glob = new Bun.Glob("**/*");
408
+ const entries = [];
409
+ for await (const entry of glob.scan({ cwd: dir, absolute: false, onlyFiles: false })) {
410
+ entries.push(entry);
411
+ }
412
+
413
+ // Group by path depth to process directories before deeply nested files
414
+ entries.sort((a, b) => a.split("/").length - b.split("/").length);
415
+
416
+ for (const entry of entries) {
417
+ const fullPath = path.join(dir, entry);
418
+ const file = Bun.file(fullPath);
419
+
420
+ try {
421
+ const stat = await file.exists();
422
+ if (!stat) continue;
423
+
424
+ if (entry.endsWith(".md")) {
425
+ const rawContent = await file.text();
426
+ const { frontmatter, body } = parseFrontmatter(rawContent, { source: fullPath });
427
+
428
+ const name = entry.split("/").pop()!.slice(0, -3); // Remove .md extension
429
+
430
+ // Build source string based on subdirectory structure
431
+ const entryDir = entry.includes("/") ? entry.split("/").slice(0, -1).join(":") : "";
432
+ const fullSubdir = subdir && entryDir ? `${subdir}:${entryDir}` : entryDir || subdir;
433
+
434
+ let sourceStr: string;
435
+ if (source === "user") {
436
+ sourceStr = fullSubdir ? `(user:${fullSubdir})` : "(user)";
437
+ } else {
438
+ sourceStr = fullSubdir ? `(project:${fullSubdir})` : "(project)";
439
+ }
440
+
441
+ // Get description from frontmatter or first non-empty line
442
+ let description = String(frontmatter.description || "");
443
+ if (!description) {
444
+ const firstLine = body.split("\n").find(line => line.trim());
445
+ if (firstLine) {
446
+ // Truncate if too long
447
+ description = firstLine.slice(0, 60);
448
+ if (firstLine.length > 60) description += "...";
449
+ }
450
+ }
451
+
452
+ // Append source to description
453
+ description = description ? `${description} ${sourceStr}` : sourceStr;
454
+
455
+ templates.push({
456
+ name,
457
+ description,
458
+ content: body,
459
+ source: sourceStr,
460
+ });
461
+ }
462
+ } catch (error) {
463
+ logger.warn("Failed to load prompt template", { path: fullPath, error: String(error) });
464
+ }
465
+ }
466
+ } catch (error) {
467
+ if (!fs.existsSync(dir)) {
468
+ return [];
469
+ }
470
+ logger.warn("Failed to scan prompt templates directory", { dir, error: String(error) });
471
+ }
472
+
473
+ return templates;
474
+ }
475
+
476
+ export interface LoadPromptTemplatesOptions {
477
+ /** Working directory for project-local templates. Default: getProjectDir() */
478
+ cwd?: string;
479
+ /** Agent config directory for global templates. Default: from getPromptsDir() */
480
+ agentDir?: string;
481
+ }
482
+
483
+ /**
484
+ * Load all prompt templates from:
485
+ * 1. Global: agentDir/prompts/
486
+ * 2. Project: cwd/.arcane/prompts/
487
+ */
488
+ export async function loadPromptTemplates(options: LoadPromptTemplatesOptions = {}): Promise<PromptTemplate[]> {
489
+ const resolvedCwd = options.cwd ?? getProjectDir();
490
+ const resolvedAgentDir = options.agentDir ?? getPromptsDir();
491
+
492
+ const templates: PromptTemplate[] = [];
493
+
494
+ // 1. Load global templates from agentDir/prompts/
495
+ // Note: if agentDir is provided, it should be the agent dir, not the prompts dir
496
+ const globalPromptsDir = options.agentDir ? path.join(options.agentDir, "prompts") : resolvedAgentDir;
497
+ templates.push(...(await loadTemplatesFromDir(globalPromptsDir, "user")));
498
+
499
+ // 2. Load project templates from cwd/.arcane/prompts/
500
+ const projectPromptsDir = getProjectPromptsDir(resolvedCwd);
501
+ templates.push(...(await loadTemplatesFromDir(projectPromptsDir, "project")));
502
+
503
+ return templates;
504
+ }
505
+
506
+ /**
507
+ * Expand a prompt template if it matches a template name.
508
+ * Returns the expanded content or the original text if not a template.
509
+ */
510
+ export function expandPromptTemplate(text: string, templates: PromptTemplate[]): string {
511
+ if (!text.startsWith("/")) return text;
512
+
513
+ const spaceIndex = text.indexOf(" ");
514
+ const templateName = spaceIndex === -1 ? text.slice(1) : text.slice(1, spaceIndex);
515
+ const argsString = spaceIndex === -1 ? "" : text.slice(spaceIndex + 1);
516
+
517
+ const template = templates.find(t => t.name === templateName);
518
+ if (template) {
519
+ const args = parseCommandArgs(argsString);
520
+ const argsText = args.join(" ");
521
+ const substituted = substituteArgs(template.content, args);
522
+ return renderPromptTemplate(substituted, { args, ARGUMENTS: argsText, arguments: argsText });
523
+ }
524
+
525
+ return text;
526
+ }
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Resolve configuration values that may be shell commands, environment variables, or literals.
3
+ *
4
+ * Note: command execution is async to avoid blocking the TUI.
5
+ */
6
+
7
+ import { executeShell } from "@nghyane/arcane-natives";
8
+
9
+ /** Cache for successful shell command results (persists for process lifetime). */
10
+ const commandResultCache = new Map<string, string>();
11
+
12
+ /** De-duplicates concurrent executions for the same command. */
13
+ const commandInFlight = new Map<string, Promise<string | undefined>>();
14
+
15
+ /**
16
+ * Resolve a config value (API key, header value, etc.) to an actual value.
17
+ * - If starts with "!", executes the rest as a shell command and uses stdout (cached)
18
+ * - Otherwise checks environment variable first, then treats as literal (not cached)
19
+ */
20
+ export async function resolveConfigValue(config: string): Promise<string | undefined> {
21
+ if (config.startsWith("!")) {
22
+ return await executeCommand(config);
23
+ }
24
+ const envValue = process.env[config];
25
+ return envValue || config;
26
+ }
27
+
28
+ async function executeCommand(commandConfig: string): Promise<string | undefined> {
29
+ const cached = commandResultCache.get(commandConfig);
30
+ if (cached !== undefined) {
31
+ return cached;
32
+ }
33
+
34
+ const existing = commandInFlight.get(commandConfig);
35
+ if (existing) {
36
+ return await existing;
37
+ }
38
+
39
+ const command = commandConfig.slice(1);
40
+ const promise = runShellCommand(command, 10_000)
41
+ .then(result => {
42
+ if (result !== undefined) {
43
+ commandResultCache.set(commandConfig, result);
44
+ }
45
+ return result;
46
+ })
47
+ .finally(() => {
48
+ commandInFlight.delete(commandConfig);
49
+ });
50
+
51
+ commandInFlight.set(commandConfig, promise);
52
+ return await promise;
53
+ }
54
+
55
+ async function runShellCommand(command: string, timeoutMs: number): Promise<string | undefined> {
56
+ try {
57
+ let output = "";
58
+ const result = await executeShell({ command, timeoutMs }, chunk => {
59
+ output += chunk;
60
+ });
61
+ if (result.timedOut || result.exitCode !== 0) {
62
+ return undefined;
63
+ }
64
+ const trimmed = output.trim();
65
+ return trimmed.length > 0 ? trimmed : undefined;
66
+ } catch {
67
+ return undefined;
68
+ }
69
+ }
70
+
71
+ /**
72
+ * Resolve all header values using the same resolution logic as API keys.
73
+ */
74
+ export async function resolveHeaders(
75
+ headers: Record<string, string> | undefined,
76
+ ): Promise<Record<string, string> | undefined> {
77
+ if (!headers) return undefined;
78
+ const resolved: Record<string, string> = {};
79
+ for (const [key, value] of Object.entries(headers)) {
80
+ const resolvedValue = await resolveConfigValue(value);
81
+ if (resolvedValue) {
82
+ resolved[key] = resolvedValue;
83
+ }
84
+ }
85
+ return Object.keys(resolved).length > 0 ? resolved : undefined;
86
+ }
87
+
88
+ /** Clear the config value command cache. Exported for testing. */
89
+ export function clearConfigValueCache(): void {
90
+ commandResultCache.clear();
91
+ commandInFlight.clear();
92
+ }