@quantiya/codevibe-core 2.0.8 → 2.0.10

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 (50) hide show
  1. package/dist/__tests__/gate-ux-regressions.test.d.ts +1 -0
  2. package/dist/appsync/__tests__/appsync-client-flag-locator.test.d.ts +1 -0
  3. package/dist/appsync/__tests__/dispose-watcher-socket.test.d.ts +1 -0
  4. package/dist/appsync/appsync-client.d.ts +62 -0
  5. package/dist/auth/__tests__/keychain-cli-nudge.test.d.ts +1 -0
  6. package/dist/auth/keychain-cli.d.ts +8 -0
  7. package/dist/index.d.ts +1 -1
  8. package/dist/index.js +523 -351
  9. package/dist/keychain/__tests__/migrate-nudge.test.d.ts +1 -0
  10. package/dist/keychain/keychain-migrate.d.ts +17 -0
  11. package/dist/keychain/migrate-nudge.d.ts +38 -0
  12. package/dist/local-executor/__tests__/protocol-backlog-wiring.test.d.ts +1 -0
  13. package/dist/local-executor/__tests__/protocol-backlog.test.d.ts +1 -0
  14. package/dist/local-executor/__tests__/workspace-cleanup-audit.test.d.ts +1 -0
  15. package/dist/local-executor/anchored-fs.d.ts +7 -0
  16. package/dist/local-executor/bounded-directory.d.ts +14 -0
  17. package/dist/local-executor/process-identity.d.ts +30 -0
  18. package/dist/local-executor/process-tree.d.ts +1 -1
  19. package/dist/local-executor/protocol-backlog.d.ts +62 -0
  20. package/dist/local-executor/workspace-cleanup-audit.d.ts +3 -0
  21. package/dist/local-executor/workspace-materializer.d.ts +23 -2
  22. package/dist/local-executor/workspace-shadow.d.ts +9 -0
  23. package/dist/local-model/manager.d.ts +1 -1
  24. package/dist/orchestration-shell/__tests__/direct-file-delete.test.d.ts +1 -0
  25. package/dist/orchestration-shell/__tests__/flag-command.test.d.ts +1 -0
  26. package/dist/orchestration-shell/__tests__/halt-message-wire-content.test.d.ts +1 -0
  27. package/dist/orchestration-shell/audit-browser.d.ts +54 -1
  28. package/dist/orchestration-shell/audit-runner.d.ts +2 -3
  29. package/dist/orchestration-shell/cli.d.ts +12 -2
  30. package/dist/orchestration-shell/cli.js +2867 -1500
  31. package/dist/orchestration-shell/context-items.d.ts +3 -0
  32. package/dist/orchestration-shell/direct-file-delete.d.ts +22 -0
  33. package/dist/orchestration-shell/flag-command.d.ts +81 -0
  34. package/dist/orchestration-shell/gate-prompts.d.ts +41 -0
  35. package/dist/orchestration-shell/index.d.ts +31 -6
  36. package/dist/orchestration-shell/quorum-loop.d.ts +64 -4
  37. package/dist/orchestration-shell/task-progress.d.ts +6 -0
  38. package/dist/orchestration-shell/types.d.ts +58 -0
  39. package/dist/orchestration-shell/workspace-shutdown.d.ts +20 -0
  40. package/dist/reduced-trust-notice.d.ts +44 -0
  41. package/dist/reviewer/providers/codex.d.ts +5 -3
  42. package/dist/reviewer/token-usage.d.ts +41 -12
  43. package/dist/reviewer/types.d.ts +3 -0
  44. package/dist/substrate/__tests__/command-runner.test.d.ts +1 -0
  45. package/dist/substrate/types.d.ts +8 -0
  46. package/dist/tool-activity/consolidator.d.ts +7 -0
  47. package/dist/tool-activity/ledger.d.ts +33 -13
  48. package/dist/track-presentation.d.ts +2 -0
  49. package/dist/track-presentation.test.d.ts +1 -0
  50. package/package.json +1 -1
@@ -81,6 +81,8 @@ export interface ContextItem {
81
81
  prev_hash: string | null;
82
82
  /** Typed payload per kind. */
83
83
  body: unknown;
84
+ /** Non-rendered counters/locator metadata; excluded from semantic content ids. */
85
+ telemetry?: unknown;
84
86
  /** ISO timestamp the item was authored (corpus-ready, §4.1). */
85
87
  authored_at: string;
86
88
  }
@@ -91,6 +93,7 @@ export interface ContextItemDraft {
91
93
  sensitivity: ContextItemSensitivity;
92
94
  visible_to: ContextItemProjectionRole[];
93
95
  body: unknown;
96
+ telemetry?: unknown;
94
97
  task_id?: string;
95
98
  track_id?: string;
96
99
  refs?: string[];
@@ -0,0 +1,22 @@
1
+ export interface DirectFileDeleteRequest {
2
+ paths: string[];
3
+ }
4
+ export interface DirectFileDeleteResult {
5
+ deleted: string[];
6
+ }
7
+ /**
8
+ * Recognize only a closed, deterministic delete request. Anything ambiguous
9
+ * remains on the ordinary planner/implementor path.
10
+ *
11
+ * Supported examples:
12
+ * Delete only a.txt.
13
+ * Please delete only `a file.txt` and `b.txt`.
14
+ * Delete only a.txt. Do not create, modify, or delete any other file.
15
+ */
16
+ export declare function parseDirectFileDeleteRequest(text: string): DirectFileDeleteRequest | null;
17
+ /**
18
+ * Delete only the explicitly named regular files. All targets are validated
19
+ * before the first mutation; each unlink is bound to the captured parent and
20
+ * file incarnation and directory-fsynced by the anchored helper.
21
+ */
22
+ export declare function executeDirectFileDelete(cwd: string, request: DirectFileDeleteRequest): Promise<DirectFileDeleteResult>;
@@ -0,0 +1,81 @@
1
+ import type { AppSyncClient } from '../appsync';
2
+ import { type AuditBrowserModel } from './audit-browser';
3
+ import type { AuditFlagIndex } from './types';
4
+ /**
5
+ * Build the session-scoped flag index from a just-rendered `/audit` browser
6
+ * model. Called at the `/audit <task-id>` dispatch site on a successful
7
+ * render; the entrypoint retains the result via `AUDIT_FLAG_INDEX_RETAINED`
8
+ * (last render wins — the reducer carries the `flagged` set forward).
9
+ * Shape-only: coordinates + wire kind + the precomputed flaggable bit; the
10
+ * decrypted payload never leaves the render.
11
+ */
12
+ export declare function buildAuditFlagIndex(taskId: string, model: AuditBrowserModel): AuditFlagIndex;
13
+ /**
14
+ * The minimal AppSync surface `/flag` needs — the existing
15
+ * `recordExecutionEvent` Class-A method (D4: the full plumbing below it
16
+ * already exists). Narrowed so tests inject a stub without the full client.
17
+ */
18
+ export type FlagAppSyncClient = Pick<AppSyncClient, 'recordExecutionEvent'>;
19
+ export interface RunFlagCommandDeps {
20
+ /** The authenticated AppSync client. */
21
+ appsyncClient: FlagAppSyncClient;
22
+ /** The retained last-rendered `/audit` index (null → never rendered). */
23
+ index: AuditFlagIndex | null;
24
+ /** The `/flag <entry-id>` argument. */
25
+ entryId: string;
26
+ /** Optional free-text note (encrypted into the flag payload; never logged). */
27
+ note?: string;
28
+ /** The shell session (locator/emit scoping + session-key lookup). */
29
+ sessionId: string;
30
+ /** Test seam — defaults to `keychainManager.getSessionKey(sessionId)`. */
31
+ getSessionKeyFn?: (sessionId: string) => Promise<string | null>;
32
+ }
33
+ /**
34
+ * The outcome of a `/flag` run. Every arm carries a ready-to-render `line`;
35
+ * `runFlagCommand` NEVER throws (mirrors `runAuditBrowser`).
36
+ */
37
+ export type RunFlagCommandResult = {
38
+ kind: 'no_index';
39
+ line: string;
40
+ } | {
41
+ kind: 'unknown_entry';
42
+ line: string;
43
+ } | {
44
+ kind: 'not_flaggable';
45
+ line: string;
46
+ } | {
47
+ kind: 'missing_seq';
48
+ line: string;
49
+ } | {
50
+ kind: 'already_flagged';
51
+ line: string;
52
+ } | {
53
+ kind: 'no_session_key';
54
+ line: string;
55
+ } | {
56
+ kind: 'flagged';
57
+ entryId: string;
58
+ line: string;
59
+ } | {
60
+ kind: 'server_rejected';
61
+ line: string;
62
+ reason: string;
63
+ } | {
64
+ kind: 'error';
65
+ line: string;
66
+ reason: string;
67
+ };
68
+ /** `/flag` before any `/audit <task-id>` render — nothing to resolve against. */
69
+ export declare const FLAG_NO_INDEX_LINE: string;
70
+ /**
71
+ * Run `/flag <entry-id>`: retained-index resolve → client approve-subset
72
+ * check → locator + dedup-key construction → Class-A `FLAG_BAD_APPROVAL`
73
+ * emit with locator forwarding. Returns a discriminated result the shell
74
+ * renders; the CALLER dispatches `AUDIT_FLAG_RECORDED` on the `flagged` arm
75
+ * (the runner stays store-free, like `runAuditBrowser`).
76
+ */
77
+ export declare function runFlagCommand(deps: RunFlagCommandDeps): Promise<RunFlagCommandResult>;
78
+ /**
79
+ * Render a `RunFlagCommandResult` as the inline `/flag` shell output line.
80
+ */
81
+ export declare function renderFlagResultText(result: RunFlagCommandResult): string;
@@ -461,11 +461,32 @@ export interface ReviewSummaryTerminalModel {
461
461
  };
462
462
  readonly tokenUsage: {
463
463
  readonly knownTotal: number | null;
464
+ readonly knownInput: number | null;
465
+ readonly knownOutput: number | null;
466
+ readonly knownCachedInput: number | null;
464
467
  readonly availability: string;
465
468
  readonly unavailableRoles: ReadonlyArray<string>;
469
+ readonly invocations: ReadonlyArray<ReviewSummaryTokenInvocationModel>;
466
470
  };
467
471
  readonly residualRisks: ReadonlyArray<string>;
468
472
  }
473
+ export interface ReviewSummaryTokenInvocationModel {
474
+ readonly role: string;
475
+ readonly agent: string;
476
+ readonly taskId: string | null;
477
+ readonly trackIndex: number | null;
478
+ readonly round: number | null;
479
+ readonly gateId: string | null;
480
+ readonly seatId: number | null;
481
+ readonly reviewerRole: string | null;
482
+ readonly inputTokens: number | null;
483
+ readonly outputTokens: number | null;
484
+ readonly cachedInputTokens: number | null;
485
+ readonly totalTokens: number | null;
486
+ readonly elapsedMs: number | null;
487
+ readonly availability: string;
488
+ readonly unavailableReason: string | null;
489
+ }
469
490
  /**
470
491
  * The fully-extracted, render-ready per-round review summary model. PURE
471
492
  * function of the decrypted summary. `null`-attached (entry has no
@@ -518,8 +539,28 @@ export interface DecryptedReviewSummaryInput {
518
539
  };
519
540
  readonly tokenUsage?: {
520
541
  readonly knownTotal?: number;
542
+ readonly knownInput?: number;
543
+ readonly knownOutput?: number;
544
+ readonly knownCachedInput?: number;
521
545
  readonly availability?: string;
522
546
  readonly unavailableRoles?: ReadonlyArray<string>;
547
+ readonly invocations?: ReadonlyArray<{
548
+ readonly role?: string;
549
+ readonly agent?: string;
550
+ readonly taskId?: string;
551
+ readonly trackIndex?: number;
552
+ readonly round?: number;
553
+ readonly gateId?: string;
554
+ readonly seatId?: number;
555
+ readonly reviewerRole?: string;
556
+ readonly inputTokens?: number;
557
+ readonly outputTokens?: number;
558
+ readonly cachedInputTokens?: number;
559
+ readonly totalTokens?: number;
560
+ readonly elapsedMs?: number;
561
+ readonly availability?: string;
562
+ readonly unavailableReason?: string;
563
+ }>;
523
564
  };
524
565
  readonly residualRisks?: ReadonlyArray<string>;
525
566
  readonly rounds?: ReadonlyArray<{
@@ -4,13 +4,14 @@ import { Session } from '../types';
4
4
  import { OrchestrationStore } from './store';
5
5
  import { AdvisoryAttachmentJournal } from './advisory-attachment-journal';
6
6
  import type { ImageAttachment } from './types';
7
- import { type GroupDecisionSubmitDeps } from './gate-decision-submit';
7
+ import { type GateDecisionSubmitDeps, type GroupDecisionSubmitDeps } from './gate-decision-submit';
8
8
  import { type ContinuationCliResult, type ContinuationCliDeps } from './slash-routes/continuation';
9
9
  import { loadReviewerWizardData } from './slash-routes/reviewers';
10
10
  import { createShellEventEmitter } from './emit-shell-event';
11
11
  import { type AgentMentionIntent, type CommandIntentTarget } from './command-intent';
12
12
  import { type BrainstormPanelActiveAgent } from './brainstorm-quorum';
13
13
  import { type RunAuditBrowserResult } from './audit-runner';
14
+ import { type RunFlagCommandResult } from './flag-command';
14
15
  import { Tier } from './types';
15
16
  import type { ConversationEntry, PendingClarification } from './types';
16
17
  import { type GatePromptEnvelope, type DecryptedReviewSummaryInput } from './gate-prompts';
@@ -23,6 +24,7 @@ import type { LocalGemmaAdvisoryRunner } from '../planner/local-advisory';
23
24
  import type { LocalExecutor } from '../local-executor';
24
25
  import type { WorkItemInput, DisjointnessRejection, RevertManifestStore } from '../local-executor';
25
26
  import type { QuorumLoop } from './quorum-loop';
27
+ import { type InvocationUsageSnapshot } from '../reviewer/token-usage';
26
28
  import { ensureFreshContextStore } from './context-store';
27
29
  import type { EnsureFreshResult } from './context-store';
28
30
  import { contextItemOccurrence, type ContextDurabilityReceipt } from './context-items';
@@ -231,6 +233,7 @@ export { compactSessionContext, maybeFireCompactionSafetyValve, rehydrateSession
231
233
  export { routeSlashCommand, applySlashOutput, type SlashOutput, type ShellAction, } from './slash-router';
232
234
  export { buildAuditBrowserModel, routeAuditEntry, auditKindLabel, auditKindCopy, renderAuditBrowserText, renderAuditEntryText, ENTRY_DETAILS_UNAVAILABLE, NO_AUDIT_ENTRIES, AUDIT_LOG_TOO_LARGE, AUDIT_LOG_TITLE, AUDIT_BROWSER_MAX_HEADLINE, WIRE_PUBLIC_PLAINTEXT_KINDS, type AuditBrowserModel, type AuditEntryModel, type AuditReviewerVerdictModel, type AuditTaskAuthorizedModel, type DecryptContentFn, } from './audit-browser';
233
235
  export { runAuditBrowser, renderAuditResultText, AUDIT_BROWSER_UPGRADE_HINT, type RunAuditBrowserResult, type RunAuditBrowserDeps, } from './audit-runner';
236
+ export { buildAuditFlagIndex, runFlagCommand, renderFlagResultText, FLAG_NO_INDEX_LINE, type RunFlagCommandResult, type RunFlagCommandDeps, type FlagAppSyncClient, } from './flag-command';
234
237
  export { AuditLogPanel } from './components/AuditLogPanel';
235
238
  export { reducer } from './reducer';
236
239
  export { createOrchestrationStore, type OrchestrationStore } from './store';
@@ -385,7 +388,18 @@ export declare function handleSubscribedEvent(event: Event, store: Orchestration
385
388
  * and DROPS (never crashes the shell, never submits ciphertext). Async — the sync
386
389
  * subscription callback fires-and-forgets via `void`; every throw is caught here.
387
390
  */
388
- export declare function routeMobileUserPrompt(event: Event, sessionKeyResolver: ((sessionId: string) => Promise<string | null>) | undefined, submit: (text: string, images?: string[], options?: ShellSubmitOptions) => Promise<void>, updateEventStatus?: (input: UpdateEventStatusInput) => Promise<unknown>): Promise<void>;
391
+ export declare function routeMobileUserPrompt(event: Event, sessionKeyResolver: ((sessionId: string) => Promise<string | null>) | undefined, submit: (text: string, images?: string[], options?: ShellSubmitOptions) => Promise<void>, updateEventStatus?: (input: UpdateEventStatusInput) => Promise<unknown>): Promise<boolean>;
392
+ /**
393
+ * Route a mobile composer reply through the desktop's canonical gate state
394
+ * machine. Mobile always transports the text as an encrypted `USER_PROMPT`;
395
+ * only the desktop that owns the live prompt interprets it as a numbered
396
+ * option, a required note, `/cancel`, or ordinary free text.
397
+ *
398
+ * Returns `true` only when the active gate consumed the input. A non-numeric
399
+ * line against an awaiting-number gate remains an ordinary prompt and returns
400
+ * `false`, matching the desktop TTY behavior.
401
+ */
402
+ export declare function routeMobileGatePromptInput(deps: GateDecisionSubmitDeps, text: string): Promise<boolean>;
389
403
  /**
390
404
  * Build the single `(event) => void` callback the AppSync events subscription
391
405
  * invokes. Routes each delivered event to exactly ONE handler:
@@ -790,6 +804,14 @@ export interface HandleShellUserInputDeps extends StructuralSummaryRunDeps {
790
804
  * rewrite without live fetch / decrypt.
791
805
  */
792
806
  runAuditBrowserFn?: (taskId: string) => Promise<RunAuditBrowserResult>;
807
+ /**
808
+ * O1 C1 (#652) — Test seam for the async `/flag <entry-id>` dispatch.
809
+ * Defaults to `runFlagCommand` over `args.appsyncClient` + the retained
810
+ * `store` flag index + `args.session.sessionId`. Tests inject a stub to
811
+ * drive the PENDING-marker rewrite (+ the `AUDIT_FLAG_RECORDED` dispatch
812
+ * on the `flagged` arm) without live emit / keychain I/O.
813
+ */
814
+ runFlagCommandFn?: (entryId: string, note?: string) => Promise<RunFlagCommandResult>;
793
815
  /**
794
816
  * CP-4 §4.2 — Test seam for the pre-classify context-store refresh. Defaults
795
817
  * to the real `ensureFreshContextStore` (probe → recompute-if-stale → persist
@@ -843,10 +865,12 @@ export interface HandleShellUserInputDeps extends StructuralSummaryRunDeps {
843
865
  * could overlap and interleave the clarification state machine
844
866
  * (USER_INPUT bookkeeping + classify + PLANNER_DECISION), corrupting it.
845
867
  *
846
- * Slash commands (`text.startsWith('/')`, matching `handleShellUserInput`'s own
847
- * routing) bypass the queue: they're fast, never trigger a planner classify,
848
- * never touch clarification state, and include `/quit` — so they must stay
849
- * responsive instead of waiting behind a slow/hung planner turn.
868
+ * Slash commands (`text.trimStart().startsWith('/')`, matching
869
+ * `handleShellUserInput`'s own routing) bypass the queue: they're fast, never
870
+ * trigger a planner classify, never touch clarification state, and include
871
+ * `/quit` — so they must stay responsive instead of waiting behind a slow/hung
872
+ * planner turn. Leading paste whitespace is presentation noise, not permission
873
+ * to reinterpret an explicit command as natural language.
850
874
  *
851
875
  * The returned function preserves the caller-visible contract: it returns the
852
876
  * promise for THIS submission's processing (so an awaiting caller still gets the
@@ -936,6 +960,7 @@ export interface BrainstormTurnOwnership {
936
960
  authorAgent: BrainstormPanelActiveAgent;
937
961
  status: 'completed' | 'quota_walled' | 'failed';
938
962
  boundedBody: string;
963
+ usage: InvocationUsageSnapshot;
939
964
  }>;
940
965
  prompt: {
941
966
  kind: 'legacy_joined';
@@ -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
@@ -963,6 +963,14 @@ export declare class QuorumLoop {
963
963
  * This also makes concurrent B.1+B.2 safe (no per-op toggle race).
964
964
  */
965
965
  private recoverySeedingDepth;
966
+ /**
967
+ * Recovery B.1 and B.2 can overlap. A per-call two-row batch is therefore
968
+ * insufficient: two concurrent calls could each launch two implementors.
969
+ * These permits are owned by the QuorumLoop/session and cover the complete
970
+ * `launchRecoveredTrack` operation across every recovery entry path.
971
+ */
972
+ private activeRecoveryRelaunches;
973
+ private readonly recoveryRelaunchWaiters;
966
974
  /**
967
975
  * Every asynchronously delivered session coroutine that can reach a task
968
976
  * workspace: Class-B consumption, shadow recovery, and B.1/B.2 team
@@ -978,6 +986,10 @@ export declare class QuorumLoop {
978
986
  private startSessionWork;
979
987
  private admittedSessionWorkMayContinue;
980
988
  private trackTeamRecovery;
989
+ private acquireRecoveryRelaunchPermit;
990
+ private releaseRecoveryRelaunchPermit;
991
+ private cancelRecoveryRelaunchWaiters;
992
+ private withRecoveryRelaunchPermit;
981
993
  /**
982
994
  * §4.3 — TEAM Class B packets buffered while the recovery seed barrier is up
983
995
  * (`recoverySeedingDepth > 0`). Drained through the normal live handlers AFTER
@@ -1083,8 +1095,11 @@ export declare class QuorumLoop {
1083
1095
  * never call each other), so it cannot self-deadlock.
1084
1096
  */
1085
1097
  private readonly shadowOpsByTask;
1098
+ /** Abort only the read-only waits owned by non-draining startup recovery. */
1099
+ private readonly backgroundRecoveryAbortControllers;
1086
1100
  /** Once set, no new implementor workspace may be created for this session. */
1087
1101
  private shuttingDown;
1102
+ private awaitBackgroundRecoveryStep;
1088
1103
  /**
1089
1104
  * Serialize one shadow lifecycle op for `taskId` behind any in-flight op for
1090
1105
  * the same task. The op's result/rejection is returned to ITS caller; a
@@ -1447,7 +1462,7 @@ export declare class QuorumLoop {
1447
1462
  * Gemini/Antigravity are out of scope (undefined). NEVER throws — a read/parse
1448
1463
  * failure yields `undefined` (segment simply omitted), never breaks the round.
1449
1464
  */
1450
- private extractImplementorTokens;
1465
+ private extractImplementorUsage;
1451
1466
  /**
1452
1467
  * PHASE-589/469 W1+W2 (LOCK #589-E/F/H) — on a TEAM track local hard-fail (any
1453
1468
  * of the 4 closed reasons: `verification_failure` / `out_of_scope_write` /
@@ -1529,6 +1544,35 @@ export declare class QuorumLoop {
1529
1544
  * `TaskGroupHalted` convergence is the authoritative group resolution).
1530
1545
  */
1531
1546
  reportTeamTrackUserResolved(taskId: string, postAction: PostDecisionAction): void;
1547
+ /**
1548
+ * H3 / Option B (#657) — emit the POSITIVE cancel-confirmation milestone on the
1549
+ * final-approval CANCEL path. Final-approval "Do not apply. Leave the task in its
1550
+ * current state" RETAINS the shadow and mutates nothing, so it triggers NEITHER
1551
+ * the promote (`promoted`) NOR the discard (`discarded`) milestone — the decision
1552
+ * was previously SILENT in non-TTY (a canceling user got no confirmation, and the
1553
+ * E2E harness had no positive signal to assert, so an unwired/hung Cancel was
1554
+ * indistinguishable from a correct one). This emits `not_applied` ("Not applied —
1555
+ * your tree is unchanged") so the user AND the harness get a positive terminal
1556
+ * that the Cancel actually resolved.
1557
+ *
1558
+ * SELF-GUARDING single source of truth: fires ONLY for a `final_approval_resolved`
1559
+ * postAction whose `decision` is NOT `approve` (Approve promotes via the
1560
+ * TaskAuthorized edge → `promoted`; Abort/Reject-restart discard → `discarded`; an
1561
+ * `open_new_round`/`continuation_switch_*` postAction keeps working, no terminal).
1562
+ * Reuses the SAME `approve`-vs-else discriminator the engine's
1563
+ * `handle_final_approval` + `postActionTeamTrackState` use
1564
+ * (`decision.trim().toLowerCase()`), so it can never diverge from the
1565
+ * Passed/Failed track classification.
1566
+ *
1567
+ * Fires for BOTH single-impl and team tracks (unlike the team-only
1568
+ * `reportTeamTrackUserResolved`) — every Cancel deserves the confirmation. Called
1569
+ * by the shell's `onTerminalDecision` (the shared TTY + non-TTY gate-resolution
1570
+ * chokepoint) after a successful `applyUserDecision`. `emitProgress` already wraps
1571
+ * the listener so a throwing consumer can NEVER break the decision path. NO
1572
+ * wire/schema change (progress is desktop-LOCAL) — `not_applied` carries ONLY the
1573
+ * taskId (SECURITY INVARIANT: no user content, mirrors `discarded`).
1574
+ */
1575
+ reportFinalApprovalCancelled(taskId: string, postAction: PostDecisionAction): void;
1532
1576
  /**
1533
1577
  * Authoritative TaskGroupHalted bridge from LocalExecutor. Calling this async
1534
1578
  * method publishes the terminal group fence synchronously (before its first
@@ -1777,6 +1821,20 @@ export declare class QuorumLoop {
1777
1821
  * RUNS (it always runs; the badge only informs the user).
1778
1822
  */
1779
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;
1780
1838
  /**
1781
1839
  * Wave B §2.1 confinement TRI-STATE for a merge-gate model/reviewer invocation
1782
1840
  * (LOCK #C14-MOAT). Path A: the CP-7 substrate/broker (not opted out + a Trusted
@@ -1944,7 +2002,9 @@ export declare class QuorumLoop {
1944
2002
  * while `pending` and un-expired), so the approved code is never lost; a
1945
2003
  * re-delivered packet (or the next live edge) promotes it.
1946
2004
  */
1947
- recoverShadows(): Promise<void>;
2005
+ recoverShadows(opts?: {
2006
+ drainOnShutdown?: boolean;
2007
+ }): Promise<void>;
1948
2008
  private recoverShadowsOwned;
1949
2009
  /**
1950
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
  } | {
@@ -66,6 +69,9 @@ export type TaskProgressEvent = ({
66
69
  } | {
67
70
  phase: 'discarded';
68
71
  taskId?: string;
72
+ } | {
73
+ phase: 'not_applied';
74
+ taskId?: string;
69
75
  } | {
70
76
  phase: 'waiting_user';
71
77
  } | {
@@ -379,6 +379,7 @@ export type ConversationEntry = {
379
379
  serverDecision: string | null;
380
380
  };
381
381
  reviewSummary?: ReviewSummaryPanelModel;
382
+ queuedReviewSummaries?: Readonly<Record<string, ReviewSummaryPanelModel>>;
382
383
  } | {
383
384
  kind: 'gate-panel';
384
385
  id: string;
@@ -667,6 +668,57 @@ export interface OrchestrationState {
667
668
  * keyboard focus. Non-team / Companion / CP-1.a sessions never open it.
668
669
  */
669
670
  reviewerWizard: ReviewerWizardState | null;
671
+ /**
672
+ * `[ADDITIVE WIDENING — O1 C1 (#652)]` per
673
+ * PHASE-O1-C1-SAFETY-OBSERVABILITY-DESIGN.md §3.1 item 1: the shell used to
674
+ * render and DISCARD the `/audit` browser model; `/flag <entry-id>` needs
675
+ * session-scoped retention of the LAST-rendered listing's
676
+ * `entryId → {seqNum, kind, flaggable}` mapping to build the plaintext
677
+ * target locator without re-querying. `null` until the first successful
678
+ * `/audit <task-id>` render. Desktop-local only; row COORDINATES + closed
679
+ * enum labels only — never decrypted payload content.
680
+ */
681
+ auditFlagIndex: AuditFlagIndex | null;
682
+ }
683
+ /**
684
+ * One retained `/audit` listing row, keyed by its audit `entry_id` in
685
+ * {@link AuditFlagIndex.entries}. Shape-only: row coordinates + the plaintext
686
+ * wire kind + the precomputed flag-eligibility bit (derived from the decrypted
687
+ * `gate_resolved` outcome at render time — the decrypted payload itself is
688
+ * NOT retained).
689
+ */
690
+ export interface AuditFlagEntryRecord {
691
+ /**
692
+ * The flagged row's audit-table sort key — the zero-padded 16-digit
693
+ * `seqNum` string exactly as surfaced by `queryAudit`'s additive
694
+ * `AuditEntryWireRow.seqNum` projection (core-rs `types.rs`), or `null`
695
+ * when the row predates the projection (stale backend) — `/flag` then
696
+ * fails closed with an actionable message.
697
+ */
698
+ seqNum: string | null;
699
+ /** Plaintext snake_case wire kind (e.g. `gate_resolved`). */
700
+ kind: string;
701
+ /**
702
+ * True iff the entry is a decrypted `gate_resolved` row whose outcome is
703
+ * the quorum's approve consensus (`consensus_approve` / `proceed`) — the
704
+ * client-side defense-in-depth subset check of design §3.1 item 1 (the
705
+ * server independently enforces the same subset, §3.1 item 4).
706
+ */
707
+ flaggable: boolean;
708
+ }
709
+ /**
710
+ * The session-scoped retained `/audit` mapping (design §3.1 item 1). Replaced
711
+ * wholesale on each successful `/audit <task-id>` render (last render wins);
712
+ * `flagged` carries forward across renders so "already flagged" survives
713
+ * re-listing. Lives in {@link OrchestrationState.auditFlagIndex}.
714
+ */
715
+ export interface AuditFlagIndex {
716
+ /** The task whose listing was rendered — becomes `flaggedTaskId`. */
717
+ taskId: string;
718
+ /** `entryId → record` for every entry in the last-rendered listing. */
719
+ entries: Map<string, AuditFlagEntryRecord>;
720
+ /** Entry ids flagged this session (dedup no-op render on repeat `/flag`). */
721
+ flagged: Set<string>;
670
722
  }
671
723
  /**
672
724
  * Snapshot threaded into the interactive `/reviewer-setup` wizard when it
@@ -853,6 +905,12 @@ export type OrchestrationAction = {
853
905
  wizard: ReviewerWizardState;
854
906
  } | {
855
907
  type: 'REVIEWER_WIZARD_CLOSE';
908
+ } | {
909
+ type: 'AUDIT_FLAG_INDEX_RETAINED';
910
+ index: AuditFlagIndex;
911
+ } | {
912
+ type: 'AUDIT_FLAG_RECORDED';
913
+ entryId: string;
856
914
  } | {
857
915
  type: 'EXIT';
858
916
  };
@@ -15,6 +15,21 @@ export interface WorkspaceShutdownOperations {
15
15
  onPlannerFlushFailure?: (error: Error) => void;
16
16
  onWorkspaceFailure?: (error: Error) => void;
17
17
  }
18
+ export interface StartedWorkspaceShutdown {
19
+ /**
20
+ * Every teardown phase, including best-effort planner flush and hosted
21
+ * retirement. This is the operation governed by the shell's normal/signal
22
+ * responsiveness deadline.
23
+ */
24
+ completion: Promise<void>;
25
+ /**
26
+ * The local resource-retirement boundary. A normal process exit must await
27
+ * this even after the broader teardown deadline expires, otherwise a large
28
+ * authenticated snapshot deletion can be killed halfway through and leak its
29
+ * private workspace.
30
+ */
31
+ resourceRetirement: Promise<void>;
32
+ }
18
33
  /**
19
34
  * Start every independent shutdown fence before awaiting any one owner.
20
35
  *
@@ -24,4 +39,9 @@ export interface WorkspaceShutdownOperations {
24
39
  * LocalExecutor drains settle can the durable store be enumerated exactly once
25
40
  * without a late publisher recreating a group behind the cleanup pass.
26
41
  */
42
+ export declare function startWorkspaceShutdownOperations(operations: WorkspaceShutdownOperations): StartedWorkspaceShutdown;
43
+ /**
44
+ * Compatibility surface for callers that need the complete shutdown rather
45
+ * than its separately-observable local resource boundary.
46
+ */
27
47
  export declare function runWorkspaceShutdownOperations(operations: WorkspaceShutdownOperations): Promise<void>;
@@ -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;
@@ -3,6 +3,7 @@ import { type SubprocessOutcome } from '../subprocess.js';
3
3
  import type { ReviewerVerdict } from '../types.js';
4
4
  import { type VerdictClassifier } from '../verdict-classifier.js';
5
5
  import type { BuiltCommand } from './claude.js';
6
+ import { type InvocationUsageSnapshot } from '../token-usage.js';
6
7
  /** Construction options. */
7
8
  export interface CodexReviewerProviderOptions {
8
9
  /** Override the `codex` executable path. Production callers pass nothing
@@ -58,15 +59,16 @@ export declare function buildCommand(executable: string, spec: ReviewerSpec, las
58
59
  export declare function buildVerdict(spec: ReviewerSpec, gateId: string, outcome: SubprocessOutcome, lastMessage: string, classifyVerdict?: VerdictClassifier): Promise<ReviewerVerdict>;
59
60
  /**
60
61
  * Sum `usage.input_tokens + usage.output_tokens` across every
61
- * `turn.completed` JSONL event in `stdout`. Returns `null` when no
62
- * `turn.completed` event reported any token count, so dashboards can
63
- * distinguish "no data" from a real zero.
62
+ * `turn.completed` JSONL event in `stdout`. Returns `null` when usage is absent,
63
+ * partial, or invalid so legacy call sites do not turn unknown values into a
64
+ * false complete total.
64
65
  *
65
66
  * Lenient: malformed JSONL lines are silently skipped (Codex's stream is
66
67
  * designed to be append-only, so partial flushes during timeout could
67
68
  * leave a final truncated line).
68
69
  */
69
70
  export declare function sumCodexTokens(stdout: string): number | null;
71
+ export declare function extractCodexUsageSnapshot(stdout: string, elapsedMs?: number | null): InvocationUsageSnapshot;
70
72
  /**
71
73
  * Generate a unique-per-spawn path for `--output-last-message`. Lives in
72
74
  * the OS temp dir; we own its lifecycle (create on codex's side, read +