@quantiya/codevibe-codex-plugin 2.0.13 → 2.0.15

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.
Files changed (32) hide show
  1. package/dist/server.js +35 -32
  2. package/hooks/common.sh +21 -9
  3. package/libexec/companion-launcher +47 -14
  4. package/node_modules/@iarna/toml/CHANGELOG.md +278 -0
  5. package/node_modules/@quantiya/codevibe-core/dist/__tests__/gate-ux-regressions.test.d.ts +1 -0
  6. package/node_modules/@quantiya/codevibe-core/dist/index.d.ts +1 -1
  7. package/node_modules/@quantiya/codevibe-core/dist/index.js +240 -240
  8. package/node_modules/@quantiya/codevibe-core/dist/local-executor/workspace-shadow.d.ts +7 -0
  9. package/node_modules/@quantiya/codevibe-core/dist/local-model/manager.d.ts +1 -1
  10. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/audit-runner.d.ts +2 -3
  11. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/cli.d.ts +2 -2
  12. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/cli.js +158 -28
  13. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/quorum-loop.d.ts +22 -3
  14. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/task-progress.d.ts +3 -0
  15. package/node_modules/@quantiya/codevibe-core/dist/reduced-trust-notice.d.ts +44 -0
  16. package/node_modules/@quantiya/codevibe-core/dist/tool-activity/consolidator.d.ts +7 -0
  17. package/node_modules/@quantiya/codevibe-core/dist/tool-activity/ledger.d.ts +33 -13
  18. package/node_modules/@quantiya/codevibe-core/package.json +1 -1
  19. package/node_modules/color-convert/CHANGELOG.md +54 -0
  20. package/node_modules/deep-extend/CHANGELOG.md +46 -0
  21. package/node_modules/es-toolkit/CHANGELOG.md +810 -0
  22. package/node_modules/es-toolkit/src/compat/_internal/Equals.d.ts +1 -0
  23. package/node_modules/es-toolkit/src/compat/_internal/IsWritable.d.ts +3 -0
  24. package/node_modules/es-toolkit/src/compat/_internal/MutableList.d.ts +4 -0
  25. package/node_modules/es-toolkit/src/compat/_internal/RejectReadonly.d.ts +4 -0
  26. package/node_modules/fs-ext/build/Makefile +2 -2
  27. package/node_modules/fs-ext/build/Release/fs_ext.node +0 -0
  28. package/node_modules/fs-ext/build/Release/obj.target/fs_ext/fs-ext.o +0 -0
  29. package/node_modules/fs-ext/build/config.gypi +1 -1
  30. package/node_modules/keytar/build/Release/keytar.node +0 -0
  31. package/node_modules/which/CHANGELOG.md +166 -0
  32. package/package.json +2 -2
@@ -223,6 +223,13 @@ export declare class WorkspaceShadow {
223
223
  private constructor();
224
224
  /** @internal — test introspection of the tracked set. */
225
225
  get trackedSetForTests(): ReadonlySet<string>;
226
+ /**
227
+ * Number of paths this shadow tracks. 2026-08-22 — exposed for the reviewer
228
+ * timeout diagnostics: workspace SIZE is what separates "the diff was large"
229
+ * from "the workspace was large" when a reviewer blows its wall clock, and
230
+ * that distinction picks the fix. A count only; never the paths.
231
+ */
232
+ get trackedCount(): number;
226
233
  /** Exact user-root instance authenticated into reviewed team bundles. */
227
234
  rootAuthorityForBundle(): WorkspaceRootAuthority;
228
235
  /** Exact disposable-root incarnation required by every task-scoped consumer. */
@@ -4,7 +4,7 @@ import { type LocalModelState, type LocalModelStateStore } from './state';
4
4
  import { type OllamaPullProgressListener } from './ollama';
5
5
  import type { LocalGemmaPlannerRunner } from '../planner/local-gemma';
6
6
  export type LocalModelCommand = 'install' | 'status' | 'remove' | 'enable' | 'warm' | 'health-check';
7
- export type LocalModelEntitlementSource = 'backend' | 'environment' | 'unauthenticated' | 'unavailable';
7
+ export type LocalModelEntitlementSource = 'backend' | 'unauthenticated' | 'unavailable';
8
8
  export interface LocalModelEntitlement {
9
9
  tier: Tier | 'UNKNOWN';
10
10
  source: LocalModelEntitlementSource;
@@ -17,9 +17,8 @@ export interface RunAuditBrowserDeps {
17
17
  /** The session the task belongs to (the `queryAudit` 2-arg shape needs it). */
18
18
  sessionId: string;
19
19
  /**
20
- * The effective tier. When provided (the CLI passes the `CODEVIBE_TIER` env
21
- * value inline), it is authoritative (honors `CODEVIBE_TIER`). When omitted,
22
- * the runner reads `getSubscriptionStatus().tier` from the backend.
20
+ * The effective tier from an already-authenticated caller. Production CLI
21
+ * omits this and lets the runner read `getSubscriptionStatus().tier`.
23
22
  */
24
23
  tier?: Tier;
25
24
  /** Test seam — defaults to `cryptoService.decryptContent`. */
@@ -84,8 +84,8 @@ export declare function resolveLaunchMode(args: Pick<ParsedCliArgs, 'agent'>, ti
84
84
  * Authentication, encryption, and backend admission are hard prerequisites.
85
85
  * Failures propagate to `main`, which exits before opening the shell.
86
86
  *
87
- * The tier is resolved here too (§3.C.19): a `CODEVIBE_TIER` env override wins
88
- * (the dev/dogfood lever), otherwise `getSubscriptionStatus` must succeed.
87
+ * The tier is resolved here too (§3.C.19): `getSubscriptionStatus` must
88
+ * succeed unless a test passes the explicit `deps.tier` seam.
89
89
  */
90
90
  export declare function resumeOrCreateSession(appsyncClient: AppSyncClient, deps?: {
91
91
  resolveSessionIdFn?: (client: AppSyncClient) => Promise<string | null>;
@@ -6832,6 +6832,8 @@ function formatTokens(n) {
6832
6832
  }
6833
6833
  function renderProgressLine(event) {
6834
6834
  switch (event.phase) {
6835
+ case "preparing_workspace":
6836
+ return "Preparing an isolated workspace copy \u2014 this can take a while on a large folder";
6835
6837
  case "shadow_created":
6836
6838
  return "Workspace copy ready \u2014 starting implementor";
6837
6839
  case "implementor_running": {
@@ -7063,6 +7065,10 @@ var REFRESH_ONLY_PHASES = /* @__PURE__ */ new Set([
7063
7065
  "not_applied",
7064
7066
  "progress_cleared"
7065
7067
  ]), IMPLEMENT_REVIEW_PHASES = /* @__PURE__ */ new Set([
7068
+ // 2026-08-22 (Stage-1 MED-6) — the preparing window belongs to the same
7069
+ // IMPLEMENT family as `shadow_created`; omitting it would silently DROP any
7070
+ // REFRESH-ONLY event that arrives while it is open.
7071
+ "preparing_workspace",
7066
7072
  "shadow_created",
7067
7073
  "implementor_running",
7068
7074
  "diff_captured",
@@ -23120,7 +23126,31 @@ var LocalGemmaPlannerAdapter = class {
23120
23126
  };
23121
23127
 
23122
23128
  // src/orchestration-shell/quorum-loop.ts
23123
- var import_node_fs19 = require("node:fs"), path54 = __toESM(require("node:path")), os29 = __toESM(require("node:os")), import_uuid8 = require("uuid"), import_ulid4 = require("ulid");
23129
+ var import_node_fs19 = require("node:fs");
23130
+
23131
+ // src/reduced-trust-notice.ts
23132
+ var surfacedRationales = /* @__PURE__ */ new Set();
23133
+ function noticeKey(sessionId, tier, reason) {
23134
+ return `${sessionId}\0${tier}\0${reason}`;
23135
+ }
23136
+ function shouldSurfaceFullReducedTrustRationale(sessionId, tier, reason) {
23137
+ let key = noticeKey(sessionId, tier, reason);
23138
+ if (surfacedRationales.has(key)) return !1;
23139
+ if (surfacedRationales.size >= 512) {
23140
+ let oldest = surfacedRationales.values().next();
23141
+ oldest.done || surfacedRationales.delete(oldest.value);
23142
+ }
23143
+ return surfacedRationales.add(key), !0;
23144
+ }
23145
+ function releaseReducedTrustRationaleClaim(sessionId, tier, reason) {
23146
+ surfacedRationales.delete(noticeKey(sessionId, tier, reason));
23147
+ }
23148
+ function collapsedReducedTrustLine(actor) {
23149
+ return `${actor} is running with reduced trust (same posture as above).`;
23150
+ }
23151
+
23152
+ // src/orchestration-shell/quorum-loop.ts
23153
+ var path54 = __toESM(require("node:path")), os29 = __toESM(require("node:os")), import_uuid8 = require("uuid"), import_ulid4 = require("ulid");
23124
23154
 
23125
23155
  // src/local-executor/authority.ts
23126
23156
  var import_node_fs6 = require("node:fs"), path26 = __toESM(require("node:path")), AuthorityError = class extends Error {
@@ -26483,6 +26513,15 @@ var WorkspaceShadow = class _WorkspaceShadow {
26483
26513
  get trackedSetForTests() {
26484
26514
  return this.trackedSet;
26485
26515
  }
26516
+ /**
26517
+ * Number of paths this shadow tracks. 2026-08-22 — exposed for the reviewer
26518
+ * timeout diagnostics: workspace SIZE is what separates "the diff was large"
26519
+ * from "the workspace was large" when a reviewer blows its wall clock, and
26520
+ * that distinction picks the fix. A count only; never the paths.
26521
+ */
26522
+ get trackedCount() {
26523
+ return this.trackedSet.size;
26524
+ }
26486
26525
  /** Exact user-root instance authenticated into reviewed team bundles. */
26487
26526
  rootAuthorityForBundle() {
26488
26527
  return { ...this.workspaceRootAuthority };
@@ -39174,7 +39213,7 @@ var LocalExecutorImpl = class {
39174
39213
  `[LocalExecutorImpl] \u26A0\uFE0F CP-7 REDUCED-TRUST (tier=${tier}) \u2014 the trusted-execution moat is ${tier === "none" ? "OFF" : "WEAKENED"} for this implementor session: ${reason}`,
39175
39214
  { sessionId: this.sessionId, agentKind, tier, reducedTrust: !0 }
39176
39215
  );
39177
- let content = `\u26A0\uFE0F Reduced-trust mode: ${reason} The implementor's ambient credentials may be reachable; the trusted-execution moat is ${tier === "none" ? "OFF" : "weakened"} for this session.`, metadata = {
39216
+ let content = tier === "none" || shouldSurfaceFullReducedTrustRationale(this.sessionId, tier, reason) ? `\u26A0\uFE0F Reduced-trust mode: ${reason} The implementor's ambient credentials may be reachable; the trusted-execution moat is ${tier === "none" ? "OFF" : "weakened"} for this session.` : collapsedReducedTrustLine("The implementor"), metadata = {
39178
39217
  source: "cp7_reduced_trust",
39179
39218
  reducedTrust: !0,
39180
39219
  tier,
@@ -47115,7 +47154,7 @@ var CONTINUATION_EXPIRES_TTL_MS = 1440 * 60 * 1e3, ACTIVE_AGENT_KINDS = ["CLAUDE
47115
47154
  function isActiveAgentKind2(agent) {
47116
47155
  return agent === "CLAUDE" || agent === "CODEX" || agent === "ANTIGRAVITY";
47117
47156
  }
47118
- var IMPLEMENTOR_TICK_MS = 1e4, TICK_SCAN_MAX_TRACKED = 5e3, TICK_SCAN_TIMEOUT_MS = 1e3, REVIEWER_ERROR_LOG_RAW_OUTPUT_CAP = 4e3;
47157
+ var IMPLEMENTOR_TICK_MS = 1e4, TICK_SCAN_MAX_TRACKED = 5e3, TICK_SCAN_TIMEOUT_MS = 1e3, BACKGROUND_RECOVERY_ABORTED = /* @__PURE__ */ Symbol("background-recovery-aborted"), REVIEWER_ERROR_LOG_RAW_OUTPUT_CAP = 4e3;
47119
47158
  function describeReviewerErrorDetail(detail) {
47120
47159
  switch (detail.kind) {
47121
47160
  case "timeout":
@@ -47898,6 +47937,8 @@ var QuorumLoop = class _QuorumLoop {
47898
47937
  * never call each other), so it cannot self-deadlock.
47899
47938
  */
47900
47939
  this.shadowOpsByTask = /* @__PURE__ */ new Map();
47940
+ /** Abort only the read-only waits owned by non-draining startup recovery. */
47941
+ this.backgroundRecoveryAbortControllers = /* @__PURE__ */ new Set();
47901
47942
  /** Once set, no new implementor workspace may be created for this session. */
47902
47943
  this.shuttingDown = !1;
47903
47944
  /**
@@ -48057,6 +48098,17 @@ var QuorumLoop = class _QuorumLoop {
48057
48098
  this.releaseRecoveryRelaunchPermit();
48058
48099
  }
48059
48100
  }
48101
+ awaitBackgroundRecoveryStep(work, signal) {
48102
+ return signal ? signal.aborted ? Promise.reject(BACKGROUND_RECOVERY_ABORTED) : new Promise((resolve18, reject) => {
48103
+ let settled = !1, finish = (complete) => {
48104
+ settled || (settled = !0, signal.removeEventListener("abort", onAbort), complete());
48105
+ }, onAbort = () => finish(() => reject(BACKGROUND_RECOVERY_ABORTED));
48106
+ signal.addEventListener("abort", onAbort, { once: !0 }), work.then(
48107
+ (value) => finish(() => resolve18(value)),
48108
+ (err) => finish(() => reject(err))
48109
+ );
48110
+ }) : work;
48111
+ }
48060
48112
  /**
48061
48113
  * Serialize one shadow lifecycle op for `taskId` behind any in-flight op for
48062
48114
  * the same task. The op's result/rejection is returned to ITS caller; a
@@ -49047,6 +49099,10 @@ var QuorumLoop = class _QuorumLoop {
49047
49099
  roundActive = !1, tickTimer && (clearInterval(tickTimer), tickTimer = null);
49048
49100
  }, roundBriefForSpawn = args.brief, copiedForSpawn = [];
49049
49101
  try {
49102
+ this.emitProgressForTask(args.taskId, originEpoch, {
49103
+ phase: "preparing_workspace",
49104
+ round: args.roundNumber
49105
+ });
49050
49106
  let shadow = await this.ensureShadow(args.taskId);
49051
49107
  if (this.teamRunIsHalted(args.teamAuthority)) return;
49052
49108
  let snapshotAuthority = shadow.snapshotAuthorityForDispatch();
@@ -50611,7 +50667,9 @@ var QuorumLoop = class _QuorumLoop {
50611
50667
  role: args.role,
50612
50668
  agentKind: args.agentKind,
50613
50669
  guardMs: SEAT_EVALUATE_TIMEOUT_MS,
50614
- audit: "synthesized ESCALATE (#C1F-8): reviewer_error:timeout (seat-guard)"
50670
+ audit: "synthesized ESCALATE (#C1F-8): reviewer_error:timeout (seat-guard)",
50671
+ // 2026-08-22 — same timeout diagnostics as the inner path (below).
50672
+ ...this.describeReviewShapeForDiagnostics(args.gateId)
50615
50673
  }), verdict = this.synthesizeEscalate(args, cleanReasoning);
50616
50674
  } else if (err instanceof ReviewerErrorClass) {
50617
50675
  let failureReason = failureReasonFromDetail(err.detail), cleanReasoning = failureReasonTemplate(args.agentKind, failureReason);
@@ -50625,7 +50683,21 @@ var QuorumLoop = class _QuorumLoop {
50625
50683
  // Audit prefix kept in LOGS only (#C1F-8) — never on the wire.
50626
50684
  audit: `synthesized ESCALATE (#C1F-8): reviewer_error:${err.detail.kind}`,
50627
50685
  ...describeReviewerErrorDetail(err.detail),
50628
- message: err.message
50686
+ message: err.message,
50687
+ // 2026-08-22 (dogfood) — TIMEOUT DIAGNOSTICS, local log only.
50688
+ //
50689
+ // A live 5-minute reviewer timeout on a ONE-FILE deletion diff was
50690
+ // not root-causable from this record: it says the wall expired but
50691
+ // nothing about what the reviewer was up against. Without the
50692
+ // review's shape you cannot separate "the diff was genuinely large"
50693
+ // from "the reviewer wandered the workspace" from "the host was
50694
+ // saturated" — the three have different fixes, and guessing between
50695
+ // them is how a one-off gets mistaken for a systemic defect.
50696
+ //
50697
+ // Emitted for EVERY reviewer error (cheap, and a spawn_failed
50698
+ // benefits from the same shape context). All values are counts and
50699
+ // labels — no diff content, no agent output, nothing on the wire.
50700
+ ...this.describeReviewShapeForDiagnostics(args.gateId)
50629
50701
  }), verdict = this.synthesizeEscalate(args, cleanReasoning);
50630
50702
  } else
50631
50703
  throw err;
@@ -50767,17 +50839,58 @@ var QuorumLoop = class _QuorumLoop {
50767
50839
  agentKind: args.agentKind,
50768
50840
  reason
50769
50841
  });
50842
+ let claimedFullRationale = !1;
50770
50843
  try {
50771
- this.surfaceHalt(
50772
- `Reviewer (${seatLabel(args.agentKind, args.seatId)}) is running with reduced trust: ${reason}`
50844
+ let actor = `Reviewer (${seatLabel(args.agentKind, args.seatId)})`, sessionId = this.deps.session.sessionId;
50845
+ claimedFullRationale = shouldSurfaceFullReducedTrustRationale(
50846
+ sessionId,
50847
+ "reviewer",
50848
+ reason
50849
+ ), this.surfaceHalt(
50850
+ claimedFullRationale ? `${actor} is running with reduced trust: ${reason}` : collapsedReducedTrustLine(actor)
50773
50851
  );
50774
50852
  } catch (e) {
50775
- logger.warn("[QuorumLoop] reduced-trust badge surfaceHalt threw (badge is best-effort) \u2014 continuing", {
50853
+ claimedFullRationale && releaseReducedTrustRationaleClaim(
50854
+ this.deps.session.sessionId,
50855
+ "reviewer",
50856
+ reason
50857
+ ), logger.warn("[QuorumLoop] reduced-trust badge surfaceHalt threw (badge is best-effort) \u2014 continuing", {
50776
50858
  seatId: args.seatId,
50777
50859
  err: e.message
50778
50860
  });
50779
50861
  }
50780
50862
  }
50863
+ /**
50864
+ * Local-only shape summary of the review a failing seat was working on.
50865
+ *
50866
+ * 2026-08-22 (dogfood): a reviewer wall-clock expiry told us WHEN it gave up
50867
+ * and nothing about WHAT it faced, so a single load-induced timeout on a
50868
+ * one-file diff looked indistinguishable from a systemic defect. These counts
50869
+ * separate the three candidate causes (big diff / big workspace / saturated
50870
+ * host) on the next occurrence.
50871
+ *
50872
+ * Counts and labels ONLY — never diff content, paths, or agent output. This
50873
+ * feeds a `logger.warn` that stays on the desktop; nothing here reaches the
50874
+ * wire. Fail-soft: diagnostics must never throw inside an error handler.
50875
+ */
50876
+ describeReviewShapeForDiagnostics(gateId) {
50877
+ try {
50878
+ let taskId = this.taskByGateId.get(gateId), reviewed = taskId ? this.reviewedSnapshotByTask.get(taskId) : void 0, shadow = taskId ? this.shadowForTask(taskId) : void 0;
50879
+ return {
50880
+ diagReviewFiles: reviewed?.length ?? null,
50881
+ // Stage-2 R1 LOW-3: `.length` counts UTF-16 code units, not bytes, so a
50882
+ // diff of multi-byte source under-reported against a byte-named field.
50883
+ // `Buffer.byteLength` is the idiom already used in this file (~:774).
50884
+ diagReviewBytes: reviewed?.reduce(
50885
+ (sum, f) => sum + (f.content ? Buffer.byteLength(f.content, "utf8") : 0),
50886
+ 0
50887
+ ) ?? null,
50888
+ diagWorkspaceTracked: shadow?.trackedCount ?? null
50889
+ };
50890
+ } catch {
50891
+ return { diagReviewFiles: null, diagUnavailable: !0 };
50892
+ }
50893
+ }
50781
50894
  // ─── CP-14 Wave B — confined class-2 resolver + final-tip Tier-2 dispatch ────
50782
50895
  /**
50783
50896
  * Wave B §2.1 confinement TRI-STATE for a merge-gate model/reviewer invocation
@@ -51240,17 +51353,25 @@ var QuorumLoop = class _QuorumLoop {
51240
51353
  * while `pending` and un-expired), so the approved code is never lost; a
51241
51354
  * re-delivered packet (or the next live edge) promotes it.
51242
51355
  */
51243
- recoverShadows() {
51244
- return this.startSessionWork((admission) => this.recoverShadowsOwned(admission));
51356
+ recoverShadows(opts = {}) {
51357
+ if (opts.drainOnShutdown ?? !0)
51358
+ return this.startSessionWork((admission2) => this.recoverShadowsOwned(admission2));
51359
+ if (this.shuttingDown) return Promise.resolve();
51360
+ let admission = /* @__PURE__ */ Symbol("quorum-background-recovery"), controller = new AbortController();
51361
+ this.backgroundRecoveryAbortControllers.add(controller);
51362
+ let recovery = this.recoverShadowsOwned(admission, controller.signal), release = () => {
51363
+ this.backgroundRecoveryAbortControllers.delete(controller);
51364
+ };
51365
+ return recovery.then(release, release), recovery;
51245
51366
  }
51246
- async recoverShadowsOwned(admission) {
51367
+ async recoverShadowsOwned(admission, signal) {
51247
51368
  if (this.admittedSessionWorkMayContinue(admission))
51248
51369
  try {
51249
- let env = this.deps.shadowEnv ?? {}, [recoverable, canonicalWorkingDir, currentOwner] = await Promise.all([
51370
+ let env = this.deps.shadowEnv ?? {}, [recoverable, canonicalWorkingDir, currentOwner] = await this.awaitBackgroundRecoveryStep(Promise.all([
51250
51371
  (this.deps.shadowRecoveryOps?.listRecoverableShadows ?? listRecoverableShadows)(env),
51251
51372
  (this.deps.shadowRecoveryOps?.captureWorkspaceRootAuthority ?? captureWorkspaceRootAuthority)(this.deps.workingDir).then((authority) => authority.canonicalPath),
51252
51373
  currentProcessIdentity()
51253
- ]);
51374
+ ]), signal);
51254
51375
  if (!this.admittedSessionWorkMayContinue(admission)) return;
51255
51376
  let now = Date.now(), ttlMs = env.ttlMs ?? DEFAULT_SHADOW_TTL_MS, keep = /* @__PURE__ */ new Set();
51256
51377
  this.activeTaskId && keep.add(this.activeTaskId);
@@ -51273,9 +51394,15 @@ var QuorumLoop = class _QuorumLoop {
51273
51394
  try {
51274
51395
  await this.runExclusiveShadowOp(recovered.taskId, async () => {
51275
51396
  if (!this.admittedSessionWorkMayContinue(admission) || this.shadowsByTask.get(recovered.taskId)?.matchesRecoveredInstance(recovered)) return;
51276
- if (!(recovered.ownerProcessIdentity.pid === currentOwner.pid && recovered.ownerProcessIdentity.incarnationId === currentOwner.incarnationId) && await isProcessIdentityAlive(recovered.ownerProcessIdentity))
51397
+ if (!(recovered.ownerProcessIdentity.pid === currentOwner.pid && recovered.ownerProcessIdentity.incarnationId === currentOwner.incarnationId) && await this.awaitBackgroundRecoveryStep(
51398
+ isProcessIdentityAlive(recovered.ownerProcessIdentity),
51399
+ signal
51400
+ ))
51277
51401
  throw new Error("recoverable workspace belongs to another live process");
51278
- let shadow = await (this.deps.shadowRecoveryOps?.reopenShadow ?? reopenShadow)(recovered, env);
51402
+ let shadow = await this.awaitBackgroundRecoveryStep(
51403
+ (this.deps.shadowRecoveryOps?.reopenShadow ?? reopenShadow)(recovered, env),
51404
+ signal
51405
+ );
51279
51406
  if (!this.admittedSessionWorkMayContinue(admission) || !shadow) return;
51280
51407
  if (!shadow.matchesRecoveredInstance(recovered))
51281
51408
  throw new Error("reopened recovery snapshot changed exact authority");
@@ -51294,6 +51421,7 @@ var QuorumLoop = class _QuorumLoop {
51294
51421
  ));
51295
51422
  });
51296
51423
  } catch (err) {
51424
+ if (err === BACKGROUND_RECOVERY_ABORTED) return;
51297
51425
  failures.push(this.rememberWorkspaceLifecycleFailure(
51298
51426
  err,
51299
51427
  `workspace ${recovered.taskId} recovery reconciliation failed`
@@ -51311,6 +51439,7 @@ var QuorumLoop = class _QuorumLoop {
51311
51439
  causes: failures
51312
51440
  });
51313
51441
  } catch (err) {
51442
+ if (err === BACKGROUND_RECOVERY_ABORTED || !this.admittedSessionWorkMayContinue(admission)) return;
51314
51443
  let failure = this.rememberWorkspaceLifecycleFailure(
51315
51444
  err,
51316
51445
  "workspace recovery/GC sweep failed"
@@ -51446,7 +51575,10 @@ var QuorumLoop = class _QuorumLoop {
51446
51575
  }
51447
51576
  async disposeWorkspaces(opts = {}) {
51448
51577
  let strict = opts.strict ?? !0;
51449
- this.shuttingDown = !0, this.cancelRecoveryRelaunchWaiters(), this.pendingB1TaskGroupId = null, this.subscriptionReady = !1, this.bufferedTeamPackets.length = 0, this.pendingGateDispatches.length = 0;
51578
+ this.shuttingDown = !0;
51579
+ for (let controller of this.backgroundRecoveryAbortControllers)
51580
+ controller.abort();
51581
+ this.cancelRecoveryRelaunchWaiters(), this.pendingB1TaskGroupId = null, this.subscriptionReady = !1, this.bufferedTeamPackets.length = 0, this.pendingGateDispatches.length = 0;
51450
51582
  let failures = [], pendingImplementors = [...this.pendingImplementorByGate.values()];
51451
51583
  for (let pending of pendingImplementors)
51452
51584
  try {
@@ -53997,7 +54129,7 @@ async function runOrchestrationShell(args) {
53997
54129
  { error: err.message }
53998
54130
  );
53999
54131
  }
54000
- args.quorumLoop && args.quorumLoop.recoverShadows().catch((err) => {
54132
+ args.quorumLoop && args.quorumLoop.recoverShadows({ drainOnShutdown: !1 }).catch((err) => {
54001
54133
  logger.warn("[orchestration-shell] startup workspace recovery failed", {
54002
54134
  error: err.message
54003
54135
  });
@@ -58973,6 +59105,7 @@ async function findPendingForIntent(intent, logger2) {
58973
59105
  var DEFINITIVE_CREATE_REJECTIONS = /* @__PURE__ */ new Set([
58974
59106
  "AccountDeletionInProgress",
58975
59107
  "CreationRequestConflict",
59108
+ "InvalidSessionStatus",
58976
59109
  "RateLimited",
58977
59110
  "SessionIdReserved",
58978
59111
  "SessionIdRetired",
@@ -58982,6 +59115,7 @@ var DEFINITIVE_CREATE_REJECTIONS = /* @__PURE__ */ new Set([
58982
59115
  "UnauthorizedException"
58983
59116
  ]), DEFINITIVE_CREATE_REJECTION_CODES = /* @__PURE__ */ new Set([
58984
59117
  "RATE_LIMITED",
59118
+ "INVALID_SESSION_STATUS",
58985
59119
  "SESSION_ID_RESERVED",
58986
59120
  "SESSION_LIMIT_EXCEEDED",
58987
59121
  "UNAUTHORIZED"
@@ -62742,9 +62876,6 @@ async function resumeOrCreateSession2(appsyncClient, deps) {
62742
62876
  }
62743
62877
  }
62744
62878
  async function resolveCliTier(appsyncClient) {
62745
- let envTier = process.env.CODEVIBE_TIER;
62746
- if (envTier === "FREE" || envTier === "PRO" || envTier === "MAX")
62747
- return envTier;
62748
62879
  try {
62749
62880
  return (await appsyncClient.getSubscriptionStatus()).tier;
62750
62881
  } catch (err) {
@@ -63031,15 +63162,17 @@ async function runAuditCli(parsed, deps) {
63031
63162
  `Usage: codevibe audit show <task-id> [--json] [--session <session-id>]
63032
63163
  `
63033
63164
  ), 2;
63034
- let appsyncClient = deps?.appsyncClient ?? new AppSyncClient();
63165
+ let appsyncClient = deps?.appsyncClient ?? new AppSyncClient(), authenticated;
63035
63166
  try {
63036
- await appsyncClient.authenticateWithStoredTokens();
63167
+ authenticated = await appsyncClient.authenticateWithStoredTokens();
63037
63168
  } catch (e) {
63038
63169
  return err(
63039
63170
  `Not signed in \u2014 run \`codevibe login\` first (${e?.message ?? "auth unavailable"}).
63040
63171
  `
63041
63172
  ), 2;
63042
63173
  }
63174
+ if (!authenticated)
63175
+ return err("Not signed in \u2014 run `codevibe login` first.\n"), 2;
63043
63176
  let sessionId = parsed.sessionId ?? null;
63044
63177
  if (!sessionId) {
63045
63178
  let resolveSessionId = deps?.resolveSessionIdFn ?? resolveActiveSessionId;
@@ -63059,10 +63192,7 @@ async function runAuditCli(parsed, deps) {
63059
63192
  let result = await runAuditBrowser({
63060
63193
  appsyncClient,
63061
63194
  taskId: parsed.taskId,
63062
- sessionId,
63063
- // Honor CODEVIBE_TIER for the Max gate (same override the rest of the CLI
63064
- // uses); when FREE/PRO/unset the runner falls back to getSubscriptionStatus.
63065
- tier: process.env.CODEVIBE_TIER === "MAX" || process.env.CODEVIBE_TIER === "PRO" || process.env.CODEVIBE_TIER === "FREE" ? process.env.CODEVIBE_TIER : void 0
63195
+ sessionId
63066
63196
  });
63067
63197
  return parsed.json ? (out(`${JSON.stringify(result, null, 2)}
63068
63198
  `), 0) : (out(`${renderAuditResultText(result)}
@@ -63127,9 +63257,9 @@ Run codevibe --help for usage.
63127
63257
  error: err?.message
63128
63258
  });
63129
63259
  });
63130
- let localModelState = await readLocalModelState(), envTier = process.env.CODEVIBE_TIER, localModelEntitlement = {
63260
+ let localModelState = await readLocalModelState(), localModelEntitlement = {
63131
63261
  tier,
63132
- source: envTier === "FREE" || envTier === "PRO" || envTier === "MAX" ? "environment" : "backend"
63262
+ source: "backend"
63133
63263
  }, localModelBoot = resolveLocalModelBoot({
63134
63264
  requestedMode: mode,
63135
63265
  entitlement: localModelEntitlement,
@@ -369,8 +369,8 @@ export interface QuorumLoopDeps {
369
369
  */
370
370
  detectedAgents?: string[];
371
371
  /**
372
- * #585 auto-continuation (Max) — the resolved subscription tier (from
373
- * `resumeOrCreateSession`: env override → getSubscriptionStatus → FREE).
372
+ * #585 auto-continuation (Max) — the resolved authenticated subscription tier
373
+ * threaded from CLI startup/resume.
374
374
  * MAX → a quota-exhausted continuation handoff AUTO-ACCEPTS on the strongest
375
375
  * available agent (no prompt). Pro/Free/unresolved/absent → the existing
376
376
  * `continuation_offer_handoff` prompt (fail-closed). Auto-continuation only
@@ -1095,8 +1095,11 @@ export declare class QuorumLoop {
1095
1095
  * never call each other), so it cannot self-deadlock.
1096
1096
  */
1097
1097
  private readonly shadowOpsByTask;
1098
+ /** Abort only the read-only waits owned by non-draining startup recovery. */
1099
+ private readonly backgroundRecoveryAbortControllers;
1098
1100
  /** Once set, no new implementor workspace may be created for this session. */
1099
1101
  private shuttingDown;
1102
+ private awaitBackgroundRecoveryStep;
1100
1103
  /**
1101
1104
  * Serialize one shadow lifecycle op for `taskId` behind any in-flight op for
1102
1105
  * the same task. The op's result/rejection is returned to ITS caller; a
@@ -1818,6 +1821,20 @@ export declare class QuorumLoop {
1818
1821
  * RUNS (it always runs; the badge only informs the user).
1819
1822
  */
1820
1823
  private surfaceReviewerReducedTrust;
1824
+ /**
1825
+ * Local-only shape summary of the review a failing seat was working on.
1826
+ *
1827
+ * 2026-08-22 (dogfood): a reviewer wall-clock expiry told us WHEN it gave up
1828
+ * and nothing about WHAT it faced, so a single load-induced timeout on a
1829
+ * one-file diff looked indistinguishable from a systemic defect. These counts
1830
+ * separate the three candidate causes (big diff / big workspace / saturated
1831
+ * host) on the next occurrence.
1832
+ *
1833
+ * Counts and labels ONLY — never diff content, paths, or agent output. This
1834
+ * feeds a `logger.warn` that stays on the desktop; nothing here reaches the
1835
+ * wire. Fail-soft: diagnostics must never throw inside an error handler.
1836
+ */
1837
+ private describeReviewShapeForDiagnostics;
1821
1838
  /**
1822
1839
  * Wave B §2.1 confinement TRI-STATE for a merge-gate model/reviewer invocation
1823
1840
  * (LOCK #C14-MOAT). Path A: the CP-7 substrate/broker (not opted out + a Trusted
@@ -1985,7 +2002,9 @@ export declare class QuorumLoop {
1985
2002
  * while `pending` and un-expired), so the approved code is never lost; a
1986
2003
  * re-delivered packet (or the next live edge) promotes it.
1987
2004
  */
1988
- recoverShadows(): Promise<void>;
2005
+ recoverShadows(opts?: {
2006
+ drainOnShutdown?: boolean;
2007
+ }): Promise<void>;
1989
2008
  private recoverShadowsOwned;
1990
2009
  /**
1991
2010
  * Session-exit ownership boundary. Stop future creates, wait behind every
@@ -5,6 +5,9 @@
5
5
  * (controlled operational notice text; see the header + the entry's carve-out).
6
6
  */
7
7
  export type TaskProgressEvent = ({
8
+ phase: 'preparing_workspace';
9
+ round: number;
10
+ } | {
8
11
  phase: 'shadow_created';
9
12
  round: number;
10
13
  } | {
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Per-session de-duplication for the CP-7 reduced-trust rationale.
3
+ *
4
+ * WHY (2026-08-22, dogfood): the reduced-trust rationale is ~600 characters and
5
+ * was surfaced in FULL once per agent — implementor, reviewer seat 0, reviewer
6
+ * seat 1 — so a single one-file task printed roughly 1.8 KB of identical
7
+ * boilerplate that buried the actual progress milestones. In the live transcript
8
+ * the banner outweighed every `●` line combined.
9
+ *
10
+ * The rationale is genuinely important the FIRST time: it tells the operator the
11
+ * trusted-execution moat is weakened for this session and why. It carries no new
12
+ * information on the second and third repetition within the same session, where
13
+ * the tier and reason are identical.
14
+ *
15
+ * So: surface the full rationale ONCE per (session, tier, reason), and collapse
16
+ * every later occurrence to a one-line reminder that still names the actor. The
17
+ * WARN log is unaffected — the durable forensic record keeps every occurrence in
18
+ * full; only the user-facing surface is de-duplicated.
19
+ *
20
+ * Keyed on (sessionId, tier, reason) rather than sessionId alone so a session
21
+ * that DEGRADES (e.g. `sandbox_exec` → `none`, or a different reason) surfaces
22
+ * the new rationale in full rather than silently collapsing a more severe
23
+ * posture into a one-liner.
24
+ */
25
+ /**
26
+ * True the FIRST time this exact (session, tier, reason) rationale is surfaced;
27
+ * false for every later call. Call once per user-facing surfacing decision.
28
+ */
29
+ export declare function shouldSurfaceFullReducedTrustRationale(sessionId: string, tier: string, reason: string): boolean;
30
+ /**
31
+ * Undo a claim (Stage-1 LOW-15). The caller test-and-sets BEFORE surfacing, so
32
+ * a surfacing that then THROWS would otherwise burn the "first" slot: every
33
+ * later actor collapses to "(same posture as above)" pointing at a rationale
34
+ * the operator never saw. Callers that surface fallibly must release on failure.
35
+ */
36
+ export declare function releaseReducedTrustRationaleClaim(sessionId: string, tier: string, reason: string): void;
37
+ /**
38
+ * The collapsed one-line form for a repeat occurrence. Names the actor so the
39
+ * operator can still see WHICH agent is reduced-trust, and points at the full
40
+ * rationale already in scrollback.
41
+ */
42
+ export declare function collapsedReducedTrustLine(actor: string): string;
43
+ /** Test-only reset — the Set is module-global and would leak across cases. */
44
+ export declare function __resetReducedTrustNoticesForTest(): void;
@@ -48,6 +48,13 @@ export interface ToolActivityTransport {
48
48
  * undecryptable generation forever (a liveness/G2 failure on key rotation).
49
49
  */
50
50
  export declare function isSessionKeyStaleError(err: unknown): boolean;
51
+ /**
52
+ * True only when the backend has proved that this session generation can never
53
+ * accept another event. These errors settle the durable window terminally;
54
+ * key rotation, contention, throttling, networking, and unknown failures remain
55
+ * retryable so recoverable tool activity is never discarded.
56
+ */
57
+ export declare function isTerminalSessionError(err: unknown): boolean;
51
58
  export interface ToolActivityConsolidatorOptions {
52
59
  agent: string;
53
60
  /** The backend session id bound into each window's envelope (X2a routing). */