@p4code/cli 0.3.23 → 0.3.25

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/bin.mjs CHANGED
@@ -127,7 +127,7 @@ const closeServer = (server) => {
127
127
  * NetService - Service tag for startup networking helpers.
128
128
  */
129
129
  var NetService = class extends Context.Service()("@p4code/shared/Net/NetService") {};
130
- const make$91 = () => {
130
+ const make$92 = () => {
131
131
  /**
132
132
  * Returns true when a TCP server can bind to {host, port}.
133
133
  * `EADDRNOTAVAIL` is treated as available so IPv6-absent hosts don't fail
@@ -236,10 +236,10 @@ const make$91 = () => {
236
236
  })
237
237
  };
238
238
  };
239
- const layer$82 = Layer.sync(NetService, make$91);
239
+ const layer$82 = Layer.sync(NetService, make$92);
240
240
  //#endregion
241
241
  //#region package.json
242
- var version = "0.3.23";
242
+ var version = "0.3.25";
243
243
  //#endregion
244
244
  //#region src/config.ts
245
245
  /**
@@ -260,8 +260,8 @@ var ServerConfig$1 = class extends Context.Service()("@p4code/cli/config/ServerC
260
260
  /** @deprecated Import and use `layerTest` from this module. */
261
261
  static layerTest = (cwd, baseDirOrPrefix) => layerTest$3(cwd, baseDirOrPrefix);
262
262
  };
263
- const make$90 = (config) => ServerConfig$1.of(config);
264
- const layer$81 = (config) => Layer.succeed(ServerConfig$1, make$90(config));
263
+ const make$91 = (config) => ServerConfig$1.of(config);
264
+ const layer$81 = (config) => Layer.succeed(ServerConfig$1, make$91(config));
265
265
  const deriveServerPaths = Effect.fn(function* (baseDir, devUrl, options = {}) {
266
266
  const { join } = yield* Path.Path;
267
267
  const stateDir = join(baseDir, devUrl !== void 0 && !options.baseDirIsExplicit ? "dev" : "userdata");
@@ -1333,6 +1333,12 @@ const ExecutionEnvironmentCapabilities = Schema$1.Struct({
1333
1333
  /** Server understands thread.pin / thread.unpin / thread.pin.reorder
1334
1334
  commands. Same version-skew contract as threadSettlement. */
1335
1335
  threadPinning: Schema$1.optionalKey(Schema$1.Boolean),
1336
+ /** Server understands the thread.fork command. Same version-skew contract
1337
+ as threadSettlement. */
1338
+ threadFork: Schema$1.optionalKey(Schema$1.Boolean),
1339
+ /** Server understands thread.scheduled-task.create / cancel and fires
1340
+ pending tasks. Same version-skew contract as threadSettlement. */
1341
+ threadScheduledTasks: Schema$1.optionalKey(Schema$1.Boolean),
1336
1342
  /** Server exposes the pull-request list, detail, activity, diff, and mutation APIs. Absent on
1337
1343
  servers from before the pull-request workspace shipped, so clients must not probe them. */
1338
1344
  pullRequests: Schema$1.optionalKey(Schema$1.Boolean),
@@ -1595,7 +1601,7 @@ const PREFERRED_DEFAULT_CODEX_MODELS = ["gpt-5.6-sol", "gpt-5.6-terra"];
1595
1601
  const DEFAULT_TEXT_GENERATION_MODEL = "gpt-5.6-luna";
1596
1602
  const DEFAULT_MODEL_BY_PROVIDER = {
1597
1603
  [CODEX_DRIVER_KIND]: DEFAULT_MODEL,
1598
- [CLAUDE_DRIVER_KIND]: "claude-sonnet-5",
1604
+ [CLAUDE_DRIVER_KIND]: "claude-fable-5-1",
1599
1605
  [CURSOR_DRIVER_KIND]: "auto",
1600
1606
  [GROK_DRIVER_KIND$1]: "grok-build",
1601
1607
  [MUSE_DRIVER_KIND]: "muse-spark-1.2",
@@ -1619,6 +1625,10 @@ const MODEL_SLUG_ALIASES_BY_PROVIDER = {
1619
1625
  "gpt-5.3-spark": "gpt-5.3-codex-spark"
1620
1626
  },
1621
1627
  [CLAUDE_DRIVER_KIND]: {
1628
+ fable: "claude-fable-5-1",
1629
+ "fable-5.1": "claude-fable-5-1",
1630
+ "fable-5-1": "claude-fable-5-1",
1631
+ "claude-fable-5.1": "claude-fable-5-1",
1622
1632
  opus: "claude-opus-5",
1623
1633
  "opus-5": "claude-opus-5",
1624
1634
  "claude-opus-5.0": "claude-opus-5",
@@ -1873,6 +1883,31 @@ const OrchestrationProposedPlan = Schema$1.Struct({
1873
1883
  createdAt: IsoDateTime,
1874
1884
  updatedAt: IsoDateTime
1875
1885
  });
1886
+ const OrchestrationScheduledTaskId = TrimmedNonEmptyString;
1887
+ const OrchestrationScheduledTaskStatus = Schema$1.Literals([
1888
+ "pending",
1889
+ "fired",
1890
+ "failed",
1891
+ "cancelled"
1892
+ ]);
1893
+ /**
1894
+ * A prompt the server sends to a thread at a chosen time. Pending tasks are
1895
+ * the live ones: firing starts a turn with `prompt`, cancelling is the way
1896
+ * out before that. A task whose turn could not start after bounded retries
1897
+ * ends `failed` with `failure` explaining why; it can be dismissed or
1898
+ * scheduled again from the client.
1899
+ */
1900
+ const OrchestrationScheduledTask = Schema$1.Struct({
1901
+ id: OrchestrationScheduledTaskId,
1902
+ prompt: TrimmedNonEmptyString,
1903
+ runAt: IsoDateTime,
1904
+ status: OrchestrationScheduledTaskStatus,
1905
+ createdAt: IsoDateTime,
1906
+ updatedAt: IsoDateTime,
1907
+ firedAt: Schema$1.NullOr(IsoDateTime).pipe(Schema$1.withDecodingDefault(Effect.succeed(null))),
1908
+ cancelledAt: Schema$1.NullOr(IsoDateTime).pipe(Schema$1.withDecodingDefault(Effect.succeed(null))),
1909
+ failure: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.withDecodingDefault(Effect.succeed(null)))
1910
+ });
1876
1911
  const SourceProposedPlanReference = Schema$1.Struct({
1877
1912
  threadId: ThreadId,
1878
1913
  planId: OrchestrationProposedPlanId
@@ -1992,6 +2027,7 @@ const OrchestrationThread = Schema$1.Struct({
1992
2027
  deletedAt: Schema$1.NullOr(IsoDateTime),
1993
2028
  messages: Schema$1.Array(OrchestrationMessage),
1994
2029
  proposedPlans: Schema$1.Array(OrchestrationProposedPlan).pipe(Schema$1.withDecodingDefault(Effect.succeed([]))),
2030
+ scheduledTasks: Schema$1.optional(Schema$1.Array(OrchestrationScheduledTask)),
1995
2031
  activities: Schema$1.Array(OrchestrationThreadActivity),
1996
2032
  checkpoints: Schema$1.Array(OrchestrationCheckpointSummary),
1997
2033
  session: Schema$1.NullOr(OrchestrationSession)
@@ -2262,6 +2298,44 @@ const ThreadCreateCommand = Schema$1.Struct({
2262
2298
  worktreePath: Schema$1.NullOr(TrimmedNonEmptyString),
2263
2299
  createdAt: IsoDateTime
2264
2300
  });
2301
+ /**
2302
+ * Creates a new thread from an existing one. The decider copies the source
2303
+ * thread's configuration and the projections copy its conversation, so the
2304
+ * fork opens with the same context while the source stays untouched.
2305
+ */
2306
+ const ThreadForkCommand = Schema$1.Struct({
2307
+ type: Schema$1.Literal("thread.fork"),
2308
+ commandId: CommandId,
2309
+ sourceThreadId: ThreadId,
2310
+ threadId: ThreadId,
2311
+ title: Schema$1.optional(TrimmedNonEmptyString),
2312
+ createdAt: IsoDateTime
2313
+ });
2314
+ const ThreadScheduledTaskCreateCommand = Schema$1.Struct({
2315
+ type: Schema$1.Literal("thread.scheduled-task.create"),
2316
+ commandId: CommandId,
2317
+ threadId: ThreadId,
2318
+ taskId: OrchestrationScheduledTaskId,
2319
+ prompt: TrimmedNonEmptyString,
2320
+ runAt: IsoDateTime,
2321
+ createdAt: IsoDateTime
2322
+ });
2323
+ const ThreadScheduledTaskCancelCommand = Schema$1.Struct({
2324
+ type: Schema$1.Literal("thread.scheduled-task.cancel"),
2325
+ commandId: CommandId,
2326
+ threadId: ThreadId,
2327
+ taskId: OrchestrationScheduledTaskId,
2328
+ cancelledAt: IsoDateTime
2329
+ });
2330
+ /** Server-only: records that the scheduler fired (or failed to fire) a task. */
2331
+ const ThreadScheduledTaskFireCommand = Schema$1.Struct({
2332
+ type: Schema$1.Literal("thread.scheduled-task.fire"),
2333
+ commandId: CommandId,
2334
+ threadId: ThreadId,
2335
+ taskId: OrchestrationScheduledTaskId,
2336
+ firedAt: IsoDateTime,
2337
+ failure: Schema$1.optional(Schema$1.String)
2338
+ });
2265
2339
  const ThreadDeleteCommand = Schema$1.Struct({
2266
2340
  type: Schema$1.Literal("thread.delete"),
2267
2341
  commandId: CommandId,
@@ -2509,6 +2583,9 @@ const DispatchableClientOrchestrationCommand = Schema$1.Union([
2509
2583
  ProjectMetaUpdateCommand,
2510
2584
  ProjectDeleteCommand,
2511
2585
  ThreadCreateCommand,
2586
+ ThreadForkCommand,
2587
+ ThreadScheduledTaskCreateCommand,
2588
+ ThreadScheduledTaskCancelCommand,
2512
2589
  ThreadDeleteCommand,
2513
2590
  ThreadArchiveCommand,
2514
2591
  ThreadUnarchiveCommand,
@@ -2540,6 +2617,9 @@ const ClientOrchestrationCommand = Schema$1.Union([
2540
2617
  ProjectMetaUpdateCommand,
2541
2618
  ProjectDeleteCommand,
2542
2619
  ThreadCreateCommand,
2620
+ ThreadForkCommand,
2621
+ ThreadScheduledTaskCreateCommand,
2622
+ ThreadScheduledTaskCancelCommand,
2543
2623
  ThreadDeleteCommand,
2544
2624
  ThreadArchiveCommand,
2545
2625
  ThreadUnarchiveCommand,
@@ -2694,7 +2774,8 @@ const InternalOrchestrationCommand = Schema$1.Union([
2694
2774
  ThreadProposedPlanUpsertCommand,
2695
2775
  ThreadTurnDiffCompleteCommand,
2696
2776
  ThreadActivityAppendCommand,
2697
- ThreadRevertCompleteCommand
2777
+ ThreadRevertCompleteCommand,
2778
+ ThreadScheduledTaskFireCommand
2698
2779
  ]);
2699
2780
  Schema$1.Union([DispatchableClientOrchestrationCommand, InternalOrchestrationCommand]);
2700
2781
  const OrchestrationEventType = Schema$1.Literals([
@@ -2728,6 +2809,9 @@ const OrchestrationEventType = Schema$1.Literals([
2728
2809
  "thread.session-force-stop-requested",
2729
2810
  "thread.session-set",
2730
2811
  "thread.proposed-plan-upserted",
2812
+ "thread.scheduled-task.created",
2813
+ "thread.scheduled-task.cancelled",
2814
+ "thread.scheduled-task.fired",
2731
2815
  "thread.turn-diff-completed",
2732
2816
  "thread.activity-appended",
2733
2817
  "thread.turn-completed",
@@ -2782,6 +2866,11 @@ const ThreadCreatedPayload$1 = Schema$1.Struct({
2782
2866
  unpromptedSubagents: Schema$1.Boolean.pipe(Schema$1.withDecodingDefault(Effect.succeed(true))),
2783
2867
  branch: Schema$1.NullOr(TrimmedNonEmptyString),
2784
2868
  worktreePath: Schema$1.NullOr(TrimmedNonEmptyString),
2869
+ /**
2870
+ * Set when the thread was forked: projections copy the source thread's
2871
+ * messages into this one. Optional so events from pre-fork servers decode.
2872
+ */
2873
+ forkedFromThreadId: Schema$1.optional(ThreadId),
2785
2874
  createdAt: IsoDateTime,
2786
2875
  updatedAt: IsoDateTime
2787
2876
  });
@@ -2994,6 +3083,21 @@ const ThreadProposedPlanUpsertedPayload$1 = Schema$1.Struct({
2994
3083
  threadId: ThreadId,
2995
3084
  proposedPlan: OrchestrationProposedPlan
2996
3085
  });
3086
+ const ThreadScheduledTaskCreatedPayload$1 = Schema$1.Struct({
3087
+ threadId: ThreadId,
3088
+ task: OrchestrationScheduledTask
3089
+ });
3090
+ const ThreadScheduledTaskCancelledPayload$1 = Schema$1.Struct({
3091
+ threadId: ThreadId,
3092
+ taskId: OrchestrationScheduledTaskId,
3093
+ cancelledAt: IsoDateTime
3094
+ });
3095
+ const ThreadScheduledTaskFiredPayload$1 = Schema$1.Struct({
3096
+ threadId: ThreadId,
3097
+ taskId: OrchestrationScheduledTaskId,
3098
+ firedAt: IsoDateTime,
3099
+ failure: Schema$1.NullOr(Schema$1.String).pipe(Schema$1.withDecodingDefault(Effect.succeed(null)))
3100
+ });
2997
3101
  const ThreadTurnDiffCompletedPayload$1 = Schema$1.Struct({
2998
3102
  threadId: ThreadId,
2999
3103
  turnId: TurnId,
@@ -3181,6 +3285,21 @@ const OrchestrationEvent = Schema$1.Union([
3181
3285
  type: Schema$1.Literal("thread.proposed-plan-upserted"),
3182
3286
  payload: ThreadProposedPlanUpsertedPayload$1
3183
3287
  }),
3288
+ Schema$1.Struct({
3289
+ ...EventBaseFields,
3290
+ type: Schema$1.Literal("thread.scheduled-task.created"),
3291
+ payload: ThreadScheduledTaskCreatedPayload$1
3292
+ }),
3293
+ Schema$1.Struct({
3294
+ ...EventBaseFields,
3295
+ type: Schema$1.Literal("thread.scheduled-task.cancelled"),
3296
+ payload: ThreadScheduledTaskCancelledPayload$1
3297
+ }),
3298
+ Schema$1.Struct({
3299
+ ...EventBaseFields,
3300
+ type: Schema$1.Literal("thread.scheduled-task.fired"),
3301
+ payload: ThreadScheduledTaskFiredPayload$1
3302
+ }),
3184
3303
  Schema$1.Struct({
3185
3304
  ...EventBaseFields,
3186
3305
  type: Schema$1.Literal("thread.turn-diff-completed"),
@@ -5159,6 +5278,11 @@ const PREVIEW_AUTOMATION_OPERATIONS = [
5159
5278
  const PreviewAutomationOperation = Schema.Literals(PREVIEW_AUTOMATION_OPERATIONS);
5160
5279
  const PreviewAutomationTabTargetFields = { tabId: Schema.optional(PreviewTabId.annotate({ description: "Exact collaborative browser tab to target. Omit to use this agent session's current tab." })).annotate({ description: "Exact collaborative browser tab to target. Omit to use this agent session's current tab." }) };
5161
5280
  const PreviewAutomationTabTargetInput = Schema.Struct(PreviewAutomationTabTargetFields);
5281
+ const INCLUDE_SCREENSHOT_DESCRIPTION = "Attach a PNG screenshot to the result. Omit it for the text-only page state, which already carries locators, visible text, and diagnostics; every attached image stays in the agent's context for the rest of the session.";
5282
+ const PreviewAutomationSnapshotInput = Schema.Struct({
5283
+ ...PreviewAutomationTabTargetFields,
5284
+ includeScreenshot: Schema.optional(Schema.Boolean.annotate({ description: INCLUDE_SCREENSHOT_DESCRIPTION })).annotate({ description: INCLUDE_SCREENSHOT_DESCRIPTION })
5285
+ });
5162
5286
  const PreviewAutomationStatus = Schema.Struct({
5163
5287
  available: Schema.Boolean,
5164
5288
  visible: Schema.Boolean,
@@ -5830,6 +5954,7 @@ const ContextMenuItemSchema = Schema$1.Struct({
5830
5954
  header: Schema$1.optionalKey(Schema$1.Boolean),
5831
5955
  separator: Schema$1.optionalKey(Schema$1.Boolean),
5832
5956
  icon: Schema$1.optionalKey(Schema$1.String),
5957
+ shortcut: Schema$1.optionalKey(Schema$1.String),
5833
5958
  children: Schema$1.optionalKey(Schema$1.Array(Schema$1.suspend(() => ContextMenuItemSchema)))
5834
5959
  });
5835
5960
  const DesktopUpdateStatusSchema = Schema$1.Literals([
@@ -8152,7 +8277,9 @@ const ClientSettingsSchema = Schema$1.Struct({
8152
8277
  })).pipe(Schema$1.withDecodingDefault(Effect.succeed([]))),
8153
8278
  providerModelPreferences: Schema$1.Record(ProviderInstanceId, Schema$1.Struct({
8154
8279
  hiddenModels: Schema$1.Array(Schema$1.String).pipe(Schema$1.withDecodingDefault(Effect.succeed([]))),
8155
- modelOrder: Schema$1.Array(Schema$1.String).pipe(Schema$1.withDecodingDefault(Effect.succeed([])))
8280
+ modelOrder: Schema$1.Array(Schema$1.String).pipe(Schema$1.withDecodingDefault(Effect.succeed([]))),
8281
+ /** Option values a model starts with in this instance until the user picks others. */
8282
+ modelOptionDefaults: Schema$1.Record(TrimmedNonEmptyString, ProviderOptionSelections).pipe(Schema$1.withDecodingDefault(Effect.succeed({})))
8156
8283
  })).pipe(Schema$1.withDecodingDefault(Effect.succeed({}))),
8157
8284
  showBuildModeToggle: Schema$1.Boolean.pipe(Schema$1.withDecodingDefault(Effect.succeed(false))),
8158
8285
  sidebarAutoSettleAfterDays: Schema$1.NullOr(SidebarAutoSettleAfterDays).pipe(Schema$1.withDecodingDefault(Effect.succeed(3))),
@@ -8610,7 +8737,8 @@ Schema$1.Struct({
8610
8737
  }))),
8611
8738
  providerModelPreferences: Schema$1.optionalKey(Schema$1.Record(ProviderInstanceId, Schema$1.Struct({
8612
8739
  hiddenModels: Schema$1.Array(Schema$1.String).pipe(Schema$1.withDecodingDefault(Effect.succeed([]))),
8613
- modelOrder: Schema$1.Array(Schema$1.String).pipe(Schema$1.withDecodingDefault(Effect.succeed([])))
8740
+ modelOrder: Schema$1.Array(Schema$1.String).pipe(Schema$1.withDecodingDefault(Effect.succeed([]))),
8741
+ modelOptionDefaults: Schema$1.Record(TrimmedNonEmptyString, ProviderOptionSelections).pipe(Schema$1.withDecodingDefault(Effect.succeed({})))
8614
8742
  }))),
8615
8743
  showBuildModeToggle: Schema$1.optionalKey(Schema$1.Boolean),
8616
8744
  sidebarAutoSettleAfterDays: Schema$1.optionalKey(Schema$1.NullOr(SidebarAutoSettleAfterDays)),
@@ -10569,6 +10697,8 @@ const agentAssetTotalBytes = (files) => files.reduce((total, file) => total + en
10569
10697
  * has. Two definitions of the same rule is how one of them ends up laxer.
10570
10698
  */
10571
10699
  const McpServerName = AgentAssetName;
10700
+ /** Provider-neutral session alias for a Claude user-scope server forwarded by p4code. */
10701
+ const mcpUserScopeSessionName = (name) => `p4-user-${name}`;
10572
10702
  /**
10573
10703
  * Where a secret goes when it is resolved.
10574
10704
  *
@@ -12487,7 +12617,7 @@ function deriveAuthClientMetadata(input) {
12487
12617
  //#endregion
12488
12618
  //#region src/auth/EnvironmentAuthPolicy.ts
12489
12619
  var EnvironmentAuthPolicy = class extends Context.Service()("@p4code/cli/auth/EnvironmentAuthPolicy") {};
12490
- const make$89 = Effect.gen(function* () {
12620
+ const make$90 = Effect.gen(function* () {
12491
12621
  const config = yield* ServerConfig$1;
12492
12622
  const isRemoteReachable = isRemoteReachableHost(config.host);
12493
12623
  const policy = config.mode === "desktop" ? isRemoteReachable ? "remote-reachable" : "desktop-managed-local" : isRemoteReachable ? "remote-reachable" : "loopback-browser";
@@ -12505,7 +12635,7 @@ const make$89 = Effect.gen(function* () {
12505
12635
  };
12506
12636
  return EnvironmentAuthPolicy.of({ getDescriptor: () => Effect.succeed(descriptor).pipe(Effect.withSpan("EnvironmentAuthPolicy.getDescriptor")) });
12507
12637
  });
12508
- const layer$80 = Layer.effect(EnvironmentAuthPolicy, make$89);
12638
+ const layer$80 = Layer.effect(EnvironmentAuthPolicy, make$90);
12509
12639
  //#endregion
12510
12640
  //#region src/persistence/Errors.ts
12511
12641
  function summarizeSchemaIssue(issue) {
@@ -12686,7 +12816,7 @@ function toPersistenceSqlOrDecodeError$6(sqlOperation, decodeOperation, correlat
12686
12816
  cause
12687
12817
  });
12688
12818
  }
12689
- const make$88 = Effect.gen(function* () {
12819
+ const make$89 = Effect.gen(function* () {
12690
12820
  const sql = yield* SqlClient.SqlClient;
12691
12821
  const createSessionRow = SqlSchema.void({
12692
12822
  Request: CreateAuthSessionInput,
@@ -12820,7 +12950,7 @@ const make$88 = Effect.gen(function* () {
12820
12950
  setLastConnectedAt
12821
12951
  };
12822
12952
  });
12823
- const layer$79 = Layer.effect(AuthSessionRepository, make$88);
12953
+ const layer$79 = Layer.effect(AuthSessionRepository, make$89);
12824
12954
  //#endregion
12825
12955
  //#region src/auth/ServerSecretStore.ts
12826
12956
  const secretStoreErrorContext = {
@@ -12887,7 +13017,7 @@ const isSecretStoreError = Schema$1.is(SecretStoreError);
12887
13017
  const isPlatformError = (value) => Predicate.isTagged(value, "PlatformError");
12888
13018
  const isSecretAlreadyExistsError = (error) => "cause" in error && isPlatformError(error.cause) && error.cause.reason._tag === "AlreadyExists";
12889
13019
  var ServerSecretStore = class extends Context.Service()("@p4code/cli/auth/ServerSecretStore") {};
12890
- const make$87 = Effect.gen(function* () {
13020
+ const make$88 = Effect.gen(function* () {
12891
13021
  const crypto = yield* Crypto.Crypto;
12892
13022
  const fileSystem = yield* FileSystem.FileSystem;
12893
13023
  const path = yield* Path.Path;
@@ -12922,15 +13052,21 @@ const make$87 = Effect.gen(function* () {
12922
13052
  };
12923
13053
  const create = (name, value) => {
12924
13054
  const secretPath = resolveSecretPath(name);
12925
- return Effect.scoped(Effect.gen(function* () {
12926
- const file = yield* fileSystem.open(secretPath, {
12927
- flag: "wx",
12928
- mode: 384
12929
- });
12930
- yield* file.writeAll(value);
12931
- yield* file.sync;
12932
- yield* fileSystem.chmod(secretPath, 384);
12933
- })).pipe(Effect.mapError((cause) => new SecretStorePersistError({
13055
+ return crypto.randomUUIDv4.pipe(Effect.mapError((cause) => new SecretStoreTemporaryPathError({
13056
+ resource: `secret ${name}`,
13057
+ cause
13058
+ })), Effect.flatMap((uuid) => {
13059
+ const tempPath = `${secretPath}.${uuid}.tmp`;
13060
+ return Effect.scoped(Effect.gen(function* () {
13061
+ const file = yield* fileSystem.open(tempPath, {
13062
+ flag: "wx",
13063
+ mode: 384
13064
+ });
13065
+ yield* file.writeAll(value);
13066
+ yield* file.sync;
13067
+ yield* fileSystem.link(tempPath, secretPath);
13068
+ })).pipe(Effect.ensuring(fileSystem.remove(tempPath).pipe(Effect.ignore)));
13069
+ }), Effect.mapError((cause) => new SecretStorePersistError({
12934
13070
  resource: `secret ${name}`,
12935
13071
  cause
12936
13072
  })));
@@ -12957,7 +13093,7 @@ const make$87 = Effect.gen(function* () {
12957
13093
  remove
12958
13094
  });
12959
13095
  });
12960
- const layer$78 = Layer.effect(ServerSecretStore, make$87);
13096
+ const layer$78 = Layer.effect(ServerSecretStore, make$88);
12961
13097
  //#endregion
12962
13098
  //#region src/auth/SessionStore.ts
12963
13099
  var MalformedSessionTokenError = class extends Schema$1.TaggedErrorClass()("MalformedSessionTokenError", {}) {
@@ -13195,7 +13331,7 @@ function toAuthClientSession(input) {
13195
13331
  current: false
13196
13332
  };
13197
13333
  }
13198
- const make$86 = Effect.gen(function* () {
13334
+ const make$87 = Effect.gen(function* () {
13199
13335
  const crypto = yield* Crypto.Crypto;
13200
13336
  const serverConfig = yield* ServerConfig$1;
13201
13337
  const secretStore = yield* ServerSecretStore;
@@ -13509,7 +13645,7 @@ const make$86 = Effect.gen(function* () {
13509
13645
  markDisconnected
13510
13646
  });
13511
13647
  });
13512
- const layer$77 = Layer.effect(SessionStore, make$86).pipe(Layer.provideMerge(layer$79));
13648
+ const layer$77 = Layer.effect(SessionStore, make$87).pipe(Layer.provideMerge(layer$79));
13513
13649
  //#endregion
13514
13650
  //#region src/persistence/AuthPairingLinks.ts
13515
13651
  const AuthPairingLinkRecord = Schema$1.Struct({
@@ -13570,7 +13706,7 @@ function toPersistenceSqlOrDecodeError$5(sqlOperation, decodeOperation, correlat
13570
13706
  cause
13571
13707
  });
13572
13708
  }
13573
- const make$85 = Effect.gen(function* () {
13709
+ const make$86 = Effect.gen(function* () {
13574
13710
  const sql = yield* SqlClient.SqlClient;
13575
13711
  const createPairingLinkRow = SqlSchema.void({
13576
13712
  Request: CreateAuthPairingLinkInput,
@@ -13705,7 +13841,7 @@ const make$85 = Effect.gen(function* () {
13705
13841
  getByCredential
13706
13842
  };
13707
13843
  });
13708
- const layer$76 = Layer.effect(AuthPairingLinkRepository, make$85);
13844
+ const layer$76 = Layer.effect(AuthPairingLinkRepository, make$86);
13709
13845
  //#endregion
13710
13846
  //#region src/auth/PairingGrantStore.ts
13711
13847
  var UnknownBootstrapCredentialError = class extends Schema$1.TaggedErrorClass()("UnknownBootstrapCredentialError", {}) {
@@ -13800,7 +13936,7 @@ const DEV_STARTUP_TTL_HOURS = Duration.hours(24);
13800
13936
  const PAIRING_TOKEN_ALPHABET = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
13801
13937
  const PAIRING_TOKEN_LENGTH = 12;
13802
13938
  const PAIRING_TOKEN_REJECTION_LIMIT = Math.floor(256 / 32) * 32;
13803
- const make$84 = Effect.gen(function* () {
13939
+ const make$85 = Effect.gen(function* () {
13804
13940
  const crypto = yield* Crypto.Crypto;
13805
13941
  const config = yield* ServerConfig$1;
13806
13942
  const pairingLinks = yield* AuthPairingLinkRepository;
@@ -13998,7 +14134,7 @@ const make$84 = Effect.gen(function* () {
13998
14134
  consume
13999
14135
  });
14000
14136
  });
14001
- const layer$75 = Layer.effect(PairingGrantStore, make$84).pipe(Layer.provideMerge(layer$76));
14137
+ const layer$75 = Layer.effect(PairingGrantStore, make$85).pipe(Layer.provideMerge(layer$76));
14002
14138
  //#endregion
14003
14139
  //#region src/persistence/DatabaseSnapshot.ts
14004
14140
  /**
@@ -15917,6 +16053,33 @@ var _053_ProjectionTurnsKeysetIndex_default = Effect.gen(function* () {
15917
16053
  `;
15918
16054
  });
15919
16055
  //#endregion
16056
+ //#region src/persistence/Migrations/054_ProjectionThreadScheduledTasks.ts
16057
+ /**
16058
+ * User-created scheduled tasks: a prompt the server sends to a thread at a
16059
+ * chosen time. Pending rows are what the scheduler re-arms after a restart.
16060
+ */
16061
+ var _054_ProjectionThreadScheduledTasks_default = Effect.gen(function* () {
16062
+ const sql = yield* SqlClient.SqlClient;
16063
+ yield* sql`
16064
+ CREATE TABLE IF NOT EXISTS projection_thread_scheduled_tasks (
16065
+ task_id TEXT PRIMARY KEY,
16066
+ thread_id TEXT NOT NULL,
16067
+ prompt TEXT NOT NULL,
16068
+ run_at TEXT NOT NULL,
16069
+ status TEXT NOT NULL,
16070
+ created_at TEXT NOT NULL,
16071
+ updated_at TEXT NOT NULL,
16072
+ fired_at TEXT,
16073
+ cancelled_at TEXT,
16074
+ failure TEXT
16075
+ )
16076
+ `;
16077
+ yield* sql`
16078
+ CREATE INDEX IF NOT EXISTS idx_projection_thread_scheduled_tasks_thread_run
16079
+ ON projection_thread_scheduled_tasks(thread_id, run_at)
16080
+ `;
16081
+ });
16082
+ //#endregion
15920
16083
  //#region src/persistence/Migrations.ts
15921
16084
  /**
15922
16085
  * MigrationsLive - Migration runner with inline loader
@@ -16202,6 +16365,11 @@ const migrationEntries = [
16202
16365
  53,
16203
16366
  "ProjectionTurnsKeysetIndex",
16204
16367
  _053_ProjectionTurnsKeysetIndex_default
16368
+ ],
16369
+ [
16370
+ 54,
16371
+ "ProjectionThreadScheduledTasks",
16372
+ _054_ProjectionThreadScheduledTasks_default
16205
16373
  ]
16206
16374
  ];
16207
16375
  const makeMigrationLoader = (throughId) => Migrator.fromRecord(Object.fromEntries(migrationEntries.filter(([id]) => throughId === void 0 || id <= throughId).map(([id, name, migration]) => [`${id}_${name}`, migration])));
@@ -17192,7 +17360,7 @@ function parseBearerToken(request) {
17192
17360
  const token = header.slice(7).trim();
17193
17361
  return token.length > 0 ? token : null;
17194
17362
  }
17195
- const make$83 = Effect.gen(function* () {
17363
+ const make$84 = Effect.gen(function* () {
17196
17364
  const policy = yield* EnvironmentAuthPolicy;
17197
17365
  const bootstrapCredentials = yield* PairingGrantStore;
17198
17366
  const sessions = yield* SessionStore;
@@ -17387,7 +17555,7 @@ const make$83 = Effect.gen(function* () {
17387
17555
  issueStartupPairingUrl
17388
17556
  });
17389
17557
  });
17390
- const layer$74 = Layer.effect(EnvironmentAuth, make$83).pipe(Layer.provideMerge(layer$75), Layer.provideMerge(layer$77), Layer.provideMerge(layer$80));
17558
+ const layer$74 = Layer.effect(EnvironmentAuth, make$84).pipe(Layer.provideMerge(layer$75), Layer.provideMerge(layer$77), Layer.provideMerge(layer$80));
17391
17559
  const storageLayer = Layer.mergeAll(layer$78, layerConfig);
17392
17560
  const runtimeLayer = layer$74.pipe(Layer.provideMerge(storageLayer));
17393
17561
  //#endregion
@@ -19225,7 +19393,7 @@ const DEFAULT_LIMITS = {
19225
19393
  windowMillis: FAILURE_WINDOW_MS,
19226
19394
  blockMillis: BLOCK_DURATION_MS
19227
19395
  };
19228
- const make$82 = Effect.fn("HubAuthThrottle.make")(function* (limits = DEFAULT_LIMITS) {
19396
+ const make$83 = Effect.fn("HubAuthThrottle.make")(function* (limits = DEFAULT_LIMITS) {
19229
19397
  const state = yield* Ref.make(initialThrottleState);
19230
19398
  return HubAuthThrottle.of({
19231
19399
  shouldRefuse: Effect.gen(function* () {
@@ -19239,7 +19407,7 @@ const make$82 = Effect.fn("HubAuthThrottle.make")(function* (limits = DEFAULT_LI
19239
19407
  })
19240
19408
  });
19241
19409
  });
19242
- const layer$73 = Layer.effect(HubAuthThrottle, make$82());
19410
+ const layer$73 = Layer.effect(HubAuthThrottle, make$83());
19243
19411
  //#endregion
19244
19412
  //#region src/hub/HubAuth.ts
19245
19413
  /**
@@ -20959,7 +21127,7 @@ function stripDefaultServerSettings(current, defaults) {
20959
21127
  }
20960
21128
  return Object.is(current, defaults) ? void 0 : current;
20961
21129
  }
20962
- const make$81 = Effect.gen(function* () {
21130
+ const make$82 = Effect.gen(function* () {
20963
21131
  const { settingsPath } = yield* ServerConfig$1;
20964
21132
  const fs = yield* FileSystem.FileSystem;
20965
21133
  const pathService = yield* Path.Path;
@@ -21180,7 +21348,7 @@ const make$81 = Effect.gen(function* () {
21180
21348
  }
21181
21349
  };
21182
21350
  });
21183
- const layer$71 = Layer.effect(ServerSettingsService, make$81);
21351
+ const layer$71 = Layer.effect(ServerSettingsService, make$82);
21184
21352
  //#endregion
21185
21353
  //#region src/pathExpansion.ts
21186
21354
  /**
@@ -21557,7 +21725,7 @@ function claudeEntryFromRegistration(registration) {
21557
21725
  };
21558
21726
  }
21559
21727
  var ClaudeMcpFiles = class extends Context.Service()("@p4code/cli/mcp/ClaudeMcpFiles") {};
21560
- const make$80 = Effect.gen(function* () {
21728
+ const make$81 = Effect.gen(function* () {
21561
21729
  const fileSystem = yield* FileSystem.FileSystem;
21562
21730
  const path = yield* Path.Path;
21563
21731
  const services = yield* Effect.context();
@@ -21615,6 +21783,8 @@ const make$80 = Effect.gen(function* () {
21615
21783
  const userPath = claudeUserConfigPath();
21616
21784
  return {
21617
21785
  readUser: readAt(userPath),
21786
+ readUserAt: (configDir) => readAt(Effect.succeed(path.join(path.resolve(expandHomePath$3(configDir)), ".claude.json"))),
21787
+ readUserFile: (filePath) => readAt(Effect.succeed(path.resolve(filePath))),
21618
21788
  upsertUser: (registration) => upsertAt(userPath)(registration),
21619
21789
  removeUser: (name) => removeAt(userPath)(name),
21620
21790
  readProject: (projectDir) => readAt(Effect.succeed(projectFile(projectDir))),
@@ -21622,9 +21792,11 @@ const make$80 = Effect.gen(function* () {
21622
21792
  removeProject: (projectDir, name) => removeAt(Effect.succeed(projectFile(projectDir)))(name)
21623
21793
  };
21624
21794
  });
21625
- const layer$70 = Layer.effect(ClaudeMcpFiles, make$80);
21795
+ const layer$70 = Layer.effect(ClaudeMcpFiles, make$81);
21626
21796
  Layer.succeed(ClaudeMcpFiles, {
21627
21797
  readUser: Effect.succeed([]),
21798
+ readUserAt: () => Effect.succeed([]),
21799
+ readUserFile: () => Effect.succeed([]),
21628
21800
  upsertUser: () => Effect.fail(new McpRegistryError({ detail: "No Claude config in tests." })),
21629
21801
  removeUser: () => Effect.fail(new McpRegistryError({ detail: "No Claude config in tests." })),
21630
21802
  readProject: () => Effect.succeed([]),
@@ -21758,7 +21930,7 @@ const decodeClientRegistration = Schema$1.decodeUnknownExit(ClientRegistrationRe
21758
21930
  const decodeTokenResponse = Schema$1.decodeUnknownExit(TokenResponse);
21759
21931
  var McpOAuth = class extends Context.Service()("@p4code/cli/mcp/McpOAuth") {};
21760
21932
  const registryError = (detail) => new McpRegistryError({ detail });
21761
- const make$79 = Effect.gen(function* () {
21933
+ const make$80 = Effect.gen(function* () {
21762
21934
  const config = yield* ServerConfig$1;
21763
21935
  const secrets = yield* ServerSecretStore;
21764
21936
  const http = yield* HttpClient.HttpClient;
@@ -22078,7 +22250,7 @@ const make$79 = Effect.gen(function* () {
22078
22250
  accessTokenFor
22079
22251
  };
22080
22252
  });
22081
- const layer$69 = Layer.effect(McpOAuth, make$79);
22253
+ const layer$69 = Layer.effect(McpOAuth, make$80);
22082
22254
  Layer.succeed(McpOAuth, {
22083
22255
  statusFor: () => Effect.succeed(Option.none()),
22084
22256
  begin: () => Effect.fail(new McpRegistryError({ detail: "OAuth sign-in is not available." })),
@@ -22096,7 +22268,7 @@ const decodeRegistration$1 = Schema$1.decodeUnknownExit(RegistrationFromJson$1);
22096
22268
  const encodeRegistration = Schema$1.encodeSync(RegistrationFromJson$1);
22097
22269
  var McpRegistry = class extends Context.Service()("@p4code/cli/mcp/McpRegistry") {};
22098
22270
  const slotsOf = (registration) => registration.secrets ?? [];
22099
- const make$78 = Effect.gen(function* () {
22271
+ const make$79 = Effect.gen(function* () {
22100
22272
  const config = yield* ServerConfig$1;
22101
22273
  const secrets = yield* ServerSecretStore;
22102
22274
  const oauth = yield* McpOAuth;
@@ -22190,64 +22362,87 @@ const make$78 = Effect.gen(function* () {
22190
22362
  target: slot.target,
22191
22363
  key: slot.key
22192
22364
  }), new TextEncoder().encode(value)).pipe(Effect.catchCause((cause) => Effect.logWarning("mcp secret write failed", { cause }).pipe(Effect.asVoid)));
22193
- return {
22194
- list,
22195
- save,
22196
- remove,
22197
- setSecret,
22198
- resolveForSession: Effect.gen(function* () {
22199
- const registrations = yield* readAll();
22200
- const resolved = {};
22201
- for (const registration of registrations) {
22202
- if (!registration.enabled) continue;
22203
- const headers = { ...registration.transport === "stdio" ? {} : registration.headers ?? {} };
22204
- const env = { ...registration.transport === "stdio" ? registration.env ?? {} : {} };
22205
- let complete = true;
22206
- for (const slot of slotsOf(registration)) {
22207
- const value = yield* readSecret(registration.name, slot);
22208
- if (Option.isNone(value)) {
22209
- complete = false;
22210
- break;
22211
- }
22212
- if (slot.target === "header") headers[slot.key] = value.value;
22213
- else env[slot.key] = value.value;
22214
- }
22215
- if (!complete) continue;
22216
- const hasExplicitAuthorization = Object.keys(headers).some((key) => key.toLowerCase() === "authorization");
22217
- if (registration.transport !== "stdio" && !hasExplicitAuthorization) {
22218
- const token = yield* oauth.accessTokenFor(registration);
22219
- if (Option.isSome(token)) headers["Authorization"] = `Bearer ${token.value}`;
22365
+ const resolveForSessionWithUserScope = (readUserScope) => Effect.gen(function* () {
22366
+ const registrations = yield* readAll();
22367
+ const resolved = {};
22368
+ for (const registration of registrations) {
22369
+ if (!registration.enabled) continue;
22370
+ const headers = { ...registration.transport === "stdio" ? {} : registration.headers ?? {} };
22371
+ const env = { ...registration.transport === "stdio" ? registration.env ?? {} : {} };
22372
+ let complete = true;
22373
+ for (const slot of slotsOf(registration)) {
22374
+ const value = yield* readSecret(registration.name, slot);
22375
+ if (Option.isNone(value)) {
22376
+ complete = false;
22377
+ break;
22220
22378
  }
22221
- resolved[registration.name] = registration.transport === "stdio" ? {
22379
+ if (slot.target === "header") headers[slot.key] = value.value;
22380
+ else env[slot.key] = value.value;
22381
+ }
22382
+ if (!complete) continue;
22383
+ const hasExplicitAuthorization = Object.keys(headers).some((key) => key.toLowerCase() === "authorization");
22384
+ if (registration.transport !== "stdio" && !hasExplicitAuthorization) {
22385
+ const token = yield* oauth.accessTokenFor(registration);
22386
+ if (Option.isSome(token)) headers["Authorization"] = `Bearer ${token.value}`;
22387
+ }
22388
+ resolved[registration.name] = registration.transport === "stdio" ? {
22389
+ type: "stdio",
22390
+ command: registration.command,
22391
+ args: registration.args ?? [],
22392
+ env
22393
+ } : {
22394
+ type: registration.transport,
22395
+ url: registration.url,
22396
+ headers
22397
+ };
22398
+ }
22399
+ for (const userScope of yield* readUserScope) {
22400
+ if (userScope.name in resolved) continue;
22401
+ const sessionName = mcpUserScopeSessionName(userScope.name);
22402
+ if (sessionName in resolved) {
22403
+ yield* Effect.logWarning("skipped user-scope MCP session alias collision", {
22404
+ server: userScope.name,
22405
+ sessionName
22406
+ });
22407
+ continue;
22408
+ }
22409
+ if (userScope.transport === "stdio") {
22410
+ resolved[sessionName] = {
22222
22411
  type: "stdio",
22223
- command: registration.command,
22224
- args: registration.args ?? [],
22225
- env
22226
- } : {
22227
- type: registration.transport,
22228
- url: registration.url,
22229
- headers
22412
+ command: userScope.command,
22413
+ args: userScope.args ?? [],
22414
+ env: userScope.env ?? {}
22230
22415
  };
22416
+ continue;
22231
22417
  }
22232
- for (const userScope of yield* claudeFiles.readUser) {
22233
- if (userScope.transport === "stdio") continue;
22234
- if (userScope.name in resolved) continue;
22418
+ const headers = { ...userScope.headers };
22419
+ if (!Object.keys(headers).some((key) => key.toLowerCase() === "authorization")) {
22235
22420
  const token = yield* oauth.accessTokenFor(userScope);
22236
- if (Option.isNone(token)) continue;
22237
- resolved[userScope.name] = {
22238
- type: userScope.transport,
22239
- url: userScope.url,
22240
- headers: {
22241
- ...userScope.headers,
22242
- Authorization: `Bearer ${token.value}`
22243
- }
22244
- };
22421
+ if (Option.isSome(token)) headers["Authorization"] = `Bearer ${token.value}`;
22422
+ else if (Option.isSome(yield* oauth.statusFor(userScope))) continue;
22245
22423
  }
22246
- return resolved;
22247
- }).pipe(Effect.provide(services), Effect.catchCause((cause) => Effect.logWarning("mcp registry resolve failed", { cause }).pipe(Effect.as({}))))
22424
+ resolved[sessionName] = {
22425
+ type: userScope.transport,
22426
+ url: userScope.url,
22427
+ headers
22428
+ };
22429
+ }
22430
+ return resolved;
22431
+ }).pipe(Effect.provide(services), Effect.catchCause((cause) => Effect.logWarning("mcp registry resolve failed", { cause }).pipe(Effect.as({}))));
22432
+ const resolveForSession = resolveForSessionWithUserScope(claudeFiles.readUser);
22433
+ const resolveForSessionAtClaudeConfigDir = (configDir) => resolveForSessionWithUserScope(claudeFiles.readUserAt(configDir));
22434
+ const resolveForSessionAtClaudeUserConfigPath = (filePath) => resolveForSessionWithUserScope(claudeFiles.readUserFile(filePath));
22435
+ return {
22436
+ list,
22437
+ save,
22438
+ remove,
22439
+ setSecret,
22440
+ resolveForSession,
22441
+ resolveForSessionAtClaudeConfigDir,
22442
+ resolveForSessionAtClaudeUserConfigPath
22248
22443
  };
22249
22444
  });
22250
- const layer$68 = Layer.effect(McpRegistry, make$78);
22445
+ const layer$68 = Layer.effect(McpRegistry, make$79);
22251
22446
  //#endregion
22252
22447
  //#region src/sync/skillDirectory.ts
22253
22448
  /**
@@ -22626,7 +22821,7 @@ const formatHubLink = (input) => encodeStoredHubLink({
22626
22821
  shareMode: input.shareMode
22627
22822
  });
22628
22823
  const fromEnvironment = (environment) => validateHubLink(environment.P4CODE_HUB_URL ?? "", environment.P4CODE_HUB_TOKEN ?? "");
22629
- const make$77 = Effect.fn("HubLink.make")(function* (environment) {
22824
+ const make$78 = Effect.fn("HubLink.make")(function* (environment) {
22630
22825
  const secrets = yield* ServerSecretStore;
22631
22826
  const env = environment ?? process.env;
22632
22827
  const fromEnv = fromEnvironment(env);
@@ -22692,7 +22887,7 @@ const make$77 = Effect.fn("HubLink.make")(function* (environment) {
22692
22887
  })
22693
22888
  };
22694
22889
  });
22695
- const layer$67 = Layer.effect(HubLink, make$77());
22890
+ const layer$67 = Layer.effect(HubLink, make$78());
22696
22891
  //#endregion
22697
22892
  //#region src/sync/HubAssetClient.ts
22698
22893
  /**
@@ -22725,7 +22920,7 @@ const decodeAssetListPage = Schema$1.decodeUnknownEffect(AssetListPage);
22725
22920
  const decodeConflictBody$1 = Schema$1.decodeUnknownEffect(ConflictBody$1);
22726
22921
  const decodeAsset = Schema$1.decodeUnknownEffect(AgentAsset);
22727
22922
  var HubAssetClient = class extends Context.Service()("@p4code/cli/sync/HubAssetClient") {};
22728
- const make$76 = Effect.gen(function* () {
22923
+ const make$77 = Effect.gen(function* () {
22729
22924
  const http = yield* HttpClient.HttpClient;
22730
22925
  const link = yield* HubLink;
22731
22926
  const requireSettings = Effect.gen(function* () {
@@ -22807,7 +23002,7 @@ const make$76 = Effect.gen(function* () {
22807
23002
  remove
22808
23003
  };
22809
23004
  });
22810
- const layer$66 = Layer.effect(HubAssetClient, make$76);
23005
+ const layer$66 = Layer.effect(HubAssetClient, make$77);
22811
23006
  //#endregion
22812
23007
  //#region src/sync/mcpRegistrationFiles.ts
22813
23008
  /**
@@ -23413,7 +23608,7 @@ const EMPTY_REPORT = {
23413
23608
  unavailable: null
23414
23609
  };
23415
23610
  var AssetSync = class extends Context.Service()("@p4code/cli/sync/AssetSync") {};
23416
- const make$75 = Effect.gen(function* () {
23611
+ const make$76 = Effect.gen(function* () {
23417
23612
  const client = yield* HubAssetClient;
23418
23613
  const link = yield* HubLink;
23419
23614
  const settingsStore = yield* ServerSettingsService;
@@ -24123,7 +24318,7 @@ const make$75 = Effect.gen(function* () {
24123
24318
  removeLocal
24124
24319
  };
24125
24320
  });
24126
- const layer$65 = Layer.effect(AssetSync, make$75);
24321
+ const layer$65 = Layer.effect(AssetSync, make$76);
24127
24322
  //#endregion
24128
24323
  //#region src/provider/CompressPrompts.ts
24129
24324
  /**
@@ -25571,6 +25766,306 @@ function requireThreadAbsent(input) {
25571
25766
  return Effect.fail(invariantError(input.command.type, `Thread '${input.threadId}' already exists and cannot be created twice.`));
25572
25767
  }
25573
25768
  //#endregion
25769
+ //#region src/attachmentPaths.ts
25770
+ function normalizeAttachmentRelativePath(rawRelativePath) {
25771
+ const normalized = NodePath.normalize(rawRelativePath).replace(/^[/\\]+/, "");
25772
+ if (normalized.length === 0 || normalized.startsWith("..") || normalized.includes("\0")) return null;
25773
+ return normalized.replace(/\\/g, "/");
25774
+ }
25775
+ function resolveAttachmentRelativePath(input) {
25776
+ const normalizedRelativePath = normalizeAttachmentRelativePath(input.relativePath);
25777
+ if (!normalizedRelativePath) return null;
25778
+ const attachmentsRoot = NodePath.resolve(input.attachmentsDir);
25779
+ const filePath = NodePath.resolve(NodePath.join(attachmentsRoot, normalizedRelativePath));
25780
+ if (!filePath.startsWith(`${attachmentsRoot}${NodePath.sep}`)) return null;
25781
+ return filePath;
25782
+ }
25783
+ //#endregion
25784
+ //#region src/imageMime.ts
25785
+ const IMAGE_EXTENSION_BY_MIME_TYPE = {
25786
+ "image/avif": ".avif",
25787
+ "image/bmp": ".bmp",
25788
+ "image/gif": ".gif",
25789
+ "image/heic": ".heic",
25790
+ "image/heif": ".heif",
25791
+ "image/jpeg": ".jpg",
25792
+ "image/jpg": ".jpg",
25793
+ "image/png": ".png",
25794
+ "image/svg+xml": ".svg",
25795
+ "image/tiff": ".tiff",
25796
+ "image/webp": ".webp"
25797
+ };
25798
+ const SAFE_IMAGE_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
25799
+ ".avif",
25800
+ ".bmp",
25801
+ ".gif",
25802
+ ".heic",
25803
+ ".heif",
25804
+ ".ico",
25805
+ ".jpeg",
25806
+ ".jpg",
25807
+ ".png",
25808
+ ".svg",
25809
+ ".tiff",
25810
+ ".webp"
25811
+ ]);
25812
+ function isBase64Char(code) {
25813
+ return code >= 97 && code <= 122 || code >= 65 && code <= 90 || code >= 48 && code <= 57 || code === 43 || code === 47 || code === 61;
25814
+ }
25815
+ function isBase64Whitespace(code) {
25816
+ return code === 13 || code === 10 || code === 32;
25817
+ }
25818
+ function parseBase64DataUrl(dataUrl) {
25819
+ const trimmed = dataUrl.trim();
25820
+ if (trimmed.slice(0, 5).toLowerCase() !== "data:") return null;
25821
+ const commaIndex = trimmed.indexOf(",");
25822
+ if (commaIndex === -1) return null;
25823
+ const header = trimmed.slice(5, commaIndex);
25824
+ if (header.length === 0) return null;
25825
+ const headerParts = [];
25826
+ for (const part of header.split(";")) {
25827
+ const partTrimmed = part.trim();
25828
+ if (partTrimmed.length > 0) headerParts.push(partTrimmed);
25829
+ }
25830
+ if (headerParts.length < 2) return null;
25831
+ if (headerParts.at(-1)?.toLowerCase() !== "base64") return null;
25832
+ const mimeType = headerParts[0]?.toLowerCase();
25833
+ if (!mimeType) return null;
25834
+ const payload = trimmed.slice(commaIndex + 1);
25835
+ const runs = [];
25836
+ let runStart = -1;
25837
+ for (let index = 0; index < payload.length; index += 1) {
25838
+ const code = payload.charCodeAt(index);
25839
+ if (isBase64Char(code)) {
25840
+ if (runStart === -1) runStart = index;
25841
+ continue;
25842
+ }
25843
+ if (!isBase64Whitespace(code)) return null;
25844
+ if (runStart !== -1) {
25845
+ runs.push(payload.slice(runStart, index));
25846
+ runStart = -1;
25847
+ }
25848
+ }
25849
+ if (runStart !== -1) runs.push(payload.slice(runStart));
25850
+ const base64 = runs.length === 1 ? runs[0] : runs.join("");
25851
+ if (base64.length === 0 || base64.length % 4 !== 0) return null;
25852
+ const firstPad = base64.indexOf("=");
25853
+ if (firstPad !== -1) {
25854
+ if (base64.length - firstPad > 2) return null;
25855
+ for (let index = firstPad; index < base64.length; index += 1) if (base64.charCodeAt(index) !== 61) return null;
25856
+ }
25857
+ return {
25858
+ mimeType,
25859
+ base64
25860
+ };
25861
+ }
25862
+ function inferImageExtension(input) {
25863
+ const key = input.mimeType.toLowerCase();
25864
+ const fromMime = Object.hasOwn(IMAGE_EXTENSION_BY_MIME_TYPE, key) ? IMAGE_EXTENSION_BY_MIME_TYPE[key] : void 0;
25865
+ if (fromMime) return fromMime;
25866
+ const fromMimeExtension = Mime.getExtension(input.mimeType);
25867
+ if (fromMimeExtension && SAFE_IMAGE_FILE_EXTENSIONS.has(fromMimeExtension)) return fromMimeExtension;
25868
+ const fileName = input.fileName?.trim() ?? "";
25869
+ const extensionMatch = /\.([a-z0-9]{1,8})$/i.exec(fileName);
25870
+ const fileNameExtension = extensionMatch ? `.${extensionMatch[1].toLowerCase()}` : "";
25871
+ if (SAFE_IMAGE_FILE_EXTENSIONS.has(fileNameExtension)) return fileNameExtension;
25872
+ return ".bin";
25873
+ }
25874
+ //#endregion
25875
+ //#region src/attachmentStore.ts
25876
+ const ATTACHMENT_FILENAME_EXTENSIONS = [
25877
+ ...SAFE_IMAGE_FILE_EXTENSIONS,
25878
+ ".pdf",
25879
+ ".bin"
25880
+ ];
25881
+ const ATTACHMENT_ID_THREAD_SEGMENT_MAX_CHARS = 80;
25882
+ const ATTACHMENT_ID_PATTERN = new RegExp(`^([a-z0-9_]+(?:-[a-z0-9_]+)*)-([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$`, "i");
25883
+ function toSafeThreadAttachmentSegment(threadId) {
25884
+ const segment = threadId.trim().toLowerCase().replace(/[^a-z0-9_-]+/gi, "-").replace(/-+/g, "-").replace(/^[-_]+|[-_]+$/g, "").slice(0, ATTACHMENT_ID_THREAD_SEGMENT_MAX_CHARS).replace(/[-_]+$/g, "");
25885
+ if (segment.length === 0) return null;
25886
+ return segment;
25887
+ }
25888
+ function createAttachmentId(threadId) {
25889
+ const threadSegment = toSafeThreadAttachmentSegment(threadId);
25890
+ if (!threadSegment) return null;
25891
+ return `${threadSegment}-${NodeCrypto.randomUUID()}`;
25892
+ }
25893
+ function parseThreadSegmentFromAttachmentId(attachmentId) {
25894
+ const normalizedId = normalizeAttachmentRelativePath(attachmentId);
25895
+ if (!normalizedId || normalizedId.includes("/") || normalizedId.includes(".")) return null;
25896
+ const match = normalizedId.match(ATTACHMENT_ID_PATTERN);
25897
+ if (!match) return null;
25898
+ return match[1]?.toLowerCase() ?? null;
25899
+ }
25900
+ function attachmentRelativePath(attachment) {
25901
+ switch (attachment.type) {
25902
+ case "image": {
25903
+ const extension = inferImageExtension({
25904
+ mimeType: attachment.mimeType,
25905
+ fileName: attachment.name
25906
+ });
25907
+ return `${attachment.id}${extension}`;
25908
+ }
25909
+ case "document": return `${attachment.id}.pdf`;
25910
+ }
25911
+ }
25912
+ function resolveAttachmentPath(input) {
25913
+ return resolveAttachmentRelativePath({
25914
+ attachmentsDir: input.attachmentsDir,
25915
+ relativePath: attachmentRelativePath(input.attachment)
25916
+ });
25917
+ }
25918
+ function resolveAttachmentPathById(input) {
25919
+ const normalizedId = normalizeAttachmentRelativePath(input.attachmentId);
25920
+ if (!normalizedId || normalizedId.includes("/") || normalizedId.includes(".")) return null;
25921
+ for (const extension of ATTACHMENT_FILENAME_EXTENSIONS) {
25922
+ const maybePath = resolveAttachmentRelativePath({
25923
+ attachmentsDir: input.attachmentsDir,
25924
+ relativePath: `${normalizedId}${extension}`
25925
+ });
25926
+ if (maybePath && NodeFS.existsSync(maybePath)) return maybePath;
25927
+ }
25928
+ return null;
25929
+ }
25930
+ function parseAttachmentIdFromRelativePath(relativePath) {
25931
+ const normalized = normalizeAttachmentRelativePath(relativePath);
25932
+ if (!normalized || normalized.includes("/")) return null;
25933
+ const extensionIndex = normalized.lastIndexOf(".");
25934
+ if (extensionIndex <= 0) return null;
25935
+ const id = normalized.slice(0, extensionIndex);
25936
+ return id.length > 0 && !id.includes(".") ? id : null;
25937
+ }
25938
+ //#endregion
25939
+ //#region src/orchestration/threadFork.ts
25940
+ /** Providers whose adapter can open a new session on top of a saved one. */
25941
+ const FORKABLE_PROVIDERS = /* @__PURE__ */ new Set(["claudeAgent"]);
25942
+ /**
25943
+ * Message ids are unique across threads, so a copied message needs an id
25944
+ * that ties it to the fork while staying derivable from the original.
25945
+ */
25946
+ function forkedMessageId(threadId, messageId) {
25947
+ return `${threadId}:fork:${messageId}`;
25948
+ }
25949
+ /**
25950
+ * Attachment ids must look like `<thread-segment>-<uuid>` and the file lives
25951
+ * beside the id, so a copy gets a fresh id under the fork's segment. The uuid
25952
+ * is derived from the source id: the pure read-model projector and the SQLite
25953
+ * projection must agree on it without sharing state.
25954
+ */
25955
+ function forkedAttachmentId(threadId, attachmentId) {
25956
+ const segment = toSafeThreadAttachmentSegment(threadId);
25957
+ if (!segment) return null;
25958
+ const digest = NodeCrypto.createHash("sha256").update(`${threadId} ${attachmentId}`).digest("hex");
25959
+ return `${segment}-${[
25960
+ digest.slice(0, 8),
25961
+ digest.slice(8, 12),
25962
+ digest.slice(12, 16),
25963
+ digest.slice(16, 20),
25964
+ digest.slice(20, 32)
25965
+ ].join("-")}`;
25966
+ }
25967
+ function copyForkedAttachments(threadId, attachments) {
25968
+ if (attachments === void 0) return void 0;
25969
+ const copies = [];
25970
+ for (const attachment of attachments) {
25971
+ const id = forkedAttachmentId(threadId, attachment.id);
25972
+ if (id === null) continue;
25973
+ copies.push({
25974
+ ...attachment,
25975
+ id
25976
+ });
25977
+ }
25978
+ return copies;
25979
+ }
25980
+ /**
25981
+ * Copies a source thread's conversation for the fork read model. Turn ids
25982
+ * belong to the source thread's turns, so copies carry none; attachments are
25983
+ * re-keyed to the fork so their files can be copied beside them; a streaming
25984
+ * message is frozen as-is.
25985
+ */
25986
+ function copyForkedMessages(threadId, messages) {
25987
+ return messages.map((message) => {
25988
+ const attachments = copyForkedAttachments(threadId, message.attachments);
25989
+ return {
25990
+ id: forkedMessageId(threadId, message.id),
25991
+ role: message.role,
25992
+ text: message.text,
25993
+ ...attachments !== void 0 ? { attachments } : {},
25994
+ turnId: null,
25995
+ streaming: false,
25996
+ createdAt: message.createdAt,
25997
+ updatedAt: message.updatedAt
25998
+ };
25999
+ });
26000
+ }
26001
+ /** Same copy as {@link copyForkedMessages}, for the SQLite message projection. */
26002
+ function copyForkedProjectionMessages(threadId, rows) {
26003
+ return rows.map((row) => {
26004
+ const attachments = copyForkedAttachments(threadId, row.attachments);
26005
+ return {
26006
+ messageId: forkedMessageId(threadId, row.messageId),
26007
+ threadId,
26008
+ turnId: null,
26009
+ role: row.role,
26010
+ text: row.text,
26011
+ ...attachments !== void 0 ? { attachments } : {},
26012
+ isStreaming: false,
26013
+ createdAt: row.createdAt,
26014
+ updatedAt: row.updatedAt
26015
+ };
26016
+ });
26017
+ }
26018
+ /** File copies that make the re-keyed attachment references resolve. */
26019
+ function collectForkedAttachmentCopies(threadId, rows) {
26020
+ const copies = [];
26021
+ for (const row of rows) for (const attachment of row.attachments ?? []) {
26022
+ const id = forkedAttachmentId(threadId, attachment.id);
26023
+ if (id === null) continue;
26024
+ copies.push({
26025
+ fromRelativePath: attachmentRelativePath(attachment),
26026
+ toRelativePath: attachmentRelativePath({
26027
+ ...attachment,
26028
+ id
26029
+ })
26030
+ });
26031
+ }
26032
+ return copies;
26033
+ }
26034
+ function isRecord$6(value) {
26035
+ return value !== null && typeof value === "object" && !Array.isArray(value);
26036
+ }
26037
+ /**
26038
+ * Provider binding for a fork, or the reason there is none. The resume cursor
26039
+ * is re-keyed to the fork and flagged so the adapter opens a new provider
26040
+ * session from the saved one instead of continuing the source's session.
26041
+ */
26042
+ function buildForkedProviderBinding(threadId, source) {
26043
+ if (source === void 0) return { rejection: "no-binding" };
26044
+ if (!FORKABLE_PROVIDERS.has(source.provider)) return { rejection: "provider-cannot-fork" };
26045
+ if (!isRecord$6(source.resumeCursor) || typeof source.resumeCursor.resume !== "string") return { rejection: "no-resume-cursor" };
26046
+ return { binding: {
26047
+ threadId,
26048
+ provider: source.provider,
26049
+ ...source.providerInstanceId ? { providerInstanceId: source.providerInstanceId } : {},
26050
+ ...source.adapterKey ? { adapterKey: source.adapterKey } : {},
26051
+ ...source.runtimeMode ? { runtimeMode: source.runtimeMode } : {},
26052
+ status: "stopped",
26053
+ resumeCursor: {
26054
+ ...source.resumeCursor,
26055
+ threadId,
26056
+ forkSession: true
26057
+ },
26058
+ runtimePayload: source.runtimePayload ?? null
26059
+ } };
26060
+ }
26061
+ function describeThreadForkRejection(rejection) {
26062
+ switch (rejection) {
26063
+ case "no-binding": return "This thread has no provider session to fork yet. Send a message first.";
26064
+ case "provider-cannot-fork": return "This thread's provider cannot fork a session. Fork is available for Claude threads.";
26065
+ case "no-resume-cursor": return "This thread's provider session cannot be resumed, so it cannot be forked.";
26066
+ }
26067
+ }
26068
+ //#endregion
25574
26069
  //#region src/orchestration/Schemas.ts
25575
26070
  const ProjectCreatedPayload = ProjectCreatedPayload$1;
25576
26071
  const ProjectMetaUpdatedPayload = ProjectMetaUpdatedPayload$1;
@@ -25593,6 +26088,9 @@ const ThreadSnoozedPayload = ThreadSnoozedPayload$1;
25593
26088
  const ThreadUnsnoozedPayload = ThreadUnsnoozedPayload$1;
25594
26089
  const MessageSentPayloadSchema = ThreadMessageSentPayload;
25595
26090
  const ThreadProposedPlanUpsertedPayload = ThreadProposedPlanUpsertedPayload$1;
26091
+ const ThreadScheduledTaskCreatedPayload = ThreadScheduledTaskCreatedPayload$1;
26092
+ const ThreadScheduledTaskCancelledPayload = ThreadScheduledTaskCancelledPayload$1;
26093
+ const ThreadScheduledTaskFiredPayload = ThreadScheduledTaskFiredPayload$1;
25596
26094
  const ThreadSessionSetPayload = ThreadSessionSetPayload$1;
25597
26095
  const ThreadTurnDiffCompletedPayload = ThreadTurnDiffCompletedPayload$1;
25598
26096
  const ThreadRevertedPayload = ThreadRevertedPayload$1;
@@ -25775,6 +26273,7 @@ function projectEvent(model, event) {
25775
26273
  })));
25776
26274
  case "thread.created": return Effect.gen(function* () {
25777
26275
  const payload = yield* decodeForEvent(ThreadCreatedPayload, event.payload, event.type, "payload");
26276
+ const forkSource = payload.forkedFromThreadId === void 0 ? void 0 : nextBase.threads.find((entry) => entry.id === payload.forkedFromThreadId);
25778
26277
  const thread = yield* decodeForEvent(OrchestrationThread, {
25779
26278
  id: payload.threadId,
25780
26279
  projectId: payload.projectId,
@@ -25795,7 +26294,7 @@ function projectEvent(model, event) {
25795
26294
  snoozedUntil: null,
25796
26295
  snoozedAt: null,
25797
26296
  deletedAt: null,
25798
- messages: [],
26297
+ messages: forkSource ? copyForkedMessages(payload.threadId, forkSource.messages) : [],
25799
26298
  activities: [],
25800
26299
  checkpoints: [],
25801
26300
  session: null
@@ -25977,6 +26476,42 @@ function projectEvent(model, event) {
25977
26476
  })
25978
26477
  };
25979
26478
  });
26479
+ case "thread.scheduled-task.created": return Effect.gen(function* () {
26480
+ const payload = yield* decodeForEvent(ThreadScheduledTaskCreatedPayload, event.payload, event.type, "payload");
26481
+ const thread = nextBase.threads.find((entry) => entry.id === payload.threadId);
26482
+ if (!thread) return nextBase;
26483
+ return {
26484
+ ...nextBase,
26485
+ threads: updateThread(nextBase.threads, payload.threadId, {
26486
+ scheduledTasks: [...(thread.scheduledTasks ?? []).filter((entry) => entry.id !== payload.task.id), payload.task],
26487
+ updatedAt: event.occurredAt
26488
+ })
26489
+ };
26490
+ });
26491
+ case "thread.scheduled-task.cancelled":
26492
+ case "thread.scheduled-task.fired": return Effect.gen(function* () {
26493
+ const payload = event.type === "thread.scheduled-task.cancelled" ? yield* decodeForEvent(ThreadScheduledTaskCancelledPayload, event.payload, event.type, "payload") : yield* decodeForEvent(ThreadScheduledTaskFiredPayload, event.payload, event.type, "payload");
26494
+ const thread = nextBase.threads.find((entry) => entry.id === payload.threadId);
26495
+ if (!thread) return nextBase;
26496
+ return {
26497
+ ...nextBase,
26498
+ threads: updateThread(nextBase.threads, payload.threadId, {
26499
+ scheduledTasks: (thread.scheduledTasks ?? []).map((task) => task.id !== payload.taskId ? task : "cancelledAt" in payload ? {
26500
+ ...task,
26501
+ status: "cancelled",
26502
+ cancelledAt: payload.cancelledAt,
26503
+ updatedAt: event.occurredAt
26504
+ } : {
26505
+ ...task,
26506
+ status: payload.failure === null ? "fired" : "failed",
26507
+ firedAt: payload.firedAt,
26508
+ failure: payload.failure,
26509
+ updatedAt: event.occurredAt
26510
+ }),
26511
+ updatedAt: event.occurredAt
26512
+ })
26513
+ };
26514
+ });
25980
26515
  case "thread.proposed-plan-upserted": return Effect.gen(function* () {
25981
26516
  const payload = yield* decodeForEvent(ThreadProposedPlanUpsertedPayload, event.payload, event.type, "payload");
25982
26517
  const thread = nextBase.threads.find((entry) => entry.id === payload.threadId);
@@ -26297,6 +26832,113 @@ const decideOrchestrationCommand = Effect.fn("decideOrchestrationCommand")(funct
26297
26832
  updatedAt: command.createdAt
26298
26833
  }
26299
26834
  };
26835
+ case "thread.fork": {
26836
+ const source = yield* requireThread({
26837
+ readModel,
26838
+ command,
26839
+ threadId: command.sourceThreadId
26840
+ });
26841
+ yield* requireThreadAbsent({
26842
+ readModel,
26843
+ command,
26844
+ threadId: command.threadId
26845
+ });
26846
+ return {
26847
+ ...yield* withEventBase({
26848
+ aggregateKind: "thread",
26849
+ aggregateId: command.threadId,
26850
+ occurredAt: command.createdAt,
26851
+ commandId: command.commandId
26852
+ }),
26853
+ type: "thread.created",
26854
+ payload: {
26855
+ threadId: command.threadId,
26856
+ projectId: source.projectId,
26857
+ title: command.title ?? `${source.title} (fork)`,
26858
+ modelSelection: source.modelSelection,
26859
+ runtimeMode: source.runtimeMode,
26860
+ interactionMode: source.interactionMode,
26861
+ compressMode: source.compressMode,
26862
+ unpromptedSubagents: source.unpromptedSubagents,
26863
+ branch: source.branch,
26864
+ worktreePath: source.worktreePath,
26865
+ forkedFromThreadId: source.id,
26866
+ createdAt: command.createdAt,
26867
+ updatedAt: command.createdAt
26868
+ }
26869
+ };
26870
+ }
26871
+ case "thread.scheduled-task.create":
26872
+ if (((yield* requireThread({
26873
+ readModel,
26874
+ command,
26875
+ threadId: command.threadId
26876
+ })).scheduledTasks ?? []).some((task) => task.id === command.taskId)) return yield* new OrchestrationCommandInvariantError({
26877
+ commandType: command.type,
26878
+ detail: `Scheduled task '${command.taskId}' already exists on thread '${command.threadId}'.`
26879
+ });
26880
+ return {
26881
+ ...yield* withEventBase({
26882
+ aggregateKind: "thread",
26883
+ aggregateId: command.threadId,
26884
+ occurredAt: command.createdAt,
26885
+ commandId: command.commandId
26886
+ }),
26887
+ type: "thread.scheduled-task.created",
26888
+ payload: {
26889
+ threadId: command.threadId,
26890
+ task: {
26891
+ id: command.taskId,
26892
+ prompt: command.prompt,
26893
+ runAt: command.runAt,
26894
+ status: "pending",
26895
+ createdAt: command.createdAt,
26896
+ updatedAt: command.createdAt,
26897
+ firedAt: null,
26898
+ cancelledAt: null,
26899
+ failure: null
26900
+ }
26901
+ }
26902
+ };
26903
+ case "thread.scheduled-task.cancel":
26904
+ case "thread.scheduled-task.fire": {
26905
+ const task = ((yield* requireThread({
26906
+ readModel,
26907
+ command,
26908
+ threadId: command.threadId
26909
+ })).scheduledTasks ?? []).find((entry) => entry.id === command.taskId);
26910
+ const cancellable = task?.status === "pending" || task?.status === "failed";
26911
+ if (task === void 0 || (command.type === "thread.scheduled-task.fire" ? task.status !== "pending" : !cancellable)) return yield* new OrchestrationCommandInvariantError({
26912
+ commandType: command.type,
26913
+ detail: `Scheduled task '${command.taskId}' is not ${command.type === "thread.scheduled-task.fire" ? "pending" : "pending or failed"} on thread '${command.threadId}'.`
26914
+ });
26915
+ const occurredAt = command.type === "thread.scheduled-task.cancel" ? command.cancelledAt : command.firedAt;
26916
+ const base = yield* withEventBase({
26917
+ aggregateKind: "thread",
26918
+ aggregateId: command.threadId,
26919
+ occurredAt,
26920
+ commandId: command.commandId
26921
+ });
26922
+ if (command.type === "thread.scheduled-task.cancel") return {
26923
+ ...base,
26924
+ type: "thread.scheduled-task.cancelled",
26925
+ payload: {
26926
+ threadId: command.threadId,
26927
+ taskId: command.taskId,
26928
+ cancelledAt: command.cancelledAt
26929
+ }
26930
+ };
26931
+ return {
26932
+ ...base,
26933
+ type: "thread.scheduled-task.fired",
26934
+ payload: {
26935
+ threadId: command.threadId,
26936
+ taskId: command.taskId,
26937
+ firedAt: command.firedAt,
26938
+ failure: command.failure ?? null
26939
+ }
26940
+ };
26941
+ }
26300
26942
  case "thread.delete": {
26301
26943
  yield* requireThread({
26302
26944
  readModel,
@@ -27864,6 +28506,23 @@ const ListProjectionThreadProposedPlansInput = Schema$1.Struct({ threadId: Threa
27864
28506
  const DeleteProjectionThreadProposedPlansInput = Schema$1.Struct({ threadId: ThreadId });
27865
28507
  var ProjectionThreadProposedPlanRepository = class extends Context.Service()("@p4code/cli/persistence/Services/ProjectionThreadProposedPlans/ProjectionThreadProposedPlanRepository") {};
27866
28508
  //#endregion
28509
+ //#region src/persistence/Services/ProjectionThreadScheduledTasks.ts
28510
+ const ProjectionThreadScheduledTask = Schema$1.Struct({
28511
+ taskId: OrchestrationScheduledTaskId,
28512
+ threadId: ThreadId,
28513
+ prompt: TrimmedNonEmptyString,
28514
+ runAt: IsoDateTime,
28515
+ status: OrchestrationScheduledTaskStatus,
28516
+ createdAt: IsoDateTime,
28517
+ updatedAt: IsoDateTime,
28518
+ firedAt: Schema$1.NullOr(IsoDateTime),
28519
+ cancelledAt: Schema$1.NullOr(IsoDateTime),
28520
+ failure: Schema$1.NullOr(Schema$1.String)
28521
+ });
28522
+ const GetProjectionThreadScheduledTaskInput = Schema$1.Struct({ taskId: OrchestrationScheduledTaskId });
28523
+ const ListProjectionThreadScheduledTasksInput = Schema$1.Struct({ threadId: ThreadId });
28524
+ var ProjectionThreadScheduledTaskRepository = class extends Context.Service()("@p4code/cli/persistence/Services/ProjectionThreadScheduledTasks/ProjectionThreadScheduledTaskRepository") {};
28525
+ //#endregion
27867
28526
  //#region src/persistence/Services/ProjectionThreadSessions.ts
27868
28527
  /**
27869
28528
  * ProjectionThreadSessionRepository - Repository interface for thread sessions.
@@ -28559,6 +29218,91 @@ const makeProjectionThreadProposedPlanRepository = Effect.gen(function* () {
28559
29218
  });
28560
29219
  const ProjectionThreadProposedPlanRepositoryLive = Layer.effect(ProjectionThreadProposedPlanRepository, makeProjectionThreadProposedPlanRepository);
28561
29220
  //#endregion
29221
+ //#region src/persistence/Layers/ProjectionThreadScheduledTasks.ts
29222
+ const makeProjectionThreadScheduledTaskRepository = Effect.gen(function* () {
29223
+ const sql = yield* SqlClient.SqlClient;
29224
+ const upsertRow = SqlSchema.void({
29225
+ Request: ProjectionThreadScheduledTask,
29226
+ execute: (row) => sql`
29227
+ INSERT INTO projection_thread_scheduled_tasks (
29228
+ task_id,
29229
+ thread_id,
29230
+ prompt,
29231
+ run_at,
29232
+ status,
29233
+ created_at,
29234
+ updated_at,
29235
+ fired_at,
29236
+ cancelled_at,
29237
+ failure
29238
+ )
29239
+ VALUES (
29240
+ ${row.taskId},
29241
+ ${row.threadId},
29242
+ ${row.prompt},
29243
+ ${row.runAt},
29244
+ ${row.status},
29245
+ ${row.createdAt},
29246
+ ${row.updatedAt},
29247
+ ${row.firedAt},
29248
+ ${row.cancelledAt},
29249
+ ${row.failure}
29250
+ )
29251
+ ON CONFLICT (task_id)
29252
+ DO UPDATE SET
29253
+ thread_id = excluded.thread_id,
29254
+ prompt = excluded.prompt,
29255
+ run_at = excluded.run_at,
29256
+ status = excluded.status,
29257
+ created_at = excluded.created_at,
29258
+ updated_at = excluded.updated_at,
29259
+ fired_at = excluded.fired_at,
29260
+ cancelled_at = excluded.cancelled_at,
29261
+ failure = excluded.failure
29262
+ `
29263
+ });
29264
+ const selectColumns = sql`
29265
+ task_id AS "taskId",
29266
+ thread_id AS "threadId",
29267
+ prompt,
29268
+ run_at AS "runAt",
29269
+ status,
29270
+ created_at AS "createdAt",
29271
+ updated_at AS "updatedAt",
29272
+ fired_at AS "firedAt",
29273
+ cancelled_at AS "cancelledAt",
29274
+ failure
29275
+ `;
29276
+ const getRow = SqlSchema.findOneOption({
29277
+ Request: GetProjectionThreadScheduledTaskInput,
29278
+ Result: ProjectionThreadScheduledTask,
29279
+ execute: ({ taskId }) => sql`
29280
+ SELECT ${selectColumns}
29281
+ FROM projection_thread_scheduled_tasks
29282
+ WHERE task_id = ${taskId}
29283
+ `
29284
+ });
29285
+ const listRows = SqlSchema.findAll({
29286
+ Request: ListProjectionThreadScheduledTasksInput,
29287
+ Result: ProjectionThreadScheduledTask,
29288
+ execute: ({ threadId }) => sql`
29289
+ SELECT ${selectColumns}
29290
+ FROM projection_thread_scheduled_tasks
29291
+ WHERE thread_id = ${threadId}
29292
+ ORDER BY run_at ASC, task_id ASC
29293
+ `
29294
+ });
29295
+ const upsert = (row) => upsertRow(row).pipe(Effect.mapError(toPersistenceSqlError("ProjectionThreadScheduledTaskRepository.upsert:query")));
29296
+ const getByTaskId = (input) => getRow(input).pipe(Effect.map(Option.getOrNull), Effect.mapError(toPersistenceSqlError("ProjectionThreadScheduledTaskRepository.getByTaskId:query")));
29297
+ const listByThreadId = (input) => listRows(input).pipe(Effect.mapError(toPersistenceSqlError("ProjectionThreadScheduledTaskRepository.listByThreadId:query")));
29298
+ return {
29299
+ upsert,
29300
+ getByTaskId,
29301
+ listByThreadId
29302
+ };
29303
+ });
29304
+ const ProjectionThreadScheduledTaskRepositoryLive = Layer.effect(ProjectionThreadScheduledTaskRepository, makeProjectionThreadScheduledTaskRepository);
29305
+ //#endregion
28562
29306
  //#region src/persistence/Layers/ProjectionThreadSessions.ts
28563
29307
  const makeProjectionThreadSessionRepository = Effect.gen(function* () {
28564
29308
  const sql = yield* SqlClient.SqlClient;
@@ -29054,182 +29798,13 @@ const makeProjectionThreadRepository = Effect.gen(function* () {
29054
29798
  });
29055
29799
  const ProjectionThreadRepositoryLive = Layer.effect(ProjectionThreadRepository, makeProjectionThreadRepository);
29056
29800
  //#endregion
29057
- //#region src/attachmentPaths.ts
29058
- function normalizeAttachmentRelativePath(rawRelativePath) {
29059
- const normalized = NodePath.normalize(rawRelativePath).replace(/^[/\\]+/, "");
29060
- if (normalized.length === 0 || normalized.startsWith("..") || normalized.includes("\0")) return null;
29061
- return normalized.replace(/\\/g, "/");
29062
- }
29063
- function resolveAttachmentRelativePath(input) {
29064
- const normalizedRelativePath = normalizeAttachmentRelativePath(input.relativePath);
29065
- if (!normalizedRelativePath) return null;
29066
- const attachmentsRoot = NodePath.resolve(input.attachmentsDir);
29067
- const filePath = NodePath.resolve(NodePath.join(attachmentsRoot, normalizedRelativePath));
29068
- if (!filePath.startsWith(`${attachmentsRoot}${NodePath.sep}`)) return null;
29069
- return filePath;
29070
- }
29071
- //#endregion
29072
- //#region src/imageMime.ts
29073
- const IMAGE_EXTENSION_BY_MIME_TYPE = {
29074
- "image/avif": ".avif",
29075
- "image/bmp": ".bmp",
29076
- "image/gif": ".gif",
29077
- "image/heic": ".heic",
29078
- "image/heif": ".heif",
29079
- "image/jpeg": ".jpg",
29080
- "image/jpg": ".jpg",
29081
- "image/png": ".png",
29082
- "image/svg+xml": ".svg",
29083
- "image/tiff": ".tiff",
29084
- "image/webp": ".webp"
29085
- };
29086
- const SAFE_IMAGE_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
29087
- ".avif",
29088
- ".bmp",
29089
- ".gif",
29090
- ".heic",
29091
- ".heif",
29092
- ".ico",
29093
- ".jpeg",
29094
- ".jpg",
29095
- ".png",
29096
- ".svg",
29097
- ".tiff",
29098
- ".webp"
29099
- ]);
29100
- function isBase64Char(code) {
29101
- return code >= 97 && code <= 122 || code >= 65 && code <= 90 || code >= 48 && code <= 57 || code === 43 || code === 47 || code === 61;
29102
- }
29103
- function isBase64Whitespace(code) {
29104
- return code === 13 || code === 10 || code === 32;
29105
- }
29106
- function parseBase64DataUrl(dataUrl) {
29107
- const trimmed = dataUrl.trim();
29108
- if (trimmed.slice(0, 5).toLowerCase() !== "data:") return null;
29109
- const commaIndex = trimmed.indexOf(",");
29110
- if (commaIndex === -1) return null;
29111
- const header = trimmed.slice(5, commaIndex);
29112
- if (header.length === 0) return null;
29113
- const headerParts = [];
29114
- for (const part of header.split(";")) {
29115
- const partTrimmed = part.trim();
29116
- if (partTrimmed.length > 0) headerParts.push(partTrimmed);
29117
- }
29118
- if (headerParts.length < 2) return null;
29119
- if (headerParts.at(-1)?.toLowerCase() !== "base64") return null;
29120
- const mimeType = headerParts[0]?.toLowerCase();
29121
- if (!mimeType) return null;
29122
- const payload = trimmed.slice(commaIndex + 1);
29123
- const runs = [];
29124
- let runStart = -1;
29125
- for (let index = 0; index < payload.length; index += 1) {
29126
- const code = payload.charCodeAt(index);
29127
- if (isBase64Char(code)) {
29128
- if (runStart === -1) runStart = index;
29129
- continue;
29130
- }
29131
- if (!isBase64Whitespace(code)) return null;
29132
- if (runStart !== -1) {
29133
- runs.push(payload.slice(runStart, index));
29134
- runStart = -1;
29135
- }
29136
- }
29137
- if (runStart !== -1) runs.push(payload.slice(runStart));
29138
- const base64 = runs.length === 1 ? runs[0] : runs.join("");
29139
- if (base64.length === 0 || base64.length % 4 !== 0) return null;
29140
- const firstPad = base64.indexOf("=");
29141
- if (firstPad !== -1) {
29142
- if (base64.length - firstPad > 2) return null;
29143
- for (let index = firstPad; index < base64.length; index += 1) if (base64.charCodeAt(index) !== 61) return null;
29144
- }
29145
- return {
29146
- mimeType,
29147
- base64
29148
- };
29149
- }
29150
- function inferImageExtension(input) {
29151
- const key = input.mimeType.toLowerCase();
29152
- const fromMime = Object.hasOwn(IMAGE_EXTENSION_BY_MIME_TYPE, key) ? IMAGE_EXTENSION_BY_MIME_TYPE[key] : void 0;
29153
- if (fromMime) return fromMime;
29154
- const fromMimeExtension = Mime.getExtension(input.mimeType);
29155
- if (fromMimeExtension && SAFE_IMAGE_FILE_EXTENSIONS.has(fromMimeExtension)) return fromMimeExtension;
29156
- const fileName = input.fileName?.trim() ?? "";
29157
- const extensionMatch = /\.([a-z0-9]{1,8})$/i.exec(fileName);
29158
- const fileNameExtension = extensionMatch ? `.${extensionMatch[1].toLowerCase()}` : "";
29159
- if (SAFE_IMAGE_FILE_EXTENSIONS.has(fileNameExtension)) return fileNameExtension;
29160
- return ".bin";
29161
- }
29162
- //#endregion
29163
- //#region src/attachmentStore.ts
29164
- const ATTACHMENT_FILENAME_EXTENSIONS = [
29165
- ...SAFE_IMAGE_FILE_EXTENSIONS,
29166
- ".pdf",
29167
- ".bin"
29168
- ];
29169
- const ATTACHMENT_ID_THREAD_SEGMENT_MAX_CHARS = 80;
29170
- const ATTACHMENT_ID_PATTERN = new RegExp(`^([a-z0-9_]+(?:-[a-z0-9_]+)*)-([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$`, "i");
29171
- function toSafeThreadAttachmentSegment(threadId) {
29172
- const segment = threadId.trim().toLowerCase().replace(/[^a-z0-9_-]+/gi, "-").replace(/-+/g, "-").replace(/^[-_]+|[-_]+$/g, "").slice(0, ATTACHMENT_ID_THREAD_SEGMENT_MAX_CHARS).replace(/[-_]+$/g, "");
29173
- if (segment.length === 0) return null;
29174
- return segment;
29175
- }
29176
- function createAttachmentId(threadId) {
29177
- const threadSegment = toSafeThreadAttachmentSegment(threadId);
29178
- if (!threadSegment) return null;
29179
- return `${threadSegment}-${NodeCrypto.randomUUID()}`;
29180
- }
29181
- function parseThreadSegmentFromAttachmentId(attachmentId) {
29182
- const normalizedId = normalizeAttachmentRelativePath(attachmentId);
29183
- if (!normalizedId || normalizedId.includes("/") || normalizedId.includes(".")) return null;
29184
- const match = normalizedId.match(ATTACHMENT_ID_PATTERN);
29185
- if (!match) return null;
29186
- return match[1]?.toLowerCase() ?? null;
29187
- }
29188
- function attachmentRelativePath(attachment) {
29189
- switch (attachment.type) {
29190
- case "image": {
29191
- const extension = inferImageExtension({
29192
- mimeType: attachment.mimeType,
29193
- fileName: attachment.name
29194
- });
29195
- return `${attachment.id}${extension}`;
29196
- }
29197
- case "document": return `${attachment.id}.pdf`;
29198
- }
29199
- }
29200
- function resolveAttachmentPath(input) {
29201
- return resolveAttachmentRelativePath({
29202
- attachmentsDir: input.attachmentsDir,
29203
- relativePath: attachmentRelativePath(input.attachment)
29204
- });
29205
- }
29206
- function resolveAttachmentPathById(input) {
29207
- const normalizedId = normalizeAttachmentRelativePath(input.attachmentId);
29208
- if (!normalizedId || normalizedId.includes("/") || normalizedId.includes(".")) return null;
29209
- for (const extension of ATTACHMENT_FILENAME_EXTENSIONS) {
29210
- const maybePath = resolveAttachmentRelativePath({
29211
- attachmentsDir: input.attachmentsDir,
29212
- relativePath: `${normalizedId}${extension}`
29213
- });
29214
- if (maybePath && NodeFS.existsSync(maybePath)) return maybePath;
29215
- }
29216
- return null;
29217
- }
29218
- function parseAttachmentIdFromRelativePath(relativePath) {
29219
- const normalized = normalizeAttachmentRelativePath(relativePath);
29220
- if (!normalized || normalized.includes("/")) return null;
29221
- const extensionIndex = normalized.lastIndexOf(".");
29222
- if (extensionIndex <= 0) return null;
29223
- const id = normalized.slice(0, extensionIndex);
29224
- return id.length > 0 && !id.includes(".") ? id : null;
29225
- }
29226
- //#endregion
29227
29801
  //#region src/orchestration/Layers/ProjectionPipeline.ts
29228
29802
  const ORCHESTRATION_PROJECTOR_NAMES = {
29229
29803
  projects: "projection.projects",
29230
29804
  threads: "projection.threads",
29231
29805
  threadMessages: "projection.thread-messages",
29232
29806
  threadProposedPlans: "projection.thread-proposed-plans",
29807
+ threadScheduledTasks: "projection.thread-scheduled-tasks",
29233
29808
  threadActivities: "projection.thread-activities",
29234
29809
  threadSessions: "projection.thread-sessions",
29235
29810
  threadTurns: "projection.thread-turns",
@@ -29448,6 +30023,7 @@ const makeOrchestrationProjectionPipeline = Effect.fn("makeOrchestrationProjecti
29448
30023
  const projectionThreadRepository = yield* ProjectionThreadRepository;
29449
30024
  const projectionThreadMessageRepository = yield* ProjectionThreadMessageRepository;
29450
30025
  const projectionThreadProposedPlanRepository = yield* ProjectionThreadProposedPlanRepository;
30026
+ const projectionThreadScheduledTaskRepository = yield* ProjectionThreadScheduledTaskRepository;
29451
30027
  const projectionThreadActivityRepository = yield* ProjectionThreadActivityRepository;
29452
30028
  const projectionThreadSessionRepository = yield* ProjectionThreadSessionRepository;
29453
30029
  const projectionTurnRepository = yield* ProjectionTurnRepository;
@@ -29455,6 +30031,7 @@ const makeOrchestrationProjectionPipeline = Effect.fn("makeOrchestrationProjecti
29455
30031
  const fileSystem = yield* FileSystem.FileSystem;
29456
30032
  const path = yield* Path.Path;
29457
30033
  const serverConfig = yield* ServerConfig$1;
30034
+ const attachmentsRootDir = serverConfig.attachmentsDir;
29458
30035
  const applyProjectsProjection = Effect.fn("applyProjectsProjection")(function* (event, _attachmentSideEffects) {
29459
30036
  switch (event.type) {
29460
30037
  case "project.created":
@@ -29854,8 +30431,34 @@ const makeOrchestrationProjectionPipeline = Effect.fn("makeOrchestrationProjecti
29854
30431
  default: return;
29855
30432
  }
29856
30433
  });
30434
+ const copyForkedAttachmentFile = Effect.fn("copyForkedAttachmentFile")(function* (copy) {
30435
+ const fromPath = resolveAttachmentRelativePath({
30436
+ attachmentsDir: attachmentsRootDir,
30437
+ relativePath: copy.fromRelativePath
30438
+ });
30439
+ const toPath = resolveAttachmentRelativePath({
30440
+ attachmentsDir: attachmentsRootDir,
30441
+ relativePath: copy.toRelativePath
30442
+ });
30443
+ if (!fromPath || !toPath) return yield* new PersistenceSqlError({
30444
+ operation: "ProjectionPipeline.copyForkedAttachmentFile",
30445
+ detail: `Unsafe attachment path while forking: ${copy.fromRelativePath}`
30446
+ });
30447
+ yield* fileSystem.copyFile(fromPath, toPath).pipe(Effect.catch((error) => error.reason._tag === "NotFound" ? Effect.logWarning("thread fork skipped a missing source attachment", { from: copy.fromRelativePath }) : Effect.fail(new PersistenceSqlError({
30448
+ operation: "ProjectionPipeline.copyForkedAttachmentFile",
30449
+ detail: `Could not copy attachment ${copy.fromRelativePath}: ${error.message}`,
30450
+ cause: error
30451
+ }))));
30452
+ });
29857
30453
  const applyThreadMessagesProjection = Effect.fn("applyThreadMessagesProjection")(function* (event, attachmentSideEffects) {
29858
30454
  switch (event.type) {
30455
+ case "thread.created": {
30456
+ if (event.payload.forkedFromThreadId === void 0) return;
30457
+ const sourceRows = yield* projectionThreadMessageRepository.listByThreadId({ threadId: event.payload.forkedFromThreadId });
30458
+ yield* Effect.forEach(collectForkedAttachmentCopies(event.payload.threadId, sourceRows), copyForkedAttachmentFile, { concurrency: 1 });
30459
+ yield* Effect.forEach(copyForkedProjectionMessages(event.payload.threadId, sourceRows), projectionThreadMessageRepository.upsert, { concurrency: 1 }).pipe(Effect.asVoid);
30460
+ return;
30461
+ }
29859
30462
  case "thread.message-sent": {
29860
30463
  const existingMessage = yield* projectionThreadMessageRepository.getByMessageId({ messageId: event.payload.messageId });
29861
30464
  const previousMessage = Option.getOrUndefined(existingMessage);
@@ -29894,6 +30497,43 @@ const makeOrchestrationProjectionPipeline = Effect.fn("makeOrchestrationProjecti
29894
30497
  default: return;
29895
30498
  }
29896
30499
  });
30500
+ const applyThreadScheduledTasksProjection = Effect.fn("applyThreadScheduledTasksProjection")(function* (event) {
30501
+ switch (event.type) {
30502
+ case "thread.scheduled-task.created":
30503
+ yield* projectionThreadScheduledTaskRepository.upsert({
30504
+ taskId: event.payload.task.id,
30505
+ threadId: event.payload.threadId,
30506
+ prompt: event.payload.task.prompt,
30507
+ runAt: event.payload.task.runAt,
30508
+ status: event.payload.task.status,
30509
+ createdAt: event.payload.task.createdAt,
30510
+ updatedAt: event.payload.task.updatedAt,
30511
+ firedAt: event.payload.task.firedAt,
30512
+ cancelledAt: event.payload.task.cancelledAt,
30513
+ failure: event.payload.task.failure
30514
+ });
30515
+ return;
30516
+ case "thread.scheduled-task.cancelled":
30517
+ case "thread.scheduled-task.fired": {
30518
+ const existing = yield* projectionThreadScheduledTaskRepository.getByTaskId({ taskId: event.payload.taskId });
30519
+ if (existing === null) return;
30520
+ yield* projectionThreadScheduledTaskRepository.upsert(event.type === "thread.scheduled-task.cancelled" ? {
30521
+ ...existing,
30522
+ status: "cancelled",
30523
+ cancelledAt: event.payload.cancelledAt,
30524
+ updatedAt: event.occurredAt
30525
+ } : {
30526
+ ...existing,
30527
+ status: event.payload.failure === null ? "fired" : "failed",
30528
+ firedAt: event.payload.firedAt,
30529
+ failure: event.payload.failure,
30530
+ updatedAt: event.occurredAt
30531
+ });
30532
+ return;
30533
+ }
30534
+ default: return;
30535
+ }
30536
+ });
29897
30537
  const applyThreadProposedPlansProjection = Effect.fn("applyThreadProposedPlansProjection")(function* (event, _attachmentSideEffects) {
29898
30538
  switch (event.type) {
29899
30539
  case "thread.proposed-plan-upserted":
@@ -30253,6 +30893,10 @@ const makeOrchestrationProjectionPipeline = Effect.fn("makeOrchestrationProjecti
30253
30893
  name: ORCHESTRATION_PROJECTOR_NAMES.threadProposedPlans,
30254
30894
  apply: applyThreadProposedPlansProjection
30255
30895
  },
30896
+ {
30897
+ name: ORCHESTRATION_PROJECTOR_NAMES.threadScheduledTasks,
30898
+ apply: applyThreadScheduledTasksProjection
30899
+ },
30256
30900
  {
30257
30901
  name: ORCHESTRATION_PROJECTOR_NAMES.threadActivities,
30258
30902
  apply: applyThreadActivitiesProjection
@@ -30302,7 +30946,7 @@ const makeOrchestrationProjectionPipeline = Effect.fn("makeOrchestrationProjecti
30302
30946
  projectEvent
30303
30947
  };
30304
30948
  });
30305
- const OrchestrationProjectionPipelineLive = Layer.effect(OrchestrationProjectionPipeline, makeOrchestrationProjectionPipeline()).pipe(Layer.provideMerge(ProjectionProjectRepositoryLive), Layer.provideMerge(ProjectionThreadRepositoryLive), Layer.provideMerge(ProjectionThreadMessageRepositoryLive), Layer.provideMerge(ProjectionThreadProposedPlanRepositoryLive), Layer.provideMerge(ProjectionThreadActivityRepositoryLive), Layer.provideMerge(ProjectionThreadSessionRepositoryLive), Layer.provideMerge(ProjectionTurnRepositoryLive), Layer.provideMerge(ProjectionPendingApprovalRepositoryLive), Layer.provideMerge(ProjectionStateRepositoryLive));
30949
+ const OrchestrationProjectionPipelineLive = Layer.effect(OrchestrationProjectionPipeline, makeOrchestrationProjectionPipeline()).pipe(Layer.provideMerge(ProjectionProjectRepositoryLive), Layer.provideMerge(ProjectionThreadRepositoryLive), Layer.provideMerge(ProjectionThreadMessageRepositoryLive), Layer.provideMerge(ProjectionThreadProposedPlanRepositoryLive), Layer.provideMerge(ProjectionThreadScheduledTaskRepositoryLive), Layer.provideMerge(ProjectionThreadActivityRepositoryLive), Layer.provideMerge(ProjectionThreadSessionRepositoryLive), Layer.provideMerge(ProjectionTurnRepositoryLive), Layer.provideMerge(ProjectionPendingApprovalRepositoryLive), Layer.provideMerge(ProjectionStateRepositoryLive));
30306
30950
  //#endregion
30307
30951
  //#region src/orchestration/ThreadBackgroundLiveness.ts
30308
30952
  /**
@@ -30330,7 +30974,7 @@ const TERMINAL_STATUSES = /* @__PURE__ */ new Set([
30330
30974
  "interrupted"
30331
30975
  ]);
30332
30976
  var ThreadBackgroundLivenessService = class extends Context.Service()("@p4code/cli/orchestration/ThreadBackgroundLiveness/ThreadBackgroundLivenessService") {};
30333
- function make$74() {
30977
+ function make$75() {
30334
30978
  const stateByThreadId = /* @__PURE__ */ new Map();
30335
30979
  const stateFor = (threadId) => {
30336
30980
  const existing = stateByThreadId.get(threadId);
@@ -30380,7 +31024,7 @@ function make$74() {
30380
31024
  }
30381
31025
  };
30382
31026
  }
30383
- const layer$64 = Layer.effect(ThreadBackgroundLivenessService, Effect.sync(make$74));
31027
+ const layer$64 = Layer.effect(ThreadBackgroundLivenessService, Effect.sync(make$75));
30384
31028
  //#endregion
30385
31029
  //#region src/persistence/Services/ProjectionCheckpoints.ts
30386
31030
  /**
@@ -30949,12 +31593,12 @@ const runProcessCore = Effect.fn("processRunner.runProcessCore")(function* (spaw
30949
31593
  stderrInvalidUtf8: stderr.invalidUtf8
30950
31594
  };
30951
31595
  });
30952
- const make$73 = Effect.fn("ProcessRunner.make")(function* () {
31596
+ const make$74 = Effect.fn("ProcessRunner.make")(function* () {
30953
31597
  const spawner = yield* ChildProcessSpawner$1.ChildProcessSpawner;
30954
31598
  const run = (input) => finalizeRunProcess(runProcessCore(spawner, input), input);
30955
31599
  return ProcessRunner.of({ run });
30956
31600
  });
30957
- const layer$63 = Layer.effect(ProcessRunner, make$73());
31601
+ const layer$63 = Layer.effect(ProcessRunner, make$74());
30958
31602
  //#endregion
30959
31603
  //#region src/project/RepositoryIdentityResolver.ts
30960
31604
  const DEFAULT_REPOSITORY_IDENTITY_CACHE_CAPACITY = 512;
@@ -31045,7 +31689,7 @@ const resolveRepositoryIdentityFromCacheKey = Effect.fn("RepositoryIdentityResol
31045
31689
  rootPath: cacheKey
31046
31690
  }) : null;
31047
31691
  });
31048
- const make$72 = Effect.fn("RepositoryIdentityResolver.make")(function* (options = {}) {
31692
+ const make$73 = Effect.fn("RepositoryIdentityResolver.make")(function* (options = {}) {
31049
31693
  const processRunner = yield* ProcessRunner;
31050
31694
  const repositoryIdentityCache = yield* Cache.makeWith((cacheKey) => resolveRepositoryIdentityFromCacheKey(cacheKey).pipe(Effect.provideService(ProcessRunner, processRunner)), {
31051
31695
  capacity: options.cacheCapacity ?? DEFAULT_REPOSITORY_IDENTITY_CACHE_CAPACITY,
@@ -31060,7 +31704,7 @@ const make$72 = Effect.fn("RepositoryIdentityResolver.make")(function* (options
31060
31704
  });
31061
31705
  return RepositoryIdentityResolver.of({ resolve });
31062
31706
  });
31063
- const layer$62 = Layer.effect(RepositoryIdentityResolver, make$72()).pipe(Layer.provide(layer$63));
31707
+ const layer$62 = Layer.effect(RepositoryIdentityResolver, make$73()).pipe(Layer.provide(layer$63));
31064
31708
  //#endregion
31065
31709
  //#region src/orchestration/Layers/ProjectionSnapshotQuery.ts
31066
31710
  const decodeReadModel = Schema$1.decodeUnknownEffect(OrchestrationReadModel);
@@ -31075,6 +31719,7 @@ const ProjectionThreadMessageDbRowSchema = ProjectionThreadMessage.mapFields(Str
31075
31719
  attachments: Schema$1.NullOr(Schema$1.fromJsonString(Schema$1.Array(ChatAttachment)))
31076
31720
  }));
31077
31721
  const ProjectionThreadProposedPlanDbRowSchema = ProjectionThreadProposedPlan;
31722
+ const ProjectionThreadScheduledTaskDbRowSchema = ProjectionThreadScheduledTask;
31078
31723
  const ProjectionThreadDbRowSchema = ProjectionThread.mapFields(Struct.assign({
31079
31724
  modelSelection: Schema$1.fromJsonString(ModelSelection),
31080
31725
  workspaceLifecycle: Schema$1.NullOr(Schema$1.fromJsonString(ThreadWorkspaceLifecycle))
@@ -31275,6 +31920,28 @@ function mapProjectShellRow(row, repositoryIdentity) {
31275
31920
  updatedAt: row.updatedAt
31276
31921
  };
31277
31922
  }
31923
+ function mapScheduledTaskRow(row) {
31924
+ return {
31925
+ id: row.taskId,
31926
+ prompt: row.prompt,
31927
+ runAt: row.runAt,
31928
+ status: row.status,
31929
+ createdAt: row.createdAt,
31930
+ updatedAt: row.updatedAt,
31931
+ firedAt: row.firedAt,
31932
+ cancelledAt: row.cancelledAt,
31933
+ failure: row.failure
31934
+ };
31935
+ }
31936
+ function groupScheduledTasksByThread(rows) {
31937
+ const byThread = /* @__PURE__ */ new Map();
31938
+ for (const row of rows) {
31939
+ const tasks = byThread.get(row.threadId) ?? [];
31940
+ tasks.push(mapScheduledTaskRow(row));
31941
+ byThread.set(row.threadId, tasks);
31942
+ }
31943
+ return byThread;
31944
+ }
31278
31945
  function mapProposedPlanRow(row) {
31279
31946
  return {
31280
31947
  id: row.planId,
@@ -31503,6 +32170,45 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
31503
32170
  updated_at AS "updatedAt"
31504
32171
  FROM projection_thread_proposed_plans
31505
32172
  ORDER BY thread_id ASC, created_at ASC, plan_id ASC
32173
+ `
32174
+ });
32175
+ const listThreadScheduledTaskRows = SqlSchema.findAll({
32176
+ Request: Schema$1.Void,
32177
+ Result: ProjectionThreadScheduledTaskDbRowSchema,
32178
+ execute: () => sql`
32179
+ SELECT
32180
+ task_id AS "taskId",
32181
+ thread_id AS "threadId",
32182
+ prompt,
32183
+ run_at AS "runAt",
32184
+ status,
32185
+ created_at AS "createdAt",
32186
+ updated_at AS "updatedAt",
32187
+ fired_at AS "firedAt",
32188
+ cancelled_at AS "cancelledAt",
32189
+ failure
32190
+ FROM projection_thread_scheduled_tasks
32191
+ ORDER BY thread_id ASC, run_at ASC, task_id ASC
32192
+ `
32193
+ });
32194
+ const listThreadScheduledTaskRowsByThread = SqlSchema.findAll({
32195
+ Request: ThreadIdLookupInput,
32196
+ Result: ProjectionThreadScheduledTaskDbRowSchema,
32197
+ execute: ({ threadId }) => sql`
32198
+ SELECT
32199
+ task_id AS "taskId",
32200
+ thread_id AS "threadId",
32201
+ prompt,
32202
+ run_at AS "runAt",
32203
+ status,
32204
+ created_at AS "createdAt",
32205
+ updated_at AS "updatedAt",
32206
+ fired_at AS "firedAt",
32207
+ cancelled_at AS "cancelledAt",
32208
+ failure
32209
+ FROM projection_thread_scheduled_tasks
32210
+ WHERE thread_id = ${threadId}
32211
+ ORDER BY run_at ASC, task_id ASC
31506
32212
  `
31507
32213
  });
31508
32214
  const listThreadActivityRows = SqlSchema.findAll({
@@ -32291,8 +32997,10 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
32291
32997
  listTurnSummaryRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getSnapshot:listTurnSummaries:query", "ProjectionSnapshotQuery.getSnapshot:listTurnSummaries:decodeRows"))),
32292
32998
  listLatestTurnRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getSnapshot:listLatestTurns:query", "ProjectionSnapshotQuery.getSnapshot:listLatestTurns:decodeRows"))),
32293
32999
  listProjectionStateRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getSnapshot:listProjectionState:query", "ProjectionSnapshotQuery.getSnapshot:listProjectionState:decodeRows"))),
32294
- listThreadPairRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getSnapshot:listThreadPairs:query", "ProjectionSnapshotQuery.getSnapshot:listThreadPairs:decodeRows")))
32295
- ])).pipe(Effect.flatMap(([projectRows, threadRows, messageRows, proposedPlanRows, activityRows, sessionRows, checkpointRows, turnRows, latestTurnRows, stateRows, threadPairRows]) => Effect.gen(function* () {
33000
+ listThreadPairRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getSnapshot:listThreadPairs:query", "ProjectionSnapshotQuery.getSnapshot:listThreadPairs:decodeRows"))),
33001
+ listThreadScheduledTaskRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getSnapshot:listThreadScheduledTasks:query", "ProjectionSnapshotQuery.getSnapshot:listThreadScheduledTasks:decodeRows")))
33002
+ ])).pipe(Effect.flatMap(([projectRows, threadRows, messageRows, proposedPlanRows, activityRows, sessionRows, checkpointRows, turnRows, latestTurnRows, stateRows, threadPairRows, scheduledTaskRows]) => Effect.gen(function* () {
33003
+ const scheduledTasksByThread = groupScheduledTasksByThread(scheduledTaskRows);
32296
33004
  const messagesByThread = /* @__PURE__ */ new Map();
32297
33005
  const proposedPlansByThread = /* @__PURE__ */ new Map();
32298
33006
  const activitiesByThread = /* @__PURE__ */ new Map();
@@ -32426,6 +33134,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
32426
33134
  deletedAt: row.deletedAt,
32427
33135
  messages: messagesByThread.get(row.threadId) ?? [],
32428
33136
  proposedPlans: proposedPlansByThread.get(row.threadId) ?? [],
33137
+ scheduledTasks: scheduledTasksByThread.get(row.threadId) ?? [],
32429
33138
  activities: activitiesByThread.get(row.threadId) ?? [],
32430
33139
  checkpoints: checkpointsByThread.get(row.threadId) ?? [],
32431
33140
  session: sessionsByThread.get(row.threadId) ?? null
@@ -32446,7 +33155,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
32446
33155
  const [thread, rows] = yield* Effect.all([getBtwThreadRow({ threadId }), listBtwContextRows({ threadId })]).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getBtwContext:query", "ProjectionSnapshotQuery.getBtwContext:decodeRows")));
32447
33156
  if (Option.isNone(thread)) return Option.none();
32448
33157
  let remaining = BTW_CONTEXT_CHARACTER_LIMIT;
32449
- const newestFirst = [...rows].reverse();
33158
+ const newestFirst = [...rows].toReversed();
32450
33159
  const retained = [];
32451
33160
  for (const row of newestFirst) {
32452
33161
  if (remaining <= 0) break;
@@ -32460,7 +33169,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
32460
33169
  return Option.some({
32461
33170
  projectId: thread.value.projectId,
32462
33171
  cwd: thread.value.cwd,
32463
- messages: retained.reverse()
33172
+ messages: retained.toReversed()
32464
33173
  });
32465
33174
  });
32466
33175
  const getCommandReadModel = () => sql.withTransaction(Effect.all([
@@ -32470,8 +33179,10 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
32470
33179
  listThreadSessionRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getCommandReadModel:listThreadSessions:query", "ProjectionSnapshotQuery.getCommandReadModel:listThreadSessions:decodeRows"))),
32471
33180
  listLatestTurnRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getCommandReadModel:listLatestTurns:query", "ProjectionSnapshotQuery.getCommandReadModel:listLatestTurns:decodeRows"))),
32472
33181
  listProjectionStateRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getCommandReadModel:listProjectionState:query", "ProjectionSnapshotQuery.getCommandReadModel:listProjectionState:decodeRows"))),
32473
- listThreadPairRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getCommandReadModel:listThreadPairs:query", "ProjectionSnapshotQuery.getCommandReadModel:listThreadPairs:decodeRows")))
32474
- ])).pipe(Effect.flatMap(([projectRows, threadRows, proposedPlanRows, sessionRows, latestTurnRows, stateRows, threadPairRows]) => Effect.sync(() => {
33182
+ listThreadPairRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getCommandReadModel:listThreadPairs:query", "ProjectionSnapshotQuery.getCommandReadModel:listThreadPairs:decodeRows"))),
33183
+ listThreadScheduledTaskRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getCommandReadModel:listThreadScheduledTasks:query", "ProjectionSnapshotQuery.getCommandReadModel:listThreadScheduledTasks:decodeRows")))
33184
+ ])).pipe(Effect.flatMap(([projectRows, threadRows, proposedPlanRows, sessionRows, latestTurnRows, stateRows, threadPairRows, scheduledTaskRows]) => Effect.sync(() => {
33185
+ const scheduledTasksByThread = groupScheduledTasksByThread(scheduledTaskRows);
32475
33186
  let updatedAt = null;
32476
33187
  const projects = [];
32477
33188
  const threads = [];
@@ -32566,6 +33277,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
32566
33277
  deletedAt: row.deletedAt,
32567
33278
  messages: [],
32568
33279
  proposedPlans: proposedPlansByThread.get(row.threadId) ?? [],
33280
+ scheduledTasks: scheduledTasksByThread.get(row.threadId) ?? [],
32569
33281
  activities: [],
32570
33282
  checkpoints: [],
32571
33283
  session: sessionByThread.get(row.threadId) ?? null
@@ -32818,7 +33530,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
32818
33530
  });
32819
33531
  });
32820
33532
  const getThreadDetailByIdBounded = (threadId, bounds) => Effect.gen(function* () {
32821
- const [threadRow, messageRows, proposedPlanRows, activityRows, checkpointRows, turnRows, latestTurnRow, sessionRow] = yield* Effect.all([
33533
+ const [threadRow, messageRows, proposedPlanRows, activityRows, checkpointRows, turnRows, latestTurnRow, sessionRow, scheduledTaskRows] = yield* Effect.all([
32822
33534
  getActiveThreadRowById({ threadId }).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getThreadDetailById:getThread:query", "ProjectionSnapshotQuery.getThreadDetailById:getThread:decodeRow"))),
32823
33535
  (bounds === void 0 ? listThreadMessageRowsByThread({ threadId }) : listThreadMessageRowsByThreadWindow({
32824
33536
  threadId,
@@ -32832,7 +33544,8 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
32832
33544
  listCheckpointRowsByThread({ threadId }).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getThreadDetailById:listCheckpoints:query", "ProjectionSnapshotQuery.getThreadDetailById:listCheckpoints:decodeRows"))),
32833
33545
  listTurnSummaryRowsByThread({ threadId }).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getThreadDetailById:listTurnSummaries:query", "ProjectionSnapshotQuery.getThreadDetailById:listTurnSummaries:decodeRows"))),
32834
33546
  getLatestTurnRowByThread({ threadId }).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getThreadDetailById:getLatestTurn:query", "ProjectionSnapshotQuery.getThreadDetailById:getLatestTurn:decodeRow"))),
32835
- getThreadSessionRowByThread({ threadId }).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getThreadDetailById:getSession:query", "ProjectionSnapshotQuery.getThreadDetailById:getSession:decodeRow")))
33547
+ getThreadSessionRowByThread({ threadId }).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getThreadDetailById:getSession:query", "ProjectionSnapshotQuery.getThreadDetailById:getSession:decodeRow"))),
33548
+ listThreadScheduledTaskRowsByThread({ threadId }).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getThreadDetailById:listScheduledTasks:query", "ProjectionSnapshotQuery.getThreadDetailById:listScheduledTasks:decodeRows")))
32836
33549
  ]);
32837
33550
  if (Option.isNone(threadRow)) return Option.none();
32838
33551
  const thread = {
@@ -32873,6 +33586,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
32873
33586
  return message;
32874
33587
  }),
32875
33588
  proposedPlans: proposedPlanRows.map(mapProposedPlanRow),
33589
+ scheduledTasks: scheduledTaskRows.map(mapScheduledTaskRow),
32876
33590
  activities: activityRows.map((row) => {
32877
33591
  const activity = {
32878
33592
  id: row.activityId,
@@ -33525,7 +34239,7 @@ function mergeWithDefaultKeybindings(custom) {
33525
34239
  * Keybindings - Service tag for keybinding configuration operations.
33526
34240
  */
33527
34241
  var Keybindings = class extends Context.Service()("@p4code/cli/keybindings") {};
33528
- const make$71 = Effect.gen(function* () {
34242
+ const make$72 = Effect.gen(function* () {
33529
34243
  const { keybindingsConfigPath } = yield* ServerConfig$1;
33530
34244
  const fs = yield* FileSystem.FileSystem;
33531
34245
  const path = yield* Path.Path;
@@ -33786,7 +34500,7 @@ const make$71 = Effect.gen(function* () {
33786
34500
  }))
33787
34501
  };
33788
34502
  });
33789
- const layer$61 = Layer.effect(Keybindings, make$71);
34503
+ const layer$61 = Layer.effect(Keybindings, make$72);
33790
34504
  //#endregion
33791
34505
  //#region src/process/externalLauncher.ts
33792
34506
  /**
@@ -34013,7 +34727,7 @@ const launchEditorProcess = Effect.fn("externalLauncher.launchEditorProcess")(fu
34013
34727
  cause
34014
34728
  }));
34015
34729
  });
34016
- const make$70 = Effect.gen(function* () {
34730
+ const make$71 = Effect.gen(function* () {
34017
34731
  const spawner = yield* ChildProcessSpawner$1.ChildProcessSpawner;
34018
34732
  const fileSystem = yield* FileSystem.FileSystem;
34019
34733
  const path = yield* Path.Path;
@@ -34024,7 +34738,7 @@ const make$70 = Effect.gen(function* () {
34024
34738
  launchEditor: (input) => provideCommandResolutionServices(Effect.flatMap(resolveEditorLaunch(input), (launch) => launchEditorProcess(launch).pipe(Effect.provideService(ChildProcessSpawner$1.ChildProcessSpawner, spawner))))
34025
34739
  });
34026
34740
  });
34027
- const layer$60 = Layer.effect(ExternalLauncher, make$70);
34741
+ const layer$60 = Layer.effect(ExternalLauncher, make$71);
34028
34742
  //#endregion
34029
34743
  //#region src/orchestration/Services/OrchestrationReactor.ts
34030
34744
  /**
@@ -34042,7 +34756,7 @@ var OrchestrationReactor = class extends Context.Service()("@p4code/cli/orchestr
34042
34756
  //#endregion
34043
34757
  //#region src/serverLifecycleEvents.ts
34044
34758
  var ServerLifecycleEvents = class extends Context.Service()("@p4code/cli/serverLifecycleEvents") {};
34045
- const make$69 = Effect.gen(function* () {
34759
+ const make$70 = Effect.gen(function* () {
34046
34760
  const pubsub = yield* PubSub.unbounded();
34047
34761
  const state = yield* Ref.make({
34048
34762
  sequence: 0,
@@ -34066,7 +34780,7 @@ const make$69 = Effect.gen(function* () {
34066
34780
  }
34067
34781
  };
34068
34782
  });
34069
- const layer$59 = Layer.effect(ServerLifecycleEvents, make$69);
34783
+ const layer$59 = Layer.effect(ServerLifecycleEvents, make$70);
34070
34784
  //#endregion
34071
34785
  //#region src/telemetry/Identify.ts
34072
34786
  const CodexAuthJsonSchema = Schema$1.Struct({ tokens: Schema$1.Struct({ account_id: Schema$1.String }) });
@@ -34239,7 +34953,7 @@ var AnalyticsService = class AnalyticsService extends Context.Service()("@p4code
34239
34953
  /** No-op layer for callers that intentionally disable telemetry. */
34240
34954
  static layerTest = Layer.succeed(AnalyticsService, inert);
34241
34955
  };
34242
- const make$68 = Effect.gen(function* () {
34956
+ const make$69 = Effect.gen(function* () {
34243
34957
  const telemetryConfig = yield* TelemetryEnvConfig;
34244
34958
  const posthogKey = telemetryConfig.posthogKey.trim();
34245
34959
  if (!telemetryConfig.enabled || posthogKey === "") return inert;
@@ -34309,7 +35023,7 @@ const make$68 = Effect.gen(function* () {
34309
35023
  flush
34310
35024
  });
34311
35025
  });
34312
- const layer$58 = Layer.effect(AnalyticsService, make$68);
35026
+ const layer$58 = Layer.effect(AnalyticsService, make$69);
34313
35027
  AnalyticsService.layerTest;
34314
35028
  //#endregion
34315
35029
  //#region src/service/pinnedRuntime.ts
@@ -34656,7 +35370,7 @@ var BootServiceInstallError = class extends Schema$1.TaggedErrorClass()("BootSer
34656
35370
  }
34657
35371
  };
34658
35372
  var BootService = class extends Context.Service()("@p4code/cli/service/bootService") {};
34659
- const make$67 = Effect.fn("cloud.boot_service.make")(function* (input) {
35373
+ const make$68 = Effect.fn("cloud.boot_service.make")(function* (input) {
34660
35374
  const hostExecPath = yield* HostProcessExecutablePath;
34661
35375
  const hostArguments = yield* HostProcessArguments;
34662
35376
  const host = input.host ?? {
@@ -34878,7 +35592,7 @@ const make$67 = Effect.fn("cloud.boot_service.make")(function* (input) {
34878
35592
  logPath
34879
35593
  });
34880
35594
  });
34881
- const layer$57 = (input) => Layer.effect(BootService, make$67(input));
35595
+ const layer$57 = (input) => Layer.effect(BootService, make$68(input));
34882
35596
  //#endregion
34883
35597
  //#region src/service/selfUpdate.ts
34884
35598
  /**
@@ -34953,7 +35667,7 @@ const resolveServerSelfUpdateCapability = Effect.fn("cloud.server_self_update.re
34953
35667
  return null;
34954
35668
  });
34955
35669
  var ServerSelfUpdate = class extends Context.Service()("@p4code/cli/service/selfUpdate/ServerSelfUpdate") {};
34956
- const make$66 = Effect.fn("cloud.server_self_update.make")(function* (options) {
35670
+ const make$67 = Effect.fn("cloud.server_self_update.make")(function* (options) {
34957
35671
  const serverConfig = yield* ServerConfig$1;
34958
35672
  const fs = yield* FileSystem.FileSystem;
34959
35673
  const path = yield* Path.Path;
@@ -35103,7 +35817,7 @@ const make$66 = Effect.fn("cloud.server_self_update.make")(function* (options) {
35103
35817
  });
35104
35818
  return ServerSelfUpdate.of({ update });
35105
35819
  });
35106
- const layer$56 = Layer.effect(ServerSelfUpdate, make$66()).pipe(Layer.provide(layer$63));
35820
+ const layer$56 = Layer.effect(ServerSelfUpdate, make$67()).pipe(Layer.provide(layer$63));
35107
35821
  //#endregion
35108
35822
  //#region src/environment/ServerEnvironmentLabel.ts
35109
35823
  const ServerEnvironmentLabelCommandProbe = Schema$1.Literals(["macos-computer-name", "linux-pretty-hostname"]);
@@ -35235,7 +35949,7 @@ function platformArch(architecture) {
35235
35949
  default: return "other";
35236
35950
  }
35237
35951
  }
35238
- const make$65 = Effect.gen(function* () {
35952
+ const make$66 = Effect.gen(function* () {
35239
35953
  const fileSystem = yield* FileSystem.FileSystem;
35240
35954
  const path = yield* Path.Path;
35241
35955
  const serverConfig = yield* ServerConfig$1;
@@ -35286,6 +36000,8 @@ const make$65 = Effect.gen(function* () {
35286
36000
  threadSettlement: true,
35287
36001
  threadSnooze: true,
35288
36002
  threadPinning: true,
36003
+ threadFork: true,
36004
+ threadScheduledTasks: true,
35289
36005
  ...serverSelfUpdate === null ? {} : { serverSelfUpdate },
35290
36006
  ...serverServiceSupervised ? { serverServiceSupervised } : {}
35291
36007
  }
@@ -35300,7 +36016,7 @@ const make$65 = Effect.gen(function* () {
35300
36016
  * state. It intentionally has no fallback Layer.succeed value: callers must
35301
36017
  * provide the external platform services and a ServerConfig.
35302
36018
  */
35303
- const layer$55 = Layer.effect(ServerEnvironment, make$65).pipe(Layer.provide(layer$63));
36019
+ const layer$55 = Layer.effect(ServerEnvironment, make$66).pipe(Layer.provide(layer$63));
35304
36020
  //#endregion
35305
36021
  //#region src/provider/Services/ProviderSessionReaper.ts
35306
36022
  var ProviderSessionReaper = class extends Context.Service()("@p4code/cli/provider/Services/ProviderSessionReaper") {};
@@ -35442,7 +36158,7 @@ const maybeOpenBrowser = (target) => Effect.gen(function* () {
35442
36158
  yield* (yield* ExternalLauncher).launchBrowser(target).pipe(Effect.catch(() => Effect.logInfo("browser auto-open unavailable", { hint: `Open ${target} in your browser.` })));
35443
36159
  });
35444
36160
  const runStartupPhase = (phase, effect) => effect.pipe(Effect.annotateSpans({ "startup.phase": phase }), Effect.withSpan(`server.startup.${phase}`));
35445
- const make$64 = Effect.gen(function* () {
36161
+ const make$65 = Effect.gen(function* () {
35446
36162
  const serverConfig = yield* ServerConfig$1;
35447
36163
  const keybindings = yield* Keybindings;
35448
36164
  const orchestrationReactor = yield* OrchestrationReactor;
@@ -35583,7 +36299,7 @@ const make$64 = Effect.gen(function* () {
35583
36299
  enqueueCommand: commandGate.enqueueCommand
35584
36300
  };
35585
36301
  });
35586
- const layer$54 = Layer.effect(ServerRuntimeStartup, make$64);
36302
+ const layer$54 = Layer.effect(ServerRuntimeStartup, make$65);
35587
36303
  //#endregion
35588
36304
  //#region src/serverRuntimeState.ts
35589
36305
  const PersistedServerRuntimeState = Schema$1.Struct({
@@ -35740,7 +36456,7 @@ function expandHomePath$2(input, path) {
35740
36456
  if (input.startsWith("~/") || input.startsWith("~\\")) return path.join(NodeOS.homedir(), input.slice(2));
35741
36457
  return input;
35742
36458
  }
35743
- const make$63 = Effect.gen(function* () {
36459
+ const make$64 = Effect.gen(function* () {
35744
36460
  const fileSystem = yield* FileSystem.FileSystem;
35745
36461
  const path = yield* Path.Path;
35746
36462
  const statWorkspaceRoot = Effect.fn("WorkspacePaths.statWorkspaceRoot")(function* (workspaceRoot, normalizedWorkspaceRoot, phase) {
@@ -35797,7 +36513,7 @@ const make$63 = Effect.gen(function* () {
35797
36513
  resolveRelativePathWithinRoot
35798
36514
  });
35799
36515
  });
35800
- const layer$53 = Layer.effect(WorkspacePaths, make$63);
36516
+ const layer$53 = Layer.effect(WorkspacePaths, make$64);
35801
36517
  //#endregion
35802
36518
  //#region src/cli/project.ts
35803
36519
  const isEnvironmentHttpCommonError = Schema$1.is(EnvironmentHttpCommonError);
@@ -36980,7 +37696,7 @@ const logP4ProjectFileLoadError = (error) => Effect.logWarning(error).pipe(Effec
36980
37696
  filePath: error.filePath,
36981
37697
  errorTag: error._tag
36982
37698
  }));
36983
- const make$62 = Effect.gen(function* () {
37699
+ const make$63 = Effect.gen(function* () {
36984
37700
  const fileSystem = yield* FileSystem.FileSystem;
36985
37701
  const path = yield* Path.Path;
36986
37702
  const load = Effect.fn("P4ProjectFileLoader.load")(function* (workspaceRoot) {
@@ -37001,7 +37717,7 @@ const make$62 = Effect.gen(function* () {
37001
37717
  });
37002
37718
  return P4ProjectFileLoader.of({ load });
37003
37719
  });
37004
- const layer$52 = Layer.effect(P4ProjectFileLoader, make$62);
37720
+ const layer$52 = Layer.effect(P4ProjectFileLoader, make$63);
37005
37721
  //#endregion
37006
37722
  //#region src/project/ProjectFaviconResolver.ts
37007
37723
  /**
@@ -37076,7 +37792,7 @@ function extractIconHref(source) {
37076
37792
  return null;
37077
37793
  }
37078
37794
  const optionOnNotFound$1 = (effect) => effect.pipe(Effect.map(Option.some), Effect.catchTags({ PlatformError: (error) => error.reason._tag === "NotFound" ? Effect.succeed(Option.none()) : Effect.fail(error) }));
37079
- const make$61 = Effect.gen(function* () {
37795
+ const make$62 = Effect.gen(function* () {
37080
37796
  const fileSystem = yield* FileSystem.FileSystem;
37081
37797
  const path = yield* Path.Path;
37082
37798
  const workspacePaths = yield* WorkspacePaths;
@@ -37145,7 +37861,7 @@ const make$61 = Effect.gen(function* () {
37145
37861
  });
37146
37862
  return ProjectFaviconResolver.of({ resolvePath });
37147
37863
  });
37148
- const layer$51 = Layer.effect(ProjectFaviconResolver, make$61);
37864
+ const layer$51 = Layer.effect(ProjectFaviconResolver, make$62);
37149
37865
  //#endregion
37150
37866
  //#region src/assets/AssetAccess.ts
37151
37867
  const ASSET_ROUTE_PREFIX = "/api/assets";
@@ -37556,10 +38272,10 @@ const resolveAsset = Effect.fn("AssetAccess.resolveAsset")(function* (token, rel
37556
38272
  //#endregion
37557
38273
  //#region src/observability/BrowserTraceCollector.ts
37558
38274
  var BrowserTraceCollector = class extends Context.Service()("@p4code/cli/observability/BrowserTraceCollector") {};
37559
- const make$60 = (sink) => BrowserTraceCollector.of({ record: (records) => Effect.sync(() => {
38275
+ const make$61 = (sink) => BrowserTraceCollector.of({ record: (records) => Effect.sync(() => {
37560
38276
  for (const record of records) sink.push(record);
37561
38277
  }) });
37562
- const layer$50 = (sink) => Layer.succeed(BrowserTraceCollector, make$60(sink));
38278
+ const layer$50 = (sink) => Layer.succeed(BrowserTraceCollector, make$61(sink));
37563
38279
  //#endregion
37564
38280
  //#region src/auth/http.ts
37565
38281
  const CREDENTIAL_RESPONSE_HEADERS = {
@@ -40612,7 +41328,7 @@ const classifyNonZeroExit = (command, stderr) => {
40612
41328
  if (command === "gh" && (normalized.includes("could not resolve to a pullrequest") || normalized.includes("repository.pullrequest") || normalized.includes("no pull requests found for branch") || normalized.includes("pull request not found")) || command === "glab" && (normalized.includes("merge request not found") || normalized.includes("not found") || normalized.includes("404")) || command === "az" && normalized.includes("pull request") && (normalized.includes("not found") || normalized.includes("does not exist"))) return "not-found";
40613
41329
  return "command-failed";
40614
41330
  };
40615
- const make$59 = Effect.gen(function* () {
41331
+ const make$60 = Effect.gen(function* () {
40616
41332
  const processRunner = yield* ProcessRunner;
40617
41333
  const run = Effect.fn("VcsProcess.run")(function* (input) {
40618
41334
  const baseError = {
@@ -40671,7 +41387,7 @@ const make$59 = Effect.gen(function* () {
40671
41387
  });
40672
41388
  return VcsProcess.of({ run });
40673
41389
  });
40674
- const layer$49 = Layer.effect(VcsProcess, make$59).pipe(Layer.provide(layer$63));
41390
+ const layer$49 = Layer.effect(VcsProcess, make$60).pipe(Layer.provide(layer$63));
40675
41391
  //#endregion
40676
41392
  //#region src/vcs/VcsDriver.ts
40677
41393
  var VcsDriver = class extends Context.Service()("@p4code/cli/vcs/VcsDriver") {};
@@ -41122,12 +41838,12 @@ const makeVcsDriver = Effect.gen(function* () {
41122
41838
  const driver = yield* makeVcsDriverShape();
41123
41839
  return VcsDriver.of(driver);
41124
41840
  });
41125
- const make$58 = Effect.gen(function* () {
41841
+ const make$59 = Effect.gen(function* () {
41126
41842
  const git = yield* makeGitVcsDriverCore();
41127
41843
  return GitVcsDriver.of(git);
41128
41844
  });
41129
41845
  Layer.effect(VcsDriver, makeVcsDriver);
41130
- const layer$48 = Layer.effect(GitVcsDriver, make$58);
41846
+ const layer$48 = Layer.effect(GitVcsDriver, make$59);
41131
41847
  //#endregion
41132
41848
  //#region src/vcs/VcsProjectConfig.ts
41133
41849
  const ProjectVcsConfigJson = fromLenientJson(Schema$1.Struct({
@@ -41159,7 +41875,7 @@ const logVcsProjectConfigError = (error) => Effect.logWarning(error).pipe(Effect
41159
41875
  configPath: error.configPath,
41160
41876
  errorTag: error._tag
41161
41877
  }));
41162
- const make$57 = Effect.gen(function* () {
41878
+ const make$58 = Effect.gen(function* () {
41163
41879
  const fileSystem = yield* FileSystem.FileSystem;
41164
41880
  const path = yield* Path.Path;
41165
41881
  const findConfigPath = Effect.fn("VcsProjectConfig.findConfigPath")(function* (cwd) {
@@ -41200,7 +41916,7 @@ const make$57 = Effect.gen(function* () {
41200
41916
  });
41201
41917
  return VcsProjectConfig.of({ resolveKind });
41202
41918
  });
41203
- const layer$47 = Layer.effect(VcsProjectConfig, make$57);
41919
+ const layer$47 = Layer.effect(VcsProjectConfig, make$58);
41204
41920
  //#endregion
41205
41921
  //#region src/vcs/VcsDriverRegistry.ts
41206
41922
  const DETECTION_CACHE_CAPACITY = 2048;
@@ -41220,7 +41936,7 @@ function parseDetectionCacheKey(key) {
41220
41936
  cwd: key.slice(separatorIndex + 1)
41221
41937
  };
41222
41938
  }
41223
- const make$56 = Effect.gen(function* () {
41939
+ const make$57 = Effect.gen(function* () {
41224
41940
  const projectConfig = yield* VcsProjectConfig;
41225
41941
  const git = yield* makeVcsDriver;
41226
41942
  const drivers = { git };
@@ -41277,7 +41993,7 @@ const make$56 = Effect.gen(function* () {
41277
41993
  resolve
41278
41994
  });
41279
41995
  });
41280
- const layer$46 = Layer.effect(VcsDriverRegistry, make$56).pipe(Layer.provide(layer$47));
41996
+ const layer$46 = Layer.effect(VcsDriverRegistry, make$57).pipe(Layer.provide(layer$47));
41281
41997
  //#endregion
41282
41998
  //#region src/checkpointing/CheckpointStore.ts
41283
41999
  /**
@@ -41297,7 +42013,7 @@ const layer$46 = Layer.effect(VcsDriverRegistry, make$56).pipe(Layer.provide(lay
41297
42013
  */
41298
42014
  /** Service tag for checkpoint persistence and restore operations. */
41299
42015
  var CheckpointStore = class extends Context.Service()("@p4code/cli/checkpointing/CheckpointStore") {};
41300
- const make$55 = Effect.gen(function* () {
42016
+ const make$56 = Effect.gen(function* () {
41301
42017
  const vcsRegistry = yield* VcsDriverRegistry;
41302
42018
  const resolveCheckpoints = Effect.fn("CheckpointStore.resolveCheckpoints")(function* (operation, cwd) {
41303
42019
  const handle = yield* vcsRegistry.resolve({ cwd });
@@ -41336,7 +42052,7 @@ const make$55 = Effect.gen(function* () {
41336
42052
  deleteCheckpointRefs
41337
42053
  });
41338
42054
  });
41339
- const layer$45 = Layer.effect(CheckpointStore, make$55);
42055
+ const layer$45 = Layer.effect(CheckpointStore, make$56);
41340
42056
  //#endregion
41341
42057
  //#region src/checkpointing/CheckpointDiffQuery.ts
41342
42058
  /**
@@ -41358,7 +42074,7 @@ function buildTurnDiffResult(input, diff) {
41358
42074
  diff
41359
42075
  };
41360
42076
  }
41361
- const make$54 = Effect.gen(function* () {
42077
+ const make$55 = Effect.gen(function* () {
41362
42078
  const projectionSnapshotQuery = yield* ProjectionSnapshotQuery;
41363
42079
  const checkpointStore = yield* CheckpointStore;
41364
42080
  const threadActivities = yield* ProjectionThreadActivityRepository;
@@ -41529,7 +42245,7 @@ const make$54 = Effect.gen(function* () {
41529
42245
  getFullThreadDiff
41530
42246
  });
41531
42247
  });
41532
- const layer$44 = Layer.effect(CheckpointDiffQuery, make$54);
42248
+ const layer$44 = Layer.effect(CheckpointDiffQuery, make$55);
41533
42249
  //#endregion
41534
42250
  //#region src/orchestration/Normalizer.ts
41535
42251
  const canonicalizeClientCommandTimestamps = (command, receivedAt) => {
@@ -41644,11 +42360,11 @@ const makeTextGenerationFromRegistry = (registry) => TextGeneration.of({
41644
42360
  detail: "This provider does not report account usage."
41645
42361
  }))))
41646
42362
  });
41647
- const make$53 = Effect.gen(function* () {
42363
+ const make$54 = Effect.gen(function* () {
41648
42364
  const registry = yield* ProviderInstanceRegistry;
41649
42365
  return makeTextGenerationFromRegistry(registry);
41650
42366
  });
41651
- const layer$43 = Layer.effect(TextGeneration, make$53);
42367
+ const layer$43 = Layer.effect(TextGeneration, make$54);
41652
42368
  //#endregion
41653
42369
  //#region src/textGeneration/TextGenerationPresets.ts
41654
42370
  const conventionalCommitsTextGenerationPolicy = {
@@ -41980,7 +42696,7 @@ const serversEqual = (left, right) => {
41980
42696
  }
41981
42697
  return true;
41982
42698
  };
41983
- const make$52 = Effect.gen(function* PortDiscoveryMake() {
42699
+ const make$53 = Effect.gen(function* PortDiscoveryMake() {
41984
42700
  const net = yield* NetService;
41985
42701
  const processRunner = yield* ProcessRunner;
41986
42702
  const hostPlatform = yield* HostProcessPlatform;
@@ -42131,7 +42847,7 @@ const make$52 = Effect.gen(function* PortDiscoveryMake() {
42131
42847
  unregisterTerminal
42132
42848
  });
42133
42849
  }).pipe(Effect.withSpan("PortDiscovery.make"));
42134
- const layer$42 = Layer.effect(PortDiscovery, make$52);
42850
+ const layer$42 = Layer.effect(PortDiscovery, make$53);
42135
42851
  //#endregion
42136
42852
  //#region src/terminal/Manager.ts
42137
42853
  /**
@@ -42809,7 +43525,7 @@ function normalizedRuntimeEnv(env) {
42809
43525
  if (entries.length === 0) return null;
42810
43526
  return Object.fromEntries(entries.toSorted(([left], [right]) => left.localeCompare(right)));
42811
43527
  }
42812
- const make$51 = Effect.fn("TerminalManager.make")(function* () {
43528
+ const make$52 = Effect.fn("TerminalManager.make")(function* () {
42813
43529
  const { terminalLogsDir } = yield* ServerConfig$1;
42814
43530
  const ptyAdapter = yield* PtyAdapter;
42815
43531
  const portDiscovery = yield* PortDiscovery;
@@ -43771,7 +44487,7 @@ const makeWithOptions$1 = Effect.fn("TerminalManager.makeWithOptions")(function*
43771
44487
  subscribeMetadata
43772
44488
  });
43773
44489
  });
43774
- const layer$41 = Layer.effect(TerminalManager, make$51()).pipe(Layer.provide(layer$63));
44490
+ const layer$41 = Layer.effect(TerminalManager, make$52()).pipe(Layer.provide(layer$63));
43775
44491
  //#endregion
43776
44492
  //#region src/project/ProjectSetupScriptRunner.ts
43777
44493
  var ProjectSetupScriptOperationError = class extends Schema$1.TaggedErrorClass()("ProjectSetupScriptOperationError", {
@@ -43802,7 +44518,7 @@ var ProjectSetupScriptProjectNotFoundError = class extends Schema$1.TaggedErrorC
43802
44518
  };
43803
44519
  Schema$1.Union([ProjectSetupScriptOperationError, ProjectSetupScriptProjectNotFoundError]);
43804
44520
  var ProjectSetupScriptRunner = class extends Context.Service()("@p4code/cli/project/ProjectSetupScriptRunner") {};
43805
- const make$50 = Effect.gen(function* () {
44521
+ const make$51 = Effect.gen(function* () {
43806
44522
  const projectionSnapshotQuery = yield* ProjectionSnapshotQuery;
43807
44523
  const terminalManager = yield* TerminalManager;
43808
44524
  const runForThread = Effect.fn("ProjectSetupScriptRunner.runForThread")(function* (input) {
@@ -43860,7 +44576,7 @@ const make$50 = Effect.gen(function* () {
43860
44576
  });
43861
44577
  return ProjectSetupScriptRunner.of({ runForThread });
43862
44578
  });
43863
- const layer$40 = Layer.effect(ProjectSetupScriptRunner, make$50);
44579
+ const layer$40 = Layer.effect(ProjectSetupScriptRunner, make$51);
43864
44580
  //#endregion
43865
44581
  //#region src/provider/Services/ProviderRegistry.ts
43866
44582
  var ProviderRegistry = class extends Context.Service()("@p4code/cli/provider/Services/ProviderRegistry") {};
@@ -44187,7 +44903,7 @@ function decodeAzureDevOpsJson(raw, schema, operation, cwd) {
44187
44903
  cause
44188
44904
  })));
44189
44905
  }
44190
- const make$49 = Effect.gen(function* () {
44906
+ const make$50 = Effect.gen(function* () {
44191
44907
  const process = yield* VcsProcess;
44192
44908
  const execute = (input) => process.run({
44193
44909
  operation: "AzureDevOpsCli.execute",
@@ -44329,7 +45045,7 @@ const make$49 = Effect.gen(function* () {
44329
45045
  }).pipe(Effect.asVoid)
44330
45046
  });
44331
45047
  });
44332
- const layer$39 = Layer.effect(AzureDevOpsCli, make$49);
45048
+ const layer$39 = Layer.effect(AzureDevOpsCli, make$50);
44333
45049
  //#endregion
44334
45050
  //#region src/sourceControl/SourceControlProviderDiscovery.ts
44335
45051
  function firstNonEmptyLine(text) {
@@ -44532,7 +45248,7 @@ function toChangeRequest$5(summary) {
44532
45248
  isCrossRepository: false
44533
45249
  };
44534
45250
  }
44535
- const make$48 = Effect.gen(function* () {
45251
+ const make$49 = Effect.gen(function* () {
44536
45252
  const azure = yield* AzureDevOpsCli;
44537
45253
  return SourceControlProvider.of({
44538
45254
  kind: "azure-devops",
@@ -44624,7 +45340,7 @@ const make$48 = Effect.gen(function* () {
44624
45340
  })))
44625
45341
  });
44626
45342
  });
44627
- Layer.effect(SourceControlProvider, make$48);
45343
+ Layer.effect(SourceControlProvider, make$49);
44628
45344
  //#endregion
44629
45345
  //#region src/sourceControl/bitbucketPullRequests.ts
44630
45346
  const BitbucketRepositoryRefSchema = Schema$1.Struct({
@@ -45001,7 +45717,7 @@ function responseError(operation, response) {
45001
45717
  responseBodyLength: collected.text.length
45002
45718
  }))));
45003
45719
  }
45004
- const make$47 = Effect.gen(function* () {
45720
+ const make$48 = Effect.gen(function* () {
45005
45721
  const config = yield* BitbucketApiEnvConfig;
45006
45722
  const httpClient = yield* HttpClient.HttpClient;
45007
45723
  const fileSystem = yield* FileSystem.FileSystem;
@@ -45217,7 +45933,7 @@ const make$47 = Effect.gen(function* () {
45217
45933
  })))
45218
45934
  });
45219
45935
  });
45220
- const layer$37 = Layer.effect(BitbucketApi, make$47);
45936
+ const layer$37 = Layer.effect(BitbucketApi, make$48);
45221
45937
  //#endregion
45222
45938
  //#region src/sourceControl/BitbucketSourceControlProvider.ts
45223
45939
  function toChangeRequest$4(summary) {
@@ -45235,7 +45951,7 @@ function toChangeRequest$4(summary) {
45235
45951
  ...summary.headRepositoryOwnerLogin !== void 0 ? { headRepositoryOwnerLogin: summary.headRepositoryOwnerLogin } : {}
45236
45952
  };
45237
45953
  }
45238
- const make$46 = Effect.gen(function* () {
45954
+ const make$47 = Effect.gen(function* () {
45239
45955
  const bitbucket = yield* BitbucketApi;
45240
45956
  return SourceControlProvider.of({
45241
45957
  kind: "bitbucket",
@@ -45326,7 +46042,7 @@ const make$46 = Effect.gen(function* () {
45326
46042
  })))
45327
46043
  });
45328
46044
  });
45329
- Layer.effect(SourceControlProvider, make$46);
46045
+ Layer.effect(SourceControlProvider, make$47);
45330
46046
  const makeDiscovery = Effect.gen(function* () {
45331
46047
  return {
45332
46048
  type: "api",
@@ -45568,7 +46284,7 @@ function deriveRepositoryCloneUrlsFromCreateOutput(stdout, repository) {
45568
46284
  sshUrl: `git@${fallbackHost}:${repository}.git`
45569
46285
  };
45570
46286
  }
45571
- const make$45 = Effect.gen(function* () {
46287
+ const make$46 = Effect.gen(function* () {
45572
46288
  const process = yield* VcsProcess;
45573
46289
  const execute = (input) => process.run({
45574
46290
  operation: "GitHubCli.execute",
@@ -45686,7 +46402,7 @@ const make$45 = Effect.gen(function* () {
45686
46402
  }).pipe(Effect.asVoid)
45687
46403
  });
45688
46404
  });
45689
- const layer$35 = Layer.effect(GitHubCli, make$45);
46405
+ const layer$35 = Layer.effect(GitHubCli, make$46);
45690
46406
  //#endregion
45691
46407
  //#region src/sourceControl/gitHubAuthStatus.ts
45692
46408
  const GitHubAuthStatusAccountSchema = Schema$1.Struct({
@@ -45787,7 +46503,7 @@ const discovery$1 = {
45787
46503
  parseAuth: parseGitHubAuth,
45788
46504
  installHint: "Install the GitHub command-line tool (`gh`) via https://cli.github.com/ or your package manager (for example `brew install gh`)."
45789
46505
  };
45790
- const make$44 = Effect.gen(function* () {
46506
+ const make$45 = Effect.gen(function* () {
45791
46507
  const github = yield* GitHubCli;
45792
46508
  const listChangeRequests = (input) => {
45793
46509
  if (input.state === "open") return github.listOpenPullRequests({
@@ -45903,7 +46619,7 @@ const make$44 = Effect.gen(function* () {
45903
46619
  })))
45904
46620
  });
45905
46621
  });
45906
- Layer.effect(SourceControlProvider, make$44);
46622
+ Layer.effect(SourceControlProvider, make$45);
45907
46623
  //#endregion
45908
46624
  //#region src/sourceControl/gitLabMergeRequests.ts
45909
46625
  const GitLabProjectReferenceSchema = Schema$1.Struct({
@@ -46215,7 +46931,7 @@ function parseRepositoryPath(repository) {
46215
46931
  projectPath
46216
46932
  };
46217
46933
  }
46218
- const make$43 = Effect.gen(function* () {
46934
+ const make$44 = Effect.gen(function* () {
46219
46935
  const process = yield* VcsProcess;
46220
46936
  const run = (input, mapError) => process.run({
46221
46937
  operation: "GitLabCli.execute",
@@ -46366,7 +47082,7 @@ const make$43 = Effect.gen(function* () {
46366
47082
  }).pipe(Effect.asVoid)
46367
47083
  });
46368
47084
  });
46369
- const layer$33 = Layer.effect(GitLabCli, make$43);
47085
+ const layer$33 = Layer.effect(GitLabCli, make$44);
46370
47086
  //#endregion
46371
47087
  //#region src/sourceControl/gitLabAuthStatus.ts
46372
47088
  const HOST_LINE_PATTERN = /^(?:[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?|\[[a-f0-9:.]+\])(?::\d+)?$/iu;
@@ -46463,7 +47179,7 @@ const discovery = {
46463
47179
  refineUnknownRemote: refineUnknownGitLabRemote,
46464
47180
  installHint: "Install the GitLab command-line tool (`glab`) from https://gitlab.com/gitlab-org/cli or your package manager (for example `brew install glab`)."
46465
47181
  };
46466
- const make$42 = Effect.gen(function* () {
47182
+ const make$43 = Effect.gen(function* () {
46467
47183
  const gitlab = yield* GitLabCli;
46468
47184
  return SourceControlProvider.of({
46469
47185
  kind: "gitlab",
@@ -46551,7 +47267,7 @@ const make$42 = Effect.gen(function* () {
46551
47267
  })))
46552
47268
  });
46553
47269
  });
46554
- Layer.effect(SourceControlProvider, make$42);
47270
+ Layer.effect(SourceControlProvider, make$43);
46555
47271
  //#endregion
46556
47272
  //#region src/sourceControl/SourceControlProviderRegistry.ts
46557
47273
  const PROVIDER_DETECTION_CACHE_CAPACITY = 2048;
@@ -46707,12 +47423,12 @@ const makeWithProviders = Effect.fn("makeSourceControlProviderRegistryWithProvid
46707
47423
  })), { concurrency: "unbounded" })
46708
47424
  });
46709
47425
  });
46710
- const make$41 = Effect.gen(function* () {
46711
- const github = yield* make$44;
46712
- const gitlab = yield* make$42;
46713
- const bitbucket = yield* make$46;
47426
+ const make$42 = Effect.gen(function* () {
47427
+ const github = yield* make$45;
47428
+ const gitlab = yield* make$43;
47429
+ const bitbucket = yield* make$47;
46714
47430
  const bitbucketDiscovery = yield* makeDiscovery;
46715
- const azureDevOps = yield* make$48;
47431
+ const azureDevOps = yield* make$49;
46716
47432
  return yield* makeWithProviders([
46717
47433
  {
46718
47434
  kind: "github",
@@ -46736,7 +47452,7 @@ const make$41 = Effect.gen(function* () {
46736
47452
  }
46737
47453
  ]);
46738
47454
  });
46739
- const layer$31 = Layer.effect(SourceControlProviderRegistry, make$41);
47455
+ const layer$31 = Layer.effect(SourceControlProviderRegistry, make$42);
46740
47456
  //#endregion
46741
47457
  //#region src/sourceControl/PrTemplateDetection.ts
46742
47458
  const TEMPLATE_MAX_BYTES = 8e3;
@@ -47106,7 +47822,7 @@ function toPullRequestHeadRemoteInfo(pr) {
47106
47822
  ...pr.headRepositoryOwnerLogin !== void 0 ? { headRepositoryOwnerLogin: pr.headRepositoryOwnerLogin } : {}
47107
47823
  };
47108
47824
  }
47109
- const make$40 = Effect.gen(function* () {
47825
+ const make$41 = Effect.gen(function* () {
47110
47826
  const gitCore = yield* GitVcsDriver;
47111
47827
  const sourceControlProviders = yield* SourceControlProviderRegistry;
47112
47828
  const textGeneration = yield* TextGeneration;
@@ -48028,7 +48744,7 @@ const make$40 = Effect.gen(function* () {
48028
48744
  runStackedAction
48029
48745
  });
48030
48746
  });
48031
- const layer$30 = Layer.effect(GitManager, make$40);
48747
+ const layer$30 = Layer.effect(GitManager, make$41);
48032
48748
  //#endregion
48033
48749
  //#region src/git/GitWorkflowService.ts
48034
48750
  var GitWorkflowService = class extends Context.Service()("@p4code/cli/git/GitWorkflowService") {};
@@ -48065,7 +48781,7 @@ function nonRepositoryListRefs() {
48065
48781
  totalCount: 0
48066
48782
  };
48067
48783
  }
48068
- const make$39 = Effect.gen(function* () {
48784
+ const make$40 = Effect.gen(function* () {
48069
48785
  const registry = yield* VcsDriverRegistry;
48070
48786
  const git = yield* GitVcsDriver;
48071
48787
  const gitManager = yield* GitManager;
@@ -48151,7 +48867,7 @@ const make$39 = Effect.gen(function* () {
48151
48867
  renameBranch: (input) => ensureGit("GitWorkflowService.renameBranch", input.cwd).pipe(Effect.andThen(git.renameBranch(input)))
48152
48868
  });
48153
48869
  });
48154
- const layer$29 = Layer.effect(GitWorkflowService, make$39);
48870
+ const layer$29 = Layer.effect(GitWorkflowService, make$40);
48155
48871
  //#endregion
48156
48872
  //#region src/pullRequest/PullRequestProvider.ts
48157
48873
  /**
@@ -48512,7 +49228,7 @@ function isReviewerName(value) {
48512
49228
  const name = value.trim();
48513
49229
  return name.length > 0 && !name.startsWith("-");
48514
49230
  }
48515
- const make$38 = Effect.gen(function* () {
49231
+ const make$39 = Effect.gen(function* () {
48516
49232
  const azure = yield* AzureDevOpsCli;
48517
49233
  const detectArgs = ["--detect", "true"];
48518
49234
  const executeJson = (input) => azure.execute({
@@ -48712,7 +49428,7 @@ const make$38 = Effect.gen(function* () {
48712
49428
  }).pipe(Effect.asVoid)
48713
49429
  });
48714
49430
  });
48715
- const layer$28 = Layer.effect(AzureDevOpsPullRequestCli, make$38);
49431
+ const layer$28 = Layer.effect(AzureDevOpsPullRequestCli, make$39);
48716
49432
  //#endregion
48717
49433
  //#region src/pullRequest/AzureDevOpsPullRequestProvider.ts
48718
49434
  const CAPABILITIES$3 = {
@@ -48787,7 +49503,7 @@ function toChangeRequest$1(pullRequest) {
48787
49503
  labels: []
48788
49504
  };
48789
49505
  }
48790
- const make$37 = Effect.gen(function* () {
49506
+ const make$38 = Effect.gen(function* () {
48791
49507
  const cli = yield* AzureDevOpsPullRequestCli;
48792
49508
  const fail = (operation) => (error) => new PullRequestProviderError({
48793
49509
  provider: "azure-devops",
@@ -49527,7 +50243,7 @@ function mergeStrategy(method) {
49527
50243
  default: return "merge_commit";
49528
50244
  }
49529
50245
  }
49530
- const make$36 = Effect.gen(function* () {
50246
+ const make$37 = Effect.gen(function* () {
49531
50247
  const bitbucket = yield* BitbucketApi;
49532
50248
  /**
49533
50249
  * The repository's own path, and the workspace above it — which the people who may review are
@@ -49807,7 +50523,7 @@ const make$36 = Effect.gen(function* () {
49807
50523
  }).pipe(Effect.asVoid))
49808
50524
  });
49809
50525
  });
49810
- const layer$27 = Layer.effect(BitbucketPullRequestApi, make$36);
50526
+ const layer$27 = Layer.effect(BitbucketPullRequestApi, make$37);
49811
50527
  //#endregion
49812
50528
  //#region src/pullRequest/BitbucketPullRequestProvider.ts
49813
50529
  const CAPABILITIES$2 = {
@@ -49887,7 +50603,7 @@ function toChangeRequest(pullRequest) {
49887
50603
  labels: []
49888
50604
  };
49889
50605
  }
49890
- const make$35 = Effect.gen(function* () {
50606
+ const make$36 = Effect.gen(function* () {
49891
50607
  const api = yield* BitbucketPullRequestApi;
49892
50608
  const fail = (operation) => (error) => new PullRequestProviderError({
49893
50609
  provider: "bitbucket",
@@ -51692,8 +52408,8 @@ function filterQualifiers(filters, viewer) {
51692
52408
  */
51693
52409
  function matchesFilters(item, filters, viewer) {
51694
52410
  if (filters === void 0) return true;
51695
- const labels = item.labels.map((label) => label.name.trim().toLowerCase());
51696
- const holds = (label) => labels.includes(label.trim().toLowerCase());
52411
+ const labels = new Set(item.labels.map((label) => label.name.trim().toLowerCase()));
52412
+ const holds = (label) => labels.has(label.trim().toLowerCase());
51697
52413
  return (filters.draft === void 0 || item.isDraft === (filters.draft === "only")) && (filters.review === void 0 || (filters.review === "none" ? item.reviewDecision === null : item.reviewDecision === filters.review)) && (filters.checks === void 0 || item.checksState === filters.checks) && (filters.labels === void 0 || filters.labels.every((group) => group.some(holds))) && (filters.excludedLabels === void 0 || !filters.excludedLabels.some(holds)) && (filters.author === void 0 || item.author?.login.toLowerCase() === resolvePullRequestAuthorFilter(filters.author, viewer).toLowerCase());
51698
52414
  }
51699
52415
  function involvementArgs(input) {
@@ -51774,7 +52490,7 @@ function actionArgs$1(action, mergeMethod, updateMethod) {
51774
52490
  case "reopen": return ["reopen"];
51775
52491
  }
51776
52492
  }
51777
- const make$34 = Effect.gen(function* () {
52493
+ const make$35 = Effect.gen(function* () {
51778
52494
  const github = yield* GitHubCli;
51779
52495
  /**
51780
52496
  * The pull request's own node id, which is what a mutation against the pull request itself is
@@ -52494,7 +53210,7 @@ const make$34 = Effect.gen(function* () {
52494
53210
  })))
52495
53211
  });
52496
53212
  });
52497
- const layer$26 = Layer.effect(GitHubPullRequestCli, make$34);
53213
+ const layer$26 = Layer.effect(GitHubPullRequestCli, make$35);
52498
53214
  //#endregion
52499
53215
  //#region src/pullRequest/GitHubPullRequestProvider.ts
52500
53216
  const CAPABILITIES$1 = {
@@ -52609,7 +53325,7 @@ function loginAvatarUrl(login, host) {
52609
53325
  }
52610
53326
  /** True where markdown would render nothing: whitespace, or only HTML comments. */
52611
53327
  const rendersEmpty = (body) => body.replace(/<!--[\s\S]*?-->/g, "").trim().length === 0;
52612
- const make$33 = Effect.gen(function* () {
53328
+ const make$34 = Effect.gen(function* () {
52613
53329
  const cli = yield* GitHubPullRequestCli;
52614
53330
  const fail = (operation) => (error) => new PullRequestProviderError({
52615
53331
  provider: "github",
@@ -53628,7 +54344,7 @@ function actionArgs(action, mergeMethod) {
53628
54344
  case "reopen": return ["reopen"];
53629
54345
  }
53630
54346
  }
53631
- const make$32 = Effect.gen(function* () {
54347
+ const make$33 = Effect.gen(function* () {
53632
54348
  const gitlab = yield* GitLabCli;
53633
54349
  const api = (input) => gitlab.execute({
53634
54350
  cwd: input.cwd,
@@ -54199,7 +54915,7 @@ const make$32 = Effect.gen(function* () {
54199
54915
  }).pipe(Effect.asVoid)
54200
54916
  });
54201
54917
  });
54202
- const layer$25 = Layer.effect(GitLabPullRequestCli, make$32);
54918
+ const layer$25 = Layer.effect(GitLabPullRequestCli, make$33);
54203
54919
  //#endregion
54204
54920
  //#region src/pullRequest/GitLabPullRequestProvider.ts
54205
54921
  const CAPABILITIES = {
@@ -54279,7 +54995,7 @@ function reasonFor(error) {
54279
54995
  if (error._tag === "GitLabCliAuthenticationError") return "unauthenticated";
54280
54996
  return "failed";
54281
54997
  }
54282
- const make$31 = Effect.gen(function* () {
54998
+ const make$32 = Effect.gen(function* () {
54283
54999
  const cli = yield* GitLabPullRequestCli;
54284
55000
  const fail = (operation) => (error) => new PullRequestProviderError({
54285
55001
  provider: "gitlab",
@@ -54422,13 +55138,13 @@ function fromProviders(providers) {
54422
55138
  * The hosts this build can read change requests from. A host with no entry here still shows up
54423
55139
  * in the provider list as unimplemented, so its projects are explained rather than missing.
54424
55140
  */
54425
- const make$30 = Effect.map(Effect.all([
54426
- make$33,
54427
- make$31,
54428
- make$35,
54429
- make$37
55141
+ const make$31 = Effect.map(Effect.all([
55142
+ make$34,
55143
+ make$32,
55144
+ make$36,
55145
+ make$38
54430
55146
  ]), fromProviders);
54431
- const layer$24 = Layer.effect(PullRequestProviderRegistry, make$30).pipe(Layer.provide(layer$26.pipe(Layer.provide(layer$35))), Layer.provide(layer$25.pipe(Layer.provide(layer$33))), Layer.provide(layer$27.pipe(Layer.provide(layer$37))), Layer.provide(layer$28.pipe(Layer.provide(layer$39))));
55147
+ const layer$24 = Layer.effect(PullRequestProviderRegistry, make$31).pipe(Layer.provide(layer$26.pipe(Layer.provide(layer$35))), Layer.provide(layer$25.pipe(Layer.provide(layer$33))), Layer.provide(layer$27.pipe(Layer.provide(layer$37))), Layer.provide(layer$28.pipe(Layer.provide(layer$39))));
54432
55148
  //#endregion
54433
55149
  //#region src/pullRequest/PullRequestService.ts
54434
55150
  /**
@@ -54616,7 +55332,7 @@ function repositoryIdentityOf(project) {
54616
55332
  if (identity.displayName) return identity.displayName;
54617
55333
  return identity.owner && identity.name ? `${identity.owner}/${identity.name}` : null;
54618
55334
  }
54619
- const make$29 = Effect.gen(function* () {
55335
+ const make$30 = Effect.gen(function* () {
54620
55336
  const registry = yield* PullRequestProviderRegistry;
54621
55337
  const projections = yield* ProjectionSnapshotQuery;
54622
55338
  const sourceControlProviders = yield* SourceControlProviderRegistry;
@@ -54782,8 +55498,8 @@ const make$29 = Effect.gen(function* () {
54782
55498
  */
54783
55499
  const matchesRowFilters = (item, filters, viewer) => {
54784
55500
  if (filters === void 0) return true;
54785
- const labels = item.labels.map((label) => label.name.trim().toLowerCase());
54786
- const holds = (label) => labels.includes(label.trim().toLowerCase());
55501
+ const labels = new Set(item.labels.map((label) => label.name.trim().toLowerCase()));
55502
+ const holds = (label) => labels.has(label.trim().toLowerCase());
54787
55503
  return (filters.draft === void 0 || item.isDraft === (filters.draft === "only")) && (filters.review === void 0 || item.reviewDecision === void 0 || (filters.review === "none" ? item.reviewDecision === null : item.reviewDecision === filters.review)) && (filters.labels === void 0 || filters.labels.every((group) => group.some(holds))) && (filters.excludedLabels === void 0 || !filters.excludedLabels.some(holds)) && (filters.author === void 0 || item.author?.login.toLowerCase() === resolvePullRequestAuthorFilter(filters.author, viewer).toLowerCase());
54788
55504
  };
54789
55505
  const toEntry = (input) => {
@@ -55586,7 +56302,7 @@ const make$29 = Effect.gen(function* () {
55586
56302
  invalidate
55587
56303
  });
55588
56304
  });
55589
- const layer$23 = Layer.effect(PullRequestService, make$29);
56305
+ const layer$23 = Layer.effect(PullRequestService, make$30);
55590
56306
  //#endregion
55591
56307
  //#region src/orchestration/ThreadWorkspaceLifecycle.ts
55592
56308
  var ThreadWorkspaceLifecycleError = class extends Data.TaggedError("ThreadWorkspaceLifecycleError") {};
@@ -55620,7 +56336,7 @@ const mapLifecycleError = Effect.mapError((cause) => cause instanceof ThreadWork
55620
56336
  detail: "Thread workspace lifecycle operation failed.",
55621
56337
  cause
55622
56338
  }));
55623
- const make$28 = Effect.gen(function* () {
56339
+ const make$29 = Effect.gen(function* () {
55624
56340
  const snapshots = yield* ProjectionSnapshotQuery;
55625
56341
  const engine = yield* OrchestrationEngineService;
55626
56342
  const gitWorkflow = yield* GitWorkflowService;
@@ -55801,7 +56517,7 @@ const make$28 = Effect.gen(function* () {
55801
56517
  record
55802
56518
  };
55803
56519
  });
55804
- const layer$22 = Layer.effect(ThreadWorkspaceLifecycleService, make$28);
56520
+ const layer$22 = Layer.effect(ThreadWorkspaceLifecycleService, make$29);
55805
56521
  //#endregion
55806
56522
  //#region src/textGeneration/BtwRequestCoordinator.ts
55807
56523
  const MAX_PENDING_BTW_CANCELLATIONS = 256;
@@ -57955,6 +58671,9 @@ const observeRpcStreamEffect = (method, effect, traceAttributes) => {
57955
58671
  return withRpcStreamTracing(method, instrumented, traceAttributes);
57956
58672
  };
57957
58673
  //#endregion
58674
+ //#region src/provider/Services/ProviderSessionDirectory.ts
58675
+ var ProviderSessionDirectory = class extends Context.Service()("@p4code/cli/provider/Services/ProviderSessionDirectory") {};
58676
+ //#endregion
57958
58677
  //#region src/provider/providerMaintenanceCommandCoordinator.ts
57959
58678
  const makeProviderMaintenanceCommandCoordinator = Effect.fn("makeProviderMaintenanceCommandCoordinator")(function* (input) {
57960
58679
  const runningTargetsRef = yield* Ref.make(/* @__PURE__ */ new Set());
@@ -58342,7 +59061,7 @@ function makeUpdateState(input) {
58342
59061
  output: input.output ?? null
58343
59062
  };
58344
59063
  }
58345
- const make$27 = Effect.fn("ProviderMaintenanceRunner.make")(function* () {
59064
+ const make$28 = Effect.fn("ProviderMaintenanceRunner.make")(function* () {
58346
59065
  const providerRegistry = yield* ProviderRegistry;
58347
59066
  const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
58348
59067
  const httpClient = yield* HttpClient.HttpClient;
@@ -58457,7 +59176,7 @@ const make$27 = Effect.fn("ProviderMaintenanceRunner.make")(function* () {
58457
59176
  });
58458
59177
  return ProviderMaintenanceRunner.of({ updateProvider });
58459
59178
  });
58460
- const layer$21 = Layer.effect(ProviderMaintenanceRunner, make$27());
59179
+ const layer$21 = Layer.effect(ProviderMaintenanceRunner, make$28());
58461
59180
  //#endregion
58462
59181
  //#region src/provider/Drivers/ClaudeHome.ts
58463
59182
  const resolveClaudeHomePath = Effect.fn("resolveClaudeHomePath")(function* (config) {
@@ -59473,7 +60192,7 @@ Layer.succeed(UsageService, UsageService.of({ readSummary: (input) => Effect.suc
59473
60192
  },
59474
60193
  scanDurationMs: 0
59475
60194
  }) }));
59476
- const make$26 = Effect.gen(function* () {
60195
+ const make$27 = Effect.gen(function* () {
59477
60196
  const fileSystem = yield* FileSystem.FileSystem;
59478
60197
  const path = yield* Path.Path;
59479
60198
  const config = yield* ServerConfig$1;
@@ -59705,7 +60424,7 @@ const make$26 = Effect.gen(function* () {
59705
60424
  };
59706
60425
  }) };
59707
60426
  });
59708
- const layer$20 = Layer.effect(UsageService, make$26);
60427
+ const layer$20 = Layer.effect(UsageService, make$27);
59709
60428
  //#endregion
59710
60429
  //#region src/feed/FeedStore.ts
59711
60430
  const storageFailure = (message) => new FeedError({
@@ -60069,7 +60788,7 @@ const jsonRequest = Effect.fn("FeedService.jsonRequest")(function* (url, token,
60069
60788
  catch: () => fail("hub_unavailable", "Hub returned invalid JSON.")
60070
60789
  });
60071
60790
  });
60072
- const make$25 = Effect.gen(function* () {
60791
+ const make$26 = Effect.gen(function* () {
60073
60792
  const hubLink = yield* HubLink;
60074
60793
  const providers = yield* ProviderInstanceRegistry;
60075
60794
  const config = yield* ServerConfig$1;
@@ -60307,7 +61026,7 @@ var FeedService = class extends Context.Reference("@p4code/cli/feed/FeedService"
60307
61026
  markRead: unavailable,
60308
61027
  cleanup: unavailable
60309
61028
  }) }) {};
60310
- const layer$19 = Layer.effect(FeedService, make$25);
61029
+ const layer$19 = Layer.effect(FeedService, make$26);
60311
61030
  const SKILL_MANIFEST_FILENAME = "SKILL.md";
60312
61031
  /**
60313
61032
  * Split a catalogue id (`owner/repo/skill-name`) into its parts.
@@ -60453,7 +61172,7 @@ const emptyFetch = (id, unavailable) => ({
60453
61172
  skipped: [],
60454
61173
  unavailable
60455
61174
  });
60456
- const make$24 = Effect.gen(function* () {
61175
+ const make$25 = Effect.gen(function* () {
60457
61176
  const http = yield* HttpClient.HttpClient;
60458
61177
  const request = Effect.fn("SkillRegistry.request")(function* (url) {
60459
61178
  return yield* http.execute(HttpClientRequest.get(url).pipe(HttpClientRequest.setHeader("accept", "application/json"), HttpClientRequest.setHeader("user-agent", "p4code"))).pipe(Effect.timeout(REQUEST_TIMEOUT_MS));
@@ -60524,7 +61243,7 @@ const make$24 = Effect.gen(function* () {
60524
61243
  fetch
60525
61244
  };
60526
61245
  });
60527
- const layer$18 = Layer.effect(SkillRegistry, make$24);
61246
+ const layer$18 = Layer.effect(SkillRegistry, make$25);
60528
61247
  //#endregion
60529
61248
  //#region src/mcp/McpInvocationContext.ts
60530
61249
  var McpInvocationContext = class extends Context.Service()("@p4code/cli/mcp/McpInvocationContext") {};
@@ -60752,7 +61471,7 @@ const classifyResponseError = (context, error) => {
60752
61471
  });
60753
61472
  }
60754
61473
  };
60755
- const make$23 = Effect.gen(function* PreviewAutomationBrokerMake() {
61474
+ const make$24 = Effect.gen(function* PreviewAutomationBrokerMake() {
60756
61475
  const crypto = yield* Crypto.Crypto;
60757
61476
  const state = yield* SynchronizedRef.make({
60758
61477
  clients: /* @__PURE__ */ new Map(),
@@ -60986,7 +61705,7 @@ const make$23 = Effect.gen(function* PreviewAutomationBrokerMake() {
60986
61705
  invoke
60987
61706
  });
60988
61707
  }).pipe(Effect.withSpan("PreviewAutomationBroker.make"));
60989
- const layer$17 = Layer.effect(PreviewAutomationBroker, make$23);
61708
+ const layer$17 = Layer.effect(PreviewAutomationBroker, make$24);
60990
61709
  //#endregion
60991
61710
  //#region src/preview/Manager.ts
60992
61711
  /**
@@ -61050,7 +61769,7 @@ const buildIdleSnapshot = (input) => ({
61050
61769
  viewport: FILL_PREVIEW_VIEWPORT,
61051
61770
  updatedAt: input.updatedAt
61052
61771
  });
61053
- const make$22 = Effect.gen(function* PreviewManagerMake() {
61772
+ const make$23 = Effect.gen(function* PreviewManagerMake() {
61054
61773
  const serverEpoch = NodeCrypto.randomUUID();
61055
61774
  const stateRef = yield* SynchronizedRef.make(initialState);
61056
61775
  const eventsPubSub = yield* PubSub.unbounded();
@@ -61281,7 +62000,7 @@ const make$22 = Effect.gen(function* PreviewManagerMake() {
61281
62000
  subscribeEvents: PubSub.subscribe(eventsPubSub)
61282
62001
  });
61283
62002
  }).pipe(Effect.withSpan("PreviewManager.make"));
61284
- const layer$16 = Layer.effect(PreviewManager, make$22);
62003
+ const layer$16 = Layer.effect(PreviewManager, make$23);
61285
62004
  //#endregion
61286
62005
  //#region src/workspace/WorkspaceSearchIndex.ts
61287
62006
  const WORKSPACE_INDEX_MAX_ENTRIES = 25e3;
@@ -61415,7 +62134,7 @@ const waitForScan = (cwd, finder, onFailure) => Effect.try({
61415
62134
  timeout: WORKSPACE_INDEX_SCAN_TIMEOUT
61416
62135
  })
61417
62136
  }), Effect.withSpan("WorkspaceSearchIndex.waitForScan"));
61418
- const make$21 = Effect.fn("WorkspaceSearchIndex.make")(function* (cwd) {
62137
+ const make$22 = Effect.fn("WorkspaceSearchIndex.make")(function* (cwd) {
61419
62138
  const finder = yield* Effect.acquireRelease(createFinder(cwd), (finder) => Effect.try({
61420
62139
  try: () => finder.destroy(),
61421
62140
  catch: (cause) => new WorkspaceSearchIndexDestroyFailed({
@@ -61489,7 +62208,7 @@ const make$21 = Effect.fn("WorkspaceSearchIndex.make")(function* (cwd) {
61489
62208
  * workspace root. WorkspaceSearchIndexMap owns memoization and idle cleanup;
61490
62209
  * using a default cwd here would mix resources from different workspaces.
61491
62210
  */
61492
- const layer$15 = (cwd) => Layer.effect(WorkspaceSearchIndex, make$21(cwd));
62211
+ const layer$15 = (cwd) => Layer.effect(WorkspaceSearchIndex, make$22(cwd));
61493
62212
  var WorkspaceSearchIndexMap = class extends LayerMap.Service()("@p4code/cli/workspace/WorkspaceSearchIndexMap", {
61494
62213
  lookup: layer$15,
61495
62214
  idleTimeToLive: WORKSPACE_INDEX_IDLE_TTL
@@ -61553,7 +62272,7 @@ const resolveBrowseTarget = Effect.fn("WorkspaceEntries.resolveBrowseTarget")(fu
61553
62272
  if (!input.cwd) return yield* new WorkspaceEntriesCurrentProjectRequiredError({ partialPath: input.partialPath });
61554
62273
  return path.resolve(expandHomePath$1(input.cwd, path), input.partialPath);
61555
62274
  });
61556
- const make$20 = Effect.gen(function* () {
62275
+ const make$21 = Effect.gen(function* () {
61557
62276
  const path = yield* Path.Path;
61558
62277
  const workspacePaths = yield* WorkspacePaths;
61559
62278
  const workspaceSearchIndexes = yield* WorkspaceSearchIndexMap;
@@ -61627,7 +62346,7 @@ const make$20 = Effect.gen(function* () {
61627
62346
  search
61628
62347
  });
61629
62348
  });
61630
- const layer$14 = Layer.effect(WorkspaceEntries, make$20).pipe(Layer.provide(WorkspaceSearchIndexMap.layer));
62349
+ const layer$14 = Layer.effect(WorkspaceEntries, make$21).pipe(Layer.provide(WorkspaceSearchIndexMap.layer));
61631
62350
  //#endregion
61632
62351
  //#region src/workspace/WorkspaceFileSystem.ts
61633
62352
  /**
@@ -61686,7 +62405,7 @@ Schema$1.Union([
61686
62405
  ]);
61687
62406
  /** Service tag for workspace file operations. */
61688
62407
  var WorkspaceFileSystem = class extends Context.Service()("@p4code/cli/workspace/WorkspaceFileSystem") {};
61689
- const make$19 = Effect.gen(function* () {
62408
+ const make$20 = Effect.gen(function* () {
61690
62409
  const fileSystem = yield* FileSystem.FileSystem;
61691
62410
  const path = yield* Path.Path;
61692
62411
  const workspacePaths = yield* WorkspacePaths;
@@ -61830,7 +62549,7 @@ const make$19 = Effect.gen(function* () {
61830
62549
  writeFile
61831
62550
  });
61832
62551
  });
61833
- const layer$13 = Layer.effect(WorkspaceFileSystem, make$19);
62552
+ const layer$13 = Layer.effect(WorkspaceFileSystem, make$20);
61834
62553
  //#endregion
61835
62554
  //#region src/vcs/VcsStatusBroadcaster.ts
61836
62555
  const DEFAULT_VCS_STATUS_REFRESH_INTERVAL = Duration.seconds(30);
@@ -61902,7 +62621,7 @@ function fingerprintStatusPart(status) {
61902
62621
  return JSON.stringify(status);
61903
62622
  }
61904
62623
  const normalizeCwd = (cwd) => Effect.service(FileSystem.FileSystem).pipe(Effect.flatMap((fs) => fs.realPath(cwd)), Effect.orElseSucceed(() => cwd));
61905
- const make$18 = Effect.gen(function* () {
62624
+ const make$19 = Effect.gen(function* () {
61906
62625
  const workflow = yield* GitWorkflowService;
61907
62626
  const fs = yield* FileSystem.FileSystem;
61908
62627
  const changesPubSub = yield* Effect.acquireRelease(PubSub.unbounded(), (pubsub) => PubSub.shutdown(pubsub));
@@ -62126,7 +62845,7 @@ const make$18 = Effect.gen(function* () {
62126
62845
  streamStatus
62127
62846
  });
62128
62847
  });
62129
- const layer$12 = Layer.effect(VcsStatusBroadcaster, make$18);
62848
+ const layer$12 = Layer.effect(VcsStatusBroadcaster, make$19);
62130
62849
  //#endregion
62131
62850
  //#region src/vcs/VcsProvisioningService.ts
62132
62851
  var VcsProvisioningService = class extends Context.Service()("@p4code/cli/vcs/VcsProvisioningService") {};
@@ -62139,7 +62858,7 @@ function resolveRequestedKind(kind) {
62139
62858
  }));
62140
62859
  return Effect.succeed(kind);
62141
62860
  }
62142
- const make$17 = Effect.gen(function* () {
62861
+ const make$18 = Effect.gen(function* () {
62143
62862
  const registry = yield* VcsDriverRegistry;
62144
62863
  const initRepository = Effect.fn("VcsProvisioningService.initRepository")(function* (input) {
62145
62864
  const kind = yield* resolveRequestedKind(input.kind);
@@ -62147,11 +62866,11 @@ const make$17 = Effect.gen(function* () {
62147
62866
  });
62148
62867
  return VcsProvisioningService.of({ initRepository });
62149
62868
  });
62150
- const layer$11 = Layer.effect(VcsProvisioningService, make$17);
62869
+ const layer$11 = Layer.effect(VcsProvisioningService, make$18);
62151
62870
  //#endregion
62152
62871
  //#region src/review/ReviewService.ts
62153
62872
  var ReviewService = class extends Context.Service()("@p4code/cli/review/ReviewService") {};
62154
- const make$16 = Effect.gen(function* () {
62873
+ const make$17 = Effect.gen(function* () {
62155
62874
  const config = yield* ServerConfig$1;
62156
62875
  const fileSystem = yield* FileSystem.FileSystem;
62157
62876
  const path = yield* Path.Path;
@@ -62207,7 +62926,7 @@ const make$16 = Effect.gen(function* () {
62207
62926
  });
62208
62927
  return ReviewService.of({ getDiffPreview });
62209
62928
  });
62210
- const layer$10 = Layer.effect(ReviewService, make$16);
62929
+ const layer$10 = Layer.effect(ReviewService, make$17);
62211
62930
  //#endregion
62212
62931
  //#region src/diagnostics/ProcessDiagnostics.ts
62213
62932
  const PROCESS_QUERY_TIMEOUT_MS = 1e3;
@@ -62502,7 +63221,7 @@ function assertDescendantPid(pid) {
62502
63221
  }));
62503
63222
  }));
62504
63223
  }
62505
- const make$15 = Effect.gen(function* () {
63224
+ const make$16 = Effect.gen(function* () {
62506
63225
  const spawner = yield* ChildProcessSpawner$1.ChildProcessSpawner;
62507
63226
  const read = Effect.gen(function* () {
62508
63227
  const readAt = yield* DateTime.now;
@@ -62546,7 +63265,7 @@ const make$15 = Effect.gen(function* () {
62546
63265
  signal
62547
63266
  });
62548
63267
  });
62549
- const layer$9 = Layer.effect(ProcessDiagnostics, make$15);
63268
+ const layer$9 = Layer.effect(ProcessDiagnostics, make$16);
62550
63269
  //#endregion
62551
63270
  //#region src/diagnostics/ProcessResourceMonitor.ts
62552
63271
  const SAMPLE_INTERVAL_MS = 5e3;
@@ -62697,7 +63416,7 @@ function aggregateProcessResourceHistory(input) {
62697
63416
  }) : Option.none()
62698
63417
  };
62699
63418
  }
62700
- const make$14 = Effect.gen(function* () {
63419
+ const make$15 = Effect.gen(function* () {
62701
63420
  const spawner = yield* ChildProcessSpawner$1.ChildProcessSpawner;
62702
63421
  const state = yield* Ref.make({
62703
63422
  samples: [],
@@ -62746,7 +63465,7 @@ const make$14 = Effect.gen(function* () {
62746
63465
  });
62747
63466
  return ProcessResourceMonitor.of({ readHistory });
62748
63467
  });
62749
- const layer$8 = Layer.effect(ProcessResourceMonitor, make$14);
63468
+ const layer$8 = Layer.effect(ProcessResourceMonitor, make$15);
62750
63469
  //#endregion
62751
63470
  //#region src/diagnostics/TraceDiagnostics.ts
62752
63471
  var TraceFileReadError = class extends Schema$1.TaggedErrorClass()("TraceFileReadError", {
@@ -62994,7 +63713,7 @@ function readTraceFile(fileSystem, path) {
62994
63713
  cause
62995
63714
  })) }));
62996
63715
  }
62997
- const make$13 = Effect.gen(function* () {
63716
+ const make$14 = Effect.gen(function* () {
62998
63717
  const fileSystem = yield* FileSystem.FileSystem;
62999
63718
  const read = Effect.fn("TraceDiagnostics.read")(function* (options) {
63000
63719
  const readAt = options.readAt ?? (yield* DateTime.now);
@@ -63038,7 +63757,7 @@ const make$13 = Effect.gen(function* () {
63038
63757
  });
63039
63758
  return TraceDiagnostics.of({ read });
63040
63759
  });
63041
- const layer$7 = Layer.effect(TraceDiagnostics, make$13);
63760
+ const layer$7 = Layer.effect(TraceDiagnostics, make$14);
63042
63761
  function readTraceDiagnostics(options) {
63043
63762
  return Effect.gen(function* () {
63044
63763
  return yield* (yield* TraceDiagnostics).read(options);
@@ -63062,7 +63781,7 @@ const VCS_PROBES = [{
63062
63781
  installHint: "Install Jujutsu with `brew install jj` or from https://github.com/jj-vcs/jj."
63063
63782
  }];
63064
63783
  var SourceControlDiscovery = class extends Context.Service()("@p4code/cli/sourceControl/SourceControlDiscovery") {};
63065
- const make$12 = Effect.gen(function* () {
63784
+ const make$13 = Effect.gen(function* () {
63066
63785
  const config = yield* ServerConfig$1;
63067
63786
  const process = yield* VcsProcess;
63068
63787
  const sourceControlProviders = yield* SourceControlProviderRegistry;
@@ -63111,7 +63830,7 @@ const make$12 = Effect.gen(function* () {
63111
63830
  sourceControlProviders: sourceControlProviders.discover
63112
63831
  }) });
63113
63832
  });
63114
- const layer$6 = Layer.effect(SourceControlDiscovery, make$12);
63833
+ const layer$6 = Layer.effect(SourceControlDiscovery, make$13);
63115
63834
  //#endregion
63116
63835
  //#region src/sourceControl/SourceControlRepositoryService.ts
63117
63836
  const isSourceControlRepositoryError = Schema$1.is(SourceControlRepositoryError);
@@ -63144,7 +63863,7 @@ function expandHomePath(input, path) {
63144
63863
  if (input.startsWith("~/") || input.startsWith("~\\")) return path.join(NodeOS.homedir(), input.slice(2));
63145
63864
  return input;
63146
63865
  }
63147
- const make$11 = Effect.gen(function* () {
63866
+ const make$12 = Effect.gen(function* () {
63148
63867
  const config = yield* ServerConfig$1;
63149
63868
  const fileSystem = yield* FileSystem.FileSystem;
63150
63869
  const git = yield* GitVcsDriver;
@@ -63283,7 +64002,7 @@ const make$11 = Effect.gen(function* () {
63283
64002
  publishRepository: (input) => publishRepository(input).pipe(mapRepositoryError("publishRepository", input.provider))
63284
64003
  });
63285
64004
  });
63286
- const layer$5 = Layer.effect(SourceControlRepositoryService, make$11);
64005
+ const layer$5 = Layer.effect(SourceControlRepositoryService, make$12);
63287
64006
  //#endregion
63288
64007
  //#region src/ws.ts
63289
64008
  /** Matches `p4c hub token add`, so a token minted here and one minted there are the same thing. */
@@ -63385,7 +64104,7 @@ function projectSetupScriptCompatibilityDetail(error) {
63385
64104
  }
63386
64105
  }
63387
64106
  function isThreadDetailEvent(event) {
63388
- return event.type === "thread.message-sent" || event.type === "thread.proposed-plan-upserted" || event.type === "thread.activity-appended" || event.type === "thread.turn-diff-completed" || event.type === "thread.reverted" || event.type === "thread.session-set";
64107
+ return event.type === "thread.message-sent" || event.type === "thread.proposed-plan-upserted" || event.type === "thread.scheduled-task.created" || event.type === "thread.scheduled-task.cancelled" || event.type === "thread.scheduled-task.fired" || event.type === "thread.activity-appended" || event.type === "thread.turn-diff-completed" || event.type === "thread.reverted" || event.type === "thread.session-set";
63389
64108
  }
63390
64109
  const PROVIDER_STATUS_DEBOUNCE_MS = 200;
63391
64110
  const SHELL_RESUME_MAX_GAP = 1e3;
@@ -63583,6 +64302,7 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.t
63583
64302
  const previewManager = yield* PreviewManager;
63584
64303
  const portDiscovery = yield* PortDiscovery;
63585
64304
  const providerRegistry = yield* ProviderRegistry;
64305
+ const providerSessionDirectory = yield* ProviderSessionDirectory;
63586
64306
  const providerMaintenanceRunner = yield* ProviderMaintenanceRunner;
63587
64307
  const serverSelfUpdate = yield* ServerSelfUpdate;
63588
64308
  const textGeneration = yield* TextGeneration;
@@ -63979,7 +64699,22 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.t
63979
64699
  onNone: () => false,
63980
64700
  onSome: (thread) => thread.session !== null && thread.session.status !== "stopped"
63981
64701
  })), Effect.orElseSucceed(() => false)) : false;
63982
- const result = yield* dispatchNormalizedCommand(normalizedCommand);
64702
+ const result = normalizedCommand.type === "thread.fork" ? yield* Effect.uninterruptible(Effect.gen(function* () {
64703
+ if (yield* projectionSnapshotQuery.getThreadShellById(normalizedCommand.threadId).pipe(Effect.map(Option.isSome), Effect.orElseSucceed(() => false))) return yield* dispatchNormalizedCommand(normalizedCommand);
64704
+ const forkBinding = yield* providerSessionDirectory.getBinding(normalizedCommand.sourceThreadId).pipe(Effect.map((source) => buildForkedProviderBinding(normalizedCommand.threadId, Option.getOrUndefined(source))), Effect.mapError((error) => new OrchestrationDispatchCommandError({
64705
+ message: `Could not read the source thread's provider session: ${error.message}`,
64706
+ cause: error
64707
+ })));
64708
+ if (forkBinding.rejection !== void 0) return yield* new OrchestrationDispatchCommandError({ message: describeThreadForkRejection(forkBinding.rejection) });
64709
+ yield* providerSessionDirectory.upsert(forkBinding.binding).pipe(Effect.mapError((error) => new OrchestrationDispatchCommandError({
64710
+ message: `Could not save the fork's provider session: ${error.message}`,
64711
+ cause: error
64712
+ })));
64713
+ return yield* dispatchNormalizedCommand(normalizedCommand).pipe(Effect.tapError(() => providerSessionDirectory.remove(normalizedCommand.threadId).pipe(Effect.catchCause((cause) => Effect.logWarning("failed to remove fork binding after dispatch failure", {
64714
+ threadId: normalizedCommand.threadId,
64715
+ cause
64716
+ })))));
64717
+ })) : yield* dispatchNormalizedCommand(normalizedCommand);
63983
64718
  if (normalizedCommand.type === "thread.archive") {
63984
64719
  const archivedThreadIds = result.events?.filter((event) => event.type === "thread.archived").map((event) => event.payload.threadId);
63985
64720
  if (archivedThreadIds === void 0 || archivedThreadIds.length === 0) return yield* new OrchestrationDispatchCommandError({ message: "Archive command completed without authoritative archive events." });
@@ -64570,7 +65305,7 @@ function toPersistenceSqlOrDecodeError(sqlOperation, decodeOperation, correlatio
64570
65305
  cause
64571
65306
  });
64572
65307
  }
64573
- const make$10 = Effect.gen(function* () {
65308
+ const make$11 = Effect.gen(function* () {
64574
65309
  const sql = yield* SqlClient.SqlClient;
64575
65310
  const upsertRuntimeRow = SqlSchema.void({
64576
65311
  Request: ProviderSessionRuntimeDbRowSchema,
@@ -64673,7 +65408,7 @@ const make$10 = Effect.gen(function* () {
64673
65408
  deleteByThreadId
64674
65409
  };
64675
65410
  });
64676
- const layer$4 = Layer.effect(ProviderSessionRuntimeRepository, make$10);
65411
+ const layer$4 = Layer.effect(ProviderSessionRuntimeRepository, make$11);
64677
65412
  //#endregion
64678
65413
  //#region src/provider/Errors.ts
64679
65414
  /**
@@ -64798,9 +65533,6 @@ var ProviderSessionDirectoryPersistenceError = class extends Schema$1.TaggedErro
64798
65533
  }
64799
65534
  };
64800
65535
  //#endregion
64801
- //#region src/provider/Services/ProviderSessionDirectory.ts
64802
- var ProviderSessionDirectory = class extends Context.Service()("@p4code/cli/provider/Services/ProviderSessionDirectory") {};
64803
- //#endregion
64804
65536
  //#region src/provider/Layers/ProviderSessionDirectory.ts
64805
65537
  const decodeProviderDriverKindValue = Schema$1.decodeUnknownEffect(ProviderDriverKind);
64806
65538
  function toPersistenceError(operation) {
@@ -64881,12 +65613,14 @@ const makeProviderSessionDirectory = Effect.gen(function* () {
64881
65613
  detail: `No persisted provider binding found for thread '${threadId}'.`
64882
65614
  }))
64883
65615
  })));
65616
+ const remove = (threadId) => repository.deleteByThreadId({ threadId }).pipe(Effect.mapError(toPersistenceError("ProviderSessionDirectory.remove:deleteByThreadId")));
64884
65617
  const listThreadIds = () => repository.list().pipe(Effect.mapError(toPersistenceError("ProviderSessionDirectory.listThreadIds:list")), Effect.map((rows) => rows.map((row) => row.threadId)));
64885
65618
  const listBindings = () => repository.list().pipe(Effect.mapError(toPersistenceError("ProviderSessionDirectory.listBindings:list")), Effect.flatMap((rows) => Effect.forEach(rows, (row) => toRuntimeBinding(row, "ProviderSessionDirectory.listBindings"), { concurrency: "unbounded" })));
64886
65619
  return {
64887
65620
  upsert,
64888
65621
  getProvider,
64889
65622
  getBinding,
65623
+ remove,
64890
65624
  listThreadIds,
64891
65625
  listBindings
64892
65626
  };
@@ -65561,12 +66295,12 @@ const makeWithOptions = Effect.fn("McpSessionRegistry.make")(function* (options
65561
66295
  });
65562
66296
  });
65563
66297
  let activeMcpSessionRegistry;
65564
- const make$9 = Effect.acquireRelease(makeWithOptions().pipe(Effect.tap((registry) => Effect.sync(() => {
66298
+ const make$10 = Effect.acquireRelease(makeWithOptions().pipe(Effect.tap((registry) => Effect.sync(() => {
65565
66299
  activeMcpSessionRegistry = registry;
65566
66300
  }))), (registry) => Effect.sync(() => {
65567
66301
  if (activeMcpSessionRegistry === registry) activeMcpSessionRegistry = void 0;
65568
66302
  }));
65569
- const layer$3 = Layer.effect(McpSessionRegistry, make$9);
66303
+ const layer$3 = Layer.effect(McpSessionRegistry, make$10);
65570
66304
  const issueActiveMcpCredential = (request) => activeMcpSessionRegistry ? activeMcpSessionRegistry.revokeThread(request.threadId).pipe(Effect.andThen(activeMcpSessionRegistry.issue(request))) : Effect.sync(() => void 0);
65571
66305
  /**
65572
66306
  * Refreshes the liveness of a thread's MCP credential. Called on every provider
@@ -67185,62 +67919,101 @@ const CLAUDE_PRESENTATION = {
67185
67919
  displayName: "Claude",
67186
67920
  showInteractionModeToggle: true
67187
67921
  };
67922
+ const MINIMUM_CLAUDE_FABLE_5_1_VERSION = "2.1.257";
67188
67923
  const MINIMUM_CLAUDE_OPUS_5_VERSION = "2.1.219";
67189
67924
  const MINIMUM_CLAUDE_FABLE_5_VERSION = "2.1.169";
67190
67925
  const MINIMUM_CLAUDE_OPUS_4_8_VERSION = "2.1.154";
67191
67926
  const MINIMUM_CLAUDE_OPUS_4_7_VERSION = "2.1.111";
67927
+ const AUTO_COMPACT_WINDOW_OPTION_ID = "autoCompactWindow";
67928
+ const AUTO_COMPACT_WINDOW_AUTO = "auto";
67929
+ /** Token counts behind each explicit auto-compact choice. */
67930
+ const AUTO_COMPACT_WINDOW_TOKENS = {
67931
+ "200k": 2e5,
67932
+ "400k": 4e5,
67933
+ "600k": 6e5
67934
+ };
67935
+ /**
67936
+ * Where Claude Code starts summarising the conversation. "Auto" keeps Claude
67937
+ * Code's own per-model threshold, which on 1M-context models lets a session
67938
+ * grow close to 1M tokens and re-read all of it on every call.
67939
+ */
67940
+ function buildAutoCompactWindowDescriptor() {
67941
+ return buildSelectOptionDescriptor({
67942
+ id: AUTO_COMPACT_WINDOW_OPTION_ID,
67943
+ label: "Auto-compact At",
67944
+ options: [{
67945
+ value: AUTO_COMPACT_WINDOW_AUTO,
67946
+ label: "Auto",
67947
+ isDefault: true
67948
+ }, ...Object.keys(AUTO_COMPACT_WINDOW_TOKENS).map((value) => ({
67949
+ value,
67950
+ label: value
67951
+ }))]
67952
+ });
67953
+ }
67954
+ const CLAUDE_FABLE_CAPABILITIES = createModelCapabilities({ optionDescriptors: [
67955
+ buildSelectOptionDescriptor({
67956
+ id: "effort",
67957
+ label: "Reasoning",
67958
+ options: [
67959
+ {
67960
+ value: "low",
67961
+ label: "Low"
67962
+ },
67963
+ {
67964
+ value: "medium",
67965
+ label: "Medium"
67966
+ },
67967
+ {
67968
+ value: "high",
67969
+ label: "High",
67970
+ isDefault: true
67971
+ },
67972
+ {
67973
+ value: "xhigh",
67974
+ label: "Extra High"
67975
+ },
67976
+ {
67977
+ value: "max",
67978
+ label: "Max"
67979
+ },
67980
+ {
67981
+ value: "ultracode",
67982
+ label: "Ultracode"
67983
+ },
67984
+ {
67985
+ value: "ultrathink",
67986
+ label: "Ultrathink"
67987
+ }
67988
+ ],
67989
+ promptInjectedValues: ["ultrathink"]
67990
+ }),
67991
+ buildSelectOptionDescriptor({
67992
+ id: "contextWindow",
67993
+ label: "Context Window",
67994
+ options: [{
67995
+ value: "200k",
67996
+ label: "200k"
67997
+ }, {
67998
+ value: "1m",
67999
+ label: "1M",
68000
+ isDefault: true
68001
+ }]
68002
+ }),
68003
+ buildAutoCompactWindowDescriptor()
68004
+ ] });
67192
68005
  const BUILT_IN_MODELS = [
68006
+ {
68007
+ slug: "claude-fable-5-1",
68008
+ name: "Claude Fable 5.1",
68009
+ isCustom: false,
68010
+ capabilities: CLAUDE_FABLE_CAPABILITIES
68011
+ },
67193
68012
  {
67194
68013
  slug: "claude-fable-5",
67195
68014
  name: "Claude Fable 5",
67196
68015
  isCustom: false,
67197
- capabilities: createModelCapabilities({ optionDescriptors: [buildSelectOptionDescriptor({
67198
- id: "effort",
67199
- label: "Reasoning",
67200
- options: [
67201
- {
67202
- value: "low",
67203
- label: "Low"
67204
- },
67205
- {
67206
- value: "medium",
67207
- label: "Medium"
67208
- },
67209
- {
67210
- value: "high",
67211
- label: "High",
67212
- isDefault: true
67213
- },
67214
- {
67215
- value: "xhigh",
67216
- label: "Extra High"
67217
- },
67218
- {
67219
- value: "max",
67220
- label: "Max"
67221
- },
67222
- {
67223
- value: "ultracode",
67224
- label: "Ultracode"
67225
- },
67226
- {
67227
- value: "ultrathink",
67228
- label: "Ultrathink"
67229
- }
67230
- ],
67231
- promptInjectedValues: ["ultrathink"]
67232
- }), buildSelectOptionDescriptor({
67233
- id: "contextWindow",
67234
- label: "Context Window",
67235
- options: [{
67236
- value: "200k",
67237
- label: "200k"
67238
- }, {
67239
- value: "1m",
67240
- label: "1M",
67241
- isDefault: true
67242
- }]
67243
- })] })
68016
+ capabilities: CLAUDE_FABLE_CAPABILITIES
67244
68017
  },
67245
68018
  {
67246
68019
  slug: "claude-opus-5",
@@ -67298,12 +68071,157 @@ const BUILT_IN_MODELS = [
67298
68071
  label: "1M",
67299
68072
  isDefault: true
67300
68073
  }]
67301
- })
68074
+ }),
68075
+ buildAutoCompactWindowDescriptor()
68076
+ ] })
68077
+ },
68078
+ {
68079
+ slug: "claude-opus-4-8",
68080
+ name: "Claude Opus 4.8",
68081
+ isCustom: false,
68082
+ capabilities: createModelCapabilities({ optionDescriptors: [
68083
+ buildSelectOptionDescriptor({
68084
+ id: "effort",
68085
+ label: "Reasoning",
68086
+ options: [
68087
+ {
68088
+ value: "low",
68089
+ label: "Low"
68090
+ },
68091
+ {
68092
+ value: "medium",
68093
+ label: "Medium"
68094
+ },
68095
+ {
68096
+ value: "high",
68097
+ label: "High",
68098
+ isDefault: true
68099
+ },
68100
+ {
68101
+ value: "xhigh",
68102
+ label: "Extra High"
68103
+ },
68104
+ {
68105
+ value: "max",
68106
+ label: "Max"
68107
+ },
68108
+ {
68109
+ value: "ultracode",
68110
+ label: "Ultracode"
68111
+ },
68112
+ {
68113
+ value: "ultrathink",
68114
+ label: "Ultrathink"
68115
+ }
68116
+ ],
68117
+ promptInjectedValues: ["ultrathink"]
68118
+ }),
68119
+ buildBooleanOptionDescriptor({
68120
+ id: "fastMode",
68121
+ label: "Fast Mode"
68122
+ }),
68123
+ buildAutoCompactWindowDescriptor()
68124
+ ] })
68125
+ },
68126
+ {
68127
+ slug: "claude-opus-4-7",
68128
+ name: "Claude Opus 4.7",
68129
+ isCustom: false,
68130
+ capabilities: createModelCapabilities({ optionDescriptors: [
68131
+ buildSelectOptionDescriptor({
68132
+ id: "effort",
68133
+ label: "Reasoning",
68134
+ options: [
68135
+ {
68136
+ value: "low",
68137
+ label: "Low"
68138
+ },
68139
+ {
68140
+ value: "medium",
68141
+ label: "Medium"
68142
+ },
68143
+ {
68144
+ value: "high",
68145
+ label: "High"
68146
+ },
68147
+ {
68148
+ value: "xhigh",
68149
+ label: "Extra High",
68150
+ isDefault: true
68151
+ },
68152
+ {
68153
+ value: "max",
68154
+ label: "Max"
68155
+ },
68156
+ {
68157
+ value: "ultrathink",
68158
+ label: "Ultrathink"
68159
+ }
68160
+ ],
68161
+ promptInjectedValues: ["ultrathink"]
68162
+ }),
68163
+ buildBooleanOptionDescriptor({
68164
+ id: "fastMode",
68165
+ label: "Fast Mode"
68166
+ }),
68167
+ buildAutoCompactWindowDescriptor()
68168
+ ] })
68169
+ },
68170
+ {
68171
+ slug: "claude-opus-4-6",
68172
+ name: "Claude Opus 4.6",
68173
+ isCustom: false,
68174
+ capabilities: createModelCapabilities({ optionDescriptors: [
68175
+ buildSelectOptionDescriptor({
68176
+ id: "effort",
68177
+ label: "Reasoning",
68178
+ options: [
68179
+ {
68180
+ value: "low",
68181
+ label: "Low"
68182
+ },
68183
+ {
68184
+ value: "medium",
68185
+ label: "Medium"
68186
+ },
68187
+ {
68188
+ value: "high",
68189
+ label: "High",
68190
+ isDefault: true
68191
+ },
68192
+ {
68193
+ value: "max",
68194
+ label: "Max"
68195
+ },
68196
+ {
68197
+ value: "ultrathink",
68198
+ label: "Ultrathink"
68199
+ }
68200
+ ],
68201
+ promptInjectedValues: ["ultrathink"]
68202
+ }),
68203
+ buildBooleanOptionDescriptor({
68204
+ id: "fastMode",
68205
+ label: "Fast Mode"
68206
+ }),
68207
+ buildSelectOptionDescriptor({
68208
+ id: "contextWindow",
68209
+ label: "Context Window",
68210
+ options: [{
68211
+ value: "200k",
68212
+ label: "200k"
68213
+ }, {
68214
+ value: "1m",
68215
+ label: "1M",
68216
+ isDefault: true
68217
+ }]
68218
+ }),
68219
+ buildAutoCompactWindowDescriptor()
67302
68220
  ] })
67303
68221
  },
67304
68222
  {
67305
- slug: "claude-opus-4-8",
67306
- name: "Claude Opus 4.8",
68223
+ slug: "claude-opus-4-5",
68224
+ name: "Claude Opus 4.5",
67307
68225
  isCustom: false,
67308
68226
  capabilities: createModelCapabilities({ optionDescriptors: [buildSelectOptionDescriptor({
67309
68227
  id: "effort",
@@ -67322,72 +68240,19 @@ const BUILT_IN_MODELS = [
67322
68240
  label: "High",
67323
68241
  isDefault: true
67324
68242
  },
67325
- {
67326
- value: "xhigh",
67327
- label: "Extra High"
67328
- },
67329
68243
  {
67330
68244
  value: "max",
67331
68245
  label: "Max"
67332
- },
67333
- {
67334
- value: "ultracode",
67335
- label: "Ultracode"
67336
- },
67337
- {
67338
- value: "ultrathink",
67339
- label: "Ultrathink"
67340
68246
  }
67341
- ],
67342
- promptInjectedValues: ["ultrathink"]
67343
- }), buildBooleanOptionDescriptor({
67344
- id: "fastMode",
67345
- label: "Fast Mode"
67346
- })] })
67347
- },
67348
- {
67349
- slug: "claude-opus-4-7",
67350
- name: "Claude Opus 4.7",
67351
- isCustom: false,
67352
- capabilities: createModelCapabilities({ optionDescriptors: [buildSelectOptionDescriptor({
67353
- id: "effort",
67354
- label: "Reasoning",
67355
- options: [
67356
- {
67357
- value: "low",
67358
- label: "Low"
67359
- },
67360
- {
67361
- value: "medium",
67362
- label: "Medium"
67363
- },
67364
- {
67365
- value: "high",
67366
- label: "High"
67367
- },
67368
- {
67369
- value: "xhigh",
67370
- label: "Extra High",
67371
- isDefault: true
67372
- },
67373
- {
67374
- value: "max",
67375
- label: "Max"
67376
- },
67377
- {
67378
- value: "ultrathink",
67379
- label: "Ultrathink"
67380
- }
67381
- ],
67382
- promptInjectedValues: ["ultrathink"]
68247
+ ]
67383
68248
  }), buildBooleanOptionDescriptor({
67384
68249
  id: "fastMode",
67385
68250
  label: "Fast Mode"
67386
68251
  })] })
67387
68252
  },
67388
68253
  {
67389
- slug: "claude-opus-4-6",
67390
- name: "Claude Opus 4.6",
68254
+ slug: "claude-sonnet-5",
68255
+ name: "Claude Sonnet 5",
67391
68256
  isCustom: false,
67392
68257
  capabilities: createModelCapabilities({ optionDescriptors: [
67393
68258
  buildSelectOptionDescriptor({
@@ -67407,6 +68272,10 @@ const BUILT_IN_MODELS = [
67407
68272
  label: "High",
67408
68273
  isDefault: true
67409
68274
  },
68275
+ {
68276
+ value: "xhigh",
68277
+ label: "Extra High"
68278
+ },
67410
68279
  {
67411
68280
  value: "max",
67412
68281
  label: "Max"
@@ -67418,146 +68287,68 @@ const BUILT_IN_MODELS = [
67418
68287
  ],
67419
68288
  promptInjectedValues: ["ultrathink"]
67420
68289
  }),
67421
- buildBooleanOptionDescriptor({
67422
- id: "fastMode",
67423
- label: "Fast Mode"
67424
- }),
67425
68290
  buildSelectOptionDescriptor({
67426
68291
  id: "contextWindow",
67427
68292
  label: "Context Window",
67428
68293
  options: [{
67429
68294
  value: "200k",
67430
- label: "200k"
68295
+ label: "200k",
68296
+ isDefault: true
67431
68297
  }, {
67432
68298
  value: "1m",
67433
- label: "1M",
67434
- isDefault: true
68299
+ label: "1M"
67435
68300
  }]
67436
- })
68301
+ }),
68302
+ buildAutoCompactWindowDescriptor()
67437
68303
  ] })
67438
68304
  },
67439
- {
67440
- slug: "claude-opus-4-5",
67441
- name: "Claude Opus 4.5",
67442
- isCustom: false,
67443
- capabilities: createModelCapabilities({ optionDescriptors: [buildSelectOptionDescriptor({
67444
- id: "effort",
67445
- label: "Reasoning",
67446
- options: [
67447
- {
67448
- value: "low",
67449
- label: "Low"
67450
- },
67451
- {
67452
- value: "medium",
67453
- label: "Medium"
67454
- },
67455
- {
67456
- value: "high",
67457
- label: "High",
67458
- isDefault: true
67459
- },
67460
- {
67461
- value: "max",
67462
- label: "Max"
67463
- }
67464
- ]
67465
- }), buildBooleanOptionDescriptor({
67466
- id: "fastMode",
67467
- label: "Fast Mode"
67468
- })] })
67469
- },
67470
- {
67471
- slug: "claude-sonnet-5",
67472
- name: "Claude Sonnet 5",
67473
- isCustom: false,
67474
- capabilities: createModelCapabilities({ optionDescriptors: [buildSelectOptionDescriptor({
67475
- id: "effort",
67476
- label: "Reasoning",
67477
- options: [
67478
- {
67479
- value: "low",
67480
- label: "Low"
67481
- },
67482
- {
67483
- value: "medium",
67484
- label: "Medium"
67485
- },
67486
- {
67487
- value: "high",
67488
- label: "High",
67489
- isDefault: true
67490
- },
67491
- {
67492
- value: "xhigh",
67493
- label: "Extra High"
67494
- },
67495
- {
67496
- value: "max",
67497
- label: "Max"
67498
- },
67499
- {
67500
- value: "ultrathink",
67501
- label: "Ultrathink"
67502
- }
67503
- ],
67504
- promptInjectedValues: ["ultrathink"]
67505
- }), buildSelectOptionDescriptor({
67506
- id: "contextWindow",
67507
- label: "Context Window",
67508
- options: [{
67509
- value: "200k",
67510
- label: "200k",
67511
- isDefault: true
67512
- }, {
67513
- value: "1m",
67514
- label: "1M"
67515
- }]
67516
- })] })
67517
- },
67518
68305
  {
67519
68306
  slug: "claude-sonnet-4-6",
67520
68307
  name: "Claude Sonnet 4.6",
67521
68308
  isCustom: false,
67522
- capabilities: createModelCapabilities({ optionDescriptors: [buildSelectOptionDescriptor({
67523
- id: "effort",
67524
- label: "Reasoning",
67525
- options: [
67526
- {
67527
- value: "low",
67528
- label: "Low"
67529
- },
67530
- {
67531
- value: "medium",
67532
- label: "Medium"
67533
- },
67534
- {
67535
- value: "high",
67536
- label: "High",
68309
+ capabilities: createModelCapabilities({ optionDescriptors: [
68310
+ buildSelectOptionDescriptor({
68311
+ id: "effort",
68312
+ label: "Reasoning",
68313
+ options: [
68314
+ {
68315
+ value: "low",
68316
+ label: "Low"
68317
+ },
68318
+ {
68319
+ value: "medium",
68320
+ label: "Medium"
68321
+ },
68322
+ {
68323
+ value: "high",
68324
+ label: "High",
68325
+ isDefault: true
68326
+ },
68327
+ {
68328
+ value: "max",
68329
+ label: "Max"
68330
+ },
68331
+ {
68332
+ value: "ultrathink",
68333
+ label: "Ultrathink"
68334
+ }
68335
+ ],
68336
+ promptInjectedValues: ["ultrathink"]
68337
+ }),
68338
+ buildSelectOptionDescriptor({
68339
+ id: "contextWindow",
68340
+ label: "Context Window",
68341
+ options: [{
68342
+ value: "200k",
68343
+ label: "200k",
67537
68344
  isDefault: true
67538
- },
67539
- {
67540
- value: "max",
67541
- label: "Max"
67542
- },
67543
- {
67544
- value: "ultrathink",
67545
- label: "Ultrathink"
67546
- }
67547
- ],
67548
- promptInjectedValues: ["ultrathink"]
67549
- }), buildSelectOptionDescriptor({
67550
- id: "contextWindow",
67551
- label: "Context Window",
67552
- options: [{
67553
- value: "200k",
67554
- label: "200k",
67555
- isDefault: true
67556
- }, {
67557
- value: "1m",
67558
- label: "1M"
67559
- }]
67560
- })] })
68345
+ }, {
68346
+ value: "1m",
68347
+ label: "1M"
68348
+ }]
68349
+ }),
68350
+ buildAutoCompactWindowDescriptor()
68351
+ ] })
67561
68352
  },
67562
68353
  {
67563
68354
  slug: "claude-haiku-4-5",
@@ -67572,6 +68363,9 @@ const BUILT_IN_MODELS = [
67572
68363
  function supportsClaudeOpus5(version) {
67573
68364
  return version ? compareSemverVersions(version, MINIMUM_CLAUDE_OPUS_5_VERSION) >= 0 : false;
67574
68365
  }
68366
+ function supportsClaudeFable51(version) {
68367
+ return version ? compareSemverVersions(version, MINIMUM_CLAUDE_FABLE_5_1_VERSION) >= 0 : false;
68368
+ }
67575
68369
  function supportsClaudeFable5(version) {
67576
68370
  return version ? compareSemverVersions(version, MINIMUM_CLAUDE_FABLE_5_VERSION) >= 0 : false;
67577
68371
  }
@@ -67583,6 +68377,7 @@ function supportsClaudeOpus47(version) {
67583
68377
  }
67584
68378
  function getBuiltInClaudeModelsForVersion(version) {
67585
68379
  return BUILT_IN_MODELS.filter((model) => {
68380
+ if (model.slug === "claude-fable-5-1") return supportsClaudeFable51(version);
67586
68381
  if (model.slug === "claude-opus-5") return supportsClaudeOpus5(version);
67587
68382
  if (model.slug === "claude-fable-5") return supportsClaudeFable5(version);
67588
68383
  if (model.slug === "claude-opus-4-8") return supportsClaudeOpus48(version);
@@ -67590,6 +68385,9 @@ function getBuiltInClaudeModelsForVersion(version) {
67590
68385
  return true;
67591
68386
  });
67592
68387
  }
68388
+ function formatClaudeFable51UpgradeMessage(version) {
68389
+ return `Claude Code ${version ? `v${version}` : "the installed version"} is too old for Claude Fable 5.1. Upgrade to v${MINIMUM_CLAUDE_FABLE_5_1_VERSION} or newer to access it.`;
68390
+ }
67593
68391
  function formatClaudeOpus5UpgradeMessage(version) {
67594
68392
  return `Claude Code ${version ? `v${version}` : "the installed version"} is too old for Claude Opus 5. Upgrade to v${MINIMUM_CLAUDE_OPUS_5_VERSION} or newer to access it.`;
67595
68393
  }
@@ -67629,7 +68427,7 @@ function resolveClaudeEffort(caps, raw) {
67629
68427
  function normalizeClaudeCliEffort(effort, model) {
67630
68428
  if (!effort || effort === "ultrathink") return;
67631
68429
  if (effort === "ultracode") return "xhigh";
67632
- if (effort === "xhigh" && model !== "claude-fable-5" && model !== "claude-opus-5" && model !== "claude-opus-4-8" && model !== "claude-sonnet-5") return "max";
68430
+ if (effort === "xhigh" && model !== "claude-fable-5-1" && model !== "claude-fable-5" && model !== "claude-opus-5" && model !== "claude-opus-4-8" && model !== "claude-sonnet-5") return "max";
67633
68431
  if (effort === "max" && model === "claude-sonnet-4-6") return "high";
67634
68432
  return effort;
67635
68433
  }
@@ -67648,6 +68446,11 @@ function resolveClaudeContextWindow(modelSelection) {
67648
68446
  }).find((candidate) => candidate.id === "contextWindow"));
67649
68447
  return typeof value === "string" ? value : void 0;
67650
68448
  }
68449
+ /** Tokens at which Claude Code should auto-compact, or undefined for its default. */
68450
+ function resolveClaudeAutoCompactWindow(modelSelection) {
68451
+ const raw = getModelSelectionStringOptionValue(modelSelection, AUTO_COMPACT_WINDOW_OPTION_ID);
68452
+ return raw === void 0 ? void 0 : AUTO_COMPACT_WINDOW_TOKENS[raw];
68453
+ }
67651
68454
  function resolveClaudeApiModelId(modelSelection) {
67652
68455
  switch (resolveClaudeContextWindow(modelSelection)) {
67653
68456
  case "1m": return `${modelSelection.model}[1m]`;
@@ -67910,7 +68713,7 @@ const checkClaudeProviderStatus = Effect.fn("checkClaudeProviderStatus")(functio
67910
68713
  });
67911
68714
  }
67912
68715
  const models = providerModelsFromSettings(getBuiltInClaudeModelsForVersion(parsedVersion), claudeSettings.customModels, DEFAULT_CLAUDE_MODEL_CAPABILITIES);
67913
- const versionUpgradeMessage = supportsClaudeOpus5(parsedVersion) ? void 0 : supportsClaudeFable5(parsedVersion) ? formatClaudeOpus5UpgradeMessage(parsedVersion) : supportsClaudeOpus48(parsedVersion) ? formatClaudeFable5UpgradeMessage(parsedVersion) : supportsClaudeOpus47(parsedVersion) ? formatClaudeOpus48UpgradeMessage(parsedVersion) : formatClaudeOpus47UpgradeMessage(parsedVersion);
68716
+ const versionUpgradeMessage = supportsClaudeFable51(parsedVersion) ? void 0 : supportsClaudeOpus5(parsedVersion) ? formatClaudeFable51UpgradeMessage(parsedVersion) : supportsClaudeFable5(parsedVersion) ? formatClaudeOpus5UpgradeMessage(parsedVersion) : supportsClaudeOpus48(parsedVersion) ? formatClaudeFable5UpgradeMessage(parsedVersion) : supportsClaudeOpus47(parsedVersion) ? formatClaudeOpus48UpgradeMessage(parsedVersion) : formatClaudeOpus47UpgradeMessage(parsedVersion);
67914
68717
  const capabilities = resolveCapabilities ? yield* resolveCapabilities(claudeSettings).pipe(Effect.orElseSucceed(() => void 0)) : void 0;
67915
68718
  const skills = yield* discoverClaudeSkills(claudeSettings, cwd, resolvedEnvironment, disabledSkills);
67916
68719
  const dedupedSlashCommands = dedupeSlashCommands(capabilities?.slashCommands ?? []);
@@ -68379,7 +69182,7 @@ function formatAskUserQuestionAnswers(answers) {
68379
69182
  /** Fresh-evidence gate adapted from superpowers' verification skill. */
68380
69183
  const VERIFY_BEFORE_COMPLETION_PROMPT = "NO COMPLETION CLAIMS WITHOUT FRESH VERIFICATION EVIDENCE. Before claiming complete, fixed, or passing: 1) identify proving command; 2) run it fresh and fully; 3) read full output, exit code, failure count; 4) confirm evidence matches claim; 5) state claim with evidence. Missing or failed proof: report actual status.";
68381
69184
  /** Visual-proof gate for user-visible frontend work. */
68382
- const SCREENSHOTS_AFTER_UI_WORK_PROMPT = "AFTER USER-VISIBLE FRONTEND WORK, FRESH VISUAL PROOF IS MANDATORY. Before completing: 1) run the relevant real client; 2) inspect the full changed surface; 3) when P4Code preview is available, use preview_snapshot for inspection, then call preview_save_screenshot once after verification passes so P4Code saves the final state under Settings > Screenshots; 4) otherwise capture the verified final state with the relevant approved browser, simulator, or computer tool; 5) verify the screenshot shows the requested result without visible errors; 6) include it in the final response. Ask before launching browser or computer use when approval is required. Skip only work with no user-visible frontend change.";
69185
+ const SCREENSHOTS_AFTER_UI_WORK_PROMPT = "AFTER USER-VISIBLE FRONTEND WORK, FRESH VISUAL PROOF IS MANDATORY. Before completing: 1) run the relevant real client; 2) inspect the full changed surface; 3) when P4Code preview is available, inspect with preview_snapshot (text state by default; pass includeScreenshot: true only for the final visual check), then call preview_save_screenshot once after verification passes so P4Code saves the final state under Settings > Screenshots; 4) otherwise capture the verified final state with the relevant approved browser, simulator, or computer tool; 5) verify the screenshot shows the requested result without visible errors; 6) include it in the final response. Keep screenshots out of your own context where possible: delegate repeated visual inspection to a read-only visual review subagent when one is available and only pull the final proof yourself. Ask before launching browser or computer use when approval is required. Skip only work with no user-visible frontend change.";
68383
69186
  /** Root-cause gate adapted from superpowers' systematic-debugging skill. */
68384
69187
  const ROOT_CAUSE_BEFORE_FIX_PROMPT = "NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST. For bugs or unexpected behavior: 1) read errors, reproduce, inspect recent changes, trace data to source; 2) compare working patterns; 3) state one hypothesis and test smallest change; 4) add failing regression test, implement one fix, verify. After 3 failed fixes, question architecture.";
68385
69188
  function guardrailPromptsFor(settings) {
@@ -68835,7 +69638,8 @@ function readClaudeResumeState(resumeCursor) {
68835
69638
  ...threadId ? { threadId } : {},
68836
69639
  ...resume ? { resume } : {},
68837
69640
  ...resumeSessionAt ? { resumeSessionAt } : {},
68838
- ...turnCountValue !== void 0 && Number.isInteger(turnCountValue) && turnCountValue >= 0 ? { turnCount: turnCountValue } : {}
69641
+ ...turnCountValue !== void 0 && Number.isInteger(turnCountValue) && turnCountValue >= 0 ? { turnCount: turnCountValue } : {},
69642
+ ...cursor.forkSession === true && resume ? { forkSession: true } : {}
68839
69643
  };
68840
69644
  }
68841
69645
  function classifyToolItemType(toolName) {
@@ -70799,8 +71603,9 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
70799
71603
  const resumeState = readClaudeResumeState(input.resumeCursor);
70800
71604
  const threadId = input.threadId;
70801
71605
  const existingResumeSessionId = resumeState?.resume;
70802
- const newSessionId = existingResumeSessionId === void 0 ? yield* randomUUIDv4 : void 0;
70803
- const sessionId = existingResumeSessionId ?? newSessionId;
71606
+ const forkSession = resumeState?.forkSession === true && existingResumeSessionId !== void 0;
71607
+ const newSessionId = existingResumeSessionId === void 0 || forkSession ? yield* randomUUIDv4 : void 0;
71608
+ const sessionId = forkSession ? newSessionId : existingResumeSessionId ?? newSessionId;
70804
71609
  const runtimeContext = yield* Effect.context();
70805
71610
  const runFork = Effect.runForkWith(runtimeContext);
70806
71611
  const runPromise = Effect.runPromiseWith(runtimeContext);
@@ -71005,6 +71810,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
71005
71810
  const descriptors = getProviderOptionDescriptors({ caps });
71006
71811
  const apiModelId = modelSelection ? resolveClaudeApiModelId(modelSelection) : void 0;
71007
71812
  const initialContextWindow = selectedClaudeContextWindow(modelSelection);
71813
+ const autoCompactWindow = resolveClaudeAutoCompactWindow(modelSelection);
71008
71814
  const effort = resolveClaudeEffort(caps, getModelSelectionStringOptionValue(modelSelection, "effort")) ?? null;
71009
71815
  const fastModeSupported = descriptors.some((descriptor) => descriptor.type === "boolean" && descriptor.id === "fastMode");
71010
71816
  const thinkingSupported = descriptors.some((descriptor) => descriptor.type === "boolean" && descriptor.id === "thinking");
@@ -71026,7 +71832,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
71026
71832
  ...skillOverrides ? { skillOverrides } : {}
71027
71833
  };
71028
71834
  const mcpSession = readMcpProviderSession(input.threadId);
71029
- const externalMcpServers = options?.resolveMcpServers === void 0 ? {} : yield* options.resolveMcpServers;
71835
+ const externalMcpServers = options?.resolveMcpServers === void 0 ? {} : yield* options.resolveMcpServers(input.cwd);
71030
71836
  const narrateBeforeTools = options?.resolveToolCallNarration === void 0 ? DEFAULT_SERVER_SETTINGS.enableToolCallNarration : yield* options.resolveToolCallNarration;
71031
71837
  const guardrailSettings = options?.resolveGuardrailPrompts === void 0 ? {
71032
71838
  enableVerificationBeforeCompletion: DEFAULT_SERVER_SETTINGS.enableVerificationBeforeCompletion,
@@ -71064,11 +71870,16 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
71064
71870
  ...permissionMode === "bypassPermissions" ? { allowDangerouslySkipPermissions: true } : {},
71065
71871
  ...Object.keys(settings).length > 0 ? { settings } : {},
71066
71872
  ...existingResumeSessionId ? { resume: existingResumeSessionId } : {},
71873
+ ...forkSession ? { forkSession: true } : {},
71067
71874
  ...newSessionId ? { sessionId: newSessionId } : {},
71068
71875
  includePartialMessages: true,
71069
71876
  canUseTool,
71070
71877
  hooks: { SubagentStart: [{ hooks: [compressionSubagentHook] }] },
71071
- env: claudeEnvironment,
71878
+ env: {
71879
+ ...claudeEnvironment,
71880
+ CLAUDE_CODE_ENABLE_TODO_TOOLS: claudeEnvironment.CLAUDE_CODE_ENABLE_TODO_TOOLS ?? "1",
71881
+ ...autoCompactWindow === void 0 ? {} : { CLAUDE_CODE_AUTO_COMPACT_WINDOW: String(autoCompactWindow) }
71882
+ },
71072
71883
  ...input.cwd ? { additionalDirectories: [input.cwd] } : {},
71073
71884
  ...Object.keys(extraArgs).length > 0 ? { extraArgs } : {},
71074
71885
  ...mcpSession || Object.keys(externalMcpServers).length > 0 ? { mcpServers: {
@@ -71084,7 +71895,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (claudeSettin
71084
71895
  "provider.kind": PROVIDER$6,
71085
71896
  "provider.thread_id": threadId,
71086
71897
  "provider.runtime_mode": input.runtimeMode,
71087
- "claude.resume.source": existingResumeSessionId !== void 0 ? "resume-session" : "generated-session",
71898
+ "claude.resume.source": forkSession ? "fork-session" : existingResumeSessionId !== void 0 ? "resume-session" : "generated-session",
71088
71899
  "claude.resume.thread_id": resumeState?.threadId ?? "",
71089
71900
  "claude.resume.session_id": existingResumeSessionId ?? "",
71090
71901
  "claude.resume.session_at": resumeState?.resumeSessionAt ?? "",
@@ -71519,24 +72330,23 @@ const ClaudeDriver = {
71519
72330
  continuationGroupKey
71520
72331
  });
71521
72332
  const mcpRegistry = yield* McpRegistry;
72333
+ const hasExplicitClaudeConfigDir = effectiveConfig.homePath.trim().length > 0 || (processEnv.CLAUDE_CONFIG_DIR?.trim().length ?? 0) > 0;
72334
+ const resolveMcpServers = (workspace) => (hasExplicitClaudeConfigDir ? resolveClaudeConfigDirPath(effectiveConfig, processEnv, workspace).pipe(Effect.map((configDir) => path.join(configDir, ".claude.json")), Effect.provideService(Path.Path, path)) : Effect.succeed(path.join(NodeOS.homedir(), ".claude.json"))).pipe(Effect.flatMap(mcpRegistry.resolveForSessionAtClaudeUserConfigPath));
71522
72335
  const resolveDisabledSkills = serverSettings.getSettings.pipe(Effect.map((settings) => settings.disabledSkills), Effect.orElseSucceed(() => []));
71523
- const resolveToolCallNarration = serverSettings.getSettings.pipe(Effect.map((settings) => settings.enableToolCallNarration), Effect.orElseSucceed(() => DEFAULT_SERVER_SETTINGS.enableToolCallNarration));
71524
- const resolveGuardrailPrompts = serverSettings.getSettings.pipe(Effect.map((settings) => ({
71525
- enableVerificationBeforeCompletion: settings.enableVerificationBeforeCompletion,
71526
- enableRootCauseBeforeFix: settings.enableRootCauseBeforeFix
71527
- })), Effect.orElseSucceed(() => ({
71528
- enableVerificationBeforeCompletion: DEFAULT_SERVER_SETTINGS.enableVerificationBeforeCompletion,
71529
- enableRootCauseBeforeFix: DEFAULT_SERVER_SETTINGS.enableRootCauseBeforeFix
71530
- })));
71531
- const resolveUnpromptedSubagents = serverSettings.getSettings.pipe(Effect.map((settings) => settings.enableUnpromptedSubagents), Effect.orElseSucceed(() => DEFAULT_SERVER_SETTINGS.enableUnpromptedSubagents));
71532
72336
  const adapter = yield* makeClaudeAdapter(effectiveConfig, {
71533
72337
  instanceId,
71534
72338
  environment: processEnv,
71535
- resolveMcpServers: mcpRegistry.resolveForSession,
72339
+ resolveMcpServers,
71536
72340
  resolveDisabledSkills,
71537
- resolveToolCallNarration,
71538
- resolveGuardrailPrompts,
71539
- resolveUnpromptedSubagents,
72341
+ resolveToolCallNarration: serverSettings.getSettings.pipe(Effect.map((settings) => settings.enableToolCallNarration), Effect.orElseSucceed(() => DEFAULT_SERVER_SETTINGS.enableToolCallNarration)),
72342
+ resolveGuardrailPrompts: serverSettings.getSettings.pipe(Effect.map((settings) => ({
72343
+ enableVerificationBeforeCompletion: settings.enableVerificationBeforeCompletion,
72344
+ enableRootCauseBeforeFix: settings.enableRootCauseBeforeFix
72345
+ })), Effect.orElseSucceed(() => ({
72346
+ enableVerificationBeforeCompletion: DEFAULT_SERVER_SETTINGS.enableVerificationBeforeCompletion,
72347
+ enableRootCauseBeforeFix: DEFAULT_SERVER_SETTINGS.enableRootCauseBeforeFix
72348
+ }))),
72349
+ resolveUnpromptedSubagents: serverSettings.getSettings.pipe(Effect.map((settings) => settings.enableUnpromptedSubagents), Effect.orElseSucceed(() => DEFAULT_SERVER_SETTINGS.enableUnpromptedSubagents)),
71540
72350
  ...eventLoggers.native ? { nativeEventLogger: eventLoggers.native } : {}
71541
72351
  });
71542
72352
  const textGeneration = yield* makeClaudeTextGeneration(effectiveConfig, processEnv);
@@ -89593,7 +90403,7 @@ const makeTerminationError$1 = (handle) => Effect.match(handle.exitCode, {
89593
90403
  //#endregion
89594
90404
  //#region ../../packages/effect-codex-app-server/src/client.ts
89595
90405
  var CodexAppServerClient = class extends Context.Service()("effect-codex-app-server/client/CodexAppServerClient") {};
89596
- const make$8 = Effect.fn("effect-codex-app-server/CodexAppServerClient.make")(function* (stdio, options = {}, terminationError) {
90406
+ const make$9 = Effect.fn("effect-codex-app-server/CodexAppServerClient.make")(function* (stdio, options = {}, terminationError) {
89597
90407
  const requestHandlers = /* @__PURE__ */ new Map();
89598
90408
  const notificationHandlers = /* @__PURE__ */ new Map();
89599
90409
  let unknownRequestHandler;
@@ -89660,7 +90470,7 @@ const make$8 = Effect.fn("effect-codex-app-server/CodexAppServerClient.make")(fu
89660
90470
  const layerChildProcess$1 = (handle, options = {}) => Layer.effect(CodexAppServerClient, makeChildProcessClient(handle, options));
89661
90471
  const makeChildProcessClient = Effect.fn("effect-codex-app-server/CodexAppServerClient.makeChildProcessClient")(function* (handle, options) {
89662
90472
  yield* Stream.runDrain(handle.stderr).pipe(Effect.ignore, Effect.forkScoped);
89663
- return yield* make$8(makeChildStdio$1(handle), options, makeTerminationError$1(handle));
90473
+ return yield* make$9(makeChildStdio$1(handle), options, makeTerminationError$1(handle));
89664
90474
  });
89665
90475
  const resolveCodexLaunchArgs = (launchArgs, environment = process.env) => environment["P4CODE_CODEX_LAUNCH_ARGS"]?.trim() || launchArgs?.trim() || "";
89666
90476
  const codexLaunchArgv = (launchArgs) => tokenizeCliArgs(launchArgs);
@@ -90707,8 +91517,8 @@ const ANSI_ESCAPE_REGEX = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g
90707
91517
  const CODEX_STDERR_LOG_REGEX = /^\d{4}-\d{2}-\d{2}T\S+\s+(TRACE|DEBUG|INFO|WARN|ERROR)\s+\S+:\s+(.*)$/;
90708
91518
  const BENIGN_ERROR_LOG_SNIPPETS = ["state db missing rollout path for thread", "state db record_discrepancy: find_thread_path_by_id_str_in_subdir, falling_back"];
90709
91519
  const CODEX_APP_SERVER_FORCE_KILL_AFTER = "2 seconds";
90710
- const PATH_DELIMITER = process.platform === "win32" ? ";" : ":";
90711
- const PATH_SEPARATOR = process.platform === "win32" ? "\\" : "/";
91520
+ const PATH_DELIMITER = NodePath.delimiter;
91521
+ const PATH_SEPARATOR = NodePath.sep;
90712
91522
  const RECOVERABLE_THREAD_RESUME_ERROR_SNIPPETS = [
90713
91523
  "not found",
90714
91524
  "missing thread",
@@ -96446,7 +97256,7 @@ const makeTerminationError = (handle) => Effect.match(handle.exitCode, {
96446
97256
  //#endregion
96447
97257
  //#region ../../packages/effect-acp/src/client.ts
96448
97258
  var AcpClient = class extends Context.Service()("effect-acp/client/AcpClient") {};
96449
- const make$7 = Effect.fn("effect-acp/AcpClient.make")(function* (stdio, options = {}, terminationError) {
97259
+ const make$8 = Effect.fn("effect-acp/AcpClient.make")(function* (stdio, options = {}, terminationError) {
96450
97260
  const coreHandlers = {};
96451
97261
  const notificationHandlers = {
96452
97262
  sessionUpdate: {
@@ -96604,7 +97414,7 @@ const make$7 = Effect.fn("effect-acp/AcpClient.make")(function* (stdio, options
96604
97414
  const layerChildProcess = (handle, options = {}) => {
96605
97415
  const stdio = makeChildStdio(handle);
96606
97416
  const terminationError = makeTerminationError(handle);
96607
- return Layer.effect(AcpClient, make$7(stdio, options, terminationError));
97417
+ return Layer.effect(AcpClient, make$8(stdio, options, terminationError));
96608
97418
  };
96609
97419
  //#endregion
96610
97420
  //#region ../../packages/shared/src/toolActivity.ts
@@ -97064,7 +97874,7 @@ function formatConfigOptionValue(value) {
97064
97874
  const defaultSessionLoadTimeout = Duration.seconds(90);
97065
97875
  const defaultSessionLoadReplayIdleGap = Duration.seconds(2);
97066
97876
  var AcpSessionRuntime = class extends Context.Service()("@p4code/cli/provider/acp/AcpSessionRuntime") {};
97067
- const make$6 = (options) => Effect.gen(function* () {
97877
+ const make$7 = (options) => Effect.gen(function* () {
97068
97878
  const crypto = yield* Crypto.Crypto;
97069
97879
  const spawner = yield* ChildProcessSpawner$1.ChildProcessSpawner;
97070
97880
  const runtimeScope = yield* Scope.Scope;
@@ -97380,7 +98190,7 @@ const make$6 = (options) => Effect.gen(function* () {
97380
98190
  notify: acp.raw.notify
97381
98191
  };
97382
98192
  });
97383
- const layer$2 = (options) => Layer.effect(AcpSessionRuntime, make$6(options));
98193
+ const layer$2 = (options) => Layer.effect(AcpSessionRuntime, make$7(options));
97384
98194
  function sessionConfigOptionsFromSetup(response) {
97385
98195
  return response?.configOptions ?? [];
97386
98196
  }
@@ -104701,8 +105511,8 @@ const PreviewSetAppearanceTool = safeBrowserTool(Tool.make("preview_set_appearan
104701
105511
  dependencies: dependencies$1
104702
105512
  }).annotate(Tool.Title, "Set preview appearance").annotate(Tool.Idempotent, true));
104703
105513
  const PreviewSnapshotTool = readonlyBrowserTool(Tool.make("preview_snapshot", {
104704
- description: "Inspect a page before interacting. Pass tabId to inspect a specific tab; omit it to use this agent session's current tab. Returns page state, semantic elements, diagnostics, action history, and a PNG screenshot.",
104705
- parameters: PreviewAutomationTabTargetInput,
105514
+ description: "Inspect a page before interacting. Pass tabId to inspect a specific tab; omit it to use this agent session's current tab. Returns page state, semantic elements, diagnostics, and action history as text. Pass includeScreenshot: true only when you need to see the rendering; the text state is enough for locators and assertions.",
105515
+ parameters: PreviewAutomationSnapshotInput,
104706
105516
  success: PreviewAutomationSnapshot,
104707
105517
  failure: PreviewAutomationError,
104708
105518
  dependencies: dependencies$1
@@ -104804,7 +105614,7 @@ const handlers$4 = {
104804
105614
  preview_navigate: (input) => invokeTargeted("navigate", input, input.timeoutMs),
104805
105615
  preview_resize: (input) => invokeTargeted("resize", input, input.timeoutMs),
104806
105616
  preview_set_appearance: (input) => invokeTargeted("setColorScheme", input),
104807
- preview_snapshot: (input) => invokeTargeted("snapshot", input ?? {}),
105617
+ preview_snapshot: (input) => invokeTargeted("snapshot", input?.tabId ? { tabId: input.tabId } : {}),
104808
105618
  preview_save_screenshot: (input) => invokeTargeted("saveScreenshot", input ?? {}),
104809
105619
  preview_click: (input) => invokeTargeted("click", input, input.timeoutMs).pipe(Effect.as(null)),
104810
105620
  preview_type: (input) => invokeTargeted("type", input, input.timeoutMs).pipe(Effect.as(null)),
@@ -104826,7 +105636,7 @@ const stringField = (record, key) => {
104826
105636
  const value = record[key];
104827
105637
  return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
104828
105638
  };
104829
- const make$5 = Effect.gen(function* () {
105639
+ const make$6 = Effect.gen(function* () {
104830
105640
  const linear = yield* LinearClient;
104831
105641
  return { resolve: Effect.fn("TicketResolver.resolve")(function* (reference) {
104832
105642
  const identifier = parseTicketReference(reference);
@@ -104857,7 +105667,7 @@ const make$5 = Effect.gen(function* () {
104857
105667
  };
104858
105668
  }) };
104859
105669
  });
104860
- const layer$1 = Layer.effect(TicketResolver, make$5);
105670
+ const layer$1 = Layer.effect(TicketResolver, make$6);
104861
105671
  //#endregion
104862
105672
  //#region src/mcp/toolkits/tasks/tools.ts
104863
105673
  const dependencies = [McpInvocationContext, TaskRepository];
@@ -106366,6 +107176,7 @@ const registerPreviewSnapshot = Effect.fn("McpHttpServer.registerPreviewSnapshot
106366
107176
  return built.handle("preview_snapshot", payload).pipe(Stream.unwrap, Stream.run(Sink.last()), Effect.flatMap(Effect.fromOption), Effect.provideService(PreviewAutomationBroker, broker), Effect.provideService(McpInvocationContext, invocation), Effect.matchCauseEffect({
106367
107177
  onFailure: previewSnapshotFailure,
106368
107178
  onSuccess: ({ encodedResult }) => {
107179
+ const includeScreenshot = payload?.includeScreenshot === true;
106369
107180
  const { screenshot, ...page } = encodedResult;
106370
107181
  const metadata = {
106371
107182
  ...page,
@@ -106381,11 +107192,11 @@ const registerPreviewSnapshot = Effect.fn("McpHttpServer.registerPreviewSnapshot
106381
107192
  content: [{
106382
107193
  type: "text",
106383
107194
  text: JSON.stringify(metadata)
106384
- }, {
107195
+ }, ...includeScreenshot ? [{
106385
107196
  type: "image",
106386
107197
  data: new Uint8Array(Buffer.from(screenshot.data, "base64")),
106387
107198
  mimeType: screenshot.mimeType
106388
- }]
107199
+ }] : []]
106389
107200
  }));
106390
107201
  }
106391
107202
  }));
@@ -106465,6 +107276,18 @@ var ThreadDeletionReactor = class extends Context.Service()("@p4code/cli/orchest
106465
107276
  //#region src/orchestration/Services/FusionWatcherReactor.ts
106466
107277
  var FusionWatcherReactor = class extends Context.Service()("@p4code/cli/orchestration/Services/FusionWatcherReactor") {};
106467
107278
  //#endregion
107279
+ //#region src/orchestration/Services/ScheduledTaskReactor.ts
107280
+ /**
107281
+ * ScheduledTaskReactor - fires user-created scheduled tasks.
107282
+ *
107283
+ * Arms one timer per pending task (from the read model at start and from
107284
+ * `thread.scheduled-task.created` events afterwards), starts the thread turn
107285
+ * when the time comes, and records the outcome on the task.
107286
+ *
107287
+ * @module ScheduledTaskReactor
107288
+ */
107289
+ var ScheduledTaskReactor = class extends Context.Service()("@p4code/cli/orchestration/Services/ScheduledTaskReactor") {};
107290
+ //#endregion
106468
107291
  //#region src/orchestration/Layers/OrchestrationReactor.ts
106469
107292
  const makeOrchestrationReactor = Effect.gen(function* () {
106470
107293
  const providerRuntimeIngestion = yield* ProviderRuntimeIngestionService;
@@ -106472,12 +107295,14 @@ const makeOrchestrationReactor = Effect.gen(function* () {
106472
107295
  const checkpointReactor = yield* CheckpointReactor;
106473
107296
  const threadDeletionReactor = yield* ThreadDeletionReactor;
106474
107297
  const fusionWatcherReactor = yield* FusionWatcherReactor;
107298
+ const scheduledTaskReactor = yield* ScheduledTaskReactor;
106475
107299
  return { start: Effect.fn("start")(function* () {
106476
107300
  yield* providerRuntimeIngestion.start();
106477
107301
  yield* providerCommandReactor.start();
106478
107302
  yield* checkpointReactor.start();
106479
107303
  yield* threadDeletionReactor.start();
106480
107304
  yield* fusionWatcherReactor.start();
107305
+ yield* scheduledTaskReactor.start();
106481
107306
  }) };
106482
107307
  });
106483
107308
  const OrchestrationReactorLive = Layer.effect(OrchestrationReactor, makeOrchestrationReactor);
@@ -107063,7 +107888,7 @@ function runtimeEventToActivities(event, taskTitle, compressMode) {
107063
107888
  }
107064
107889
  return [];
107065
107890
  }
107066
- const make$4 = Effect.gen(function* () {
107891
+ const make$5 = Effect.gen(function* () {
107067
107892
  const crypto = yield* Crypto.Crypto;
107068
107893
  const orchestrationEngine = yield* OrchestrationEngineService;
107069
107894
  const projectionSnapshotQuery = yield* ProjectionSnapshotQuery;
@@ -107693,7 +108518,7 @@ const make$4 = Effect.gen(function* () {
107693
108518
  drain: worker.drain
107694
108519
  };
107695
108520
  });
107696
- const ProviderRuntimeIngestionLive = Layer.effect(ProviderRuntimeIngestionService, make$4).pipe(Layer.provide(ProjectionTurnRepositoryLive), Layer.provide(layer$64));
108521
+ const ProviderRuntimeIngestionLive = Layer.effect(ProviderRuntimeIngestionService, make$5).pipe(Layer.provide(ProjectionTurnRepositoryLive), Layer.provide(layer$64));
107697
108522
  //#endregion
107698
108523
  //#region src/provider/userInvokedSkills.ts
107699
108524
  /**
@@ -107869,8 +108694,8 @@ const DEFAULT_RUNTIME_MODE = "full-access";
107869
108694
  const DEFAULT_THREAD_TITLE = "New thread";
107870
108695
  const NON_SYSTEM_PROVIDER_STRUCTURED_USER_QUESTIONS = structuredUserQuestionPrompt("your provider's structured user-input question tool");
107871
108696
  const FUSION_PROMOTION_INSTRUCTIONS = `Work independently in this normal thread. Fusion is a silent escalation path, not a startup procedure. Do not inspect Fusion tools/skill, mention Fusion status, or announce that Fusion was not invoked. First analyze the task normally. Only if that analysis reveals a concrete unresolved tradeoff, correctness risk, or design decision materially needing a second opinion, stop before implementation, propose Fusion, and ask the user for explicit approval. The user may approve with ordinary affirmative text such as "approved"; /fusion or $fusion also authorizes Fusion directly without a prior proposal. Do not activate, spawn, or promote until one of those authorizations arrives. UI work, complex logic, task size, unfamiliarity, or duration alone never qualifies.`;
107872
- const FUSION_BUILDER_INSTRUCTIONS = `You are Fusion Builder in an already-created native server pair. Server owns pairing and coordination. Do not inspect or invoke the Fusion skill, create/pair/rename threads, or announce/setup Fusion. Start the user's task directly. Before editing, create and maintain the phase list in the same plan/todo tool you use for ordinary step tracking, never the MCP task board tools - one entry per phase in order, exactly one in progress at a time, marked completed at each phase end - so phases render in the task banner. That list holds phase entries only for the whole task; keep step-level or per-file todos out of it. Prose alone leaves the banner empty. Split it into the fewest substantial phases the task genuinely needs plus a final integration/whole-task phase; most tasks need one to three work phases. Each phase is a complete reviewable slice of behavior. Never split per file, per function, or per trivial step: over-splitting spends review turns instead of finishing the job. Add a phase only when a real review boundary, risky decision, or independent behavior separates the work. Complete exactly one phase per turn, and finish the whole phase in that turn rather than stopping early. Do not run tests, typecheck, lint, or builds per phase; write the tests the change needs, then run verification once in the final phase over the whole task. Exception: a phase whose own correctness is unclear may run the single narrowest check that resolves it. End every phase turn with phase completed, todo status, changed behavior/files, and remaining phases; do not start the next phase in the same turn. Server then wakes the paired Supervisor, which resumes you through ${FUSION_ADVICE_PROMPT_PREFIX}; a user message may also revise or resume the work. Final phase verifies the entire task against the original request and labels it ready for whole-task review. Supervisor is unreachable during your turn. Never spawn/use another Supervisor thread/subagent or attribute Supervisor decisions without ${FUSION_ADVICE_PROMPT_PREFIX}. Within the current phase, continue when straightforward or evidence is clear. For a concrete unresolved tradeoff, correctness risk, or design decision materially needing judgment, stop safely before the risky choice; final response states the exact question and why review is needed. Evaluate/follow Supervisor advice unless conflicting with user request or verified repo state.`;
107873
- const FUSION_WATCHER_INSTRUCTIONS = `You are Fusion Supervisor (watcher) in an already-created native server pair. Server owns pairing and coordination and wakes you with ${FUSION_REVIEW_PROMPT_PREFIX} or ${FUSION_GATE_PROMPT_PREFIX} prompts at builder turn boundaries; this message arrived outside such a wake, so your conversational memory of the pair may be gone. The pair metadata below is authoritative: the builder thread exists and is the counterpart thread id. Never report that no builder thread exists. To resume supervision, read builder events with thread_watch_events from lastReviewedImplementerSequence with limit 50, paging forward with the last returned sequence rather than requesting a whole range at once, derive phase from artifacts (git log/status, PR, builder events), steer with thread_advise, and answer an open gate with thread_gate_respond. When a review or gate wake prompt specifies an explicit event range, that range wins over this metadata. Never poll or wait for the builder; deliver review or advice, then end the turn.`;
108697
+ const FUSION_BUILDER_INSTRUCTIONS = `You are Fusion Builder in an already-created native server pair. Server owns pairing and coordination. Do not inspect or invoke the Fusion skill, create/pair/rename threads, or announce/setup Fusion. Start the user's task directly. Before editing, create and maintain the phase list with your provider's step-tracking tool (Claude Code: TaskCreate for each phase, then TaskUpdate for status, or TodoWrite when that is the tool offered; Codex: update_plan), never the MCP task board tools - one entry per phase in order, exactly one in progress at a time, marked completed at each phase end - so phases render in the task banner. That list holds phase entries only for the whole task; keep step-level or per-file todos out of it. Prose alone leaves the banner empty. Split it into the fewest substantial phases the task genuinely needs plus a final integration/whole-task phase; most tasks need one to three work phases. Each phase is a complete reviewable slice of behavior. Never split per file, per function, or per trivial step: over-splitting spends review turns instead of finishing the job. Add a phase only when a real review boundary, risky decision, or independent behavior separates the work. Complete exactly one phase per turn, and finish the whole phase in that turn rather than stopping early. Do not run tests, typecheck, lint, or builds per phase; write the tests the change needs, then run verification once in the final phase over the whole task. Exception: a phase whose own correctness is unclear may run the single narrowest check that resolves it. End every phase turn with phase completed, todo status, changed behavior/files, and remaining phases; do not start the next phase in the same turn. Server then wakes the paired Supervisor, which resumes you through ${FUSION_ADVICE_PROMPT_PREFIX}; a user message may also revise or resume the work. Final phase verifies the entire task against the original request and labels it ready for whole-task review. Supervisor is unreachable during your turn. Never spawn/use another Supervisor thread/subagent or attribute Supervisor decisions without ${FUSION_ADVICE_PROMPT_PREFIX}. Within the current phase, continue when straightforward or evidence is clear. For a concrete unresolved tradeoff, correctness risk, or design decision materially needing judgment, stop safely before the risky choice; final response states the exact question and why review is needed. Evaluate/follow Supervisor advice unless conflicting with user request or verified repo state.`;
108698
+ const FUSION_WATCHER_INSTRUCTIONS = `You are Fusion Supervisor (watcher) in an already-created native server pair. Server owns pairing and coordination and wakes you with ${FUSION_REVIEW_PROMPT_PREFIX} or ${FUSION_GATE_PROMPT_PREFIX} prompts at builder turn boundaries; this message arrived outside such a wake, so your conversational memory of the pair may be gone. The pair metadata below is authoritative: the builder thread exists and is the counterpart thread id. Never report that no builder thread exists. To resume supervision, read builder events with thread_watch_events from lastReviewedImplementerSequence with limit 50, paging forward with the last returned sequence rather than requesting a whole range at once, derive phase from artifacts (git log/status, PR, builder events, including its turn.plan.updated phase list), steer with thread_advise, and answer an open gate with thread_gate_respond. When a review or gate wake prompt specifies an explicit event range, that range wins over this metadata. Never poll or wait for the builder; deliver review or advice, then end the turn.`;
107874
108699
  const isFusionWatcherWakeMessageId = (messageId) => messageId.startsWith("fusion-review:") || messageId.startsWith("fusion-gate:");
107875
108700
  const fusionPairContext = (pair, role) => {
107876
108701
  const counterpartThreadId = role === "implementer" ? pair.watcherThreadId : pair.implementerThreadId;
@@ -107958,7 +108783,7 @@ function resolvePendingWorkspaceCleanupGroups(input) {
107958
108783
  }
107959
108784
  return groups;
107960
108785
  }
107961
- const make$3 = Effect.gen(function* () {
108786
+ const make$4 = Effect.gen(function* () {
107962
108787
  const crypto = yield* Crypto.Crypto;
107963
108788
  const orchestrationEngine = yield* OrchestrationEngineService;
107964
108789
  const projectionSnapshotQuery = yield* ProjectionSnapshotQuery;
@@ -108837,7 +109662,7 @@ const make$3 = Effect.gen(function* () {
108837
109662
  drain: Effect.all([worker.drain, forceStopDrain], { discard: true }).pipe(Effect.asVoid)
108838
109663
  };
108839
109664
  });
108840
- const ProviderCommandReactorLive = Layer.effect(ProviderCommandReactor, make$3);
109665
+ const ProviderCommandReactorLive = Layer.effect(ProviderCommandReactor, make$4);
108841
109666
  //#endregion
108842
109667
  //#region src/checkpointing/Diffs.ts
108843
109668
  function parseTurnDiffFilesFromUnifiedDiff(diff) {
@@ -108867,7 +109692,7 @@ function checkpointStatusFromRuntime(status) {
108867
109692
  default: return "ready";
108868
109693
  }
108869
109694
  }
108870
- const make$2 = Effect.gen(function* () {
109695
+ const make$3 = Effect.gen(function* () {
108871
109696
  const randomUUID = (yield* Crypto.Crypto).randomUUIDv4;
108872
109697
  const serverEventId = randomUUID.pipe(Effect.map(EventId.make));
108873
109698
  const serverCommandId = (tag) => randomUUID.pipe(Effect.map((uuid) => CommandId.make(`server:${tag}:${uuid}`)));
@@ -109349,7 +110174,7 @@ const make$2 = Effect.gen(function* () {
109349
110174
  drain: worker.drain
109350
110175
  };
109351
110176
  });
109352
- const CheckpointReactorLive = Layer.effect(CheckpointReactor, make$2);
110177
+ const CheckpointReactorLive = Layer.effect(CheckpointReactor, make$3);
109353
110178
  //#endregion
109354
110179
  //#region src/orchestration/Layers/FusionWatcherReactor.ts
109355
110180
  const GATE_TIMEOUT_SWEEP_INTERVAL = "10 seconds";
@@ -109439,7 +110264,7 @@ Then thread_gate_respond, threadId ${input.implementerThreadId}, gateId ${input.
109439
110264
  - "object" plus message: send objection, spend round. After ${input.roundCap} objections, escalate to user.
109440
110265
 
109441
110266
  No answer within ${Math.round(input.gateTimeoutMs / 1e3)} seconds: fail open, record unwatched. Answer, briefly explain to user, end turn; never wait for builder.`;
109442
- const make$1 = Effect.gen(function* () {
110267
+ const make$2 = Effect.gen(function* () {
109443
110268
  const orchestrationEngine = yield* OrchestrationEngineService;
109444
110269
  const projectionSnapshotQuery = yield* ProjectionSnapshotQuery;
109445
110270
  /**
@@ -110039,7 +110864,7 @@ const make$1 = Effect.gen(function* () {
110039
110864
  sweepGates: sweepGateTimeouts.pipe(Effect.catchCause((cause) => Effect.logWarning("fusion gate timeout sweep failed", { cause: Cause.pretty(cause) })))
110040
110865
  };
110041
110866
  });
110042
- const FusionWatcherReactorLive = Layer.effect(FusionWatcherReactor, make$1);
110867
+ const FusionWatcherReactorLive = Layer.effect(FusionWatcherReactor, make$2);
110043
110868
  //#endregion
110044
110869
  //#region src/orchestration/Layers/ThreadDeletionReactor.ts
110045
110870
  const logCleanupCauseUnlessInterrupted = ({ effect, message, threadId }) => effect.pipe(Effect.catchCause((cause) => {
@@ -110049,7 +110874,7 @@ const logCleanupCauseUnlessInterrupted = ({ effect, message, threadId }) => effe
110049
110874
  cause: Cause.pretty(cause)
110050
110875
  });
110051
110876
  }));
110052
- const make = Effect.gen(function* () {
110877
+ const make$1 = Effect.gen(function* () {
110053
110878
  const orchestrationEngine = yield* OrchestrationEngineService;
110054
110879
  const providerService = yield* ProviderService;
110055
110880
  const terminalManager = yield* TerminalManager;
@@ -110090,7 +110915,213 @@ const make = Effect.gen(function* () {
110090
110915
  drain: worker.drain
110091
110916
  };
110092
110917
  });
110093
- const ThreadDeletionReactorLive = Layer.effect(ThreadDeletionReactor, make);
110918
+ const ThreadDeletionReactorLive = Layer.effect(ThreadDeletionReactor, make$1);
110919
+ //#endregion
110920
+ //#region src/orchestration/scheduledTasks.ts
110921
+ /** Milliseconds until a task is due; 0 for anything already overdue. */
110922
+ function scheduledTaskDelayMs(runAt, nowMs) {
110923
+ const runAtMs = Date.parse(runAt);
110924
+ if (Number.isNaN(runAtMs)) return 0;
110925
+ return Math.max(0, runAtMs - nowMs);
110926
+ }
110927
+ function pendingScheduledTasks(threads) {
110928
+ return threads.flatMap((thread) => thread.deletedAt !== null ? [] : (thread.scheduledTasks ?? []).filter((task) => task.status === "pending").map((task) => ({
110929
+ threadId: thread.id,
110930
+ task
110931
+ })));
110932
+ }
110933
+ /**
110934
+ * Task ids are unique per thread only, so every key derived from a task is
110935
+ * scoped by its thread.
110936
+ */
110937
+ function scheduledTaskKey(threadId, taskId) {
110938
+ return `${threadId}:${taskId}`;
110939
+ }
110940
+ /**
110941
+ * Every turn-start attempt gets its own command id: the engine keeps a
110942
+ * rejected receipt per command id, so reusing one would replay the first
110943
+ * rejection (a busy thread) on every retry. Crash idempotence comes from the
110944
+ * deterministic message id instead: a turn that already sent
110945
+ * {@link scheduledTaskMessageId} is never started again.
110946
+ */
110947
+ function scheduledTaskTurnCommandId(threadId, taskId, attemptToken) {
110948
+ return CommandId.make(`scheduled-task:${threadId}:${taskId}:turn:${attemptToken}`);
110949
+ }
110950
+ function scheduledTaskFireCommandId(threadId, taskId) {
110951
+ return CommandId.make(`scheduled-task:${threadId}:${taskId}:fire`);
110952
+ }
110953
+ function scheduledTaskMessageId(threadId, taskId) {
110954
+ return MessageId.make(`scheduled-task:${threadId}:${taskId}`);
110955
+ }
110956
+ //#endregion
110957
+ //#region src/orchestration/Layers/ScheduledTaskReactor.ts
110958
+ /**
110959
+ * A turn that cannot start (thread busy, provider down) is retried on this
110960
+ * cadence before the task is marked failed; the count resets with the process,
110961
+ * and the periodic reconcile re-arms anything still pending.
110962
+ */
110963
+ const SCHEDULED_TASK_TURN_RETRY_DELAY = Duration.minutes(2);
110964
+ /** Re-arms pending tasks that lost their timer (fire failure, missed event). */
110965
+ const SCHEDULED_TASK_RECONCILE_INTERVAL = Duration.minutes(5);
110966
+ /** Engine-level failures while firing (e.g. persistence) back off briefly and retry. */
110967
+ const FIRE_RETRY = {
110968
+ schedule: Schedule.exponential(Duration.seconds(10)),
110969
+ times: 3
110970
+ };
110971
+ const make = Effect.gen(function* () {
110972
+ const orchestrationEngine = yield* OrchestrationEngineService;
110973
+ const projectionSnapshotQuery = yield* ProjectionSnapshotQuery;
110974
+ const threadMessages = yield* ProjectionThreadMessageRepository;
110975
+ const timers = /* @__PURE__ */ new Map();
110976
+ const turnAttempts = /* @__PURE__ */ new Map();
110977
+ const nowIso = Effect.map(DateTime.now, DateTime.formatIso);
110978
+ const disarm = (threadId, taskId) => Effect.gen(function* () {
110979
+ const key = scheduledTaskKey(threadId, taskId);
110980
+ turnAttempts.delete(key);
110981
+ const fiber = timers.get(key);
110982
+ if (fiber === void 0) return;
110983
+ timers.delete(key);
110984
+ yield* Fiber.interrupt(fiber);
110985
+ });
110986
+ const describeFailure = (failure) => failure instanceof Error ? failure.message : String(failure);
110987
+ /**
110988
+ * Starts the turn, then marks the task fired. The turn's user message has a
110989
+ * deterministic id, so a crash between the two steps re-fires on the next
110990
+ * boot without a second turn: an existing message means the turn already
110991
+ * started. Each attempt uses a fresh command id because the engine replays
110992
+ * a rejected receipt for a reused one. A turn that cannot start re-arms the
110993
+ * task for a bounded number of retries and only then records the failure.
110994
+ */
110995
+ const fire = Effect.fn("ScheduledTaskReactor.fire")(function* (threadId, task) {
110996
+ const key = scheduledTaskKey(threadId, task.id);
110997
+ timers.delete(key);
110998
+ const thread = (yield* projectionSnapshotQuery.getCommandReadModel()).threads.find((entry) => entry.id === threadId);
110999
+ const current = thread?.scheduledTasks?.find((entry) => entry.id === task.id);
111000
+ if (thread === void 0 || thread.deletedAt !== null || current?.status !== "pending") {
111001
+ turnAttempts.delete(key);
111002
+ return;
111003
+ }
111004
+ const messageId = scheduledTaskMessageId(threadId, task.id);
111005
+ const turnResult = Option.isSome(yield* threadMessages.getByMessageId({ messageId })) ? { _tag: "Success" } : yield* orchestrationEngine.dispatch({
111006
+ type: "thread.turn.start",
111007
+ commandId: scheduledTaskTurnCommandId(threadId, task.id, String(yield* Clock.currentTimeMillis)),
111008
+ threadId,
111009
+ message: {
111010
+ messageId,
111011
+ role: "user",
111012
+ text: task.prompt,
111013
+ attachments: []
111014
+ },
111015
+ runtimeMode: thread.runtimeMode,
111016
+ interactionMode: thread.interactionMode,
111017
+ compressMode: thread.compressMode,
111018
+ unpromptedSubagents: thread.unpromptedSubagents,
111019
+ createdAt: yield* nowIso
111020
+ }).pipe(Effect.result);
111021
+ if (turnResult._tag === "Failure") {
111022
+ const attempts = (turnAttempts.get(key) ?? 0) + 1;
111023
+ if (attempts < 10) {
111024
+ turnAttempts.set(key, attempts);
111025
+ yield* Effect.logInfo("scheduled task turn could not start; retrying", {
111026
+ threadId,
111027
+ taskId: task.id,
111028
+ attempt: attempts,
111029
+ failure: describeFailure(turnResult.failure)
111030
+ });
111031
+ yield* armAfter(threadId, task, SCHEDULED_TASK_TURN_RETRY_DELAY);
111032
+ return;
111033
+ }
111034
+ turnAttempts.delete(key);
111035
+ yield* orchestrationEngine.dispatch({
111036
+ type: "thread.scheduled-task.fire",
111037
+ commandId: scheduledTaskFireCommandId(threadId, task.id),
111038
+ threadId,
111039
+ taskId: task.id,
111040
+ firedAt: yield* nowIso,
111041
+ failure: `Could not start the turn after ${attempts} attempts: ${describeFailure(turnResult.failure)}`
111042
+ });
111043
+ return;
111044
+ }
111045
+ turnAttempts.delete(key);
111046
+ yield* orchestrationEngine.dispatch({
111047
+ type: "thread.scheduled-task.fire",
111048
+ commandId: scheduledTaskFireCommandId(threadId, task.id),
111049
+ threadId,
111050
+ taskId: task.id,
111051
+ firedAt: yield* nowIso
111052
+ });
111053
+ });
111054
+ const armAfter = (threadId, task, delay) => Effect.gen(function* () {
111055
+ const key = scheduledTaskKey(threadId, task.id);
111056
+ const existing = timers.get(key);
111057
+ if (existing !== void 0) {
111058
+ timers.delete(key);
111059
+ yield* Fiber.interrupt(existing);
111060
+ }
111061
+ const fiber = yield* Effect.forkDetach(Effect.sleep(delay).pipe(Effect.flatMap(() => fire(threadId, task).pipe(Effect.retry(FIRE_RETRY))), Effect.catchCause((cause) => Cause.hasInterruptsOnly(cause) ? Effect.void : Effect.logWarning("scheduled task failed to fire; it stays pending until reconcile re-arms it", {
111062
+ threadId,
111063
+ taskId: task.id,
111064
+ cause: Cause.pretty(cause)
111065
+ }))));
111066
+ timers.set(key, fiber);
111067
+ });
111068
+ const arm = (threadId, task) => Effect.gen(function* () {
111069
+ const delayMs = scheduledTaskDelayMs(task.runAt, yield* Clock.currentTimeMillis);
111070
+ yield* armAfter(threadId, task, Duration.millis(delayMs));
111071
+ });
111072
+ /** Arms every pending task that has no live timer; the read model is authoritative. */
111073
+ const reconcile = Effect.fn("ScheduledTaskReactor.reconcile")(function* () {
111074
+ const readModel = yield* projectionSnapshotQuery.getCommandReadModel();
111075
+ for (const pending of pendingScheduledTasks(readModel.threads)) {
111076
+ if (timers.has(scheduledTaskKey(pending.threadId, pending.task.id))) continue;
111077
+ yield* arm(pending.threadId, pending.task);
111078
+ }
111079
+ });
111080
+ const processEvent = Effect.fn("ScheduledTaskReactor.processEvent")(function* (event) {
111081
+ switch (event.type) {
111082
+ case "thread.scheduled-task.created":
111083
+ yield* arm(event.payload.threadId, event.payload.task);
111084
+ return;
111085
+ case "thread.scheduled-task.cancelled":
111086
+ case "thread.scheduled-task.fired":
111087
+ yield* disarm(event.payload.threadId, event.payload.taskId);
111088
+ return;
111089
+ case "thread.deleted":
111090
+ for (const key of Array.from(timers.keys())) {
111091
+ if (!key.startsWith(`${event.payload.threadId}:`)) continue;
111092
+ const fiber = timers.get(key);
111093
+ timers.delete(key);
111094
+ turnAttempts.delete(key);
111095
+ if (fiber !== void 0) yield* Fiber.interrupt(fiber);
111096
+ }
111097
+ return;
111098
+ }
111099
+ });
111100
+ const processEventSafely = (event) => processEvent(event).pipe(Effect.catchCause((cause) => Cause.hasInterruptsOnly(cause) ? Effect.failCause(cause) : Effect.logWarning("scheduled task reactor failed to process event", {
111101
+ eventType: event.type,
111102
+ cause: Cause.pretty(cause)
111103
+ })));
111104
+ const worker = yield* makeDrainableWorker(processEventSafely);
111105
+ const logReconcileFailure = (cause) => Effect.logWarning("scheduled task reconcile failed", { cause: Cause.pretty(cause) });
111106
+ return {
111107
+ start: Effect.fn("start")(function* () {
111108
+ yield* Effect.forkScoped(Stream.runForEach(orchestrationEngine.streamDomainEvents, (event) => {
111109
+ switch (event.type) {
111110
+ case "thread.scheduled-task.created":
111111
+ case "thread.scheduled-task.cancelled":
111112
+ case "thread.scheduled-task.fired":
111113
+ case "thread.deleted": return worker.enqueue(event);
111114
+ default: return Effect.void;
111115
+ }
111116
+ }));
111117
+ yield* reconcile().pipe(Effect.catchCause(logReconcileFailure));
111118
+ yield* Effect.forkScoped(Effect.repeat(reconcile().pipe(Effect.catchCause(logReconcileFailure)), Schedule.spaced(SCHEDULED_TASK_RECONCILE_INTERVAL)).pipe(Effect.delay(SCHEDULED_TASK_RECONCILE_INTERVAL)));
111119
+ yield* Effect.addFinalizer(() => Effect.forEach([...timers.values()], (fiber) => Fiber.interrupt(fiber), { discard: true }).pipe(Effect.tap(() => Effect.sync(() => timers.clear()))));
111120
+ }),
111121
+ drain: worker.drain
111122
+ };
111123
+ });
111124
+ const ScheduledTaskReactorLive = Layer.effect(ScheduledTaskReactor, make);
110094
111125
  //#endregion
110095
111126
  //#region src/provider/providerStatusCache.ts
110096
111127
  const decodeProviderStatusCache = Schema$1.decodeUnknownEffect(Schema$1.fromJsonString(ServerProvider));
@@ -110871,7 +111902,7 @@ const PlatformServicesLive = Layer.unwrap(Effect.gen(function* () {
110871
111902
  return layer;
110872
111903
  }
110873
111904
  }));
110874
- const ReactorLayerLive = Layer.empty.pipe(Layer.provideMerge(OrchestrationReactorLive), Layer.provideMerge(ProviderRuntimeIngestionLive), Layer.provideMerge(ProviderCommandReactorLive), Layer.provideMerge(CheckpointReactorLive), Layer.provideMerge(ThreadDeletionReactorLive), Layer.provideMerge(FusionWatcherReactorLive), Layer.provideMerge(RuntimeReceiptBusLive));
111905
+ const ReactorLayerLive = Layer.empty.pipe(Layer.provideMerge(OrchestrationReactorLive), Layer.provideMerge(ProviderRuntimeIngestionLive), Layer.provideMerge(ProviderCommandReactorLive), Layer.provideMerge(CheckpointReactorLive), Layer.provideMerge(ThreadDeletionReactorLive), Layer.provideMerge(FusionWatcherReactorLive), Layer.provideMerge(ScheduledTaskReactorLive), Layer.provideMerge(RuntimeReceiptBusLive));
110875
111906
  const ProviderSessionDirectoryLayerLive = ProviderSessionDirectoryLive.pipe(Layer.provide(layer$4));
110876
111907
  const ProviderLayerLive = ProviderServiceLive.pipe(Layer.provide(ProviderAdapterRegistryLive), Layer.provideMerge(ProviderSessionDirectoryLayerLive));
110877
111908
  const PersistenceLayerLive = Layer.empty.pipe(Layer.provideMerge(layerConfig));