lalph 0.3.4 → 0.3.6
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/cli.mjs +52 -8
- package/package.json +1 -1
- package/src/PromptGen.ts +25 -4
- package/src/commands/root.ts +47 -2
- package/src/domain/Errors.ts +8 -0
- package/src/domain/LinearIssues.ts +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -144005,7 +144005,11 @@ var IssuesNode = class extends Class("IssuesNode")({
|
|
|
144005
144005
|
}) {
|
|
144006
144006
|
blockedBy = this.inverseRelations.nodes.filter((relation) => relation.type === "blocks" && incompleteStates.has(relation.issue.state.type));
|
|
144007
144007
|
};
|
|
144008
|
-
const incompleteStates = new Set([
|
|
144008
|
+
const incompleteStates = new Set([
|
|
144009
|
+
"backlog",
|
|
144010
|
+
"unstarted",
|
|
144011
|
+
"started"
|
|
144012
|
+
]);
|
|
144009
144013
|
const LinearIssueData = Struct({ issue: IssuesNode });
|
|
144010
144014
|
var Issues = class extends Class("Issues")({ nodes: Array$1(IssuesNode) }) {};
|
|
144011
144015
|
var LinearIssuesData = class extends Class("LinearIssuesData")({ issues: Issues }) {};
|
|
@@ -151362,13 +151366,34 @@ ${options.plan}
|
|
|
151362
151366
|
accordingly.
|
|
151363
151367
|
2. Add a detailed implementation plan to the specification, breaking down the work into
|
|
151364
151368
|
smaller, manageable tasks.
|
|
151365
|
-
3. Start two subagents
|
|
151366
|
-
- The first subagent will
|
|
151367
|
-
|
|
151368
|
-
|
|
151369
|
+
3. Start two subagents to review the plan:
|
|
151370
|
+
- The first subagent will recieve the following prompt:
|
|
151371
|
+
\`\`\`
|
|
151372
|
+
Your job is to thoroughly review the specification created for the request,
|
|
151373
|
+
recommend improvements, and ensure every detail is covered.
|
|
151374
|
+
|
|
151375
|
+
Below is the original request.
|
|
151376
|
+
|
|
151377
|
+
---
|
|
151378
|
+
|
|
151379
|
+
{insert original prompt here}
|
|
151380
|
+
\`\`\`
|
|
151381
|
+
|
|
151382
|
+
- The second subagent will receive the following prompt:
|
|
151383
|
+
\`\`\`
|
|
151384
|
+
Your job is to look over the implementation plan, and ensure each task is
|
|
151385
|
+
small, atomic and independently shippable. You also **NEED TO** make sure task
|
|
151369
151386
|
can be completed without failing validation checks (typechecks, linting, tests).
|
|
151370
151387
|
If a task will only pass validations when combined with another, the subagent should
|
|
151371
151388
|
combine the work into one task.
|
|
151389
|
+
|
|
151390
|
+
Below is the original request.
|
|
151391
|
+
|
|
151392
|
+
---
|
|
151393
|
+
|
|
151394
|
+
{insert original prompt here}
|
|
151395
|
+
\`\`\`
|
|
151396
|
+
|
|
151372
151397
|
4. Write the specification details to a \`.lalph/plan.json\` file using the following format:
|
|
151373
151398
|
\`\`\`json
|
|
151374
151399
|
{
|
|
@@ -151421,6 +151446,9 @@ ${prdNotes(options)}`;
|
|
|
151421
151446
|
var RunnerStalled = class extends TaggedError("RunnerStalled") {
|
|
151422
151447
|
message = "The runner has stalled due to inactivity.";
|
|
151423
151448
|
};
|
|
151449
|
+
var TaskStateChanged = class extends TaggedError("TaskStateChanged") {
|
|
151450
|
+
message = `Task "${this.issueId}" moved to "${this.state}", cancelling run.`;
|
|
151451
|
+
};
|
|
151424
151452
|
|
|
151425
151453
|
//#endregion
|
|
151426
151454
|
//#region src/domain/WorkerState.ts
|
|
@@ -152175,7 +152203,7 @@ const run = fnUntraced(function* (options) {
|
|
|
152175
152203
|
yield* fs.writeFileString(pathService.join(worktree.directory, ".lalph", "feedback.md"), feedback);
|
|
152176
152204
|
}
|
|
152177
152205
|
const taskPreset = getOrElse$1(yield* source.issueCliAgentPreset(chosenTask.prd), () => preset);
|
|
152178
|
-
yield* gen(function* () {
|
|
152206
|
+
if (yield* gen(function* () {
|
|
152179
152207
|
registry.update(currentWorker.state, (s) => s.transitionTo(WorkerStatus.Working({ issueId: taskId })));
|
|
152180
152208
|
const instructions = (yield* PromptGen).prompt({
|
|
152181
152209
|
specsDirectory: options.specsDirectory,
|
|
@@ -152204,7 +152232,7 @@ const run = fnUntraced(function* (options) {
|
|
|
152204
152232
|
stallTimeout: options.stallTimeout,
|
|
152205
152233
|
preset: taskPreset,
|
|
152206
152234
|
task: chosenTask.prd
|
|
152207
|
-
})));
|
|
152235
|
+
})), raceFirst(watchTaskState({ issueId: taskId })), as(false), catchTag("TaskStateChanged", (error) => log$1(`Task ${error.issueId} moved to ${error.state}; cancelling run.`).pipe(as(true))))) return;
|
|
152208
152236
|
yield* gitFlow.postWork({
|
|
152209
152237
|
worktree,
|
|
152210
152238
|
targetBranch: getOrUndefined(options.targetBranch),
|
|
@@ -152297,6 +152325,22 @@ const commandRoot = make$35("lalph", {
|
|
|
152297
152325
|
layer,
|
|
152298
152326
|
layer$17
|
|
152299
152327
|
]))));
|
|
152328
|
+
const watchTaskState = fnUntraced(function* (options) {
|
|
152329
|
+
const registry = yield* AtomRegistry;
|
|
152330
|
+
const projectId = yield* CurrentProjectId;
|
|
152331
|
+
return yield* toStreamResult(registry, currentIssuesAtom(projectId)).pipe(runForEach((issues) => {
|
|
152332
|
+
const issue = issues.find((entry) => entry.id === options.issueId);
|
|
152333
|
+
if (!issue) return fail$4(new TaskStateChanged({
|
|
152334
|
+
issueId: options.issueId,
|
|
152335
|
+
state: "missing"
|
|
152336
|
+
}));
|
|
152337
|
+
if (issue.state === "in-progress" || issue.state === "in-review") return void_$1;
|
|
152338
|
+
return fail$4(new TaskStateChanged({
|
|
152339
|
+
issueId: options.issueId,
|
|
152340
|
+
state: issue.state
|
|
152341
|
+
}));
|
|
152342
|
+
}), withSpan("Main.watchTaskState"));
|
|
152343
|
+
});
|
|
152300
152344
|
|
|
152301
152345
|
//#endregion
|
|
152302
152346
|
//#region src/Agents/planner.ts
|
|
@@ -152513,7 +152557,7 @@ const commandSource = make$35("source").pipe(withDescription("Select the issue s
|
|
|
152513
152557
|
|
|
152514
152558
|
//#endregion
|
|
152515
152559
|
//#region package.json
|
|
152516
|
-
var version = "0.3.
|
|
152560
|
+
var version = "0.3.6";
|
|
152517
152561
|
|
|
152518
152562
|
//#endregion
|
|
152519
152563
|
//#region src/commands/projects/ls.ts
|
package/package.json
CHANGED
package/src/PromptGen.ts
CHANGED
|
@@ -255,13 +255,34 @@ ${options.plan}
|
|
|
255
255
|
accordingly.
|
|
256
256
|
2. Add a detailed implementation plan to the specification, breaking down the work into
|
|
257
257
|
smaller, manageable tasks.
|
|
258
|
-
3. Start two subagents
|
|
259
|
-
- The first subagent will
|
|
260
|
-
|
|
261
|
-
|
|
258
|
+
3. Start two subagents to review the plan:
|
|
259
|
+
- The first subagent will recieve the following prompt:
|
|
260
|
+
\`\`\`
|
|
261
|
+
Your job is to thoroughly review the specification created for the request,
|
|
262
|
+
recommend improvements, and ensure every detail is covered.
|
|
263
|
+
|
|
264
|
+
Below is the original request.
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
{insert original prompt here}
|
|
269
|
+
\`\`\`
|
|
270
|
+
|
|
271
|
+
- The second subagent will receive the following prompt:
|
|
272
|
+
\`\`\`
|
|
273
|
+
Your job is to look over the implementation plan, and ensure each task is
|
|
274
|
+
small, atomic and independently shippable. You also **NEED TO** make sure task
|
|
262
275
|
can be completed without failing validation checks (typechecks, linting, tests).
|
|
263
276
|
If a task will only pass validations when combined with another, the subagent should
|
|
264
277
|
combine the work into one task.
|
|
278
|
+
|
|
279
|
+
Below is the original request.
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
{insert original prompt here}
|
|
284
|
+
\`\`\`
|
|
285
|
+
|
|
265
286
|
4. Write the specification details to a \`.lalph/plan.json\` file using the following format:
|
|
266
287
|
\`\`\`json
|
|
267
288
|
{
|
package/src/commands/root.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
Iterable,
|
|
9
9
|
Option,
|
|
10
10
|
Path,
|
|
11
|
+
Stream,
|
|
11
12
|
} from "effect"
|
|
12
13
|
import { PromptGen } from "../PromptGen.ts"
|
|
13
14
|
import { Prd } from "../Prd.ts"
|
|
@@ -17,12 +18,13 @@ import { IssueSource } from "../IssueSource.ts"
|
|
|
17
18
|
import {
|
|
18
19
|
checkForWork,
|
|
19
20
|
CurrentIssueSource,
|
|
21
|
+
currentIssuesAtom,
|
|
20
22
|
resetInProgress,
|
|
21
23
|
} from "../CurrentIssueSource.ts"
|
|
22
24
|
import { GithubCli } from "../Github/Cli.ts"
|
|
23
25
|
import { agentWorker } from "../Agents/worker.ts"
|
|
24
26
|
import { agentChooser } from "../Agents/chooser.ts"
|
|
25
|
-
import { RunnerStalled } from "../domain/Errors.ts"
|
|
27
|
+
import { RunnerStalled, TaskStateChanged } from "../domain/Errors.ts"
|
|
26
28
|
import { agentReviewer } from "../Agents/reviewer.ts"
|
|
27
29
|
import { agentTimeout } from "../Agents/timeout.ts"
|
|
28
30
|
import { CurrentProjectId, Settings } from "../Settings.ts"
|
|
@@ -135,7 +137,7 @@ const run = Effect.fnUntraced(
|
|
|
135
137
|
() => preset,
|
|
136
138
|
)
|
|
137
139
|
|
|
138
|
-
yield* Effect.gen(function* () {
|
|
140
|
+
const cancelled = yield* Effect.gen(function* () {
|
|
139
141
|
//
|
|
140
142
|
// 2. Work on task
|
|
141
143
|
// -----------------------
|
|
@@ -185,8 +187,17 @@ const run = Effect.fnUntraced(
|
|
|
185
187
|
task: chosenTask.prd,
|
|
186
188
|
}),
|
|
187
189
|
),
|
|
190
|
+
Effect.raceFirst(watchTaskState({ issueId: taskId })),
|
|
191
|
+
Effect.as(false),
|
|
192
|
+
Effect.catchTag("TaskStateChanged", (error) =>
|
|
193
|
+
Effect.log(
|
|
194
|
+
`Task ${error.issueId} moved to ${error.state}; cancelling run.`,
|
|
195
|
+
).pipe(Effect.as(true)),
|
|
196
|
+
),
|
|
188
197
|
)
|
|
189
198
|
|
|
199
|
+
if (cancelled) return
|
|
200
|
+
|
|
190
201
|
yield* gitFlow.postWork({
|
|
191
202
|
worktree,
|
|
192
203
|
targetBranch: Option.getOrUndefined(options.targetBranch),
|
|
@@ -396,3 +407,37 @@ export const commandRoot = Command.make("lalph", {
|
|
|
396
407
|
),
|
|
397
408
|
),
|
|
398
409
|
)
|
|
410
|
+
|
|
411
|
+
const watchTaskState = Effect.fnUntraced(function* (options: {
|
|
412
|
+
readonly issueId: string
|
|
413
|
+
}) {
|
|
414
|
+
const registry = yield* AtomRegistry.AtomRegistry
|
|
415
|
+
const projectId = yield* CurrentProjectId
|
|
416
|
+
|
|
417
|
+
return yield* AtomRegistry.toStreamResult(
|
|
418
|
+
registry,
|
|
419
|
+
currentIssuesAtom(projectId),
|
|
420
|
+
).pipe(
|
|
421
|
+
Stream.runForEach((issues) => {
|
|
422
|
+
const issue = issues.find((entry) => entry.id === options.issueId)
|
|
423
|
+
if (!issue) {
|
|
424
|
+
return Effect.fail(
|
|
425
|
+
new TaskStateChanged({
|
|
426
|
+
issueId: options.issueId,
|
|
427
|
+
state: "missing",
|
|
428
|
+
}),
|
|
429
|
+
)
|
|
430
|
+
}
|
|
431
|
+
if (issue.state === "in-progress" || issue.state === "in-review") {
|
|
432
|
+
return Effect.void
|
|
433
|
+
}
|
|
434
|
+
return Effect.fail(
|
|
435
|
+
new TaskStateChanged({
|
|
436
|
+
issueId: options.issueId,
|
|
437
|
+
state: issue.state,
|
|
438
|
+
}),
|
|
439
|
+
)
|
|
440
|
+
}),
|
|
441
|
+
Effect.withSpan("Main.watchTaskState"),
|
|
442
|
+
)
|
|
443
|
+
})
|
package/src/domain/Errors.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { Data } from "effect"
|
|
2
|
+
import type { PrdIssue } from "./PrdIssue.ts"
|
|
2
3
|
|
|
3
4
|
export class RunnerStalled extends Data.TaggedError("RunnerStalled") {
|
|
4
5
|
readonly message = "The runner has stalled due to inactivity."
|
|
5
6
|
}
|
|
7
|
+
|
|
8
|
+
export class TaskStateChanged extends Data.TaggedError("TaskStateChanged")<{
|
|
9
|
+
readonly issueId: string
|
|
10
|
+
readonly state: PrdIssue["state"] | "missing"
|
|
11
|
+
}> {
|
|
12
|
+
readonly message = `Task "${this.issueId}" moved to "${this.state}", cancelling run.`
|
|
13
|
+
}
|
|
@@ -54,7 +54,7 @@ export class IssuesNode extends S.Class<IssuesNode>("IssuesNode")({
|
|
|
54
54
|
incompleteStates.has(relation.issue.state.type),
|
|
55
55
|
)
|
|
56
56
|
}
|
|
57
|
-
const incompleteStates = new Set<Type>(["unstarted", "started"])
|
|
57
|
+
const incompleteStates = new Set<Type>(["backlog", "unstarted", "started"])
|
|
58
58
|
|
|
59
59
|
export const LinearIssueData = S.Struct({
|
|
60
60
|
issue: IssuesNode,
|