instar 1.3.343 → 1.3.345

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 (147) hide show
  1. package/dist/commands/init.d.ts +4 -4
  2. package/dist/commands/init.d.ts.map +1 -1
  3. package/dist/commands/init.js.map +1 -1
  4. package/dist/commands/reflect.d.ts.map +1 -1
  5. package/dist/commands/reflect.js +7 -0
  6. package/dist/commands/reflect.js.map +1 -1
  7. package/dist/commands/server.d.ts.map +1 -1
  8. package/dist/commands/server.js +126 -8
  9. package/dist/commands/server.js.map +1 -1
  10. package/dist/commands/setup.d.ts +1 -1
  11. package/dist/commands/setup.d.ts.map +1 -1
  12. package/dist/commands/setup.js.map +1 -1
  13. package/dist/core/Config.d.ts +12 -3
  14. package/dist/core/Config.d.ts.map +1 -1
  15. package/dist/core/Config.js +40 -6
  16. package/dist/core/Config.js.map +1 -1
  17. package/dist/core/FrameworkSessionStore.d.ts +1 -1
  18. package/dist/core/FrameworkSessionStore.d.ts.map +1 -1
  19. package/dist/core/PiCliIntelligenceProvider.d.ts +52 -0
  20. package/dist/core/PiCliIntelligenceProvider.d.ts.map +1 -0
  21. package/dist/core/PiCliIntelligenceProvider.js +71 -0
  22. package/dist/core/PiCliIntelligenceProvider.js.map +1 -0
  23. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  24. package/dist/core/PostUpdateMigrator.js +57 -0
  25. package/dist/core/PostUpdateMigrator.js.map +1 -1
  26. package/dist/core/PreCompactionFlush.d.ts +1 -1
  27. package/dist/core/PreCompactionFlush.d.ts.map +1 -1
  28. package/dist/core/ResumeValidator.d.ts +1 -1
  29. package/dist/core/ResumeValidator.d.ts.map +1 -1
  30. package/dist/core/SessionManager.d.ts +130 -0
  31. package/dist/core/SessionManager.d.ts.map +1 -1
  32. package/dist/core/SessionManager.js +545 -10
  33. package/dist/core/SessionManager.js.map +1 -1
  34. package/dist/core/TopicFrameworksStore.d.ts.map +1 -1
  35. package/dist/core/TopicFrameworksStore.js +3 -0
  36. package/dist/core/TopicFrameworksStore.js.map +1 -1
  37. package/dist/core/frameworkInjectionProcesses.d.ts.map +1 -1
  38. package/dist/core/frameworkInjectionProcesses.js +4 -0
  39. package/dist/core/frameworkInjectionProcesses.js.map +1 -1
  40. package/dist/core/frameworkSessionLaunch.d.ts +8 -0
  41. package/dist/core/frameworkSessionLaunch.d.ts.map +1 -1
  42. package/dist/core/frameworkSessionLaunch.js +73 -0
  43. package/dist/core/frameworkSessionLaunch.js.map +1 -1
  44. package/dist/core/intelligenceProviderFactory.d.ts +15 -1
  45. package/dist/core/intelligenceProviderFactory.d.ts.map +1 -1
  46. package/dist/core/intelligenceProviderFactory.js +39 -1
  47. package/dist/core/intelligenceProviderFactory.js.map +1 -1
  48. package/dist/core/types.d.ts +88 -8
  49. package/dist/core/types.d.ts.map +1 -1
  50. package/dist/core/types.js.map +1 -1
  51. package/dist/messaging/SpawnRequestManager.d.ts +14 -0
  52. package/dist/messaging/SpawnRequestManager.d.ts.map +1 -1
  53. package/dist/messaging/SpawnRequestManager.js +17 -0
  54. package/dist/messaging/SpawnRequestManager.js.map +1 -1
  55. package/dist/messaging/shared/telegramRelayPrompt.d.ts +1 -1
  56. package/dist/messaging/shared/telegramRelayPrompt.d.ts.map +1 -1
  57. package/dist/monitoring/ApprenticeshipCycleStore.d.ts +59 -1
  58. package/dist/monitoring/ApprenticeshipCycleStore.d.ts.map +1 -1
  59. package/dist/monitoring/ApprenticeshipCycleStore.js +77 -2
  60. package/dist/monitoring/ApprenticeshipCycleStore.js.map +1 -1
  61. package/dist/monitoring/ReapLog.d.ts +6 -0
  62. package/dist/monitoring/ReapLog.d.ts.map +1 -1
  63. package/dist/monitoring/ReapLog.js +1 -0
  64. package/dist/monitoring/ReapLog.js.map +1 -1
  65. package/dist/monitoring/SessionReaper.d.ts +1 -1
  66. package/dist/monitoring/SessionReaper.d.ts.map +1 -1
  67. package/dist/monitoring/SessionReaper.js.map +1 -1
  68. package/dist/monitoring/frameworkActivitySignals.d.ts.map +1 -1
  69. package/dist/monitoring/frameworkActivitySignals.js +21 -0
  70. package/dist/monitoring/frameworkActivitySignals.js.map +1 -1
  71. package/dist/monitoring/frameworkProcessSignals.d.ts.map +1 -1
  72. package/dist/monitoring/frameworkProcessSignals.js +22 -0
  73. package/dist/monitoring/frameworkProcessSignals.js.map +1 -1
  74. package/dist/providers/adapters/pi-cli/capabilities.d.ts +31 -0
  75. package/dist/providers/adapters/pi-cli/capabilities.d.ts.map +1 -0
  76. package/dist/providers/adapters/pi-cli/capabilities.js +40 -0
  77. package/dist/providers/adapters/pi-cli/capabilities.js.map +1 -0
  78. package/dist/providers/adapters/pi-cli/config.d.ts +65 -0
  79. package/dist/providers/adapters/pi-cli/config.d.ts.map +1 -0
  80. package/dist/providers/adapters/pi-cli/config.js +43 -0
  81. package/dist/providers/adapters/pi-cli/config.js.map +1 -0
  82. package/dist/providers/adapters/pi-cli/control/piHardKill.d.ts +19 -0
  83. package/dist/providers/adapters/pi-cli/control/piHardKill.d.ts.map +1 -0
  84. package/dist/providers/adapters/pi-cli/control/piHardKill.js +67 -0
  85. package/dist/providers/adapters/pi-cli/control/piHardKill.js.map +1 -0
  86. package/dist/providers/adapters/pi-cli/errors.d.ts +43 -0
  87. package/dist/providers/adapters/pi-cli/errors.d.ts.map +1 -0
  88. package/dist/providers/adapters/pi-cli/errors.js +71 -0
  89. package/dist/providers/adapters/pi-cli/errors.js.map +1 -0
  90. package/dist/providers/adapters/pi-cli/index.d.ts +39 -0
  91. package/dist/providers/adapters/pi-cli/index.d.ts.map +1 -0
  92. package/dist/providers/adapters/pi-cli/index.js +69 -0
  93. package/dist/providers/adapters/pi-cli/index.js.map +1 -0
  94. package/dist/providers/adapters/pi-cli/observability/sessionId.d.ts +27 -0
  95. package/dist/providers/adapters/pi-cli/observability/sessionId.d.ts.map +1 -0
  96. package/dist/providers/adapters/pi-cli/observability/sessionId.js +53 -0
  97. package/dist/providers/adapters/pi-cli/observability/sessionId.js.map +1 -0
  98. package/dist/providers/adapters/pi-cli/policy.d.ts +44 -0
  99. package/dist/providers/adapters/pi-cli/policy.d.ts.map +1 -0
  100. package/dist/providers/adapters/pi-cli/policy.js +74 -0
  101. package/dist/providers/adapters/pi-cli/policy.js.map +1 -0
  102. package/dist/providers/adapters/pi-cli/transport/agenticSessionRpc.d.ts +34 -0
  103. package/dist/providers/adapters/pi-cli/transport/agenticSessionRpc.d.ts.map +1 -0
  104. package/dist/providers/adapters/pi-cli/transport/agenticSessionRpc.js +194 -0
  105. package/dist/providers/adapters/pi-cli/transport/agenticSessionRpc.js.map +1 -0
  106. package/dist/providers/adapters/pi-cli/transport/oneShotCompletion.d.ts +33 -0
  107. package/dist/providers/adapters/pi-cli/transport/oneShotCompletion.d.ts.map +1 -0
  108. package/dist/providers/adapters/pi-cli/transport/oneShotCompletion.js +166 -0
  109. package/dist/providers/adapters/pi-cli/transport/oneShotCompletion.js.map +1 -0
  110. package/dist/providers/adapters/pi-cli/transport/piSpawn.d.ts +87 -0
  111. package/dist/providers/adapters/pi-cli/transport/piSpawn.d.ts.map +1 -0
  112. package/dist/providers/adapters/pi-cli/transport/piSpawn.js +242 -0
  113. package/dist/providers/adapters/pi-cli/transport/piSpawn.js.map +1 -0
  114. package/dist/providers/adapters/pi-cli/transport/rpcClient.d.ts +103 -0
  115. package/dist/providers/adapters/pi-cli/transport/rpcClient.d.ts.map +1 -0
  116. package/dist/providers/adapters/pi-cli/transport/rpcClient.js +238 -0
  117. package/dist/providers/adapters/pi-cli/transport/rpcClient.js.map +1 -0
  118. package/dist/providers/bootRegistration.d.ts +38 -0
  119. package/dist/providers/bootRegistration.d.ts.map +1 -1
  120. package/dist/providers/bootRegistration.js +52 -0
  121. package/dist/providers/bootRegistration.js.map +1 -1
  122. package/dist/providers/parity/rules/skillParityRule.d.ts.map +1 -1
  123. package/dist/providers/parity/rules/skillParityRule.js +6 -0
  124. package/dist/providers/parity/rules/skillParityRule.js.map +1 -1
  125. package/dist/scaffold/templates.d.ts.map +1 -1
  126. package/dist/scaffold/templates.js +3 -2
  127. package/dist/scaffold/templates.js.map +1 -1
  128. package/dist/scheduler/JobScheduler.d.ts.map +1 -1
  129. package/dist/scheduler/JobScheduler.js +22 -0
  130. package/dist/scheduler/JobScheduler.js.map +1 -1
  131. package/dist/server/routes.d.ts.map +1 -1
  132. package/dist/server/routes.js +10 -3
  133. package/dist/server/routes.js.map +1 -1
  134. package/dist/threadline/PipeSessionSpawner.d.ts +23 -0
  135. package/dist/threadline/PipeSessionSpawner.d.ts.map +1 -1
  136. package/dist/threadline/PipeSessionSpawner.js +27 -0
  137. package/dist/threadline/PipeSessionSpawner.js.map +1 -1
  138. package/package.json +2 -2
  139. package/scripts/lint-no-direct-destructive.js +3 -0
  140. package/scripts/lint-no-unfunneled-headless-launch.js +128 -0
  141. package/src/data/builtin-manifest.json +65 -65
  142. package/src/scaffold/templates.ts +3 -2
  143. package/upgrades/1.3.344.md +46 -0
  144. package/upgrades/1.3.345.md +154 -0
  145. package/upgrades/side-effects/apprenticeship-layer-balance.md +50 -0
  146. package/upgrades/side-effects/june15-headless-spawn-reroute.md +105 -0
  147. package/upgrades/side-effects/pi-harness-integration.md +82 -0
@@ -28,8 +28,6 @@ import { AgentServer } from '../server/AgentServer.js';
28
28
  import { TelegramAdapter, TOPIC_STYLE, selectTopicEmoji } from '../messaging/TelegramAdapter.js';
29
29
  import { getTelegramInboundDir } from '../messaging/shared/telegramInboundFiles.js';
30
30
  import { RelationshipManager } from '../core/RelationshipManager.js';
31
- import { ClaudeCliIntelligenceProvider } from '../core/ClaudeCliIntelligenceProvider.js';
32
- import { wrapIntelligenceWithCircuitBreaker } from '../core/CircuitBreakingIntelligenceProvider.js';
33
31
  import { configureLlmCircuitBreaker } from '../core/LlmCircuitBreaker.js';
34
32
  import { isClaudeForbidden } from '../core/claudeForbiddenGuard.js';
35
33
  import { FeedbackManager } from '../core/FeedbackManager.js';
@@ -2241,6 +2239,40 @@ export async function startServer(options) {
2241
2239
  const ids = [...anthropicRegistration.registered, ...anthropicRegistration.alreadyRegistered];
2242
2240
  console.log(pc.green(` Providers registry: ${ids.join(', ')} registered`));
2243
2241
  }
2242
+ // pi-cli adapter (PI-HARNESS-INTEGRATION-SPEC §4.2) — ships dark:
2243
+ // registers ONLY when enabledFrameworks explicitly contains 'pi-cli'
2244
+ // AND the binary is detectable. Own try/catch: a pi registration
2245
+ // failure must never affect the Anthropic adapters or the boot.
2246
+ try {
2247
+ const { registerPiAdapters } = await import('../providers/bootRegistration.js');
2248
+ const piRegistration = await registerPiAdapters({
2249
+ ...(config.enabledFrameworks ? { enabledFrameworks: config.enabledFrameworks } : {}),
2250
+ ...(config.sessions?.frameworkBinaryPaths?.['pi-cli']
2251
+ ? { piPath: config.sessions.frameworkBinaryPaths['pi-cli'] }
2252
+ : {}),
2253
+ ...(config.sessions?.frameworkDefaultModels?.['pi-cli']
2254
+ ? { model: config.sessions.frameworkDefaultModels['pi-cli'] }
2255
+ : {}),
2256
+ ...(config.sessions?.piCliAllowAnthropicProviders !== undefined
2257
+ ? { allowAnthropicProviders: config.sessions.piCliAllowAnthropicProviders }
2258
+ : {}),
2259
+ sessionDir: path.join(config.stateDir, 'pi-sessions'),
2260
+ });
2261
+ if (piRegistration.skippedReason) {
2262
+ if (piRegistration.skippedReason === 'pi-binary-missing') {
2263
+ // Configured-but-missing is worth a visible (non-fatal) note.
2264
+ console.log(pc.yellow(` Providers registry: pi-cli enabled but binary missing — install @earendil-works/pi-coding-agent`));
2265
+ }
2266
+ // 'pi-not-enabled' is the dark default — say nothing.
2267
+ }
2268
+ else {
2269
+ const piIds = [...piRegistration.registered, ...piRegistration.alreadyRegistered];
2270
+ console.log(pc.green(` Providers registry: ${piIds.join(', ')} registered`));
2271
+ }
2272
+ }
2273
+ catch (err) {
2274
+ console.warn(` Providers registry: pi-cli registration failed (non-fatal): ${err instanceof Error ? err.message : err}`);
2275
+ }
2244
2276
  // Read-only probe — `getRoutingPolicy` isn't on the public surface,
2245
2277
  // so we test by attempting a no-op resolve and seeing whether the
2246
2278
  // chain fires. Cheaper proxy: a private convention — set a marker
@@ -2713,6 +2745,11 @@ export async function startServer(options) {
2713
2745
  const codexThreadlineMcp = config.threadline
2714
2746
  ? resolveThreadlineMcpEntry(config.sessions.projectDir, config.stateDir, config.projectName)
2715
2747
  : undefined;
2748
+ // Headless-spawn reroute (june15-headless-spawn-reroute, PR2): thread the
2749
+ // subscriptionPath mode + caps so spawnSession's claude-code headless branch
2750
+ // knows whether to reroute a `claude -p` one-shot onto the interactive
2751
+ // (subscription) lane. Absent/'off' ⇒ today's behavior, byte-for-byte.
2752
+ const subscriptionPathCfg = config.intelligence?.subscriptionPath;
2716
2753
  const sessionManagerConfig = {
2717
2754
  ...config.sessions,
2718
2755
  ...(codexThreadlineMcp ? { codexThreadlineMcp } : {}),
@@ -2720,8 +2757,21 @@ export async function startServer(options) {
2720
2757
  ...(config.sessions.respawnBuildContext ?? {}),
2721
2758
  enabled: config.sessions.respawnBuildContext?.enabled ?? !!config.developmentAgent,
2722
2759
  },
2760
+ subscriptionPathMode: subscriptionPathCfg?.mode ?? 'off',
2761
+ ...(subscriptionPathCfg?.maxRerouted != null ? { subscriptionMaxRerouted: subscriptionPathCfg.maxRerouted } : {}),
2762
+ ...(subscriptionPathCfg?.maxReroutedLifetimeMinutes != null
2763
+ ? { subscriptionReroutedLifetimeMinutes: subscriptionPathCfg.maxReroutedLifetimeMinutes }
2764
+ : {}),
2723
2765
  };
2724
2766
  const sessionManager = new SessionManager(sessionManagerConfig, state);
2767
+ // Wire the SAME TTL-cached SDK-credit reader PR1's routing policy uses, so
2768
+ // the reroute 'auto' decision and the intelligence-funnel routing share one
2769
+ // credit source and can't drift (june15-headless-spawn-reroute, PR2). Only
2770
+ // when registration succeeded; otherwise 'auto' resolves to the subscription
2771
+ // floor via the null-snapshot contract.
2772
+ if (anthropicRegistration?.readSdkCredit) {
2773
+ sessionManager.setSdkCreditReader(anthropicRegistration.readSdkCredit);
2774
+ }
2725
2775
  // Input Guard is constructed later (after sharedIntelligence is available)
2726
2776
  // so the topic coherence reviewer can route through the IntelligenceProvider
2727
2777
  // abstraction instead of calling Anthropic directly.
@@ -2919,10 +2969,18 @@ export async function startServer(options) {
2919
2969
  : 'Claude CLI subscription';
2920
2970
  }
2921
2971
  else {
2922
- // Fall back to the legacy Claude path for backwards-compat. Wrap with
2923
- // the circuit breaker (the factory path above is already wrapped).
2972
+ // Fall back to the legacy Claude path for backwards-compat via the
2973
+ // factory, not direct construction (june15-headless-spawn-reroute,
2974
+ // Class 8): the factory carries the breaker wrap AND the
2975
+ // subscription-path router, so a fallback provider can't silently
2976
+ // dodge June-15 routing. Factory-null (no claude binary) now yields
2977
+ // an honest absence instead of a provider with an undefined path.
2924
2978
  sharedIntelligence =
2925
- wrapIntelligenceWithCircuitBreaker(new ClaudeCliIntelligenceProvider(config.sessions.claudePath)) ?? undefined;
2979
+ buildIntelligenceProvider({
2980
+ framework: 'claude-code',
2981
+ binaryPath: config.sessions.claudePath,
2982
+ ...(subscriptionPathOption ? { subscriptionPath: subscriptionPathOption } : {}),
2983
+ }) ?? undefined;
2926
2984
  intelligenceSource = 'Claude CLI subscription (fallback)';
2927
2985
  }
2928
2986
  }
@@ -2958,6 +3016,19 @@ export async function startServer(options) {
2958
3016
  ...(fw === 'claude-code' && subscriptionPathOption
2959
3017
  ? { subscriptionPath: subscriptionPathOption }
2960
3018
  : {}),
3019
+ // pi-cli routing (PI-HARNESS-INTEGRATION-SPEC §4.4): thread the
3020
+ // configured model pattern + the explicit Anthropic override.
3021
+ // Absent pattern ⇒ the factory degrades to null (guarded by design).
3022
+ ...(fw === 'pi-cli'
3023
+ ? {
3024
+ ...(config.sessions?.frameworkDefaultModels?.['pi-cli']
3025
+ ? { piModel: config.sessions.frameworkDefaultModels['pi-cli'] }
3026
+ : {}),
3027
+ ...(config.sessions?.piCliAllowAnthropicProviders !== undefined
3028
+ ? { piAllowAnthropicProviders: config.sessions.piCliAllowAnthropicProviders }
3029
+ : {}),
3030
+ }
3031
+ : {}),
2961
3032
  }),
2962
3033
  onDegrade: (info) => {
2963
3034
  try {
@@ -3053,8 +3124,14 @@ export async function startServer(options) {
3053
3124
  // be built but a claude binary path is still configured. Skipped on
3054
3125
  // codex-only agents (isClaudeForbidden) — there, relationships run
3055
3126
  // without LLM intelligence rather than silently using Claude.
3127
+ // Via the factory (Class 8): carries breaker + subscription router.
3128
+ const { buildIntelligenceProvider: buildFallbackIP } = await import('../core/intelligenceProviderFactory.js');
3056
3129
  config.relationships.intelligence =
3057
- wrapIntelligenceWithCircuitBreaker(new ClaudeCliIntelligenceProvider(config.sessions.claudePath)) ?? undefined;
3130
+ buildFallbackIP({
3131
+ framework: 'claude-code',
3132
+ binaryPath: config.sessions.claudePath,
3133
+ ...(subscriptionPathOption ? { subscriptionPath: subscriptionPathOption } : {}),
3134
+ }) ?? undefined;
3058
3135
  intelligenceMode = 'LLM-supervised (Claude CLI subscription, fallback)';
3059
3136
  }
3060
3137
  relationships = new RelationshipManager(config.relationships);
@@ -4442,6 +4519,10 @@ export async function startServer(options) {
4442
4519
  reason: e.reason,
4443
4520
  disposition: e.disposition,
4444
4521
  origin: e.origin,
4522
+ // Positive-lane observability (june15-headless-spawn-reroute O4): record
4523
+ // which billing lane the reaped session ran on so the soak can confirm
4524
+ // rerouted sessions reach their completion from the reap-log too.
4525
+ ...(e.session.launchLane ? { launchLane: e.session.launchLane } : {}),
4445
4526
  });
4446
4527
  reapNotifier.onReaped({ session: e.session, reason: e.reason, disposition: e.disposition, origin: e.origin });
4447
4528
  // Coherence journal 'reaped' (§3.3): emitted HERE, alongside the
@@ -4689,8 +4770,15 @@ export async function startServer(options) {
4689
4770
  summaryIntelligence = sharedIntelligence;
4690
4771
  }
4691
4772
  else if (!isClaudeForbidden()) {
4692
- const { ClaudeCliIntelligenceProvider } = await import('../core/ClaudeCliIntelligenceProvider.js');
4693
- summaryIntelligence = wrapIntelligenceWithCircuitBreaker(new ClaudeCliIntelligenceProvider(config.sessions.claudePath));
4773
+ // Via the factory (june15-headless-spawn-reroute, Class 8): carries
4774
+ // the breaker wrap + the subscription-path router so topic summaries
4775
+ // can't silently dodge June-15 routing.
4776
+ const { buildIntelligenceProvider: buildSummaryIP } = await import('../core/intelligenceProviderFactory.js');
4777
+ summaryIntelligence = buildSummaryIP({
4778
+ framework: 'claude-code',
4779
+ binaryPath: config.sessions.claudePath,
4780
+ ...(subscriptionPathOption ? { subscriptionPath: subscriptionPathOption } : {}),
4781
+ });
4694
4782
  }
4695
4783
  // On a codex-only agent without a built Codex provider, summaryIntelligence
4696
4784
  // stays null — topic summaries are skipped rather than run on Claude.
@@ -7460,6 +7548,21 @@ export async function startServer(options) {
7460
7548
  ?? config.maxSessions
7461
7549
  ?? 5,
7462
7550
  getActiveSessions: () => sessionManager.listRunningSessions(),
7551
+ // Subscription-quota gate (june15-headless-spawn-reroute, finding S1):
7552
+ // wired ONLY when the subscription-path reroute is active — rerouted
7553
+ // A2A cold spawns land on the operator's 5h window, so inbound peer
7554
+ // traffic must respect the same quota gate scheduled jobs already do
7555
+ // (otherwise a chatty peer can rate-limit the USER's own
7556
+ // conversations). mode 'off' (the fleet default): seam absent,
7557
+ // admission byte-for-byte unchanged.
7558
+ ...((config.intelligence?.subscriptionPath?.mode === 'auto'
7559
+ || config.intelligence?.subscriptionPath?.mode === 'force')
7560
+ ? {
7561
+ shouldSpawnSession: (priority) => quotaTracker
7562
+ ? quotaTracker.shouldSpawnSession(priority)
7563
+ : { allowed: true, reason: 'No quota tracker — fail open' },
7564
+ }
7565
+ : {}),
7463
7566
  spawnSession: async (prompt, opts) => {
7464
7567
  // Warm-session A2A (Arch Y): when the SpawnRequest is flagged interactive,
7465
7568
  // launch a PERSISTENT (keep-alive) interactive worker instead of the
@@ -7855,6 +7958,21 @@ export async function startServer(options) {
7855
7958
  // Same per-agent codex threadline MCP override as SessionManager, so a
7856
7959
  // codex pipe-reply worker uses THIS agent's threadline MCP.
7857
7960
  ...(codexThreadlineMcp ? { codexThreadlineMcp } : {}),
7961
+ // June-15 subscription-path gates (spec Class 7 + findings S1/S4):
7962
+ // live mode accessor — under 'force' a claude-code pipe spawn
7963
+ // refuses from inside spawn() (the only shape that both fires the
7964
+ // degradation event AND falls through to the rerouted A2A path);
7965
+ // the quota gate stops auto-mode pipe spawns from hammering a hot
7966
+ // 5h window. Mode 'off' (default): both accessors are inert.
7967
+ getSubscriptionPathMode: () => config.intelligence?.subscriptionPath?.mode ?? 'off',
7968
+ ...((config.intelligence?.subscriptionPath?.mode === 'auto'
7969
+ || config.intelligence?.subscriptionPath?.mode === 'force')
7970
+ ? {
7971
+ shouldSpawnSession: () => quotaTracker
7972
+ ? quotaTracker.shouldSpawnSession()
7973
+ : { allowed: true, reason: 'No quota tracker — fail open' },
7974
+ }
7975
+ : {}),
7858
7976
  });
7859
7977
  console.log(pc.dim(` Pipe sessions: enabled (model: ${pipeConfig?.model ?? 'sonnet'}, max: ${pipeConfig?.maxConcurrent ?? 5})`));
7860
7978
  }