@harness-engineering/orchestrator 0.6.0 → 0.7.0

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.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
- import { Issue, AgentEvent, WorkflowConfig, TokenUsage, ConcernSignal, ScopeTier, EscalationConfig, RoutingDecision, Result, WorkflowDefinition, WorkspaceConfig, HooksConfig, AgentBackend, SessionStartParams, AgentSession, AgentError, TurnParams, TurnResult, CheckScriptDefinition, OutputRetentionConfig, BackendDef, RoutingConfig, RoutingUseCase, ContainerConfig, SecretConfig, AgentConfig, CustomTaskDefinition, TokenScope, AuthToken, AuthTokenPublic, IndexedFileKind, SessionSearchResult, ReindexStats, SessionSummarizationConfig, SessionSummary, SessionSummaryMeta, SessionsConfig, GatewayEvent, NotificationEnvelope, NotificationDeliveryResult, NotificationSinkConfig, NotificationsConfig } from '@harness-engineering/types';
1
+ import * as _harness_engineering_types from '@harness-engineering/types';
2
+ import { Issue, AgentEvent, WorkflowConfig, TokenUsage, ConcernSignal, ScopeTier, EscalationConfig, IssueRoutingDecision, Result, WorkflowDefinition, BackendDef, RoutingConfig, WorkspaceConfig, HooksConfig, AgentBackend, SessionStartParams, AgentSession, AgentError, TurnParams, TurnResult, CheckScriptDefinition, OutputRetentionConfig, RoutingDecision, RoutingUseCase, ContainerConfig, SecretConfig, AgentConfig, CustomTaskDefinition, TokenScope, AuthToken, AuthTokenPublic, IndexedFileKind, SessionSearchResult, ReindexStats, SessionSummarizationConfig, SessionSummary, SessionSummaryMeta, SessionsConfig, GatewayEvent, NotificationEnvelope, NotificationDeliveryResult, NotificationSinkConfig, NotificationsConfig } from '@harness-engineering/types';
2
3
  import { IssueTrackerClient, Issue as Issue$1, TrackerConfig, CacheMetricsRecorder, ArchiveHooks, SkillProposal, ProposalGateFinding } from '@harness-engineering/core';
3
4
  import { EnrichedSpec, ComplexityScore, SimulationResult, IntelligencePipeline, WeightedRecommendation, AnalysisProvider } from '@harness-engineering/intelligence';
4
5
  import { GraphStore } from '@harness-engineering/graph';
@@ -366,6 +367,10 @@ interface TickEvent {
366
367
  simulationResults?: Map<string, SimulationResult>;
367
368
  /** Pre-computed persona recommendations from specialization scorer (issueId -> recommendations) */
368
369
  personaRecommendations?: Map<string, WeightedRecommendation[]>;
370
+ /** Identity of this orchestrator. Items assigned to a different value are
371
+ * filtered out of dispatch by `selectCandidates`. Omit for back-compat
372
+ * (preserves today's permissive behavior). */
373
+ selfAssignee?: string;
369
374
  }
370
375
  interface WorkerExitEvent {
371
376
  type: 'worker_exit';
@@ -485,11 +490,11 @@ declare function sortCandidates(issues: readonly Issue[]): Issue[];
485
490
  * Check if a single issue is dispatch-eligible.
486
491
  * State comparisons are case-insensitive.
487
492
  */
488
- declare function isEligible(issue: Issue, state: OrchestratorState, activeStates: string[], terminalStates: string[]): boolean;
493
+ declare function isEligible(issue: Issue, state: OrchestratorState, activeStates: string[], terminalStates: string[], selfAssignee?: string | null): boolean;
489
494
  /**
490
495
  * Select and sort eligible candidates from a list of issues.
491
496
  */
492
- declare function selectCandidates(issues: readonly Issue[], state: OrchestratorState, activeStates: string[], terminalStates: string[]): Issue[];
497
+ declare function selectCandidates(issues: readonly Issue[], state: OrchestratorState, activeStates: string[], terminalStates: string[], selfAssignee?: string | null): Issue[];
493
498
 
494
499
  /**
495
500
  * Get the number of available global concurrency slots.
@@ -549,7 +554,7 @@ declare function detectScopeTier(issue: Issue, artifacts: ArtifactPresence): Sco
549
554
  * 4. If tier is in signalGated -> check concern signals
550
555
  * 5. Otherwise -> dispatch-local (safe default)
551
556
  */
552
- declare function routeIssue(scopeTier: ScopeTier, concernSignals: ConcernSignal[], config: EscalationConfig): RoutingDecision;
557
+ declare function routeIssue(scopeTier: ScopeTier, concernSignals: ConcernSignal[], config: EscalationConfig): IssueRoutingDecision;
553
558
 
554
559
  /**
555
560
  * Candidate skills the orchestrator may dispatch to. Keep this set
@@ -864,9 +869,107 @@ declare class WorkflowLoader {
864
869
  loadWorkflow(filePath: string): Promise<Result<WorkflowDefinition, Error>>;
865
870
  }
866
871
 
867
- declare function validateWorkflowConfig(config: unknown): Result<WorkflowConfig, Error>;
872
+ /**
873
+ * Cross-field check: every value in `routing` must reference a key in
874
+ * `backends`. Mirrors the Phase 1 standalone helper but returns a flat
875
+ * array of issues for synchronous consumption inside
876
+ * `validateWorkflowConfig` (which is hand-rolled, not a Zod parse).
877
+ *
878
+ * Exported for unit testing. Production callers should prefer
879
+ * `validateWorkflowConfig` (which wraps this helper with the surrounding
880
+ * legacy-vs-modern branching).
881
+ */
882
+ declare function crossFieldRoutingIssues(backends: Record<string, BackendDef>, routing: RoutingConfig): Array<{
883
+ path: string[];
884
+ message: string;
885
+ }>;
886
+ /**
887
+ * Spec B Phase 2 / S3: produce non-blocking warnings for misconfigured
888
+ * routing entries that are SYNTACTICALLY valid (the cross-field check
889
+ * has passed) but SEMANTICALLY suspicious:
890
+ *
891
+ * - `routing.skills.<name>` where `<name>` is not in the local skill
892
+ * catalog. Likely a typo or a skill that was renamed / removed.
893
+ *
894
+ * - `routing.modes.<mode>` where `<mode>` is not in the
895
+ * STANDARD_COGNITIVE_MODES tuple. Since `CognitiveMode` allows the
896
+ * `(string & {})` escape hatch, the type system accepts custom modes
897
+ * — but operators are far more likely to typo a standard mode than
898
+ * introduce a custom one, so we warn.
899
+ *
900
+ * Returns an empty array when `knownSkillNames` is empty (i.e., the
901
+ * catalog could not be discovered — most likely because `agents/skills/`
902
+ * is absent). Skipping is preferable to flooding the operator with
903
+ * false positives when the catalog itself is missing.
904
+ *
905
+ * Warnings are advisory; the loader continues to return `Ok` and the
906
+ * orchestrator starts normally.
907
+ */
908
+ declare function routingWarnings(routing: RoutingConfig, knownSkillNames: readonly string[]): string[];
909
+ interface ValidateWorkflowConfigOptions {
910
+ /**
911
+ * Known skill names from the local catalog. When non-empty, used to
912
+ * warn (S3) on `routing.skills.<name>` references that are not in
913
+ * the catalog. When empty, skill-name warnings are suppressed — the
914
+ * caller is presumed to be running without a discoverable catalog
915
+ * (e.g., tests, or orchestrator outside a harness project root).
916
+ */
917
+ knownSkillNames?: readonly string[];
918
+ }
919
+ interface ValidatedWorkflowConfig {
920
+ config: WorkflowConfig;
921
+ /**
922
+ * Non-blocking warnings produced during validation. Currently
923
+ * includes (Spec B Phase 2 / S3):
924
+ * - `routing.skills.<name>` not in the local catalog
925
+ * - `routing.modes.<mode>` not in `STANDARD_COGNITIVE_MODES`
926
+ */
927
+ warnings: readonly string[];
928
+ }
929
+ declare function validateWorkflowConfig(config: unknown, options?: ValidateWorkflowConfigOptions): Result<ValidatedWorkflowConfig, Error>;
868
930
  declare function getDefaultConfig(): WorkflowConfig;
869
931
 
932
+ /**
933
+ * Spec B Phase 3: an entry in the local skill catalog.
934
+ *
935
+ * Carries the skill's catalog `name` AND optional `cognitive_mode`
936
+ * declaration from `skill.yaml`. Consumed by the orchestrator dispatch
937
+ * site to construct `{ kind: 'skill', skillName, cognitiveMode }`
938
+ * RoutingUseCases so per-skill / per-mode routing fires at dispatch.
939
+ */
940
+ interface SkillCatalogEntry {
941
+ readonly name: string;
942
+ readonly cognitiveMode?: string;
943
+ }
944
+ /**
945
+ * Spec B Phase 3: read the local skill catalog at orchestrator startup,
946
+ * returning each declared skill's `name` AND optional `cognitive_mode`.
947
+ *
948
+ * Reads from EVERY host subdirectory under `agents/skills/` (claude-code,
949
+ * cursor, gemini, etc.). Names are deduplicated across hosts — first
950
+ * occurrence wins (matches Phase 2 behavior for `discoverSkillCatalogNames`).
951
+ *
952
+ * Returns an empty array when `agents/skills/` is absent (orchestrator
953
+ * running outside a harness project root). In that case dispatch-site
954
+ * routing falls through to per-tier resolution, preserving today's
955
+ * behavior (F11/N2).
956
+ *
957
+ * Errors reading individual skill.yaml files (malformed YAML, missing
958
+ * `name` field, IO errors) are swallowed silently. The catalog is
959
+ * advisory; a single broken skill.yaml should not block dispatch.
960
+ */
961
+ declare function discoverSkillCatalog(projectRoot: string): SkillCatalogEntry[];
962
+ /**
963
+ * Spec B Phase 2: read the local skill catalog at orchestrator startup
964
+ * for warning-level routing validation (`routing.skills.<name>` where
965
+ * `<name>` is not in the catalog).
966
+ *
967
+ * Spec B Phase 3: thin alias over {@link discoverSkillCatalog} — name
968
+ * extraction preserved for the Phase 2 WorkflowLoader → validation
969
+ * pipeline (no behavioral change for Phase 2 callers).
970
+ */
971
+ declare function discoverSkillCatalogNames(projectRoot: string): string[];
972
+
870
973
  /**
871
974
  * Adapter for using a markdown roadmap file as an issue tracker.
872
975
  *
@@ -1254,6 +1357,144 @@ interface MaintenanceStatus {
1254
1357
  history: RunResult[];
1255
1358
  }
1256
1359
 
1360
+ interface RoutingDecisionBusFilter {
1361
+ skillName?: string;
1362
+ mode?: string;
1363
+ backendName?: string;
1364
+ limit?: number;
1365
+ }
1366
+ interface RoutingDecisionBusOptions {
1367
+ /** Default 500. Bound on the in-memory ring buffer. */
1368
+ capacity?: number;
1369
+ /**
1370
+ * Logger for the structured `routing-decision` line (O1) and for
1371
+ * one-off warn() when a subscriber throws (S6). When omitted, the
1372
+ * bus silently swallows subscriber errors (test-mode default).
1373
+ */
1374
+ logger?: StructuredLogger;
1375
+ }
1376
+ /**
1377
+ * Spec B Phase 4 (D8): in-process bus + ring buffer for
1378
+ * {@link RoutingDecision} events. One emit() per
1379
+ * {@link BackendRouter.resolve} call; subscribers receive the
1380
+ * decision synchronously after the ring buffer is updated.
1381
+ *
1382
+ * Subscriber errors are isolated (caught + logged, never thrown
1383
+ * back to the emitter) so a misbehaving subscriber cannot block a
1384
+ * dispatch. (S6)
1385
+ *
1386
+ * Capacity-bound (default 500) via Array.shift() — acceptable for
1387
+ * v1 (see plan C4); switch to circular indexing if 24h dispatch
1388
+ * volume ever pushes 10K+ records/min.
1389
+ */
1390
+ declare class RoutingDecisionBus {
1391
+ private readonly ringBuffer;
1392
+ private readonly listeners;
1393
+ private readonly capacity;
1394
+ private readonly logger;
1395
+ constructor(opts?: RoutingDecisionBusOptions);
1396
+ emit(decision: RoutingDecision): void;
1397
+ recent(filter?: RoutingDecisionBusFilter): RoutingDecision[];
1398
+ subscribe(listener: (d: RoutingDecision) => void): () => void;
1399
+ /**
1400
+ * Spec B Phase 5 (review-S2 fix): release all subscriber references so
1401
+ * teardown can complete without anchoring closures. Called from
1402
+ * `Orchestrator.stop()` before nulling the bus reference. The bus
1403
+ * remains usable after clear — `subscribe()` works as normal.
1404
+ */
1405
+ clearListeners(): void;
1406
+ }
1407
+
1408
+ interface BackendRouterOptions {
1409
+ backends: Record<string, BackendDef>;
1410
+ routing: RoutingConfig;
1411
+ /**
1412
+ * Spec B Phase 4 (D8): when present, every resolve() emits its
1413
+ * decision onto the bus. The bus owns the structured log line + ring
1414
+ * buffer; the router stays a pure resolution function.
1415
+ */
1416
+ decisionBus?: RoutingDecisionBus;
1417
+ }
1418
+ /**
1419
+ * BackendRouter (Spec B Phase 1)
1420
+ *
1421
+ * Owns the lookup from a {@link RoutingUseCase} (a discriminated query
1422
+ * — tier, intelligence layer, maintenance, chat, isolation, **skill**,
1423
+ * **mode**) to a {@link RoutingDecision} naming a chosen backend and
1424
+ * the full resolution path that produced it.
1425
+ *
1426
+ * Resolution order (D2): invocation override -> per-skill -> per-mode
1427
+ * -> existing per-tier/intelligence/isolation/maintenance/chat ->
1428
+ * `routing.default`. Within each source, fallback chain entries are
1429
+ * tried in declared order; first existing backend wins. Unknown
1430
+ * entries are recorded with `outcome: 'unknown-backend'` and the walk
1431
+ * continues.
1432
+ *
1433
+ * Construction-time validation guarantees every name referenced by
1434
+ * `routing` is present in `backends` so the static-config case can
1435
+ * never produce a runtime exhaustion throw. The runtime throw at the
1436
+ * end of `resolve()` is a safety net for future dynamic-backends
1437
+ * scenarios where a chain entry can become unknown post-construction.
1438
+ */
1439
+ declare class BackendRouter {
1440
+ private readonly backends;
1441
+ private readonly routing;
1442
+ private readonly decisionBus;
1443
+ constructor(opts: BackendRouterOptions);
1444
+ /**
1445
+ * Resolve a {@link RoutingUseCase} to a {@link RoutingDecision}.
1446
+ *
1447
+ * @param useCase the routing query
1448
+ * @param opts.invocationOverride if set and the named backend exists,
1449
+ * beats all other sources (D7 — the `--backend <name>` escape hatch)
1450
+ */
1451
+ resolve(useCase: RoutingUseCase, opts?: {
1452
+ invocationOverride?: string;
1453
+ }): RoutingDecision;
1454
+ /**
1455
+ * Returns the {@link BackendDef} reference for the resolved name.
1456
+ * Identity-equal to the entry in `backends` (no copy) so callers
1457
+ * relying on reference equality (SC21) continue to work.
1458
+ */
1459
+ resolveDefinition(useCase: RoutingUseCase, opts?: {
1460
+ invocationOverride?: string;
1461
+ }): BackendDef;
1462
+ /**
1463
+ * Spec B Phase 4 (closes P1-IMP-2): a single resolve() + def lookup
1464
+ * for callers that need both. Replaces the previous pattern of
1465
+ * `resolveDefinition(useCase) + resolve(useCase)` which produced two
1466
+ * RoutingDecision emissions per dispatch — doubling routing-decision
1467
+ * log volume now that Phase 4 emits.
1468
+ *
1469
+ * Identity-equal `BackendDef` (no copy) so callers relying on
1470
+ * reference equality (SC21) continue to work.
1471
+ */
1472
+ resolveDecisionAndDef(useCase: RoutingUseCase, opts?: {
1473
+ invocationOverride?: string;
1474
+ }): {
1475
+ decision: RoutingDecision;
1476
+ def: BackendDef;
1477
+ };
1478
+ /**
1479
+ * The pre-Spec-B resolution helper: returns the configured
1480
+ * {@link RoutingValue} for tier/intelligence/isolation/maintenance/chat
1481
+ * use cases (or `undefined` for skill/mode use cases, which are owned
1482
+ * by the per-skill / per-mode steps in {@link resolve}). Returning
1483
+ * `undefined` lets the caller fall through to `routing.default`.
1484
+ */
1485
+ private resolveExistingUseCase;
1486
+ private validateReferences;
1487
+ }
1488
+
1489
+ /**
1490
+ * The central orchestrator that manages the lifecycle of coding agents.
1491
+ *
1492
+ * It polls an issue tracker for candidate tasks, manages ephemeral workspaces,
1493
+ * runs agents to resolve issues, and updates the tracker with progress.
1494
+ *
1495
+ * @fires Orchestrator#state_change Emitted when the internal state machine transitions
1496
+ * @fires Orchestrator#agent_event Emitted when an agent produces an output or thought
1497
+ */
1257
1498
  declare class Orchestrator extends EventEmitter {
1258
1499
  private state;
1259
1500
  private config;
@@ -1278,6 +1519,14 @@ declare class Orchestrator extends EventEmitter {
1278
1519
  * construction time. Eliminating this fallback is autopilot Phase 4+.
1279
1520
  */
1280
1521
  private backendFactory;
1522
+ /**
1523
+ * Spec B Phase 4 (D8): per-orchestrator in-process bus for
1524
+ * `RoutingDecision` events. Constructed alongside backendFactory when
1525
+ * agent.backends synthesis succeeds; null when legacy single-backend
1526
+ * config bypassed backends. Phase 5+ consumers (HTTP, WS, dashboard)
1527
+ * subscribe via `getRoutingDecisionBus()`.
1528
+ */
1529
+ private routingDecisionBus;
1281
1530
  /**
1282
1531
  * Test-only: when overrides.backend is provided, dispatch uses this
1283
1532
  * instance directly (bypassing the factory). Mirrors Phase 1
@@ -1300,6 +1549,15 @@ declare class Orchestrator extends EventEmitter {
1300
1549
  * so this map is the single source of truth post-migration.
1301
1550
  */
1302
1551
  private localResolvers;
1552
+ /**
1553
+ * Spec B Phase 3: skill catalog (name + cognitiveMode) read once at
1554
+ * construction from `projectRoot/agents/skills/`. Consulted by
1555
+ * `buildRoutingUseCase` at dispatch start to construct
1556
+ * `{ kind: 'skill', skillName, cognitiveMode }` RoutingUseCases.
1557
+ * Empty when the orchestrator runs outside a harness project root
1558
+ * (then dispatch falls through to per-tier, preserving F11/N2).
1559
+ */
1560
+ private readonly skillCatalog;
1303
1561
  /**
1304
1562
  * Per-resolver `onStatusChange` unsubscribe callbacks. Spec 2 Phase 5
1305
1563
  * (SC39): each local/pi resolver gets its own listener emitting a
@@ -1482,6 +1740,34 @@ declare class Orchestrator extends EventEmitter {
1482
1740
  * Returns a point-in-time snapshot of the orchestrator's internal state.
1483
1741
  */
1484
1742
  getSnapshot(): Record<string, unknown>;
1743
+ /**
1744
+ * Spec B Phase 4 (D8): expose the bus for Phase 5 (HTTP routes) and
1745
+ * Phase 7 (dashboard WS broadcast). Returns null when the legacy
1746
+ * single-backend config bypassed agent.backends synthesis.
1747
+ */
1748
+ getRoutingDecisionBus(): RoutingDecisionBus | null;
1749
+ /**
1750
+ * Spec B Phase 5: live BackendRouter for HTTP routes. The orchestrator
1751
+ * dispatch path uses the factory-owned router directly; observability
1752
+ * routes (config / decisions) reach it through this accessor. Returns
1753
+ * null when the legacy single-backend config bypassed agent.backends
1754
+ * synthesis (no backendFactory built).
1755
+ */
1756
+ getBackendRouter(): BackendRouter | null;
1757
+ /**
1758
+ * Spec B Phase 5: snapshot of the active RoutingConfig for the config
1759
+ * route and the trace route's bus-less router construction. Returns
1760
+ * null when the operator's harness.config.json carries no
1761
+ * `agent.routing` block.
1762
+ */
1763
+ getRoutingConfig(): _harness_engineering_types.RoutingConfig | null;
1764
+ /**
1765
+ * Spec B Phase 5: snapshot of `agent.backends` for the config route
1766
+ * (existence annotations) and the trace route (bus-less router
1767
+ * construction). Returns null when no synthesized backends map exists
1768
+ * (legacy single-backend configs).
1769
+ */
1770
+ getBackends(): Record<string, _harness_engineering_types.BackendDef> | null;
1485
1771
  /** Returns the maintenance scheduler status, or null if maintenance is not enabled. */
1486
1772
  getMaintenanceStatus(): MaintenanceStatus | null;
1487
1773
  }
@@ -1497,47 +1783,6 @@ declare function launchTUI(orchestrator: Orchestrator): {
1497
1783
  waitUntilExit: () => Promise<void>;
1498
1784
  };
1499
1785
 
1500
- interface BackendRouterOptions {
1501
- backends: Record<string, BackendDef>;
1502
- routing: RoutingConfig;
1503
- }
1504
- /**
1505
- * BackendRouter
1506
- *
1507
- * Owns the lookup from a `RoutingUseCase` (a discriminated query — tier,
1508
- * intelligence layer, maintenance, chat) to a named backend.
1509
- * Construction-time validation guarantees every name referenced by
1510
- * `routing` is present in `backends` so runtime lookups are total and
1511
- * never throw on unknown-name references (D6/D7).
1512
- *
1513
- * Lookups for tier/intelligence use cases that fall through to undefined
1514
- * mappings return `routing.default` without throwing — this matches the
1515
- * spec's "every use case inherits default unless explicitly routed"
1516
- * semantics. The `maintenance` and `chat` kinds always resolve to
1517
- * `routing.default` (SC19, SC20).
1518
- */
1519
- declare class BackendRouter {
1520
- private readonly backends;
1521
- private readonly routing;
1522
- constructor(opts: BackendRouterOptions);
1523
- /**
1524
- * Returns the backend name for a given use case.
1525
- *
1526
- * - `tier`: per-tier override, falling back to `routing.default`.
1527
- * - `intelligence`: per-layer override under `routing.intelligence`,
1528
- * falling back to `routing.default`.
1529
- * - `maintenance` / `chat`: always `routing.default`.
1530
- */
1531
- resolve(useCase: RoutingUseCase): string;
1532
- /**
1533
- * Returns the BackendDef reference for the resolved name. Returns the
1534
- * exact reference held in `backends` (no copy) so identity comparisons
1535
- * succeed (SC21).
1536
- */
1537
- resolveDefinition(useCase: RoutingUseCase): BackendDef;
1538
- private validateReferences;
1539
- }
1540
-
1541
1786
  /**
1542
1787
  * Options for `OrchestratorBackendFactory`.
1543
1788
  *
@@ -1572,6 +1817,11 @@ interface OrchestratorBackendFactoryOptions {
1572
1817
  * `/api/v1/telemetry/cache/stats` endpoint sees the full rolling window.
1573
1818
  */
1574
1819
  cacheMetrics?: CacheMetricsRecorder;
1820
+ /**
1821
+ * Spec B Phase 4 (D8): forwarded to the underlying BackendRouter so
1822
+ * every resolve() during forUseCase / resolveName emits.
1823
+ */
1824
+ decisionBus?: RoutingDecisionBus;
1575
1825
  }
1576
1826
  /**
1577
1827
  * High-level factory wrapping `BackendRouter` + `createBackend` plus
@@ -1604,8 +1854,19 @@ declare class OrchestratorBackendFactory {
1604
1854
  * is `undefined` for pure-modern configs. Threading the routed name
1605
1855
  * through dispatch eliminates that gap.
1606
1856
  */
1607
- resolveName(useCase: RoutingUseCase): string;
1608
- forUseCase(useCase: RoutingUseCase): AgentBackend;
1857
+ resolveName(useCase: RoutingUseCase, opts?: {
1858
+ invocationOverride?: string;
1859
+ }): string;
1860
+ /**
1861
+ * Spec B Phase 1: expose the underlying router for callers that need
1862
+ * it directly (e.g., {@link buildIntelligencePipeline} for the
1863
+ * I1 SEL/PESL comparison fix). Read-only access; consumers must not
1864
+ * mutate router state.
1865
+ */
1866
+ getRouter(): BackendRouter;
1867
+ forUseCase(useCase: RoutingUseCase, opts?: {
1868
+ invocationOverride?: string;
1869
+ }): AgentBackend;
1609
1870
  /**
1610
1871
  * Rebuild a `local`/`pi` backend with a resolver-bound `getModel`,
1611
1872
  * mirroring `createBackend`'s local/pi branches but substituting the
@@ -2291,4 +2552,4 @@ declare function emitProposalCreated(bus: EventEmitter, proposal: SkillProposal)
2291
2552
  declare function emitProposalApproved(bus: EventEmitter, proposal: SkillProposal): void;
2292
2553
  declare function emitProposalRejected(bus: EventEmitter, proposal: SkillProposal): void;
2293
2554
 
2294
- export { type AgentUpdateEvent, AnalysisArchive, type AnalysisRecord, type ApplyEventResult, type ArtifactPresence, type AttemptStats, BUILT_IN_TASKS, BackendRouter, type BackendRouterOptions, type BaseRefFallbackEvent, type BuildArchiveHooksOptions, ClaimManager, type ClaimManagerConfig, type CleanWorkspaceEffect, type CreateTokenInput, type CreateTokenResult, type CustomTaskValidationError, type DispatchEffect, type EmitLogEffect, type EscalateEffect, type ExecFileFn$1 as ExecFileFn, type FromConfigOptions, GateNotReadyError, type GateResult, GateRunError, type Highlight, type HighlightsInfo, type IndexedDoc, InteractionQueue, type LinearGraphQLExtension, LinearGraphQLStub, type LiveSession, MAX_ATTEMPTS, type MigrationResult, MockBackend, type NotificationSink, type NotificationSinkDeliverInput, ORCHESTRATOR_IDENTITY_FILE, Orchestrator, OrchestratorBackendFactory, type OrchestratorBackendFactoryOptions, type OrchestratorContext, type OrchestratorEvent, type OrchestratorState, PRDetector, type PRDetectorLogger, type PendingInteraction, type PersistedOutputEntry, PromotionError, type PromotionResult, PromptRenderer, type ProposalApprovedData, type ProposalCreatedData, type ProposalRejectedData, type PublishedIndex, type QueueInsertInput, type QueueRow, type QueueStats, RETRY_DELAYS_MS, type RateLimitSnapshot as RateLimitComputeSnapshot, type RateLimitConfig, type RateLimitSnapshot$1 as RateLimitSnapshot, type RegistryEntry, type ReleaseClaimEffect, type RetryEntry, type RetryFiredEvent, RoadmapTrackerAdapter, type RunAttemptPhase, type RunOrigin, type RunningEntry, type ScheduleRetryEffect, type SearchOptions, type SideEffect, SinkConfigError, SinkRegistry, SlackSink, type SlackSinkOptions, SqliteSearchIndex, type StallDetectedEvent, type StopEffect, type StreamManifest, StreamRecorder, type SummarizeContext, type SummarizeResult, type SyncMainOptions, type SyncMainResult, type SyncSkipReason, type TaskDefinition, TaskOutputStore, type TaskType, type TickEvent, TokenStore, type TokenTotals, type TriageConfig, type TriageDecision, type TriageSignals, type TriageSkill, type UpdateTokensEffect, WebhookQueue, type WorkerExitEvent, WorkflowLoader, WorkspaceHooks, WorkspaceManager, type WorkspaceManagerOptions, applyEvent, artifactPresenceFromIssue, buildArchiveHooks, calculateRetryDelay, canDispatch, computeRateLimitDelay, createBackend, createEmptyState, detectScopeTier, emitProposalApproved, emitProposalCreated, emitProposalRejected, extractHighlights, extractTitlePrefix, getAvailableSlots, getDefaultConfig, getPerStateCount, indexSessionDirectory, isEligible, isSummaryEnabled, launchTUI, loadPublishedIndex, migrateAgentConfig, normalizeFts5Query, openSearchIndex, promote, reconcile, reindexFromArchive, renderAnalysisComment, renderLlmSummaryMarkdown, renderPRComment, resolveEscalationConfig, resolveOrchestratorId, routeIssue, runGate, savePublishedIndex, searchIndexPath, selectCandidates, sortCandidates, summarizeArchivedSession, syncMain, triageIssue, truncateForBudget, validateCustomTasks, validateWorkflowConfig, wireNotificationSinks, wrapAsEnvelope };
2555
+ export { type AgentUpdateEvent, AnalysisArchive, type AnalysisRecord, type ApplyEventResult, type ArtifactPresence, type AttemptStats, BUILT_IN_TASKS, BackendRouter, type BackendRouterOptions, type BaseRefFallbackEvent, type BuildArchiveHooksOptions, ClaimManager, type ClaimManagerConfig, type CleanWorkspaceEffect, type CreateTokenInput, type CreateTokenResult, type CustomTaskValidationError, type DispatchEffect, type EmitLogEffect, type EscalateEffect, type ExecFileFn$1 as ExecFileFn, type FromConfigOptions, GateNotReadyError, type GateResult, GateRunError, type Highlight, type HighlightsInfo, type IndexedDoc, InteractionQueue, type LinearGraphQLExtension, LinearGraphQLStub, type LiveSession, MAX_ATTEMPTS, type MigrationResult, MockBackend, type NotificationSink, type NotificationSinkDeliverInput, ORCHESTRATOR_IDENTITY_FILE, Orchestrator, OrchestratorBackendFactory, type OrchestratorBackendFactoryOptions, type OrchestratorContext, type OrchestratorEvent, type OrchestratorState, PRDetector, type PRDetectorLogger, type PendingInteraction, type PersistedOutputEntry, PromotionError, type PromotionResult, PromptRenderer, type ProposalApprovedData, type ProposalCreatedData, type ProposalRejectedData, type PublishedIndex, type QueueInsertInput, type QueueRow, type QueueStats, RETRY_DELAYS_MS, type RateLimitSnapshot as RateLimitComputeSnapshot, type RateLimitConfig, type RateLimitSnapshot$1 as RateLimitSnapshot, type RegistryEntry, type ReleaseClaimEffect, type RetryEntry, type RetryFiredEvent, RoadmapTrackerAdapter, type RunAttemptPhase, type RunOrigin, type RunningEntry, type ScheduleRetryEffect, type SearchOptions, type SideEffect, SinkConfigError, SinkRegistry, type SkillCatalogEntry, SlackSink, type SlackSinkOptions, SqliteSearchIndex, type StallDetectedEvent, type StopEffect, type StreamManifest, StreamRecorder, type SummarizeContext, type SummarizeResult, type SyncMainOptions, type SyncMainResult, type SyncSkipReason, type TaskDefinition, TaskOutputStore, type TaskType, type TickEvent, TokenStore, type TokenTotals, type TriageConfig, type TriageDecision, type TriageSignals, type TriageSkill, type UpdateTokensEffect, type ValidateWorkflowConfigOptions, type ValidatedWorkflowConfig, WebhookQueue, type WorkerExitEvent, WorkflowLoader, WorkspaceHooks, WorkspaceManager, type WorkspaceManagerOptions, applyEvent, artifactPresenceFromIssue, buildArchiveHooks, calculateRetryDelay, canDispatch, computeRateLimitDelay, createBackend, createEmptyState, crossFieldRoutingIssues, detectScopeTier, discoverSkillCatalog, discoverSkillCatalogNames, emitProposalApproved, emitProposalCreated, emitProposalRejected, extractHighlights, extractTitlePrefix, getAvailableSlots, getDefaultConfig, getPerStateCount, indexSessionDirectory, isEligible, isSummaryEnabled, launchTUI, loadPublishedIndex, migrateAgentConfig, normalizeFts5Query, openSearchIndex, promote, reconcile, reindexFromArchive, renderAnalysisComment, renderLlmSummaryMarkdown, renderPRComment, resolveEscalationConfig, resolveOrchestratorId, routeIssue, routingWarnings, runGate, savePublishedIndex, searchIndexPath, selectCandidates, sortCandidates, summarizeArchivedSession, syncMain, triageIssue, truncateForBudget, validateCustomTasks, validateWorkflowConfig, wireNotificationSinks, wrapAsEnvelope };