@quantiya/codevibe-codex-plugin 2.0.51 → 2.0.53

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 (26) hide show
  1. package/node_modules/@quantiya/codevibe-core/dist/index.d.ts +4 -1
  2. package/node_modules/@quantiya/codevibe-core/dist/index.js +559 -536
  3. package/node_modules/@quantiya/codevibe-core/dist/local-executor/anchored-fs.d.ts +20 -1
  4. package/node_modules/@quantiya/codevibe-core/dist/local-executor/bounded-directory.d.ts +1 -14
  5. package/node_modules/@quantiya/codevibe-core/dist/local-executor/bounded-helper.d.ts +1 -1
  6. package/node_modules/@quantiya/codevibe-core/dist/local-executor/durable-directory.d.ts +0 -4
  7. package/node_modules/@quantiya/codevibe-core/dist/local-executor/process-tree.d.ts +9 -0
  8. package/node_modules/@quantiya/codevibe-core/dist/local-executor/shadow-protocol.d.ts +6 -0
  9. package/node_modules/@quantiya/codevibe-core/dist/local-executor/shadow-recovery.d.ts +55 -13
  10. package/node_modules/@quantiya/codevibe-core/dist/local-executor/workspace-authority.d.ts +2 -0
  11. package/node_modules/@quantiya/codevibe-core/dist/local-executor/workspace-shadow.d.ts +3 -2
  12. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/cli.d.ts +55 -3
  13. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/cli.js +3819 -851
  14. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/components/OrchestrationApp.d.ts +1 -0
  15. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/doctor-cli.d.ts +79 -3
  16. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/emit-shell-event.d.ts +2 -0
  17. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/index.d.ts +4 -2
  18. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/quorum-loop.d.ts +115 -2
  19. package/node_modules/@quantiya/codevibe-core/dist/orchestration-shell/status-format.d.ts +1 -1
  20. package/node_modules/@quantiya/codevibe-core/dist/planner/client.d.ts +3 -0
  21. package/node_modules/@quantiya/codevibe-core/dist/planner/composite-adapter.d.ts +39 -0
  22. package/node_modules/@quantiya/codevibe-core/dist/planner/index.d.ts +1 -0
  23. package/node_modules/@quantiya/codevibe-core/dist/substrate-launch/index.d.ts +1 -1
  24. package/node_modules/@quantiya/codevibe-core/dist/substrate-launch/reviewer-credential-preflight.d.ts +26 -0
  25. package/node_modules/@quantiya/codevibe-core/package.json +2 -2
  26. package/package.json +3 -3
@@ -36,6 +36,7 @@ export interface OrchestrationAppProps {
36
36
  */
37
37
  plannerRuntimeKind?: PlannerRuntimeKind;
38
38
  plannerLabel?: string;
39
+ plannerAdapter?: unknown;
39
40
  /**
40
41
  * TUI redesign (2026-06-29) — the PLAINTEXT cwd for the status bar, threaded
41
42
  * from the shell entry (process.cwd()). Sourced here rather than from
@@ -1,3 +1,4 @@
1
+ import { type ShadowEnv } from '../local-executor/shadow-protocol';
1
2
  interface RegisteredRoot {
2
3
  path: string;
3
4
  dev?: string;
@@ -21,6 +22,72 @@ export interface RootDiagnosis {
21
22
  markers: string[];
22
23
  verdict: 'healthy' | 'reconcilable' | 'bytes-may-exist' | 'unknown';
23
24
  }
25
+ export interface AgentCliStatus {
26
+ agent: 'CLAUDE' | 'CODEX' | 'ANTIGRAVITY';
27
+ command: string;
28
+ name: string;
29
+ installed: boolean;
30
+ version?: string;
31
+ binPath?: string;
32
+ error?: string;
33
+ }
34
+ export interface AuthPreflightStatus {
35
+ authenticated: boolean;
36
+ email?: string;
37
+ userId?: string;
38
+ expiresAt?: string;
39
+ tokenExpired: boolean;
40
+ deviceIdentityPresent: boolean;
41
+ deviceIdentityId?: string;
42
+ deviceIdentityError?: string;
43
+ vendorKeys: {
44
+ anthropic: boolean;
45
+ openai: boolean;
46
+ custodyBackend?: string;
47
+ };
48
+ error?: string;
49
+ }
50
+ export interface ConnectivityPreflightStatus {
51
+ appsyncReachable: boolean;
52
+ appsyncUrl: string;
53
+ latencyMs?: number;
54
+ error?: string;
55
+ }
56
+ export interface OrphanPreflightStatus {
57
+ deadProcessOwnersCount: number;
58
+ orphanedShadowCount: number;
59
+ retainedStateDiagnostics?: string[];
60
+ error?: string;
61
+ }
62
+ export interface DoctorCliOpts {
63
+ stateRoot?: string;
64
+ ownerRoot?: string;
65
+ skipPreflight?: boolean;
66
+ detectAgentsFn?: () => Promise<AgentCliStatus[]> | AgentCliStatus[];
67
+ authStatusFn?: () => Promise<AuthPreflightStatus>;
68
+ connectivityFn?: (url: string) => Promise<ConnectivityPreflightStatus>;
69
+ orphanProbeFn?: (stateRoot: string) => Promise<OrphanPreflightStatus>;
70
+ reapShadowsFn?: (keepTaskIds?: ReadonlySet<string>, env?: ShadowEnv) => Promise<{
71
+ reaped: string[];
72
+ retained: string[];
73
+ }>;
74
+ reapProcessOwnersFn?: () => Promise<{
75
+ reaped: number;
76
+ retained: number;
77
+ }>;
78
+ refreshTokenFn?: () => Promise<boolean>;
79
+ }
80
+ export declare function probeAgentClis(env?: NodeJS.ProcessEnv): AgentCliStatus[];
81
+ export declare function probeAuthPreflight(): Promise<AuthPreflightStatus>;
82
+ export declare function probeBackendConnectivity(appsyncUrl: string): Promise<ConnectivityPreflightStatus>;
83
+ /**
84
+ * Derives the process-owner registry root without string surgery on stateRoot (N10).
85
+ * Uses opts.ownerRoot if given; falls back to parent of opts.stateRoot only when an explicit
86
+ * stateRoot was passed; otherwise uses canonical product accessor processOwnerRoot().
87
+ */
88
+ export declare function resolveOwnerRoot(opts?: DoctorCliOpts, stateRoot?: string): string;
89
+ export declare function probeOrphanStatus(stateRoot: string, ownerRootOverride?: string, shadowRootOverride?: string): Promise<OrphanPreflightStatus>;
90
+ export declare function renderPreflight(agents: AgentCliStatus[], auth: AuthPreflightStatus, connectivity: ConnectivityPreflightStatus, orphans: OrphanPreflightStatus): void;
24
91
  /** The product's own state root — never a second spelling of it (Stage 1 F7). */
25
92
  export declare function shadowStateRoot(): string;
26
93
  /** Read the registry. A missing or unreadable registry is reported, never repaired. */
@@ -38,7 +105,16 @@ export declare function collectMarkers(stateRoot: string): Map<string, string[]>
38
105
  */
39
106
  export declare function inodeSurvivesInParent(root: RegisteredRoot): boolean | undefined;
40
107
  export declare function diagnose(stateRoot: string, roots: RegisteredRoot[]): RootDiagnosis[];
41
- export declare function runDoctorCli(argv: string[], opts?: {
42
- stateRoot?: string;
43
- }): Promise<number>;
108
+ export interface RepairOutcome {
109
+ pruneAttempted: boolean;
110
+ pruneSuccess: boolean;
111
+ pruneCount: number;
112
+ pruneError?: string;
113
+ refreshAttempted: boolean;
114
+ refreshSuccess: boolean;
115
+ refreshError?: string;
116
+ }
117
+ export declare function renderRepairPlan(orphans: OrphanPreflightStatus, auth: AuthPreflightStatus): boolean;
118
+ export declare function performOrphanAndAuthRepairs(opts: DoctorCliOpts, stateRoot: string, orphans: OrphanPreflightStatus, auth: AuthPreflightStatus): Promise<RepairOutcome>;
119
+ export declare function runDoctorCli(argv: string[], opts?: DoctorCliOpts): Promise<number>;
44
120
  export {};
@@ -33,6 +33,8 @@ export interface ShellEventEmit {
33
33
  timestamp?: string;
34
34
  /** Pre-minted nonce when encrypted metadata must bind the response nonce. */
35
35
  writerEventNonce?: string;
36
+ /** Idempotency key for receiving boundary deduplication in DynamoDB (R5-F2). */
37
+ clientEventId?: string;
36
38
  /** P16/P20 encrypted terminal-result authority. All four fields are atomic. */
37
39
  writerEventKind?: 'WORKSPACE_OUTCOME';
38
40
  writerSessionGenerationId?: string;
@@ -144,7 +144,8 @@ export interface RunOrchestrationShellArgs {
144
144
  * planner semantics. `local_gemma_qat` means natural-language decisions came
145
145
  * from the local runtime and need shell-owned M1 safety/milestone gates.
146
146
  * `local_unavailable` means the user opted into local-model orchestration but
147
- * the verified runtime is not usable; no hosted fallback is allowed.
147
+ * the verified runtime is not usable; for Pro/Max sessions it falls back to
148
+ * hosted Bedrock planner, while Free tier operates in Companion Mode.
148
149
  */
149
150
  plannerRuntimeKind?: 'hosted' | 'local_gemma_qat' | 'local_unavailable';
150
151
  /**
@@ -330,7 +331,7 @@ export type { Mode, Tier, PlannerDecision, AgentKind, PlannerHealthState, Runnin
330
331
  export { formatElapsed, isSpinnerPhase, renderProgressLine, type TaskProgressEvent, type OnProgress, } from './task-progress';
331
332
  export { createTaskProgressRelay, formatMobileProgressMessage, MAX_MOBILE_PROGRESS_MESSAGE_LENGTH, type TaskProgressRelay, type TaskProgressRelayDeps, } from './task-progress-relay';
332
333
  export { runDeclaredTestSurfaces, DECLARED_TEST_TIMEOUT_MS, type DeclaredTestResult, type DeclaredTestReason, type RunDeclaredTestSurfacesArgs, } from './declared-test-runner';
333
- export { QuorumLoop, type QuorumLoopDeps } from './quorum-loop';
334
+ export { QuorumLoop, type QuorumLoopDeps, claimOutageNotificationOnDisk, isOutageNotificationDeliveredOnDisk, markOutageNotificationDeliveredOnDisk, releaseOutageNotificationClaimOnDisk, tryAcquireRecoveryLock, releaseRecoveryLock, cleanArbiterSafely, type RecoveryLockHandle, type RecoveryLockDeps, defaultOutageNotificationRoot, } from './quorum-loop';
334
335
  /**
335
336
  * [A1g] Round-5 (Codex round-4 MEDIUM) — INVOCATION-OWNED conversation deltas.
336
337
  *
@@ -1131,6 +1132,7 @@ export declare function serializeShellSubmissions(handler: (text: string, images
1131
1132
  * slash route then reports "unavailable").
1132
1133
  */
1133
1134
  export declare function buildContinuationActionDeps(args: RunOrchestrationShellArgs, store: OrchestrationStore): Partial<ContinuationCliDeps>;
1135
+ export declare function shouldSuppressStructuralContextRefresh(args: RunOrchestrationShellArgs): boolean;
1134
1136
  /**
1135
1137
  * Tokenize a command line string respecting single/double quotes and backslash escapes.
1136
1138
  * Returns tokens array or error if unclosed quote / trailing escape.
@@ -1,3 +1,4 @@
1
+ import * as fsSync from 'node:fs';
1
2
  import type { AppSyncClient, TeamTrackRecoveryRow } from '../appsync/appsync-client';
2
3
  import type { Session } from '../types';
3
4
  import type { LocalExecutor } from '../local-executor';
@@ -80,10 +81,103 @@ export declare function classifyImplementorRoundFailure(err: unknown): string;
80
81
  * An UNMATCHED quota error degrades FAIL-SAFE to the existing born-halt
81
82
  * `surfaceHalt` (the user just doesn't get auto-continuation; identical to
82
83
  * today) — NOT fail-open.
83
- *
84
- * Exported for the L1 fixture test (I5).
84
+ */
85
+ export type ProviderFailureClassifier = 'rate_limit_429' | 'overloaded_529' | 'quota_exhausted' | 'model_error';
86
+ export interface ProviderFailureClassification {
87
+ isOutage: boolean;
88
+ classifier: ProviderFailureClassifier | null;
89
+ verbatimLine: string;
90
+ humaneMessage: string;
91
+ actionAdvice: string;
92
+ }
93
+ /**
94
+ * HB-60 — Provider rate limit, quota exhaustion, and server overload classifier.
95
+ * Categorizes failure text into a structured, wire-safe classification label with
96
+ * a humane explanation and recommended recovery advice for desktop and mobile surfacing.
97
+ * Anchored to HTTP error tokens and provider phrases to prevent false positives on
98
+ * compiler line numbers, durations, or token counts.
99
+ */
100
+ export declare function classifyProviderFailure(text: string): ProviderFailureClassification;
101
+ /**
102
+ * Scans provider stdout (e.g. from `codex exec --json` or `claude --json`)
103
+ * for structured failure events (`{"type":"error"}` or `{"type":"turn.failed"}`)
104
+ * and extracts all failure error messages for provider outage classification.
105
+ */
106
+ export declare function extractFailureMessagesFromStdout(stdout: string): string[];
107
+ export declare function extractFailureMessageFromStdout(stdout: string): string | null;
108
+ /**
109
+ * Format a clear, humane TUI banner for desktop rendering when a provider outage or quota occurs.
110
+ */
111
+ export declare function formatProviderOutageBanner(agent: string, classification: ProviderFailureClassification): string;
112
+ /**
113
+ * Exported for the L1 fixture test (I5) and provider rate-limit classification (HB-60).
85
114
  */
86
115
  export declare function classifyImplementorQuotaFailure(exitCode: number | undefined, text: string): boolean;
116
+ /**
117
+ * Root directory for persisting provider outage notification delivery markers.
118
+ * Configurable via CODEVIBE_OUTAGE_NOTIFICATION_ROOT for hermetic test isolation.
119
+ */
120
+ export declare function defaultOutageNotificationRoot(): string;
121
+ export interface OutageNotificationMarker {
122
+ status: 'claimed' | 'delivered';
123
+ disposition?: 'dispatched' | 'acknowledged' | 'retained';
124
+ deliveryId: string;
125
+ sessionId?: string;
126
+ taskId?: string;
127
+ agent?: string;
128
+ classifier?: string;
129
+ claimedAtMs?: number;
130
+ deliveredAt?: string;
131
+ pid?: number;
132
+ ambiguousOutcome?: boolean;
133
+ reason?: string;
134
+ error?: string;
135
+ }
136
+ export interface RecoveryLockHandle {
137
+ lockDir: string;
138
+ token: string;
139
+ }
140
+ export interface RecoveryLockDeps {
141
+ fs?: {
142
+ readdirSync?: typeof fsSync.readdirSync;
143
+ readFileSync?: typeof fsSync.readFileSync;
144
+ writeFileSync?: typeof fsSync.writeFileSync;
145
+ renameSync?: typeof fsSync.renameSync;
146
+ unlinkSync?: typeof fsSync.unlinkSync;
147
+ rmdirSync?: typeof fsSync.rmdirSync;
148
+ existsSync?: typeof fsSync.existsSync;
149
+ mkdirSync?: typeof fsSync.mkdirSync;
150
+ };
151
+ }
152
+ export declare function cleanArbiterSafely(arbiterDir: string, expectedToken: string, deps?: RecoveryLockDeps): void;
153
+ export declare function tryAcquireRecoveryLock(lockDir: string, deps?: RecoveryLockDeps): RecoveryLockHandle | null;
154
+ export declare function releaseRecoveryLock(handle: RecoveryLockHandle | null | undefined, deps?: RecoveryLockDeps): void;
155
+ /**
156
+ * Atomically claims an outage notification delivery on disk before emission begins (R4-F2, R5-F3, R6-F3, R7-F3, R7-F4).
157
+ * Uses atomic temporary file publication via linkSync, exclusive recovery locking with tombstone rename,
158
+ * and fail-closed crash deduplication so lost acknowledgements never produce duplicate mobile pushes on restart.
159
+ */
160
+ export declare function claimOutageNotificationOnDisk(deliveryId: string, payload: Record<string, unknown>): {
161
+ claimed: boolean;
162
+ alreadyDelivered: boolean;
163
+ };
164
+ /**
165
+ * Releases a transient claim on disk if emission aborted cleanly without reaching the backend.
166
+ * Ownership-checked: only unlinks if the file is currently claimed by claimantPid (R5-F3).
167
+ */
168
+ export declare function releaseOutageNotificationClaimOnDisk(deliveryId: string, claimantPid?: number): void;
169
+ /**
170
+ * Determines whether an emit error definitively proves the mutation was not committed (R5-F2).
171
+ */
172
+ export declare function isDefinitiveNonDelivery(reason?: string): boolean;
173
+ /**
174
+ * Checks whether an outage notification has already been successfully delivered and persisted on disk.
175
+ */
176
+ export declare function isOutageNotificationDeliveredOnDisk(deliveryId: string): boolean;
177
+ /**
178
+ * Persists an outage notification delivery marker to disk atomically so deduplication survives process restart.
179
+ */
180
+ export declare function markOutageNotificationDeliveredOnDisk(deliveryId: string, payload: Record<string, unknown>): void;
87
181
  /**
88
182
  * Audited-path fix (Fix 1) — build the SAFE, no-plaintext desktop advisory text
89
183
  * for a hosted-side PolicyRejection. Uses ONLY the closed `category` classifier
@@ -1007,6 +1101,18 @@ export declare class QuorumLoop {
1007
1101
  * manual prompt (fail-closed; the Max user is prompted instead of auto-resumed).
1008
1102
  */
1009
1103
  private readonly quotaContinuationOffers;
1104
+ /**
1105
+ * HB-60 — deduplicated provider outages / rate limits announced to the user
1106
+ * and mobile companion. Keyed by `${sessionId}:${taskId}:${classifier}` so
1107
+ * one notification is dispatched per failure event and a resumed session does
1108
+ * not re-announce it.
1109
+ */
1110
+ private static readonly globalAnnouncedOutages;
1111
+ private static readonly inFlightOutageEmissions;
1112
+ private readonly announcedDesktopOutages;
1113
+ private readonly announcedProviderOutages;
1114
+ /** @internal reset process-wide announced provider outages for unit tests (memory-only) */
1115
+ static resetGlobalAnnouncedOutages(): void;
1010
1116
  /** REVISE_FEEDBACK ids already consumed (deterministic dedup). */
1011
1117
  private readonly seenReviseFeedbackIds;
1012
1118
  /**
@@ -2711,6 +2817,13 @@ export declare class QuorumLoop {
2711
2817
  */
2712
2818
  private resolveForcedImplementorAgent;
2713
2819
  private resolveQuotaClassificationText;
2820
+ /**
2821
+ * HB-60 / Must-Have 2: Gracefully surface provider rate limit / 429 / 529 / quota
2822
+ * errors via a humane TUI banner and mobile AppSync NOTIFICATION alert.
2823
+ * Wire-safety invariant: zero raw agent prompt/diff/output on the wire;
2824
+ * only closed humane message and structured classification metadata cross into AppSync.
2825
+ */
2826
+ announceProviderOutageIfNew(taskId: string, agent: AgentKind, textOrClassification: string | ProviderFailureClassification): Promise<boolean>;
2714
2827
  /**
2715
2828
  * #585 §3.5 / §3.6 — the `quota_exhausted` fork. The implementor halted on a
2716
2829
  * quota error (born-halt or, defensively, a throw). Bound-check the
@@ -30,7 +30,7 @@ export declare function prettyModelLabel(model: string | null | undefined): stri
30
30
  * - `local_gemma_qat` → dim `<label> · local` (no color → caller renders dim)
31
31
  * - `local_unavailable`→ yellow degraded warning (the ONE state worth surfacing —
32
32
  * NL routing is off; only deterministic slash commands work)
33
- * - `hosted` → null (hosted planner retired no badge)
33
+ * - `hosted` → dim `Gemma · hosted` (hosted Bedrock Gemma planner active)
34
34
  *
35
35
  * The badge is a boot-time FACT, not a live health light — copy avoids implying
36
36
  * liveness (see design doc "Architecture grounding").
@@ -67,6 +67,9 @@ export declare class PlannerBudgetExceededError extends Error {
67
67
  export declare class PlannerTierGateRejectedError extends Error {
68
68
  constructor(msg: string);
69
69
  }
70
+ export declare class PlannerMalformedRequestError extends Error {
71
+ constructor(msg: string);
72
+ }
70
73
  export declare class BackendPlannerClient implements PlannerAdapter {
71
74
  private transport;
72
75
  private cache;
@@ -0,0 +1,39 @@
1
+ import type { Tier } from '../orchestration-shell/types';
2
+ import type { PlannerAdapter, PlannerDecision, PlannerInput, PlannerProbeResult } from './adapter';
3
+ import type { PlannerHealthMachine } from './health-state';
4
+ export interface CompositePlannerAdapterOptions {
5
+ localAdapter?: PlannerAdapter | null;
6
+ hostedAdapter: PlannerAdapter;
7
+ tier: Tier;
8
+ localRuntimeKind?: 'hosted' | 'local_gemma_qat' | 'local_unavailable';
9
+ localRuntimeLabel?: string;
10
+ hostedHealth?: PlannerHealthMachine | null;
11
+ recoveryProbeIntervalMs?: number;
12
+ onNotice?: (message: string) => void;
13
+ onBeforeHostedFallback?: (input: PlannerInput) => Promise<PlannerInput>;
14
+ }
15
+ export declare class CompositePlannerAdapter implements PlannerAdapter {
16
+ private readonly opts;
17
+ private activeSessionId;
18
+ private currentSource;
19
+ private recoveryTimer;
20
+ private readonly sourceChangeListeners;
21
+ private readonly recoveryIntervalMs;
22
+ private beforeHostedFallbackHook;
23
+ constructor(opts: CompositePlannerAdapterOptions);
24
+ setBeforeHostedFallback(hook: (input: PlannerInput) => Promise<PlannerInput>): void;
25
+ get activeSource(): 'local' | 'hosted';
26
+ get runtimeKind(): 'local_gemma_qat' | 'local_unavailable' | 'hosted';
27
+ get runtimeLabel(): string;
28
+ get suppressStructuralContextRefresh(): boolean;
29
+ onSourceChange(listener: (source: 'local' | 'hosted') => void): () => void;
30
+ private notifySourceChange;
31
+ private transitionToHosted;
32
+ private transitionToLocal;
33
+ private startRecoveryProbe;
34
+ private stopRecoveryProbe;
35
+ setActiveSession(sessionId: string | null): void;
36
+ classify(input: PlannerInput): Promise<PlannerDecision>;
37
+ probe(): Promise<PlannerProbeResult>;
38
+ dispose(): void;
39
+ }
@@ -5,3 +5,4 @@ export { PlannerHealthMachine } from './health-state';
5
5
  export { BackendPlannerClient, PlannerBudgetExceededError, PlannerTierGateRejectedError, type PlannerAppSyncTransport, type PlannerCryptoBridge, type SessionKeyResolver, type ShellEventEmit, type EmitShellEventFn, } from './client';
6
6
  export { LocalGemmaPlannerAdapter, parseLocalGemmaPlannerDecision, PlannerOutputUnparseableError, renderLocalGemmaPlannerPrompt, type LocalGemmaPlannerRunner, } from './local-gemma';
7
7
  export { parseLocalGemmaAdvisorySummary, renderLocalGemmaFamiliarizePrompt, renderLocalGemmaMultiBrowsePrompt, renderLocalGemmaBrowsePrompt, MAX_BROWSE_CONTENT_CHARS, MAX_MULTI_BROWSE_TOTAL_CONTENT_CHARS, MAX_MULTI_BROWSE_RENDERED_PROMPT_CHARS, type LocalGemmaAdvisoryRunner, } from './local-advisory';
8
+ export { CompositePlannerAdapter, type CompositePlannerAdapterOptions, } from './composite-adapter';
@@ -6,7 +6,7 @@ export { buildSanitizedBaseEnv, assertNoAmbientCreds, SAFE_ENV_ALLOWLIST, SANDBO
6
6
  export type { SanitizedEnvInput } from "./sanitized-env";
7
7
  export { ApiKeyBootstrap, SANDBOX_BOOTSTRAP_DIR, HELPER_SCRIPT_NAME, TOKEN_FILE_NAME, CODEX_PROVIDER_ID, } from "./apikey-bootstrap";
8
8
  export type { ApiKeyBootstrapInput } from "./apikey-bootstrap";
9
- export { assertReviewerVendorCredential, reviewerProviderFor, withReviewerCredentialPreflight, ReviewerCredentialMissingError, REVIEWER_CREDENTIAL_MISSING, } from "./reviewer-credential-preflight";
9
+ export { assertReviewerVendorCredential, reviewerProviderFor, withReviewerCredentialPreflight, ReviewerCredentialMissingError, REVIEWER_CREDENTIAL_MISSING, assertImplementorVendorCredential, implementorProviderFor, withImplementorCredentialPreflight, ImplementorCredentialMissingError, IMPLEMENTOR_CREDENTIAL_MISSING, } from "./reviewer-credential-preflight";
10
10
  export type { ReviewerCredentialStore } from "./reviewer-credential-preflight";
11
11
  export { scrubLeEnvOrReexec, buildScrubbedLeEnv, findCredShapedKeys, isCredShapedEnvKey, LE_ENV_SCRUBBED_MARKER, } from "./le-env-scrub";
12
12
  export type { LeEnvScrubDeps } from "./le-env-scrub";
@@ -9,6 +9,10 @@ export declare const REVIEWER_CREDENTIAL_MISSING = "ReviewerCredentialMissingErr
9
9
  export declare class ReviewerCredentialMissingError extends Error {
10
10
  name: string;
11
11
  }
12
+ export declare const IMPLEMENTOR_CREDENTIAL_MISSING = "ImplementorCredentialMissingError";
13
+ export declare class ImplementorCredentialMissingError extends Error {
14
+ name: string;
15
+ }
12
16
  /**
13
17
  * The minimal store surface the preflight needs (structurally satisfied by
14
18
  * `KeychainVendorKeyStore`); narrow so tests can stub it without keychain IO.
@@ -24,6 +28,10 @@ export interface ReviewerCredentialStore {
24
28
  * them (the loop pre-routes them to legacy+badge before engaging anyway).
25
29
  */
26
30
  export declare function reviewerProviderFor(agent: string): VendorProvider | null;
31
+ /**
32
+ * Map an implementor agent kind to its broker vendor provider.
33
+ */
34
+ export declare function implementorProviderFor(agentKind: string): VendorProvider | null;
27
35
  /**
28
36
  * Throw (fail-closed) when a Trusted reviewer is about to substrate-engage but
29
37
  * no vendor credential exists for its provider. The message is the user-facing
@@ -48,3 +56,21 @@ export declare function withReviewerCredentialPreflight<I extends {
48
56
  mode: string;
49
57
  teardown: () => Promise<void>;
50
58
  }>(engage: (input: I) => Promise<R>, store: ReviewerCredentialStore): (input: I) => Promise<R>;
59
+ /**
60
+ * Throw (fail-closed) when a Trusted implementor is about to substrate-engage
61
+ * but no vendor credential exists for its provider.
62
+ */
63
+ export declare function assertImplementorVendorCredential(agentKind: string, store: ReviewerCredentialStore): Promise<void>;
64
+ /**
65
+ * Wrap an implementor substrate engager with the credential preflight, ordered
66
+ * AFTER tier selection: the underlying engage runs first, and the credential check
67
+ * applies ONLY when the ladder actually chose `substrate` (broker) mode. On
68
+ * substrate + missing credential the engaged substrate is torn down and the
69
+ * actionable `ImplementorCredentialMissingError` propagates (fail-closed).
70
+ */
71
+ export declare function withImplementorCredentialPreflight<I extends {
72
+ agentKind: string;
73
+ }, R extends {
74
+ mode: string;
75
+ teardown: () => Promise<void>;
76
+ }>(engage: (input: I) => Promise<R>, store: ReviewerCredentialStore): (input: I) => Promise<R>;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quantiya/codevibe-core",
3
- "version": "2.0.44",
3
+ "version": "2.0.46",
4
4
  "description": "Core library for CodeVibe plugins - shared keychain, crypto, AppSync, and auth functionality",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -18,7 +18,7 @@
18
18
  "typecheck": "tsc --noEmit",
19
19
  "emit-types": "tsc -p tsconfig.types.json --emitDeclarationOnly",
20
20
  "build": "rm -rf dist && npm run emit-types && esbuild src/index.ts --bundle --platform=node --target=node18 --minify --packages=external --define:__CODEVIBE_TEST_BUILD__=false --outfile=dist/index.js && esbuild src/orchestration-shell/cli.ts --bundle --platform=node --target=node18 --minify-syntax --packages=external --define:__CODEVIBE_TEST_BUILD__=false --outfile=dist/orchestration-shell/cli.js --banner:js=\"#!/usr/bin/env node\" && esbuild src/orchestration-shell/web/web-extract-worker.ts --bundle --platform=node --target=node18 --minify --packages=external --outfile=dist/orchestration-shell/web-extract-worker.js && npm run verify-no-test-hooks && npm run verify-no-test-types",
21
- "verify-no-test-hooks": "if grep -ERl 'CODEVIBE_TEST_FORCE_QUOTA_FAIL|CODEVIBE_TEST_FORCE_IMPLEMENTOR_AGENT|CODEVIBE_ANCHORED_PUBLICATION_AUTHORITY_ROOT|codevibe-anchored-publications-|cv-publication-authority-vitest-|codevibe\\.test\\.publication-authority-|setPublicationAuthorityRootForTestBuild|__CODEVIBE_TEST_BUILD__|_onBeforeLinkForTesting|_onBeforeSummariesLockForTesting|__codevibe_test_on_before_link|__codevibe_test_on_before_summaries_lock' dist; then echo 'ERROR: a test-only hook leaked into a published artifact (prod-unreachability invariant)'; exit 1; fi; echo 'OK \u2014 no test-only hooks in published artifacts'",
21
+ "verify-no-test-hooks": "if grep -ERl 'CODEVIBE_TEST_FORCE_QUOTA_FAIL|CODEVIBE_TEST_FORCE_IMPLEMENTOR_AGENT|CODEVIBE_ANCHORED_PUBLICATION_AUTHORITY_ROOT|codevibe-anchored-publications-|cv-publication-authority-vitest-|codevibe\\.test\\.publication-authority-|setPublicationAuthorityRootForTestBuild|__CODEVIBE_TEST_BUILD__|_onBeforeLinkForTesting|_onBeforeSummariesLockForTesting|__codevibe_test_on_before_link|__codevibe_test_on_before_summaries_lock|simulatePostPublicationError' dist; then echo 'ERROR: a test-only hook leaked into a published artifact (prod-unreachability invariant)'; exit 1; fi; echo 'OK no test-only hooks in published artifacts'",
22
22
  "verify-no-test-types": "if find dist -type f \\( -path '*/__tests__/*' -o -name '*.test.d.ts' -o -name 'test-publication-authority-setup.d.ts' \\) | grep -q .; then echo 'verify-no-test-types: test declarations present in dist (tsconfig.types.json must exclude test sources)' >&2; exit 1; fi",
23
23
  "clean": "rm -rf dist",
24
24
  "prepublishOnly": "npm run build",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@quantiya/codevibe-codex-plugin",
3
- "version": "2.0.51",
4
- "description": "Control OpenAI Codex CLI from your iPhone and Android \u2014 real-time sync, approve file edits, send prompts by voice. Part of CodeVibe.",
3
+ "version": "2.0.53",
4
+ "description": "Control OpenAI Codex CLI from your iPhone and Android real-time sync, approve file edits, send prompts by voice. Part of CodeVibe.",
5
5
  "main": "dist/server.js",
6
6
  "codevibe": {
7
7
  "companionLauncher": "./libexec/companion-launcher"
@@ -47,7 +47,7 @@
47
47
  "node": ">=22.0.0"
48
48
  },
49
49
  "dependencies": {
50
- "@quantiya/codevibe-core": "^2.0.44",
50
+ "@quantiya/codevibe-core": "^2.0.46",
51
51
  "@quantiya/quorum-core": "^1.0.1",
52
52
  "chokidar": "^4.0.0",
53
53
  "dotenv": "^16.6.1",