lalph 0.1.50 → 0.1.51

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
@@ -60210,6 +60210,7 @@ var PrdIssue = class PrdIssue extends Class("PrdIssue")({
60210
60210
  ]).annotate({ description: "The state of the issue." }),
60211
60211
  blockedBy: Array$1(String$1).annotate({ description: "An array of issue IDs that block this issue. These issues must be completed before this issue can be worked on." }),
60212
60212
  complete: Boolean$2.annotate({ description: "Whether the issue is complete." }),
60213
+ autoMerge: Boolean$2.annotate({ description: "Whether the issue should be auto-merged when complete. Read-only field" }),
60213
60214
  githubPrNumber: NullOr(Finite).annotate({ description: "The created or updated Github pull request number for this task." })
60214
60215
  }) {
60215
60216
  static Array = Array$1(this);
@@ -134468,6 +134469,7 @@ const LinearIssueSource = effect(IssueSource, gen(function* () {
134468
134469
  const project = yield* getOrSelectProject;
134469
134470
  const teamId = yield* getOrSelectTeamId(project);
134470
134471
  const labelId = yield* getOrSelectLabel$1;
134472
+ const autoMergeLabelId = yield* getOrSelectAutoMergeLabel$1;
134471
134473
  const identifierMap = /* @__PURE__ */ new Map();
134472
134474
  const backlogState = linear.states.find((s) => s.type === "backlog" && s.name.toLowerCase().includes("backlog")) || linear.states.find((s) => s.type === "backlog");
134473
134475
  const todoState = linear.states.find((s) => s.type === "unstarted" && (s.name.toLowerCase().includes("todo") || s.name.toLowerCase().includes("unstarted"))) || linear.states.find((s) => s.type === "unstarted");
@@ -134527,6 +134529,7 @@ const LinearIssueSource = effect(IssueSource, gen(function* () {
134527
134529
  state,
134528
134530
  complete: state === "in-review" || state === "done",
134529
134531
  blockedBy: blockedBy.map((i) => i.identifier),
134532
+ autoMerge: autoMergeLabelId.pipe(map$11((labelId$1) => issue.labelIds.includes(labelId$1)), getOrElse(() => false)),
134530
134533
  githubPrNumber: null
134531
134534
  });
134532
134535
  }), { concurrency: 10 }), runCollect, mapError$2((cause) => new IssueSourceError({ cause })));
@@ -134595,6 +134598,7 @@ const resetLinear = gen(function* () {
134595
134598
  yield* selectedProjectId.set(none$3());
134596
134599
  yield* selectedTeamId.set(none$3());
134597
134600
  yield* selectedLabelId.set(none$3());
134601
+ yield* selectedAutoMergeLabelId.set(none$3());
134598
134602
  });
134599
134603
  var LinearError = class extends ErrorClass("lalph/LinearError")({
134600
134604
  _tag: tag("LinearError"),
@@ -134655,10 +134659,32 @@ const labelIdSelect = gen(function* () {
134655
134659
  return labelId;
134656
134660
  });
134657
134661
  const getOrSelectLabel$1 = gen(function* () {
134658
- const labedId = yield* selectedLabelId.get;
134659
- if (isSome(labedId)) return labedId.value;
134662
+ const labelId = yield* selectedLabelId.get;
134663
+ if (isSome(labelId)) return labelId.value;
134660
134664
  return yield* labelIdSelect;
134661
134665
  });
134666
+ const selectedAutoMergeLabelId = new Setting("linear.selectedAutoMergeLabelId", Option(String$1));
134667
+ const autoMergeLabelIdSelect = gen(function* () {
134668
+ const linear = yield* Linear;
134669
+ const labels = yield* runCollect(linear.labels);
134670
+ const labelId = yield* select({
134671
+ message: "Select a label to mark issues for auto merge",
134672
+ choices: [{
134673
+ title: "Disabled",
134674
+ value: none$3()
134675
+ }].concat(labels.map((label) => ({
134676
+ title: label.name,
134677
+ value: some(label.id)
134678
+ })))
134679
+ });
134680
+ yield* selectedAutoMergeLabelId.set(some(labelId));
134681
+ return labelId;
134682
+ });
134683
+ const getOrSelectAutoMergeLabel$1 = gen(function* () {
134684
+ const labelId = yield* selectedAutoMergeLabelId.get;
134685
+ if (isSome(labelId)) return labelId.value;
134686
+ return yield* autoMergeLabelIdSelect;
134687
+ });
134662
134688
 
134663
134689
  //#endregion
134664
134690
  //#region node_modules/.pnpm/universal-user-agent@7.0.3/node_modules/universal-user-agent/index.js
@@ -140773,6 +140799,7 @@ const GithubIssueSource = effect(IssueSource, gen(function* () {
140773
140799
  const github = yield* Github;
140774
140800
  const [owner, repo] = (yield* make$21`gh repo view --json nameWithOwner -q ${".nameWithOwner"}`.pipe(string, option$1, flatMap((o) => o.pipe(map$11(trim), filter$5(isNonEmpty), fromOption)), mapError$2((_) => new GithubRepoNotFound()))).split("/");
140775
140801
  const labelFilter$1 = yield* getOrSelectLabel;
140802
+ const autoMergeLabelName = yield* getOrSelectAutoMergeLabel;
140776
140803
  const hasLabel = (label, name) => label.some((l) => typeof l === "string" ? l === name : l.name === name);
140777
140804
  const listOpenBlockedBy = (issueId) => github.stream((rest, page) => rest.issues.listDependenciesBlockedBy({
140778
140805
  owner,
@@ -140809,6 +140836,7 @@ const GithubIssueSource = effect(IssueSource, gen(function* () {
140809
140836
  state,
140810
140837
  complete: state === "done" || state === "in-review",
140811
140838
  blockedBy: dependencies.map((dep) => `#${dep.number}`),
140839
+ autoMerge: autoMergeLabelName.pipe(map$11((labelName) => hasLabel(issue.labels, labelName)), getOrElse(() => false)),
140812
140840
  githubPrNumber: null
140813
140841
  });
140814
140842
  }), { concurrency: 10 }), runCollect, mapError$2((cause) => new IssueSourceError({ cause })));
@@ -140928,7 +140956,19 @@ const getOrSelectLabel = gen(function* () {
140928
140956
  if (isSome(label)) return label.value;
140929
140957
  return yield* labelSelect;
140930
140958
  });
140931
- const resetGithub = labelFilter.set(none$3());
140959
+ const autoMergeLabel = new Setting("github.autoMergeLabel", Option(String$1));
140960
+ const autoMergeLabelSelect = gen(function* () {
140961
+ const label = yield* text$2({ message: "What label do you want to use for auto-mergable issues? (leave empty for none)" });
140962
+ const labelOption = some(label.trim()).pipe(filter$5(isNonEmpty));
140963
+ yield* autoMergeLabel.set(some(labelOption));
140964
+ return labelOption;
140965
+ });
140966
+ const getOrSelectAutoMergeLabel = gen(function* () {
140967
+ const label = yield* autoMergeLabel.get;
140968
+ if (isSome(label)) return label.value;
140969
+ return yield* autoMergeLabelSelect;
140970
+ });
140971
+ const resetGithub = labelFilter.set(none$3()).pipe(andThen(autoMergeLabel.set(none$3())));
140932
140972
  const maybeNextPage = (page, linkHeader) => pipe(fromNullishOr$2(linkHeader), filter$5((_) => _.includes(`rel="next"`)), as$2(page + 1));
140933
140973
 
140934
140974
  //#endregion
@@ -141281,21 +141321,24 @@ var Prd = class extends Service()("lalph/Prd", { make: gen(function* () {
141281
141321
  });
141282
141322
  });
141283
141323
  const mergeConflictInstruction = "Next step: Rebase PR and resolve merge conflicts.";
141324
+ const flagUnmergable = fnUntraced(function* (options) {
141325
+ const issue = current.find((entry) => entry.id === options.issueId);
141326
+ if (!issue) return;
141327
+ const nextDescription = issue.description.includes(mergeConflictInstruction) ? issue.description : `${mergeConflictInstruction}\n\n${issue.description.trim()}`;
141328
+ yield* source.updateIssue({
141329
+ issueId: issue.id,
141330
+ description: nextDescription,
141331
+ state: "todo"
141332
+ });
141333
+ });
141334
+ const findById = (issueId) => sync(() => current.find((i) => i.id === issueId) ?? null);
141284
141335
  return {
141285
141336
  path: prdFile,
141286
141337
  mergableGithubPrs,
141287
141338
  revertStateIds,
141288
141339
  maybeRevertIssue,
141289
- flagUnmergable: fnUntraced(function* (options) {
141290
- const issue = current.find((entry) => entry.id === options.issueId);
141291
- if (!issue) return;
141292
- const nextDescription = issue.description.includes(mergeConflictInstruction) ? issue.description : `${mergeConflictInstruction}\n\n${issue.description.trim()}`;
141293
- yield* source.updateIssue({
141294
- issueId: issue.id,
141295
- description: nextDescription,
141296
- state: "todo"
141297
- });
141298
- })
141340
+ flagUnmergable,
141341
+ findById
141299
141342
  };
141300
141343
  }) }) {
141301
141344
  static layerNoWorktree = effect(this, this.make);
@@ -141331,14 +141374,8 @@ const run = fnUntraced(function* (options) {
141331
141374
  const promptGen = yield* PromptGen;
141332
141375
  const cliAgent = yield* getOrSelectCliAgent;
141333
141376
  const prd = yield* Prd;
141334
- const exec = (template, ...args$1) => make$21({
141335
- cwd: worktree.directory,
141336
- extendEnv: true
141337
- })(template, ...args$1).pipe(exitCode);
141338
- const execOutput = (template, ...args$1) => make$21({
141339
- cwd: worktree.directory,
141340
- extendEnv: true
141341
- })(template, ...args$1).pipe(string, map$5((output) => output.trim()));
141377
+ const exec = (template, ...args$1) => make$21({ cwd: worktree.directory })(template, ...args$1).pipe(exitCode);
141378
+ const execOutput = (template, ...args$1) => make$21({ cwd: worktree.directory })(template, ...args$1).pipe(string, map$5((output) => output.trim()));
141342
141379
  const execWithStallTimeout = fnUntraced(function* (command) {
141343
141380
  let lastOutputAt = yield* now;
141344
141381
  const stallTimeout = suspend$2(function loop() {
@@ -141385,29 +141422,28 @@ const run = fnUntraced(function* (options) {
141385
141422
  onTimeout: () => fail$4(new RunnerStalled())
141386
141423
  }));
141387
141424
  const taskJson = yield* fs.readFileString(pathService.join(worktree.directory, ".lalph", "task.json"));
141388
- const task = yield* decodeEffect(ChosenTask)(taskJson);
141425
+ const taskId = (yield* decodeEffect(ChosenTask)(taskJson)).id;
141426
+ const task = yield* prd.findById(taskId);
141427
+ if (!task) return;
141389
141428
  yield* completeWith(options.startedDeferred, void_$1);
141390
141429
  const exitCode$1 = yield* execWithStallTimeout(cliAgent.command({
141391
141430
  prompt: promptGen.prompt({
141392
- taskId: task.id,
141431
+ taskId,
141393
141432
  targetBranch: getOrUndefined(options.targetBranch),
141394
141433
  specsDirectory: options.specsDirectory
141395
141434
  }),
141396
141435
  prdFilePath: pathService.join(".lalph", "prd.yml")
141397
141436
  })).pipe(timeout(options.runTimeout), catchTag("TimeoutError", fnUntraced(function* (error$1) {
141398
141437
  yield* execWithStallTimeout(cliAgent.command({
141399
- prompt: promptGen.promptTimeout({ taskId: task.id }),
141438
+ prompt: promptGen.promptTimeout({ taskId }),
141400
141439
  prdFilePath: pathService.join(".lalph", "prd.yml")
141401
141440
  }));
141402
141441
  return yield* error$1;
141403
141442
  })));
141404
141443
  yield* log$1(`Agent exited with code: ${exitCode$1}`);
141405
141444
  const prs = yield* prd.mergableGithubPrs;
141406
- if (prs.length === 0) yield* prd.maybeRevertIssue({
141407
- ...task,
141408
- issueId: task.id
141409
- });
141410
- else if (options.autoMerge) for (const pr of prs) {
141445
+ if (prs.length === 0) yield* prd.maybeRevertIssue({ issueId: taskId });
141446
+ else if (task.autoMerge) for (const pr of prs) {
141411
141447
  if (isSome(options.targetBranch)) yield* exec`gh pr edit ${pr.prNumber} --base ${options.targetBranch.value}`;
141412
141448
  if ((yield* exec`gh pr merge ${pr.prNumber} -sd`) !== 0) yield* prd.flagUnmergable({ issueId: pr.issueId });
141413
141449
  }
@@ -141483,6 +141519,7 @@ title: Issue Title
141483
141519
  priority: 3
141484
141520
  estimate: null
141485
141521
  blockedBy: []
141522
+ autoMerge: false
141486
141523
  ---
141487
141524
 
141488
141525
  Describe the issue here.`;
@@ -141490,7 +141527,8 @@ const FrontMatterSchema = toCodecJson(Struct({
141490
141527
  title: String$1,
141491
141528
  priority: Finite,
141492
141529
  estimate: NullOr(Finite),
141493
- blockedBy: Array$1(String$1)
141530
+ blockedBy: Array$1(String$1),
141531
+ autoMerge: Boolean$2
141494
141532
  }));
141495
141533
  const createIssue = make$27("issue").pipe(withDescription("Create a new issue in the selected issue source"), withHandler(fnUntraced(function* () {
141496
141534
  const source = yield* IssueSource;
@@ -141536,7 +141574,6 @@ const createIssue = make$27("issue").pipe(withDescription("Create a new issue in
141536
141574
  //#region src/cli.ts
141537
141575
  const iterations = integer("iterations").pipe(withDescription$1("Number of iterations to run, defaults to unlimited"), withAlias("i"), withDefault(Number.POSITIVE_INFINITY));
141538
141576
  const concurrency = integer("concurrency").pipe(withDescription$1("Number of concurrent agents, defaults to 1"), withAlias("c"), withDefault(1));
141539
- const autoMerge = boolean("auto-merge").pipe(withAlias("a"), withDescription$1("Automatically merge eligible PRs"));
141540
141577
  const targetBranch = string$1("target-branch").pipe(withDescription$1("Target branch for PRs. Env variable: LALPH_TARGET_BRANCH"), withAlias("b"), withFallbackConfig(string$4("LALPH_TARGET_BRANCH")), optional);
141541
141578
  const maxIterationMinutes = integer("max-minutes").pipe(withDescription$1("Maximum number of minutes to allow an iteration to run. Defaults to 90 minutes. Env variable: LALPH_MAX_MINUTES"), withFallbackConfig(int("LALPH_MAX_MINUTES")), withDefault(90));
141542
141579
  const stallMinutes = integer("stall-minutes").pipe(withDescription$1("If no activity occurs for this many minutes, the iteration will be stopped. Defaults to 5 minutes. Env variable: LALPH_STALL_MINUTES"), withFallbackConfig(int("LALPH_STALL_MINUTES")), withDefault(5));
@@ -141545,13 +141582,12 @@ const reset = boolean("reset").pipe(withDescription$1("Reset the current issue s
141545
141582
  const root = make$27("lalph", {
141546
141583
  iterations,
141547
141584
  concurrency,
141548
- autoMerge,
141549
141585
  targetBranch,
141550
141586
  maxIterationMinutes,
141551
141587
  stallMinutes,
141552
141588
  reset,
141553
141589
  specsDirectory
141554
- }).pipe(withHandler(fnUntraced(function* ({ iterations: iterations$1, concurrency: concurrency$1, autoMerge: autoMerge$1, targetBranch: targetBranch$1, maxIterationMinutes: maxIterationMinutes$1, stallMinutes: stallMinutes$1, reset: reset$2, specsDirectory: specsDirectory$1 }) {
141590
+ }).pipe(withHandler(fnUntraced(function* ({ iterations: iterations$1, concurrency: concurrency$1, targetBranch: targetBranch$1, maxIterationMinutes: maxIterationMinutes$1, stallMinutes: stallMinutes$1, reset: reset$2, specsDirectory: specsDirectory$1 }) {
141555
141591
  if (reset$2) yield* resetCurrentIssueSource;
141556
141592
  const source = yield* build(CurrentIssueSource.layer);
141557
141593
  yield* getOrSelectCliAgent;
@@ -141570,7 +141606,6 @@ const root = make$27("lalph", {
141570
141606
  const startedDeferred = yield* make$47();
141571
141607
  yield* checkForWork.pipe(andThen(run({
141572
141608
  startedDeferred,
141573
- autoMerge: autoMerge$1,
141574
141609
  targetBranch: targetBranch$1,
141575
141610
  specsDirectory: specsDirectory$1,
141576
141611
  stallTimeout: minutes(stallMinutes$1),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "lalph",
3
3
  "type": "module",
4
- "version": "0.1.50",
4
+ "version": "0.1.51",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -11,6 +11,7 @@ title: Issue Title
11
11
  priority: 3
12
12
  estimate: null
13
13
  blockedBy: []
14
+ autoMerge: false
14
15
  ---
15
16
 
16
17
  Describe the issue here.`
@@ -21,6 +22,7 @@ const FrontMatterSchema = Schema.toCodecJson(
21
22
  priority: Schema.Finite,
22
23
  estimate: Schema.NullOr(Schema.Finite),
23
24
  blockedBy: Schema.Array(Schema.String),
25
+ autoMerge: Schema.Boolean,
24
26
  }),
25
27
  )
26
28
 
package/src/Github.ts CHANGED
@@ -112,6 +112,7 @@ export const GithubIssueSource = Layer.effect(
112
112
  )
113
113
  const [owner, repo] = nameWithOwner.split("/") as [string, string]
114
114
  const labelFilter = yield* getOrSelectLabel
115
+ const autoMergeLabelName = yield* getOrSelectAutoMergeLabel
115
116
 
116
117
  const hasLabel = (
117
118
  label: ReadonlyArray<
@@ -190,6 +191,10 @@ export const GithubIssueSource = Layer.effect(
190
191
  state,
191
192
  complete: state === "done" || state === "in-review",
192
193
  blockedBy: dependencies.map((dep) => `#${dep.number}`),
194
+ autoMerge: autoMergeLabelName.pipe(
195
+ Option.map((labelName) => hasLabel(issue.labels, labelName)),
196
+ Option.getOrElse(() => false),
197
+ ),
193
198
  githubPrNumber: null,
194
199
  })
195
200
  }),
@@ -411,7 +416,34 @@ const getOrSelectLabel = Effect.gen(function* () {
411
416
  return yield* labelSelect
412
417
  })
413
418
 
414
- export const resetGithub = labelFilter.set(Option.none())
419
+ // == auto merge label
420
+
421
+ const autoMergeLabel = new Setting(
422
+ "github.autoMergeLabel",
423
+ Schema.Option(Schema.String),
424
+ )
425
+ const autoMergeLabelSelect = Effect.gen(function* () {
426
+ const label = yield* Prompt.text({
427
+ message:
428
+ "What label do you want to use for auto-mergable issues? (leave empty for none)",
429
+ })
430
+ const labelOption = Option.some(label.trim()).pipe(
431
+ Option.filter(String.isNonEmpty),
432
+ )
433
+ yield* autoMergeLabel.set(Option.some(labelOption))
434
+ return labelOption
435
+ })
436
+ const getOrSelectAutoMergeLabel = Effect.gen(function* () {
437
+ const label = yield* autoMergeLabel.get
438
+ if (Option.isSome(label)) {
439
+ return label.value
440
+ }
441
+ return yield* autoMergeLabelSelect
442
+ })
443
+
444
+ export const resetGithub = labelFilter
445
+ .set(Option.none())
446
+ .pipe(Effect.andThen(autoMergeLabel.set(Option.none())))
415
447
 
416
448
  // == helpers
417
449
 
package/src/Linear.ts CHANGED
@@ -120,6 +120,7 @@ export const LinearIssueSource = Layer.effect(
120
120
  const project = yield* getOrSelectProject
121
121
  const teamId = yield* getOrSelectTeamId(project)
122
122
  const labelId = yield* getOrSelectLabel
123
+ const autoMergeLabelId = yield* getOrSelectAutoMergeLabel
123
124
 
124
125
  // Map of linear identifier to issue id
125
126
  const identifierMap = new Map<string, string>()
@@ -231,6 +232,10 @@ export const LinearIssueSource = Layer.effect(
231
232
  state,
232
233
  complete: state === "in-review" || state === "done",
233
234
  blockedBy: blockedBy.map((i) => i.identifier),
235
+ autoMerge: autoMergeLabelId.pipe(
236
+ Option.map((labelId) => issue.labelIds.includes(labelId)),
237
+ Option.getOrElse(() => false),
238
+ ),
234
239
  githubPrNumber: null,
235
240
  })
236
241
  }),
@@ -372,6 +377,7 @@ export const resetLinear = Effect.gen(function* () {
372
377
  yield* selectedProjectId.set(Option.none())
373
378
  yield* selectedTeamId.set(Option.none())
374
379
  yield* selectedLabelId.set(Option.none())
380
+ yield* selectedAutoMergeLabelId.set(Option.none())
375
381
  })
376
382
 
377
383
  export class LinearError extends Schema.ErrorClass("lalph/LinearError")({
@@ -459,9 +465,43 @@ const labelIdSelect = Effect.gen(function* () {
459
465
  return labelId
460
466
  })
461
467
  const getOrSelectLabel = Effect.gen(function* () {
462
- const labedId = yield* selectedLabelId.get
463
- if (Option.isSome(labedId)) {
464
- return labedId.value
468
+ const labelId = yield* selectedLabelId.get
469
+ if (Option.isSome(labelId)) {
470
+ return labelId.value
465
471
  }
466
472
  return yield* labelIdSelect
467
473
  })
474
+
475
+ // Auto merge label selection
476
+
477
+ const selectedAutoMergeLabelId = new Setting(
478
+ "linear.selectedAutoMergeLabelId",
479
+ Schema.Option(Schema.String),
480
+ )
481
+ const autoMergeLabelIdSelect = Effect.gen(function* () {
482
+ const linear = yield* Linear
483
+ const labels = yield* Stream.runCollect(linear.labels)
484
+ const labelId = yield* Prompt.select({
485
+ message: "Select a label to mark issues for auto merge",
486
+ choices: [
487
+ {
488
+ title: "Disabled",
489
+ value: Option.none<string>(),
490
+ },
491
+ ].concat(
492
+ labels.map((label) => ({
493
+ title: label.name,
494
+ value: Option.some(label.id),
495
+ })),
496
+ ),
497
+ })
498
+ yield* selectedAutoMergeLabelId.set(Option.some(labelId))
499
+ return labelId
500
+ })
501
+ const getOrSelectAutoMergeLabel = Effect.gen(function* () {
502
+ const labelId = yield* selectedAutoMergeLabelId.get
503
+ if (Option.isSome(labelId)) {
504
+ return labelId.value
505
+ }
506
+ return yield* autoMergeLabelIdSelect
507
+ })
package/src/Prd.ts CHANGED
@@ -193,12 +193,16 @@ export class Prd extends ServiceMap.Service<Prd>()("lalph/Prd", {
193
193
  })
194
194
  })
195
195
 
196
+ const findById = (issueId: string) =>
197
+ Effect.sync(() => current.find((i) => i.id === issueId) ?? null)
198
+
196
199
  return {
197
200
  path: prdFile,
198
201
  mergableGithubPrs,
199
202
  revertStateIds,
200
203
  maybeRevertIssue,
201
204
  flagUnmergable,
205
+ findById,
202
206
  } as const
203
207
  }),
204
208
  }) {
package/src/Runner.ts CHANGED
@@ -19,7 +19,6 @@ import { getOrSelectCliAgent } from "./CliAgent.ts"
19
19
  export const run = Effect.fnUntraced(
20
20
  function* (options: {
21
21
  readonly startedDeferred: Deferred.Deferred<void>
22
- readonly autoMerge: boolean
23
22
  readonly targetBranch: Option.Option<string>
24
23
  readonly specsDirectory: string
25
24
  readonly stallTimeout: Duration.Duration
@@ -38,7 +37,6 @@ export const run = Effect.fnUntraced(
38
37
  ) =>
39
38
  ChildProcess.make({
40
39
  cwd: worktree.directory,
41
- extendEnv: true,
42
40
  })(template, ...args).pipe(ChildProcess.exitCode)
43
41
 
44
42
  const execOutput = (
@@ -47,7 +45,6 @@ export const run = Effect.fnUntraced(
47
45
  ) =>
48
46
  ChildProcess.make({
49
47
  cwd: worktree.directory,
50
- extendEnv: true,
51
48
  })(template, ...args).pipe(
52
49
  ChildProcess.string,
53
50
  Effect.map((output) => output.trim()),
@@ -131,13 +128,15 @@ export const run = Effect.fnUntraced(
131
128
  const taskJson = yield* fs.readFileString(
132
129
  pathService.join(worktree.directory, ".lalph", "task.json"),
133
130
  )
134
- const task = yield* Schema.decodeEffect(ChosenTask)(taskJson)
131
+ const taskId = (yield* Schema.decodeEffect(ChosenTask)(taskJson)).id
132
+ const task = yield* prd.findById(taskId)
133
+ if (!task) return
135
134
 
136
135
  yield* Deferred.completeWith(options.startedDeferred, Effect.void)
137
136
 
138
137
  const cliCommand = cliAgent.command({
139
138
  prompt: promptGen.prompt({
140
- taskId: task.id,
139
+ taskId,
141
140
  targetBranch: Option.getOrUndefined(options.targetBranch),
142
141
  specsDirectory: options.specsDirectory,
143
142
  }),
@@ -151,7 +150,7 @@ export const run = Effect.fnUntraced(
151
150
  Effect.fnUntraced(function* (error) {
152
151
  const timeoutCommand = cliAgent.command({
153
152
  prompt: promptGen.promptTimeout({
154
- taskId: task.id,
153
+ taskId,
155
154
  }),
156
155
  prdFilePath: pathService.join(".lalph", "prd.yml"),
157
156
  })
@@ -164,11 +163,8 @@ export const run = Effect.fnUntraced(
164
163
 
165
164
  const prs = yield* prd.mergableGithubPrs
166
165
  if (prs.length === 0) {
167
- yield* prd.maybeRevertIssue({
168
- ...task,
169
- issueId: task.id,
170
- })
171
- } else if (options.autoMerge) {
166
+ yield* prd.maybeRevertIssue({ issueId: taskId })
167
+ } else if (task.autoMerge) {
172
168
  for (const pr of prs) {
173
169
  if (Option.isSome(options.targetBranch)) {
174
170
  yield* exec`gh pr edit ${pr.prNumber} --base ${options.targetBranch.value}`
package/src/cli.ts CHANGED
@@ -37,11 +37,6 @@ const concurrency = Flag.integer("concurrency").pipe(
37
37
  Flag.withDefault(1),
38
38
  )
39
39
 
40
- const autoMerge = Flag.boolean("auto-merge").pipe(
41
- Flag.withAlias("a"),
42
- Flag.withDescription("Automatically merge eligible PRs"),
43
- )
44
-
45
40
  const targetBranch = Flag.string("target-branch").pipe(
46
41
  Flag.withDescription(
47
42
  "Target branch for PRs. Env variable: LALPH_TARGET_BRANCH",
@@ -84,7 +79,6 @@ const reset = Flag.boolean("reset").pipe(
84
79
  const root = Command.make("lalph", {
85
80
  iterations,
86
81
  concurrency,
87
- autoMerge,
88
82
  targetBranch,
89
83
  maxIterationMinutes,
90
84
  stallMinutes,
@@ -95,7 +89,6 @@ const root = Command.make("lalph", {
95
89
  Effect.fnUntraced(function* ({
96
90
  iterations,
97
91
  concurrency,
98
- autoMerge,
99
92
  targetBranch,
100
93
  maxIterationMinutes,
101
94
  stallMinutes,
@@ -135,7 +128,6 @@ const root = Command.make("lalph", {
135
128
  Effect.andThen(
136
129
  run({
137
130
  startedDeferred,
138
- autoMerge,
139
131
  targetBranch,
140
132
  specsDirectory,
141
133
  stallTimeout: Duration.minutes(stallMinutes),
@@ -36,6 +36,10 @@ export class PrdIssue extends Schema.Class<PrdIssue>("PrdIssue")({
36
36
  complete: Schema.Boolean.annotate({
37
37
  description: "Whether the issue is complete.",
38
38
  }),
39
+ autoMerge: Schema.Boolean.annotate({
40
+ description:
41
+ "Whether the issue should be auto-merged when complete. Read-only field",
42
+ }),
39
43
  githubPrNumber: Schema.NullOr(Schema.Finite).annotate({
40
44
  description:
41
45
  "The created or updated Github pull request number for this task.",