@enderfga/claw-orchestrator 5.0.0 → 6.0.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 (158) hide show
  1. package/README.md +28 -28
  2. package/dist/bin/cli.js +107 -1
  3. package/dist/bin/cli.js.map +1 -1
  4. package/dist/src/acp-server.d.ts +5 -5
  5. package/dist/src/acp-server.js +3 -3
  6. package/dist/src/acp-server.js.map +1 -1
  7. package/dist/src/autoloop/dispatcher.d.ts +22 -0
  8. package/dist/src/autoloop/dispatcher.js +71 -13
  9. package/dist/src/autoloop/dispatcher.js.map +1 -1
  10. package/dist/src/autoloop/messages.d.ts +10 -0
  11. package/dist/src/autoloop/messages.js.map +1 -1
  12. package/dist/src/autoloop/runner.js +6 -0
  13. package/dist/src/autoloop/runner.js.map +1 -1
  14. package/dist/src/constants.d.ts +0 -6
  15. package/dist/src/constants.js +0 -6
  16. package/dist/src/constants.js.map +1 -1
  17. package/dist/src/council.d.ts +15 -0
  18. package/dist/src/council.js +48 -35
  19. package/dist/src/council.js.map +1 -1
  20. package/dist/src/dashboard/index.html +191 -6
  21. package/dist/src/embedded-server.js +132 -9
  22. package/dist/src/embedded-server.js.map +1 -1
  23. package/dist/src/fanout.d.ts +30 -1
  24. package/dist/src/fanout.js +32 -3
  25. package/dist/src/fanout.js.map +1 -1
  26. package/dist/src/index.d.ts +1 -0
  27. package/dist/src/index.js +360 -4
  28. package/dist/src/index.js.map +1 -1
  29. package/dist/src/kernel/agent-step.d.ts +59 -0
  30. package/dist/src/kernel/agent-step.js +100 -0
  31. package/dist/src/kernel/agent-step.js.map +1 -0
  32. package/dist/src/kernel/conditions.d.ts +11 -0
  33. package/dist/src/kernel/conditions.js +24 -0
  34. package/dist/src/kernel/conditions.js.map +1 -0
  35. package/dist/src/kernel/engine.d.ts +319 -0
  36. package/dist/src/kernel/engine.js +1047 -0
  37. package/dist/src/kernel/engine.js.map +1 -0
  38. package/dist/src/kernel/exec.d.ts +43 -0
  39. package/dist/src/kernel/exec.js +112 -0
  40. package/dist/src/kernel/exec.js.map +1 -0
  41. package/dist/src/kernel/file-lock.d.ts +50 -0
  42. package/dist/src/kernel/file-lock.js +135 -0
  43. package/dist/src/kernel/file-lock.js.map +1 -0
  44. package/dist/src/kernel/nodes/agent.d.ts +4 -0
  45. package/dist/src/kernel/nodes/agent.js +35 -0
  46. package/dist/src/kernel/nodes/agent.js.map +1 -0
  47. package/dist/src/kernel/nodes/autoloop.d.ts +78 -0
  48. package/dist/src/kernel/nodes/autoloop.js +75 -0
  49. package/dist/src/kernel/nodes/autoloop.js.map +1 -0
  50. package/dist/src/kernel/nodes/council.d.ts +12 -0
  51. package/dist/src/kernel/nodes/council.js +88 -0
  52. package/dist/src/kernel/nodes/council.js.map +1 -0
  53. package/dist/src/kernel/nodes/fanout.d.ts +11 -0
  54. package/dist/src/kernel/nodes/fanout.js +63 -0
  55. package/dist/src/kernel/nodes/fanout.js.map +1 -0
  56. package/dist/src/kernel/nodes/human-gate.d.ts +4 -0
  57. package/dist/src/kernel/nodes/human-gate.js +7 -0
  58. package/dist/src/kernel/nodes/human-gate.js.map +1 -0
  59. package/dist/src/kernel/nodes/index.d.ts +12 -0
  60. package/dist/src/kernel/nodes/index.js +21 -0
  61. package/dist/src/kernel/nodes/index.js.map +1 -0
  62. package/dist/src/kernel/nodes/router.d.ts +4 -0
  63. package/dist/src/kernel/nodes/router.js +12 -0
  64. package/dist/src/kernel/nodes/router.js.map +1 -0
  65. package/dist/src/kernel/nodes/subflow.d.ts +13 -0
  66. package/dist/src/kernel/nodes/subflow.js +38 -0
  67. package/dist/src/kernel/nodes/subflow.js.map +1 -0
  68. package/dist/src/kernel/nodes/ultraapp.d.ts +60 -0
  69. package/dist/src/kernel/nodes/ultraapp.js +62 -0
  70. package/dist/src/kernel/nodes/ultraapp.js.map +1 -0
  71. package/dist/src/kernel/nodes/verifier.d.ts +14 -0
  72. package/dist/src/kernel/nodes/verifier.js +84 -0
  73. package/dist/src/kernel/nodes/verifier.js.map +1 -0
  74. package/dist/src/kernel/projections.d.ts +42 -0
  75. package/dist/src/kernel/projections.js +133 -0
  76. package/dist/src/kernel/projections.js.map +1 -0
  77. package/dist/src/kernel/repo.d.ts +13 -0
  78. package/dist/src/kernel/repo.js +64 -0
  79. package/dist/src/kernel/repo.js.map +1 -0
  80. package/dist/src/kernel/secrets.d.ts +25 -0
  81. package/dist/src/kernel/secrets.js +48 -0
  82. package/dist/src/kernel/secrets.js.map +1 -0
  83. package/dist/src/kernel/store.d.ts +225 -0
  84. package/dist/src/kernel/store.js +838 -0
  85. package/dist/src/kernel/store.js.map +1 -0
  86. package/dist/src/kernel/templates/index.d.ts +140 -0
  87. package/dist/src/kernel/templates/index.js +266 -0
  88. package/dist/src/kernel/templates/index.js.map +1 -0
  89. package/dist/src/kernel/types.d.ts +326 -0
  90. package/dist/src/kernel/types.js +19 -0
  91. package/dist/src/kernel/types.js.map +1 -0
  92. package/dist/src/models.d.ts +1 -1
  93. package/dist/src/models.js +31 -3
  94. package/dist/src/models.js.map +1 -1
  95. package/dist/src/persistent-cursor-session.js +6 -1
  96. package/dist/src/persistent-cursor-session.js.map +1 -1
  97. package/dist/src/persistent-grok-session.d.ts +40 -0
  98. package/dist/src/persistent-grok-session.js +197 -0
  99. package/dist/src/persistent-grok-session.js.map +1 -0
  100. package/dist/src/run-ledger.d.ts +57 -3
  101. package/dist/src/run-ledger.js +45 -2
  102. package/dist/src/run-ledger.js.map +1 -1
  103. package/dist/src/session-manager.d.ts +176 -129
  104. package/dist/src/session-manager.js +657 -603
  105. package/dist/src/session-manager.js.map +1 -1
  106. package/dist/src/types.d.ts +37 -4
  107. package/dist/src/types.js +15 -1
  108. package/dist/src/types.js.map +1 -1
  109. package/dist/src/ultraapp/build.d.ts +117 -3
  110. package/dist/src/ultraapp/build.js +319 -3
  111. package/dist/src/ultraapp/build.js.map +1 -1
  112. package/dist/src/ultraapp/contract.d.ts +52 -0
  113. package/dist/src/ultraapp/contract.js +83 -0
  114. package/dist/src/ultraapp/contract.js.map +1 -0
  115. package/dist/src/ultraapp/conventions.js +9 -2
  116. package/dist/src/ultraapp/conventions.js.map +1 -1
  117. package/dist/src/ultraapp/fix-on-failure.d.ts +21 -2
  118. package/dist/src/ultraapp/fix-on-failure.js +46 -62
  119. package/dist/src/ultraapp/fix-on-failure.js.map +1 -1
  120. package/dist/src/ultraapp/manager.d.ts +107 -2
  121. package/dist/src/ultraapp/manager.js +305 -86
  122. package/dist/src/ultraapp/manager.js.map +1 -1
  123. package/dist/src/verify/baseline.d.ts +73 -0
  124. package/dist/src/verify/baseline.js +186 -0
  125. package/dist/src/verify/baseline.js.map +1 -0
  126. package/dist/src/verify/contract.d.ts +116 -0
  127. package/dist/src/verify/contract.js +142 -0
  128. package/dist/src/verify/contract.js.map +1 -0
  129. package/dist/src/verify/evidence.d.ts +61 -0
  130. package/dist/src/verify/evidence.js +133 -0
  131. package/dist/src/verify/evidence.js.map +1 -0
  132. package/dist/src/verify/runner.d.ts +63 -0
  133. package/dist/src/verify/runner.js +317 -0
  134. package/dist/src/verify/runner.js.map +1 -0
  135. package/openclaw.plugin.json +8 -0
  136. package/package.json +2 -2
  137. package/skills/SKILL.md +121 -80
  138. package/skills/references/acp.md +18 -18
  139. package/skills/references/autoloop.md +148 -72
  140. package/skills/references/claude-cli-tracking.md +4 -4
  141. package/skills/references/cli.md +103 -60
  142. package/skills/references/council.md +109 -37
  143. package/skills/references/dashboard.md +34 -6
  144. package/skills/references/getting-started.md +14 -14
  145. package/skills/references/inbox.md +4 -4
  146. package/skills/references/mcp.md +39 -34
  147. package/skills/references/multi-engine.md +109 -51
  148. package/skills/references/observability.md +88 -27
  149. package/skills/references/openai-compat.md +40 -40
  150. package/skills/references/sessions.md +44 -26
  151. package/skills/references/tools.md +402 -309
  152. package/skills/references/ultra.md +45 -45
  153. package/skills/references/ultraapp.md +126 -50
  154. package/skills/references/verification.md +187 -0
  155. package/skills/references/workflow.md +362 -0
  156. package/dist/src/ultraapp/fix-on-failure-session.d.ts +0 -23
  157. package/dist/src/ultraapp/fix-on-failure-session.js +0 -51
  158. package/dist/src/ultraapp/fix-on-failure-session.js.map +0 -1
@@ -16,8 +16,11 @@ interface PersistedSession {
16
16
  lastActivity: number;
17
17
  }
18
18
  import { type Logger } from './logger.js';
19
+ import { type RunSummary } from './kernel/store.js';
20
+ import type { KernelEvent, RunRecord, RunState, WorkflowSpec } from './kernel/types.js';
21
+ import { type EvidenceBundle } from './verify/evidence.js';
19
22
  import { type RunLedgerQuery, type RunLedgerRow, type RunLedgerSummary } from './run-ledger.js';
20
- import { type SessionConfig, type SessionInfo, type SendResult, type PluginConfig, type EffortLevel, type EngineType, type CustomEngineConfig, type AgentInfo, type SkillInfo, type RuleInfo, type StreamEvent, type ISession, type CouncilConfig, type CouncilSession, type CouncilReviewResult, type CouncilAcceptResult, type CouncilRejectResult, type InboxMessage, type UltraplanResult, type UltrareviewResult } from './types.js';
23
+ import { type SessionConfig, type SessionInfo, type SendOptions, type SendResult, type PluginConfig, type EffortLevel, type EngineType, type CustomEngineConfig, type AgentInfo, type SkillInfo, type RuleInfo, type ISession, type CouncilConfig, type CouncilSession, type CouncilReviewResult, type CouncilAcceptResult, type CouncilRejectResult, type InboxMessage, type UltraplanResult, type UltrareviewResult } from './types.js';
21
24
  import { Council } from './council.js';
22
25
  import { type FanoutConfig, type FanoutSession } from './fanout.js';
23
26
  import { AutoloopRunner } from './autoloop/runner.js';
@@ -25,88 +28,7 @@ import { ClaudeAgentDispatcher } from './autoloop/dispatcher.js';
25
28
  import type { AutoloopState } from './autoloop/types.js';
26
29
  import { UltraappManager } from './ultraapp/manager.js';
27
30
  import type { UltraappRouter } from './ultraapp/router.js';
28
- interface SendOptions {
29
- effort?: EffortLevel;
30
- plan?: boolean;
31
- autoResume?: boolean;
32
- timeout?: number;
33
- onEvent?: (event: StreamEvent) => void;
34
- onChunk?: (chunk: string) => void;
35
- /**
36
- * council id / fanout id / autoloop run id. Recorded on the run-ledger row so
37
- * a multi-agent run can be reconstructed from the ledger after the fact.
38
- */
39
- parentRunId?: string;
40
- }
41
- /** Public shape returned by listCouncilsFromDisk(). Mirrors a subset of CouncilSession. */
42
- export interface CouncilDiskRecord {
43
- id: string;
44
- task: string;
45
- status: string;
46
- startTime: string;
47
- }
48
- /**
49
- * One row in ~/.claw-orchestrator/autoloop-registry.jsonl. Used to make
50
- * autoloop runs visible across processes (the ledger lives at
51
- * <workspace>/tasks/<run_id>/, workspaces vary, so we keep a central
52
- * append-only index here).
53
- */
54
- export interface AutoloopRegistryEntry {
55
- run_id: string;
56
- workspace: string;
57
- ledger_dir: string;
58
- started_at: string;
59
- planner_session: string;
60
- /** Optional for compatibility with registry rows written before role-level engine support. */
61
- planner_engine?: EngineType;
62
- planner_model?: string;
63
- coder_engine?: EngineType;
64
- coder_model?: string;
65
- reviewer_engine?: EngineType;
66
- reviewer_model?: string;
67
- }
68
- /** Append-only registry write. Safe under concurrent writers — append is atomic for short lines. */
69
- export declare function appendAutoloopRegistry(file: string, entry: AutoloopRegistryEntry): void;
70
- /**
71
- * Write the current row for a run, dropping any older rows for the same id.
72
- *
73
- * The registry is append-only and `listAutoloopsFromRegistry` dedups on read
74
- * (newest wins), so correctness never depended on cleanup — but a run now emits
75
- * a row at start, another on every successful `spawn_subagents`, and another on
76
- * every resume, none of which were ever removed. The file grew monotonically and
77
- * every list / resume parses all of it. Callers use this AFTER the operation
78
- * succeeds, so a failed start still leaves the previous row intact.
79
- */
80
- export declare function upsertAutoloopRegistry(file: string, entry: AutoloopRegistryEntry): void;
81
- /**
82
- * Read the registry, dedup by run_id (newest entry wins), drop entries whose
83
- * ledger_dir no longer exists on disk (cleanup of moved/deleted workspaces).
84
- * Returns entries newest-first.
85
- */
86
- export declare function listAutoloopsFromRegistry(file?: string): AutoloopRegistryEntry[];
87
- /**
88
- * Rewrite the registry with every line for the given run_id filtered out.
89
- * Used by autoloopDelete to scrub a run from cross-process visibility.
90
- * No-op if the file does not exist. Returns the number of lines removed.
91
- */
92
- export declare function removeAutoloopFromRegistry(file: string, runId: string): number;
93
- /**
94
- * Enumerate council sessions from on-disk transcripts. Called by
95
- * SessionManager.councilList() to surface runs that the current process didn't
96
- * spawn itself (e.g. runs started in another process whose transcripts have
97
- * already been flushed to ~/.openclaw/council-logs/).
98
- *
99
- * Format parsed (matches src/council.ts saveTranscript):
100
- * - **ID**: <session.id>
101
- * - **Time**: <iso>
102
- * - **Task**: <text>
103
- * - **Status**: <consensus|max_rounds|...>
104
- *
105
- * Legacy transcripts written before the ID field was added fall back to a
106
- * filename-derived id (basename without .md). That's stable across reruns
107
- * even if uncomfortable as a display id.
108
- */
109
- export declare function listCouncilsFromDisk(logDir?: string): CouncilDiskRecord[];
31
+ type AutoloopRoleName = 'planner' | 'coder' | 'reviewer';
110
32
  export declare class SessionManager {
111
33
  private sessions;
112
34
  private _pendingSessions;
@@ -119,6 +41,8 @@ export declare class SessionManager {
119
41
  private _activePids;
120
42
  private _circuitBreaker;
121
43
  private _inbox;
44
+ /** cwd → detected language, so the manifest probe runs once per directory. */
45
+ private _repoLangCache;
122
46
  private logger;
123
47
  private _ultraappManager;
124
48
  private _ultraappRouter;
@@ -162,6 +86,12 @@ export declare class SessionManager {
162
86
  * query gives the spend for that window without double-counting.
163
87
  */
164
88
  private _recordRunTurn;
89
+ /**
90
+ * Repo language for the ledger row, memoised per cwd — the detector stats a
91
+ * handful of manifest paths and a turn-rate filesystem probe is wasteful when
92
+ * a session's cwd never changes.
93
+ */
94
+ private _repoLang;
165
95
  private _reportedModel;
166
96
  private _turnWasEstimated;
167
97
  /**
@@ -172,6 +102,68 @@ export declare class SessionManager {
172
102
  rows: RunLedgerRow[];
173
103
  summary: RunLedgerSummary;
174
104
  };
105
+ /**
106
+ * Lazily built, like every other subsystem here — constructing it at plugin
107
+ * load would create run directories for a process that may never run anything.
108
+ */
109
+ private get kernel();
110
+ /** Named built-ins available to `subflow` nodes and to `workflow_start`. */
111
+ private _resolveTemplate;
112
+ /**
113
+ * Subscribe to kernel events (for the SSE endpoint). Returns an unsubscribe
114
+ * function — SessionManager is not an EventEmitter, and making it one just for
115
+ * this would widen its surface for one consumer.
116
+ */
117
+ onWorkflowEvent(listener: (e: {
118
+ runId: string;
119
+ event: KernelEvent;
120
+ }) => void): () => void;
121
+ workflowStart(spec: WorkflowSpec, opts?: {
122
+ runId?: string;
123
+ cwd?: string;
124
+ contract?: unknown;
125
+ }): Promise<RunRecord>;
126
+ workflowStatus(runId: string): RunRecord;
127
+ workflowList(query?: {
128
+ workflow?: string;
129
+ state?: RunState;
130
+ limit?: number;
131
+ }): RunSummary[];
132
+ workflowCancel(runId: string): {
133
+ cancelled: boolean;
134
+ };
135
+ /**
136
+ * Re-attach to a run.
137
+ *
138
+ * `secrets` re-supplies the material the spec deliberately does not carry —
139
+ * per-agent custom-engine configs, keyed as `{ agentCustomEngines: { <name>: cfg } }`.
140
+ * A run that used one cannot be resumed in a fresh process without them,
141
+ * because they were never written down.
142
+ */
143
+ workflowResume(runId: string, opts?: {
144
+ secrets?: Record<string, unknown>;
145
+ }): Promise<RunRecord>;
146
+ workflowSteer(runId: string, text: string): {
147
+ steered: boolean;
148
+ };
149
+ workflowApprove(runId: string, approved: boolean): {
150
+ answered: boolean;
151
+ };
152
+ workflowDelete(runId: string): void;
153
+ workflowEvidence(runId: string, evidenceId?: string): EvidenceBundle | undefined;
154
+ /**
155
+ * Run an acceptance contract against a directory, outside any workflow.
156
+ *
157
+ * This is the escape hatch for work that did not come through the kernel — a
158
+ * plain `session_send` that edited a repo, or a run from an older version. The
159
+ * contract comes from the caller and is normalized before anything executes.
160
+ */
161
+ verifyRun(args: {
162
+ cwd: string;
163
+ contract: unknown;
164
+ baseSha?: string;
165
+ label?: string;
166
+ }): Promise<EvidenceBundle>;
175
167
  stopSession(name: string, opts?: {
176
168
  keepPersisted?: boolean;
177
169
  }): Promise<void>;
@@ -481,42 +473,43 @@ export declare class SessionManager {
481
473
  private _storedResumeId;
482
474
  private _listMdFiles;
483
475
  private _createSession;
484
- private councils;
485
- private councilCleanupTimers;
486
- councilStart(task: string, config: CouncilConfig): CouncilSession;
487
- private _scheduleCouncilCleanup;
488
- /** Clear and forget a cleanup timer (used on abort/shutdown so it can't fire late). */
489
- private _clearCleanupTimer;
476
+ councilStart(task: string, config: CouncilConfig): Promise<CouncilSession>;
490
477
  councilStatus(id: string): CouncilSession | undefined;
491
478
  /**
492
- * List all council sessions visible to this process.
479
+ * Every council this machine has run, newest first.
493
480
  *
494
- * Includes (a) in-memory sessions managed by this SessionManager and (b)
495
- * sessions reconstructed from on-disk transcripts at ~/.openclaw/council-logs/.
496
- * The disk path lets the dashboard see runs started in OTHER processes
497
- * (e.g. plugin-managed runs visible to a standalone clawo-serve dashboard).
498
- * Dedup by id; in-memory wins. Sorted by startTime descending so the newest
499
- * appears at the top of the sidebar.
481
+ * Cross-process visibility used to come from scraping `~/.openclaw/council-logs/*.md`
482
+ * with a regex and fabricating a stub session with no responses and an empty
483
+ * config. Runs are stored records now, so the dashboard sees the real thing.
500
484
  */
501
485
  councilList(): CouncilSession[];
502
486
  /** Used by embedded-server to subscribe to a council's event stream. */
503
487
  getCouncil(id: string): Council | undefined;
488
+ /** The live council for a run, or a clear error about why there isn't one. */
489
+ private _liveCouncil;
504
490
  councilAbort(id: string): void;
505
491
  councilInject(id: string, message: string): void;
506
492
  councilReview(id: string): Promise<CouncilReviewResult>;
507
493
  councilAccept(id: string): Promise<CouncilAcceptResult>;
508
494
  councilReject(id: string, feedback: string): Promise<CouncilRejectResult>;
509
- private fanouts;
510
- private fanoutCleanupTimers;
495
+ /**
496
+ * A `Council` for review / accept / reject.
497
+ *
498
+ * These three act on the git state a finished council left behind — branches,
499
+ * worktrees, plan.md — so they do not need the instance that produced it, only
500
+ * one pointed at the same project directory. Reconstructing from the run
501
+ * record is what makes them work after a restart, which the in-memory map made
502
+ * impossible.
503
+ */
504
+ private _councilForPostProcessing;
511
505
  /**
512
506
  * Start a fan-out: run the task across N engine/model agents in parallel and
513
507
  * collect their answers (optional synthesis). Runs in the background; poll
514
508
  * with fanoutStatus. Distinct from council — no rounds, votes, or worktrees.
515
509
  */
516
- fanoutStart(config: FanoutConfig): FanoutSession;
510
+ fanoutStart(config: FanoutConfig): Promise<FanoutSession>;
517
511
  fanoutStatus(id: string): FanoutSession;
518
512
  fanoutAbort(id: string): void;
519
- private _scheduleFanoutCleanup;
520
513
  private get _sessionLookup();
521
514
  sessionSendTo(from: string, to: string, message: string, summary?: string): Promise<{
522
515
  delivered: boolean;
@@ -524,38 +517,75 @@ export declare class SessionManager {
524
517
  }>;
525
518
  sessionInbox(name: string, unreadOnly?: boolean): InboxMessage[];
526
519
  sessionDeliverInbox(name: string): Promise<number>;
527
- private ultraplans;
520
+ private _kernel;
521
+ /**
522
+ * Deferreds resolved by the `autoloop` node once its engine is up, so
523
+ * `autoloopStart` can return the Planner session name the caller expects
524
+ * without polling.
525
+ */
526
+ /**
527
+ * Deferreds resolved by the `autoloop` node once its engine is up.
528
+ *
529
+ * Keyed by the start's tag rather than its run id. A run id gets reused — a
530
+ * start that failed frees it for a retry — so keying on the id let a dying
531
+ * start settle, or clear, the retry's deferred instead of its own, and the
532
+ * retry then waited forever for a signal with nowhere to land.
533
+ */
534
+ private _autoloopReady;
535
+ /**
536
+ * Run ids with a start in flight — the window between "run created" and
537
+ * "engine up". Deleting inside it would drop the run while its Planner
538
+ * session is still being created, orphaning a session that finishes a moment
539
+ * later with nothing pointing at it.
540
+ */
541
+ private _autoloopStarting;
542
+ /** Latest role selection per run, published into the node payload. */
543
+ private _autoloopSelection;
544
+ /** Per-run checkpoint refreshers, registered by the autoloop node executor. */
545
+ private _autoloopPublishers;
528
546
  ultraplanStart(task: string, opts?: {
529
547
  model?: string;
530
548
  cwd?: string;
531
549
  timeout?: number;
532
- }): UltraplanResult;
533
- private _runUltraplan;
550
+ }): Promise<UltraplanResult>;
534
551
  ultraplanStatus(id: string): UltraplanResult | undefined;
535
- private ultrareviews;
536
- private ultrareviewPollers;
537
552
  ultrareviewStart(cwd: string, opts?: {
538
553
  agentCount?: number;
539
554
  maxDurationMinutes?: number;
540
555
  model?: string;
541
556
  focus?: string;
542
557
  engines?: EngineType[];
543
- }): UltrareviewResult;
558
+ }): Promise<UltrareviewResult>;
544
559
  ultrareviewStatus(id: string): UltrareviewResult | undefined;
545
- private autoloops;
546
- private _deletingAutoloops;
547
560
  /**
548
- * Runs whose Planner is mid-startup. The delete fence was one-directional:
549
- * a start could not race a delete, but a delete COULD race a start — it would
550
- * resolve `true`, drop the registry row, and leave the still-starting Planner
551
- * session orphaned (no run to stop it, no entry to find it by). Deleting a run
552
- * that is still coming up is rejected instead.
561
+ * Build and start the Planner/Coder/Reviewer engine for a run.
562
+ *
563
+ * This is everything `autoloopStart` used to be except the bookkeeping: the
564
+ * `autoloops` map and the private JSONL registry are gone, and the kernel owns
565
+ * the lifecycle. Called from the `autoloop` node executor, which holds the
566
+ * returned objects for as long as the loop runs.
567
+ */
568
+ /**
569
+ * Resolve until the loop stops.
570
+ *
571
+ * The runner is an event emitter, not a promise: it settles when a
572
+ * `terminate` envelope is drained or the phase-error circuit trips. Cancelling
573
+ * the run stops it too, which is what makes `workflow_cancel` work on an
574
+ * autoloop.
553
575
  */
554
- private _startingAutoloops;
576
+ private _awaitAutoloopExit;
577
+ private _bootAutoloop;
555
578
  /**
556
579
  * Start a v2 autoloop in chat mode. Creates the Planner persistent session,
557
580
  * returns the run handle. Coder/Reviewer are NOT started until S3's
558
581
  * spawn_subagents tool is called.
582
+ *
583
+ * The run is a kernel run whose single `autoloop` node holds the loop for as
584
+ * long as it lives. That is what replaced the `autoloops` map, the
585
+ * `autoloop-registry.jsonl` file with its four bespoke read/write helpers, and
586
+ * the two `Set`s that fenced start against delete: a run has one owner now,
587
+ * and `runId` collisions are refused by the run store rather than by a map
588
+ * lookup that only saw this process.
559
589
  */
560
590
  autoloopStart(opts: {
561
591
  runId: string;
@@ -583,15 +613,15 @@ export declare class SessionManager {
583
613
  autoloopChat(runId: string, text: string): Promise<{
584
614
  reply: string;
585
615
  }>;
586
- autoloopStatus(runId: string): AutoloopState | undefined;
587
- autoloopList(): AutoloopState[];
588
616
  /**
589
- * Reset a single subagent on a v2 run. Useful when an agent has drifted
590
- * (chat memory implies hallucination, repeated rejects, or context bloat).
591
- * Coder/Reviewer: safe to reset; the next directive/review_request will
592
- * re-prime from system prompt + ledger artifacts.
593
- * Planner: requires force=true and discards user-conversation context.
617
+ * The running loop for a run, or a clear reason why there is not one.
618
+ *
619
+ * Chatting with a Planner needs the live dispatcher; a run that finished or
620
+ * belongs to another process has a readable record and no one to talk to.
594
621
  */
622
+ private _liveAutoloop;
623
+ autoloopStatus(runId: string): AutoloopState | undefined;
624
+ autoloopList(): AutoloopState[];
595
625
  autoloopResetAgent(runId: string, agent: 'planner' | 'coder' | 'reviewer', opts?: {
596
626
  force?: boolean;
597
627
  eagerRestart?: boolean;
@@ -614,23 +644,40 @@ export declare class SessionManager {
614
644
  * is still served via /autoloop/<id>/chat_history so the dashboard can
615
645
  * replay the conversation visually.
616
646
  */
647
+ /**
648
+ * Which roles of a stored autoloop run need a custom-engine config before it
649
+ * can be resumed.
650
+ *
651
+ * Custom-engine configs are never persisted, so a resume has to be given them
652
+ * again — and a caller that cannot find out which roles need one can only
653
+ * guess. The dashboard's Resume button used to send an empty body
654
+ * unconditionally, which meant a custom-engine run could be resumed from the
655
+ * library and from the HTTP API but not from the UI that offers the button.
656
+ *
657
+ * Returns role names only. Nothing here is sensitive: the engine kind is
658
+ * already in `spec.json`, and the answer is a list of roles, not credentials.
659
+ */
660
+ autoloopResumeRequirements(runId: string): {
661
+ runId: string;
662
+ rolesNeedingCustomEngine: AutoloopRoleName[];
663
+ };
617
664
  autoloopResume(runId: string, opts?: {
618
665
  plannerCustomEngine?: CustomEngineConfig;
619
666
  coderCustomEngine?: CustomEngineConfig;
620
667
  reviewerCustomEngine?: CustomEngineConfig;
621
668
  }): Promise<AutoloopState>;
669
+ /** Re-attach a stored autoloop run: same run id, same spec, fresh engine. */
670
+ private _resumeAutoloopRun;
622
671
  /**
623
- * Delete a run from the system: stop the runner if it's still alive in this
624
- * process, then scrub the row from the cross-process registry so it stops
625
- * appearing in `autoloop_list` / the dashboard. The ledger directory on disk
626
- * is NOT removed — postmortem artifacts (chat history, push log, plan.md)
627
- * are kept for the user to inspect or `rm` manually.
672
+ * Delete a run: really gone, not paused.
628
673
  *
629
- * Returns true if anything was removed (in-memory entry OR registry row).
674
+ * The two `Set` fences this used to open with — one refusing a delete while a
675
+ * start was in flight, one blocking a concurrent start during the async
676
+ * teardown — protected a shared `Map` that no longer exists. Cancelling the
677
+ * run is what stops it, and the run store refuses to recreate a live id.
630
678
  */
631
679
  autoloopDelete(runId: string): Promise<boolean>;
632
- private _autoloopDeleteInner;
633
- /** Used by embedded-server to attach SSE listeners. */
680
+ /** Used by embedded-server to attach SSE listeners. Live runs only. */
634
681
  getAutoloop(runId: string): {
635
682
  runner: AutoloopRunner;
636
683
  dispatcher: ClaudeAgentDispatcher;