@p4code/cli 0.2.7 → 0.2.9

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
@@ -125,7 +125,7 @@ const closeServer = (server) => {
125
125
  * NetService - Service tag for startup networking helpers.
126
126
  */
127
127
  var NetService = class extends Context.Service()("@p4code/shared/Net/NetService") {};
128
- const make$87 = () => {
128
+ const make$88 = () => {
129
129
  /**
130
130
  * Returns true when a TCP server can bind to {host, port}.
131
131
  * `EADDRNOTAVAIL` is treated as available so IPv6-absent hosts don't fail
@@ -234,10 +234,10 @@ const make$87 = () => {
234
234
  })
235
235
  };
236
236
  };
237
- const layer$79 = Layer.sync(NetService, make$87);
237
+ const layer$79 = Layer.sync(NetService, make$88);
238
238
  //#endregion
239
239
  //#region package.json
240
- var version = "0.2.7";
240
+ var version = "0.2.9";
241
241
  //#endregion
242
242
  //#region src/config.ts
243
243
  /**
@@ -258,8 +258,8 @@ var ServerConfig$1 = class extends Context.Service()("@p4code/cli/config/ServerC
258
258
  /** @deprecated Import and use `layerTest` from this module. */
259
259
  static layerTest = (cwd, baseDirOrPrefix) => layerTest$3(cwd, baseDirOrPrefix);
260
260
  };
261
- const make$86 = (config) => ServerConfig$1.of(config);
262
- const layer$78 = (config) => Layer.succeed(ServerConfig$1, make$86(config));
261
+ const make$87 = (config) => ServerConfig$1.of(config);
262
+ const layer$78 = (config) => Layer.succeed(ServerConfig$1, make$87(config));
263
263
  const deriveServerPaths = Effect.fn(function* (baseDir, devUrl, options = {}) {
264
264
  const { join } = yield* Path.Path;
265
265
  const stateDir = join(baseDir, devUrl !== void 0 && !options.baseDirIsExplicit ? "dev" : "userdata");
@@ -1005,6 +1005,7 @@ const makeEntityId = (brand) => {
1005
1005
  return TrimmedNonEmptyString.pipe(Schema$1.brand(brand));
1006
1006
  };
1007
1007
  const ThreadId = makeEntityId("ThreadId");
1008
+ const ThreadPairId = makeEntityId("ThreadPairId");
1008
1009
  const ProjectId = makeEntityId("ProjectId");
1009
1010
  /**
1010
1011
  * Identifies a task on the agent task board. Unrelated to {@link RuntimeTaskId},
@@ -1830,6 +1831,8 @@ const OrchestrationMessage = Schema$1.Struct({
1830
1831
  createdAt: IsoDateTime,
1831
1832
  updatedAt: IsoDateTime
1832
1833
  });
1834
+ const FUSION_REVIEW_PROMPT_PREFIX = "[fusion-review]";
1835
+ const FUSION_NO_OBJECTION_TEXT = "[fusion-no-objection]";
1833
1836
  const OrchestrationProposedPlanId = TrimmedNonEmptyString;
1834
1837
  const OrchestrationProposedPlan = Schema$1.Struct({
1835
1838
  id: OrchestrationProposedPlanId,
@@ -1947,10 +1950,20 @@ const OrchestrationThread = Schema$1.Struct({
1947
1950
  checkpoints: Schema$1.Array(OrchestrationCheckpointSummary),
1948
1951
  session: Schema$1.NullOr(OrchestrationSession)
1949
1952
  });
1953
+ /** Persisted relationship between two otherwise ordinary threads. */
1954
+ const OrchestrationThreadPair = Schema$1.Struct({
1955
+ id: ThreadPairId,
1956
+ implementerThreadId: ThreadId,
1957
+ watcherThreadId: ThreadId,
1958
+ lastReviewedImplementerSequence: NonNegativeInt,
1959
+ createdAt: IsoDateTime,
1960
+ detachedAt: Schema$1.NullOr(IsoDateTime)
1961
+ });
1950
1962
  const OrchestrationReadModel = Schema$1.Struct({
1951
1963
  snapshotSequence: NonNegativeInt,
1952
1964
  projects: Schema$1.Array(OrchestrationProject),
1953
1965
  threads: Schema$1.Array(OrchestrationThread),
1966
+ threadPairs: Schema$1.optional(Schema$1.Array(OrchestrationThreadPair)),
1954
1967
  updatedAt: IsoDateTime
1955
1968
  });
1956
1969
  const OrchestrationProjectShell = Schema$1.Struct({
@@ -1994,6 +2007,7 @@ const OrchestrationShellSnapshot = Schema$1.Struct({
1994
2007
  snapshotSequence: NonNegativeInt,
1995
2008
  projects: Schema$1.Array(OrchestrationProjectShell),
1996
2009
  threads: Schema$1.Array(OrchestrationThreadShell),
2010
+ threadPairs: Schema$1.optional(Schema$1.Array(OrchestrationThreadPair)),
1997
2011
  updatedAt: IsoDateTime
1998
2012
  });
1999
2013
  const OrchestrationShellStreamEvent = Schema$1.Union([
@@ -2016,6 +2030,16 @@ const OrchestrationShellStreamEvent = Schema$1.Union([
2016
2030
  kind: Schema$1.Literal("thread-removed"),
2017
2031
  sequence: NonNegativeInt,
2018
2032
  threadId: ThreadId
2033
+ }),
2034
+ Schema$1.Struct({
2035
+ kind: Schema$1.Literal("thread-pair-upserted"),
2036
+ sequence: NonNegativeInt,
2037
+ pair: OrchestrationThreadPair
2038
+ }),
2039
+ Schema$1.Struct({
2040
+ kind: Schema$1.Literal("thread-pair-removed"),
2041
+ sequence: NonNegativeInt,
2042
+ pairId: ThreadPairId
2019
2043
  })
2020
2044
  ]);
2021
2045
  const OrchestrationShellStreamItem = Schema$1.Union([
@@ -2282,6 +2306,20 @@ const ThreadSessionStopCommand = Schema$1.Struct({
2282
2306
  threadId: ThreadId,
2283
2307
  createdAt: IsoDateTime
2284
2308
  });
2309
+ const ThreadPairCreateCommand = Schema$1.Struct({
2310
+ type: Schema$1.Literal("thread-pair.create"),
2311
+ commandId: CommandId,
2312
+ pairId: ThreadPairId,
2313
+ implementerThreadId: ThreadId,
2314
+ watcherThreadId: ThreadId,
2315
+ createdAt: IsoDateTime
2316
+ });
2317
+ const ThreadPairDetachCommand = Schema$1.Struct({
2318
+ type: Schema$1.Literal("thread-pair.detach"),
2319
+ commandId: CommandId,
2320
+ pairId: ThreadPairId,
2321
+ createdAt: IsoDateTime
2322
+ });
2285
2323
  const DispatchableClientOrchestrationCommand = Schema$1.Union([
2286
2324
  ProjectCreateCommand,
2287
2325
  ProjectMetaUpdateCommand,
@@ -2304,7 +2342,9 @@ const DispatchableClientOrchestrationCommand = Schema$1.Union([
2304
2342
  ThreadApprovalRespondCommand,
2305
2343
  ThreadUserInputRespondCommand,
2306
2344
  ThreadCheckpointRevertCommand,
2307
- ThreadSessionStopCommand
2345
+ ThreadSessionStopCommand,
2346
+ ThreadPairCreateCommand,
2347
+ ThreadPairDetachCommand
2308
2348
  ]);
2309
2349
  const ClientOrchestrationCommand = Schema$1.Union([
2310
2350
  ProjectCreateCommand,
@@ -2328,7 +2368,9 @@ const ClientOrchestrationCommand = Schema$1.Union([
2328
2368
  ThreadApprovalRespondCommand,
2329
2369
  ThreadUserInputRespondCommand,
2330
2370
  ThreadCheckpointRevertCommand,
2331
- ThreadSessionStopCommand
2371
+ ThreadSessionStopCommand,
2372
+ ThreadPairCreateCommand,
2373
+ ThreadPairDetachCommand
2332
2374
  ]);
2333
2375
  const ThreadSessionSetCommand = Schema$1.Struct({
2334
2376
  type: Schema$1.Literal("thread.session.set"),
@@ -2337,6 +2379,26 @@ const ThreadSessionSetCommand = Schema$1.Struct({
2337
2379
  session: OrchestrationSession,
2338
2380
  createdAt: IsoDateTime
2339
2381
  });
2382
+ const ThreadTurnCompleteCommand = Schema$1.Struct({
2383
+ type: Schema$1.Literal("thread.turn.complete"),
2384
+ commandId: CommandId,
2385
+ threadId: ThreadId,
2386
+ turnId: Schema$1.optional(TurnId),
2387
+ state: Schema$1.Literals([
2388
+ "completed",
2389
+ "failed",
2390
+ "interrupted",
2391
+ "cancelled"
2392
+ ]),
2393
+ completedAt: IsoDateTime
2394
+ });
2395
+ const ThreadPairCursorAdvanceCommand = Schema$1.Struct({
2396
+ type: Schema$1.Literal("thread-pair.cursor.advance"),
2397
+ commandId: CommandId,
2398
+ pairId: ThreadPairId,
2399
+ implementerSequence: NonNegativeInt,
2400
+ advancedAt: IsoDateTime
2401
+ });
2340
2402
  const ThreadMessageAssistantDeltaCommand = Schema$1.Struct({
2341
2403
  type: Schema$1.Literal("thread.message.assistant.delta"),
2342
2404
  commandId: CommandId,
@@ -2390,6 +2452,8 @@ const ThreadRevertCompleteCommand = Schema$1.Struct({
2390
2452
  });
2391
2453
  const InternalOrchestrationCommand = Schema$1.Union([
2392
2454
  ThreadSessionSetCommand,
2455
+ ThreadTurnCompleteCommand,
2456
+ ThreadPairCursorAdvanceCommand,
2393
2457
  ThreadMessageAssistantDeltaCommand,
2394
2458
  ThreadMessageAssistantCompleteCommand,
2395
2459
  ThreadProposedPlanUpsertCommand,
@@ -2426,9 +2490,17 @@ const OrchestrationEventType = Schema$1.Literals([
2426
2490
  "thread.session-set",
2427
2491
  "thread.proposed-plan-upserted",
2428
2492
  "thread.turn-diff-completed",
2429
- "thread.activity-appended"
2493
+ "thread.activity-appended",
2494
+ "thread.turn-completed",
2495
+ "thread-pair.created",
2496
+ "thread-pair.detached",
2497
+ "thread-pair.cursor-advanced"
2498
+ ]);
2499
+ const OrchestrationAggregateKind = Schema$1.Literals([
2500
+ "project",
2501
+ "thread",
2502
+ "thread-pair"
2430
2503
  ]);
2431
- const OrchestrationAggregateKind = Schema$1.Literals(["project", "thread"]);
2432
2504
  const OrchestrationActorKind = Schema$1.Literals([
2433
2505
  "client",
2434
2506
  "server",
@@ -2595,6 +2667,33 @@ const ThreadSessionSetPayload$1 = Schema$1.Struct({
2595
2667
  threadId: ThreadId,
2596
2668
  session: OrchestrationSession
2597
2669
  });
2670
+ const ThreadTurnCompletedPayload = Schema$1.Struct({
2671
+ threadId: ThreadId,
2672
+ turnId: Schema$1.NullOr(TurnId),
2673
+ state: Schema$1.Literals([
2674
+ "completed",
2675
+ "failed",
2676
+ "interrupted",
2677
+ "cancelled"
2678
+ ]),
2679
+ completedAt: IsoDateTime
2680
+ });
2681
+ const ThreadPairCreatedPayload$1 = Schema$1.Struct({
2682
+ pairId: ThreadPairId,
2683
+ implementerThreadId: ThreadId,
2684
+ watcherThreadId: ThreadId,
2685
+ lastReviewedImplementerSequence: NonNegativeInt,
2686
+ createdAt: IsoDateTime
2687
+ });
2688
+ const ThreadPairDetachedPayload$1 = Schema$1.Struct({
2689
+ pairId: ThreadPairId,
2690
+ detachedAt: IsoDateTime
2691
+ });
2692
+ const ThreadPairCursorAdvancedPayload$1 = Schema$1.Struct({
2693
+ pairId: ThreadPairId,
2694
+ implementerSequence: NonNegativeInt,
2695
+ advancedAt: IsoDateTime
2696
+ });
2598
2697
  const ThreadProposedPlanUpsertedPayload$1 = Schema$1.Struct({
2599
2698
  threadId: ThreadId,
2600
2699
  proposedPlan: OrchestrationProposedPlan
@@ -2624,7 +2723,11 @@ const EventBaseFields = {
2624
2723
  sequence: NonNegativeInt,
2625
2724
  eventId: EventId,
2626
2725
  aggregateKind: OrchestrationAggregateKind,
2627
- aggregateId: Schema$1.Union([ProjectId, ThreadId]),
2726
+ aggregateId: Schema$1.Union([
2727
+ ProjectId,
2728
+ ThreadId,
2729
+ ThreadPairId
2730
+ ]),
2628
2731
  occurredAt: IsoDateTime,
2629
2732
  commandId: Schema$1.NullOr(CommandId),
2630
2733
  causationEventId: Schema$1.NullOr(EventId),
@@ -2771,6 +2874,26 @@ const OrchestrationEvent = Schema$1.Union([
2771
2874
  ...EventBaseFields,
2772
2875
  type: Schema$1.Literal("thread.activity-appended"),
2773
2876
  payload: ThreadActivityAppendedPayload$1
2877
+ }),
2878
+ Schema$1.Struct({
2879
+ ...EventBaseFields,
2880
+ type: Schema$1.Literal("thread.turn-completed"),
2881
+ payload: ThreadTurnCompletedPayload
2882
+ }),
2883
+ Schema$1.Struct({
2884
+ ...EventBaseFields,
2885
+ type: Schema$1.Literal("thread-pair.created"),
2886
+ payload: ThreadPairCreatedPayload$1
2887
+ }),
2888
+ Schema$1.Struct({
2889
+ ...EventBaseFields,
2890
+ type: Schema$1.Literal("thread-pair.detached"),
2891
+ payload: ThreadPairDetachedPayload$1
2892
+ }),
2893
+ Schema$1.Struct({
2894
+ ...EventBaseFields,
2895
+ type: Schema$1.Literal("thread-pair.cursor-advanced"),
2896
+ payload: ThreadPairCursorAdvancedPayload$1
2774
2897
  })
2775
2898
  ]);
2776
2899
  const OrchestrationThreadStreamItem = Schema$1.Union([
@@ -9209,6 +9332,12 @@ const ThreadSpawnResult = Schema$1.Struct({
9209
9332
  projectId: ProjectId,
9210
9333
  title: TrimmedNonEmptyString
9211
9334
  });
9335
+ const ThreadPairCreateInput = Schema$1.Struct({ watcherThreadId: ThreadId.annotate({ description: "The watcher thread to pair with this session's own thread. It must have been created by this session through thread_spawn." }) });
9336
+ const ThreadPairCreateResult = Schema$1.Struct({
9337
+ pairId: ThreadPairId,
9338
+ implementerThreadId: ThreadId,
9339
+ watcherThreadId: ThreadId
9340
+ });
9212
9341
  const ThreadConfigureInput = Schema$1.Struct({
9213
9342
  threadId: ControlTargetThreadId,
9214
9343
  title: Schema$1.optional(TrimmedNonEmptyString),
@@ -11565,7 +11694,7 @@ function deriveAuthClientMetadata(input) {
11565
11694
  //#endregion
11566
11695
  //#region src/auth/EnvironmentAuthPolicy.ts
11567
11696
  var EnvironmentAuthPolicy = class extends Context.Service()("@p4code/cli/auth/EnvironmentAuthPolicy") {};
11568
- const make$85 = Effect.gen(function* () {
11697
+ const make$86 = Effect.gen(function* () {
11569
11698
  const config = yield* ServerConfig$1;
11570
11699
  const isRemoteReachable = isRemoteReachableHost(config.host);
11571
11700
  const policy = config.mode === "desktop" ? isRemoteReachable ? "remote-reachable" : "desktop-managed-local" : isRemoteReachable ? "remote-reachable" : "loopback-browser";
@@ -11583,7 +11712,7 @@ const make$85 = Effect.gen(function* () {
11583
11712
  };
11584
11713
  return EnvironmentAuthPolicy.of({ getDescriptor: () => Effect.succeed(descriptor).pipe(Effect.withSpan("EnvironmentAuthPolicy.getDescriptor")) });
11585
11714
  });
11586
- const layer$77 = Layer.effect(EnvironmentAuthPolicy, make$85);
11715
+ const layer$77 = Layer.effect(EnvironmentAuthPolicy, make$86);
11587
11716
  //#endregion
11588
11717
  //#region src/persistence/Errors.ts
11589
11718
  function summarizeSchemaIssue(issue) {
@@ -11764,7 +11893,7 @@ function toPersistenceSqlOrDecodeError$6(sqlOperation, decodeOperation, correlat
11764
11893
  cause
11765
11894
  });
11766
11895
  }
11767
- const make$84 = Effect.gen(function* () {
11896
+ const make$85 = Effect.gen(function* () {
11768
11897
  const sql = yield* SqlClient.SqlClient;
11769
11898
  const createSessionRow = SqlSchema.void({
11770
11899
  Request: CreateAuthSessionInput,
@@ -11898,7 +12027,7 @@ const make$84 = Effect.gen(function* () {
11898
12027
  setLastConnectedAt
11899
12028
  };
11900
12029
  });
11901
- const layer$76 = Layer.effect(AuthSessionRepository, make$84);
12030
+ const layer$76 = Layer.effect(AuthSessionRepository, make$85);
11902
12031
  //#endregion
11903
12032
  //#region src/auth/ServerSecretStore.ts
11904
12033
  const secretStoreErrorContext = {
@@ -11965,7 +12094,7 @@ const isSecretStoreError = Schema$1.is(SecretStoreError);
11965
12094
  const isPlatformError = (value) => Predicate.isTagged(value, "PlatformError");
11966
12095
  const isSecretAlreadyExistsError = (error) => "cause" in error && isPlatformError(error.cause) && error.cause.reason._tag === "AlreadyExists";
11967
12096
  var ServerSecretStore = class extends Context.Service()("@p4code/cli/auth/ServerSecretStore") {};
11968
- const make$83 = Effect.gen(function* () {
12097
+ const make$84 = Effect.gen(function* () {
11969
12098
  const crypto = yield* Crypto.Crypto;
11970
12099
  const fileSystem = yield* FileSystem.FileSystem;
11971
12100
  const path = yield* Path.Path;
@@ -12035,7 +12164,7 @@ const make$83 = Effect.gen(function* () {
12035
12164
  remove
12036
12165
  });
12037
12166
  });
12038
- const layer$75 = Layer.effect(ServerSecretStore, make$83);
12167
+ const layer$75 = Layer.effect(ServerSecretStore, make$84);
12039
12168
  //#endregion
12040
12169
  //#region src/auth/SessionStore.ts
12041
12170
  var MalformedSessionTokenError = class extends Schema$1.TaggedErrorClass()("MalformedSessionTokenError", {}) {
@@ -12273,7 +12402,7 @@ function toAuthClientSession(input) {
12273
12402
  current: false
12274
12403
  };
12275
12404
  }
12276
- const make$82 = Effect.gen(function* () {
12405
+ const make$83 = Effect.gen(function* () {
12277
12406
  const crypto = yield* Crypto.Crypto;
12278
12407
  const serverConfig = yield* ServerConfig$1;
12279
12408
  const secretStore = yield* ServerSecretStore;
@@ -12587,7 +12716,7 @@ const make$82 = Effect.gen(function* () {
12587
12716
  markDisconnected
12588
12717
  });
12589
12718
  });
12590
- const layer$74 = Layer.effect(SessionStore, make$82).pipe(Layer.provideMerge(layer$76));
12719
+ const layer$74 = Layer.effect(SessionStore, make$83).pipe(Layer.provideMerge(layer$76));
12591
12720
  //#endregion
12592
12721
  //#region src/persistence/AuthPairingLinks.ts
12593
12722
  const AuthPairingLinkRecord = Schema$1.Struct({
@@ -12648,7 +12777,7 @@ function toPersistenceSqlOrDecodeError$5(sqlOperation, decodeOperation, correlat
12648
12777
  cause
12649
12778
  });
12650
12779
  }
12651
- const make$81 = Effect.gen(function* () {
12780
+ const make$82 = Effect.gen(function* () {
12652
12781
  const sql = yield* SqlClient.SqlClient;
12653
12782
  const createPairingLinkRow = SqlSchema.void({
12654
12783
  Request: CreateAuthPairingLinkInput,
@@ -12783,7 +12912,7 @@ const make$81 = Effect.gen(function* () {
12783
12912
  getByCredential
12784
12913
  };
12785
12914
  });
12786
- const layer$73 = Layer.effect(AuthPairingLinkRepository, make$81);
12915
+ const layer$73 = Layer.effect(AuthPairingLinkRepository, make$82);
12787
12916
  //#endregion
12788
12917
  //#region src/auth/PairingGrantStore.ts
12789
12918
  var UnknownBootstrapCredentialError = class extends Schema$1.TaggedErrorClass()("UnknownBootstrapCredentialError", {}) {
@@ -12878,7 +13007,7 @@ const DEV_STARTUP_TTL_HOURS = Duration.hours(24);
12878
13007
  const PAIRING_TOKEN_ALPHABET = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";
12879
13008
  const PAIRING_TOKEN_LENGTH = 12;
12880
13009
  const PAIRING_TOKEN_REJECTION_LIMIT = Math.floor(256 / 32) * 32;
12881
- const make$80 = Effect.gen(function* () {
13010
+ const make$81 = Effect.gen(function* () {
12882
13011
  const crypto = yield* Crypto.Crypto;
12883
13012
  const config = yield* ServerConfig$1;
12884
13013
  const pairingLinks = yield* AuthPairingLinkRepository;
@@ -13076,7 +13205,7 @@ const make$80 = Effect.gen(function* () {
13076
13205
  consume
13077
13206
  });
13078
13207
  });
13079
- const layer$72 = Layer.effect(PairingGrantStore, make$80).pipe(Layer.provideMerge(layer$73));
13208
+ const layer$72 = Layer.effect(PairingGrantStore, make$81).pipe(Layer.provideMerge(layer$73));
13080
13209
  //#endregion
13081
13210
  //#region src/persistence/DatabaseSnapshot.ts
13082
13211
  /**
@@ -14831,6 +14960,69 @@ var _045_ProjectionThreadsBackgroundWork_default = Effect.gen(function* () {
14831
14960
  `;
14832
14961
  });
14833
14962
  //#endregion
14963
+ //#region src/persistence/Migrations/046_ThreadPairs.ts
14964
+ /** Persisted Fusion relationship and durable watcher cursor. */
14965
+ var _046_ThreadPairs_default = Effect.gen(function* () {
14966
+ const sql = yield* SqlClient.SqlClient;
14967
+ yield* sql`
14968
+ CREATE TABLE thread_pairs (
14969
+ pair_id TEXT PRIMARY KEY,
14970
+ implementer_thread_id TEXT NOT NULL,
14971
+ watcher_thread_id TEXT NOT NULL,
14972
+ last_reviewed_implementer_sequence INTEGER NOT NULL DEFAULT 0,
14973
+ created_at TEXT NOT NULL,
14974
+ detached_at TEXT,
14975
+ CHECK (implementer_thread_id <> watcher_thread_id),
14976
+ CHECK (last_reviewed_implementer_sequence >= 0),
14977
+ FOREIGN KEY (implementer_thread_id) REFERENCES projection_threads(thread_id),
14978
+ FOREIGN KEY (watcher_thread_id) REFERENCES projection_threads(thread_id)
14979
+ )
14980
+ `;
14981
+ yield* sql`
14982
+ CREATE UNIQUE INDEX thread_pairs_active_implementer_idx
14983
+ ON thread_pairs(implementer_thread_id)
14984
+ WHERE detached_at IS NULL
14985
+ `;
14986
+ yield* sql`
14987
+ CREATE UNIQUE INDEX thread_pairs_active_watcher_idx
14988
+ ON thread_pairs(watcher_thread_id)
14989
+ WHERE detached_at IS NULL
14990
+ `;
14991
+ yield* sql`
14992
+ CREATE TRIGGER thread_pairs_active_cross_role_insert
14993
+ BEFORE INSERT ON thread_pairs
14994
+ WHEN NEW.detached_at IS NULL AND EXISTS (
14995
+ SELECT 1
14996
+ FROM thread_pairs
14997
+ WHERE detached_at IS NULL
14998
+ AND (
14999
+ implementer_thread_id IN (NEW.implementer_thread_id, NEW.watcher_thread_id)
15000
+ OR watcher_thread_id IN (NEW.implementer_thread_id, NEW.watcher_thread_id)
15001
+ )
15002
+ )
15003
+ BEGIN
15004
+ SELECT RAISE(ABORT, 'thread already belongs to an active pair');
15005
+ END
15006
+ `;
15007
+ yield* sql`
15008
+ CREATE TRIGGER thread_pairs_active_cross_role_update
15009
+ BEFORE UPDATE OF implementer_thread_id, watcher_thread_id, detached_at ON thread_pairs
15010
+ WHEN NEW.detached_at IS NULL AND EXISTS (
15011
+ SELECT 1
15012
+ FROM thread_pairs
15013
+ WHERE pair_id <> NEW.pair_id
15014
+ AND detached_at IS NULL
15015
+ AND (
15016
+ implementer_thread_id IN (NEW.implementer_thread_id, NEW.watcher_thread_id)
15017
+ OR watcher_thread_id IN (NEW.implementer_thread_id, NEW.watcher_thread_id)
15018
+ )
15019
+ )
15020
+ BEGIN
15021
+ SELECT RAISE(ABORT, 'thread already belongs to an active pair');
15022
+ END
15023
+ `;
15024
+ });
15025
+ //#endregion
14834
15026
  //#region src/persistence/Migrations.ts
14835
15027
  /**
14836
15028
  * MigrationsLive - Migration runner with inline loader
@@ -15076,6 +15268,11 @@ const migrationEntries = [
15076
15268
  45,
15077
15269
  "ProjectionThreadsBackgroundWork",
15078
15270
  _045_ProjectionThreadsBackgroundWork_default
15271
+ ],
15272
+ [
15273
+ 46,
15274
+ "ThreadPairs",
15275
+ _046_ThreadPairs_default
15079
15276
  ]
15080
15277
  ];
15081
15278
  const makeMigrationLoader = (throughId) => Migrator.fromRecord(Object.fromEntries(migrationEntries.filter(([id]) => throughId === void 0 || id <= throughId).map(([id, name, migration]) => [`${id}_${name}`, migration])));
@@ -15326,7 +15523,7 @@ function parseBearerToken(request) {
15326
15523
  const token = header.slice(7).trim();
15327
15524
  return token.length > 0 ? token : null;
15328
15525
  }
15329
- const make$79 = Effect.gen(function* () {
15526
+ const make$80 = Effect.gen(function* () {
15330
15527
  const policy = yield* EnvironmentAuthPolicy;
15331
15528
  const bootstrapCredentials = yield* PairingGrantStore;
15332
15529
  const sessions = yield* SessionStore;
@@ -15521,7 +15718,7 @@ const make$79 = Effect.gen(function* () {
15521
15718
  issueStartupPairingUrl
15522
15719
  });
15523
15720
  });
15524
- const layer$71 = Layer.effect(EnvironmentAuth, make$79).pipe(Layer.provideMerge(layer$72), Layer.provideMerge(layer$74), Layer.provideMerge(layer$77));
15721
+ const layer$71 = Layer.effect(EnvironmentAuth, make$80).pipe(Layer.provideMerge(layer$72), Layer.provideMerge(layer$74), Layer.provideMerge(layer$77));
15525
15722
  const storageLayer = Layer.mergeAll(layer$75, layerConfig);
15526
15723
  const runtimeLayer = layer$71.pipe(Layer.provideMerge(storageLayer));
15527
15724
  //#endregion
@@ -16418,7 +16615,7 @@ const DEFAULT_LIMITS = {
16418
16615
  windowMillis: FAILURE_WINDOW_MS,
16419
16616
  blockMillis: BLOCK_DURATION_MS
16420
16617
  };
16421
- const make$78 = Effect.fn("HubAuthThrottle.make")(function* (limits = DEFAULT_LIMITS) {
16618
+ const make$79 = Effect.fn("HubAuthThrottle.make")(function* (limits = DEFAULT_LIMITS) {
16422
16619
  const state = yield* Ref.make(initialThrottleState);
16423
16620
  return HubAuthThrottle.of({
16424
16621
  shouldRefuse: Effect.gen(function* () {
@@ -16432,7 +16629,7 @@ const make$78 = Effect.fn("HubAuthThrottle.make")(function* (limits = DEFAULT_LI
16432
16629
  })
16433
16630
  });
16434
16631
  });
16435
- const layer$70 = Layer.effect(HubAuthThrottle, make$78());
16632
+ const layer$70 = Layer.effect(HubAuthThrottle, make$79());
16436
16633
  //#endregion
16437
16634
  //#region src/hub/HubAuth.ts
16438
16635
  /**
@@ -17755,7 +17952,7 @@ function stripDefaultServerSettings(current, defaults) {
17755
17952
  }
17756
17953
  return Object.is(current, defaults) ? void 0 : current;
17757
17954
  }
17758
- const make$77 = Effect.gen(function* () {
17955
+ const make$78 = Effect.gen(function* () {
17759
17956
  const { settingsPath } = yield* ServerConfig$1;
17760
17957
  const fs = yield* FileSystem.FileSystem;
17761
17958
  const pathService = yield* Path.Path;
@@ -17976,7 +18173,7 @@ const make$77 = Effect.gen(function* () {
17976
18173
  }
17977
18174
  };
17978
18175
  });
17979
- const layer$68 = Layer.effect(ServerSettingsService, make$77);
18176
+ const layer$68 = Layer.effect(ServerSettingsService, make$78);
17980
18177
  //#endregion
17981
18178
  //#region src/pathExpansion.ts
17982
18179
  /**
@@ -18350,7 +18547,7 @@ function claudeEntryFromRegistration(registration) {
18350
18547
  };
18351
18548
  }
18352
18549
  var ClaudeMcpFiles = class extends Context.Service()("@p4code/cli/mcp/ClaudeMcpFiles") {};
18353
- const make$76 = Effect.gen(function* () {
18550
+ const make$77 = Effect.gen(function* () {
18354
18551
  const fileSystem = yield* FileSystem.FileSystem;
18355
18552
  const path = yield* Path.Path;
18356
18553
  const services = yield* Effect.context();
@@ -18415,7 +18612,7 @@ const make$76 = Effect.gen(function* () {
18415
18612
  removeProject: (projectDir, name) => removeAt(Effect.succeed(projectFile(projectDir)))(name)
18416
18613
  };
18417
18614
  });
18418
- const layer$67 = Layer.effect(ClaudeMcpFiles, make$76);
18615
+ const layer$67 = Layer.effect(ClaudeMcpFiles, make$77);
18419
18616
  Layer.succeed(ClaudeMcpFiles, {
18420
18617
  readUser: Effect.succeed([]),
18421
18618
  upsertUser: () => Effect.fail(new McpRegistryError({ detail: "No Claude config in tests." })),
@@ -18551,7 +18748,7 @@ const decodeClientRegistration = Schema$1.decodeUnknownExit(ClientRegistrationRe
18551
18748
  const decodeTokenResponse = Schema$1.decodeUnknownExit(TokenResponse);
18552
18749
  var McpOAuth = class extends Context.Service()("@p4code/cli/mcp/McpOAuth") {};
18553
18750
  const registryError = (detail) => new McpRegistryError({ detail });
18554
- const make$75 = Effect.gen(function* () {
18751
+ const make$76 = Effect.gen(function* () {
18555
18752
  const config = yield* ServerConfig$1;
18556
18753
  const secrets = yield* ServerSecretStore;
18557
18754
  const http = yield* HttpClient.HttpClient;
@@ -18871,7 +19068,7 @@ const make$75 = Effect.gen(function* () {
18871
19068
  accessTokenFor
18872
19069
  };
18873
19070
  });
18874
- const layer$66 = Layer.effect(McpOAuth, make$75);
19071
+ const layer$66 = Layer.effect(McpOAuth, make$76);
18875
19072
  Layer.succeed(McpOAuth, {
18876
19073
  statusFor: () => Effect.succeed(Option.none()),
18877
19074
  begin: () => Effect.fail(new McpRegistryError({ detail: "OAuth sign-in is not available." })),
@@ -18889,7 +19086,7 @@ const decodeRegistration$1 = Schema$1.decodeUnknownExit(RegistrationFromJson$1);
18889
19086
  const encodeRegistration = Schema$1.encodeSync(RegistrationFromJson$1);
18890
19087
  var McpRegistry = class extends Context.Service()("@p4code/cli/mcp/McpRegistry") {};
18891
19088
  const slotsOf = (registration) => registration.secrets ?? [];
18892
- const make$74 = Effect.gen(function* () {
19089
+ const make$75 = Effect.gen(function* () {
18893
19090
  const config = yield* ServerConfig$1;
18894
19091
  const secrets = yield* ServerSecretStore;
18895
19092
  const oauth = yield* McpOAuth;
@@ -19040,7 +19237,7 @@ const make$74 = Effect.gen(function* () {
19040
19237
  }).pipe(Effect.provide(services), Effect.catchCause((cause) => Effect.logWarning("mcp registry resolve failed", { cause }).pipe(Effect.as({}))))
19041
19238
  };
19042
19239
  });
19043
- const layer$65 = Layer.effect(McpRegistry, make$74);
19240
+ const layer$65 = Layer.effect(McpRegistry, make$75);
19044
19241
  //#endregion
19045
19242
  //#region src/sync/skillDirectory.ts
19046
19243
  /**
@@ -19419,7 +19616,7 @@ const formatHubLink = (input) => encodeStoredHubLink({
19419
19616
  shareMode: input.shareMode
19420
19617
  });
19421
19618
  const fromEnvironment = (environment) => validateHubLink(environment.P4CODE_HUB_URL ?? "", environment.P4CODE_HUB_TOKEN ?? "");
19422
- const make$73 = Effect.fn("HubLink.make")(function* (environment) {
19619
+ const make$74 = Effect.fn("HubLink.make")(function* (environment) {
19423
19620
  const secrets = yield* ServerSecretStore;
19424
19621
  const env = environment ?? process.env;
19425
19622
  const fromEnv = fromEnvironment(env);
@@ -19485,7 +19682,7 @@ const make$73 = Effect.fn("HubLink.make")(function* (environment) {
19485
19682
  })
19486
19683
  };
19487
19684
  });
19488
- const layer$64 = Layer.effect(HubLink, make$73());
19685
+ const layer$64 = Layer.effect(HubLink, make$74());
19489
19686
  //#endregion
19490
19687
  //#region src/sync/HubAssetClient.ts
19491
19688
  /**
@@ -19518,7 +19715,7 @@ const decodeAssetListPage = Schema$1.decodeUnknownEffect(AssetListPage);
19518
19715
  const decodeConflictBody$1 = Schema$1.decodeUnknownEffect(ConflictBody$1);
19519
19716
  const decodeAsset = Schema$1.decodeUnknownEffect(AgentAsset);
19520
19717
  var HubAssetClient = class extends Context.Service()("@p4code/cli/sync/HubAssetClient") {};
19521
- const make$72 = Effect.gen(function* () {
19718
+ const make$73 = Effect.gen(function* () {
19522
19719
  const http = yield* HttpClient.HttpClient;
19523
19720
  const link = yield* HubLink;
19524
19721
  const requireSettings = Effect.gen(function* () {
@@ -19600,7 +19797,7 @@ const make$72 = Effect.gen(function* () {
19600
19797
  remove
19601
19798
  };
19602
19799
  });
19603
- const layer$63 = Layer.effect(HubAssetClient, make$72);
19800
+ const layer$63 = Layer.effect(HubAssetClient, make$73);
19604
19801
  //#endregion
19605
19802
  //#region src/sync/mcpRegistrationFiles.ts
19606
19803
  /**
@@ -20175,7 +20372,7 @@ const EMPTY_REPORT = {
20175
20372
  unavailable: null
20176
20373
  };
20177
20374
  var AssetSync = class extends Context.Service()("@p4code/cli/sync/AssetSync") {};
20178
- const make$71 = Effect.gen(function* () {
20375
+ const make$72 = Effect.gen(function* () {
20179
20376
  const client = yield* HubAssetClient;
20180
20377
  const link = yield* HubLink;
20181
20378
  const settingsStore = yield* ServerSettingsService;
@@ -20888,7 +21085,7 @@ const make$71 = Effect.gen(function* () {
20888
21085
  removeLocal
20889
21086
  };
20890
21087
  });
20891
- const layer$62 = Layer.effect(AssetSync, make$71);
21088
+ const layer$62 = Layer.effect(AssetSync, make$72);
20892
21089
  //#endregion
20893
21090
  //#region src/provider/CompressPrompts.ts
20894
21091
  /**
@@ -21808,7 +22005,11 @@ var ProjectionSnapshotQuery = class extends Context.Service()("@p4code/cli/orche
21808
22005
  const OrchestrationCommandReceipt = Schema$1.Struct({
21809
22006
  commandId: CommandId,
21810
22007
  aggregateKind: OrchestrationAggregateKind,
21811
- aggregateId: Schema$1.Union([ProjectId, ThreadId]),
22008
+ aggregateId: Schema$1.Union([
22009
+ ProjectId,
22010
+ ThreadId,
22011
+ ThreadPairId
22012
+ ]),
21812
22013
  acceptedAt: IsoDateTime,
21813
22014
  resultSequence: NonNegativeInt,
21814
22015
  status: OrchestrationCommandReceiptStatus,
@@ -21900,7 +22101,11 @@ const EventMetadataFromJsonString = Schema$1.fromJsonString(OrchestrationEventMe
21900
22101
  const AppendEventRequestSchema = Schema$1.Struct({
21901
22102
  eventId: EventId,
21902
22103
  aggregateKind: OrchestrationAggregateKind,
21903
- streamId: Schema$1.Union([ProjectId, ThreadId]),
22104
+ streamId: Schema$1.Union([
22105
+ ProjectId,
22106
+ ThreadId,
22107
+ ThreadPairId
22108
+ ]),
21904
22109
  type: OrchestrationEventType,
21905
22110
  causationEventId: Schema$1.NullOr(EventId),
21906
22111
  correlationId: Schema$1.NullOr(CommandId),
@@ -21915,7 +22120,11 @@ const OrchestrationEventPersistedRowSchema = Schema$1.Struct({
21915
22120
  eventId: EventId,
21916
22121
  type: OrchestrationEventType,
21917
22122
  aggregateKind: OrchestrationAggregateKind,
21918
- aggregateId: Schema$1.Union([ProjectId, ThreadId]),
22123
+ aggregateId: Schema$1.Union([
22124
+ ProjectId,
22125
+ ThreadId,
22126
+ ThreadPairId
22127
+ ]),
21919
22128
  occurredAt: IsoDateTime,
21920
22129
  commandId: Schema$1.NullOr(CommandId),
21921
22130
  causationEventId: Schema$1.NullOr(EventId),
@@ -22274,6 +22483,9 @@ const ThreadSessionSetPayload = ThreadSessionSetPayload$1;
22274
22483
  const ThreadTurnDiffCompletedPayload = ThreadTurnDiffCompletedPayload$1;
22275
22484
  const ThreadRevertedPayload = ThreadRevertedPayload$1;
22276
22485
  const ThreadActivityAppendedPayload = ThreadActivityAppendedPayload$1;
22486
+ const ThreadPairCreatedPayload = ThreadPairCreatedPayload$1;
22487
+ const ThreadPairDetachedPayload = ThreadPairDetachedPayload$1;
22488
+ const ThreadPairCursorAdvancedPayload = ThreadPairCursorAdvancedPayload$1;
22277
22489
  //#endregion
22278
22490
  //#region src/orchestration/projector.ts
22279
22491
  function checkpointStatusToLatestTurnState(status) {
@@ -22347,6 +22559,7 @@ function createEmptyReadModel(nowIso) {
22347
22559
  snapshotSequence: 0,
22348
22560
  projects: [],
22349
22561
  threads: [],
22562
+ threadPairs: [],
22350
22563
  updatedAt: nowIso
22351
22564
  };
22352
22565
  }
@@ -22357,6 +22570,31 @@ function projectEvent(model, event) {
22357
22570
  updatedAt: event.occurredAt
22358
22571
  };
22359
22572
  switch (event.type) {
22573
+ case "thread-pair.created": return decodeForEvent(ThreadPairCreatedPayload, event.payload, event.type, "payload").pipe(Effect.map((payload) => ({
22574
+ ...nextBase,
22575
+ threadPairs: [...(nextBase.threadPairs ?? []).filter((pair) => pair.id !== payload.pairId), {
22576
+ id: payload.pairId,
22577
+ implementerThreadId: payload.implementerThreadId,
22578
+ watcherThreadId: payload.watcherThreadId,
22579
+ lastReviewedImplementerSequence: payload.lastReviewedImplementerSequence,
22580
+ createdAt: payload.createdAt,
22581
+ detachedAt: null
22582
+ }]
22583
+ })));
22584
+ case "thread-pair.detached": return decodeForEvent(ThreadPairDetachedPayload, event.payload, event.type, "payload").pipe(Effect.map((payload) => ({
22585
+ ...nextBase,
22586
+ threadPairs: (nextBase.threadPairs ?? []).map((pair) => pair.id === payload.pairId ? {
22587
+ ...pair,
22588
+ detachedAt: payload.detachedAt
22589
+ } : pair)
22590
+ })));
22591
+ case "thread-pair.cursor-advanced": return decodeForEvent(ThreadPairCursorAdvancedPayload, event.payload, event.type, "payload").pipe(Effect.map((payload) => ({
22592
+ ...nextBase,
22593
+ threadPairs: (nextBase.threadPairs ?? []).map((pair) => pair.id === payload.pairId ? {
22594
+ ...pair,
22595
+ lastReviewedImplementerSequence: payload.implementerSequence
22596
+ } : pair)
22597
+ })));
22360
22598
  case "project.created": return decodeForEvent(ProjectCreatedPayload, event.payload, event.type, "payload").pipe(Effect.map((payload) => {
22361
22599
  const existing = nextBase.projects.find((entry) => entry.id === payload.projectId);
22362
22600
  const nextProject = {
@@ -22896,6 +23134,16 @@ const decideOrchestrationCommand = Effect.fn("decideOrchestrationCommand")(funct
22896
23134
  command,
22897
23135
  threadId: command.threadId
22898
23136
  });
23137
+ const activePair = (readModel.threadPairs ?? []).find((pair) => pair.detachedAt === null && (pair.implementerThreadId === command.threadId || pair.watcherThreadId === command.threadId));
23138
+ if (activePair !== void 0) return yield* decideCommandSequence({
23139
+ readModel,
23140
+ commands: [{
23141
+ type: "thread-pair.detach",
23142
+ commandId: command.commandId,
23143
+ pairId: activePair.id,
23144
+ createdAt: yield* nowIso$8
23145
+ }, command]
23146
+ });
22899
23147
  const occurredAt = yield* nowIso$8;
22900
23148
  return {
22901
23149
  ...yield* withEventBase({
@@ -22911,6 +23159,118 @@ const decideOrchestrationCommand = Effect.fn("decideOrchestrationCommand")(funct
22911
23159
  }
22912
23160
  };
22913
23161
  }
23162
+ case "thread-pair.create": {
23163
+ if (command.implementerThreadId === command.watcherThreadId) return yield* new OrchestrationCommandInvariantError({
23164
+ commandType: command.type,
23165
+ detail: "Fusion implementer and watcher must be distinct threads."
23166
+ });
23167
+ const implementer = yield* requireThread({
23168
+ readModel,
23169
+ command,
23170
+ threadId: command.implementerThreadId
23171
+ });
23172
+ const watcher = yield* requireThread({
23173
+ readModel,
23174
+ command,
23175
+ threadId: command.watcherThreadId
23176
+ });
23177
+ if (implementer.projectId !== watcher.projectId) return yield* new OrchestrationCommandInvariantError({
23178
+ commandType: command.type,
23179
+ detail: "Fusion implementer and watcher must belong to the same project."
23180
+ });
23181
+ const activePairs = readModel.threadPairs ?? [];
23182
+ if (activePairs.some((pair) => pair.id === command.pairId)) return yield* new OrchestrationCommandInvariantError({
23183
+ commandType: command.type,
23184
+ detail: `Thread pair '${command.pairId}' already exists.`
23185
+ });
23186
+ const occupiedThreadIds = new Set(activePairs.filter((pair) => pair.detachedAt === null).flatMap((pair) => [pair.implementerThreadId, pair.watcherThreadId]));
23187
+ if (occupiedThreadIds.has(command.implementerThreadId) || occupiedThreadIds.has(command.watcherThreadId)) return yield* new OrchestrationCommandInvariantError({
23188
+ commandType: command.type,
23189
+ detail: "Each thread may belong to only one active Fusion pair."
23190
+ });
23191
+ return {
23192
+ ...yield* withEventBase({
23193
+ aggregateKind: "thread-pair",
23194
+ aggregateId: command.pairId,
23195
+ occurredAt: command.createdAt,
23196
+ commandId: command.commandId
23197
+ }),
23198
+ type: "thread-pair.created",
23199
+ payload: {
23200
+ pairId: command.pairId,
23201
+ implementerThreadId: command.implementerThreadId,
23202
+ watcherThreadId: command.watcherThreadId,
23203
+ lastReviewedImplementerSequence: readModel.snapshotSequence,
23204
+ createdAt: command.createdAt
23205
+ }
23206
+ };
23207
+ }
23208
+ case "thread.turn.complete":
23209
+ yield* requireThread({
23210
+ readModel,
23211
+ command,
23212
+ threadId: command.threadId
23213
+ });
23214
+ return {
23215
+ ...yield* withEventBase({
23216
+ aggregateKind: "thread",
23217
+ aggregateId: command.threadId,
23218
+ occurredAt: command.completedAt,
23219
+ commandId: command.commandId
23220
+ }),
23221
+ type: "thread.turn-completed",
23222
+ payload: {
23223
+ threadId: command.threadId,
23224
+ turnId: command.turnId ?? null,
23225
+ state: command.state,
23226
+ completedAt: command.completedAt
23227
+ }
23228
+ };
23229
+ case "thread-pair.detach": {
23230
+ const pair = (readModel.threadPairs ?? []).find((candidate) => candidate.id === command.pairId);
23231
+ if (pair === void 0 || pair.detachedAt !== null) return yield* new OrchestrationCommandInvariantError({
23232
+ commandType: command.type,
23233
+ detail: `Active thread pair '${command.pairId}' does not exist.`
23234
+ });
23235
+ return {
23236
+ ...yield* withEventBase({
23237
+ aggregateKind: "thread-pair",
23238
+ aggregateId: command.pairId,
23239
+ occurredAt: command.createdAt,
23240
+ commandId: command.commandId
23241
+ }),
23242
+ type: "thread-pair.detached",
23243
+ payload: {
23244
+ pairId: command.pairId,
23245
+ detachedAt: command.createdAt
23246
+ }
23247
+ };
23248
+ }
23249
+ case "thread-pair.cursor.advance": {
23250
+ const pair = (readModel.threadPairs ?? []).find((candidate) => candidate.id === command.pairId);
23251
+ if (pair === void 0 || pair.detachedAt !== null) return yield* new OrchestrationCommandInvariantError({
23252
+ commandType: command.type,
23253
+ detail: `Active thread pair '${command.pairId}' does not exist.`
23254
+ });
23255
+ if (command.implementerSequence < pair.lastReviewedImplementerSequence) return yield* new OrchestrationCommandInvariantError({
23256
+ commandType: command.type,
23257
+ detail: `Thread pair '${command.pairId}' cursor cannot move backwards.`
23258
+ });
23259
+ return {
23260
+ ...yield* withEventBase({
23261
+ aggregateKind: "thread-pair",
23262
+ aggregateId: command.pairId,
23263
+ occurredAt: command.advancedAt,
23264
+ commandId: command.commandId
23265
+ }),
23266
+ type: "thread-pair.cursor-advanced",
23267
+ payload: {
23268
+ pairId: command.pairId,
23269
+ implementerSequence: command.implementerSequence,
23270
+ advancedAt: command.advancedAt
23271
+ }
23272
+ };
23273
+ }
22914
23274
  case "thread.archive": {
22915
23275
  yield* requireThreadNotArchived({
22916
23276
  readModel,
@@ -23601,6 +23961,12 @@ function commandToAggregateRef(command) {
23601
23961
  aggregateKind: "project",
23602
23962
  aggregateId: command.projectId
23603
23963
  };
23964
+ case "thread-pair.create":
23965
+ case "thread-pair.detach":
23966
+ case "thread-pair.cursor.advance": return {
23967
+ aggregateKind: "thread-pair",
23968
+ aggregateId: command.pairId
23969
+ };
23604
23970
  default: return {
23605
23971
  aggregateKind: "thread",
23606
23972
  aggregateId: command.threadId
@@ -25247,7 +25613,8 @@ const ORCHESTRATION_PROJECTOR_NAMES = {
25247
25613
  threadSessions: "projection.thread-sessions",
25248
25614
  threadTurns: "projection.thread-turns",
25249
25615
  checkpoints: "projection.checkpoints",
25250
- pendingApprovals: "projection.pending-approvals"
25616
+ pendingApprovals: "projection.pending-approvals",
25617
+ threadPairs: "projection.thread-pairs"
25251
25618
  };
25252
25619
  /**
25253
25620
  * Turn state to settle still-running turns with when their session leaves the
@@ -25506,6 +25873,50 @@ const makeOrchestrationProjectionPipeline = Effect.fn("makeOrchestrationProjecti
25506
25873
  default: return;
25507
25874
  }
25508
25875
  });
25876
+ const applyThreadPairsProjection = Effect.fn("applyThreadPairsProjection")(function* (event, _attachmentSideEffects) {
25877
+ switch (event.type) {
25878
+ case "thread-pair.created":
25879
+ yield* sql`
25880
+ INSERT INTO thread_pairs (
25881
+ pair_id,
25882
+ implementer_thread_id,
25883
+ watcher_thread_id,
25884
+ last_reviewed_implementer_sequence,
25885
+ created_at,
25886
+ detached_at
25887
+ ) VALUES (
25888
+ ${event.payload.pairId},
25889
+ ${event.payload.implementerThreadId},
25890
+ ${event.payload.watcherThreadId},
25891
+ ${event.payload.lastReviewedImplementerSequence},
25892
+ ${event.payload.createdAt},
25893
+ NULL
25894
+ )
25895
+ ON CONFLICT(pair_id) DO UPDATE SET
25896
+ implementer_thread_id = excluded.implementer_thread_id,
25897
+ watcher_thread_id = excluded.watcher_thread_id,
25898
+ last_reviewed_implementer_sequence = excluded.last_reviewed_implementer_sequence,
25899
+ created_at = excluded.created_at,
25900
+ detached_at = NULL
25901
+ `.pipe(Effect.mapError(toPersistenceSqlError("ProjectionPipeline.threadPairs:create")));
25902
+ return;
25903
+ case "thread-pair.detached":
25904
+ yield* sql`
25905
+ UPDATE thread_pairs
25906
+ SET detached_at = ${event.payload.detachedAt}
25907
+ WHERE pair_id = ${event.payload.pairId}
25908
+ `.pipe(Effect.mapError(toPersistenceSqlError("ProjectionPipeline.threadPairs:detach")));
25909
+ return;
25910
+ case "thread-pair.cursor-advanced":
25911
+ yield* sql`
25912
+ UPDATE thread_pairs
25913
+ SET last_reviewed_implementer_sequence = ${event.payload.implementerSequence}
25914
+ WHERE pair_id = ${event.payload.pairId}
25915
+ `.pipe(Effect.mapError(toPersistenceSqlError("ProjectionPipeline.threadPairs:cursor")));
25916
+ return;
25917
+ default: return;
25918
+ }
25919
+ });
25509
25920
  const refreshThreadShellSummary = Effect.fn("refreshThreadShellSummary")(function* (threadId) {
25510
25921
  const existingRow = yield* projectionThreadRepository.getById({ threadId });
25511
25922
  if (Option.isNone(existingRow)) return;
@@ -26144,6 +26555,10 @@ const makeOrchestrationProjectionPipeline = Effect.fn("makeOrchestrationProjecti
26144
26555
  name: ORCHESTRATION_PROJECTOR_NAMES.projects,
26145
26556
  apply: applyProjectsProjection
26146
26557
  },
26558
+ {
26559
+ name: ORCHESTRATION_PROJECTOR_NAMES.threadPairs,
26560
+ apply: applyThreadPairsProjection
26561
+ },
26147
26562
  {
26148
26563
  name: ORCHESTRATION_PROJECTOR_NAMES.threadMessages,
26149
26564
  apply: applyThreadMessagesProjection
@@ -26739,12 +27154,12 @@ const runProcessCore = Effect.fn("processRunner.runProcessCore")(function* (spaw
26739
27154
  stderrInvalidUtf8: stderr.invalidUtf8
26740
27155
  };
26741
27156
  });
26742
- const make$70 = Effect.fn("ProcessRunner.make")(function* () {
27157
+ const make$71 = Effect.fn("ProcessRunner.make")(function* () {
26743
27158
  const spawner = yield* ChildProcessSpawner$1.ChildProcessSpawner;
26744
27159
  const run = (input) => finalizeRunProcess(runProcessCore(spawner, input), input);
26745
27160
  return ProcessRunner.of({ run });
26746
27161
  });
26747
- const layer$61 = Layer.effect(ProcessRunner, make$70());
27162
+ const layer$61 = Layer.effect(ProcessRunner, make$71());
26748
27163
  //#endregion
26749
27164
  //#region src/project/RepositoryIdentityResolver.ts
26750
27165
  const DEFAULT_REPOSITORY_IDENTITY_CACHE_CAPACITY = 512;
@@ -26835,7 +27250,7 @@ const resolveRepositoryIdentityFromCacheKey = Effect.fn("RepositoryIdentityResol
26835
27250
  rootPath: cacheKey
26836
27251
  }) : null;
26837
27252
  });
26838
- const make$69 = Effect.fn("RepositoryIdentityResolver.make")(function* (options = {}) {
27253
+ const make$70 = Effect.fn("RepositoryIdentityResolver.make")(function* (options = {}) {
26839
27254
  const processRunner = yield* ProcessRunner;
26840
27255
  const repositoryIdentityCache = yield* Cache.makeWith((cacheKey) => resolveRepositoryIdentityFromCacheKey(cacheKey).pipe(Effect.provideService(ProcessRunner, processRunner)), {
26841
27256
  capacity: options.cacheCapacity ?? DEFAULT_REPOSITORY_IDENTITY_CACHE_CAPACITY,
@@ -26850,7 +27265,7 @@ const make$69 = Effect.fn("RepositoryIdentityResolver.make")(function* (options
26850
27265
  });
26851
27266
  return RepositoryIdentityResolver.of({ resolve });
26852
27267
  });
26853
- const layer$60 = Layer.effect(RepositoryIdentityResolver, make$69()).pipe(Layer.provide(layer$61));
27268
+ const layer$60 = Layer.effect(RepositoryIdentityResolver, make$70()).pipe(Layer.provide(layer$61));
26854
27269
  //#endregion
26855
27270
  //#region src/orchestration/Layers/ProjectionSnapshotQuery.ts
26856
27271
  const decodeReadModel = Schema$1.decodeUnknownEffect(OrchestrationReadModel);
@@ -26891,6 +27306,14 @@ const ProjectionTurnSummaryDbRowSchema = Schema$1.Struct({
26891
27306
  completedAt: Schema$1.NullOr(IsoDateTime)
26892
27307
  });
26893
27308
  const ProjectionStateDbRowSchema = ProjectionState;
27309
+ const ProjectionThreadPairDbRowSchema = Schema$1.Struct({
27310
+ id: ThreadPairId,
27311
+ implementerThreadId: ThreadId,
27312
+ watcherThreadId: ThreadId,
27313
+ lastReviewedImplementerSequence: NonNegativeInt,
27314
+ createdAt: IsoDateTime,
27315
+ detachedAt: Schema$1.NullOr(IsoDateTime)
27316
+ });
26894
27317
  const ProjectionCountsRowSchema = Schema$1.Struct({
26895
27318
  projectCount: Schema$1.Number,
26896
27319
  threadCount: Schema$1.Number
@@ -26938,7 +27361,8 @@ const REQUIRED_SNAPSHOT_PROJECTORS = [
26938
27361
  ORCHESTRATION_PROJECTOR_NAMES.threadProposedPlans,
26939
27362
  ORCHESTRATION_PROJECTOR_NAMES.threadActivities,
26940
27363
  ORCHESTRATION_PROJECTOR_NAMES.threadSessions,
26941
- ORCHESTRATION_PROJECTOR_NAMES.checkpoints
27364
+ ORCHESTRATION_PROJECTOR_NAMES.checkpoints,
27365
+ ORCHESTRATION_PROJECTOR_NAMES.threadPairs
26942
27366
  ];
26943
27367
  function maxIso(left, right) {
26944
27368
  if (left === null) return right;
@@ -27060,6 +27484,21 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
27060
27484
  deleted_at AS "deletedAt"
27061
27485
  FROM projection_projects
27062
27486
  ORDER BY created_at ASC, project_id ASC
27487
+ `
27488
+ });
27489
+ const listThreadPairRows = SqlSchema.findAll({
27490
+ Request: Schema$1.Void,
27491
+ Result: ProjectionThreadPairDbRowSchema,
27492
+ execute: () => sql`
27493
+ SELECT
27494
+ pair_id AS "id",
27495
+ implementer_thread_id AS "implementerThreadId",
27496
+ watcher_thread_id AS "watcherThreadId",
27497
+ last_reviewed_implementer_sequence AS "lastReviewedImplementerSequence",
27498
+ created_at AS "createdAt",
27499
+ detached_at AS "detachedAt"
27500
+ FROM thread_pairs
27501
+ ORDER BY created_at ASC, pair_id ASC
27063
27502
  `
27064
27503
  });
27065
27504
  const listThreadRows = SqlSchema.findAll({
@@ -27765,8 +28204,9 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
27765
28204
  listCheckpointRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getSnapshot:listCheckpoints:query", "ProjectionSnapshotQuery.getSnapshot:listCheckpoints:decodeRows"))),
27766
28205
  listTurnSummaryRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getSnapshot:listTurnSummaries:query", "ProjectionSnapshotQuery.getSnapshot:listTurnSummaries:decodeRows"))),
27767
28206
  listLatestTurnRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getSnapshot:listLatestTurns:query", "ProjectionSnapshotQuery.getSnapshot:listLatestTurns:decodeRows"))),
27768
- listProjectionStateRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getSnapshot:listProjectionState:query", "ProjectionSnapshotQuery.getSnapshot:listProjectionState:decodeRows")))
27769
- ])).pipe(Effect.flatMap(([projectRows, threadRows, messageRows, proposedPlanRows, activityRows, sessionRows, checkpointRows, turnRows, latestTurnRows, stateRows]) => Effect.gen(function* () {
28207
+ listProjectionStateRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getSnapshot:listProjectionState:query", "ProjectionSnapshotQuery.getSnapshot:listProjectionState:decodeRows"))),
28208
+ listThreadPairRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getSnapshot:listThreadPairs:query", "ProjectionSnapshotQuery.getSnapshot:listThreadPairs:decodeRows")))
28209
+ ])).pipe(Effect.flatMap(([projectRows, threadRows, messageRows, proposedPlanRows, activityRows, sessionRows, checkpointRows, turnRows, latestTurnRows, stateRows, threadPairRows]) => Effect.gen(function* () {
27770
28210
  const messagesByThread = /* @__PURE__ */ new Map();
27771
28211
  const proposedPlansByThread = /* @__PURE__ */ new Map();
27772
28212
  const activitiesByThread = /* @__PURE__ */ new Map();
@@ -27774,6 +28214,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
27774
28214
  const turnsByThread = /* @__PURE__ */ new Map();
27775
28215
  const sessionsByThread = /* @__PURE__ */ new Map();
27776
28216
  const latestTurnByThread = /* @__PURE__ */ new Map();
28217
+ const threadPairs = [...threadPairRows];
27777
28218
  let updatedAt = null;
27778
28219
  for (const row of projectRows) updatedAt = maxIso(updatedAt, row.updatedAt);
27779
28220
  for (const row of threadRows) updatedAt = maxIso(updatedAt, row.updatedAt);
@@ -27904,6 +28345,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
27904
28345
  snapshotSequence: computeSnapshotSequence(stateRows),
27905
28346
  projects,
27906
28347
  threads,
28348
+ threadPairs,
27907
28349
  updatedAt: updatedAt ?? "1970-01-01T00:00:00.000Z"
27908
28350
  };
27909
28351
  return yield* decodeReadModel(snapshot).pipe(Effect.mapError(toPersistenceDecodeError("ProjectionSnapshotQuery.getSnapshot:decodeReadModel")));
@@ -27917,11 +28359,13 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
27917
28359
  listThreadProposedPlanRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getCommandReadModel:listThreadProposedPlans:query", "ProjectionSnapshotQuery.getCommandReadModel:listThreadProposedPlans:decodeRows"))),
27918
28360
  listThreadSessionRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getCommandReadModel:listThreadSessions:query", "ProjectionSnapshotQuery.getCommandReadModel:listThreadSessions:decodeRows"))),
27919
28361
  listLatestTurnRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getCommandReadModel:listLatestTurns:query", "ProjectionSnapshotQuery.getCommandReadModel:listLatestTurns:decodeRows"))),
27920
- listProjectionStateRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getCommandReadModel:listProjectionState:query", "ProjectionSnapshotQuery.getCommandReadModel:listProjectionState:decodeRows")))
27921
- ])).pipe(Effect.flatMap(([projectRows, threadRows, proposedPlanRows, sessionRows, latestTurnRows, stateRows]) => Effect.sync(() => {
28362
+ listProjectionStateRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getCommandReadModel:listProjectionState:query", "ProjectionSnapshotQuery.getCommandReadModel:listProjectionState:decodeRows"))),
28363
+ listThreadPairRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getCommandReadModel:listThreadPairs:query", "ProjectionSnapshotQuery.getCommandReadModel:listThreadPairs:decodeRows")))
28364
+ ])).pipe(Effect.flatMap(([projectRows, threadRows, proposedPlanRows, sessionRows, latestTurnRows, stateRows, threadPairRows]) => Effect.sync(() => {
27922
28365
  let updatedAt = null;
27923
28366
  const projects = [];
27924
28367
  const threads = [];
28368
+ const threadPairs = [...threadPairRows];
27925
28369
  for (let index = 0; index < projectRows.length; index += 1) {
27926
28370
  const row = projectRows[index];
27927
28371
  if (!row) continue;
@@ -28018,6 +28462,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
28018
28462
  snapshotSequence: computeSnapshotSequence(stateRows),
28019
28463
  projects,
28020
28464
  threads,
28465
+ threadPairs,
28021
28466
  updatedAt: updatedAt ?? "1970-01-01T00:00:00.000Z"
28022
28467
  };
28023
28468
  })), Effect.mapError((error) => {
@@ -28029,8 +28474,9 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
28029
28474
  listActiveThreadRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getShellSnapshot:listThreads:query", "ProjectionSnapshotQuery.getShellSnapshot:listThreads:decodeRows"))),
28030
28475
  listActiveThreadSessionRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getShellSnapshot:listThreadSessions:query", "ProjectionSnapshotQuery.getShellSnapshot:listThreadSessions:decodeRows"))),
28031
28476
  listActiveLatestTurnRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getShellSnapshot:listLatestTurns:query", "ProjectionSnapshotQuery.getShellSnapshot:listLatestTurns:decodeRows"))),
28032
- listProjectionStateRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getShellSnapshot:listProjectionState:query", "ProjectionSnapshotQuery.getShellSnapshot:listProjectionState:decodeRows")))
28033
- ])).pipe(Effect.flatMap(([projectRows, threadRows, sessionRows, latestTurnRows, stateRows]) => Effect.gen(function* () {
28477
+ listProjectionStateRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getShellSnapshot:listProjectionState:query", "ProjectionSnapshotQuery.getShellSnapshot:listProjectionState:decodeRows"))),
28478
+ listThreadPairRows(void 0).pipe(Effect.mapError(toPersistenceSqlOrDecodeError$1("ProjectionSnapshotQuery.getShellSnapshot:listThreadPairs:query", "ProjectionSnapshotQuery.getShellSnapshot:listThreadPairs:decodeRows")))
28479
+ ])).pipe(Effect.flatMap(([projectRows, threadRows, sessionRows, latestTurnRows, stateRows, threadPairRows]) => Effect.gen(function* () {
28034
28480
  let updatedAt = null;
28035
28481
  for (const row of projectRows) updatedAt = maxIso(updatedAt, row.updatedAt);
28036
28482
  for (const row of threadRows) updatedAt = maxIso(updatedAt, row.updatedAt);
@@ -28074,6 +28520,7 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () {
28074
28520
  hasBackgroundTasks: row.backgroundTaskCount > 0,
28075
28521
  scheduledWakeAt: row.scheduledWakeAt
28076
28522
  }) : Result.failVoid),
28523
+ threadPairs: threadPairRows.filter((pair) => pair.detachedAt === null),
28077
28524
  updatedAt: updatedAt ?? "1970-01-01T00:00:00.000Z"
28078
28525
  };
28079
28526
  return yield* decodeShellSnapshot(snapshot).pipe(Effect.mapError(toPersistenceDecodeError("ProjectionSnapshotQuery.getShellSnapshot:decodeShellSnapshot")));
@@ -28860,7 +29307,7 @@ function mergeWithDefaultKeybindings(custom) {
28860
29307
  * Keybindings - Service tag for keybinding configuration operations.
28861
29308
  */
28862
29309
  var Keybindings = class extends Context.Service()("@p4code/cli/keybindings") {};
28863
- const make$68 = Effect.gen(function* () {
29310
+ const make$69 = Effect.gen(function* () {
28864
29311
  const { keybindingsConfigPath } = yield* ServerConfig$1;
28865
29312
  const fs = yield* FileSystem.FileSystem;
28866
29313
  const path = yield* Path.Path;
@@ -29121,7 +29568,7 @@ const make$68 = Effect.gen(function* () {
29121
29568
  }))
29122
29569
  };
29123
29570
  });
29124
- const layer$59 = Layer.effect(Keybindings, make$68);
29571
+ const layer$59 = Layer.effect(Keybindings, make$69);
29125
29572
  //#endregion
29126
29573
  //#region src/process/externalLauncher.ts
29127
29574
  /**
@@ -29348,7 +29795,7 @@ const launchEditorProcess = Effect.fn("externalLauncher.launchEditorProcess")(fu
29348
29795
  cause
29349
29796
  }));
29350
29797
  });
29351
- const make$67 = Effect.gen(function* () {
29798
+ const make$68 = Effect.gen(function* () {
29352
29799
  const spawner = yield* ChildProcessSpawner$1.ChildProcessSpawner;
29353
29800
  const fileSystem = yield* FileSystem.FileSystem;
29354
29801
  const path = yield* Path.Path;
@@ -29359,7 +29806,7 @@ const make$67 = Effect.gen(function* () {
29359
29806
  launchEditor: (input) => provideCommandResolutionServices(Effect.flatMap(resolveEditorLaunch(input), (launch) => launchEditorProcess(launch).pipe(Effect.provideService(ChildProcessSpawner$1.ChildProcessSpawner, spawner))))
29360
29807
  });
29361
29808
  });
29362
- const layer$58 = Layer.effect(ExternalLauncher, make$67);
29809
+ const layer$58 = Layer.effect(ExternalLauncher, make$68);
29363
29810
  //#endregion
29364
29811
  //#region src/orchestration/Services/OrchestrationReactor.ts
29365
29812
  /**
@@ -29377,7 +29824,7 @@ var OrchestrationReactor = class extends Context.Service()("@p4code/cli/orchestr
29377
29824
  //#endregion
29378
29825
  //#region src/serverLifecycleEvents.ts
29379
29826
  var ServerLifecycleEvents = class extends Context.Service()("@p4code/cli/serverLifecycleEvents") {};
29380
- const make$66 = Effect.gen(function* () {
29827
+ const make$67 = Effect.gen(function* () {
29381
29828
  const pubsub = yield* PubSub.unbounded();
29382
29829
  const state = yield* Ref.make({
29383
29830
  sequence: 0,
@@ -29401,7 +29848,7 @@ const make$66 = Effect.gen(function* () {
29401
29848
  }
29402
29849
  };
29403
29850
  });
29404
- const layer$57 = Layer.effect(ServerLifecycleEvents, make$66);
29851
+ const layer$57 = Layer.effect(ServerLifecycleEvents, make$67);
29405
29852
  //#endregion
29406
29853
  //#region src/telemetry/Identify.ts
29407
29854
  const CodexAuthJsonSchema = Schema$1.Struct({ tokens: Schema$1.Struct({ account_id: Schema$1.String }) });
@@ -29574,7 +30021,7 @@ var AnalyticsService = class AnalyticsService extends Context.Service()("@p4code
29574
30021
  /** No-op layer for callers that intentionally disable telemetry. */
29575
30022
  static layerTest = Layer.succeed(AnalyticsService, inert);
29576
30023
  };
29577
- const make$65 = Effect.gen(function* () {
30024
+ const make$66 = Effect.gen(function* () {
29578
30025
  const telemetryConfig = yield* TelemetryEnvConfig;
29579
30026
  const posthogKey = telemetryConfig.posthogKey.trim();
29580
30027
  if (!telemetryConfig.enabled || posthogKey === "") return inert;
@@ -29644,7 +30091,7 @@ const make$65 = Effect.gen(function* () {
29644
30091
  flush
29645
30092
  });
29646
30093
  });
29647
- const layer$56 = Layer.effect(AnalyticsService, make$65);
30094
+ const layer$56 = Layer.effect(AnalyticsService, make$66);
29648
30095
  AnalyticsService.layerTest;
29649
30096
  //#endregion
29650
30097
  //#region src/service/pinnedRuntime.ts
@@ -29991,7 +30438,7 @@ var BootServiceInstallError = class extends Schema$1.TaggedErrorClass()("BootSer
29991
30438
  }
29992
30439
  };
29993
30440
  var BootService = class extends Context.Service()("@p4code/cli/service/bootService") {};
29994
- const make$64 = Effect.fn("cloud.boot_service.make")(function* (input) {
30441
+ const make$65 = Effect.fn("cloud.boot_service.make")(function* (input) {
29995
30442
  const hostExecPath = yield* HostProcessExecutablePath;
29996
30443
  const hostArguments = yield* HostProcessArguments;
29997
30444
  const host = input.host ?? {
@@ -30213,7 +30660,7 @@ const make$64 = Effect.fn("cloud.boot_service.make")(function* (input) {
30213
30660
  logPath
30214
30661
  });
30215
30662
  });
30216
- const layer$55 = (input) => Layer.effect(BootService, make$64(input));
30663
+ const layer$55 = (input) => Layer.effect(BootService, make$65(input));
30217
30664
  //#endregion
30218
30665
  //#region src/service/selfUpdate.ts
30219
30666
  /**
@@ -30288,7 +30735,7 @@ const resolveServerSelfUpdateCapability = Effect.fn("cloud.server_self_update.re
30288
30735
  return null;
30289
30736
  });
30290
30737
  var ServerSelfUpdate = class extends Context.Service()("@p4code/cli/service/selfUpdate/ServerSelfUpdate") {};
30291
- const make$63 = Effect.fn("cloud.server_self_update.make")(function* (options) {
30738
+ const make$64 = Effect.fn("cloud.server_self_update.make")(function* (options) {
30292
30739
  const serverConfig = yield* ServerConfig$1;
30293
30740
  const fs = yield* FileSystem.FileSystem;
30294
30741
  const path = yield* Path.Path;
@@ -30438,7 +30885,7 @@ const make$63 = Effect.fn("cloud.server_self_update.make")(function* (options) {
30438
30885
  });
30439
30886
  return ServerSelfUpdate.of({ update });
30440
30887
  });
30441
- const layer$54 = Layer.effect(ServerSelfUpdate, make$63()).pipe(Layer.provide(layer$61));
30888
+ const layer$54 = Layer.effect(ServerSelfUpdate, make$64()).pipe(Layer.provide(layer$61));
30442
30889
  //#endregion
30443
30890
  //#region src/environment/ServerEnvironmentLabel.ts
30444
30891
  const ServerEnvironmentLabelCommandProbe = Schema$1.Literals(["macos-computer-name", "linux-pretty-hostname"]);
@@ -30570,7 +31017,7 @@ function platformArch(architecture) {
30570
31017
  default: return "other";
30571
31018
  }
30572
31019
  }
30573
- const make$62 = Effect.gen(function* () {
31020
+ const make$63 = Effect.gen(function* () {
30574
31021
  const fileSystem = yield* FileSystem.FileSystem;
30575
31022
  const path = yield* Path.Path;
30576
31023
  const serverConfig = yield* ServerConfig$1;
@@ -30634,7 +31081,7 @@ const make$62 = Effect.gen(function* () {
30634
31081
  * state. It intentionally has no fallback Layer.succeed value: callers must
30635
31082
  * provide the external platform services and a ServerConfig.
30636
31083
  */
30637
- const layer$53 = Layer.effect(ServerEnvironment, make$62).pipe(Layer.provide(layer$61));
31084
+ const layer$53 = Layer.effect(ServerEnvironment, make$63).pipe(Layer.provide(layer$61));
30638
31085
  //#endregion
30639
31086
  //#region src/provider/Services/ProviderSessionReaper.ts
30640
31087
  var ProviderSessionReaper = class extends Context.Service()("@p4code/cli/provider/Services/ProviderSessionReaper") {};
@@ -31712,7 +32159,7 @@ const maybeOpenBrowser = (target) => Effect.gen(function* () {
31712
32159
  yield* (yield* ExternalLauncher).launchBrowser(target).pipe(Effect.catch(() => Effect.logInfo("browser auto-open unavailable", { hint: `Open ${target} in your browser.` })));
31713
32160
  });
31714
32161
  const runStartupPhase = (phase, effect) => effect.pipe(Effect.annotateSpans({ "startup.phase": phase }), Effect.withSpan(`server.startup.${phase}`));
31715
- const make$61 = Effect.gen(function* () {
32162
+ const make$62 = Effect.gen(function* () {
31716
32163
  const serverConfig = yield* ServerConfig$1;
31717
32164
  const keybindings = yield* Keybindings;
31718
32165
  const orchestrationReactor = yield* OrchestrationReactor;
@@ -31853,7 +32300,7 @@ const make$61 = Effect.gen(function* () {
31853
32300
  enqueueCommand: commandGate.enqueueCommand
31854
32301
  };
31855
32302
  });
31856
- const layer$52 = Layer.effect(ServerRuntimeStartup, make$61);
32303
+ const layer$52 = Layer.effect(ServerRuntimeStartup, make$62);
31857
32304
  //#endregion
31858
32305
  //#region src/serverRuntimeState.ts
31859
32306
  const PersistedServerRuntimeState = Schema$1.Struct({
@@ -32010,7 +32457,7 @@ function expandHomePath$2(input, path) {
32010
32457
  if (input.startsWith("~/") || input.startsWith("~\\")) return path.join(NodeOS.homedir(), input.slice(2));
32011
32458
  return input;
32012
32459
  }
32013
- const make$60 = Effect.gen(function* () {
32460
+ const make$61 = Effect.gen(function* () {
32014
32461
  const fileSystem = yield* FileSystem.FileSystem;
32015
32462
  const path = yield* Path.Path;
32016
32463
  const statWorkspaceRoot = Effect.fn("WorkspacePaths.statWorkspaceRoot")(function* (workspaceRoot, normalizedWorkspaceRoot, phase) {
@@ -32067,7 +32514,7 @@ const make$60 = Effect.gen(function* () {
32067
32514
  resolveRelativePathWithinRoot
32068
32515
  });
32069
32516
  });
32070
- const layer$51 = Layer.effect(WorkspacePaths, make$60);
32517
+ const layer$51 = Layer.effect(WorkspacePaths, make$61);
32071
32518
  //#endregion
32072
32519
  //#region src/cli/project.ts
32073
32520
  const isEnvironmentHttpCommonError = Schema$1.is(EnvironmentHttpCommonError);
@@ -33250,7 +33697,7 @@ const logP4ProjectFileLoadError = (error) => Effect.logWarning(error).pipe(Effec
33250
33697
  filePath: error.filePath,
33251
33698
  errorTag: error._tag
33252
33699
  }));
33253
- const make$59 = Effect.gen(function* () {
33700
+ const make$60 = Effect.gen(function* () {
33254
33701
  const fileSystem = yield* FileSystem.FileSystem;
33255
33702
  const path = yield* Path.Path;
33256
33703
  const load = Effect.fn("P4ProjectFileLoader.load")(function* (workspaceRoot) {
@@ -33271,7 +33718,7 @@ const make$59 = Effect.gen(function* () {
33271
33718
  });
33272
33719
  return P4ProjectFileLoader.of({ load });
33273
33720
  });
33274
- const layer$50 = Layer.effect(P4ProjectFileLoader, make$59);
33721
+ const layer$50 = Layer.effect(P4ProjectFileLoader, make$60);
33275
33722
  //#endregion
33276
33723
  //#region src/project/ProjectFaviconResolver.ts
33277
33724
  /**
@@ -33346,7 +33793,7 @@ function extractIconHref(source) {
33346
33793
  return null;
33347
33794
  }
33348
33795
  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) }));
33349
- const make$58 = Effect.gen(function* () {
33796
+ const make$59 = Effect.gen(function* () {
33350
33797
  const fileSystem = yield* FileSystem.FileSystem;
33351
33798
  const path = yield* Path.Path;
33352
33799
  const workspacePaths = yield* WorkspacePaths;
@@ -33415,7 +33862,7 @@ const make$58 = Effect.gen(function* () {
33415
33862
  });
33416
33863
  return ProjectFaviconResolver.of({ resolvePath });
33417
33864
  });
33418
- const layer$49 = Layer.effect(ProjectFaviconResolver, make$58);
33865
+ const layer$49 = Layer.effect(ProjectFaviconResolver, make$59);
33419
33866
  //#endregion
33420
33867
  //#region src/assets/AssetAccess.ts
33421
33868
  const ASSET_ROUTE_PREFIX = "/api/assets";
@@ -33826,10 +34273,10 @@ const resolveAsset = Effect.fn("AssetAccess.resolveAsset")(function* (token, rel
33826
34273
  //#endregion
33827
34274
  //#region src/observability/BrowserTraceCollector.ts
33828
34275
  var BrowserTraceCollector = class extends Context.Service()("@p4code/cli/observability/BrowserTraceCollector") {};
33829
- const make$57 = (sink) => BrowserTraceCollector.of({ record: (records) => Effect.sync(() => {
34276
+ const make$58 = (sink) => BrowserTraceCollector.of({ record: (records) => Effect.sync(() => {
33830
34277
  for (const record of records) sink.push(record);
33831
34278
  }) });
33832
- const layer$48 = (sink) => Layer.succeed(BrowserTraceCollector, make$57(sink));
34279
+ const layer$48 = (sink) => Layer.succeed(BrowserTraceCollector, make$58(sink));
33833
34280
  //#endregion
33834
34281
  //#region src/auth/http.ts
33835
34282
  const CREDENTIAL_RESPONSE_HEADERS = {
@@ -36882,7 +37329,7 @@ const classifyNonZeroExit = (command, stderr) => {
36882
37329
  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";
36883
37330
  return "command-failed";
36884
37331
  };
36885
- const make$56 = Effect.gen(function* () {
37332
+ const make$57 = Effect.gen(function* () {
36886
37333
  const processRunner = yield* ProcessRunner;
36887
37334
  const run = Effect.fn("VcsProcess.run")(function* (input) {
36888
37335
  const baseError = {
@@ -36941,7 +37388,7 @@ const make$56 = Effect.gen(function* () {
36941
37388
  });
36942
37389
  return VcsProcess.of({ run });
36943
37390
  });
36944
- const layer$47 = Layer.effect(VcsProcess, make$56).pipe(Layer.provide(layer$61));
37391
+ const layer$47 = Layer.effect(VcsProcess, make$57).pipe(Layer.provide(layer$61));
36945
37392
  //#endregion
36946
37393
  //#region src/vcs/VcsDriver.ts
36947
37394
  var VcsDriver = class extends Context.Service()("@p4code/cli/vcs/VcsDriver") {};
@@ -37392,12 +37839,12 @@ const makeVcsDriver = Effect.gen(function* () {
37392
37839
  const driver = yield* makeVcsDriverShape();
37393
37840
  return VcsDriver.of(driver);
37394
37841
  });
37395
- const make$55 = Effect.gen(function* () {
37842
+ const make$56 = Effect.gen(function* () {
37396
37843
  const git = yield* makeGitVcsDriverCore();
37397
37844
  return GitVcsDriver.of(git);
37398
37845
  });
37399
37846
  Layer.effect(VcsDriver, makeVcsDriver);
37400
- const layer$46 = Layer.effect(GitVcsDriver, make$55);
37847
+ const layer$46 = Layer.effect(GitVcsDriver, make$56);
37401
37848
  //#endregion
37402
37849
  //#region src/vcs/VcsProjectConfig.ts
37403
37850
  const ProjectVcsConfigJson = fromLenientJson(Schema$1.Struct({
@@ -37429,7 +37876,7 @@ const logVcsProjectConfigError = (error) => Effect.logWarning(error).pipe(Effect
37429
37876
  configPath: error.configPath,
37430
37877
  errorTag: error._tag
37431
37878
  }));
37432
- const make$54 = Effect.gen(function* () {
37879
+ const make$55 = Effect.gen(function* () {
37433
37880
  const fileSystem = yield* FileSystem.FileSystem;
37434
37881
  const path = yield* Path.Path;
37435
37882
  const findConfigPath = Effect.fn("VcsProjectConfig.findConfigPath")(function* (cwd) {
@@ -37470,7 +37917,7 @@ const make$54 = Effect.gen(function* () {
37470
37917
  });
37471
37918
  return VcsProjectConfig.of({ resolveKind });
37472
37919
  });
37473
- const layer$45 = Layer.effect(VcsProjectConfig, make$54);
37920
+ const layer$45 = Layer.effect(VcsProjectConfig, make$55);
37474
37921
  //#endregion
37475
37922
  //#region src/vcs/VcsDriverRegistry.ts
37476
37923
  const DETECTION_CACHE_CAPACITY = 2048;
@@ -37490,7 +37937,7 @@ function parseDetectionCacheKey(key) {
37490
37937
  cwd: key.slice(separatorIndex + 1)
37491
37938
  };
37492
37939
  }
37493
- const make$53 = Effect.gen(function* () {
37940
+ const make$54 = Effect.gen(function* () {
37494
37941
  const projectConfig = yield* VcsProjectConfig;
37495
37942
  const git = yield* makeVcsDriver;
37496
37943
  const drivers = { git };
@@ -37547,7 +37994,7 @@ const make$53 = Effect.gen(function* () {
37547
37994
  resolve
37548
37995
  });
37549
37996
  });
37550
- const layer$44 = Layer.effect(VcsDriverRegistry, make$53).pipe(Layer.provide(layer$45));
37997
+ const layer$44 = Layer.effect(VcsDriverRegistry, make$54).pipe(Layer.provide(layer$45));
37551
37998
  //#endregion
37552
37999
  //#region src/checkpointing/CheckpointStore.ts
37553
38000
  /**
@@ -37567,7 +38014,7 @@ const layer$44 = Layer.effect(VcsDriverRegistry, make$53).pipe(Layer.provide(lay
37567
38014
  */
37568
38015
  /** Service tag for checkpoint persistence and restore operations. */
37569
38016
  var CheckpointStore = class extends Context.Service()("@p4code/cli/checkpointing/CheckpointStore") {};
37570
- const make$52 = Effect.gen(function* () {
38017
+ const make$53 = Effect.gen(function* () {
37571
38018
  const vcsRegistry = yield* VcsDriverRegistry;
37572
38019
  const resolveCheckpoints = Effect.fn("CheckpointStore.resolveCheckpoints")(function* (operation, cwd) {
37573
38020
  const handle = yield* vcsRegistry.resolve({ cwd });
@@ -37606,7 +38053,7 @@ const make$52 = Effect.gen(function* () {
37606
38053
  deleteCheckpointRefs
37607
38054
  });
37608
38055
  });
37609
- const layer$43 = Layer.effect(CheckpointStore, make$52);
38056
+ const layer$43 = Layer.effect(CheckpointStore, make$53);
37610
38057
  //#endregion
37611
38058
  //#region src/checkpointing/CheckpointDiffQuery.ts
37612
38059
  /**
@@ -37628,7 +38075,7 @@ function buildTurnDiffResult(input, diff) {
37628
38075
  diff
37629
38076
  };
37630
38077
  }
37631
- const make$51 = Effect.gen(function* () {
38078
+ const make$52 = Effect.gen(function* () {
37632
38079
  const projectionSnapshotQuery = yield* ProjectionSnapshotQuery;
37633
38080
  const checkpointStore = yield* CheckpointStore;
37634
38081
  const threadActivities = yield* ProjectionThreadActivityRepository;
@@ -37799,7 +38246,7 @@ const make$51 = Effect.gen(function* () {
37799
38246
  getFullThreadDiff
37800
38247
  });
37801
38248
  });
37802
- const layer$42 = Layer.effect(CheckpointDiffQuery, make$51);
38249
+ const layer$42 = Layer.effect(CheckpointDiffQuery, make$52);
37803
38250
  //#endregion
37804
38251
  //#region ../../packages/shared/src/toolCategory.ts
37805
38252
  const TOOL_CATEGORY_TITLES = {
@@ -40813,7 +41260,7 @@ function makeUpdateState(input) {
40813
41260
  output: input.output ?? null
40814
41261
  };
40815
41262
  }
40816
- const make$50 = Effect.fn("ProviderMaintenanceRunner.make")(function* () {
41263
+ const make$51 = Effect.fn("ProviderMaintenanceRunner.make")(function* () {
40817
41264
  const providerRegistry = yield* ProviderRegistry;
40818
41265
  const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
40819
41266
  const httpClient = yield* HttpClient.HttpClient;
@@ -40928,7 +41375,7 @@ const make$50 = Effect.fn("ProviderMaintenanceRunner.make")(function* () {
40928
41375
  });
40929
41376
  return ProviderMaintenanceRunner.of({ updateProvider });
40930
41377
  });
40931
- const layer$41 = Layer.effect(ProviderMaintenanceRunner, make$50());
41378
+ const layer$41 = Layer.effect(ProviderMaintenanceRunner, make$51());
40932
41379
  //#endregion
40933
41380
  //#region src/provider/Services/ProviderInstanceRegistry.ts
40934
41381
  var ProviderInstanceRegistry = class extends Context.Service()("@p4code/cli/provider/Services/ProviderInstanceRegistry") {};
@@ -40952,11 +41399,11 @@ const makeTextGenerationFromRegistry = (registry) => TextGeneration.of({
40952
41399
  detail: "This provider does not report account usage."
40953
41400
  }))))
40954
41401
  });
40955
- const make$49 = Effect.gen(function* () {
41402
+ const make$50 = Effect.gen(function* () {
40956
41403
  const registry = yield* ProviderInstanceRegistry;
40957
41404
  return makeTextGenerationFromRegistry(registry);
40958
41405
  });
40959
- const layer$40 = Layer.effect(TextGeneration, make$49);
41406
+ const layer$40 = Layer.effect(TextGeneration, make$50);
40960
41407
  //#endregion
40961
41408
  //#region src/provider/Drivers/ClaudeHome.ts
40962
41409
  const resolveClaudeHomePath = Effect.fn("resolveClaudeHomePath")(function* (config) {
@@ -41948,7 +42395,7 @@ Layer.succeed(UsageService, UsageService.of({ readSummary: (input) => Effect.suc
41948
42395
  },
41949
42396
  scanDurationMs: 0
41950
42397
  }) }));
41951
- const make$48 = Effect.gen(function* () {
42398
+ const make$49 = Effect.gen(function* () {
41952
42399
  const fileSystem = yield* FileSystem.FileSystem;
41953
42400
  const path = yield* Path.Path;
41954
42401
  const config = yield* ServerConfig$1;
@@ -42180,7 +42627,7 @@ const make$48 = Effect.gen(function* () {
42180
42627
  };
42181
42628
  }) };
42182
42629
  });
42183
- const layer$39 = Layer.effect(UsageService, make$48);
42630
+ const layer$39 = Layer.effect(UsageService, make$49);
42184
42631
  const SKILL_MANIFEST_FILENAME = "SKILL.md";
42185
42632
  /**
42186
42633
  * Split a catalogue id (`owner/repo/skill-name`) into its parts.
@@ -42326,7 +42773,7 @@ const emptyFetch = (id, unavailable) => ({
42326
42773
  skipped: [],
42327
42774
  unavailable
42328
42775
  });
42329
- const make$47 = Effect.gen(function* () {
42776
+ const make$48 = Effect.gen(function* () {
42330
42777
  const http = yield* HttpClient.HttpClient;
42331
42778
  const request = Effect.fn("SkillRegistry.request")(function* (url) {
42332
42779
  return yield* http.execute(HttpClientRequest.get(url).pipe(HttpClientRequest.setHeader("accept", "application/json"), HttpClientRequest.setHeader("user-agent", "p4code"))).pipe(Effect.timeout(REQUEST_TIMEOUT_MS));
@@ -42397,7 +42844,7 @@ const make$47 = Effect.gen(function* () {
42397
42844
  fetch
42398
42845
  };
42399
42846
  });
42400
- const layer$38 = Layer.effect(SkillRegistry, make$47);
42847
+ const layer$38 = Layer.effect(SkillRegistry, make$48);
42401
42848
  //#endregion
42402
42849
  //#region ../../packages/shared/src/KeyedCoalescingWorker.ts
42403
42850
  const makeKeyedCoalescingWorker = (options) => Effect.gen(function* () {
@@ -42696,7 +43143,7 @@ const serversEqual = (left, right) => {
42696
43143
  }
42697
43144
  return true;
42698
43145
  };
42699
- const make$46 = Effect.gen(function* PortDiscoveryMake() {
43146
+ const make$47 = Effect.gen(function* PortDiscoveryMake() {
42700
43147
  const net = yield* NetService;
42701
43148
  const processRunner = yield* ProcessRunner;
42702
43149
  const hostPlatform = yield* HostProcessPlatform;
@@ -42847,7 +43294,7 @@ const make$46 = Effect.gen(function* PortDiscoveryMake() {
42847
43294
  unregisterTerminal
42848
43295
  });
42849
43296
  }).pipe(Effect.withSpan("PortDiscovery.make"));
42850
- const layer$37 = Layer.effect(PortDiscovery, make$46);
43297
+ const layer$37 = Layer.effect(PortDiscovery, make$47);
42851
43298
  //#endregion
42852
43299
  //#region src/terminal/Manager.ts
42853
43300
  /**
@@ -43525,7 +43972,7 @@ function normalizedRuntimeEnv(env) {
43525
43972
  if (entries.length === 0) return null;
43526
43973
  return Object.fromEntries(entries.toSorted(([left], [right]) => left.localeCompare(right)));
43527
43974
  }
43528
- const make$45 = Effect.fn("TerminalManager.make")(function* () {
43975
+ const make$46 = Effect.fn("TerminalManager.make")(function* () {
43529
43976
  const { terminalLogsDir } = yield* ServerConfig$1;
43530
43977
  const ptyAdapter = yield* PtyAdapter;
43531
43978
  const portDiscovery = yield* PortDiscovery;
@@ -44487,7 +44934,7 @@ const makeWithOptions$1 = Effect.fn("TerminalManager.makeWithOptions")(function*
44487
44934
  subscribeMetadata
44488
44935
  });
44489
44936
  });
44490
- const layer$36 = Layer.effect(TerminalManager, make$45()).pipe(Layer.provide(layer$61));
44937
+ const layer$36 = Layer.effect(TerminalManager, make$46()).pipe(Layer.provide(layer$61));
44491
44938
  //#endregion
44492
44939
  //#region src/mcp/McpInvocationContext.ts
44493
44940
  var McpInvocationContext = class extends Context.Service()("@p4code/cli/mcp/McpInvocationContext") {};
@@ -44697,7 +45144,7 @@ const classifyResponseError = (context, error) => {
44697
45144
  });
44698
45145
  }
44699
45146
  };
44700
- const make$44 = Effect.gen(function* PreviewAutomationBrokerMake() {
45147
+ const make$45 = Effect.gen(function* PreviewAutomationBrokerMake() {
44701
45148
  const crypto = yield* Crypto.Crypto;
44702
45149
  const state = yield* SynchronizedRef.make({
44703
45150
  clients: /* @__PURE__ */ new Map(),
@@ -44931,7 +45378,7 @@ const make$44 = Effect.gen(function* PreviewAutomationBrokerMake() {
44931
45378
  invoke
44932
45379
  });
44933
45380
  }).pipe(Effect.withSpan("PreviewAutomationBroker.make"));
44934
- const layer$35 = Layer.effect(PreviewAutomationBroker, make$44);
45381
+ const layer$35 = Layer.effect(PreviewAutomationBroker, make$45);
44935
45382
  //#endregion
44936
45383
  //#region src/preview/Manager.ts
44937
45384
  /**
@@ -44995,7 +45442,7 @@ const buildIdleSnapshot = (input) => ({
44995
45442
  viewport: FILL_PREVIEW_VIEWPORT,
44996
45443
  updatedAt: input.updatedAt
44997
45444
  });
44998
- const make$43 = Effect.gen(function* PreviewManagerMake() {
45445
+ const make$44 = Effect.gen(function* PreviewManagerMake() {
44999
45446
  const serverEpoch = NodeCrypto.randomUUID();
45000
45447
  const stateRef = yield* SynchronizedRef.make(initialState);
45001
45448
  const eventsPubSub = yield* PubSub.unbounded();
@@ -45226,7 +45673,7 @@ const make$43 = Effect.gen(function* PreviewManagerMake() {
45226
45673
  subscribeEvents: PubSub.subscribe(eventsPubSub)
45227
45674
  });
45228
45675
  }).pipe(Effect.withSpan("PreviewManager.make"));
45229
- const layer$34 = Layer.effect(PreviewManager, make$43);
45676
+ const layer$34 = Layer.effect(PreviewManager, make$44);
45230
45677
  //#endregion
45231
45678
  //#region src/workspace/WorkspaceSearchIndex.ts
45232
45679
  const WORKSPACE_INDEX_MAX_ENTRIES = 25e3;
@@ -45360,7 +45807,7 @@ const waitForScan = (cwd, finder, onFailure) => Effect.try({
45360
45807
  timeout: WORKSPACE_INDEX_SCAN_TIMEOUT
45361
45808
  })
45362
45809
  }), Effect.withSpan("WorkspaceSearchIndex.waitForScan"));
45363
- const make$42 = Effect.fn("WorkspaceSearchIndex.make")(function* (cwd) {
45810
+ const make$43 = Effect.fn("WorkspaceSearchIndex.make")(function* (cwd) {
45364
45811
  const finder = yield* Effect.acquireRelease(createFinder(cwd), (finder) => Effect.try({
45365
45812
  try: () => finder.destroy(),
45366
45813
  catch: (cause) => new WorkspaceSearchIndexDestroyFailed({
@@ -45434,7 +45881,7 @@ const make$42 = Effect.fn("WorkspaceSearchIndex.make")(function* (cwd) {
45434
45881
  * workspace root. WorkspaceSearchIndexMap owns memoization and idle cleanup;
45435
45882
  * using a default cwd here would mix resources from different workspaces.
45436
45883
  */
45437
- const layer$33 = (cwd) => Layer.effect(WorkspaceSearchIndex, make$42(cwd));
45884
+ const layer$33 = (cwd) => Layer.effect(WorkspaceSearchIndex, make$43(cwd));
45438
45885
  var WorkspaceSearchIndexMap = class extends LayerMap.Service()("@p4code/cli/workspace/WorkspaceSearchIndexMap", {
45439
45886
  lookup: layer$33,
45440
45887
  idleTimeToLive: WORKSPACE_INDEX_IDLE_TTL
@@ -45498,7 +45945,7 @@ const resolveBrowseTarget = Effect.fn("WorkspaceEntries.resolveBrowseTarget")(fu
45498
45945
  if (!input.cwd) return yield* new WorkspaceEntriesCurrentProjectRequiredError({ partialPath: input.partialPath });
45499
45946
  return path.resolve(expandHomePath$1(input.cwd, path), input.partialPath);
45500
45947
  });
45501
- const make$41 = Effect.gen(function* () {
45948
+ const make$42 = Effect.gen(function* () {
45502
45949
  const path = yield* Path.Path;
45503
45950
  const workspacePaths = yield* WorkspacePaths;
45504
45951
  const workspaceSearchIndexes = yield* WorkspaceSearchIndexMap;
@@ -45572,7 +46019,7 @@ const make$41 = Effect.gen(function* () {
45572
46019
  search
45573
46020
  });
45574
46021
  });
45575
- const layer$32 = Layer.effect(WorkspaceEntries, make$41).pipe(Layer.provide(WorkspaceSearchIndexMap.layer));
46022
+ const layer$32 = Layer.effect(WorkspaceEntries, make$42).pipe(Layer.provide(WorkspaceSearchIndexMap.layer));
45576
46023
  //#endregion
45577
46024
  //#region src/workspace/WorkspaceFileSystem.ts
45578
46025
  /**
@@ -45631,7 +46078,7 @@ Schema$1.Union([
45631
46078
  ]);
45632
46079
  /** Service tag for workspace file operations. */
45633
46080
  var WorkspaceFileSystem = class extends Context.Service()("@p4code/cli/workspace/WorkspaceFileSystem") {};
45634
- const make$40 = Effect.gen(function* () {
46081
+ const make$41 = Effect.gen(function* () {
45635
46082
  const fileSystem = yield* FileSystem.FileSystem;
45636
46083
  const path = yield* Path.Path;
45637
46084
  const workspacePaths = yield* WorkspacePaths;
@@ -45775,7 +46222,7 @@ const make$40 = Effect.gen(function* () {
45775
46222
  writeFile
45776
46223
  });
45777
46224
  });
45778
- const layer$31 = Layer.effect(WorkspaceFileSystem, make$40);
46225
+ const layer$31 = Layer.effect(WorkspaceFileSystem, make$41);
45779
46226
  //#endregion
45780
46227
  //#region src/textGeneration/TextGenerationPresets.ts
45781
46228
  const conventionalCommitsTextGenerationPolicy = {
@@ -45839,7 +46286,7 @@ var ProjectSetupScriptProjectNotFoundError = class extends Schema$1.TaggedErrorC
45839
46286
  };
45840
46287
  Schema$1.Union([ProjectSetupScriptOperationError, ProjectSetupScriptProjectNotFoundError]);
45841
46288
  var ProjectSetupScriptRunner = class extends Context.Service()("@p4code/cli/project/ProjectSetupScriptRunner") {};
45842
- const make$39 = Effect.gen(function* () {
46289
+ const make$40 = Effect.gen(function* () {
45843
46290
  const projectionSnapshotQuery = yield* ProjectionSnapshotQuery;
45844
46291
  const terminalManager = yield* TerminalManager;
45845
46292
  const runForThread = Effect.fn("ProjectSetupScriptRunner.runForThread")(function* (input) {
@@ -45897,7 +46344,7 @@ const make$39 = Effect.gen(function* () {
45897
46344
  });
45898
46345
  return ProjectSetupScriptRunner.of({ runForThread });
45899
46346
  });
45900
- const layer$30 = Layer.effect(ProjectSetupScriptRunner, make$39);
46347
+ const layer$30 = Layer.effect(ProjectSetupScriptRunner, make$40);
45901
46348
  //#endregion
45902
46349
  //#region src/sourceControl/azureDevOpsPullRequests.ts
45903
46350
  const AzureDevOpsPullRequestSchema = Schema$1.Struct({
@@ -46221,7 +46668,7 @@ function decodeAzureDevOpsJson(raw, schema, operation, cwd) {
46221
46668
  cause
46222
46669
  })));
46223
46670
  }
46224
- const make$38 = Effect.gen(function* () {
46671
+ const make$39 = Effect.gen(function* () {
46225
46672
  const process = yield* VcsProcess;
46226
46673
  const execute = (input) => process.run({
46227
46674
  operation: "AzureDevOpsCli.execute",
@@ -46363,7 +46810,7 @@ const make$38 = Effect.gen(function* () {
46363
46810
  }).pipe(Effect.asVoid)
46364
46811
  });
46365
46812
  });
46366
- const layer$29 = Layer.effect(AzureDevOpsCli, make$38);
46813
+ const layer$29 = Layer.effect(AzureDevOpsCli, make$39);
46367
46814
  //#endregion
46368
46815
  //#region src/sourceControl/SourceControlProviderDiscovery.ts
46369
46816
  function firstNonEmptyLine(text) {
@@ -46566,7 +47013,7 @@ function toChangeRequest$5(summary) {
46566
47013
  isCrossRepository: false
46567
47014
  };
46568
47015
  }
46569
- const make$37 = Effect.gen(function* () {
47016
+ const make$38 = Effect.gen(function* () {
46570
47017
  const azure = yield* AzureDevOpsCli;
46571
47018
  return SourceControlProvider.of({
46572
47019
  kind: "azure-devops",
@@ -46658,7 +47105,7 @@ const make$37 = Effect.gen(function* () {
46658
47105
  })))
46659
47106
  });
46660
47107
  });
46661
- Layer.effect(SourceControlProvider, make$37);
47108
+ Layer.effect(SourceControlProvider, make$38);
46662
47109
  //#endregion
46663
47110
  //#region src/sourceControl/bitbucketPullRequests.ts
46664
47111
  const BitbucketRepositoryRefSchema = Schema$1.Struct({
@@ -47035,7 +47482,7 @@ function responseError(operation, response) {
47035
47482
  responseBodyLength: collected.text.length
47036
47483
  }))));
47037
47484
  }
47038
- const make$36 = Effect.gen(function* () {
47485
+ const make$37 = Effect.gen(function* () {
47039
47486
  const config = yield* BitbucketApiEnvConfig;
47040
47487
  const httpClient = yield* HttpClient.HttpClient;
47041
47488
  const fileSystem = yield* FileSystem.FileSystem;
@@ -47251,7 +47698,7 @@ const make$36 = Effect.gen(function* () {
47251
47698
  })))
47252
47699
  });
47253
47700
  });
47254
- const layer$27 = Layer.effect(BitbucketApi, make$36);
47701
+ const layer$27 = Layer.effect(BitbucketApi, make$37);
47255
47702
  //#endregion
47256
47703
  //#region src/sourceControl/BitbucketSourceControlProvider.ts
47257
47704
  function toChangeRequest$4(summary) {
@@ -47269,7 +47716,7 @@ function toChangeRequest$4(summary) {
47269
47716
  ...summary.headRepositoryOwnerLogin !== void 0 ? { headRepositoryOwnerLogin: summary.headRepositoryOwnerLogin } : {}
47270
47717
  };
47271
47718
  }
47272
- const make$35 = Effect.gen(function* () {
47719
+ const make$36 = Effect.gen(function* () {
47273
47720
  const bitbucket = yield* BitbucketApi;
47274
47721
  return SourceControlProvider.of({
47275
47722
  kind: "bitbucket",
@@ -47360,7 +47807,7 @@ const make$35 = Effect.gen(function* () {
47360
47807
  })))
47361
47808
  });
47362
47809
  });
47363
- Layer.effect(SourceControlProvider, make$35);
47810
+ Layer.effect(SourceControlProvider, make$36);
47364
47811
  const makeDiscovery = Effect.gen(function* () {
47365
47812
  return {
47366
47813
  type: "api",
@@ -47602,7 +48049,7 @@ function deriveRepositoryCloneUrlsFromCreateOutput(stdout, repository) {
47602
48049
  sshUrl: `git@${fallbackHost}:${repository}.git`
47603
48050
  };
47604
48051
  }
47605
- const make$34 = Effect.gen(function* () {
48052
+ const make$35 = Effect.gen(function* () {
47606
48053
  const process = yield* VcsProcess;
47607
48054
  const execute = (input) => process.run({
47608
48055
  operation: "GitHubCli.execute",
@@ -47720,7 +48167,7 @@ const make$34 = Effect.gen(function* () {
47720
48167
  }).pipe(Effect.asVoid)
47721
48168
  });
47722
48169
  });
47723
- const layer$25 = Layer.effect(GitHubCli, make$34);
48170
+ const layer$25 = Layer.effect(GitHubCli, make$35);
47724
48171
  //#endregion
47725
48172
  //#region src/sourceControl/gitHubAuthStatus.ts
47726
48173
  const GitHubAuthStatusAccountSchema = Schema$1.Struct({
@@ -47821,7 +48268,7 @@ const discovery$1 = {
47821
48268
  parseAuth: parseGitHubAuth,
47822
48269
  installHint: "Install the GitHub command-line tool (`gh`) via https://cli.github.com/ or your package manager (for example `brew install gh`)."
47823
48270
  };
47824
- const make$33 = Effect.gen(function* () {
48271
+ const make$34 = Effect.gen(function* () {
47825
48272
  const github = yield* GitHubCli;
47826
48273
  const listChangeRequests = (input) => {
47827
48274
  if (input.state === "open") return github.listOpenPullRequests({
@@ -47937,7 +48384,7 @@ const make$33 = Effect.gen(function* () {
47937
48384
  })))
47938
48385
  });
47939
48386
  });
47940
- Layer.effect(SourceControlProvider, make$33);
48387
+ Layer.effect(SourceControlProvider, make$34);
47941
48388
  //#endregion
47942
48389
  //#region src/sourceControl/gitLabMergeRequests.ts
47943
48390
  const GitLabProjectReferenceSchema = Schema$1.Struct({
@@ -48249,7 +48696,7 @@ function parseRepositoryPath(repository) {
48249
48696
  projectPath
48250
48697
  };
48251
48698
  }
48252
- const make$32 = Effect.gen(function* () {
48699
+ const make$33 = Effect.gen(function* () {
48253
48700
  const process = yield* VcsProcess;
48254
48701
  const run = (input, mapError) => process.run({
48255
48702
  operation: "GitLabCli.execute",
@@ -48400,7 +48847,7 @@ const make$32 = Effect.gen(function* () {
48400
48847
  }).pipe(Effect.asVoid)
48401
48848
  });
48402
48849
  });
48403
- const layer$23 = Layer.effect(GitLabCli, make$32);
48850
+ const layer$23 = Layer.effect(GitLabCli, make$33);
48404
48851
  //#endregion
48405
48852
  //#region src/sourceControl/gitLabAuthStatus.ts
48406
48853
  const HOST_LINE_PATTERN = /^(?:[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?|\[[a-f0-9:.]+\])(?::\d+)?$/iu;
@@ -48497,7 +48944,7 @@ const discovery = {
48497
48944
  refineUnknownRemote: refineUnknownGitLabRemote,
48498
48945
  installHint: "Install the GitLab command-line tool (`glab`) from https://gitlab.com/gitlab-org/cli or your package manager (for example `brew install glab`)."
48499
48946
  };
48500
- const make$31 = Effect.gen(function* () {
48947
+ const make$32 = Effect.gen(function* () {
48501
48948
  const gitlab = yield* GitLabCli;
48502
48949
  return SourceControlProvider.of({
48503
48950
  kind: "gitlab",
@@ -48585,7 +49032,7 @@ const make$31 = Effect.gen(function* () {
48585
49032
  })))
48586
49033
  });
48587
49034
  });
48588
- Layer.effect(SourceControlProvider, make$31);
49035
+ Layer.effect(SourceControlProvider, make$32);
48589
49036
  //#endregion
48590
49037
  //#region src/sourceControl/SourceControlProviderRegistry.ts
48591
49038
  const PROVIDER_DETECTION_CACHE_CAPACITY = 2048;
@@ -48741,12 +49188,12 @@ const makeWithProviders = Effect.fn("makeSourceControlProviderRegistryWithProvid
48741
49188
  })), { concurrency: "unbounded" })
48742
49189
  });
48743
49190
  });
48744
- const make$30 = Effect.gen(function* () {
48745
- const github = yield* make$33;
48746
- const gitlab = yield* make$31;
48747
- const bitbucket = yield* make$35;
49191
+ const make$31 = Effect.gen(function* () {
49192
+ const github = yield* make$34;
49193
+ const gitlab = yield* make$32;
49194
+ const bitbucket = yield* make$36;
48748
49195
  const bitbucketDiscovery = yield* makeDiscovery;
48749
- const azureDevOps = yield* make$37;
49196
+ const azureDevOps = yield* make$38;
48750
49197
  return yield* makeWithProviders([
48751
49198
  {
48752
49199
  kind: "github",
@@ -48770,7 +49217,7 @@ const make$30 = Effect.gen(function* () {
48770
49217
  }
48771
49218
  ]);
48772
49219
  });
48773
- const layer$21 = Layer.effect(SourceControlProviderRegistry, make$30);
49220
+ const layer$21 = Layer.effect(SourceControlProviderRegistry, make$31);
48774
49221
  //#endregion
48775
49222
  //#region src/sourceControl/PrTemplateDetection.ts
48776
49223
  const TEMPLATE_MAX_BYTES = 8e3;
@@ -49140,7 +49587,7 @@ function toPullRequestHeadRemoteInfo(pr) {
49140
49587
  ...pr.headRepositoryOwnerLogin !== void 0 ? { headRepositoryOwnerLogin: pr.headRepositoryOwnerLogin } : {}
49141
49588
  };
49142
49589
  }
49143
- const make$29 = Effect.gen(function* () {
49590
+ const make$30 = Effect.gen(function* () {
49144
49591
  const gitCore = yield* GitVcsDriver;
49145
49592
  const sourceControlProviders = yield* SourceControlProviderRegistry;
49146
49593
  const textGeneration = yield* TextGeneration;
@@ -50062,7 +50509,7 @@ const make$29 = Effect.gen(function* () {
50062
50509
  runStackedAction
50063
50510
  });
50064
50511
  });
50065
- const layer$20 = Layer.effect(GitManager, make$29);
50512
+ const layer$20 = Layer.effect(GitManager, make$30);
50066
50513
  //#endregion
50067
50514
  //#region src/git/GitWorkflowService.ts
50068
50515
  var GitWorkflowService = class extends Context.Service()("@p4code/cli/git/GitWorkflowService") {};
@@ -50099,7 +50546,7 @@ function nonRepositoryListRefs() {
50099
50546
  totalCount: 0
50100
50547
  };
50101
50548
  }
50102
- const make$28 = Effect.gen(function* () {
50549
+ const make$29 = Effect.gen(function* () {
50103
50550
  const registry = yield* VcsDriverRegistry;
50104
50551
  const git = yield* GitVcsDriver;
50105
50552
  const gitManager = yield* GitManager;
@@ -50185,7 +50632,7 @@ const make$28 = Effect.gen(function* () {
50185
50632
  renameBranch: (input) => ensureGit("GitWorkflowService.renameBranch", input.cwd).pipe(Effect.andThen(git.renameBranch(input)))
50186
50633
  });
50187
50634
  });
50188
- const layer$19 = Layer.effect(GitWorkflowService, make$28);
50635
+ const layer$19 = Layer.effect(GitWorkflowService, make$29);
50189
50636
  //#endregion
50190
50637
  //#region src/vcs/VcsStatusBroadcaster.ts
50191
50638
  const DEFAULT_VCS_STATUS_REFRESH_INTERVAL = Duration.seconds(30);
@@ -50257,7 +50704,7 @@ function fingerprintStatusPart(status) {
50257
50704
  return JSON.stringify(status);
50258
50705
  }
50259
50706
  const normalizeCwd = (cwd) => Effect.service(FileSystem.FileSystem).pipe(Effect.flatMap((fs) => fs.realPath(cwd)), Effect.orElseSucceed(() => cwd));
50260
- const make$27 = Effect.gen(function* () {
50707
+ const make$28 = Effect.gen(function* () {
50261
50708
  const workflow = yield* GitWorkflowService;
50262
50709
  const fs = yield* FileSystem.FileSystem;
50263
50710
  const changesPubSub = yield* Effect.acquireRelease(PubSub.unbounded(), (pubsub) => PubSub.shutdown(pubsub));
@@ -50481,7 +50928,7 @@ const make$27 = Effect.gen(function* () {
50481
50928
  streamStatus
50482
50929
  });
50483
50930
  });
50484
- const layer$18 = Layer.effect(VcsStatusBroadcaster, make$27);
50931
+ const layer$18 = Layer.effect(VcsStatusBroadcaster, make$28);
50485
50932
  //#endregion
50486
50933
  //#region src/vcs/VcsProvisioningService.ts
50487
50934
  var VcsProvisioningService = class extends Context.Service()("@p4code/cli/vcs/VcsProvisioningService") {};
@@ -50494,7 +50941,7 @@ function resolveRequestedKind(kind) {
50494
50941
  }));
50495
50942
  return Effect.succeed(kind);
50496
50943
  }
50497
- const make$26 = Effect.gen(function* () {
50944
+ const make$27 = Effect.gen(function* () {
50498
50945
  const registry = yield* VcsDriverRegistry;
50499
50946
  const initRepository = Effect.fn("VcsProvisioningService.initRepository")(function* (input) {
50500
50947
  const kind = yield* resolveRequestedKind(input.kind);
@@ -50502,11 +50949,11 @@ const make$26 = Effect.gen(function* () {
50502
50949
  });
50503
50950
  return VcsProvisioningService.of({ initRepository });
50504
50951
  });
50505
- const layer$17 = Layer.effect(VcsProvisioningService, make$26);
50952
+ const layer$17 = Layer.effect(VcsProvisioningService, make$27);
50506
50953
  //#endregion
50507
50954
  //#region src/review/ReviewService.ts
50508
50955
  var ReviewService = class extends Context.Service()("@p4code/cli/review/ReviewService") {};
50509
- const make$25 = Effect.gen(function* () {
50956
+ const make$26 = Effect.gen(function* () {
50510
50957
  const config = yield* ServerConfig$1;
50511
50958
  const fileSystem = yield* FileSystem.FileSystem;
50512
50959
  const path = yield* Path.Path;
@@ -50562,7 +51009,7 @@ const make$25 = Effect.gen(function* () {
50562
51009
  });
50563
51010
  return ReviewService.of({ getDiffPreview });
50564
51011
  });
50565
- const layer$16 = Layer.effect(ReviewService, make$25);
51012
+ const layer$16 = Layer.effect(ReviewService, make$26);
50566
51013
  //#endregion
50567
51014
  //#region src/diagnostics/ProcessDiagnostics.ts
50568
51015
  const PROCESS_QUERY_TIMEOUT_MS = 1e3;
@@ -50857,7 +51304,7 @@ function assertDescendantPid(pid) {
50857
51304
  }));
50858
51305
  }));
50859
51306
  }
50860
- const make$24 = Effect.gen(function* () {
51307
+ const make$25 = Effect.gen(function* () {
50861
51308
  const spawner = yield* ChildProcessSpawner$1.ChildProcessSpawner;
50862
51309
  const read = Effect.gen(function* () {
50863
51310
  const readAt = yield* DateTime.now;
@@ -50901,7 +51348,7 @@ const make$24 = Effect.gen(function* () {
50901
51348
  signal
50902
51349
  });
50903
51350
  });
50904
- const layer$15 = Layer.effect(ProcessDiagnostics, make$24);
51351
+ const layer$15 = Layer.effect(ProcessDiagnostics, make$25);
50905
51352
  //#endregion
50906
51353
  //#region src/diagnostics/ProcessResourceMonitor.ts
50907
51354
  const SAMPLE_INTERVAL_MS = 5e3;
@@ -51052,7 +51499,7 @@ function aggregateProcessResourceHistory(input) {
51052
51499
  }) : Option.none()
51053
51500
  };
51054
51501
  }
51055
- const make$23 = Effect.gen(function* () {
51502
+ const make$24 = Effect.gen(function* () {
51056
51503
  const spawner = yield* ChildProcessSpawner$1.ChildProcessSpawner;
51057
51504
  const state = yield* Ref.make({
51058
51505
  samples: [],
@@ -51101,7 +51548,7 @@ const make$23 = Effect.gen(function* () {
51101
51548
  });
51102
51549
  return ProcessResourceMonitor.of({ readHistory });
51103
51550
  });
51104
- const layer$14 = Layer.effect(ProcessResourceMonitor, make$23);
51551
+ const layer$14 = Layer.effect(ProcessResourceMonitor, make$24);
51105
51552
  //#endregion
51106
51553
  //#region src/diagnostics/TraceDiagnostics.ts
51107
51554
  var TraceFileReadError = class extends Schema$1.TaggedErrorClass()("TraceFileReadError", {
@@ -51349,7 +51796,7 @@ function readTraceFile(fileSystem, path) {
51349
51796
  cause
51350
51797
  })) }));
51351
51798
  }
51352
- const make$22 = Effect.gen(function* () {
51799
+ const make$23 = Effect.gen(function* () {
51353
51800
  const fileSystem = yield* FileSystem.FileSystem;
51354
51801
  const read = Effect.fn("TraceDiagnostics.read")(function* (options) {
51355
51802
  const readAt = options.readAt ?? (yield* DateTime.now);
@@ -51393,7 +51840,7 @@ const make$22 = Effect.gen(function* () {
51393
51840
  });
51394
51841
  return TraceDiagnostics.of({ read });
51395
51842
  });
51396
- const layer$13 = Layer.effect(TraceDiagnostics, make$22);
51843
+ const layer$13 = Layer.effect(TraceDiagnostics, make$23);
51397
51844
  function readTraceDiagnostics(options) {
51398
51845
  return Effect.gen(function* () {
51399
51846
  return yield* (yield* TraceDiagnostics).read(options);
@@ -51755,7 +52202,7 @@ function isReviewerName(value) {
51755
52202
  const name = value.trim();
51756
52203
  return name.length > 0 && !name.startsWith("-");
51757
52204
  }
51758
- const make$21 = Effect.gen(function* () {
52205
+ const make$22 = Effect.gen(function* () {
51759
52206
  const azure = yield* AzureDevOpsCli;
51760
52207
  const detectArgs = ["--detect", "true"];
51761
52208
  const executeJson = (input) => azure.execute({
@@ -51955,7 +52402,7 @@ const make$21 = Effect.gen(function* () {
51955
52402
  }).pipe(Effect.asVoid)
51956
52403
  });
51957
52404
  });
51958
- const layer$12 = Layer.effect(AzureDevOpsPullRequestCli, make$21);
52405
+ const layer$12 = Layer.effect(AzureDevOpsPullRequestCli, make$22);
51959
52406
  //#endregion
51960
52407
  //#region src/pullRequest/AzureDevOpsPullRequestProvider.ts
51961
52408
  const CAPABILITIES$3 = {
@@ -52030,7 +52477,7 @@ function toChangeRequest$1(pullRequest) {
52030
52477
  labels: []
52031
52478
  };
52032
52479
  }
52033
- const make$20 = Effect.gen(function* () {
52480
+ const make$21 = Effect.gen(function* () {
52034
52481
  const cli = yield* AzureDevOpsPullRequestCli;
52035
52482
  const fail = (operation) => (error) => new PullRequestProviderError({
52036
52483
  provider: "azure-devops",
@@ -52762,7 +53209,7 @@ function mergeStrategy(method) {
52762
53209
  default: return "merge_commit";
52763
53210
  }
52764
53211
  }
52765
- const make$19 = Effect.gen(function* () {
53212
+ const make$20 = Effect.gen(function* () {
52766
53213
  const bitbucket = yield* BitbucketApi;
52767
53214
  /**
52768
53215
  * The repository's own path, and the workspace above it — which the people who may review are
@@ -53042,7 +53489,7 @@ const make$19 = Effect.gen(function* () {
53042
53489
  }).pipe(Effect.asVoid))
53043
53490
  });
53044
53491
  });
53045
- const layer$11 = Layer.effect(BitbucketPullRequestApi, make$19);
53492
+ const layer$11 = Layer.effect(BitbucketPullRequestApi, make$20);
53046
53493
  //#endregion
53047
53494
  //#region src/pullRequest/BitbucketPullRequestProvider.ts
53048
53495
  const CAPABILITIES$2 = {
@@ -53122,7 +53569,7 @@ function toChangeRequest(pullRequest) {
53122
53569
  labels: []
53123
53570
  };
53124
53571
  }
53125
- const make$18 = Effect.gen(function* () {
53572
+ const make$19 = Effect.gen(function* () {
53126
53573
  const api = yield* BitbucketPullRequestApi;
53127
53574
  const fail = (operation) => (error) => new PullRequestProviderError({
53128
53575
  provider: "bitbucket",
@@ -55003,7 +55450,7 @@ function actionArgs$1(action, mergeMethod, updateMethod) {
55003
55450
  case "reopen": return ["reopen"];
55004
55451
  }
55005
55452
  }
55006
- const make$17 = Effect.gen(function* () {
55453
+ const make$18 = Effect.gen(function* () {
55007
55454
  const github = yield* GitHubCli;
55008
55455
  /**
55009
55456
  * The pull request's own node id, which is what a mutation against the pull request itself is
@@ -55723,7 +56170,7 @@ const make$17 = Effect.gen(function* () {
55723
56170
  })))
55724
56171
  });
55725
56172
  });
55726
- const layer$10 = Layer.effect(GitHubPullRequestCli, make$17);
56173
+ const layer$10 = Layer.effect(GitHubPullRequestCli, make$18);
55727
56174
  //#endregion
55728
56175
  //#region src/pullRequest/GitHubPullRequestProvider.ts
55729
56176
  const CAPABILITIES$1 = {
@@ -55838,7 +56285,7 @@ function loginAvatarUrl(login, host) {
55838
56285
  }
55839
56286
  /** True where markdown would render nothing: whitespace, or only HTML comments. */
55840
56287
  const rendersEmpty = (body) => body.replace(/<!--[\s\S]*?-->/g, "").trim().length === 0;
55841
- const make$16 = Effect.gen(function* () {
56288
+ const make$17 = Effect.gen(function* () {
55842
56289
  const cli = yield* GitHubPullRequestCli;
55843
56290
  const fail = (operation) => (error) => new PullRequestProviderError({
55844
56291
  provider: "github",
@@ -56852,7 +57299,7 @@ function actionArgs(action, mergeMethod) {
56852
57299
  case "reopen": return ["reopen"];
56853
57300
  }
56854
57301
  }
56855
- const make$15 = Effect.gen(function* () {
57302
+ const make$16 = Effect.gen(function* () {
56856
57303
  const gitlab = yield* GitLabCli;
56857
57304
  const api = (input) => gitlab.execute({
56858
57305
  cwd: input.cwd,
@@ -57423,7 +57870,7 @@ const make$15 = Effect.gen(function* () {
57423
57870
  }).pipe(Effect.asVoid)
57424
57871
  });
57425
57872
  });
57426
- const layer$9 = Layer.effect(GitLabPullRequestCli, make$15);
57873
+ const layer$9 = Layer.effect(GitLabPullRequestCli, make$16);
57427
57874
  //#endregion
57428
57875
  //#region src/pullRequest/GitLabPullRequestProvider.ts
57429
57876
  const CAPABILITIES = {
@@ -57503,7 +57950,7 @@ function reasonFor(error) {
57503
57950
  if (error._tag === "GitLabCliAuthenticationError") return "unauthenticated";
57504
57951
  return "failed";
57505
57952
  }
57506
- const make$14 = Effect.gen(function* () {
57953
+ const make$15 = Effect.gen(function* () {
57507
57954
  const cli = yield* GitLabPullRequestCli;
57508
57955
  const fail = (operation) => (error) => new PullRequestProviderError({
57509
57956
  provider: "gitlab",
@@ -57646,13 +58093,13 @@ function fromProviders(providers) {
57646
58093
  * The hosts this build can read change requests from. A host with no entry here still shows up
57647
58094
  * in the provider list as unimplemented, so its projects are explained rather than missing.
57648
58095
  */
57649
- const make$13 = Effect.map(Effect.all([
57650
- make$16,
57651
- make$14,
57652
- make$18,
57653
- make$20
58096
+ const make$14 = Effect.map(Effect.all([
58097
+ make$17,
58098
+ make$15,
58099
+ make$19,
58100
+ make$21
57654
58101
  ]), fromProviders);
57655
- const layer$8 = Layer.effect(PullRequestProviderRegistry, make$13).pipe(Layer.provide(layer$10.pipe(Layer.provide(layer$25))), Layer.provide(layer$9.pipe(Layer.provide(layer$23))), Layer.provide(layer$11.pipe(Layer.provide(layer$27))), Layer.provide(layer$12.pipe(Layer.provide(layer$29))));
58102
+ const layer$8 = Layer.effect(PullRequestProviderRegistry, make$14).pipe(Layer.provide(layer$10.pipe(Layer.provide(layer$25))), Layer.provide(layer$9.pipe(Layer.provide(layer$23))), Layer.provide(layer$11.pipe(Layer.provide(layer$27))), Layer.provide(layer$12.pipe(Layer.provide(layer$29))));
57656
58103
  //#endregion
57657
58104
  //#region src/pullRequest/PullRequestService.ts
57658
58105
  /**
@@ -57840,7 +58287,7 @@ function repositoryIdentityOf(project) {
57840
58287
  if (identity.displayName) return identity.displayName;
57841
58288
  return identity.owner && identity.name ? `${identity.owner}/${identity.name}` : null;
57842
58289
  }
57843
- const make$12 = Effect.gen(function* () {
58290
+ const make$13 = Effect.gen(function* () {
57844
58291
  const registry = yield* PullRequestProviderRegistry;
57845
58292
  const projections = yield* ProjectionSnapshotQuery;
57846
58293
  const sourceControlProviders = yield* SourceControlProviderRegistry;
@@ -58808,7 +59255,7 @@ const make$12 = Effect.gen(function* () {
58808
59255
  invalidate
58809
59256
  });
58810
59257
  });
58811
- const layer$7 = Layer.effect(PullRequestService, make$12);
59258
+ const layer$7 = Layer.effect(PullRequestService, make$13);
58812
59259
  //#endregion
58813
59260
  //#region src/sourceControl/SourceControlDiscovery.ts
58814
59261
  const VCS_PROBES = [{
@@ -58827,7 +59274,7 @@ const VCS_PROBES = [{
58827
59274
  installHint: "Install Jujutsu with `brew install jj` or from https://github.com/jj-vcs/jj."
58828
59275
  }];
58829
59276
  var SourceControlDiscovery = class extends Context.Service()("@p4code/cli/sourceControl/SourceControlDiscovery") {};
58830
- const make$11 = Effect.gen(function* () {
59277
+ const make$12 = Effect.gen(function* () {
58831
59278
  const config = yield* ServerConfig$1;
58832
59279
  const process = yield* VcsProcess;
58833
59280
  const sourceControlProviders = yield* SourceControlProviderRegistry;
@@ -58876,7 +59323,7 @@ const make$11 = Effect.gen(function* () {
58876
59323
  sourceControlProviders: sourceControlProviders.discover
58877
59324
  }) });
58878
59325
  });
58879
- const layer$6 = Layer.effect(SourceControlDiscovery, make$11);
59326
+ const layer$6 = Layer.effect(SourceControlDiscovery, make$12);
58880
59327
  //#endregion
58881
59328
  //#region src/sourceControl/SourceControlRepositoryService.ts
58882
59329
  const isSourceControlRepositoryError = Schema$1.is(SourceControlRepositoryError);
@@ -58909,7 +59356,7 @@ function expandHomePath(input, path) {
58909
59356
  if (input.startsWith("~/") || input.startsWith("~\\")) return path.join(NodeOS.homedir(), input.slice(2));
58910
59357
  return input;
58911
59358
  }
58912
- const make$10 = Effect.gen(function* () {
59359
+ const make$11 = Effect.gen(function* () {
58913
59360
  const config = yield* ServerConfig$1;
58914
59361
  const fileSystem = yield* FileSystem.FileSystem;
58915
59362
  const git = yield* GitVcsDriver;
@@ -59048,7 +59495,7 @@ const make$10 = Effect.gen(function* () {
59048
59495
  publishRepository: (input) => publishRepository(input).pipe(mapRepositoryError("publishRepository", input.provider))
59049
59496
  });
59050
59497
  });
59051
- const layer$5 = Layer.effect(SourceControlRepositoryService, make$10);
59498
+ const layer$5 = Layer.effect(SourceControlRepositoryService, make$11);
59052
59499
  //#endregion
59053
59500
  //#region src/ws.ts
59054
59501
  /** Matches `p4c hub token add`, so a token minted here and one minted there are the same thing. */
@@ -59451,6 +59898,23 @@ const makeWsRpcLayer = (currentSession, previewAutomationBroker) => WsRpcGroup.t
59451
59898
  threadId: event.payload.threadId
59452
59899
  }));
59453
59900
  case "thread.unarchived": return threadUpsertOrRemove(event.payload.threadId, event.sequence);
59901
+ case "thread-pair.created": return Effect.succeed(Option.some({
59902
+ kind: "thread-pair-upserted",
59903
+ sequence: event.sequence,
59904
+ pair: {
59905
+ id: event.payload.pairId,
59906
+ implementerThreadId: event.payload.implementerThreadId,
59907
+ watcherThreadId: event.payload.watcherThreadId,
59908
+ lastReviewedImplementerSequence: event.payload.lastReviewedImplementerSequence,
59909
+ createdAt: event.payload.createdAt,
59910
+ detachedAt: null
59911
+ }
59912
+ }));
59913
+ case "thread-pair.detached": return Effect.succeed(Option.some({
59914
+ kind: "thread-pair-removed",
59915
+ sequence: event.sequence,
59916
+ pairId: event.payload.pairId
59917
+ }));
59454
59918
  default:
59455
59919
  if (event.aggregateKind !== "thread") return Effect.succeed(Option.none());
59456
59920
  return threadUpsertOrRemove(ThreadId.make(event.aggregateId), event.sequence);
@@ -60272,7 +60736,7 @@ function toPersistenceSqlOrDecodeError(sqlOperation, decodeOperation, correlatio
60272
60736
  cause
60273
60737
  });
60274
60738
  }
60275
- const make$9 = Effect.gen(function* () {
60739
+ const make$10 = Effect.gen(function* () {
60276
60740
  const sql = yield* SqlClient.SqlClient;
60277
60741
  const upsertRuntimeRow = SqlSchema.void({
60278
60742
  Request: ProviderSessionRuntimeDbRowSchema,
@@ -60375,7 +60839,7 @@ const make$9 = Effect.gen(function* () {
60375
60839
  deleteByThreadId
60376
60840
  };
60377
60841
  });
60378
- const layer$4 = Layer.effect(ProviderSessionRuntimeRepository, make$9);
60842
+ const layer$4 = Layer.effect(ProviderSessionRuntimeRepository, make$10);
60379
60843
  //#endregion
60380
60844
  //#region src/provider/Errors.ts
60381
60845
  /**
@@ -61029,6 +61493,54 @@ const makeWithOptions = Effect.fn("McpSessionRegistry.make")(function* (options
61029
61493
  };
61030
61494
  });
61031
61495
  });
61496
+ const grantWatchThread = Effect.fn("McpSessionRegistry.grantWatchThread")(function* ({ watcherThreadId, watchedThreadId }) {
61497
+ yield* SynchronizedRef.update(state, ({ records, spawnedThreadIds }) => {
61498
+ const next = new Map(records);
61499
+ for (const [tokenHash, record] of records) {
61500
+ if (record.scope.threadId !== watcherThreadId) continue;
61501
+ next.set(tokenHash, {
61502
+ ...record,
61503
+ scope: {
61504
+ ...record.scope,
61505
+ capabilities: /* @__PURE__ */ new Set([...record.scope.capabilities, "watch"]),
61506
+ watchThreadIds: /* @__PURE__ */ new Set([...record.scope.watchThreadIds ?? [], watchedThreadId])
61507
+ }
61508
+ });
61509
+ }
61510
+ return {
61511
+ records: next,
61512
+ spawnedThreadIds
61513
+ };
61514
+ });
61515
+ });
61516
+ const revokeWatchThread = Effect.fn("McpSessionRegistry.revokeWatchThread")(function* ({ watcherThreadId, watchedThreadId }) {
61517
+ yield* SynchronizedRef.update(state, ({ records, spawnedThreadIds }) => {
61518
+ const next = new Map(records);
61519
+ for (const [tokenHash, record] of records) {
61520
+ if (record.scope.threadId !== watcherThreadId) continue;
61521
+ const watchThreadIds = new Set(record.scope.watchThreadIds ?? []);
61522
+ watchThreadIds.delete(watchedThreadId);
61523
+ const capabilities = new Set(record.scope.capabilities);
61524
+ if (watchThreadIds.size === 0) capabilities.delete("watch");
61525
+ const { watchThreadIds: _previousWatchThreadIds, ...scopeWithoutWatch } = record.scope;
61526
+ next.set(tokenHash, {
61527
+ ...record,
61528
+ scope: watchThreadIds.size > 0 ? {
61529
+ ...scopeWithoutWatch,
61530
+ capabilities,
61531
+ watchThreadIds
61532
+ } : {
61533
+ ...scopeWithoutWatch,
61534
+ capabilities
61535
+ }
61536
+ });
61537
+ }
61538
+ return {
61539
+ records: next,
61540
+ spawnedThreadIds
61541
+ };
61542
+ });
61543
+ });
61032
61544
  const recordSpawnedThread = Effect.fn("McpSessionRegistry.recordSpawnedThread")(function* (input) {
61033
61545
  yield* SynchronizedRef.update(state, ({ records, spawnedThreadIds }) => {
61034
61546
  const next = new Map(records);
@@ -61050,6 +61562,8 @@ const makeWithOptions = Effect.fn("McpSessionRegistry.make")(function* (options
61050
61562
  issue,
61051
61563
  resolve,
61052
61564
  touch,
61565
+ grantWatchThread,
61566
+ revokeWatchThread,
61053
61567
  recordSpawnedThread,
61054
61568
  revokeProviderSession: Effect.fn("McpSessionRegistry.revokeProviderSession")(function* (providerSessionId) {
61055
61569
  yield* revokeWhere((record) => record.scope.providerSessionId === providerSessionId);
@@ -61064,18 +61578,20 @@ const makeWithOptions = Effect.fn("McpSessionRegistry.make")(function* (options
61064
61578
  });
61065
61579
  });
61066
61580
  let activeMcpSessionRegistry;
61067
- const make$8 = Effect.acquireRelease(makeWithOptions().pipe(Effect.tap((registry) => Effect.sync(() => {
61581
+ const make$9 = Effect.acquireRelease(makeWithOptions().pipe(Effect.tap((registry) => Effect.sync(() => {
61068
61582
  activeMcpSessionRegistry = registry;
61069
61583
  }))), (registry) => Effect.sync(() => {
61070
61584
  if (activeMcpSessionRegistry === registry) activeMcpSessionRegistry = void 0;
61071
61585
  }));
61072
- const layer$3 = Layer.effect(McpSessionRegistry, make$8);
61586
+ const layer$3 = Layer.effect(McpSessionRegistry, make$9);
61073
61587
  const issueActiveMcpCredential = (request) => activeMcpSessionRegistry ? activeMcpSessionRegistry.revokeThread(request.threadId).pipe(Effect.andThen(activeMcpSessionRegistry.issue(request))) : Effect.sync(() => void 0);
61074
61588
  /**
61075
61589
  * Refreshes the liveness of a thread's MCP credential. Called on every provider
61076
61590
  * turn so an active session is never mistaken for an abandoned one.
61077
61591
  */
61078
61592
  const touchActiveMcpThread = (threadId) => activeMcpSessionRegistry ? activeMcpSessionRegistry.touch(threadId) : Effect.void;
61593
+ const grantActiveMcpWatchThread = (input) => activeMcpSessionRegistry ? activeMcpSessionRegistry.grantWatchThread(input) : Effect.void;
61594
+ const revokeActiveMcpWatchThread = (input) => activeMcpSessionRegistry ? activeMcpSessionRegistry.revokeWatchThread(input) : Effect.void;
61079
61595
  const revokeActiveMcpThread = (threadId) => activeMcpSessionRegistry ? activeMcpSessionRegistry.revokeThread(threadId) : Effect.void;
61080
61596
  const revokeAllActiveMcpCredentials = () => activeMcpSessionRegistry ? activeMcpSessionRegistry.revokeAll : Effect.void;
61081
61597
  //#endregion
@@ -61161,9 +61677,10 @@ const makeProviderService = Effect.fn("makeProviderService")(function* (options)
61161
61677
  const directory = yield* ProviderSessionDirectory;
61162
61678
  const runtimeEventPubSub = yield* PubSub.unbounded();
61163
61679
  const nowIso = Effect.map(DateTime.now, DateTime.formatIso);
61164
- const prepareMcpSession = (threadId, providerInstanceId) => issueActiveMcpCredential({
61680
+ const prepareMcpSession = (threadId, providerInstanceId, watchThreadIds) => issueActiveMcpCredential({
61165
61681
  threadId,
61166
- providerInstanceId
61682
+ providerInstanceId,
61683
+ ...watchThreadIds !== void 0 ? { watchThreadIds } : {}
61167
61684
  }).pipe(Effect.tap((credential) => credential ? Effect.sync(() => setMcpProviderSession(credential.config)) : Effect.void));
61168
61685
  const clearMcpSession = (threadId) => revokeActiveMcpThread(threadId).pipe(Effect.tap(() => Effect.sync(() => clearMcpProviderSession(threadId))));
61169
61686
  const publishRuntimeEvent = (event) => Effect.succeed(event).pipe(Effect.tap((canonicalEvent) => canonicalEventLogger ? canonicalEventLogger.write(canonicalEvent, canonicalEvent.threadId) : Effect.void), Effect.flatMap((canonicalEvent) => PubSub.publish(runtimeEventPubSub, canonicalEvent)), Effect.asVoid);
@@ -61308,7 +61825,7 @@ const makeProviderService = Effect.fn("makeProviderService")(function* (options)
61308
61825
  })));
61309
61826
  }), { discard: true });
61310
61827
  });
61311
- const startSession = Effect.fn("startSession")(function* (threadId, rawInput) {
61828
+ const startSession = Effect.fn("startSession")(function* (threadId, rawInput, options) {
61312
61829
  const parsed = yield* decodeInputOrValidationError({
61313
61830
  operation: "ProviderService.startSession",
61314
61831
  schema: ProviderSessionStartInput,
@@ -61344,7 +61861,7 @@ const makeProviderService = Effect.fn("makeProviderService")(function* (options)
61344
61861
  "provider.cwd.effective": effectiveCwd ?? ""
61345
61862
  });
61346
61863
  const adapter = yield* registry.getByInstance(resolvedInstanceId);
61347
- yield* prepareMcpSession(threadId, resolvedInstanceId);
61864
+ yield* prepareMcpSession(threadId, resolvedInstanceId, options?.watchThreadIds);
61348
61865
  const session = yield* adapter.startSession({
61349
61866
  ...input,
61350
61867
  providerInstanceId: resolvedInstanceId,
@@ -85119,7 +85636,7 @@ const makeTerminationError$1 = (handle) => Effect.match(handle.exitCode, {
85119
85636
  //#endregion
85120
85637
  //#region ../../packages/effect-codex-app-server/src/client.ts
85121
85638
  var CodexAppServerClient = class extends Context.Service()("effect-codex-app-server/client/CodexAppServerClient") {};
85122
- const make$7 = Effect.fn("effect-codex-app-server/CodexAppServerClient.make")(function* (stdio, options = {}, terminationError) {
85639
+ const make$8 = Effect.fn("effect-codex-app-server/CodexAppServerClient.make")(function* (stdio, options = {}, terminationError) {
85123
85640
  const requestHandlers = /* @__PURE__ */ new Map();
85124
85641
  const notificationHandlers = /* @__PURE__ */ new Map();
85125
85642
  let unknownRequestHandler;
@@ -85186,7 +85703,7 @@ const make$7 = Effect.fn("effect-codex-app-server/CodexAppServerClient.make")(fu
85186
85703
  const layerChildProcess$1 = (handle, options = {}) => Layer.effect(CodexAppServerClient, makeChildProcessClient(handle, options));
85187
85704
  const makeChildProcessClient = Effect.fn("effect-codex-app-server/CodexAppServerClient.makeChildProcessClient")(function* (handle, options) {
85188
85705
  yield* Stream.runDrain(handle.stderr).pipe(Effect.ignore, Effect.forkScoped);
85189
- return yield* make$7(makeChildStdio$1(handle), options, makeTerminationError$1(handle));
85706
+ return yield* make$8(makeChildStdio$1(handle), options, makeTerminationError$1(handle));
85190
85707
  });
85191
85708
  //#endregion
85192
85709
  //#region src/provider/Layers/CodexProvider.ts
@@ -91244,7 +91761,7 @@ const makeTerminationError = (handle) => Effect.match(handle.exitCode, {
91244
91761
  //#endregion
91245
91762
  //#region ../../packages/effect-acp/src/client.ts
91246
91763
  var AcpClient = class extends Context.Service()("effect-acp/client/AcpClient") {};
91247
- const make$6 = Effect.fn("effect-acp/AcpClient.make")(function* (stdio, options = {}, terminationError) {
91764
+ const make$7 = Effect.fn("effect-acp/AcpClient.make")(function* (stdio, options = {}, terminationError) {
91248
91765
  const coreHandlers = {};
91249
91766
  const notificationHandlers = {
91250
91767
  sessionUpdate: {
@@ -91402,7 +91919,7 @@ const make$6 = Effect.fn("effect-acp/AcpClient.make")(function* (stdio, options
91402
91919
  const layerChildProcess = (handle, options = {}) => {
91403
91920
  const stdio = makeChildStdio(handle);
91404
91921
  const terminationError = makeTerminationError(handle);
91405
- return Layer.effect(AcpClient, make$6(stdio, options, terminationError));
91922
+ return Layer.effect(AcpClient, make$7(stdio, options, terminationError));
91406
91923
  };
91407
91924
  //#endregion
91408
91925
  //#region ../../packages/shared/src/toolActivity.ts
@@ -91862,7 +92379,7 @@ function formatConfigOptionValue(value) {
91862
92379
  const defaultSessionLoadTimeout = Duration.seconds(90);
91863
92380
  const defaultSessionLoadReplayIdleGap = Duration.seconds(2);
91864
92381
  var AcpSessionRuntime = class extends Context.Service()("@p4code/cli/provider/acp/AcpSessionRuntime") {};
91865
- const make$5 = (options) => Effect.gen(function* () {
92382
+ const make$6 = (options) => Effect.gen(function* () {
91866
92383
  const crypto = yield* Crypto.Crypto;
91867
92384
  const spawner = yield* ChildProcessSpawner$1.ChildProcessSpawner;
91868
92385
  const runtimeScope = yield* Scope.Scope;
@@ -92171,7 +92688,7 @@ const make$5 = (options) => Effect.gen(function* () {
92171
92688
  notify: acp.raw.notify
92172
92689
  };
92173
92690
  });
92174
- const layer$2 = (options) => Layer.effect(AcpSessionRuntime, make$5(options));
92691
+ const layer$2 = (options) => Layer.effect(AcpSessionRuntime, make$6(options));
92175
92692
  function sessionConfigOptionsFromSetup(response) {
92176
92693
  return response?.configOptions ?? [];
92177
92694
  }
@@ -99558,7 +100075,7 @@ const stringField = (record, key) => {
99558
100075
  const value = record[key];
99559
100076
  return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
99560
100077
  };
99561
- const make$4 = Effect.gen(function* () {
100078
+ const make$5 = Effect.gen(function* () {
99562
100079
  const linear = yield* LinearClient;
99563
100080
  return { resolve: Effect.fn("TicketResolver.resolve")(function* (reference) {
99564
100081
  const identifier = parseTicketReference(reference);
@@ -99589,7 +100106,7 @@ const make$4 = Effect.gen(function* () {
99589
100106
  };
99590
100107
  }) };
99591
100108
  });
99592
- const layer$1 = Layer.effect(TicketResolver, make$4);
100109
+ const layer$1 = Layer.effect(TicketResolver, make$5);
99593
100110
  //#endregion
99594
100111
  //#region src/mcp/toolkits/tasks/tools.ts
99595
100112
  const dependencies = [McpInvocationContext, TaskRepository];
@@ -100117,6 +100634,17 @@ const ThreadSpawnTool = Tool.make("thread_spawn", {
100117
100634
  Crypto.Crypto
100118
100635
  ]
100119
100636
  }).annotate(Tool.Title, "Start a thread").annotate(Tool.Readonly, false).annotate(Tool.Destructive, false).annotate(Tool.Idempotent, false);
100637
+ const ThreadPairCreateTool = Tool.make("thread_pair_create", {
100638
+ description: "Create a persisted Fusion pair between this agent session's own thread as implementer and a watcher it previously created with thread_spawn. Returns the pair id used by clients to open the paired view. No browser authentication or direct database access is needed.",
100639
+ parameters: ThreadPairCreateInput,
100640
+ success: ThreadPairCreateResult,
100641
+ failure: ThreadControlToolError,
100642
+ dependencies: [
100643
+ McpInvocationContext,
100644
+ OrchestrationEngineService,
100645
+ Crypto.Crypto
100646
+ ]
100647
+ }).annotate(Tool.Title, "Create a Fusion pair").annotate(Tool.Readonly, false).annotate(Tool.Destructive, false).annotate(Tool.Idempotent, false);
100120
100648
  const ThreadConfigureTool = Tool.make("thread_configure", {
100121
100649
  description: "Change a thread's settings: title, model, permission mode, interaction mode, compression, and whether it may use subagents without asking. Omit threadId to configure this session's own thread; name one only if this session started it. Every field is optional and an omitted field is left alone; the settings actually changed come back in the result.",
100122
100650
  parameters: ThreadConfigureInput,
@@ -100187,7 +100715,7 @@ const AssetCompressTool = Tool.make("asset_compress", {
100187
100715
  Path.Path
100188
100716
  ]
100189
100717
  }).annotate(Tool.Title, "Compress an asset").annotate(Tool.Readonly, false).annotate(Tool.Destructive, true).annotate(Tool.Idempotent, false);
100190
- const ThreadToolkit = Toolkit.make(ThreadSpawnTool, ThreadConfigureTool, ThreadSettleTool, ThreadSnoozeTool, ThreadRenameTool, MemoryAppendTool, AssetCompressTool);
100718
+ const ThreadToolkit = Toolkit.make(ThreadSpawnTool, ThreadPairCreateTool, ThreadConfigureTool, ThreadSettleTool, ThreadSnoozeTool, ThreadRenameTool, MemoryAppendTool, AssetCompressTool);
100191
100719
  //#endregion
100192
100720
  //#region src/mcp/toolkits/threads/handlers.ts
100193
100721
  const DEFAULT_MEMORY_APPEND_TARGET = "CLAUDE.md";
@@ -100284,6 +100812,24 @@ const ThreadToolkitHandlersLive = ThreadToolkit.toLayer({
100284
100812
  title: input.title
100285
100813
  };
100286
100814
  }),
100815
+ thread_pair_create: (input) => Effect.gen(function* () {
100816
+ const { invocation, threadId: watcherThreadId } = yield* requireThreadControlTarget(input.watcherThreadId);
100817
+ const crypto = yield* Crypto.Crypto;
100818
+ const pairId = ThreadPairId.make(yield* crypto.randomUUIDv4.pipe(Effect.orDie));
100819
+ yield* dispatchControl({
100820
+ type: "thread-pair.create",
100821
+ commandId: yield* newCommandId,
100822
+ pairId,
100823
+ implementerThreadId: invocation.threadId,
100824
+ watcherThreadId,
100825
+ createdAt: DateTime.formatIso(yield* DateTime.now)
100826
+ }, invocation.threadId);
100827
+ return {
100828
+ pairId,
100829
+ implementerThreadId: invocation.threadId,
100830
+ watcherThreadId
100831
+ };
100832
+ }),
100287
100833
  thread_configure: (input) => Effect.gen(function* () {
100288
100834
  const { threadId } = yield* requireThreadControlTarget(input.threadId);
100289
100835
  const createdAt = DateTime.formatIso(yield* DateTime.now);
@@ -100695,17 +101241,22 @@ var ProviderRuntimeIngestionService = class extends Context.Service()("@p4code/c
100695
101241
  */
100696
101242
  var ThreadDeletionReactor = class extends Context.Service()("@p4code/cli/orchestration/Services/ThreadDeletionReactor") {};
100697
101243
  //#endregion
101244
+ //#region src/orchestration/Services/FusionWatcherReactor.ts
101245
+ var FusionWatcherReactor = class extends Context.Service()("@p4code/cli/orchestration/Services/FusionWatcherReactor") {};
101246
+ //#endregion
100698
101247
  //#region src/orchestration/Layers/OrchestrationReactor.ts
100699
101248
  const makeOrchestrationReactor = Effect.gen(function* () {
100700
101249
  const providerRuntimeIngestion = yield* ProviderRuntimeIngestionService;
100701
101250
  const providerCommandReactor = yield* ProviderCommandReactor;
100702
101251
  const checkpointReactor = yield* CheckpointReactor;
100703
101252
  const threadDeletionReactor = yield* ThreadDeletionReactor;
101253
+ const fusionWatcherReactor = yield* FusionWatcherReactor;
100704
101254
  return { start: Effect.fn("start")(function* () {
100705
101255
  yield* providerRuntimeIngestion.start();
100706
101256
  yield* providerCommandReactor.start();
100707
101257
  yield* checkpointReactor.start();
100708
101258
  yield* threadDeletionReactor.start();
101259
+ yield* fusionWatcherReactor.start();
100709
101260
  }) };
100710
101261
  });
100711
101262
  const OrchestrationReactorLive = Layer.effect(OrchestrationReactor, makeOrchestrationReactor);
@@ -101287,7 +101838,7 @@ function runtimeEventToActivities(event, taskTitle, compressMode) {
101287
101838
  }
101288
101839
  return [];
101289
101840
  }
101290
- const make$3 = Effect.gen(function* () {
101841
+ const make$4 = Effect.gen(function* () {
101291
101842
  const crypto = yield* Crypto.Crypto;
101292
101843
  const orchestrationEngine = yield* OrchestrationEngineService;
101293
101844
  const projectionSnapshotQuery = yield* ProjectionSnapshotQuery;
@@ -101790,6 +102341,14 @@ const make$3 = Effect.gen(function* () {
101790
102341
  updatedAt: now
101791
102342
  });
101792
102343
  }
102344
+ if (shouldApplyThreadLifecycle) yield* orchestrationEngine.dispatch({
102345
+ type: "thread.turn.complete",
102346
+ commandId: yield* providerCommandId(event, "thread-turn-complete"),
102347
+ threadId: thread.id,
102348
+ ...turnId ? { turnId } : {},
102349
+ state: normalizeRuntimeTurnState(event.payload.state),
102350
+ completedAt: now
102351
+ });
101793
102352
  }
101794
102353
  if (event.type === "session.exited") yield* clearTurnStateForSession(thread.id);
101795
102354
  if (event.type === "runtime.error") {
@@ -101888,7 +102447,7 @@ const make$3 = Effect.gen(function* () {
101888
102447
  drain: worker.drain
101889
102448
  };
101890
102449
  });
101891
- const ProviderRuntimeIngestionLive = Layer.effect(ProviderRuntimeIngestionService, make$3).pipe(Layer.provide(ProjectionTurnRepositoryLive));
102450
+ const ProviderRuntimeIngestionLive = Layer.effect(ProviderRuntimeIngestionService, make$4).pipe(Layer.provide(ProjectionTurnRepositoryLive));
101892
102451
  //#endregion
101893
102452
  //#region src/provider/userInvokedSkills.ts
101894
102453
  /**
@@ -102074,7 +102633,7 @@ function buildGeneratedWorktreeBranchName(raw) {
102074
102633
  const branchFragment = (normalized.startsWith(`p4code/`) ? normalized.slice(`${WORKTREE_BRANCH_PREFIX}/`.length) : normalized).replace(/[^a-z0-9/_-]+/g, "-").replace(/\/+/g, "/").replace(/-+/g, "-").replace(/^[./_-]+|[./_-]+$/g, "").slice(0, 64).replace(/[./_-]+$/g, "");
102075
102634
  return `${WORKTREE_BRANCH_PREFIX}/${branchFragment.length > 0 ? branchFragment : "update"}`;
102076
102635
  }
102077
- const make$2 = Effect.gen(function* () {
102636
+ const make$3 = Effect.gen(function* () {
102078
102637
  const crypto = yield* Crypto.Crypto;
102079
102638
  const orchestrationEngine = yield* OrchestrationEngineService;
102080
102639
  const projectionSnapshotQuery = yield* ProjectionSnapshotQuery;
@@ -102282,6 +102841,11 @@ const make$2 = Effect.gen(function* () {
102282
102841
  if (!thread) return yield* Effect.die(/* @__PURE__ */ new Error(`Thread '${threadId}' was not found in read model.`));
102283
102842
  const desiredRuntimeMode = thread.runtimeMode;
102284
102843
  const requestedModelSelection = options?.modelSelection;
102844
+ const watchThreadIds = ((yield* projectionSnapshotQuery.getCommandReadModel()).threadPairs ?? []).filter((pair) => pair.detachedAt === null && pair.watcherThreadId === threadId).map((pair) => pair.implementerThreadId);
102845
+ yield* Effect.forEach(watchThreadIds, (watchedThreadId) => grantActiveMcpWatchThread({
102846
+ watcherThreadId: threadId,
102847
+ watchedThreadId
102848
+ }), { discard: true });
102285
102849
  const resolveActiveSession = (threadId) => providerService.listSessions().pipe(Effect.map((sessions) => sessions.find((session) => session.threadId === threadId)));
102286
102850
  const activeSession = yield* resolveActiveSession(threadId);
102287
102851
  const activeThreadSession = thread.session !== null && thread.session.status !== "stopped" && activeSession ? thread.session : null;
@@ -102371,7 +102935,7 @@ const make$2 = Effect.gen(function* () {
102371
102935
  runtimeMode: desiredRuntimeMode,
102372
102936
  compressMode: thread.compressMode,
102373
102937
  unpromptedSubagents: thread.unpromptedSubagents
102374
- });
102938
+ }, watchThreadIds.length > 0 ? { watchThreadIds } : void 0);
102375
102939
  };
102376
102940
  const bindSessionToThread = (session) => Effect.gen(function* () {
102377
102941
  if (session.providerInstanceId === void 0) return yield* new ProviderAdapterRequestError({
@@ -102789,7 +103353,7 @@ const make$2 = Effect.gen(function* () {
102789
103353
  drain: worker.drain
102790
103354
  };
102791
103355
  });
102792
- const ProviderCommandReactorLive = Layer.effect(ProviderCommandReactor, make$2);
103356
+ const ProviderCommandReactorLive = Layer.effect(ProviderCommandReactor, make$3);
102793
103357
  //#endregion
102794
103358
  //#region src/checkpointing/Diffs.ts
102795
103359
  function parseTurnDiffFilesFromUnifiedDiff(diff) {
@@ -102819,7 +103383,7 @@ function checkpointStatusFromRuntime(status) {
102819
103383
  default: return "ready";
102820
103384
  }
102821
103385
  }
102822
- const make$1 = Effect.gen(function* () {
103386
+ const make$2 = Effect.gen(function* () {
102823
103387
  const randomUUID = (yield* Crypto.Crypto).randomUUIDv4;
102824
103388
  const serverEventId = randomUUID.pipe(Effect.map(EventId.make));
102825
103389
  const serverCommandId = (tag) => randomUUID.pipe(Effect.map((uuid) => CommandId.make(`server:${tag}:${uuid}`)));
@@ -103301,7 +103865,106 @@ const make$1 = Effect.gen(function* () {
103301
103865
  drain: worker.drain
103302
103866
  };
103303
103867
  });
103304
- const CheckpointReactorLive = Layer.effect(CheckpointReactor, make$1);
103868
+ const CheckpointReactorLive = Layer.effect(CheckpointReactor, make$2);
103869
+ //#endregion
103870
+ //#region src/orchestration/Layers/FusionWatcherReactor.ts
103871
+ const reviewCommandId = (pairId, sequence) => CommandId.make(`server:fusion:${pairId}:review:${sequence}`);
103872
+ const cursorCommandId = (pairId, sequence) => CommandId.make(`server:fusion:${pairId}:cursor:${sequence}`);
103873
+ const reviewMessageId = (pairId, sequence) => MessageId.make(`fusion-review:${pairId}:${sequence}`);
103874
+ const watcherPrompt = (input) => `${FUSION_REVIEW_PROMPT_PREFIX}
103875
+ Review implementer thread ${input.implementerThreadId} after its accepted turn completion.
103876
+
103877
+ Call thread_watch_events with threadId ${input.implementerThreadId} and afterSequence ${input.afterSequence}. Continue paging through sequence ${input.throughSequence}. Inspect repository state when useful.
103878
+
103879
+ Report only a concrete objection: correctness risk, missed requirement, regression, unsafe change, or unnecessary scope. Cite evidence. If no objection exists, return exactly ${FUSION_NO_OBJECTION_TEXT} and nothing else. This marker is hidden from the transcript.`;
103880
+ const make$1 = Effect.gen(function* () {
103881
+ const orchestrationEngine = yield* OrchestrationEngineService;
103882
+ const projectionSnapshotQuery = yield* ProjectionSnapshotQuery;
103883
+ const processReview = Effect.fn("FusionWatcherReactor.processReview")(function* (pair, completion) {
103884
+ const readModel = yield* projectionSnapshotQuery.getCommandReadModel();
103885
+ const currentPair = (readModel.threadPairs ?? []).find((candidate) => candidate.id === pair.id);
103886
+ if (currentPair === void 0 || currentPair.detachedAt !== null || completion.sequence <= currentPair.lastReviewedImplementerSequence) return;
103887
+ const watcher = readModel.threads.find((thread) => thread.id === currentPair.watcherThreadId && thread.deletedAt === null);
103888
+ if (watcher === void 0) return;
103889
+ yield* orchestrationEngine.dispatch({
103890
+ type: "thread.turn.start",
103891
+ commandId: reviewCommandId(currentPair.id, completion.sequence),
103892
+ threadId: watcher.id,
103893
+ message: {
103894
+ messageId: reviewMessageId(currentPair.id, completion.sequence),
103895
+ role: "user",
103896
+ text: watcherPrompt({
103897
+ implementerThreadId: currentPair.implementerThreadId,
103898
+ afterSequence: currentPair.lastReviewedImplementerSequence,
103899
+ throughSequence: completion.sequence
103900
+ }),
103901
+ attachments: []
103902
+ },
103903
+ runtimeMode: watcher.runtimeMode,
103904
+ interactionMode: watcher.interactionMode,
103905
+ compressMode: watcher.compressMode,
103906
+ unpromptedSubagents: watcher.unpromptedSubagents,
103907
+ createdAt: completion.occurredAt
103908
+ });
103909
+ yield* orchestrationEngine.dispatch({
103910
+ type: "thread-pair.cursor.advance",
103911
+ commandId: cursorCommandId(currentPair.id, completion.sequence),
103912
+ pairId: currentPair.id,
103913
+ implementerSequence: completion.sequence,
103914
+ advancedAt: completion.occurredAt
103915
+ });
103916
+ });
103917
+ const catchUpPair = Effect.fn("FusionWatcherReactor.catchUpPair")(function* (pair, throughSequence) {
103918
+ if (throughSequence <= pair.lastReviewedImplementerSequence) return;
103919
+ const completions = (yield* orchestrationEngine.readEvents(pair.lastReviewedImplementerSequence, throughSequence - pair.lastReviewedImplementerSequence).pipe(Stream.takeWhile((event) => event.sequence <= throughSequence), Stream.runCollect)).filter((event) => event.type === "thread.turn-completed" && event.payload.threadId === pair.implementerThreadId);
103920
+ for (const completion of completions) yield* processReview(pair, completion);
103921
+ });
103922
+ const processCompletion = Effect.fn("FusionWatcherReactor.processCompletion")(function* (event) {
103923
+ const pairs = ((yield* projectionSnapshotQuery.getCommandReadModel()).threadPairs ?? []).filter((pair) => pair.detachedAt === null && pair.implementerThreadId === event.payload.threadId && event.sequence > pair.lastReviewedImplementerSequence);
103924
+ yield* Effect.forEach(pairs, (pair) => catchUpPair(pair, event.sequence), {
103925
+ concurrency: 1,
103926
+ discard: true
103927
+ });
103928
+ });
103929
+ const processEvent = Effect.fn("FusionWatcherReactor.processEvent")(function* (event) {
103930
+ if (event.type === "thread.turn-completed") {
103931
+ yield* processCompletion(event);
103932
+ return;
103933
+ }
103934
+ if (event.type === "thread-pair.created") {
103935
+ yield* grantActiveMcpWatchThread({
103936
+ watcherThreadId: event.payload.watcherThreadId,
103937
+ watchedThreadId: event.payload.implementerThreadId
103938
+ });
103939
+ return;
103940
+ }
103941
+ const pair = ((yield* projectionSnapshotQuery.getCommandReadModel()).threadPairs ?? []).find((candidate) => candidate.id === event.payload.pairId);
103942
+ if (pair === void 0) return;
103943
+ yield* revokeActiveMcpWatchThread({
103944
+ watcherThreadId: pair.watcherThreadId,
103945
+ watchedThreadId: pair.implementerThreadId
103946
+ });
103947
+ });
103948
+ const processSafely = (event) => processEvent(event).pipe(Effect.catchCause((cause) => {
103949
+ if (Cause.hasInterruptsOnly(cause)) return Effect.failCause(cause);
103950
+ return Effect.logWarning("fusion watcher reactor failed to process completion", {
103951
+ eventType: event.type,
103952
+ sequence: event.sequence,
103953
+ cause: Cause.pretty(cause)
103954
+ });
103955
+ }));
103956
+ const worker = yield* makeDrainableWorker(processSafely);
103957
+ const enqueueEvent = (event) => event.type === "thread.turn-completed" || event.type === "thread-pair.created" || event.type === "thread-pair.detached" ? worker.enqueue(event) : Effect.void;
103958
+ return {
103959
+ start: Effect.fn("FusionWatcherReactor.start")(function* () {
103960
+ yield* Effect.forkScoped(Stream.runForEach(orchestrationEngine.streamDomainEvents, enqueueEvent));
103961
+ const headSequence = yield* orchestrationEngine.latestSequence;
103962
+ yield* Stream.runForEach(orchestrationEngine.readEvents(0, Math.max(1, headSequence)), enqueueEvent).pipe(Effect.catchCause((cause) => Effect.logWarning("fusion watcher reactor failed historical replay", { cause: Cause.pretty(cause) })));
103963
+ }),
103964
+ drain: worker.drain
103965
+ };
103966
+ });
103967
+ const FusionWatcherReactorLive = Layer.effect(FusionWatcherReactor, make$1);
103305
103968
  //#endregion
103306
103969
  //#region src/orchestration/Layers/ThreadDeletionReactor.ts
103307
103970
  const logCleanupCauseUnlessInterrupted = ({ effect, message, threadId }) => effect.pipe(Effect.catchCause((cause) => {
@@ -104063,7 +104726,7 @@ const PlatformServicesLive = Layer.unwrap(Effect.gen(function* () {
104063
104726
  return layer;
104064
104727
  }
104065
104728
  }));
104066
- const ReactorLayerLive = Layer.empty.pipe(Layer.provideMerge(OrchestrationReactorLive), Layer.provideMerge(ProviderRuntimeIngestionLive), Layer.provideMerge(ProviderCommandReactorLive), Layer.provideMerge(CheckpointReactorLive), Layer.provideMerge(ThreadDeletionReactorLive), Layer.provideMerge(RuntimeReceiptBusLive));
104729
+ 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));
104067
104730
  const ProviderSessionDirectoryLayerLive = ProviderSessionDirectoryLive.pipe(Layer.provide(layer$4));
104068
104731
  const ProviderLayerLive = ProviderServiceLive.pipe(Layer.provide(ProviderAdapterRegistryLive), Layer.provideMerge(ProviderSessionDirectoryLayerLive));
104069
104732
  const PersistenceLayerLive = Layer.empty.pipe(Layer.provideMerge(layerConfig));