@quantiya/codevibe-core 2.0.72 → 2.0.74

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.
@@ -321,6 +321,92 @@ function isAgentInstalled(agent, env, commonPaths = COMMON_AGENT_PATHS) {
321
321
  return !1;
322
322
  }
323
323
  }
324
+ function firstNonEmpty(...values) {
325
+ for (let v of values)
326
+ if (typeof v == "string") {
327
+ let trimmed = v.trim();
328
+ if (trimmed.length > 0) return trimmed;
329
+ }
330
+ return null;
331
+ }
332
+ function detectAgentModel(agent, env = process.env, homeDirOrOptions, options) {
333
+ let homeDir = typeof homeDirOrOptions == "string" ? homeDirOrOptions : void 0, opts = typeof homeDirOrOptions == "object" && homeDirOrOptions !== null ? homeDirOrOptions : options, envKey = `CODEVIBE_${agent}_MODEL`, envKeyVal = firstNonEmpty(env[envKey]);
334
+ if (envKeyVal) return envKeyVal;
335
+ if (agent === "ANTIGRAVITY") {
336
+ let agyExplicit = firstNonEmpty(env.CODEVIBE_AGY_MODEL, env.CODEVIBE_ANTIGRAVITY_MODEL);
337
+ if (agyExplicit) return agyExplicit;
338
+ }
339
+ if (opts?.explicitOnly)
340
+ return null;
341
+ if (agent === "CODEX") {
342
+ let codexVal = firstNonEmpty(env.CODEX_MODEL, env.OPENAI_MODEL);
343
+ if (codexVal) return codexVal;
344
+ } else if (agent === "ANTIGRAVITY") {
345
+ let agyVal = firstNonEmpty(env.ANTIGRAVITY_MODEL, env.AGY_MODEL, env.GEMINI_MODEL);
346
+ if (agyVal) return agyVal;
347
+ } else if (agent === "CLAUDE") {
348
+ let claudeVal = firstNonEmpty(env.CLAUDE_MODEL, env.ANTHROPIC_MODEL);
349
+ if (claudeVal) return claudeVal;
350
+ }
351
+ let resolvedHome = homeDir ?? env.HOME;
352
+ if (agent === "CODEX")
353
+ try {
354
+ let codexHome = env.CODEX_HOME && env.CODEX_HOME.trim() ? env.CODEX_HOME.trim() : resolvedHome && resolvedHome.trim() ? path34.join(resolvedHome, ".codex") : null;
355
+ if (codexHome) {
356
+ let configPath = path34.join(codexHome, "config.toml");
357
+ if (fs29.existsSync(configPath)) {
358
+ let content = fs29.readFileSync(configPath, "utf8"), parsed = toml2.parse(content);
359
+ if (typeof parsed?.profile == "string" && typeof parsed.profiles?.[parsed.profile]?.model == "string") {
360
+ let profileModel = parsed.profiles[parsed.profile].model.trim();
361
+ if (profileModel) return profileModel;
362
+ }
363
+ if (typeof parsed?.model == "string" && parsed.model.trim())
364
+ return parsed.model.trim();
365
+ }
366
+ }
367
+ } catch {
368
+ }
369
+ if (resolvedHome && resolvedHome.trim()) {
370
+ if (agent === "ANTIGRAVITY") {
371
+ let candidates = [
372
+ path34.join(resolvedHome, ".gemini", "antigravity-cli", "settings.json"),
373
+ path34.join(resolvedHome, ".gemini", "settings.json")
374
+ ];
375
+ for (let candidate of candidates)
376
+ try {
377
+ if (fs29.existsSync(candidate)) {
378
+ let parsed = JSON.parse(fs29.readFileSync(candidate, "utf8"));
379
+ if (typeof parsed?.model == "string" && parsed.model.trim())
380
+ return parsed.model.trim();
381
+ }
382
+ } catch {
383
+ }
384
+ } else if (agent === "CLAUDE") {
385
+ let candidates = [
386
+ path34.join(resolvedHome, ".claude.json"),
387
+ path34.join(resolvedHome, ".claude", "settings.json")
388
+ ];
389
+ for (let candidate of candidates)
390
+ try {
391
+ if (fs29.existsSync(candidate)) {
392
+ let parsed = JSON.parse(fs29.readFileSync(candidate, "utf8"));
393
+ if (typeof parsed?.model == "string" && parsed.model.trim())
394
+ return parsed.model.trim();
395
+ }
396
+ } catch {
397
+ }
398
+ }
399
+ }
400
+ return DEFAULT_AGENT_MODELS[agent] ?? null;
401
+ }
402
+ function detectInstalledAgentModels(env = process.env, homeDir, installedAgents, options) {
403
+ let models = {}, installed = installedAgents ?? detectInstalledAgents(env);
404
+ for (let agent of installed) {
405
+ let model = detectAgentModel(agent, env, homeDir, options);
406
+ model && (models[agent] = model);
407
+ }
408
+ return logger.debug("[detectInstalledAgentModels] Detected models", { models }), models;
409
+ }
324
410
  async function pushDetectedAgents(client, log, capabilityRegistry, detectFn = detectInstalledAgents, replace = !1) {
325
411
  let agents = detectFn();
326
412
  if (agents.length === 0) {
@@ -352,10 +438,10 @@ async function pushDetectedAgents(client, log, capabilityRegistry, detectFn = de
352
438
  });
353
439
  }
354
440
  }
355
- var import_child_process3, fs29, path34, AGENT_BINARIES, COMMON_AGENT_PATHS, init_detect_agents = __esm({
441
+ var import_child_process3, fs29, path34, toml2, AGENT_BINARIES, COMMON_AGENT_PATHS, DEFAULT_AGENT_MODELS, init_detect_agents = __esm({
356
442
  "src/orchestration/detect-agents.ts"() {
357
443
  "use strict";
358
- import_child_process3 = require("child_process"), fs29 = __toESM(require("fs")), path34 = __toESM(require("path"));
444
+ import_child_process3 = require("child_process"), fs29 = __toESM(require("fs")), path34 = __toESM(require("path")), toml2 = __toESM(require("@iarna/toml"));
359
445
  init_env_scrub();
360
446
  init_logger2();
361
447
  AGENT_BINARIES = {
@@ -372,6 +458,12 @@ var import_child_process3, fs29, path34, AGENT_BINARIES, COMMON_AGENT_PATHS, ini
372
458
  "/usr/bin",
373
459
  "/bin"
374
460
  ];
461
+ DEFAULT_AGENT_MODELS = {
462
+ CLAUDE: "claude-opus-5",
463
+ GEMINI: "gemini-2.5-pro",
464
+ CODEX: "gpt-6.1",
465
+ ANTIGRAVITY: "gemini-3.8"
466
+ };
375
467
  }
376
468
  });
377
469
 
@@ -8694,8 +8786,8 @@ function validateSourceCursor(value, options) {
8694
8786
  return row3;
8695
8787
  }
8696
8788
  function createSourceJournal(options) {
8697
- let { id: id5, scope, stream } = options, parse6 = (value) => validateSourceCursor(value, options), read = () => options.read(parse6), required = async () => await read() ?? options.missing(), write = async (row3, assertOwnership) => {
8698
- let validated = parse6(row3);
8789
+ let { id: id5, scope, stream } = options, parse7 = (value) => validateSourceCursor(value, options), read = () => options.read(parse7), required = async () => await read() ?? options.missing(), write = async (row3, assertOwnership) => {
8790
+ let validated = parse7(row3);
8699
8791
  await assertOwnership(), await options.write(validated);
8700
8792
  }, recoverLocked = async (assertOwnership) => {
8701
8793
  let row3 = await read();
@@ -8793,13 +8885,14 @@ function createSourcePair(options) {
8793
8885
  return { ...baseline, ...pending2.length && { pendingFrameEndOffset: Math.min(...pending2) } };
8794
8886
  };
8795
8887
  return Object.freeze({
8796
- open: (initial) => {
8888
+ open: (initial, validateInitial) => {
8797
8889
  let snapshot2 = typeof initial == "number" ? initial : position2(initial);
8798
8890
  return options.locked(async () => {
8799
8891
  await recover();
8800
8892
  let present = (await Promise.all(lanes.map((lane) => lane.load()))).filter((row3) => row3 !== null);
8801
8893
  if (present.length === 1 && (present[0].lastFrame !== null || present[0].entries.length !== 0 || present[0].skippedBytes !== 0 || present[0].projection !== null))
8802
8894
  return options.invalid();
8895
+ present.length || validateInitial?.();
8803
8896
  let baseline = present.length ? earliest(present) : snapshot2, rows = [];
8804
8897
  for (let lane of lanes) rows.push(await lane.open(baseline));
8805
8898
  return earliest(rows);
@@ -9991,9 +10084,7 @@ function createPromptRetentionJournal(store) {
9991
10084
  await fence(), receipt2.status === "RERAISE_REQUIRED" && (row3.entries.push({ ...receipt2, reRaiseToken: (0, import_node_crypto12.randomUUID)() }), await save(), await settle(promptId2));
9992
10085
  }
9993
10086
  });
9994
- }, remove: () => store.runExclusive(async (fence) => {
9995
- await fence(), await store.remove(), await fence();
9996
- }) });
10087
+ }, remove: () => store.remove() });
9997
10088
  }
9998
10089
 
9999
10090
  // src/appsync/sync-prompt-publication.ts
@@ -10196,7 +10287,7 @@ function decodeSessionRetirement(value, userId, bad3) {
10196
10287
  let toolOutbox = null;
10197
10288
  if (row3.toolOutbox !== null) {
10198
10289
  let location = row3.toolOutbox;
10199
- if (!location || typeof location != "object" || Object.keys(location).sort().join(",") !== "agent,root" || !["codex", "claude"].includes(location.agent) || typeof location.root != "string" || location.root.includes("\0") || Buffer.byteLength(location.root) > 4096 || !path17.isAbsolute(location.root) || path17.resolve(location.root) !== location.root) return bad3();
10290
+ if (!location || typeof location != "object" || Object.keys(location).sort().join(",") !== "agent,root" || !["codex", "claude", "agy"].includes(location.agent) || typeof location.root != "string" || location.root.includes("\0") || Buffer.byteLength(location.root) > 4096 || !path17.isAbsolute(location.root) || path17.resolve(location.root) !== location.root) return bad3();
10200
10291
  toolOutbox = Object.freeze({ agent: location.agent, root: location.root });
10201
10292
  }
10202
10293
  return Object.freeze({ schemaVersion: 1, kind: "SESSION_RETIREMENT", operationId: clientOperationId, input, toolOutbox });
@@ -10441,19 +10532,10 @@ var sourceCursorId = (scope, stream) => stableUuid("codevibe-sync-source-cursor-
10441
10532
  let scope = this.sessionScope;
10442
10533
  if (!scope) return invalid7();
10443
10534
  let id5 = stableUuid("codevibe-sync-desktop-registration-v1\0", [scope.sessionId, scope.sessionGenerationId]);
10444
- this.options.assertAccount(), await this.ensureDirectory();
10445
- let owner = await this.lock(`registration-${id5}.lockdir`).acquire();
10446
- try {
10447
- return await this.withStore(async (key) => {
10448
- let row3 = await this.readValue(id5, key, ".desktop", (value) => decodeDesktopSyncRegistration(value, invalid7));
10449
- if (!row3) return !1;
10450
- if (row3.operationId !== id5) return invalid7();
10451
- if (this.requireScope(row3), this.options.assertAccount(), !await owner.reassertOwnership()) throw new SyncJournalError("SYNC_JOURNAL_LOCK_LOST");
10452
- return await import_node_fs5.promises.unlink(this.file(id5, ".desktop")), await this.syncDirectory(this.directory), !0;
10453
- });
10454
- } finally {
10455
- await owner.release();
10456
- }
10535
+ return this.removeBookkeepingRecord(id5, ".desktop", [`registration-${id5}.lockdir`], async (key) => {
10536
+ let row3 = await this.readValue(id5, key, ".desktop", (value) => decodeDesktopSyncRegistration(value, invalid7));
10537
+ return row3 ? row3.operationId !== id5 ? invalid7() : (this.requireScope(row3), !0) : !1;
10538
+ });
10457
10539
  }
10458
10540
  /** Provider queues share the existing encrypted/account-fenced capacity.
10459
10541
  * Native identity and generation are immutable: no automatic re-homing. */
@@ -10746,13 +10828,12 @@ var sourceCursorId = (scope, stream) => stableUuid("codevibe-sync-source-cursor-
10746
10828
  let sealed = this.seal(row3, key);
10747
10829
  await this.checkCapacity(Buffer.byteLength(sealed), id5 + ".retention"), await this.write(id5, sealed, ".retention");
10748
10830
  }),
10749
- remove: () => this.withStore(async (key) => {
10750
- let row3 = await this.readValue(id5, key, ".retention", decodePromptRetention);
10751
- if (row3) {
10752
- if (row3.operationId !== id5 || !this.matchesScope(row3)) return invalid7();
10753
- this.options.assertAccount(), await import_node_fs5.promises.unlink(this.file(id5, ".retention")), await this.syncDirectory(this.directory);
10754
- }
10755
- })
10831
+ remove: async () => {
10832
+ await this.removeBookkeepingRecord(id5, ".retention", ["prompt-retention-" + id5 + ".lockdir"], async (key) => {
10833
+ let row3 = await this.readValue(id5, key, ".retention", decodePromptRetention);
10834
+ return row3 ? row3.operationId !== id5 || !this.matchesScope(row3) ? invalid7() : !0 : !1;
10835
+ });
10836
+ }
10756
10837
  });
10757
10838
  }
10758
10839
  /** Canonical INACTIVE proof and joined publication owners are prerequisites.
@@ -10816,23 +10897,11 @@ var sourceCursorId = (scope, stream) => stableUuid("codevibe-sync-source-cursor-
10816
10897
  }
10817
10898
  return ids2.sort();
10818
10899
  }), removed = 0;
10819
- for (let id5 of ids) {
10820
- let owner = await this.lock("deferred-dispatch-" + id5 + ".lockdir").acquire();
10821
- try {
10822
- await this.withStore(async (key) => {
10823
- let row3 = await read(id5, key);
10824
- if (row3) {
10825
- if (!deferredScopeMatches(row3, scope)) return invalid7();
10826
- if (!row3.entries.some((entry5) => entry5.notice)) {
10827
- if (this.options.assertAccount(), !await owner.reassertOwnership()) throw new SyncJournalError("SYNC_JOURNAL_LOCK_LOST");
10828
- await import_node_fs5.promises.unlink(this.file(id5, ".deferred")), await this.syncDirectory(this.directory), removed++;
10829
- }
10830
- }
10831
- });
10832
- } finally {
10833
- await owner.release();
10834
- }
10835
- }
10900
+ for (let id5 of ids)
10901
+ await this.removeBookkeepingRecord(id5, ".deferred", ["deferred-dispatch-" + id5 + ".lockdir"], async (key) => {
10902
+ let row3 = await read(id5, key);
10903
+ return row3 ? deferredScopeMatches(row3, scope) ? !row3.entries.some((entry5) => entry5.notice) : invalid7() : !1;
10904
+ }) && removed++;
10836
10905
  return removed;
10837
10906
  }
10838
10907
  /** One small encrypted row for unresolved inbound inputs. Completed cloud
@@ -10882,23 +10951,30 @@ var sourceCursorId = (scope, stream) => stableUuid("codevibe-sync-source-cursor-
10882
10951
  let scope = this.sessionScope;
10883
10952
  if (!scope) return invalid7();
10884
10953
  let id5 = stableUuid("codevibe-sync-inbound-v1\0", [scope.sessionId, scope.sessionGenerationId]);
10954
+ return this.removeBookkeepingRecord(id5, ".inbox", [`inbound-dispatch-${id5}.lockdir`, `inbound-record-${id5}.lockdir`], async (key) => {
10955
+ let row3 = await this.readValue(id5, key, ".inbox", decodeDesktopInbound);
10956
+ return row3 ? row3.operationId !== id5 ? invalid7() : (this.requireScope(row3), !0) : !1;
10957
+ });
10958
+ }
10959
+ /** The encrypted record is also the recovery index for these outer locks.
10960
+ * Release them strictly BEFORE unlinking it, while the store stays fenced.
10961
+ * A failed release preserves the record and the caller's retirement intent. */
10962
+ async removeBookkeepingRecord(id5, suffix, names, removable) {
10885
10963
  this.options.assertAccount(), await this.ensureDirectory();
10886
- let dispatch = await this.lock(`inbound-dispatch-${id5}.lockdir`).acquire();
10964
+ let owners = [], release = async () => {
10965
+ let failed = (await Promise.allSettled(owners.splice(0).reverse().map((owner) => owner.release()))).find((result) => result.status === "rejected");
10966
+ if (failed?.status === "rejected") throw failed.reason;
10967
+ };
10887
10968
  try {
10888
- let record2 = await this.lock(`inbound-record-${id5}.lockdir`).acquire();
10889
- try {
10890
- return await this.withStore(async (key) => {
10891
- let row3 = await this.readValue(id5, key, ".inbox", decodeDesktopInbound);
10892
- if (!row3) return !1;
10893
- if (row3.operationId !== id5) return invalid7();
10894
- if (this.requireScope(row3), this.options.assertAccount(), !await dispatch.reassertOwnership() || !await record2.reassertOwnership()) throw new SyncJournalError("SYNC_JOURNAL_LOCK_LOST");
10895
- return await import_node_fs5.promises.unlink(this.file(id5, ".inbox")), await this.syncDirectory(this.directory), !0;
10896
- });
10897
- } finally {
10898
- await record2.release();
10899
- }
10969
+ for (let name of names) owners.push(await this.lock(name, !0).acquire());
10970
+ return await this.withStore(async (key, storeFence) => {
10971
+ let remove = await removable(key);
10972
+ this.options.assertAccount();
10973
+ for (let owner of owners) if (!await owner.reassertOwnership()) throw new SyncJournalError("SYNC_JOURNAL_LOCK_LOST");
10974
+ return await release(), await storeFence(), remove ? (await import_node_fs5.promises.unlink(this.file(id5, suffix)), await this.syncDirectory(this.directory), await storeFence(), !0) : !1;
10975
+ });
10900
10976
  } finally {
10901
- await dispatch.release();
10977
+ await release();
10902
10978
  }
10903
10979
  }
10904
10980
  /** Exact empty-source GC only after the owner has joined all its emitters
@@ -10957,7 +11033,34 @@ var sourceCursorId = (scope, stream) => stableUuid("codevibe-sync-source-cursor-
10957
11033
  if (errorCode(error) !== "ENOENT") throw error;
10958
11034
  return this.options.assertAccount(), !1;
10959
11035
  }
10960
- return this.withStore(async (key) => (await this.retiredSourcePlan(key, expectedSessionKeyGen)).sources.length > 0);
11036
+ return await this.withStore(async (key) => (await this.retiredSourcePlan(key, expectedSessionKeyGen)).sources.length > 0) ? !0 : this.hasSessionRegistrationState();
11037
+ }
11038
+ /** Presence is not deletion authority. Callers still need their joined
11039
+ * terminal owner and fresh retirement confirmation before cleanup. */
11040
+ async hasSessionRegistrationState() {
11041
+ if (!this.sessionScope) return invalid7();
11042
+ this.options.assertAccount();
11043
+ try {
11044
+ await import_node_fs5.promises.lstat(this.directory);
11045
+ } catch (error) {
11046
+ if (errorCode(error) !== "ENOENT") throw error;
11047
+ return this.options.assertAccount(), !1;
11048
+ }
11049
+ return this.withStore(async (key) => {
11050
+ let records = [
11051
+ [".desktop", (value) => decodeDesktopSyncRegistration(value, invalid7)],
11052
+ [".inbox", decodeDesktopInbound],
11053
+ [".retention", decodePromptRetention],
11054
+ [".echo", decodeMobileEcho],
11055
+ [".deferred", decodeDeferredInputs]
11056
+ ];
11057
+ for (let [suffix, decode] of records) for (let name of await this.recordNames(suffix)) {
11058
+ let row3 = await this.readValue(name.slice(0, -suffix.length), key, suffix, decode);
11059
+ if (!row3) return invalid7();
11060
+ if (this.matchesScope(row3)) return !0;
11061
+ }
11062
+ return !1;
11063
+ });
10961
11064
  }
10962
11065
  /** Durable stop/join intent -> confirmed source cleanup -> control ACKs ->
10963
11066
  * intent removal. Network I/O never holds the account-store lock. */
@@ -10991,7 +11094,7 @@ var sourceCursorId = (scope, stream) => stableUuid("codevibe-sync-source-cursor-
10991
11094
  if (!saved) return null;
10992
11095
  await fence();
10993
11096
  let result = await cleanup(saved, fence);
10994
- return await fence(), await this.withStore(async (key, storeFence) => {
11097
+ return await fence(), options.isComplete && !options.isComplete(result) || await this.withStore(async (key, storeFence) => {
10995
11098
  if (!await read(key)) throw new SyncJournalError("SYNC_JOURNAL_MISSING");
10996
11099
  await fence();
10997
11100
  let held = owner;
@@ -11883,23 +11986,24 @@ var UUID9 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f
11883
11986
  throw new SyncEventClientError("INVALID_SYNC_INPUT");
11884
11987
  };
11885
11988
  function toolWindow(scope, id5, value) {
11886
- let envelope = ToolActivityOutboxEnvelopeSchema.parse(value);
11887
- (id5 !== scope.sessionId || envelope.backendSessionId !== id5 || envelope.syncSessionGenerationId !== scope.sessionGenerationId || !/^[A-Za-z0-9_-]{1,128}$/.test(envelope.clientEventId) || !/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}Z$/.test(envelope.windowStart) || !Number.isFinite(Date.parse(envelope.windowStart)) || new Date(envelope.windowStart).toISOString() !== envelope.windowStart) && invalid8();
11989
+ let envelope = ToolActivityOutboxEnvelopeSchema.parse(value), timestamp5 = /^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\dZ$/.test(envelope.windowStart) ? envelope.windowStart.slice(0, -1) + ".000Z" : envelope.windowStart;
11990
+ (id5 !== scope.sessionId || envelope.backendSessionId !== id5 || envelope.syncSessionGenerationId !== scope.sessionGenerationId || !/^[A-Za-z0-9_-]{1,128}$/.test(envelope.clientEventId) || !/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{3}Z$/.test(timestamp5) || !Number.isFinite(Date.parse(timestamp5)) || new Date(timestamp5).toISOString() !== timestamp5) && invalid8();
11888
11991
  let bytes = (0, import_node_crypto16.createHash)("sha256").update("codevibe-sync-tool-window-v1\0").update(JSON.stringify([scope.sessionId, scope.sessionGenerationId, envelope.clientEventId])).digest().subarray(0, 16);
11889
11992
  bytes[6] = bytes[6] & 15 | 128, bytes[8] = bytes[8] & 63 | 128;
11890
11993
  let hex = bytes.toString("hex"), operationId2 = [hex.slice(0, 8), hex.slice(8, 12), hex.slice(12, 16), hex.slice(16, 20), hex.slice(20)].join("-");
11891
- return { envelope, operationId: operationId2 };
11994
+ return { envelope, operationId: operationId2, timestamp: timestamp5 };
11892
11995
  }
11893
11996
  async function retireToolActivityWindows(options) {
11894
11997
  let scope = { ...options.sessionScope };
11895
11998
  return await options.outbox.withRetirementSources(scope, async (sources) => {
11999
+ if (options.deferIfPaged && sources.hasMore) return { windowsRemoved: 0, operationsRemoved: 0, hasMore: !0 };
11896
12000
  let ids = sources.windows.map((window) => toolWindow(scope, scope.sessionId, window).operationId), operationsRemoved = await options.writer.removeRetiredToolOperations(
11897
12001
  ids,
11898
12002
  options.expectedSessionKeyGen,
11899
12003
  options.confirm,
11900
12004
  sources
11901
12005
  );
11902
- return { windowsRemoved: ids.length, operationsRemoved };
12006
+ return { windowsRemoved: ids.length, operationsRemoved, ...sources.hasMore && { hasMore: !0 } };
11903
12007
  }) ?? { windowsRemoved: 0, operationsRemoved: 0 };
11904
12008
  }
11905
12009
  function createToolActivitySyncTransport(options) {
@@ -11910,7 +12014,7 @@ function createToolActivitySyncTransport(options) {
11910
12014
  protocol: "SYNC_V2",
11911
12015
  sessionGenerationId: scope.sessionGenerationId,
11912
12016
  send: async (id5, value) => {
11913
- let { envelope, operationId: operationId2 } = window(id5, value);
12017
+ let { envelope, operationId: operationId2, timestamp: timestamp5 } = window(id5, value);
11914
12018
  try {
11915
12019
  return await writer.retry(operationId2);
11916
12020
  } catch (error) {
@@ -11923,7 +12027,7 @@ function createToolActivitySyncTransport(options) {
11923
12027
  ...scope,
11924
12028
  clientOperationId: operationId2,
11925
12029
  type: "TOOL_ACTIVITY",
11926
- timestamp: envelope.windowStart,
12030
+ timestamp: timestamp5,
11927
12031
  expectedSessionKeyGen: context.sessionKeyGen ?? SESSION_KEY_GEN_ABSENT_SENTINEL,
11928
12032
  isEncrypted: !0,
11929
12033
  encryptionVersion: 1,
@@ -12251,6 +12355,18 @@ var ToolActivityLedger = class {
12251
12355
  async markRetired(clientEventId, invocationIds) {
12252
12356
  return this.markSettled(clientEventId, invocationIds, "terminal", !0);
12253
12357
  }
12358
+ /** One durable mutation per bounded retirement page, not per window. */
12359
+ async markRetiredWindows(windows) {
12360
+ let ids = new Set(windows.map((window) => window.clientEventId));
12361
+ await this.mutateAndPersist((next, terminalWindows) => {
12362
+ for (let window of windows) {
12363
+ terminalWindows.add(window.clientEventId);
12364
+ for (let id5 of window.invocationIds) id5 && !next.has(id5) && next.set(id5, { clientEventId: window.clientEventId, byteOffset: 0, state: "terminal" });
12365
+ }
12366
+ for (let [id5, entry5] of next) ids.has(entry5.clientEventId) && entry5.state === "durably-outboxed" && next.set(id5, { ...entry5, state: "terminal" });
12367
+ return !0;
12368
+ }, !0);
12369
+ }
12254
12370
  /** R2 keeps a window settlement independently of occurrence remapping/pruning. */
12255
12371
  async markSettled(clientEventId, invocationIds, disposition, requireDirectorySync = !1) {
12256
12372
  await this.mutateAndPersist((next, terminalWindows) => {
@@ -12464,7 +12580,7 @@ var RESERVED_STATE_FILES = /* @__PURE__ */ new Set(["ledger.json", "legacy-owned
12464
12580
  }
12465
12581
  /** Trusted local namespace persisted inside the encrypted cleanup intent. */
12466
12582
  retirementLocation() {
12467
- if (this.agent !== "codex" && this.agent !== "claude") throw new Error("Invalid tool sync provider");
12583
+ if (!["codex", "claude", "agy"].includes(this.agent)) throw new Error("Invalid tool sync provider");
12468
12584
  return Object.freeze({ agent: this.agent, root: path21.resolve(this.rootDir) });
12469
12585
  }
12470
12586
  entryPath(sessionId, clientEventId) {
@@ -12578,23 +12694,25 @@ var RESERVED_STATE_FILES = /* @__PURE__ */ new Set(["ledger.json", "legacy-owned
12578
12694
  throw new Error("Invalid tool sync generation");
12579
12695
  let { sessionId, sessionGenerationId } = scope;
12580
12696
  return this.withSyncRecovery(sessionId, async (fence) => {
12581
- let dir = this.sessionDir(sessionId), snapshots = [], names = 0, bytes = 0, windows = 0, listing = await import_node_fs8.promises.opendir(dir);
12697
+ let dir = this.sessionDir(sessionId), snapshots = [], bytes = 0, hasMore = !1, listing = await import_node_fs8.promises.opendir(dir);
12582
12698
  for await (let entry5 of listing) {
12583
- if (++names > 1032) throw new Error("Tool sync outbox capacity exceeded");
12584
12699
  if (entry5.name.endsWith(".corrupt")) throw new Error("Tool sync outbox recovery required");
12585
12700
  if (entry5.name.includes(TEMP_INFIX) || RESERVED_STATE_FILES.has(entry5.name) || !entry5.name.endsWith(".json")) continue;
12586
- if (++windows > 256) throw new Error("Tool sync outbox capacity exceeded");
12587
- let file = await readBoundedToolFile(path21.join(dir, entry5.name), 1024 * 1024);
12588
- if (bytes += file.bytes.length, bytes > 32 * 1024 * 1024) throw new Error("Tool sync outbox capacity exceeded");
12589
- let envelope = ToolActivityOutboxEnvelopeSchema.parse(JSON.parse(file.bytes.toString("utf8")));
12701
+ let file = await readBoundedToolFile(path21.join(dir, entry5.name), 1024 * 1024), envelope = ToolActivityOutboxEnvelopeSchema.parse(JSON.parse(file.bytes.toString("utf8")));
12590
12702
  if (envelope.backendSessionId !== sessionId || !/^[A-Za-z0-9_-]{1,128}$/.test(envelope.clientEventId) || entry5.name !== `${envelope.clientEventId}.json`) throw new Error("Tool sync outbox recovery required");
12591
- envelope.syncSessionGenerationId === sessionGenerationId && snapshots.push({
12592
- name: entry5.name,
12593
- dev: file.dev,
12594
- ino: file.ino,
12595
- sha256: (0, import_node_crypto17.createHash)("sha256").update(file.bytes).digest("hex"),
12596
- envelope
12597
- });
12703
+ if (envelope.syncSessionGenerationId === sessionGenerationId) {
12704
+ if (snapshots.length >= 256 || bytes + file.bytes.length > 32 * 1024 * 1024) {
12705
+ hasMore = !0;
12706
+ break;
12707
+ }
12708
+ bytes += file.bytes.length, snapshots.push({
12709
+ name: entry5.name,
12710
+ dev: file.dev,
12711
+ ino: file.ino,
12712
+ sha256: (0, import_node_crypto17.createHash)("sha256").update(file.bytes).digest("hex"),
12713
+ envelope
12714
+ });
12715
+ }
12598
12716
  }
12599
12717
  if (!snapshots.length) return null;
12600
12718
  let ledger = new ToolActivityLedger({ agent: this.agent, sessionId, root: this.rootDir, logger: this.logger });
@@ -12608,10 +12726,9 @@ var RESERVED_STATE_FILES = /* @__PURE__ */ new Set(["ledger.json", "legacy-owned
12608
12726
  };
12609
12727
  return action2({
12610
12728
  windows: snapshots.map((snapshot2) => snapshot2.envelope),
12729
+ hasMore,
12611
12730
  markRetired: async () => {
12612
- await verify();
12613
- for (let { envelope } of snapshots)
12614
- await fence(), await ledger.markRetired(envelope.clientEventId, envelope.invocationIds);
12731
+ await verify(), await ledger.markRetiredWindows(snapshots.map((snapshot2) => snapshot2.envelope));
12615
12732
  },
12616
12733
  prune: async () => {
12617
12734
  await verify();
@@ -14396,6 +14513,13 @@ var AppSyncClient = class _AppSyncClient {
14396
14513
  async retireDesktopSyncRegistration(options, retired) {
14397
14514
  let userId = this.getCurrentUserId();
14398
14515
  if (this.assertSyncAccount(userId), !retired || retired.userId !== userId || retired.sessionId !== options.sessionId || retired.status !== "INACTIVE" /* INACTIVE */ || retired.sessionGenerationId !== options.sessionGenerationId) throw new SyncEventClientError("SYNC_SESSION_UNAVAILABLE");
14516
+ return this.removeDesktopSyncRegistrationState(options);
14517
+ }
14518
+ /** Both callers have terminal authority and have joined their read owners:
14519
+ * the returned INACTIVE session above, or a freshly confirmed durable intent. */
14520
+ async removeDesktopSyncRegistrationState(options) {
14521
+ let userId = this.getCurrentUserId();
14522
+ this.assertSyncAccount(userId);
14399
14523
  let writer = this.desktopSyncWriter({ root: options.root, sessionScope: options }), result = await writer.removeDesktopRegistration();
14400
14524
  return await writer.removeInbound(), await writer.removeDeferredInputs(), await writer.removeMobileEchoes(), await writer.promptRetention().remove(), this.assertSyncAccount(userId), result;
14401
14525
  }
@@ -14830,7 +14954,7 @@ var AppSyncClient = class _AppSyncClient {
14830
14954
  return this.resolvePromptPublication({ sessionId: input.sessionId, promptId: input.promptId }, async () => (await fence(), _AppSyncClient.throwIfAborted(signal), await this.resolveDesktopSyncPrompt(input, signal), await fence(), !0), { ...options, signal });
14831
14955
  }
14832
14956
  /** Explicit session-owned restart recovery. Inventory is bounded by the
14833
- * account store's 256-file cap; empty inventory does no cloud I/O. Reuses
14957
+ * account store's file cap; empty inventory does no cloud I/O. Reuses
14834
14958
  * original ownership/generation, not current Session or encryption state.
14835
14959
  * No failure/age/quota condition deletes an outstanding intent. */
14836
14960
  recoverPromptResolutions(options, signal) {
@@ -14945,7 +15069,18 @@ var AppSyncClient = class _AppSyncClient {
14945
15069
  }), toolOutbox = options.toolOutbox?.retirementLocation() ?? null;
14946
15070
  await this.quiesceDesktopSyncSession(sessionId, quiesce, signal);
14947
15071
  let writer = this.desktopSyncWriter({ root, sessionScope: input }), hasWork = await writer.hasSessionRetirementWork(input.expectedSessionKeyGen) || options.toolOutbox && await options.toolOutbox.withRetirementSources(input, async () => !0);
14948
- return this.assertSyncAccount(userId), _AppSyncClient.throwIfAborted(signal), hasWork ? await writer.runSessionRetirement(input, toolOutbox, (record2, fence) => this.finishRecordedSessionRetirement(record2, { root }, fence, signal)) ?? { sourcesRemoved: 0, operationsRemoved: 0 } : { sourcesRemoved: 0, operationsRemoved: 0 };
15072
+ if (this.assertSyncAccount(userId), _AppSyncClient.throwIfAborted(signal), !hasWork) return { sourcesRemoved: 0, operationsRemoved: 0 };
15073
+ let result = await writer.runSessionRetirement(
15074
+ input,
15075
+ toolOutbox,
15076
+ (record2, fence) => this.finishRecordedSessionRetirement(record2, { root, deferOversizedTools: !0 }, fence, signal),
15077
+ { isComplete: (result2) => !result2.cleanupDeferred }
15078
+ );
15079
+ return result?.cleanupDeferred && logger.warn("[sync-retirement] cloud session retired; local cleanup page remains durable", {
15080
+ sessionId,
15081
+ sourcesRemoved: result.sourcesRemoved,
15082
+ operationsRemoved: result.operationsRemoved
15083
+ }), result ?? { sourcesRemoved: 0, operationsRemoved: 0 };
14949
15084
  }
14950
15085
  /** No Session fetch, live key lookup, native-process operation or re-homing.
14951
15086
  * The encrypted intent records a completed producer join; fresh cloud proof
@@ -14959,7 +15094,12 @@ var AppSyncClient = class _AppSyncClient {
14959
15094
  try {
14960
15095
  let writer = this.desktopSyncWriter({ root, sessionScope: record2.input });
14961
15096
  await this.quiesceDesktopSyncSession(record2.input.sessionId, async () => {
14962
- }, signal), await writer.runSessionRetirement(record2.input, record2.toolOutbox, (saved, fence) => this.finishRecordedSessionRetirement(saved, { root }, fence, signal), { existingOnly: !0 }), completed++;
15097
+ }, signal), (await writer.runSessionRetirement(
15098
+ record2.input,
15099
+ record2.toolOutbox,
15100
+ (saved, fence) => this.finishRecordedSessionRetirement(saved, { root }, fence, signal),
15101
+ { existingOnly: !0, isComplete: (result2) => !result2.cleanupDeferred }
15102
+ ))?.cleanupDeferred ? deferred++ : completed++;
14963
15103
  } catch (error) {
14964
15104
  this.assertSyncAccount(userId), _AppSyncClient.throwIfAborted(signal), deferred++, logger.warn("[sync-retirement] prior-session cleanup retained for recovery", {
14965
15105
  code: error instanceof SyncJournalError ? error.code : "CLEANUP_DEFERRED"
@@ -14985,12 +15125,12 @@ var AppSyncClient = class _AppSyncClient {
14985
15125
  await work, this.assertSyncAccount(userId), _AppSyncClient.throwIfAborted(signal);
14986
15126
  }
14987
15127
  async finishRecordedSessionRetirement(record2, options, fence, signal) {
14988
- let { input } = record2, { root } = options, userId = this.getCurrentUserId(), writer = this.desktopSyncWriter({ root, sessionScope: input });
15128
+ let { input } = record2, { root } = options, userId = this.getCurrentUserId(), writer = this.desktopSyncWriter({ root, sessionScope: input }), confirmed = !1, confirm = async (request3) => {
15129
+ let receipt2 = await this.confirmDesktopSyncRetirement(request3, signal);
15130
+ return confirmed = !0, receipt2;
15131
+ };
14989
15132
  await fence(), _AppSyncClient.throwIfAborted(signal);
14990
- let result = await writer.removeRetiredSources(
14991
- input.expectedSessionKeyGen,
14992
- (request3) => this.confirmDesktopSyncRetirement(request3, signal)
14993
- );
15133
+ let result = await writer.removeRetiredSources(input.expectedSessionKeyGen, confirm), cleanupDeferred = !1;
14994
15134
  if (record2.toolOutbox) {
14995
15135
  await fence();
14996
15136
  let tools = await retireToolActivityWindows({
@@ -14998,13 +15138,14 @@ var AppSyncClient = class _AppSyncClient {
14998
15138
  writer,
14999
15139
  outbox: new ToolActivityOutbox({ ...record2.toolOutbox, logger }),
15000
15140
  expectedSessionKeyGen: input.expectedSessionKeyGen,
15001
- confirm: (input2) => this.confirmDesktopSyncRetirement(input2, signal)
15141
+ confirm,
15142
+ deferIfPaged: options.deferOversizedTools
15002
15143
  });
15003
- result.sourcesRemoved += tools.windowsRemoved, result.operationsRemoved += tools.operationsRemoved;
15144
+ result.sourcesRemoved += tools.windowsRemoved, result.operationsRemoved += tools.operationsRemoved, cleanupDeferred = tools.hasMore === !0;
15004
15145
  }
15005
15146
  for (let input2 of await writer.promptResolutions())
15006
15147
  await fence(), this.assertSyncAccount(userId), _AppSyncClient.throwIfAborted(signal), await writer.runPromptResolution(input2, async (saved, fence2) => (await fence2(), await this.resolveDesktopSyncPrompt(saved, signal), await fence2(), !0), { existingOnly: !0 });
15007
- return await fence(), this.assertSyncAccount(userId), _AppSyncClient.throwIfAborted(signal), result;
15148
+ return await fence(), this.assertSyncAccount(userId), _AppSyncClient.throwIfAborted(signal), await writer.hasSessionRegistrationState() && (confirmed || await confirm(input), await fence(), _AppSyncClient.throwIfAborted(signal), await this.removeDesktopSyncRegistrationState({ ...input, root })), await fence(), this.assertSyncAccount(userId), _AppSyncClient.throwIfAborted(signal), { ...result, ...cleanupDeferred && { cleanupDeferred: !0 } };
15008
15149
  }
15009
15150
  /** Wire-only PROMPT_OWNERSHIP transition. It cannot create an Event. Plugin
15010
15151
  * preimage authority does not require the retired Session's encryption key;
@@ -60353,7 +60494,8 @@ ${formatPacket(packet, hash3)}`
60353
60494
  }
60354
60495
 
60355
60496
  // src/orchestration-shell/audit-summary.ts
60356
- var crypto27 = __toESM(require("node:crypto")), MAX_SUMMARY_BYTES = 16384, FIELD_MAX_CHARS = 512, MAX_SEATS_PER_MODEL = 10, MAX_FINDINGS_PER_MODEL = 20, MAX_RESIDUALS_PER_RECORD = 10;
60497
+ var crypto27 = __toESM(require("node:crypto"));
60498
+ var MAX_SUMMARY_BYTES = 16384, FIELD_MAX_CHARS = 512, MAX_SEATS_PER_MODEL = 10, MAX_FINDINGS_PER_MODEL = 20, MAX_RESIDUALS_PER_RECORD = 10;
60357
60499
  var SECTION_BYTE_BUDGETS = {
60358
60500
  section1: 1800,
60359
60501
  section2: 7500,
@@ -60441,7 +60583,7 @@ function boundSummaryModel(model) {
60441
60583
  role: capCodePoints(s.role, 64),
60442
60584
  reviewerModel: capCodePoints(s.reviewerModel, 64),
60443
60585
  reviewerAgent: capCodePoints(s.reviewerAgent, 64),
60444
- modelUsed: capCodePoints(s.modelUsed, 64),
60586
+ modelUsed: s.modelUsed ? capCodePoints(s.modelUsed, 64) : void 0,
60445
60587
  verdict: capCodePoints(s.verdict, 32),
60446
60588
  reasoning: capCodePoints(s.reasoning, FIELD_MAX_CHARS),
60447
60589
  durationSeconds: typeof s.durationSeconds == "number" ? s.durationSeconds : null,
@@ -60462,8 +60604,8 @@ function boundSummaryModel(model) {
60462
60604
  testDetails: capCodePoints(model.verification?.testDetails, FIELD_MAX_CHARS),
60463
60605
  teardownStatus: model.verification?.teardownStatus ?? "unrecorded",
60464
60606
  filesApplied: typeof model.verification?.filesApplied == "number" ? model.verification.filesApplied : void 0,
60465
- completedAt: capCodePoints(model.verification?.completedAt, 64),
60466
- serverAuthorizedAt: capCodePoints(model.verification?.serverAuthorizedAt, 64),
60607
+ completedAt: model.verification?.completedAt ? capCodePoints(model.verification.completedAt, 64) : void 0,
60608
+ serverAuthorizedAt: model.verification?.serverAuthorizedAt ? capCodePoints(model.verification.serverAuthorizedAt, 64) : void 0,
60467
60609
  workspaceApplicationStatus: model.verification?.workspaceApplicationStatus
60468
60610
  }
60469
60611
  };
@@ -61141,11 +61283,13 @@ function compileAuditSummary(args) {
61141
61283
  let displayRound = rec.round + 1;
61142
61284
  rec.historyDegraded && (historyDegraded = !0), rec.omittedFindingsCount && (recordOmittedFindings += rec.omittedFindingsCount), rec.omittedResidualsCount && (recordOmittedResiduals += rec.omittedResidualsCount);
61143
61285
  let dur = typeof rec.durationSeconds == "number" ? rec.durationSeconds : typeof rec.latencyMs == "number" ? rec.latencyMs / 1e3 : null;
61144
- dur !== null ? totalReviewerSeconds += dur : (timingPartial = !0, roundTimingPartial[displayRound] = !0), dur !== null && (roundDurations[displayRound] = Math.max(roundDurations[displayRound] ?? 0, dur)), seats.push({
61286
+ dur !== null ? totalReviewerSeconds += dur : (timingPartial = !0, roundTimingPartial[displayRound] = !0), dur !== null && (roundDurations[displayRound] = Math.max(roundDurations[displayRound] ?? 0, dur));
61287
+ let agentKey = rec.reviewerAgent ? rec.reviewerAgent.toUpperCase() : void 0, detectedDefault = agentKey && args.detectedAgentModels ? args.detectedAgentModels[agentKey] || args.detectedAgentModels[rec.reviewerAgent.toLowerCase()] || args.detectedAgentModels[rec.reviewerAgent] : void 0, displayModel;
61288
+ rec.modelUsed && rec.modelUsed.trim() ? displayModel = rec.modelUsed.trim() : detectedDefault && detectedDefault.trim() ? displayModel = `native default (unverified: ${detectedDefault.trim()})` : displayModel = "native default (unverified)", seats.push({
61145
61289
  round: displayRound,
61146
61290
  seatId: String(rec.seatId),
61147
61291
  role: rec.role,
61148
- reviewerModel: rec.modelUsed || rec.reviewerAgent,
61292
+ reviewerModel: displayModel,
61149
61293
  reviewerAgent: rec.reviewerAgent,
61150
61294
  modelUsed: rec.modelUsed ?? void 0,
61151
61295
  verdict: normalizeVerdictKind(rec.verdict),
@@ -61157,7 +61301,7 @@ function compileAuditSummary(args) {
61157
61301
  findings.push({
61158
61302
  round: displayRound,
61159
61303
  seatId: String(rec.seatId),
61160
- findingId: `F-${displayRound}-${rec.seatId}-${idx + 1}`,
61304
+ findingId: `F-${displayRound}-${displaySeatNumber(rec.seatId)}-${idx + 1}`,
61161
61305
  issue: sc,
61162
61306
  changesMade: "Unavailable (resolution not recorded)"
61163
61307
  });
@@ -61246,13 +61390,15 @@ function compileAuditSummary(args) {
61246
61390
  let maxSeatDur = 0;
61247
61391
  for (let [seatId, s] of gate.seats.entries()) {
61248
61392
  let dur = typeof s.durationSeconds == "number" ? s.durationSeconds : null;
61249
- dur !== null ? (totalReviewerSeconds += dur, maxSeatDur = Math.max(maxSeatDur, dur)) : (timingPartial = !0, roundTimingPartial[gate.roundNumber] = !0), seats.push({
61393
+ dur !== null ? (totalReviewerSeconds += dur, maxSeatDur = Math.max(maxSeatDur, dur)) : (timingPartial = !0, roundTimingPartial[gate.roundNumber] = !0);
61394
+ let agentKey = s.reviewerAgent ? s.reviewerAgent.toUpperCase() : void 0, detectedDefault = agentKey && args.detectedAgentModels ? args.detectedAgentModels[agentKey] || args.detectedAgentModels[s.reviewerAgent?.toLowerCase() ?? ""] || args.detectedAgentModels[s.reviewerAgent ?? ""] : void 0, displayModel;
61395
+ s.modelUsed && s.modelUsed.trim() ? displayModel = s.modelUsed.trim() : s.reviewerModel && s.reviewerModel !== "unknown" && s.reviewerModel !== s.reviewerAgent ? displayModel = s.reviewerModel : detectedDefault && detectedDefault.trim() ? displayModel = `native default (unverified: ${detectedDefault.trim()})` : displayModel = "native default (unverified)", seats.push({
61250
61396
  round: gate.roundNumber,
61251
61397
  seatId: s.seatId,
61252
61398
  role: s.role,
61253
- reviewerModel: s.reviewerModel,
61399
+ reviewerModel: displayModel,
61254
61400
  reviewerAgent: s.reviewerAgent,
61255
- modelUsed: s.modelUsed,
61401
+ modelUsed: s.modelUsed ?? void 0,
61256
61402
  verdict: s.verdict,
61257
61403
  reasoning: s.reasoning,
61258
61404
  durationSeconds: dur,
@@ -61357,16 +61503,16 @@ function renderSummaryMarkdown(summaryModel) {
61357
61503
  else {
61358
61504
  let tableHeader = `| Round | Seat | Role | Agent | Model | Verdict | Duration |
61359
61505
  |-------|------|------|-------|-------|---------|----------|`, tableRows = bounded.seats.map((s) => {
61360
- let durStr = typeof s.durationSeconds == "number" ? `${s.durationSeconds.toFixed(1)}s` : "N/A";
61361
- return `| ${s.round} | ${escapeMarkdownTableCell(s.seatId)} | ${escapeMarkdownTableCell(s.role)} | ${escapeMarkdownTableCell(s.reviewerAgent ?? s.role)} | ${escapeMarkdownTableCell(s.reviewerModel)} | ${escapeMarkdownTableCell(s.verdict)} | ${durStr} |`;
61506
+ let durStr = typeof s.durationSeconds == "number" ? `${s.durationSeconds.toFixed(1)}s` : "N/A", displaySeat = displaySeatNumber(s.seatId);
61507
+ return `| ${s.round} | ${escapeMarkdownTableCell(displaySeat)} | ${escapeMarkdownTableCell(s.role)} | ${escapeMarkdownTableCell(s.reviewerAgent ?? s.role)} | ${escapeMarkdownTableCell(s.reviewerModel)} | ${escapeMarkdownTableCell(s.verdict)} | ${durStr} |`;
61362
61508
  });
61363
61509
  s2 = [tableHeader, ...tableRows].join(`
61364
61510
  `);
61365
61511
  }
61366
61512
  let s3 = "";
61367
61513
  bounded.findings.length === 0 ? s3 = "None recorded." : s3 = bounded.findings.map((f) => {
61368
- let resolution = f.changesMade ? sanitizeMarkdownContent(f.changesMade) : "Unavailable (resolution not recorded)", safeFindingId = String(f.findingId).replace(/[\r\n]+/g, " ").replace(/`/g, "'").trim(), safeSeatId = String(f.seatId).replace(/[\r\n]+/g, " ").replace(/`/g, "'").trim();
61369
- return `- **[Round ${f.round} / Seat ${escapeMarkdownTableCell(safeSeatId)}]** \`${safeFindingId}\`: ${sanitizeMarkdownContent(f.issue)} -> ${resolution}`;
61514
+ let resolution = f.changesMade ? sanitizeMarkdownContent(f.changesMade) : "Unavailable (resolution not recorded)", safeFindingId = String(f.findingId).replace(/[\r\n]+/g, " ").replace(/`/g, "'").trim(), safeSeatId = String(f.seatId).replace(/[\r\n]+/g, " ").replace(/`/g, "'").trim(), displaySeat = displaySeatNumber(safeSeatId);
61515
+ return `- **[Round ${f.round} / Seat ${escapeMarkdownTableCell(displaySeat)}]** \`${safeFindingId}\`: ${sanitizeMarkdownContent(f.issue)} -> ${resolution}`;
61370
61516
  }).join(`
61371
61517
  `);
61372
61518
  let roundTimes = /* @__PURE__ */ new Map(), roundHasPartial = /* @__PURE__ */ new Map();
@@ -64765,7 +64911,8 @@ var QuorumLoop = class _QuorumLoop {
64765
64911
  * Enables reconciliation if a user decision arrives or is replayed after promotion.
64766
64912
  */
64767
64913
  this.completedTaskSummaries = /* @__PURE__ */ new Map();
64768
- this.expectedRosterByTask = /* @__PURE__ */ new Map();
64914
+ this.declaredRosterByTask = /* @__PURE__ */ new Map();
64915
+ this.dispatchedRosterByTask = /* @__PURE__ */ new Map();
64769
64916
  this.taskDegradedMetadataByTask = /* @__PURE__ */ new Map();
64770
64917
  /**
64771
64918
  * A1b — the implementor's own per-round stdout rationale (the
@@ -65325,6 +65472,7 @@ var QuorumLoop = class _QuorumLoop {
65325
65472
  } catch {
65326
65473
  }
65327
65474
  }
65475
+ /** @internal */
65328
65476
  recordCompletedTaskSummary(taskId, info) {
65329
65477
  try {
65330
65478
  this.withCompletedSummariesLock(() => {
@@ -66074,6 +66222,25 @@ var QuorumLoop = class _QuorumLoop {
66074
66222
  }
66075
66223
  return out;
66076
66224
  }
66225
+ getDetectedModelForAgent(agent) {
66226
+ if (!agent) return null;
66227
+ let up = agent.toUpperCase(), low = agent.toLowerCase(), models = this.deps.detectedAgentModels;
66228
+ if (models) {
66229
+ if (models[up]) return models[up];
66230
+ if (models[low]) return models[low];
66231
+ }
66232
+ return null;
66233
+ }
66234
+ getExplicitModelForAgent(agent) {
66235
+ if (!agent) return null;
66236
+ let up = agent.toUpperCase(), low = agent.toLowerCase(), models = this.deps.configuredAgentModels;
66237
+ if (models) {
66238
+ if (models[up]) return models[up];
66239
+ if (models[low]) return models[low];
66240
+ if (models[agent]) return models[agent];
66241
+ }
66242
+ return null;
66243
+ }
66077
66244
  /**
66078
66245
  * #585 auto-continuation (Max) — pick the agent to AUTO-CONTINUE on when the
66079
66246
  * implementor for `taskId` hit a quota wall, or `null` to fall through to the
@@ -66349,8 +66516,8 @@ var QuorumLoop = class _QuorumLoop {
66349
66516
  async handleGateDispatch(payload, envelopeTaskId) {
66350
66517
  let dispatchTaskId = envelopeTaskId || this.latestInFlightStart;
66351
66518
  if (dispatchTaskId && Array.isArray(payload.reviewerSeats) && payload.reviewerSeats.length > 0) {
66352
- let roster = this.expectedRosterByTask.get(dispatchTaskId);
66353
- roster || (roster = /* @__PURE__ */ new Map(), this.expectedRosterByTask.set(dispatchTaskId, roster));
66519
+ let roster = this.declaredRosterByTask.get(dispatchTaskId);
66520
+ roster || (roster = /* @__PURE__ */ new Map(), this.declaredRosterByTask.set(dispatchTaskId, roster));
66354
66521
  for (let seat of payload.reviewerSeats)
66355
66522
  roster.set(String(seat.seatId), String(seat.role || "reviewer").toLowerCase());
66356
66523
  }
@@ -66789,7 +66956,7 @@ var QuorumLoop = class _QuorumLoop {
66789
66956
  if (!stale) return;
66790
66957
  await stale.assertCanDiscard(), logger.info("[QuorumLoop] replacing a stale shadow for a fresh round-0 dispatch (restart)", {
66791
66958
  taskId
66792
- }), await stale.discard(), this.shadowsByTask.get(taskId) === stale && this.shadowsByTask.delete(taskId), this.userNotesByTask.delete(taskId), this.reviewScopeResetTasks.delete(taskId), this.roundHistoryByTask.delete(taskId), this.rationaleByTask.delete(taskId), this.taskDegradedMetadataByTask.delete(taskId), this.expectedRosterByTask.delete(taskId), this.clearSeenGateDispatchRunIdsForTask(taskId), this.activeGateByTaskId.delete(taskId), this.conflictedSeatsByTask.delete(taskId), this.nonApprovedSeatsByTask.delete(taskId);
66959
+ }), await stale.discard(), this.shadowsByTask.get(taskId) === stale && this.shadowsByTask.delete(taskId), this.userNotesByTask.delete(taskId), this.reviewScopeResetTasks.delete(taskId), this.roundHistoryByTask.delete(taskId), this.rationaleByTask.delete(taskId), this.taskDegradedMetadataByTask.delete(taskId), this.declaredRosterByTask.delete(taskId), this.dispatchedRosterByTask.delete(taskId), this.clearSeenGateDispatchRunIdsForTask(taskId), this.activeGateByTaskId.delete(taskId), this.conflictedSeatsByTask.delete(taskId), this.nonApprovedSeatsByTask.delete(taskId);
66793
66960
  let nextFence = (this.restartFenceByTaskId.get(taskId) ?? 0) + 1;
66794
66961
  this.restartFenceByTaskId.set(taskId, nextFence), this.reviewedSnapshotByTask.delete(taskId);
66795
66962
  }
@@ -67733,14 +67900,16 @@ ${section}`);
67733
67900
  let completedInfo = this.getCompletedTaskSummary(taskId);
67734
67901
  if (completedInfo)
67735
67902
  try {
67736
- let summaryModel = compileAuditSummary({
67903
+ let d = decision?.decision?.toLowerCase(), isApprove = (d === "approve" || d === "accept") && decision?.isFinalApproval !== !1, isPendingMerge = completedInfo.workspaceApplicationStatus === "pending_merge_gate", summaryModel = compileAuditSummary({
67737
67904
  taskId,
67738
67905
  sessionId: this.deps.session.sessionId,
67739
67906
  historySnapshot: completedInfo.historySnapshot,
67740
67907
  userDecision: decision,
67741
67908
  filesApplied: completedInfo.filesApplied,
67742
67909
  completedAt: completedInfo.completedAt,
67743
- workspaceApplicationStatus: completedInfo.workspaceApplicationStatus
67910
+ serverAuthorizedAt: isApprove && !isPendingMerge ? decision?.serverRecordedAt ?? void 0 : void 0,
67911
+ workspaceApplicationStatus: completedInfo.workspaceApplicationStatus,
67912
+ detectedAgentModels: this.deps.detectedAgentModels
67744
67913
  }), markdown = renderSummaryMarkdown(summaryModel);
67745
67914
  try {
67746
67915
  this.deps.onTaskAuditSummary?.(summaryModel, markdown);
@@ -67795,17 +67964,23 @@ ${section}`);
67795
67964
  let records = this.roundHistoryByTask.get(taskId) ?? [], taskDegraded = this.taskDegradedMetadataByTask.get(taskId), historyDegraded = !!taskDegraded?.historyDegraded, omittedFindingsCount = taskDegraded?.omittedFindingsCount ?? 0, omittedResidualsCount = taskDegraded?.omittedResidualsCount ?? 0, omittedRounds = taskDegraded?.omittedRounds, truncatedForSize = taskDegraded?.truncatedForSize;
67796
67965
  for (let r of records)
67797
67966
  r.historyDegraded && (historyDegraded = !0), omittedFindingsCount += r.omittedFindingsCount ?? 0, omittedResidualsCount += r.omittedResidualsCount ?? 0;
67798
- let seatCount = this.deps.tier === "MAX" ? 3 : 2, rosterMap = this.expectedRosterByTask.get(taskId), expectedRosterMap = /* @__PURE__ */ new Map();
67799
- if (rosterMap && rosterMap.size > 0)
67800
- for (let [seatId, role] of rosterMap.entries())
67967
+ let declaredRoster = this.declaredRosterByTask.get(taskId), expectedRosterMap = /* @__PURE__ */ new Map();
67968
+ if (declaredRoster && declaredRoster.size > 0)
67969
+ for (let [seatId, role] of declaredRoster.entries())
67801
67970
  expectedRosterMap.set(seatId, role);
67802
- else
67971
+ else {
67803
67972
  for (let r of records)
67804
67973
  expectedRosterMap.set(String(r.seatId), String(r.role || "reviewer").toLowerCase());
67805
- let missingIdx = 0;
67806
- for (; expectedRosterMap.size < seatCount; ) {
67807
- let seatKey2 = `missing-seat-${missingIdx++}`;
67808
- expectedRosterMap.has(seatKey2) || expectedRosterMap.set(seatKey2, "required_seat_unassigned");
67974
+ let dispatched = this.dispatchedRosterByTask.get(taskId);
67975
+ if (dispatched)
67976
+ for (let [seatId, role] of dispatched.entries())
67977
+ expectedRosterMap.set(seatId, role);
67978
+ let minRequiredSeats = this.deps.tier === "FREE" ? 1 : 2, padIdx = 0;
67979
+ for (; expectedRosterMap.size < minRequiredSeats; ) {
67980
+ let syntheticSeat = String(padIdx);
67981
+ expectedRosterMap.has(syntheticSeat) || expectedRosterMap.set(syntheticSeat, "required_seat_unassigned"), padIdx++;
67982
+ }
67983
+ this.deps.tier !== "FREE" && expectedRosterMap.set("unverified_roster_declaration", "required_seat_unassigned");
67809
67984
  }
67810
67985
  let expectedRoster = Array.from(expectedRosterMap.entries()).map(([seatId, role]) => ({ seatId, role }));
67811
67986
  return {
@@ -67862,8 +68037,8 @@ ${section}`);
67862
68037
  ingestReviewSummary(taskId, summary) {
67863
68038
  if (!taskId || !summary || this.isWorkspaceTaskTerminallyRetired(taskId) || this.getCompletedTaskSummary(taskId))
67864
68039
  return;
67865
- let roster = this.expectedRosterByTask.get(taskId);
67866
- if (roster || (roster = /* @__PURE__ */ new Map(), this.expectedRosterByTask.set(taskId, roster)), summary.reviewQuorum && Array.isArray(summary.reviewQuorum.seats))
68040
+ let roster = this.declaredRosterByTask.get(taskId);
68041
+ if (roster || (roster = /* @__PURE__ */ new Map(), this.declaredRosterByTask.set(taskId, roster)), summary.reviewQuorum && Array.isArray(summary.reviewQuorum.seats))
67867
68042
  for (let s of summary.reviewQuorum.seats) {
67868
68043
  if (!s || s.seatId == null || String(s.seatId).trim().length === 0) continue;
67869
68044
  let seatIdStr = String(s.seatId).trim(), roleStr = String(s.role || "").trim().toLowerCase();
@@ -68304,7 +68479,7 @@ ${section}`);
68304
68479
  });
68305
68480
  return;
68306
68481
  }
68307
- if (opts?.preserveReviseContext || (this.userNotesByTask.delete(taskId), this.reviewScopeResetTasks.delete(taskId), this.reviewScopeResetEligibleTasks.delete(taskId), this.roundHistoryByTask.delete(taskId), opts?.taskContinues !== !0 && this.forgetSingleTask(taskId, "discarded"), this.rationaleByTask.delete(taskId), this.taskDegradedMetadataByTask.delete(taskId), this.expectedRosterByTask.delete(taskId), this.activeGateByTaskId.delete(taskId), this.conflictedSeatsByTask.delete(taskId), this.nonApprovedSeatsByTask.delete(taskId), this.restartFenceByTaskId.delete(taskId), appendContextItem(this.deps.session.sessionId, {
68482
+ if (opts?.preserveReviseContext || (this.userNotesByTask.delete(taskId), this.reviewScopeResetTasks.delete(taskId), this.reviewScopeResetEligibleTasks.delete(taskId), this.roundHistoryByTask.delete(taskId), opts?.taskContinues !== !0 && this.forgetSingleTask(taskId, "discarded"), this.rationaleByTask.delete(taskId), this.taskDegradedMetadataByTask.delete(taskId), this.declaredRosterByTask.delete(taskId), this.dispatchedRosterByTask.delete(taskId), this.activeGateByTaskId.delete(taskId), this.conflictedSeatsByTask.delete(taskId), this.nonApprovedSeatsByTask.delete(taskId), this.restartFenceByTaskId.delete(taskId), appendContextItem(this.deps.session.sessionId, {
68308
68483
  kind: "verdict",
68309
68484
  author: { role: "engine" },
68310
68485
  sensitivity: "user",
@@ -68513,7 +68688,7 @@ ${section}`);
68513
68688
  error: err?.message
68514
68689
  }), historySnapshot = null;
68515
68690
  }
68516
- this.userNotesByTask.delete(taskId), this.reviewScopeResetTasks.delete(taskId), this.reviewScopeResetEligibleTasks.delete(taskId), this.roundHistoryByTask.delete(taskId), this.forgetSingleTask(taskId, "apply_failed"), this.rationaleByTask.delete(taskId), this.taskDegradedMetadataByTask.delete(taskId), this.expectedRosterByTask.delete(taskId), this.activeGateByTaskId.delete(taskId), this.conflictedSeatsByTask.delete(taskId), this.nonApprovedSeatsByTask.delete(taskId), this.restartFenceByTaskId.delete(taskId);
68691
+ this.userNotesByTask.delete(taskId), this.reviewScopeResetTasks.delete(taskId), this.reviewScopeResetEligibleTasks.delete(taskId), this.roundHistoryByTask.delete(taskId), this.forgetSingleTask(taskId, "apply_failed"), this.rationaleByTask.delete(taskId), this.taskDegradedMetadataByTask.delete(taskId), this.declaredRosterByTask.delete(taskId), this.dispatchedRosterByTask.delete(taskId), this.activeGateByTaskId.delete(taskId), this.conflictedSeatsByTask.delete(taskId), this.nonApprovedSeatsByTask.delete(taskId), this.restartFenceByTaskId.delete(taskId);
68517
68692
  let shadow = this.shadowsByTask.get(taskId);
68518
68693
  if (!shadow) {
68519
68694
  if (this.singleTaskHistory.get(taskId)?.outcome === "discarded") {
@@ -68735,12 +68910,16 @@ ${section}`);
68735
68910
  }
68736
68911
  discarded && this.shadowsByTask.get(taskId) === shadow && this.shadowsByTask.delete(taskId), discarded && this.terminallyRetiredWorkspaceTasks.add(taskId), this.reviewedSnapshotByTask.delete(taskId);
68737
68912
  try {
68738
- let userDecision = this.lastUserDecisionByTask.get(taskId) ?? null, completedAt = (/* @__PURE__ */ new Date()).toISOString(), summaryModel = compileAuditSummary({
68913
+ let userDecision = this.lastUserDecisionByTask.get(taskId) ?? null, completedAt = (/* @__PURE__ */ new Date()).toISOString(), d = userDecision?.decision?.toLowerCase(), isApprove = d === "approve" || d === "accept", summaryModel = compileAuditSummary({
68739
68914
  taskId,
68740
68915
  sessionId: this.deps.session.sessionId,
68741
68916
  historySnapshot,
68742
68917
  userDecision,
68743
- workspaceApplicationStatus: "pending_merge_gate"
68918
+ completedAt,
68919
+ serverAuthorizedAt: void 0,
68920
+ // pending merge gate — unpromoted
68921
+ workspaceApplicationStatus: "pending_merge_gate",
68922
+ detectedAgentModels: this.deps.detectedAgentModels
68744
68923
  }), markdown = renderSummaryMarkdown(summaryModel);
68745
68924
  try {
68746
68925
  this.deps.onTaskAuditSummary?.(summaryModel, markdown);
@@ -68955,13 +69134,15 @@ ${section}`);
68955
69134
  }), onTaskBoundary(this.deps.session.sessionId).catch(() => {
68956
69135
  }), this.emitProgress({ phase: "promoted", files: appliedPaths.length, taskId }, originEpoch);
68957
69136
  try {
68958
- let userDecision = this.lastUserDecisionByTask.get(taskId) ?? null, completedAt = this.lastWorkspaceOutcome?.completedAt ?? (/* @__PURE__ */ new Date()).toISOString(), filesApplied = appliedPaths.length, summaryModel = compileAuditSummary({
69137
+ let userDecision = this.lastUserDecisionByTask.get(taskId) ?? null, completedAt = this.lastWorkspaceOutcome?.completedAt ?? (/* @__PURE__ */ new Date()).toISOString(), filesApplied = appliedPaths.length, d = userDecision?.decision?.toLowerCase(), isApprove = (d === "approve" || d === "accept") && userDecision?.isFinalApproval !== !1, summaryModel = compileAuditSummary({
68959
69138
  taskId,
68960
69139
  sessionId: this.deps.session.sessionId,
68961
69140
  historySnapshot,
68962
69141
  userDecision,
68963
69142
  filesApplied,
68964
- completedAt
69143
+ completedAt,
69144
+ serverAuthorizedAt: isApprove ? userDecision?.serverRecordedAt ?? void 0 : void 0,
69145
+ detectedAgentModels: this.deps.detectedAgentModels
68965
69146
  }), markdown = renderSummaryMarkdown(summaryModel);
68966
69147
  try {
68967
69148
  this.deps.onTaskAuditSummary?.(summaryModel, markdown);
@@ -68987,6 +69168,14 @@ ${section}`);
68987
69168
  sessionId: this.deps.session.sessionId,
68988
69169
  summary: summaryModel
68989
69170
  }
69171
+ }).then((result) => {
69172
+ if (result.emitted) return;
69173
+ let code = result.error?.code;
69174
+ logger.warn("[QuorumLoop] Companion audit summary was not acknowledged (non-fatal)", {
69175
+ taskId,
69176
+ reason: result.reason,
69177
+ ...typeof code == "string" && /^[A-Z][A-Z0-9_]{0,79}$/.test(code) ? { errorCode: code } : {}
69178
+ });
68990
69179
  }).catch((wErr) => {
68991
69180
  logger.warn("[QuorumLoop] Companion audit summary emission failed (non-fatal)", {
68992
69181
  taskId,
@@ -69183,8 +69372,8 @@ ${section}`);
69183
69372
  seatId: seat,
69184
69373
  ...dispatchTaskId ? { taskId: dispatchTaskId } : {}
69185
69374
  }), dispatchTaskId) {
69186
- let roster = this.expectedRosterByTask.get(dispatchTaskId);
69187
- roster || (roster = /* @__PURE__ */ new Map(), this.expectedRosterByTask.set(dispatchTaskId, roster)), roster.set(String(seat), String(payload.role || "reviewer"));
69375
+ let roster = this.dispatchedRosterByTask.get(dispatchTaskId);
69376
+ roster || (roster = /* @__PURE__ */ new Map(), this.dispatchedRosterByTask.set(dispatchTaskId, roster)), roster.set(String(seat), String(payload.role || "reviewer"));
69188
69377
  }
69189
69378
  let dispatched = this.dispatchedSeatsByGate.get(payload.gateId) ?? /* @__PURE__ */ new Set(), wasNew = !dispatched.has(seat);
69190
69379
  dispatched.add(seat), this.dispatchedSeatsByGate.set(payload.gateId, dispatched), wasNew && this.emitProgressForTask(dispatchTaskId, originEpoch, {
@@ -69278,7 +69467,7 @@ ${section}`);
69278
69467
  tool_allowlist: [...REVIEWER_TOOL_ALLOWLIST],
69279
69468
  prompt_template: promptText,
69280
69469
  timeout_ms: REVIEWER_TIMEOUT_MS,
69281
- model_hint: null
69470
+ model_hint: this.getExplicitModelForAgent(args.agentKind)
69282
69471
  }, seatSubstrate;
69283
69472
  try {
69284
69473
  seatSubstrate = await this.engageSeatSubstrate(args, key);
@@ -69891,7 +70080,7 @@ ${section}`);
69891
70080
  tool_allowlist: [...REVIEWER_TOOL_ALLOWLIST],
69892
70081
  prompt_template: renderFinalTier2Prompt(diff, bundleSections),
69893
70082
  timeout_ms: REVIEWER_TIMEOUT_MS,
69894
- model_hint: null
70083
+ model_hint: this.getExplicitModelForAgent(agent)
69895
70084
  }, verdict = await this.deps.reviewerRegistry.evaluate(spec, `wave-b-tier2-${args.ownerTaskId}`, {
69896
70085
  ...this.deps.classifyVerdict !== void 0 ? { classifyVerdict: this.deps.classifyVerdict } : {},
69897
70086
  ...substrate !== void 0 ? { substrate, workdir: this.deps.workingDir } : {},
@@ -81104,9 +81293,9 @@ function createTaskProgressRelay(deps) {
81104
81293
  let minIntervalMs = deps.minIntervalMs ?? DEFAULT_MIN_RELAY_INTERVAL_MS, lastRelayedAt = 0, lastMessage = null, lastPhase = null, lastTaskId = null, pendingTimeout = null, pendingFlush = null, emit = async (event, message2) => {
81105
81294
  pendingTimeout && (clearTimeout(pendingTimeout), pendingTimeout = null), pendingFlush = null;
81106
81295
  let taskId = event.progressTaskId ?? ("taskId" in event && typeof event.taskId == "string" ? event.taskId : void 0);
81107
- lastRelayedAt = Date.now(), lastMessage = message2, lastPhase = event.phase, lastTaskId = taskId ?? null, RUNTIME_LABELLED_PHASES.has(event.phase) ? logger.info("[task-progress-relay] relayed", { phase: event.phase, message: message2 }) : logger.debug("[task-progress-relay] relayed", { phase: event.phase });
81296
+ lastRelayedAt = Date.now(), lastMessage = message2, lastPhase = event.phase, lastTaskId = taskId ?? null;
81108
81297
  try {
81109
- return await deps.emitShellEvent({
81298
+ let result = await deps.emitShellEvent({
81110
81299
  sessionId: deps.sessionId,
81111
81300
  type: "NOTIFICATION",
81112
81301
  source: "DESKTOP",
@@ -81118,7 +81307,16 @@ function createTaskProgressRelay(deps) {
81118
81307
  message: message2,
81119
81308
  ...taskId ? { taskId } : {}
81120
81309
  }
81121
- }), !0;
81310
+ });
81311
+ if (!result.emitted) {
81312
+ let code = result.error?.code;
81313
+ return logger.warn("[task-progress-relay] progress notification was not acknowledged", {
81314
+ phase: event.phase,
81315
+ reason: result.reason,
81316
+ ...typeof code == "string" && /^[A-Z][A-Z0-9_]{0,79}$/.test(code) ? { errorCode: code } : {}
81317
+ }), !1;
81318
+ }
81319
+ return RUNTIME_LABELLED_PHASES.has(event.phase) ? logger.info("[task-progress-relay] relayed", { phase: event.phase, message: message2 }) : logger.debug("[task-progress-relay] relayed", { phase: event.phase }), !0;
81122
81320
  } catch (err) {
81123
81321
  return logger.debug("[task-progress-relay] failed to emit progress notification (non-fatal)", {
81124
81322
  phase: event.phase,
@@ -82571,7 +82769,7 @@ async function runOrchestrationShellSession(args) {
82571
82769
  finalApprovalCancelled ? "CANCEL" : "ABORT"
82572
82770
  ), args.quorumLoop.reportTeamTrackUserResolved(taskId, postAction), args.quorumLoop.reportFinalApprovalCancelled(taskId, postAction);
82573
82771
  try {
82574
- let timestamp5 = gateResolution?.recordedAt || (/* @__PURE__ */ new Date()).toISOString(), gateId = gateResolution?.gateId, decisionClaimId = gateResolution?.decisionClaimId;
82772
+ let timestamp5 = (/* @__PURE__ */ new Date()).toISOString(), serverRecordedAt = gateResolution?.recordedAt, gateId = gateResolution?.gateId, decisionClaimId = gateResolution?.decisionClaimId;
82575
82773
  if (postAction.kind === "final_approval_resolved") {
82576
82774
  let dec = canonicalDecision ? canonicalDecision.trim().toLowerCase() : postAction.decision;
82577
82775
  args.quorumLoop?.recordUserDecision?.(taskId, {
@@ -82579,7 +82777,8 @@ async function runOrchestrationShellSession(args) {
82579
82777
  isFinalApproval: !0,
82580
82778
  gateId,
82581
82779
  decisionClaimId,
82582
- timestamp: timestamp5
82780
+ timestamp: timestamp5,
82781
+ serverRecordedAt
82583
82782
  });
82584
82783
  } else if (postAction.kind === "terminate_gate") {
82585
82784
  let canon = canonicalDecision ? canonicalDecision.trim().toLowerCase() : "", dec = canon === "accept_with_notes" || !canon && postAction.notes ? "accept_with_notes" : canon || "accept";
@@ -82589,14 +82788,16 @@ async function runOrchestrationShellSession(args) {
82589
82788
  notes: postAction.notes ?? void 0,
82590
82789
  gateId,
82591
82790
  decisionClaimId,
82592
- timestamp: timestamp5
82791
+ timestamp: timestamp5,
82792
+ serverRecordedAt
82593
82793
  });
82594
82794
  } else postAction.kind === "abort_task" && args.quorumLoop?.recordUserDecision?.(taskId, {
82595
82795
  decision: "cancel",
82596
82796
  isFinalApproval: !1,
82597
82797
  gateId,
82598
82798
  decisionClaimId,
82599
- timestamp: timestamp5
82799
+ timestamp: timestamp5,
82800
+ serverRecordedAt
82600
82801
  });
82601
82802
  } catch {
82602
82803
  }
@@ -88100,6 +88301,7 @@ var import_uuid18 = require("uuid"), fs65 = __toESM(require("fs"));
88100
88301
 
88101
88302
  // src/orchestration-shell/doctor-cli.ts
88102
88303
  var fs59 = __toESM(require("fs")), path79 = __toESM(require("path")), crypto32 = __toESM(require("crypto")), import_child_process7 = require("child_process");
88304
+ init_detect_agents();
88103
88305
 
88104
88306
  // src/auth/auth-service.ts
88105
88307
  var crypto31 = __toESM(require("crypto")), fs58 = __toESM(require("fs")), http3 = __toESM(require("http")), import_child_process6 = require("child_process");
@@ -88731,13 +88933,16 @@ function probeAgentClis(env = process.env) {
88731
88933
  error: err.message
88732
88934
  };
88733
88935
  }
88936
+ let explicitModel = detectAgentModel(agent, env, { explicitOnly: !0 }), resolvedModel = explicitModel ?? detectAgentModel(agent, env) ?? void 0;
88734
88937
  return {
88735
88938
  agent,
88736
88939
  command,
88737
88940
  name,
88738
88941
  installed: !0,
88739
88942
  version: version || "installed",
88740
- binPath
88943
+ binPath,
88944
+ model: resolvedModel,
88945
+ modelIsConfigured: !!explicitModel
88741
88946
  };
88742
88947
  });
88743
88948
  }
@@ -88982,9 +89187,10 @@ function renderPreflight(agents, auth, connectivity, orphans) {
88982
89187
  console.log(`${colors.bold}CodeVibe Preflight Diagnostics${colors.reset}
88983
89188
  `), console.log(`${colors.bold}Agent CLIs:${colors.reset}`);
88984
89189
  for (let agent of agents)
88985
- if (agent.installed)
88986
- console.log(` [${colors.green}ok${colors.reset}] ${agent.name} (${agent.version ?? "installed"})${agent.binPath ? ` ${colors.dim}${agent.binPath}${colors.reset}` : ""}`);
88987
- else {
89190
+ if (agent.installed) {
89191
+ let modelInfo = agent.model ? agent.modelIsConfigured ? ` [model: ${agent.model}]` : ` [model: native default (unverified: ${agent.model})]` : "";
89192
+ console.log(` [${colors.green}ok${colors.reset}] ${agent.name} (${agent.version ?? "installed"})${modelInfo}${agent.binPath ? ` ${colors.dim}${agent.binPath}${colors.reset}` : ""}`);
89193
+ } else {
88988
89194
  let reason = agent.error ? `(${agent.error})` : "(not in $PATH)";
88989
89195
  console.log(` [${colors.yellow}missing${colors.reset}] ${agent.name} ${colors.dim}${reason}${colors.reset}`);
88990
89196
  }
@@ -93622,7 +93828,7 @@ Run codevibe --help for usage.
93622
93828
  if ((args.resume || args.continue) && tier === "FREE")
93623
93829
  return process.stderr.write(`${RESUME_NEEDS_PAID_TIER2}
93624
93830
  `), 1;
93625
- let mode = await resolveLaunchMode(args, tier), detectedAgents = detectInstalledAgents();
93831
+ let mode = await resolveLaunchMode(args, tier), detectedAgents = detectInstalledAgents(), detectedAgentModels = detectInstalledAgentModels(process.env, void 0, detectedAgents), configuredAgentModels = detectInstalledAgentModels(process.env, void 0, detectedAgents, { explicitOnly: !0 });
93626
93832
  await pushDetectedAgents(
93627
93833
  appsyncClient,
93628
93834
  logger,
@@ -93746,6 +93952,8 @@ ${err.message}
93746
93952
  // CP-1.f LOCK RP-6 — thread the single host-agent probe so the
93747
93953
  // QuorumLoop carries it in `startTask` (race-free gate-row stamp).
93748
93954
  detectedAgents,
93955
+ detectedAgentModels,
93956
+ configuredAgentModels,
93749
93957
  // #585 auto-continuation (Max) — the authoritative resolved tier (the
93750
93958
  // team path is MAX-only, but thread it explicitly for consistency).
93751
93959
  tier,
@@ -93776,6 +93984,8 @@ ${err.message}
93776
93984
  // CP-1.f LOCK RP-6 — thread the single host-agent probe so the
93777
93985
  // QuorumLoop carries it in `startTask` (race-free gate-row stamp).
93778
93986
  detectedAgents,
93987
+ detectedAgentModels,
93988
+ configuredAgentModels,
93779
93989
  // #585 auto-continuation (Max) — the authoritative resolved tier.
93780
93990
  tier,
93781
93991
  // [Gemma classifier · §Wiring] The session's Gemma pipeline (the planner's
@@ -93977,6 +94187,8 @@ function buildAndArmQuorumLoop(args) {
93977
94187
  workingDir: args.workingDir,
93978
94188
  // CP-1.f LOCK RP-6 — race-free request-carried host agents.
93979
94189
  detectedAgents: args.detectedAgents,
94190
+ ...args.detectedAgentModels ? { detectedAgentModels: args.detectedAgentModels } : {},
94191
+ ...args.configuredAgentModels ? { configuredAgentModels: args.configuredAgentModels } : {},
93980
94192
  // #585 auto-continuation (Max) — thread the resolved tier to the loop.
93981
94193
  tier: args.tier,
93982
94194
  // CP-1.f execute-first (#EF-1 / #SR-2) — synchronous halt + fail-closed
@@ -94122,6 +94334,8 @@ async function buildQuorumLoopExecutor(args) {
94122
94334
  holder: quorumLoopHolder,
94123
94335
  // CP-1.f LOCK RP-6 — race-free request-carried host agents.
94124
94336
  detectedAgents: args.detectedAgents,
94337
+ ...args.detectedAgentModels ? { detectedAgentModels: args.detectedAgentModels } : {},
94338
+ ...args.configuredAgentModels ? { configuredAgentModels: args.configuredAgentModels } : {},
94125
94339
  // #585 auto-continuation (Max) — thread the resolved tier to the loop.
94126
94340
  tier: args.tier,
94127
94341
  // [Gemma classifier · §Wiring] Thread the runner so the loop wires the
@@ -94639,6 +94853,8 @@ async function buildTeamLocalExecutor(args) {
94639
94853
  ...args.onTaskAuditSummary ? { onTaskAuditSummary: args.onTaskAuditSummary } : {},
94640
94854
  // CP-1.f LOCK RP-6 — race-free request-carried host agents.
94641
94855
  detectedAgents: args.detectedAgents,
94856
+ ...args.detectedAgentModels ? { detectedAgentModels: args.detectedAgentModels } : {},
94857
+ ...args.configuredAgentModels ? { configuredAgentModels: args.configuredAgentModels } : {},
94642
94858
  // #585 auto-continuation (Max) — thread the resolved tier to the loop.
94643
94859
  tier: args.tier,
94644
94860
  // [Gemma classifier · §Wiring] Thread the runner so the loop wires the