@harness-engineering/orchestrator 0.8.4 → 0.9.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,6 +1,6 @@
1
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, LocalModelStatus, CustomTaskDefinition, TokenScope, AuthToken, AuthTokenPublic, IndexedFileKind, SessionSearchResult, ReindexStats, SessionSummarizationConfig, SessionSummary, SessionSummaryMeta, SessionsConfig, GatewayEvent, NotificationEnvelope, NotificationDeliveryResult, NotificationSinkConfig, NotificationsConfig } from '@harness-engineering/types';
3
- import { IssueTrackerClient, Issue as Issue$1, TrackerConfig, CacheMetricsRecorder, ArchiveHooks, SkillProposal, ProposalGateFinding } from '@harness-engineering/core';
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, LocalModelStatus, CustomTaskDefinition, MaintenanceConfig, TokenScope, AuthToken, AuthTokenPublic, IndexedFileKind, SessionSearchResult, ReindexStats, SessionSummarizationConfig, SessionSummary, SessionSummaryMeta, SessionsConfig, GatewayEvent, NotificationEnvelope, NotificationDeliveryResult, NotificationSinkConfig, NotificationsConfig } from '@harness-engineering/types';
3
+ import { IssueTrackerClient, Issue as Issue$1, TrackerConfig, eventSourcing, CacheMetricsRecorder, ArchiveHooks, SkillProposal, ProposalGateFinding } from '@harness-engineering/core';
4
4
  import { EnrichedSpec, ComplexityScore, SimulationResult, IntelligencePipeline, WeightedRecommendation, AnalysisProvider } from '@harness-engineering/intelligence';
5
5
  import { GraphStore } from '@harness-engineering/graph';
6
6
  import { execFile } from 'node:child_process';
@@ -1044,6 +1044,15 @@ declare class RoadmapTrackerAdapter implements IssueTrackerClient {
1044
1044
  * state and clearing the assignee field.
1045
1045
  */
1046
1046
  releaseIssue(issueId: string): Promise<Result<void, Error>>;
1047
+ /**
1048
+ * Resolve the roadmap store anchored on the configured aggregate file path.
1049
+ * The shard backend is chosen when a sibling `roadmap.d/` exists next to the
1050
+ * file; otherwise the monolith file is read/written whole. Callers guard
1051
+ * `this.config.filePath` before invoking.
1052
+ */
1053
+ private resolveStore;
1054
+ /** Load the roadmap via the store (sharded or monolith), returning a Result. */
1055
+ private loadRoadmap;
1047
1056
  private findFeatureById;
1048
1057
  /**
1049
1058
  * Fetches full issue details for a list of identifiers.
@@ -1062,12 +1071,47 @@ declare class RoadmapTrackerAdapter implements IssueTrackerClient {
1062
1071
  }
1063
1072
 
1064
1073
  /**
1065
- * Interface for Linear GraphQL tool extension.
1066
- * This is a stub implementation for Phase 4.
1074
+ * Interface for a Linear GraphQL tool extension — a thin authenticated client
1075
+ * over Linear's GraphQL API (https://linear.app/developers/graphql).
1067
1076
  */
1068
1077
  interface LinearGraphQLExtension {
1078
+ /**
1079
+ * Execute a GraphQL operation. Resolves to `Ok(data)` (the `data` object of
1080
+ * the GraphQL envelope) on success, or `Err` on a transport failure, a non-2xx
1081
+ * HTTP status, or a GraphQL `errors` array.
1082
+ */
1083
+ query(query: string, variables?: Record<string, unknown>): Promise<Result<unknown, Error>>;
1084
+ }
1085
+ interface LinearGraphQLClientOptions {
1086
+ /**
1087
+ * Linear authentication token. A personal API key is sent verbatim in the
1088
+ * `Authorization` header; an OAuth access token must be passed already prefixed
1089
+ * with `Bearer ` (Linear's two supported schemes).
1090
+ */
1091
+ apiKey: string;
1092
+ /** Override the GraphQL endpoint (e.g. a proxy). Defaults to Linear's API. */
1093
+ endpoint?: string;
1094
+ /** Injectable fetch for tests; defaults to the global `fetch`. */
1095
+ fetchFn?: typeof fetch;
1096
+ }
1097
+ /**
1098
+ * Real Linear GraphQL client. Replaces {@link LinearGraphQLStub}, which only
1099
+ * logged the query and returned an empty object. POSTs the operation to Linear's
1100
+ * GraphQL endpoint with the API key, and normalizes the three failure modes
1101
+ * (transport throw, non-2xx HTTP, GraphQL `errors`) into a single `Err`.
1102
+ */
1103
+ declare class LinearGraphQLClient implements LinearGraphQLExtension {
1104
+ private readonly apiKey;
1105
+ private readonly endpoint;
1106
+ private readonly fetchFn;
1107
+ constructor(opts: LinearGraphQLClientOptions);
1069
1108
  query(query: string, variables?: Record<string, unknown>): Promise<Result<unknown, Error>>;
1070
1109
  }
1110
+ /**
1111
+ * @deprecated Phase-4 placeholder retained for backward compatibility. It logs
1112
+ * the query and returns an empty object; use {@link LinearGraphQLClient} for a
1113
+ * real authenticated client.
1114
+ */
1071
1115
  declare class LinearGraphQLStub implements LinearGraphQLExtension {
1072
1116
  query(query: string, _variables?: Record<string, unknown>): Promise<Result<unknown, Error>>;
1073
1117
  }
@@ -1264,6 +1308,15 @@ type RunOrigin = 'cron' | 'cli' | {
1264
1308
  kind: 'chain';
1265
1309
  upstreamTaskId: string;
1266
1310
  };
1311
+ /**
1312
+ * Run mode for a maintenance task (on-demand pipeline, D4).
1313
+ *
1314
+ * - 'fix' — current cron behavior: mechanical-ai dispatches on findings,
1315
+ * pure-ai always dispatches, PRs may be opened. Default.
1316
+ * - 'report' — read-only sweep: run the check step, record findings, and take
1317
+ * the no-dispatch branch — never dispatch a fix agent or open a PR.
1318
+ */
1319
+ type RunMode = 'report' | 'fix';
1267
1320
  /**
1268
1321
  * Per-task cost ceiling (Hermes Phase 5).
1269
1322
  *
@@ -1325,6 +1378,15 @@ interface TaskDefinition {
1325
1378
  outputRetention?: OutputRetentionConfig;
1326
1379
  /** Hermes Phase 2 — Marks tasks originating from `customTasks` config. */
1327
1380
  isCustom?: boolean;
1381
+ /**
1382
+ * On-demand maintenance pipeline (D5). When `true`, the task is excluded
1383
+ * from the human "overdue" sweep computed by `selectTasks` — used for
1384
+ * git-mutating housekeeping (`main-sync`, `perf-baselines`,
1385
+ * `session-cleanup`) and one-shot backfills (`proposal-provenance-backfill`)
1386
+ * that are infra hygiene, not developer-facing health signals.
1387
+ * `undefined` (default) → sweep-eligible.
1388
+ */
1389
+ excludeFromHumanSweep?: boolean;
1328
1390
  }
1329
1391
  /**
1330
1392
  * Result of a single maintenance task run.
@@ -1533,6 +1595,13 @@ declare class BackendRouter {
1533
1595
  private validateReferences;
1534
1596
  }
1535
1597
 
1598
+ /**
1599
+ * The lanes projection shape, re-exported so the orchestrator can hold a
1600
+ * read-back snapshot without importing the core `eventSourcing` namespace
1601
+ * directly — keeping this module the single orchestrator<->core lane coupling.
1602
+ */
1603
+ type PersistedLanes = eventSourcing.LanesProjection;
1604
+
1536
1605
  /**
1537
1606
  * Derives the worktree seed paths from a workflow config when
1538
1607
  * {@link WorkspaceConfig.seedPaths} is not set explicitly.
@@ -1545,6 +1614,20 @@ declare class BackendRouter {
1545
1614
  * otherwise miss it.
1546
1615
  */
1547
1616
  declare function deriveSeedPaths(config: WorkflowConfig): string[];
1617
+ /**
1618
+ * Resolve a maintenance `checkCommand` (or housekeeping command) into a runnable
1619
+ * argv. Built-in maintenance task definitions store the command as harness
1620
+ * SUBCOMMAND argv (e.g. `['check-arch']`, `['graph','scan']`); `main-sync`
1621
+ * carries an explicit leading `'harness'` literal. Either way the command must
1622
+ * be executed through the `harness` binary, so:
1623
+ * - `['check-arch']` → `['harness', 'check-arch']`
1624
+ * - `['harness','sync-main']` → `['harness', 'sync-main']` (no double-prefix)
1625
+ * - `[]` → `[]`
1626
+ *
1627
+ * The cron daemon resolves `harness` from PATH (the pre-existing assumption that
1628
+ * `main-sync` already relied on).
1629
+ */
1630
+ declare function normalizeHarnessCommand(command: string[]): string[];
1548
1631
  /**
1549
1632
  * The central orchestrator that manages the lifecycle of coding agents.
1550
1633
  *
@@ -1656,6 +1739,11 @@ declare class Orchestrator extends EventEmitter {
1656
1739
  private abortControllers;
1657
1740
  /** Guards against overlapping ticks when a tick takes longer than the polling interval */
1658
1741
  private tickInProgress;
1742
+ /** Phase 4 (DLane-5): lanes read back from the durable log on first tick, for
1743
+ * observability only — NOT fed into reconciliation. Empty until the first tick. */
1744
+ private persistedLanes;
1745
+ /** Ensures the lane read-back diagnostic runs at most once (first tick). */
1746
+ private laneReadbackDone;
1659
1747
  /** Timestamp of the last stale branch sweep (at most once per hour) */
1660
1748
  private lastBranchSweepMs;
1661
1749
  /** Current tick-phase activity visible to the dashboard */
@@ -1698,6 +1786,25 @@ declare class Orchestrator extends EventEmitter {
1698
1786
  * @param effect - The effect to handle
1699
1787
  */
1700
1788
  private handleEffect;
1789
+ /**
1790
+ * Phase 4 (DLane-5): persist an orchestrator lane transition to the durable
1791
+ * core event log at the effect boundary. NEVER throws — `persistLane` returns
1792
+ * an `Err` Result on failure, which is logged and swallowed here so a
1793
+ * lane-persistence failure can never break orchestrator dispatch.
1794
+ */
1795
+ private persistLaneSafe;
1796
+ /**
1797
+ * Phase 4 (DLane-5): read persisted task lanes back from the durable log and
1798
+ * log a one-line summary. Stores the projection on `this.persistedLanes` for
1799
+ * observability. Read-only — never feeds reconciliation, never throws.
1800
+ */
1801
+ private readBackPersistedLanes;
1802
+ /**
1803
+ * Phase 4 (DLane-5): the task lanes most recently read back from the durable
1804
+ * log on startup, exposed for external observability. Read-only — a fresh
1805
+ * `{ tasks: {} }` until the first tick's read-back has run.
1806
+ */
1807
+ getPersistedLanes(): PersistedLanes;
1701
1808
  /**
1702
1809
  * Guards workspace cleanup by checking whether the agent pushed a branch
1703
1810
  * that does not yet have a pull request. If so, the worktree is preserved
@@ -1980,6 +2087,30 @@ interface CreateBackendOptions {
1980
2087
  */
1981
2088
  declare function createBackend(def: BackendDef, options?: CreateBackendOptions): AgentBackend;
1982
2089
 
2090
+ /**
2091
+ * Maintenance backend resolver: map a configured backend NAME to a live
2092
+ * {@link AgentBackend}, or `null` when the name is absent from the loaded
2093
+ * `agent.backends` map. `null` lets the real agent dispatcher no-op honestly
2094
+ * (graceful degradation on a plain checkout) instead of throwing.
2095
+ */
2096
+ type BackendResolver = (backendName: string) => AgentBackend | null;
2097
+ /**
2098
+ * Build a {@link BackendResolver} from a synthesized `agent.backends` map.
2099
+ *
2100
+ * This is the ONE shared implementation of "resolve a backend name against a
2101
+ * backends map via `createBackend`, else null". It is consumed by BOTH:
2102
+ * - the cron orchestrator (`createMaintenanceTaskRunner`), passing
2103
+ * `this.getBackends()`, and
2104
+ * - the on-demand CLI (`harness maintenance run --fix` →
2105
+ * `makeResolveBackend`), passing the config it loaded from
2106
+ * `harness.orchestrator.md`.
2107
+ *
2108
+ * Keeping it in the orchestrator package (next to `createBackend`) avoids the
2109
+ * two call sites drifting. A `null`/`undefined`/empty map yields a resolver
2110
+ * that always returns `null` — the nothing-configured degradation case.
2111
+ */
2112
+ declare function makeBackendResolver(backends: Record<string, BackendDef> | null | undefined): BackendResolver;
2113
+
1983
2114
  /**
1984
2115
  * Zod schema for `BackendDef` (Spec 2 — multi-backend routing).
1985
2116
  *
@@ -2426,6 +2557,520 @@ interface CustomTaskValidatorDeps {
2426
2557
  */
2427
2558
  declare function validateCustomTasks(customTasks: Record<string, CustomTaskDefinition> | undefined, builtIns: readonly TaskDefinition[], deps?: CustomTaskValidatorDeps): Result<void, CustomTaskValidationError[]>;
2428
2559
 
2560
+ /** Selection filter for `selectTasks`. `now` is injected for determinism. */
2561
+ interface TaskSelectionFilter {
2562
+ mode: 'overdue' | 'all' | 'ids';
2563
+ /** Required when `mode === 'ids'`; ignored otherwise. */
2564
+ ids?: string[];
2565
+ /** Reference instant — never read from the wall clock internally. */
2566
+ now: Date;
2567
+ }
2568
+ /**
2569
+ * Select the maintenance tasks to run for an on-demand sweep (D3/D5).
2570
+ * Operates only on sweep-eligible tasks (`excludeFromHumanSweep !== true`)
2571
+ * in every mode. Deterministic under the injected `filter.now`.
2572
+ *
2573
+ * - `overdue`: eligible tasks with no satisfying run since their previous fire.
2574
+ * - `all`: every eligible task.
2575
+ * - `ids`: the eligible subset named in `filter.ids` (a named excluded id
2576
+ * is dropped, honoring "excluded tasks never run in either path").
2577
+ * `filter.ids` is treated as a SET membership test, not an ordered
2578
+ * request list: results preserve the input `tasks` array order, not
2579
+ * the order ids appear in `filter.ids`. Duplicate ids are collapsed
2580
+ * and a task is returned at most once. Callers that need request
2581
+ * order must reorder the result themselves.
2582
+ */
2583
+ declare function selectTasks(tasks: TaskDefinition[], history: RunResult[], filter: TaskSelectionFilter): TaskDefinition[];
2584
+
2585
+ /**
2586
+ * Hermes Phase 2 — Result of running an arbitrary check script.
2587
+ *
2588
+ * Structurally compatible with `CheckCommandResult` (`task-runner.ts`) so
2589
+ * `TaskRunner` can consume it through the same interface, plus a parsed
2590
+ * structured envelope and the captured stderr stream. `structured` is
2591
+ * `null` when no JSON status line was found on stdout. The shape is
2592
+ * declared locally (not imported from `task-runner.ts`) to keep the
2593
+ * module dependency one-way: `task-runner.ts` depends on
2594
+ * `check-script-runner.ts`, never the reverse.
2595
+ */
2596
+ interface CheckScriptResult {
2597
+ passed: boolean;
2598
+ findings: number;
2599
+ /** Raw stdout. Field name matches `CheckCommandResult.output` for compatibility. */
2600
+ output: string;
2601
+ stderr: string;
2602
+ structured: CheckScriptStatusEnvelope | null;
2603
+ }
2604
+ interface CheckScriptStatusEnvelope {
2605
+ status: 'ok' | 'findings' | 'skip' | 'error';
2606
+ findings?: number;
2607
+ wakeAgent?: boolean;
2608
+ message?: string;
2609
+ outputs?: Record<string, unknown>;
2610
+ }
2611
+ /**
2612
+ * Spawns an arbitrary executable for the mechanical/report/housekeeping
2613
+ * check step. Honors the structured JSON status envelope (last non-empty
2614
+ * stdout line) per Hermes Phase 2 D6. Falls back to the legacy heuristic
2615
+ * regex when no JSON envelope is present.
2616
+ *
2617
+ * The runner is intentionally simple and shells out via `execFile` (no
2618
+ * shell, no `sh -c`) — `args` are passed verbatim to avoid argument
2619
+ * injection from operator-supplied config.
2620
+ */
2621
+ declare class CheckScriptRunner {
2622
+ private cwd;
2623
+ constructor(cwd: string);
2624
+ run(spec: CheckScriptDefinition, cwd?: string): Promise<CheckScriptResult>;
2625
+ }
2626
+
2627
+ /**
2628
+ * Hermes Phase 2 — Reads an inline-skill body by name. Wraps the host's
2629
+ * skill registry; absent skills resolve to `null` so the resolver can
2630
+ * warn-and-skip instead of throwing.
2631
+ */
2632
+ interface InlineSkillReader {
2633
+ read(skillName: string): Promise<string | null>;
2634
+ }
2635
+ interface ContextResolverOptions {
2636
+ outputStore: TaskOutputStore;
2637
+ skillReader?: InlineSkillReader;
2638
+ logger?: MaintenanceLogger;
2639
+ /** Per-upstream truncation bound. Default: 2000 chars. */
2640
+ perUpstreamMaxChars?: number;
2641
+ }
2642
+ /**
2643
+ * Resolves Hermes Phase 2 prompt-context inputs for a maintenance task:
2644
+ *
2645
+ * - `resolveContextFrom(taskIds, opts)`: pulls each upstream's latest
2646
+ * output from the store, applies stale/missing markers, and emits a
2647
+ * `## Upstream context` markdown block.
2648
+ *
2649
+ * - `resolveInlineSkills(skillNames, budgetTokens)`: pulls each skill's
2650
+ * markdown body via the registry, applies a per-skill char-count
2651
+ * budget (4 chars ≈ 1 token), warns-then-truncates on overflow, and
2652
+ * emits a `## Reference skills` markdown block.
2653
+ *
2654
+ * Both methods return an empty string when their inputs are absent so
2655
+ * callers can `prompt = skills + upstream + base` without conditional
2656
+ * scaffolding.
2657
+ */
2658
+ declare class ContextResolver {
2659
+ private outputStore;
2660
+ private skillReader;
2661
+ private logger;
2662
+ private perUpstreamMaxChars;
2663
+ constructor(options: ContextResolverOptions);
2664
+ resolveContextFrom(upstreamTaskIds: string[] | undefined, options?: {
2665
+ maxAgeMinutes?: number;
2666
+ }): Promise<string>;
2667
+ resolveInlineSkills(skillNames: string[] | undefined, budgetTokens?: number): Promise<string>;
2668
+ private formatUpstream;
2669
+ }
2670
+
2671
+ /**
2672
+ * Interface for running CLI check commands in-process.
2673
+ * Each method returns a structured result with a findings count.
2674
+ */
2675
+ interface CheckCommandRunner {
2676
+ /**
2677
+ * Runs a check command and returns its structured output.
2678
+ * @param command - CLI command args (e.g., ['check-arch'])
2679
+ * @param cwd - Working directory
2680
+ * @returns Object with findings count and whether the check passed
2681
+ */
2682
+ run(command: string[], cwd: string): Promise<CheckCommandResult>;
2683
+ }
2684
+ interface CheckCommandResult {
2685
+ passed: boolean;
2686
+ findings: number;
2687
+ /** Raw output for logging/reporting */
2688
+ output: string;
2689
+ /**
2690
+ * True when the check command could NOT be executed to a usable result —
2691
+ * the process failed to spawn (ENOENT), the subcommand was unknown, or it
2692
+ * crashed with no parseable findings count. This is distinct from a check
2693
+ * that ran fine and legitimately reported findings (`passed: false`,
2694
+ * `findings > 0`). The TaskRunner maps `executionFailed` onto
2695
+ * `status: 'failure'` so an un-runnable check is never masked as a
2696
+ * successful 1-finding run (ADR 0050 — exit-1-on-check-crash). Omitted /
2697
+ * `undefined` is treated as `false` for backward compatibility with runners
2698
+ * that predate this field.
2699
+ */
2700
+ executionFailed?: boolean;
2701
+ }
2702
+ /**
2703
+ * Interface for dispatching an AI agent to fix issues.
2704
+ * Wraps AgentRunner.runSession() with maintenance-specific parameters.
2705
+ */
2706
+ interface AgentDispatcher {
2707
+ /**
2708
+ * Dispatch an AI agent to fix issues on a branch.
2709
+ * @param skill - Skill name to dispatch (e.g., 'harness-arch-fix')
2710
+ * @param branch - Branch to work on
2711
+ * @param backendName - Backend name to use (e.g., 'local', 'claude')
2712
+ * @param cwd - Working directory (worktree path)
2713
+ * @param options - Hermes Phase 2: optional `promptContext` prepended to
2714
+ * the agent's system prompt (inlined skills + upstream
2715
+ * outputs). The dispatcher MAY ignore this field on
2716
+ * backends that don't support context injection; the
2717
+ * TaskRunner persists it independently for observability.
2718
+ * @returns Whether the agent produced any commits
2719
+ */
2720
+ dispatch(skill: string, branch: string, backendName: string, cwd: string, options?: AgentDispatchOptions): Promise<AgentDispatchResult>;
2721
+ }
2722
+ interface AgentDispatchOptions {
2723
+ /** Hermes Phase 2 — prompt context (inlined skills + upstream outputs). */
2724
+ promptContext?: string;
2725
+ }
2726
+ interface AgentDispatchResult {
2727
+ producedCommits: boolean;
2728
+ fixed: number;
2729
+ }
2730
+ /**
2731
+ * Interface for running housekeeping commands directly.
2732
+ */
2733
+ interface CommandExecutor {
2734
+ /**
2735
+ * Executes a command directly (no AI). Returns captured stdout so
2736
+ * housekeeping tasks emitting a JSON status line (e.g. `sync-main --json`)
2737
+ * can be parsed by the runner.
2738
+ *
2739
+ * @param command - Command args (e.g., ['cleanup-sessions'])
2740
+ * @param cwd - Working directory
2741
+ */
2742
+ exec(command: string[], cwd: string): Promise<CommandExecResult>;
2743
+ }
2744
+ interface CommandExecResult {
2745
+ /** Captured stdout. May be empty for legacy housekeeping commands. */
2746
+ stdout: string;
2747
+ }
2748
+ /**
2749
+ * Interface for managing branches and PRs for maintenance tasks.
2750
+ * Matches PRManager's public API shape for DI.
2751
+ */
2752
+ interface PRLifecycleManager {
2753
+ ensureBranch(branchName: string, baseBranch: string): Promise<{
2754
+ created: boolean;
2755
+ recreated: boolean;
2756
+ }>;
2757
+ ensurePR(task: TaskDefinition, runSummary: string): Promise<{
2758
+ prUrl: string;
2759
+ prUpdated: boolean;
2760
+ }>;
2761
+ }
2762
+ interface TaskRunnerOptions {
2763
+ config: MaintenanceConfig;
2764
+ checkRunner: CheckCommandRunner;
2765
+ agentDispatcher: AgentDispatcher;
2766
+ commandExecutor: CommandExecutor;
2767
+ /** Project root directory for running commands */
2768
+ cwd: string;
2769
+ /** Optional PR lifecycle manager for branch/PR operations */
2770
+ prManager?: PRLifecycleManager;
2771
+ /** Base branch for PR operations (defaults to 'main') */
2772
+ baseBranch?: string;
2773
+ /**
2774
+ * Hermes Phase 2 — Optional check-script runner. When a task declares
2775
+ * `checkScript`, the runner consults this instead of `checkRunner`.
2776
+ * Required for any custom task that uses `checkScript`; tests that don't
2777
+ * exercise custom tasks may omit it.
2778
+ */
2779
+ checkScriptRunner?: CheckScriptRunner;
2780
+ /**
2781
+ * Hermes Phase 2 — Optional context resolver providing `contextFrom`
2782
+ * upstream injection and `inlineSkills` payload assembly.
2783
+ */
2784
+ contextResolver?: ContextResolver;
2785
+ /**
2786
+ * Hermes Phase 2 — Persists per-task outputs (stdout / structured /
2787
+ * resolved context) at the end of each run.
2788
+ */
2789
+ outputStore?: TaskOutputStore;
2790
+ }
2791
+ /**
2792
+ * TaskRunner executes a single maintenance task based on its type.
2793
+ *
2794
+ * Execution paths:
2795
+ * - mechanical-ai: run check -> if findings, dispatch AI agent
2796
+ * - pure-ai: always dispatch AI agent
2797
+ * - report-only: run check, record findings, no AI
2798
+ * - housekeeping: run command directly, no AI
2799
+ */
2800
+ declare class TaskRunner {
2801
+ private config;
2802
+ private checkRunner;
2803
+ private agentDispatcher;
2804
+ private commandExecutor;
2805
+ private cwd;
2806
+ private prManager;
2807
+ private baseBranch;
2808
+ private checkScriptRunner;
2809
+ private contextResolver;
2810
+ private outputStore;
2811
+ constructor(options: TaskRunnerOptions);
2812
+ /**
2813
+ * Run a maintenance task and return the result.
2814
+ * Dispatches to the appropriate execution path based on task type.
2815
+ * Never throws -- errors are captured in the RunResult.
2816
+ *
2817
+ * @param task - Resolved task definition.
2818
+ * @param origin - Hermes Phase 2 trigger-source tag; defaults to `'cron'`
2819
+ * when called from the scheduler path.
2820
+ */
2821
+ run(task: TaskDefinition, origin?: RunOrigin, mode?: RunMode): Promise<RunResult>;
2822
+ private persistOutput;
2823
+ /**
2824
+ * Run the check step using whichever runner the task asks for. Custom
2825
+ * tasks that declare `checkScript` go through the Hermes Phase 2
2826
+ * `CheckScriptRunner`; built-ins (and customs that use the legacy
2827
+ * `checkCommand` shape) go through the original heuristic runner.
2828
+ */
2829
+ private runCheckStep;
2830
+ /**
2831
+ * Hermes Phase 2 — Compose the agent prompt-context block from inlined
2832
+ * skills + upstream task outputs. Returns an empty string when nothing
2833
+ * is configured (or when the resolver is absent), which is the safe
2834
+ * no-op default.
2835
+ */
2836
+ private composePromptContext;
2837
+ /**
2838
+ * Mechanical-AI: run check (legacy or Phase 2 script), dispatch AI agent
2839
+ * only if fixable findings exist; persist captured stdout/stderr/context
2840
+ * via the output store on the way out.
2841
+ */
2842
+ private runMechanicalAI;
2843
+ /**
2844
+ * Pure-AI: always dispatch agent with configured skill.
2845
+ */
2846
+ private runPureAI;
2847
+ /**
2848
+ * Report-only: run check (legacy or Phase 2 script), record metrics, no AI dispatch.
2849
+ *
2850
+ * Honors the JSON status contract emitted by Phase 4/5 CLIs (`harness pulse run`
2851
+ * and `harness compound scan-candidates` in `--non-interactive` mode):
2852
+ * {"status":"success"|"skipped"|"failure"|"no-issues",
2853
+ * "candidatesFound"?: number, "error"?: string, "reason"?: string}
2854
+ *
2855
+ * Legacy report-only tasks emit free-form output and fall through to 'success'.
2856
+ */
2857
+ private runReportOnly;
2858
+ /**
2859
+ * Housekeeping: run command directly, no AI, no PR.
2860
+ *
2861
+ * Captures stdout and parses a trailing JSON status line if present.
2862
+ * Recognized contracts:
2863
+ * - Phase 4/5 status contract (e.g., harness pulse run): success/skipped/failure/no-issues
2864
+ * - sync-main contract: updated/no-op/skipped/error → mapped onto the run-result status
2865
+ * Legacy housekeeping commands that emit no JSON keep the prior behavior:
2866
+ * status: 'success', findings: 0.
2867
+ *
2868
+ * Hermes Phase 2: a `checkScript` may replace `checkCommand` for housekeeping
2869
+ * tasks; the runner falls through to the same JSON-status parsing path.
2870
+ */
2871
+ private runHousekeeping;
2872
+ /**
2873
+ * Resolve which AI backend name to use for a given task.
2874
+ * Priority: per-task override > global config > 'local' default.
2875
+ */
2876
+ private resolveBackend;
2877
+ private failureResult;
2878
+ /**
2879
+ * A precondition-gated check (e.g. `predict` with <3 snapshots, or a
2880
+ * graph-backed check before `harness scan`). The command is correctly
2881
+ * configured; the repo just lacks the state it needs. Reported as `skipped`
2882
+ * — distinct from a hard `failure` — carrying the refusal line as the reason
2883
+ * (surfaced in the run-report summary column). ADR 0050.
2884
+ */
2885
+ private skippedResult;
2886
+ }
2887
+ /**
2888
+ * Classification of a check that a `CheckCommandRunner` flagged
2889
+ * `executionFailed` (non-zero exit / spawn error with no parseable finding
2890
+ * count). The runners cannot tell these three cases apart with a single
2891
+ * boolean, so the TaskRunner re-classifies the captured output here — keeping
2892
+ * the logic in ONE shared place consumed by BOTH the cron orchestrator and the
2893
+ * on-demand CLI (they each own a thin `CheckCommandRunner` but share this
2894
+ * `TaskRunner`). See ADR 0050 (report-first / execution-honesty).
2895
+ *
2896
+ * - `unrunnable` → the subcommand could not execute at all (unknown command,
2897
+ * ENOENT, missing module, empty output). Maps to `failure`.
2898
+ * - `precondition`→ the subcommand ran but refused because required state is
2899
+ * absent in this repo (e.g. `predict` needs ≥3 snapshots;
2900
+ * graph-backed checks need `harness scan` first). This is NOT
2901
+ * a misconfiguration or a breakage — maps to `skipped` with a
2902
+ * reason so dashboards/cron don't cry wolf.
2903
+ * - `ran-no-count`→ the subcommand ran and exited non-zero to SIGNAL drift but
2904
+ * emitted no machine-parseable count (e.g. `cleanup`,
2905
+ * `check-docs`). A check that ran and flagged work is not an
2906
+ * execution failure — maps to a real (recovered or assumed)
2907
+ * finding count, never `failure`.
2908
+ */
2909
+ type CheckFailureKind = 'unrunnable' | 'precondition' | 'ran-no-count';
2910
+ interface CheckFailureClassification {
2911
+ kind: CheckFailureKind;
2912
+ /** Human-readable reason, populated for `precondition` (the refusal line). */
2913
+ reason?: string;
2914
+ }
2915
+ /**
2916
+ * Parse an EXPLICIT finding count from output the primary `N keyword` parser in
2917
+ * the `CheckCommandRunner` missed — it only matches "45 issues", not the
2918
+ * "Entropy issues: 32264" (count-after-keyword) shape. Returns `null` when no
2919
+ * explicit count is present (vs `recoverFindingsCount`, which defaults to 1).
2920
+ *
2921
+ * A recoverable explicit count is the strongest possible signal that a check
2922
+ * actually RAN and produced findings, so the classifier trusts it over any
2923
+ * scary-looking words ("ENOENT", "not found") buried in the findings body.
2924
+ */
2925
+ declare function explicitFindingsCount(output: string): number | null;
2926
+ /**
2927
+ * Recover a finding count from a `ran-no-count` output, falling back to 1 — the
2928
+ * check ran and flagged something, exact count unknown.
2929
+ */
2930
+ declare function recoverFindingsCount(output: string): number;
2931
+ declare function classifyCheckExecutionFailure(output: string): CheckFailureClassification;
2932
+
2933
+ /**
2934
+ * Dependencies for {@link createAgentDispatcher}. All side-effecting collaborators
2935
+ * are injected so the dispatcher is unit-testable with a MockBackend and a fake
2936
+ * git seam (no real agent process, no real repository).
2937
+ */
2938
+ interface AgentDispatcherDeps {
2939
+ /**
2940
+ * Resolve a configured backend by name (e.g. `'local'`, `'claude'`). Returns
2941
+ * `null` when the name is unknown/unconfigured — the dispatcher then no-ops
2942
+ * rather than throwing, so a misconfigured maintenance task degrades to
2943
+ * "produced nothing" instead of crashing the scheduler.
2944
+ */
2945
+ resolveBackend: (backendName: string) => AgentBackend | null;
2946
+ /** Run `git <args>` in `cwd`, returning trimmed stdout (throws on failure). */
2947
+ git: (args: string[], cwd: string) => string;
2948
+ /** Max agent turns per dispatch. Defaults to 10. */
2949
+ maxTurns?: number;
2950
+ logger: {
2951
+ info: (message: string, meta?: Record<string, unknown>) => void;
2952
+ warn: (message: string, meta?: Record<string, unknown>) => void;
2953
+ };
2954
+ }
2955
+ /**
2956
+ * Wire the maintenance {@link AgentDispatcher} to a real agent session.
2957
+ *
2958
+ * Replaces the previous stub (which only logged and returned `producedCommits:
2959
+ * false`). Resolves the named backend, drives a multi-turn {@link AgentRunner}
2960
+ * session over the skill prompt in the worktree, then measures whether the agent
2961
+ * actually committed anything by diffing `HEAD` before/after. Commit count — not
2962
+ * the agent's self-report — is the source of truth for `fixed`.
2963
+ */
2964
+ declare function createAgentDispatcher(deps: AgentDispatcherDeps): AgentDispatcher;
2965
+
2966
+ /**
2967
+ * Options for the MaintenanceReporter.
2968
+ */
2969
+ interface MaintenanceReporterOptions {
2970
+ /** Directory where history.json is persisted (default: '.harness/maintenance/') */
2971
+ persistDir?: string;
2972
+ /** Logger for structured error/info output. Falls back to console if not provided. */
2973
+ logger?: MaintenanceLogger;
2974
+ }
2975
+ declare class MaintenanceReporter {
2976
+ private persistDir;
2977
+ private logger;
2978
+ private history;
2979
+ constructor(options?: MaintenanceReporterOptions);
2980
+ /**
2981
+ * Load history from disk. Creates the persist directory if it does not exist.
2982
+ * Errors in persistence are logged to stderr, not thrown.
2983
+ */
2984
+ load(): Promise<void>;
2985
+ /**
2986
+ * Record a run result. Appends to in-memory history (most recent first),
2987
+ * caps at MAX_HISTORY, and writes to disk asynchronously.
2988
+ */
2989
+ record(result: RunResult): Promise<void>;
2990
+ /**
2991
+ * Returns a paginated slice of the run history (most recent first).
2992
+ */
2993
+ getHistory(limit: number, offset: number): RunResult[];
2994
+ /**
2995
+ * Write history to disk. Errors are logged, not thrown.
2996
+ */
2997
+ private persist;
2998
+ }
2999
+
3000
+ /**
3001
+ * Generous stdout/stderr capture ceiling for spawned maintenance checks. The
3002
+ * Node `execFile` default (1 MB) is far too small for verbose checks — e.g.
3003
+ * `harness cleanup` on a large repo emits ~8 MB — and an exceeded buffer
3004
+ * rejects with EMPTY stdout/stderr, which the runner would misread as a check
3005
+ * that produced no output (a false execution failure). 64 MB leaves ample
3006
+ * headroom while still bounding memory.
3007
+ */
3008
+ declare const MAINTENANCE_CHECK_MAX_BUFFER: number;
3009
+ /**
3010
+ * Per-check wall-clock budget. Raised from the original 120 s because heavy
3011
+ * whole-repo checks legitimately need longer on large monorepos — `harness
3012
+ * cleanup` (all entropy types) takes ~165 s here — and a too-tight timeout
3013
+ * SIGTERMs the child, yielding empty output that the runner can only read as a
3014
+ * (false) execution failure. 300 s keeps a bound while letting real checks
3015
+ * finish.
3016
+ */
3017
+ declare const MAINTENANCE_CHECK_TIMEOUT_MS = 300000;
3018
+ /** A resolved child-process invocation: the file to spawn and its argv. The two
3019
+ * callers build this differently (CLI: `process.execPath` + the CLI's own entry
3020
+ * script; cron: the `harness` binary on PATH) but the spawn/parse core is one. */
3021
+ interface HarnessSpawn {
3022
+ file: string;
3023
+ args: string[];
3024
+ }
3025
+ /** The shape of an `execFile` rejection the timeout/classification logic reads. */
3026
+ interface ExecFileError {
3027
+ stdout?: string | Buffer;
3028
+ stderr?: string | Buffer;
3029
+ killed?: boolean;
3030
+ signal?: string | null;
3031
+ code?: string | number | null;
3032
+ }
3033
+ /** Injectable `execFile` (promisified) so tests can drive the spawn-error,
3034
+ * clean-run, findings, and timeout branches without real subprocesses. */
3035
+ type ExecFileAsyncFn = (file: string, args: string[], options: {
3036
+ cwd: string;
3037
+ timeout: number;
3038
+ maxBuffer: number;
3039
+ }) => Promise<{
3040
+ stdout: string | Buffer;
3041
+ stderr?: string | Buffer;
3042
+ }>;
3043
+ interface RunHarnessCheckOptions {
3044
+ /** Injected for tests; defaults to the real promisified `execFile`. */
3045
+ execFileAsync?: ExecFileAsyncFn;
3046
+ /** Per-check wall-clock budget (default {@link MAINTENANCE_CHECK_TIMEOUT_MS}). */
3047
+ timeoutMs?: number;
3048
+ /** stdout/stderr capture ceiling (default {@link MAINTENANCE_CHECK_MAX_BUFFER}). */
3049
+ maxBuffer?: number;
3050
+ }
3051
+ /** Best-effort detection of a child killed by the `execFile` timeout (SIGTERM /
3052
+ * ETIMEDOUT / killed flag). */
3053
+ declare function isCheckTimeoutError(e: ExecFileError): boolean;
3054
+ /**
3055
+ * Spawn a resolved harness check invocation and classify its result into a
3056
+ * {@link CheckCommandResult}. Behavior (shared by cron + CLI):
3057
+ *
3058
+ * - clean exit, parseable count → `{ findings: N }` (or 0 on a parse-miss; a
3059
+ * check that ran and said nothing is clean, not "1 finding").
3060
+ * - non-zero exit WITH a parseable count → real findings (`executionFailed:
3061
+ * false`) — e.g. `check-arch` exits 1 with "45 issues".
3062
+ * - non-zero exit / spawn error with NO parseable count → `executionFailed:
3063
+ * true`, findings 0 (a broken check is not "1 finding"; ADR 0050).
3064
+ * - TIMEOUT (SIGTERM/ETIMEDOUT) → `executionFailed: true`, findings 0, with a
3065
+ * distinct "check timed out after Nms" marker APPENDED to whatever the child
3066
+ * flushed. A timed-out check did not complete: even partial parseable output
3067
+ * ("5 issues") it flushed before SIGTERM is truncated and untrustworthy, so
3068
+ * the timeout is classified ahead of any finding count — never a "ran-no-
3069
+ * count" success. {@link import('./task-runner').classifyCheckExecutionFailure}
3070
+ * matches this marker before `explicitFindingsCount`.
3071
+ */
3072
+ declare function runHarnessCheck(spawn: HarnessSpawn, cwd: string, opts?: RunHarnessCheckOptions): Promise<CheckCommandResult>;
3073
+
2429
3074
  interface CreateTokenInput {
2430
3075
  name: string;
2431
3076
  scopes: TokenScope[];
@@ -2875,4 +3520,4 @@ declare function emitProposalCreated(bus: EventEmitter, proposal: SkillProposal)
2875
3520
  declare function emitProposalApproved(bus: EventEmitter, proposal: SkillProposal): void;
2876
3521
  declare function emitProposalRejected(bus: EventEmitter, proposal: SkillProposal): void;
2877
3522
 
2878
- export { type AgentUpdateEvent, AnalysisArchive, type AnalysisRecord, type ApplyEventResult, type ArtifactPresence, type AttemptStats, BUILT_IN_TASKS, BackendDefSchema, 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, LocalModelResolver, type LocalModelResolverOptions, 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 ResolverLogger, type RetryEntry, type RetryFiredEvent, RoadmapTrackerAdapter, RoutingConfigSchema, RoutingValueSchema, 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, defaultFetchModels, deriveSeedPaths, detectScopeTier, discoverSkillCatalog, discoverSkillCatalogNames, emitProposalApproved, emitProposalCreated, emitProposalRejected, extractHighlights, extractTitlePrefix, getAvailableSlots, getDefaultConfig, getPerStateCount, indexSessionDirectory, isEligible, isSummaryEnabled, launchTUI, loadPublishedIndex, migrateAgentConfig, normalizeFts5Query, normalizeLocalModel, openSearchIndex, promote, reconcile, reindexFromArchive, renderAnalysisComment, renderLlmSummaryMarkdown, renderPRComment, resolveEscalationConfig, resolveOrchestratorId, routeIssue, routingWarnings, runGate, savePublishedIndex, searchIndexPath, selectCandidates, sortCandidates, summarizeArchivedSession, syncMain, triageIssue, truncateForBudget, validateCustomTasks, validateWorkflowConfig, wireNotificationSinks, wrapAsEnvelope };
3523
+ export { type AgentDispatchResult, type AgentDispatcher, type AgentDispatcherDeps, type AgentUpdateEvent, AnalysisArchive, type AnalysisRecord, type ApplyEventResult, type ArtifactPresence, type AttemptStats, BUILT_IN_TASKS, BackendDefSchema, type BackendResolver, BackendRouter, type BackendRouterOptions, type BaseRefFallbackEvent, type BuildArchiveHooksOptions, type CheckCommandResult, type CheckCommandRunner, type CheckFailureClassification, type CheckFailureKind, CheckScriptRunner, ClaimManager, type ClaimManagerConfig, type CleanWorkspaceEffect, type CommandExecResult, type CommandExecutor, type CreateTokenInput, type CreateTokenResult, type CustomTaskValidationError, type DispatchEffect, type EmitLogEffect, type EscalateEffect, type ExecFileAsyncFn, type ExecFileError, type ExecFileFn$1 as ExecFileFn, type FromConfigOptions, GateNotReadyError, type GateResult, GateRunError, type HarnessSpawn, type Highlight, type HighlightsInfo, type IndexedDoc, InteractionQueue, LinearGraphQLClient, type LinearGraphQLClientOptions, type LinearGraphQLExtension, LinearGraphQLStub, type LiveSession, LocalModelResolver, type LocalModelResolverOptions, MAINTENANCE_CHECK_MAX_BUFFER, MAINTENANCE_CHECK_TIMEOUT_MS, MAX_ATTEMPTS, MaintenanceReporter, type MaintenanceReporterOptions, type MigrationResult, MockBackend, type NotificationSink, type NotificationSinkDeliverInput, ORCHESTRATOR_IDENTITY_FILE, Orchestrator, OrchestratorBackendFactory, type OrchestratorBackendFactoryOptions, type OrchestratorContext, type OrchestratorEvent, type OrchestratorState, PRDetector, type PRDetectorLogger, type PRLifecycleManager, 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 ResolverLogger, type RetryEntry, type RetryFiredEvent, RoadmapTrackerAdapter, RoutingConfigSchema, RoutingValueSchema, type RunAttemptPhase, type RunHarnessCheckOptions, type RunMode, type RunOrigin, type RunResult, 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, TaskRunner, type TaskRunnerOptions, type TaskSelectionFilter, 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, classifyCheckExecutionFailure, computeRateLimitDelay, createAgentDispatcher, createBackend, createEmptyState, crossFieldRoutingIssues, defaultFetchModels, deriveSeedPaths, detectScopeTier, discoverSkillCatalog, discoverSkillCatalogNames, emitProposalApproved, emitProposalCreated, emitProposalRejected, explicitFindingsCount, extractHighlights, extractTitlePrefix, getAvailableSlots, getDefaultConfig, getPerStateCount, indexSessionDirectory, isCheckTimeoutError, isEligible, isSummaryEnabled, launchTUI, loadPublishedIndex, makeBackendResolver, migrateAgentConfig, normalizeFts5Query, normalizeHarnessCommand, normalizeLocalModel, openSearchIndex, promote, reconcile, recoverFindingsCount, reindexFromArchive, renderAnalysisComment, renderLlmSummaryMarkdown, renderPRComment, resolveEscalationConfig, resolveOrchestratorId, routeIssue, routingWarnings, runGate, runHarnessCheck, savePublishedIndex, searchIndexPath, selectCandidates, selectTasks, sortCandidates, summarizeArchivedSession, syncMain, triageIssue, truncateForBudget, validateCustomTasks, validateWorkflowConfig, wireNotificationSinks, wrapAsEnvelope };