@gitkraken/compose-tools 0.1.0 → 0.3.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.
- package/CHANGELOG.md +72 -1
- package/README.md +109 -22
- package/dist/errors/workflow.d.ts +16 -6
- package/dist/errors/workflow.js +1 -1
- package/dist/git/apply-branches.d.ts +0 -2
- package/dist/git/apply-branches.js +1 -1
- package/dist/git/apply-target.d.ts +10 -3
- package/dist/git/apply-target.js +1 -1
- package/dist/git/commit-chain.d.ts +47 -33
- package/dist/git/commit-chain.js +7 -5
- package/dist/git/diff-collector.d.ts +69 -19
- package/dist/git/diff-collector.js +6 -7
- package/dist/git/index.d.ts +2 -2
- package/dist/git/index.js +1 -1
- package/dist/git/port-dispatch.d.ts +11 -3
- package/dist/git/port-dispatch.js +4 -3
- package/dist/git/reparent.d.ts +39 -0
- package/dist/git/reparent.js +5 -0
- package/dist/git/require-exec.js +1 -1
- package/dist/git/safety-range.d.ts +33 -0
- package/dist/git/safety-range.js +5 -0
- package/dist/git/safety.d.ts +3 -3
- package/dist/git/safety.js +1 -1
- package/dist/git/types.d.ts +16 -15
- package/dist/git/utils/authorship.d.ts +22 -0
- package/dist/git/utils/authorship.js +1 -0
- package/dist/git/utils/conventions.d.ts +0 -1
- package/dist/git/utils/conventions.js +4 -4
- package/dist/git/utils/hunk-parser.d.ts +1 -1
- package/dist/git/utils/hunk-parser.js +1 -1
- package/dist/git/utils/temp-index.d.ts +1 -1
- package/dist/git/utils/temp-index.js +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.js +1 -1
- package/dist/ports/git.d.ts +48 -7
- package/dist/tasks/ai-loop.d.ts +9 -15
- package/dist/tasks/ai-loop.js +2 -2
- package/dist/tasks/analyze/analyze.js +1 -1
- package/dist/tasks/analyze/prompt.d.ts +2 -0
- package/dist/tasks/analyze/prompt.js +5 -5
- package/dist/tasks/analyze/types.d.ts +6 -1
- package/dist/tasks/analyze/validator.js +1 -1
- package/dist/tasks/compose-group/compose-group.js +1 -1
- package/dist/tasks/compose-group/prompt.d.ts +2 -0
- package/dist/tasks/compose-group/prompt.js +52 -46
- package/dist/tasks/compose-group/types.d.ts +6 -1
- package/dist/tasks/group/group.js +1 -1
- package/dist/tasks/group/prompt.d.ts +2 -0
- package/dist/tasks/group/prompt.js +45 -39
- package/dist/tasks/group/types.d.ts +6 -1
- package/dist/tasks/group/validator.js +9 -4
- package/dist/tasks/order/order.js +1 -1
- package/dist/tasks/order/types.d.ts +3 -1
- package/dist/tasks/order/validator.js +1 -1
- package/dist/tasks/partition/partition.js +1 -1
- package/dist/tasks/partition/types.d.ts +3 -1
- package/dist/tasks/partition/validator.js +1 -1
- package/dist/tasks/quick-compose/prompt.d.ts +2 -0
- package/dist/tasks/quick-compose/prompt.js +24 -15
- package/dist/tasks/quick-compose/quick-compose.js +1 -1
- package/dist/tasks/quick-compose/types.d.ts +6 -1
- package/dist/tasks/quick-compose/validator.js +10 -2
- package/dist/tasks/types.d.ts +10 -9
- package/dist/tasks/utils/redact.d.ts +14 -0
- package/dist/tasks/utils/redact.js +1 -0
- package/dist/utils/cancellation.d.ts +26 -0
- package/dist/utils/cancellation.js +1 -0
- package/dist/workflows/compose.d.ts +89 -10
- package/dist/workflows/compose.js +3 -2
- package/dist/workflows/split.d.ts +14 -3
- package/dist/workflows/split.js +3 -3
- package/dist/workflows/types.d.ts +46 -18
- package/dist/workflows/undo.d.ts +18 -11
- package/dist/workflows/undo.js +1 -1
- package/package.json +2 -2
- package/dist/cancellation.d.ts +0 -20
- package/dist/cancellation.js +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ComposeHunk } from "../../tasks/types.js";
|
|
2
2
|
|
|
3
3
|
//#region src/git/utils/hunk-parser.d.ts
|
|
4
|
-
declare function parseUnifiedDiff(diffText: string,
|
|
4
|
+
declare function parseUnifiedDiff(diffText: string, startIndex?: number): ComposeHunk[];
|
|
5
5
|
//#endregion
|
|
6
6
|
export { parseUnifiedDiff };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const e=/^diff --git /m,t=/^@@ /m;function n(e,t
|
|
1
|
+
const e=/^diff --git /m,t=/^@@ /m;function n(e,t=0){if(!e.trim())return[];let n=r(e),a=[],o=t;for(let e of n){let{diffHeader:t,fileName:n,originalFileName:r,isRename:s,isBinary:c,binaryPatchData:l,hunkSections:u}=i(e);if(c){a.push({index:o++,fileName:n,diffHeader:t,hunkHeader:``,content:`Binary file change`,additions:0,deletions:0,isRename:s,originalFileName:r,isBinary:!0,binaryPatchData:l});continue}if(u.length===0){a.push({index:o++,fileName:n,diffHeader:t,hunkHeader:s?`rename`:``,content:s?`Rename from ${r}\nRename to ${n}`:``,additions:0,deletions:0,isRename:s,originalFileName:r});continue}for(let e of u)a.push({index:o++,fileName:n,diffHeader:t,hunkHeader:e.header,content:e.content,additions:e.additions,deletions:e.deletions,isRename:!1,originalFileName:r})}return a}function r(t){let n=[],r=t.split(e);for(let e=1;e<r.length;e++)n.push(`diff --git ${r[e]}`);return n}function i(e){let n=e.indexOf(`
|
|
2
2
|
GIT binary patch
|
|
3
3
|
`);if(n!==-1){let t=e.slice(0,n).trimEnd(),r=e.slice(n+1),i=a(t),{isRename:s,originalFileName:c}=o(t);return{diffHeader:t,fileName:i,originalFileName:c,isRename:s,isBinary:!0,binaryPatchData:r,hunkSections:[]}}let r=e.search(t),i,c;r===-1?(i=e.trimEnd(),c=``):(i=e.slice(0,r).trimEnd(),c=e.slice(r));let l=a(i),{isRename:u,originalFileName:d}=o(i),f=c?s(c):[];return{diffHeader:i,fileName:l,originalFileName:d,isRename:u,isBinary:!1,hunkSections:f}}function a(e){let t=e.split(`
|
|
4
4
|
`);for(let e of t)if(e.startsWith(`+++ b/`))return e.slice(6);for(let e of t)if(e.startsWith(`rename to `))return e.slice(10);return t[0]?.match(/^diff --git a\/.+ b\/(.+)$/)?.[1]??`unknown`}function o(e){let t=e.split(`
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ComposeGitPort } from "../../ports/git.js";
|
|
2
2
|
|
|
3
3
|
//#region src/git/utils/temp-index.d.ts
|
|
4
|
-
declare function withUntrackedInTempIndex<T>(git: ComposeGitPort, fn: (indexEnv: Record<string, string>) => Promise<T
|
|
4
|
+
declare function withUntrackedInTempIndex<T>(git: ComposeGitPort, fn: (indexEnv: Record<string, string>) => Promise<T>): Promise<T>;
|
|
5
5
|
//#endregion
|
|
6
6
|
export { withUntrackedInTempIndex };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{ComposeGitPortMissingOpError as e}from"../../ports/git.js";import{gitDir as t,listUntracked as n,stageAll as r}from"../port-dispatch.js";import{randomUUID as i}from"node:crypto";import*as a from"node:fs";import*as o from"node:os";import*as s from"node:path";async function c(e,t
|
|
1
|
+
import{ComposeGitPortMissingOpError as e}from"../../ports/git.js";import{gitDir as t,listUntracked as n,stageAll as r}from"../port-dispatch.js";import{randomUUID as i}from"node:crypto";import*as a from"node:fs";import*as o from"node:os";import*as s from"node:path";async function c(e,t){let c=await l(e),u=s.join(o.tmpdir(),`compose-tmp-idx-${i()}`);try{a.copyFileSync(c,u);let i={GIT_INDEX_FILE:u},o=await n(e);return o.length>0&&await r(e,{intentToAdd:!0,paths:o,indexEnv:i}),await t(i)}finally{try{a.unlinkSync(u)}catch{}}}async function l(n){let r=await t(n);if(!r)throw new e(`gitDir`,`The temp-index helper needs to resolve the real .git/index path. Provide 'gitDir' (or 'exec').`);return s.join(r,`index`)}export{c as withUntrackedInTempIndex};
|
package/dist/index.d.ts
CHANGED
|
@@ -2,11 +2,12 @@ import { PhaseDetail, ProgressEvent, TokenUsage } from "./ai/types.js";
|
|
|
2
2
|
import { AIError, AIErrorCode } from "./errors/ai.js";
|
|
3
3
|
import { GitError, GitErrorCode } from "./errors/git.js";
|
|
4
4
|
import { TaskInputError } from "./errors/task.js";
|
|
5
|
-
import {
|
|
5
|
+
import { ComposeWorkflowError, ComposeWorkflowErrorCode, ComposeWorkflowInputError } from "./errors/workflow.js";
|
|
6
6
|
import { ApplyPatchOptions, CheckoutOptions, CleanOptions, CommitTreeOptions, ComposeGitOps, ComposeGitPort, ComposeGitPortMissingOpError, DeleteBranchOptions, DiffTreeOptions, ForEachRefOptions, GitCommitIdentity, IndexScopedOptions, LogOptions, OpOptions, SigningConfig, StageAllOptions, StashPushOptions, UpdateRefOptions } from "./ports/git.js";
|
|
7
7
|
import { BranchGroup, BranchOrdering, BranchPartition, CommitDetail, CommitSuggestion, ComposeHunk, ComposeTaskName, PromptOverride } from "./tasks/types.js";
|
|
8
8
|
import { ConventionDescriptor } from "./git/utils/conventions.js";
|
|
9
9
|
import { AfterModelCallInfo, BeforeModelCallInfo, BeforePromptInfo, OnAfterModelCall, OnBeforeModelCall, OnBeforePrompt, estimatedCharactersPerToken } from "./tasks/ai-loop.js";
|
|
10
|
+
import { REDACTED_HUNK_CONTENT, RedactHunkContent } from "./tasks/utils/redact.js";
|
|
10
11
|
import { AnalysisResult, AnalyzeInput, AnalyzeOutput, Concern, ConcernDependency, HunkAnnotation, HunkOrderingConstraint } from "./tasks/analyze/types.js";
|
|
11
12
|
import { GroupInput, GroupOutput, GroupingResult, GroupingStrategy } from "./tasks/group/types.js";
|
|
12
13
|
import { OrderInput, OrderOutput, OrderingResult } from "./tasks/order/types.js";
|
|
@@ -14,6 +15,7 @@ import { QuickComposeInput, QuickComposeOutput, QuickComposeResult } from "./tas
|
|
|
14
15
|
import { ComposeSession } from "./tasks/session.js";
|
|
15
16
|
import { PartitionInput, PartitionOutput, PartitionResult, PartitionStrategy } from "./tasks/partition/types.js";
|
|
16
17
|
import { ComposeContext, ComposeSource, ComposeTarget } from "./workflows/types.js";
|
|
18
|
+
import { StashConflict } from "./git/types.js";
|
|
17
19
|
import { ComposeBranchPlan } from "./git/apply-target.js";
|
|
18
20
|
import { analyze } from "./tasks/analyze/analyze.js";
|
|
19
21
|
import { ComposeGroupInput, ComposeGroupOutput } from "./tasks/compose-group/types.js";
|
|
@@ -25,4 +27,5 @@ import { quickCompose } from "./tasks/quick-compose/quick-compose.js";
|
|
|
25
27
|
import { ApplyComposePlanInput, ApplyComposePlanResult, ComposeApplyPlan, ComposeDepth, ComposeInput, ComposePlan, ComposePlanInput, ComposePlanResult, ComposeProgressEvent, ComposeResult, ComposeStrategy, applyComposePlan, compose, composePlan, defaultPhaseMessages } from "./workflows/compose.js";
|
|
26
28
|
import { SplitInput, SplitPlan, SplitProgressEvent, SplitResult, split } from "./workflows/split.js";
|
|
27
29
|
import { UndoComposeInput, ValidateUndoComposeInput, listUndoIds, undoCompose, validateUndoCompose } from "./workflows/undo.js";
|
|
28
|
-
|
|
30
|
+
import { UndoForceOptions } from "@gitkraken/shared-tools";
|
|
31
|
+
export { AIError, type AIErrorCode, type AfterModelCallInfo, type AnalysisResult, type AnalyzeInput, type AnalyzeOutput, type ApplyComposePlanInput, type ApplyComposePlanResult, type ApplyPatchOptions, type BeforeModelCallInfo, type BeforePromptInfo, type BranchGroup, type BranchOrdering, type BranchPartition, type CheckoutOptions, type CleanOptions, type CommitDetail, type CommitSuggestion, type CommitTreeOptions, type ComposeApplyPlan, type ComposeBranchPlan, type ComposeContext, type ComposeDepth, type ComposeGitOps, type ComposeGitPort, ComposeGitPortMissingOpError, type ComposeGroupInput, type ComposeGroupOutput, type ComposeHunk, type ComposeInput, type ComposePlan, type ComposePlanInput, type ComposePlanResult, type ComposeProgressEvent, type ComposeResult, type ComposeSession, type ComposeSource, type ComposeStrategy, type ComposeTarget, type ComposeTaskName, ComposeWorkflowError, type ComposeWorkflowErrorCode, ComposeWorkflowInputError, type Concern, type ConcernDependency, type ConventionDescriptor, type DeleteBranchOptions, type DiffTreeOptions, type ForEachRefOptions, type GitCommitIdentity, GitError, type GitErrorCode, type GroupInput, type GroupOutput, type GroupingResult, type GroupingStrategy, type HunkAnnotation, type HunkOrderingConstraint, type IndexScopedOptions, type LogOptions, type OnAfterModelCall, type OnBeforeModelCall, type OnBeforePrompt, type OpOptions, type OrderInput, type OrderOutput, type OrderingResult, type PartitionInput, type PartitionOutput, type PartitionResult, type PartitionStrategy, type PhaseDetail, type ProgressEvent, type PromptOverride, type QuickComposeInput, type QuickComposeOutput, type QuickComposeResult, REDACTED_HUNK_CONTENT, type RedactHunkContent, type SigningConfig, type SplitInput, type SplitPlan, type SplitProgressEvent, type SplitResult, type StageAllOptions, type StashConflict, type StashPushOptions, TaskInputError, type TokenUsage, type UndoComposeInput, type UndoForceOptions, type UpdateRefOptions, type ValidateUndoComposeInput, analyze, applyComposePlan, compose, composeGroup, composePlan, defaultPhaseMessages, estimatedCharactersPerToken, group, listUndoIds, order, partition, quickCompose, split, undoCompose, validateUndoCompose };
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{AIError as e}from"./errors/ai.js";import{GitError as t}from"./errors/git.js";import{TaskInputError as n}from"./errors/task.js";import{ComposeWorkflowError as r,ComposeWorkflowInputError as i}from"./errors/workflow.js";import{ComposeGitPortMissingOpError as a}from"./ports/git.js";import{estimatedCharactersPerToken as o}from"./tasks/ai-loop.js";import{REDACTED_HUNK_CONTENT as s}from"./tasks/utils/redact.js";import{analyze as c}from"./tasks/analyze/analyze.js";import{composeGroup as l}from"./tasks/compose-group/compose-group.js";import{group as u}from"./tasks/group/group.js";import{order as d}from"./tasks/order/order.js";import{partition as f}from"./tasks/partition/partition.js";import{quickCompose as p}from"./tasks/quick-compose/quick-compose.js";import{applyComposePlan as m,compose as h,composePlan as g,defaultPhaseMessages as _}from"./workflows/compose.js";import{split as v}from"./workflows/split.js";import{listUndoIds as y,undoCompose as b,validateUndoCompose as x}from"./workflows/undo.js";export{e as AIError,a as ComposeGitPortMissingOpError,r as ComposeWorkflowError,i as ComposeWorkflowInputError,t as GitError,s as REDACTED_HUNK_CONTENT,n as TaskInputError,c as analyze,m as applyComposePlan,h as compose,l as composeGroup,g as composePlan,_ as defaultPhaseMessages,o as estimatedCharactersPerToken,u as group,y as listUndoIds,d as order,f as partition,p as quickCompose,v as split,b as undoCompose,x as validateUndoCompose};
|
package/dist/ports/git.d.ts
CHANGED
|
@@ -28,12 +28,19 @@ interface ComposeGitOps {
|
|
|
28
28
|
currentBranch?: (opts?: OpOptions) => Promise<string | null>;
|
|
29
29
|
/** Best common ancestor between two refs. Covers `merge-base a b`. */
|
|
30
30
|
mergeBase?: (a: string, b: string, opts?: OpOptions) => Promise<string>;
|
|
31
|
+
/** Check whether `ancestor` is an ancestor of `descendant`. Covers `merge-base --is-ancestor`. */
|
|
32
|
+
mergeBaseIsAncestor?: (ancestor: string, descendant: string, opts?: OpOptions) => Promise<boolean>;
|
|
31
33
|
/** Tree-to-tree unified diff. Covers `diff --binary from to` and `diff --name-only from to`. */
|
|
32
34
|
diffTree?: (from: string, to: string, opts?: DiffTreeOptions) => Promise<string>;
|
|
33
35
|
/** Commit log with custom format. Covers various `git log --format=... <range>` / `-1 <sha>` uses. */
|
|
34
36
|
log?: (opts: LogOptions) => Promise<string>;
|
|
35
37
|
/** Ref enumeration. Covers `for-each-ref`. */
|
|
36
38
|
forEachRef?: (opts: ForEachRefOptions) => Promise<string>;
|
|
39
|
+
/**
|
|
40
|
+
* List commits in a range alongside their immediate children. Covers `rev-list --children`.
|
|
41
|
+
* `children` includes every direct child, even those outside the queried range.
|
|
42
|
+
*/
|
|
43
|
+
revListChildren?: (opts: RevListChildrenOptions) => Promise<RevListChildrenEntry[]>;
|
|
37
44
|
/** Write the current (or temp) index to a tree object. Covers `write-tree`. */
|
|
38
45
|
writeTree?: (opts?: IndexScopedOptions) => Promise<string>;
|
|
39
46
|
/** Load a tree's contents into the current (or temp) index. Covers `read-tree <sha>`. */
|
|
@@ -52,6 +59,8 @@ interface ComposeGitOps {
|
|
|
52
59
|
commitTree?: (tree: string, parents: string[], message: string, opts?: CommitTreeOptions) => Promise<string>;
|
|
53
60
|
/** Apply a unified diff patch to the current (or temp) index. Covers `apply --cached --allow-binary-replacement`. */
|
|
54
61
|
applyPatchToIndex?: (patch: string, opts?: ApplyPatchOptions) => Promise<void>;
|
|
62
|
+
/** Apply a unified diff patch to the working tree (no staging). Covers `apply --allow-binary-replacement`. */
|
|
63
|
+
applyPatchToWorkdir?: (patch: string, opts?: ApplyPatchToWorkdirOptions) => Promise<void>;
|
|
55
64
|
/** 3-way merge producing a tree SHA. Covers `merge-tree --write-tree a b`. */
|
|
56
65
|
mergeTree?: (a: string, b: string, opts?: OpOptions) => Promise<string>;
|
|
57
66
|
/** Create a branch at `startPoint`. Covers `branch name start`. */
|
|
@@ -70,8 +79,10 @@ interface ComposeGitOps {
|
|
|
70
79
|
discardWorkdirChanges?: (paths?: string[], opts?: OpOptions) => Promise<void>;
|
|
71
80
|
/** Push current workdir state to stash. Covers `stash push --include-untracked -m msg`. */
|
|
72
81
|
stashPush?: (opts?: StashPushOptions) => Promise<void>;
|
|
73
|
-
/** Pop the top stash entry. Covers `stash pop`. */
|
|
74
|
-
stashPop?: (opts?:
|
|
82
|
+
/** Pop the top stash entry. `withIndex: true` maps to `--index`. Covers `stash pop` and `stash pop --index`. */
|
|
83
|
+
stashPop?: (opts?: StashPopOptions) => Promise<void>;
|
|
84
|
+
/** Drop a specific stash entry. Covers `stash drop stash@{N}`. */
|
|
85
|
+
stashDrop?: (stashRef: string, opts?: OpOptions) => Promise<void>;
|
|
75
86
|
/**
|
|
76
87
|
* Apply an existing commit onto the current HEAD, producing a new commit.
|
|
77
88
|
* Covers `git cherry-pick <sha>`. Throws when conflicts make the pick fail —
|
|
@@ -84,10 +95,16 @@ interface ComposeGitOps {
|
|
|
84
95
|
/** Abort an in-progress cherry-pick. Covers `git cherry-pick --abort`. */
|
|
85
96
|
cherryPickAbort?: (opts?: OpOptions) => Promise<void>;
|
|
86
97
|
}
|
|
87
|
-
/**
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
98
|
+
/**
|
|
99
|
+
* Options passed to every op. Currently empty — git operations are not
|
|
100
|
+
* cancellable in this library; they run to completion to avoid leaving the
|
|
101
|
+
* repo in a half-mutated state. Domain workflows route cancellation only
|
|
102
|
+
* into the AI loop.
|
|
103
|
+
*
|
|
104
|
+
* Kept as an interface so individual ops that need extra options (e.g.
|
|
105
|
+
* {@link CheckoutOptions}, {@link UpdateRefOptions}) can extend it.
|
|
106
|
+
*/
|
|
107
|
+
interface OpOptions {}
|
|
91
108
|
interface DiffTreeOptions extends OpOptions {
|
|
92
109
|
/** Include binary hunks as base85. Default true. */
|
|
93
110
|
binary?: boolean;
|
|
@@ -102,12 +119,26 @@ interface LogOptions extends OpOptions {
|
|
|
102
119
|
noMerges?: boolean;
|
|
103
120
|
reverse?: boolean;
|
|
104
121
|
author?: string;
|
|
122
|
+
/** Force parents-before-children ordering. Maps to `--topo-order`. */
|
|
123
|
+
topoOrder?: boolean;
|
|
105
124
|
}
|
|
106
125
|
interface ForEachRefOptions extends OpOptions {
|
|
107
126
|
format: string;
|
|
108
127
|
prefix?: string;
|
|
109
128
|
sort?: string;
|
|
110
129
|
limit?: number;
|
|
130
|
+
/** When set, only returns refs pointing at the given commit SHA. Maps to `--points-at=<sha>`. */
|
|
131
|
+
pointsAt?: string;
|
|
132
|
+
}
|
|
133
|
+
interface RevListChildrenOptions extends OpOptions {
|
|
134
|
+
/** Commit range to query, e.g. `from..to`. */
|
|
135
|
+
range: string;
|
|
136
|
+
/** Reverse the output (oldest first). Maps to `--reverse`. */
|
|
137
|
+
reverse?: boolean;
|
|
138
|
+
}
|
|
139
|
+
interface RevListChildrenEntry {
|
|
140
|
+
sha: string;
|
|
141
|
+
children: string[];
|
|
111
142
|
}
|
|
112
143
|
/**
|
|
113
144
|
* Index-scoped options.
|
|
@@ -154,6 +185,10 @@ interface ApplyPatchOptions extends IndexScopedOptions {
|
|
|
154
185
|
/** Allow binary hunks in the patch. Default true. */
|
|
155
186
|
allowBinaryReplacement?: boolean;
|
|
156
187
|
}
|
|
188
|
+
interface ApplyPatchToWorkdirOptions extends OpOptions {
|
|
189
|
+
/** Allow binary hunks in the patch. Default true. */
|
|
190
|
+
allowBinaryReplacement?: boolean;
|
|
191
|
+
}
|
|
157
192
|
interface DeleteBranchOptions extends OpOptions {
|
|
158
193
|
force?: boolean;
|
|
159
194
|
}
|
|
@@ -179,6 +214,12 @@ interface StashPushOptions extends OpOptions {
|
|
|
179
214
|
message?: string;
|
|
180
215
|
includeUntracked?: boolean;
|
|
181
216
|
}
|
|
217
|
+
interface StashPopOptions extends OpOptions {
|
|
218
|
+
/** Restore staged-vs-unstaged split where possible. Maps to `--index`. */
|
|
219
|
+
withIndex?: boolean;
|
|
220
|
+
/** Specific stash entry to pop (e.g. `stash@{2}`). Defaults to the topmost. */
|
|
221
|
+
ref?: string;
|
|
222
|
+
}
|
|
182
223
|
/**
|
|
183
224
|
* The full port shape the library accepts. Exec is optional — if absent,
|
|
184
225
|
* every flow must be fully served by high-level ops.
|
|
@@ -196,4 +237,4 @@ declare class ComposeGitPortMissingOpError extends Error {
|
|
|
196
237
|
constructor(op: string, hint?: string);
|
|
197
238
|
}
|
|
198
239
|
//#endregion
|
|
199
|
-
export { ApplyPatchOptions, CheckoutOptions, CleanOptions, CommitTreeOptions, ComposeGitOps, ComposeGitPort, ComposeGitPortMissingOpError, DeleteBranchOptions, DiffTreeOptions, ForEachRefOptions, GitCommitIdentity, IndexScopedOptions, LogOptions, OpOptions, SigningConfig, StageAllOptions, StashPushOptions, UpdateRefOptions };
|
|
240
|
+
export { ApplyPatchOptions, ApplyPatchToWorkdirOptions, CheckoutOptions, CleanOptions, CommitTreeOptions, ComposeGitOps, ComposeGitPort, ComposeGitPortMissingOpError, DeleteBranchOptions, DiffTreeOptions, ForEachRefOptions, GitCommitIdentity, IndexScopedOptions, LogOptions, OpOptions, RevListChildrenEntry, RevListChildrenOptions, SigningConfig, StageAllOptions, StashPopOptions, StashPushOptions, UpdateRefOptions };
|
package/dist/tasks/ai-loop.d.ts
CHANGED
|
@@ -34,15 +34,14 @@ interface AfterModelCallInfo {
|
|
|
34
34
|
type OnBeforeModelCall = (info: BeforeModelCallInfo) => void;
|
|
35
35
|
type OnAfterModelCall = (info: AfterModelCallInfo) => void;
|
|
36
36
|
/**
|
|
37
|
-
* Gating hook fired immediately before each model.generate call.
|
|
37
|
+
* Gating hook fired immediately before each `model.generate` call. Returning
|
|
38
|
+
* `false` aborts the loop with a native `AbortError` (DOMException with
|
|
39
|
+
* `name === 'AbortError'`). Intended for cost warnings, large-prompt
|
|
40
|
+
* confirmations, policy checks, and similar caller-side UX.
|
|
38
41
|
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* The library provides `tokenEstimate` as a rough `charCount / 2.8`
|
|
44
|
-
* approximation — reasonable for code-heavy prompts but not authoritative.
|
|
45
|
-
* Consumers can ignore it and estimate their own way.
|
|
42
|
+
* `tokenEstimate` is a rough `charCount / 2.8` approximation — reasonable for
|
|
43
|
+
* code-heavy prompts but not authoritative. Callers can ignore it and
|
|
44
|
+
* estimate their own way.
|
|
46
45
|
*/
|
|
47
46
|
interface BeforePromptInfo {
|
|
48
47
|
phase: string;
|
|
@@ -65,16 +64,11 @@ interface AiLoopParams<T> {
|
|
|
65
64
|
onProgress?: (event: ProgressEvent) => void;
|
|
66
65
|
validate: (responseText: string) => ValidationResult<T>;
|
|
67
66
|
taskName: string;
|
|
68
|
-
|
|
69
|
-
/** Phase label stamped on Before/After model-call hook events. */
|
|
67
|
+
cancellation?: AbortSignal;
|
|
68
|
+
/** Phase label stamped on Before/After model-call hook events. Defaults to `taskName`. */
|
|
70
69
|
phase?: string;
|
|
71
70
|
onBeforeModelCall?: OnBeforeModelCall;
|
|
72
71
|
onAfterModelCall?: OnAfterModelCall;
|
|
73
|
-
/**
|
|
74
|
-
* Gating hook. Called before each model.generate. If it returns `false`, the
|
|
75
|
-
* loop aborts with an AbortError (caught by the workflow and surfaced as a
|
|
76
|
-
* `WorkflowError('CANCELLED')`).
|
|
77
|
-
*/
|
|
78
72
|
onBeforePrompt?: OnBeforePrompt;
|
|
79
73
|
promptVersion?: string;
|
|
80
74
|
}
|
package/dist/tasks/ai-loop.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
2
|
-
`)}`)}function
|
|
1
|
+
import{AIError as e}from"../errors/ai.js";import{TaskInputError as t}from"../errors/task.js";import{appendAssistantMessage as n,appendUserMessage as r,createAiSession as i}from"../ai/session.js";import{addUsage as a}from"../ai/types.js";import{randomUUID as o}from"node:crypto";const s=2.8;async function c(a){let{model:s,userPrompt:c,maxRetries:d=3,maxTokens:f=16384,onProgress:p,validate:m,taskName:h,cancellation:g,phase:_=h,onBeforeModelCall:v,onAfterModelCall:y,promptVersion:b}=a;if(!a.session&&!a.systemPrompt)throw new t(`${h}: either 'session' or 'systemPrompt' must be provided`);let x=Date.now(),S;a.session?S=r(a.session,c):(S=i(a.systemPrompt),S=r(S,c));let C,w=[],T=d+1,E=[];for(let e=0;e<=d;e++){g?.throwIfAborted();let t=e+1;if(p?.({type:`attempt_start`,attempt:t,maxAttempts:T}),a.onBeforePrompt){let e=(S.systemPrompt?.length??0)+S.messages.reduce((e,t)=>e+t.content.length,0);if(!await a.onBeforePrompt({phase:_,attempt:t,maxAttempts:T,charCount:e,messageCount:S.messages.length,tokenEstimate:Math.ceil(e/2.8)}))throw new DOMException(`Prompt gate declined by caller (onBeforePrompt returned false)`,`AbortError`)}let i=o();E.push(i);let c=Date.now();v?.({phase:_,attempt:t,maxAttempts:T,callId:i});let h;try{h=await s.generate({system:S.systemPrompt,messages:[...S.messages],maxTokens:f,temperature:0,signal:g})}catch(e){let n=e instanceof Error?e.message:String(e);throw y?.({phase:_,attempt:t,callId:i,success:!1,durationMs:Date.now()-c,error:{code:e?.code??`UNKNOWN`,message:n},promptVersion:b}),l(e)||g?.aborted?new DOMException(n,`AbortError`):e}y?.({phase:_,attempt:t,callId:i,success:!0,durationMs:Date.now()-c,usage:h.usage,promptVersion:b}),C=u(C,h.usage);let D=m(h.text);if(D.valid&&D.result!==void 0)return S=n(S,h.text),{result:D.result,session:S,usage:C,attempts:t,durationMs:Date.now()-x,callIds:E};w=D.errors??[`Unknown validation error`],p?.({type:`validation_failed`,attempt:t,maxAttempts:T,errors:w}),e<d&&D.retryFeedback&&(S=n(S,h.text),S=r(S,D.retryFeedback))}throw new e(`VALIDATION_EXHAUSTED`,`Failed to get valid ${h} after ${T} attempts. Last errors:\n${w.join(`
|
|
2
|
+
`)}`)}function l(e){return e instanceof Error&&(e.name===`AbortError`||e.name===`DOMException`)}function u(e,t){if(!e)return t;if(!t)return e;let n={...e};return a(n,t),n}function d(e){let t=e.match(/<output>([\s\S]*?)(?:<\/output>|$)/)?.[1]?.trim()??null;return t?t.match(/^```(?:\w*)\n?([\s\S]*?)```$/)?.[1]?.trim()??t:null}export{s as estimatedCharactersPerToken,d as extractOutputTag,c as runAiLoop};
|
|
@@ -1 +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{buildAnalyzeSystemPrompt as r,buildAnalyzeUserPrompt as i}from"./prompt.js";import{validateAnalyzeResponse as a}from"./validator.js";async function o(o){let s=o.hunks;if(!s||s.length===0)throw new e(`No hunks provided: supply 'hunks'`);if(o.session?.completedSteps.analyze)return{result:o.session.completedSteps.analyze,session:o.session,attempts:0,durationMs:0,callIds:[]};let c=n(i({hunks:s,commitMessages:o.commitMessages,commitOrder:o.commitOrder,branchName:o.branchName,baseBranch:o.baseBranch,issueUrl:o.issueUrl,pullRequestUrl:o.pullRequestUrl,instructions:o.instructions}),o.promptOverride),l=s.length,u=await t({model:o.model,systemPrompt:o.session?void 0:o.promptOverride?.system??r(),userPrompt:c,session:o.session,maxRetries:o.maxRetries,onProgress:o.onProgress,
|
|
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{buildAnalyzeSystemPrompt as r,buildAnalyzeUserPrompt as i}from"./prompt.js";import{validateAnalyzeResponse as a}from"./validator.js";async function o(o){let s=o.hunks;if(!s||s.length===0)throw new e(`No hunks provided: supply 'hunks'`);if(o.session?.completedSteps.analyze)return{result:o.session.completedSteps.analyze,session:o.session,attempts:0,durationMs:0,callIds:[]};let c=n(i({hunks:s,commitMessages:o.commitMessages,commitOrder:o.commitOrder,branchName:o.branchName,baseBranch:o.baseBranch,issueUrl:o.issueUrl,pullRequestUrl:o.pullRequestUrl,instructions:o.instructions,redactHunkContent:o.redactHunkContent}),o.promptOverride),l=s.length,u=await t({model:o.model,systemPrompt:o.session?void 0:o.promptOverride?.system??r(),userPrompt:c,session:o.session,maxRetries:o.maxRetries,maxTokens:o.maxTokens,onProgress:o.onProgress,cancellation:o.cancellation,onBeforeModelCall:o.onBeforeModelCall,onAfterModelCall:o.onAfterModelCall,onBeforePrompt:o.onBeforePrompt,validate:e=>a(e,l),taskName:`analyze`}),d=o.session?.completedSteps??{},f={...u.session,completedSteps:{...d,analyze:u.result}};return{result:u.result,session:f,usage:u.usage,attempts:u.attempts,durationMs:u.durationMs,callIds:u.callIds}}export{o as analyze};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ComposeHunk } from "../types.js";
|
|
2
|
+
import { RedactHunkContent } from "../utils/redact.js";
|
|
2
3
|
|
|
3
4
|
//#region src/tasks/analyze/prompt.d.ts
|
|
4
5
|
declare function buildAnalyzeSystemPrompt(): string;
|
|
@@ -11,6 +12,7 @@ declare function buildAnalyzeUserPrompt(params: {
|
|
|
11
12
|
issueUrl?: string;
|
|
12
13
|
pullRequestUrl?: string;
|
|
13
14
|
instructions?: string;
|
|
15
|
+
redactHunkContent?: RedactHunkContent;
|
|
14
16
|
}): string;
|
|
15
17
|
//#endregion
|
|
16
18
|
export { buildAnalyzeSystemPrompt, buildAnalyzeUserPrompt };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{hunkContentForPrompt as e}from"../utils/redact.js";import{analysisResultSchema as t}from"./schema.js";import{z as n}from"zod";const r=JSON.stringify(n.toJSONSchema(t),null,2);function i(){return`You are an advanced AI code analysis assistant. Your task is to deeply analyze a set of code changes (provided as diff hunks) and produce a structured understanding of what the changes accomplish, what concerns they address, and how hunks relate to each other.
|
|
2
2
|
|
|
3
3
|
Your analysis must produce:
|
|
4
4
|
1. **Title** — a short, PR-style title for the changes (under 72 characters, imperative mood, e.g. "Add user authentication and session management"). This should capture the essence of what the changes accomplish.
|
|
@@ -25,10 +25,10 @@ Rules:
|
|
|
25
25
|
Output your analysis as JSON inside a <output> tag matching this schema:
|
|
26
26
|
|
|
27
27
|
\`\`\`json
|
|
28
|
-
${
|
|
28
|
+
${r}
|
|
29
29
|
\`\`\`
|
|
30
30
|
|
|
31
|
-
Return only the <output> tag and no other text.`}function
|
|
32
|
-
`)}\n</context>`),
|
|
31
|
+
Return only the <output> tag and no other text.`}function a(t){let{hunks:n,commitMessages:r,commitOrder:i,branchName:a,baseBranch:o,issueUrl:s,pullRequestUrl:c,instructions:l,redactHunkContent:u}=t,d=`Analyze the following code changes:\n\n<hunks>\n${JSON.stringify(n.map(t=>({index:t.index,fileName:t.fileName,hunkHeader:t.hunkHeader,content:e(t,u),...t.isBinary?{isBinary:!0}:{},...t.isRename?{isRename:!0}:{},...t.originalFileName?{originalFileName:t.originalFileName}:{}})))}\n</hunks>`,f=[];if(a&&f.push(`Branch: ${a}`),o&&f.push(`Base branch: ${o}`),s&&f.push(`Issue: ${s}`),c&&f.push(`Pull request: ${c}`),f.length>0&&(d+=`\n\n<context>\n${f.join(`
|
|
32
|
+
`)}\n</context>`),r?.length){let e=r.map((e,t)=>({index:t,sha:i?.[t],message:e}));d+=`\n\n<commit_messages>\n${JSON.stringify(e)}\n</commit_messages>`}return l&&(d+=`\n\nCarefully follow these additional instructions, but do not deviate from the output structure:\n${l}`),d+=`
|
|
33
33
|
|
|
34
|
-
Now analyze the changes and return your structured analysis. Return only the <output> tag and no other text.`,
|
|
34
|
+
Now analyze the changes and return your structured analysis. Return only the <output> tag and no other text.`,d}export{i as buildAnalyzeSystemPrompt,a as buildAnalyzeUserPrompt};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ProgressEvent, TokenUsage } from "../../ai/types.js";
|
|
2
2
|
import { ComposeHunk, PromptOverride } from "../types.js";
|
|
3
3
|
import { OnAfterModelCall, OnBeforeModelCall, OnBeforePrompt } from "../ai-loop.js";
|
|
4
|
+
import { RedactHunkContent } from "../utils/redact.js";
|
|
4
5
|
import { ComposeSession } from "../session.js";
|
|
5
6
|
import { AiModelPort } from "@gitkraken/shared-tools";
|
|
6
7
|
|
|
@@ -14,11 +15,15 @@ interface AnalyzeInput {
|
|
|
14
15
|
issueUrl?: string;
|
|
15
16
|
pullRequestUrl?: string;
|
|
16
17
|
instructions?: string;
|
|
18
|
+
/** See {@link RedactHunkContent}. */
|
|
19
|
+
redactHunkContent?: RedactHunkContent;
|
|
17
20
|
model: AiModelPort;
|
|
18
21
|
session?: ComposeSession;
|
|
19
22
|
maxRetries?: number;
|
|
23
|
+
/** Output-token cap forwarded to `runAiLoop`. Default 16384; bump for analyze on very large diffs where the structured output (per-hunk annotations) overflows the cap mid-JSON. */
|
|
24
|
+
maxTokens?: number;
|
|
20
25
|
onProgress?: (event: ProgressEvent) => void;
|
|
21
|
-
|
|
26
|
+
cancellation?: AbortSignal;
|
|
22
27
|
onBeforeModelCall?: OnBeforeModelCall;
|
|
23
28
|
onAfterModelCall?: OnAfterModelCall;
|
|
24
29
|
onBeforePrompt?: OnBeforePrompt;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{extractOutputTag as e}from"../ai-loop.js";import{analysisResultSchema as t}from"./schema.js";function n(n,a){
|
|
1
|
+
import{extractOutputTag as e}from"../ai-loop.js";import{analysisResultSchema as t}from"./schema.js";function n(n,a){let o=null;try{if(o=e(n),!o)return r([`No <output> tag found in response`],i());let s=JSON.parse(o),c=t.safeParse(s);if(!c.success)return r(c.error.issues.map(e=>`${e.path.join(`.`)}: ${e.message}`),i());let l=c.data,u=new Set(l.hunkAnnotations.map(e=>e.hunkIndex)),d=[...new Set(Array.from({length:a},(e,t)=>t))].filter(e=>!u.has(e));return d.length>0?r([`Missing annotations for hunks: ${d.join(`, `)}`],`Your response is missing annotations for some hunks. Every hunk must be annotated.\n\nMissing: ${d.join(`, `)}\n\nPlease provide a corrected response.`):{valid:!0,result:{title:l.title,summary:l.summary,concerns:l.concerns,dependencies:l.dependencies,hunkAnnotations:l.hunkAnnotations,orderingConstraints:l.orderingConstraints}}}catch(e){let t=e instanceof Error?e.message:String(e),a=(o??n).slice(-300);return r([`Failed to parse response as valid JSON: ${t}`,`Response tail: ${a}`],i())}}function r(e,t){return{valid:!1,errors:e,retryFeedback:t}}function i(){return`Your response has an invalid structure. Please return JSON inside <output> tags with this structure:
|
|
2
2
|
<output>
|
|
3
3
|
{
|
|
4
4
|
"title": "Short PR-style title (under 72 chars)",
|
|
@@ -1 +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"../group/validator.js";import{buildComposeGroupSystemPrompt as i,buildComposeGroupUserPrompt as a}from"./prompt.js";async function o(o){let s=o.hunks,c=o.mode??`branches`;if(!s||s.length===0)throw new e(`No hunks provided for compose-group`);if(o.session?.completedSteps.composeGroup)return{result:o.session.completedSteps.composeGroup,session:o.session,attempts:0,durationMs:0,callIds:[]};let l=o.promptOverride?.system??i(o.conventions,c,o.strategy,o.includeAnalysis,o.lightweight),u=n(a({hunks:s,commitMessages:o.commitMessages,commitOrder:o.commitOrder,branchName:o.branchName,baseBranch:o.baseBranch,issueUrl:o.issueUrl,pullRequestUrl:o.pullRequestUrl,instructions:o.instructions,condensed:o.condensed}),o.promptOverride),d=await t({model:o.model,systemPrompt:l,userPrompt:u,maxRetries:o.maxRetries,onProgress:o.onProgress,
|
|
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"../group/validator.js";import{buildComposeGroupSystemPrompt as i,buildComposeGroupUserPrompt as a}from"./prompt.js";async function o(o){let s=o.hunks,c=o.mode??`branches`;if(!s||s.length===0)throw new e(`No hunks provided for compose-group`);if(o.session?.completedSteps.composeGroup)return{result:o.session.completedSteps.composeGroup,session:o.session,attempts:0,durationMs:0,callIds:[]};let l=o.promptOverride?.system??i(o.conventions,c,o.strategy,o.includeAnalysis,o.lightweight),u=n(a({hunks:s,commitMessages:o.commitMessages,commitOrder:o.commitOrder,branchName:o.branchName,baseBranch:o.baseBranch,issueUrl:o.issueUrl,pullRequestUrl:o.pullRequestUrl,instructions:o.instructions,condensed:o.condensed,redactHunkContent:o.redactHunkContent}),o.promptOverride),d=await t({model:o.model,systemPrompt:l,userPrompt:u,maxRetries:o.maxRetries,maxTokens:o.maxTokens,onProgress:o.onProgress,cancellation:o.cancellation,onBeforeModelCall:o.onBeforeModelCall,onAfterModelCall:o.onAfterModelCall,onBeforePrompt:o.onBeforePrompt,validate:e=>r(e,s.length,c,o.existingBranchNames),taskName:`compose-group`}),f=o.session?.completedSteps??{},p={...d.session,completedSteps:{...f,composeGroup:d.result}};return{result:d.result,session:p,usage:d.usage,attempts:d.attempts,durationMs:d.durationMs,callIds:d.callIds}}export{o as composeGroup};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ComposeHunk } from "../types.js";
|
|
2
2
|
import { ConventionDescriptor } from "../../git/utils/conventions.js";
|
|
3
|
+
import { RedactHunkContent } from "../utils/redact.js";
|
|
3
4
|
import { GroupingStrategy } from "../group/types.js";
|
|
4
5
|
|
|
5
6
|
//#region src/tasks/compose-group/prompt.d.ts
|
|
@@ -21,6 +22,7 @@ declare function buildComposeGroupUserPrompt(params: {
|
|
|
21
22
|
pullRequestUrl?: string;
|
|
22
23
|
instructions?: string;
|
|
23
24
|
condensed?: boolean;
|
|
25
|
+
redactHunkContent?: RedactHunkContent;
|
|
24
26
|
}): string;
|
|
25
27
|
//#endregion
|
|
26
28
|
export { buildComposeGroupSystemPrompt, buildComposeGroupUserPrompt };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{hunkContentForPrompt as e}from"../utils/redact.js";import{groupingResultSchema as t}from"../group/schema.js";import{z as n}from"zod";const r=JSON.stringify(n.toJSONSchema(t),null,2),i=`
|
|
2
2
|
In addition to the \`branches\` field, include an \`analysis\` field at the top level:
|
|
3
3
|
|
|
4
4
|
\`\`\`json
|
|
@@ -10,31 +10,38 @@ In addition to the \`branches\` field, include an \`analysis\` field at the top
|
|
|
10
10
|
"branches": [ ... ]
|
|
11
11
|
}
|
|
12
12
|
\`\`\`
|
|
13
|
-
`,
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
13
|
+
`,a=`5. Write a full commit message for each commit containing both a summary and a description:
|
|
14
|
+
- **Summary** (first line): concise, 50 chars max, third-person singular present tense ("Fixes", "Adds", "Improves"). This line stands alone as the commit subject.
|
|
15
|
+
- **Blank line**: mandatory separator between summary and description.
|
|
16
|
+
- **Description** (body): one or more lines explaining *why* this change was made, not *what* it does. Focus on motivation, trade-offs, or context a reviewer needs. For non-trivial changes, always include a description — don't leave it at just the summary.
|
|
17
|
+
- Informal yet professional tone.`;function o(e,t=`branches`,n,r,i){return i?t===`commits`?d(e,n):f(e,n):t===`commits`?s(e,n,r):c(e,n,r)}function s(e,t,n){let o=e?.promptFragment?`5. Write a commit message for each commit following the repository's conventions (see below).
|
|
17
18
|
6. Write a detailed explanation for each commit as if explaining to a reviewer.
|
|
18
19
|
|
|
19
|
-
${e.promptFragment}`:`${
|
|
20
|
-
6. Write a detailed explanation for each commit as if explaining to a reviewer`,s=
|
|
20
|
+
${e.promptFragment}`:`${a}
|
|
21
|
+
6. Write a detailed explanation for each commit as if explaining to a reviewer`,s=u(t?.commitGranularity);return`You are an advanced AI programming assistant tasked with analyzing and organizing code changes into commits.
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
## Critical constraints (output is rejected if violated)
|
|
24
|
+
|
|
25
|
+
1. **Each hunk index appears exactly once across the entire response.** Not zero. Not two. Exactly one occurrence — meaning it appears in exactly one commit's \`hunks\` array, and only once within that array. Listing the same index twice inside one commit's \`hunks\`, OR listing it in two different commits, both count as duplicates and both fail validation. This is the most common failure mode when two hunks look similar (same file, same kind of change).
|
|
26
|
+
2. **All hunk indices 0..N-1 must appear** across the union of every commit's \`hunks\` array.
|
|
27
|
+
3. Each commit must contain at least one hunk. No empty commits.
|
|
28
|
+
4. Each commit's \`id\` must be unique (e.g. \`commit-1\`, \`commit-2\`).
|
|
29
|
+
|
|
30
|
+
Before producing the \`<output>\` tag, do a self-check: count the total number of hunk indices across every commit's \`hunks\` array. That count MUST equal the input hunk count. If it does not match, you have either duplicated or skipped a hunk — find and fix it before outputting.
|
|
31
|
+
|
|
32
|
+
${n?`## Step 1: Analysis`:`## Step 1: Internal Analysis`}
|
|
23
33
|
|
|
24
34
|
Before grouping, analyze the changes to understand:
|
|
25
35
|
- **Concerns** — what distinct themes, features, or purposes exist across the hunks
|
|
26
36
|
- **Dependencies** — which hunks provide things (define functions, types, files) that other hunks consume (import, call, reference)
|
|
27
37
|
- **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
38
|
|
|
29
|
-
${
|
|
39
|
+
${n?"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
40
|
|
|
31
41
|
## Step 2: Group hunks into commits
|
|
32
42
|
|
|
33
43
|
1. Group hunks into logical units that make sense together and can be applied atomically
|
|
34
|
-
2.
|
|
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
|
|
44
|
+
2. Ensure each commit is self-contained and atomic
|
|
38
45
|
${o}
|
|
39
46
|
${s}
|
|
40
47
|
|
|
@@ -43,22 +50,27 @@ ${s}
|
|
|
43
50
|
Output your organization as JSON inside a <output> tag matching this schema:
|
|
44
51
|
|
|
45
52
|
\`\`\`json
|
|
46
|
-
${
|
|
53
|
+
${r}
|
|
47
54
|
\`\`\`
|
|
48
|
-
${
|
|
55
|
+
${n?i:``}
|
|
49
56
|
Wrap all commits in a single branch object with id "default", name "", title "", and description "".
|
|
50
57
|
|
|
51
|
-
|
|
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).
|
|
58
|
+
Return only the <output> tag and no other text.`}function c(e,t,n){let o=e?.promptFragment?`5. Write a commit message for each commit following the repository's conventions (see below).
|
|
56
59
|
6. Write a detailed explanation for each commit as if explaining to a reviewer.
|
|
57
60
|
|
|
58
|
-
${e.promptFragment}`:`${
|
|
59
|
-
6. Write a detailed explanation for each commit as if explaining to a reviewer`,s=
|
|
61
|
+
${e.promptFragment}`:`${a}
|
|
62
|
+
6. Write a detailed explanation for each commit as if explaining to a reviewer`,s=l(t?.branchSplitting,e),c=u(t?.commitGranularity);return`You are an advanced AI programming assistant tasked with analyzing and organizing code changes into commits and branches.
|
|
60
63
|
|
|
61
|
-
|
|
64
|
+
## Critical constraints (output is rejected if violated)
|
|
65
|
+
|
|
66
|
+
1. **Each hunk index appears exactly once across the entire response.** Not zero. Not two. Exactly one occurrence — meaning it appears in exactly one branch, in exactly one commit within that branch, and only once within that commit's \`hunks\` array. Listing the same index twice inside one commit's \`hunks\`, OR listing it in two different commits, OR listing it in two different branches, all count as duplicates and all fail validation. This is the most common failure mode when two hunks look similar (same file, same kind of change).
|
|
67
|
+
2. **All hunk indices 0..N-1 must appear** across the union of every commit's \`hunks\` array across every branch.
|
|
68
|
+
3. Each commit must contain at least one hunk. No empty commits.
|
|
69
|
+
4. Each commit \`id\` must be unique across the whole response.
|
|
70
|
+
|
|
71
|
+
Before producing the \`<output>\` tag, do a self-check: count the total number of hunk indices across every commit's \`hunks\` array (across every branch). That count MUST equal the input hunk count. If it does not match, you have either duplicated or skipped a hunk — find and fix it before outputting.
|
|
72
|
+
|
|
73
|
+
${n?`## Step 1: Analysis`:`## Step 1: Internal Analysis`}
|
|
62
74
|
|
|
63
75
|
Before grouping, analyze the changes to understand:
|
|
64
76
|
- **Concerns** — what distinct themes, features, or purposes exist across the hunks
|
|
@@ -66,7 +78,7 @@ Before grouping, analyze the changes to understand:
|
|
|
66
78
|
- **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
79
|
- **Merge-order preference** — even if two concerns compile independently, would merging one without the other be confusing or incomplete?
|
|
68
80
|
|
|
69
|
-
${
|
|
81
|
+
${n?"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
82
|
|
|
71
83
|
## Step 2: Organize hunks into commits and branches
|
|
72
84
|
|
|
@@ -78,12 +90,9 @@ Your job has two levels:
|
|
|
78
90
|
### Commit guidelines
|
|
79
91
|
|
|
80
92
|
1. Group hunks into logical units that make sense together and can be applied atomically
|
|
81
|
-
2.
|
|
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
|
|
93
|
+
2. Ensure each commit is self-contained and atomic
|
|
85
94
|
${o}
|
|
86
|
-
${
|
|
95
|
+
${c}
|
|
87
96
|
|
|
88
97
|
### Branch guidelines
|
|
89
98
|
|
|
@@ -94,17 +103,14 @@ ${s}
|
|
|
94
103
|
Output your organization as JSON inside a <output> tag matching this schema:
|
|
95
104
|
|
|
96
105
|
\`\`\`json
|
|
97
|
-
${
|
|
106
|
+
${r}
|
|
98
107
|
\`\`\`
|
|
99
|
-
${
|
|
100
|
-
|
|
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.
|
|
108
|
+
${n?i:``}
|
|
109
|
+
Return only the <output> tag and no other text.`}function l(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
110
|
${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
|
|
111
|
+
- 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 u(e){return e===`consolidated`?`
|
|
106
112
|
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
|
|
113
|
+
Prefer more, smaller commits. Each distinct change should be its own commit.`:``}function d(e,t){return`Organize code hunks into clean, atomic commits.
|
|
108
114
|
|
|
109
115
|
## Rules
|
|
110
116
|
|
|
@@ -115,7 +121,7 @@ Prefer more, smaller commits. Each distinct change should be its own commit.`:``
|
|
|
115
121
|
5. ${e?.promptFragment?`Write commit messages following the repository's conventions (see below). Write a one-sentence explanation per commit.
|
|
116
122
|
|
|
117
123
|
${e.promptFragment}`:`Write commit messages: first line under 50 chars, imperative mood ("Add", "Fix", "Update"). Write a one-sentence explanation per commit.`}
|
|
118
|
-
${
|
|
124
|
+
${u(t?.commitGranularity)}
|
|
119
125
|
|
|
120
126
|
## Output
|
|
121
127
|
|
|
@@ -125,9 +131,9 @@ JSON inside <output> tags. Use one branch with id "default", name "", title "",
|
|
|
125
131
|
{"branches":[{"id":"default","name":"","title":"","description":"","commits":[{"id":"commit-1","message":"Add feature X","explanation":"Brief reason.","hunks":[0,1,2]}]}]}
|
|
126
132
|
\`\`\`
|
|
127
133
|
|
|
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
|
|
134
|
+
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 f(e,t){let n=e?.promptFragment?`Write commit messages following the repository's conventions (see below). Write a one-sentence explanation per commit.
|
|
129
135
|
|
|
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=
|
|
136
|
+
${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=l(t?.branchSplitting,e);return`Organize code hunks into clean, atomic commits and branches.
|
|
131
137
|
|
|
132
138
|
## Commit rules
|
|
133
139
|
|
|
@@ -136,7 +142,7 @@ ${e.promptFragment}`:`Write commit messages: first line under 50 chars, third-pe
|
|
|
136
142
|
3. Each commit needs a unique ID (e.g., "commit-1", "commit-2").
|
|
137
143
|
4. Every commit must have at least one hunk. No empty commits.
|
|
138
144
|
5. ${n}
|
|
139
|
-
${
|
|
145
|
+
${u(t?.commitGranularity)}
|
|
140
146
|
|
|
141
147
|
## Branch guidelines
|
|
142
148
|
|
|
@@ -152,11 +158,11 @@ JSON inside <output> tags. Each branch needs a unique ID and non-empty name.
|
|
|
152
158
|
|
|
153
159
|
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
160
|
|
|
155
|
-
Return only the <output> tag and no other text.`}function
|
|
161
|
+
Return only the <output> tag and no other text.`}function p(t){let{hunks:n,commitMessages:r,commitOrder:i,branchName:a,baseBranch:o,issueUrl:s,pullRequestUrl:c,instructions:l,condensed:u,redactHunkContent:d}=t,f=JSON.stringify(u?n.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}:{}})):n.map(t=>({index:t.index,fileName:t.fileName,hunkHeader:t.hunkHeader,content:e(t,d),...t.isBinary?{isBinary:!0}:{},...t.isRename?{isRename:!0}:{},...t.originalFileName?{originalFileName:t.originalFileName}:{}}))),p=`Organize these ${n.length} code hunks (indices 0 to ${n.length-1}) into commits. Every index must appear exactly once.
|
|
156
162
|
|
|
157
163
|
<hunks>
|
|
158
|
-
${
|
|
159
|
-
</hunks>`,
|
|
160
|
-
`)}`),
|
|
164
|
+
${f}
|
|
165
|
+
</hunks>`,m=[];return a&&m.push(`Branch: ${a}`),o&&m.push(`Base: ${o}`),s&&m.push(`Issue: ${s}`),c&&m.push(`PR: ${c}`),m.length>0&&(p+=`\n\nContext:\n${m.join(`
|
|
166
|
+
`)}`),r?.length&&(p+=`\n\nOriginal commit messages (match their style):\n<commit_messages>\n${JSON.stringify(r)}\n</commit_messages>`),i?.length&&(p+=`\n\nOriginal commit order:\n${JSON.stringify(i)}`),l&&(p+=`\n\nAdditional instructions:\n${l}`),p+=`
|
|
161
167
|
|
|
162
|
-
Return only the <output> tag and no other text.`,
|
|
168
|
+
Return only the <output> tag and no other text.`,p}export{o as buildComposeGroupSystemPrompt,p as buildComposeGroupUserPrompt};
|