@enderfga/claw-orchestrator 5.1.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 (147) hide show
  1. package/README.md +26 -26
  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.js +359 -4
  27. package/dist/src/index.js.map +1 -1
  28. package/dist/src/kernel/agent-step.d.ts +59 -0
  29. package/dist/src/kernel/agent-step.js +100 -0
  30. package/dist/src/kernel/agent-step.js.map +1 -0
  31. package/dist/src/kernel/conditions.d.ts +11 -0
  32. package/dist/src/kernel/conditions.js +24 -0
  33. package/dist/src/kernel/conditions.js.map +1 -0
  34. package/dist/src/kernel/engine.d.ts +319 -0
  35. package/dist/src/kernel/engine.js +1047 -0
  36. package/dist/src/kernel/engine.js.map +1 -0
  37. package/dist/src/kernel/exec.d.ts +43 -0
  38. package/dist/src/kernel/exec.js +112 -0
  39. package/dist/src/kernel/exec.js.map +1 -0
  40. package/dist/src/kernel/file-lock.d.ts +50 -0
  41. package/dist/src/kernel/file-lock.js +135 -0
  42. package/dist/src/kernel/file-lock.js.map +1 -0
  43. package/dist/src/kernel/nodes/agent.d.ts +4 -0
  44. package/dist/src/kernel/nodes/agent.js +35 -0
  45. package/dist/src/kernel/nodes/agent.js.map +1 -0
  46. package/dist/src/kernel/nodes/autoloop.d.ts +78 -0
  47. package/dist/src/kernel/nodes/autoloop.js +75 -0
  48. package/dist/src/kernel/nodes/autoloop.js.map +1 -0
  49. package/dist/src/kernel/nodes/council.d.ts +12 -0
  50. package/dist/src/kernel/nodes/council.js +88 -0
  51. package/dist/src/kernel/nodes/council.js.map +1 -0
  52. package/dist/src/kernel/nodes/fanout.d.ts +11 -0
  53. package/dist/src/kernel/nodes/fanout.js +63 -0
  54. package/dist/src/kernel/nodes/fanout.js.map +1 -0
  55. package/dist/src/kernel/nodes/human-gate.d.ts +4 -0
  56. package/dist/src/kernel/nodes/human-gate.js +7 -0
  57. package/dist/src/kernel/nodes/human-gate.js.map +1 -0
  58. package/dist/src/kernel/nodes/index.d.ts +12 -0
  59. package/dist/src/kernel/nodes/index.js +21 -0
  60. package/dist/src/kernel/nodes/index.js.map +1 -0
  61. package/dist/src/kernel/nodes/router.d.ts +4 -0
  62. package/dist/src/kernel/nodes/router.js +12 -0
  63. package/dist/src/kernel/nodes/router.js.map +1 -0
  64. package/dist/src/kernel/nodes/subflow.d.ts +13 -0
  65. package/dist/src/kernel/nodes/subflow.js +38 -0
  66. package/dist/src/kernel/nodes/subflow.js.map +1 -0
  67. package/dist/src/kernel/nodes/ultraapp.d.ts +60 -0
  68. package/dist/src/kernel/nodes/ultraapp.js +62 -0
  69. package/dist/src/kernel/nodes/ultraapp.js.map +1 -0
  70. package/dist/src/kernel/nodes/verifier.d.ts +14 -0
  71. package/dist/src/kernel/nodes/verifier.js +84 -0
  72. package/dist/src/kernel/nodes/verifier.js.map +1 -0
  73. package/dist/src/kernel/projections.d.ts +42 -0
  74. package/dist/src/kernel/projections.js +133 -0
  75. package/dist/src/kernel/projections.js.map +1 -0
  76. package/dist/src/kernel/repo.d.ts +13 -0
  77. package/dist/src/kernel/repo.js +64 -0
  78. package/dist/src/kernel/repo.js.map +1 -0
  79. package/dist/src/kernel/secrets.d.ts +25 -0
  80. package/dist/src/kernel/secrets.js +48 -0
  81. package/dist/src/kernel/secrets.js.map +1 -0
  82. package/dist/src/kernel/store.d.ts +225 -0
  83. package/dist/src/kernel/store.js +838 -0
  84. package/dist/src/kernel/store.js.map +1 -0
  85. package/dist/src/kernel/templates/index.d.ts +140 -0
  86. package/dist/src/kernel/templates/index.js +266 -0
  87. package/dist/src/kernel/templates/index.js.map +1 -0
  88. package/dist/src/kernel/types.d.ts +326 -0
  89. package/dist/src/kernel/types.js +19 -0
  90. package/dist/src/kernel/types.js.map +1 -0
  91. package/dist/src/run-ledger.d.ts +57 -3
  92. package/dist/src/run-ledger.js +45 -2
  93. package/dist/src/run-ledger.js.map +1 -1
  94. package/dist/src/session-manager.d.ts +176 -129
  95. package/dist/src/session-manager.js +652 -603
  96. package/dist/src/session-manager.js.map +1 -1
  97. package/dist/src/types.d.ts +33 -3
  98. package/dist/src/ultraapp/build.d.ts +117 -3
  99. package/dist/src/ultraapp/build.js +319 -3
  100. package/dist/src/ultraapp/build.js.map +1 -1
  101. package/dist/src/ultraapp/contract.d.ts +52 -0
  102. package/dist/src/ultraapp/contract.js +83 -0
  103. package/dist/src/ultraapp/contract.js.map +1 -0
  104. package/dist/src/ultraapp/conventions.js +9 -2
  105. package/dist/src/ultraapp/conventions.js.map +1 -1
  106. package/dist/src/ultraapp/fix-on-failure.d.ts +21 -2
  107. package/dist/src/ultraapp/fix-on-failure.js +46 -62
  108. package/dist/src/ultraapp/fix-on-failure.js.map +1 -1
  109. package/dist/src/ultraapp/manager.d.ts +107 -2
  110. package/dist/src/ultraapp/manager.js +305 -86
  111. package/dist/src/ultraapp/manager.js.map +1 -1
  112. package/dist/src/verify/baseline.d.ts +73 -0
  113. package/dist/src/verify/baseline.js +186 -0
  114. package/dist/src/verify/baseline.js.map +1 -0
  115. package/dist/src/verify/contract.d.ts +116 -0
  116. package/dist/src/verify/contract.js +142 -0
  117. package/dist/src/verify/contract.js.map +1 -0
  118. package/dist/src/verify/evidence.d.ts +61 -0
  119. package/dist/src/verify/evidence.js +133 -0
  120. package/dist/src/verify/evidence.js.map +1 -0
  121. package/dist/src/verify/runner.d.ts +63 -0
  122. package/dist/src/verify/runner.js +317 -0
  123. package/dist/src/verify/runner.js.map +1 -0
  124. package/openclaw.plugin.json +8 -0
  125. package/package.json +2 -2
  126. package/skills/SKILL.md +120 -79
  127. package/skills/references/acp.md +17 -17
  128. package/skills/references/autoloop.md +139 -65
  129. package/skills/references/claude-cli-tracking.md +4 -4
  130. package/skills/references/cli.md +101 -59
  131. package/skills/references/council.md +109 -37
  132. package/skills/references/dashboard.md +34 -6
  133. package/skills/references/getting-started.md +13 -13
  134. package/skills/references/inbox.md +4 -4
  135. package/skills/references/mcp.md +39 -34
  136. package/skills/references/multi-engine.md +51 -47
  137. package/skills/references/observability.md +88 -28
  138. package/skills/references/openai-compat.md +39 -39
  139. package/skills/references/sessions.md +43 -25
  140. package/skills/references/tools.md +402 -309
  141. package/skills/references/ultra.md +45 -45
  142. package/skills/references/ultraapp.md +126 -50
  143. package/skills/references/verification.md +187 -0
  144. package/skills/references/workflow.md +362 -0
  145. package/dist/src/ultraapp/fix-on-failure-session.d.ts +0 -23
  146. package/dist/src/ultraapp/fix-on-failure-session.js +0 -51
  147. package/dist/src/ultraapp/fix-on-failure-session.js.map +0 -1
@@ -4,29 +4,293 @@
4
4
  * Default concurrency = 1. Pending builds are FIFO. Subscribers receive every
5
5
  * BuildEvent emitted by the worker for any currently-running build.
6
6
  *
7
- * Disk persistence (in-progress + pending lists) is NOT done in v0.2 — if the
8
- * orchestrator restarts mid-build, the build is marked failed and the user
9
- * can rerun. Adding restart resilience is later scope.
7
+ * The queue is durable as of 6.0.0. It used to say so in this comment: "Disk
8
+ * persistence (in-progress + pending lists) is NOT done in v0.2 — if the
9
+ * orchestrator restarts mid-build, the build is marked failed and the user can
10
+ * rerun." In practice a restart did not mark anything: the pending list simply
11
+ * vanished, along with any queued build the user was waiting on, with no record
12
+ * that it had ever been asked for.
13
+ *
14
+ * Now the pending list and the in-flight run id are written on every change and
15
+ * restored on construction. A build that was in flight when the process died is
16
+ * re-queued rather than resumed — each build starts from a fresh council
17
+ * worktree, so re-running is safe and resuming a half-built tree is not.
18
+ *
19
+ * Durability without ownership would be worse than neither: two processes each
20
+ * restoring the same file would each run the same builds, doing every side
21
+ * effect twice. So restoring takes a lease on the state file, held by pid and
22
+ * heartbeated. A queue that cannot take the lease starts empty and leaves the
23
+ * work to whoever owns it.
10
24
  */
25
+ import crypto from 'node:crypto';
11
26
  import { EventEmitter } from 'node:events';
27
+ import fs from 'node:fs';
28
+ import path from 'node:path';
29
+ import { withFileLock } from '../kernel/file-lock.js';
30
+ /** How long an owner may go without a heartbeat before the queue is up for grabs. */
31
+ const OWNER_TTL_MS = 60_000;
32
+ /** Refresh interval, comfortably inside the TTL. */
33
+ const HEARTBEAT_MS = 15_000;
34
+ function ownerIsLive(owner, selfId) {
35
+ if (!owner)
36
+ return false;
37
+ if (owner.ownerId === selfId)
38
+ return true;
39
+ const age = Date.now() - Date.parse(owner.renewedAt);
40
+ if (Number.isNaN(age) || age > OWNER_TTL_MS)
41
+ return false;
42
+ try {
43
+ process.kill(owner.pid, 0);
44
+ return true;
45
+ }
46
+ catch (err) {
47
+ return err.code === 'EPERM';
48
+ }
49
+ }
12
50
  export class UltraappBuildQueue {
13
51
  emitter = new EventEmitter();
14
52
  pending = [];
15
53
  currentRunId = null;
16
54
  worker;
17
55
  concurrency;
56
+ statePath;
57
+ heartbeat;
58
+ /** This queue instance's identity as an owner. Per instance, not per process. */
59
+ ownerId = `queue-${crypto.randomUUID()}`;
60
+ /** Consecutive failed dispatch claims, per build. Cleared once it starts. */
61
+ dispatchRetries = new Map();
18
62
  idlePromise = Promise.resolve();
19
63
  idleResolve = null;
20
64
  constructor(opts) {
21
65
  this.worker = opts.worker;
22
66
  this.concurrency = opts.concurrency ?? 1;
67
+ this.statePath = opts.statePath;
68
+ const restored = this.restore();
69
+ if (this.statePath && !this.notOwner) {
70
+ // Independent of any build finishing: a worker that runs for ten minutes
71
+ // makes no state writes, and must not look abandoned for it.
72
+ this.heartbeat = setInterval(() => this.persist(), HEARTBEAT_MS);
73
+ if (typeof this.heartbeat.unref === 'function')
74
+ this.heartbeat.unref();
75
+ }
76
+ if (this.notOwner)
77
+ opts.onNotOwner?.(this.notOwner);
78
+ if (restored.length > 0) {
79
+ opts.onRestore?.(restored);
80
+ this.markBusy();
81
+ void this.tryDispatch();
82
+ }
83
+ }
84
+ /** Set when another live queue holds the claim. */
85
+ notOwner;
86
+ /**
87
+ * True when this process is executing the queue.
88
+ *
89
+ * Reads the state file rather than answering from the last decision, so a
90
+ * queue that has been taken over reports it even before its next write finds
91
+ * out. Advisory only — nothing acts on this answer; `enqueue` and dispatch
92
+ * re-check under the lock, because a lock-free read is a snapshot and a claim
93
+ * is not.
94
+ */
95
+ ownsQueue() {
96
+ if (this.notOwner)
97
+ return false;
98
+ if (!this.statePath)
99
+ return true;
100
+ try {
101
+ const parsed = JSON.parse(fs.readFileSync(this.statePath, 'utf8'));
102
+ if (parsed?.owner && parsed.owner.ownerId !== this.ownerId && ownerIsLive(parsed.owner, this.ownerId)) {
103
+ return false;
104
+ }
105
+ }
106
+ catch {
107
+ // No state file yet, or unreadable: nothing says anyone else has it.
108
+ }
109
+ return true;
110
+ }
111
+ /** Refuse an operation that only the owner may perform. */
112
+ assertOwner(action) {
113
+ if (!this.notOwner)
114
+ return;
115
+ throw new Error(`Cannot ${action}: this build queue is owned by ${this.notOwner.ownerId} (pid ${this.notOwner.pid}) ` +
116
+ `(last seen ${this.notOwner.renewedAt}). Running its builds here would execute them twice.`);
117
+ }
118
+ /** Release the claim so another process can pick the queue up promptly. */
119
+ stop() {
120
+ if (this.heartbeat)
121
+ clearInterval(this.heartbeat);
122
+ this.heartbeat = undefined;
123
+ }
124
+ /**
125
+ * Read back a queue left by a previous process.
126
+ *
127
+ * A build that was in flight goes to the FRONT of the restored queue: it was
128
+ * asked for first, and the user has been waiting on it longest.
129
+ */
130
+ /**
131
+ * Claim the queue and read back whatever the last owner left.
132
+ *
133
+ * Read-then-decide is not a claim. Two processes starting with no state file
134
+ * both saw "free", both concluded they owned it, and nothing wrote an owner
135
+ * until the first enqueue — by which time both were running the same builds.
136
+ * The read and the claim happen inside one `O_EXCL` critical section now.
137
+ */
138
+ restore() {
139
+ if (!this.statePath)
140
+ return [];
141
+ let entered = false;
142
+ const ids = this.withLock(() => {
143
+ entered = true;
144
+ return this.claimLocked();
145
+ }, []);
146
+ if (!entered && !this.notOwner) {
147
+ // We never got inside the critical section — someone else is claiming
148
+ // right now, or the lock file is unusable. Either way we have not taken
149
+ // the queue, and acting as though we had is how both processes end up
150
+ // running the same builds.
151
+ this.notOwner = { ownerId: 'unknown', pid: -1, renewedAt: new Date().toISOString() };
152
+ }
153
+ return ids ?? [];
154
+ }
155
+ /**
156
+ * Run `fn` inside the queue's lock, waiting briefly for it.
157
+ *
158
+ * Shared with the run store, and for the same reason: a lock that is merely
159
+ * busy must not be reported the same way as a claim that has moved on.
160
+ */
161
+ withLock(fn, onContended) {
162
+ if (!this.statePath)
163
+ return undefined;
164
+ const result = withFileLock(`${this.statePath}.lock`, fn, { staleMs: OWNER_TTL_MS, createParent: true });
165
+ return result.ok ? result.value : onContended;
166
+ }
167
+ /** The critical section of `restore`: inspect the owner and take it, or step aside. */
168
+ claimLocked() {
169
+ if (!this.statePath)
170
+ return [];
171
+ let parsed;
172
+ try {
173
+ parsed = JSON.parse(fs.readFileSync(this.statePath, 'utf8'));
174
+ }
175
+ catch {
176
+ parsed = { pending: [], current: null };
177
+ }
178
+ if (ownerIsLive(parsed.owner, this.ownerId)) {
179
+ // Someone else is running these. Taking them would execute every build
180
+ // twice; the honest move is to start empty and say so.
181
+ this.notOwner = parsed.owner;
182
+ return [];
183
+ }
184
+ const ids = [
185
+ ...(parsed.current ? [parsed.current] : []),
186
+ ...(Array.isArray(parsed.pending) ? parsed.pending.filter((x) => typeof x === 'string') : []),
187
+ ];
188
+ for (const runId of ids)
189
+ this.pending.push({ runId });
190
+ // Stake the claim before releasing the lock, so a racer that gets in next
191
+ // sees an owner rather than an empty file.
192
+ this.writeStateUnchecked();
193
+ return ids;
194
+ }
195
+ /**
196
+ * Persist the queue, if we still own it.
197
+ *
198
+ * Best-effort about I/O, not about ownership: the check happens inside the
199
+ * lock, in the same critical section as the write. Taking the claim at
200
+ * construction and then writing unconditionally forever was not ownership — a
201
+ * queue whose heartbeat had lapsed and been taken over would quietly stamp
202
+ * itself back in as owner on its next persist, clobbering the new owner's
203
+ * pending list and running its builds a second time.
204
+ */
205
+ persist() {
206
+ if (!this.statePath)
207
+ return 'ephemeral';
208
+ if (this.notOwner)
209
+ return 'superseded';
210
+ return this.withLock(() => this.writeStateLocked(), 'blocked') ?? 'blocked';
211
+ }
212
+ /** Caller must hold the lock. Steps aside — permanently — if the claim moved on. */
213
+ writeStateLocked() {
214
+ if (!this.statePath)
215
+ return 'ephemeral';
216
+ let parsed;
217
+ try {
218
+ parsed = JSON.parse(fs.readFileSync(this.statePath, 'utf8'));
219
+ }
220
+ catch {
221
+ parsed = undefined;
222
+ }
223
+ if (parsed?.owner && parsed.owner.ownerId !== this.ownerId && ownerIsLive(parsed.owner, this.ownerId)) {
224
+ this.standDown(parsed.owner);
225
+ return 'superseded';
226
+ }
227
+ this.writeStateUnchecked();
228
+ return 'committed';
229
+ }
230
+ /**
231
+ * Hand the queue over: stop heartbeating and drop the pending list.
232
+ *
233
+ * Keeping the list would be worse than losing it — every entry now belongs to
234
+ * the new owner, who has its own copy, and dispatching from ours is the double
235
+ * execution the claim exists to prevent. A build already in flight cannot be
236
+ * recalled; it finishes, and nothing further starts.
237
+ */
238
+ standDown(owner) {
239
+ this.notOwner = owner;
240
+ this.stop();
241
+ this.pending.length = 0;
242
+ if (this.currentRunId === null)
243
+ this.markIdle();
244
+ }
245
+ writeStateUnchecked() {
246
+ if (!this.statePath)
247
+ return;
248
+ try {
249
+ fs.mkdirSync(path.dirname(this.statePath), { recursive: true });
250
+ const state = {
251
+ pending: this.pending.map((p) => p.runId),
252
+ current: this.currentRunId,
253
+ // Every write is also the heartbeat, so a queue that stops making
254
+ // progress stops holding the claim.
255
+ owner: { ownerId: this.ownerId, pid: process.pid, renewedAt: new Date().toISOString() },
256
+ };
257
+ const tmp = `${this.statePath}.tmp.${process.pid}.${crypto.randomBytes(4).toString('hex')}`;
258
+ fs.writeFileSync(tmp, JSON.stringify(state));
259
+ fs.renameSync(tmp, this.statePath);
260
+ }
261
+ catch {
262
+ // A queue that cannot be persisted still works for this process.
263
+ }
23
264
  }
24
265
  /**
25
266
  * Enqueue a build. Resolves immediately after the run is appended to the
26
267
  * pending list. Use {@link idle} to wait for the queue to drain.
27
268
  */
28
269
  async enqueue(runId) {
270
+ // Refusing at construction is not enough: `ownsQueue()` returning false
271
+ // while `enqueue` cheerfully ran the build — and rewrote the owner to
272
+ // ourselves — is exactly the double execution the claim exists to stop.
273
+ this.assertOwner('enqueue');
29
274
  this.pending.push({ runId });
275
+ // The claim is re-checked inside the same critical section the write happens
276
+ // in. Owning the queue at construction says nothing about owning it now: the
277
+ // heartbeat can have lapsed and someone else can have taken over, and an
278
+ // `enqueue` that only consulted the construction-time answer would run their
279
+ // builds a second time.
280
+ //
281
+ // Three outcomes, not two. `superseded` refuses. `blocked` — we could not
282
+ // even get into the critical section — also refuses, because an enqueue that
283
+ // cannot be recorded may be an enqueue into a queue somebody else now owns;
284
+ // the earlier version returned a bare `false` here and carried on, and ran a
285
+ // build whose queue state on disk already belonged to another process.
286
+ const persisted = this.persist();
287
+ if (persisted === 'superseded')
288
+ this.assertOwner('enqueue');
289
+ if (persisted === 'blocked') {
290
+ this.pending.pop();
291
+ throw new Error(`Cannot enqueue: the build queue state file is locked by another process, so this build cannot be ` +
292
+ `recorded. Retry in a moment.`);
293
+ }
30
294
  this.markBusy();
31
295
  const pos = this.position(runId);
32
296
  if (pos > 0) {
@@ -38,6 +302,7 @@ export class UltraappBuildQueue {
38
302
  const idx = this.pending.findIndex((p) => p.runId === runId);
39
303
  if (idx >= 0) {
40
304
  this.pending.splice(idx, 1);
305
+ this.persist();
41
306
  this.emit({ type: 'build-cancelled', runId });
42
307
  if (this.pending.length === 0 && this.currentRunId === null)
43
308
  this.markIdle();
@@ -65,6 +330,8 @@ export class UltraappBuildQueue {
65
330
  return this.idlePromise;
66
331
  }
67
332
  async tryDispatch() {
333
+ if (this.notOwner)
334
+ return;
68
335
  if (this.currentRunId !== null)
69
336
  return;
70
337
  if (this.concurrency !== 1)
@@ -75,6 +342,25 @@ export class UltraappBuildQueue {
75
342
  return;
76
343
  }
77
344
  this.currentRunId = next.runId;
345
+ // Same check before starting work as before recording it, and with the same
346
+ // three outcomes: only `committed` (or an ephemeral queue, which owns
347
+ // nothing and persists nothing) may dispatch. Dispatching on `blocked` is
348
+ // how a superseded queue ran a build whose state on disk already named
349
+ // another owner.
350
+ const persisted = this.persist();
351
+ if (persisted === 'superseded') {
352
+ this.currentRunId = null;
353
+ this.markIdle();
354
+ return;
355
+ }
356
+ if (persisted === 'blocked') {
357
+ // Transient: put the build back at the front and try again shortly.
358
+ this.currentRunId = null;
359
+ this.pending.unshift(next);
360
+ this._retryDispatch(next.runId);
361
+ return;
362
+ }
363
+ this.dispatchRetries.delete(next.runId);
78
364
  try {
79
365
  await this.worker(next.runId, (e) => this.emit(e));
80
366
  }
@@ -88,9 +374,39 @@ export class UltraappBuildQueue {
88
374
  }
89
375
  finally {
90
376
  this.currentRunId = null;
377
+ this.persist();
91
378
  void this.tryDispatch();
92
379
  }
93
380
  }
381
+ /**
382
+ * Re-attempt a dispatch that could not claim the state file.
383
+ *
384
+ * Bounded: a queue that cannot record what it is doing must eventually say so
385
+ * rather than spinning, and the build is failed with the reason instead of
386
+ * quietly never starting.
387
+ */
388
+ _retryDispatch(runId) {
389
+ const attempts = (this.dispatchRetries.get(runId) ?? 0) + 1;
390
+ this.dispatchRetries.set(runId, attempts);
391
+ if (attempts > 8) {
392
+ this.dispatchRetries.delete(runId);
393
+ const idx = this.pending.findIndex((p) => p.runId === runId);
394
+ if (idx >= 0)
395
+ this.pending.splice(idx, 1);
396
+ this.emit({
397
+ type: 'build-failed',
398
+ runId,
399
+ phase: 'orchestrator',
400
+ reason: 'the build queue state file stayed locked by another process; the build was not started',
401
+ });
402
+ if (this.pending.length === 0 && this.currentRunId === null)
403
+ this.markIdle();
404
+ return;
405
+ }
406
+ const timer = setTimeout(() => void this.tryDispatch(), 100 * attempts);
407
+ if (typeof timer.unref === 'function')
408
+ timer.unref();
409
+ }
94
410
  emit(e) {
95
411
  this.emitter.emit('event', e);
96
412
  }
@@ -1 +1 @@
1
- {"version":3,"file":"build.js","sourceRoot":"","sources":["../../../src/ultraapp/build.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../../src/ultraapp/build.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * UltraApp's acceptance contracts — the only mode whose contract is on by default.
3
+ *
4
+ * It earns that because it already ran most of these commands, and because its
5
+ * own documentation has claimed two gates that the code never enforced:
6
+ *
7
+ * 1. `conventions.ts` §4 states "fix-on-failure runs `npm run smoke` and gates
8
+ * build-success on its passing". It did not — the step list was install /
9
+ * build / test / docker-build, with no smoke anywhere. The claim is now true.
10
+ * 2. `ultraapp.md` recorded, as a known limitation since 4.0.0, that the §7g
11
+ * frontend gate "relies on per-agent honesty about running the screenshot
12
+ * capture", with a follow-up promised to make it structural. The capture is
13
+ * now performed by the runtime against the deployed URL and stored as
14
+ * evidence, so whether it happened is no longer an agent's word.
15
+ *
16
+ * What §7g still does not do is judge the pixels. A human or an agent still
17
+ * decides whether the render is acceptable; the runtime guarantees only that the
18
+ * images exist and are of the deployed app. Calling that visual regression would
19
+ * be the same overclaim this module exists to remove.
20
+ */
21
+ import type { AcceptanceContract } from '../verify/contract.js';
22
+ /** §7g's two viewports, unchanged from the convention text agents were given. */
23
+ export declare const UI_VIEWPORTS: {
24
+ width: number;
25
+ height: number;
26
+ label: string;
27
+ }[];
28
+ export interface BuildContractOptions {
29
+ useDocker: boolean;
30
+ fixRounds?: number;
31
+ }
32
+ /**
33
+ * Build-stage checks, run in the council's worktree. The order is the old
34
+ * `DEFAULT_STEPS` order, plus the smoke step the docs already promised.
35
+ */
36
+ export declare function ultraappBuildContract(opts: BuildContractOptions): AcceptanceContract;
37
+ /**
38
+ * Whether a missing/failed screenshot capture should fail the deploy.
39
+ *
40
+ * Default is lenient: capture and store, record a failure, but do not sink a
41
+ * working app because the host has no Chrome. `CLAWO_ULTRAAPP_VISUAL_GATE=strict`
42
+ * makes it binding for setups that want §7g fully enforced.
43
+ */
44
+ export declare function visualGateIsStrict(env?: NodeJS.ProcessEnv): boolean;
45
+ /**
46
+ * Deploy-stage checks, run against the live URL.
47
+ *
48
+ * No health probe here on purpose: `deployArtifact` already polls `/health` and
49
+ * refuses to report success without it, so re-probing would be a second source
50
+ * of truth for a question that is already settled.
51
+ */
52
+ export declare function ultraappDeployContract(url: string, env?: NodeJS.ProcessEnv): AcceptanceContract;
@@ -0,0 +1,83 @@
1
+ /**
2
+ * UltraApp's acceptance contracts — the only mode whose contract is on by default.
3
+ *
4
+ * It earns that because it already ran most of these commands, and because its
5
+ * own documentation has claimed two gates that the code never enforced:
6
+ *
7
+ * 1. `conventions.ts` §4 states "fix-on-failure runs `npm run smoke` and gates
8
+ * build-success on its passing". It did not — the step list was install /
9
+ * build / test / docker-build, with no smoke anywhere. The claim is now true.
10
+ * 2. `ultraapp.md` recorded, as a known limitation since 4.0.0, that the §7g
11
+ * frontend gate "relies on per-agent honesty about running the screenshot
12
+ * capture", with a follow-up promised to make it structural. The capture is
13
+ * now performed by the runtime against the deployed URL and stored as
14
+ * evidence, so whether it happened is no longer an agent's word.
15
+ *
16
+ * What §7g still does not do is judge the pixels. A human or an agent still
17
+ * decides whether the render is acceptable; the runtime guarantees only that the
18
+ * images exist and are of the deployed app. Calling that visual regression would
19
+ * be the same overclaim this module exists to remove.
20
+ */
21
+ /** §7g's two viewports, unchanged from the convention text agents were given. */
22
+ export const UI_VIEWPORTS = [
23
+ { width: 1440, height: 900, label: 'desktop' },
24
+ { width: 375, height: 812, label: 'mobile' },
25
+ ];
26
+ const TEN_MIN = 10 * 60_000;
27
+ /**
28
+ * Build-stage checks, run in the council's worktree. The order is the old
29
+ * `DEFAULT_STEPS` order, plus the smoke step the docs already promised.
30
+ */
31
+ export function ultraappBuildContract(opts) {
32
+ const checks = [
33
+ { id: 'install', spec: { type: 'command', cmd: 'npm', args: ['install'], timeoutMs: TEN_MIN }, required: true },
34
+ { id: 'build', spec: { type: 'command', cmd: 'npm', args: ['run', 'build'], timeoutMs: TEN_MIN }, required: true },
35
+ { id: 'test', spec: { type: 'command', cmd: 'npm', args: ['test'], timeoutMs: TEN_MIN }, required: true },
36
+ ];
37
+ if (opts.useDocker) {
38
+ checks.push({
39
+ id: 'docker-build',
40
+ spec: { type: 'command', cmd: 'docker', args: ['build', '-t', 'ultraapp-fix:test', '.'], timeoutMs: TEN_MIN },
41
+ required: true,
42
+ });
43
+ }
44
+ // Required, because §4 of the conventions makes `scripts.smoke` mandatory and
45
+ // tells the council the gate is binding. A codebase without it has not met the
46
+ // brief it was given.
47
+ checks.push({
48
+ id: 'smoke',
49
+ spec: { type: 'command', cmd: 'npm', args: ['run', 'smoke'], timeoutMs: TEN_MIN },
50
+ required: true,
51
+ });
52
+ return { id: 'ultraapp-build', checks, fixOnFailureRounds: opts.fixRounds ?? 5 };
53
+ }
54
+ /**
55
+ * Whether a missing/failed screenshot capture should fail the deploy.
56
+ *
57
+ * Default is lenient: capture and store, record a failure, but do not sink a
58
+ * working app because the host has no Chrome. `CLAWO_ULTRAAPP_VISUAL_GATE=strict`
59
+ * makes it binding for setups that want §7g fully enforced.
60
+ */
61
+ export function visualGateIsStrict(env = process.env) {
62
+ return (env.CLAWO_ULTRAAPP_VISUAL_GATE || '').toLowerCase() === 'strict';
63
+ }
64
+ /**
65
+ * Deploy-stage checks, run against the live URL.
66
+ *
67
+ * No health probe here on purpose: `deployArtifact` already polls `/health` and
68
+ * refuses to report success without it, so re-probing would be a second source
69
+ * of truth for a question that is already settled.
70
+ */
71
+ export function ultraappDeployContract(url, env = process.env) {
72
+ return {
73
+ id: 'ultraapp-deploy',
74
+ checks: [
75
+ {
76
+ id: 'frontend-gate',
77
+ spec: { type: 'screenshot', url, viewports: UI_VIEWPORTS },
78
+ required: visualGateIsStrict(env),
79
+ },
80
+ ],
81
+ };
82
+ }
83
+ //# sourceMappingURL=contract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../../../src/ultraapp/contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,iFAAiF;AACjF,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,SAAS,EAAE;IAC9C,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,QAAQ,EAAE;CAC7C,CAAC;AAEF,MAAM,OAAO,GAAG,EAAE,GAAG,MAAM,CAAC;AAO5B;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAA0B;IAC9D,MAAM,MAAM,GAAoB;QAC9B,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;QAC/G,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;QAClH,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE;KAC1G,CAAC;IACF,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,MAAM,CAAC,IAAI,CAAC;YACV,EAAE,EAAE,cAAc;YAClB,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,IAAI,EAAE,mBAAmB,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE;YAC7G,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;IACL,CAAC;IACD,8EAA8E;IAC9E,+EAA+E;IAC/E,sBAAsB;IACtB,MAAM,CAAC,IAAI,CAAC;QACV,EAAE,EAAE,OAAO;QACX,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE;QACjF,QAAQ,EAAE,IAAI;KACf,CAAC,CAAC;IAEH,OAAO,EAAE,EAAE,EAAE,gBAAgB,EAAE,MAAM,EAAE,kBAAkB,EAAE,IAAI,CAAC,SAAS,IAAI,CAAC,EAAE,CAAC;AACnF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACrE,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,KAAK,QAAQ,CAAC;AAC3E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CAAC,GAAW,EAAE,MAAyB,OAAO,CAAC,GAAG;IACtF,OAAO;QACL,EAAE,EAAE,iBAAiB;QACrB,MAAM,EAAE;YACN;gBACE,EAAE,EAAE,eAAe;gBACnB,IAAI,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,SAAS,EAAE,YAAY,EAAE;gBAC1D,QAAQ,EAAE,kBAAkB,CAAC,GAAG,CAAC;aAClC;SACF;KACF,CAAC;AACJ,CAAC"}
@@ -92,8 +92,9 @@ internally. ENTRYPOINT runs the production server. Build args:
92
92
  Smoke test: package.json must expose "scripts.smoke" that drives ONE complete
93
93
  job using AppSpec.inputs[].examples[0].ref files copied into the image at
94
94
  build time under $DATA_DIR/_smoke/. The smoke test asserts pipeline completes and
95
- output matches AppSpec.outputs[].type. fix-on-failure runs "npm run smoke" and
96
- gates build-success on its passing.
95
+ output matches AppSpec.outputs[].type. The orchestrator runs "npm run smoke"
96
+ itself as part of the build acceptance contract and gates build-success on its
97
+ exit code — a codebase without a working "scripts.smoke" does not build.
97
98
 
98
99
  Smoke test must complete in < 90 seconds for the reference-trace inputs
99
100
  provided. If your pipeline genuinely takes longer, design the smoke test to
@@ -205,6 +206,12 @@ tags, class names, and \`@media\` queries don't tell you what the page
205
206
  actually looks like. You MUST capture screenshots and look at the pixels
206
207
  before voting.
207
208
 
209
+ Note on who checks what: after deployment the orchestrator captures both
210
+ viewports against the live URL itself and stores the PNGs as run evidence,
211
+ so whether a capture happened is no longer taken on trust. It does not
212
+ judge the rendering — that is still your job, and it is why the steps
213
+ below are yours to perform in your own worktree before you vote.
214
+
208
215
  Before voting [CONSENSUS: YES], EVERY agent MUST:
209
216
 
210
217
  1. Start the dev/preview server in their worktree (\`npm run preview\` or
@@ -1 +1 @@
1
- {"version":3,"file":"conventions.js","sourceRoot":"","sources":["../../../src/ultraapp/conventions.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,CAAC,MAAM,yBAAyB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+OxC,CAAC,IAAI,EAAE,CAAC"}
1
+ {"version":3,"file":"conventions.js","sourceRoot":"","sources":["../../../src/ultraapp/conventions.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,CAAC,MAAM,yBAAyB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsPxC,CAAC,IAAI,EAAE,CAAC"}
@@ -1,10 +1,18 @@
1
1
  /**
2
- * Purpose-built helper: run the standard verification pipeline in a worktree,
3
- * spawn a Claude session to fix mechanical errors on red, retry up to N rounds.
2
+ * Run the verification pipeline in a worktree, spawn a session to fix mechanical
3
+ * errors on red, retry up to N rounds.
4
+ *
5
+ * As of 6.0.0 this is an adapter over `src/verify/`, not its own runner. The
6
+ * logic it used to own — ordered steps, exit-code gating, byte-capped tails, the
7
+ * fix loop — moved out to become mode-agnostic, and came back with the two
8
+ * things it was missing: a per-step timeout (a wedged `npm test` used to hang
9
+ * the pipeline forever) and an honoured `required` flag (the field was declared
10
+ * here and never read, so every step was fatal).
4
11
  *
5
12
  * Not to be confused with src/autoloop/, which is a planner/coder/reviewer
6
13
  * message-bus orchestrator for a different problem shape.
7
14
  */
15
+ import type { AcceptanceContract, CheckResult } from '../verify/contract.js';
8
16
  export interface ShellResult {
9
17
  ok: boolean;
10
18
  stdout: string;
@@ -24,16 +32,27 @@ export interface FixOnFailureArgs {
24
32
  maxRounds: number;
25
33
  shell?: ShellRunner;
26
34
  spawnFixer?: FixerSpawner;
35
+ /** Legacy step list. Each entry becomes a `command` check. */
27
36
  steps?: Array<{
28
37
  cmd: string;
29
38
  args: string[];
30
39
  required?: boolean;
40
+ timeoutMs?: number;
31
41
  }>;
42
+ /** Full acceptance contract. Takes precedence over `steps`. */
43
+ contract?: AcceptanceContract;
44
+ /** Where screenshot-style checks drop files. Defaults to a temp dir. */
45
+ artifactDir?: string;
32
46
  }
33
47
  export interface FixOnFailureResult {
34
48
  ok: boolean;
35
49
  rounds: number;
36
50
  lastError?: string;
37
51
  failingCommand?: string;
52
+ /** Per-check outcomes, for an evidence bundle. Absent on stubbed results. */
53
+ results?: CheckResult[];
38
54
  }
55
+ export declare const DEFAULT_STEPS: NonNullable<FixOnFailureArgs['steps']>;
56
+ /** Translate the legacy step list into contract checks, `required` included this time. */
57
+ export declare function stepsToContract(steps: NonNullable<FixOnFailureArgs['steps']>, fixOnFailureRounds: number): AcceptanceContract;
39
58
  export declare function runFixOnFailure(args: FixOnFailureArgs): Promise<FixOnFailureResult>;