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 +49 -23
- package/package.json +1 -1
- package/src/CurrentIssueSource.ts +1 -20
- package/src/commands/root.ts +31 -33
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*
|
|
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.
|
|
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
|
@@ -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 {
|
|
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
|
-
}
|
package/src/commands/root.ts
CHANGED
|
@@ -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*
|
|
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
|