@quantiya/codevibe-core 2.0.6 → 2.0.7

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 (159) hide show
  1. package/README.md +7 -5
  2. package/dist/agy-cli-contract.d.ts +14 -0
  3. package/dist/appsync/appsync-client.d.ts +59 -31
  4. package/dist/appsync/event-throttle.d.ts +33 -0
  5. package/dist/appsync/index.d.ts +3 -2
  6. package/dist/appsync/queries.d.ts +4 -2
  7. package/dist/auth/auth-telemetry.d.ts +26 -0
  8. package/dist/auth/vendor-key-cli.d.ts +49 -0
  9. package/dist/companion-mode/index.d.ts +36 -22
  10. package/dist/companion-mode/persist-preference.d.ts +1 -5
  11. package/dist/companion-mode/resolve-agent.d.ts +5 -4
  12. package/dist/config/config.d.ts +0 -5
  13. package/dist/credential-broker/__tests__/upstream-result-helpers.d.ts +21 -0
  14. package/dist/credential-broker/broker.d.ts +196 -12
  15. package/dist/credential-broker/chatgpt-config.d.ts +40 -0
  16. package/dist/credential-broker/index.d.ts +4 -1
  17. package/dist/credential-broker/oauth-account-lock.d.ts +104 -0
  18. package/dist/credential-broker/oauth-refresh.d.ts +72 -0
  19. package/dist/credential-broker/types.d.ts +165 -17
  20. package/dist/credential-broker/upstream-client.d.ts +3 -2
  21. package/dist/credential-broker/vendor-key-store.d.ts +32 -1
  22. package/dist/crypto/__tests__/encrypt-for-emit.test.d.ts +1 -0
  23. package/dist/crypto/encrypt-for-emit.d.ts +39 -0
  24. package/dist/crypto/index.d.ts +2 -0
  25. package/dist/daemon/__tests__/process-guards.test.d.ts +1 -0
  26. package/dist/daemon/index.d.ts +2 -0
  27. package/dist/daemon/process-guards.d.ts +38 -0
  28. package/dist/index.d.ts +17 -2
  29. package/dist/index.js +308 -281
  30. package/dist/keychain/keychain-manager.d.ts +25 -4
  31. package/dist/local-executor/__tests__/reviewer-rationale-flag.test.d.ts +1 -0
  32. package/dist/local-executor/class-a-sign.d.ts +15 -0
  33. package/dist/local-executor/group-decision-outcome.d.ts +11 -0
  34. package/dist/local-executor/implementor-argv.d.ts +89 -7
  35. package/dist/local-executor/local-executor-impl.d.ts +18 -7
  36. package/dist/local-executor/merge-conflict-resolve.d.ts +19 -0
  37. package/dist/local-executor/revert-reconcile.d.ts +12 -0
  38. package/dist/local-executor/reviewer-rationale-flag.d.ts +10 -0
  39. package/dist/local-executor/types.d.ts +1 -0
  40. package/dist/local-model/manager.d.ts +1 -1
  41. package/dist/local-model/ollama.d.ts +40 -0
  42. package/dist/orchestration/__tests__/detect-agents.test.d.ts +1 -0
  43. package/dist/orchestration/detect-agents.d.ts +10 -30
  44. package/dist/orchestration/index.d.ts +1 -2
  45. package/dist/orchestration-shell/__tests__/a1a-planner-offers.test.d.ts +1 -0
  46. package/dist/orchestration-shell/__tests__/a6-cli-surface.test.d.ts +1 -0
  47. package/dist/orchestration-shell/__tests__/advisory-attachments-dir-race.test.d.ts +1 -0
  48. package/dist/orchestration-shell/__tests__/advisory-multi-mention-panel.test.d.ts +1 -0
  49. package/dist/orchestration-shell/__tests__/advisory-panel-attachments.test.d.ts +1 -0
  50. package/dist/orchestration-shell/__tests__/advisory-quota-stdout-result.test.d.ts +1 -0
  51. package/dist/orchestration-shell/__tests__/agent-turn-context-batch.test.d.ts +1 -0
  52. package/dist/orchestration-shell/__tests__/bounded-shutdown.test.d.ts +1 -0
  53. package/dist/orchestration-shell/__tests__/brainstorm-quorum-wiring.test.d.ts +1 -0
  54. package/dist/orchestration-shell/__tests__/brainstorm-quorum.test.d.ts +1 -0
  55. package/dist/orchestration-shell/__tests__/cli-team-session-key.test.d.ts +1 -0
  56. package/dist/orchestration-shell/__tests__/command-intent.test.d.ts +1 -0
  57. package/dist/orchestration-shell/__tests__/context-compaction.test.d.ts +1 -0
  58. package/dist/orchestration-shell/__tests__/context-items-hosted-sync.test.d.ts +1 -0
  59. package/dist/orchestration-shell/__tests__/context-items-wiring.test.d.ts +1 -0
  60. package/dist/orchestration-shell/__tests__/context-items.test.d.ts +1 -0
  61. package/dist/orchestration-shell/__tests__/cp8-full-team-events.test.d.ts +1 -0
  62. package/dist/orchestration-shell/__tests__/cp8-team-decomposed-zk.test.d.ts +1 -0
  63. package/dist/orchestration-shell/__tests__/explicit-tty-exit.test.d.ts +1 -0
  64. package/dist/orchestration-shell/__tests__/mention-suggest.test.d.ts +1 -0
  65. package/dist/orchestration-shell/__tests__/route-browse-summarize-recovery.test.d.ts +1 -0
  66. package/dist/orchestration-shell/attachments.d.ts +58 -2
  67. package/dist/orchestration-shell/bounded-shutdown.d.ts +16 -0
  68. package/dist/orchestration-shell/brainstorm-quorum.d.ts +118 -0
  69. package/dist/orchestration-shell/cli.d.ts +97 -70
  70. package/dist/orchestration-shell/cli.js +30990 -22426
  71. package/dist/orchestration-shell/command-intent.d.ts +56 -0
  72. package/dist/orchestration-shell/components/InputBar.d.ts +6 -0
  73. package/dist/orchestration-shell/components/OrchestrationApp.d.ts +2 -0
  74. package/dist/orchestration-shell/context-compaction.d.ts +264 -0
  75. package/dist/orchestration-shell/context-items-hosted-sync.d.ts +19 -0
  76. package/dist/orchestration-shell/context-items.d.ts +408 -0
  77. package/dist/orchestration-shell/context-store.d.ts +162 -0
  78. package/dist/orchestration-shell/emit-shell-event.d.ts +34 -13
  79. package/dist/orchestration-shell/explicit-tty-exit.d.ts +18 -0
  80. package/dist/orchestration-shell/gate-prompts.d.ts +3 -3
  81. package/dist/orchestration-shell/index.d.ts +306 -37
  82. package/dist/orchestration-shell/mention-suggest.d.ts +11 -0
  83. package/dist/orchestration-shell/mode-selection.d.ts +4 -22
  84. package/dist/orchestration-shell/quorum-loop.d.ts +336 -20
  85. package/dist/orchestration-shell/task-progress.d.ts +2 -0
  86. package/dist/orchestration-shell/team-decompose.d.ts +37 -19
  87. package/dist/orchestration-shell/types.d.ts +71 -4
  88. package/dist/planner/index.d.ts +1 -1
  89. package/dist/planner/local-advisory.d.ts +12 -0
  90. package/dist/planner/local-gemma.d.ts +27 -0
  91. package/dist/planner/types.d.ts +7 -0
  92. package/dist/reviewer/index.d.ts +0 -2
  93. package/dist/reviewer/provider.d.ts +9 -6
  94. package/dist/reviewer/providers/antigravity.d.ts +2 -3
  95. package/dist/reviewer/registry.d.ts +9 -4
  96. package/dist/reviewer/token-usage.d.ts +10 -0
  97. package/dist/session/__tests__/device-registration-lease.test.d.ts +1 -0
  98. package/dist/session/__tests__/pending-session-create.test.d.ts +1 -0
  99. package/dist/session/__tests__/session-rekey-fingerprint.test.d.ts +1 -0
  100. package/dist/session/__tests__/session-resume-key-reconciliation.test.d.ts +1 -0
  101. package/dist/session/__tests__/session-resume-pending-first.test.d.ts +1 -0
  102. package/dist/session/device-key-watcher.d.ts +1 -0
  103. package/dist/session/index.d.ts +4 -2
  104. package/dist/session/pending-session-create.d.ts +61 -0
  105. package/dist/session/register-device-key.d.ts +11 -1
  106. package/dist/session/session-rekey.d.ts +4 -5
  107. package/dist/session/session-resume.d.ts +21 -1
  108. package/dist/substrate/docker.d.ts +7 -0
  109. package/dist/substrate/sandbox-exec.d.ts +17 -3
  110. package/dist/substrate/types.d.ts +32 -3
  111. package/dist/substrate-launch/apikey-bootstrap.d.ts +24 -1
  112. package/dist/substrate-launch/engage-substrate.d.ts +17 -0
  113. package/dist/substrate-launch/sanitized-env.d.ts +5 -5
  114. package/dist/tool-activity/__tests__/consolidator.test.d.ts +1 -0
  115. package/dist/tool-activity/__tests__/digest.test.d.ts +1 -0
  116. package/dist/tool-activity/__tests__/flock-rollout-lock.test.d.ts +1 -0
  117. package/dist/tool-activity/__tests__/ledger.test.d.ts +1 -0
  118. package/dist/tool-activity/__tests__/outbox.test.d.ts +1 -0
  119. package/dist/tool-activity/__tests__/replay-cursor.test.d.ts +1 -0
  120. package/dist/tool-activity/__tests__/session-map.test.d.ts +1 -0
  121. package/dist/tool-activity/__tests__/socket-rollout-lock.test.d.ts +1 -0
  122. package/dist/tool-activity/atomic-file.d.ts +27 -0
  123. package/dist/tool-activity/consolidator.d.ts +253 -0
  124. package/dist/tool-activity/digest.d.ts +4 -0
  125. package/dist/tool-activity/flock-rollout-lock.d.ts +68 -0
  126. package/dist/tool-activity/index.d.ts +9 -0
  127. package/dist/tool-activity/ledger.d.ts +274 -0
  128. package/dist/tool-activity/outbox.d.ts +60 -0
  129. package/dist/tool-activity/replay-cursor.d.ts +156 -0
  130. package/dist/tool-activity/session-map.d.ts +133 -0
  131. package/dist/tool-activity/socket-rollout-lock.d.ts +57 -0
  132. package/dist/tool-activity/types.d.ts +368 -0
  133. package/dist/types/encryption.d.ts +4 -0
  134. package/dist/types/events.d.ts +24 -4
  135. package/dist/types/session.d.ts +32 -2
  136. package/package.json +5 -4
  137. package/dist/orchestration/orchestration-cli.d.ts +0 -12
  138. package/dist/orchestration/setup-bootstrap.d.ts +0 -146
  139. package/dist/orchestration/setup-failure-recourse.d.ts +0 -23
  140. package/dist/orchestration/setup-save.d.ts +0 -47
  141. package/dist/orchestration/setup-seat-picker.d.ts +0 -72
  142. package/dist/orchestration/setup-telemetry.d.ts +0 -54
  143. package/dist/orchestration/setup-test-agents.d.ts +0 -108
  144. package/dist/orchestration/setup-types.d.ts +0 -146
  145. package/dist/orchestration/setup-wizard.d.ts +0 -57
  146. package/dist/orchestration-shell/cohort-flag.d.ts +0 -16
  147. package/dist/reviewer/providers/gemini.d.ts +0 -109
  148. /package/dist/{companion-mode/__tests__/detect-parallel.test.d.ts → appsync/__tests__/appsync-client-context-items.test.d.ts} +0 -0
  149. /package/dist/{orchestration-shell/__tests__/cli-stub-session-adapter.test.d.ts → appsync/__tests__/heartbeat-active.test.d.ts} +0 -0
  150. /package/dist/{orchestration/__tests__/setup-bootstrap.test.d.ts → appsync/__tests__/orphan-sweep-null-heartbeat.test.d.ts} +0 -0
  151. /package/dist/{orchestration/__tests__/setup-failure-recourse.test.d.ts → auth/__tests__/vendor-key-cli.test.d.ts} +0 -0
  152. /package/dist/{orchestration/__tests__/setup-save.test.d.ts → companion-mode/__tests__/mode-selected-emit.test.d.ts} +0 -0
  153. /package/dist/{orchestration/__tests__/setup-seat-picker.test.d.ts → companion-mode/__tests__/private-launcher-detection.test.d.ts} +0 -0
  154. /package/dist/{orchestration/__tests__/setup-telemetry.test.d.ts → companion-mode/__tests__/private-launcher-path.test.d.ts} +0 -0
  155. /package/dist/{orchestration/__tests__/setup-test-agents.test.d.ts → credential-broker/__tests__/broker-c4.test.d.ts} +0 -0
  156. /package/dist/{orchestration/__tests__/setup-types.test.d.ts → credential-broker/__tests__/broker-streaming.test.d.ts} +0 -0
  157. /package/dist/{orchestration/__tests__/setup-wizard.test.d.ts → credential-broker/__tests__/chatgpt-config.test.d.ts} +0 -0
  158. /package/dist/{reviewer/providers/__tests__/gemini-live-smoke.test.d.ts → credential-broker/__tests__/oauth-account-lock.test.d.ts} +0 -0
  159. /package/dist/{reviewer/providers/__tests__/gemini.test.d.ts → credential-broker/__tests__/oauth-refresh.test.d.ts} +0 -0
@@ -1,7 +1,38 @@
1
+ import { PassThrough } from "node:stream";
1
2
  import { type StrictAuditSink } from "./audit-sink";
2
3
  import { getProviderConfig } from "./broker-config";
3
4
  import { type RotationHandle } from "./broker-token";
4
- import { type BrokerRequest, type BrokerResponse, type BrokerToken, type ModelGatewayBroker, type UpstreamClient, type VendorKeyStore, type VendorProvider } from "./types";
5
+ import { type RefreshTransport } from "./oauth-refresh";
6
+ import { OAuthAccountLock } from "./oauth-account-lock";
7
+ import { type BrokerHandled, type BrokerRequest, type BrokerResponse, type BrokerToken, type ModelGatewayBroker, type ResponseSink, type UpstreamClient, type VendorKeyStore, type VendorOAuthBundle, type VendorProvider } from "./types";
8
+ /**
9
+ * PHASE-643 §3.3 — the streaming STALL meter: a `PassThrough`-derived stage that
10
+ * OWNS the idle timer (there is NO outer timer variable — agy R5, eliminating
11
+ * the stale-reference leak structurally). It ARMS the timer at construction,
12
+ * RE-ARMS it per chunk, calls `onIdle()` (→ `reg.controller.abort()`) on fire,
13
+ * and DISARMS it in `_destroy()`.
14
+ *
15
+ * Arm-order pin (Stage-1 v10): the timer arms LAZILY in `_construct` — which
16
+ * Node invokes AFTER `new IdleMeter(...)` has returned and been assigned to
17
+ * `meter` — so a constructor throw could never leave an armed timer that
18
+ * `meter?.destroy()` cannot reach. `autoDestroy` is pinned `true` (the Node
19
+ * default; pipeline explicitly skips destroying naturally-completed streams, so
20
+ * `autoDestroy` is what runs `_destroy` — and thus disarms the timer — on a
21
+ * successful stream), guaranteeing no timer survives a completed stream and no
22
+ * spurious late abort can fire.
23
+ */
24
+ export declare class IdleMeter extends PassThrough {
25
+ private readonly idleMs;
26
+ private readonly onIdle;
27
+ private idleTimer;
28
+ private disarmed;
29
+ constructor(idleMs: number, onIdle: () => void);
30
+ _construct(callback: (err?: Error | null) => void): void;
31
+ _transform(chunk: unknown, _enc: BufferEncoding, cb: (err?: Error | null, data?: unknown) => void): void;
32
+ _destroy(err: Error | null, cb: (err?: Error | null) => void): void;
33
+ private arm;
34
+ private disarm;
35
+ }
5
36
  /**
6
37
  * Construction-time dependencies. All injectable so W1 unit-tests run
7
38
  * against stubs (no network, deterministic audit ACKs). Defaults wire the
@@ -18,7 +49,38 @@ export interface BrokerDeps {
18
49
  vendorKeyStore?: VendorKeyStore;
19
50
  /** Strict audit sink (defaults to the in-memory stub until W3, §3.5). */
20
51
  auditSink?: StrictAuditSink;
52
+ /**
53
+ * PHASE-626 §5 — the C4 refresh transport (token endpoint). Defaults to the
54
+ * hardened `FetchRefreshTransport`. Injected as a stub in tests.
55
+ */
56
+ refreshTransport?: RefreshTransport;
57
+ /**
58
+ * PHASE-626 §5 — the cross-process OAuth-account lock for the (single) C4
59
+ * provider `openai`. Defaults to the portable `mkdir`-lock at
60
+ * `defaultOAuthLockDir("vendor-oauth-openai")`. Injected in tests.
61
+ */
62
+ oauthLock?: OAuthAccountLock;
63
+ /** Proactive-refresh age threshold (ms). Test override. */
64
+ proactiveRefreshThresholdMs?: number;
65
+ /** stop() bounded-drain timeout (ms). Test override. */
66
+ stopDrainTimeoutMs?: number;
67
+ /** Injectable clock/delay for the stop drain (tests). */
68
+ now?: () => number;
69
+ delay?: (ms: number) => Promise<void>;
21
70
  }
71
+ /**
72
+ * LOCAL-ONLY diagnostic shape of a non-200 upstream body. Upstream error
73
+ * bodies are UNTRUSTED and can carry credential material in ANY string —
74
+ * including inside the canonical `error.message`/`type`/`code` fields (a bare
75
+ * JWT matches no I2 pattern; Stage-2 r3 empirically refuted the
76
+ * scrub-the-allow-listed-values variant) — so ZERO upstream-controlled bytes
77
+ * may reach the logger. Reports structure only: which canonical error fields
78
+ * exist (key names come from OUR constant list, never the body) and their
79
+ * byte lengths. Own-property reads only (the W1 R3 prototype-pollution
80
+ * class). Cannot throw: no upstream value is ever serialized or traversed
81
+ * beyond one fixed level.
82
+ */
83
+ export declare function upstreamErrorShape(body: unknown): Record<string, unknown> | undefined;
22
84
  /**
23
85
  * The local model-gateway broker (§3.2). One per session on
24
86
  * `127.0.0.1:<ephemeral>`. Holds the upstream credential in-process only
@@ -35,12 +97,34 @@ export declare class LocalModelGatewayBroker implements ModelGatewayBroker, Vend
35
97
  private readonly brokerId;
36
98
  private server;
37
99
  private boundAddr;
38
- /** In-process cache of upstream vendor keys (zeroized on stop()). */
100
+ /** In-process cache of the resolved upstream credential (zeroized on stop()). */
39
101
  private upstreamKeys;
40
102
  /** Latest `credential_issuance_id` per provider (for the model_call FK). */
41
103
  private issuanceIds;
42
104
  private issuanceCounter;
105
+ private readonly refreshTransport;
106
+ private oauthLock;
107
+ private readonly proactiveThresholdMs;
108
+ private readonly stopDrainTimeoutMs;
109
+ private readonly nowFn;
110
+ private readonly delayFn;
111
+ /**
112
+ * Per-provider credential generation (§5) — advances on EVERY self-refresh
113
+ * AND on adopting a sibling's persisted bundle. A 401 issued under an older
114
+ * generation retries on the current credential WITHOUT re-refreshing.
115
+ */
116
+ private credentialGeneration;
117
+ /** Intra-instance single-flight: one in-flight refresh per provider. */
118
+ private inflightRefresh;
119
+ /** STOPPING gate — reject new gateway work once set. */
120
+ private stopping;
121
+ /** Monotonic lifecycle generation `stop()` bumps (straggler no-op guard). */
122
+ private lifecycleGeneration;
123
+ /** Registered in-flight credential-bearing outer ops. */
124
+ private readonly ops;
43
125
  constructor(deps: BrokerDeps);
126
+ /** Lazily resolve the OAuth-account lock for the (only) C4 provider `openai`. */
127
+ private getOAuthLock;
44
128
  /**
45
129
  * Start the per-session HTTP gateway on an ephemeral loopback port + mint
46
130
  * the session's broker token. Resolves the bound `127.0.0.1:<port>`.
@@ -53,8 +137,29 @@ export declare class LocalModelGatewayBroker implements ModelGatewayBroker, Vend
53
137
  /**
54
138
  * Tear down: close the HTTP server, ZEROIZE the in-process upstream
55
139
  * credentials, and clear the broker token. Idempotent.
140
+ *
141
+ * PHASE-626 §5 stop lifecycle (Stage-2 R1/R2/R3/R4 Codex): today's naive
142
+ * "clear the map immediately" lets an in-flight keychain load or refresh
143
+ * completing AFTER `stop()` silently REPOPULATE credentials post-stop. The
144
+ * new lifecycle: (1) enter STOPPING (reject new work) + bump the lifecycle
145
+ * generation so any straggler resuming post-stop aborts as a no-op; (2) await
146
+ * a BOUNDED drain of in-flight credential-bearing ops; (3) ABORT every
147
+ * registered signal (cancels abortable inner ops: the model-forward fetch +
148
+ * refresh transport) AND await the SETTLEMENT of every registered outer task
149
+ * (non-cancellable host ops — keychain, `mkdir`-lock, audit-sink — are awaited
150
+ * to natural settlement, never falsely raced); (4) drop ALL credential +
151
+ * in-flight-promise references as the FINAL step.
56
152
  */
57
153
  stop(): Promise<void>;
154
+ /**
155
+ * Register an in-flight credential-bearing OUTER operation SYNCHRONOUSLY
156
+ * (before its first `await`) so `stop()` can abort + await it. Closes the
157
+ * started-but-unregistered pre-registration race.
158
+ */
159
+ private registerOp;
160
+ private deregisterOp;
161
+ /** True once `stop()` has bumped past the op's captured generation. */
162
+ private isStale;
58
163
  /** The current broker token (for the agent's apiKeyHelper bootstrap). */
59
164
  currentBrokerToken(): BrokerToken | null;
60
165
  /**
@@ -92,25 +197,104 @@ export declare class LocalModelGatewayBroker implements ModelGatewayBroker, Vend
92
197
  rollbackBrokerTokenRotation(handle?: RotationHandle): void;
93
198
  getVendorKey(provider: VendorProvider): Promise<string | null>;
94
199
  setVendorKey(provider: VendorProvider, key: string): Promise<void>;
200
+ clearVendorKey(provider: VendorProvider): Promise<boolean>;
201
+ getVendorOAuthBundle(provider: VendorProvider): Promise<VendorOAuthBundle | null>;
202
+ setVendorOAuthBundle(provider: VendorProvider, bundle: VendorOAuthBundle): Promise<void>;
203
+ clearVendorOAuthBundle(provider: VendorProvider): Promise<boolean>;
95
204
  /**
96
205
  * Handle one broker request (§3.2). The pure, transport-agnostic core —
97
206
  * the HTTP server (`handleHttp`) adapts node req/res onto this. Route
98
- * table check first (everything else → 403), then broker-token auth on
99
- * the two POSTs (the ONLY 401 is an invalid agent→broker token), then
100
- * the per-provider gateway (§3.3/§3.4/§3.5).
207
+ * table check first (everything else → 403), then local metadata/health,
208
+ * then broker-token auth on the two model POSTs (the ONLY 401 is an
209
+ * invalid agent→broker token), then the per-provider gateway (§3.3/§3.4/§3.5).
101
210
  */
102
211
  handle(req: BrokerRequest): Promise<BrokerResponse>;
212
+ handle(req: BrokerRequest, sink: ResponseSink): Promise<BrokerResponse | BrokerHandled>;
213
+ /**
214
+ * The credential-bearing OUTER operation (§5 stop lifecycle). Registers on
215
+ * the op-registry SYNCHRONOUSLY (before its first `await`), then runs the
216
+ * gateway body with the registration's abort signal + captured lifecycle
217
+ * generation, and deregisters in `finally`.
218
+ */
103
219
  private gateway;
220
+ private gatewayInner;
221
+ /**
222
+ * PHASE-643 §3.3 — the in-scope streaming write for a 200 `text/event-stream`
223
+ * forward. Runs INSIDE the op scope (the op stays in `this.ops` across the
224
+ * stream → `stop()` phase-3 settles). Pipes the upstream body incrementally
225
+ * into the caller-provided sink, byte-for-byte, forwarding ONLY `content-type`.
226
+ *
227
+ * Teardown principle (R6): NO ownership tracking — a resolving `pipeline()` does
228
+ * NOT prove it adopted the stages (a setup-time rejection, e.g.
229
+ * `ERR_STREAM_UNABLE_TO_PIPE` on an already-destroyed sink, leaves BOTH the
230
+ * source AND the meter live). The unified catch UNCONDITIONALLY + IDEMPOTENTLY
231
+ * tears down EVERY broker-allocated stage — `meter?.destroy()` (disarms its
232
+ * armed idle timer via `_destroy`) FIRST (Stage-2 R6 Codex MED, empirically
233
+ * reproduced on Node ≥22), then a guarded `source` destroy-before-abort with a
234
+ * no-op `'error'` listener (§5.1-D), then `reg.controller.abort()` — on ANY
235
+ * throw OR pipeline rejection in steps 1–3, whether or not the pipeline was
236
+ * invoked or already destroyed the stages. A missed teardown would leave a live
237
+ * credential-bearing fetch (or an armed ref'd timer) that `stop()` can no longer
238
+ * reach after op deregister.
239
+ */
240
+ private streamForward;
104
241
  /**
105
- * Load the vendor key, caching it in-process, and emit
106
- * `broker_credential_loaded` (§3.5) on each keychain load — with a
107
- * `key_fingerprint` (sha256 prefix) and a fresh `credential_issuance_id`,
108
- * NEVER the key. The credential-loaded audit is best-effort (it does not
109
- * gate the forward — the `model_call` row does); a lost load-audit is a
110
- * forensic gap, not an unsafe effect.
242
+ * Build the upstream `{url, headers}` for a resolved credential (§5). For an
243
+ * `oauth_bundle` (C4) the URL is OVERRIDDEN to the ChatGPT config and its
244
+ * synthesized headers (originator / User-Agent) are merged over the openai
245
+ * canonical headers; the credential headers add `Authorization: Bearer` +
246
+ * `ChatGPT-Account-Id`. For C1/C2/C3 the canonical URL + the C2-beta synthesis
247
+ * are preserved unchanged.
111
248
  */
112
- private loadVendorKey;
249
+ private buildUpstreamTarget;
250
+ /**
251
+ * Load the vendor credential (class-discriminated + precedence), caching it
252
+ * in-process, and emit `broker_credential_loaded` (§3.5) — with a
253
+ * `key_fingerprint` (sha256 prefix over the class-appropriate string; for an
254
+ * oauth_bundle the `refresh_token`) and a fresh `credential_issuance_id`,
255
+ * NEVER the raw credential.
256
+ *
257
+ * Precedence (§5): C1/C2/C3 (`vendor-key-<provider>`) WINS over a C4
258
+ * `vendor-oauth-openai` bundle. Explicit key wins; no config knob.
259
+ */
260
+ private loadVendorCredential;
261
+ private genOf;
262
+ private currentBundle;
263
+ /** Is the C4 bundle's `last_refresh` older than the proactive threshold? */
264
+ private isProactiveDue;
265
+ /**
266
+ * Adopt a bundle into the in-process cache AND advance the local credential
267
+ * generation (§5 — adoption is treated identically to a self-refresh, so a
268
+ * stale-generation 401 recognizes the rotation and does not re-rotate).
269
+ * Respects the lifecycle guard: never repopulates a cleared cache post-stop.
270
+ */
271
+ private adoptBundle;
272
+ /**
273
+ * Ensure a fresh C4 access token via single-flight + the cross-broker lock.
274
+ * `mode` distinguishes reactive (post-401 — a transient failure fails the
275
+ * call closed) from proactive (token still valid — a transient failure keeps
276
+ * serving the current token). `usedGen` (reactive only) is the generation the
277
+ * failed request rode: a 401 older than the current generation retries on the
278
+ * CURRENT credential WITHOUT refreshing (staggered-stale-401 guard).
279
+ */
280
+ private refreshOAuth;
281
+ /**
282
+ * The cross-broker critical section (§5): acquire the OAuth-account lock →
283
+ * RE-READ the persisted bundle under the lock → compare-and-skip on
284
+ * `access_token` identity → refresh via the token endpoint → reassert
285
+ * ownership → whole-bundle write-through → advance generation → release.
286
+ * The single-flight promise resolves only AFTER persist + cache update.
287
+ */
288
+ private doRefreshUnderLock;
113
289
  private lastIssuanceId;
290
+ /**
291
+ * The user-visible remediation response for a PERMANENT (`invalid_grant`) C4
292
+ * refresh failure — the refresh token is dead, so no in-broker recovery is
293
+ * possible and the user must re-import (§5 failure classification + remediation
294
+ * scoping). Shared by BOTH the reactive (post-401) and proactive refresh paths
295
+ * so the surfaced instruction cannot drift.
296
+ */
297
+ private permanentRefreshResponse;
114
298
  /**
115
299
  * Map an upstream response to the agent-facing status (§3.2). An upstream
116
300
  * 401/403 (bad/expired vendor key) → 502 (NOT a pass-through 401, which
@@ -0,0 +1,40 @@
1
+ /** The C4 ChatGPT-subscription upstream wire facts (LIVE-PINNED, §13 OQ-1). */
2
+ export interface ChatGptUpstreamConfig {
3
+ /** ChatGPT backend origin the C4 Bearer forwards to (origin confinement target). */
4
+ readonly upstreamBaseUrl: string;
5
+ /** The Responses route appended to the base for `/v1/responses`-shaped calls. */
6
+ readonly upstreamPath: string;
7
+ /**
8
+ * Headers the broker SYNTHESIZES on EVERY C4 upstream call (NOT agent-
9
+ * supplied — the canonical constructor drops all agent headers). These are
10
+ * broker-owned constants; the credential-derived `ChatGPT-Account-Id` +
11
+ * `Authorization` are added separately by `credentialHeaders` (they depend
12
+ * on the resolved bundle).
13
+ */
14
+ readonly synthesizedHeaders: Readonly<Record<string, string>>;
15
+ /**
16
+ * PHASE-643-B §7 (v11) — pinned WIRE FACT: the real chatgpt.com Responses
17
+ * endpoint returns `200` + a genuine SSE body with NO `Content-Type` header at
18
+ * all (probe-proven 2026-07-21 — Cloudflare-fronted, `Transfer-Encoding:
19
+ * chunked`, no content-type either with or without an `Accept` header). So a
20
+ * `200` with an ABSENT/empty content-type on THIS endpoint must be STREAMED as
21
+ * SSE, not buffered. This is per-endpoint pinned knowledge (same class as the
22
+ * `originator`/UA pins), NOT body-sniffing and NOT `Accept` synthesis. Only the
23
+ * flagged (C4/oauth_bundle chatgpt) target sets it; declared non-SSE 200s
24
+ * (`application/json`) on this target STILL buffer.
25
+ */
26
+ readonly assumeSseOn200: boolean;
27
+ }
28
+ export declare const CHATGPT_UPSTREAM_CONFIG: ChatGptUpstreamConfig;
29
+ /** The full pinned C4 model-forward URL (`{base}{route}`). */
30
+ export declare function chatGptUpstreamUrl(): string;
31
+ /** OAuth token-refresh endpoint (LIVE-PINNED). */
32
+ export declare const CHATGPT_TOKEN_ENDPOINT = "https://auth.openai.com/oauth/token";
33
+ /** Public OAuth client_id for the refresh grant (LIVE-PINNED). */
34
+ export declare const CHATGPT_OAUTH_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
35
+ /**
36
+ * The request content type for the refresh grant. The body is
37
+ * `grant_type=refresh_token&refresh_token=…&client_id=…` (§5), so it is a
38
+ * standard OAuth2 form-encoded token request.
39
+ */
40
+ export declare const CHATGPT_REFRESH_CONTENT_TYPE = "application/x-www-form-urlencoded";
@@ -1,4 +1,4 @@
1
- export type { VendorProvider, BrokerRouteMethod, BrokerRoute, BrokerStatus, BrokerRequest, BrokerResponse, ModelGatewayBroker, VendorKeyStore, BrokerToken, UpstreamResponse, UpstreamClient, } from "./types";
1
+ export type { VendorProvider, BrokerRouteMethod, BrokerRoute, BrokerStatus, BrokerRequest, BrokerResponse, BrokerHandled, ResponseSink, ModelGatewayBroker, VendorKeyStore, VendorOAuthBundle, ResolvedCredential, BrokerToken, UpstreamResult, UpstreamResponse, UpstreamClient, } from "./types";
2
2
  export { BROKER_ROUTES } from "./types";
3
3
  export { LocalModelGatewayBroker } from "./broker";
4
4
  export type { BrokerDeps } from "./broker";
@@ -7,6 +7,9 @@ export type { StrictAuditSink, AuditKindCp7, RecordedAuditEmit } from "./audit-s
7
7
  export { StubStrictAuditSink } from "./audit-sink";
8
8
  export { KeychainVendorKeyStore } from "./vendor-key-store";
9
9
  export { BrokerTokenMinter, type RotationHandle } from "./broker-token";
10
+ export { CHATGPT_UPSTREAM_CONFIG, chatGptUpstreamUrl, CHATGPT_TOKEN_ENDPOINT, CHATGPT_OAUTH_CLIENT_ID, CHATGPT_REFRESH_CONTENT_TYPE, } from "./chatgpt-config";
11
+ export { FetchRefreshTransport, refreshOAuthToken, buildRefreshBody, type RefreshTransport, type RefreshOutcome, } from "./oauth-refresh";
12
+ export { OAuthAccountLock, createOAuthAccountLock, defaultOAuthLockDir, type OAuthAccountLockOptions, type LockHandle, type LockOwner, } from "./oauth-account-lock";
10
13
  export { buildCanonicalRequest, selfCredentialGuard, requestSha256, CanonicalRejectError, } from "./canonical";
11
14
  export type { CanonicalInput, CanonicalRequest } from "./canonical";
12
15
  export { scrubRequestBody } from "./scrubber";
@@ -0,0 +1,104 @@
1
+ /** Liveness of a recorded lock owner (only `dead` is ever reclaimed). */
2
+ export type OwnerLiveness = "alive" | "dead" | "unknown";
3
+ /** The `owner.json` record written once per acquisition. */
4
+ export interface LockOwner {
5
+ pid: number;
6
+ host: string;
7
+ /** Random per-ACQUISITION nonce — the fence for every destructive/heartbeat op. */
8
+ ownerId: string;
9
+ /** Acquisition time (ISO), for diagnostics. */
10
+ startedAt: string;
11
+ }
12
+ export interface OAuthAccountLockOptions {
13
+ /** The canonical lockdir path (keyed to the OAuth account). */
14
+ lockDir: string;
15
+ /** Staleness TTL (» max critical-section time). Default 30s. */
16
+ ttlMs?: number;
17
+ /** Heartbeat interval (« TTL). Default 5s. */
18
+ heartbeatMs?: number;
19
+ /** Contention deadline. Default 60s. */
20
+ maxWaitMs?: number;
21
+ /** Base retry backoff. Default 25ms (capped 1s). */
22
+ backoffMs?: number;
23
+ now?: () => number;
24
+ delay?: (ms: number) => Promise<void>;
25
+ /** This process's pid (injectable for tests). */
26
+ pid?: number;
27
+ /** This host's id (injectable for tests). */
28
+ hostId?: string;
29
+ /** Liveness probe (injectable for tests). Default = same-host `process.kill(pid,0)`. */
30
+ isProcessAlive?: (pid: number, host: string) => OwnerLiveness;
31
+ /** Per-acquisition nonce generator (injectable for tests). */
32
+ randomId?: () => string;
33
+ /** `utimes(lockdir)` heartbeat op (injectable so tests can observe/spy). */
34
+ utimesFn?: (dir: string) => Promise<void>;
35
+ /** Disable the auto-interval heartbeat (tests drive ticks manually). */
36
+ disableAutoHeartbeat?: boolean;
37
+ }
38
+ /** A held lock. `release` is one-shot + idempotent. */
39
+ export interface LockHandle {
40
+ readonly ownerId: string;
41
+ /**
42
+ * Reassert-before-mutation (§5 primary revocation-wins backstop): re-read the
43
+ * canonical `owner.json` and return true iff `ownerId === ours`. The broker
44
+ * calls this IMMEDIATELY before EVERY keychain `setPassword`/`deletePassword`,
45
+ * aborting fail-closed on a false result — independently defeating any
46
+ * displacement that COMPLETED before the re-read.
47
+ */
48
+ reassertOwnership(): Promise<boolean>;
49
+ /** One-shot release: cancel+join heartbeat, then unlink+rmdir under `ownerId` re-assert. */
50
+ release(): Promise<void>;
51
+ /** TEST-ONLY: run one heartbeat tick synchronously (simulates a queued `utimes`). */
52
+ _tickForTest(): Promise<void>;
53
+ }
54
+ /** The portable cross-process OAuth-account lock (§5 / AMEND-1). */
55
+ export declare class OAuthAccountLock {
56
+ private readonly lockDir;
57
+ private readonly ownerFile;
58
+ private readonly reclaimGuardDir;
59
+ private readonly ttlMs;
60
+ private readonly heartbeatMs;
61
+ private readonly maxWaitMs;
62
+ private readonly backoffMs;
63
+ private readonly now;
64
+ private readonly delayFn;
65
+ private readonly pid;
66
+ private readonly hostId;
67
+ private readonly isProcessAlive;
68
+ private readonly randomId;
69
+ private readonly utimesFn;
70
+ private readonly disableAutoHeartbeat;
71
+ constructor(opts: OAuthAccountLockOptions);
72
+ /**
73
+ * Acquire the lock (bounded by `maxWaitMs`). Resolves a {@link LockHandle} on
74
+ * success; REJECTS fail-closed on: an unwritable lockdir root, a contention
75
+ * timeout (live/ambiguous/ownerless holder), or a dead/stranded reclaim guard.
76
+ * ZERO side effects on the persisted bundle on any fail-closed path.
77
+ */
78
+ acquire(): Promise<LockHandle>;
79
+ /** Whether the EXISTING lockdir holder is reclaimable (dead), or must be waited on. */
80
+ private classifyExistingHolder;
81
+ /**
82
+ * Reclaim a stale, provably-dead lockdir under the SEPARATE reclaim guard.
83
+ * Returns a fresh {@link LockHandle} on success, or `null` if the reclaim was
84
+ * aborted (a sibling already reclaimed, or the guard is held). Throws only if
85
+ * the guard is dead/stranded (fail-closed → offline cleanup).
86
+ */
87
+ private tryReclaim;
88
+ /** Write `owner.json`, start the heartbeat, and build the handle. */
89
+ private onAcquired;
90
+ private tryMkdir;
91
+ private readOwner;
92
+ private lockDirAge;
93
+ private removeStaleDir;
94
+ private rmdirQuiet;
95
+ private backoff;
96
+ }
97
+ /**
98
+ * Default lockdir path for a provider's OAuth account — a stable per-host path
99
+ * under `~/.codevibe/locks/` (all C4 brokers are same-host, so a shared
100
+ * filesystem path gives cross-process exclusion). NOT under the substrate
101
+ * mount (I1) — this is host-side broker coordination only.
102
+ */
103
+ export declare function defaultOAuthLockDir(account: string): string;
104
+ export declare function createOAuthAccountLock(opts: OAuthAccountLockOptions): OAuthAccountLock;
@@ -0,0 +1,72 @@
1
+ import type { VendorOAuthBundle } from "./types";
2
+ /**
3
+ * The injected refresh transport (§5). Separate from the model `UpstreamClient`
4
+ * (different content type, form body, token endpoint). Widened to accept an
5
+ * optional `signal` (the stop-lifecycle end-to-end cancellation contract).
6
+ * Resolves `{status, rawBody, contentType}`; REJECTS only on a transport error
7
+ * OR a 3xx redirect (redirect confinement).
8
+ */
9
+ export interface RefreshTransport {
10
+ post(args: {
11
+ url: string;
12
+ body: string;
13
+ contentType: string;
14
+ signal?: AbortSignal;
15
+ }): Promise<RefreshTransportResponse>;
16
+ }
17
+ export interface RefreshTransportResponse {
18
+ status: number;
19
+ /** Raw response text (bounded); parsed by the classifier, NEVER logged. */
20
+ rawBody: string;
21
+ /** Lowercased response `content-type`, if any. */
22
+ contentType?: string;
23
+ /**
24
+ * True iff the body exceeded the bounded-read cap and was NOT materialized
25
+ * (transport streamed at most the cap + cancelled). The classifier treats an
26
+ * oversized body as transient WITHOUT parsing (it was never fully read).
27
+ */
28
+ oversized?: boolean;
29
+ }
30
+ /** The outcome of a refresh attempt — drives the reactive/proactive posture. */
31
+ export type RefreshOutcome = {
32
+ kind: "rotated";
33
+ bundle: VendorOAuthBundle;
34
+ } | {
35
+ kind: "permanent";
36
+ reason: string;
37
+ } | {
38
+ kind: "transient";
39
+ reason: string;
40
+ };
41
+ /**
42
+ * The production fetch-backed {@link RefreshTransport}. Mirrors
43
+ * `FetchUpstreamClient`'s hardened posture for the NEW secret surface.
44
+ */
45
+ export declare class FetchRefreshTransport implements RefreshTransport {
46
+ private readonly opts;
47
+ constructor(opts?: {
48
+ fetchFn?: typeof fetch;
49
+ timeoutMs?: number;
50
+ });
51
+ post(args: {
52
+ url: string;
53
+ body: string;
54
+ contentType: string;
55
+ signal?: AbortSignal;
56
+ }): Promise<RefreshTransportResponse>;
57
+ }
58
+ /** Build the OAuth2 refresh-grant form body (`refresh_token` is a secret). */
59
+ export declare function buildRefreshBody(refreshToken: string): string;
60
+ /**
61
+ * Perform ONE token refresh against the pinned endpoint and classify the
62
+ * result. On success returns a `rotated` bundle that already applies the §5
63
+ * write-through merge rule (`refresh_token`/`id_token` ?? current;
64
+ * `account_id` from current; `last_refresh` = now) — persistence + cache +
65
+ * generation advance are the caller's job (under the cross-broker lock).
66
+ *
67
+ * `now` supplies the `last_refresh` timestamp (injectable for tests).
68
+ */
69
+ export declare function refreshOAuthToken(current: VendorOAuthBundle, transport: RefreshTransport, opts?: {
70
+ signal?: AbortSignal;
71
+ now?: () => Date;
72
+ }): Promise<RefreshOutcome>;