@nghyane/arcane 0.1.13 → 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 (323) 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/index.ts +1 -35
  30. package/src/exa/render.ts +30 -190
  31. package/src/export/html/index.ts +1 -1
  32. package/src/extensibility/custom-tools/loader.ts +1 -1
  33. package/src/extensibility/custom-tools/types.ts +5 -1
  34. package/src/extensibility/custom-tools/wrapper.ts +1 -1
  35. package/src/extensibility/extensions/runner.ts +1 -1
  36. package/src/extensibility/extensions/types.ts +1 -1
  37. package/src/extensibility/extensions/wrapper.ts +7 -15
  38. package/src/extensibility/hooks/runner.ts +1 -1
  39. package/src/extensibility/hooks/types.ts +1 -1
  40. package/src/extensibility/plugins/doctor.ts +1 -1
  41. package/src/index.ts +13 -13
  42. package/src/lsp/index.ts +77 -24
  43. package/src/lsp/render.ts +34 -583
  44. package/src/lsp/types.ts +3 -3
  45. package/src/lsp/utils.ts +1 -1
  46. package/src/main.ts +1 -1
  47. package/src/mcp/tool-bridge.ts +1 -24
  48. package/src/modes/components/assistant-message.ts +7 -7
  49. package/src/modes/components/bash-execution.ts +48 -113
  50. package/src/modes/components/bordered-loader.ts +1 -1
  51. package/src/modes/components/branch-summary-message.ts +13 -10
  52. package/src/modes/components/compaction-summary-message.ts +14 -13
  53. package/src/modes/components/context-group.ts +106 -0
  54. package/src/modes/components/custom-message.ts +4 -5
  55. package/src/modes/components/diff.ts +2 -2
  56. package/src/modes/components/dynamic-border.ts +1 -1
  57. package/src/modes/components/extensions/extension-dashboard.ts +1 -1
  58. package/src/modes/components/extensions/extension-list.ts +1 -1
  59. package/src/modes/components/extensions/inspector-panel.ts +1 -1
  60. package/src/modes/components/footer.ts +2 -2
  61. package/src/modes/components/history-search.ts +1 -1
  62. package/src/modes/components/hook-editor.ts +1 -1
  63. package/src/modes/components/hook-input.ts +1 -1
  64. package/src/modes/components/hook-message.ts +4 -5
  65. package/src/modes/components/hook-selector.ts +1 -1
  66. package/src/modes/components/index.ts +0 -2
  67. package/src/modes/components/keybinding-hints.ts +1 -1
  68. package/src/modes/components/login-dialog.ts +1 -1
  69. package/src/modes/components/mcp-add-wizard.ts +1 -1
  70. package/src/modes/components/model-selector.ts +1 -1
  71. package/src/modes/components/oauth-selector.ts +1 -1
  72. package/src/modes/components/plugin-settings.ts +1 -1
  73. package/src/modes/components/python-execution.ts +49 -92
  74. package/src/modes/components/queue-mode-selector.ts +1 -1
  75. package/src/modes/components/session-selector.ts +1 -1
  76. package/src/modes/components/settings-defs.ts +5 -10
  77. package/src/modes/components/settings-selector.ts +1 -1
  78. package/src/modes/components/show-images-selector.ts +1 -1
  79. package/src/modes/components/skill-message.ts +4 -4
  80. package/src/modes/components/status-line/segments.ts +2 -2
  81. package/src/modes/components/status-line/separators.ts +1 -1
  82. package/src/modes/components/status-line-segment-editor.ts +1 -1
  83. package/src/modes/components/status-line.ts +1 -1
  84. package/src/modes/components/theme-selector.ts +1 -1
  85. package/src/modes/components/thinking-selector.ts +1 -1
  86. package/src/modes/components/todo-display.ts +2 -4
  87. package/src/modes/components/todo-reminder.ts +4 -4
  88. package/src/modes/components/tool-execution.ts +118 -440
  89. package/src/modes/components/tool-image-display.ts +107 -0
  90. package/src/modes/components/tree-selector.ts +2 -2
  91. package/src/modes/components/ttsr-notification.ts +4 -17
  92. package/src/modes/components/user-message-selector.ts +1 -1
  93. package/src/modes/components/user-message.ts +9 -10
  94. package/src/modes/components/welcome.ts +1 -1
  95. package/src/modes/controllers/command-controller.ts +1 -1
  96. package/src/modes/controllers/event-controller.ts +58 -187
  97. package/src/modes/controllers/extension-ui-controller.ts +1 -1
  98. package/src/modes/controllers/input-controller.ts +3 -1
  99. package/src/modes/controllers/mcp-command-controller.ts +1 -1
  100. package/src/modes/controllers/selector-controller.ts +3 -26
  101. package/src/modes/controllers/ssh-command-controller.ts +1 -1
  102. package/src/modes/interactive-mode.ts +3 -7
  103. package/src/modes/print-mode.ts +5 -5
  104. package/src/modes/rpc/rpc-mode.ts +1 -1
  105. package/src/modes/types.ts +1 -2
  106. package/src/modes/utils/ui-helpers.ts +34 -32
  107. package/src/patch/edit-tool.ts +742 -0
  108. package/src/patch/index.ts +32 -898
  109. package/src/patch/schemas.ts +208 -0
  110. package/src/patch/shared.ts +83 -151
  111. package/src/prompts/agents/explore.md +22 -37
  112. package/src/prompts/agents/frontmatter.md +1 -1
  113. package/src/prompts/agents/init.md +2 -2
  114. package/src/prompts/agents/librarian.md +30 -21
  115. package/src/prompts/agents/oracle.md +9 -2
  116. package/src/prompts/agents/reviewer.md +15 -49
  117. package/src/prompts/agents/task.md +17 -9
  118. package/src/prompts/compaction/branch-summary-context.md +1 -1
  119. package/src/prompts/compaction/branch-summary-preamble.md +1 -1
  120. package/src/prompts/compaction/branch-summary.md +4 -1
  121. package/src/prompts/compaction/compaction-short-summary.md +1 -1
  122. package/src/prompts/compaction/compaction-summary-context.md +1 -1
  123. package/src/prompts/compaction/compaction-summary.md +4 -1
  124. package/src/prompts/compaction/compaction-turn-prefix.md +1 -1
  125. package/src/prompts/compaction/compaction-update-summary.md +1 -1
  126. package/src/prompts/memories/consolidation.md +1 -1
  127. package/src/prompts/memories/read_path.md +1 -1
  128. package/src/prompts/memories/stage_one_input.md +1 -1
  129. package/src/prompts/memories/stage_one_system.md +1 -1
  130. package/src/prompts/review-request.md +1 -1
  131. package/src/prompts/system/agent-creation-architect.md +1 -1
  132. package/src/prompts/system/agent-creation-user.md +1 -1
  133. package/src/prompts/system/custom-system-prompt.md +1 -1
  134. package/src/prompts/system/file-operations.md +1 -1
  135. package/src/prompts/system/subagent-system-prompt.md +2 -2
  136. package/src/prompts/system/summarization-system.md +1 -1
  137. package/src/prompts/system/system-prompt.md +163 -178
  138. package/src/prompts/system/title-system.md +1 -1
  139. package/src/prompts/system/ttsr-interrupt.md +1 -1
  140. package/src/prompts/system/verification-reminder.md +6 -0
  141. package/src/prompts/system/web-search.md +1 -1
  142. package/src/sdk.ts +0 -9
  143. package/src/session/agent-session.ts +244 -1459
  144. package/src/session/model-controller.ts +406 -0
  145. package/src/session/retry-utils.ts +71 -0
  146. package/src/session/session-manager.ts +22 -186
  147. package/src/session/session-types.ts +312 -0
  148. package/src/session/stats.ts +387 -0
  149. package/src/session/streaming-edit.ts +258 -0
  150. package/src/session/ttsr.ts +213 -0
  151. package/src/slash-commands/builtin-registry.ts +0 -8
  152. package/src/stt/recorder.ts +2 -2
  153. package/src/system-prompt.ts +1 -14
  154. package/src/task/agents.ts +7 -33
  155. package/src/task/executor.ts +50 -438
  156. package/src/task/index.ts +104 -71
  157. package/src/task/progress-tracker.ts +390 -0
  158. package/src/task/render.ts +371 -187
  159. package/src/task/subprocess-tool-registry.ts +1 -1
  160. package/src/task/types.ts +14 -47
  161. package/src/tools/ask.ts +31 -42
  162. package/src/tools/bash-interactive.ts +2 -2
  163. package/src/tools/bash-interceptor.ts +2 -2
  164. package/src/tools/bash-normalize.ts +1 -1
  165. package/src/tools/bash-skill-urls.ts +2 -2
  166. package/src/tools/bash.ts +87 -136
  167. package/src/tools/browser.ts +54 -84
  168. package/src/tools/create-tools.ts +186 -0
  169. package/src/tools/default-renderer.ts +104 -0
  170. package/src/tools/explore.ts +11 -10
  171. package/src/tools/fetch.ts +24 -114
  172. package/src/tools/find.ts +48 -132
  173. package/src/tools/gemini-image.ts +5 -15
  174. package/src/tools/github.ts +450 -0
  175. package/src/tools/grep.ts +43 -179
  176. package/src/tools/index.ts +35 -198
  177. package/src/tools/json-tree.ts +3 -3
  178. package/src/tools/librarian.ts +18 -18
  179. package/src/tools/list-limit.ts +2 -2
  180. package/src/tools/notebook.ts +35 -87
  181. package/src/tools/oracle.ts +25 -25
  182. package/src/tools/output-meta.ts +89 -4
  183. package/src/tools/output-utils.ts +2 -2
  184. package/src/tools/python.ts +86 -637
  185. package/src/tools/read.ts +36 -119
  186. package/src/tools/reviewer-tool.ts +19 -21
  187. package/src/tools/search-code.ts +128 -0
  188. package/src/tools/ssh.ts +67 -126
  189. package/src/tools/subagent-tool.ts +197 -123
  190. package/src/tools/todo-write.ts +15 -31
  191. package/src/tools/tool-errors.ts +0 -30
  192. package/src/tools/undo-edit.ts +30 -67
  193. package/src/tools/write.ts +78 -127
  194. package/src/tui/code-cell.ts +4 -4
  195. package/src/tui/file-list.ts +2 -2
  196. package/src/tui/output-block.ts +1 -1
  197. package/src/tui/status-line.ts +1 -1
  198. package/src/tui/tree-list.ts +2 -2
  199. package/src/tui/types.ts +1 -1
  200. package/src/tui/utils.ts +1 -1
  201. package/src/{tools → ui}/render-utils.ts +87 -126
  202. package/src/utils/external-editor.ts +4 -4
  203. package/src/utils/file-mentions.ts +1 -1
  204. package/src/utils/index.ts +30 -0
  205. package/src/utils/tools-manager.ts +9 -19
  206. package/src/web/github-client.ts +290 -0
  207. package/src/web/scrapers/github.ts +11 -62
  208. package/src/web/search/auth.ts +1 -3
  209. package/src/web/search/index.ts +82 -46
  210. package/src/web/search/provider.ts +11 -16
  211. package/src/web/search/providers/grep.ts +160 -0
  212. package/src/web/search/render.ts +48 -235
  213. package/src/web/search/types.ts +1 -1
  214. package/src/commands/commit.ts +0 -36
  215. package/src/commit/agentic/agent.ts +0 -311
  216. package/src/commit/agentic/fallback.ts +0 -96
  217. package/src/commit/agentic/index.ts +0 -359
  218. package/src/commit/agentic/prompts/analyze-file.md +0 -22
  219. package/src/commit/agentic/prompts/session-user.md +0 -25
  220. package/src/commit/agentic/prompts/split-confirm.md +0 -1
  221. package/src/commit/agentic/prompts/system.md +0 -38
  222. package/src/commit/agentic/state.ts +0 -69
  223. package/src/commit/agentic/tools/analyze-file.ts +0 -118
  224. package/src/commit/agentic/tools/git-file-diff.ts +0 -194
  225. package/src/commit/agentic/tools/git-hunk.ts +0 -50
  226. package/src/commit/agentic/tools/git-overview.ts +0 -84
  227. package/src/commit/agentic/tools/index.ts +0 -56
  228. package/src/commit/agentic/tools/propose-changelog.ts +0 -128
  229. package/src/commit/agentic/tools/propose-commit.ts +0 -154
  230. package/src/commit/agentic/tools/recent-commits.ts +0 -81
  231. package/src/commit/agentic/tools/split-commit.ts +0 -280
  232. package/src/commit/agentic/topo-sort.ts +0 -44
  233. package/src/commit/agentic/trivial.ts +0 -51
  234. package/src/commit/agentic/validation.ts +0 -200
  235. package/src/commit/analysis/conventional.ts +0 -165
  236. package/src/commit/analysis/index.ts +0 -4
  237. package/src/commit/analysis/scope.ts +0 -242
  238. package/src/commit/analysis/summary.ts +0 -112
  239. package/src/commit/analysis/validation.ts +0 -66
  240. package/src/commit/changelog/detect.ts +0 -37
  241. package/src/commit/changelog/generate.ts +0 -110
  242. package/src/commit/changelog/index.ts +0 -234
  243. package/src/commit/changelog/parse.ts +0 -44
  244. package/src/commit/cli.ts +0 -93
  245. package/src/commit/git/diff.ts +0 -148
  246. package/src/commit/git/errors.ts +0 -9
  247. package/src/commit/git/index.ts +0 -211
  248. package/src/commit/git/operations.ts +0 -54
  249. package/src/commit/index.ts +0 -5
  250. package/src/commit/map-reduce/index.ts +0 -64
  251. package/src/commit/map-reduce/map-phase.ts +0 -178
  252. package/src/commit/map-reduce/reduce-phase.ts +0 -145
  253. package/src/commit/map-reduce/utils.ts +0 -9
  254. package/src/commit/message.ts +0 -11
  255. package/src/commit/model-selection.ts +0 -69
  256. package/src/commit/pipeline.ts +0 -243
  257. package/src/commit/prompts/analysis-system.md +0 -148
  258. package/src/commit/prompts/analysis-user.md +0 -38
  259. package/src/commit/prompts/changelog-system.md +0 -50
  260. package/src/commit/prompts/changelog-user.md +0 -18
  261. package/src/commit/prompts/file-observer-system.md +0 -24
  262. package/src/commit/prompts/file-observer-user.md +0 -8
  263. package/src/commit/prompts/reduce-system.md +0 -50
  264. package/src/commit/prompts/reduce-user.md +0 -17
  265. package/src/commit/prompts/summary-retry.md +0 -3
  266. package/src/commit/prompts/summary-system.md +0 -38
  267. package/src/commit/prompts/summary-user.md +0 -13
  268. package/src/commit/prompts/types-description.md +0 -2
  269. package/src/commit/types.ts +0 -109
  270. package/src/commit/utils/exclusions.ts +0 -42
  271. package/src/mcp/render.ts +0 -123
  272. package/src/modes/components/agent-dashboard.ts +0 -1130
  273. package/src/modes/components/codemode-group.ts +0 -369
  274. package/src/modes/components/read-tool-group.ts +0 -119
  275. package/src/modes/components/visual-truncate.ts +0 -63
  276. package/src/prompts/system/subagent-user-prompt.md +0 -8
  277. package/src/prompts/tools/ask.md +0 -44
  278. package/src/prompts/tools/bash.md +0 -24
  279. package/src/prompts/tools/browser.md +0 -33
  280. package/src/prompts/tools/calculator.md +0 -12
  281. package/src/prompts/tools/explore.md +0 -29
  282. package/src/prompts/tools/fetch.md +0 -16
  283. package/src/prompts/tools/find.md +0 -18
  284. package/src/prompts/tools/gemini-image.md +0 -23
  285. package/src/prompts/tools/grep.md +0 -28
  286. package/src/prompts/tools/hashline.md +0 -232
  287. package/src/prompts/tools/librarian.md +0 -24
  288. package/src/prompts/tools/lsp.md +0 -28
  289. package/src/prompts/tools/oracle.md +0 -26
  290. package/src/prompts/tools/patch.md +0 -74
  291. package/src/prompts/tools/python.md +0 -66
  292. package/src/prompts/tools/read.md +0 -36
  293. package/src/prompts/tools/replace.md +0 -38
  294. package/src/prompts/tools/reviewer.md +0 -41
  295. package/src/prompts/tools/ssh.md +0 -51
  296. package/src/prompts/tools/task-summary.md +0 -28
  297. package/src/prompts/tools/task.md +0 -146
  298. package/src/prompts/tools/todo-write.md +0 -65
  299. package/src/prompts/tools/undo-edit.md +0 -7
  300. package/src/prompts/tools/web-search.md +0 -19
  301. package/src/prompts/tools/write.md +0 -18
  302. package/src/task/batch.ts +0 -102
  303. package/src/task/discovery.ts +0 -126
  304. package/src/task/parallel.ts +0 -84
  305. package/src/task/template.ts +0 -32
  306. package/src/tools/calculator.ts +0 -537
  307. package/src/tools/jtd-to-typescript.ts +0 -198
  308. package/src/tools/renderers.ts +0 -60
  309. package/src/tools/tool-result.ts +0 -86
  310. /package/src/{modes/theme → theme}/dark.json +0 -0
  311. /package/src/{modes/theme → theme}/defaults/dark-catppuccin.json +0 -0
  312. /package/src/{modes/theme → theme}/defaults/dark-dracula.json +0 -0
  313. /package/src/{modes/theme → theme}/defaults/dark-gruvbox.json +0 -0
  314. /package/src/{modes/theme → theme}/defaults/dark-solarized.json +0 -0
  315. /package/src/{modes/theme → theme}/defaults/dark-tokyo-night.json +0 -0
  316. /package/src/{modes/theme → theme}/defaults/index.ts +0 -0
  317. /package/src/{modes/theme → theme}/defaults/light-catppuccin.json +0 -0
  318. /package/src/{modes/theme → theme}/defaults/light-github.json +0 -0
  319. /package/src/{modes/theme → theme}/defaults/light-solarized.json +0 -0
  320. /package/src/{modes/theme → theme}/light.json +0 -0
  321. /package/src/{modes/theme → theme}/mermaid-cache.ts +0 -0
  322. /package/src/{modes/theme → theme}/theme-schema.json +0 -0
  323. /package/src/{modes/theme → theme}/theme.ts +0 -0
@@ -1,154 +0,0 @@
1
- import { Type } from "@sinclair/typebox";
2
- import type { CommitAgentState } from "../../../commit/agentic/state";
3
- import {
4
- capDetails,
5
- MAX_DETAIL_ITEMS,
6
- normalizeSummary,
7
- SUMMARY_MAX_CHARS,
8
- validateSummaryRules,
9
- validateTypeConsistency,
10
- } from "../../../commit/agentic/validation";
11
- import { validateAnalysis } from "../../../commit/analysis/validation";
12
- import type { ControlledGit } from "../../../commit/git";
13
- import type { CommitType, ConventionalAnalysis, ConventionalDetail } from "../../../commit/types";
14
- import type { CustomTool } from "../../../extensibility/custom-tools/types";
15
-
16
- const commitTypeSchema = Type.Union([
17
- Type.Literal("feat"),
18
- Type.Literal("fix"),
19
- Type.Literal("refactor"),
20
- Type.Literal("perf"),
21
- Type.Literal("docs"),
22
- Type.Literal("test"),
23
- Type.Literal("build"),
24
- Type.Literal("ci"),
25
- Type.Literal("chore"),
26
- Type.Literal("style"),
27
- Type.Literal("revert"),
28
- ]);
29
-
30
- const detailSchema = Type.Object({
31
- text: Type.String(),
32
- changelog_category: Type.Optional(
33
- Type.Union([
34
- Type.Literal("Added"),
35
- Type.Literal("Changed"),
36
- Type.Literal("Fixed"),
37
- Type.Literal("Deprecated"),
38
- Type.Literal("Removed"),
39
- Type.Literal("Security"),
40
- Type.Literal("Breaking Changes"),
41
- ]),
42
- ),
43
- user_visible: Type.Optional(Type.Boolean()),
44
- });
45
-
46
- const proposeCommitSchema = Type.Object({
47
- type: commitTypeSchema,
48
- scope: Type.Union([Type.String(), Type.Null()]),
49
- summary: Type.String(),
50
- details: Type.Array(detailSchema),
51
- issue_refs: Type.Array(Type.String()),
52
- });
53
-
54
- interface ProposalResponse {
55
- valid: boolean;
56
- errors: string[];
57
- warnings: string[];
58
- proposal?: {
59
- type: CommitType;
60
- scope: string | null;
61
- summary: string;
62
- details: ConventionalDetail[];
63
- issue_refs: string[];
64
- };
65
- }
66
-
67
- function normalizeDetails(
68
- details: Array<{
69
- text: string;
70
- changelog_category?: ConventionalDetail["changelogCategory"];
71
- user_visible?: boolean;
72
- }>,
73
- ): ConventionalDetail[] {
74
- return details.map(detail => ({
75
- text: detail.text.trim(),
76
- changelogCategory: detail.user_visible ? detail.changelog_category : undefined,
77
- userVisible: detail.user_visible ?? false,
78
- }));
79
- }
80
-
81
- export function createProposeCommitTool(
82
- git: ControlledGit,
83
- state: CommitAgentState,
84
- ): CustomTool<typeof proposeCommitSchema> {
85
- return {
86
- name: "propose_commit",
87
- label: "Propose Commit",
88
- description: "Submit the final conventional commit proposal.",
89
- parameters: proposeCommitSchema,
90
- async execute(_toolCallId, params) {
91
- const scope = params.scope?.trim() || null;
92
- const summary = normalizeSummary(params.summary, params.type, scope);
93
- const details = normalizeDetails(params.details);
94
- const { details: cappedDetails, warnings: detailWarnings } = capDetails(details);
95
- const analysis: ConventionalAnalysis = {
96
- type: params.type,
97
- scope,
98
- details: cappedDetails,
99
- issueRefs: params.issue_refs ?? [],
100
- };
101
-
102
- const summaryValidation = validateSummaryRules(summary);
103
- const analysisValidation = validateAnalysis(analysis);
104
- const stagedFiles = state.overview?.files ?? (await git.getStagedFiles());
105
- const diffText = state.diffText ?? (await git.getDiff(true));
106
- const typeValidation = validateTypeConsistency(params.type, stagedFiles, {
107
- diffText,
108
- summary,
109
- details: cappedDetails,
110
- });
111
-
112
- const errors = [...summaryValidation.errors, ...analysisValidation.errors, ...typeValidation.errors];
113
- const warnings = [...summaryValidation.warnings, ...detailWarnings, ...typeValidation.warnings];
114
-
115
- const response: ProposalResponse = {
116
- valid: errors.length === 0,
117
- errors,
118
- warnings,
119
- };
120
-
121
- if (response.valid) {
122
- response.proposal = {
123
- type: analysis.type,
124
- scope: analysis.scope,
125
- summary,
126
- details: analysis.details,
127
- issue_refs: analysis.issueRefs,
128
- };
129
- state.proposal = {
130
- analysis,
131
- summary,
132
- warnings,
133
- };
134
- }
135
-
136
- const text = JSON.stringify(
137
- {
138
- ...response,
139
- constraints: {
140
- maxSummaryChars: SUMMARY_MAX_CHARS,
141
- maxDetailItems: MAX_DETAIL_ITEMS,
142
- },
143
- },
144
- null,
145
- 2,
146
- );
147
-
148
- return {
149
- content: [{ type: "text", text }],
150
- details: response,
151
- };
152
- },
153
- };
154
- }
@@ -1,81 +0,0 @@
1
- import { Type } from "@sinclair/typebox";
2
- import type { ControlledGit } from "../../../commit/git";
3
- import type { CustomTool } from "../../../extensibility/custom-tools/types";
4
-
5
- const recentCommitsSchema = Type.Object({
6
- count: Type.Optional(Type.Number({ description: "Number of commits to fetch", minimum: 1, maximum: 50 })),
7
- });
8
-
9
- interface RecentCommitStats {
10
- scopeUsagePercent: number;
11
- commonVerbs: Record<string, number>;
12
- summaryLength: { min: number; max: number; average: number };
13
- lowercaseSummaryPercent: number;
14
- topScopes: Record<string, number>;
15
- }
16
-
17
- function extractSummary(subject: string): string {
18
- const match = subject.match(/^[a-z]+(?:\([^)]+\))?:\s+(.*)$/i);
19
- if (match?.[1]) return match[1].trim();
20
- return subject.trim();
21
- }
22
-
23
- function extractScope(subject: string): string | null {
24
- const match = subject.match(/^[a-z]+\(([^)]+)\):/i);
25
- return match?.[1]?.trim() ?? null;
26
- }
27
-
28
- export function createRecentCommitsTool(git: ControlledGit): CustomTool<typeof recentCommitsSchema> {
29
- return {
30
- name: "recent_commits",
31
- label: "Recent Commits",
32
- description: "Return recent commit subjects with style statistics.",
33
- parameters: recentCommitsSchema,
34
- async execute(_toolCallId, params) {
35
- const count = params.count ?? 8;
36
- const commits = await git.getRecentCommits(count);
37
- const verbs: Record<string, number> = {};
38
- const scopes: Record<string, number> = {};
39
- const lengths: number[] = [];
40
- let scopeCount = 0;
41
- let lowercaseCount = 0;
42
-
43
- for (const subject of commits) {
44
- const summary = extractSummary(subject);
45
- const scope = extractScope(subject);
46
- if (scope) {
47
- scopeCount += 1;
48
- scopes[scope] = (scopes[scope] ?? 0) + 1;
49
- }
50
- if (summary[0] && summary[0] === summary[0].toLowerCase()) {
51
- lowercaseCount += 1;
52
- }
53
- const firstWord = summary.split(/\s+/)[0]?.toLowerCase();
54
- if (firstWord) {
55
- verbs[firstWord] = (verbs[firstWord] ?? 0) + 1;
56
- }
57
- lengths.push(summary.length);
58
- }
59
-
60
- const min = lengths.length > 0 ? Math.min(...lengths) : 0;
61
- const max = lengths.length > 0 ? Math.max(...lengths) : 0;
62
- const average = lengths.length > 0 ? lengths.reduce((sum, value) => sum + value, 0) / lengths.length : 0;
63
- const scopeUsagePercent = commits.length > 0 ? Math.round((scopeCount / commits.length) * 100) : 0;
64
- const lowercaseSummaryPercent = commits.length > 0 ? Math.round((lowercaseCount / commits.length) * 100) : 0;
65
-
66
- const stats: RecentCommitStats = {
67
- scopeUsagePercent,
68
- commonVerbs: verbs,
69
- summaryLength: { min, max, average: Number(average.toFixed(1)) },
70
- lowercaseSummaryPercent,
71
- topScopes: scopes,
72
- };
73
-
74
- const payload = { commits, stats };
75
- return {
76
- content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
77
- details: payload,
78
- };
79
- },
80
- };
81
- }
@@ -1,280 +0,0 @@
1
- import { Type } from "@sinclair/typebox";
2
- import type { CommitAgentState, SplitCommitGroup, SplitCommitPlan } from "../../../commit/agentic/state";
3
- import { computeDependencyOrder } from "../../../commit/agentic/topo-sort";
4
- import {
5
- capDetails,
6
- MAX_DETAIL_ITEMS,
7
- normalizeSummary,
8
- SUMMARY_MAX_CHARS,
9
- validateSummaryRules,
10
- validateTypeConsistency,
11
- } from "../../../commit/agentic/validation";
12
- import { validateScope } from "../../../commit/analysis/validation";
13
- import type { ControlledGit } from "../../../commit/git";
14
- import type { ConventionalDetail } from "../../../commit/types";
15
- import type { CustomTool } from "../../../extensibility/custom-tools/types";
16
-
17
- const commitTypeSchema = Type.Union([
18
- Type.Literal("feat"),
19
- Type.Literal("fix"),
20
- Type.Literal("refactor"),
21
- Type.Literal("perf"),
22
- Type.Literal("docs"),
23
- Type.Literal("test"),
24
- Type.Literal("build"),
25
- Type.Literal("ci"),
26
- Type.Literal("chore"),
27
- Type.Literal("style"),
28
- Type.Literal("revert"),
29
- ]);
30
-
31
- const detailSchema = Type.Object({
32
- text: Type.String(),
33
- changelog_category: Type.Optional(
34
- Type.Union([
35
- Type.Literal("Added"),
36
- Type.Literal("Changed"),
37
- Type.Literal("Fixed"),
38
- Type.Literal("Deprecated"),
39
- Type.Literal("Removed"),
40
- Type.Literal("Security"),
41
- Type.Literal("Breaking Changes"),
42
- ]),
43
- ),
44
- user_visible: Type.Optional(Type.Boolean()),
45
- });
46
-
47
- const hunkSelectorSchema = Type.Union([
48
- Type.Object({ type: Type.Literal("all") }),
49
- Type.Object({ type: Type.Literal("indices"), indices: Type.Array(Type.Number(), { minItems: 1 }) }),
50
- Type.Object({ type: Type.Literal("lines"), start: Type.Number(), end: Type.Number() }),
51
- ]);
52
-
53
- const fileChangeSchema = Type.Object({
54
- path: Type.String(),
55
- hunks: hunkSelectorSchema,
56
- });
57
-
58
- const splitCommitSchema = Type.Object({
59
- commits: Type.Array(
60
- Type.Object({
61
- changes: Type.Array(fileChangeSchema, { minItems: 1 }),
62
- type: commitTypeSchema,
63
- scope: Type.Union([Type.String(), Type.Null()]),
64
- summary: Type.String(),
65
- details: Type.Optional(Type.Array(detailSchema)),
66
- issue_refs: Type.Optional(Type.Array(Type.String())),
67
- rationale: Type.Optional(Type.String()),
68
- dependencies: Type.Optional(Type.Array(Type.Number())),
69
- }),
70
- { minItems: 2 },
71
- ),
72
- });
73
-
74
- interface SplitCommitResponse {
75
- valid: boolean;
76
- errors: string[];
77
- warnings: string[];
78
- proposal?: SplitCommitPlan;
79
- }
80
-
81
- function normalizeDetails(
82
- details: Array<{
83
- text: string;
84
- changelog_category?: ConventionalDetail["changelogCategory"];
85
- user_visible?: boolean;
86
- }>,
87
- ): ConventionalDetail[] {
88
- return details.map(detail => ({
89
- text: detail.text.trim(),
90
- changelogCategory: detail.user_visible ? detail.changelog_category : undefined,
91
- userVisible: detail.user_visible ?? false,
92
- }));
93
- }
94
-
95
- export function createSplitCommitTool(
96
- git: ControlledGit,
97
- state: CommitAgentState,
98
- changelogTargets: string[],
99
- ): CustomTool<typeof splitCommitSchema> {
100
- return {
101
- name: "split_commit",
102
- label: "Split Commit",
103
- description: "Propose multiple atomic commits for unrelated changes.",
104
- parameters: splitCommitSchema,
105
- async execute(_toolCallId, params) {
106
- const stagedFiles = state.overview?.files ?? (await git.getStagedFiles());
107
- const stagedSet = new Set(stagedFiles);
108
- const changelogSet = new Set(changelogTargets);
109
- const usedFiles = new Set<string>();
110
- const errors: string[] = [];
111
- const warnings: string[] = [];
112
- const diffText = await git.getDiff(true);
113
-
114
- const commits: SplitCommitGroup[] = params.commits.map((commit, index) => {
115
- const scope = commit.scope?.trim() || null;
116
- const summary = normalizeSummary(commit.summary, commit.type, scope);
117
- const detailInput = normalizeDetails(commit.details ?? []);
118
- const detailResult = capDetails(detailInput);
119
- warnings.push(...detailResult.warnings.map(warning => `Commit ${index + 1}: ${warning}`));
120
- const issueRefs = commit.issue_refs ?? [];
121
- const dependencies = (commit.dependencies ?? []).map(dep => Math.floor(dep));
122
- const changes = commit.changes.map(change => ({
123
- path: change.path,
124
- hunks: change.hunks,
125
- }));
126
- const files = changes.map(change => change.path);
127
-
128
- const summaryValidation = validateSummaryRules(summary);
129
- const scopeValidation = validateScope(scope);
130
- const typeValidation = validateTypeConsistency(commit.type, files, {
131
- diffText,
132
- summary,
133
- details: detailResult.details,
134
- });
135
-
136
- if (summaryValidation.errors.length > 0) {
137
- errors.push(...summaryValidation.errors.map(error => `Commit ${index + 1}: ${error}`));
138
- }
139
- if (!scopeValidation.valid) {
140
- errors.push(...scopeValidation.errors.map(error => `Commit ${index + 1}: ${error}`));
141
- }
142
- if (typeValidation.errors.length > 0) {
143
- errors.push(...typeValidation.errors.map(error => `Commit ${index + 1}: ${error}`));
144
- }
145
- warnings.push(...summaryValidation.warnings.map(warning => `Commit ${index + 1}: ${warning}`));
146
- warnings.push(...typeValidation.warnings.map(warning => `Commit ${index + 1}: ${warning}`));
147
- const hunkValidation = validateHunkSelectors(index, changes, files);
148
- warnings.push(...hunkValidation.warnings);
149
- errors.push(...hunkValidation.errors);
150
- errors.push(...validateDependencies(index, dependencies, params.commits.length));
151
-
152
- return {
153
- changes,
154
- type: commit.type,
155
- scope,
156
- summary,
157
- details: detailResult.details,
158
- issueRefs,
159
- rationale: commit.rationale?.trim() || undefined,
160
- dependencies,
161
- };
162
- });
163
-
164
- for (const commit of commits) {
165
- const seen = new Set<string>();
166
- for (const change of commit.changes) {
167
- const file = change.path;
168
- if (!stagedSet.has(file) && !changelogSet.has(file)) {
169
- errors.push(`File not staged: ${file}`);
170
- continue;
171
- }
172
- if (seen.has(file)) {
173
- errors.push(`File listed multiple times in commit ${commit.summary}: ${file}`);
174
- continue;
175
- }
176
- if (usedFiles.has(file)) {
177
- errors.push(`File appears in multiple commits: ${file}`);
178
- continue;
179
- }
180
- seen.add(file);
181
- usedFiles.add(file);
182
- }
183
- }
184
-
185
- for (const file of stagedFiles) {
186
- if (!usedFiles.has(file)) {
187
- errors.push(`Staged file missing from split plan: ${file}`);
188
- }
189
- }
190
-
191
- const dependencyCheck = computeDependencyOrder(commits);
192
- if ("error" in dependencyCheck) {
193
- errors.push(dependencyCheck.error);
194
- }
195
-
196
- const response: SplitCommitResponse = {
197
- valid: errors.length === 0,
198
- errors,
199
- warnings,
200
- };
201
-
202
- if (response.valid) {
203
- response.proposal = { commits, warnings };
204
- state.splitProposal = response.proposal;
205
- }
206
-
207
- const text = JSON.stringify(
208
- {
209
- ...response,
210
- constraints: {
211
- maxSummaryChars: SUMMARY_MAX_CHARS,
212
- maxDetailItems: MAX_DETAIL_ITEMS,
213
- },
214
- },
215
- null,
216
- 2,
217
- );
218
-
219
- return {
220
- content: [{ type: "text", text }],
221
- details: response,
222
- };
223
- },
224
- };
225
- }
226
-
227
- function validateHunkSelectors(
228
- commitIndex: number,
229
- changes: SplitCommitGroup["changes"],
230
- files: string[],
231
- ): { errors: string[]; warnings: string[] } {
232
- const errors: string[] = [];
233
- const warnings: string[] = [];
234
- const prefix = `Commit ${commitIndex + 1}`;
235
- if (files.length === 0) {
236
- errors.push(`${prefix}: no files specified`);
237
- return { errors, warnings };
238
- }
239
- for (const change of changes) {
240
- if (change.hunks.type === "indices") {
241
- const invalid = change.hunks.indices.filter(
242
- value => !Number.isFinite(value) || Math.floor(value) !== value || value < 1,
243
- );
244
- if (invalid.length > 0) {
245
- errors.push(`${prefix}: invalid hunk indices for ${change.path}`);
246
- }
247
- continue;
248
- }
249
- if (change.hunks.type === "lines") {
250
- const { start, end } = change.hunks;
251
- if (!Number.isFinite(start) || !Number.isFinite(end)) {
252
- errors.push(`${prefix}: invalid line range for ${change.path}`);
253
- continue;
254
- }
255
- if (Math.floor(start) !== start || Math.floor(end) !== end || start < 1 || end < start) {
256
- errors.push(`${prefix}: invalid line range for ${change.path}`);
257
- }
258
- }
259
- }
260
- return { errors, warnings };
261
- }
262
-
263
- function validateDependencies(commitIndex: number, dependencies: number[], totalCommits: number): string[] {
264
- const errors: string[] = [];
265
- const prefix = `Commit ${commitIndex + 1}`;
266
- for (const dependency of dependencies) {
267
- if (!Number.isFinite(dependency) || Math.floor(dependency) !== dependency) {
268
- errors.push(`${prefix}: dependency index must be an integer`);
269
- continue;
270
- }
271
- if (dependency === commitIndex) {
272
- errors.push(`${prefix}: cannot depend on itself`);
273
- continue;
274
- }
275
- if (dependency < 0 || dependency >= totalCommits) {
276
- errors.push(`${prefix}: dependency index out of range (${dependency})`);
277
- }
278
- }
279
- return errors;
280
- }
@@ -1,44 +0,0 @@
1
- import type { SplitCommitGroup } from "./state";
2
-
3
- export function computeDependencyOrder(groups: SplitCommitGroup[]): number[] | { error: string } {
4
- const total = groups.length;
5
- const inDegree = new Array<number>(total).fill(0);
6
- const edges = Array.from({ length: total }, () => new Set<number>());
7
-
8
- for (let index = 0; index < total; index += 1) {
9
- const dependencies = groups[index]?.dependencies ?? [];
10
- for (const dependency of dependencies) {
11
- if (dependency < 0 || dependency >= total) {
12
- return { error: `Invalid dependency index: ${dependency}` };
13
- }
14
- if (!edges[dependency]?.has(index)) {
15
- edges[dependency]?.add(index);
16
- inDegree[index] += 1;
17
- }
18
- }
19
- }
20
-
21
- const queue: number[] = [];
22
- for (let index = 0; index < total; index += 1) {
23
- if (inDegree[index] === 0) queue.push(index);
24
- }
25
-
26
- const order: number[] = [];
27
- while (queue.length > 0) {
28
- const current = queue.shift();
29
- if (current === undefined) break;
30
- order.push(current);
31
- for (const next of edges[current] ?? []) {
32
- inDegree[next] -= 1;
33
- if (inDegree[next] === 0) {
34
- queue.push(next);
35
- }
36
- }
37
- }
38
-
39
- if (order.length !== total) {
40
- return { error: "Circular dependency detected in split commit plan." };
41
- }
42
-
43
- return order;
44
- }
@@ -1,51 +0,0 @@
1
- import type { CommitType } from "../../commit/types";
2
-
3
- export interface TrivialChangeResult {
4
- isTrivial: true;
5
- type: CommitType;
6
- summary: string;
7
- }
8
-
9
- const WHITESPACE_ONLY_PATTERN = /^[-+][\t ]*$/;
10
- const IMPORT_LINE_PATTERN = /^[-+]\s*(import\s|from\s|export\s.*from|require\(|module\.exports)/;
11
- const EMPTY_LINE_PATTERN = /^[-+]\s*$/;
12
-
13
- export function detectTrivialChange(diff: string): TrivialChangeResult | null {
14
- const lines = diff.split("\n");
15
- const changeLines = lines.filter(line => line.startsWith("+") || line.startsWith("-"));
16
- const contentLines = changeLines.filter(
17
- line => !line.startsWith("+++") && !line.startsWith("---") && !line.startsWith("@@"),
18
- );
19
-
20
- if (contentLines.length === 0) return null;
21
-
22
- if (isOnlyWhitespace(contentLines)) {
23
- return { isTrivial: true, type: "style", summary: "formatted code" };
24
- }
25
-
26
- if (isOnlyImports(contentLines)) {
27
- return { isTrivial: true, type: "style", summary: "reorganized imports" };
28
- }
29
-
30
- return null;
31
- }
32
-
33
- function isOnlyWhitespace(lines: string[]): boolean {
34
- for (const line of lines) {
35
- const content = line.slice(1);
36
- if (content.trim().length > 0 && !WHITESPACE_ONLY_PATTERN.test(line)) {
37
- return false;
38
- }
39
- }
40
- return true;
41
- }
42
-
43
- function isOnlyImports(lines: string[]): boolean {
44
- for (const line of lines) {
45
- if (EMPTY_LINE_PATTERN.test(line)) continue;
46
- if (!IMPORT_LINE_PATTERN.test(line)) {
47
- return false;
48
- }
49
- }
50
- return true;
51
- }