@ordewell/core 0.9.1 → 0.10.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.
Files changed (63) hide show
  1. package/dist/{IFileSystem-BjiyCQ8O.d.ts → IFileSystem-BCJBHFwB.d.ts} +1 -1
  2. package/dist/{IFileSystem-Cy-TAWvu.d.mts → IFileSystem-Bj6fy1cG.d.mts} +1 -1
  3. package/dist/{IRunner-Corods20.d.ts → IRunner-C7_SSpzG.d.ts} +228 -13
  4. package/dist/{IRunner-D6YfbmHn.d.mts → IRunner-hWAJC4hg.d.mts} +228 -13
  5. package/dist/ModeResolver-m1d8Cb-j.d.mts +35 -0
  6. package/dist/ModeResolver-u5ZhRC8x.d.ts +35 -0
  7. package/dist/{Task-1Q19y7sZ.d.mts → Task-CxwnCJLi.d.mts} +346 -127
  8. package/dist/{Task-1Q19y7sZ.d.ts → Task-CxwnCJLi.d.ts} +346 -127
  9. package/dist/{chunk-UUU46PVQ.mjs → chunk-2IIRSBEQ.mjs} +109 -142
  10. package/dist/chunk-2IIRSBEQ.mjs.map +1 -0
  11. package/dist/{chunk-OOZWSUIE.mjs → chunk-CH5IGWFS.mjs} +545 -966
  12. package/dist/chunk-CH5IGWFS.mjs.map +1 -0
  13. package/dist/chunk-DJAPDO6E.mjs +1358 -0
  14. package/dist/chunk-DJAPDO6E.mjs.map +1 -0
  15. package/dist/chunk-DNFT4SQG.mjs +97 -0
  16. package/dist/chunk-DNFT4SQG.mjs.map +1 -0
  17. package/dist/index.d.mts +3107 -3988
  18. package/dist/index.d.ts +3107 -3988
  19. package/dist/index.js +21576 -17642
  20. package/dist/index.js.map +1 -1
  21. package/dist/index.mjs +19222 -15561
  22. package/dist/index.mjs.map +1 -1
  23. package/dist/parsing.d.mts +55 -3
  24. package/dist/parsing.d.ts +55 -3
  25. package/dist/parsing.js +311 -124
  26. package/dist/parsing.js.map +1 -1
  27. package/dist/parsing.mjs +86 -6
  28. package/dist/parsing.mjs.map +1 -1
  29. package/dist/plan-utils-B6yJdpgi.d.ts +2902 -0
  30. package/dist/plan-utils-CKXdD1AD.d.mts +2902 -0
  31. package/dist/plan-utils.d.mts +4 -5
  32. package/dist/plan-utils.d.ts +4 -5
  33. package/dist/plan-utils.js +471 -86
  34. package/dist/plan-utils.js.map +1 -1
  35. package/dist/plan-utils.mjs +68 -19
  36. package/dist/testing.d.mts +22 -4
  37. package/dist/testing.d.ts +22 -4
  38. package/dist/testing.js +45 -9
  39. package/dist/testing.js.map +1 -1
  40. package/dist/testing.mjs +46 -11
  41. package/dist/testing.mjs.map +1 -1
  42. package/package.json +2 -10
  43. package/skills/tdd/SKILL.md +0 -1
  44. package/dist/ModeResolver-DE-o2lRF.d.mts +0 -48
  45. package/dist/ModeResolver-EWlpmVAy.d.ts +0 -48
  46. package/dist/chunk-2M4X3VB7.mjs +0 -432
  47. package/dist/chunk-2M4X3VB7.mjs.map +0 -1
  48. package/dist/chunk-H5O74L77.mjs +0 -185
  49. package/dist/chunk-H5O74L77.mjs.map +0 -1
  50. package/dist/chunk-OOZWSUIE.mjs.map +0 -1
  51. package/dist/chunk-UUU46PVQ.mjs.map +0 -1
  52. package/dist/chunk-V3JHS7AX.mjs +0 -27
  53. package/dist/chunk-V3JHS7AX.mjs.map +0 -1
  54. package/dist/order-labels.d.mts +0 -30
  55. package/dist/order-labels.d.ts +0 -30
  56. package/dist/order-labels.js +0 -54
  57. package/dist/order-labels.js.map +0 -1
  58. package/dist/order-labels.mjs +0 -13
  59. package/dist/order-labels.mjs.map +0 -1
  60. package/dist/parsing-CZdp2p_n.d.ts +0 -154
  61. package/dist/parsing-GgUJoYKs.d.mts +0 -154
  62. package/dist/plan-utils-BmUp_Lko.d.mts +0 -1222
  63. package/dist/plan-utils-tWfH48YX.d.ts +0 -1222
@@ -1,3 +1,15 @@
1
+ interface TaskDiffRead {
2
+ repo?: string;
3
+ path?: string;
4
+ }
5
+ type TaskDiffResult = {
6
+ available: true;
7
+ text: string;
8
+ } | {
9
+ available: false;
10
+ reason: string;
11
+ };
12
+
1
13
  /**
2
14
  * Why isolated execution is unavailable for a workspace. The orchestrator needs
3
15
  * the reason, not just a boolean: `dirty` is offered a stash or an explicit
@@ -45,6 +57,10 @@ type IsolationOutcome = 'merged' | 'conflict' | 'failed';
45
57
  type IsolationTaskStatus = 'active' | 'kept' | 'conflict' | 'repairing' | 'failed' | 'merged';
46
58
  /** One repo's share of a task: its worktree inside the task workspace. */
47
59
  interface IsolationTaskRepo {
60
+ /** Integration tip when this task started; absent in older saved runs. */
61
+ baseRef?: string;
62
+ /** Task branch tip before integration removes it; excludes concurrent landings. */
63
+ taskTip?: string;
48
64
  /** Absolute path of this repo's worktree: the task workspace joined with the repo's path. */
49
65
  worktree: string;
50
66
  /**
@@ -79,6 +95,8 @@ interface IsolationTaskRecord {
79
95
  status: IsolationTaskStatus;
80
96
  /** Keyed by repo path. */
81
97
  repos: Record<string, IsolationTaskRepo>;
98
+ /** Unrecovered branches from a conflict fallback, so a later continue cannot forget them. */
99
+ continuationWork?: PreservedWork[];
82
100
  /** The repo whose merge stopped the task from landing, while `status` is `conflict` or `failed`. */
83
101
  conflictRepo?: string;
84
102
  /**
@@ -226,6 +244,12 @@ interface IsolationHandoff {
226
244
  repos: IsolationHandoffRepo[];
227
245
  /** Tasks that landed on the integration branches, in plan order. */
228
246
  landed: IsolationLandedTask[];
247
+ /**
248
+ * The run's end is an Act supervisor's to handle first (ADR-0029), so a
249
+ * surface shows the handoff without popping it up. Sent again without this
250
+ * once the supervisor's turn on it ends with the run still unmerged.
251
+ */
252
+ deferredTo?: 'supervisor';
229
253
  }
230
254
  /** A plan's isolation as a surface shows it: a mark for each task the run touched, and its handoff. */
231
255
  interface IsolationView {
@@ -288,6 +312,11 @@ type RepairEvidence = {
288
312
  repo: string;
289
313
  files?: string[];
290
314
  };
315
+ interface SetupFailure {
316
+ /** Relative to the task workspace; `.` for a lone repository. */
317
+ repo: string;
318
+ detail: string;
319
+ }
291
320
  interface PreparedTask {
292
321
  cwd: string;
293
322
  branch: string;
@@ -297,8 +326,11 @@ interface PreparedTask {
297
326
  * stay in the task, so the user is told.
298
327
  */
299
328
  copied: string[];
329
+ /** Repos whose setup command failed, so they got the default links instead; absent when none did. */
330
+ setupFailed?: SetupFailure[];
300
331
  /** What the attempt this one replaces left unlanded, kept on a branch before its worktree went; absent when nothing was. */
301
332
  preserved?: PreservedWork[];
333
+ continuation?: 'restored' | 'fallback';
302
334
  }
303
335
  /** A task as a removal names it. */
304
336
  type IsolationTaskRef = Pick<IsolationTaskRecord, 'taskId' | 'order' | 'title'>;
@@ -368,11 +400,11 @@ interface IWorktreeIsolation {
368
400
  /**
369
401
  * Create the task workspace — one worktree per isolated repo from its
370
402
  * integration tip, the shared paths linked in — and return the cwd to spawn
371
- * the Runner into. A second `prepare` for the same task is a retry: the old
372
- * attempt is discarded and the workspace recreated from the tips, so the
373
- * task sees everything its predecessors have integrated.
403
+ * the Runner into. Fresh attempts start clean from the tips. A continuation
404
+ * restores the previous attempt's preserved work on top of them, falling
405
+ * back to the tips in every repo when any restoration conflicts (ADR-0018).
374
406
  */
375
- prepare(task: Task, run: IsolationRun): Promise<PreparedTask>;
407
+ prepare(task: Task, run: IsolationRun, intent?: 'fresh' | 'continuation'): Promise<PreparedTask>;
376
408
  /**
377
409
  * Hand a conflicted task's kept workspace to a conflict repair (ADR-0015)
378
410
  * as it is — nothing is re-cut — and return the same cwd. Records each
@@ -433,6 +465,7 @@ interface IWorktreeIsolation {
433
465
  pruneOrphans(run: IsolationRun): Promise<IsolationPruneResult>;
434
466
  /** Unified diff of each repo's integration branch against its base ref. */
435
467
  reviewDiff(run: IsolationRun): Promise<string>;
468
+ taskDiff?(run: IsolationRun, taskId: string, options: TaskDiffRead): Promise<TaskDiffResult>;
436
469
  /**
437
470
  * Mark the landed tasks whose work the checked-out HEAD now contains in
438
471
  * every repo they changed (`git merge-base --is-ancestor`), and return their
@@ -495,6 +528,8 @@ interface UsageRecord {
495
528
  /** The provider or runner id that reported the call — `openai`, `claude-code`, … */
496
529
  source: string;
497
530
  model?: string;
531
+ /** A session breakdown can name a model without identifying the current context. */
532
+ aggregate?: true;
498
533
  inputTokens?: number;
499
534
  outputTokens?: number;
500
535
  /** The share of `inputTokens` served from the provider's prompt cache. */
@@ -547,6 +582,9 @@ declare function addUsage(totals: UsageTotals, record: UsageRecord): UsageTotals
547
582
  interface PlannerUsage {
548
583
  totals: UsageTotals;
549
584
  bySubagent?: Record<string, UsageTotals>;
585
+ byModel?: ModelUsage[];
586
+ source?: string;
587
+ model?: string;
550
588
  lastPromptTokens?: number;
551
589
  contextWindow?: number;
552
590
  }
@@ -555,6 +593,8 @@ declare function addPlannerUsage(usage: PlannerUsage, record: UsageRecord): Plan
555
593
  declare function isMeasured(totals: UsageTotals): boolean;
556
594
  /** What the token line shows of a ledger — live from its broadcast, or reloaded from the saved one. */
557
595
  interface UsageLine {
596
+ byModel?: ModelUsage[];
597
+ model?: string;
558
598
  totals: UsageTotals;
559
599
  bySubagent?: Record<string, UsageTotals>;
560
600
  contextFill?: {
@@ -574,6 +614,81 @@ declare function plannerContextFill(usage: PlannerUsage): {
574
614
  usedTokens: number;
575
615
  windowTokens: number;
576
616
  } | undefined;
617
+ interface ModelUsage {
618
+ source: string;
619
+ model?: string;
620
+ totals: UsageTotals;
621
+ }
622
+ declare function addModelUsage(models: readonly ModelUsage[], record: UsageRecord): ModelUsage[];
623
+ interface AttemptUsage extends PlannerUsage {
624
+ attempt: number;
625
+ runner: string;
626
+ startedAt: string;
627
+ endedAt?: string;
628
+ wallTimeMs: number;
629
+ }
630
+ declare function startAttemptUsage(attempt: number, runner: string, startedAt: string): AttemptUsage;
631
+ declare function addAttemptUsage(usage: AttemptUsage, record: UsageRecord, now: string): AttemptUsage;
632
+ declare function endAttemptUsage(usage: AttemptUsage, now: string): AttemptUsage;
633
+ interface PlanUsage {
634
+ totals: UsageTotals;
635
+ byModel: ModelUsage[];
636
+ wallTimeMs: number;
637
+ attempts: number;
638
+ }
639
+ declare function addUsageTotals(totals: UsageTotals, addition: UsageTotals): UsageTotals;
640
+ interface UsageTask {
641
+ attemptUsage?: readonly AttemptUsage[];
642
+ subtasks?: readonly UsageTask[];
643
+ }
644
+ declare function planUsage(tasks: readonly UsageTask[]): PlanUsage;
645
+
646
+ /**
647
+ * How far a plan's supervisor may act in its wake-up turns (ADR-0029): a plan
648
+ * setting, saved on the run as it starts. Off: it never wakes. Watch: it
649
+ * wakes, reads and suggests. Act: Watch, and acting within its loop guards
650
+ * without asking.
651
+ */
652
+ type SupervisorLevel = 'off' | 'watch' | 'act';
653
+ declare function isSupervisorLevel(value: unknown): value is SupervisorLevel;
654
+ /**
655
+ * Who asked the command seam for an action (ADR-0029): the user, a planner
656
+ * turn the user started, or the supervisor at its level.
657
+ */
658
+ type ExecutionActor = {
659
+ kind: 'user';
660
+ } | {
661
+ kind: 'planner-turn';
662
+ } | {
663
+ kind: 'supervisor';
664
+ level: SupervisorLevel;
665
+ }
666
+ /** The user's standing instruction to start each plan the planner submits (ADR-0030). */
667
+ | {
668
+ kind: 'autorun';
669
+ };
670
+ type ExecutionCommandName = 'run_plan' | 'run_task' | 'stop_task' | 'stop_run' | 'retry_task' | 'message_task' | 'answer_approval' | 'merge_all' | 'skip_task';
671
+ /**
672
+ * One call at the command seam as the timeline keeps it: what was asked, by
673
+ * whom, about which task, and how it ended — done, refused by the seam, or
674
+ * declined by the user it asked.
675
+ */
676
+ interface ExecutionRecord {
677
+ command: ExecutionCommandName;
678
+ actor: ExecutionActor['kind'];
679
+ /** Present when the supervisor asked. */
680
+ level?: SupervisorLevel;
681
+ /** `ref` is how the plan numbers it: "#4", or "#4.1" for a subtask. */
682
+ task?: {
683
+ id: string;
684
+ ref: string;
685
+ title: string;
686
+ };
687
+ outcome: 'done' | 'refused' | 'declined';
688
+ /** The refusal, the message sent, or the note a denial carried. */
689
+ detail?: string;
690
+ at: string;
691
+ }
577
692
 
578
693
  declare const BUILTIN_SKILL_NAMES: readonly ["grilling", "to-spec", "improve-codebase-architecture", "tdd"];
579
694
  interface SkillMetadata {
@@ -665,6 +780,109 @@ declare class SkillsService {
665
780
  */
666
781
  declare function createSkillsService(workspaceRoot?: string, workspaceRepos?: readonly string[]): SkillsService;
667
782
 
783
+ /**
784
+ * The loop guards of an Act supervisor (ADR-0029): pure checks that stop it
785
+ * spinning. Each answers with the trip — the note the model is refused with,
786
+ * and the message the user is told — or null to let the action through. The
787
+ * session keeps what they remember of the run and calls them where the action
788
+ * executes: the command seam for retries, the edit path for edits, the
789
+ * supervisor for its wake-ups.
790
+ */
791
+ /** Retries an Act supervisor may make of one task in a run when the plan sets none. */
792
+ declare const DEFAULT_SUPERVISOR_RETRY_LIMIT = 2;
793
+ /** A guard that tripped. */
794
+ interface GuardTrip {
795
+ /** The guard and what it caught, so the user is told of one trip once however often the model repeats the call. */
796
+ key: string;
797
+ /** The note the model is refused with: the guard, and what would be accepted. */
798
+ refusal: string;
799
+ /** What the user is told, as the supervisor's message. */
800
+ escalation: string;
801
+ }
802
+ /** A task as the command seam located it: the task, and how the plan numbers it. */
803
+ interface GuardTarget {
804
+ task: Readonly<Task>;
805
+ ref: string;
806
+ }
807
+ /** What an attempt was told and who ran it: a retry after a failure has to change one of them. */
808
+ interface AttemptShape {
809
+ prompt: string;
810
+ skills: readonly string[];
811
+ runner: string;
812
+ model: string | null;
813
+ effort: string | null;
814
+ }
815
+ /**
816
+ * What the loop guards remember as plain data, saved on the plan so a daemon
817
+ * restart does not hand an Act supervisor a fresh retry budget or forget the
818
+ * tasks it removed (ADR-0029). Maps become records and the reported-trip set an
819
+ * array, so it round-trips through JSON.
820
+ */
821
+ interface SupervisionMemorySnapshot {
822
+ /** Retries of one task this run, by task id. */
823
+ retries: Record<string, number>;
824
+ /** Skips of a task the supervisor had retried, by task id: each counts against the retry limit. Absent on saves before skip. */
825
+ skips?: Record<string, number>;
826
+ /** What each failed task's attempt ran with, by task id. */
827
+ failedWith: Record<string, AttemptShape>;
828
+ /** The supervisor's own edits this run. */
829
+ edits: EditMemory;
830
+ /** The keys of the guard trips the user was already told of. */
831
+ told: string[];
832
+ }
833
+ /** What the supervisor's own edits did this run: the tasks it removed, and each field it changed. */
834
+ interface EditMemory {
835
+ removed: readonly {
836
+ title: string;
837
+ prompt: string;
838
+ }[];
839
+ changed: readonly {
840
+ taskId: string;
841
+ field: string;
842
+ from: string;
843
+ }[];
844
+ }
845
+
846
+ /**
847
+ * When the supervisor wakes during a run, and what it is told (#27). Only an
848
+ * attention event wakes it; passes ride along as context. It keeps no clock:
849
+ * the host stamps each event and polls on its own tick.
850
+ */
851
+ type RunEventKind = 'task_passed' | 'task_failed' | 'waiting_input' | 'waiting_approval' | 'task_idle' | 'landing_conflict' | 'usage_limit' | 'auto_merge_stopped' | 'run_finished';
852
+ type RunEvent = {
853
+ kind: RunEventKind;
854
+ taskId?: string;
855
+ /** Epoch ms, on the same clock the host passes to `poll`. */
856
+ at: number;
857
+ detail?: string;
858
+ /** `usage_limit` only: the runner whose limit paused the task. */
859
+ runner?: string;
860
+ /** `usage_limit` only: when its tasks resume on their own (ISO time); null when they wait for a manual retry. */
861
+ resumeAt?: string | null;
862
+ /** `usage_limit` in a batch: every task the runner's limit paused in it, in arrival order. */
863
+ taskIds?: string[];
864
+ };
865
+ /** What the policy holds before its next wake-up, for the plan (ADR-0029). */
866
+ interface WakePolicySnapshot {
867
+ /** Attention events inside the debounce window, in arrival order. */
868
+ attention: RunEvent[];
869
+ /** The passes since the previous wake-up. */
870
+ sinceLast: RunEvent[];
871
+ }
872
+
873
+ /**
874
+ * What the supervisor gathered but has not delivered, saved on the plan so a
875
+ * daemon restart still delivers a batch that was inside its debounce window
876
+ * (ADR-0029). Undelivered batches already wait as `pendingTurns`; this is only
877
+ * the state the policy and the wake-up rate keep before a batch exists.
878
+ */
879
+ interface SupervisorSnapshot {
880
+ /** The events inside the debounce window and the passes since the last wake-up. */
881
+ policy: WakePolicySnapshot;
882
+ /** When each wake-up since the last pass was delivered, for the wake-up rate guard. */
883
+ wakeUps: number[];
884
+ }
885
+
668
886
  interface UserStep {
669
887
  order: number;
670
888
  instruction: string;
@@ -687,19 +905,27 @@ interface Verdict {
687
905
  }
688
906
  interface TaskOutputSummary {
689
907
  reviewReason: string;
908
+ /** The `task_complete` summary, the task's report; absent when the attempt ended without one, and from sessions saved before it was kept. */
909
+ report?: string;
910
+ /** Empty when there is a report: the turn's final text is the report itself. */
690
911
  logTail: string;
691
912
  capturedAt: string;
692
913
  }
693
914
  type TaskType = 'ai' | 'user';
694
- type TaskStatus = 'pending' | 'approved' | 'in_progress' | 'completed' | 'failed' | 'blocked' | 'awaiting_user';
915
+ /**
916
+ * `skipped` is terminal and verdict-less: the task will not be waited for, and
917
+ * nothing it did lands. Its dependents go ahead without it.
918
+ */
919
+ type TaskStatus = 'pending' | 'approved' | 'in_progress' | 'completed' | 'failed' | 'blocked' | 'awaiting_user' | 'skipped';
695
920
  type TaskMode = string;
696
921
  /**
697
922
  * Why an `awaiting_user` task waits (ADR-0018, W1): a structured turn that
698
923
  * ended without a `task_complete` call, a checkpoint question, work that did not
699
- * land, or an ops task that changed tracked files (ADR-0020). Saved, so no
700
- * surface has to guess it from whether an attempt is live.
924
+ * land, an ops task that changed tracked files (ADR-0020), or its runner's
925
+ * usage limit. Saved, so no surface has to guess it from whether an attempt
926
+ * is live.
701
927
  */
702
- type AwaitingReason = 'input' | 'checkpoint' | 'conflict' | 'files-changed';
928
+ type AwaitingReason = 'input' | 'checkpoint' | 'conflict' | 'files-changed' | 'usage-limit';
703
929
  declare function isAwaitingReason(value: unknown): value is AwaitingReason;
704
930
  interface TaskModelAssignment {
705
931
  modelId: string;
@@ -714,14 +940,6 @@ interface TaskModelAssignment {
714
940
  availableVariants?: string[];
715
941
  }
716
942
  type RunnerId = string;
717
- /**
718
- * Bring loaded tasks to the structured-only shape, in place. A task saved
719
- * while the terminal transport existed may say it ran there, and why; neither
720
- * means anything now, and such a task left no session to continue. Its
721
- * completion marker id went with the text markers: completion is reported
722
- * only through `task_complete`.
723
- */
724
- declare function migrateLoadedTasks(tasks: readonly Task[]): void;
725
943
  /**
726
944
  * A task skill as one attempt received it: read from the task's own worktree
727
945
  * (or global) at spawn, kept so the user can see what the runner was told
@@ -750,15 +968,23 @@ interface Task {
750
968
  outputSummary?: TaskOutputSummary;
751
969
  assignedModel?: TaskModelAssignment;
752
970
  assignedRunner: RunnerId;
753
- thinkingEffort?: string;
754
971
  taskMode?: TaskMode;
755
972
  autonomy?: 'AFK' | 'HITL';
756
973
  sliceType?: 'HITL' | 'AFK';
757
974
  userStoriesCovered?: string[];
758
975
  /** The runner's saved session for a later continue; cleared when a fresh attempt starts. */
759
976
  runnerSessionId?: string;
760
- /** Set only while `status` is `awaiting_user`, and not always then — a usage-limit pause has none. */
977
+ /** Set only while `status` is `awaiting_user`, and not always then — a pause saved by an older build has none. */
761
978
  awaitingReason?: AwaitingReason;
979
+ /**
980
+ * When a task paused on its runner's usage limit is resumed on its own (ISO
981
+ * time): the reset the runner announced, plus a short margin. Absent when no
982
+ * reset time could be read or the user cancelled the resume — the task then
983
+ * waits for a manual retry. Set only with `awaitingReason` `usage-limit`.
984
+ */
985
+ resumeAt?: string;
986
+ /** Why the task was skipped, as whoever skipped it put it; set only while `status` is `skipped`, and not always then. */
987
+ skipReason?: string;
762
988
  /**
763
989
  * An ops task (ADR-0020): it changes no repository files, runs at the
764
990
  * workspace root rather than in a worktree, and waits for the change tasks
@@ -780,13 +1006,15 @@ interface Task {
780
1006
  skills?: string[];
781
1007
  /** The skills the latest attempt was given, as read when it spawned. */
782
1008
  attemptSkills?: TaskSkillSnapshot[];
1009
+ /**
1010
+ * Who put the task in the plan, when it was not the user's own planning:
1011
+ * `supervisor` for a task an Act supervisor added during a run, which
1012
+ * counts as approved to run (ADR-0029). Set by the session, never by an op.
1013
+ */
1014
+ addedBy?: 'supervisor';
1015
+ attemptUsage?: AttemptUsage[];
783
1016
  }
784
- interface DiscoveredMode {
785
- id: string;
786
- label: string;
787
- description: string;
788
- }
789
- type ResearchToolType = 'read_file' | 'read_files' | 'glob' | 'grep' | 'find_symbol' | 'list_dir' | 'bash' | 'fetch' | 'web_search' | 'spawn_research_agent'
1017
+ type ResearchToolType = 'read_file' | 'read_files' | 'glob' | 'grep' | 'find_symbol' | 'list_dir' | 'bash' | 'fetch' | 'web_search' | 'spawn_research_agent' | 'task_query' | 'task_output' | 'task_diff'
790
1018
  /**
791
1019
  * A tool belonging to a harness planner's own toolbox (ADR-0009) that has no
792
1020
  * Ordewell equivalent — Edit, WebFetch, TodoWrite, whatever a coding agent
@@ -870,19 +1098,6 @@ interface ResearchProgress {
870
1098
  digest?: string;
871
1099
  usage?: UsageTotals;
872
1100
  }
873
- interface ThinkingBlock {
874
- id: string;
875
- text: string;
876
- }
877
- interface StreamThinkingEvent {
878
- type: 'thinking';
879
- block: ThinkingBlock;
880
- }
881
- interface StreamStepEvent {
882
- type: 'step';
883
- step: ResearchStep;
884
- }
885
- type StreamEvent = StreamThinkingEvent | StreamStepEvent;
886
1101
  interface DiscoveredModel {
887
1102
  modelId: string;
888
1103
  modelLabel: string;
@@ -933,12 +1148,21 @@ interface ConversationMessage {
933
1148
  * user-triggered compaction left in place of the earlier messages — always
934
1149
  * the transcript's first entry. 'skill_load' is a skill loaded into the
935
1150
  * conversation, its snapshot in `skill`; one the user invoked follows the
936
- * message that named it. Absent for ordinary chat turns, so sessions saved
937
- * before markers existed degrade gracefully.
1151
+ * message that named it. 'execution' is a call at the command seam
1152
+ * (ADR-0029), its record in `execution`. 'wake_up' is the digest a wake-up
1153
+ * gave the supervisor (role 'user': the model was told it), and
1154
+ * 'supervisor' what the supervisor said in a wake-up turn (ADR-0029).
1155
+ * Absent for ordinary chat turns, so sessions saved before markers existed
1156
+ * degrade gracefully.
938
1157
  */
939
- kind?: 'plan_generated' | 'system' | 'compaction' | 'skill_load';
1158
+ kind?: 'plan_generated' | 'system' | 'compaction' | 'skill_load' | 'execution' | 'wake_up' | 'supervisor';
1159
+ actor?: 'Ordewell setting';
940
1160
  /** Present exactly when `kind` is 'skill_load'. */
941
1161
  skill?: SkillLoad;
1162
+ /** Present exactly when `kind` is 'execution'. */
1163
+ execution?: ExecutionRecord;
1164
+ /** A user's message that was force sent, stopping the turn before it (ADR-0023). */
1165
+ forced?: true;
942
1166
  }
943
1167
  /**
944
1168
  * A skill's SKILL.md as it was when loaded into a planner conversation. A
@@ -964,24 +1188,65 @@ interface SkillLoad {
964
1188
  }
965
1189
  /** A skill load as a surface announces it — the body stays with the transcript. */
966
1190
  type SkillLoadNotice = Omit<SkillLoad, 'content'>;
967
- /** A message the user sent, as opposed to a skill load their message caused. */
968
- declare function isUserMessage(entry: ConversationMessage): boolean;
1191
+ /** A message the user sent, as opposed to a skill load their message caused or a wake-up digest. */
1192
+ declare function isUserMessage(entry: Pick<ConversationMessage, 'role' | 'kind'>): boolean;
1193
+ /** A follow-up an older build queued behind a run's batch boundary; read only to carry it over as a {@link PendingPlanTurn}. */
969
1194
  interface QueuedMessage {
970
1195
  id: string;
971
1196
  text: string;
972
1197
  timestamp: string;
973
- /** What its `/name` tokens loaded when it was sent: the drain composes them with the text, as a live send does. */
974
1198
  skills?: SkillLoad[];
975
1199
  }
976
- interface PlanModificationWarnings {
977
- deletedCompleted: string[];
978
- changedCompleted: string[];
979
- deletedInProgress: string[];
980
- modifiedInProgress: string[];
981
- brokenDependencies: string[];
1200
+ /** Who a planner turn answers (ADR-0029): the user's message, or a wake-up batch the supervisor is given. */
1201
+ type PlanTurnSource = 'user' | 'supervisor';
1202
+ /**
1203
+ * A planner turn's input not yet answered by a turn that ended. It leaves the
1204
+ * plan with the change its turn made, in the same save, so a reload replays
1205
+ * exactly the inputs no turn answered — once. A supervisor's input is a
1206
+ * wake-up batch not yet delivered (ADR-0029): it stays until a turn lands
1207
+ * with it, whatever turns fail meanwhile.
1208
+ */
1209
+ interface PendingPlanTurn {
1210
+ id: string;
1211
+ source: PlanTurnSource;
1212
+ /** The user's message, or a wake-up batch's digest. */
1213
+ text: string;
1214
+ timestamp: string;
1215
+ /** What its `/name` tokens loaded when it was sent, so a replay sends the same skills. */
1216
+ skills?: SkillLoad[];
1217
+ /** Force sent: it waits ahead of every input not forced, and its turn is its own (ADR-0023, F2). */
1218
+ forced?: true;
1219
+ }
1220
+ /**
1221
+ * The run's own copy of the user's run settings (ADR-0030): taken when the
1222
+ * user starts it, changed at once by a change made in this session, and
1223
+ * lowered by a tripped guard or a failed supervisor.
1224
+ */
1225
+ interface RunSettings {
1226
+ mergeAtGatesAutomatically: boolean;
1227
+ /** Absent on a run started before supervisor levels existed: Off. */
1228
+ supervisorLevel?: SupervisorLevel;
1229
+ /** Absent on a run started before ADR-0030: the user's setting. */
1230
+ supervisorRetryLimit?: number;
1231
+ /** Absent on a run started before ADR-0030: the user's setting. */
1232
+ wakeUpReadBudget?: number;
1233
+ /** Why the supervisor stopped for the rest of this run, which carries on as Off; absent while it watches. */
1234
+ unsupervised?: string;
1235
+ }
1236
+ /**
1237
+ * What supervision remembers across a daemon restart (ADR-0029): the loop
1238
+ * guards' memory and the wake-up state not yet delivered with a turn.
1239
+ */
1240
+ interface SupervisionSnapshot {
1241
+ /** Retries, failed-attempt shapes, the supervisor's edits and what the user was told. */
1242
+ guards?: SupervisionMemorySnapshot;
1243
+ /** The events inside their debounce window and the wake-up rate's timestamps. */
1244
+ wake?: SupervisorSnapshot;
982
1245
  }
983
- declare function emptyWarnings(): PlanModificationWarnings;
984
1246
  interface LegacyPlanState {
1247
+ runSettings?: RunSettings;
1248
+ /** What supervision remembers across a daemon restart (ADR-0029); absent on plans saved before it existed. */
1249
+ supervision?: SupervisionSnapshot;
985
1250
  tasks: Task[];
986
1251
  generatedAt: string;
987
1252
  status: PlanStatus;
@@ -992,7 +1257,9 @@ interface LegacyPlanState {
992
1257
  conversationHistory?: ConversationMessage[];
993
1258
  /** Full markdown PRD once written by the planner (PRD mode), also saved to .scratch/<slug>/PRD.md. */
994
1259
  prdMarkdown?: string;
995
- /** Follow-ups queued while tasks execute — applied as plan modifications between batches. */
1260
+ /** Planner turn inputs no turn has answered yet (ADR-0029); a reload replays them. */
1261
+ pendingTurns?: PendingPlanTurn[];
1262
+ /** Written by builds that queued mid-run edits; a load moves it into {@link pendingTurns}. */
996
1263
  queuedMessages?: QueuedMessage[];
997
1264
  /**
998
1265
  * The plan's isolation run (ADR-0013), written from the orchestrator at
@@ -1003,6 +1270,13 @@ interface LegacyPlanState {
1003
1270
  isolation?: PlanIsolation;
1004
1271
  /** Kept so a reopened session shows the same token line (#49). */
1005
1272
  plannerUsage?: PlannerUsage;
1273
+ /**
1274
+ * The tasks the user approved to run: every task when they executed the
1275
+ * plan, and each one they started or retried themselves since. A command
1276
+ * from anyone else starts only these (ADR-0029); a task the planner added
1277
+ * after the approval waits for the user's.
1278
+ */
1279
+ approvedTasks?: string[];
1006
1280
  }
1007
1281
  interface Message {
1008
1282
  id: string;
@@ -1032,91 +1306,36 @@ type PlanState = {
1032
1306
  status: PlanStatus;
1033
1307
  };
1034
1308
  declare function migratePlanState(raw: unknown): PlanState;
1035
- declare function migrateLegacyPlan(legacy: LegacyPlanState): PlanState;
1036
1309
 
1037
1310
  declare function createTask(overrides?: Partial<Task>): Task;
1038
- declare function isSkillName(name: string): boolean;
1039
- /**
1040
- * The `skills` field as a task stores it, however it arrived: the planner's
1041
- * JSON is untyped. Names are trimmed, lower-cased and deduplicated, and one
1042
- * no skill could have is dropped; none at all is stored absent, so a plan
1043
- * without skills reads exactly as it did before them.
1044
- */
1045
- declare function skillNames(value: unknown): string[] | undefined;
1046
- /**
1047
- * The skills of a task a merge or a split makes from others: what the edit
1048
- * chose when it named any, none when it chose an explicit `[]`, else what the
1049
- * tasks it came from had — a malformed value is not a request to drop them.
1050
- */
1051
- declare function inheritedSkills(chosen: unknown, inherited: readonly string[] | undefined): string[] | undefined;
1052
- /**
1053
- * The `ops` flag as a task stores it (ADR-0020), however it arrived. Only a
1054
- * literal `true` on an AI task marks an ops task: the planner's JSON is
1055
- * untyped, and a quoted "true" read as ops would move a task out of its
1056
- * worktree. Anything else is a change task, stored absent so saved plans need
1057
- * no migration. Whether the task may be ops at all — a subtask may not — is
1058
- * for whoever knows where it sits: parsing drops the flag, an edit refuses it.
1059
- */
1060
- declare function opsFlag(value: unknown, type?: Task['type']): true | undefined;
1061
- /**
1062
- * The flag of a task a merge or a split makes from others: what the edit
1063
- * chose, else ops only when every task it came from was. A merge that takes
1064
- * in a change edits files, so it is a change; a split part runs where its
1065
- * task did.
1066
- */
1067
- declare function inheritedOps(from: readonly Pick<Task, 'ops'>[], chosen?: boolean): boolean;
1068
1311
  /** The runner set a plan has until one is chosen: the one runner every host ships. */
1069
1312
  declare const DEFAULT_RUNNERS: readonly RunnerId[];
1070
1313
  declare function createEmptyPlan(): LegacyPlanState;
1071
1314
  declare function flattenTasks(tasks: readonly Task[]): Task[];
1072
- /** A flattened task with the parent it hangs under, null for a top-level task. */
1073
- interface TaskWithParent {
1074
- task: Task;
1075
- parent: Task | null;
1076
- }
1077
- declare function flattenTasksWithParents(tasks: readonly Task[]): TaskWithParent[];
1078
- declare function migrateTask(task: Record<string, unknown>): Task;
1079
- declare function addTaskToPlan(tasks: readonly Task[], partial: Partial<Task>): Task[];
1080
- declare function removeTaskFromPlan(tasks: readonly Task[], taskId: string): Task[];
1081
- declare function updateTaskInPlan(tasks: readonly Task[], taskId: string, changes: Partial<Task>): Task[];
1082
- declare function renumberTasks(tasks: readonly Task[]): Task[];
1083
1315
  /**
1084
- * Lay a planner-written task list over the plan it rewrites without letting it
1085
- * change execution state. A planner restates tasks; it never witnessed one run,
1086
- * so the status it writes is not evidence. A settled task is kept exactly as
1087
- * it stands wherever the rewrite names it, and put back beside its old
1088
- * neighbour where the rewrite leaves it out. Every other task keeps the status
1089
- * it had; a task the rewrite adds starts pending.
1316
+ * A phase-tagged plan rejoined into its tree. The execution log is flat — a
1317
+ * finished subtask is logged on its own as well as inside its parent — and in
1318
+ * the order tasks finished, so read as a list it puts subtasks at the top level
1319
+ * under orders that clash with real top-level tasks. A task's own entry is the
1320
+ * latest word on it: its parent's copy was taken when the parent last changed.
1090
1321
  */
1091
- declare function keepExecutionState(current: readonly Task[], rewrite: Task[]): Task[];
1092
- /** What only execution reads; {@link keepExecutionState} puts it back on whatever a planner returns. */
1093
- declare const EXECUTION_ONLY: readonly ["attemptSkills", "runnerSessionId", "awaitingReason", "forcedPastGate", "outputSummary"];
1094
- type PlannerTaskView = Omit<Task, typeof EXECUTION_ONLY[number] | 'subtasks'> & {
1095
- subtasks: PlannerTaskView[];
1096
- };
1322
+ declare function rejoinPlanTree<T extends {
1323
+ id: string;
1324
+ order: number;
1325
+ subtasks?: T[];
1326
+ }>(pending: readonly T[], log: readonly T[]): T[];
1097
1327
  /**
1098
- * A task as a planner prompt carries it. An attempt's skill snapshots are
1099
- * whole SKILL.md bodies and an output summary holds a log tail: sent on every
1100
- * planner call, they cost tokens and invite the planner to edit state it does
1101
- * not own.
1328
+ * A flattened task with the parent it hangs under, null for a top-level task,
1329
+ * and the path label and reference (`#2.1.3`) `TaskRefs` renders for it.
1102
1330
  */
1103
- declare function plannerTaskView(task: Task): PlannerTaskView;
1104
- declare function validateModifiedPlan(original: Task[], modified: Task[]): PlanModificationWarnings;
1105
- interface ActiveTaskSession {
1106
- id: string;
1107
- taskId: string;
1108
- }
1109
- interface ValidationResult {
1110
- valid: boolean;
1111
- errors: string[];
1112
- }
1113
- interface ValidationContext {
1114
- executionLog: TaskSnapshot[];
1115
- oldPending: Task[];
1116
- newPending: Task[];
1117
- activeSessions: Map<string, ActiveTaskSession>;
1331
+ interface TaskWithParent {
1332
+ task: Task;
1333
+ parent: Task | null;
1334
+ label: string;
1335
+ ref: string;
1118
1336
  }
1119
- type ValidationCheck = (ctx: ValidationContext) => ValidationResult;
1120
- declare function warningsText(w: PlanModificationWarnings): string | null;
1337
+ declare function flattenTasksWithParents(tasks: readonly Task[]): TaskWithParent[];
1338
+ /** A task paused on its runner's usage limit, whether it resumes on its own or waits for the user (#84). */
1339
+ declare function pausedOnLimit(task: Readonly<Task>): boolean;
1121
1340
 
1122
- export { type SkillLoad as $, type ActiveTaskSession as A, BUILTIN_SKILL_NAMES as B, type ConversationMessage as C, DEFAULT_RUNNERS as D, type PlanStatus as E, type PlannerTaskView as F, type PlannerUsage as G, type PreparedTask as H, type IWorktreeIsolation as I, type PreservedWork as J, type RepairEvidence as K, type LegacyPlanState as L, type Message as M, type RepoGroupLayout as N, type ResearchLogEntry as O, type PlanIsolation as P, type QueuedMessage as Q, type RefusedRemoval as R, type ResearchProgress as S, type ResearchStep as T, type ResearchStepOutcome as U, type ResearchToolType as V, type RunnerId as W, type ShadowedSkill as X, type SkillAppliesTo as Y, type SkillCatalog as Z, type SkillInfo as _, type AwaitingReason as a, warningsText as a$, type SkillLoadNotice as a0, type SkillMetadata as a1, type SkillSource as a2, SkillsService as a3, type StreamEvent as a4, type StreamStepEvent as a5, type StreamThinkingEvent as a6, type SubagentLogEntry as a7, type SubagentOutcome as a8, type Task as a9, createEmptyPlan as aA, createSkillsService as aB, createTask as aC, emptyWarnings as aD, flattenTasks as aE, flattenTasksWithParents as aF, inheritedOps as aG, inheritedSkills as aH, isAwaitingReason as aI, isMeasured as aJ, isSkillName as aK, isUserMessage as aL, keepExecutionState as aM, migrateLegacyPlan as aN, migrateLoadedTasks as aO, migratePlanState as aP, migrateTask as aQ, opsFlag as aR, partedPromptUsage as aS, plannerContextFill as aT, plannerTaskView as aU, removeTaskFromPlan as aV, renumberTasks as aW, skillNames as aX, updateTaskInPlan as aY, usageLine as aZ, validateModifiedPlan as a_, type TaskIsolation as aa, type TaskIsolationState as ab, type TaskMode as ac, type TaskModelAssignment as ad, type TaskOutputSummary as ae, type TaskSkillNotice as af, type TaskSkillSnapshot as ag, type TaskSnapshot as ah, type TaskStatus as ai, type TaskType as aj, type TaskWithParent as ak, type ThinkingBlock as al, type TreeSnapshot as am, type UsageLine as an, type UsageRecord as ao, type UsageTotals as ap, type UserPromptEntry as aq, type UserStep as ar, type ValidationCheck as as, type ValidationContext as at, type ValidationResult as au, type Verdict as av, type VerificationCheck as aw, addPlannerUsage as ax, addTaskToPlan as ay, addUsage as az, type DiscoveredMode as b, type DiscoveredModel as c, type IntegrationDisposal as d, type InvalidSkill as e, type IsolationAvailability as f, type IsolationHandoff as g, type IsolationHandoffRepo as h, type IsolationInactiveReason as i, type IsolationLandedTask as j, type IsolationLanding as k, type IsolationMergeBlock as l, type IsolationMergeBlockReason as m, type IsolationMergeResult as n, type IsolationOutcome as o, type IsolationPruneResult as p, type IsolationRemoval as q, type IsolationRepo as r, type IsolationRun as s, type IsolationTaskRecord as t, type IsolationTaskRef as u, type IsolationTaskRepo as v, type IsolationTaskStatus as w, type IsolationView as x, type PlanModificationWarnings as y, type PlanState as z };
1341
+ export { type RunnerId as $, type AttemptUsage as A, BUILTIN_SKILL_NAMES as B, type ConversationMessage as C, DEFAULT_RUNNERS as D, type ExecutionActor as E, type IsolationView as F, type GuardTarget as G, type PlanIsolation as H, type IWorktreeIsolation as I, type PlanState as J, type PlanStatus as K, type LegacyPlanState as L, type ModelUsage as M, type PlanUsage as N, type PlannerUsage as O, type PendingPlanTurn as P, type PreparedTask as Q, type PreservedWork as R, type RefusedRemoval as S, type RepairEvidence as T, type RepoGroupLayout as U, type ResearchLogEntry as V, type ResearchProgress as W, type ResearchStep as X, type ResearchStepOutcome as Y, type ResearchToolType as Z, type RunSettings as _, type AwaitingReason as a, type SetupFailure as a0, type ShadowedSkill as a1, type SkillAppliesTo as a2, type SkillCatalog as a3, type SkillInfo as a4, type SkillLoad as a5, type SkillLoadNotice as a6, type SkillMetadata as a7, type SkillSource as a8, SkillsService as a9, endAttemptUsage as aA, flattenTasks as aB, flattenTasksWithParents as aC, isAwaitingReason as aD, isMeasured as aE, isSupervisorLevel as aF, isUserMessage as aG, migratePlanState as aH, partedPromptUsage as aI, pausedOnLimit as aJ, planUsage as aK, plannerContextFill as aL, rejoinPlanTree as aM, startAttemptUsage as aN, usageLine as aO, type SubagentOutcome as aa, type SupervisorLevel as ab, type Task as ac, type TaskDiffRead as ad, type TaskDiffResult as ae, type TaskIsolation as af, type TaskIsolationState as ag, type TaskModelAssignment as ah, type TaskSkillNotice as ai, type TaskSkillSnapshot as aj, type TaskSnapshot as ak, type TaskStatus as al, type TreeSnapshot as am, type UsageLine as an, type UsageRecord as ao, type UsageTotals as ap, type Verdict as aq, type VerificationCheck as ar, addAttemptUsage as as, addModelUsage as at, addPlannerUsage as au, addUsage as av, addUsageTotals as aw, createEmptyPlan as ax, createSkillsService as ay, createTask as az, DEFAULT_SUPERVISOR_RETRY_LIMIT as b, type DiscoveredModel as c, type ExecutionCommandName as d, type ExecutionRecord as e, type GuardTrip as f, type IntegrationDisposal as g, type InvalidSkill as h, type IsolationAvailability as i, type IsolationHandoff as j, type IsolationHandoffRepo as k, type IsolationInactiveReason as l, type IsolationLandedTask as m, type IsolationLanding as n, type IsolationMergeBlock as o, type IsolationMergeBlockReason as p, type IsolationMergeResult as q, type IsolationOutcome as r, type IsolationPruneResult as s, type IsolationRemoval as t, type IsolationRepo as u, type IsolationRun as v, type IsolationTaskRecord as w, type IsolationTaskRef as x, type IsolationTaskRepo as y, type IsolationTaskStatus as z };