lalph 0.3.47 → 0.3.49

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
@@ -24452,6 +24452,50 @@ const publish = /* @__PURE__ */ dual(2, (self, value) => suspend$3(() => {
24452
24452
  return self.strategy.handleSurplus(self.pubsub, self.subscribers, [value], self.shutdownFlag);
24453
24453
  }));
24454
24454
  /**
24455
+ * Publishes all of the specified messages to the `PubSub`, returning whether they
24456
+ * were published to the `PubSub`.
24457
+ *
24458
+ * @example
24459
+ * ```ts
24460
+ * import { Effect } from "effect"
24461
+ * import * as PubSub from "effect/PubSub"
24462
+ *
24463
+ * const program = Effect.gen(function*() {
24464
+ * const pubsub = yield* PubSub.bounded<string>(10)
24465
+ *
24466
+ * // Publish multiple messages at once
24467
+ * const messages = ["Hello", "World", "from", "Effect"]
24468
+ * const allPublished = yield* PubSub.publishAll(pubsub, messages)
24469
+ * console.log("All messages published:", allPublished) // true
24470
+ *
24471
+ * // With a smaller capacity
24472
+ * const smallPubsub = yield* PubSub.bounded<string>(2)
24473
+ * const manyMessages = ["msg1", "msg2", "msg3", "msg4"]
24474
+ *
24475
+ * // Will suspend until space becomes available for all messages
24476
+ * const publishAllEffect = PubSub.publishAll(smallPubsub, manyMessages)
24477
+ *
24478
+ * // Subscribe to consume messages and free space
24479
+ * yield* Effect.scoped(Effect.gen(function*() {
24480
+ * const subscription = yield* PubSub.subscribe(smallPubsub)
24481
+ * yield* PubSub.takeAll(subscription) // consume all messages
24482
+ * const result = yield* publishAllEffect
24483
+ * console.log("All messages eventually published:", result)
24484
+ * }))
24485
+ * })
24486
+ * ```
24487
+ *
24488
+ * @since 2.0.0
24489
+ * @category publishing
24490
+ */
24491
+ const publishAll = /* @__PURE__ */ dual(2, (self, elements) => suspend$3(() => {
24492
+ if (self.shutdownFlag.current) return interrupt$1;
24493
+ const surplus = self.pubsub.publishAll(elements);
24494
+ self.strategy.completeSubscribersUnsafe(self.pubsub, self.subscribers);
24495
+ if (surplus.length === 0) return succeed$3(true);
24496
+ return self.strategy.handleSurplus(self.pubsub, self.subscribers, surplus, self.shutdownFlag);
24497
+ }));
24498
+ /**
24455
24499
  * Subscribes to receive messages from the `PubSub`. The resulting subscription can
24456
24500
  * be evaluated multiple times within the scope to take a message from the `PubSub`
24457
24501
  * each time.
@@ -28443,6 +28487,11 @@ const toPull$1 = /* @__PURE__ */ fnUntraced(function* (self) {
28443
28487
  const toPullScoped = (self, scope) => toTransform(self)(done(), scope);
28444
28488
  const makePubSub = (options) => acquireRelease(options.capacity === "unbounded" ? unbounded$1(options) : options.strategy === "dropping" ? dropping(options) : options.strategy === "sliding" ? sliding(options) : bounded$1(options), shutdown$1);
28445
28489
  /**
28490
+ * @since 4.0.0
28491
+ * @category Destructors
28492
+ */
28493
+ const runIntoPubSubArray = /* @__PURE__ */ dual((args) => isChannel(args[0]), (self, pubsub, options) => runForEach$1(self, (value) => publishAll(pubsub, value)).pipe(options?.shutdownOnEnd === true ? ensuring$2(shutdown$1(pubsub)) : identity));
28494
+ /**
28446
28495
  * Converts a channel to a PubSub for concurrent consumption.
28447
28496
  *
28448
28497
  * @since 4.0.0
@@ -28913,9 +28962,9 @@ const getState = (self) => uninterruptibleMask((restore) => {
28913
28962
  const get$11 = /* @__PURE__ */ fnUntraced(function* (self_) {
28914
28963
  const self = self_;
28915
28964
  const state = yield* getState(self);
28916
- const scope$7 = yield* scope;
28965
+ const scope$8 = yield* scope;
28917
28966
  const isFinite = self.idleTimeToLive !== void 0 && isFinite$2(self.idleTimeToLive);
28918
- yield* addFinalizerExit(scope$7, () => {
28967
+ yield* addFinalizerExit(scope$8, () => {
28919
28968
  state.refCount--;
28920
28969
  if (state.refCount > 0) return void_$1;
28921
28970
  if (self.idleTimeToLive === void 0) {
@@ -30930,6 +30979,38 @@ const toReadableStreamWith = /* @__PURE__ */ dual((args) => isStream(args[0]), (
30930
30979
  */
30931
30980
  const toReadableStreamEffect = /* @__PURE__ */ dual((args) => isStream(args[0]), (self, options) => map$8(services(), (context) => toReadableStreamWith(self, context, options)));
30932
30981
  /**
30982
+ * Runs the stream, publishing elements into the provided PubSub.
30983
+ *
30984
+ * `shutdownOnEnd` controls whether the PubSub is shut down when the stream ends.
30985
+ * It only shuts down when set to `true`.
30986
+ *
30987
+ * @example
30988
+ * ```ts
30989
+ * import { Console, Effect, PubSub, Stream } from "effect"
30990
+ *
30991
+ * const program = Effect.scoped(Effect.gen(function* () {
30992
+ * const pubsub = yield* PubSub.unbounded<number>()
30993
+ * const subscription = yield* PubSub.subscribe(pubsub)
30994
+ *
30995
+ * yield* Stream.runIntoPubSub(Stream.fromIterable([1, 2]), pubsub)
30996
+ *
30997
+ * const first = yield* PubSub.take(subscription)
30998
+ * const second = yield* PubSub.take(subscription)
30999
+ *
31000
+ * yield* Console.log(first)
31001
+ * yield* Console.log(second)
31002
+ * }))
31003
+ *
31004
+ * Effect.runPromise(program)
31005
+ * //=> 1
31006
+ * //=> 2
31007
+ * ```
31008
+ *
31009
+ * @since 2.0.0
31010
+ * @category Destructors
31011
+ */
31012
+ const runIntoPubSub = /* @__PURE__ */ dual((args) => isStream(args[0]), (self, pubsub, options) => runIntoPubSubArray(self.channel, pubsub, options));
31013
+ /**
30933
31014
  * Converts a stream to a PubSub for concurrent consumption.
30934
31015
  *
30935
31016
  * `Take` values include the stream's end and failure signals.
@@ -52972,6 +53053,32 @@ const randomWith = (f) => withFiber((fiber) => succeed$3(f(fiber.getRef(Random))
52972
53053
  * @category Random Number Generators
52973
53054
  */
52974
53055
  const next = /* @__PURE__ */ randomWith((r) => r.nextDoubleUnsafe());
53056
+ /**
53057
+ * Uses the pseudo-random number generator to shuffle the specified iterable.
53058
+ *
53059
+ * @example
53060
+ * ```ts
53061
+ * import { Effect, Random } from "effect"
53062
+ *
53063
+ * const program = Effect.gen(function*() {
53064
+ * const values = yield* Random.shuffle([1, 2, 3, 4, 5])
53065
+ * console.log(values)
53066
+ * })
53067
+ * ```
53068
+ *
53069
+ * @since 4.0.0
53070
+ * @category Random Number Generators
53071
+ */
53072
+ const shuffle = (elements) => randomWith((r) => {
53073
+ const buffer = Array.from(elements);
53074
+ for (let i = buffer.length - 1; i >= 1; i = i - 1) {
53075
+ const index = Math.min(i, Math.floor(r.nextDoubleUnsafe() * (i + 1)));
53076
+ const value = buffer[i];
53077
+ buffer[i] = buffer[index];
53078
+ buffer[index] = value;
53079
+ }
53080
+ return buffer;
53081
+ });
52975
53082
  //#endregion
52976
53083
  //#region node_modules/.pnpm/effect@4.0.0-beta.30/node_modules/effect/dist/Ref.js
52977
53084
  const RefProto = {
@@ -53380,7 +53487,7 @@ var BackingPersistence = class extends Service$1()("effect/persistence/BackingPe
53380
53487
  */
53381
53488
  const layer$21 = /* @__PURE__ */ effect$1(Persistence)(/* @__PURE__ */ gen(function* () {
53382
53489
  const backing = yield* BackingPersistence;
53383
- const scope$5 = yield* scope;
53490
+ const scope$6 = yield* scope;
53384
53491
  return Persistence.of({ make: fnUntraced(function* (options) {
53385
53492
  const storage = yield* backing.make(options.storeId);
53386
53493
  const timeToLive = options.timeToLive ?? (() => infinity);
@@ -53415,7 +53522,7 @@ const layer$21 = /* @__PURE__ */ effect$1(Persistence)(/* @__PURE__ */ gen(funct
53415
53522
  }
53416
53523
  out[i] = exit$3.value;
53417
53524
  }
53418
- if (toRemove) for (let i = 0; i < toRemove.length; i++) yield* forkIn(storage.remove(toRemove[i]), scope$5);
53525
+ if (toRemove) for (let i = 0; i < toRemove.length; i++) yield* forkIn(storage.remove(toRemove[i]), scope$6);
53419
53526
  return out;
53420
53527
  }),
53421
53528
  set(key, value) {
@@ -85497,9 +85604,9 @@ const layer$6 = /* @__PURE__ */ provideMerge(layer$20, /* @__PURE__ */ mergeAll$
85497
85604
  * @category constructors
85498
85605
  */
85499
85606
  const make$15 = /* @__PURE__ */ fnUntraced(function* (evaluate, options) {
85500
- const scope$3 = yield* scope;
85607
+ const scope$4 = yield* scope;
85501
85608
  const server = evaluate();
85502
- yield* addFinalizer$1(scope$3, callback$1((resume) => {
85609
+ yield* addFinalizer$1(scope$4, callback$1((resume) => {
85503
85610
  if (!server.listening) return resume(void_$1);
85504
85611
  server.close((error) => {
85505
85612
  if (error) resume(die$2(error));
@@ -85519,7 +85626,7 @@ const make$15 = /* @__PURE__ */ fnUntraced(function* (evaluate, options) {
85519
85626
  const address = server.address();
85520
85627
  const wss = yield* acquireRelease(sync(() => new import_websocket_server.default({ noServer: true })), (wss) => callback$1((resume) => {
85521
85628
  wss.close(() => resume(void_$1));
85522
- })).pipe(provide$4(scope$3), cached);
85629
+ })).pipe(provide$4(scope$4), cached);
85523
85630
  return make$21({
85524
85631
  address: typeof address === "string" ? {
85525
85632
  _tag: "UnixAddress",
@@ -85530,14 +85637,14 @@ const make$15 = /* @__PURE__ */ fnUntraced(function* (evaluate, options) {
85530
85637
  port: address.port
85531
85638
  },
85532
85639
  serve: fnUntraced(function* (httpApp, middleware) {
85533
- const scope$4 = yield* scope;
85640
+ const scope$5 = yield* scope;
85534
85641
  const handler = yield* makeHandler(httpApp, {
85535
85642
  middleware,
85536
- scope: scope$4
85643
+ scope: scope$5
85537
85644
  });
85538
85645
  const upgradeHandler = yield* makeUpgradeHandler(wss, httpApp, {
85539
85646
  middleware,
85540
- scope: scope$4
85647
+ scope: scope$5
85541
85648
  });
85542
85649
  yield* addFinalizer(() => sync(() => {
85543
85650
  server.off("request", handler);
@@ -86389,12 +86496,12 @@ const AtomRegistry = /* @__PURE__ */ Service$1(TypeId$6);
86389
86496
  * @category Layers
86390
86497
  */
86391
86498
  const layerOptions = (options) => effect$1(AtomRegistry, gen(function* () {
86392
- const scope$2 = yield* scope;
86499
+ const scope$3 = yield* scope;
86393
86500
  const registry = make$13({
86394
86501
  ...options,
86395
86502
  scheduleTask: options?.scheduleTask
86396
86503
  });
86397
- yield* addFinalizer$1(scope$2, sync(() => registry.dispose()));
86504
+ yield* addFinalizer$1(scope$3, sync(() => registry.dispose()));
86398
86505
  return registry;
86399
86506
  }));
86400
86507
  /**
@@ -180286,12 +180393,11 @@ The following instructions should be done without interaction or asking for perm
180286
180393
  Set \`githubPrNumber\` to the PR number if one exists, otherwise use \`null\`.
180287
180394
  ` : "\n\nLeave `githubPrNumber` as null."}
180288
180395
  `;
180289
- const promptChooseClanka = (options) => `Your job is to choose the next task to work on using "listEligibleTasks".
180290
- **DO NOT** implement the task yet.
180291
-
180292
- The following instructions should be done without interaction or asking for permission.
180293
-
180294
- - Decide which single task to work on next from "listEligibleTasks". This should
180396
+ const promptChooseClanka = (options) => `- Use the "listEligibleTasks" function to view the list of tasks that you can start working on.
180397
+ - **NO NOT PARSE THE yaml OUTPUT IN ANY WAY**
180398
+ - **DO NOT** implement the task yet.
180399
+ - **DO NOT** use the "delegate" function for any step in this workflow
180400
+ - After reading through the list of tasks, choose the task to work on. This should
180295
180401
  be the task YOU decide as the most important to work on next, not just the
180296
180402
  first task in the list.${options.gitFlow.requiresGithubPr ? `
180297
180403
  - Check if there is an open Github PR for the chosen task. If there is, note the PR number for inclusion when calling "chooseTask".
@@ -188245,7 +188351,7 @@ var ji = Bt, Ii = Object.assign(Qe, { sync: Bt }), zi = Ut, Bi = Object.assign(e
188245
188351
  });
188246
188352
  Ze.glob = Ze;
188247
188353
  //#endregion
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
188354
+ //#region node_modules/.pnpm/clanka@0.0.23_@effect+ai-openai-compat@4.0.0-beta.30_effect@4.0.0-beta.30__@effect+ai-o_733f8e6611470b8c9676b30a3d55b413/node_modules/clanka/dist/ApplyPatch.js
188249
188355
  /**
188250
188356
  * @since 1.0.0
188251
188357
  */
@@ -188574,7 +188680,7 @@ const patchChunks = (file, input, chunks) => {
188574
188680
  return eol === "\r\n" ? text.replace(/\n/g, "\r\n") : text;
188575
188681
  };
188576
188682
  //#endregion
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
188683
+ //#region node_modules/.pnpm/clanka@0.0.23_@effect+ai-openai-compat@4.0.0-beta.30_effect@4.0.0-beta.30__@effect+ai-o_733f8e6611470b8c9676b30a3d55b413/node_modules/clanka/dist/AgentTools.js
188578
188684
  /**
188579
188685
  * @since 1.0.0
188580
188686
  */
@@ -188614,7 +188720,7 @@ const AgentTools = make$9(make$7("readFile", {
188614
188720
  }),
188615
188721
  dependencies: [CurrentDirectory]
188616
188722
  }), make$7("applyPatch", {
188617
- description: "Apply a git diff / unified diff patch across one or more files.",
188723
+ description: "Apply a git diff / unified diff patch, or a wrapped apply_patch patch, across one or more files.",
188618
188724
  parameters: String$1.annotate({ identifier: "patch" }),
188619
188725
  success: String$1,
188620
188726
  dependencies: [CurrentDirectory]
@@ -188643,6 +188749,7 @@ const AgentTools = make$9(make$7("readFile", {
188643
188749
  parameters: Struct({
188644
188750
  pattern: String$1,
188645
188751
  glob: optional$2(String$1).annotate({ documentation: "--glob" }),
188752
+ noIgnore: optional$2(Boolean$2).annotate({ documentation: "--no-ignore" }),
188646
188753
  maxLines: optional$2(Finite).annotate({ documentation: "The total maximum number of lines to return across all files (default: 500)" })
188647
188754
  }),
188648
188755
  success: String$1,
@@ -188704,7 +188811,6 @@ const AgentToolHandlers = AgentTools.toLayer(gen(function* () {
188704
188811
  yield* logInfo(`Calling "writeFile"`).pipe(annotateLogs({ path: options.path }));
188705
188812
  const cwd = yield* CurrentDirectory;
188706
188813
  const path = pathService.resolve(cwd, options.path);
188707
- if (yield* fs.exists(path)) return yield* die$2("File already exists");
188708
188814
  yield* fs.makeDirectory(pathService.dirname(path), { recursive: true });
188709
188815
  yield* fs.writeFileString(path, options.content);
188710
188816
  }, orDie$2),
@@ -188740,6 +188846,7 @@ const AgentToolHandlers = AgentTools.toLayer(gen(function* () {
188740
188846
  "--line-number"
188741
188847
  ];
188742
188848
  if (options.glob) args.push("--glob", options.glob);
188849
+ if (options.noIgnore) args.push("--no-ignore");
188743
188850
  args.push(options.pattern);
188744
188851
  let stream = pipe(spawner.streamLines(make$36("rg", args, {
188745
188852
  cwd,
@@ -188870,7 +188977,7 @@ const AgentToolHandlers = AgentTools.toLayer(gen(function* () {
188870
188977
  }));
188871
188978
  var ApplyPatchError = class extends TaggedClass$1("ApplyPatchError") {};
188872
188979
  //#endregion
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
188980
+ //#region node_modules/.pnpm/clanka@0.0.23_@effect+ai-openai-compat@4.0.0-beta.30_effect@4.0.0-beta.30__@effect+ai-o_733f8e6611470b8c9676b30a3d55b413/node_modules/clanka/dist/Executor.js
188874
188981
  /**
188875
188982
  * @since 1.0.0
188876
188983
  */
@@ -188950,7 +189057,7 @@ var QueueWriteStream = class extends Writable {
188950
189057
  }
188951
189058
  };
188952
189059
  //#endregion
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
189060
+ //#region node_modules/.pnpm/clanka@0.0.23_@effect+ai-openai-compat@4.0.0-beta.30_effect@4.0.0-beta.30__@effect+ai-o_733f8e6611470b8c9676b30a3d55b413/node_modules/clanka/dist/TypeBuilder.js
188954
189061
  const resolveDocumentation = resolveAt("documentation");
188955
189062
  const identifierPattern = /^[$A-Z_a-z][$0-9A-Z_a-z]*$/u;
188956
189063
  const Precedence = {
@@ -189223,7 +189330,7 @@ const render = (schema, options) => {
189223
189330
  return printNode({ text: documentation === void 0 ? rendered.text : `${renderJsDoc(documentation, 0, printerOptions)}${printerOptions.newLine}${rendered.text}` }, printerOptions);
189224
189331
  };
189225
189332
  //#endregion
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
189333
+ //#region node_modules/.pnpm/clanka@0.0.23_@effect+ai-openai-compat@4.0.0-beta.30_effect@4.0.0-beta.30__@effect+ai-o_733f8e6611470b8c9676b30a3d55b413/node_modules/clanka/dist/ToolkitRenderer.js
189227
189334
  /**
189228
189335
  * @since 1.0.0
189229
189336
  */
@@ -189245,7 +189352,7 @@ declare function ${name}(${params}): Promise<${render(tool.successSchema)}>`);
189245
189352
  }) });
189246
189353
  };
189247
189354
  //#endregion
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
189355
+ //#region node_modules/.pnpm/clanka@0.0.23_@effect+ai-openai-compat@4.0.0-beta.30_effect@4.0.0-beta.30__@effect+ai-o_733f8e6611470b8c9676b30a3d55b413/node_modules/clanka/dist/Agent.js
189249
189356
  /**
189250
189357
  * @since 1.0.0
189251
189358
  */
@@ -189300,7 +189407,8 @@ ${content}
189300
189407
  for (const [id, state] of outputBuffer) {
189301
189408
  outputBuffer.delete(id);
189302
189409
  offerAllUnsafe(output, state);
189303
- if (state[state.length - 1]._tag === "ReasoningDelta") {
189410
+ const lastPart = state[state.length - 1];
189411
+ if (lastPart._tag === "ScriptDelta" || lastPart._tag === "ReasoningDelta") {
189304
189412
  currentOutputAgent = id;
189305
189413
  break;
189306
189414
  }
@@ -189322,17 +189430,23 @@ ${content}
189322
189430
  ${prompt}`));
189323
189431
  return gen(function* () {
189324
189432
  const provider = yield* ProviderName;
189325
- offerUnsafe(output, new SubagentStart({
189326
- id,
189327
- prompt,
189328
- model: yield* ModelName,
189329
- provider
189330
- }));
189433
+ maybeSend({
189434
+ agentId,
189435
+ part: new SubagentStart({
189436
+ id,
189437
+ prompt,
189438
+ model: yield* ModelName,
189439
+ provider
189440
+ }),
189441
+ release: true
189442
+ });
189331
189443
  return yield* stream.pipe(runForEachArray((parts) => {
189332
189444
  for (const part of parts) switch (part._tag) {
189333
189445
  case "SubagentStart":
189334
189446
  case "SubagentComplete":
189335
- case "SubagentPart": break;
189447
+ case "SubagentPart":
189448
+ offerUnsafe(output, part);
189449
+ break;
189336
189450
  default:
189337
189451
  offerUnsafe(output, new SubagentPart({
189338
189452
  id,
@@ -189555,7 +189669,7 @@ Javascript output:
189555
189669
  \`\`\``;
189556
189670
  };
189557
189671
  const generateSystemMulti = (toolsDts) => {
189558
- return `From now on only respond with plain javascript code which will be executed for you.
189672
+ return `You complete your tasks by **only writing javascript code** to interact with your environment.
189559
189673
 
189560
189674
  - Use \`console.log\` to print any output you need.
189561
189675
  - Top level await is supported.
@@ -200013,7 +200127,7 @@ const transformToolCallParams = /* @__PURE__ */ fnUntraced(function* (tools, too
200013
200127
  })));
200014
200128
  });
200015
200129
  //#endregion
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
200130
+ //#region node_modules/.pnpm/clanka@0.0.23_@effect+ai-openai-compat@4.0.0-beta.30_effect@4.0.0-beta.30__@effect+ai-o_733f8e6611470b8c9676b30a3d55b413/node_modules/clanka/dist/CodexAuth.js
200017
200131
  /**
200018
200132
  * @since 1.0.0
200019
200133
  */
@@ -200233,7 +200347,7 @@ var CodexAuth = class CodexAuth extends Service$1()("clanka/CodexAuth") {
200233
200347
  static layerClient = this.layerClientNoDeps.pipe(provide$3(CodexAuth.layer));
200234
200348
  };
200235
200349
  //#endregion
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
200350
+ //#region node_modules/.pnpm/clanka@0.0.23_@effect+ai-openai-compat@4.0.0-beta.30_effect@4.0.0-beta.30__@effect+ai-o_733f8e6611470b8c9676b30a3d55b413/node_modules/clanka/dist/Codex.js
200237
200351
  /**
200238
200352
  * @since 1.0.0
200239
200353
  */
@@ -201548,7 +201662,7 @@ const getUsageDetailNumber = (details, field) => {
201548
201662
  return typeof value === "number" ? value : void 0;
201549
201663
  };
201550
201664
  //#endregion
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
201665
+ //#region node_modules/.pnpm/clanka@0.0.23_@effect+ai-openai-compat@4.0.0-beta.30_effect@4.0.0-beta.30__@effect+ai-o_733f8e6611470b8c9676b30a3d55b413/node_modules/clanka/dist/CopilotAuth.js
201552
201666
  /**
201553
201667
  * @since 1.0.0
201554
201668
  */
@@ -201739,7 +201853,7 @@ var GithubCopilotAuth = class GithubCopilotAuth extends Service$1()("clanka/Gith
201739
201853
  static layerClient = this.layerClientNoDeps.pipe(provide$3(GithubCopilotAuth.layer));
201740
201854
  };
201741
201855
  //#endregion
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
201856
+ //#region node_modules/.pnpm/clanka@0.0.23_@effect+ai-openai-compat@4.0.0-beta.30_effect@4.0.0-beta.30__@effect+ai-o_733f8e6611470b8c9676b30a3d55b413/node_modules/clanka/dist/Copilot.js
201743
201857
  /**
201744
201858
  * @since 1.0.0
201745
201859
  */
@@ -202162,7 +202276,7 @@ Object.defineProperties(createChalk.prototype, styles);
202162
202276
  const chalk = createChalk();
202163
202277
  createChalk({ level: stderrColor ? stderrColor.level : 0 });
202164
202278
  //#endregion
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
202279
+ //#region node_modules/.pnpm/clanka@0.0.23_@effect+ai-openai-compat@4.0.0-beta.30_effect@4.0.0-beta.30__@effect+ai-o_733f8e6611470b8c9676b30a3d55b413/node_modules/clanka/dist/OutputFormatter.js
202166
202280
  /**
202167
202281
  * @since 1.0.0
202168
202282
  */
@@ -202203,6 +202317,47 @@ const scriptIcon = "󰯁";
202203
202317
  const subagentIcon = " ";
202204
202318
  const thinkingIcon = "󰟶";
202205
202319
  const doneIcon = "";
202320
+ /**
202321
+ * @since 1.0.0
202322
+ * @category Muxer
202323
+ */
202324
+ var Muxer = class extends Service$1()("clanka/OutputFormatter/Muxer") {};
202325
+ /**
202326
+ * @since 1.0.0
202327
+ * @category Muxer
202328
+ */
202329
+ const layerMuxer = (formatter) => effect$1(Muxer, gen(function* () {
202330
+ const scope$2 = yield* scope;
202331
+ const output = yield* unbounded$1();
202332
+ let agentCount = 0;
202333
+ let currentAgentId = null;
202334
+ const semaphore = makeUnsafe$8(1);
202335
+ return Muxer.of({
202336
+ add(stream) {
202337
+ const id = ++agentCount;
202338
+ return stream.pipe(tap(fnUntraced(function* (part_) {
202339
+ if (currentAgentId === null || id !== currentAgentId) yield* semaphore.take(1);
202340
+ switch ((part_._tag === "SubagentPart" ? part_.part : part_)._tag) {
202341
+ case "ReasoningStart":
202342
+ case "ScriptStart":
202343
+ currentAgentId = id;
202344
+ break;
202345
+ case "ScriptDelta":
202346
+ case "ReasoningDelta": break;
202347
+ default:
202348
+ currentAgentId = null;
202349
+ break;
202350
+ }
202351
+ if (id !== currentAgentId) yield* semaphore.release(1);
202352
+ })), formatter, runIntoPubSub(output), onExit$1(() => {
202353
+ if (currentAgentId !== id) return void_$1;
202354
+ currentAgentId = null;
202355
+ return semaphore.release(1);
202356
+ }), forkIn(scope$2), asVoid);
202357
+ },
202358
+ output: fromPubSub(output)
202359
+ });
202360
+ }));
202206
202361
  //#endregion
202207
202362
  //#region src/TaskTools.ts
202208
202363
  var ChosenTaskDeferred = class extends Reference("lalph/TaskTools/ChosenTaskDeferred", { defaultValue: makeUnsafe$13 }) {};
@@ -202221,6 +202376,14 @@ const TaskList = Array$1(Struct({
202221
202376
  "blockedBy"
202222
202377
  ])
202223
202378
  }));
202379
+ const toTaskListItem = (issue) => ({
202380
+ id: issue.id ?? "",
202381
+ title: issue.title,
202382
+ description: issue.description,
202383
+ state: issue.state,
202384
+ priority: issue.priority,
202385
+ blockedBy: issue.blockedBy
202386
+ });
202224
202387
  var TaskTools = class extends make$9(make$7("listTasks", {
202225
202388
  description: "Returns the current list of tasks.",
202226
202389
  success: TaskList,
@@ -202251,43 +202414,31 @@ var TaskTools = class extends make$9(make$7("listTasks", {
202251
202414
  parameters: String$1.annotate({ identifier: "taskId" }),
202252
202415
  dependencies: [CurrentProjectId]
202253
202416
  })) {};
202254
- var TaskToolsWithChoose = class extends merge(TaskTools, make$9(make$7("chooseTask", {
202417
+ var TaskChooseTools = class extends make$9(make$7("chooseTask", {
202255
202418
  description: "Choose the task to work on",
202256
202419
  parameters: Struct({
202257
202420
  taskId: String$1,
202258
202421
  githubPrNumber: optional$2(Number$1)
202259
202422
  })
202260
202423
  }), make$7("listEligibleTasks", {
202261
- description: "List tasks eligible for being chosen with chooseTask.",
202262
- success: TaskList,
202424
+ description: "List tasks eligible for being chosen with chooseTask in yaml format.",
202425
+ success: String$1,
202263
202426
  dependencies: [CurrentProjectId]
202264
- }))) {};
202427
+ })) {};
202428
+ var TaskToolsWithChoose = class extends merge(TaskTools, TaskChooseTools) {};
202265
202429
  const TaskToolsHandlers = TaskToolsWithChoose.toLayer(gen(function* () {
202266
202430
  const source = yield* IssueSource;
202267
202431
  return TaskToolsWithChoose.of({
202268
202432
  listTasks: fn("TaskTools.listTasks")(function* () {
202269
202433
  yield* log$1(`Calling "listTasks"`);
202270
202434
  const projectId = yield* CurrentProjectId;
202271
- return (yield* source.issues(projectId)).map((issue) => ({
202272
- id: issue.id ?? "",
202273
- title: issue.title,
202274
- description: issue.description,
202275
- state: issue.state,
202276
- priority: issue.priority,
202277
- blockedBy: issue.blockedBy
202278
- }));
202435
+ return (yield* source.issues(projectId)).map(toTaskListItem);
202279
202436
  }, orDie$2),
202280
202437
  listEligibleTasks: fn("TaskTools.listEligibleTasks")(function* () {
202281
202438
  yield* log$1(`Calling "listEligibleTasks"`);
202282
202439
  const projectId = yield* CurrentProjectId;
202283
- return (yield* source.issues(projectId)).filter((t) => t.blockedBy.length === 0 && t.state === "todo").map((issue) => ({
202284
- id: issue.id ?? "",
202285
- title: issue.title,
202286
- description: issue.description,
202287
- state: issue.state,
202288
- priority: issue.priority,
202289
- blockedBy: issue.blockedBy
202290
- }));
202440
+ const shuffled = yield* shuffle((yield* source.issues(projectId)).filter((t) => t.state === "todo" && t.blockedBy.length === 0).map(toTaskListItem));
202441
+ return import_dist.stringify(shuffled, null, 2);
202291
202442
  }, orDie$2),
202292
202443
  chooseTask: fn("TaskTools.chooseTask")(function* (options) {
202293
202444
  yield* log$1(`Calling "chooseTask"`).pipe(annotateLogs(options));
@@ -202359,28 +202510,27 @@ const reasoningToCopilotConfig = (model, reasoning) => {
202359
202510
  };
202360
202511
  //#endregion
202361
202512
  //#region src/Clanka.ts
202362
- const runClanka = fnUntraced(
202363
- /** The working directory to run the agent in */
202364
- function* (options) {
202365
- const models = yield* ClankaModels;
202366
- const agent = yield* make$5({
202367
- ...options,
202368
- tools: options.withChoose ? TaskToolsWithChoose : TaskTools,
202369
- subagentModel: clankaSubagent(models, options.model)
202370
- }).pipe(provide$1(models.get(options.model)));
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) => {
202377
- for (const item of out) process.stdout.write(item);
202378
- return void_$1;
202379
- }));
202380
- },
202381
- scoped$1,
202382
- provide$1([layerServices, TaskToolsHandlers])
202383
- );
202513
+ const ClankaMuxerLayer = effectDiscard(gen(function* () {
202514
+ const muxer = yield* Muxer;
202515
+ const stdio = yield* Stdio;
202516
+ yield* muxer.output.pipe(run$7(stdio.stdout()), forkScoped);
202517
+ })).pipe(provideMerge(layerMuxer(pretty)));
202518
+ const runClanka = fnUntraced(function* (options) {
202519
+ const models = yield* ClankaModels;
202520
+ const muxer = yield* Muxer;
202521
+ const agent = yield* make$5({
202522
+ ...options,
202523
+ tools: options.withChoose ? TaskChooseTools : TaskTools,
202524
+ subagentModel: clankaSubagent(models, options.model)
202525
+ }).pipe(provide$1(models.get(options.model)));
202526
+ yield* muxer.add(agent.output);
202527
+ let stream = options.stallTimeout ? withStallTimeout(options.stallTimeout)(agent.output) : agent.output;
202528
+ if (options.steer) yield* options.steer.pipe(switchMap(fnUntraced(function* (message) {
202529
+ yield* log$1(`Received steer message: ${message}`);
202530
+ yield* agent.steer(message);
202531
+ }, fromEffectDrain)), runDrain, forkScoped);
202532
+ yield* stream.pipe(runDrain, catchTag$1("AgentFinished", () => void_$1));
202533
+ }, scoped$1, provide$1([layerServices, TaskToolsHandlers]));
202384
202534
  //#endregion
202385
202535
  //#region src/Agents/worker.ts
202386
202536
  const agentWorker = fnUntraced(function* (options) {
@@ -202394,7 +202544,7 @@ const agentWorker = fnUntraced(function* (options) {
202394
202544
  prompt: options.prompt,
202395
202545
  stallTimeout: options.stallTimeout,
202396
202546
  steer: options.steer
202397
- }).pipe(options.taskRef ? provideService$2(CurrentTaskRef, options.taskRef) : identity);
202547
+ });
202398
202548
  return ExitCode(0);
202399
202549
  }
202400
202550
  return yield* pipe(options.preset.cliAgent.command({
@@ -202719,7 +202869,7 @@ const run = fnUntraced(function* (options) {
202719
202869
  preset: taskPreset,
202720
202870
  prompt: instructions,
202721
202871
  steer
202722
- }).pipe(catchStallInReview, withSpan("Main.agentWorker"))}`);
202872
+ }).pipe(provideService$2(CurrentTaskRef, issueRef), catchStallInReview, withSpan("Main.agentWorker"))}`);
202723
202873
  if (options.review) {
202724
202874
  registry.update(currentWorker.state, (s) => s.transitionTo(WorkerStatus.Reviewing({ issueId: taskId })));
202725
202875
  yield* agentReviewer({
@@ -202821,6 +202971,7 @@ const commandRoot = make$46("lalph", {
202821
202971
  });
202822
202972
  }, scoped$1, provide$1([
202823
202973
  ClankaModels.layer,
202974
+ ClankaMuxerLayer,
202824
202975
  PromptGen.layer,
202825
202976
  GithubCli.layer,
202826
202977
  Settings.layer,
@@ -202925,6 +203076,7 @@ const generateTasks = fnUntraced(function* ({ specsDirectory, specificationPath,
202925
203076
  });
202926
203077
  }, provide$1([
202927
203078
  ClankaModels.layer,
203079
+ ClankaMuxerLayer,
202928
203080
  Settings.layer,
202929
203081
  PromptGen.layer,
202930
203082
  Prd.layerProvided.pipe(provideMerge(layerProjectIdPrompt))
@@ -202997,7 +203149,8 @@ const commandPlan = make$46("plan", {
202997
203149
  }).pipe(provide$1([
202998
203150
  Settings.layer,
202999
203151
  CurrentIssueSource.layer,
203000
- ClankaModels.layer
203152
+ ClankaModels.layer,
203153
+ ClankaMuxerLayer
203001
203154
  ]));
203002
203155
  }, scoped$1, provide$1(Editor.layer))), withSubcommands([commandPlanTasks]));
203003
203156
  const plan = fnUntraced(function* (options) {
@@ -203129,7 +203282,7 @@ const commandEdit = make$46("edit").pipe(withDescription("Open the selected proj
203129
203282
  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));
203130
203283
  //#endregion
203131
203284
  //#region package.json
203132
- var version = "0.3.47";
203285
+ var version = "0.3.49";
203133
203286
  //#endregion
203134
203287
  //#region src/commands/projects/ls.ts
203135
203288
  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.47",
4
+ "version": "0.3.49",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -30,13 +30,13 @@
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.17",
33
+ "clanka": "^0.0.23",
34
34
  "concurrently": "^9.2.1",
35
35
  "effect": "4.0.0-beta.30",
36
36
  "husky": "^9.1.7",
37
37
  "lint-staged": "^16.3.3",
38
38
  "octokit": "^5.0.5",
39
- "oxlint": "^1.52.0",
39
+ "oxlint": "^1.53.0",
40
40
  "prettier": "^3.8.1",
41
41
  "tsdown": "^0.21.1",
42
42
  "typescript": "^5.9.3",
@@ -1,10 +1,9 @@
1
- import { Duration, Effect, identity, Path, pipe, Stream } from "effect"
1
+ import { Duration, Effect, 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"
8
7
 
9
8
  export const agentWorker = Effect.fnUntraced(function* (options: {
10
9
  readonly stallTimeout: Duration.Duration
@@ -12,7 +11,6 @@ export const agentWorker = Effect.fnUntraced(function* (options: {
12
11
  readonly system?: string
13
12
  readonly prompt: string
14
13
  readonly steer?: Stream.Stream<string>
15
- readonly taskRef?: CurrentTaskRef["Service"]
16
14
  }) {
17
15
  const pathService = yield* Path.Path
18
16
  const worktree = yield* Worktree
@@ -26,11 +24,7 @@ export const agentWorker = Effect.fnUntraced(function* (options: {
26
24
  prompt: options.prompt,
27
25
  stallTimeout: options.stallTimeout,
28
26
  steer: options.steer,
29
- }).pipe(
30
- options.taskRef
31
- ? Effect.provideService(CurrentTaskRef, options.taskRef)
32
- : identity,
33
- )
27
+ })
34
28
  return ExitCode(0)
35
29
  }
36
30
 
package/src/Clanka.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { Agent, OutputFormatter } from "clanka"
2
- import { Duration, Effect, Stream } from "effect"
2
+ import { Duration, Effect, Layer, Stdio, Stream } from "effect"
3
3
  import {
4
+ TaskChooseTools,
4
5
  TaskTools,
5
6
  TaskToolsHandlers,
6
7
  TaskToolsWithChoose,
@@ -8,8 +9,15 @@ import {
8
9
  import { ClankaModels, clankaSubagent } from "./ClankaModels.ts"
9
10
  import { withStallTimeout } from "./shared/stream.ts"
10
11
 
12
+ export const ClankaMuxerLayer = Layer.effectDiscard(
13
+ Effect.gen(function* () {
14
+ const muxer = yield* OutputFormatter.Muxer
15
+ const stdio = yield* Stdio.Stdio
16
+ yield* muxer.output.pipe(Stream.run(stdio.stdout()), Effect.forkScoped)
17
+ }),
18
+ ).pipe(Layer.provideMerge(OutputFormatter.layerMuxer(OutputFormatter.pretty)))
19
+
11
20
  export const runClanka = Effect.fnUntraced(
12
- /** The working directory to run the agent in */
13
21
  function* (options: {
14
22
  readonly directory: string
15
23
  readonly model: string
@@ -20,14 +28,18 @@ export const runClanka = Effect.fnUntraced(
20
28
  readonly withChoose?: boolean | undefined
21
29
  }) {
22
30
  const models = yield* ClankaModels
31
+ const muxer = yield* OutputFormatter.Muxer
32
+
23
33
  const agent = yield* Agent.make({
24
34
  ...options,
25
- tools: options.withChoose
26
- ? TaskToolsWithChoose
27
- : (TaskTools as unknown as typeof TaskToolsWithChoose),
35
+ tools: (options.withChoose
36
+ ? TaskChooseTools
37
+ : TaskTools) as unknown as typeof TaskToolsWithChoose,
28
38
  subagentModel: clankaSubagent(models, options.model),
29
39
  }).pipe(Effect.provide(models.get(options.model)))
30
40
 
41
+ yield* muxer.add(agent.output)
42
+
31
43
  let stream = options.stallTimeout
32
44
  ? withStallTimeout(options.stallTimeout)(agent.output)
33
45
  : agent.output
@@ -45,14 +57,9 @@ export const runClanka = Effect.fnUntraced(
45
57
  )
46
58
  }
47
59
 
48
- return yield* stream.pipe(
49
- OutputFormatter.pretty,
50
- Stream.runForEachArray((out) => {
51
- for (const item of out) {
52
- process.stdout.write(item)
53
- }
54
- return Effect.void
55
- }),
60
+ yield* stream.pipe(
61
+ Stream.runDrain,
62
+ Effect.catchTag("AgentFinished", () => Effect.void),
56
63
  )
57
64
  },
58
65
  Effect.scoped,
package/src/PromptGen.ts CHANGED
@@ -90,12 +90,11 @@ Set \`githubPrNumber\` to the PR number if one exists, otherwise use \`null\`.
90
90
 
91
91
  const promptChooseClanka = (options: {
92
92
  readonly gitFlow: GitFlow["Service"]
93
- }) => `Your job is to choose the next task to work on using "listEligibleTasks".
94
- **DO NOT** implement the task yet.
95
-
96
- The following instructions should be done without interaction or asking for permission.
97
-
98
- - Decide which single task to work on next from "listEligibleTasks". This should
93
+ }) => `- Use the "listEligibleTasks" function to view the list of tasks that you can start working on.
94
+ - **NO NOT PARSE THE yaml OUTPUT IN ANY WAY**
95
+ - **DO NOT** implement the task yet.
96
+ - **DO NOT** use the "delegate" function for any step in this workflow
97
+ - After reading through the list of tasks, choose the task to work on. This should
99
98
  be the task YOU decide as the most important to work on next, not just the
100
99
  first task in the list.${
101
100
  options.gitFlow.requiresGithubPr
package/src/TaskTools.ts CHANGED
@@ -3,6 +3,7 @@ import {
3
3
  Effect,
4
4
  MutableRef,
5
5
  Option,
6
+ Random,
6
7
  Schema,
7
8
  ServiceMap,
8
9
  Struct,
@@ -11,6 +12,7 @@ import { Tool, Toolkit } from "effect/unstable/ai"
11
12
  import { PrdIssue } from "./domain/PrdIssue.ts"
12
13
  import { IssueSource } from "./IssueSource.ts"
13
14
  import { CurrentProjectId } from "./Settings.ts"
15
+ import * as Yaml from "yaml"
14
16
 
15
17
  export class ChosenTaskDeferred extends ServiceMap.Reference(
16
18
  "lalph/TaskTools/ChosenTaskDeferred",
@@ -48,6 +50,15 @@ const TaskList = Schema.Array(
48
50
  }),
49
51
  )
50
52
 
53
+ const toTaskListItem = (issue: PrdIssue) => ({
54
+ id: issue.id ?? "",
55
+ title: issue.title,
56
+ description: issue.description,
57
+ state: issue.state,
58
+ priority: issue.priority,
59
+ blockedBy: issue.blockedBy,
60
+ })
61
+
51
62
  export class TaskTools extends Toolkit.make(
52
63
  Tool.make("listTasks", {
53
64
  description: "Returns the current list of tasks.",
@@ -86,22 +97,25 @@ export class TaskTools extends Toolkit.make(
86
97
  }),
87
98
  ) {}
88
99
 
100
+ export class TaskChooseTools extends Toolkit.make(
101
+ Tool.make("chooseTask", {
102
+ description: "Choose the task to work on",
103
+ parameters: Schema.Struct({
104
+ taskId: Schema.String,
105
+ githubPrNumber: Schema.optional(Schema.Number),
106
+ }),
107
+ }),
108
+ Tool.make("listEligibleTasks", {
109
+ description:
110
+ "List tasks eligible for being chosen with chooseTask in yaml format.",
111
+ success: Schema.String,
112
+ dependencies: [CurrentProjectId],
113
+ }),
114
+ ) {}
115
+
89
116
  export class TaskToolsWithChoose extends Toolkit.merge(
90
117
  TaskTools,
91
- Toolkit.make(
92
- Tool.make("chooseTask", {
93
- description: "Choose the task to work on",
94
- parameters: Schema.Struct({
95
- taskId: Schema.String,
96
- githubPrNumber: Schema.optional(Schema.Number),
97
- }),
98
- }),
99
- Tool.make("listEligibleTasks", {
100
- description: "List tasks eligible for being chosen with chooseTask.",
101
- success: TaskList,
102
- dependencies: [CurrentProjectId],
103
- }),
104
- ),
118
+ TaskChooseTools,
105
119
  ) {}
106
120
 
107
121
  export const TaskToolsHandlers = TaskToolsWithChoose.toLayer(
@@ -113,29 +127,16 @@ export const TaskToolsHandlers = TaskToolsWithChoose.toLayer(
113
127
  yield* Effect.log(`Calling "listTasks"`)
114
128
  const projectId = yield* CurrentProjectId
115
129
  const tasks = yield* source.issues(projectId)
116
- return tasks.map((issue) => ({
117
- id: issue.id ?? "",
118
- title: issue.title,
119
- description: issue.description,
120
- state: issue.state,
121
- priority: issue.priority,
122
- blockedBy: issue.blockedBy,
123
- }))
130
+ return tasks.map(toTaskListItem)
124
131
  }, Effect.orDie),
125
132
  listEligibleTasks: Effect.fn("TaskTools.listEligibleTasks")(function* () {
126
133
  yield* Effect.log(`Calling "listEligibleTasks"`)
127
134
  const projectId = yield* CurrentProjectId
128
- const tasks = yield* source.issues(projectId)
129
- return tasks
130
- .filter((t) => t.blockedBy.length === 0 && t.state === "todo")
131
- .map((issue) => ({
132
- id: issue.id ?? "",
133
- title: issue.title,
134
- description: issue.description,
135
- state: issue.state,
136
- priority: issue.priority,
137
- blockedBy: issue.blockedBy,
138
- }))
135
+ const tasks = (yield* source.issues(projectId))
136
+ .filter((t) => t.state === "todo" && t.blockedBy.length === 0)
137
+ .map(toTaskListItem)
138
+ const shuffled = yield* Random.shuffle(tasks)
139
+ return Yaml.stringify(shuffled, null, 2)
139
140
  }, Effect.orDie),
140
141
  chooseTask: Effect.fn("TaskTools.chooseTask")(function* (options) {
141
142
  yield* Effect.log(`Calling "chooseTask"`).pipe(
@@ -11,6 +11,7 @@ import { selectCliAgentPreset } from "../../Presets.ts"
11
11
  import { CurrentIssueSource } from "../../CurrentIssueSource.ts"
12
12
  import type { CliAgentPreset } from "../../domain/CliAgentPreset.ts"
13
13
  import { ClankaModels } from "../../ClankaModels.ts"
14
+ import { ClankaMuxerLayer } from "../../Clanka.ts"
14
15
 
15
16
  const specificationPath = Argument.path("spec", {
16
17
  pathType: "file",
@@ -72,6 +73,7 @@ const generateTasks = Effect.fnUntraced(
72
73
  },
73
74
  Effect.provide([
74
75
  ClankaModels.layer,
76
+ ClankaMuxerLayer,
75
77
  Settings.layer,
76
78
  PromptGen.layer,
77
79
  Prd.layerProvided.pipe(Layer.provideMerge(layerProjectIdPrompt)),
@@ -25,6 +25,7 @@ import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"
25
25
  import { parseBranch } from "../shared/git.ts"
26
26
  import type { CliAgentPreset } from "../domain/CliAgentPreset.ts"
27
27
  import { ClankaModels } from "../ClankaModels.ts"
28
+ import { ClankaMuxerLayer } from "../Clanka.ts"
28
29
 
29
30
  const dangerous = Flag.boolean("dangerous").pipe(
30
31
  Flag.withAlias("d"),
@@ -99,6 +100,7 @@ export const commandPlan = Command.make("plan", {
99
100
  Settings.layer,
100
101
  CurrentIssueSource.layer,
101
102
  ClankaModels.layer,
103
+ ClankaMuxerLayer,
102
104
  ]),
103
105
  )
104
106
  },
@@ -52,6 +52,9 @@ import type { ChildProcessSpawner } from "effect/unstable/process"
52
52
  import { ClankaModels } from "../ClankaModels.ts"
53
53
  import type { AiError } from "effect/unstable/ai/AiError"
54
54
  import type { PrdIssue } from "../domain/PrdIssue.ts"
55
+ import { CurrentTaskRef } from "../TaskTools.ts"
56
+ import type { OutputFormatter } from "clanka"
57
+ import { ClankaMuxerLayer } from "../Clanka.ts"
55
58
 
56
59
  // Main iteration run logic
57
60
 
@@ -88,6 +91,7 @@ const run = Effect.fnUntraced(
88
91
  | Prd
89
92
  | Worktree
90
93
  | ClankaModels
94
+ | OutputFormatter.Muxer
91
95
  | Scope.Scope
92
96
  > {
93
97
  const projectId = yield* CurrentProjectId
@@ -236,7 +240,11 @@ const run = Effect.fnUntraced(
236
240
  preset: taskPreset,
237
241
  prompt: instructions,
238
242
  steer,
239
- }).pipe(catchStallInReview, Effect.withSpan("Main.agentWorker"))
243
+ }).pipe(
244
+ Effect.provideService(CurrentTaskRef, issueRef),
245
+ catchStallInReview,
246
+ Effect.withSpan("Main.agentWorker"),
247
+ )
240
248
  yield* Effect.log(`Agent exited with code: ${exitCode}`)
241
249
 
242
250
  // 3. Review task
@@ -484,6 +492,7 @@ export const commandRoot = Command.make("lalph", {
484
492
  Effect.scoped,
485
493
  Effect.provide([
486
494
  ClankaModels.layer,
495
+ ClankaMuxerLayer,
487
496
  PromptGen.layer,
488
497
  GithubCli.layer,
489
498
  Settings.layer,