@llm4ts/flow 2.10.0 → 2.11.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/dist/Landing.d.ts +17 -0
- package/dist/Landing.d.ts.map +1 -1
- package/dist/Landing.js +47 -2
- package/dist/Landing.js.map +1 -1
- package/package.json +2 -2
- package/src/Landing.ts +70 -2
package/dist/Landing.d.ts
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Schema from "effect/Schema";
|
|
2
3
|
import type { LlmServiceShape } from "@llm4ts/core/LlmService";
|
|
3
4
|
import type { FlowContextShape } from "./FlowContext.ts";
|
|
4
5
|
import { EpicCheckoutDirty, EpicIncomplete, LandingFailed, type FlowError } from "./FlowError.ts";
|
|
5
6
|
import { type PlainFileStoreShape } from "./Persistence.ts";
|
|
6
7
|
import type { ReviewResult } from "./Review.ts";
|
|
7
8
|
import type { StoryPlan } from "./StoryPlan.ts";
|
|
9
|
+
export declare const EpicLandedVersion = 1;
|
|
10
|
+
declare const EpicLanded_base: Schema.Class<EpicLanded, Schema.Struct<{
|
|
11
|
+
readonly target: Schema.String;
|
|
12
|
+
readonly epicBranch: Schema.String;
|
|
13
|
+
}>, {}>;
|
|
14
|
+
/** Written to the epic's state directory once it lands: listings show it, reruns see it. */
|
|
15
|
+
export declare class EpicLanded extends EpicLanded_base {
|
|
16
|
+
}
|
|
17
|
+
export declare const landedPath: (stateDir: string) => string;
|
|
8
18
|
export interface LandOptions {
|
|
9
19
|
readonly plan: StoryPlan;
|
|
10
20
|
readonly files: PlainFileStoreShape;
|
|
@@ -22,6 +32,8 @@ export interface LandOptions {
|
|
|
22
32
|
readonly system?: string;
|
|
23
33
|
/** Fix rounds before giving up. Default 3. */
|
|
24
34
|
readonly maxRounds?: number;
|
|
35
|
+
/** Keep the story worktrees and branches after landing. Default false: they go. */
|
|
36
|
+
readonly keepWorktrees?: boolean;
|
|
25
37
|
}
|
|
26
38
|
export interface LandReport {
|
|
27
39
|
readonly epicBranch: string;
|
|
@@ -30,6 +42,11 @@ export interface LandReport {
|
|
|
30
42
|
readonly conflicts: ReadonlyArray<string>;
|
|
31
43
|
/** Coder rounds it took (0: clean and green on the first try). */
|
|
32
44
|
readonly rounds: number;
|
|
45
|
+
/** Story worktrees removed after landing. */
|
|
46
|
+
readonly removedWorktrees: number;
|
|
47
|
+
/** Story branches deleted after landing (each fully merged into the target). */
|
|
48
|
+
readonly deletedBranches: number;
|
|
33
49
|
}
|
|
34
50
|
export declare const landEpic: (context: FlowContextShape, options: LandOptions) => Effect.Effect<LandReport, import("./FlowError.ts").PersistenceError | import("./FlowError.ts").PlanParseError | import("./FlowError.ts").UnsupportedSchemaVersion | import("./FlowError.ts").WorkspacePathError | import("./FlowError.ts").WorkspaceLimitError | import("./FlowError.ts").WorkspaceIoError | import("./FlowError.ts").FlowAborted | import("./FlowError.ts").ProcessError | import("./FlowError.ts").FlowLlmError | import("./FlowError.ts").FlowCapabilityDenied | import("./FlowError.ts").ColumnNotFound | import("./FlowError.ts").BudgetExceeded | import("./FlowError.ts").StoryPlanInvalid | import("./FlowError.ts").PerimeterViolation | import("./FlowError.ts").MissingDependency | import("./FlowError.ts").MergeConflict | EpicCheckoutDirty | import("./FlowError.ts").RosterInvalid | EpicIncomplete | LandingFailed | import("./FlowError.ts").RosterExhausted | import("./FlowError.ts").StoryFailed | import("./FlowError.ts").DecisionsInvalid | import("./FlowError.ts").OpenPointsPending | import("./FlowError.ts").ContractConflict, never>;
|
|
51
|
+
export {};
|
|
35
52
|
//# sourceMappingURL=Landing.d.ts.map
|
package/dist/Landing.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Landing.d.ts","sourceRoot":"","sources":["../src/Landing.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAE9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACxD,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAGjG,OAAO,
|
|
1
|
+
{"version":3,"file":"Landing.d.ts","sourceRoot":"","sources":["../src/Landing.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAE9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AACxD,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,aAAa,EAAE,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAGjG,OAAO,EAAgC,KAAK,mBAAmB,EAAE,MAAM,kBAAkB,CAAA;AACzF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAK/C,eAAO,MAAM,iBAAiB,IAAI,CAAA;;;;;AAElC,4FAA4F;AAC5F,qBAAa,UAAW,SAAQ,eAG9B;CAAG;AAEL,eAAO,MAAM,UAAU,GAAI,UAAU,MAAM,KAAG,MAAuC,CAAA;AAErF,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAA;IACxB,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAA;IACnC,uFAAuF;IACvF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,+BAA+B;IAC/B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,sBAAsB;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,oDAAoD;IACpD,QAAQ,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,YAAY,EAAE,SAAS,CAAC,CAAA;IAC3E,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,CAAC,EAAE,eAAe,CAAA;IAChC,iCAAiC;IACjC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,8CAA8C;IAC9C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,mFAAmF;IACnF,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAA;CACjC;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,gEAAgE;IAChE,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACzC,kEAAkE;IAClE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,6CAA6C;IAC7C,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;IACjC,gFAAgF;IAChF,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;CACjC;AAYD,eAAO,MAAM,QAAQ,ykCA6KnB,CAAA"}
|
package/dist/Landing.js
CHANGED
|
@@ -5,13 +5,22 @@
|
|
|
5
5
|
// commit on the target. Nothing touches the target until the epic branch is
|
|
6
6
|
// green with the target's history in it.
|
|
7
7
|
import * as Effect from "effect/Effect";
|
|
8
|
+
import * as Schema from "effect/Schema";
|
|
8
9
|
import { makeChat } from "./Chat.js";
|
|
9
10
|
import { EpicCheckoutDirty, EpicIncomplete, LandingFailed } from "./FlowError.js";
|
|
10
11
|
import { Info } from "./FlowEvents.js";
|
|
11
12
|
import { statusPaths } from "./GitTool.js";
|
|
12
|
-
import { loadVersioned } from "./Persistence.js";
|
|
13
|
+
import { loadVersioned, saveVersioned } from "./Persistence.js";
|
|
13
14
|
import { StoryState, StoryStateVersion } from "./Stories.js";
|
|
14
15
|
const join = (root, path) => `${root.replace(/[\\/]+$/, "")}/${path.replace(/^[\\/]+/, "")}`;
|
|
16
|
+
export const EpicLandedVersion = 1;
|
|
17
|
+
/** Written to the epic's state directory once it lands: listings show it, reruns see it. */
|
|
18
|
+
export class EpicLanded extends Schema.Class("EpicLanded")({
|
|
19
|
+
target: Schema.String,
|
|
20
|
+
epicBranch: Schema.String
|
|
21
|
+
}) {
|
|
22
|
+
}
|
|
23
|
+
export const landedPath = (stateDir) => join(stateDir, "landed.json");
|
|
15
24
|
const markerPattern = /^(<{7} |={7}$|>{7} )/m;
|
|
16
25
|
const issueLines = (result) => result.issues
|
|
17
26
|
.map((issue) => `- ${issue.title}${issue.description.length === 0 ? "" : `: ${issue.description.slice(-1500)}`}`)
|
|
@@ -116,7 +125,43 @@ export const landEpic = Effect.fn("@llm4ts/flow/Landing.land")(function* (contex
|
|
|
116
125
|
}
|
|
117
126
|
yield* git.checkout(target);
|
|
118
127
|
yield* git.merge(epicBranch, `${plan.epicId}: land ${epicBranch}`);
|
|
128
|
+
yield* saveVersioned(files, landedPath(options.stateDir), EpicLandedVersion, EpicLanded, EpicLanded.make({ target, epicBranch }));
|
|
119
129
|
yield* say(`landed ${epicBranch} on ${target}${rounds === 0 ? "" : ` after ${rounds} fix round(s)`}`);
|
|
120
|
-
|
|
130
|
+
// 5. The stories' worktrees and branches have done their job: their work
|
|
131
|
+
// is in the target's history. The epic's record (plan, board, report,
|
|
132
|
+
// story states, traces) stays. A worktree with uncommitted work, or a
|
|
133
|
+
// branch not fully merged, is kept and named.
|
|
134
|
+
let removedWorktrees = 0;
|
|
135
|
+
let deletedBranches = 0;
|
|
136
|
+
if (options.keepWorktrees !== true) {
|
|
137
|
+
const kept = [];
|
|
138
|
+
for (const story of plan.stories) {
|
|
139
|
+
const state = yield* loadVersioned(files, join(options.stateDir, `stories/${story.id}.json`), StoryStateVersion, StoryState);
|
|
140
|
+
if (state === undefined) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if ((yield* files.read(join(state.worktree, ".git"))) !== undefined) {
|
|
144
|
+
const removed = yield* git.removeWorktree(state.worktree).pipe(Effect.as(true), Effect.catch(() => Effect.succeed(false)));
|
|
145
|
+
if (removed) {
|
|
146
|
+
removedWorktrees += 1;
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
kept.push(`${state.worktree} (uncommitted work)`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (yield* git.branchExists(state.branch)) {
|
|
153
|
+
if (yield* git.isAncestor(state.branch, target)) {
|
|
154
|
+
yield* git.deleteBranch(state.branch);
|
|
155
|
+
deletedBranches += 1;
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
kept.push(`${state.branch} (not merged into ${target})`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
yield* say(`removed ${removedWorktrees} story worktree(s) and deleted ${deletedBranches} merged story branch(es)` +
|
|
163
|
+
(kept.length === 0 ? "" : `; kept: ${kept.join(", ")}`));
|
|
164
|
+
}
|
|
165
|
+
return { epicBranch, target, conflicts, rounds, removedWorktrees, deletedBranches };
|
|
121
166
|
});
|
|
122
167
|
//# sourceMappingURL=Landing.js.map
|
package/dist/Landing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Landing.js","sourceRoot":"","sources":["../src/Landing.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,8EAA8E;AAC9E,0EAA0E;AAC1E,yEAAyE;AACzE,4EAA4E;AAC5E,yCAAyC;AACzC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAEvC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AAEpC,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,aAAa,EAAkB,MAAM,gBAAgB,CAAA;AACjG,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,aAAa,EAA4B,MAAM,kBAAkB,CAAA;
|
|
1
|
+
{"version":3,"file":"Landing.js","sourceRoot":"","sources":["../src/Landing.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@llm4ts/flow",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.11.0",
|
|
4
4
|
"description": "Effect-native LLM workflow, persistence, review, and repository automation",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
"typescript"
|
|
102
102
|
],
|
|
103
103
|
"dependencies": {
|
|
104
|
-
"@llm4ts/core": "2.
|
|
104
|
+
"@llm4ts/core": "2.11.0"
|
|
105
105
|
},
|
|
106
106
|
"peerDependencies": {
|
|
107
107
|
"effect": "4.0.0-rc.115"
|
package/src/Landing.ts
CHANGED
|
@@ -5,13 +5,14 @@
|
|
|
5
5
|
// commit on the target. Nothing touches the target until the epic branch is
|
|
6
6
|
// green with the target's history in it.
|
|
7
7
|
import * as Effect from "effect/Effect"
|
|
8
|
+
import * as Schema from "effect/Schema"
|
|
8
9
|
import type { LlmServiceShape } from "@llm4ts/core/LlmService"
|
|
9
10
|
import { makeChat } from "./Chat.ts"
|
|
10
11
|
import type { FlowContextShape } from "./FlowContext.ts"
|
|
11
12
|
import { EpicCheckoutDirty, EpicIncomplete, LandingFailed, type FlowError } from "./FlowError.ts"
|
|
12
13
|
import { Info } from "./FlowEvents.ts"
|
|
13
14
|
import { statusPaths } from "./GitTool.ts"
|
|
14
|
-
import { loadVersioned, type PlainFileStoreShape } from "./Persistence.ts"
|
|
15
|
+
import { loadVersioned, saveVersioned, type PlainFileStoreShape } from "./Persistence.ts"
|
|
15
16
|
import type { ReviewResult } from "./Review.ts"
|
|
16
17
|
import { StoryState, StoryStateVersion } from "./Stories.ts"
|
|
17
18
|
import type { StoryPlan } from "./StoryPlan.ts"
|
|
@@ -19,6 +20,16 @@ import type { StoryPlan } from "./StoryPlan.ts"
|
|
|
19
20
|
const join = (root: string, path: string): string =>
|
|
20
21
|
`${root.replace(/[\\/]+$/, "")}/${path.replace(/^[\\/]+/, "")}`
|
|
21
22
|
|
|
23
|
+
export const EpicLandedVersion = 1
|
|
24
|
+
|
|
25
|
+
/** Written to the epic's state directory once it lands: listings show it, reruns see it. */
|
|
26
|
+
export class EpicLanded extends Schema.Class<EpicLanded>("EpicLanded")({
|
|
27
|
+
target: Schema.String,
|
|
28
|
+
epicBranch: Schema.String
|
|
29
|
+
}) {}
|
|
30
|
+
|
|
31
|
+
export const landedPath = (stateDir: string): string => join(stateDir, "landed.json")
|
|
32
|
+
|
|
22
33
|
export interface LandOptions {
|
|
23
34
|
readonly plan: StoryPlan
|
|
24
35
|
readonly files: PlainFileStoreShape
|
|
@@ -36,6 +47,8 @@ export interface LandOptions {
|
|
|
36
47
|
readonly system?: string
|
|
37
48
|
/** Fix rounds before giving up. Default 3. */
|
|
38
49
|
readonly maxRounds?: number
|
|
50
|
+
/** Keep the story worktrees and branches after landing. Default false: they go. */
|
|
51
|
+
readonly keepWorktrees?: boolean
|
|
39
52
|
}
|
|
40
53
|
|
|
41
54
|
export interface LandReport {
|
|
@@ -45,6 +58,10 @@ export interface LandReport {
|
|
|
45
58
|
readonly conflicts: ReadonlyArray<string>
|
|
46
59
|
/** Coder rounds it took (0: clean and green on the first try). */
|
|
47
60
|
readonly rounds: number
|
|
61
|
+
/** Story worktrees removed after landing. */
|
|
62
|
+
readonly removedWorktrees: number
|
|
63
|
+
/** Story branches deleted after landing (each fully merged into the target). */
|
|
64
|
+
readonly deletedBranches: number
|
|
48
65
|
}
|
|
49
66
|
|
|
50
67
|
const markerPattern = /^(<{7} |={7}$|>{7} )/m
|
|
@@ -175,8 +192,59 @@ export const landEpic = Effect.fn("@llm4ts/flow/Landing.land")(function* (
|
|
|
175
192
|
}
|
|
176
193
|
yield* git.checkout(target)
|
|
177
194
|
yield* git.merge(epicBranch, `${plan.epicId}: land ${epicBranch}`)
|
|
195
|
+
yield* saveVersioned(
|
|
196
|
+
files,
|
|
197
|
+
landedPath(options.stateDir),
|
|
198
|
+
EpicLandedVersion,
|
|
199
|
+
EpicLanded,
|
|
200
|
+
EpicLanded.make({ target, epicBranch })
|
|
201
|
+
)
|
|
178
202
|
yield* say(
|
|
179
203
|
`landed ${epicBranch} on ${target}${rounds === 0 ? "" : ` after ${rounds} fix round(s)`}`
|
|
180
204
|
)
|
|
181
|
-
|
|
205
|
+
|
|
206
|
+
// 5. The stories' worktrees and branches have done their job: their work
|
|
207
|
+
// is in the target's history. The epic's record (plan, board, report,
|
|
208
|
+
// story states, traces) stays. A worktree with uncommitted work, or a
|
|
209
|
+
// branch not fully merged, is kept and named.
|
|
210
|
+
let removedWorktrees = 0
|
|
211
|
+
let deletedBranches = 0
|
|
212
|
+
if (options.keepWorktrees !== true) {
|
|
213
|
+
const kept: Array<string> = []
|
|
214
|
+
for (const story of plan.stories) {
|
|
215
|
+
const state = yield* loadVersioned(
|
|
216
|
+
files,
|
|
217
|
+
join(options.stateDir, `stories/${story.id}.json`),
|
|
218
|
+
StoryStateVersion,
|
|
219
|
+
StoryState
|
|
220
|
+
)
|
|
221
|
+
if (state === undefined) {
|
|
222
|
+
continue
|
|
223
|
+
}
|
|
224
|
+
if ((yield* files.read(join(state.worktree, ".git"))) !== undefined) {
|
|
225
|
+
const removed = yield* git.removeWorktree(state.worktree).pipe(
|
|
226
|
+
Effect.as(true),
|
|
227
|
+
Effect.catch(() => Effect.succeed(false))
|
|
228
|
+
)
|
|
229
|
+
if (removed) {
|
|
230
|
+
removedWorktrees += 1
|
|
231
|
+
} else {
|
|
232
|
+
kept.push(`${state.worktree} (uncommitted work)`)
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (yield* git.branchExists(state.branch)) {
|
|
236
|
+
if (yield* git.isAncestor(state.branch, target)) {
|
|
237
|
+
yield* git.deleteBranch(state.branch)
|
|
238
|
+
deletedBranches += 1
|
|
239
|
+
} else {
|
|
240
|
+
kept.push(`${state.branch} (not merged into ${target})`)
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
yield* say(
|
|
245
|
+
`removed ${removedWorktrees} story worktree(s) and deleted ${deletedBranches} merged story branch(es)` +
|
|
246
|
+
(kept.length === 0 ? "" : `; kept: ${kept.join(", ")}`)
|
|
247
|
+
)
|
|
248
|
+
}
|
|
249
|
+
return { epicBranch, target, conflicts, rounds, removedWorktrees, deletedBranches }
|
|
182
250
|
})
|