@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
@@ -330,6 +330,8 @@ export type ConversationEntry = {
330
330
  final: true;
331
331
  source: 'planner' | 'shell';
332
332
  text: string;
333
+ localOnly?: true;
334
+ handoffExcluded?: true;
333
335
  } | {
334
336
  kind: 'gate-prompt';
335
337
  id: string;
@@ -409,6 +411,54 @@ export interface PendingClarification {
409
411
  */
410
412
  attachmentPaths?: string[];
411
413
  }
414
+ /**
415
+ * A1a #3/#4 — one numbered choice in a `PendingPlannerOffer`. Contract-ready
416
+ * shape (mirrors `GatePromptOption`) so an F4 mobile renderer (Wave 3, after the
417
+ * contract freeze) can consume it verbatim; `id` is a stable option key,
418
+ * `label`/`description` are the shell-authored (never model-authored) render copy.
419
+ */
420
+ export interface PlannerOfferOption {
421
+ readonly id: string;
422
+ readonly label: string;
423
+ readonly description: string;
424
+ }
425
+ /**
426
+ * A1a #3/#4 (design §7 R3 / §8.3) — a lightweight interactive offer the shell
427
+ * presents instead of a silent spawn. Modeled on `pendingClarification` (NOT the
428
+ * server-coupled gate-prompt path): the offer + its numbered options are held in
429
+ * the local store, and the numbered reply resolves it locally. F4 mirrors a
430
+ * separate encrypted INTERACTIVE_PROMPT for mobile rendering; the local menu text
431
+ * stays out of workflow handoff context.
432
+ *
433
+ * - `team_decomposition` (#4): the planner routed `team_decompose`; rather than
434
+ * silent-launching a team, offer Accept-team / Reject→single / Talk-it-through.
435
+ * - `build_transition` (#3): a mid-active-design "let's build it"; rather than
436
+ * silent-spawning an implementor, offer Build-now / Keep-discussing.
437
+ *
438
+ * The stashed context lets each kind resolve WITHOUT re-classifying: the
439
+ * team-decomposition briefs the accept path feeds to `routeTeamDecompose` /
440
+ * `dispatchSynthesizedSingleStartTask`, and the build request the transition
441
+ * proceeds with.
442
+ */
443
+ export interface PendingPlannerOffer {
444
+ kind: 'team_decomposition' | 'build_transition';
445
+ /** Contract-ready shape (mirror GatePromptOption). Shell-authored copy. */
446
+ options: ReadonlyArray<PlannerOfferOption>;
447
+ /** The `advisory` conversation entry that rendered the numbered options. */
448
+ conversationEntryId: string;
449
+ /** The planner's short reason (why this offer) — surfaced in the render. */
450
+ rationale: string;
451
+ /** team_decomposition: the decomposer input brief for `routeTeamDecompose`. */
452
+ decomposerBrief?: string;
453
+ /** team_decomposition / build fallback: the brief for reject → single agent. */
454
+ singleFallbackBrief?: string;
455
+ /** build_transition: the build request to proceed with on accept (no re-classify). */
456
+ originalUserPrompt?: string;
457
+ /** IMAGE-ATTACHMENT-DESIGN.md §5/§7.5 — team attachments, armed on the launch. */
458
+ attachments?: ImageAttachment[];
459
+ /** §13 Option-2 — ordered-with-dups carried paths for the number-based chip rewrite. */
460
+ attachmentPaths?: string[];
461
+ }
412
462
  /**
413
463
  * [ADDITIVE WIDENING — CP-12 W3, per PHASE-CP-12-DESIGN.md §3.5 "minimal
414
464
  * multi-track status node; rich UX is #469"]. Per-track lifecycle state as the
@@ -445,7 +495,7 @@ export interface TeamTrackEntry {
445
495
  }
446
496
  /**
447
497
  * [ADDITIVE WIDENING — CP-12 W3] Minimal team state. `null` for
448
- * single-track/Companion/stub sessions (no team → no status node). Populated
498
+ * single-track/Companion sessions (no team → no status node). Populated
449
499
  * when `/team` accepts a task group + per-track W2.b shell events arrive.
450
500
  */
451
501
  export interface TeamState {
@@ -536,6 +586,16 @@ export interface OrchestrationState {
536
586
  activeReviewerSeats: Map<string, ReviewerSeatState>;
537
587
  currentGate: GateState | null;
538
588
  pendingClarification: PendingClarification | null;
589
+ /**
590
+ * `[ADDITIVE WIDENING — A1a #3/#4]` The active lightweight local interactive
591
+ * offer (team-decomposition / build-transition), or `null` when none is in
592
+ * flight (the default). Set by `PLANNER_OFFER_PRESENTED`; a single in-range
593
+ * numeric reply resolves it locally (see `handleShellUserInput`), and any
594
+ * non-offer resolution clears it (`CLEAR_PENDING_PLANNER_OFFER`). F4 mirrors an
595
+ * encrypted INTERACTIVE_PROMPT for mobile, but this store node remains the local
596
+ * source of truth.
597
+ */
598
+ pendingPlannerOffer: PendingPlannerOffer | null;
539
599
  inputHistory: string[];
540
600
  /**
541
601
  * `[ADDITIVE WIDENING — CP-1.d]` per `PHASE-CP-1-D-DESIGN.md` §4.8
@@ -552,7 +612,7 @@ export interface OrchestrationState {
552
612
  structuralSummaryError: string | null;
553
613
  /**
554
614
  * `[ADDITIVE WIDENING — CP-12 W3]` per PHASE-CP-12-DESIGN.md §3.5. `null`
555
- * for single-track/Companion/stub sessions (the status node is hidden).
615
+ * for single-track/Companion sessions (the status node is hidden).
556
616
  * Populated by `/team` (createTaskGroup accepted) + the W2.b per-track shell
557
617
  * events. Rich per-track timeline + MergeGate result card are
558
618
  * [DEFERRED → CP-8 #469].
@@ -563,7 +623,7 @@ export interface OrchestrationState {
563
623
  * live status line (spinner). `null` when idle / waiting on the user. Updated
564
624
  * in place by `TASK_PROGRESS` spinner phases; cleared by `waiting_user` and by
565
625
  * the terminal milestone phases (`promoted` / `discarded`). Non-loop /
566
- * Companion / stub sessions never dispatch `TASK_PROGRESS`, so this stays null.
626
+ * Companion sessions never dispatch `TASK_PROGRESS`, so this stays null.
567
627
  */
568
628
  progress: LiveProgress | null;
569
629
  /**
@@ -585,7 +645,7 @@ export interface OrchestrationState {
585
645
  * props with no in-component network I/O:
586
646
  * - `tier` decides the seat budget (Pro = 2 seats, Max = 3).
587
647
  * - `installedAgents` is the host-detected agent set — the wizard offers ONLY
588
- * these as reviewer choices (mirrors the `codevibe orchestration configure`
648
+ * these as reviewer choices (mirrors the `/reviewer-setup`
589
649
  * CLI), so a user can never pick an uninstalled agent.
590
650
  * - `currentSeats` is shown as a CONTEXT line at the top of the wizard (the
591
651
  * user's existing panel) — display only; the wizard starts fresh at the
@@ -675,6 +735,11 @@ export type OrchestrationAction = {
675
735
  task: RunningTaskState;
676
736
  } | {
677
737
  type: 'CLEAR_PENDING_CLARIFICATION';
738
+ } | {
739
+ type: 'PLANNER_OFFER_PRESENTED';
740
+ offer: PendingPlannerOffer;
741
+ } | {
742
+ type: 'CLEAR_PENDING_PLANNER_OFFER';
678
743
  } | {
679
744
  type: 'STRUCTURAL_SUMMARY_GENERATED';
680
745
  summary: StructuralSummary;
@@ -711,6 +776,8 @@ export type OrchestrationAction = {
711
776
  type: 'SHELL_ADVISORY';
712
777
  text: string;
713
778
  source: 'shell';
779
+ localOnly?: true;
780
+ handoffExcluded?: true;
714
781
  } | {
715
782
  type: 'GATE_PROMPT_NOTES_CANCELLED';
716
783
  promptEntryId: string;
@@ -3,5 +3,5 @@ export * from './adapter';
3
3
  export { PlannerCacheLayer } from './cache';
4
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
- export { LocalGemmaPlannerAdapter, parseLocalGemmaPlannerDecision, renderLocalGemmaPlannerPrompt, type LocalGemmaPlannerRunner, } from './local-gemma';
6
+ export { LocalGemmaPlannerAdapter, parseLocalGemmaPlannerDecision, PlannerOutputUnparseableError, renderLocalGemmaPlannerPrompt, type LocalGemmaPlannerRunner, } from './local-gemma';
7
7
  export { parseLocalGemmaAdvisorySummary, renderLocalGemmaFamiliarizePrompt, type LocalGemmaAdvisoryRunner, } from './local-advisory';
@@ -1,6 +1,17 @@
1
1
  import type { StructuralSummary } from '../structural-summary/types';
2
2
  export interface LocalGemmaAdvisoryRunner {
3
3
  generateAdvisory(promptText: string, options?: LocalGemmaAdvisoryOptions): Promise<string>;
4
+ /**
5
+ * Dogfood #618 — optional fire-and-forget model pre-warm (load + keep_alive).
6
+ * Never throws; resolves false on failure. Called once at shell startup.
7
+ */
8
+ warm?(): Promise<boolean>;
9
+ /**
10
+ * #618 Stage-2 — optional fire-and-forget model release (keep_alive: 0).
11
+ * Never throws; resolves false on failure. Called once at shell teardown so
12
+ * the model's memory isn't held for the keep_alive window after quit.
13
+ */
14
+ unload?(): Promise<boolean>;
4
15
  runtimeLabel: string;
5
16
  }
6
17
  export type LocalGemmaAdvisoryResponseFormat = 'json' | 'text';
@@ -46,6 +57,7 @@ export declare function renderLocalGemmaBrowsePrompt(args: {
46
57
  };
47
58
  content: string;
48
59
  }): string;
60
+ export declare function boundedPriorBrainstormTurns(turns: string[] | undefined): string[];
49
61
  /**
50
62
  * WEB-BROWSING (search-route): turn the user's request + recent conversation into a
51
63
  * concise web-search QUERY. The local model resolves acronyms/pronouns from context
@@ -5,8 +5,35 @@ export interface LocalGemmaPlannerRunner {
5
5
  classify(promptText: string): Promise<string>;
6
6
  generateAdvisory?: LocalGemmaAdvisoryRunner['generateAdvisory'];
7
7
  probe?(): Promise<PlannerProbeResult>;
8
+ /**
9
+ * Dogfood #618 — optional fire-and-forget model pre-warm (load into memory +
10
+ * arm keep_alive). Never throws; resolves false on failure. The shell calls
11
+ * this once at startup so the session's first classify/advisory doesn't pay
12
+ * the runtime's cold load.
13
+ */
14
+ warm?(): Promise<boolean>;
15
+ /**
16
+ * #618 Stage-2 — optional fire-and-forget model release (keep_alive: 0),
17
+ * called once at shell teardown. Never throws; resolves false on failure.
18
+ */
19
+ unload?(): Promise<boolean>;
8
20
  runtimeLabel: string;
9
21
  }
22
+ /**
23
+ * A1a P0 (R3 — design §7 "the conductor must NEVER hard-fail"): thrown when the
24
+ * local Gemma model RESPONDED but its output could not be parsed into a valid
25
+ * route (out-of-domain prose, truncated JSON, unsupported action/keys, etc.).
26
+ *
27
+ * This is deliberately DISTINCT from an infrastructure failure (Ollama
28
+ * unreachable / timeout / budget / tier-gate — those reject out of the runner,
29
+ * never reach the parser). The orchestration shell catches THIS class and
30
+ * degrades to a safe "general question / not a build request" advisory route
31
+ * instead of surfacing a `planner-error`; a genuine infra failure still surfaces
32
+ * "Planner unavailable" because retrying would not help.
33
+ */
34
+ export declare class PlannerOutputUnparseableError extends Error {
35
+ constructor(message: string);
36
+ }
10
37
  /**
11
38
  * Text-only route classifier prompt. It intentionally excludes repository
12
39
  * paths, summaries, source snippets, file bodies, and the raw structural digest.
@@ -63,6 +63,13 @@ export interface PlannerInput {
63
63
  clarifications: Clarification[];
64
64
  sessionContext: SessionContext;
65
65
  budgetHint: BudgetHint;
66
+ /**
67
+ * Local-planner-only, role-filtered rendering of the canonical ContextItems
68
+ * session history. The hosted planner client deliberately ignores this field;
69
+ * it exists so local Gemma can resolve ordinary multi-turn references without
70
+ * relying on shell text heuristics or a model-private conversation cache.
71
+ */
72
+ canonicalConversationContext?: string;
66
73
  }
67
74
  export interface PlannerDecision {
68
75
  action: 'start_task' | 'summarize_current_status' | 'advisory_response' | 'ask_user' | 'refuse' | 'team_decompose' | 'familiarize' | 'brainstorm' | 'browse';
@@ -7,8 +7,6 @@ export type { RunReviewerOptions, SubprocessError, SubprocessOutcome, } from './
7
7
  export { runReviewer, SubprocessErrorClass } from './subprocess.js';
8
8
  export type { ClaudeReviewerProviderOptions } from './providers/claude.js';
9
9
  export { ClaudeReviewerProvider } from './providers/claude.js';
10
- export type { GeminiEnvelope, GeminiModelStats, GeminiReviewerProviderOptions, GeminiStats, } from './providers/gemini.js';
11
- export { GeminiReviewerProvider } from './providers/gemini.js';
12
10
  export type { CodexReviewerProviderOptions } from './providers/codex.js';
13
11
  export { CodexReviewerProvider } from './providers/codex.js';
14
12
  export type { AntigravityReviewerProviderOptions } from './providers/antigravity.js';
@@ -37,8 +37,10 @@ export interface ReviewerEvaluateOptions {
37
37
  * the workdir on BOTH backends — A5 `cwd: workdir`; Docker `docker exec -w
38
38
  * /workspace`) and reads it back from `<workdir>/<name>` on the host (the same
39
39
  * inode, even when A5 canonicalizes the workdir — the host read follows the
40
- * symlink). The Claude / Gemini providers do not use a file output, so they
41
- * ignore this field. ABSENT (legacy path / non-substrate) → the provider uses
40
+ * symlink). The Claude provider uses no file output and ignores this field;
41
+ * the Antigravity provider writes no verdict file either but DOES consume
42
+ * `workdir` (`--add-dir <workdir>` — agy is workspace-centric). ABSENT
43
+ * (legacy path / non-substrate) → the provider uses
42
44
  * its byte-identical legacy `os.tmpdir()` location.
43
45
  *
44
46
  * # Why this is NOT derivable from `substrate`
@@ -105,10 +107,11 @@ export interface ReviewerSpec {
105
107
  * is agent-agnostic here; each provider enforces the sandbox in its own
106
108
  * way:
107
109
  * - Claude: `--allowed-tools Read,Grep,Glob` CLI flag.
108
- * - Gemini: `--approval-mode plan` (Gemini's first-class read-only mode).
109
- * The `tool_allowlist` is intentionally unused by the Gemini provider;
110
- * plan mode is the sandbox contract. 2.0.x task #62 tracks adding
111
- * `--policy <tempfile>` as defense-in-depth.
110
+ * - Antigravity: no native read-only flag AND no CP-7 substrate — agy is
111
+ * reduced-trust (§6 Q4), so the loop pre-routes agy seats to the LEGACY
112
+ * unsandboxed path with a reduced-trust badge. Agy 1.1.2 requires the
113
+ * prompt as `--print <prompt>` and is granted the repo via
114
+ * `--add-dir <workdir>`.
112
115
  * - Codex: `--sandbox read-only --skip-git-repo-check` flags + per-spawn
113
116
  * ephemeral output file.
114
117
  */
@@ -25,9 +25,8 @@ export declare class AntigravityReviewerProvider implements ReviewerProvider {
25
25
  /**
26
26
  * Construct the agy CLI invocation (design D4):
27
27
  *
28
- * - `--print ''` — non-interactive one-shot; the EMPTY value selects the
29
- * STDIN prompt (fed by `runReviewer`), keeping multi-line markdown out of
30
- * argv (same posture as gemini's `-p ''`).
28
+ * - `--print <prompt>` — non-interactive one-shot. Agy 1.1.2 requires the
29
+ * prompt value in argv; stdin prompt mode was removed.
31
30
  * - `--model <hint>` — optional; omitted when `spec.model_hint` is `null`
32
31
  * (agy default model).
33
32
  * - `--print-timeout <s>s` — agy's INTERNAL print-mode poll ceiling, derived
@@ -24,7 +24,6 @@ export declare class ReviewerRegistry implements ReviewerProvider {
24
24
  * ```ts
25
25
  * const registry = new ReviewerRegistry()
26
26
  * .with('claude', new ClaudeReviewerProvider())
27
- * .with('gemini', new GeminiReviewerProvider())
28
27
  * .with('codex', new CodexReviewerProvider());
29
28
  * ```
30
29
  *
@@ -65,11 +64,18 @@ export declare class ReviewerRegistry implements ReviewerProvider {
65
64
  evaluate(spec: ReviewerSpec, gateId: string, opts?: ReviewerEvaluateOptions): Promise<ReviewerVerdict>;
66
65
  }
67
66
  /**
68
- * Production factory: build a registry pre-populated with all four
69
- * subprocess providers (Claude, Gemini, Codex, Antigravity) using the
67
+ * Production factory: build a registry pre-populated with the three
68
+ * supported subprocess providers (Claude, Codex, Antigravity) using the
70
69
  * standard binaries from PATH. Equivalent of Rust's
71
70
  * `withSubprocessProviders()` napi factory.
72
71
  *
72
+ * Gemini is SUNSET (2026-07): it is no longer registered here, so a policy
73
+ * that names a `gemini` reviewer fails closed via `evaluate`'s
74
+ * missing-provider path (throws `spawn_failed` → engine escalates to the
75
+ * user) rather than silently spawning `gemini`. The `'GEMINI'` AgentKind
76
+ * value is retained for backward-compatible deserialization of legacy
77
+ * records; it is simply not a routable reviewer.
78
+ *
73
79
  * Plugins call this once at startup and hand the registry to the
74
80
  * engine fan-out path. Inert registrations cost nothing — no
75
81
  * subprocess fires until the policy actually references that agent.
@@ -80,7 +86,6 @@ export declare class ReviewerRegistry implements ReviewerProvider {
80
86
  * ```ts
81
87
  * const registry = new ReviewerRegistry()
82
88
  * .with('claude', new ClaudeReviewerProvider({ executable: '/opt/bin/claude' }))
83
- * .with('gemini', new GeminiReviewerProvider({ executable: '/opt/bin/gemini' }))
84
89
  * .with('codex', new CodexReviewerProvider({ executable: '/opt/bin/codex' }));
85
90
  * ```
86
91
  */
@@ -9,6 +9,16 @@
9
9
  * never corrupts the accumulator.
10
10
  */
11
11
  export declare function finiteToken(n: unknown): number;
12
+ /**
13
+ * Locate the FIRST balanced top-level `{...}` in `stdout` that parses to an object
14
+ * with `type === 'result'` — Claude may emit non-JSON warning / MCP lines before
15
+ * the terminal result envelope, so we scan candidate `{` positions rather than
16
+ * parsing the whole stdout blindly. Returns the parsed object, or null if none
17
+ * parses to a `result` envelope. Exported for the orchestration-shell advisory
18
+ * quota classifier ([#637] — the Claude usage-limit rides in this envelope's
19
+ * `result` field); never throws.
20
+ */
21
+ export declare function firstResultEnvelope(stdout: string): Record<string, unknown> | null;
12
22
  /**
13
23
  * [P2-6] Unwrap a Claude Code `--output-format json` NON-interactive envelope into
14
24
  * `{ text, tokens }`. The ENTIRE body is `try/catch`-guarded — ANY throw (parse
@@ -1,5 +1,6 @@
1
1
  import { AppSyncClient } from '../appsync/appsync-client';
2
2
  import { Logger } from '../logger';
3
+ export declare function isOwnDeviceRegistration(ownDeviceId: string, registeredDeviceId: string): boolean;
3
4
  /**
4
5
  * Start the device-key registration watcher for the authenticated user.
5
6
  *
@@ -1,5 +1,7 @@
1
- export { resumeOrCreateSession, prepareSessionEncryption } from './session-resume';
2
- export type { ResumeOrCreateSessionInput, ResumeOrCreateSessionResult } from './session-resume';
1
+ export { resumeOrCreateSession, prepareSessionEncryption, PlannerProxyServiceKeyMissingError, SessionEncryptionPreparationError, } from './session-resume';
2
+ export type { ResumeOrCreateSessionInput, ResumeOrCreateSessionResult, SessionEncryptionPreparationFailureKind, } from './session-resume';
3
+ export { createSessionWithPendingLedger, replayPendingSessionCreateForIntent, } from './pending-session-create';
4
+ export type { PendingSessionCreateIntent } from './pending-session-create';
3
5
  export { rekeySessionForNewDevices } from './session-rekey';
4
6
  export { startDeviceKeyWatcher } from './device-key-watcher';
5
7
  export { registerDeviceEncryptionKey } from './register-device-key';
@@ -0,0 +1,61 @@
1
+ import { type AppSyncClient } from '../appsync';
2
+ import type { Logger } from '../logger';
3
+ import type { CreateSessionInput, Session } from '../types';
4
+ interface PendingSessionCreateRecord {
5
+ schema: 'codevibe.pending_session_create.v2';
6
+ sessionId: string;
7
+ creationRequestId: string;
8
+ intentFingerprint: string;
9
+ input: CreateSessionInput;
10
+ sessionKey: string | null;
11
+ createdAt: string;
12
+ }
13
+ export interface PendingSessionCreateIntent {
14
+ userId: string;
15
+ agentType: NonNullable<CreateSessionInput['agentType']>;
16
+ /** Plain local path. It is persisted only inside the sealed ledger. */
17
+ projectPath: string;
18
+ }
19
+ declare function ledgerPath(sessionId: string): string;
20
+ declare function fingerprintIntent(intent: PendingSessionCreateIntent): string;
21
+ declare function readPending(sessionId: string): Promise<PendingSessionCreateRecord | null>;
22
+ declare function removePending(sessionId: string, record?: PendingSessionCreateRecord): Promise<void>;
23
+ declare function findPendingForIntent(intent: PendingSessionCreateIntent, logger: Logger): Promise<PendingSessionCreateRecord | null>;
24
+ /**
25
+ * Persist one exact create envelope before network I/O and replay it unchanged
26
+ * after an ambiguous transport failure or process restart.
27
+ */
28
+ export declare function createSessionWithPendingLedger(args: {
29
+ input: CreateSessionInput;
30
+ sessionKey: string | null;
31
+ intent: PendingSessionCreateIntent;
32
+ appSyncClient: Pick<AppSyncClient, 'createSession'>;
33
+ logger: Logger;
34
+ /**
35
+ * Synchronous lifecycle handoff fired immediately after the backend response
36
+ * is proven to match the sealed request, before keychain or ledger cleanup.
37
+ */
38
+ onAdmitted?: (session: Session) => void;
39
+ }): Promise<{
40
+ session: Session;
41
+ sessionKey: string | null;
42
+ }>;
43
+ /** Replay an interrupted create before minting a new id for the same intent. */
44
+ export declare function replayPendingSessionCreateForIntent(args: {
45
+ intent: PendingSessionCreateIntent;
46
+ appSyncClient: Pick<AppSyncClient, 'createSession'>;
47
+ logger: Logger;
48
+ onAdmitted?: (session: Session) => void;
49
+ }): Promise<{
50
+ session: Session;
51
+ sessionKey: string | null;
52
+ } | null>;
53
+ export declare const pendingSessionCreateTestSeams: {
54
+ ledgerPath: typeof ledgerPath;
55
+ readPending: typeof readPending;
56
+ removePending: typeof removePending;
57
+ findPendingForIntent: typeof findPendingForIntent;
58
+ fingerprintIntent: typeof fingerprintIntent;
59
+ setRemovalFault(fault: "after_tombstone" | null): void;
60
+ };
61
+ export {};
@@ -1,5 +1,15 @@
1
1
  import { AppSyncClient } from '../appsync/appsync-client';
2
2
  import { Logger } from '../logger';
3
+ export declare function registrationLeaseIsFresh(lastUsedAt: string | undefined, nowMs?: number): boolean;
4
+ export interface RegisterDeviceEncryptionKeyOptions {
5
+ /**
6
+ * Publish even when the normal registration lease is fresh. Recovery paths
7
+ * use this to emit the mutation that wakes peer device-key subscriptions.
8
+ */
9
+ force?: boolean;
10
+ /** Structured diagnostic explaining why a forced registration was needed. */
11
+ reason?: string;
12
+ }
3
13
  /**
4
14
  * Register the current device's ECDH public key with the backend.
5
15
  *
@@ -10,4 +20,4 @@ import { Logger } from '../logger';
10
20
  * @param appSyncClient Authenticated AppSyncClient.
11
21
  * @param logger Plugin-specific logger so log lines are tagged correctly.
12
22
  */
13
- export declare function registerDeviceEncryptionKey(appSyncClient: AppSyncClient, logger: Logger): Promise<void>;
23
+ export declare function registerDeviceEncryptionKey(appSyncClient: AppSyncClient, logger: Logger, options?: RegisterDeviceEncryptionKeyOptions): Promise<void>;
@@ -8,8 +8,8 @@ export interface RekeyOptions {
8
8
  * they already have an entry in `session.encryptedKeys`. Use this
9
9
  * when you know a specific device just re-registered — for example,
10
10
  * when handling an `onDeviceKeyRegistered` subscription event — so
11
- * a rotated public key gets a fresh wrapped entry. The old entry
12
- * is left intact; the new one is appended via `grantSessionKey`.
11
+ * a rotated public key gets a fresh wrapped entry. The backend replaces
12
+ * the recipient's prior entry atomically and collapses legacy duplicates.
13
13
  *
14
14
  * Default: empty. The bulk diff path (catch-up after disconnect,
15
15
  * catch-up at session resume) does not pass this and relies on the
@@ -23,9 +23,8 @@ export interface RekeyOptions {
23
23
  * key to any device that is missing an entry (or that the caller has
24
24
  * explicitly marked as needing a fresh wrap via `forceDeviceIds`).
25
25
  *
26
- * Safe to call repeatedly. No-op when every registered device already
27
- * has an entry and nothing is forced. Does not modify or remove existing
28
- * entries — only appends new ones via the grantSessionKey mutation.
26
+ * Safe to call repeatedly. No-op when every registered device has an envelope
27
+ * bound to its current public key and nothing is forced.
29
28
  *
30
29
  * @param sessionId The session to re-key.
31
30
  * @param sessionKey The plaintext session key (base64). The caller must
@@ -19,10 +19,24 @@ export interface ResumeOrCreateSessionInput {
19
19
  metadata?: Record<string, any>;
20
20
  }
21
21
  export interface ResumeOrCreateSessionResult {
22
+ /**
23
+ * The authoritative backend row ID. This can differ from the requested ID
24
+ * when a sealed, ambiguous create is replayed for the same launch intent.
25
+ * Callers MUST bind subscriptions, heartbeats, and events to this value.
26
+ */
27
+ sessionId: string;
22
28
  /** Whether an existing session was found and reactivated */
23
29
  resumed: boolean;
24
30
  /** The E2E session key (for encrypting/decrypting events), or null if no encryption */
25
31
  sessionKey: string | null;
32
+ /**
33
+ * The session-key generation of the AUTHORITATIVE row (§4.5 key-gen binding),
34
+ * or null when unencrypted / the backend echoed no generation. Callers stamp
35
+ * this onto `expectedSessionKeyGen` so a key rotation racing an event write is
36
+ * rejected by the backend ConditionCheck rather than committing an
37
+ * undecryptable row (tool-event consolidation #229/#230).
38
+ */
39
+ sessionKeyGen: string | null;
26
40
  }
27
41
  /**
28
42
  * CP-1.b IMPL r5 H-2 — Typed error thrown by `prepareSessionEncryption()`
@@ -45,7 +59,13 @@ export interface ResumeOrCreateSessionResult {
45
59
  * shell-side typed error closes the funnel at session-create time so
46
60
  * the user never reaches a session that can't be decrypted.
47
61
  */
48
- export declare class PlannerProxyServiceKeyMissingError extends Error {
62
+ export type SessionEncryptionPreparationFailureKind = 'backend_unavailable' | 'local_key_unavailable';
63
+ export declare class SessionEncryptionPreparationError extends Error {
64
+ readonly kind: SessionEncryptionPreparationFailureKind;
65
+ readonly cause?: unknown;
66
+ constructor(kind: SessionEncryptionPreparationFailureKind, message: string, cause?: unknown);
67
+ }
68
+ export declare class PlannerProxyServiceKeyMissingError extends SessionEncryptionPreparationError {
49
69
  constructor(msg: string);
50
70
  }
51
71
  /**
@@ -48,6 +48,8 @@ export declare function buildContainerEntrypoint(sanitizedEnv: Readonly<Record<s
48
48
  * - `-v <relayScript>:/codevibe/relay.js:ro` → the in-container relay (ro).
49
49
  * - `-v <udsDir>:/codevibe/broker:rw` → the bind-mounted broker UDS dir (rw,
50
50
  * so the container's `connect()` works; the dir holds only the socket).
51
+ * - `-v <bootstrap>:/codevibe/agent:ro` → broker helper + token file (ro).
52
+ * - `-v <agentConfig>:/codevibe/agent-config:rw` → non-secret CLI config/runtime.
51
53
  * - env via repeated `-e K=V` built EXACTLY from `spec.sanitizedEnv` (no host
52
54
  * env passthrough; `docker run` does NOT inherit the host env). MED fix:
53
55
  * the `-e` flags ADD to the image's baked env, so the AUTHORITATIVE wipe is
@@ -70,6 +72,11 @@ export declare function buildRunArgv(args: {
70
72
  hostDir: string;
71
73
  sandboxDir: string;
72
74
  };
75
+ /** CP-7 PART D — mutable CLI config/runtime mount (`hostDir`→`sandboxDir:rw`). */
76
+ agentConfig?: {
77
+ hostDir: string;
78
+ sandboxDir: string;
79
+ };
73
80
  }): string[];
74
81
  /**
75
82
  * `docker exec [-i] <name> env -i <sanitizedEnv> <argv...>` — run the agent
@@ -62,8 +62,8 @@ export interface SandboxExecDeps {
62
62
  export declare function buildSeatbeltProfile(workdir: string, execPath?: string,
63
63
  /**
64
64
  * CP-7 PART D — extra READ-ONLY dirs to grant (the apiKeyHelper bootstrap dir
65
- * holding the helper script + broker-token file + agent config). Read-only:
66
- * the agent reads the current token; no write grant (the host owns rotation).
65
+ * holding the helper script + broker-token file). Read-only: the agent reads
66
+ * the current token; no write grant (the host owns rotation).
67
67
  * These are explicit, scoped subpaths — NOT $HOME / /Users (the MED-fix
68
68
  * invariant that host secrets stay unreadable still holds).
69
69
  */
@@ -102,7 +102,21 @@ homedir?: string,
102
102
  * Null/absent → no audit deny is emitted (e.g. a unit test without a real audit
103
103
  * tree); production always threads the resolved audit dir.
104
104
  */
105
- auditDir?: string | null): string;
105
+ auditDir?: string | null,
106
+ /**
107
+ * Extra dirs that the agent may read/write. Used only for the mutable CLI
108
+ * config/runtime dir; the broker-token helper stays in `extraReadDirs`.
109
+ */
110
+ extraWriteDirs?: readonly string[],
111
+ /**
112
+ * A1d (design §8.1 — the resolver sandbox lattice). Network posture:
113
+ * `'loopback'` (default — the CP-7 broker tier, byte-identical profile) or
114
+ * `'open'` (the resolver-confinement row for a broker-less reduced-trust
115
+ * agent: inbound stays denied, ALL outbound is allowed so the agent's own
116
+ * file-authed model call reaches its vendor directly). See
117
+ * {@link SubstrateSpec.networkPosture}.
118
+ */
119
+ networkPosture?: 'loopback' | 'open'): string;
106
120
  /**
107
121
  * A5 macOS `sandbox-exec` substrate (`egressFidelity: 'coarse'`). See file
108
122
  * header. NOT the default — the LE selects it as the macOS Docker-fallback.
@@ -59,8 +59,7 @@ export interface SubstrateSpec {
59
59
  /**
60
60
  * CP-7 PART D (§3.3 agy-R3 bootstrap) — OPTIONAL, additive. The host
61
61
  * directory holding the agent's `apiKeyHelper` script + the broker-token
62
- * file + the agent config (Claude `settings.json` / Codex `config.toml`),
63
- * bind-mounted READ-ONLY into the sandbox at `sandboxDir` so the wiped,
62
+ * file, bind-mounted READ-ONLY into the sandbox at `sandboxDir` so the wiped,
64
63
  * `--network none` agent can read the CURRENT broker token from a file
65
64
  * WITHOUT a network/IPC fetch. The host LE REFRESHES the token file
66
65
  * out-of-band on rotation; the read-only mount lets the host rewrite the
@@ -71,11 +70,25 @@ export interface SubstrateSpec {
71
70
  * wire; every existing `SubstrateSpec` construction still compiles.
72
71
  */
73
72
  agentBootstrap?: {
74
- /** Host dir holding the helper script + token file + agent config (0700). */
73
+ /** Host dir holding the helper script + token file (0700). */
75
74
  hostDir: string;
76
75
  /** Read-only mount point inside the sandbox (NOT under the workdir). */
77
76
  sandboxDir: string;
78
77
  };
78
+ /**
79
+ * CP-7 PART D follow-up — mutable CLI config/runtime dir. Real agent CLIs
80
+ * create small startup/cache files beside their config (`CODEX_HOME`,
81
+ * `CLAUDE_CONFIG_DIR`). The broker-token helper stays in
82
+ * {@link agentBootstrap} and remains read-only; this separate dir is writable
83
+ * and contains only non-secret config/runtime state. It also lives outside the
84
+ * workdir so it never appears in diffs. LOCAL-ONLY; never on any wire.
85
+ */
86
+ agentConfig?: {
87
+ /** Host dir holding settings/config/runtime files (0700). */
88
+ hostDir: string;
89
+ /** Writable mount/grant point inside the sandbox. */
90
+ sandboxDir: string;
91
+ };
79
92
  /**
80
93
  * CP-7 W3 — Stage-2 r1 HIGH (A5 audit-readability). OPTIONAL, additive. The
81
94
  * RESOLVED per-task audit DIR (the sibling `.codevibe/audit/<group>/<track>/`
@@ -88,6 +101,22 @@ export interface SubstrateSpec {
88
101
  * construction still compiles (absent → no audit deny is emitted).
89
102
  */
90
103
  auditDir?: string;
104
+ /**
105
+ * A1d (design §8.1 — the write-capable resolver sandbox lattice). OPTIONAL,
106
+ * additive; A5-only (A1 ignores it — the docker row is never launched with an
107
+ * open posture). Network posture the Seatbelt profile emits:
108
+ * - `'loopback'` (default, absent) — deny all network, re-allow loopback
109
+ * only: the CP-7 broker tier (the agent's ONLY model path is the broker).
110
+ * - `'open'` — deny inbound, allow ALL outbound: the RESOLVER-CONFINEMENT
111
+ * row for a broker-less reduced-trust agent (agy/gemini) whose model call
112
+ * dials its vendor DIRECTLY with its own file-based auth. The confinement
113
+ * objective on that row is FS-WRITE confinement (writes stay strictly
114
+ * inside the disposable merge workspace), not egress pinning — the engage
115
+ * result carries a reduced-trust badge for the open egress.
116
+ * A LOCAL-ONLY field — never on any wire; every existing `SubstrateSpec`
117
+ * construction still compiles (absent → loopback, byte-identical profile).
118
+ */
119
+ networkPosture?: "loopback" | "open";
91
120
  }
92
121
  /**
93
122
  * A structural `ChildProcess` subset. The LE widens its internal child