lalph 0.3.46 → 0.3.47
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 +332 -35
- package/package.json +2 -2
- package/src/Agents/worker.ts +10 -2
- package/src/Clanka.ts +14 -3
- package/src/Editor.ts +12 -1
- package/src/TaskTools.ts +22 -5
- package/src/commands/issue.ts +13 -3
- package/src/commands/plan.ts +58 -36
- package/src/commands/root.ts +45 -0
- package/src/domain/PrdIssue.ts +15 -0
package/dist/cli.mjs
CHANGED
|
@@ -5353,6 +5353,18 @@ const succeed$8 = succeed$9;
|
|
|
5353
5353
|
*/
|
|
5354
5354
|
const fail$10 = fail$11;
|
|
5355
5355
|
/**
|
|
5356
|
+
* A pre-built `Result<void>` holding `undefined` as its failure value.
|
|
5357
|
+
*
|
|
5358
|
+
* - Use when you need a `Result` that represents "failed with no meaningful value"
|
|
5359
|
+
* - Equivalent to `Result.fail(undefined)` but avoids an extra allocation
|
|
5360
|
+
*
|
|
5361
|
+
* @see {@link fail}
|
|
5362
|
+
*
|
|
5363
|
+
* @category Constructors
|
|
5364
|
+
* @since 4.0.0
|
|
5365
|
+
*/
|
|
5366
|
+
const failVoid = /* @__PURE__ */ fail$10(void 0);
|
|
5367
|
+
/**
|
|
5356
5368
|
* Checks whether a `Result` is a `Failure`.
|
|
5357
5369
|
*
|
|
5358
5370
|
* - Acts as a TypeScript type guard, narrowing to `Failure<A, E>`
|
|
@@ -13021,7 +13033,7 @@ const repeat$1 = /* @__PURE__ */ dual(2, (self, options) => {
|
|
|
13021
13033
|
return repeatOrElse$1(self, typeof options === "function" ? options(identity) : isSchedule(options) ? options : buildFromOptions(options), fail$9);
|
|
13022
13034
|
});
|
|
13023
13035
|
/** @internal */
|
|
13024
|
-
const retry$
|
|
13036
|
+
const retry$4 = /* @__PURE__ */ dual(2, (self, options) => {
|
|
13025
13037
|
return retryOrElse$1(self, typeof options === "function" ? options(identity) : isSchedule(options) ? options : buildFromOptions(options), fail$9);
|
|
13026
13038
|
});
|
|
13027
13039
|
const passthroughForever = /* @__PURE__ */ passthrough$2(forever$1);
|
|
@@ -14800,7 +14812,7 @@ const tapCause = tapCause$1;
|
|
|
14800
14812
|
* @since 2.0.0
|
|
14801
14813
|
* @category Error Handling
|
|
14802
14814
|
*/
|
|
14803
|
-
const retry$
|
|
14815
|
+
const retry$3 = retry$4;
|
|
14804
14816
|
/**
|
|
14805
14817
|
* Discards both the success and failure values of an effect.
|
|
14806
14818
|
*
|
|
@@ -24046,6 +24058,90 @@ const set$9 = /* @__PURE__ */ dual(2, (self, value) => {
|
|
|
24046
24058
|
self.current = value;
|
|
24047
24059
|
return self;
|
|
24048
24060
|
});
|
|
24061
|
+
/**
|
|
24062
|
+
* Sets the MutableRef to a new value and returns the new value.
|
|
24063
|
+
*
|
|
24064
|
+
* @example
|
|
24065
|
+
* ```ts
|
|
24066
|
+
* import { MutableRef } from "effect"
|
|
24067
|
+
*
|
|
24068
|
+
* const ref = MutableRef.make("old")
|
|
24069
|
+
*
|
|
24070
|
+
* // Set and get the new value
|
|
24071
|
+
* const newValue = MutableRef.setAndGet(ref, "new")
|
|
24072
|
+
* console.log(newValue) // "new"
|
|
24073
|
+
* console.log(MutableRef.get(ref)) // "new"
|
|
24074
|
+
*
|
|
24075
|
+
* // Useful for assignments that need the value
|
|
24076
|
+
* const counter = MutableRef.make(0)
|
|
24077
|
+
* const currentValue = MutableRef.setAndGet(counter, 42)
|
|
24078
|
+
* console.log(`Counter set to: ${currentValue}`) // "Counter set to: 42"
|
|
24079
|
+
*
|
|
24080
|
+
* // Pipe-able version
|
|
24081
|
+
* const setValue = MutableRef.setAndGet("final")
|
|
24082
|
+
* const result = setValue(ref)
|
|
24083
|
+
* console.log(result) // "final"
|
|
24084
|
+
*
|
|
24085
|
+
* // Difference from set: returns value instead of reference
|
|
24086
|
+
* const ref1 = MutableRef.make(1)
|
|
24087
|
+
* const returnedRef = MutableRef.set(ref1, 2) // Returns MutableRef
|
|
24088
|
+
* const returnedValue = MutableRef.setAndGet(ref1, 3) // Returns value
|
|
24089
|
+
* console.log(returnedValue) // 3
|
|
24090
|
+
* ```
|
|
24091
|
+
*
|
|
24092
|
+
* @since 2.0.0
|
|
24093
|
+
* @category general
|
|
24094
|
+
*/
|
|
24095
|
+
const setAndGet = /* @__PURE__ */ dual(2, (self, value) => {
|
|
24096
|
+
self.current = value;
|
|
24097
|
+
return self.current;
|
|
24098
|
+
});
|
|
24099
|
+
/**
|
|
24100
|
+
* Updates the MutableRef with the result of applying a function to its current value,
|
|
24101
|
+
* and returns the new value.
|
|
24102
|
+
*
|
|
24103
|
+
* @example
|
|
24104
|
+
* ```ts
|
|
24105
|
+
* import { MutableRef } from "effect"
|
|
24106
|
+
*
|
|
24107
|
+
* const counter = MutableRef.make(5)
|
|
24108
|
+
*
|
|
24109
|
+
* // Increment and get the new value
|
|
24110
|
+
* const newValue = MutableRef.updateAndGet(counter, (n) => n + 1)
|
|
24111
|
+
* console.log(newValue) // 6
|
|
24112
|
+
* console.log(MutableRef.get(counter)) // 6
|
|
24113
|
+
*
|
|
24114
|
+
* // Double the value and get the result
|
|
24115
|
+
* const doubled = MutableRef.updateAndGet(counter, (n) => n * 2)
|
|
24116
|
+
* console.log(doubled) // 12
|
|
24117
|
+
*
|
|
24118
|
+
* // Transform string and get result
|
|
24119
|
+
* const message = MutableRef.make("hello")
|
|
24120
|
+
* const upperCase = MutableRef.updateAndGet(message, (s) => s.toUpperCase())
|
|
24121
|
+
* console.log(upperCase) // "HELLO"
|
|
24122
|
+
*
|
|
24123
|
+
* // Pipe-able version
|
|
24124
|
+
* const increment = MutableRef.updateAndGet((n: number) => n + 1)
|
|
24125
|
+
* const result = increment(counter)
|
|
24126
|
+
* console.log(result) // 13 (new value)
|
|
24127
|
+
*
|
|
24128
|
+
* // Useful for calculations that need the result
|
|
24129
|
+
* const score = MutableRef.make(100)
|
|
24130
|
+
* const bonus = 50
|
|
24131
|
+
* const newScore = MutableRef.updateAndGet(score, (s) => s + bonus)
|
|
24132
|
+
* console.log(`New score: ${newScore}`) // "New score: 150"
|
|
24133
|
+
*
|
|
24134
|
+
* // Array transformations
|
|
24135
|
+
* const list = MutableRef.make<Array<number>>([1, 2, 3])
|
|
24136
|
+
* const newList = MutableRef.updateAndGet(list, (arr) => arr.map((x) => x * 2))
|
|
24137
|
+
* console.log(newList) // [2, 4, 6]
|
|
24138
|
+
* console.log(MutableRef.get(list)) // [2, 4, 6]
|
|
24139
|
+
* ```
|
|
24140
|
+
*
|
|
24141
|
+
* @since 2.0.0
|
|
24142
|
+
* @category general
|
|
24143
|
+
*/
|
|
24144
|
+
const updateAndGet = /* @__PURE__ */ dual(2, (self, f) => setAndGet(self, f(get$14(self))));
|
|
24049
24145
|
//#endregion
|
|
24050
24146
|
//#region node_modules/.pnpm/effect@4.0.0-beta.30/node_modules/effect/dist/PubSub.js
|
|
24051
24147
|
/**
|
|
@@ -27684,6 +27780,18 @@ const filterArray = /* @__PURE__ */ dual(2, (self, predicate) => transformPull$1
|
|
|
27684
27780
|
* @since 4.0.0
|
|
27685
27781
|
* @category Filtering
|
|
27686
27782
|
*/
|
|
27783
|
+
const filterMapArray = /* @__PURE__ */ dual(2, (self, filter) => transformPull$1(self, (pull) => succeed$3(flatMap$4(pull, function loop(arr) {
|
|
27784
|
+
const passes = [];
|
|
27785
|
+
for (let i = 0; i < arr.length; i++) {
|
|
27786
|
+
const result = filter(arr[i]);
|
|
27787
|
+
if (isSuccess$5(result)) passes.push(result.success);
|
|
27788
|
+
}
|
|
27789
|
+
return isReadonlyArrayNonEmpty(passes) ? succeed$3(passes) : flatMap$4(pull, loop);
|
|
27790
|
+
}))));
|
|
27791
|
+
/**
|
|
27792
|
+
* @since 4.0.0
|
|
27793
|
+
* @category Filtering
|
|
27794
|
+
*/
|
|
27687
27795
|
const filterMapArrayEffect = /* @__PURE__ */ dual(2, (self, filter) => transformPull$1(self, (pull) => succeed$3(flatMap$4(pull, function loop(arr) {
|
|
27688
27796
|
return flatMap$4(filterMapEffect$1(arr, filter), (passes) => isReadonlyArrayNonEmpty(passes) ? succeed$3(passes) : flatMap$4(pull, loop));
|
|
27689
27797
|
}))));
|
|
@@ -27796,6 +27904,63 @@ const mapError$1 = /* @__PURE__ */ dual(2, (self, f) => catch_$1(self, (err) =>
|
|
|
27796
27904
|
*/
|
|
27797
27905
|
const orDie$1 = (self) => catch_$1(self, die$1);
|
|
27798
27906
|
/**
|
|
27907
|
+
* Returns a new channel that retries this channel according to the specified
|
|
27908
|
+
* schedule whenever it fails.
|
|
27909
|
+
*
|
|
27910
|
+
* @since 4.0.0
|
|
27911
|
+
* @category utils
|
|
27912
|
+
*/
|
|
27913
|
+
const retry$2 = /* @__PURE__ */ dual(2, (self, schedule) => suspend$2(() => {
|
|
27914
|
+
let step = void 0;
|
|
27915
|
+
let meta = CurrentMetadata.defaultValue();
|
|
27916
|
+
const withReset = onFirst(provideServiceEffect(self, CurrentMetadata, sync(() => meta)), () => {
|
|
27917
|
+
step = void 0;
|
|
27918
|
+
return void_$1;
|
|
27919
|
+
});
|
|
27920
|
+
const resolvedSchedule = typeof schedule === "function" ? schedule(identity) : schedule;
|
|
27921
|
+
const loop = catch_$1(withReset, fnUntraced(function* (error) {
|
|
27922
|
+
if (!step) step = yield* toStepWithMetadata(resolvedSchedule);
|
|
27923
|
+
meta = yield* step(error);
|
|
27924
|
+
return loop;
|
|
27925
|
+
}, (effect, error) => catchDone(effect, () => succeed$3(fail$3(error))), unwrap$2));
|
|
27926
|
+
return loop;
|
|
27927
|
+
}));
|
|
27928
|
+
/**
|
|
27929
|
+
* Returns a new channel, which sequentially combines this channel, together
|
|
27930
|
+
* with the provided factory function, which creates a second channel based on
|
|
27931
|
+
* the output values of this channel. The result is a channel that will first
|
|
27932
|
+
* perform the functions of this channel, before performing the functions of
|
|
27933
|
+
* the created channel (including yielding its terminal value).
|
|
27934
|
+
*
|
|
27935
|
+
* @example
|
|
27936
|
+
* ```ts
|
|
27937
|
+
* import { Channel, Data } from "effect"
|
|
27938
|
+
*
|
|
27939
|
+
* class SwitchError extends Data.TaggedError("SwitchError")<{
|
|
27940
|
+
* readonly reason: string
|
|
27941
|
+
* }> {}
|
|
27942
|
+
*
|
|
27943
|
+
* // Create a channel that outputs numbers
|
|
27944
|
+
* const numberChannel = Channel.fromIterable([1, 2, 3])
|
|
27945
|
+
*
|
|
27946
|
+
* // Switch to new channels based on each value
|
|
27947
|
+
* const switchedChannel = Channel.switchMap(
|
|
27948
|
+
* numberChannel,
|
|
27949
|
+
* (n) => Channel.fromIterable([`value-${n}`])
|
|
27950
|
+
* )
|
|
27951
|
+
*
|
|
27952
|
+
* // Outputs: "value-1", "value-2", "value-3"
|
|
27953
|
+
* ```
|
|
27954
|
+
*
|
|
27955
|
+
* @since 2.0.0
|
|
27956
|
+
* @category sequencing
|
|
27957
|
+
*/
|
|
27958
|
+
const switchMap$1 = /* @__PURE__ */ dual((args) => isChannel(args[0]), (self, f, options) => self.pipe(map$7(f), mergeAll$1({
|
|
27959
|
+
...options,
|
|
27960
|
+
concurrency: options?.concurrency ?? 1,
|
|
27961
|
+
switch: true
|
|
27962
|
+
})));
|
|
27963
|
+
/**
|
|
27799
27964
|
* Merges multiple channels with specified concurrency and buffering options.
|
|
27800
27965
|
*
|
|
27801
27966
|
* @example
|
|
@@ -28066,6 +28231,18 @@ const onExit = /* @__PURE__ */ dual(2, (self, finalizer) => fromTransformBracket
|
|
|
28066
28231
|
* @since 4.0.0
|
|
28067
28232
|
* @category utils
|
|
28068
28233
|
*/
|
|
28234
|
+
const onFirst = /* @__PURE__ */ dual(2, (self, onFirst) => transformPull$1(self, (pull) => sync(() => {
|
|
28235
|
+
let isFirst = true;
|
|
28236
|
+
const pullFirst = tap$1(pull, (element) => {
|
|
28237
|
+
isFirst = false;
|
|
28238
|
+
return onFirst(element);
|
|
28239
|
+
});
|
|
28240
|
+
return suspend$3(() => isFirst ? pullFirst : pull);
|
|
28241
|
+
})));
|
|
28242
|
+
/**
|
|
28243
|
+
* @since 4.0.0
|
|
28244
|
+
* @category utils
|
|
28245
|
+
*/
|
|
28069
28246
|
const onEnd$1 = /* @__PURE__ */ dual(2, (self, onEnd) => transformPull$1(self, (pull) => succeed$3(catchDone(pull, (leftover) => flatMap$4(onEnd, () => done(leftover))))));
|
|
28070
28247
|
/**
|
|
28071
28248
|
* Returns a new channel with an attached finalizer. The finalizer is
|
|
@@ -28104,6 +28281,11 @@ const runWith$1 = (self, f, onHalt) => suspend$3(() => {
|
|
|
28104
28281
|
*/
|
|
28105
28282
|
const provideService$1 = /* @__PURE__ */ dual(3, (self, key, service) => fromTransform$1((upstream, scope) => map$8(provideService$2(toTransform(self)(upstream, scope), key, service), provideService$2(key, service))));
|
|
28106
28283
|
/**
|
|
28284
|
+
* @since 4.0.0
|
|
28285
|
+
* @category Services
|
|
28286
|
+
*/
|
|
28287
|
+
const provideServiceEffect = /* @__PURE__ */ dual(3, (self, key, service) => fromTransform$1((upstream, scope) => flatMap$4(service, (s) => toTransform(provideService$1(self, key, s))(upstream, scope))));
|
|
28288
|
+
/**
|
|
28107
28289
|
* Runs a channel and discards all output elements, returning only the final result.
|
|
28108
28290
|
*
|
|
28109
28291
|
* @example
|
|
@@ -29581,6 +29763,30 @@ const tap = /* @__PURE__ */ dual((args) => isStream(args[0]), (self, f, options)
|
|
|
29581
29763
|
*/
|
|
29582
29764
|
const flatMap$2 = /* @__PURE__ */ dual((args) => isStream(args[0]), (self, f, options) => self.channel.pipe(flattenArray, flatMap$3((a) => f(a).channel, options), fromChannel));
|
|
29583
29765
|
/**
|
|
29766
|
+
* Switches to the latest stream produced by the mapping function, interrupting
|
|
29767
|
+
* the previous stream when a new element arrives.
|
|
29768
|
+
*
|
|
29769
|
+
* @example
|
|
29770
|
+
* ```ts
|
|
29771
|
+
* import { Console, Effect, Stream } from "effect"
|
|
29772
|
+
*
|
|
29773
|
+
* const program = Stream.make(1, 2, 3).pipe(
|
|
29774
|
+
* Stream.switchMap((n) => (n === 3 ? Stream.make(n) : Stream.never)),
|
|
29775
|
+
* Stream.runCollect
|
|
29776
|
+
* )
|
|
29777
|
+
*
|
|
29778
|
+
* Effect.gen(function*() {
|
|
29779
|
+
* const result = yield* program
|
|
29780
|
+
* yield* Console.log(result)
|
|
29781
|
+
* // Output: [ 3 ]
|
|
29782
|
+
* })
|
|
29783
|
+
* ```
|
|
29784
|
+
*
|
|
29785
|
+
* @since 4.0.0
|
|
29786
|
+
* @category Sequencing
|
|
29787
|
+
*/
|
|
29788
|
+
const switchMap = /* @__PURE__ */ dual((args) => isStream(args[0]), (self, f, options) => self.channel.pipe(flattenArray, switchMap$1((a) => f(a).channel, options), fromChannel));
|
|
29789
|
+
/**
|
|
29584
29790
|
* Flattens a stream of streams into a single stream by concatenating the
|
|
29585
29791
|
* inner streams in strict order.
|
|
29586
29792
|
*
|
|
@@ -29764,6 +29970,13 @@ const mergeAll = /* @__PURE__ */ dual(2, (streams, options) => flatten(fromItera
|
|
|
29764
29970
|
*/
|
|
29765
29971
|
const filter$3 = /* @__PURE__ */ dual(2, (self, predicate) => fromChannel(filterArray(toChannel(self), predicate)));
|
|
29766
29972
|
/**
|
|
29973
|
+
* Filters and maps stream elements in one pass using a `Filter`.
|
|
29974
|
+
*
|
|
29975
|
+
* @since 4.0.0
|
|
29976
|
+
* @category Filtering
|
|
29977
|
+
*/
|
|
29978
|
+
const filterMap$2 = /* @__PURE__ */ dual(2, (self, filter) => fromChannel(filterMapArray(toChannel(self), filter)));
|
|
29979
|
+
/**
|
|
29767
29980
|
* Effectfully filters and maps elements in a single pass.
|
|
29768
29981
|
*
|
|
29769
29982
|
* @since 4.0.0
|
|
@@ -29945,6 +30158,38 @@ const mapError = /* @__PURE__ */ dual(2, (self, f) => fromChannel(mapError$1(sel
|
|
|
29945
30158
|
*/
|
|
29946
30159
|
const orDie = (self) => fromChannel(orDie$1(self.channel));
|
|
29947
30160
|
/**
|
|
30161
|
+
* When the stream fails, retry it according to the given schedule.
|
|
30162
|
+
*
|
|
30163
|
+
* This retries the entire stream, so will re-execute all of the stream's
|
|
30164
|
+
* acquire operations.
|
|
30165
|
+
*
|
|
30166
|
+
* The schedule is reset as soon as the first element passes through the
|
|
30167
|
+
* stream again.
|
|
30168
|
+
*
|
|
30169
|
+
* @example
|
|
30170
|
+
* ```ts
|
|
30171
|
+
* import { Console, Effect, Schedule, Stream } from "effect"
|
|
30172
|
+
*
|
|
30173
|
+
* const program = Effect.gen(function*() {
|
|
30174
|
+
* const values = yield* Stream.make(1).pipe(
|
|
30175
|
+
* Stream.concat(Stream.fail("boom")),
|
|
30176
|
+
* Stream.retry(Schedule.recurs(1)),
|
|
30177
|
+
* Stream.take(2),
|
|
30178
|
+
* Stream.runCollect
|
|
30179
|
+
* )
|
|
30180
|
+
*
|
|
30181
|
+
* yield* Console.log(values)
|
|
30182
|
+
* })
|
|
30183
|
+
*
|
|
30184
|
+
* Effect.runPromise(program)
|
|
30185
|
+
* // Output: [ 1, 1 ]
|
|
30186
|
+
* ```
|
|
30187
|
+
*
|
|
30188
|
+
* @since 2.0.0
|
|
30189
|
+
* @category Error Handling
|
|
30190
|
+
*/
|
|
30191
|
+
const retry$1 = /* @__PURE__ */ dual(2, (self, policy) => fromChannel(retry$2(self.channel, policy)));
|
|
30192
|
+
/**
|
|
29948
30193
|
* Takes the first `n` elements from this stream, returning `Stream.empty` when `n < 1`.
|
|
29949
30194
|
*
|
|
29950
30195
|
* @example
|
|
@@ -57286,7 +57531,7 @@ const retryTransient = /* @__PURE__ */ dual(2, (self, options) => {
|
|
|
57286
57531
|
schedule: passthroughSchedule,
|
|
57287
57532
|
times,
|
|
57288
57533
|
while: isTransientResponse
|
|
57289
|
-
}), retryOn === "response-only" ? identity : retry$
|
|
57534
|
+
}), retryOn === "response-only" ? identity : retry$3({
|
|
57290
57535
|
while: isOnlySchedule || options.while === void 0 ? isTransientError : or(isTransientError, options.while),
|
|
57291
57536
|
schedule,
|
|
57292
57537
|
times
|
|
@@ -87378,6 +87623,15 @@ var PrdIssue = class PrdIssue extends Class$1("PrdIssue")({
|
|
|
87378
87623
|
autoMerge
|
|
87379
87624
|
});
|
|
87380
87625
|
}
|
|
87626
|
+
update(options) {
|
|
87627
|
+
return new PrdIssue({
|
|
87628
|
+
...this,
|
|
87629
|
+
title: options.title ?? this.title,
|
|
87630
|
+
description: options.description ?? this.description,
|
|
87631
|
+
state: options.state ?? this.state,
|
|
87632
|
+
blockedBy: options.blockedBy ?? this.blockedBy
|
|
87633
|
+
});
|
|
87634
|
+
}
|
|
87381
87635
|
};
|
|
87382
87636
|
//#endregion
|
|
87383
87637
|
//#region node_modules/.pnpm/@linear+sdk@77.0.0_graphql@16.12.0/node_modules/@linear/sdk/dist/chunk-DPPnyiuk.mjs
|
|
@@ -179923,7 +180177,7 @@ var CurrentIssueSource = class CurrentIssueSource extends Service$1()("lalph/Cur
|
|
|
179923
180177
|
const services$8 = yield* services();
|
|
179924
180178
|
const refresh = set$4(ref, build$1).pipe(provideServices(services$8));
|
|
179925
180179
|
const proxy = IssueSource.of({
|
|
179926
|
-
issues: (projectId) => get$6(ref).pipe(flatMap$4((source) => source.issues(projectId)), tapErrorTag("IssueSourceError", (e) => logWarning("Rebuilding issue source due to error", fail$7(e)).pipe(andThen(ignore$1(refresh)))), retry$
|
|
180180
|
+
issues: (projectId) => get$6(ref).pipe(flatMap$4((source) => source.issues(projectId)), tapErrorTag("IssueSourceError", (e) => logWarning("Rebuilding issue source due to error", fail$7(e)).pipe(andThen(ignore$1(refresh)))), retry$3(refreshSchedule)),
|
|
179927
180181
|
createIssue: (projectId, options) => get$6(ref).pipe(flatMap$4((source) => source.createIssue(projectId, options))),
|
|
179928
180182
|
updateIssue: (options) => get$6(ref).pipe(flatMap$4((source) => source.updateIssue(options))),
|
|
179929
180183
|
cancelIssue: (projectId, issueId) => get$6(ref).pipe(flatMap$4((source) => source.cancelIssue(projectId, issueId))),
|
|
@@ -180775,7 +181029,7 @@ var Prd = class extends Service$1()("lalph/Prd", { make: gen(function* () {
|
|
|
180775
181029
|
if (currentYaml === nextYaml) return;
|
|
180776
181030
|
yield* fs.writeFileString(prdFile, nextYaml);
|
|
180777
181031
|
}, scoped$1, withSpan("Prd.updateSync"), run$3(updateSyncHandle, { onlyIfMissing: true }), syncSemaphore.withPermitsIfAvailable(1));
|
|
180778
|
-
yield* fs.watch(lalphDir).pipe(debounce(50), runForEach((_) => clear(updateSyncHandle).pipe(andThen(ignore$1(sync$2)))), retry$
|
|
181032
|
+
yield* fs.watch(lalphDir).pipe(debounce(50), runForEach((_) => clear(updateSyncHandle).pipe(andThen(ignore$1(sync$2)))), retry$3(forever$1), forkScoped);
|
|
180779
181033
|
yield* toStreamResult(registry, currentIssuesAtom(projectId)).pipe(runForEach(updateSync), forkScoped);
|
|
180780
181034
|
const findById = fnUntraced(function* (issueId) {
|
|
180781
181035
|
return (yield* getCurrentIssues).find((i) => i.id === issueId) ?? null;
|
|
@@ -187991,7 +188245,7 @@ var ji = Bt, Ii = Object.assign(Qe, { sync: Bt }), zi = Ut, Bi = Object.assign(e
|
|
|
187991
188245
|
});
|
|
187992
188246
|
Ze.glob = Ze;
|
|
187993
188247
|
//#endregion
|
|
187994
|
-
//#region node_modules/.pnpm/clanka@0.0.
|
|
188248
|
+
//#region node_modules/.pnpm/clanka@0.0.17_@effect+ai-openai-compat@4.0.0-beta.30_effect@4.0.0-beta.30__@effect+ai-o_aaa5a0e42657b29782e5d1fe76ccda57/node_modules/clanka/dist/ApplyPatch.js
|
|
187995
188249
|
/**
|
|
187996
188250
|
* @since 1.0.0
|
|
187997
188251
|
*/
|
|
@@ -188320,7 +188574,7 @@ const patchChunks = (file, input, chunks) => {
|
|
|
188320
188574
|
return eol === "\r\n" ? text.replace(/\n/g, "\r\n") : text;
|
|
188321
188575
|
};
|
|
188322
188576
|
//#endregion
|
|
188323
|
-
//#region node_modules/.pnpm/clanka@0.0.
|
|
188577
|
+
//#region node_modules/.pnpm/clanka@0.0.17_@effect+ai-openai-compat@4.0.0-beta.30_effect@4.0.0-beta.30__@effect+ai-o_aaa5a0e42657b29782e5d1fe76ccda57/node_modules/clanka/dist/AgentTools.js
|
|
188324
188578
|
/**
|
|
188325
188579
|
* @since 1.0.0
|
|
188326
188580
|
*/
|
|
@@ -188616,7 +188870,7 @@ const AgentToolHandlers = AgentTools.toLayer(gen(function* () {
|
|
|
188616
188870
|
}));
|
|
188617
188871
|
var ApplyPatchError = class extends TaggedClass$1("ApplyPatchError") {};
|
|
188618
188872
|
//#endregion
|
|
188619
|
-
//#region node_modules/.pnpm/clanka@0.0.
|
|
188873
|
+
//#region node_modules/.pnpm/clanka@0.0.17_@effect+ai-openai-compat@4.0.0-beta.30_effect@4.0.0-beta.30__@effect+ai-o_aaa5a0e42657b29782e5d1fe76ccda57/node_modules/clanka/dist/Executor.js
|
|
188620
188874
|
/**
|
|
188621
188875
|
* @since 1.0.0
|
|
188622
188876
|
*/
|
|
@@ -188696,7 +188950,7 @@ var QueueWriteStream = class extends Writable {
|
|
|
188696
188950
|
}
|
|
188697
188951
|
};
|
|
188698
188952
|
//#endregion
|
|
188699
|
-
//#region node_modules/.pnpm/clanka@0.0.
|
|
188953
|
+
//#region node_modules/.pnpm/clanka@0.0.17_@effect+ai-openai-compat@4.0.0-beta.30_effect@4.0.0-beta.30__@effect+ai-o_aaa5a0e42657b29782e5d1fe76ccda57/node_modules/clanka/dist/TypeBuilder.js
|
|
188700
188954
|
const resolveDocumentation = resolveAt("documentation");
|
|
188701
188955
|
const identifierPattern = /^[$A-Z_a-z][$0-9A-Z_a-z]*$/u;
|
|
188702
188956
|
const Precedence = {
|
|
@@ -188969,7 +189223,7 @@ const render = (schema, options) => {
|
|
|
188969
189223
|
return printNode({ text: documentation === void 0 ? rendered.text : `${renderJsDoc(documentation, 0, printerOptions)}${printerOptions.newLine}${rendered.text}` }, printerOptions);
|
|
188970
189224
|
};
|
|
188971
189225
|
//#endregion
|
|
188972
|
-
//#region node_modules/.pnpm/clanka@0.0.
|
|
189226
|
+
//#region node_modules/.pnpm/clanka@0.0.17_@effect+ai-openai-compat@4.0.0-beta.30_effect@4.0.0-beta.30__@effect+ai-o_aaa5a0e42657b29782e5d1fe76ccda57/node_modules/clanka/dist/ToolkitRenderer.js
|
|
188973
189227
|
/**
|
|
188974
189228
|
* @since 1.0.0
|
|
188975
189229
|
*/
|
|
@@ -188991,7 +189245,7 @@ declare function ${name}(${params}): Promise<${render(tool.successSchema)}>`);
|
|
|
188991
189245
|
}) });
|
|
188992
189246
|
};
|
|
188993
189247
|
//#endregion
|
|
188994
|
-
//#region node_modules/.pnpm/clanka@0.0.
|
|
189248
|
+
//#region node_modules/.pnpm/clanka@0.0.17_@effect+ai-openai-compat@4.0.0-beta.30_effect@4.0.0-beta.30__@effect+ai-o_aaa5a0e42657b29782e5d1fe76ccda57/node_modules/clanka/dist/Agent.js
|
|
188995
189249
|
/**
|
|
188996
189250
|
* @since 1.0.0
|
|
188997
189251
|
*/
|
|
@@ -189231,7 +189485,7 @@ ${prompt}`));
|
|
|
189231
189485
|
case "finish": break;
|
|
189232
189486
|
}
|
|
189233
189487
|
return void_$1;
|
|
189234
|
-
}), retry$
|
|
189488
|
+
}), retry$3({ while: (err) => {
|
|
189235
189489
|
response = [];
|
|
189236
189490
|
return err.isRetryable;
|
|
189237
189491
|
} }), modelConfig.systemPromptTransform ? (effect) => modelConfig.systemPromptTransform(system, effect) : identity);
|
|
@@ -189305,7 +189559,7 @@ const generateSystemMulti = (toolsDts) => {
|
|
|
189305
189559
|
|
|
189306
189560
|
- Use \`console.log\` to print any output you need.
|
|
189307
189561
|
- Top level await is supported.
|
|
189308
|
-
-
|
|
189562
|
+
- AVOID passing scripts into the "bash" function, and instead write javascript.
|
|
189309
189563
|
|
|
189310
189564
|
**When you have fully completed your task**, call the "taskComplete" function with the final output.
|
|
189311
189565
|
Make sure every detail of the task is done before calling "taskComplete".
|
|
@@ -189323,7 +189577,7 @@ const generateSystemSingle = (toolsDts) => {
|
|
|
189323
189577
|
|
|
189324
189578
|
- Use \`console.log\` to print any output you need.
|
|
189325
189579
|
- Top level await is supported.
|
|
189326
|
-
-
|
|
189580
|
+
- AVOID passing scripts into the "bash" function, and instead write javascript.
|
|
189327
189581
|
|
|
189328
189582
|
You have the following functions available to you:
|
|
189329
189583
|
|
|
@@ -199759,7 +200013,7 @@ const transformToolCallParams = /* @__PURE__ */ fnUntraced(function* (tools, too
|
|
|
199759
200013
|
})));
|
|
199760
200014
|
});
|
|
199761
200015
|
//#endregion
|
|
199762
|
-
//#region node_modules/.pnpm/clanka@0.0.
|
|
200016
|
+
//#region node_modules/.pnpm/clanka@0.0.17_@effect+ai-openai-compat@4.0.0-beta.30_effect@4.0.0-beta.30__@effect+ai-o_aaa5a0e42657b29782e5d1fe76ccda57/node_modules/clanka/dist/CodexAuth.js
|
|
199763
200017
|
/**
|
|
199764
200018
|
* @since 1.0.0
|
|
199765
200019
|
*/
|
|
@@ -199937,7 +200191,7 @@ var CodexAuth = class CodexAuth extends Service$1()("clanka/CodexAuth") {
|
|
|
199937
200191
|
user_code: deviceCode.userCode
|
|
199938
200192
|
}));
|
|
199939
200193
|
const delayMs = deviceCode.intervalMs + POLLING_SAFETY_MARGIN_MS;
|
|
199940
|
-
return yield* httpClient.execute(request).pipe(retry$
|
|
200194
|
+
return yield* httpClient.execute(request).pipe(retry$3({
|
|
199941
200195
|
while: (e) => e.response?.status === 403 || e.response?.status === 404,
|
|
199942
200196
|
schedule: spaced(delayMs)
|
|
199943
200197
|
}), mapError$2((cause) => requestDeviceCodeError("Failed to poll Codex device authorization", cause)), flatMap$4((response) => schemaBodyJson(AuthorizationCodeResponseSchema)(response).pipe(mapError$2((cause) => requestDeviceCodeError("Failed to decode the Codex authorization approval response", cause)), map$8((payload) => ({
|
|
@@ -199979,7 +200233,7 @@ var CodexAuth = class CodexAuth extends Service$1()("clanka/CodexAuth") {
|
|
|
199979
200233
|
static layerClient = this.layerClientNoDeps.pipe(provide$3(CodexAuth.layer));
|
|
199980
200234
|
};
|
|
199981
200235
|
//#endregion
|
|
199982
|
-
//#region node_modules/.pnpm/clanka@0.0.
|
|
200236
|
+
//#region node_modules/.pnpm/clanka@0.0.17_@effect+ai-openai-compat@4.0.0-beta.30_effect@4.0.0-beta.30__@effect+ai-o_aaa5a0e42657b29782e5d1fe76ccda57/node_modules/clanka/dist/Codex.js
|
|
199983
200237
|
/**
|
|
199984
200238
|
* @since 1.0.0
|
|
199985
200239
|
*/
|
|
@@ -201294,7 +201548,7 @@ const getUsageDetailNumber = (details, field) => {
|
|
|
201294
201548
|
return typeof value === "number" ? value : void 0;
|
|
201295
201549
|
};
|
|
201296
201550
|
//#endregion
|
|
201297
|
-
//#region node_modules/.pnpm/clanka@0.0.
|
|
201551
|
+
//#region node_modules/.pnpm/clanka@0.0.17_@effect+ai-openai-compat@4.0.0-beta.30_effect@4.0.0-beta.30__@effect+ai-o_aaa5a0e42657b29782e5d1fe76ccda57/node_modules/clanka/dist/CopilotAuth.js
|
|
201298
201552
|
/**
|
|
201299
201553
|
* @since 1.0.0
|
|
201300
201554
|
*/
|
|
@@ -201485,7 +201739,7 @@ var GithubCopilotAuth = class GithubCopilotAuth extends Service$1()("clanka/Gith
|
|
|
201485
201739
|
static layerClient = this.layerClientNoDeps.pipe(provide$3(GithubCopilotAuth.layer));
|
|
201486
201740
|
};
|
|
201487
201741
|
//#endregion
|
|
201488
|
-
//#region node_modules/.pnpm/clanka@0.0.
|
|
201742
|
+
//#region node_modules/.pnpm/clanka@0.0.17_@effect+ai-openai-compat@4.0.0-beta.30_effect@4.0.0-beta.30__@effect+ai-o_aaa5a0e42657b29782e5d1fe76ccda57/node_modules/clanka/dist/Copilot.js
|
|
201489
201743
|
/**
|
|
201490
201744
|
* @since 1.0.0
|
|
201491
201745
|
*/
|
|
@@ -201908,7 +202162,7 @@ Object.defineProperties(createChalk.prototype, styles);
|
|
|
201908
202162
|
const chalk = createChalk();
|
|
201909
202163
|
createChalk({ level: stderrColor ? stderrColor.level : 0 });
|
|
201910
202164
|
//#endregion
|
|
201911
|
-
//#region node_modules/.pnpm/clanka@0.0.
|
|
202165
|
+
//#region node_modules/.pnpm/clanka@0.0.17_@effect+ai-openai-compat@4.0.0-beta.30_effect@4.0.0-beta.30__@effect+ai-o_aaa5a0e42657b29782e5d1fe76ccda57/node_modules/clanka/dist/OutputFormatter.js
|
|
201912
202166
|
/**
|
|
201913
202167
|
* @since 1.0.0
|
|
201914
202168
|
*/
|
|
@@ -201952,6 +202206,11 @@ const doneIcon = "";
|
|
|
201952
202206
|
//#endregion
|
|
201953
202207
|
//#region src/TaskTools.ts
|
|
201954
202208
|
var ChosenTaskDeferred = class extends Reference("lalph/TaskTools/ChosenTaskDeferred", { defaultValue: makeUnsafe$13 }) {};
|
|
202209
|
+
var CurrentTaskRef = class CurrentTaskRef extends Service$1()("lalph/TaskTools/CurrentTaskRef") {
|
|
202210
|
+
static update(f) {
|
|
202211
|
+
return serviceOption(CurrentTaskRef).pipe(map$8(map$15((ref) => updateAndGet(ref, f))));
|
|
202212
|
+
}
|
|
202213
|
+
};
|
|
201955
202214
|
const TaskList = Array$1(Struct({
|
|
201956
202215
|
id: String$1.annotate({ documentation: "The unique identifier of the task." }),
|
|
201957
202216
|
...pick(PrdIssue.fields, [
|
|
@@ -201959,7 +202218,6 @@ const TaskList = Array$1(Struct({
|
|
|
201959
202218
|
"description",
|
|
201960
202219
|
"state",
|
|
201961
202220
|
"priority",
|
|
201962
|
-
"estimate",
|
|
201963
202221
|
"blockedBy"
|
|
201964
202222
|
])
|
|
201965
202223
|
}));
|
|
@@ -201974,7 +202232,6 @@ var TaskTools = class extends make$9(make$7("listTasks", {
|
|
|
201974
202232
|
description: PrdIssue.fields.description,
|
|
201975
202233
|
state: PrdIssue.fields.state,
|
|
201976
202234
|
priority: PrdIssue.fields.priority,
|
|
201977
|
-
estimate: PrdIssue.fields.estimate,
|
|
201978
202235
|
blockedBy: PrdIssue.fields.blockedBy
|
|
201979
202236
|
}),
|
|
201980
202237
|
success: String$1,
|
|
@@ -202017,7 +202274,6 @@ const TaskToolsHandlers = TaskToolsWithChoose.toLayer(gen(function* () {
|
|
|
202017
202274
|
description: issue.description,
|
|
202018
202275
|
state: issue.state,
|
|
202019
202276
|
priority: issue.priority,
|
|
202020
|
-
estimate: issue.estimate,
|
|
202021
202277
|
blockedBy: issue.blockedBy
|
|
202022
202278
|
}));
|
|
202023
202279
|
}, orDie$2),
|
|
@@ -202030,7 +202286,6 @@ const TaskToolsHandlers = TaskToolsWithChoose.toLayer(gen(function* () {
|
|
|
202030
202286
|
description: issue.description,
|
|
202031
202287
|
state: issue.state,
|
|
202032
202288
|
priority: issue.priority,
|
|
202033
|
-
estimate: issue.estimate,
|
|
202034
202289
|
blockedBy: issue.blockedBy
|
|
202035
202290
|
}));
|
|
202036
202291
|
}, orDie$2),
|
|
@@ -202044,12 +202299,14 @@ const TaskToolsHandlers = TaskToolsWithChoose.toLayer(gen(function* () {
|
|
|
202044
202299
|
return (yield* source.createIssue(projectId, new PrdIssue({
|
|
202045
202300
|
...options,
|
|
202046
202301
|
id: null,
|
|
202302
|
+
estimate: null,
|
|
202047
202303
|
autoMerge: false
|
|
202048
202304
|
}))).id;
|
|
202049
202305
|
}, orDie$2),
|
|
202050
202306
|
updateTask: fn("TaskTools.updateTask")(function* (options) {
|
|
202051
202307
|
yield* log$1(`Calling "updateTask"`).pipe(annotateLogs({ taskId: options.taskId }));
|
|
202052
202308
|
const projectId = yield* CurrentProjectId;
|
|
202309
|
+
yield* CurrentTaskRef.update((prev) => prev.update(options));
|
|
202053
202310
|
yield* source.updateIssue({
|
|
202054
202311
|
projectId,
|
|
202055
202312
|
issueId: options.taskId,
|
|
@@ -202111,10 +202368,15 @@ const runClanka = fnUntraced(
|
|
|
202111
202368
|
tools: options.withChoose ? TaskToolsWithChoose : TaskTools,
|
|
202112
202369
|
subagentModel: clankaSubagent(models, options.model)
|
|
202113
202370
|
}).pipe(provide$1(models.get(options.model)));
|
|
202114
|
-
|
|
202371
|
+
let stream = options.stallTimeout ? withStallTimeout(options.stallTimeout)(agent.output) : agent.output;
|
|
202372
|
+
if (options.steer) yield* options.steer.pipe(switchMap(fnUntraced(function* (message) {
|
|
202373
|
+
yield* log$1(`Received steer message: ${message}`);
|
|
202374
|
+
yield* agent.steer(message);
|
|
202375
|
+
}, fromEffectDrain)), runDrain, forkScoped);
|
|
202376
|
+
return yield* stream.pipe(pretty, runForEachArray((out) => {
|
|
202115
202377
|
for (const item of out) process.stdout.write(item);
|
|
202116
202378
|
return void_$1;
|
|
202117
|
-
})
|
|
202379
|
+
}));
|
|
202118
202380
|
},
|
|
202119
202381
|
scoped$1,
|
|
202120
202382
|
provide$1([layerServices, TaskToolsHandlers])
|
|
@@ -202130,8 +202392,9 @@ const agentWorker = fnUntraced(function* (options) {
|
|
|
202130
202392
|
model: options.preset.extraArgs.join(" "),
|
|
202131
202393
|
system: options.system,
|
|
202132
202394
|
prompt: options.prompt,
|
|
202133
|
-
stallTimeout: options.stallTimeout
|
|
202134
|
-
|
|
202395
|
+
stallTimeout: options.stallTimeout,
|
|
202396
|
+
steer: options.steer
|
|
202397
|
+
}).pipe(options.taskRef ? provideService$2(CurrentTaskRef, options.taskRef) : identity);
|
|
202135
202398
|
return ExitCode(0);
|
|
202136
202399
|
}
|
|
202137
202400
|
return yield* pipe(options.preset.cliAgent.command({
|
|
@@ -202446,10 +202709,16 @@ const run = fnUntraced(function* (options) {
|
|
|
202446
202709
|
githubPrNumber: chosenTask.githubPrNumber ?? void 0,
|
|
202447
202710
|
gitFlow
|
|
202448
202711
|
});
|
|
202712
|
+
const issueRef = make$63(chosenTask.prd.update({ state: "in-progress" }));
|
|
202713
|
+
const steer = yield* taskUpdateSteer({
|
|
202714
|
+
issueId: taskId,
|
|
202715
|
+
current: issueRef
|
|
202716
|
+
});
|
|
202449
202717
|
yield* log$1(`Agent exited with code: ${yield* agentWorker({
|
|
202450
202718
|
stallTimeout: options.stallTimeout,
|
|
202451
202719
|
preset: taskPreset,
|
|
202452
|
-
prompt: instructions
|
|
202720
|
+
prompt: instructions,
|
|
202721
|
+
steer
|
|
202453
202722
|
}).pipe(catchStallInReview, withSpan("Main.agentWorker"))}`);
|
|
202454
202723
|
if (options.review) {
|
|
202455
202724
|
registry.update(currentWorker.state, (s) => s.transitionTo(WorkerStatus.Reviewing({ issueId: taskId })));
|
|
@@ -202576,6 +202845,19 @@ const watchTaskState = fnUntraced(function* (options) {
|
|
|
202576
202845
|
}));
|
|
202577
202846
|
}), withSpan("Main.watchTaskState"));
|
|
202578
202847
|
});
|
|
202848
|
+
const taskUpdateSteer = fnUntraced(function* (options) {
|
|
202849
|
+
return toStreamResult(yield* AtomRegistry, currentIssuesAtom(yield* CurrentProjectId)).pipe(drop(1), retry$1(forever$1), orDie, filterMap$2((issues) => {
|
|
202850
|
+
const issue = issues.find((entry) => entry.id === options.issueId);
|
|
202851
|
+
if (!issue) return failVoid;
|
|
202852
|
+
if (!issue.isChangedComparedTo(options.current.current)) return failVoid;
|
|
202853
|
+
set$9(options.current, issue);
|
|
202854
|
+
return succeed$8(`The task has been updated by the user. Here is the latest information:
|
|
202855
|
+
|
|
202856
|
+
# ${issue.title}
|
|
202857
|
+
|
|
202858
|
+
${issue.description}`);
|
|
202859
|
+
}));
|
|
202860
|
+
});
|
|
202579
202861
|
//#endregion
|
|
202580
202862
|
//#region src/Agents/planner.ts
|
|
202581
202863
|
const agentPlanner = fnUntraced(function* (options) {
|
|
@@ -202675,7 +202957,12 @@ var Editor = class extends Service$1()("lalph/Editor", { make: gen(function* ()
|
|
|
202675
202957
|
const content = (yield* fs.readFileString(file)).trim();
|
|
202676
202958
|
if (content === initialContent) return yield* new NoSuchElementError();
|
|
202677
202959
|
return content;
|
|
202678
|
-
}, scoped$1, provideService$2(ChildProcessSpawner, spawner), option$1)
|
|
202960
|
+
}, scoped$1, provideService$2(ChildProcessSpawner, spawner), option$1),
|
|
202961
|
+
saveTemp: fnUntraced(function* (content, options) {
|
|
202962
|
+
const file = yield* fs.makeTempFile({ suffix: options.suffix ?? ".txt" });
|
|
202963
|
+
yield* fs.writeFileString(file, content);
|
|
202964
|
+
return file;
|
|
202965
|
+
})
|
|
202679
202966
|
};
|
|
202680
202967
|
}) }) {
|
|
202681
202968
|
static layer = effect$1(this, this.make).pipe(provide$3(PlatformServices));
|
|
@@ -202692,6 +202979,10 @@ const commandPlan = make$46("plan", {
|
|
|
202692
202979
|
onSuccess: (path) => fs.readFileString(path).pipe(asSome)
|
|
202693
202980
|
});
|
|
202694
202981
|
if (isNone(thePlan)) return;
|
|
202982
|
+
yield* addFinalizer((exit) => {
|
|
202983
|
+
if (isSuccess$3(exit)) return void_$1;
|
|
202984
|
+
return pipe(editor.saveTemp(thePlan.value, { suffix: ".md" }), flatMap$4((file) => log$1(`Saved your plan to: ${file}`)), ignore$1);
|
|
202985
|
+
});
|
|
202695
202986
|
yield* gen(function* () {
|
|
202696
202987
|
const project = withNewProject ? yield* addOrUpdateProject() : yield* selectProject;
|
|
202697
202988
|
const { specsDirectory } = yield* commandRoot;
|
|
@@ -202708,7 +202999,7 @@ const commandPlan = make$46("plan", {
|
|
|
202708
202999
|
CurrentIssueSource.layer,
|
|
202709
203000
|
ClankaModels.layer
|
|
202710
203001
|
]));
|
|
202711
|
-
}, provide$1(Editor.layer))), withSubcommands([commandPlanTasks]));
|
|
203002
|
+
}, scoped$1, provide$1(Editor.layer))), withSubcommands([commandPlanTasks]));
|
|
202712
203003
|
const plan = fnUntraced(function* (options) {
|
|
202713
203004
|
const fs = yield* FileSystem;
|
|
202714
203005
|
const pathService = yield* Path$1;
|
|
@@ -202785,12 +203076,18 @@ const FrontMatterSchema = toCodecJson(Struct({
|
|
|
202785
203076
|
autoMerge: Boolean$2
|
|
202786
203077
|
}));
|
|
202787
203078
|
const handler$1 = flow(withHandler(fnUntraced(function* () {
|
|
202788
|
-
const
|
|
203079
|
+
const editor = yield* Editor;
|
|
203080
|
+
const content = yield* editor.editTemp({
|
|
202789
203081
|
suffix: ".md",
|
|
202790
203082
|
initialContent: issueTemplate
|
|
202791
203083
|
});
|
|
202792
203084
|
if (isNone(content)) return;
|
|
202793
|
-
const
|
|
203085
|
+
const contentValue = content.value.trim();
|
|
203086
|
+
yield* addFinalizer((exit) => {
|
|
203087
|
+
if (isSuccess$3(exit)) return void_$1;
|
|
203088
|
+
return pipe(editor.saveTemp(contentValue, { suffix: ".md" }), flatMap$4((file) => log$1(`Saved your issue to: ${file}`)), ignore$1);
|
|
203089
|
+
});
|
|
203090
|
+
const lines = contentValue.split("\n");
|
|
202794
203091
|
const yamlLines = [];
|
|
202795
203092
|
let descriptionStartIndex = 0;
|
|
202796
203093
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -202818,7 +203115,7 @@ const handler$1 = flow(withHandler(fnUntraced(function* () {
|
|
|
202818
203115
|
console.log(`Created issue with ID: ${created.id}`);
|
|
202819
203116
|
console.log(`URL: ${created.url}`);
|
|
202820
203117
|
}).pipe(provide$1([layerProjectIdPrompt, CurrentIssueSource.layer]));
|
|
202821
|
-
})), provide(Editor.layer));
|
|
203118
|
+
}, scoped$1)), provide(Editor.layer));
|
|
202822
203119
|
const commandIssue = make$46("issue").pipe(withDescription("Create a new issue in your editor."), withAlias("i"), handler$1);
|
|
202823
203120
|
//#endregion
|
|
202824
203121
|
//#region src/commands/edit.ts
|
|
@@ -202832,7 +203129,7 @@ const commandEdit = make$46("edit").pipe(withDescription("Open the selected proj
|
|
|
202832
203129
|
const commandSource = make$46("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));
|
|
202833
203130
|
//#endregion
|
|
202834
203131
|
//#region package.json
|
|
202835
|
-
var version = "0.3.
|
|
203132
|
+
var version = "0.3.47";
|
|
202836
203133
|
//#endregion
|
|
202837
203134
|
//#region src/commands/projects/ls.ts
|
|
202838
203135
|
const commandProjectsLs = make$46("ls").pipe(withDescription("List configured projects and how they run (enabled state, concurrency, branch, git flow, review agent)."), withHandler(fnUntraced(function* () {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lalph",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.47",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"@octokit/plugin-rest-endpoint-methods": "^17.0.0",
|
|
31
31
|
"@octokit/types": "^16.0.0",
|
|
32
32
|
"@typescript/native-preview": "7.0.0-dev.20260310.1",
|
|
33
|
-
"clanka": "^0.0.
|
|
33
|
+
"clanka": "^0.0.17",
|
|
34
34
|
"concurrently": "^9.2.1",
|
|
35
35
|
"effect": "4.0.0-beta.30",
|
|
36
36
|
"husky": "^9.1.7",
|
package/src/Agents/worker.ts
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
|
-
import { Duration, Effect, Path, pipe } from "effect"
|
|
1
|
+
import { Duration, Effect, identity, Path, pipe, Stream } from "effect"
|
|
2
2
|
import { ChildProcess } from "effect/unstable/process"
|
|
3
3
|
import { Worktree } from "../Worktree.ts"
|
|
4
4
|
import type { CliAgentPreset } from "../domain/CliAgentPreset.ts"
|
|
5
5
|
import { runClanka } from "../Clanka.ts"
|
|
6
6
|
import { ExitCode } from "effect/unstable/process/ChildProcessSpawner"
|
|
7
|
+
import { CurrentTaskRef } from "../TaskTools.ts"
|
|
7
8
|
|
|
8
9
|
export const agentWorker = Effect.fnUntraced(function* (options: {
|
|
9
10
|
readonly stallTimeout: Duration.Duration
|
|
10
11
|
readonly preset: CliAgentPreset
|
|
11
12
|
readonly system?: string
|
|
12
13
|
readonly prompt: string
|
|
14
|
+
readonly steer?: Stream.Stream<string>
|
|
15
|
+
readonly taskRef?: CurrentTaskRef["Service"]
|
|
13
16
|
}) {
|
|
14
17
|
const pathService = yield* Path.Path
|
|
15
18
|
const worktree = yield* Worktree
|
|
@@ -22,7 +25,12 @@ export const agentWorker = Effect.fnUntraced(function* (options: {
|
|
|
22
25
|
system: options.system,
|
|
23
26
|
prompt: options.prompt,
|
|
24
27
|
stallTimeout: options.stallTimeout,
|
|
25
|
-
|
|
28
|
+
steer: options.steer,
|
|
29
|
+
}).pipe(
|
|
30
|
+
options.taskRef
|
|
31
|
+
? Effect.provideService(CurrentTaskRef, options.taskRef)
|
|
32
|
+
: identity,
|
|
33
|
+
)
|
|
26
34
|
return ExitCode(0)
|
|
27
35
|
}
|
|
28
36
|
|
package/src/Clanka.ts
CHANGED
|
@@ -7,8 +7,6 @@ import {
|
|
|
7
7
|
} from "./TaskTools.ts"
|
|
8
8
|
import { ClankaModels, clankaSubagent } from "./ClankaModels.ts"
|
|
9
9
|
import { withStallTimeout } from "./shared/stream.ts"
|
|
10
|
-
import type { AiError } from "effect/unstable/ai"
|
|
11
|
-
import type { RunnerStalled } from "./domain/Errors.ts"
|
|
12
10
|
|
|
13
11
|
export const runClanka = Effect.fnUntraced(
|
|
14
12
|
/** The working directory to run the agent in */
|
|
@@ -18,6 +16,7 @@ export const runClanka = Effect.fnUntraced(
|
|
|
18
16
|
readonly prompt: string
|
|
19
17
|
readonly system?: string | undefined
|
|
20
18
|
readonly stallTimeout?: Duration.Input | undefined
|
|
19
|
+
readonly steer?: Stream.Stream<string> | undefined
|
|
21
20
|
readonly withChoose?: boolean | undefined
|
|
22
21
|
}) {
|
|
23
22
|
const models = yield* ClankaModels
|
|
@@ -33,6 +32,19 @@ export const runClanka = Effect.fnUntraced(
|
|
|
33
32
|
? withStallTimeout(options.stallTimeout)(agent.output)
|
|
34
33
|
: agent.output
|
|
35
34
|
|
|
35
|
+
if (options.steer) {
|
|
36
|
+
yield* options.steer.pipe(
|
|
37
|
+
Stream.switchMap(
|
|
38
|
+
Effect.fnUntraced(function* (message) {
|
|
39
|
+
yield* Effect.log(`Received steer message: ${message}`)
|
|
40
|
+
yield* agent.steer(message)
|
|
41
|
+
}, Stream.fromEffectDrain),
|
|
42
|
+
),
|
|
43
|
+
Stream.runDrain,
|
|
44
|
+
Effect.forkScoped,
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
36
48
|
return yield* stream.pipe(
|
|
37
49
|
OutputFormatter.pretty,
|
|
38
50
|
Stream.runForEachArray((out) => {
|
|
@@ -41,7 +53,6 @@ export const runClanka = Effect.fnUntraced(
|
|
|
41
53
|
}
|
|
42
54
|
return Effect.void
|
|
43
55
|
}),
|
|
44
|
-
(_) => _ as Effect.Effect<void, AiError.AiError | RunnerStalled>,
|
|
45
56
|
)
|
|
46
57
|
},
|
|
47
58
|
Effect.scoped,
|
package/src/Editor.ts
CHANGED
|
@@ -57,7 +57,18 @@ export class Editor extends ServiceMap.Service<Editor>()("lalph/Editor", {
|
|
|
57
57
|
Effect.option,
|
|
58
58
|
)
|
|
59
59
|
|
|
60
|
-
|
|
60
|
+
const saveTemp = Effect.fnUntraced(function* (
|
|
61
|
+
content: string,
|
|
62
|
+
options: { suffix?: string },
|
|
63
|
+
) {
|
|
64
|
+
const file = yield* fs.makeTempFile({
|
|
65
|
+
suffix: options.suffix ?? ".txt",
|
|
66
|
+
})
|
|
67
|
+
yield* fs.writeFileString(file, content)
|
|
68
|
+
return file
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
return { edit, editTemp, saveTemp } as const
|
|
61
72
|
}),
|
|
62
73
|
}) {
|
|
63
74
|
static layer = Layer.effect(this, this.make).pipe(
|
package/src/TaskTools.ts
CHANGED
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Deferred,
|
|
3
|
+
Effect,
|
|
4
|
+
MutableRef,
|
|
5
|
+
Option,
|
|
6
|
+
Schema,
|
|
7
|
+
ServiceMap,
|
|
8
|
+
Struct,
|
|
9
|
+
} from "effect"
|
|
2
10
|
import { Tool, Toolkit } from "effect/unstable/ai"
|
|
3
11
|
import { PrdIssue } from "./domain/PrdIssue.ts"
|
|
4
12
|
import { IssueSource } from "./IssueSource.ts"
|
|
@@ -14,6 +22,17 @@ export class ChosenTaskDeferred extends ServiceMap.Reference(
|
|
|
14
22
|
},
|
|
15
23
|
) {}
|
|
16
24
|
|
|
25
|
+
export class CurrentTaskRef extends ServiceMap.Service<
|
|
26
|
+
CurrentTaskRef,
|
|
27
|
+
MutableRef.MutableRef<PrdIssue>
|
|
28
|
+
>()("lalph/TaskTools/CurrentTaskRef") {
|
|
29
|
+
static update(f: (prev: PrdIssue) => PrdIssue) {
|
|
30
|
+
return Effect.serviceOption(CurrentTaskRef).pipe(
|
|
31
|
+
Effect.map(Option.map((ref) => MutableRef.updateAndGet(ref, f))),
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
17
36
|
const TaskList = Schema.Array(
|
|
18
37
|
Schema.Struct({
|
|
19
38
|
id: Schema.String.annotate({
|
|
@@ -24,7 +43,6 @@ const TaskList = Schema.Array(
|
|
|
24
43
|
"description",
|
|
25
44
|
"state",
|
|
26
45
|
"priority",
|
|
27
|
-
"estimate",
|
|
28
46
|
"blockedBy",
|
|
29
47
|
]),
|
|
30
48
|
}),
|
|
@@ -43,7 +61,6 @@ export class TaskTools extends Toolkit.make(
|
|
|
43
61
|
description: PrdIssue.fields.description,
|
|
44
62
|
state: PrdIssue.fields.state,
|
|
45
63
|
priority: PrdIssue.fields.priority,
|
|
46
|
-
estimate: PrdIssue.fields.estimate,
|
|
47
64
|
blockedBy: PrdIssue.fields.blockedBy,
|
|
48
65
|
}),
|
|
49
66
|
success: Schema.String,
|
|
@@ -102,7 +119,6 @@ export const TaskToolsHandlers = TaskToolsWithChoose.toLayer(
|
|
|
102
119
|
description: issue.description,
|
|
103
120
|
state: issue.state,
|
|
104
121
|
priority: issue.priority,
|
|
105
|
-
estimate: issue.estimate,
|
|
106
122
|
blockedBy: issue.blockedBy,
|
|
107
123
|
}))
|
|
108
124
|
}, Effect.orDie),
|
|
@@ -118,7 +134,6 @@ export const TaskToolsHandlers = TaskToolsWithChoose.toLayer(
|
|
|
118
134
|
description: issue.description,
|
|
119
135
|
state: issue.state,
|
|
120
136
|
priority: issue.priority,
|
|
121
|
-
estimate: issue.estimate,
|
|
122
137
|
blockedBy: issue.blockedBy,
|
|
123
138
|
}))
|
|
124
139
|
}, Effect.orDie),
|
|
@@ -137,6 +152,7 @@ export const TaskToolsHandlers = TaskToolsWithChoose.toLayer(
|
|
|
137
152
|
new PrdIssue({
|
|
138
153
|
...options,
|
|
139
154
|
id: null,
|
|
155
|
+
estimate: null,
|
|
140
156
|
autoMerge: false,
|
|
141
157
|
}),
|
|
142
158
|
)
|
|
@@ -147,6 +163,7 @@ export const TaskToolsHandlers = TaskToolsWithChoose.toLayer(
|
|
|
147
163
|
Effect.annotateLogs({ taskId: options.taskId }),
|
|
148
164
|
)
|
|
149
165
|
const projectId = yield* CurrentProjectId
|
|
166
|
+
yield* CurrentTaskRef.update((prev) => prev.update(options))
|
|
150
167
|
yield* source.updateIssue({
|
|
151
168
|
projectId,
|
|
152
169
|
issueId: options.taskId,
|
package/src/commands/issue.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command } from "effect/unstable/cli"
|
|
2
2
|
import { CurrentIssueSource } from "../CurrentIssueSource.ts"
|
|
3
|
-
import { Effect, flow, Option, Schema } from "effect"
|
|
3
|
+
import { Effect, Exit, flow, Option, pipe, Schema } from "effect"
|
|
4
4
|
import { IssueSource } from "../IssueSource.ts"
|
|
5
5
|
import { PrdIssue } from "../domain/PrdIssue.ts"
|
|
6
6
|
import * as Yaml from "yaml"
|
|
@@ -40,8 +40,18 @@ const handler = flow(
|
|
|
40
40
|
if (Option.isNone(content)) {
|
|
41
41
|
return
|
|
42
42
|
}
|
|
43
|
+
const contentValue = content.value.trim()
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
yield* Effect.addFinalizer((exit) => {
|
|
46
|
+
if (Exit.isSuccess(exit)) return Effect.void
|
|
47
|
+
return pipe(
|
|
48
|
+
editor.saveTemp(contentValue, { suffix: ".md" }),
|
|
49
|
+
Effect.flatMap((file) => Effect.log(`Saved your issue to: ${file}`)),
|
|
50
|
+
Effect.ignore,
|
|
51
|
+
)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
const lines = contentValue.split("\n")
|
|
45
55
|
const yamlLines: string[] = []
|
|
46
56
|
let descriptionStartIndex = 0
|
|
47
57
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -81,7 +91,7 @@ const handler = flow(
|
|
|
81
91
|
console.log(`Created issue with ID: ${created.id}`)
|
|
82
92
|
console.log(`URL: ${created.url}`)
|
|
83
93
|
}).pipe(Effect.provide([layerProjectIdPrompt, CurrentIssueSource.layer]))
|
|
84
|
-
}),
|
|
94
|
+
}, Effect.scoped),
|
|
85
95
|
),
|
|
86
96
|
Command.provide(Editor.layer),
|
|
87
97
|
)
|
package/src/commands/plan.ts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Data,
|
|
3
|
+
Effect,
|
|
4
|
+
Exit,
|
|
5
|
+
FileSystem,
|
|
6
|
+
Option,
|
|
7
|
+
Path,
|
|
8
|
+
pipe,
|
|
9
|
+
Schema,
|
|
10
|
+
} from "effect"
|
|
2
11
|
import { PromptGen } from "../PromptGen.ts"
|
|
3
12
|
import { Prd } from "../Prd.ts"
|
|
4
13
|
import { Worktree } from "../Worktree.ts"
|
|
@@ -48,41 +57,54 @@ export const commandPlan = Command.make("plan", {
|
|
|
48
57
|
"Draft a plan in your editor (or use --file); then generate a specification under --specs and create PRD tasks from it. Use --new to create a project first, and --dangerous to skip permission prompts during spec generation.",
|
|
49
58
|
),
|
|
50
59
|
Command.withHandler(
|
|
51
|
-
Effect.fnUntraced(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
60
|
+
Effect.fnUntraced(
|
|
61
|
+
function* ({ dangerous, withNewProject, file }) {
|
|
62
|
+
const editor = yield* Editor
|
|
63
|
+
const fs = yield* FileSystem.FileSystem
|
|
64
|
+
|
|
65
|
+
const thePlan = yield* Effect.matchEffect(file.asEffect(), {
|
|
66
|
+
onFailure: () => editor.editTemp({ suffix: ".md" }),
|
|
67
|
+
onSuccess: (path) => fs.readFileString(path).pipe(Effect.asSome),
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
if (Option.isNone(thePlan)) return
|
|
71
|
+
|
|
72
|
+
yield* Effect.addFinalizer((exit) => {
|
|
73
|
+
if (Exit.isSuccess(exit)) return Effect.void
|
|
74
|
+
return pipe(
|
|
75
|
+
editor.saveTemp(thePlan.value, { suffix: ".md" }),
|
|
76
|
+
Effect.flatMap((file) => Effect.log(`Saved your plan to: ${file}`)),
|
|
77
|
+
Effect.ignore,
|
|
78
|
+
)
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
// We nest this effect, so we can launch the editor first as fast as
|
|
82
|
+
// possible
|
|
83
|
+
yield* Effect.gen(function* () {
|
|
84
|
+
const project = withNewProject
|
|
85
|
+
? yield* addOrUpdateProject()
|
|
86
|
+
: yield* selectProject
|
|
87
|
+
const { specsDirectory } = yield* commandRoot
|
|
88
|
+
const preset = yield* selectCliAgentPreset
|
|
89
|
+
|
|
90
|
+
yield* plan({
|
|
91
|
+
plan: thePlan.value,
|
|
92
|
+
specsDirectory,
|
|
93
|
+
targetBranch: project.targetBranch,
|
|
94
|
+
dangerous,
|
|
95
|
+
preset,
|
|
96
|
+
}).pipe(Effect.provideService(CurrentProjectId, project.id))
|
|
97
|
+
}).pipe(
|
|
98
|
+
Effect.provide([
|
|
99
|
+
Settings.layer,
|
|
100
|
+
CurrentIssueSource.layer,
|
|
101
|
+
ClankaModels.layer,
|
|
102
|
+
]),
|
|
103
|
+
)
|
|
104
|
+
},
|
|
105
|
+
Effect.scoped,
|
|
106
|
+
Effect.provide(Editor.layer),
|
|
107
|
+
),
|
|
86
108
|
),
|
|
87
109
|
Command.withSubcommands([commandPlanTasks]),
|
|
88
110
|
)
|
package/src/commands/root.ts
CHANGED
|
@@ -6,9 +6,12 @@ import {
|
|
|
6
6
|
FiberSet,
|
|
7
7
|
FileSystem,
|
|
8
8
|
Iterable,
|
|
9
|
+
MutableRef,
|
|
9
10
|
Option,
|
|
10
11
|
Path,
|
|
11
12
|
PlatformError,
|
|
13
|
+
Result,
|
|
14
|
+
Schedule,
|
|
12
15
|
Schema,
|
|
13
16
|
Scope,
|
|
14
17
|
Semaphore,
|
|
@@ -48,6 +51,7 @@ import type { TimeoutError } from "effect/Cause"
|
|
|
48
51
|
import type { ChildProcessSpawner } from "effect/unstable/process"
|
|
49
52
|
import { ClankaModels } from "../ClankaModels.ts"
|
|
50
53
|
import type { AiError } from "effect/unstable/ai/AiError"
|
|
54
|
+
import type { PrdIssue } from "../domain/PrdIssue.ts"
|
|
51
55
|
|
|
52
56
|
// Main iteration run logic
|
|
53
57
|
|
|
@@ -217,10 +221,21 @@ const run = Effect.fnUntraced(
|
|
|
217
221
|
gitFlow,
|
|
218
222
|
})
|
|
219
223
|
|
|
224
|
+
const issueRef = MutableRef.make(
|
|
225
|
+
chosenTask.prd.update({
|
|
226
|
+
state: "in-progress",
|
|
227
|
+
}),
|
|
228
|
+
)
|
|
229
|
+
const steer = yield* taskUpdateSteer({
|
|
230
|
+
issueId: taskId,
|
|
231
|
+
current: issueRef,
|
|
232
|
+
})
|
|
233
|
+
|
|
220
234
|
const exitCode = yield* agentWorker({
|
|
221
235
|
stallTimeout: options.stallTimeout,
|
|
222
236
|
preset: taskPreset,
|
|
223
237
|
prompt: instructions,
|
|
238
|
+
steer,
|
|
224
239
|
}).pipe(catchStallInReview, Effect.withSpan("Main.agentWorker"))
|
|
225
240
|
yield* Effect.log(`Agent exited with code: ${exitCode}`)
|
|
226
241
|
|
|
@@ -515,3 +530,33 @@ const watchTaskState = Effect.fnUntraced(function* (options: {
|
|
|
515
530
|
Effect.withSpan("Main.watchTaskState"),
|
|
516
531
|
)
|
|
517
532
|
})
|
|
533
|
+
|
|
534
|
+
const taskUpdateSteer = Effect.fnUntraced(function* (options: {
|
|
535
|
+
readonly issueId: string
|
|
536
|
+
readonly current: MutableRef.MutableRef<PrdIssue>
|
|
537
|
+
}) {
|
|
538
|
+
const registry = yield* AtomRegistry.AtomRegistry
|
|
539
|
+
const projectId = yield* CurrentProjectId
|
|
540
|
+
|
|
541
|
+
return AtomRegistry.toStreamResult(
|
|
542
|
+
registry,
|
|
543
|
+
currentIssuesAtom(projectId),
|
|
544
|
+
).pipe(
|
|
545
|
+
Stream.drop(1),
|
|
546
|
+
Stream.retry(Schedule.forever),
|
|
547
|
+
Stream.orDie,
|
|
548
|
+
Stream.filterMap((issues) => {
|
|
549
|
+
const issue = issues.find((entry) => entry.id === options.issueId)
|
|
550
|
+
if (!issue) return Result.failVoid
|
|
551
|
+
if (!issue.isChangedComparedTo(options.current.current)) {
|
|
552
|
+
return Result.failVoid
|
|
553
|
+
}
|
|
554
|
+
MutableRef.set(options.current, issue)
|
|
555
|
+
return Result.succeed(`The task has been updated by the user. Here is the latest information:
|
|
556
|
+
|
|
557
|
+
# ${issue.title}
|
|
558
|
+
|
|
559
|
+
${issue.description}`)
|
|
560
|
+
}),
|
|
561
|
+
)
|
|
562
|
+
})
|
package/src/domain/PrdIssue.ts
CHANGED
|
@@ -105,4 +105,19 @@ export class PrdIssue extends Schema.Class<PrdIssue>("PrdIssue")({
|
|
|
105
105
|
autoMerge,
|
|
106
106
|
})
|
|
107
107
|
}
|
|
108
|
+
|
|
109
|
+
update(options: {
|
|
110
|
+
readonly title?: string | undefined
|
|
111
|
+
readonly description?: string | undefined
|
|
112
|
+
readonly state?: PrdIssue["state"] | undefined
|
|
113
|
+
readonly blockedBy?: ReadonlyArray<string> | undefined
|
|
114
|
+
}): PrdIssue {
|
|
115
|
+
return new PrdIssue({
|
|
116
|
+
...this,
|
|
117
|
+
title: options.title ?? this.title,
|
|
118
|
+
description: options.description ?? this.description,
|
|
119
|
+
state: options.state ?? this.state,
|
|
120
|
+
blockedBy: options.blockedBy ?? this.blockedBy,
|
|
121
|
+
})
|
|
122
|
+
}
|
|
108
123
|
}
|