@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.
- package/README.md +28 -28
- package/dist/bin/cli.js +107 -1
- package/dist/bin/cli.js.map +1 -1
- package/dist/src/acp-server.d.ts +5 -5
- package/dist/src/acp-server.js +3 -3
- package/dist/src/acp-server.js.map +1 -1
- package/dist/src/autoloop/dispatcher.d.ts +22 -0
- package/dist/src/autoloop/dispatcher.js +71 -13
- package/dist/src/autoloop/dispatcher.js.map +1 -1
- package/dist/src/autoloop/messages.d.ts +10 -0
- package/dist/src/autoloop/messages.js.map +1 -1
- package/dist/src/autoloop/runner.js +6 -0
- package/dist/src/autoloop/runner.js.map +1 -1
- package/dist/src/constants.d.ts +0 -6
- package/dist/src/constants.js +0 -6
- package/dist/src/constants.js.map +1 -1
- package/dist/src/council.d.ts +15 -0
- package/dist/src/council.js +48 -35
- package/dist/src/council.js.map +1 -1
- package/dist/src/dashboard/index.html +191 -6
- package/dist/src/embedded-server.js +132 -9
- package/dist/src/embedded-server.js.map +1 -1
- package/dist/src/fanout.d.ts +30 -1
- package/dist/src/fanout.js +32 -3
- package/dist/src/fanout.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.js +360 -4
- package/dist/src/index.js.map +1 -1
- package/dist/src/kernel/agent-step.d.ts +59 -0
- package/dist/src/kernel/agent-step.js +100 -0
- package/dist/src/kernel/agent-step.js.map +1 -0
- package/dist/src/kernel/conditions.d.ts +11 -0
- package/dist/src/kernel/conditions.js +24 -0
- package/dist/src/kernel/conditions.js.map +1 -0
- package/dist/src/kernel/engine.d.ts +319 -0
- package/dist/src/kernel/engine.js +1047 -0
- package/dist/src/kernel/engine.js.map +1 -0
- package/dist/src/kernel/exec.d.ts +43 -0
- package/dist/src/kernel/exec.js +112 -0
- package/dist/src/kernel/exec.js.map +1 -0
- package/dist/src/kernel/file-lock.d.ts +50 -0
- package/dist/src/kernel/file-lock.js +135 -0
- package/dist/src/kernel/file-lock.js.map +1 -0
- package/dist/src/kernel/nodes/agent.d.ts +4 -0
- package/dist/src/kernel/nodes/agent.js +35 -0
- package/dist/src/kernel/nodes/agent.js.map +1 -0
- package/dist/src/kernel/nodes/autoloop.d.ts +78 -0
- package/dist/src/kernel/nodes/autoloop.js +75 -0
- package/dist/src/kernel/nodes/autoloop.js.map +1 -0
- package/dist/src/kernel/nodes/council.d.ts +12 -0
- package/dist/src/kernel/nodes/council.js +88 -0
- package/dist/src/kernel/nodes/council.js.map +1 -0
- package/dist/src/kernel/nodes/fanout.d.ts +11 -0
- package/dist/src/kernel/nodes/fanout.js +63 -0
- package/dist/src/kernel/nodes/fanout.js.map +1 -0
- package/dist/src/kernel/nodes/human-gate.d.ts +4 -0
- package/dist/src/kernel/nodes/human-gate.js +7 -0
- package/dist/src/kernel/nodes/human-gate.js.map +1 -0
- package/dist/src/kernel/nodes/index.d.ts +12 -0
- package/dist/src/kernel/nodes/index.js +21 -0
- package/dist/src/kernel/nodes/index.js.map +1 -0
- package/dist/src/kernel/nodes/router.d.ts +4 -0
- package/dist/src/kernel/nodes/router.js +12 -0
- package/dist/src/kernel/nodes/router.js.map +1 -0
- package/dist/src/kernel/nodes/subflow.d.ts +13 -0
- package/dist/src/kernel/nodes/subflow.js +38 -0
- package/dist/src/kernel/nodes/subflow.js.map +1 -0
- package/dist/src/kernel/nodes/ultraapp.d.ts +60 -0
- package/dist/src/kernel/nodes/ultraapp.js +62 -0
- package/dist/src/kernel/nodes/ultraapp.js.map +1 -0
- package/dist/src/kernel/nodes/verifier.d.ts +14 -0
- package/dist/src/kernel/nodes/verifier.js +84 -0
- package/dist/src/kernel/nodes/verifier.js.map +1 -0
- package/dist/src/kernel/projections.d.ts +42 -0
- package/dist/src/kernel/projections.js +133 -0
- package/dist/src/kernel/projections.js.map +1 -0
- package/dist/src/kernel/repo.d.ts +13 -0
- package/dist/src/kernel/repo.js +64 -0
- package/dist/src/kernel/repo.js.map +1 -0
- package/dist/src/kernel/secrets.d.ts +25 -0
- package/dist/src/kernel/secrets.js +48 -0
- package/dist/src/kernel/secrets.js.map +1 -0
- package/dist/src/kernel/store.d.ts +225 -0
- package/dist/src/kernel/store.js +838 -0
- package/dist/src/kernel/store.js.map +1 -0
- package/dist/src/kernel/templates/index.d.ts +140 -0
- package/dist/src/kernel/templates/index.js +266 -0
- package/dist/src/kernel/templates/index.js.map +1 -0
- package/dist/src/kernel/types.d.ts +326 -0
- package/dist/src/kernel/types.js +19 -0
- package/dist/src/kernel/types.js.map +1 -0
- package/dist/src/models.d.ts +1 -1
- package/dist/src/models.js +31 -3
- package/dist/src/models.js.map +1 -1
- package/dist/src/persistent-cursor-session.js +6 -1
- package/dist/src/persistent-cursor-session.js.map +1 -1
- package/dist/src/persistent-grok-session.d.ts +40 -0
- package/dist/src/persistent-grok-session.js +197 -0
- package/dist/src/persistent-grok-session.js.map +1 -0
- package/dist/src/run-ledger.d.ts +57 -3
- package/dist/src/run-ledger.js +45 -2
- package/dist/src/run-ledger.js.map +1 -1
- package/dist/src/session-manager.d.ts +176 -129
- package/dist/src/session-manager.js +657 -603
- package/dist/src/session-manager.js.map +1 -1
- package/dist/src/types.d.ts +37 -4
- package/dist/src/types.js +15 -1
- package/dist/src/types.js.map +1 -1
- package/dist/src/ultraapp/build.d.ts +117 -3
- package/dist/src/ultraapp/build.js +319 -3
- package/dist/src/ultraapp/build.js.map +1 -1
- package/dist/src/ultraapp/contract.d.ts +52 -0
- package/dist/src/ultraapp/contract.js +83 -0
- package/dist/src/ultraapp/contract.js.map +1 -0
- package/dist/src/ultraapp/conventions.js +9 -2
- package/dist/src/ultraapp/conventions.js.map +1 -1
- package/dist/src/ultraapp/fix-on-failure.d.ts +21 -2
- package/dist/src/ultraapp/fix-on-failure.js +46 -62
- package/dist/src/ultraapp/fix-on-failure.js.map +1 -1
- package/dist/src/ultraapp/manager.d.ts +107 -2
- package/dist/src/ultraapp/manager.js +305 -86
- package/dist/src/ultraapp/manager.js.map +1 -1
- package/dist/src/verify/baseline.d.ts +73 -0
- package/dist/src/verify/baseline.js +186 -0
- package/dist/src/verify/baseline.js.map +1 -0
- package/dist/src/verify/contract.d.ts +116 -0
- package/dist/src/verify/contract.js +142 -0
- package/dist/src/verify/contract.js.map +1 -0
- package/dist/src/verify/evidence.d.ts +61 -0
- package/dist/src/verify/evidence.js +133 -0
- package/dist/src/verify/evidence.js.map +1 -0
- package/dist/src/verify/runner.d.ts +63 -0
- package/dist/src/verify/runner.js +317 -0
- package/dist/src/verify/runner.js.map +1 -0
- package/openclaw.plugin.json +8 -0
- package/package.json +2 -2
- package/skills/SKILL.md +121 -80
- package/skills/references/acp.md +18 -18
- package/skills/references/autoloop.md +148 -72
- package/skills/references/claude-cli-tracking.md +4 -4
- package/skills/references/cli.md +103 -60
- package/skills/references/council.md +109 -37
- package/skills/references/dashboard.md +34 -6
- package/skills/references/getting-started.md +14 -14
- package/skills/references/inbox.md +4 -4
- package/skills/references/mcp.md +39 -34
- package/skills/references/multi-engine.md +109 -51
- package/skills/references/observability.md +88 -27
- package/skills/references/openai-compat.md +40 -40
- package/skills/references/sessions.md +44 -26
- package/skills/references/tools.md +402 -309
- package/skills/references/ultra.md +45 -45
- package/skills/references/ultraapp.md +126 -50
- package/skills/references/verification.md +187 -0
- package/skills/references/workflow.md +362 -0
- package/dist/src/ultraapp/fix-on-failure-session.d.ts +0 -23
- package/dist/src/ultraapp/fix-on-failure-session.js +0 -51
- package/dist/src/ultraapp/fix-on-failure-session.js.map +0 -1
|
@@ -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.
|
|
96
|
-
gates build-success on its
|
|
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
|
|
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
|
-
*
|
|
3
|
-
*
|
|
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>;
|
|
@@ -1,76 +1,60 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
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
|
*/
|
|
8
|
-
import
|
|
9
|
-
|
|
15
|
+
import path from 'node:path';
|
|
16
|
+
import os from 'node:os';
|
|
17
|
+
import { runContract } from '../verify/runner.js';
|
|
18
|
+
const TEN_MIN = 10 * 60_000;
|
|
19
|
+
export const DEFAULT_STEPS = [
|
|
10
20
|
{ cmd: 'npm', args: ['install'] },
|
|
11
21
|
{ cmd: 'npm', args: ['run', 'build'] },
|
|
12
22
|
{ cmd: 'npm', args: ['test'] },
|
|
13
23
|
{ cmd: 'docker', args: ['build', '-t', 'ultraapp-fix:test', '.'] },
|
|
14
24
|
];
|
|
15
|
-
|
|
16
|
-
export
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (failure === null)
|
|
24
|
-
return { ok: true, rounds };
|
|
25
|
-
if (rounds >= args.maxRounds) {
|
|
26
|
-
return {
|
|
27
|
-
ok: false,
|
|
28
|
-
rounds,
|
|
29
|
-
lastError: failure.lastError,
|
|
30
|
-
failingCommand: failure.failingCommand,
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
rounds++;
|
|
34
|
-
await spawnFixer({
|
|
35
|
-
worktreePath: args.worktreePath,
|
|
36
|
-
failingCommand: failure.failingCommand,
|
|
37
|
-
tail: failure.tail,
|
|
38
|
-
});
|
|
39
|
-
}
|
|
25
|
+
/** Translate the legacy step list into contract checks, `required` included this time. */
|
|
26
|
+
export function stepsToContract(steps, fixOnFailureRounds) {
|
|
27
|
+
const checks = steps.map((s, i) => ({
|
|
28
|
+
id: `${s.cmd}-${i + 1}`,
|
|
29
|
+
spec: { type: 'command', cmd: s.cmd, args: s.args, timeoutMs: s.timeoutMs ?? TEN_MIN },
|
|
30
|
+
required: s.required !== false,
|
|
31
|
+
}));
|
|
32
|
+
return { id: 'fix-on-failure', checks, fixOnFailureRounds };
|
|
40
33
|
}
|
|
41
|
-
async function
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
34
|
+
export async function runFixOnFailure(args) {
|
|
35
|
+
const contract = args.contract ?? stepsToContract(args.steps ?? DEFAULT_STEPS, args.maxRounds);
|
|
36
|
+
const spawnFixer = args.spawnFixer
|
|
37
|
+
? ({ cwd, failingCheck, tail }) => args.spawnFixer({ worktreePath: cwd, failingCommand: failingCheck, tail })
|
|
38
|
+
: undefined;
|
|
39
|
+
const { results, passed, rounds } = await runContract({ ...contract, fixOnFailureRounds: args.maxRounds }, {
|
|
40
|
+
cwd: args.worktreePath,
|
|
41
|
+
artifactDir: args.artifactDir ?? path.join(os.tmpdir(), 'clawo-fix-artifacts'),
|
|
42
|
+
exec: args.shell ? shellToExec(args.shell) : undefined,
|
|
43
|
+
}, spawnFixer);
|
|
44
|
+
const failing = results.find((r) => r.required && !r.passed);
|
|
45
|
+
return {
|
|
46
|
+
ok: passed,
|
|
47
|
+
rounds,
|
|
48
|
+
lastError: failing ? (failing.tail ?? failing.detail).slice(0, 500) : undefined,
|
|
49
|
+
failingCommand: failing?.detail,
|
|
50
|
+
results,
|
|
51
|
+
};
|
|
55
52
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
53
|
+
/** Keep the injectable `ShellRunner` seam callers already depend on. */
|
|
54
|
+
function shellToExec(shell) {
|
|
55
|
+
return async (cmd, cmdArgs, opts) => {
|
|
56
|
+
const r = await shell(cmd, cmdArgs, { cwd: opts.cwd ?? process.cwd() });
|
|
57
|
+
return { code: r.ok ? 0 : 1, out: r.stdout, err: r.stderr, timedOut: false, durationMs: 0 };
|
|
58
|
+
};
|
|
62
59
|
}
|
|
63
|
-
const realShell = (cmd, args, opts) => new Promise((resolve) => {
|
|
64
|
-
const child = spawn(cmd, args, { cwd: opts.cwd, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
65
|
-
let stdout = '';
|
|
66
|
-
let stderr = '';
|
|
67
|
-
child.stdout.on('data', (d) => (stdout = appendCapped(stdout, d.toString())));
|
|
68
|
-
child.stderr.on('data', (d) => (stderr = appendCapped(stderr, d.toString())));
|
|
69
|
-
child.on('close', (code) => resolve({ ok: code === 0, stdout, stderr }));
|
|
70
|
-
child.on('error', (e) => resolve({ ok: false, stdout, stderr: stderr + e.message }));
|
|
71
|
-
});
|
|
72
|
-
const defaultSpawnFixer = async (args) => {
|
|
73
|
-
const { spawnFixerSession } = await import('./fix-on-failure-session.js');
|
|
74
|
-
await spawnFixerSession(args);
|
|
75
|
-
};
|
|
76
60
|
//# sourceMappingURL=fix-on-failure.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fix-on-failure.js","sourceRoot":"","sources":["../../../src/ultraapp/fix-on-failure.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"fix-on-failure.js","sourceRoot":"","sources":["../../../src/ultraapp/fix-on-failure.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,WAAW,EAA2C,MAAM,qBAAqB,CAAC;AAyC3F,MAAM,OAAO,GAAG,EAAE,GAAG,MAAM,CAAC;AAE5B,MAAM,CAAC,MAAM,aAAa,GAA2C;IACnE,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,SAAS,CAAC,EAAE;IACjC,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE;IACtC,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE;IAC9B,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,OAAO,EAAE,IAAI,EAAE,mBAAmB,EAAE,GAAG,CAAC,EAAE;CACnE,CAAC;AAEF,0FAA0F;AAC1F,MAAM,UAAU,eAAe,CAC7B,KAA6C,EAC7C,kBAA0B;IAE1B,MAAM,MAAM,GAAoB,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QACnD,EAAE,EAAE,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE;QACvB,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,IAAI,OAAO,EAAE;QACtF,QAAQ,EAAE,CAAC,CAAC,QAAQ,KAAK,KAAK;KAC/B,CAAC,CAAC,CAAC;IACJ,OAAO,EAAE,EAAE,EAAE,gBAAgB,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC;AAC9D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAsB;IAC1D,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,eAAe,CAAC,IAAI,CAAC,KAAK,IAAI,aAAa,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;IAC/F,MAAM,UAAU,GAAmC,IAAI,CAAC,UAAU;QAChE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,UAAW,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,cAAc,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC;QAC9G,CAAC,CAAC,SAAS,CAAC;IAEd,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,WAAW,CACnD,EAAE,GAAG,QAAQ,EAAE,kBAAkB,EAAE,IAAI,CAAC,SAAS,EAAE,EACnD;QACE,GAAG,EAAE,IAAI,CAAC,YAAY;QACtB,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,qBAAqB,CAAC;QAC9E,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS;KACvD,EACD,UAAU,CACX,CAAC;IAEF,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC7D,OAAO;QACL,EAAE,EAAE,MAAM;QACV,MAAM;QACN,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS;QAC/E,cAAc,EAAE,OAAO,EAAE,MAAM;QAC/B,OAAO;KACR,CAAC;AACJ,CAAC;AAED,wEAAwE;AACxE,SAAS,WAAW,CAAC,KAAkB;IACrC,OAAO,KAAK,EAAE,GAAW,EAAE,OAAiB,EAAE,IAAsB,EAAE,EAAE;QACtE,MAAM,CAAC,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACxE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;IAC9F,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { type AppSpec } from './spec.js';
|
|
2
|
-
import { type UltraappStore, type ChatEntry } from './store.js';
|
|
2
|
+
import { type UltraappStore, type ChatEntry, type RunMode } from './store.js';
|
|
3
3
|
import { type QuestionEnvelope } from './interview-parser.js';
|
|
4
4
|
import { type PatchOp } from './json-patch.js';
|
|
5
5
|
import type { BuildEvent } from './build-events.js';
|
|
6
|
+
import { RunKernel } from '../kernel/engine.js';
|
|
7
|
+
import type { RunRecord } from '../kernel/types.js';
|
|
8
|
+
import { type AcceptanceContract, type CheckResult } from '../verify/contract.js';
|
|
6
9
|
import { type DeployArgs, type DeployResult } from './deploy.js';
|
|
7
10
|
import type { UltraappRouter } from './router.js';
|
|
8
11
|
export type RunEvent = {
|
|
@@ -56,23 +59,69 @@ export interface UltraappManagerOptions {
|
|
|
56
59
|
`build-complete` (v0.2 behaviour); when present, deploy runs after build
|
|
57
60
|
and the run reaches `done` with a public-but-local URL. */
|
|
58
61
|
router?: UltraappRouter;
|
|
62
|
+
/**
|
|
63
|
+
* The run kernel that drives the build pipeline.
|
|
64
|
+
*
|
|
65
|
+
* Supplied by SessionManager in production so UltraApp's runs share the one
|
|
66
|
+
* run store, listing and ownership model as everything else. Left out, a
|
|
67
|
+
* private kernel is wired up — which keeps the class usable on its own, and
|
|
68
|
+
* still means there is only one execution model, not two.
|
|
69
|
+
*/
|
|
70
|
+
kernel?: RunKernel;
|
|
59
71
|
/** Test seam: stub the deploy state machine. */
|
|
60
72
|
deployFn?: (a: DeployArgs) => Promise<DeployResult>;
|
|
73
|
+
/**
|
|
74
|
+
* Override the build-stage acceptance contract.
|
|
75
|
+
*
|
|
76
|
+
* A caller-supplied contract, never an agent-supplied one — the same rule as
|
|
77
|
+
* everywhere else in the verification plane. It exists because the default
|
|
78
|
+
* really does run `npm install && npm run build && npm test` in the generated
|
|
79
|
+
* codebase, which a unit test has no business doing; tests declare a trivial
|
|
80
|
+
* contract the way they inject `deployFn`.
|
|
81
|
+
*/
|
|
82
|
+
buildContract?: AcceptanceContract;
|
|
83
|
+
/**
|
|
84
|
+
* Test seam: stub the deploy-stage acceptance checks. The real one drives a
|
|
85
|
+
* headless browser against the deployed URL, which a stubbed deploy has not
|
|
86
|
+
* got, so tests inject their own the same way they inject `deployFn`.
|
|
87
|
+
*/
|
|
88
|
+
runDeployChecksFn?: (contract: AcceptanceContract, cwd: string, artifactDir: string) => Promise<CheckResult[]>;
|
|
61
89
|
/** Runtime mode for build + deploy. 'host' (default) runs the generated
|
|
62
90
|
app as a regular Node process — works anywhere Node works, no extra
|
|
63
91
|
deps. 'docker' uses `docker build` + `docker run` for isolation; only
|
|
64
92
|
use this when you want shared-host hardening. */
|
|
65
93
|
runtimeMode?: 'host' | 'docker';
|
|
66
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* The kernel run id for an app's current build.
|
|
97
|
+
*
|
|
98
|
+
* Stable rather than per-attempt, so `clawo workflow show ultraapp-<id>` always
|
|
99
|
+
* names the build that matters; a rebuild deletes the previous run and starts a
|
|
100
|
+
* new one under the same id, which the incarnation check makes safe.
|
|
101
|
+
*/
|
|
102
|
+
export declare function ultraappKernelRunId(appRunId: string): string;
|
|
103
|
+
/**
|
|
104
|
+
* UltraApp's `RunMode`, derived from the kernel record.
|
|
105
|
+
*
|
|
106
|
+
* The build pipeline no longer has a state machine of its own: this reads the
|
|
107
|
+
* one the kernel keeps. `interview` and `queued` are not here because they are
|
|
108
|
+
* not pipeline states — nothing is running yet, and the interview genuinely is
|
|
109
|
+
* not a workflow.
|
|
110
|
+
*/
|
|
111
|
+
export declare function ultraappModeOf(record: RunRecord): RunMode;
|
|
67
112
|
export declare class UltraappManager {
|
|
68
113
|
private readonly opts;
|
|
69
114
|
private readonly runs;
|
|
70
115
|
private readonly skillContent;
|
|
71
116
|
private readonly buildQueue;
|
|
72
117
|
private readonly narrators;
|
|
118
|
+
private readonly kernel;
|
|
119
|
+
/** Per-run serialisation for the mode projection. See {@link projectMode}. */
|
|
120
|
+
private readonly projectChain;
|
|
73
121
|
private readonly classifierSessions;
|
|
74
122
|
private readonly inflightWork;
|
|
75
123
|
constructor(opts: UltraappManagerOptions);
|
|
124
|
+
private ultraappNodeDeps;
|
|
76
125
|
get store(): UltraappStore;
|
|
77
126
|
createRun(): Promise<string>;
|
|
78
127
|
submitAnswer(runId: string, answer: {
|
|
@@ -94,8 +143,64 @@ export declare class UltraappManager {
|
|
|
94
143
|
startBuild(runId: string): Promise<void>;
|
|
95
144
|
cancelBuild(runId: string): void;
|
|
96
145
|
buildPosition(runId: string): number;
|
|
146
|
+
/**
|
|
147
|
+
* Run the build pipeline as a kernel workflow.
|
|
148
|
+
*
|
|
149
|
+
* This used to be a hand-rolled sequence: council, then fix-on-failure, then
|
|
150
|
+
* deploy, with a mode enum written at each step and nothing checkpointed
|
|
151
|
+
* between them. It worked, but it meant UltraApp was a second runtime standing
|
|
152
|
+
* beside the one this release exists to be — its runs were invisible to
|
|
153
|
+
* `workflow_list` and the Runs tab, and a crash halfway through threw away a
|
|
154
|
+
* finished council and started it again from nothing.
|
|
155
|
+
*
|
|
156
|
+
* Now the sequence is a `WorkflowSpec` and the kernel drives it. What is left
|
|
157
|
+
* here is the part that is genuinely UltraApp's: turning kernel events into
|
|
158
|
+
* `BuildEvent`s for the dashboard, and keeping `RunMode` — which the whole
|
|
159
|
+
* UI and every stored run reads — as a projection of the kernel's state
|
|
160
|
+
* rather than as a second source of truth.
|
|
161
|
+
*
|
|
162
|
+
* The interview and the done-mode conversation are deliberately NOT here.
|
|
163
|
+
* They are user-driven and open-ended; expressing them as a workflow would
|
|
164
|
+
* mean a router self-loop fighting the visit bound, or one fake node with a
|
|
165
|
+
* state machine hidden inside it. That would be unification as theatre.
|
|
166
|
+
*/
|
|
97
167
|
private runBuild;
|
|
98
|
-
|
|
168
|
+
/** Best-effort narrator startup; its failure must not sink a build. */
|
|
169
|
+
private startNarrator;
|
|
170
|
+
/**
|
|
171
|
+
* Translate the run's kernel events into build events and mode transitions.
|
|
172
|
+
*
|
|
173
|
+
* The mode is recomputed from the record every time rather than stepped
|
|
174
|
+
* forward, so a handler that arrives late cannot write a stale value over a
|
|
175
|
+
* newer one — which it otherwise can, because these handlers are async and the
|
|
176
|
+
* kernel does not wait for them.
|
|
177
|
+
*/
|
|
178
|
+
private subscribeKernel;
|
|
179
|
+
private onKernelEvent;
|
|
180
|
+
/**
|
|
181
|
+
* Write UltraApp's mode as it is implied by the kernel record, right now.
|
|
182
|
+
*
|
|
183
|
+
* Serialised per run, and that is the whole mechanism. These are fired from
|
|
184
|
+
* async event handlers, so two of them can read the record at different
|
|
185
|
+
* moments and still write in the opposite order — which showed up as a run
|
|
186
|
+
* that had already failed reverting to `building`. Chaining read-compute-write
|
|
187
|
+
* makes the last write the one computed last, and the kernel record only ever
|
|
188
|
+
* moves forward, so the last computed value is the current one.
|
|
189
|
+
*/
|
|
190
|
+
private projectMode;
|
|
191
|
+
private projectModeNow;
|
|
192
|
+
/** Emit the terminal build event and settle the mode from the final record. */
|
|
193
|
+
private settleBuild;
|
|
194
|
+
/**
|
|
195
|
+
* Deploy the built codebase and check the deployed thing.
|
|
196
|
+
*
|
|
197
|
+
* Returns an outcome rather than writing modes: the mode is projected from the
|
|
198
|
+
* kernel now, and a stage that also wrote it would put the two back out of
|
|
199
|
+
* step. The acceptance verdict comes back with the outcome because it is the
|
|
200
|
+
* run's terminal verdict — §7g screenshots are taken against a URL that does
|
|
201
|
+
* not exist until this has run, so the contract cannot sit in the spec.
|
|
202
|
+
*/
|
|
203
|
+
private deployStage;
|
|
99
204
|
startContainer(runId: string): Promise<{
|
|
100
205
|
ok: boolean;
|
|
101
206
|
error?: string;
|