@gitkraken/compose-tools 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 (122) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/LICENSE +19 -0
  3. package/README.md +543 -0
  4. package/dist/ai/session.d.ts +12 -0
  5. package/dist/ai/session.js +1 -0
  6. package/dist/ai/types.d.ts +31 -0
  7. package/dist/ai/types.js +1 -0
  8. package/dist/cancellation.d.ts +20 -0
  9. package/dist/cancellation.js +1 -0
  10. package/dist/errors/ai.d.ts +10 -0
  11. package/dist/errors/ai.js +1 -0
  12. package/dist/errors/git.d.ts +12 -0
  13. package/dist/errors/git.js +1 -0
  14. package/dist/errors/task.d.ts +6 -0
  15. package/dist/errors/task.js +1 -0
  16. package/dist/errors/workflow.d.ts +13 -0
  17. package/dist/errors/workflow.js +1 -0
  18. package/dist/git/apply-branches.d.ts +28 -0
  19. package/dist/git/apply-branches.js +1 -0
  20. package/dist/git/apply-target.d.ts +39 -0
  21. package/dist/git/apply-target.js +1 -0
  22. package/dist/git/commit-chain.d.ts +87 -0
  23. package/dist/git/commit-chain.js +6 -0
  24. package/dist/git/diff-collector.d.ts +80 -0
  25. package/dist/git/diff-collector.js +8 -0
  26. package/dist/git/index.d.ts +7 -0
  27. package/dist/git/index.js +1 -0
  28. package/dist/git/port-dispatch.d.ts +34 -0
  29. package/dist/git/port-dispatch.js +3 -0
  30. package/dist/git/require-exec.d.ts +17 -0
  31. package/dist/git/require-exec.js +1 -0
  32. package/dist/git/safety.d.ts +22 -0
  33. package/dist/git/safety.js +1 -0
  34. package/dist/git/types.d.ts +43 -0
  35. package/dist/git/types.js +1 -0
  36. package/dist/git/utils/conventions.d.ts +33 -0
  37. package/dist/git/utils/conventions.js +10 -0
  38. package/dist/git/utils/crypto.d.ts +4 -0
  39. package/dist/git/utils/crypto.js +1 -0
  40. package/dist/git/utils/hunk-parser.d.ts +6 -0
  41. package/dist/git/utils/hunk-parser.js +7 -0
  42. package/dist/git/utils/patch-builder.d.ts +6 -0
  43. package/dist/git/utils/patch-builder.js +2 -0
  44. package/dist/git/utils/temp-index.d.ts +6 -0
  45. package/dist/git/utils/temp-index.js +1 -0
  46. package/dist/index.d.ts +28 -0
  47. package/dist/index.js +1 -0
  48. package/dist/ports/git.d.ts +199 -0
  49. package/dist/ports/git.js +1 -0
  50. package/dist/tasks/ai-loop.d.ts +99 -0
  51. package/dist/tasks/ai-loop.js +2 -0
  52. package/dist/tasks/analyze/analyze.d.ts +6 -0
  53. package/dist/tasks/analyze/analyze.js +1 -0
  54. package/dist/tasks/analyze/prompt.d.ts +16 -0
  55. package/dist/tasks/analyze/prompt.js +34 -0
  56. package/dist/tasks/analyze/schema.d.ts +38 -0
  57. package/dist/tasks/analyze/schema.js +1 -0
  58. package/dist/tasks/analyze/types.d.ts +69 -0
  59. package/dist/tasks/analyze/types.js +1 -0
  60. package/dist/tasks/analyze/validator.d.ts +7 -0
  61. package/dist/tasks/analyze/validator.js +13 -0
  62. package/dist/tasks/compose-group/compose-group.d.ts +15 -0
  63. package/dist/tasks/compose-group/compose-group.js +1 -0
  64. package/dist/tasks/compose-group/prompt.d.ts +26 -0
  65. package/dist/tasks/compose-group/prompt.js +162 -0
  66. package/dist/tasks/compose-group/types.d.ts +62 -0
  67. package/dist/tasks/compose-group/types.js +1 -0
  68. package/dist/tasks/group/group.d.ts +6 -0
  69. package/dist/tasks/group/group.js +1 -0
  70. package/dist/tasks/group/prompt.d.ts +15 -0
  71. package/dist/tasks/group/prompt.js +158 -0
  72. package/dist/tasks/group/schema.d.ts +19 -0
  73. package/dist/tasks/group/schema.js +1 -0
  74. package/dist/tasks/group/types.d.ts +61 -0
  75. package/dist/tasks/group/types.js +1 -0
  76. package/dist/tasks/group/validator.d.ts +7 -0
  77. package/dist/tasks/group/validator.js +53 -0
  78. package/dist/tasks/index.d.ts +15 -0
  79. package/dist/tasks/index.js +1 -0
  80. package/dist/tasks/order/order.d.ts +6 -0
  81. package/dist/tasks/order/order.js +1 -0
  82. package/dist/tasks/order/prompt.d.ts +13 -0
  83. package/dist/tasks/order/prompt.js +45 -0
  84. package/dist/tasks/order/schema.d.ts +12 -0
  85. package/dist/tasks/order/schema.js +1 -0
  86. package/dist/tasks/order/types.d.ts +36 -0
  87. package/dist/tasks/order/types.js +1 -0
  88. package/dist/tasks/order/validator.d.ts +11 -0
  89. package/dist/tasks/order/validator.js +12 -0
  90. package/dist/tasks/partition/partition.d.ts +6 -0
  91. package/dist/tasks/partition/partition.js +1 -0
  92. package/dist/tasks/partition/prompt.d.ts +16 -0
  93. package/dist/tasks/partition/prompt.js +61 -0
  94. package/dist/tasks/partition/schema.d.ts +14 -0
  95. package/dist/tasks/partition/schema.js +1 -0
  96. package/dist/tasks/partition/types.d.ts +53 -0
  97. package/dist/tasks/partition/types.js +1 -0
  98. package/dist/tasks/partition/validator.d.ts +7 -0
  99. package/dist/tasks/partition/validator.js +11 -0
  100. package/dist/tasks/quick-compose/prompt.d.ts +18 -0
  101. package/dist/tasks/quick-compose/prompt.js +47 -0
  102. package/dist/tasks/quick-compose/quick-compose.d.ts +6 -0
  103. package/dist/tasks/quick-compose/quick-compose.js +1 -0
  104. package/dist/tasks/quick-compose/schema.d.ts +27 -0
  105. package/dist/tasks/quick-compose/schema.js +1 -0
  106. package/dist/tasks/quick-compose/types.d.ts +63 -0
  107. package/dist/tasks/quick-compose/types.js +1 -0
  108. package/dist/tasks/quick-compose/validator.d.ts +7 -0
  109. package/dist/tasks/quick-compose/validator.js +25 -0
  110. package/dist/tasks/session.d.ts +22 -0
  111. package/dist/tasks/session.js +1 -0
  112. package/dist/tasks/types.d.ts +101 -0
  113. package/dist/tasks/types.js +3 -0
  114. package/dist/workflows/compose.d.ts +371 -0
  115. package/dist/workflows/compose.js +2 -0
  116. package/dist/workflows/split.d.ts +80 -0
  117. package/dist/workflows/split.js +3 -0
  118. package/dist/workflows/types.d.ts +63 -0
  119. package/dist/workflows/types.js +1 -0
  120. package/dist/workflows/undo.d.ts +56 -0
  121. package/dist/workflows/undo.js +1 -0
  122. package/package.json +37 -0
@@ -0,0 +1,162 @@
1
+ import{groupingResultSchema as e}from"../group/schema.js";import{z as t}from"zod";const n=JSON.stringify(t.toJSONSchema(e),null,2),r=`
2
+ In addition to the \`branches\` field, include an \`analysis\` field at the top level:
3
+
4
+ \`\`\`json
5
+ {
6
+ "analysis": {
7
+ "concerns": ["description of theme 1", "description of theme 2"],
8
+ "key_dependencies": ["theme 1 defines types that theme 2 imports"]
9
+ },
10
+ "branches": [ ... ]
11
+ }
12
+ \`\`\`
13
+ `,i=`5. Write a commit message for each commit:
14
+ - First line: concise summary, 50 chars max, third-person singular present tense ("Fixes", "Adds", "Improves")
15
+ - Then a blank line followed by details focusing on "why" not "what"
16
+ - Informal yet professional tone`;function a(e,t=`branches`,n,r,i){return i?t===`commits`?u(e,n):d(e,n):t===`commits`?o(e,n,r):s(e,n,r)}function o(e,t,a){let o=e?.promptFragment?`5. Write a commit message for each commit following the repository's conventions (see below).
17
+ 6. Write a detailed explanation for each commit as if explaining to a reviewer.
18
+
19
+ ${e.promptFragment}`:`${i}
20
+ 6. Write a detailed explanation for each commit as if explaining to a reviewer`,s=l(t?.commitGranularity);return`You are an advanced AI programming assistant tasked with analyzing and organizing code changes into commits.
21
+
22
+ ${a?`## Step 1: Analysis`:`## Step 1: Internal Analysis`}
23
+
24
+ Before grouping, analyze the changes to understand:
25
+ - **Concerns** — what distinct themes, features, or purposes exist across the hunks
26
+ - **Dependencies** — which hunks provide things (define functions, types, files) that other hunks consume (import, call, reference)
27
+ - **Ordering constraints** — if hunk A defines something hunk B uses, they should be in the same commit or A's commit should come before B's
28
+
29
+ ${a?"Output this analysis as a JSON field named `analysis` alongside your `branches` field. The `analysis` field should contain:\n- `concerns`: array of strings, each describing a distinct theme or feature in the changes\n- `key_dependencies`: array of strings, each describing an ordering dependency between concerns":`Do NOT output this analysis. Use it internally to inform your grouping decisions.`}
30
+
31
+ ## Step 2: Group hunks into commits
32
+
33
+ 1. Group hunks into logical units that make sense together and can be applied atomically
34
+ 2. Use each hunk only once. Ensure all hunks are assigned to exactly one commit
35
+ 3. Ensure each commit is self-contained and atomic
36
+ 4. Each commit must have a unique ID (e.g., "commit-1", "commit-2")
37
+ 5. Every commit must contain at least one hunk. Do not produce empty commits — if you want to split a theme across multiple commits, each resulting commit needs its own hunks
38
+ ${o}
39
+ ${s}
40
+
41
+ ## Required Output Format
42
+
43
+ Output your organization as JSON inside a <output> tag matching this schema:
44
+
45
+ \`\`\`json
46
+ ${n}
47
+ \`\`\`
48
+ ${a?r:``}
49
+ Wrap all commits in a single branch object with id "default", name "", title "", and description "".
50
+
51
+ Remember:
52
+ - Every hunk must be assigned to exactly one commit
53
+ - Every commit must contain at least one hunk (no empty commits)
54
+ - Use exactly one branch with id "default", name "", title "", and description ""
55
+ - Return only the <output> tag and no other text.`}function s(e,t,a){let o=e?.promptFragment?`5. Write a commit message for each commit following the repository's conventions (see below).
56
+ 6. Write a detailed explanation for each commit as if explaining to a reviewer.
57
+
58
+ ${e.promptFragment}`:`${i}
59
+ 6. Write a detailed explanation for each commit as if explaining to a reviewer`,s=c(t?.branchSplitting,e),u=l(t?.commitGranularity);return`You are an advanced AI programming assistant tasked with analyzing and organizing code changes into commits and branches.
60
+
61
+ ${a?`## Step 1: Analysis`:`## Step 1: Internal Analysis`}
62
+
63
+ Before grouping, analyze the changes to understand:
64
+ - **Concerns** — what distinct themes, features, or purposes exist across the hunks
65
+ - **Dependencies** — which hunks provide things (define functions, types, files) that other hunks consume (import, call, reference)
66
+ - **Ordering constraints** — if hunk A defines something hunk B uses, they should be in the same commit or A's commit should come before B's
67
+ - **Merge-order preference** — even if two concerns compile independently, would merging one without the other be confusing or incomplete?
68
+
69
+ ${a?"Output this analysis as a JSON field named `analysis` alongside your `branches` field. The `analysis` field should contain:\n- `concerns`: array of strings, each describing a distinct theme or feature in the changes\n- `key_dependencies`: array of strings, each describing an ordering dependency between concerns":`Do NOT output this analysis. Use it internally to inform your grouping decisions.`}
70
+
71
+ ## Step 2: Organize hunks into commits and branches
72
+
73
+ Your job has two levels:
74
+
75
+ **Level 1: Commits** — group hunks into logical, atomic commits.
76
+ **Level 2: Branches** — group commits into branches, where each branch is a cohesive unit of work suitable for one pull request.
77
+
78
+ ### Commit guidelines
79
+
80
+ 1. Group hunks into logical units that make sense together and can be applied atomically
81
+ 2. Use each hunk only once. Ensure all hunks are assigned to exactly one commit
82
+ 3. Ensure each commit is self-contained and atomic
83
+ 4. Each commit must have a unique ID (e.g., "commit-1", "commit-2")
84
+ 5. Every commit must contain at least one hunk. Do not produce empty commits — if you want to split a theme across multiple commits, each resulting commit needs its own hunks
85
+ ${o}
86
+ ${u}
87
+
88
+ ### Branch guidelines
89
+
90
+ ${s}
91
+
92
+ ## Required Output Format
93
+
94
+ Output your organization as JSON inside a <output> tag matching this schema:
95
+
96
+ \`\`\`json
97
+ ${n}
98
+ \`\`\`
99
+ ${a?r:``}
100
+ Remember:
101
+ - Every hunk must be assigned to exactly one commit in exactly one branch
102
+ - Every commit must contain at least one hunk (no empty commits)
103
+ - Return only the <output> tag and no other text.`}function c(e,t){let n=`Each branch must have a descriptive name, a short PR-style title (under 72 characters, imperative mood), and at least one commit.`,r=`- Each commit belongs to exactly one branch.
104
+ ${t?.promptFragment?`- ${n} Follow the repository's branch naming conventions (see above).`:`- ${n}`}
105
+ - Changes addressing the same pattern across different files belong in ONE branch.`,i=`- Consider merge-order preference, not just code dependencies. Even if two concerns compile independently, they may need to be in the same branch if merging one without the other would be confusing or incomplete.`;return e===`conservative`?`${r}\n- Default to a single branch. Only create multiple branches when concerns are completely unrelated.\n${i}\n- When in doubt, use fewer branches.`:e===`aggressive`?`${r}\n- Create separate branches for each distinct concern.\n${i}\n- Prefer more branches over fewer.`:`${r}\n- Create separate branches when concerns are genuinely independent — meaning a reviewer would gain nothing from seeing them together.\n- Keep changes in the same branch when they form a coherent story.\n${i}\n- When in doubt: "Would a reviewer want to see these together?"`}function l(e){return e===`consolidated`?`
106
+ Prefer fewer, larger commits. Combine related changes into a single commit when they serve the same purpose.`:e===`granular`?`
107
+ Prefer more, smaller commits. Each distinct change should be its own commit.`:``}function u(e,t){return`Organize code hunks into clean, atomic commits.
108
+
109
+ ## Rules
110
+
111
+ 1. Group related hunks by purpose. All hunks of a renamed file must share a commit.
112
+ 2. Every hunk index (0 to N-1) in exactly one commit — no gaps, no duplicates.
113
+ 3. Each commit needs a unique ID (e.g. "commit-1", "commit-2").
114
+ 4. Every commit must have at least one hunk. No empty commits.
115
+ 5. ${e?.promptFragment?`Write commit messages following the repository's conventions (see below). Write a one-sentence explanation per commit.
116
+
117
+ ${e.promptFragment}`:`Write commit messages: first line under 50 chars, imperative mood ("Add", "Fix", "Update"). Write a one-sentence explanation per commit.`}
118
+ ${l(t?.commitGranularity)}
119
+
120
+ ## Output
121
+
122
+ JSON inside <output> tags. Use one branch with id "default", name "", title "", description "".
123
+
124
+ \`\`\`
125
+ {"branches":[{"id":"default","name":"","title":"","description":"","commits":[{"id":"commit-1","message":"Add feature X","explanation":"Brief reason.","hunks":[0,1,2]}]}]}
126
+ \`\`\`
127
+
128
+ CRITICAL: Every hunk index must appear exactly once across all commits. Every commit must contain at least one hunk. Missing hunks, duplicate hunks, or empty commits will fail validation. Return only the <output> tag.`}function d(e,t){let n=e?.promptFragment?`Write commit messages following the repository's conventions (see below). Write a one-sentence explanation per commit.
129
+
130
+ ${e.promptFragment}`:`Write commit messages: first line under 50 chars, third-person singular present tense ("Fixes", "Adds", "Improves"). Write a one-sentence explanation per commit.`,r=c(t?.branchSplitting,e);return`Organize code hunks into clean, atomic commits and branches.
131
+
132
+ ## Commit rules
133
+
134
+ 1. Group related hunks by purpose. All hunks of a renamed file must share a commit.
135
+ 2. Every hunk index (0 to N-1) in exactly one commit — no gaps, no duplicates.
136
+ 3. Each commit needs a unique ID (e.g., "commit-1", "commit-2").
137
+ 4. Every commit must have at least one hunk. No empty commits.
138
+ 5. ${n}
139
+ ${l(t?.commitGranularity)}
140
+
141
+ ## Branch guidelines
142
+
143
+ ${r}
144
+
145
+ ## Output
146
+
147
+ JSON inside <output> tags. Each branch needs a unique ID and non-empty name.
148
+
149
+ \`\`\`
150
+ {"branches":[{"id":"branch-1","name":"feat/example","title":"Add example","description":"Brief.","commits":[{"id":"commit-1","message":"Add X","explanation":"Reason.","hunks":[0,1]}]}]}
151
+ \`\`\`
152
+
153
+ CRITICAL: Every hunk index must appear exactly once across all commits in all branches. Every commit must contain at least one hunk. Missing hunks, duplicate hunks, or empty commits will fail validation. Each branch must have a unique ID and non-empty name.
154
+
155
+ Return only the <output> tag and no other text.`}function f(e){let{hunks:t,commitMessages:n,commitOrder:r,branchName:i,baseBranch:a,issueUrl:o,pullRequestUrl:s,instructions:c,condensed:l}=e,u=JSON.stringify(l?t.map(e=>({index:e.index,fileName:e.fileName,hunkHeader:e.hunkHeader,additions:e.additions,deletions:e.deletions,...e.isBinary?{isBinary:!0}:{},...e.isRename?{isRename:!0}:{},...e.originalFileName?{originalFileName:e.originalFileName}:{}})):t.map(e=>({index:e.index,fileName:e.fileName,hunkHeader:e.hunkHeader,content:e.content,...e.isBinary?{isBinary:!0}:{},...e.isRename?{isRename:!0}:{},...e.originalFileName?{originalFileName:e.originalFileName}:{}}))),d=`Organize these ${t.length} code hunks (indices 0 to ${t.length-1}) into commits. Every index must appear exactly once.
156
+
157
+ <hunks>
158
+ ${u}
159
+ </hunks>`,f=[];return i&&f.push(`Branch: ${i}`),a&&f.push(`Base: ${a}`),o&&f.push(`Issue: ${o}`),s&&f.push(`PR: ${s}`),f.length>0&&(d+=`\n\nContext:\n${f.join(`
160
+ `)}`),n?.length&&(d+=`\n\nOriginal commit messages (match their style):\n<commit_messages>\n${JSON.stringify(n)}\n</commit_messages>`),r?.length&&(d+=`\n\nOriginal commit order:\n${JSON.stringify(r)}`),c&&(d+=`\n\nAdditional instructions:\n${c}`),d+=`
161
+
162
+ Return only the <output> tag and no other text.`,d}export{a as buildComposeGroupSystemPrompt,f as buildComposeGroupUserPrompt};
@@ -0,0 +1,62 @@
1
+ import { ProgressEvent, TokenUsage } from "../../ai/types.js";
2
+ import { ComposeHunk, PromptOverride } from "../types.js";
3
+ import { ConventionDescriptor } from "../../git/utils/conventions.js";
4
+ import { OnAfterModelCall, OnBeforeModelCall, OnBeforePrompt } from "../ai-loop.js";
5
+ import { GroupingResult, GroupingStrategy } from "../group/types.js";
6
+ import { ComposeSession } from "../session.js";
7
+ import { AiModelPort } from "@gitkraken/shared-tools";
8
+
9
+ //#region src/tasks/compose-group/types.d.ts
10
+ /**
11
+ * Input for the compose-group task (balanced mode).
12
+ *
13
+ * Combines the context from analyze (branch/issue/commit order) with the
14
+ * grouping parameters from group, allowing the AI to reason about concerns
15
+ * and dependencies internally before producing a GroupingResult.
16
+ */
17
+ interface ComposeGroupInput {
18
+ hunks: ComposeHunk[];
19
+ commitMessages?: string[];
20
+ /** Commit SHAs in their original order — gives the AI chronological context. */
21
+ commitOrder?: string[];
22
+ branchName?: string;
23
+ baseBranch?: string;
24
+ issueUrl?: string;
25
+ pullRequestUrl?: string;
26
+ instructions?: string;
27
+ conventions?: ConventionDescriptor;
28
+ /** "commits" = flat commit list. "branches" = AI decides branches (default). */
29
+ mode?: 'commits' | 'branches';
30
+ /** Controls how aggressively the AI splits branches and commits. */
31
+ strategy?: GroupingStrategy;
32
+ /** Branch names that already exist — used to detect collisions during validation. */
33
+ existingBranchNames?: Set<string>;
34
+ /** When true, the AI outputs its analysis (concerns, dependencies) alongside grouping. */
35
+ includeAnalysis?: boolean;
36
+ /** When true, uses a minimal prompt without analysis instructions. For fast single-call compose. */
37
+ lightweight?: boolean;
38
+ /** When true, sends only hunk metadata (fileName, hunkHeader, counts) without diff content. */
39
+ condensed?: boolean;
40
+ model: AiModelPort;
41
+ /** Prior session to resume from. When `completedSteps.composeGroup` is present, skip the AI call. */
42
+ session?: ComposeSession;
43
+ maxRetries?: number;
44
+ onProgress?: (event: ProgressEvent) => void;
45
+ signal?: AbortSignal;
46
+ onBeforeModelCall?: OnBeforeModelCall;
47
+ onAfterModelCall?: OnAfterModelCall;
48
+ onBeforePrompt?: OnBeforePrompt;
49
+ /** Optional prompt override. When set, replaces or decorates the built-in prompts. */
50
+ promptOverride?: PromptOverride;
51
+ }
52
+ /** Same output type as the standard group task. */
53
+ type ComposeGroupOutput = {
54
+ result: GroupingResult;
55
+ session: ComposeSession;
56
+ usage?: TokenUsage;
57
+ attempts: number;
58
+ durationMs: number;
59
+ callIds: string[];
60
+ };
61
+ //#endregion
62
+ export { ComposeGroupInput, ComposeGroupOutput };
@@ -0,0 +1 @@
1
+ export{};
@@ -0,0 +1,6 @@
1
+ import { GroupInput, GroupOutput } from "./types.js";
2
+
3
+ //#region src/tasks/group/group.d.ts
4
+ declare function group(input: GroupInput): Promise<GroupOutput>;
5
+ //#endregion
6
+ export { group };
@@ -0,0 +1 @@
1
+ import{TaskInputError as e}from"../../errors/task.js";import{runAiLoop as t}from"../ai-loop.js";import{applyUserPromptOverride as n}from"../types.js";import{validateGroupResponse as r}from"./validator.js";import{buildGroupContinuationPrompt as i,buildGroupSystemPrompt as a,buildGroupUserPrompt as o}from"./prompt.js";async function s(s){let c=s.hunks,l=s.mode??`branches`;if((!c||c.length===0)&&!s.session)throw new e(`No hunks provided: supply 'hunks' or run analyze() first with a session`);if(s.session?.completedSteps.group)return{result:s.session.completedSteps.group,session:s.session,attempts:0,durationMs:0,callIds:[]};let u=n(s.session?i(s,l):o({hunks:c,commitMessages:s.commitMessages,instructions:s.instructions,mode:l}),s.promptOverride),d=c?.length??s.session?.completedSteps.analyze?.hunkAnnotations.length??0;if(d===0)throw new e(`Cannot validate grouping: no hunk count available from input or session`);let f=await t({model:s.model,systemPrompt:s.session?void 0:s.promptOverride?.system??a(s.conventions,l,s.strategy),userPrompt:u,session:s.session,maxRetries:s.maxRetries,onProgress:s.onProgress,signal:s.signal,onBeforeModelCall:s.onBeforeModelCall,onAfterModelCall:s.onAfterModelCall,onBeforePrompt:s.onBeforePrompt,validate:e=>r(e,d,l,s.existingBranchNames),taskName:`group`}),p=s.session?.completedSteps??{},m={...f.session,completedSteps:{...p,group:f.result}};return{result:f.result,session:m,usage:f.usage,attempts:f.attempts,durationMs:f.durationMs,callIds:f.callIds}}export{s as group};
@@ -0,0 +1,15 @@
1
+ import { ComposeHunk } from "../types.js";
2
+ import { ConventionDescriptor } from "../../git/utils/conventions.js";
3
+ import { GroupInput, GroupingStrategy } from "./types.js";
4
+
5
+ //#region src/tasks/group/prompt.d.ts
6
+ declare function buildGroupSystemPrompt(conventions?: ConventionDescriptor, mode?: 'commits' | 'branches', strategy?: GroupingStrategy): string;
7
+ declare function buildGroupUserPrompt(params: {
8
+ hunks: ComposeHunk[];
9
+ commitMessages?: string[];
10
+ instructions?: string;
11
+ mode?: 'commits' | 'branches';
12
+ }): string;
13
+ declare function buildGroupContinuationPrompt(input: GroupInput, mode: 'commits' | 'branches'): string;
14
+ //#endregion
15
+ export { buildGroupContinuationPrompt, buildGroupSystemPrompt, buildGroupUserPrompt };
@@ -0,0 +1,158 @@
1
+ import{groupingResultSchema as e}from"./schema.js";import{z as t}from"zod";const n=JSON.stringify(t.toJSONSchema(e),null,2),r=`5. Write a commit message for each commit:
2
+ - First line: concise summary, 50 chars max, third-person singular present tense ("Fixes", "Adds", "Improves")
3
+ - Then a blank line followed by details focusing on "why" not "what"
4
+ - Informal yet professional tone`,i=`Each branch must have a descriptive name, a short PR-style title (under 72 characters, imperative mood), and at least one commit.`;function a(e,t=`branches`,n){return t===`commits`?o(e,n):s(e,n)}function o(e,t){return`You are an advanced AI programming assistant tasked with organizing code changes into commits. You will be working with individual code hunks.
5
+
6
+ ## Commit guidelines
7
+
8
+ 1. Group hunks into logical units that make sense together and can be applied atomically
9
+ 2. Use each hunk only once. Ensure all hunks are assigned to exactly one commit
10
+ 3. Ensure each commit is self-contained and atomic
11
+ 4. Each commit must have a unique ID (e.g., "commit-1", "commit-2")
12
+ 5. Every commit must contain at least one hunk. Do not produce empty commits
13
+ ${e?.promptFragment?`5. Write a commit message for each commit following the repository's conventions (see below).
14
+ 6. Write a detailed explanation for each commit as if explaining to a reviewer.
15
+
16
+ ${e.promptFragment}`:`${r}
17
+ 6. Write a detailed explanation for each commit as if explaining to a reviewer`}
18
+ ${l(t?.commitGranularity)}
19
+
20
+ ## Required Output Format
21
+
22
+ Output your organization as JSON inside a <output> tag matching this schema:
23
+
24
+ \`\`\`json
25
+ ${n}
26
+ \`\`\`
27
+
28
+ Wrap all commits in a single branch object with id "default", name "", title "", and description "".
29
+
30
+ Remember:
31
+ - Every hunk must be assigned to exactly one commit
32
+ - Every commit must contain at least one hunk (no empty commits)
33
+ - Use exactly one branch with id "default", name "", title "", and description ""
34
+ - Return only the <output> tag and no other text.`}function s(e,t){let i=e?.promptFragment?`5. Write a commit message for each commit following the repository's conventions (see below).
35
+ 6. Write a detailed explanation for each commit as if explaining to a reviewer.
36
+
37
+ ${e.promptFragment}`:`${r}
38
+ 6. Write a detailed explanation for each commit as if explaining to a reviewer`,a=c(t?.branchSplitting,e);return`You are an advanced AI programming assistant tasked with organizing code changes into commits and branches. You will be working with individual code hunks.
39
+
40
+ Your job has two levels:
41
+
42
+ **Level 1: Commits** — group hunks into logical, atomic commits.
43
+ **Level 2: Branches** — group commits into branches, where each branch is a cohesive unit of work suitable for one pull request.
44
+
45
+ ## Commit guidelines
46
+
47
+ 1. Group hunks into logical units that make sense together and can be applied atomically
48
+ 2. Use each hunk only once. Ensure all hunks are assigned to exactly one commit
49
+ 3. Ensure each commit is self-contained and atomic
50
+ 4. Each commit must have a unique ID (e.g., "commit-1", "commit-2")
51
+ 5. Every commit must contain at least one hunk. Do not produce empty commits
52
+ ${i}
53
+ ${l(t?.commitGranularity)}
54
+
55
+ ## Branch guidelines
56
+
57
+ ${a}
58
+
59
+ ## Required Output Format
60
+
61
+ Output your organization as JSON inside a <output> tag matching this schema:
62
+
63
+ \`\`\`json
64
+ ${n}
65
+ \`\`\`
66
+
67
+ Remember:
68
+ - Every hunk must be assigned to exactly one commit in exactly one branch
69
+ - Every commit must contain at least one hunk (no empty commits)
70
+ - Return only the <output> tag and no other text.`}function c(e,t){let n=`- Each commit belongs to exactly one branch.
71
+ ${t?.promptFragment?`- ${i} Follow the repository's branch naming conventions (see above).`:`- ${i}`}
72
+ - Changes addressing the same pattern across different files belong in ONE branch. For example, applying the same bug fix to multiple functions, or updating similar config across modules — these are the same concern even if the files are different.`,r=`- Consider merge-order preference, not just code dependencies. Even if two concerns compile independently, they may need to be in the same branch or stacked branches if merging one without the other would be confusing or incomplete (e.g., documentation that describes utilities introduced in other commits should be in the same branch or stacked after those utilities).`;return e===`conservative`?`${n}
73
+ - Default to a single branch. Only create multiple branches when concerns are completely unrelated — different domains, different purposes, and no merge-order preference between them.
74
+ ${r}
75
+ - When in doubt, use fewer branches.`:e===`aggressive`?`${n}
76
+ - Create separate branches for each distinct concern. If changes touch different features, different subsystems, or solve different problems, they should be in separate branches even if they are in a related domain.
77
+ ${r}
78
+ - Prefer more branches over fewer. Each PR should be as focused as possible.`:`${n}
79
+ - Create separate branches when concerns are genuinely independent — meaning they address different problems or features, and a reviewer would gain nothing from seeing them together in one PR. Two commits that each add a separate utility function unrelated to each other are good candidates for independent branches.
80
+ - Keep changes in the same branch when they form a coherent story that benefits from being reviewed together, even if they could technically stand alone.
81
+ ${r}
82
+ - When in doubt, consider: "Would a reviewer want to see these changes together, or would separating them make review easier?" If separating helps, split.`}function l(e){return e===`consolidated`?`
83
+ Prefer fewer, larger commits. Combine related changes into a single commit when they serve the same purpose. A commit can touch many files if they are all part of the same logical change.`:e===`granular`?`
84
+ Prefer more, smaller commits. Each distinct change should be its own commit, even if multiple changes serve a similar purpose. Aim for commits that touch as few files as possible.`:``}function u(e){let{hunks:t,commitMessages:n,instructions:r,mode:i=`branches`}=e,a=JSON.stringify(t.map(e=>({index:e.index,fileName:e.fileName,hunkHeader:e.hunkHeader,content:e.content,...e.isBinary?{isBinary:!0}:{},...e.isRename?{isRename:!0}:{},...e.originalFileName?{originalFileName:e.originalFileName}:{}}))),o=`${i===`commits`?`Examine the following ${t.length} code hunks (indices 0 to ${t.length-1}) and organize them into commits. Every index must appear exactly once.`:`Examine the following ${t.length} code hunks (indices 0 to ${t.length-1}) and organize them into commits and branches. Every index must appear exactly once.`}
85
+
86
+ <hunks>
87
+ ${a}
88
+ </hunks>`;return n?.length&&(o+=`
89
+
90
+ The following commit messages are from the original commits. Use them to understand intent and match their style:
91
+
92
+ <commit_messages>
93
+ ${JSON.stringify(n)}
94
+ </commit_messages>`),r&&(o+=`
95
+
96
+ Carefully follow these additional instructions, but do not deviate from the output structure:
97
+ ${r}`),o+=`\n\n${i===`commits`?`Now organize the hunks into commits.`:`Now organize the hunks into commits and branches.`} Return only the <output> tag and no other text.`,o}function d(e,t){let n;return n=t===`commits`?`Based on your analysis of the changes, now organize the hunks into commits. Each hunk must be assigned to exactly one commit.`:f(e.strategy),e.conventions?.promptFragment&&(n+=`\n\n${e.conventions.promptFragment}`),e.commitMessages?.length&&(n+=`\n\nMatch the style of these original commit messages:\n${JSON.stringify(e.commitMessages)}`),e.instructions&&(n+=`\n\nAdditional instructions:\n${e.instructions}`),t===`commits`?n+=`
98
+
99
+ Return your grouping as JSON inside <output> tags. Wrap all commits in a single branch with id "default", name "", title "", description "":
100
+ <output>
101
+ {
102
+ "branches": [
103
+ {
104
+ "id": "default",
105
+ "name": "",
106
+ "title": "",
107
+ "description": "",
108
+ "commits": [
109
+ {
110
+ "id": "[commit id]",
111
+ "message": "[commit message]",
112
+ "explanation": "[explanation]",
113
+ "hunks": [0, 1, 2]
114
+ }
115
+ ]
116
+ }
117
+ ]
118
+ }
119
+ </output>
120
+
121
+ Return only the <output> tag and no other text.`:n+=`
122
+
123
+ Return your grouping as JSON inside <output> tags:
124
+ <output>
125
+ {
126
+ "branches": [
127
+ {
128
+ "id": "[branch id]",
129
+ "name": "[branch name]",
130
+ "title": "[short PR title]",
131
+ "description": "[branch description]",
132
+ "commits": [
133
+ {
134
+ "id": "[commit id]",
135
+ "message": "[commit message]",
136
+ "explanation": "[explanation]",
137
+ "hunks": [0, 1, 2]
138
+ }
139
+ ]
140
+ }
141
+ ]
142
+ }
143
+ </output>
144
+
145
+ Return only the <output> tag and no other text.`,n}function f(e){let t=e?.branchSplitting??`balanced`,n=`Based on your analysis of the changes, now organize the hunks into commits and branches. Each hunk must be assigned to exactly one commit, and each commit belongs to exactly one branch.`,r=`Consider merge-order preference: even if two concerns compile independently, they should be in the same branch or stacked if merging one without the other would be incomplete or confusing (e.g., documentation for utilities should be with or after those utilities).`;return t===`conservative`?`${n}
146
+
147
+ Default to a single branch. Only create multiple branches when concerns are completely unrelated — different domains, different purposes, no merge-order preference.
148
+ ${r}
149
+ When in doubt, use fewer branches.`:t===`aggressive`?`${n}
150
+
151
+ Create separate branches for each distinct concern. If changes address different features or subsystems, give each its own branch. Prefer more branches over fewer — each PR should be as focused as possible.
152
+ ${r}`:`${n}
153
+
154
+ Create separate branches when concerns are genuinely independent — different problems or features where a reviewer would gain nothing from seeing them together in one PR. For example, a utility function addition and an unrelated error handling improvement are good candidates for separate branches.
155
+
156
+ Keep changes in the same branch when they form a coherent story that benefits from joint review, or when there is a merge-order preference between them.
157
+ ${r}
158
+ When in doubt, consider: "Would a reviewer want to see these together, or would separating them make review easier?"`}export{d as buildGroupContinuationPrompt,a as buildGroupSystemPrompt,u as buildGroupUserPrompt};
@@ -0,0 +1,19 @@
1
+ import { z } from "zod";
2
+
3
+ //#region src/tasks/group/schema.d.ts
4
+ declare const groupingResultSchema: z.ZodObject<{
5
+ branches: z.ZodArray<z.ZodObject<{
6
+ id: z.ZodString;
7
+ name: z.ZodString;
8
+ title: z.ZodString;
9
+ description: z.ZodString;
10
+ commits: z.ZodArray<z.ZodObject<{
11
+ id: z.ZodString;
12
+ message: z.ZodString;
13
+ explanation: z.ZodString;
14
+ hunks: z.ZodArray<z.ZodNumber>;
15
+ }, z.core.$strip>>;
16
+ }, z.core.$strip>>;
17
+ }, z.core.$strip>;
18
+ //#endregion
19
+ export { groupingResultSchema };
@@ -0,0 +1 @@
1
+ import{z as e}from"zod";const t=e.object({id:e.string().describe(`Unique commit ID (e.g. commit-1)`),message:e.string().describe(`Commit message`),explanation:e.string().describe(`Detailed explanation of the commit`),hunks:e.array(e.number().int().describe(`Hunk index`)).describe(`Hunk indices included in this commit`)}),n=e.object({id:e.string().min(1).describe(`Unique branch ID`),name:e.string().describe(`Branch name (empty string for commits-only mode)`),title:e.string().describe(`Short PR-style title for this branch (under 72 chars, imperative mood, e.g. 'Add user authentication')`),description:e.string().describe(`What this branch accomplishes`),commits:e.array(t).min(1).describe(`Commits in this branch`)}),r=e.object({branches:e.array(n).min(1).describe(`Branches containing grouped commits`)});export{r as groupingResultSchema};
@@ -0,0 +1,61 @@
1
+ import { ProgressEvent, TokenUsage } from "../../ai/types.js";
2
+ import { BranchGroup, ComposeHunk, PromptOverride } from "../types.js";
3
+ import { ConventionDescriptor } from "../../git/utils/conventions.js";
4
+ import { OnAfterModelCall, OnBeforeModelCall, OnBeforePrompt } from "../ai-loop.js";
5
+ import { AnalysisResult } from "../analyze/types.js";
6
+ import { ComposeSession } from "../session.js";
7
+ import { AiModelPort } from "@gitkraken/shared-tools";
8
+
9
+ //#region src/tasks/group/types.d.ts
10
+ interface GroupingStrategy {
11
+ /**
12
+ * How aggressively to split changes into separate branches.
13
+ * - "conservative": default to one branch; only split when concerns are completely unrelated
14
+ * - "balanced": split when concerns are independent, even if they touch a similar domain (default)
15
+ * - "aggressive": maximize branch count; any distinct concern gets its own branch
16
+ */
17
+ branchSplitting?: 'conservative' | 'balanced' | 'aggressive';
18
+ /**
19
+ * How aggressively to split changes into multiple commits vs consolidating.
20
+ * - "consolidated": fewer, larger commits; combine related changes
21
+ * - "balanced": natural grouping by logical unit of work (default)
22
+ * - "granular": maximize commit count; each distinct change gets its own commit
23
+ */
24
+ commitGranularity?: 'consolidated' | 'balanced' | 'granular';
25
+ }
26
+ interface GroupInput {
27
+ hunks?: ComposeHunk[];
28
+ analysis?: AnalysisResult;
29
+ commitMessages?: string[];
30
+ instructions?: string;
31
+ conventions?: ConventionDescriptor;
32
+ /** "commits" = flat commit list (no branch naming). "branches" = AI decides branches (default). */
33
+ mode?: 'commits' | 'branches';
34
+ /** Controls how aggressively the AI splits branches and commits. */
35
+ strategy?: GroupingStrategy;
36
+ /** Branch names that already exist in the repo — used to detect collisions during validation. */
37
+ existingBranchNames?: Set<string>;
38
+ model: AiModelPort;
39
+ session?: ComposeSession;
40
+ maxRetries?: number;
41
+ onProgress?: (event: ProgressEvent) => void;
42
+ signal?: AbortSignal;
43
+ onBeforeModelCall?: OnBeforeModelCall;
44
+ onAfterModelCall?: OnAfterModelCall;
45
+ onBeforePrompt?: OnBeforePrompt;
46
+ /** Optional prompt override. When set, replaces or decorates the built-in prompts. */
47
+ promptOverride?: PromptOverride;
48
+ }
49
+ interface GroupingResult {
50
+ branches: BranchGroup[];
51
+ }
52
+ interface GroupOutput {
53
+ result: GroupingResult;
54
+ session: ComposeSession;
55
+ usage?: TokenUsage;
56
+ attempts: number;
57
+ durationMs: number;
58
+ callIds: string[];
59
+ }
60
+ //#endregion
61
+ export { GroupInput, GroupOutput, GroupingResult, GroupingStrategy };
@@ -0,0 +1 @@
1
+ export{};
@@ -0,0 +1,7 @@
1
+ import { ValidationResult } from "../ai-loop.js";
2
+ import { GroupingResult } from "./types.js";
3
+
4
+ //#region src/tasks/group/validator.d.ts
5
+ declare function validateGroupResponse(responseText: string, totalHunks: number, mode?: 'commits' | 'branches', existingBranchNames?: Set<string>): ValidationResult<GroupingResult>;
6
+ //#endregion
7
+ export { validateGroupResponse };
@@ -0,0 +1,53 @@
1
+ import{extractOutputTag as e}from"../ai-loop.js";import{groupingResultSchema as t}from"./schema.js";function n(n,a,o=`branches`,s){let c=null;try{if(c=e(n),!c)return r([`No <output> tag found in response`],i(o));let l=JSON.parse(c),u=t.safeParse(l);if(!u.success)return r(u.error.issues.map(e=>`${e.path.join(`.`)}: ${e.message}`),i(o));let d=u.data,f=[],p=new Set,m=[],h=new Set,g=[],_=[],v=new Set,y=new Set;for(let e of d.branches){if(v.has(e.id))return r([`Duplicate branch ID: '${e.id}'`],i(o));if(v.add(e.id),o===`branches`&&e.name.length===0)return r([`Branch '${e.id}': missing or empty 'name'`],i(o));if(o===`branches`&&e.name.length>0){if(y.has(e.name))return r([`Duplicate branch name: '${e.name}'`],`Multiple branches use the name '${e.name}'. Each branch must have a unique name. Please rename one of them.`);if(y.add(e.name),s?.has(e.name))return r([`Branch name '${e.name}' already exists in the repository`],`The branch name '${e.name}' already exists in the repository. Please choose a different name for branch '${e.id}'.`)}let t=[];for(let n of e.commits){h.has(n.id)&&g.push(n.id),h.add(n.id);let e=[];for(let t of n.hunks)p.has(t)&&m.push(t),p.add(t),e.push(t);e.length===0&&_.push(n.id),t.push({id:n.id,message:n.message,explanation:n.explanation,hunkIndices:e})}f.push({id:e.id,name:e.name,title:e.title,description:e.description,commits:t})}if(g.length>0)return r([`Duplicate commit IDs: ${g.join(`, `)}`],`Some commit IDs appear multiple times. Each must be unique.\n\nDuplicates: ${g.join(`, `)}`);if(_.length>0)return r([`Empty commits (no hunks assigned): ${_.join(`, `)}`],`Every commit must contain at least one hunk. These commits have an empty \`hunks\` array: ${_.join(`, `)}.
2
+
3
+ Either assign at least one hunk to each of these commits, or remove them entirely. If a commit's purpose is already covered by another commit, remove the duplicate. If a commit is supposed to cover specific hunks, assign those hunk indices to it. Every hunk index still needs to appear in exactly one commit.`);let b=new Set(Array.from({length:a},(e,t)=>t)),x=[...b].filter(e=>!p.has(e)),S=[...p].filter(e=>!b.has(e));if(m.length>0||x.length>0||S.length>0){let e=[],t=[];return m.length>0&&(e.push(`Duplicate hunks (assigned to multiple commits): ${m.join(`, `)}`),t.push(`Duplicate hunks: ${m.join(`, `)}`)),x.length>0&&(e.push(`Missing hunks (not assigned to any commit): ${x.join(`, `)}`),t.push(`Missing hunks: ${x.join(`, `)}`)),S.length>0&&(e.push(`Extra hunks (index out of range): ${S.join(`, `)}`),t.push(`Extra hunks: ${S.join(`, `)}`)),r(t,`There are ${a} hunks (indices 0 to ${a-1}). Every index must appear in exactly one commit — no duplicates, no gaps, no out-of-range indices.
4
+
5
+ Your response has these problems:
6
+ ${e.map(e=>`- ${e}`).join(`
7
+ `)}
8
+
9
+ Fix these specific issues and return the corrected JSON inside <output> tags.`)}return{valid:!0,result:{branches:f}}}catch(e){let t=e instanceof Error?e.message:String(e),a=(c??n).substring(0,200);return r([`Failed to parse response as valid JSON: ${t}`,`Response preview: ${a}`],i(o))}}function r(e,t){return{valid:!1,errors:e,retryFeedback:t}}function i(e){return e===`commits`?`Your response has an invalid structure. Please return JSON inside <output> tags. Use a single branch with id "default", name "", description "":
10
+ <output>
11
+ {
12
+ "branches": [
13
+ {
14
+ "id": "default",
15
+ "name": "",
16
+ "title": "",
17
+ "description": "",
18
+ "commits": [
19
+ {
20
+ "id": "[commit id]",
21
+ "message": "[commit message]",
22
+ "explanation": "[explanation]",
23
+ "hunks": [0, 1, 2]
24
+ }
25
+ ]
26
+ }
27
+ ]
28
+ }
29
+ </output>
30
+
31
+ Return only the <output> tag and no other text.`:`Your response has an invalid structure. Please return JSON inside <output> tags:
32
+ <output>
33
+ {
34
+ "branches": [
35
+ {
36
+ "id": "[branch id]",
37
+ "name": "[branch name]",
38
+ "title": "[short PR title]",
39
+ "description": "[branch description]",
40
+ "commits": [
41
+ {
42
+ "id": "[commit id]",
43
+ "message": "[commit message]",
44
+ "explanation": "[explanation]",
45
+ "hunks": [0, 1, 2]
46
+ }
47
+ ]
48
+ }
49
+ ]
50
+ }
51
+ </output>
52
+
53
+ Return only the <output> tag and no other text.`}export{n as validateGroupResponse};
@@ -0,0 +1,15 @@
1
+ import { BranchGroup, BranchOrdering, BranchPartition, CommitDetail, CommitSuggestion, ComposeHunk, ComposeTaskName, PromptOverride } from "./types.js";
2
+ import { AnalysisResult, AnalyzeInput, AnalyzeOutput, Concern, ConcernDependency, HunkAnnotation, HunkOrderingConstraint } from "./analyze/types.js";
3
+ import { GroupInput, GroupOutput, GroupingResult, GroupingStrategy } from "./group/types.js";
4
+ import { OrderInput, OrderOutput, OrderingResult } from "./order/types.js";
5
+ import { QuickComposeInput, QuickComposeOutput, QuickComposeResult } from "./quick-compose/types.js";
6
+ import { ComposeSession } from "./session.js";
7
+ import { PartitionInput, PartitionOutput, PartitionResult, PartitionStrategy } from "./partition/types.js";
8
+ import { analyze } from "./analyze/analyze.js";
9
+ import { ComposeGroupInput, ComposeGroupOutput } from "./compose-group/types.js";
10
+ import { composeGroup } from "./compose-group/compose-group.js";
11
+ import { group } from "./group/group.js";
12
+ import { order } from "./order/order.js";
13
+ import { partition } from "./partition/partition.js";
14
+ import { quickCompose } from "./quick-compose/quick-compose.js";
15
+ export { type AnalysisResult, type AnalyzeInput, type AnalyzeOutput, type BranchGroup, type BranchOrdering, type BranchPartition, type CommitDetail, type CommitSuggestion, type ComposeGroupInput, type ComposeGroupOutput, type ComposeHunk, type ComposeSession, type ComposeTaskName, type Concern, type ConcernDependency, type GroupInput, type GroupOutput, type GroupingResult, type GroupingStrategy, type HunkAnnotation, type HunkOrderingConstraint, type OrderInput, type OrderOutput, type OrderingResult, type PartitionInput, type PartitionOutput, type PartitionResult, type PartitionStrategy, type PromptOverride, type QuickComposeInput, type QuickComposeOutput, type QuickComposeResult, analyze, composeGroup, group, order, partition, quickCompose };
@@ -0,0 +1 @@
1
+ import{analyze as e}from"./analyze/analyze.js";import{composeGroup as t}from"./compose-group/compose-group.js";import{group as n}from"./group/group.js";import{order as r}from"./order/order.js";import{partition as i}from"./partition/partition.js";import{quickCompose as a}from"./quick-compose/quick-compose.js";export{e as analyze,t as composeGroup,n as group,r as order,i as partition,a as quickCompose};
@@ -0,0 +1,6 @@
1
+ import { OrderInput, OrderOutput } from "./types.js";
2
+
3
+ //#region src/tasks/order/order.d.ts
4
+ declare function order(input: OrderInput): Promise<OrderOutput>;
5
+ //#endregion
6
+ export { order };
@@ -0,0 +1 @@
1
+ import{TaskInputError as e}from"../../errors/task.js";import{runAiLoop as t}from"../ai-loop.js";import{applyUserPromptOverride as n}from"../types.js";import{buildOrderContinuationPrompt as r,buildOrderSystemPrompt as i,buildOrderUserPrompt as a}from"./prompt.js";import{validateOrderResponse as o}from"./validator.js";async function s(s){let c=s.branches??s.session?.completedSteps.group?.branches;if((!c||c.length===0)&&!s.session)throw new e(`No branches provided: supply 'branches' or run group() first with a session`);if(s.session?.completedSteps.order)return{result:s.session.completedSteps.order,session:s.session,attempts:0,durationMs:0,callIds:[]};let l=(c??[]).map(e=>({branchId:e.id,commitIds:e.commits.map(e=>e.id)})),u=n(s.session?r(s):a({branches:c,hunks:s.hunks,instructions:s.instructions}),s.promptOverride),d=await t({model:s.model,systemPrompt:s.session?void 0:s.promptOverride?.system??i(),userPrompt:u,session:s.session,maxRetries:s.maxRetries,onProgress:s.onProgress,signal:s.signal,onBeforeModelCall:s.onBeforeModelCall,onAfterModelCall:s.onAfterModelCall,onBeforePrompt:s.onBeforePrompt,validate:e=>o(e,l),taskName:`order`}),f=s.session?.completedSteps??{},p={...d.session,completedSteps:{...f,order:d.result}};return{result:d.result,session:p,usage:d.usage,attempts:d.attempts,durationMs:d.durationMs,callIds:d.callIds}}export{s as order};
@@ -0,0 +1,13 @@
1
+ import { BranchGroup, ComposeHunk } from "../types.js";
2
+ import { OrderInput } from "./types.js";
3
+
4
+ //#region src/tasks/order/prompt.d.ts
5
+ declare function buildOrderSystemPrompt(): string;
6
+ declare function buildOrderUserPrompt(params: {
7
+ branches: BranchGroup[];
8
+ hunks?: ComposeHunk[];
9
+ instructions?: string;
10
+ }): string;
11
+ declare function buildOrderContinuationPrompt(input: OrderInput): string;
12
+ //#endregion
13
+ export { buildOrderContinuationPrompt, buildOrderSystemPrompt, buildOrderUserPrompt };