@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,384 @@
1
+ /**
2
+ * Auto-read file mentions from user prompts.
3
+ *
4
+ * When users reference files with @path syntax (e.g., "@src/foo.ts"),
5
+ * we automatically inject the file contents as a FileMentionMessage
6
+ * so the agent doesn't need to read them manually.
7
+ */
8
+ import * as fs from "node:fs/promises";
9
+ import path from "node:path";
10
+ import type { AgentMessage } from "@nghyane/arcane-agent";
11
+ import { glob } from "@nghyane/arcane-natives";
12
+ import { formatHashLines } from "../patch/hashline";
13
+ import type { FileMentionMessage } from "../session/messages";
14
+ import {
15
+ DEFAULT_MAX_BYTES,
16
+ formatBytes,
17
+ truncateHead,
18
+ truncateStringToBytesFromStart,
19
+ } from "../session/streaming-output";
20
+ import { resolveReadPath } from "../tools/path-utils";
21
+ import { formatAge } from "../tools/render-utils";
22
+ import { fuzzyMatch } from "./fuzzy";
23
+ import { formatDimensionNote, resizeImage } from "./image-resize";
24
+ import { detectSupportedImageMimeTypeFromFile } from "./mime";
25
+
26
+ /** Regex to match @filepath patterns in text */
27
+ const FILE_MENTION_REGEX = /@([^\s@]+)/g;
28
+ const LEADING_PUNCTUATION_REGEX = /^[`"'([{<]+/;
29
+ const TRAILING_PUNCTUATION_REGEX = /[)\]}>.,;:!?"'`]+$/;
30
+ const MENTION_BOUNDARY_REGEX = /[\s([{<"'`]/;
31
+ const DEFAULT_DIR_LIMIT = 500;
32
+ const MIN_FUZZY_QUERY_LENGTH = 5;
33
+ const MAX_RESOLUTION_CANDIDATES = 20_000;
34
+ const PATH_SEPARATOR_REGEX = /[/._\-\s]+/g;
35
+
36
+ type MentionDiscoveryProfile = {
37
+ hidden: boolean;
38
+ gitignore: boolean;
39
+ includeNodeModules: boolean;
40
+ maxResults: number;
41
+ cache: boolean;
42
+ };
43
+
44
+ function getMentionCandidateDiscoveryProfile(): MentionDiscoveryProfile {
45
+ return {
46
+ hidden: true,
47
+ gitignore: true,
48
+ cache: true,
49
+ includeNodeModules: true,
50
+ maxResults: MAX_RESOLUTION_CANDIDATES,
51
+ };
52
+ }
53
+
54
+ // Avoid OOM when users @mention very large files. Above these limits we skip
55
+ // auto-reading and only include the path in the message.
56
+ const MAX_AUTO_READ_TEXT_BYTES = 5 * 1024 * 1024; // 5MB
57
+ const MAX_AUTO_READ_IMAGE_BYTES = 25 * 1024 * 1024; // 25MB
58
+
59
+ function isMentionBoundary(text: string, index: number): boolean {
60
+ if (index === 0) return true;
61
+ return MENTION_BOUNDARY_REGEX.test(text[index - 1]);
62
+ }
63
+
64
+ function sanitizeMentionPath(rawPath: string): string | null {
65
+ let cleaned = rawPath.trim();
66
+ cleaned = cleaned.replace(LEADING_PUNCTUATION_REGEX, "");
67
+ cleaned = cleaned.replace(TRAILING_PUNCTUATION_REGEX, "");
68
+ cleaned = cleaned.trim();
69
+ return cleaned.length > 0 ? cleaned : null;
70
+ }
71
+
72
+ type MentionCandidate = {
73
+ path: string;
74
+ pathLower: string;
75
+ normalizedPath: string;
76
+ };
77
+
78
+ function normalizeMentionQuery(query: string): string {
79
+ return query.toLowerCase().replace(PATH_SEPARATOR_REGEX, "");
80
+ }
81
+
82
+ async function pathExists(filePath: string): Promise<boolean> {
83
+ try {
84
+ await Bun.file(filePath).stat();
85
+ return true;
86
+ } catch {
87
+ return false;
88
+ }
89
+ }
90
+
91
+ async function listMentionCandidates(cwd: string): Promise<MentionCandidate[]> {
92
+ let entries: string[];
93
+ try {
94
+ const discoveryProfile = getMentionCandidateDiscoveryProfile();
95
+ const result = await glob({
96
+ pattern: "**/*",
97
+ path: cwd,
98
+ ...discoveryProfile,
99
+ });
100
+ entries = result.matches.map(match => match.path);
101
+ } catch {
102
+ return [];
103
+ }
104
+
105
+ entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
106
+ const candidates: MentionCandidate[] = [];
107
+ for (const entry of entries) {
108
+ const pathLower = entry.toLowerCase();
109
+ const normalizedPath = normalizeMentionQuery(entry);
110
+ if (normalizedPath.length === 0) {
111
+ continue;
112
+ }
113
+ candidates.push({ path: entry, pathLower, normalizedPath });
114
+ }
115
+ return candidates;
116
+ }
117
+
118
+ async function resolveMentionPath(
119
+ filePath: string,
120
+ cwd: string,
121
+ getMentionCandidates: () => Promise<MentionCandidate[]>,
122
+ ): Promise<string | null> {
123
+ const absolutePath = resolveReadPath(filePath, cwd);
124
+ if (await pathExists(absolutePath)) {
125
+ return filePath;
126
+ }
127
+
128
+ const queryLower = filePath.toLowerCase();
129
+ const candidates = await getMentionCandidates();
130
+ const prefixMatches = candidates.filter(candidate => candidate.pathLower.startsWith(queryLower));
131
+ if (prefixMatches.length === 1) {
132
+ return prefixMatches[0]?.path ?? null;
133
+ }
134
+ if (prefixMatches.length > 1) {
135
+ return null;
136
+ }
137
+
138
+ const normalizedQuery = normalizeMentionQuery(filePath);
139
+ if (normalizedQuery.length < MIN_FUZZY_QUERY_LENGTH) {
140
+ return null;
141
+ }
142
+
143
+ const scored = candidates
144
+ .map(candidate => ({ candidate, match: fuzzyMatch(normalizedQuery, candidate.normalizedPath) }))
145
+ .filter(entry => entry.match.matches)
146
+ .sort((a, b) => {
147
+ if (a.match.score !== b.match.score) {
148
+ return a.match.score - b.match.score;
149
+ }
150
+ return a.candidate.path.localeCompare(b.candidate.path);
151
+ });
152
+
153
+ if (scored.length === 0) {
154
+ return null;
155
+ }
156
+
157
+ const best = scored[0];
158
+
159
+ return best?.candidate.path ?? null;
160
+ }
161
+
162
+ function buildTextOutput(textContent: string): { output: string; lineCount: number } {
163
+ const allLines = textContent.split("\n");
164
+ const totalFileLines = allLines.length;
165
+ const truncation = truncateHead(textContent);
166
+
167
+ if (truncation.firstLineExceedsLimit) {
168
+ const firstLine = allLines[0] ?? "";
169
+ const firstLineBytes = Buffer.byteLength(firstLine, "utf-8");
170
+ const snippet = truncateStringToBytesFromStart(firstLine, DEFAULT_MAX_BYTES);
171
+ let outputText = snippet.text;
172
+
173
+ if (outputText.length > 0) {
174
+ outputText += `\n\n[Line 1 is ${formatBytes(firstLineBytes)}, exceeds ${formatBytes(
175
+ DEFAULT_MAX_BYTES,
176
+ )} limit. Showing first ${formatBytes(snippet.bytes)} of the line.]`;
177
+ } else {
178
+ outputText = `[Line 1 is ${formatBytes(firstLineBytes)}, exceeds ${formatBytes(
179
+ DEFAULT_MAX_BYTES,
180
+ )} limit. Unable to display a valid UTF-8 snippet.]`;
181
+ }
182
+
183
+ return { output: outputText, lineCount: totalFileLines };
184
+ }
185
+
186
+ let outputText = truncation.content;
187
+
188
+ if (truncation.truncated) {
189
+ const endLineDisplay = truncation.outputLines;
190
+ const nextOffset = endLineDisplay + 1;
191
+
192
+ if (truncation.truncatedBy === "lines") {
193
+ outputText += `\n\n[Showing lines 1-${endLineDisplay} of ${totalFileLines}. Use offset=${nextOffset} to continue]`;
194
+ } else {
195
+ outputText += `\n\n[Showing lines 1-${endLineDisplay} of ${totalFileLines} (${formatBytes(
196
+ DEFAULT_MAX_BYTES,
197
+ )} limit). Use offset=${nextOffset} to continue]`;
198
+ }
199
+ }
200
+
201
+ return { output: outputText, lineCount: totalFileLines };
202
+ }
203
+
204
+ async function buildDirectoryListing(absolutePath: string): Promise<{ output: string; lineCount: number }> {
205
+ let entries: string[];
206
+ try {
207
+ entries = await Array.fromAsync(new Bun.Glob("*").scan({ cwd: absolutePath, dot: true, onlyFiles: false }));
208
+ } catch {
209
+ return { output: "(empty directory)", lineCount: 1 };
210
+ }
211
+
212
+ entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
213
+
214
+ const results: string[] = [];
215
+ let entryLimitReached = false;
216
+
217
+ for (const entry of entries) {
218
+ if (results.length >= DEFAULT_DIR_LIMIT) {
219
+ entryLimitReached = true;
220
+ break;
221
+ }
222
+
223
+ const fullPath = path.join(absolutePath, entry);
224
+ let suffix = "";
225
+ let age = "";
226
+
227
+ try {
228
+ const stat = await Bun.file(fullPath).stat();
229
+ if (stat.isDirectory()) {
230
+ suffix = "/";
231
+ }
232
+ const ageSeconds = Math.floor((Date.now() - stat.mtimeMs) / 1000);
233
+ age = formatAge(ageSeconds);
234
+ } catch {
235
+ continue;
236
+ }
237
+
238
+ const line = age ? `${entry}${suffix} (${age})` : `${entry}${suffix}`;
239
+ results.push(line);
240
+ }
241
+
242
+ if (results.length === 0) {
243
+ return { output: "(empty directory)", lineCount: 1 };
244
+ }
245
+
246
+ const rawOutput = results.join("\n");
247
+ const truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });
248
+ let output = truncation.content;
249
+
250
+ const notices: string[] = [];
251
+ if (entryLimitReached) {
252
+ notices.push(`${DEFAULT_DIR_LIMIT} entries limit reached. Use limit=${DEFAULT_DIR_LIMIT * 2} for more`);
253
+ }
254
+ if (truncation.truncated) {
255
+ notices.push(`${formatBytes(DEFAULT_MAX_BYTES)} limit reached`);
256
+ }
257
+ if (notices.length > 0) {
258
+ output += `\n\n[${notices.join(". ")}]`;
259
+ }
260
+
261
+ return { output, lineCount: output.split("\n").length };
262
+ }
263
+
264
+ /** Extract all @filepath mentions from text */
265
+ export function extractFileMentions(text: string): string[] {
266
+ const matches = [...text.matchAll(FILE_MENTION_REGEX)];
267
+ const mentions: string[] = [];
268
+
269
+ for (const match of matches) {
270
+ const index = match.index ?? 0;
271
+ if (!isMentionBoundary(text, index)) continue;
272
+
273
+ const cleaned = sanitizeMentionPath(match[1]);
274
+ if (!cleaned) continue;
275
+
276
+ mentions.push(cleaned);
277
+ }
278
+
279
+ return [...new Set(mentions)];
280
+ }
281
+
282
+ /**
283
+ * Generate a FileMentionMessage containing the contents of mentioned files.
284
+ * Returns empty array if no files could be read.
285
+ */
286
+ export async function generateFileMentionMessages(
287
+ filePaths: string[],
288
+ cwd: string,
289
+ options?: { autoResizeImages?: boolean; useHashLines?: boolean },
290
+ ): Promise<AgentMessage[]> {
291
+ if (filePaths.length === 0) return [];
292
+
293
+ const autoResizeImages = options?.autoResizeImages ?? true;
294
+
295
+ const files: FileMentionMessage["files"] = [];
296
+ let mentionCandidatesPromise: Promise<MentionCandidate[]> | null = null;
297
+ const getMentionCandidates = (): Promise<MentionCandidate[]> => {
298
+ mentionCandidatesPromise ??= listMentionCandidates(cwd);
299
+ return mentionCandidatesPromise;
300
+ };
301
+
302
+ for (const filePath of filePaths) {
303
+ const resolvedPath = await resolveMentionPath(filePath, cwd, getMentionCandidates);
304
+ if (!resolvedPath) {
305
+ continue;
306
+ }
307
+ const absolutePath = resolveReadPath(resolvedPath, cwd);
308
+ try {
309
+ const stat = await Bun.file(absolutePath).stat();
310
+ if (stat.isDirectory()) {
311
+ const { output, lineCount } = await buildDirectoryListing(absolutePath);
312
+ files.push({ path: resolvedPath, content: output, lineCount });
313
+ continue;
314
+ }
315
+
316
+ const mimeType = await detectSupportedImageMimeTypeFromFile(absolutePath);
317
+ if (mimeType) {
318
+ if (stat.size > MAX_AUTO_READ_IMAGE_BYTES) {
319
+ files.push({
320
+ path: resolvedPath,
321
+ content: `(skipped auto-read: too large, ${formatBytes(stat.size)})`,
322
+ byteSize: stat.size,
323
+ skippedReason: "tooLarge",
324
+ });
325
+ continue;
326
+ }
327
+ const buffer = await fs.readFile(absolutePath);
328
+ if (buffer.length === 0) {
329
+ continue;
330
+ }
331
+
332
+ const base64Content = buffer.toBase64();
333
+ let image = { type: "image" as const, mimeType, data: base64Content };
334
+ let dimensionNote: string | undefined;
335
+
336
+ if (autoResizeImages) {
337
+ try {
338
+ const resized = await resizeImage({ type: "image", data: base64Content, mimeType });
339
+ dimensionNote = formatDimensionNote(resized);
340
+ image = {
341
+ type: "image" as const,
342
+ mimeType: resized.mimeType,
343
+ data: resized.data,
344
+ };
345
+ } catch {
346
+ image = { type: "image" as const, mimeType, data: base64Content };
347
+ }
348
+ }
349
+
350
+ files.push({ path: resolvedPath, content: dimensionNote ?? "", image });
351
+ continue;
352
+ }
353
+
354
+ if (stat.size > MAX_AUTO_READ_TEXT_BYTES) {
355
+ files.push({
356
+ path: resolvedPath,
357
+ content: `(skipped auto-read: too large, ${formatBytes(stat.size)})`,
358
+ byteSize: stat.size,
359
+ skippedReason: "tooLarge",
360
+ });
361
+ continue;
362
+ }
363
+
364
+ const content = await Bun.file(absolutePath).text();
365
+ let { output, lineCount } = buildTextOutput(content);
366
+ if (options?.useHashLines) {
367
+ output = formatHashLines(output);
368
+ }
369
+ files.push({ path: resolvedPath, content: output, lineCount });
370
+ } catch {
371
+ // File doesn't exist or isn't readable - skip silently
372
+ }
373
+ }
374
+
375
+ if (files.length === 0) return [];
376
+
377
+ const message: FileMentionMessage = {
378
+ role: "fileMention",
379
+ files,
380
+ timestamp: Date.now(),
381
+ };
382
+
383
+ return [message];
384
+ }
@@ -0,0 +1,101 @@
1
+ import { logger } from "@nghyane/arcane-utils";
2
+ import { YAML } from "bun";
3
+
4
+ function stripHtmlComments(content: string): string {
5
+ return content.replace(/<!--[\s\S]*?-->/g, "");
6
+ }
7
+
8
+ function toError(value: unknown): Error {
9
+ return value instanceof Error ? value : new Error(String(`YAML: ${value}`));
10
+ }
11
+
12
+ function truncate(content: string, maxLength: number): string {
13
+ return content.length > maxLength ? `${content.slice(0, maxLength)}…` : content;
14
+ }
15
+
16
+ export class FrontmatterError extends Error {
17
+ constructor(
18
+ error: Error,
19
+ readonly source?: unknown,
20
+ ) {
21
+ super(`Failed to parse YAML frontmatter (${source}): ${error.message}`, { cause: error });
22
+ this.name = "FrontmatterError";
23
+ }
24
+
25
+ toString(): string {
26
+ // Format the error with stack and detail, including the error message, stack, and source if present
27
+ const details: string[] = [this.message];
28
+ if (this.source !== undefined) {
29
+ details.push(`Source: ${JSON.stringify(this.source)}`);
30
+ }
31
+ if (this.cause && typeof this.cause === "object" && "stack" in this.cause && this.cause.stack) {
32
+ details.push(`Stack:\n${this.cause.stack}`);
33
+ } else if (this.stack) {
34
+ details.push(`Stack:\n${this.stack}`);
35
+ }
36
+ return details.join("\n\n");
37
+ }
38
+ }
39
+
40
+ export interface FrontmatterOptions {
41
+ /** Source of the content (alias: source) */
42
+ location?: unknown;
43
+ /** Source of the content (alias for location) */
44
+ source?: unknown;
45
+ /** Fallback frontmatter values */
46
+ fallback?: Record<string, unknown>;
47
+ /** Normalize the content */
48
+ normalize?: boolean;
49
+ /** Level of error handling */
50
+ level?: "off" | "warn" | "fatal";
51
+ }
52
+
53
+ /**
54
+ * Parse YAML frontmatter from markdown content
55
+ * Returns { frontmatter, body } where body has frontmatter stripped
56
+ */
57
+ export function parseFrontmatter(
58
+ content: string,
59
+ options?: FrontmatterOptions,
60
+ ): { frontmatter: Record<string, unknown>; body: string } {
61
+ const { location, source, fallback, normalize = true, level = "warn" } = options ?? {};
62
+ const loc = location ?? source;
63
+ const frontmatter: Record<string, unknown> = Object.assign({}, fallback);
64
+
65
+ const normalized = normalize ? stripHtmlComments(content.replace(/\r\n/g, "\n").replace(/\r/g, "\n")) : content;
66
+ if (!normalized.startsWith("---")) {
67
+ return { frontmatter, body: normalized };
68
+ }
69
+
70
+ const endIndex = normalized.indexOf("\n---", 3);
71
+ if (endIndex === -1) {
72
+ return { frontmatter, body: normalized };
73
+ }
74
+
75
+ const metadata = normalized.slice(4, endIndex);
76
+ const body = normalized.slice(endIndex + 4).trim();
77
+
78
+ try {
79
+ // Replace tabs with spaces for YAML compatibility, use failsafe mode for robustness
80
+ const loaded = YAML.parse(metadata.replaceAll("\t", " ")) as Record<string, unknown> | null;
81
+ return { frontmatter: Object.assign(frontmatter, loaded), body: body };
82
+ } catch (error) {
83
+ const err = new FrontmatterError(toError(error), loc ?? `Inline '${truncate(content, 64)}'`);
84
+ if (level === "warn" || level === "fatal") {
85
+ logger.warn("Failed to parse YAML frontmatter", { err: err.toString() });
86
+ }
87
+ if (level === "fatal") {
88
+ throw err;
89
+ }
90
+
91
+ // Simple YAML parsing - just key: value pairs
92
+ for (const line of metadata.split("\n")) {
93
+ const match = line.match(/^(\w+):\s*(.*)$/);
94
+ if (match) {
95
+ frontmatter[match[1]] = match[2].trim();
96
+ }
97
+ }
98
+
99
+ return { frontmatter, body: body };
100
+ }
101
+ }
@@ -0,0 +1,108 @@
1
+ // Fuzzy search. Matches if all query characters appear in order (not necessarily consecutive).
2
+ // Lower score = better match.
3
+
4
+ export interface FuzzyMatch {
5
+ matches: boolean;
6
+ score: number;
7
+ }
8
+
9
+ export function fuzzyMatch(query: string, text: string): FuzzyMatch {
10
+ const queryLower = query.toLowerCase();
11
+ const textLower = text.toLowerCase();
12
+
13
+ if (queryLower.length === 0) {
14
+ return { matches: true, score: 0 };
15
+ }
16
+
17
+ if (queryLower.length > textLower.length) {
18
+ return { matches: false, score: 0 };
19
+ }
20
+
21
+ let queryIndex = 0;
22
+ let score = 0;
23
+ let lastMatchIndex = -1;
24
+ let consecutiveMatches = 0;
25
+
26
+ for (let i = 0; i < textLower.length && queryIndex < queryLower.length; i++) {
27
+ if (textLower[i] === queryLower[queryIndex]) {
28
+ const isWordBoundary = i === 0 || /[\s\-_./]/.test(textLower[i - 1]!);
29
+
30
+ // Reward consecutive character matches (e.g., typing "foo" matches "foobar" better than "f_o_o")
31
+ if (lastMatchIndex === i - 1) {
32
+ consecutiveMatches++;
33
+ score -= consecutiveMatches * 5;
34
+ } else {
35
+ consecutiveMatches = 0;
36
+ // Penalize gaps between matched characters
37
+ if (lastMatchIndex >= 0) {
38
+ score += (i - lastMatchIndex - 1) * 2;
39
+ }
40
+ }
41
+
42
+ // Reward matches at word boundaries (start of words are more likely intentional targets)
43
+ if (isWordBoundary) {
44
+ score -= 10;
45
+ }
46
+
47
+ // Slight penalty for matches later in the string (prefer earlier matches)
48
+ score += i * 0.1;
49
+
50
+ lastMatchIndex = i;
51
+ queryIndex++;
52
+ }
53
+ }
54
+
55
+ // Not all query characters were found in order
56
+ if (queryIndex < queryLower.length) {
57
+ return { matches: false, score: 0 };
58
+ }
59
+
60
+ return { matches: true, score };
61
+ }
62
+
63
+ // Filter and sort items by fuzzy match quality (best matches first)
64
+ // Supports space-separated tokens: all tokens must match, sorted by match count then score
65
+ export function fuzzyFilter<T>(items: T[], query: string, getText: (item: T) => string): T[] {
66
+ if (!query.trim()) {
67
+ return items;
68
+ }
69
+
70
+ // Split query into tokens
71
+ const tokens = query
72
+ .trim()
73
+ .split(/\s+/)
74
+ .filter(t => t.length > 0);
75
+
76
+ if (tokens.length === 0) {
77
+ return items;
78
+ }
79
+
80
+ const results: { item: T; totalScore: number }[] = [];
81
+
82
+ for (const item of items) {
83
+ const text = getText(item);
84
+ let totalScore = 0;
85
+ let allMatch = true;
86
+
87
+ // Check each token against the text - ALL must match
88
+ for (const token of tokens) {
89
+ const match = fuzzyMatch(token, text);
90
+ if (match.matches) {
91
+ totalScore += match.score;
92
+ } else {
93
+ allMatch = false;
94
+ break;
95
+ }
96
+ }
97
+
98
+ // Only include if all tokens match
99
+ if (allMatch) {
100
+ results.push({ item, totalScore });
101
+ }
102
+ }
103
+
104
+ // Sort by score (asc, lower is better)
105
+ results.sort((a, b) => a.totalScore - b.totalScore);
106
+
107
+ return results.map(r => r.item);
108
+ }
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Ignore file handling for .gitignore/.ignore/.fdignore support when scanning directories.
3
+ */
4
+ import * as path from "node:path";
5
+ import ignore from "ignore";
6
+
7
+ export const IGNORE_FILE_NAMES = [".gitignore", ".ignore", ".fdignore"] as const;
8
+
9
+ export type IgnoreMatcher = ignore.Ignore;
10
+
11
+ /**
12
+ * Convert a path to POSIX format (forward slashes).
13
+ */
14
+ export function toPosixPath(p: string): string {
15
+ return p.split(path.sep).join("/");
16
+ }
17
+
18
+ /**
19
+ * Prefix an ignore pattern to make it relative to a subdirectory.
20
+ * Returns null for comments and empty lines.
21
+ */
22
+ export function prefixIgnorePattern(line: string, prefix: string): string | null {
23
+ const trimmed = line.trim();
24
+ if (!trimmed) return null;
25
+ if (trimmed.startsWith("#") && !trimmed.startsWith("\\#")) return null;
26
+
27
+ let pattern = line;
28
+ let negated = false;
29
+
30
+ if (pattern.startsWith("!")) {
31
+ negated = true;
32
+ pattern = pattern.slice(1);
33
+ } else if (pattern.startsWith("\\!")) {
34
+ pattern = pattern.slice(1);
35
+ }
36
+
37
+ if (pattern.startsWith("/")) {
38
+ pattern = pattern.slice(1);
39
+ }
40
+
41
+ const prefixed = prefix ? `${prefix}${pattern}` : pattern;
42
+ return negated ? `!${prefixed}` : prefixed;
43
+ }
44
+
45
+ /**
46
+ * Read and add ignore rules from a directory to the matcher.
47
+ */
48
+ export async function addIgnoreRules(
49
+ ig: IgnoreMatcher,
50
+ dir: string,
51
+ rootDir: string,
52
+ readFile: (path: string) => Promise<string | null>,
53
+ ): Promise<void> {
54
+ const relativeDir = path.relative(rootDir, dir);
55
+ const prefix = relativeDir ? `${toPosixPath(relativeDir)}/` : "";
56
+
57
+ for (const filename of IGNORE_FILE_NAMES) {
58
+ const ignorePath = path.join(dir, filename);
59
+ const content = await readFile(ignorePath);
60
+ if (!content) continue;
61
+
62
+ const patterns = content
63
+ .split(/\r?\n/)
64
+ .map(line => prefixIgnorePattern(line, prefix))
65
+ .filter((line): line is string => Boolean(line));
66
+
67
+ if (patterns.length > 0) {
68
+ ig.add(patterns);
69
+ }
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Read and add ignore rules from a directory to the matcher (synchronous version).
75
+ */
76
+ export function addIgnoreRulesSync(
77
+ ig: IgnoreMatcher,
78
+ dir: string,
79
+ rootDir: string,
80
+ readFileSync: (path: string) => string | null,
81
+ ): void {
82
+ const relativeDir = path.relative(rootDir, dir);
83
+ const prefix = relativeDir ? `${toPosixPath(relativeDir)}/` : "";
84
+
85
+ for (const filename of IGNORE_FILE_NAMES) {
86
+ const ignorePath = path.join(dir, filename);
87
+ const content = readFileSync(ignorePath);
88
+ if (!content) continue;
89
+
90
+ const patterns = content
91
+ .split(/\r?\n/)
92
+ .map(line => prefixIgnorePattern(line, prefix))
93
+ .filter((line): line is string => Boolean(line));
94
+
95
+ if (patterns.length > 0) {
96
+ ig.add(patterns);
97
+ }
98
+ }
99
+ }
100
+
101
+ /**
102
+ * Create a fresh ignore matcher.
103
+ */
104
+ export function createIgnoreMatcher(): IgnoreMatcher {
105
+ return ignore();
106
+ }
107
+
108
+ /**
109
+ * Check if a path should be ignored.
110
+ * @param ig - The ignore matcher
111
+ * @param root - The root directory for relative path calculation
112
+ * @param fullPath - The full path to check
113
+ * @param isDir - Whether the path is a directory
114
+ */
115
+ export function shouldIgnore(ig: IgnoreMatcher, root: string, fullPath: string, isDir: boolean): boolean {
116
+ const relPath = toPosixPath(path.relative(root, fullPath));
117
+ const ignorePath = isDir ? `${relPath}/` : relPath;
118
+ return ig.ignores(ignorePath);
119
+ }