lalph 0.3.97 → 0.3.98

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
@@ -31501,6 +31501,42 @@ const takeUntil = /* @__PURE__ */ dual((args) => isStream(args[0]), (self, predi
31501
31501
  });
31502
31502
  })));
31503
31503
  /**
31504
+ * Effectful predicate version of `takeUntil`.
31505
+ *
31506
+ * @example
31507
+ * ```ts
31508
+ * import { Console, Effect, Stream } from "effect"
31509
+ *
31510
+ * const program = Effect.gen(function*() {
31511
+ * const result = yield* Stream.range(1, 5).pipe(
31512
+ * Stream.takeUntilEffect((n) => Effect.succeed(n % 3 === 0)),
31513
+ * Stream.runCollect
31514
+ * )
31515
+ * yield* Console.log(result)
31516
+ * })
31517
+ *
31518
+ * Effect.runPromise(program)
31519
+ * // Output: [ 1, 2, 3 ]
31520
+ * ```
31521
+ *
31522
+ * @since 2.0.0
31523
+ * @category Filtering
31524
+ */
31525
+ const takeUntilEffect = /* @__PURE__ */ dual((args) => isStream(args[0]), (self, predicate, options) => transformPull(self, (pull, _scope) => sync(() => {
31526
+ let i = 0;
31527
+ let done$6 = false;
31528
+ return gen(function* () {
31529
+ if (done$6) return yield* done();
31530
+ const chunk = yield* pull;
31531
+ for (let j = 0; j < chunk.length; j++) if (yield* predicate(chunk[j], i++)) {
31532
+ done$6 = true;
31533
+ const arr = chunk.slice(0, options?.excludeLast ? j : j + 1);
31534
+ return isReadonlyArrayNonEmpty(arr) ? arr : yield* done();
31535
+ }
31536
+ return chunk;
31537
+ });
31538
+ })));
31539
+ /**
31504
31540
  * Drops the first `n` elements from this stream.
31505
31541
  *
31506
31542
  * @example
@@ -240005,11 +240041,6 @@ var CurrentIssueSource = class CurrentIssueSource extends Service$1()("lalph/Cur
240005
240041
  };
240006
240042
  const refreshSchedule = exponential(100, 1.5).pipe(either(spaced("30 seconds")));
240007
240043
  const getCurrentIssues = (projectId) => IssueSource.use((s) => pipe$1(s.ref(projectId), flatMap$4(get$5)));
240008
- const checkForWork = fnUntraced(function* (project) {
240009
- if (project.gitFlow === "ralph") return;
240010
- const { issues } = yield* getCurrentIssues(project.id);
240011
- if (!issues.some((issue) => issue.state === "todo" && issue.blockedBy.length === 0)) return yield* new NoMoreWork({});
240012
- });
240013
240044
  const resetInProgress = gen(function* () {
240014
240045
  const source = yield* IssueSource;
240015
240046
  const projectId = yield* CurrentProjectId;
@@ -240025,9 +240056,6 @@ const resetInProgress = gen(function* () {
240025
240056
  discard: true
240026
240057
  });
240027
240058
  });
240028
- var NoMoreWork = class extends ErrorClass("lalph/Prd/NoMoreWork")({ _tag: tag("NoMoreWork") }) {
240029
- message = "No more work to be done!";
240030
- };
240031
240059
  //#endregion
240032
240060
  //#region src/PromptGen.ts
240033
240061
  var PromptGen = class extends Service$1()("lalph/PromptGen", { make: gen(function* () {
@@ -241697,6 +241725,7 @@ const runProject = fnUntraced(function* (options) {
241697
241725
  const iterationsDisplay = isFinite ? options.iterations : "unlimited";
241698
241726
  const semaphore = makeUnsafe$9(options.project.concurrency);
241699
241727
  const fibers = yield* make$56();
241728
+ const issuesRef = yield* (yield* IssueSource).ref(options.project.id);
241700
241729
  let executionMode;
241701
241730
  if (options.project.gitFlow === "ralph") {
241702
241731
  if (!options.project.ralphSpec) return yield* new RalphSpecMissing({ projectId: options.project.id });
@@ -241733,20 +241762,22 @@ const runProject = fnUntraced(function* (options) {
241733
241762
  research: options.project.researchAgent
241734
241763
  });
241735
241764
  };
241736
- const handleNoMoreWork = (currentIteration, setIterations) => {
241737
- if (executionMode._tag === "ralph") return void_$2;
241738
- if (isFinite) {
241739
- setIterations(currentIteration);
241740
- return log$1(`No more work to process, ending after ${currentIteration} iteration(s).`);
241741
- }
241742
- return andThen(size$3(fibers) <= 1 ? log$1("No more work to process, waiting 30 seconds...") : void_$2, sleep(seconds(30)));
241743
- };
241744
241765
  yield* resetInProgress.pipe(withSpan$1("Main.resetInProgress"));
241745
241766
  yield* log$1(`Executing ${iterationsDisplay} iteration(s) with concurrency ${options.project.concurrency}`);
241746
241767
  let iterations = options.iterations;
241747
241768
  let iteration = 0;
241748
241769
  let quit = false;
241749
241770
  yield* mount(activeWorkerLoggingAtom);
241771
+ const waitForWork = executionMode._tag === "ralph" ? void_$2 : changes(issuesRef).pipe(takeUntilEffect(fnUntraced(function* ({ issues }) {
241772
+ if (issues.some((issue) => issue.state === "todo" && issue.blockedBy.length === 0)) return true;
241773
+ if (isFinite) {
241774
+ quit = true;
241775
+ yield* log$1(`No more work to process, ending after ${iteration} iteration(s).`);
241776
+ return yield* interrupt$1;
241777
+ }
241778
+ if (size$3(fibers) <= 1) yield* log$1("No more work to process");
241779
+ return false;
241780
+ })), runDrain);
241750
241781
  while (true) {
241751
241782
  yield* semaphore.take(1);
241752
241783
  if (quit || isFinite && iteration >= iterations) break;
@@ -241754,17 +241785,12 @@ const runProject = fnUntraced(function* (options) {
241754
241785
  const startedDeferred = yield* make$87();
241755
241786
  let ralphDone = false;
241756
241787
  const gitFlowLayer = resolveGitFlowLayer();
241757
- const fiber = yield* checkForWork(options.project).pipe(andThen(resolveRunEffect(startedDeferred).pipe(provide$1(gitFlowLayer, { local: true }), withWorkerState(options.project.id))), catchTags$1({
241788
+ const fiber = yield* waitForWork.pipe(andThen(resolveRunEffect(startedDeferred).pipe(provide$1(gitFlowLayer, { local: true }), withWorkerState(options.project.id))), catchTags$1({
241758
241789
  ChosenTaskNotFound(_error) {
241759
241790
  if (executionMode._tag !== "ralph") return void_$2;
241760
241791
  ralphDone = true;
241761
241792
  return log$1(`No more work to process for Ralph, ending after ${currentIteration + 1} iteration(s).`);
241762
241793
  },
241763
- NoMoreWork(_error) {
241764
- return handleNoMoreWork(currentIteration, (newIterations) => {
241765
- iterations = newIterations;
241766
- });
241767
- },
241768
241794
  QuitError(_error) {
241769
241795
  quit = true;
241770
241796
  return void_$2;
@@ -242133,7 +242159,7 @@ const commandEdit = make$60("edit").pipe(withDescription("Open the selected proj
242133
242159
  const commandSource = make$60("source").pipe(withDescription("Select the issue source to use (e.g. GitHub Issues or Linear). This applies to all projects."), withHandler(() => selectIssueSource), provide(Settings.layer));
242134
242160
  //#endregion
242135
242161
  //#region package.json
242136
- var version = "0.3.97";
242162
+ var version = "0.3.98";
242137
242163
  //#endregion
242138
242164
  //#region src/Tracing.ts
242139
242165
  const TracingLayer = unwrap$3(gen(function* () {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "lalph",
3
3
  "type": "module",
4
- "version": "0.3.97",
4
+ "version": "0.3.98",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -17,7 +17,7 @@ import { GithubIssueSource } from "./Github.ts"
17
17
  import { IssuesChange, IssueSource } from "./IssueSource.ts"
18
18
  import { PlatformServices } from "./shared/platform.ts"
19
19
  import type { PrdIssue } from "./domain/PrdIssue.ts"
20
- import type { Project, ProjectId } from "./domain/Project.ts"
20
+ import type { ProjectId } from "./domain/Project.ts"
21
21
  import type { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner"
22
22
 
23
23
  const issueSources: ReadonlyArray<typeof CurrentIssueSource.Service> = [
@@ -202,17 +202,6 @@ const getCurrentIssues = (projectId: ProjectId) =>
202
202
  pipe(s.ref(projectId), Effect.flatMap(SubscriptionRef.get)),
203
203
  )
204
204
 
205
- export const checkForWork = Effect.fnUntraced(function* (project: Project) {
206
- if (project.gitFlow === "ralph") return
207
- const { issues } = yield* getCurrentIssues(project.id)
208
- const hasIncomplete = issues.some(
209
- (issue) => issue.state === "todo" && issue.blockedBy.length === 0,
210
- )
211
- if (!hasIncomplete) {
212
- return yield* new NoMoreWork({})
213
- }
214
- })
215
-
216
205
  export const resetInProgress = Effect.gen(function* () {
217
206
  const source = yield* IssueSource
218
207
  const projectId = yield* CurrentProjectId
@@ -233,11 +222,3 @@ export const resetInProgress = Effect.gen(function* () {
233
222
  { concurrency: 5, discard: true },
234
223
  )
235
224
  })
236
-
237
- export class NoMoreWork extends Schema.ErrorClass<NoMoreWork>(
238
- "lalph/Prd/NoMoreWork",
239
- )({
240
- _tag: Schema.tag("NoMoreWork"),
241
- }) {
242
- readonly message = "No more work to be done!"
243
- }
@@ -24,11 +24,7 @@ import { Prd } from "../Prd.ts"
24
24
  import { Worktree } from "../Worktree.ts"
25
25
  import { Flag, Command, Prompt } from "effect/unstable/cli"
26
26
  import { IssueSource, IssueSourceError } from "../IssueSource.ts"
27
- import {
28
- checkForWork,
29
- CurrentIssueSource,
30
- resetInProgress,
31
- } from "../CurrentIssueSource.ts"
27
+ import { CurrentIssueSource, resetInProgress } from "../CurrentIssueSource.ts"
32
28
  import { GithubCli } from "../Github/Cli.ts"
33
29
  import { agentWorker } from "../Agents/worker.ts"
34
30
  import { agentChooser, ChosenTaskNotFound } from "../Agents/chooser.ts"
@@ -542,6 +538,8 @@ const runProject = Effect.fnUntraced(
542
538
  const iterationsDisplay = isFinite ? options.iterations : "unlimited"
543
539
  const semaphore = Semaphore.makeUnsafe(options.project.concurrency)
544
540
  const fibers = yield* FiberSet.make()
541
+ const source = yield* IssueSource
542
+ const issuesRef = yield* source.ref(options.project.id)
545
543
 
546
544
  let executionMode: ProjectExecutionMode
547
545
  if (options.project.gitFlow === "ralph") {
@@ -594,28 +592,6 @@ const runProject = Effect.fnUntraced(
594
592
  })
595
593
  }
596
594
 
597
- const handleNoMoreWork = (
598
- currentIteration: number,
599
- setIterations: (iterations: number) => void,
600
- ) => {
601
- if (executionMode._tag === "ralph") {
602
- return Effect.void
603
- }
604
- if (isFinite) {
605
- // If we have a finite number of iterations, we exit when no more
606
- // work is found
607
- setIterations(currentIteration)
608
- return Effect.log(
609
- `No more work to process, ending after ${currentIteration} iteration(s).`,
610
- )
611
- }
612
- const log =
613
- Iterable.size(fibers) <= 1
614
- ? Effect.log("No more work to process, waiting 30 seconds...")
615
- : Effect.void
616
- return Effect.andThen(log, Effect.sleep(Duration.seconds(30)))
617
- }
618
-
619
595
  yield* resetInProgress.pipe(Effect.withSpan("Main.resetInProgress"))
620
596
 
621
597
  yield* Effect.log(
@@ -628,6 +604,33 @@ const runProject = Effect.fnUntraced(
628
604
 
629
605
  yield* Atom.mount(activeWorkerLoggingAtom)
630
606
 
607
+ const waitForWork =
608
+ executionMode._tag === "ralph"
609
+ ? Effect.void
610
+ : SubscriptionRef.changes(issuesRef).pipe(
611
+ Stream.takeUntilEffect(
612
+ Effect.fnUntraced(function* ({ issues }) {
613
+ const hasIncomplete = issues.some(
614
+ (issue) =>
615
+ issue.state === "todo" && issue.blockedBy.length === 0,
616
+ )
617
+ if (hasIncomplete) return true
618
+ if (isFinite) {
619
+ quit = true
620
+ yield* Effect.log(
621
+ `No more work to process, ending after ${iteration} iteration(s).`,
622
+ )
623
+ return yield* Effect.interrupt
624
+ }
625
+ if (Iterable.size(fibers) <= 1) {
626
+ yield* Effect.log("No more work to process")
627
+ }
628
+ return false
629
+ }),
630
+ ),
631
+ Stream.runDrain,
632
+ )
633
+
631
634
  while (true) {
632
635
  yield* semaphore.take(1)
633
636
  if (quit || (isFinite && iteration >= iterations)) {
@@ -640,7 +643,7 @@ const runProject = Effect.fnUntraced(
640
643
  let ralphDone = false
641
644
 
642
645
  const gitFlowLayer = resolveGitFlowLayer()
643
- const fiber = yield* checkForWork(options.project).pipe(
646
+ const fiber = yield* waitForWork.pipe(
644
647
  Effect.andThen(
645
648
  resolveRunEffect(startedDeferred).pipe(
646
649
  Effect.provide(gitFlowLayer, { local: true }),
@@ -657,11 +660,6 @@ const runProject = Effect.fnUntraced(
657
660
  `No more work to process for Ralph, ending after ${currentIteration + 1} iteration(s).`,
658
661
  )
659
662
  },
660
- NoMoreWork(_error) {
661
- return handleNoMoreWork(currentIteration, (newIterations) => {
662
- iterations = newIterations
663
- })
664
- },
665
663
  QuitError(_error) {
666
664
  quit = true
667
665
  return Effect.void