@ordewell/core 0.4.23 → 0.5.1

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 (46) hide show
  1. package/dist/{ITerminalRunner-CuNYBnqK.d.mts → ITerminalRunner-DCjsa2-I.d.mts} +31 -1
  2. package/dist/{ITerminalRunner-Da1gIAFX.d.ts → ITerminalRunner-H1yT8LTy.d.ts} +31 -1
  3. package/dist/{ModeResolver-mtIWrLXn.d.mts → ModeResolver-DVJ7HV3k.d.mts} +1 -1
  4. package/dist/{ModeResolver-Ob-ihQbI.d.ts → ModeResolver-Dkig8ghQ.d.ts} +1 -1
  5. package/dist/Task-BxQkPlXO.d.mts +664 -0
  6. package/dist/Task-BxQkPlXO.d.ts +664 -0
  7. package/dist/{chunk-O2MFTRHA.mjs → chunk-GWPIYDQW.mjs} +29 -5
  8. package/dist/chunk-GWPIYDQW.mjs.map +1 -0
  9. package/dist/{chunk-T4KGVP4N.mjs → chunk-JVMDEHRQ.mjs} +1 -1
  10. package/dist/chunk-JVMDEHRQ.mjs.map +1 -0
  11. package/dist/chunk-T2S5O36I.mjs +103 -0
  12. package/dist/chunk-T2S5O36I.mjs.map +1 -0
  13. package/dist/{chunk-MKUTJDT2.mjs → chunk-XWOUIA6A.mjs} +2 -2
  14. package/dist/index.d.mts +614 -104
  15. package/dist/index.d.ts +614 -104
  16. package/dist/index.js +3780 -1209
  17. package/dist/index.js.map +1 -1
  18. package/dist/index.mjs +3747 -1291
  19. package/dist/index.mjs.map +1 -1
  20. package/dist/order-labels.d.mts +1 -1
  21. package/dist/order-labels.d.ts +1 -1
  22. package/dist/{parsing-BJoHbA-t.d.ts → parsing-CF_grC29.d.ts} +2 -2
  23. package/dist/{parsing-BWfpLch9.d.mts → parsing-DRp4dPC0.d.mts} +2 -2
  24. package/dist/parsing.d.mts +3 -3
  25. package/dist/parsing.d.ts +3 -3
  26. package/dist/parsing.js.map +1 -1
  27. package/dist/parsing.mjs +2 -2
  28. package/dist/{plan-utils-DJm2a7Zp.d.ts → plan-utils-CkNbqAmS.d.ts} +63 -5
  29. package/dist/{plan-utils-s6VL8NDF.d.mts → plan-utils-CtB3_Ovf.d.mts} +63 -5
  30. package/dist/plan-utils.d.mts +3 -3
  31. package/dist/plan-utils.d.ts +3 -3
  32. package/dist/plan-utils.js +7 -0
  33. package/dist/plan-utils.js.map +1 -1
  34. package/dist/plan-utils.mjs +6 -2
  35. package/dist/testing.d.mts +93 -3
  36. package/dist/testing.d.ts +93 -3
  37. package/dist/testing.js +200 -0
  38. package/dist/testing.js.map +1 -1
  39. package/dist/testing.mjs +179 -0
  40. package/dist/testing.mjs.map +1 -1
  41. package/package.json +1 -1
  42. package/dist/Task-4rDGr8Su.d.mts +0 -271
  43. package/dist/Task-4rDGr8Su.d.ts +0 -271
  44. package/dist/chunk-O2MFTRHA.mjs.map +0 -1
  45. package/dist/chunk-T4KGVP4N.mjs.map +0 -1
  46. /package/dist/{chunk-MKUTJDT2.mjs.map → chunk-XWOUIA6A.mjs.map} +0 -0
package/dist/index.d.mts CHANGED
@@ -1,17 +1,17 @@
1
- import { h as RunnerId, c as PlanStatus, L as LegacyPlanState, a as DiscoveredModel, T as Task, d as ResearchProgress, R as ResearchLogEntry, C as ConversationMessage, n as TaskSnapshot, Q as QueuedMessage, A as ActiveTaskSession, g as ResearchToolType, b as PlanState, v as Verdict } from './Task-4rDGr8Su.mjs';
2
- export { D as DiscoveredMode, M as Message, P as PlanModificationWarnings, e as ResearchStep, f as ResearchStepOutcome, S as StreamEvent, i as StreamStepEvent, j as StreamThinkingEvent, k as TaskMode, l as TaskModelAssignment, m as TaskOutputSummary, o as TaskStatus, p as TaskType, q as TaskWithParent, r as ThinkingBlock, U as UserPromptEntry, s as UserStep, V as ValidationCheck, t as ValidationContext, u as ValidationResult, w as VerificationCheck, x as addTaskToPlan, y as createEmptyPlan, z as createTask, B as emptyWarnings, E as flattenTasks, F as flattenTasksWithParents, G as migrateLegacyPlan, H as migratePlanState, I as migrateTask, J as removeTaskFromPlan, K as renumberTasks, N as updateTaskInPlan, O as validateModifiedPlan, W as warningsText } from './Task-4rDGr8Su.mjs';
3
- import { f as IFileSystem, R as ReadFileOpts, T as ToolOutcome, d as GrepOptions, c as GlobOptions, b as FindSymbolOptions, I as IConfig, A as AiProvider, r as ProviderModelLists, i as ITerminalSession, h as ITerminalRunner, w as RunnerRegistry, k as OrchestratorOption, u as RunnerInvocation, g as IPluginStore, v as RunnerPluginManifest, t as ResolveContext } from './ITerminalRunner-CuNYBnqK.mjs';
4
- export { a as AllProviderModels, C as CatalogModel, D as DiscoveryCommand, F as FetchAllProviderModelsOptions, G as GREP_DEFAULT_HEAD_LIMIT, e as GrepOutputMode, M as ModelCatalog, j as ModelShortcut, O as ORCHESTRATOR_SHORTCUTS, P as PluginCloneFn, l as PluginEntry, m as PluginFeatures, n as PluginMode, o as PluginModelDiscovery, p as PluginRunnerDef, q as ProviderCredentialSource, s as ProviderModelsResult, S as SEARCH_EXCLUSIONS, x as collectProviderCredentials, y as enabledRunners, z as fetchAllProviderModels, B as isReservedRunnerName, E as knownModelId, H as resolveModelShortcut, J as resolveProvider, K as toOrchestratorOptions } from './ITerminalRunner-CuNYBnqK.mjs';
1
+ import { F as RunnerId, u as PlanStatus, L as LegacyPlanState, k as IsolationMergeResult, g as IsolationLandedTask, I as IWorktreeIsolation, w as RepoGroupLayout, a as DiscoveredModel, T as Task, y as ResearchProgress, x as ResearchLogEntry, C as ConversationMessage, V as TaskSnapshot, d as IsolationHandoff, J as TaskIsolation, r as IsolationView, P as PlanIsolation, Q as QueuedMessage, A as ActiveTaskSession, E as ResearchToolType, t as PlanState, a3 as Verdict } from './Task-BxQkPlXO.mjs';
2
+ export { D as DiscoveredMode, b as IntegrationDisposal, c as IsolationAvailability, e as IsolationHandoffRepo, f as IsolationInactiveReason, h as IsolationLanding, i as IsolationMergeBlock, j as IsolationMergeBlockReason, l as IsolationOutcome, m as IsolationRepo, n as IsolationRun, o as IsolationTaskRecord, p as IsolationTaskRepo, q as IsolationTaskStatus, M as Message, s as PlanModificationWarnings, v as PreparedTask, R as RepairEvidence, z as ResearchStep, B as ResearchStepOutcome, S as StreamEvent, G as StreamStepEvent, H as StreamThinkingEvent, K as TaskIsolationState, N as TaskMode, O as TaskModelAssignment, U as TaskOutputSummary, W as TaskStatus, X as TaskType, Y as TaskWithParent, Z as ThinkingBlock, _ as UserPromptEntry, $ as UserStep, a0 as ValidationCheck, a1 as ValidationContext, a2 as ValidationResult, a4 as VerificationCheck, a5 as addTaskToPlan, a6 as createEmptyPlan, a7 as createTask, a8 as emptyWarnings, a9 as flattenTasks, aa as flattenTasksWithParents, ab as migrateLegacyPlan, ac as migratePlanState, ad as migrateTask, ae as removeTaskFromPlan, af as renumberTasks, ag as updateTaskInPlan, ah as validateModifiedPlan, ai as warningsText } from './Task-BxQkPlXO.mjs';
3
+ import { f as IFileSystem, R as ReadFileOpts, T as ToolOutcome, d as GrepOptions, c as GlobOptions, b as FindSymbolOptions, I as IConfig, A as AiProvider, r as ProviderModelLists, i as ITerminalSession, h as ITerminalRunner, w as RunnerRegistry, k as OrchestratorOption, u as RunnerInvocation, g as IPluginStore, v as RunnerPluginManifest, t as ResolveContext } from './ITerminalRunner-DCjsa2-I.mjs';
4
+ export { a as AllProviderModels, C as CatalogModel, D as DiscoveryCommand, F as FetchAllProviderModelsOptions, G as GREP_DEFAULT_HEAD_LIMIT, e as GrepOutputMode, M as ModelCatalog, j as ModelShortcut, O as ORCHESTRATOR_SHORTCUTS, P as PluginCloneFn, l as PluginEntry, m as PluginFeatures, n as PluginMode, o as PluginModelDiscovery, p as PluginRunnerDef, q as ProviderCredentialSource, s as ProviderModelsResult, S as SEARCH_EXCLUSIONS, x as collectProviderCredentials, y as enabledRunners, z as fetchAllProviderModels, B as isReservedRunnerName, E as knownModelId, H as resolveModelShortcut, J as resolveProvider, K as toOrchestratorOptions } from './ITerminalRunner-DCjsa2-I.mjs';
5
5
  import { I as IApproval, d as ApprovalRequest, a as ApprovalMode } from './ApprovalPolicy-BVhGdECT.mjs';
6
6
  export { A as ApprovalKind, b as ApprovalPolicy, c as ApprovalPolicyOptions, e as ApprovalSource, D as DENY_ALL } from './ApprovalPolicy-BVhGdECT.mjs';
7
- import { R as RunnerModeInfo } from './ModeResolver-mtIWrLXn.mjs';
8
- export { M as ManifestLookup, b as buildModeGuide, f as filteredBuildModes, r as resolveDefaultMode, a as resolveTaskMode, c as runnerModesFrom } from './ModeResolver-mtIWrLXn.mjs';
9
- import { T as TaskOp, c as SessionBroadcaster } from './plan-utils-s6VL8NDF.mjs';
10
- export { A as ApplyTaskOpsResult, C as CHECKPOINT_TRUNCATE_LENGTH, S as SerializedPlan, a as SerializedTask, b as SerializedTaskStatus, d as SessionMessage, e as TaskRef, f as applyTaskOps, g as canMergeTasks, h as canSetDependencies, i as canSplitTask, j as classifyOutcome, k as dependencyCandidates, l as dependentsOf, m as executionSummary, p as parseTaskOpsJson, s as serializePlan, n as serializeTask, o as serializeTaskStatus, q as summarizeToolCall, t as textHasTaskOps, r as truncateCheckpointSummary } from './plan-utils-s6VL8NDF.mjs';
7
+ import { T as TaskOp, f as SessionBroadcaster, h as SessionNotice } from './plan-utils-CtB3_Ovf.mjs';
8
+ export { A as Adr0013IsolationRun, a as Adr0013PlanIsolation, b as Adr0013TaskRecord, c as ApplyTaskOpsResult, C as CHECKPOINT_TRUNCATE_LENGTH, S as SerializedPlan, d as SerializedTask, e as SerializedTaskStatus, g as SessionMessage, i as TaskRef, j as applyTaskOps, k as canMergeTasks, l as canSetDependencies, m as canSplitTask, n as capConflictFiles, o as classifyOutcome, p as dependencyCandidates, q as dependentsOf, r as executionSummary, s as migratePlanIsolation, t as parseTaskOpsJson, u as serializePlan, v as serializeTask, w as serializeTaskStatus, x as summarizeToolCall, y as textHasTaskOps, z as truncateCheckpointSummary } from './plan-utils-CtB3_Ovf.mjs';
9
+ import { R as RunnerModeInfo } from './ModeResolver-DVJ7HV3k.mjs';
10
+ export { M as ManifestLookup, b as buildModeGuide, f as filteredBuildModes, r as resolveDefaultMode, a as resolveTaskMode, c as runnerModesFrom } from './ModeResolver-DVJ7HV3k.mjs';
11
11
  import { ChildProcess } from 'child_process';
12
12
  import { EventEmitter } from 'events';
13
- import { b as PlanParseError } from './parsing-BWfpLch9.mjs';
14
- export { P as PLAN_ENVELOPE_KEY, a as PartialPlanTask, T as TASK_OPS_ENVELOPE_KEY, c as TASK_QUERY_ENVELOPE_KEY, d as checkDepsResolve, e as checkImmutableLog, f as checkInProgress, g as checkNoCycles, h as checkUniqueIds, i as escapeControlCharsInStrings, j as extractJsonObject, k as extractObjectWithBalance, l as extractObjectsWithKey, m as looksLikePlanAttempt, p as parsePartialPlan, n as parsePlanJson, s as stripModelNoise, o as stripTrailingCommas, v as validatePlanModification } from './parsing-BWfpLch9.mjs';
13
+ import { b as PlanParseError } from './parsing-DRp4dPC0.mjs';
14
+ export { P as PLAN_ENVELOPE_KEY, a as PartialPlanTask, T as TASK_OPS_ENVELOPE_KEY, c as TASK_QUERY_ENVELOPE_KEY, d as checkDepsResolve, e as checkImmutableLog, f as checkInProgress, g as checkNoCycles, h as checkUniqueIds, i as escapeControlCharsInStrings, j as extractJsonObject, k as extractObjectWithBalance, l as extractObjectsWithKey, m as looksLikePlanAttempt, p as parsePartialPlan, n as parsePlanJson, s as stripModelNoise, o as stripTrailingCommas, v as validatePlanModification } from './parsing-DRp4dPC0.mjs';
15
15
  export { resolveOrderLabel, taskOrderLabel } from './order-labels.mjs';
16
16
 
17
17
  interface SessionMeta {
@@ -523,6 +523,11 @@ declare abstract class BaseConfig implements IConfig {
523
523
  get researchMaxFileSize(): number;
524
524
  get planMapEnabled(): boolean;
525
525
  get autonomousMode(): boolean;
526
+ get worktreeIsolation(): boolean;
527
+ get worktreeSetupCommand(): string | undefined;
528
+ get workspaceRepos(): string[];
529
+ get worktreeLinks(): string[];
530
+ get conflictRepairAttempts(): number;
526
531
  get approvalMode(): ApprovalMode;
527
532
  get approvalPreApproved(): string[];
528
533
  protected static detectProvider(fallback: AiProvider): AiProvider;
@@ -553,6 +558,35 @@ interface INotification {
553
558
  confirm(msg: string, options: string[]): Promise<string | undefined>;
554
559
  }
555
560
 
561
+ /**
562
+ * How "Merge all" went, in words every surface shares. `group` is whether the
563
+ * run spans more than a lone repo at `.`; only a merge into every repository
564
+ * has something to say about that. `repaired` names the landed tasks that only
565
+ * landed after a conflict repair (ADR-0015), so a clean-looking merge still
566
+ * points review at what changed to get there.
567
+ */
568
+ declare function describeMergeResult(result: IsolationMergeResult, branch: string, group: boolean, repaired?: IsolationLandedTask[]): {
569
+ level: 'info' | 'warn' | 'error';
570
+ message: string;
571
+ };
572
+
573
+ type GitExecFn = (file: string, args: string[], opts: {
574
+ cwd?: string;
575
+ env: NodeJS.ProcessEnv;
576
+ }) => Promise<{
577
+ stdout: string;
578
+ stderr: string;
579
+ }>;
580
+ interface WorktreeIsolationDeps {
581
+ config: Pick<IConfig, 'worktreeIsolation' | 'worktreeSetupCommand' | 'workspaceRepos' | 'worktreeLinks'>;
582
+ /** Test seam: every git invocation goes through this. */
583
+ execFileImpl?: GitExecFn;
584
+ resolvePath?: () => Promise<string>;
585
+ platform?: NodeJS.Platform;
586
+ mintRunId?: () => string;
587
+ }
588
+ declare function createWorktreeIsolation(deps: WorktreeIsolationDeps): IWorktreeIsolation;
589
+
556
590
  interface ILogger {
557
591
  warn(scope: string, message: string, err?: unknown): void;
558
592
  }
@@ -628,9 +662,75 @@ interface PlannerRuntimeToggles {
628
662
  * every planner signature used to carry positionally — where a thirteenth
629
663
  * parameter was the only place left to put a new toggle.
630
664
  */
665
+ /**
666
+ * Where the run's tasks will work: `false` in the shared workspace root;
667
+ * otherwise each in its own worktree of every repo of the group (ADR-0013,
668
+ * ADR-0014), which is what decides if tasks on the same file must be ordered.
669
+ */
670
+ type IsolatedExecution = false | RepoGroupLayout;
631
671
  interface PlannerModes {
632
672
  autonomousDefault: boolean;
633
673
  verification: boolean;
674
+ /** Not a toggle: a fact about the run. */
675
+ isolatedExecution: IsolatedExecution;
676
+ }
677
+
678
+ /** Context of one task attempt, enough to locate its transcript. */
679
+ interface TranscriptQuery {
680
+ runner: string;
681
+ /** The task's working directory (the agent's cwd at spawn). */
682
+ cwd: string;
683
+ /** When the agent process started, ISO — used to reject older sessions. */
684
+ startedAt?: string;
685
+ /**
686
+ * The task's completion marker UUID. The prompt carries it, so a transcript
687
+ * that does not contain it belongs to some other task — parallel attempts in
688
+ * one cwd are otherwise indistinguishable by directory and recency.
689
+ */
690
+ marker: string;
691
+ }
692
+ /** Reads the agent's own session transcript for a task's final answer. */
693
+ interface TranscriptReader {
694
+ /** Last assistant-authored prose, clamped to `maxChars` from the end, or null. */
695
+ finalAssistantText(query: TranscriptQuery, maxChars?: number): Promise<string | null>;
696
+ }
697
+ /** The part of a task attempt its output is looked up by. */
698
+ interface TaskOutputAttempt {
699
+ readonly taskId: string;
700
+ readonly runner: string;
701
+ /** Null when the attempt ended before its working directory was settled. */
702
+ readonly cwd: string | null;
703
+ readonly startedAt: string;
704
+ /** The completion marker UUID the attempt's prompt carried. */
705
+ readonly completionMarker: string;
706
+ }
707
+ interface LiveTailOptions {
708
+ maxLines: number;
709
+ /** A previous {@link LiveTail.nextOffset}: only output after it is rendered. */
710
+ sinceOffset?: number;
711
+ }
712
+ interface LiveTail {
713
+ /** Clean terminal render, not raw ANSI. */
714
+ text: string;
715
+ /** Total output received so far; pass it back as `sinceOffset` to read only what follows. */
716
+ nextOffset: number;
717
+ running: boolean;
718
+ }
719
+ /**
720
+ * The one owner of a task attempt's output: what it printed while running
721
+ * and what it answered once it ended.
722
+ */
723
+ interface TaskOutputSource {
724
+ /** Start capturing a session; replaces any earlier capture of the task. */
725
+ attach(taskId: string, session: ITerminalSession): void;
726
+ /** Stop capturing the task's session; what was captured stays readable. */
727
+ detach(taskId: string): void;
728
+ /** Drop every capture (a new plan reuses task ids). */
729
+ reset(): void;
730
+ /** The attempt's final answer: its transcript first, the clean terminal render otherwise. */
731
+ finalText(attempt: TaskOutputAttempt, doneToken: string): Promise<string>;
732
+ /** Recent output of the task's latest capture, or null if it never had one. */
733
+ liveTail(taskId: string, opts: LiveTailOptions): LiveTail | null;
634
734
  }
635
735
 
636
736
  /**
@@ -648,8 +748,19 @@ interface PlannerModes {
648
748
  * lives in PlanRepair alongside the plan and task-ops envelopes.
649
749
  */
650
750
  /** The long fields a query may ask for. Everything else is already in the plan block. */
651
- declare const TASK_QUERY_FIELDS: readonly ["description", "prompt", "userSteps", "verdict", "outputSummary", "userStoriesCovered"];
751
+ declare const TASK_QUERY_FIELDS: readonly ["description", "prompt", "userSteps", "verdict", "outputSummary", "userStoriesCovered", "output"];
652
752
  type TaskQueryField = typeof TASK_QUERY_FIELDS[number];
753
+ /** Lines a `output` read returns when the query sets no count. */
754
+ declare const OUTPUT_LINES_DEFAULT = 80;
755
+ /** Hard cap on `outputLines` — the tail read is bounded however the planner asks. */
756
+ declare const OUTPUT_LINES_MAX = 400;
757
+ /**
758
+ * Character budget the rendered answer converges to. A running output tail is
759
+ * the only part with no natural bound — a runner may print for minutes — so
760
+ * the tail absorbs the clamp; everything else (task bodies, the catalog cap)
761
+ * is bounded upstream.
762
+ */
763
+ declare const TASK_QUERY_ANSWER_MAX_CHARS = 20000;
653
764
  interface TaskQuery {
654
765
  /** Task references to read in full — an id, "#order", a bare order, or a title. */
655
766
  tasks: string[];
@@ -657,6 +768,10 @@ interface TaskQuery {
657
768
  fields?: TaskQueryField[];
658
769
  /** Also return the full runner/model catalog with labels, variants and mode descriptions. */
659
770
  catalog: boolean;
771
+ /** Line count for `output` reads. Clamped at render to [1, {@link OUTPUT_LINES_MAX}]. */
772
+ outputLines?: number;
773
+ /** A previous answer's next offset: the output tail then covers only what came after it. */
774
+ outputSince?: number;
660
775
  }
661
776
  declare function textHasTaskQuery(text: string): boolean;
662
777
  /** Parse a `{"taskQuery":...}` reply. Throws PlanParseError when the JSON is unusable. */
@@ -685,12 +800,19 @@ declare const TASK_QUERY_ANSWER_OR_OPS: string;
685
800
  declare const TASK_QUERY_PROTOCOL: string[];
686
801
  /** The one-line reminder the per-turn plan block carries, so the protocol has a single owner. */
687
802
  declare const TASK_QUERY_REMINDER = "- To READ a task in full (prompt, user steps, verdict, output, user stories) or the whole model/mode catalog before editing, reply with ONLY {\"taskQuery\":{\"tasks\":[\"<id or #order>\"],\"catalog\":true}} \u2014 it changes nothing, and you then reply again with your ops.";
803
+ /**
804
+ * Where an `output` read is answered from: the orchestrator's live capture of
805
+ * the task's latest attempt. Injected so this module stays planner-side and
806
+ * never imports the orchestrator.
807
+ */
808
+ type LiveOutputLookup = (taskId: string, opts: LiveTailOptions) => LiveTail | null;
688
809
  /**
689
810
  * Render the injected answer to one read. Never persisted — it is context for
690
811
  * the planner's next reply and nothing else — so it is built fresh from live
691
- * state on every query rather than cached.
812
+ * state on every query rather than cached. `liveOutput` backs the `output`
813
+ * field; omitting it reads as "nothing captured".
692
814
  */
693
- declare function renderTaskQueryAnswer(query: TaskQuery, tasks: Task[], catalog: TaskQueryCatalog): string;
815
+ declare function renderTaskQueryAnswer(query: TaskQuery, tasks: Task[], catalog: TaskQueryCatalog, liveOutput?: LiveOutputLookup): string;
694
816
 
695
817
  declare abstract class AbstractTerminalSession implements ITerminalSession {
696
818
  id: string;
@@ -967,6 +1089,7 @@ declare class HeadlessRunner extends AbstractRunner<HeadlessSession> {
967
1089
  private hasScriptCmd;
968
1090
  private resolvePath;
969
1091
  private launchDeps;
1092
+ private spawnCount;
970
1093
  /**
971
1094
  * Session shape: a piped subprocess is not a terminal, so runners get their
972
1095
  * non-interactive subcommand. The VS Code runner owns a pseudoterminal and
@@ -976,6 +1099,13 @@ declare class HeadlessRunner extends AbstractRunner<HeadlessSession> {
976
1099
  */
977
1100
  protected readonly defaultInteractive: boolean;
978
1101
  constructor(deps?: HeadlessRunnerDeps);
1102
+ /**
1103
+ * Unique per spawn, not per task: a retry reuses its task id and ids often
1104
+ * share a prefix, and a shared registry key let the old attempt's exit
1105
+ * unregister the new one. Unlike TmuxRunner, nothing outside this process
1106
+ * keys on the id, so a counter is enough to scope it to the attempt.
1107
+ */
1108
+ protected nextSessionId(taskId: string): string;
979
1109
  protected createSession(id: string, taskId: string): HeadlessSession;
980
1110
  /** Everything up to, but not including, spawning — so a surface that owns its own child reaches the same decisions. */
981
1111
  protected prepareLaunch(opts: RunnerSpawnOptions, ptyOptions?: PtyWrapOptions): Promise<PreparedLaunch>;
@@ -1233,6 +1363,8 @@ interface ConversationRequest {
1233
1363
  runnerModes?: Record<RunnerId, RunnerModeInfo[]>;
1234
1364
  autonomousDefault?: boolean;
1235
1365
  verificationEnabled?: boolean;
1366
+ /** Where tasks will run (ADR-0013, ADR-0014): in worktrees, the prompt drops file-overlap ordering and describes a repo group. */
1367
+ isolatedExecution?: IsolatedExecution;
1236
1368
  signal?: AbortSignal;
1237
1369
  /**
1238
1370
  * Persisted dialogue to seed a resumed conversation (session reload). The
@@ -1308,6 +1440,13 @@ interface IAiService {
1308
1440
  * `continueConversation`, restart instead so the new model takes effect.
1309
1441
  */
1310
1442
  conversationMatchesConfig?(): boolean;
1443
+ /**
1444
+ * Optional: prune bulky raw tool output out of the live conversation, in
1445
+ * place, keeping subagent digests. Returns the characters removed. Absent
1446
+ * where the backend holds no tool transcript to prune (a harness planner's
1447
+ * agent owns its own context).
1448
+ */
1449
+ pruneContext?(): number;
1311
1450
  /**
1312
1451
  * One-shot research + plan for non-conversational surfaces (CLI `plan --goal`,
1313
1452
  * web REST). Never asks questions — it plans with what it can find.
@@ -1391,6 +1530,7 @@ declare abstract class BaseAiService {
1391
1530
  abstract reset(): void;
1392
1531
  abstract ensureInit(): void;
1393
1532
  hasActiveConversation(): boolean;
1533
+ pruneContext(): number;
1394
1534
  protected startAbortScope(callerSignal?: AbortSignal): AbortSignal | undefined;
1395
1535
  protected stopAbortScope(): void;
1396
1536
  sendPlanningPrompt(prompt: string, runners: RunnerId[], runnerModes?: Record<RunnerId, RunnerModeInfo[]>, autonomousDefault?: boolean): Promise<Task[]>;
@@ -1626,10 +1766,39 @@ interface OrchestratorObserver {
1626
1766
  taskTitle: string;
1627
1767
  summary: string;
1628
1768
  }): void;
1769
+ /** The isolation run record changed and should be persisted with the plan. */
1770
+ onIsolationChanged?(): void;
1771
+ /** A run did not start: the tree is dirty, and the user picks stash or no isolation. `repos` names the dirty repos of a group. */
1772
+ onIsolationBlocked?(data: {
1773
+ reason: 'dirty';
1774
+ repos: string[];
1775
+ }): void;
1776
+ /** An isolated run settled; emitted before `onExecutionComplete`, which surfaces treat as terminal. */
1777
+ onIsolationHandoff?(handoff: IsolationHandoff): void;
1778
+ /**
1779
+ * What a run says about how it isolates — the fallback to the workspace root,
1780
+ * shared paths, copies, a stash. Beside the notification channel, which a
1781
+ * daemon may leave unwired, so a surface without toasts can still show it.
1782
+ */
1783
+ onIsolationNotice?(data: {
1784
+ level: 'info' | 'warn';
1785
+ message: string;
1786
+ }): void;
1787
+ }
1788
+ type AttemptPhase = 'starting' | 'running' | 'integrating';
1789
+ /** Read-only view of a task's live attempt. */
1790
+ interface TaskAttemptSnapshot {
1791
+ taskId: string;
1792
+ attempt: number;
1793
+ phase: AttemptPhase;
1794
+ sessionId: string | null;
1795
+ runner: string;
1796
+ cwd: string | null;
1797
+ startedAt: string;
1629
1798
  }
1630
1799
  /**
1631
1800
  * The pure scheduler. Owns execution state (`running`, `planStatus`,
1632
- * `reviewApproved`, `activeTaskSessions`, `messageQueue`) and the verifier.
1801
+ * `reviewApproved`, the live task attempts, `messageQueue`) and the verifier.
1633
1802
  * All task-shaped state — the plan tree, the flat index, the completed set
1634
1803
  * — lives in {@link PlanStore}, injected at construction. The orchestrator
1635
1804
  * calls `store.markCompleted(id)` / `store.markFailed(id)` instead of mutating
@@ -1641,15 +1810,16 @@ declare class TaskOrchestrator {
1641
1810
  private config;
1642
1811
  private notifications;
1643
1812
  private terminalRunner;
1813
+ private output;
1644
1814
  private store;
1645
- private activeTaskSessions;
1646
- private startingTaskIds;
1815
+ private attempts;
1647
1816
  private verifier;
1648
1817
  private running;
1649
1818
  private planStatus;
1650
1819
  private messageQueue;
1651
1820
  private reviewApproved;
1652
1821
  private retryCounts;
1822
+ private spawnCounts;
1653
1823
  /**
1654
1824
  * Tasks pulled out of auto-scheduling (user-cancelled or failed to spawn).
1655
1825
  * They stay 'pending' — "not executed" — but the scheduler skips them until
@@ -1657,18 +1827,33 @@ declare class TaskOrchestrator {
1657
1827
  * task whose spawn always throws.
1658
1828
  */
1659
1829
  private onHold;
1830
+ private isolation;
1831
+ /** The plan's isolation run (ADR-0013). Outlives one run: a resumed plan continues it. */
1832
+ private isolationRun;
1833
+ /** Copied paths already reported for the current run: every task gets the same copies. */
1834
+ private reportedCopies;
1835
+ /**
1836
+ * How the open run executes; null while no run is open. A run is one
1837
+ * Execute-Plan or one manual task run, from its start until it settles or
1838
+ * is stopped.
1839
+ */
1840
+ private runMode;
1841
+ /** Resolver task id → the conflicted task it resolves; see {@link linkConflictResolver}. */
1842
+ private resolvers;
1843
+ private opening;
1844
+ /** The start a dirty tree turned away, replayed once the user chooses how to go on. */
1845
+ private blockedStart;
1846
+ /** The dirty repos behind {@link blockedStart}, for the stash notice. */
1847
+ private blockedRepos;
1660
1848
  private registry;
1661
1849
  private workspaceRootFn;
1662
1850
  private observers;
1663
1851
  private tddEnabled;
1664
- /**
1665
- * Spawn context per active task, for locating the agent's own session
1666
- * transcript at verdict time (issue #16). Cleared with the session entry.
1667
- */
1668
- private taskSpawnContext;
1669
- constructor(config: IConfig, notifications: INotification, terminalRunner: ITerminalRunner, store?: PlanStore);
1852
+ constructor(config: IConfig, notifications: INotification, terminalRunner: ITerminalRunner, store?: PlanStore, output?: TaskOutputSource, isolation?: IWorktreeIsolation);
1670
1853
  /** Advisory silence timestamp for a task's live runner, or null if not idle. */
1671
1854
  getIdleSince(taskId: string): string | null;
1855
+ /** Recent clean output of a task's latest attempt, running or ended; null if it never ran. */
1856
+ getLiveOutput(taskId: string, opts: LiveTailOptions): LiveTail | null;
1672
1857
  get storeInstance(): PlanStore;
1673
1858
  setWorkspaceRoot(fn: () => string): void;
1674
1859
  setRegistry(registry: RunnerRegistry): void;
@@ -1694,8 +1879,48 @@ declare class TaskOrchestrator {
1694
1879
  get isReviewApproved(): boolean;
1695
1880
  get status(): 'approved' | 'running' | 'completed';
1696
1881
  get activeTaskIds(): string[];
1882
+ /** Task id → session id of every attempt whose runner is up; a spawn in flight has no session yet. */
1697
1883
  get activeSessionMap(): Map<string, string>;
1884
+ getAttempt(taskId: string): TaskAttemptSnapshot | undefined;
1885
+ /** Where a task's isolated work stands; null when the plan has no isolation run to speak of. */
1886
+ getTaskIsolation(taskId: string): TaskIsolation | null;
1887
+ /**
1888
+ * The plan's isolation as a surface shows it, for one with no stream to have
1889
+ * told it — a reconnected webview, a session just loaded. Null without a run.
1890
+ */
1891
+ isolationView(): IsolationView | null;
1892
+ getAttemptSession(taskId: string): ITerminalSession | undefined;
1698
1893
  get queuedCount(): number;
1894
+ /** A run is waiting on the user to stash or to go on without isolation. */
1895
+ get awaitingIsolationChoice(): boolean;
1896
+ /**
1897
+ * Take over a plan's persisted isolation, or none for a plan that has not
1898
+ * isolated yet. Whatever a crashed process left behind for the run — a
1899
+ * worktree still marked active, a directory no record owns — is pruned,
1900
+ * while kept, failed and conflicted worktrees stay for the user.
1901
+ *
1902
+ * Deliberately silent on the observer: adopting is not a change to persist,
1903
+ * and a host that adopts without persisting (VS Code's restore) would
1904
+ * otherwise write a new session file on every reload.
1905
+ */
1906
+ adoptIsolation(state: PlanIsolation | null): Promise<void>;
1907
+ reviewRunDiff(): Promise<string>;
1908
+ /**
1909
+ * "Merge all": the run's integration branches into whatever the user has
1910
+ * checked out, in every repo or none. Once everything merged, the run has
1911
+ * nothing left to hand over, so it is cleared up and forgotten; a branch
1912
+ * the user's HEAD somehow does not contain stays for the next run's sweep.
1913
+ */
1914
+ mergeRun(): Promise<IsolationMergeResult>;
1915
+ private clearMergedRun;
1916
+ /** Worktrees and task branches go; the integration branch and the record stay for review and merge. */
1917
+ cleanupRun(): Promise<void>;
1918
+ /** The run and everything it made go, and the plan forgets it; the next run starts afresh. */
1919
+ discardRun(): Promise<void>;
1920
+ private forgetRun;
1921
+ private requireRun;
1922
+ /** What the plan persists of isolated execution; null when no run ever isolated. */
1923
+ get isolationRecord(): PlanIsolation | null;
1699
1924
  queueMessage(text: string): void;
1700
1925
  getQueuedMessages(): QueuedMessage[];
1701
1926
  setQueuedMessages(messages: QueuedMessage[]): void;
@@ -1718,7 +1943,63 @@ declare class TaskOrchestrator {
1718
1943
  stop(): void;
1719
1944
  onUserTaskComplete(taskId: string): Promise<void>;
1720
1945
  private onVerdict;
1946
+ private afterVerdict;
1947
+ /**
1948
+ * A repair's verdict decides only whether its work may try to land. It never
1949
+ * replaces the verdict the task's own work earned, and a repair that does not
1950
+ * land leaves the task waiting on the user — never a failed task, so never a
1951
+ * halted run.
1952
+ */
1953
+ private settleRepair;
1954
+ /**
1955
+ * Evidence before the queue: the repair's work is committed and checked, and
1956
+ * only then merged, through the same serialized landing as any other task —
1957
+ * so a repair the tip has moved past again is a fresh conflict, not a pass.
1958
+ */
1959
+ private landRepair;
1960
+ private landedRepair;
1961
+ /** A repair that did not land leaves the task as its conflict did: waiting on the user, worktree and refs kept. */
1962
+ private unrepaired;
1963
+ private describeEvidence;
1964
+ /**
1965
+ * Merge a passed attempt's worktree. The attempt stays live while it waits on
1966
+ * the module's merge queue, so a cancel, retry or stop in that window still
1967
+ * wins, and nothing counts the task as done before its work is on the
1968
+ * integration branch.
1969
+ */
1970
+ private integrate;
1971
+ /** A worktree whose work is not on the integration branch yet. */
1972
+ private hasUnlandedWork;
1973
+ private integrateWork;
1974
+ /** Settle a task whose work passed, by what its integration reported. */
1975
+ private landPassed;
1976
+ private landUnmerged;
1977
+ /** The repair a conflicted task is owed next; null when repair is off, used up, or there is no isolated run to repair it in. */
1978
+ private nextRepair;
1979
+ private noRepairReason;
1980
+ /**
1981
+ * Mark which added task resolves which conflict. The resolver merges the
1982
+ * conflicted task's branch by hand in its own worktree; once that lands, the
1983
+ * conflicted task's branch is already on the integration branch and it can
1984
+ * land in turn — through the same merge, so a resolver that did not really
1985
+ * bring it along conflicts again instead of being taken at its word.
1986
+ */
1987
+ linkConflictResolver(resolverId: string, conflictedId: string): void;
1988
+ private landResolved;
1989
+ /**
1990
+ * Let go of a task's worktree. `keep` leaves it and its branch for
1991
+ * inspection; otherwise both go. A merge still in flight finishes first, so
1992
+ * the worktree is never torn down underneath it.
1993
+ */
1994
+ private releaseWorktree;
1721
1995
  getReadyTasks(): Task[];
1996
+ /**
1997
+ * In an isolated run a dependency is met once its work is on the integration
1998
+ * branch, not merely once it passed: the dependent's worktree is cut from
1999
+ * that branch, so starting earlier would hand it a tree without the work it
2000
+ * depends on.
2001
+ */
2002
+ private dependencyMet;
1722
2003
  isBlocked(task: Task): boolean;
1723
2004
  /**
1724
2005
  * Cancel a running (or scheduled) task: kill its session and return it to
@@ -1728,12 +2009,10 @@ declare class TaskOrchestrator {
1728
2009
  cancelTask(taskId: string): Promise<void>;
1729
2010
  /**
1730
2011
  * Let go of a task that is leaving the plan. A live runner is cancelled
1731
- * through {@link cancelTask} so the verifier generation is bumped before the
1732
- * process dies; a spawn still in flight is dropped from `startingTaskIds`,
2012
+ * through {@link cancelTask}; a spawn still in flight just loses its attempt,
1733
2013
  * which is what makes {@link startTask} kill the session it is about to
1734
- * receive. The id's remaining bookkeeping goes too — a hold or retry count
1735
- * kept for a task that no longer exists would be inherited by nothing and
1736
- * leaves `isRunning` reading true forever.
2014
+ * receive. The id's cross-attempt bookkeeping goes too — a hold or retry
2015
+ * count kept for a task that no longer exists would be inherited by nothing.
1737
2016
  */
1738
2017
  releaseTask(taskId: string): Promise<void>;
1739
2018
  markTaskComplete(taskId: string): Promise<void>;
@@ -1779,6 +2058,75 @@ declare class TaskOrchestrator {
1779
2058
  };
1780
2059
  tick(): Promise<void>;
1781
2060
  private startTask;
2061
+ /**
2062
+ * A spawn whose attempt ended while it was in flight: kill what it produced
2063
+ * and take back the claim it made. Only the claim — whatever ended the
2064
+ * attempt may have decided the task since (mark complete, cancel, retry).
2065
+ */
2066
+ private abandonSpawn;
2067
+ private repairPrompt;
2068
+ /**
2069
+ * The one place an attempt's working directory is decided. Async so a
2070
+ * per-attempt workspace (worktree isolation, #12) can be prepared here.
2071
+ */
2072
+ private resolveAttemptCwd;
2073
+ private tell;
2074
+ private reportCopies;
2075
+ /**
2076
+ * Open a run if none is: decide once, at its start, whether it executes in
2077
+ * worktrees. `resume` is what a dirty tree parks until the user chooses how
2078
+ * to go on. Resolves false when the run did not start.
2079
+ */
2080
+ private openRun;
2081
+ /**
2082
+ * Whether the run in force, or else the next one, gives each task its own
2083
+ * worktrees, and of which repo group — what the planner is told, since it
2084
+ * decides whether tasks on the same file have to be ordered and which shared
2085
+ * paths two tasks must not edit at once. A tree that would block counts as
2086
+ * not isolating: the user may yet run without isolation, and ordering is
2087
+ * the safe rule then.
2088
+ */
2089
+ plannerIsolation(): Promise<IsolatedExecution>;
2090
+ private decideRun;
2091
+ private activate;
2092
+ /** What earlier runs left merged in the group goes; a failure here is worth a word, never a stopped run. */
2093
+ private sweep;
2094
+ /**
2095
+ * The plan's run carries on while anything has landed on its integration
2096
+ * branch: a resumed plan's dependents must start from a tip that holds their
2097
+ * predecessors' work, and a fresh branch from the checked-out commit does not.
2098
+ */
2099
+ private continuableRun;
2100
+ /**
2101
+ * A run with nothing landed holds only superseded attempts, so it goes whole.
2102
+ * One that cannot be continued for another reason — it ran from a different
2103
+ * workspace path — keeps its integration branch in each repo that has not
2104
+ * merged it: only the user gives landed work up.
2105
+ */
2106
+ private mintRun;
2107
+ /** Close the open run. An isolated one hands its integration branch over for review. */
2108
+ private closeRun;
2109
+ /**
2110
+ * Replay the start a dirty tree turned away. `stash` puts the user's tracked
2111
+ * changes on the git stash first, so the run isolates; `shared` runs this one
2112
+ * run in the workspace root, knowingly.
2113
+ */
2114
+ continueBlockedRun(how: 'stash' | 'shared'): Promise<void>;
2115
+ /**
2116
+ * The one way an attempt ends. Dropping the record is itself what
2117
+ * invalidates a spawn still in flight ({@link startTask} kills the session
2118
+ * it receives for an attempt that is no longer current).
2119
+ *
2120
+ * A user interruption also bumps the verifier's generation *before* stopping
2121
+ * the runner: some runners (e.g. tmux) fire onExit synchronously from
2122
+ * stop(), and if that exit reaches VerdictEngine under the still-valid
2123
+ * generation it delivers a verdict that marks the task 'completed' for one
2124
+ * tick — long enough for the scheduler to start a dependent task. A verdict
2125
+ * leaves the runner up so its terminal stays readable, and stop/load reset
2126
+ * the whole verifier themselves.
2127
+ */
2128
+ private endAttempt;
2129
+ private endAllAttempts;
1782
2130
  }
1783
2131
 
1784
2132
  /**
@@ -1821,6 +2169,8 @@ interface ModifyDuringExecutionRequest {
1821
2169
  runnerModes?: Record<RunnerId, RunnerModeInfo[]>;
1822
2170
  autonomousDefault?: boolean;
1823
2171
  perRunnerAllowlist?: Partial<Record<RunnerId, string[]>>;
2172
+ /** Where the run in force puts each task (ADR-0013, ADR-0014). */
2173
+ isolatedExecution?: IsolatedExecution;
1824
2174
  }
1825
2175
  interface ModifyDuringExecutionResult {
1826
2176
  pendingTasks: Task[];
@@ -2333,6 +2683,39 @@ declare function mapAgentTool(name: string): MappedTool;
2333
2683
  */
2334
2684
  declare function normalizeAgentArgs(tool: ResearchToolType, args: Record<string, unknown>): Record<string, unknown>;
2335
2685
 
2686
+ /**
2687
+ * A conversation edit (rewind, fork) the conversation refused because the
2688
+ * request itself is wrong — no such message, nothing to fork. Transport-agnostic
2689
+ * like `PlanEditError`: a route maps it to a status, core carries none.
2690
+ */
2691
+ declare class ConversationEditError extends Error {
2692
+ constructor(message: string);
2693
+ }
2694
+ /**
2695
+ * Refused because a planner turn is in flight. Distinct from a bad request:
2696
+ * the same call succeeds once the turn settles, and the turn would otherwise
2697
+ * append its reply to a transcript that no longer holds the message it
2698
+ * answers.
2699
+ */
2700
+ declare class ConversationBusyError extends ConversationEditError {
2701
+ constructor(operation: string);
2702
+ }
2703
+ /** A user message a rewind can fork the conversation from just before. */
2704
+ interface RewindTarget {
2705
+ /** Position in the transcript — what {@link PlannerConversation.cloneBefore} takes. */
2706
+ index: number;
2707
+ preview: string;
2708
+ /** The whole message — the preview cuts it to one line, and a surface confirming the rewind quotes it. */
2709
+ content: string;
2710
+ timestamp: string;
2711
+ }
2712
+ /** What a compaction left behind. */
2713
+ interface ConversationCompaction {
2714
+ summary: string;
2715
+ /** Transcript entries kept verbatim after the summary entry. */
2716
+ keptMessages: number;
2717
+ }
2718
+
2336
2719
  declare const BUILTIN_SKILL_NAMES: readonly ["grilling", "to-spec", "improve-codebase-architecture"];
2337
2720
  interface SkillMetadata {
2338
2721
  name: string;
@@ -2423,6 +2806,16 @@ declare function resolveSkillInvocation(text: string, skillsService: Pick<Skills
2423
2806
  * settings (tdd, verification) are read live via the `settings` callback so a toggle
2424
2807
  * between generate and execute takes effect.
2425
2808
  */
2809
+ /** Where a fork landed: the new session's id, and what adopting it needs. */
2810
+ interface ConversationFork {
2811
+ sessionId: string;
2812
+ goal: string;
2813
+ workspace: string;
2814
+ }
2815
+ /** A fork made by a rewind, and the full text of the message it was made just before. */
2816
+ interface ConversationRewind extends ConversationFork {
2817
+ rewoundMessage: string;
2818
+ }
2426
2819
  interface SessionDeps {
2427
2820
  config: IConfig;
2428
2821
  notifications: INotification;
@@ -2434,6 +2827,8 @@ interface SessionDeps {
2434
2827
  fsAdapter: IFileSystem;
2435
2828
  /** Emits plan-lifecycle events to the surface. Transport-agnostic. */
2436
2829
  broadcast: SessionBroadcaster;
2830
+ /** Where {@link SessionNotice}s go, for a host whose `notifications` are not seen by the user. */
2831
+ onNotice?: (notice: SessionNotice) => void;
2437
2832
  /** Shared across sessions — sole producer of model catalogs and routing lists. */
2438
2833
  modelResolver: ModelResolver;
2439
2834
  /** Live runtime settings (tdd, verification). Read at each operation that needs them. */
@@ -2457,6 +2852,17 @@ interface SessionDeps {
2457
2852
  * over the session's workspace root.
2458
2853
  */
2459
2854
  skillsService?: SkillsService;
2855
+ /**
2856
+ * Where a task's output and final answer are read. Defaults to the agents'
2857
+ * own transcripts under the user's home; tests inject one that never
2858
+ * touches the disk.
2859
+ */
2860
+ taskOutput?: TaskOutputSource;
2861
+ /**
2862
+ * Git worktree isolation (ADR-0013). Defaults to git itself, gated by
2863
+ * `config.worktreeIsolation`; tests inject `FakeWorktreeIsolation`.
2864
+ */
2865
+ isolation?: IWorktreeIsolation;
2460
2866
  }
2461
2867
  /**
2462
2868
  * The per-session execution stack — deepened from a wiring bag into the
@@ -2486,6 +2892,7 @@ declare class Session {
2486
2892
  private goal;
2487
2893
  private workspace;
2488
2894
  private broadcast;
2895
+ private onNotice?;
2489
2896
  private modelResolver;
2490
2897
  private fsAdapter;
2491
2898
  private approvals;
@@ -2498,6 +2905,7 @@ declare class Session {
2498
2905
  private readonly hostSessionId?;
2499
2906
  private currentSessionId;
2500
2907
  private readonly skillsService;
2908
+ private readonly conversation;
2501
2909
  constructor(deps: SessionDeps);
2502
2910
  /**
2503
2911
  * The planner transport for the provider configured *right now* (ADR-0009).
@@ -2531,6 +2939,7 @@ declare class Session {
2531
2939
  get planTasks(): Task[];
2532
2940
  private attachObserver;
2533
2941
  private buildObserver;
2942
+ private broadcastStatus;
2534
2943
  private translateProgress;
2535
2944
  /** Persists PlanStore state to disk. PlanStore is the single authority;
2536
2945
  * LegacyPlanState.tasks is populated only here, at persist time. */
@@ -2541,8 +2950,8 @@ declare class Session {
2541
2950
  * A new plan starts from zero: drop the live planner conversation and every
2542
2951
  * task, log, and queued message left over from a previous plan on this
2543
2952
  * Session. Without this, a long-lived Session (VS Code hosts exactly one)
2544
- * leaks the previous session's tasks into `planContextBlock()` — the model
2545
- * is told they are the CURRENT plan and re-presents them as its draft.
2953
+ * leaks the previous session's tasks into the per-turn plan block — the
2954
+ * model is told they are the CURRENT plan and re-presents them as its draft.
2546
2955
  */
2547
2956
  private beginFreshPlan;
2548
2957
  /**
@@ -2611,8 +3020,8 @@ declare class Session {
2611
3020
  generatePlan(goal: string, runners: RunnerId[], options?: GeneratePlanOptions): Promise<LegacyPlanState>;
2612
3021
  /**
2613
3022
  * Kick off the planner conversation (ADR-0002): research + the first planner
2614
- * message. The AI service retains the tool-use history; the Session persists
2615
- * the user/assistant dialogue on the plan state.
3023
+ * message. The conversation itself — transcript, live model context, turn
3024
+ * settlement — is {@link PlannerConversation}'s; the Session hosts it.
2616
3025
  */
2617
3026
  startPlanning(goal: string, runners: RunnerId[], options?: GeneratePlanOptions): Promise<LegacyPlanState>;
2618
3027
  /**
@@ -2621,69 +3030,31 @@ declare class Session {
2621
3030
  */
2622
3031
  continueConversation(userMessage: string, options?: GeneratePlanOptions): Promise<LegacyPlanState>;
2623
3032
  /**
2624
- * Answer every read the planner emits until it says something else.
2625
- *
2626
- * The channel is a text envelope rather than a registered tool because the
2627
- * protocol has to be identical on both planner backends (ADR-0009): Ordewell
2628
- * owns a tool loop only in the API case, and a harness planner running as a
2629
- * coding-agent subprocess can only be reached this way.
2630
- *
2631
- * Draining here — outside {@link repairLoop} — is what keeps reads free of
2632
- * the repair budget. A planner that looks a task up and *then* fumbles its
2633
- * ops JSON still gets its two corrective retries; charging it for the read
2634
- * would cost it the chance to fix the edit.
2635
- */
2636
- private drainTaskQueries;
2637
- /**
2638
- * Render one read out of live state. Never persisted to the transcript: the
2639
- * detail is context for the planner's next reply, and re-sending it on every
2640
- * later turn is exactly the cost this channel exists to avoid.
2641
- */
2642
- private taskQueryAnswer;
2643
- /**
2644
- * Drive a planner turn to a persisted, broadcast outcome. Task edits apply
2645
- * atomically; validation failures are fed back to the model for up to 2
2646
- * silent retries, then surfaced as a message with the plan untouched. The
2647
- * first turn (startPlanning) and every later turn route through here — one
2648
- * path, not two.
3033
+ * Copy this conversation and its task list into a new persisted session and
3034
+ * answer its id. This session is untouched — not even its live planner
3035
+ * context, so the original carries on exactly where it was. The fork holds
3036
+ * no run (see {@link forkPlanState}); a host adopts it like any saved
3037
+ * session, and its first message replays the copied transcript.
2649
3038
  */
2650
- private settleTurn;
3039
+ forkConversation(): ConversationFork;
2651
3040
  /**
2652
- * The catalog the planner may actually draw from — model ids and task-mode
2653
- * ids, per selected runner — emitted on EVERY turn, before any plan exists
2654
- * or after. The system prompt shows this once at conversation start; a long
2655
- * clarifying conversation outlives that single showing and the planner
2656
- * starts misquoting it, so this re-states it per turn instead.
2657
- *
2658
- * Built from the allowlist-filtered view (`filterModelsForPrompt`), the same
2659
- * one the system prompt used — a restricted allowlist stays a hard bound on
2660
- * every turn, not just the first. {@link models} itself is never
2661
- * filtered: `coerceAssignments` needs the full discovered catalog alongside
2662
- * the allowlist to resolve labels and clamp effort to real variants.
2663
- *
2664
- * Reads `this.plan.runners` live, so a runner admitted mid-session by a
2665
- * retarget (`admitRunner`) is filtered and shown like every other — there is
2666
- * no separate "originally selected" list to fall stale.
3041
+ * Fork the conversation from just before a user message (a transcript
3042
+ * position from {@link rewindTargets}): the fork holds everything said
3043
+ * before it and the current task list, like {@link forkConversation}, and
3044
+ * this session keeps its whole history. The message's full text comes back
3045
+ * so a surface can offer it for resending.
2667
3046
  */
2668
- private catalogBlock;
3047
+ rewindConversation(userMessageIndex: number): ConversationRewind;
3048
+ private saveFork;
2669
3049
  /**
2670
- * The "you are here" block for post-plan chat: current tasks with stable
2671
- * references, plus the task-ops protocol. Injected per turn (never
2672
- * persisted) so the model always sees live statuses — including which tasks
2673
- * are locked by a running execution.
3050
+ * Condense the conversation on the user's say-so: a hidden planner turn
3051
+ * summarises it, and the summary replaces everything but the last two
3052
+ * exchanges. Conversation only — the tasks, and any run
3053
+ * executing them, are untouched. Atomic: a failed or stopped turn changes
3054
+ * nothing.
2674
3055
  */
2675
- private planContextBlock;
2676
- /** Validate + commit a task_ops turn atomically. Returns the errors on rejection (plan untouched). */
2677
- private applyTaskOpsTurn;
2678
- /**
2679
- * Resume a persisted dialogue onto a fresh AI-service conversation — either
2680
- * because the in-memory one is gone (session reload, extension restart), or
2681
- * because {@link continueConversation} found it stale against the planner
2682
- * config now in effect (a harness planner's model/effort switched mid-chat).
2683
- * The saved transcript seeds the new conversation; no LLM call happens
2684
- * before the user's message is sent.
2685
- */
2686
- private resumeConversation;
3056
+ compactConversation(signal?: AbortSignal): Promise<ConversationCompaction>;
3057
+ rewindTargets(): RewindTarget[];
2687
3058
  /** Whether the planner conversation is live (started and not yet committed to a plan). */
2688
3059
  get isConversationActive(): boolean;
2689
3060
  /**
@@ -2695,10 +3066,22 @@ declare class Session {
2695
3066
  * bare /unknown through to be mis-resolved.
2696
3067
  */
2697
3068
  private resolveSkillInvocation;
2698
- /** Append one dialogue entry to the persisted transcript. Callers persist via the mutatePlan ritual. */
2699
- private appendTranscript;
2700
- /** Commit a settled (non-task_ops) turn. Both branches run the mutatePlan ritual. */
2701
- private applyConversationTurn;
3069
+ /**
3070
+ * The one place planning discovers what it may draw from: the runners'
3071
+ * models (cached for later effort clamping), their modes, and the settings
3072
+ * in force. `filteredModels` is the allowlisted view a prompt may show;
3073
+ * `modelsByRunner` stays whole because coercion needs real labels and variants.
3074
+ */
3075
+ private plannerCatalog;
3076
+ private conversationOpening;
3077
+ /**
3078
+ * Load planner-produced tasks, coerced to the allowlist read live — it may
3079
+ * have changed since planning started. An edit on an armed scheduler is
3080
+ * reconciled rather than reloaded: `loadPlan` clears the on-hold set and the
3081
+ * review approval, so a task the user cancelled would be re-armed and
3082
+ * re-spawned by the re-tick that follows.
3083
+ */
3084
+ private adoptPlannerTasks;
2702
3085
  /**
2703
3086
  * PRD mode: when the planner writes the full markdown PRD, save it to
2704
3087
  * .scratch/<slug>/PRD.md (Matt Pocock to-prd convention) and keep it on the plan.
@@ -2724,6 +3107,43 @@ declare class Session {
2724
3107
  get queuedCount(): number;
2725
3108
  getTask(taskId: string): Task | undefined;
2726
3109
  get isReviewApproved(): boolean;
3110
+ /** Replay a run a dirty tree blocked, after stashing the tracked changes. */
3111
+ continueWithStash(): Promise<void>;
3112
+ /** Replay a run a dirty tree blocked, in the workspace root, for this run only. */
3113
+ continueWithoutIsolation(): Promise<void>;
3114
+ /**
3115
+ * Each task's isolation mark and the run's handoff, read from the run record.
3116
+ * The stream reports changes only; a surface that (re)connects or loads a
3117
+ * session asks here instead.
3118
+ */
3119
+ isolationView(): IsolationView | null;
3120
+ /** The run's integration branch against its base ref, as a unified diff. */
3121
+ reviewRunDiff(): Promise<string>;
3122
+ /**
3123
+ * "Merge all": each repo's integration branch into whatever the user has
3124
+ * checked out there — every repo, or none if any cannot take it. The one
3125
+ * irreversible step of isolated execution, so this explicit call is the
3126
+ * only way it ever happens.
3127
+ */
3128
+ mergeRun(): Promise<IsolationMergeResult>;
3129
+ /** Remove the run's worktrees and task branches; keep its integration branch to review or merge. */
3130
+ cleanupRun(): Promise<void>;
3131
+ /**
3132
+ * Give the whole run up, integration branch included. The plan is not
3133
+ * rewritten: a task that landed there stays completed until the user says
3134
+ * otherwise (Mark not done), because only they know whether they kept the work.
3135
+ */
3136
+ discardRun(): Promise<void>;
3137
+ private requireSettledRun;
3138
+ /**
3139
+ * The opt-in way through a merge conflict: add an AI task, on the conflicted
3140
+ * task's own runner and model, that merges its branch by hand in a worktree
3141
+ * of its own. When that task lands, the conflicted one lands through it (see
3142
+ * {@link TaskOrchestrator.linkConflictResolver}). The automatic answer to a
3143
+ * conflict is a repair, a new attempt of the same task (ADR-0015); a task is
3144
+ * only ever added to the plan by this call.
3145
+ */
3146
+ resolveConflictAsTask(taskId: string): Promise<LegacyPlanState | null>;
2727
3147
  stopExecution(): void;
2728
3148
  /**
2729
3149
  * The one mutation seam: every structural plan mutation runs the same
@@ -2740,7 +3160,7 @@ declare class Session {
2740
3160
  * queues — so a task the edit just unblocked would sit ready and never
2741
3161
  * start. `tick()` no-ops while the scheduler is idle, so this costs nothing
2742
3162
  * during plain planning. The planner-driven path re-ticks in
2743
- * {@link settleTurn} instead; it must not tick twice.
3163
+ * {@link PlannerConversation} instead (`afterEdit`); it must not tick twice.
2744
3164
  */
2745
3165
  private editPlan;
2746
3166
  /**
@@ -2860,25 +3280,31 @@ declare function globalDataDir(): string;
2860
3280
  */
2861
3281
  declare function migrateOldConfigDir(): void;
2862
3282
 
2863
- type VerdictListener = (taskId: string, verdict: Verdict, output: string) => void;
3283
+ type VerdictListener = (taskId: string, verdict: Verdict) => void;
2864
3284
  type CheckpointListener = (taskId: string, summary: string) => void;
2865
3285
  /** Fires on every idleSince transition (null→timestamp on silence, timestamp→null on resume/teardown). */
2866
3286
  type IdleListener = (taskId: string, idleSince: string | null) => void;
2867
3287
  declare class VerdictEngine {
2868
3288
  private markerSeen;
2869
- private buffers;
2870
- private checkpointCounts;
3289
+ private markerTails;
3290
+ private checkpointCarry;
2871
3291
  private pausedSessions;
2872
3292
  private listeners;
2873
3293
  private checkpointListeners;
2874
3294
  private idleListeners;
2875
3295
  /**
2876
- * Per-task generation counter. Incremented on every watch() and clear().
3296
+ * Per-task generation. Replaced on every watch(), clear() and verdict.
2877
3297
  * Stale callbacks (from a prior session whose generation doesn't match
2878
3298
  * the current one) bail out instead of delivering a verdict for the
2879
3299
  * wrong session.
2880
3300
  */
2881
3301
  private generations;
3302
+ /**
3303
+ * Generations come from one counter that {@link reset} never rewinds: a
3304
+ * per-task count restarted at 1 after a reset, and the next watch handed a
3305
+ * session that outlived the reset the same generation as its successor.
3306
+ */
3307
+ private lastGeneration;
2882
3308
  private idleTimers;
2883
3309
  private idleSince;
2884
3310
  onVerdict(listener: VerdictListener): void;
@@ -2901,12 +3327,16 @@ declare class VerdictEngine {
2901
3327
  approveCheckpoint(taskId: string): void;
2902
3328
  rejectCheckpoint(taskId: string, reason: string): void;
2903
3329
  /**
2904
- * Attach to a spawned session: buffer output, scan for the task's completion
3330
+ * Attach to a spawned session: scan the output tail for the task's completion
2905
3331
  * marker (delivering a verdict immediately while leaving interactive sessions
2906
3332
  * open), scan for checkpoint markers, and on exit produce a failed verdict
2907
3333
  * when the marker was never observed.
2908
3334
  */
2909
3335
  watch(task: Task, session: ITerminalSession): void;
3336
+ /** Scan only the new text plus the unmatched carry, so a long run stays linear. */
3337
+ private scanCheckpoints;
3338
+ private bumpGeneration;
3339
+ private forget;
2910
3340
  /** Manual "Mark complete" override: a pass verdict that bypasses evidence. */
2911
3341
  markComplete(task: Task): Verdict;
2912
3342
  /** Clear verification state for a task (used on retry). */
@@ -2916,6 +3346,49 @@ declare class VerdictEngine {
2916
3346
  private decide;
2917
3347
  }
2918
3348
 
3349
+ /**
3350
+ * Owns one bounded raw buffer per task attempt, fed from the attempt's
3351
+ * session, and reads final answers from the agent's transcript through an
3352
+ * injected {@link TranscriptReader}.
3353
+ */
3354
+ declare class BufferedTaskOutputSource implements TaskOutputSource {
3355
+ private captures;
3356
+ private transcripts;
3357
+ private maxBufferChars;
3358
+ constructor(opts?: {
3359
+ transcripts?: TranscriptReader;
3360
+ maxBufferChars?: number;
3361
+ });
3362
+ attach(taskId: string, session: ITerminalSession): void;
3363
+ detach(taskId: string): void;
3364
+ reset(): void;
3365
+ finalText(attempt: TaskOutputAttempt, doneToken: string): Promise<string>;
3366
+ liveTail(taskId: string, opts: LiveTailOptions): LiveTail | null;
3367
+ private append;
3368
+ }
3369
+
3370
+ /**
3371
+ * Read a task's final answer from the agent's own session transcript — the
3372
+ * clean, structured record the agent writes about itself — instead of
3373
+ * reconstructing what a TUI painted (issue #16, built on #14's render).
3374
+ *
3375
+ * These stores are private and undocumented and DO rotate (OpenCode migrated
3376
+ * from files to SQLite mid-2026). Every reader is therefore defensive: any
3377
+ * missing file, unparseable line, or shape drift returns null and the caller
3378
+ * falls back to the terminal capture. Nothing here is a hard dependency.
3379
+ *
3380
+ * Directory and recency only narrow the candidates: with several attempts in
3381
+ * one cwd the newest session is whichever task finished last. A transcript is
3382
+ * accepted only when its content carries the task's completion marker.
3383
+ */
3384
+ declare class HomeTranscriptReader implements TranscriptReader {
3385
+ private readonly home;
3386
+ constructor(opts?: {
3387
+ homeDir?: string;
3388
+ });
3389
+ finalAssistantText(query: TranscriptQuery, maxChars?: number): Promise<string | null>;
3390
+ }
3391
+
2919
3392
  /**
2920
3393
  * The ids a runner may actually run: the user's allowlist with the ids that
2921
3394
  * provably belong to a *different* runner dropped. `undefined` means no
@@ -2999,9 +3472,18 @@ declare function buildResearchToolsPrompt(): string;
2999
3472
  * never a task plan.
3000
3473
  */
3001
3474
  declare function buildSubagentSystemPrompt(): string;
3002
- declare function buildConversationSystemPrompt(goal: string, context: string, modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>, runners: RunnerId[], runnerModes?: Record<RunnerId, RunnerModeInfo[]>, autonomousDefault?: boolean, verificationEnabled?: boolean,
3003
- /** Harness planner (ADR-0009): the agent owns its own tools and research budget. */
3004
- harnessMode?: boolean): string;
3475
+ /**
3476
+ * Facts about who plans and where tasks will run, as opposed to the user's
3477
+ * mode toggles: they change what the prompt can promise, not what it asks for.
3478
+ */
3479
+ interface ConversationVariant {
3480
+ /** Harness planner (ADR-0009): the agent owns its own tools and research budget. */
3481
+ harness?: boolean;
3482
+ /** Every AI task gets its own worktree (ADR-0013), so file overlap no longer forces an order; of every repo of a group (ADR-0014). */
3483
+ isolatedExecution?: IsolatedExecution;
3484
+ }
3485
+ declare function buildConversationSystemPrompt(goal: string, context: string, modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>, runners: RunnerId[], runnerModes?: Record<RunnerId, RunnerModeInfo[]>, autonomousDefault?: boolean, verificationEnabled?: boolean, variant?: ConversationVariant): string;
3486
+ /** The one-shot planner's core rules for tasks that share the workspace root. */
3005
3487
  declare const CORE_PLANNER_PROMPT: string;
3006
3488
  declare function buildResearchPrompt(userGoal: string, context: string, modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>, runners: RunnerId[], runnerModes?: Record<RunnerId, RunnerModeInfo[]>, modes?: PlannerModes): string;
3007
3489
  declare function buildPlanWithResults(userGoal: string, context: string, researchResults: string, modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>, runners: RunnerId[], runnerModes?: Record<RunnerId, RunnerModeInfo[]>, modes?: PlannerModes): string;
@@ -3009,7 +3491,7 @@ declare function buildModifyPlanPrompt(existingPlan: LegacyPlanState, userReques
3009
3491
  declare function modelContextBlock(modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>, runners: RunnerId[], runnerModes?: Record<RunnerId, RunnerModeInfo[]>, autonomousDefault?: boolean): string;
3010
3492
  declare function executionLogBlock(executionLog: TaskSnapshot[]): string;
3011
3493
  declare function pendingEditRulesBlock(): string;
3012
- declare function buildModifyDuringExecutionPrompt(executionLog: TaskSnapshot[], pendingTasks: string, userMessage: string, modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>, runners: RunnerId[], runnerModes?: Record<RunnerId, RunnerModeInfo[]>, autonomousDefault?: boolean): string;
3494
+ declare function buildModifyDuringExecutionPrompt(executionLog: TaskSnapshot[], pendingTasks: string, userMessage: string, modelsByRunner: Partial<Record<RunnerId, DiscoveredModel[]>>, runners: RunnerId[], runnerModes?: Record<RunnerId, RunnerModeInfo[]>, modes?: Pick<PlannerModes, 'autonomousDefault' | 'isolatedExecution'>): string;
3013
3495
  /**
3014
3496
  * User-message prompt for a planner-driven merge: asks the model to combine the
3015
3497
  * selected tasks into one. Routed through the conversation loop, so the
@@ -3023,6 +3505,34 @@ declare function buildMergePrompt(taskIds: string[], tasks: Task[]): string;
3023
3505
  * the user does not hand-type the parts.
3024
3506
  */
3025
3507
  declare function buildSplitPrompt(taskId: string, tasks: Task[]): string;
3508
+ /**
3509
+ * Runner prompt for the opt-in task that resolves an integration conflict
3510
+ * (ADR-0013). The resolver's own worktree starts at the integration tip, so the
3511
+ * merge it performs is exactly the one that conflicted; the conflicted task
3512
+ * then lands through that merge. Ordewell never resolves a conflict itself.
3513
+ *
3514
+ * In a repo group (ADR-0014) the conflict in one repo rolled the task back in
3515
+ * all of them, so the resolver merges the branch in every repo the task
3516
+ * changed, not only the one that conflicted.
3517
+ */
3518
+ declare function buildConflictResolutionPrompt(task: Task, conflict: {
3519
+ branch: string;
3520
+ repos: string[];
3521
+ conflictRepo?: string;
3522
+ }, integrationBranch: string): string;
3523
+ /**
3524
+ * Runner prompt for a conflict repair (ADR-0015): a new attempt of the
3525
+ * conflicted task itself, in its kept worktree, so the merge runs the other
3526
+ * way round from {@link buildConflictResolutionPrompt} — the integration tip
3527
+ * into the task's branch. Whether it worked is decided by the evidence checks
3528
+ * and the landing that follow, never by the agent's word.
3529
+ */
3530
+ declare function buildConflictRepairPrompt(task: Task, conflict: {
3531
+ branch: string;
3532
+ repos: string[];
3533
+ conflictRepo?: string;
3534
+ conflictFiles?: string[];
3535
+ }, integrationBranch: string): string;
3026
3536
 
3027
3537
  /**
3028
3538
  * The one owner of "the model emitted something unusable — correct it and
@@ -3677,4 +4187,4 @@ declare class PlannerModelMemory {
3677
4187
  recall(provider: string, catalog: PlannerModelCandidate[]): PlannerModelRecall;
3678
4188
  }
3679
4189
 
3680
- export { ALLOWED_PLUGIN_HOSTS, ALL_PROVIDERS, AUTO_COMMANDS, AbstractRunner, AbstractTerminalSession, ActiveTaskSession, type AgentAdapter, type AgentAdapterFactory, type AgentEvent, type AgentProcessDeps, type AgentStartOptions, AiProvider, ApprovalMode, ApprovalRequest, BUILTIN_SKILL_NAMES, BaseAiService, BaseConfig, BaseFileSystem, CLAUDE_CODE_MANIFEST, CLI_PROVIDERS, CMD_EXE_MAX_COMMAND_LINE, CORE_PLANNER_PROMPT, type CappedRows, type CheckpointListener, ClaudeCodeAdapter, CliAgentAiService, type CliAgentAiServiceDeps, CodexAdapter, type CommandClassification, CommandLineTooLongError, type CommandTier, type ComposeOptions, ConsoleLogger, ContextCollector, ConversationMessage, type ConversationRequest, type ConversationTurn, DAEMON_SUBPROTOCOL, DAEMON_TOKEN_SUBPROTOCOL_PREFIX, DiscoveredModel, EmbeddedNewlineError, type EnvAdmission, EnvConfig, type ExecFileFn, type ExecImpl, ExecutableNotFoundError, FindSymbolOptions, FsPluginStore, GIT_READONLY_SUBCOMMANDS, GeminiService, GlobOptions, type GrepInvocation, GrepOptions, type HasBinFn, HeadlessRunner, type HeadlessRunnerDeps, HeadlessSession, type IAiService, IApproval, IConfig, IFileSystem, type ILogger, type INotification, IPluginStore, ITerminalRunner, ITerminalSession, JSON_REPAIR_INSTRUCTION, type KillTreeDeps, type LaunchDeps, type LaunchPlan, LegacyPlanState, LineBuffer, type MappedTool, ModelResolver, type ModelResolverDeps, type ModifyPlanRequest, type NotificationAction, OPENCODE_MANIFEST, ORDEWELL_SETTABLE_ENV, OpenAiService, OpenCodeAdapter, type OrchestratorObserver, OrchestratorOption, PLUGIN_NAME_PATTERN, PROVIDER_CREDENTIAL_ENV, PROVIDER_DETECT_PRIORITY, PROVIDER_LABEL, PROVIDER_PRIORITY, PROVIDER_SHORT_LABEL, type PendingApproval, PendingApprovals, type PendingApprovalsOptions, PlanEditError, PlanParseError, type PlanRequest, PlanState, PlanStatus, PlanStore, Planner, type PlannerModelCandidate, type PlannerModelChoice, PlannerModelMemory, type PlannerModelRecall, type PlannerModelStore, type PlannerReplyClassification, type PlannerRuntimeToggles, type PluginSource, type PrdBlock, type PreparedLaunch, type PriorOutput, type ProbeFn, ProviderModelLists, type ProviderRegistration, type PtySize, type PtyWrapOptions, QueuedMessage, REFUSED_COMMANDS, ReadFileOpts, type RepairLoopOpts, type RepairVerdict, type ResearchChat, ResearchLogEntry, ResearchProgress, type ResearchShell, type ResearchShellDeps, ResearchToolType, type ResearchTurn, ResolveContext, type RunnerCatalog, RunnerId, RunnerInstallation, RunnerInvocation, type RunnerMode, RunnerModeInfo, RunnerPluginManifest, RunnerRegistry, type RunnerSpawnOptions, SETTINGS_ENV_ALLOWLIST, SETTINGS_ENV_REFUSED, STATE_DIR, STOPPED_TOOL_RESULT, SYMBOL_LANGUAGES, Session, SessionBroadcaster, type SessionData, type SessionDeps, type SessionMeta, type SessionPlanner, type SessionRuntimeSettings, SettingsService, type ShellDialect, type SkillInfo, type SkillMetadata, SkillsService, type SpawnSpec, StdioAgentAdapter, TASK_QUERY_ANSWER_OR_OPS, TASK_QUERY_FIELDS, TASK_QUERY_PROTOCOL, TASK_QUERY_REMINDER, TRUNCATED_PLAN_REPAIR_INSTRUCTION, Task, TaskOp, TaskOrchestrator, type TaskQuery, type TaskQueryCatalog, type TaskQueryField, TaskSnapshot, TmuxRunner, type TmuxRunnerDeps, type TokenCarriers, type ToolCall, ToolOutcome, type ToolResult, type UserSettings, Verdict, VerdictEngine, type VerdictListener, WINDOWS_MAX_COMMAND_LINE, type WorkspaceCheckDeps, WorkspaceNotAProjectError, WorkspaceNotFoundError, type WorkspaceProjectCheckDeps, admitSettingsEnv, applyHeadLimit, assertInstallablePluginUrl, assertPlainPluginName, assertWorkspaceExists, assertWorkspaceIsProject, augmentPromptWithPriorOutputs, augmentedPath, bearerHeaderValue, buildConversationSystemPrompt, buildFallbackGrepArgs, buildGlobArgs, buildGrepArgs, buildMergePrompt, buildModifyDuringExecutionPrompt, buildModifyPlanPrompt, buildPlanWithResults, buildResearchPrompt, buildResearchToolsPrompt, buildRunnerInvocation, buildShellInvocation, buildSplitPrompt, buildSubagentSystemPrompt, clampThinkingEffort, classifyCommand, classifyPlannerReply, classifyPluginSource, clearAugmentedPathCache, clearDaemonToken, clearResearchShellCache, clearState, clipboardCopyCommand, coerceAssignments, collectDirectDependencyOutputs, composeAugmentedPrompt, configuredProviders, createAiService, createSkillsService, daemonTokenPath, defaultLogger, definitionPattern, deleteSession, discoverGeminiModels, effectiveAllowlist, ensureDir, ensureStateDirIgnored, executionLogBlock, extractPrdBlock, extractPresentedToken, filterFallbackByAnchoredInclude, filterModelsForPrompt, formatSearchOutput, generatePlanWithRepair, getLatestSession, getProviderMeta, getSettingsPath, getStateDir, globalDataDir, grantScopeFor, hasTmux, includeGlobFor, isCliProvider, isExecutableResolved, isOpenAiProvider, isPlainPluginName, isValidManifest, killTree, languageForId, listSessions, loadSession, loadSessionPlanState, loadState, mapAgentTool, migrateOldConfigDir, mintDaemonToken, mintSessionId, modelContextBlock, modifyValidationFeedback, normalizeAgentArgs, normalizeGeminiModel, parseTaskQueryJson, pendingEditRulesBlock, planDirectLaunch, planShellLaunch, posixShellQuote, prefixModelId, providerForRunner, reEmitPlanPrompt, reEmitTaskOpsPrompt, reEmitTaskQueryPrompt, readDaemonToken, referencePattern, renderPlanMap, renderPriorOutputs, renderTaskQueryAnswer, repairLoop, researchShellWarning, researchToolsPath, resolveArgs, resolvePluginInstallDir, resolveProviderFromPrefix, resolveResearchShell, resolveSkillInvocation, resolveWithin, retargetTaskRunner, runnerAssignment, runnerForProvider, sanitizeSlug, savePrdMarkdown, saveSession, saveState, sessionRuntimeSettings, stateExists, stripAnsi, stripModelPrefix, summarizeOutput, taskOpsRejectedPrompt, taskQuerySignature, textHasTaskQuery, tmuxSessionName, tmuxSocketName, tmuxWindowName, tokenSubprotocols, tokensMatch, truncatedPlanReEmitPrompt, wellKnownBinDirs, windowsCommandLine, withPath, wrapWithPty };
4190
+ export { ALLOWED_PLUGIN_HOSTS, ALL_PROVIDERS, AUTO_COMMANDS, AbstractRunner, AbstractTerminalSession, ActiveTaskSession, type AgentAdapter, type AgentAdapterFactory, type AgentEvent, type AgentProcessDeps, type AgentStartOptions, AiProvider, ApprovalMode, ApprovalRequest, BUILTIN_SKILL_NAMES, BaseAiService, BaseConfig, BaseFileSystem, BufferedTaskOutputSource, CLAUDE_CODE_MANIFEST, CLI_PROVIDERS, CMD_EXE_MAX_COMMAND_LINE, CORE_PLANNER_PROMPT, type CappedRows, type CheckpointListener, ClaudeCodeAdapter, CliAgentAiService, type CliAgentAiServiceDeps, CodexAdapter, type CommandClassification, CommandLineTooLongError, type CommandTier, type ComposeOptions, ConsoleLogger, ContextCollector, ConversationBusyError, type ConversationCompaction, ConversationEditError, type ConversationFork, ConversationMessage, type ConversationRequest, type ConversationRewind, type ConversationTurn, type ConversationVariant, DAEMON_SUBPROTOCOL, DAEMON_TOKEN_SUBPROTOCOL_PREFIX, DiscoveredModel, EmbeddedNewlineError, type EnvAdmission, EnvConfig, type ExecFileFn, type ExecImpl, ExecutableNotFoundError, FindSymbolOptions, FsPluginStore, GIT_READONLY_SUBCOMMANDS, GeminiService, type GitExecFn, GlobOptions, type GrepInvocation, GrepOptions, type HasBinFn, HeadlessRunner, type HeadlessRunnerDeps, HeadlessSession, HomeTranscriptReader, type IAiService, IApproval, IConfig, IFileSystem, type ILogger, type INotification, IPluginStore, ITerminalRunner, ITerminalSession, IWorktreeIsolation, IsolationHandoff, IsolationLandedTask, IsolationMergeResult, IsolationView, JSON_REPAIR_INSTRUCTION, type KillTreeDeps, type LaunchDeps, type LaunchPlan, LegacyPlanState, LineBuffer, type LiveOutputLookup, type LiveTail, type LiveTailOptions, type MappedTool, ModelResolver, type ModelResolverDeps, type ModifyPlanRequest, type NotificationAction, OPENCODE_MANIFEST, ORDEWELL_SETTABLE_ENV, OUTPUT_LINES_DEFAULT, OUTPUT_LINES_MAX, OpenAiService, OpenCodeAdapter, type OrchestratorObserver, OrchestratorOption, PLUGIN_NAME_PATTERN, PROVIDER_CREDENTIAL_ENV, PROVIDER_DETECT_PRIORITY, PROVIDER_LABEL, PROVIDER_PRIORITY, PROVIDER_SHORT_LABEL, type PendingApproval, PendingApprovals, type PendingApprovalsOptions, PlanEditError, PlanIsolation, PlanParseError, type PlanRequest, PlanState, PlanStatus, PlanStore, Planner, type PlannerModelCandidate, type PlannerModelChoice, PlannerModelMemory, type PlannerModelRecall, type PlannerModelStore, type PlannerReplyClassification, type PlannerRuntimeToggles, type PluginSource, type PrdBlock, type PreparedLaunch, type PriorOutput, type ProbeFn, ProviderModelLists, type ProviderRegistration, type PtySize, type PtyWrapOptions, QueuedMessage, REFUSED_COMMANDS, ReadFileOpts, type RepairLoopOpts, type RepairVerdict, RepoGroupLayout, type ResearchChat, ResearchLogEntry, ResearchProgress, type ResearchShell, type ResearchShellDeps, ResearchToolType, type ResearchTurn, ResolveContext, type RewindTarget, type RunnerCatalog, RunnerId, RunnerInstallation, RunnerInvocation, type RunnerMode, RunnerModeInfo, RunnerPluginManifest, RunnerRegistry, type RunnerSpawnOptions, SETTINGS_ENV_ALLOWLIST, SETTINGS_ENV_REFUSED, STATE_DIR, STOPPED_TOOL_RESULT, SYMBOL_LANGUAGES, Session, SessionBroadcaster, type SessionData, type SessionDeps, type SessionMeta, SessionNotice, type SessionPlanner, type SessionRuntimeSettings, SettingsService, type ShellDialect, type SkillInfo, type SkillMetadata, SkillsService, type SpawnSpec, StdioAgentAdapter, TASK_QUERY_ANSWER_MAX_CHARS, TASK_QUERY_ANSWER_OR_OPS, TASK_QUERY_FIELDS, TASK_QUERY_PROTOCOL, TASK_QUERY_REMINDER, TRUNCATED_PLAN_REPAIR_INSTRUCTION, Task, type TaskAttemptSnapshot, TaskIsolation, TaskOp, TaskOrchestrator, type TaskOutputAttempt, type TaskOutputSource, type TaskQuery, type TaskQueryCatalog, type TaskQueryField, TaskSnapshot, TmuxRunner, type TmuxRunnerDeps, type TokenCarriers, type ToolCall, ToolOutcome, type ToolResult, type TranscriptQuery, type TranscriptReader, type UserSettings, Verdict, VerdictEngine, type VerdictListener, WINDOWS_MAX_COMMAND_LINE, type WorkspaceCheckDeps, WorkspaceNotAProjectError, WorkspaceNotFoundError, type WorkspaceProjectCheckDeps, type WorktreeIsolationDeps, admitSettingsEnv, applyHeadLimit, assertInstallablePluginUrl, assertPlainPluginName, assertWorkspaceExists, assertWorkspaceIsProject, augmentPromptWithPriorOutputs, augmentedPath, bearerHeaderValue, buildConflictRepairPrompt, buildConflictResolutionPrompt, buildConversationSystemPrompt, buildFallbackGrepArgs, buildGlobArgs, buildGrepArgs, buildMergePrompt, buildModifyDuringExecutionPrompt, buildModifyPlanPrompt, buildPlanWithResults, buildResearchPrompt, buildResearchToolsPrompt, buildRunnerInvocation, buildShellInvocation, buildSplitPrompt, buildSubagentSystemPrompt, clampThinkingEffort, classifyCommand, classifyPlannerReply, classifyPluginSource, clearAugmentedPathCache, clearDaemonToken, clearResearchShellCache, clearState, clipboardCopyCommand, coerceAssignments, collectDirectDependencyOutputs, composeAugmentedPrompt, configuredProviders, createAiService, createSkillsService, createWorktreeIsolation, daemonTokenPath, defaultLogger, definitionPattern, deleteSession, describeMergeResult, discoverGeminiModels, effectiveAllowlist, ensureDir, ensureStateDirIgnored, executionLogBlock, extractPrdBlock, extractPresentedToken, filterFallbackByAnchoredInclude, filterModelsForPrompt, formatSearchOutput, generatePlanWithRepair, getLatestSession, getProviderMeta, getSettingsPath, getStateDir, globalDataDir, grantScopeFor, hasTmux, includeGlobFor, isCliProvider, isExecutableResolved, isOpenAiProvider, isPlainPluginName, isValidManifest, killTree, languageForId, listSessions, loadSession, loadSessionPlanState, loadState, mapAgentTool, migrateOldConfigDir, mintDaemonToken, mintSessionId, modelContextBlock, modifyValidationFeedback, normalizeAgentArgs, normalizeGeminiModel, parseTaskQueryJson, pendingEditRulesBlock, planDirectLaunch, planShellLaunch, posixShellQuote, prefixModelId, providerForRunner, reEmitPlanPrompt, reEmitTaskOpsPrompt, reEmitTaskQueryPrompt, readDaemonToken, referencePattern, renderPlanMap, renderPriorOutputs, renderTaskQueryAnswer, repairLoop, researchShellWarning, researchToolsPath, resolveArgs, resolvePluginInstallDir, resolveProviderFromPrefix, resolveResearchShell, resolveSkillInvocation, resolveWithin, retargetTaskRunner, runnerAssignment, runnerForProvider, sanitizeSlug, savePrdMarkdown, saveSession, saveState, sessionRuntimeSettings, stateExists, stripAnsi, stripModelPrefix, summarizeOutput, taskOpsRejectedPrompt, taskQuerySignature, textHasTaskQuery, tmuxSessionName, tmuxSocketName, tmuxWindowName, tokenSubprotocols, tokensMatch, truncatedPlanReEmitPrompt, wellKnownBinDirs, windowsCommandLine, withPath, wrapWithPty };