@nghyane/arcane 0.1.12 → 0.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (333) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/package.json +21 -70
  3. package/scripts/format-prompts.ts +1 -3
  4. package/src/cli/args.ts +2 -7
  5. package/src/cli/config-cli.ts +1 -1
  6. package/src/cli/plugin-cli.ts +1 -1
  7. package/src/cli/setup-cli.ts +1 -1
  8. package/src/cli/update-cli.ts +1 -1
  9. package/src/cli/web-search-cli.ts +1 -1
  10. package/src/cli.ts +0 -1
  11. package/src/commands/config.ts +1 -1
  12. package/src/commands/grep.ts +1 -1
  13. package/src/commands/jupyter.ts +1 -1
  14. package/src/commands/plugin.ts +1 -1
  15. package/src/commands/setup.ts +1 -1
  16. package/src/commands/shell.ts +1 -1
  17. package/src/commands/ssh.ts +1 -1
  18. package/src/commands/stats.ts +1 -1
  19. package/src/commands/update.ts +1 -1
  20. package/src/config/model-registry.ts +3 -4
  21. package/src/config/model-resolver.ts +36 -9
  22. package/src/config/prompt-templates.ts +1 -9
  23. package/src/config/settings-schema.ts +32 -88
  24. package/src/config/settings.ts +3 -4
  25. package/src/debug/index.ts +1 -1
  26. package/src/debug/log-formatting.ts +1 -1
  27. package/src/debug/log-viewer.ts +2 -2
  28. package/src/discovery/helpers.ts +13 -3
  29. package/src/exa/company.ts +2 -7
  30. package/src/exa/index.ts +1 -35
  31. package/src/exa/linkedin.ts +2 -7
  32. package/src/exa/mcp-client.ts +21 -11
  33. package/src/exa/render.ts +30 -190
  34. package/src/exa/researcher.ts +2 -12
  35. package/src/exa/search.ts +5 -25
  36. package/src/exa/types.ts +3 -3
  37. package/src/exec/bash-executor.ts +2 -1
  38. package/src/exec/non-interactive-env.ts +43 -0
  39. package/src/export/html/index.ts +1 -1
  40. package/src/extensibility/custom-tools/loader.ts +1 -1
  41. package/src/extensibility/custom-tools/types.ts +5 -1
  42. package/src/extensibility/custom-tools/wrapper.ts +1 -1
  43. package/src/extensibility/extensions/runner.ts +1 -1
  44. package/src/extensibility/extensions/types.ts +1 -1
  45. package/src/extensibility/extensions/wrapper.ts +7 -15
  46. package/src/extensibility/hooks/runner.ts +1 -1
  47. package/src/extensibility/hooks/types.ts +1 -1
  48. package/src/extensibility/plugins/doctor.ts +1 -1
  49. package/src/index.ts +13 -13
  50. package/src/lsp/index.ts +77 -24
  51. package/src/lsp/render.ts +34 -583
  52. package/src/lsp/types.ts +3 -3
  53. package/src/lsp/utils.ts +1 -1
  54. package/src/main.ts +1 -1
  55. package/src/mcp/tool-bridge.ts +1 -24
  56. package/src/modes/components/assistant-message.ts +7 -7
  57. package/src/modes/components/bash-execution.ts +48 -113
  58. package/src/modes/components/bordered-loader.ts +1 -1
  59. package/src/modes/components/branch-summary-message.ts +13 -10
  60. package/src/modes/components/compaction-summary-message.ts +14 -13
  61. package/src/modes/components/context-group.ts +106 -0
  62. package/src/modes/components/custom-message.ts +4 -5
  63. package/src/modes/components/diff.ts +2 -2
  64. package/src/modes/components/dynamic-border.ts +1 -1
  65. package/src/modes/components/extensions/extension-dashboard.ts +2 -2
  66. package/src/modes/components/extensions/extension-list.ts +1 -1
  67. package/src/modes/components/extensions/inspector-panel.ts +8 -3
  68. package/src/modes/components/footer.ts +2 -2
  69. package/src/modes/components/history-search.ts +1 -1
  70. package/src/modes/components/hook-editor.ts +1 -1
  71. package/src/modes/components/hook-input.ts +1 -1
  72. package/src/modes/components/hook-message.ts +4 -5
  73. package/src/modes/components/hook-selector.ts +1 -1
  74. package/src/modes/components/index.ts +0 -2
  75. package/src/modes/components/keybinding-hints.ts +1 -1
  76. package/src/modes/components/login-dialog.ts +1 -1
  77. package/src/modes/components/mcp-add-wizard.ts +1 -1
  78. package/src/modes/components/model-selector.ts +1 -1
  79. package/src/modes/components/oauth-selector.ts +1 -1
  80. package/src/modes/components/plugin-settings.ts +1 -1
  81. package/src/modes/components/python-execution.ts +49 -92
  82. package/src/modes/components/queue-mode-selector.ts +1 -1
  83. package/src/modes/components/session-selector.ts +1 -1
  84. package/src/modes/components/settings-defs.ts +5 -10
  85. package/src/modes/components/settings-selector.ts +1 -1
  86. package/src/modes/components/show-images-selector.ts +1 -1
  87. package/src/modes/components/skill-message.ts +4 -4
  88. package/src/modes/components/status-line/segments.ts +2 -2
  89. package/src/modes/components/status-line/separators.ts +1 -1
  90. package/src/modes/components/status-line-segment-editor.ts +1 -1
  91. package/src/modes/components/status-line.ts +1 -1
  92. package/src/modes/components/theme-selector.ts +1 -1
  93. package/src/modes/components/thinking-selector.ts +1 -1
  94. package/src/modes/components/todo-display.ts +2 -4
  95. package/src/modes/components/todo-reminder.ts +4 -4
  96. package/src/modes/components/tool-execution.ts +118 -440
  97. package/src/modes/components/tool-image-display.ts +107 -0
  98. package/src/modes/components/tree-selector.ts +2 -2
  99. package/src/modes/components/ttsr-notification.ts +4 -17
  100. package/src/modes/components/user-message-selector.ts +1 -1
  101. package/src/modes/components/user-message.ts +9 -10
  102. package/src/modes/components/welcome.ts +1 -1
  103. package/src/modes/controllers/command-controller.ts +1 -1
  104. package/src/modes/controllers/event-controller.ts +58 -187
  105. package/src/modes/controllers/extension-ui-controller.ts +1 -1
  106. package/src/modes/controllers/input-controller.ts +3 -1
  107. package/src/modes/controllers/mcp-command-controller.ts +1 -1
  108. package/src/modes/controllers/selector-controller.ts +3 -26
  109. package/src/modes/controllers/ssh-command-controller.ts +1 -1
  110. package/src/modes/interactive-mode.ts +3 -7
  111. package/src/modes/print-mode.ts +5 -5
  112. package/src/modes/rpc/rpc-mode.ts +1 -1
  113. package/src/modes/types.ts +1 -2
  114. package/src/modes/utils/ui-helpers.ts +34 -32
  115. package/src/patch/edit-tool.ts +742 -0
  116. package/src/patch/index.ts +32 -898
  117. package/src/patch/schemas.ts +208 -0
  118. package/src/patch/shared.ts +83 -151
  119. package/src/prompts/agents/explore.md +22 -37
  120. package/src/prompts/agents/frontmatter.md +1 -1
  121. package/src/prompts/agents/init.md +2 -2
  122. package/src/prompts/agents/librarian.md +30 -21
  123. package/src/prompts/agents/oracle.md +9 -2
  124. package/src/prompts/agents/reviewer.md +15 -49
  125. package/src/prompts/agents/task.md +17 -9
  126. package/src/prompts/compaction/branch-summary-context.md +1 -1
  127. package/src/prompts/compaction/branch-summary-preamble.md +1 -1
  128. package/src/prompts/compaction/branch-summary.md +4 -1
  129. package/src/prompts/compaction/compaction-short-summary.md +1 -1
  130. package/src/prompts/compaction/compaction-summary-context.md +1 -1
  131. package/src/prompts/compaction/compaction-summary.md +4 -1
  132. package/src/prompts/compaction/compaction-turn-prefix.md +1 -1
  133. package/src/prompts/compaction/compaction-update-summary.md +1 -1
  134. package/src/prompts/memories/consolidation.md +1 -1
  135. package/src/prompts/memories/read_path.md +1 -1
  136. package/src/prompts/memories/stage_one_input.md +1 -1
  137. package/src/prompts/memories/stage_one_system.md +1 -1
  138. package/src/prompts/review-request.md +1 -1
  139. package/src/prompts/system/agent-creation-architect.md +1 -1
  140. package/src/prompts/system/agent-creation-user.md +1 -1
  141. package/src/prompts/system/custom-system-prompt.md +1 -1
  142. package/src/prompts/system/file-operations.md +1 -1
  143. package/src/prompts/system/subagent-system-prompt.md +2 -2
  144. package/src/prompts/system/summarization-system.md +1 -1
  145. package/src/prompts/system/system-prompt.md +163 -178
  146. package/src/prompts/system/title-system.md +1 -1
  147. package/src/prompts/system/ttsr-interrupt.md +1 -1
  148. package/src/prompts/system/verification-reminder.md +6 -0
  149. package/src/prompts/system/web-search.md +1 -1
  150. package/src/sdk.ts +0 -9
  151. package/src/session/agent-session.ts +244 -1459
  152. package/src/session/auth-storage.ts +5 -0
  153. package/src/session/model-controller.ts +406 -0
  154. package/src/session/retry-utils.ts +71 -0
  155. package/src/session/session-manager.ts +22 -186
  156. package/src/session/session-types.ts +312 -0
  157. package/src/session/stats.ts +387 -0
  158. package/src/session/streaming-edit.ts +258 -0
  159. package/src/session/ttsr.ts +213 -0
  160. package/src/slash-commands/builtin-registry.ts +0 -8
  161. package/src/ssh/connection-manager.ts +1 -0
  162. package/src/stt/recorder.ts +2 -2
  163. package/src/system-prompt.ts +1 -14
  164. package/src/task/agents.ts +7 -33
  165. package/src/task/executor.ts +50 -438
  166. package/src/task/index.ts +104 -71
  167. package/src/task/progress-tracker.ts +390 -0
  168. package/src/task/render.ts +371 -187
  169. package/src/task/subprocess-tool-registry.ts +1 -1
  170. package/src/task/types.ts +14 -47
  171. package/src/tools/ask.ts +31 -42
  172. package/src/tools/bash-interactive.ts +4 -47
  173. package/src/tools/bash-interceptor.ts +2 -2
  174. package/src/tools/bash-normalize.ts +1 -1
  175. package/src/tools/bash-skill-urls.ts +2 -2
  176. package/src/tools/bash.ts +87 -136
  177. package/src/tools/browser.ts +54 -84
  178. package/src/tools/create-tools.ts +186 -0
  179. package/src/tools/default-renderer.ts +104 -0
  180. package/src/tools/explore.ts +11 -10
  181. package/src/tools/fetch.ts +24 -114
  182. package/src/tools/find.ts +48 -132
  183. package/src/tools/gemini-image.ts +5 -15
  184. package/src/tools/github.ts +450 -0
  185. package/src/tools/grep.ts +43 -179
  186. package/src/tools/index.ts +35 -198
  187. package/src/tools/json-tree.ts +3 -3
  188. package/src/tools/librarian.ts +18 -18
  189. package/src/tools/list-limit.ts +2 -2
  190. package/src/tools/notebook.ts +35 -87
  191. package/src/tools/oracle.ts +25 -25
  192. package/src/tools/output-meta.ts +89 -4
  193. package/src/tools/output-utils.ts +2 -2
  194. package/src/tools/python.ts +86 -637
  195. package/src/tools/read.ts +36 -119
  196. package/src/tools/reviewer-tool.ts +19 -21
  197. package/src/tools/search-code.ts +128 -0
  198. package/src/tools/ssh.ts +67 -126
  199. package/src/tools/subagent-tool.ts +197 -123
  200. package/src/tools/todo-write.ts +15 -31
  201. package/src/tools/tool-errors.ts +0 -30
  202. package/src/tools/undo-edit.ts +30 -67
  203. package/src/tools/write.ts +78 -127
  204. package/src/tui/code-cell.ts +4 -4
  205. package/src/tui/file-list.ts +2 -2
  206. package/src/tui/output-block.ts +1 -1
  207. package/src/tui/status-line.ts +1 -1
  208. package/src/tui/tree-list.ts +2 -2
  209. package/src/tui/types.ts +1 -1
  210. package/src/tui/utils.ts +1 -1
  211. package/src/{tools → ui}/render-utils.ts +87 -126
  212. package/src/utils/external-editor.ts +4 -4
  213. package/src/utils/file-mentions.ts +1 -1
  214. package/src/utils/index.ts +30 -0
  215. package/src/utils/tools-manager.ts +9 -19
  216. package/src/web/github-client.ts +290 -0
  217. package/src/web/scrapers/github.ts +11 -62
  218. package/src/web/search/auth.ts +1 -3
  219. package/src/web/search/index.ts +85 -49
  220. package/src/web/search/provider.ts +11 -16
  221. package/src/web/search/providers/grep.ts +160 -0
  222. package/src/web/search/render.ts +48 -235
  223. package/src/web/search/types.ts +1 -1
  224. package/src/commands/commit.ts +0 -36
  225. package/src/commit/agentic/agent.ts +0 -311
  226. package/src/commit/agentic/fallback.ts +0 -96
  227. package/src/commit/agentic/index.ts +0 -359
  228. package/src/commit/agentic/prompts/analyze-file.md +0 -22
  229. package/src/commit/agentic/prompts/session-user.md +0 -25
  230. package/src/commit/agentic/prompts/split-confirm.md +0 -1
  231. package/src/commit/agentic/prompts/system.md +0 -38
  232. package/src/commit/agentic/state.ts +0 -69
  233. package/src/commit/agentic/tools/analyze-file.ts +0 -118
  234. package/src/commit/agentic/tools/git-file-diff.ts +0 -194
  235. package/src/commit/agentic/tools/git-hunk.ts +0 -50
  236. package/src/commit/agentic/tools/git-overview.ts +0 -84
  237. package/src/commit/agentic/tools/index.ts +0 -56
  238. package/src/commit/agentic/tools/propose-changelog.ts +0 -128
  239. package/src/commit/agentic/tools/propose-commit.ts +0 -154
  240. package/src/commit/agentic/tools/recent-commits.ts +0 -81
  241. package/src/commit/agentic/tools/split-commit.ts +0 -280
  242. package/src/commit/agentic/topo-sort.ts +0 -44
  243. package/src/commit/agentic/trivial.ts +0 -51
  244. package/src/commit/agentic/validation.ts +0 -200
  245. package/src/commit/analysis/conventional.ts +0 -165
  246. package/src/commit/analysis/index.ts +0 -4
  247. package/src/commit/analysis/scope.ts +0 -242
  248. package/src/commit/analysis/summary.ts +0 -112
  249. package/src/commit/analysis/validation.ts +0 -66
  250. package/src/commit/changelog/detect.ts +0 -37
  251. package/src/commit/changelog/generate.ts +0 -110
  252. package/src/commit/changelog/index.ts +0 -234
  253. package/src/commit/changelog/parse.ts +0 -44
  254. package/src/commit/cli.ts +0 -93
  255. package/src/commit/git/diff.ts +0 -148
  256. package/src/commit/git/errors.ts +0 -9
  257. package/src/commit/git/index.ts +0 -211
  258. package/src/commit/git/operations.ts +0 -54
  259. package/src/commit/index.ts +0 -5
  260. package/src/commit/map-reduce/index.ts +0 -64
  261. package/src/commit/map-reduce/map-phase.ts +0 -178
  262. package/src/commit/map-reduce/reduce-phase.ts +0 -145
  263. package/src/commit/map-reduce/utils.ts +0 -9
  264. package/src/commit/message.ts +0 -11
  265. package/src/commit/model-selection.ts +0 -69
  266. package/src/commit/pipeline.ts +0 -243
  267. package/src/commit/prompts/analysis-system.md +0 -148
  268. package/src/commit/prompts/analysis-user.md +0 -38
  269. package/src/commit/prompts/changelog-system.md +0 -50
  270. package/src/commit/prompts/changelog-user.md +0 -18
  271. package/src/commit/prompts/file-observer-system.md +0 -24
  272. package/src/commit/prompts/file-observer-user.md +0 -8
  273. package/src/commit/prompts/reduce-system.md +0 -50
  274. package/src/commit/prompts/reduce-user.md +0 -17
  275. package/src/commit/prompts/summary-retry.md +0 -3
  276. package/src/commit/prompts/summary-system.md +0 -38
  277. package/src/commit/prompts/summary-user.md +0 -13
  278. package/src/commit/prompts/types-description.md +0 -2
  279. package/src/commit/types.ts +0 -109
  280. package/src/commit/utils/exclusions.ts +0 -42
  281. package/src/mcp/render.ts +0 -123
  282. package/src/modes/components/agent-dashboard.ts +0 -1130
  283. package/src/modes/components/codemode-group.ts +0 -369
  284. package/src/modes/components/read-tool-group.ts +0 -119
  285. package/src/modes/components/visual-truncate.ts +0 -63
  286. package/src/prompts/system/subagent-user-prompt.md +0 -8
  287. package/src/prompts/tools/ask.md +0 -44
  288. package/src/prompts/tools/bash.md +0 -24
  289. package/src/prompts/tools/browser.md +0 -33
  290. package/src/prompts/tools/calculator.md +0 -12
  291. package/src/prompts/tools/explore.md +0 -29
  292. package/src/prompts/tools/fetch.md +0 -16
  293. package/src/prompts/tools/find.md +0 -18
  294. package/src/prompts/tools/gemini-image.md +0 -23
  295. package/src/prompts/tools/grep.md +0 -28
  296. package/src/prompts/tools/hashline.md +0 -232
  297. package/src/prompts/tools/librarian.md +0 -24
  298. package/src/prompts/tools/lsp.md +0 -28
  299. package/src/prompts/tools/oracle.md +0 -26
  300. package/src/prompts/tools/patch.md +0 -74
  301. package/src/prompts/tools/python.md +0 -66
  302. package/src/prompts/tools/read.md +0 -36
  303. package/src/prompts/tools/replace.md +0 -38
  304. package/src/prompts/tools/reviewer.md +0 -41
  305. package/src/prompts/tools/ssh.md +0 -51
  306. package/src/prompts/tools/task-summary.md +0 -28
  307. package/src/prompts/tools/task.md +0 -146
  308. package/src/prompts/tools/todo-write.md +0 -65
  309. package/src/prompts/tools/undo-edit.md +0 -7
  310. package/src/prompts/tools/web-search.md +0 -19
  311. package/src/prompts/tools/write.md +0 -18
  312. package/src/task/batch.ts +0 -102
  313. package/src/task/discovery.ts +0 -126
  314. package/src/task/parallel.ts +0 -84
  315. package/src/task/template.ts +0 -32
  316. package/src/tools/calculator.ts +0 -537
  317. package/src/tools/jtd-to-typescript.ts +0 -198
  318. package/src/tools/renderers.ts +0 -60
  319. package/src/tools/tool-result.ts +0 -86
  320. /package/src/{modes/theme → theme}/dark.json +0 -0
  321. /package/src/{modes/theme → theme}/defaults/dark-catppuccin.json +0 -0
  322. /package/src/{modes/theme → theme}/defaults/dark-dracula.json +0 -0
  323. /package/src/{modes/theme → theme}/defaults/dark-gruvbox.json +0 -0
  324. /package/src/{modes/theme → theme}/defaults/dark-solarized.json +0 -0
  325. /package/src/{modes/theme → theme}/defaults/dark-tokyo-night.json +0 -0
  326. /package/src/{modes/theme → theme}/defaults/index.ts +0 -0
  327. /package/src/{modes/theme → theme}/defaults/light-catppuccin.json +0 -0
  328. /package/src/{modes/theme → theme}/defaults/light-github.json +0 -0
  329. /package/src/{modes/theme → theme}/defaults/light-solarized.json +0 -0
  330. /package/src/{modes/theme → theme}/light.json +0 -0
  331. /package/src/{modes/theme → theme}/mermaid-cache.ts +0 -0
  332. /package/src/{modes/theme → theme}/theme-schema.json +0 -0
  333. /package/src/{modes/theme → theme}/theme.ts +0 -0
@@ -1,145 +0,0 @@
1
- import type { Api, AssistantMessage, Model, ToolCall } from "@nghyane/arcane-ai";
2
- import { completeSimple, validateToolCall } from "@nghyane/arcane-ai";
3
- import { Type } from "@sinclair/typebox";
4
- import reduceSystemPrompt from "../../commit/prompts/reduce-system.md" with { type: "text" };
5
- import reduceUserPrompt from "../../commit/prompts/reduce-user.md" with { type: "text" };
6
- import type { ChangelogCategory, ConventionalAnalysis, FileObservation } from "../../commit/types";
7
- import { renderPromptTemplate } from "../../config/prompt-templates";
8
-
9
- const ReduceTool = {
10
- name: "create_conventional_analysis",
11
- description: "Synthesize file observations into a conventional commit analysis.",
12
- parameters: Type.Object({
13
- type: Type.Union([
14
- Type.Literal("feat"),
15
- Type.Literal("fix"),
16
- Type.Literal("refactor"),
17
- Type.Literal("docs"),
18
- Type.Literal("test"),
19
- Type.Literal("chore"),
20
- Type.Literal("style"),
21
- Type.Literal("perf"),
22
- Type.Literal("build"),
23
- Type.Literal("ci"),
24
- Type.Literal("revert"),
25
- ]),
26
- scope: Type.Union([Type.String(), Type.Null()]),
27
- details: Type.Array(
28
- Type.Object({
29
- text: Type.String(),
30
- changelog_category: Type.Optional(
31
- Type.Union([
32
- Type.Literal("Added"),
33
- Type.Literal("Changed"),
34
- Type.Literal("Fixed"),
35
- Type.Literal("Deprecated"),
36
- Type.Literal("Removed"),
37
- Type.Literal("Security"),
38
- Type.Literal("Breaking Changes"),
39
- ]),
40
- ),
41
- user_visible: Type.Optional(Type.Boolean()),
42
- }),
43
- ),
44
- issue_refs: Type.Array(Type.String()),
45
- }),
46
- };
47
-
48
- export interface ReducePhaseInput {
49
- model: Model<Api>;
50
- apiKey: string;
51
- observations: FileObservation[];
52
- stat: string;
53
- scopeCandidates: string;
54
- typesDescription?: string;
55
- }
56
-
57
- export async function runReducePhase({
58
- model,
59
- apiKey,
60
- observations,
61
- stat,
62
- scopeCandidates,
63
- typesDescription,
64
- }: ReducePhaseInput): Promise<ConventionalAnalysis> {
65
- const prompt = renderPromptTemplate(reduceUserPrompt, {
66
- types_description: typesDescription,
67
- observations: observations.flatMap(obs => obs.observations.map(line => `- ${obs.file}: ${line}`)).join("\n"),
68
- stat,
69
- scope_candidates: scopeCandidates,
70
- });
71
- const response = await completeSimple(
72
- model,
73
- {
74
- systemPrompt: renderPromptTemplate(reduceSystemPrompt),
75
- messages: [{ role: "user", content: prompt, timestamp: Date.now() }],
76
- tools: [ReduceTool],
77
- },
78
- { apiKey, maxTokens: 2400 },
79
- );
80
-
81
- return parseAnalysisResponse(response);
82
- }
83
-
84
- function parseAnalysisResponse(message: AssistantMessage): ConventionalAnalysis {
85
- const toolCall = extractToolCall(message, "create_conventional_analysis");
86
- if (toolCall) {
87
- const parsed = validateToolCall([ReduceTool], toolCall) as {
88
- type: ConventionalAnalysis["type"];
89
- scope: string | null;
90
- details: Array<{ text: string; changelog_category?: ChangelogCategory; user_visible?: boolean }>;
91
- issue_refs: string[];
92
- };
93
- return normalizeAnalysis(parsed);
94
- }
95
- const text = extractTextContent(message);
96
- const parsed = parseJsonPayload(text) as {
97
- type: ConventionalAnalysis["type"];
98
- scope: string | null;
99
- details: Array<{ text: string; changelog_category?: ChangelogCategory; user_visible?: boolean }>;
100
- issue_refs: string[];
101
- };
102
- return normalizeAnalysis(parsed);
103
- }
104
-
105
- function parseJsonPayload(text: string): unknown {
106
- const trimmed = text.trim();
107
- if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
108
- return JSON.parse(trimmed) as unknown;
109
- }
110
- const match = trimmed.match(/\{[\s\S]*\}/);
111
- if (!match) {
112
- throw new Error("No JSON payload found in reduce response");
113
- }
114
- return JSON.parse(match[0]) as unknown;
115
- }
116
-
117
- function normalizeAnalysis(parsed: {
118
- type: ConventionalAnalysis["type"];
119
- scope: string | null;
120
- details: Array<{ text: string; changelog_category?: ChangelogCategory; user_visible?: boolean }>;
121
- issue_refs: string[];
122
- }): ConventionalAnalysis {
123
- return {
124
- type: parsed.type,
125
- scope: parsed.scope?.trim() || null,
126
- details: parsed.details.map(detail => ({
127
- text: detail.text.trim(),
128
- changelogCategory: detail.user_visible ? detail.changelog_category : undefined,
129
- userVisible: detail.user_visible ?? false,
130
- })),
131
- issueRefs: parsed.issue_refs ?? [],
132
- };
133
- }
134
-
135
- function extractToolCall(message: AssistantMessage, name: string): ToolCall | undefined {
136
- return message.content.find(content => content.type === "toolCall" && content.name === name) as ToolCall | undefined;
137
- }
138
-
139
- function extractTextContent(message: AssistantMessage): string {
140
- return message.content
141
- .filter(content => content.type === "text")
142
- .map(content => content.text)
143
- .join("")
144
- .trim();
145
- }
@@ -1,9 +0,0 @@
1
- export function estimateTokens(text: string): number {
2
- return Math.ceil(text.length / 4);
3
- }
4
-
5
- export function truncateToTokenLimit(text: string, maxTokens: number): string {
6
- const maxChars = maxTokens * 4;
7
- if (text.length <= maxChars) return text;
8
- return `${text.slice(0, maxChars)}\n... (truncated)`;
9
- }
@@ -1,11 +0,0 @@
1
- import type { ConventionalAnalysis } from "./types";
2
-
3
- export function formatCommitMessage(analysis: ConventionalAnalysis, summary: string): string {
4
- const scopePart = analysis.scope ? `(${analysis.scope})` : "";
5
- const header = `${analysis.type}${scopePart}: ${summary}`;
6
- const bodyLines = analysis.details.map(detail => `- ${detail.text.trim()}`);
7
- if (bodyLines.length === 0) {
8
- return header;
9
- }
10
- return `${header}\n\n${bodyLines.join("\n")}`;
11
- }
@@ -1,69 +0,0 @@
1
- import type { Api, Model } from "@nghyane/arcane-ai";
2
- import { MODEL_ROLE_IDS } from "../config/model-registry";
3
- import {
4
- expandRoleAlias,
5
- parseModelPattern,
6
- resolveModelFromSettings,
7
- resolveModelFromString,
8
- } from "../config/model-resolver";
9
- import type { Settings } from "../config/settings";
10
- import MODEL_PRIO from "../priority.json" with { type: "json" };
11
-
12
- export async function resolvePrimaryModel(
13
- override: string | undefined,
14
- settings: Settings,
15
- modelRegistry: {
16
- getAvailable: () => Model<Api>[];
17
- getApiKey: (model: Model<Api>) => Promise<string | undefined>;
18
- },
19
- ): Promise<{ model: Model<Api>; apiKey: string }> {
20
- const available = modelRegistry.getAvailable();
21
- const matchPreferences = { usageOrder: settings.getStorage()?.getModelUsageOrder() };
22
- const roleOrder = ["commit", "fast", ...MODEL_ROLE_IDS] as const;
23
- const model = override
24
- ? resolveModelFromString(expandRoleAlias(override, settings), available, matchPreferences)
25
- : resolveModelFromSettings({
26
- settings,
27
- availableModels: available,
28
- matchPreferences,
29
- roleOrder,
30
- });
31
- if (!model) {
32
- throw new Error("No model available for commit generation");
33
- }
34
- const apiKey = await modelRegistry.getApiKey(model);
35
- if (!apiKey) {
36
- throw new Error(`No API key available for model ${model.provider}/${model.id}`);
37
- }
38
- return { model, apiKey };
39
- }
40
-
41
- export async function resolveFastModel(
42
- settings: Settings,
43
- modelRegistry: {
44
- getAvailable: () => Model<Api>[];
45
- getApiKey: (model: Model<Api>) => Promise<string | undefined>;
46
- },
47
- fallbackModel: Model<Api>,
48
- fallbackApiKey: string,
49
- ): Promise<{ model: Model<Api>; apiKey: string }> {
50
- const available = modelRegistry.getAvailable();
51
- const matchPreferences = { usageOrder: settings.getStorage()?.getModelUsageOrder() };
52
- const role = settings.getModelRole("fast");
53
- const roleModel = role
54
- ? resolveModelFromString(expandRoleAlias(role, settings), available, matchPreferences)
55
- : undefined;
56
- if (roleModel) {
57
- const apiKey = await modelRegistry.getApiKey(roleModel);
58
- if (apiKey) return { model: roleModel, apiKey };
59
- }
60
-
61
- for (const pattern of MODEL_PRIO.fast) {
62
- const candidate = parseModelPattern(pattern, available, matchPreferences).model;
63
- if (!candidate) continue;
64
- const apiKey = await modelRegistry.getApiKey(candidate);
65
- if (apiKey) return { model: candidate, apiKey };
66
- }
67
-
68
- return { model: fallbackModel, apiKey: fallbackApiKey };
69
- }
@@ -1,243 +0,0 @@
1
- import * as path from "node:path";
2
- import type { Api, Model } from "@nghyane/arcane-ai";
3
- import { logger } from "@nghyane/arcane-utils";
4
- import { getProjectDir } from "@nghyane/arcane-utils/dirs";
5
- import { ModelRegistry } from "../config/model-registry";
6
- import { renderPromptTemplate } from "../config/prompt-templates";
7
- import { Settings } from "../config/settings";
8
- import { discoverAuthStorage } from "../sdk";
9
- import { loadProjectContextFiles } from "../system-prompt";
10
- import { runAgenticCommit } from "./agentic";
11
- import {
12
- extractScopeCandidates,
13
- generateConventionalAnalysis,
14
- generateSummary,
15
- validateAnalysis,
16
- validateSummary,
17
- } from "./analysis";
18
- import { runChangelogFlow } from "./changelog";
19
- import { ControlledGit } from "./git";
20
- import { runMapReduceAnalysis, shouldUseMapReduce } from "./map-reduce";
21
- import { formatCommitMessage } from "./message";
22
- import { resolveFastModel, resolvePrimaryModel } from "./model-selection";
23
- import summaryRetryPrompt from "./prompts/summary-retry.md" with { type: "text" };
24
- import typesDescriptionPrompt from "./prompts/types-description.md" with { type: "text" };
25
- import type { CommitCommandArgs, ConventionalAnalysis } from "./types";
26
-
27
- const SUMMARY_MAX_CHARS = 72;
28
- const RECENT_COMMITS_COUNT = 8;
29
- const TYPES_DESCRIPTION = renderPromptTemplate(typesDescriptionPrompt);
30
-
31
- /**
32
- * Execute the arcane commit pipeline for staged changes.
33
- */
34
- export async function runCommitCommand(args: CommitCommandArgs): Promise<void> {
35
- if (args.legacy) {
36
- return runLegacyCommitCommand(args);
37
- }
38
- return runAgenticCommit(args);
39
- }
40
-
41
- async function runLegacyCommitCommand(args: CommitCommandArgs): Promise<void> {
42
- const cwd = getProjectDir();
43
- const settings = await Settings.init();
44
- const commitSettings = settings.getGroup("commit");
45
- const authStorage = await discoverAuthStorage();
46
- const modelRegistry = new ModelRegistry(authStorage);
47
- await modelRegistry.refresh();
48
-
49
- const { model: primaryModel, apiKey: primaryApiKey } = await resolvePrimaryModel(
50
- args.model,
51
- settings,
52
- modelRegistry,
53
- );
54
- const { model: fastModel, apiKey: fastApiKey } = await resolveFastModel(
55
- settings,
56
- modelRegistry,
57
- primaryModel,
58
- primaryApiKey,
59
- );
60
-
61
- const git = new ControlledGit(cwd);
62
- let stagedFiles = await git.getStagedFiles();
63
- if (stagedFiles.length === 0) {
64
- writeStdout("No staged changes detected, staging all changes...");
65
- await git.stageAll();
66
- stagedFiles = await git.getStagedFiles();
67
- }
68
- if (stagedFiles.length === 0) {
69
- writeStderr("No changes to commit.");
70
- return;
71
- }
72
-
73
- if (!args.noChangelog) {
74
- await runChangelogFlow({
75
- git,
76
- cwd,
77
- model: primaryModel,
78
- apiKey: primaryApiKey,
79
- stagedFiles,
80
- dryRun: args.dryRun,
81
- maxDiffChars: commitSettings.changelogMaxDiffChars,
82
- });
83
- }
84
-
85
- const diff = await git.getDiff(true);
86
- const stat = await git.getStat(true);
87
- const numstat = await git.getNumstat(true);
88
- const scopeCandidates = extractScopeCandidates(numstat).scopeCandidates;
89
- const recentCommits = await git.getRecentCommits(RECENT_COMMITS_COUNT);
90
- const contextFiles = await loadProjectContextFiles({ cwd });
91
- const formattedContextFiles = contextFiles.map(file => ({
92
- path: path.relative(cwd, file.path),
93
- content: file.content,
94
- }));
95
-
96
- const analysis = await generateAnalysis({
97
- diff,
98
- stat,
99
- scopeCandidates,
100
- recentCommits,
101
- contextFiles: formattedContextFiles,
102
- userContext: args.context,
103
- primaryModel,
104
- primaryApiKey,
105
- fastModel,
106
- fastApiKey,
107
- commitSettings,
108
- });
109
-
110
- const analysisValidation = validateAnalysis(analysis);
111
- if (!analysisValidation.valid) {
112
- logger.warn("commit analysis validation failed", { errors: analysisValidation.errors });
113
- }
114
-
115
- const summary = await generateSummaryWithRetry({
116
- analysis,
117
- stat,
118
- model: primaryModel,
119
- apiKey: primaryApiKey,
120
- userContext: args.context,
121
- });
122
-
123
- const commitMessage = formatCommitMessage(analysis, summary.summary);
124
-
125
- if (args.dryRun) {
126
- writeStdout("\nGenerated commit message:\n");
127
- writeStdout(commitMessage);
128
- return;
129
- }
130
-
131
- await git.commit(commitMessage);
132
- writeStdout("Commit created.");
133
- if (args.push) {
134
- await git.push();
135
- writeStdout("Pushed to remote.");
136
- }
137
- }
138
-
139
- async function generateAnalysis(input: {
140
- diff: string;
141
- stat: string;
142
- scopeCandidates: string;
143
- recentCommits: string[];
144
- contextFiles: Array<{ path: string; content: string }>;
145
- userContext?: string;
146
- primaryModel: Model<Api>;
147
- primaryApiKey: string;
148
- fastModel: Model<Api>;
149
- fastApiKey: string;
150
- commitSettings: {
151
- mapReduceEnabled: boolean;
152
- mapReduceMinFiles: number;
153
- mapReduceMaxFileTokens: number;
154
- mapReduceTimeoutMs: number;
155
- mapReduceMaxConcurrency: number;
156
- changelogMaxDiffChars: number;
157
- };
158
- }): Promise<ConventionalAnalysis> {
159
- if (
160
- shouldUseMapReduce(input.diff, {
161
- enabled: input.commitSettings.mapReduceEnabled,
162
- minFiles: input.commitSettings.mapReduceMinFiles,
163
- maxFileTokens: input.commitSettings.mapReduceMaxFileTokens,
164
- })
165
- ) {
166
- writeStdout("Large diff detected, using map-reduce analysis...");
167
- return runMapReduceAnalysis({
168
- model: input.primaryModel,
169
- apiKey: input.primaryApiKey,
170
- fastModel: input.fastModel,
171
- fastApiKey: input.fastApiKey,
172
- diff: input.diff,
173
- stat: input.stat,
174
- scopeCandidates: input.scopeCandidates,
175
- typesDescription: TYPES_DESCRIPTION,
176
- settings: {
177
- enabled: input.commitSettings.mapReduceEnabled,
178
- minFiles: input.commitSettings.mapReduceMinFiles,
179
- maxFileTokens: input.commitSettings.mapReduceMaxFileTokens,
180
- maxConcurrency: input.commitSettings.mapReduceMaxConcurrency,
181
- timeoutMs: input.commitSettings.mapReduceTimeoutMs,
182
- },
183
- });
184
- }
185
-
186
- return generateConventionalAnalysis({
187
- model: input.primaryModel,
188
- apiKey: input.primaryApiKey,
189
- contextFiles: input.contextFiles,
190
- userContext: input.userContext,
191
- typesDescription: TYPES_DESCRIPTION,
192
- recentCommits: input.recentCommits,
193
- scopeCandidates: input.scopeCandidates,
194
- stat: input.stat,
195
- diff: input.diff,
196
- });
197
- }
198
-
199
- async function generateSummaryWithRetry(input: {
200
- analysis: ConventionalAnalysis;
201
- stat: string;
202
- model: Model<Api>;
203
- apiKey: string;
204
- userContext?: string;
205
- }): Promise<{ summary: string }> {
206
- let context = input.userContext;
207
- for (let attempt = 0; attempt < 3; attempt += 1) {
208
- const result = await generateSummary({
209
- model: input.model,
210
- apiKey: input.apiKey,
211
- commitType: input.analysis.type,
212
- scope: input.analysis.scope,
213
- details: input.analysis.details.map(detail => detail.text),
214
- stat: input.stat,
215
- maxChars: SUMMARY_MAX_CHARS,
216
- userContext: context,
217
- });
218
- const validation = validateSummary(result.summary, SUMMARY_MAX_CHARS);
219
- if (validation.valid) {
220
- return result;
221
- }
222
- if (attempt === 2) {
223
- return result;
224
- }
225
- context = buildRetryContext(input.userContext, validation.errors);
226
- }
227
- throw new Error("Summary generation failed");
228
- }
229
-
230
- function buildRetryContext(base: string | undefined, errors: string[]): string {
231
- return renderPromptTemplate(summaryRetryPrompt, {
232
- base_context: base,
233
- errors: errors.join("; "),
234
- });
235
- }
236
-
237
- function writeStdout(message: string): void {
238
- process.stdout.write(`${message}\n`);
239
- }
240
-
241
- function writeStderr(message: string): void {
242
- process.stderr.write(`${message}\n`);
243
- }
@@ -1,148 +0,0 @@
1
- <context>
2
- Senior release engineer writing precise, changelog-ready commit classifications.
3
- </context>
4
-
5
- <instructions>
6
- Classify git diff into conventional commit format.
7
- ## 1. Determine Scope
8
-
9
- Apply scope when 60%+ line changes target single component:
10
- - 150 lines in src/api/, 30 in src/lib.rs -> "api"
11
- - 50 lines in src/api/, 50 in src/types/ -> null (50/50 split)
12
-
13
- Use null for: cross-cutting changes, project-wide refactoring.
14
-
15
- Forbidden scopes (use null): src, lib, include, tests, benches, examples, docs, project name, app, main, entire, all, misc.
16
-
17
- Prefer scopes from <common_scopes> over inventing new.
18
- ## 2. Generate Details (0-6 items)
19
-
20
- Each detail:
21
- 1. Past-tense verb, ends with period
22
- 2. Explains impact/rationale (skip trivial what-changed)
23
- 3. Uses precise names (modules, APIs, files)
24
- 4. Under 120 characters
25
-
26
- Abstraction preference:
27
- - BEST: "Replaced polling with event-driven model for 10x throughput."
28
- - GOOD: "Consolidated three HTTP builders into unified API."
29
- - SKIP: "Renamed workspacePath to locate."
30
-
31
- Group 3+ similar changes: "Updated 5 test files for new API." (not five bullets).
32
-
33
- Issue references inline: (#123), (#123, #456), (#123-#125).
34
-
35
- Priority: user-visible -> perf/security -> architecture -> internal.
36
-
37
- Exclude: import changes, whitespace, formatting, trivial renames, debug prints, comment-only, file moves without modification.
38
-
39
- State only visible rationale. If unclear, use neutral: "Updated logic for correctness."
40
- ## 3. Assign Changelog Metadata
41
-
42
- |Condition|changelog_category|
43
- |---|---|
44
- |New public API, feature, capability|"Added"|
45
- |Modified existing behavior|"Changed"|
46
- |Bug fix, correction|"Fixed"|
47
- |Feature marked for removal|"Deprecated"|
48
- |Feature/API removed|"Removed"|
49
- |Security fix or improvement|"Security"|
50
-
51
- user_visible: true for: new features, APIs, breaking changes, user-affecting bug fixes, user-facing docs, security fixes.
52
-
53
- user_visible: false for: internal refactoring, performance optimizations (unless documented), test/build/CI, code style.
54
-
55
- Omit changelog_category when user_visible false.
56
- </instructions>
57
-
58
- <output_format>
59
- Call create_conventional_analysis with:
60
-
61
- {
62
- "type": "feat|fix|refactor|docs|test|chore|style|perf|build|ci|revert",
63
- "scope": "component-name" | null,
64
- "details": [
65
- {
66
- "text": "Past-tense description ending with period.",
67
- "changelog_category": "Added|Changed|Fixed|Deprecated|Removed|Security",
68
- "user_visible": true
69
- },
70
- {
71
- "text": "Internal change description.",
72
- "user_visible": false
73
- }
74
- ],
75
- "issue_refs": []
76
- }
77
- </output_format>
78
-
79
- <example name="feature-with-api">
80
- {
81
- "type": "feat",
82
- "scope": "api",
83
- "details": [
84
- {
85
- "text": "Added TLS mutual authentication to prevent man-in-the-middle attacks (#100).",
86
- "changelog_category": "Added",
87
- "user_visible": true
88
- },
89
- {
90
- "text": "Implemented builder pattern to simplify transport configuration (#101).",
91
- "changelog_category": "Added",
92
- "user_visible": true
93
- },
94
- {
95
- "text": "Migrated 6 integration tests to exercise new security features.",
96
- "user_visible": false
97
- }
98
- ],
99
- "issue_refs": []
100
- }
101
- </example>
102
-
103
- <example name="internal-refactor">
104
- {
105
- "type": "refactor",
106
- "scope": "parser",
107
- "details": [
108
- {
109
- "text": "Extracted validation logic into separate module for reusability.",
110
- "user_visible": false
111
- },
112
- {
113
- "text": "Consolidated error handling across 12 functions to reduce duplication.",
114
- "user_visible": false
115
- }
116
- ],
117
- "issue_refs": []
118
- }
119
- </example>
120
-
121
- <example name="bug-fix">
122
- {
123
- "type": "fix",
124
- "scope": "parser",
125
- "details": [
126
- {
127
- "text": "Corrected off-by-one error causing buffer overflow on large inputs (#456).",
128
- "changelog_category": "Fixed",
129
- "user_visible": true
130
- },
131
- {
132
- "text": "Added bounds checking to prevent panic on empty files (#457).",
133
- "changelog_category": "Fixed",
134
- "user_visible": true
135
- }
136
- ],
137
- "issue_refs": []
138
- }
139
- </example>
140
-
141
- <example name="minimal-chore">
142
- {
143
- "type": "chore",
144
- "scope": "deps",
145
- "details": [],
146
- "issue_refs": []
147
- }
148
- </example>
@@ -1,38 +0,0 @@
1
- {{#if context_files}}
2
- <project_context>
3
- {{#each context_files}}
4
- <file path="{{ path }}">
5
- {{ content }}
6
- </file>
7
- {{/each}}
8
- </project_context>
9
- {{/if}}
10
- {{#if user_context}}
11
- <user_context>
12
- {{ user_context }}
13
- </user_context>
14
- {{/if}}
15
- {{#if types_description}}
16
- <commit_types>
17
- {{ types_description }}
18
- </commit_types>
19
- {{/if}}
20
- <diff_statistics>
21
- {{ stat }}
22
- </diff_statistics>
23
- <scope_candidates>
24
- {{ scope_candidates }}
25
- </scope_candidates>
26
- {{#if common_scopes}}
27
- <common_scopes>
28
- {{ common_scopes }}
29
- </common_scopes>
30
- {{/if}}
31
- {{#if recent_commits}}
32
- <style_patterns>
33
- {{ recent_commits }}
34
- </style_patterns>
35
- {{/if}}
36
- <diff>
37
- {{ diff }}
38
- </diff>