lazycodex-ai 5.0.0-beta.62 → 5.0.0-beta.63
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/dist/cli/doctor/checks/browser-provider.d.ts +2 -0
- package/dist/cli/index.js +64 -35
- package/dist/cli-node/index.js +64 -35
- package/package.json +2 -6
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +2 -0
- package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +5 -4
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/src/directive-content.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/directive.md +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/CHANGELOG.md +13 -0
- package/packages/omo-codex/plugin/components/ulw-loop/directive.md +5 -4
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.js +5 -4
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +582 -322
- package/packages/omo-codex/plugin/components/ulw-loop/dist/domain-types.d.ts +5 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/evidence.js +16 -12
- package/packages/omo-codex/plugin/components/ulw-loop/dist/ledger.d.ts +4 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/ledger.js +34 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-commit.d.ts +19 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-commit.js +107 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.d.ts +2 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.js +48 -22
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.d.ts +9 -7
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.js +105 -114
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-log.d.ts +15 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-log.js +86 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-missing-recovery.d.ts +5 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-missing-recovery.js +15 -3
- package/packages/omo-codex/plugin/components/ulw-loop/dist/review-blockers.js +3 -4
- package/packages/omo-codex/plugin/components/ulw-loop/dist/sdk/factory.js +12 -5
- package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-budget-io.d.ts +5 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-budget-io.js +67 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-guard.js +8 -62
- package/packages/omo-codex/plugin/components/ulw-loop/dist/state-lock.d.ts +11 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/state-lock.js +120 -88
- package/packages/omo-codex/plugin/components/ulw-loop/dist/status-next-actions.d.ts +3 -2
- package/packages/omo-codex/plugin/components/ulw-loop/dist/status-next-actions.js +18 -10
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-batch.js +4 -4
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering.js +5 -5
- package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +8 -17
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +2 -2
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +5 -4
- package/packages/omo-codex/plugin/components/ulw-loop/src/domain-types.ts +5 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/evidence.ts +16 -16
- package/packages/omo-codex/plugin/components/ulw-loop/src/ledger.ts +33 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/plan-commit.ts +124 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/plan-crud.ts +58 -51
- package/packages/omo-codex/plugin/components/ulw-loop/src/plan-io.ts +126 -140
- package/packages/omo-codex/plugin/components/ulw-loop/src/plan-log.ts +84 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/plan-missing-recovery.ts +26 -3
- package/packages/omo-codex/plugin/components/ulw-loop/src/review-blockers.ts +3 -3
- package/packages/omo-codex/plugin/components/ulw-loop/src/sdk/factory.ts +30 -5
- package/packages/omo-codex/plugin/components/ulw-loop/src/spawn-budget-io.ts +59 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/spawn-guard.ts +8 -59
- package/packages/omo-codex/plugin/components/ulw-loop/src/state-lock.ts +129 -111
- package/packages/omo-codex/plugin/components/ulw-loop/src/status-next-actions.ts +19 -10
- package/packages/omo-codex/plugin/components/ulw-loop/src/steering-batch.ts +4 -4
- package/packages/omo-codex/plugin/components/ulw-loop/src/steering.ts +5 -4
- package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +8 -16
- package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/barrier.ts +13 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/commit-child.ts +65 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/commit-cli-qa.mjs +76 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/commit-crash.ts +23 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/commit-mutations.mjs +58 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/commit-writer.ts +65 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/lease-clock.ts +23 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/plan-commit-log.test.ts +252 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/plan-commit-recovery.test.ts +190 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/plan-io.test.ts +50 -35
- package/packages/omo-codex/plugin/components/ulw-loop/test/plan-log-newest.test.ts +72 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/sdk-completed-plan.test.ts +43 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/sdk-session-context.test.ts +21 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/state-lock.test.ts +92 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/status-next-actions-surface.test.ts +133 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/steering-batch.test.ts +12 -12
- package/packages/omo-codex/plugin/components/ulw-loop/test/steering.test.ts +4 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/package-lock.json +12 -12
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/scripts/sync-skills.d.mts +4 -0
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +15 -7
- package/packages/omo-codex/plugin/skills/ast-grep/SKILL.md +12 -0
- package/packages/omo-codex/plugin/skills/debugging/references/tools/playwright-cli.md +79 -161
- package/packages/omo-codex/plugin/skills/frontend/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/aside.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/clone-from-url.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/lighthouse-audit.py +2 -2
- package/packages/omo-codex/plugin/skills/review-work/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/ATTRIBUTION.md +1 -82
- package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +17 -29
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +2 -1
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/templates/package.json +2 -2
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/templates/playwright_mobile_chrome.js +5 -2
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/templates/playwright_real_chrome.js +8 -6
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_stealth.py +86 -0
- package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_templates.py +4 -7
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/chrome-stealth.md +86 -100
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +9 -3
- package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/playwright.md +16 -13
- package/packages/omo-codex/plugin/skills/ultimate-browsing/scripts/extract_cookies.py +3 -3
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +5 -4
- package/packages/omo-codex/plugin/skills/ulw-execute/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +2 -2
- package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +3 -3
- package/packages/omo-codex/plugin/skills/visual-qa/AGENTS.md +1 -1
- package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/visual-qa/references/browser-setup.md +75 -0
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +4 -2
- package/packages/prompts-core/prompts/ultrawork/codex.md +5 -4
- package/packages/shared-skills/skills/ast-grep/SKILL.md +12 -0
- package/packages/shared-skills/skills/debugging/references/tools/playwright-cli.md +79 -161
- package/packages/shared-skills/skills/frontend/SKILL.md +1 -1
- package/packages/shared-skills/skills/frontend/references/design/aside.md +1 -1
- package/packages/shared-skills/skills/frontend/references/design/clone-from-url.md +1 -1
- package/packages/shared-skills/skills/frontend/scripts/perfection/lighthouse-audit.py +2 -2
- package/packages/shared-skills/skills/review-work/SKILL.md +1 -1
- package/packages/shared-skills/skills/ultimate-browsing/ATTRIBUTION.md +1 -82
- package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +17 -29
- package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +2 -1
- package/packages/shared-skills/skills/ultimate-browsing/engine/templates/package.json +2 -2
- package/packages/shared-skills/skills/ultimate-browsing/engine/templates/playwright_mobile_chrome.js +5 -2
- package/packages/shared-skills/skills/ultimate-browsing/engine/templates/playwright_real_chrome.js +8 -6
- package/packages/shared-skills/skills/ultimate-browsing/engine/tests/test_playwright_stealth.py +86 -0
- package/packages/shared-skills/skills/ultimate-browsing/engine/tests/test_playwright_templates.py +4 -7
- package/packages/shared-skills/skills/ultimate-browsing/references/chrome-stealth.md +86 -100
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +9 -3
- package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/playwright.md +16 -13
- package/packages/shared-skills/skills/ultimate-browsing/scripts/extract_cookies.py +3 -3
- package/packages/shared-skills/skills/ulw-execute/SKILL.md +1 -1
- package/packages/shared-skills/skills/ulw-plan/scripts/scaffold-plan.mjs +1 -1
- package/packages/shared-skills/skills/ulw-research/SKILL.md +3 -3
- package/packages/shared-skills/skills/visual-qa/AGENTS.md +1 -1
- package/packages/shared-skills/skills/visual-qa/SKILL.md +1 -1
- package/packages/shared-skills/skills/visual-qa/references/browser-setup.md +75 -0
- package/packages/omo-codex/plugin/skills/visual-qa/references/agent-browser-setup.md +0 -45
- package/packages/shared-skills/skills/visual-qa/references/agent-browser-setup.md +0 -45
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"type": "command",
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook user-prompt-submit --with-ultrawork",
|
|
9
9
|
"timeout": 10,
|
|
10
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
10
|
+
"statusMessage": "(OmO 5.0.0-beta.63) Checking Ulw-Loop Steering"
|
|
11
11
|
}
|
|
12
12
|
]
|
|
13
13
|
}
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"type": "command",
|
|
21
21
|
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-tool-use-spawn",
|
|
22
22
|
"timeout": 5,
|
|
23
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
23
|
+
"statusMessage": "(OmO 5.0.0-beta.63) Recording Spawn Admission"
|
|
24
24
|
}
|
|
25
25
|
]
|
|
26
26
|
}
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"type": "command",
|
|
34
34
|
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook pre-tool-use",
|
|
35
35
|
"timeout": 5,
|
|
36
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
36
|
+
"statusMessage": "(OmO 5.0.0-beta.63) Enforcing Unlimited Ulw-Loop Budget"
|
|
37
37
|
}
|
|
38
38
|
]
|
|
39
39
|
},
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"type": "command",
|
|
45
45
|
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook pre-tool-use-spawn",
|
|
46
46
|
"timeout": 5,
|
|
47
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
47
|
+
"statusMessage": "(OmO 5.0.0-beta.63) Guarding Ulw-Loop Spawns"
|
|
48
48
|
}
|
|
49
49
|
]
|
|
50
50
|
}
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"type": "command",
|
|
57
57
|
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook stop",
|
|
58
58
|
"timeout": 10,
|
|
59
|
-
"statusMessage": "(OmO 5.0.0-beta.
|
|
59
|
+
"statusMessage": "(OmO 5.0.0-beta.63) Checking Ulw-Loop Resume"
|
|
60
60
|
}
|
|
61
61
|
]
|
|
62
62
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@code-yeongyu/codex-ulw-loop",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.63",
|
|
4
4
|
"description": "Codex plugin: durable repo-native multi-goal orchestration with embedded success criteria and observable evidence audit.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "npm@11.12.1",
|
package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md
CHANGED
|
@@ -20,7 +20,7 @@ Run each criterion's real-surface proof yourself through the channel that faithf
|
|
|
20
20
|
|
|
21
21
|
1. **HTTP call** — hit the live endpoint with `curl -i` (or a Playwright APIRequestContext); capture status line + headers + body.
|
|
22
22
|
2. **Terminal / TUI** - prove it through the xterm.js web terminal; tmux `send-keys` is fine for a boot smoke, but NEVER `tmux capture-pane` for color/layout/CJK evidence (it degrades truecolor).
|
|
23
|
-
3. **Browser use** — in Codex,
|
|
23
|
+
3. **Browser use** — in Codex, prefer `browser:control-in-app-browser`. Otherwise, or for Chrome semantics, stealth, trace, or auth, WRITE a `playwright-core` script and run it from js eval against local Chrome (`channel: "chrome"`; persistent context on a CLONED profile, never the live one). Capture action log + screenshot path. Never downgrade a browser-facing criterion.
|
|
24
24
|
4. **Computer use** — for desktop/GUI apps, drive the running app via OS automation (computer-use, AppleScript, xdotool, etc.); capture action log + screenshot.
|
|
25
25
|
|
|
26
26
|
For TUI visual QA (mandatory when a PR or review must inspect the terminal screen),
|
|
@@ -165,7 +165,7 @@ Loop per goal. Cap at 5 cycles per goal. Cap identical same-criterion failures a
|
|
|
165
165
|
4. INTEGRATE + CRITICAL SELF-QA + GIT CHECKPOINT (EVERY WORKER RETURN): do NOT trust the worker's report. Read the diff yourself, re-run its tests, and run LSP diagnostics on the changed files. Treat "done" as a claim to disprove. If the diff drifts, the test is hollow, or evidence is missing, RESPAWN the worker with the specific failure context. Once the work unit is verified, use `git-master` before staging: inspect recent repository commits and touched-path history to infer commit language, Conventional Commit scope, message shape, and unit size. Stage only that unit's files and commit in the observed style; do not carry verified work forward into a later omnibus commit. If no git-tracked files changed or committing is unsafe, record the no-commit reason as evidence. Forward every finding/learning to subsequent workers.
|
|
166
166
|
5. EXECUTE-AS-SCENARIO: ACTUALLY run the Manual-QA scenario the criterion named (channel table above). Run it yourself for the orchestrator check; for heavier flows dispatch a dedicated QA execution worker (`lazycodex-worker-medium` by default; `lazycodex-worker-high` when the QA flow itself is hard) whose ONLY job is to drive the channel and write the artifact to the named evidence path. If the scenario FAILS, respawn the implementing worker with the captured failure — do not hand-patch around it.
|
|
167
167
|
6. CAPTURE: collect the observable artifact path: transcript, stdout, screenshot, assertion, status+body, diff, or parsed dump. No artifact written at the evidence path — not done; record BLOCKED and respawn QA.
|
|
168
|
-
7. CLEAN (PAIRED, NEVER SKIP): tear down every runtime artifact step 5 spawned BEFORE recording — server PIDs (`kill`, verify `kill -0` fails), `tmux` sessions (`tmux kill-session -t ulw-qa-<criterion>`; confirm `tmux ls`), browser / Playwright contexts (`.close()`), containers (`docker rm -f`), bound ports (`lsof -i :<port>` empty), temp sockets / files / dirs (`rm -rf` the `mktemp` paths), QA-only env vars, AND close every finished worker (v1 `close_agent`; on V2 finished workers end on their own — `interrupt_agent` any still running). Register each teardown as its own todo the moment the QA spawns the resource (scripts, tmux assets,
|
|
168
|
+
7. CLEAN (PAIRED, NEVER SKIP): tear down every runtime artifact step 5 spawned BEFORE recording — server PIDs (`kill`, verify `kill -0` fails), `tmux` sessions (`tmux kill-session -t ulw-qa-<criterion>`; confirm `tmux ls`), browser / Playwright contexts (`.close()`), containers (`docker rm -f`), bound ports (`lsof -i :<port>` empty), temp sockets / files / dirs (`rm -rf` the `mktemp` paths), QA-only env vars, AND close every finished worker (v1 `close_agent`; on V2 finished workers end on their own — `interrupt_agent` any still running). Register each teardown as its own todo the moment the QA spawns the resource (scripts, tmux assets, browser contexts, PIDs, ports) so none is forgotten. Embed a one-line cleanup receipt in the evidence string, e.g. `cleanup: killed 12345; tmux kill-session ulw-qa-foo; rm -rf /tmp/ulw.aB12cD; interrupt_agent w-3`. Missing receipt → record BLOCKED, not PASS.
|
|
169
169
|
8. RECORD one result immediately from the artifact you just wrote — never from memory or a later turn — stamping the capture tree `$(git rev-parse --short "HEAD^{tree}")` into the evidence:
|
|
170
170
|
- PASS: `omo-agent-toolkit ulw-loop record-evidence --goal-id <id> --criterion-id <id> --status pass --evidence "<observable> @tree:<short-tree> | <cleanup receipt>" --json`
|
|
171
171
|
- FAIL: `omo-agent-toolkit ulw-loop record-evidence --goal-id <id> --criterion-id <id> --status fail --evidence "<observable> @tree:<short-tree> | <cleanup receipt>" --notes "<diagnosis>" --json`
|
|
@@ -10,7 +10,8 @@ import { requireAllCriteriaPass, requireAllPlanCriteriaPass, requireEssentialCri
|
|
|
10
10
|
import { codexGoalMode, isFinalRunCompletionCandidate } from "./goal-status.js";
|
|
11
11
|
import type { UlwLoopScope } from "./paths.js";
|
|
12
12
|
import { ulwLoopAttemptEvidenceDir } from "./paths.js";
|
|
13
|
-
import {
|
|
13
|
+
import { commit } from "./plan-commit.js";
|
|
14
|
+
import { readUlwLoopPlan, withUlwLoopMutationLock } from "./plan-io.js";
|
|
14
15
|
import {
|
|
15
16
|
classifyExternalAuthorizationBlocker,
|
|
16
17
|
clearGoalBlockerFields,
|
|
@@ -226,11 +227,11 @@ export async function checkpointUlwLoop(
|
|
|
226
227
|
if (aggregateCompletion !== undefined) plan.aggregateCompletion = aggregateCompletion;
|
|
227
228
|
if (aggregateCompletion !== undefined) nextActions = [...nextActions, 'aggregate complete — now update_goal({status:"complete"})'];
|
|
228
229
|
plan.updatedAt = now;
|
|
229
|
-
await writePlan(repoRoot, plan, scope);
|
|
230
230
|
const ledgerEntry = buildLedger(now, args, goal, qualityGate, codexGoal, aggregateCompletion);
|
|
231
|
-
|
|
231
|
+
const entries = [ledgerEntry];
|
|
232
232
|
const closedBatch = args.status === "complete" ? batchClosedBy(plan, goal.id) : undefined;
|
|
233
|
-
if (closedBatch !== undefined)
|
|
233
|
+
if (closedBatch !== undefined) entries.push({ at: now, kind: "batch_closed", goalId: goal.id, message: closedBatch.batchId });
|
|
234
|
+
await commit(repoRoot, scope, { plan, entries });
|
|
234
235
|
return aggregateCompletion === undefined
|
|
235
236
|
? { plan, goal, ledgerEntry, nextActions, warnings }
|
|
236
237
|
: { plan, goal, ledgerEntry, aggregateCompletion, nextActions, warnings };
|
|
@@ -63,6 +63,9 @@ export interface UlwLoopValidationBatch {
|
|
|
63
63
|
|
|
64
64
|
export interface UlwLoopPlan {
|
|
65
65
|
version: 1;
|
|
66
|
+
revision?: number;
|
|
67
|
+
brief?: string;
|
|
68
|
+
ledgerResetRevision?: number;
|
|
66
69
|
evidenceLayoutVersion?: 2;
|
|
67
70
|
createdAt: string;
|
|
68
71
|
updatedAt: string;
|
|
@@ -158,6 +161,8 @@ export interface UlwLoopQualityGateSenpi extends UlwLoopQualityGateCommon {
|
|
|
158
161
|
export type UlwLoopQualityGate = UlwLoopQualityGateLazycodex | UlwLoopQualityGateSenpi;
|
|
159
162
|
|
|
160
163
|
export interface UlwLoopLedgerEntry {
|
|
164
|
+
revision?: number;
|
|
165
|
+
id?: string;
|
|
161
166
|
at: string;
|
|
162
167
|
kind: UlwLoopLedgerEventKind;
|
|
163
168
|
goalId?: string;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { essentialCriteriaOf, hasAllCriteriaPass, hasEssentialCriteriaPass } from "./goal-status.js";
|
|
2
2
|
import type { UlwLoopScope } from "./paths.js";
|
|
3
|
-
import {
|
|
3
|
+
import { commit } from "./plan-commit.js";
|
|
4
|
+
import { readUlwLoopPlan, withUlwLoopMutationLock } from "./plan-io.js";
|
|
4
5
|
import type { UlwLoopItem, UlwLoopLedgerEntry, UlwLoopPlan, UlwLoopSuccessCriterion } from "./types.js";
|
|
5
6
|
import { iso, UlwLoopError } from "./types.js";
|
|
6
7
|
|
|
@@ -75,7 +76,6 @@ export async function recordEvidence(
|
|
|
75
76
|
if (args.notes !== undefined) criterion.notes = args.notes;
|
|
76
77
|
goal.updatedAt = capturedAt;
|
|
77
78
|
plan.updatedAt = capturedAt;
|
|
78
|
-
await writePlan(repoRoot, plan, scope);
|
|
79
79
|
const ledgerEntry: UlwLoopLedgerEntry = {
|
|
80
80
|
at: capturedAt,
|
|
81
81
|
kind,
|
|
@@ -87,7 +87,7 @@ export async function recordEvidence(
|
|
|
87
87
|
before: { status: prevStatus },
|
|
88
88
|
after: { goalId: goal.id, criterionId: criterion.id, status: args.status, evidence, capturedAt, prevStatus },
|
|
89
89
|
};
|
|
90
|
-
await
|
|
90
|
+
await commit(repoRoot, scope, { plan, entries: [ledgerEntry] });
|
|
91
91
|
return { plan, goal, criterion, ledgerEntry };
|
|
92
92
|
});
|
|
93
93
|
}
|
|
@@ -115,19 +115,19 @@ export async function markCriteriaPendingResetForGoal(
|
|
|
115
115
|
}
|
|
116
116
|
goal.updatedAt = now;
|
|
117
117
|
plan.updatedAt = now;
|
|
118
|
-
await
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
);
|
|
118
|
+
await commit(repoRoot, scope, {
|
|
119
|
+
plan,
|
|
120
|
+
entries: [
|
|
121
|
+
{
|
|
122
|
+
at: now,
|
|
123
|
+
kind: "criteria_revised",
|
|
124
|
+
goalId,
|
|
125
|
+
message: `Reset ${goal.successCriteria.length} criteria to pending.`,
|
|
126
|
+
before,
|
|
127
|
+
after: { resetCount: goal.successCriteria.length },
|
|
128
|
+
},
|
|
129
|
+
],
|
|
130
|
+
});
|
|
131
131
|
return { plan, resetCount: goal.successCriteria.length };
|
|
132
132
|
});
|
|
133
133
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { type UlwLoopScope, ulwLoopDir } from "./paths.js";
|
|
3
|
+
import { readOptional, readRecords, reconcilePlan } from "./plan-log.js";
|
|
4
|
+
import type { UlwLoopLedgerEntry } from "./types.js";
|
|
5
|
+
|
|
6
|
+
export function readLedgerAt(dir: string): UlwLoopLedgerEntry[] {
|
|
7
|
+
const entries = new Map<string, UlwLoopLedgerEntry>();
|
|
8
|
+
const lines = (readOptional(join(dir, "ledger.jsonl")) ?? "").split(/\r?\n/);
|
|
9
|
+
for (const [index, line] of lines.entries()) {
|
|
10
|
+
if (line.trim().length === 0) continue;
|
|
11
|
+
try {
|
|
12
|
+
const entry: UlwLoopLedgerEntry = JSON.parse(line);
|
|
13
|
+
entry.revision ??= 0;
|
|
14
|
+
entry.id ??= `legacy-${index + 1}`;
|
|
15
|
+
entries.set(entry.id, entry);
|
|
16
|
+
} catch (error) {
|
|
17
|
+
if (!(error instanceof SyntaxError)) throw error;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
for (const record of readRecords(dir))
|
|
21
|
+
for (const [seq, entry] of record.ledger.entries()) {
|
|
22
|
+
const id = entry.id ?? `${record.revision}-${seq}`;
|
|
23
|
+
entries.set(id, { ...entry, revision: record.revision, id });
|
|
24
|
+
}
|
|
25
|
+
const reset = reconcilePlan(dir)?.ledgerResetRevision ?? 0;
|
|
26
|
+
const sequence = (entry: UlwLoopLedgerEntry) => Number(entry.id?.split("-").at(-1) ?? 0);
|
|
27
|
+
return [...entries.values()]
|
|
28
|
+
.filter((entry) => (entry.revision ?? 0) >= reset)
|
|
29
|
+
.sort((a, b) => (a.revision ?? 0) - (b.revision ?? 0) || sequence(a) - sequence(b));
|
|
30
|
+
}
|
|
31
|
+
export function readLedger(repoRoot: string, scope?: UlwLoopScope): UlwLoopLedgerEntry[] {
|
|
32
|
+
return readLedgerAt(ulwLoopDir(repoRoot, scope));
|
|
33
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
import { randomUUID } from "node:crypto";
|
|
3
|
+
import { linkSync, mkdirSync, renameSync, rmSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { rename, writeFile } from "node:fs/promises";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { readLedgerAt } from "./ledger.js";
|
|
7
|
+
import { type UlwLoopScope, ulwLoopDir, ulwLoopStateLockPath } from "./paths.js";
|
|
8
|
+
import { assertStateLockOwned, migrationEntries } from "./plan-io.js";
|
|
9
|
+
import { hasCode, type PlanCommitRecord, readOptional, readRecords, reconcilePlan } from "./plan-log.js";
|
|
10
|
+
import { UlwLoopError, type UlwLoopLedgerEntry, type UlwLoopPlan } from "./types.js";
|
|
11
|
+
|
|
12
|
+
interface CommitHooks {
|
|
13
|
+
readonly beforeMutation?: () => void | Promise<void>;
|
|
14
|
+
readonly beforeCommit?: () => void | Promise<void>;
|
|
15
|
+
readonly afterCommit?: () => void | Promise<void>;
|
|
16
|
+
readonly link?: (source: string, destination: string) => void;
|
|
17
|
+
readonly writeView?: (path: string, content: string) => Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
const hooks = new AsyncLocalStorage<CommitHooks>();
|
|
20
|
+
export function withCommitHooks<T>(value: CommitHooks, fn: () => Promise<T>): Promise<T> {
|
|
21
|
+
return hooks.run(value, fn);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function beforePlanMutation(): Promise<void> {
|
|
25
|
+
await hooks.getStore()?.beforeMutation?.();
|
|
26
|
+
}
|
|
27
|
+
export async function writeViewFile(path: string, content: string): Promise<void> {
|
|
28
|
+
await (hooks.getStore()?.writeView ?? writeFile)(path, content);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// link is the sole commit point; no copy fallback (Node copyFile is not atomic).
|
|
32
|
+
// A resumed zombie can publish first, but never overwrite an existing revision.
|
|
33
|
+
// Logical audit order is (revision, sequence), not materialization completion time.
|
|
34
|
+
export async function commit(
|
|
35
|
+
repoRoot: string,
|
|
36
|
+
scope: UlwLoopScope | undefined,
|
|
37
|
+
mutation: {
|
|
38
|
+
readonly plan: UlwLoopPlan;
|
|
39
|
+
readonly entries: readonly UlwLoopLedgerEntry[];
|
|
40
|
+
},
|
|
41
|
+
): Promise<void> {
|
|
42
|
+
const { plan } = mutation;
|
|
43
|
+
const dir = ulwLoopDir(repoRoot, scope);
|
|
44
|
+
assertStateLockOwned(ulwLoopStateLockPath(repoRoot, scope));
|
|
45
|
+
await hooks.getStore()?.beforeCommit?.();
|
|
46
|
+
const next = (plan.revision ?? 0) + 1;
|
|
47
|
+
const brief = plan.brief ?? readOptional(join(dir, "brief.md")) ?? "";
|
|
48
|
+
const entries = [...migrationEntries(plan), ...mutation.entries].map((entry, seq) => ({
|
|
49
|
+
...entry,
|
|
50
|
+
revision: next,
|
|
51
|
+
id: `${next}-${seq}`,
|
|
52
|
+
}));
|
|
53
|
+
const record: PlanCommitRecord = {
|
|
54
|
+
version: 1,
|
|
55
|
+
revision: next,
|
|
56
|
+
plan: { ...plan, revision: next, brief },
|
|
57
|
+
ledger: entries,
|
|
58
|
+
};
|
|
59
|
+
mkdirSync(join(dir, "revisions"), { recursive: true });
|
|
60
|
+
mkdirSync(join(dir, "tmp"), { recursive: true });
|
|
61
|
+
const temp = join(dir, "tmp", `${process.pid}-${randomUUID()}.json`);
|
|
62
|
+
try {
|
|
63
|
+
writeFileSync(temp, `${JSON.stringify(record)}\n`, { flag: "wx" });
|
|
64
|
+
try {
|
|
65
|
+
(hooks.getStore()?.link ?? linkSync)(temp, join(dir, "revisions", `${String(next).padStart(8, "0")}.json`));
|
|
66
|
+
} catch (error) {
|
|
67
|
+
if (hasCode(error, "EEXIST"))
|
|
68
|
+
throw new UlwLoopError("Another writer published the read revision.", "ULW_LOOP_PUBLISH_CONFLICT", {
|
|
69
|
+
cause: error,
|
|
70
|
+
});
|
|
71
|
+
if (["EPERM", "ENOTSUP", "EXDEV"].some((code) => hasCode(error, code)))
|
|
72
|
+
throw new UlwLoopError(
|
|
73
|
+
"Immutable ulw-loop publication requires atomic hard links.",
|
|
74
|
+
"ULW_LOOP_PUBLISH_UNSUPPORTED_FS",
|
|
75
|
+
{ cause: error },
|
|
76
|
+
);
|
|
77
|
+
throw error;
|
|
78
|
+
}
|
|
79
|
+
} finally {
|
|
80
|
+
rmSync(temp, { force: true });
|
|
81
|
+
}
|
|
82
|
+
plan.revision = next;
|
|
83
|
+
plan.brief = brief;
|
|
84
|
+
for (const [index, entry] of mutation.entries.entries())
|
|
85
|
+
Object.assign(entry, entries[index + entries.length - mutation.entries.length]);
|
|
86
|
+
await hooks.getStore()?.afterCommit?.();
|
|
87
|
+
await materialize(dir);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function viewContents(dir: string): [string, string][] {
|
|
91
|
+
const plan = reconcilePlan(dir);
|
|
92
|
+
if (plan === undefined || readRecords(dir).length === 0) return [];
|
|
93
|
+
const ledger = readLedgerAt(dir);
|
|
94
|
+
const views: [string, string][] = [
|
|
95
|
+
["goals.json", `${JSON.stringify(plan, null, 2)}\n`],
|
|
96
|
+
["ledger.jsonl", ledger.length === 0 ? "" : `${ledger.map((entry) => JSON.stringify(entry)).join("\n")}\n`],
|
|
97
|
+
["brief.md", plan.brief ?? readOptional(join(dir, "brief.md")) ?? ""],
|
|
98
|
+
];
|
|
99
|
+
return views.filter(([name, content]) => readOptional(join(dir, name)) !== content);
|
|
100
|
+
}
|
|
101
|
+
export function materializeSync(dir: string): void {
|
|
102
|
+
for (const [name, content] of viewContents(dir)) {
|
|
103
|
+
mkdirSync(join(dir, "tmp"), { recursive: true });
|
|
104
|
+
const temp = join(dir, "tmp", `${process.pid}-${randomUUID()}-${name}`);
|
|
105
|
+
try {
|
|
106
|
+
writeFileSync(temp, content, { flag: "wx" });
|
|
107
|
+
renameSync(temp, join(dir, name));
|
|
108
|
+
} finally {
|
|
109
|
+
rmSync(temp, { force: true });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
export async function materialize(dir: string): Promise<void> {
|
|
114
|
+
for (const [name, content] of viewContents(dir)) {
|
|
115
|
+
mkdirSync(join(dir, "tmp"), { recursive: true });
|
|
116
|
+
const temp = join(dir, "tmp", `${process.pid}-${randomUUID()}-${name}`);
|
|
117
|
+
try {
|
|
118
|
+
await writeViewFile(temp, content);
|
|
119
|
+
await rename(temp, join(dir, name));
|
|
120
|
+
} finally {
|
|
121
|
+
rmSync(temp, { force: true });
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -1,20 +1,21 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
|
-
import { mkdir, writeFile } from "node:fs/promises";
|
|
3
|
-
|
|
4
1
|
import { aggregateCodexObjectiveForScope, isUlwLoopDone } from "./goal-status.js";
|
|
5
2
|
import {
|
|
6
3
|
type UlwLoopScope,
|
|
7
|
-
ulwLoopBriefPath,
|
|
8
4
|
ulwLoopBriefRelativePath,
|
|
9
|
-
ulwLoopDir,
|
|
10
|
-
ulwLoopGoalsPath,
|
|
11
5
|
ulwLoopGoalsRelativePath,
|
|
12
|
-
ulwLoopLedgerPath,
|
|
13
6
|
ulwLoopLedgerRelativePath,
|
|
14
7
|
} from "./paths.js";
|
|
8
|
+
import { beforePlanMutation, commit } from "./plan-commit.js";
|
|
15
9
|
import { appendGoalToPlan, deriveGoalCandidates, makeGoal } from "./plan-goal-factory.js";
|
|
16
|
-
import {
|
|
17
|
-
import type {
|
|
10
|
+
import { planExists, readUlwLoopPlan, withUlwLoopMutationLock } from "./plan-io.js";
|
|
11
|
+
import type { UlwLoopToolkitSurface } from "./surface.js";
|
|
12
|
+
import type {
|
|
13
|
+
UlwLoopCodexGoalMode,
|
|
14
|
+
UlwLoopItem,
|
|
15
|
+
UlwLoopLedgerEntry,
|
|
16
|
+
UlwLoopPlan,
|
|
17
|
+
UlwLoopSuccessCriterion,
|
|
18
|
+
} from "./types.js";
|
|
18
19
|
import { iso, UlwLoopError } from "./types.js";
|
|
19
20
|
import { parseValidationBatches } from "./validation-batch.js";
|
|
20
21
|
|
|
@@ -60,11 +61,19 @@ export async function createUlwLoopPlan(
|
|
|
60
61
|
repoRoot: string,
|
|
61
62
|
args: { brief: string; codexGoalMode?: UlwLoopCodexGoalMode; force?: boolean; validationBatchesJson?: string },
|
|
62
63
|
scope?: UlwLoopScope,
|
|
64
|
+
surface: UlwLoopToolkitSurface = "lazycodex",
|
|
63
65
|
): Promise<UlwLoopPlan> {
|
|
64
66
|
return withUlwLoopMutationLock(repoRoot, scope, async () => {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
let existing: UlwLoopPlan | undefined;
|
|
68
|
+
if (planExists(repoRoot, scope)) {
|
|
69
|
+
try {
|
|
70
|
+
existing = await readUlwLoopPlan(repoRoot, scope);
|
|
71
|
+
} catch (error) {
|
|
72
|
+
if (!args.force) throw error;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (!args.force && existing !== undefined) {
|
|
76
|
+
if (isUlwLoopDone(existing)) throw completedPlanExistsError(scope, surface);
|
|
68
77
|
throw new UlwLoopError(
|
|
69
78
|
`Refusing to overwrite existing ${ulwLoopGoalsRelativePath(scope)}; pass --force to recreate it.`,
|
|
70
79
|
"ULW_LOOP_PLAN_EXISTS",
|
|
@@ -76,6 +85,9 @@ export async function createUlwLoopPlan(
|
|
|
76
85
|
);
|
|
77
86
|
const plan: UlwLoopPlan = {
|
|
78
87
|
version: 1,
|
|
88
|
+
revision: existing?.revision ?? 0,
|
|
89
|
+
ledgerResetRevision: (existing?.revision ?? 0) + 1,
|
|
90
|
+
brief: args.brief.endsWith("\n") ? args.brief : `${args.brief}\n`,
|
|
79
91
|
evidenceLayoutVersion: 2,
|
|
80
92
|
createdAt: now,
|
|
81
93
|
updatedAt: now,
|
|
@@ -88,29 +100,27 @@ export async function createUlwLoopPlan(
|
|
|
88
100
|
const validationBatches = await parseValidationBatches(args.validationBatchesJson, goals);
|
|
89
101
|
if (validationBatches !== undefined) plan.validationBatches = validationBatches;
|
|
90
102
|
if (plan.codexGoalMode === "aggregate") plan.codexObjective = aggregateCodexObjectiveForScope(scope);
|
|
91
|
-
await
|
|
92
|
-
await
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
);
|
|
97
|
-
await writePlan(repoRoot, plan, scope);
|
|
98
|
-
await writeFile(ulwLoopLedgerPath(repoRoot, scope), "", "utf8");
|
|
99
|
-
await appendLedger(
|
|
100
|
-
repoRoot,
|
|
101
|
-
{ at: now, kind: "plan_created", message: `${goals.length} goal(s) created` },
|
|
102
|
-
scope,
|
|
103
|
-
);
|
|
103
|
+
await beforePlanMutation();
|
|
104
|
+
await commit(repoRoot, scope, {
|
|
105
|
+
plan,
|
|
106
|
+
entries: [{ at: now, kind: "plan_created", message: `${goals.length} goal(s) created` }],
|
|
107
|
+
});
|
|
104
108
|
return plan;
|
|
105
109
|
});
|
|
106
110
|
}
|
|
107
111
|
|
|
108
|
-
function completedPlanExistsError(scope
|
|
112
|
+
function completedPlanExistsError(scope: UlwLoopScope | undefined, surface: UlwLoopToolkitSurface): UlwLoopError {
|
|
109
113
|
return new UlwLoopError(
|
|
110
114
|
[
|
|
111
115
|
`Existing ulw-loop aggregate is already complete at ${ulwLoopGoalsRelativePath(scope)}.`,
|
|
112
|
-
|
|
113
|
-
|
|
116
|
+
...(surface === "omo-senpi"
|
|
117
|
+
? [
|
|
118
|
+
"Start a new run under a fresh session id (a new senpi session) or call agentToolkit.createGoals({ brief, force: true }) to recreate.",
|
|
119
|
+
]
|
|
120
|
+
: [
|
|
121
|
+
"Start a new run with `omo-agent-toolkit ulw-loop create-goals --session-id <new-id> ...` to isolate fresh state.",
|
|
122
|
+
"Use --force only when you intentionally want to overwrite the completed evidence.",
|
|
123
|
+
]),
|
|
114
124
|
].join(" "),
|
|
115
125
|
"ULW_LOOP_PLAN_EXISTS_COMPLETE",
|
|
116
126
|
);
|
|
@@ -125,12 +135,10 @@ export async function addUlwLoopGoal(
|
|
|
125
135
|
const plan = await readUlwLoopPlan(repoRoot, scope);
|
|
126
136
|
const now = iso();
|
|
127
137
|
const goal = appendGoalToPlan(plan, args.title, args.objective, now);
|
|
128
|
-
await
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
scope,
|
|
133
|
-
);
|
|
138
|
+
await commit(repoRoot, scope, {
|
|
139
|
+
plan,
|
|
140
|
+
entries: [{ at: now, kind: "goal_added", goalId: goal.id, status: goal.status, message: goal.title }],
|
|
141
|
+
});
|
|
134
142
|
return { plan, goal };
|
|
135
143
|
});
|
|
136
144
|
}
|
|
@@ -146,21 +154,18 @@ export async function startNextUlwLoop(
|
|
|
146
154
|
if (plan.aggregateCompletion?.status === "complete") return { done: true, plan };
|
|
147
155
|
const existing = plan.goals.find((goal) => goal.status === "in_progress" && isScheduleEligible(goal));
|
|
148
156
|
if (existing) return { plan, goal: existing, resumed: true };
|
|
157
|
+
const entries: UlwLoopLedgerEntry[] = [];
|
|
149
158
|
let next = plan.goals.find((goal) => goal.status === "pending" && isScheduleEligible(goal));
|
|
150
159
|
if (!next && args.retryFailed) {
|
|
151
160
|
next = plan.goals.find((goal) => goal.status === "failed" && !goal.nonRetriable && isScheduleEligible(goal));
|
|
152
161
|
if (next)
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
...(next.failureReason ? { message: next.failureReason } : {}),
|
|
161
|
-
},
|
|
162
|
-
scope,
|
|
163
|
-
);
|
|
162
|
+
entries.push({
|
|
163
|
+
at: now,
|
|
164
|
+
kind: "goal_retried",
|
|
165
|
+
goalId: next.id,
|
|
166
|
+
status: "pending",
|
|
167
|
+
...(next.failureReason ? { message: next.failureReason } : {}),
|
|
168
|
+
});
|
|
164
169
|
}
|
|
165
170
|
if (!next) return { done: true, plan };
|
|
166
171
|
next.status = "in_progress";
|
|
@@ -170,12 +175,14 @@ export async function startNextUlwLoop(
|
|
|
170
175
|
next.updatedAt = now;
|
|
171
176
|
plan.activeGoalId = next.id;
|
|
172
177
|
plan.updatedAt = now;
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
178
|
+
entries.push({
|
|
179
|
+
at: now,
|
|
180
|
+
kind: "goal_started",
|
|
181
|
+
goalId: next.id,
|
|
182
|
+
status: next.status,
|
|
183
|
+
message: `Attempt ${next.attempt}`,
|
|
184
|
+
});
|
|
185
|
+
await commit(repoRoot, scope, { plan, entries });
|
|
179
186
|
return { plan, goal: next, resumed: false };
|
|
180
187
|
});
|
|
181
188
|
}
|