lalph 0.3.5 → 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 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(["unstarted", "started"]);
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 }) {};
@@ -151442,6 +151446,9 @@ ${prdNotes(options)}`;
151442
151446
  var RunnerStalled = class extends TaggedError("RunnerStalled") {
151443
151447
  message = "The runner has stalled due to inactivity.";
151444
151448
  };
151449
+ var TaskStateChanged = class extends TaggedError("TaskStateChanged") {
151450
+ message = `Task "${this.issueId}" moved to "${this.state}", cancelling run.`;
151451
+ };
151445
151452
 
151446
151453
  //#endregion
151447
151454
  //#region src/domain/WorkerState.ts
@@ -152196,7 +152203,7 @@ const run = fnUntraced(function* (options) {
152196
152203
  yield* fs.writeFileString(pathService.join(worktree.directory, ".lalph", "feedback.md"), feedback);
152197
152204
  }
152198
152205
  const taskPreset = getOrElse$1(yield* source.issueCliAgentPreset(chosenTask.prd), () => preset);
152199
- yield* gen(function* () {
152206
+ if (yield* gen(function* () {
152200
152207
  registry.update(currentWorker.state, (s) => s.transitionTo(WorkerStatus.Working({ issueId: taskId })));
152201
152208
  const instructions = (yield* PromptGen).prompt({
152202
152209
  specsDirectory: options.specsDirectory,
@@ -152225,7 +152232,7 @@ const run = fnUntraced(function* (options) {
152225
152232
  stallTimeout: options.stallTimeout,
152226
152233
  preset: taskPreset,
152227
152234
  task: chosenTask.prd
152228
- })));
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;
152229
152236
  yield* gitFlow.postWork({
152230
152237
  worktree,
152231
152238
  targetBranch: getOrUndefined(options.targetBranch),
@@ -152318,6 +152325,22 @@ const commandRoot = make$35("lalph", {
152318
152325
  layer,
152319
152326
  layer$17
152320
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
+ });
152321
152344
 
152322
152345
  //#endregion
152323
152346
  //#region src/Agents/planner.ts
@@ -152534,7 +152557,7 @@ const commandSource = make$35("source").pipe(withDescription("Select the issue s
152534
152557
 
152535
152558
  //#endregion
152536
152559
  //#region package.json
152537
- var version = "0.3.5";
152560
+ var version = "0.3.6";
152538
152561
 
152539
152562
  //#endregion
152540
152563
  //#region src/commands/projects/ls.ts
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "lalph",
3
3
  "type": "module",
4
- "version": "0.3.5",
4
+ "version": "0.3.6",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -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
+ })
@@ -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,