lazycodex-ai 5.0.0-beta.62 → 5.0.0-beta.64
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 +70 -41
- package/dist/cli-node/index.js +70 -41
- 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 +4 -2
- 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-codex-validation.d.ts +7 -5
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-codex-validation.js +7 -2
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.js +7 -4
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +931 -442
- package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-snapshot.d.ts +6 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-snapshot.js +20 -12
- package/packages/omo-codex/plugin/components/ulw-loop/dist/domain-types.d.ts +8 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/driver-objective-ack.d.ts +4 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/driver-objective-ack.js +18 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/evidence-artifacts.d.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/evidence-artifacts.js +37 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/evidence.d.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/evidence.js +24 -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/paths.d.ts +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/paths.js +6 -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 +6 -2
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.js +54 -25
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-goal-factory.d.ts +10 -3
- package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-goal-factory.js +38 -31
- 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 +11 -8
- package/packages/omo-codex/plugin/components/ulw-loop/dist/sdk/factory.js +28 -12
- package/packages/omo-codex/plugin/components/ulw-loop/dist/sdk/manifest.d.ts +335 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/sdk/manifest.js +109 -10
- package/packages/omo-codex/plugin/components/ulw-loop/dist/sdk/types.d.ts +3 -0
- 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-mutations.d.ts +3 -2
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-mutations.js +4 -4
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-types.d.ts +9 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering.d.ts +3 -2
- package/packages/omo-codex/plugin/components/ulw-loop/dist/steering.js +11 -11
- package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +8 -17
- package/packages/omo-codex/plugin/components/ulw-loop/dist/success-criteria-input.d.ts +9 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/success-criteria-input.js +41 -0
- 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-codex-validation.ts +15 -3
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +7 -4
- package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-snapshot.ts +26 -14
- package/packages/omo-codex/plugin/components/ulw-loop/src/domain-types.ts +8 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/driver-objective-ack.ts +20 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/evidence-artifacts.ts +45 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/evidence.ts +23 -16
- package/packages/omo-codex/plugin/components/ulw-loop/src/ledger.ts +33 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/paths.ts +7 -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 +67 -54
- package/packages/omo-codex/plugin/components/ulw-loop/src/plan-goal-factory.ts +63 -31
- 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 +11 -7
- package/packages/omo-codex/plugin/components/ulw-loop/src/sdk/factory.ts +47 -12
- package/packages/omo-codex/plugin/components/ulw-loop/src/sdk/manifest.ts +124 -10
- package/packages/omo-codex/plugin/components/ulw-loop/src/sdk/types.ts +3 -0
- 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-mutations.ts +5 -4
- package/packages/omo-codex/plugin/components/ulw-loop/src/steering-types.ts +13 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/steering.ts +12 -10
- package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +8 -16
- package/packages/omo-codex/plugin/components/ulw-loop/src/success-criteria-input.ts +56 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/codex-goal-snapshot.test.ts +37 -1
- 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-driver-states.test.ts +33 -4
- package/packages/omo-codex/plugin/components/ulw-loop/test/sdk-dx.test.ts +219 -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 +6 -4
- 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
|
@@ -8,12 +8,18 @@ export interface CodexGoalSnapshot {
|
|
|
8
8
|
export interface CodexGoalReconciliation {
|
|
9
9
|
ok: boolean;
|
|
10
10
|
snapshot: CodexGoalSnapshot;
|
|
11
|
+
/** Facts to know (a differing driver objective); never something to do. */
|
|
11
12
|
warnings: string[];
|
|
13
|
+
/** Things to do next (create, re-create, or resume the driver goal). */
|
|
14
|
+
nextActions: string[];
|
|
12
15
|
errors: string[];
|
|
16
|
+
/** The differing objective this reconciliation reported for the first time, for the caller to acknowledge. */
|
|
17
|
+
unacknowledgedObjective?: string;
|
|
13
18
|
}
|
|
14
19
|
export interface ReconcileCodexGoalOptions {
|
|
15
20
|
expectedObjective: string;
|
|
16
21
|
readonly acceptedObjectives?: readonly string[];
|
|
22
|
+
readonly acknowledgedObjectives?: readonly string[];
|
|
17
23
|
}
|
|
18
24
|
export declare class CodexGoalSnapshotError extends Error {
|
|
19
25
|
}
|
|
@@ -73,29 +73,37 @@ export function reconcileCodexGoalSnapshot(snapshot, options) {
|
|
|
73
73
|
const effectiveSnapshot = snapshot ?? { available: false, raw: null };
|
|
74
74
|
const errors = [];
|
|
75
75
|
const warnings = [];
|
|
76
|
+
const nextActions = [];
|
|
76
77
|
const expected = options.expectedObjective;
|
|
77
|
-
const normalizedExpected = normalizeObjective(expected);
|
|
78
78
|
if (!effectiveSnapshot.available) {
|
|
79
|
-
|
|
80
|
-
return { ok: errors.length === 0, snapshot: effectiveSnapshot, warnings, errors };
|
|
79
|
+
nextActions.push(`call get_goal; if none, create_goal with codexObjective "${expected}" verbatim`);
|
|
80
|
+
return { ok: errors.length === 0, snapshot: effectiveSnapshot, warnings, nextActions, errors };
|
|
81
81
|
}
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
].filter(Boolean));
|
|
82
|
+
const normalized = (objectives) => new Set(objectives.map(normalizeObjective).filter(Boolean));
|
|
83
|
+
const accepted = normalized([expected, ...(options.acceptedObjectives ?? [])]);
|
|
84
|
+
const acknowledged = normalized(options.acknowledgedObjectives ?? []);
|
|
86
85
|
const actual = normalizeObjective(effectiveSnapshot.objective ?? "");
|
|
87
|
-
|
|
86
|
+
let unacknowledgedObjective;
|
|
87
|
+
if (actual && !accepted.has(actual) && !acknowledged.has(actual)) {
|
|
88
88
|
warnings.push(`driver_objective_differs: expected "${expected}", got "${actual}".`);
|
|
89
|
+
unacknowledgedObjective = actual;
|
|
89
90
|
}
|
|
90
91
|
const actualStatus = effectiveSnapshot.status ?? "unknown";
|
|
91
92
|
if (actualStatus === "paused" || actualStatus === "usage_limited" || actualStatus === "budget_limited") {
|
|
92
|
-
|
|
93
|
+
nextActions.push("/goal resume or raise the budget");
|
|
93
94
|
}
|
|
94
95
|
if (actualStatus === "complete")
|
|
95
|
-
|
|
96
|
-
return {
|
|
96
|
+
nextActions.push(`driver closed early: call create_goal with codexObjective "${expected}" verbatim`);
|
|
97
|
+
return {
|
|
98
|
+
ok: errors.length === 0,
|
|
99
|
+
snapshot: effectiveSnapshot,
|
|
100
|
+
warnings,
|
|
101
|
+
nextActions,
|
|
102
|
+
errors,
|
|
103
|
+
...(unacknowledgedObjective === undefined ? {} : { unacknowledgedObjective }),
|
|
104
|
+
};
|
|
97
105
|
}
|
|
98
106
|
export function formatCodexGoalReconciliation(reconciliation) {
|
|
99
|
-
const parts = [...reconciliation.errors, ...reconciliation.warnings];
|
|
107
|
+
const parts = [...reconciliation.errors, ...reconciliation.nextActions, ...reconciliation.warnings];
|
|
100
108
|
return parts.join(" ");
|
|
101
109
|
}
|
|
@@ -10,6 +10,7 @@ export interface UlwLoopSuccessCriterion {
|
|
|
10
10
|
status: UlwLoopCriterionStatus;
|
|
11
11
|
capturedAt?: string;
|
|
12
12
|
notes?: string;
|
|
13
|
+
artifacts?: string[];
|
|
13
14
|
}
|
|
14
15
|
export interface UlwLoopItem {
|
|
15
16
|
id: string;
|
|
@@ -50,6 +51,9 @@ export interface UlwLoopValidationBatch {
|
|
|
50
51
|
}
|
|
51
52
|
export interface UlwLoopPlan {
|
|
52
53
|
version: 1;
|
|
54
|
+
revision?: number;
|
|
55
|
+
brief?: string;
|
|
56
|
+
ledgerResetRevision?: number;
|
|
53
57
|
evidenceLayoutVersion?: 2;
|
|
54
58
|
createdAt: string;
|
|
55
59
|
updatedAt: string;
|
|
@@ -59,6 +63,7 @@ export interface UlwLoopPlan {
|
|
|
59
63
|
codexGoalMode?: UlwLoopCodexGoalMode;
|
|
60
64
|
codexObjective?: string;
|
|
61
65
|
codexObjectiveAliases?: string[];
|
|
66
|
+
acknowledgedDriverObjectives?: string[];
|
|
62
67
|
aggregateCompletion?: UlwLoopAggregateCompletion;
|
|
63
68
|
activeGoalId?: string;
|
|
64
69
|
validationBatches?: readonly UlwLoopValidationBatch[];
|
|
@@ -136,6 +141,8 @@ export interface UlwLoopQualityGateSenpi extends UlwLoopQualityGateCommon {
|
|
|
136
141
|
}
|
|
137
142
|
export type UlwLoopQualityGate = UlwLoopQualityGateLazycodex | UlwLoopQualityGateSenpi;
|
|
138
143
|
export interface UlwLoopLedgerEntry {
|
|
144
|
+
revision?: number;
|
|
145
|
+
id?: string;
|
|
139
146
|
at: string;
|
|
140
147
|
kind: UlwLoopLedgerEventKind;
|
|
141
148
|
goalId?: string;
|
|
@@ -146,6 +153,7 @@ export interface UlwLoopLedgerEntry {
|
|
|
146
153
|
codexGoal?: unknown;
|
|
147
154
|
evidence?: string;
|
|
148
155
|
capturedEvidence?: string;
|
|
156
|
+
artifacts?: string[];
|
|
149
157
|
qualityGate?: unknown;
|
|
150
158
|
steering?: UlwLoopSteeringAudit;
|
|
151
159
|
before?: unknown;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { UlwLoopPlan } from "./types.js";
|
|
2
|
+
export declare function normalizeDriverObjective(value: string): string;
|
|
3
|
+
export declare function acknowledgedDriverObjectives(plan: UlwLoopPlan): readonly string[];
|
|
4
|
+
export declare function acknowledgeDriverObjective(plan: UlwLoopPlan, objective: string | undefined): boolean;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export function normalizeDriverObjective(value) {
|
|
2
|
+
return value.replace(/\s+/g, " ").trim();
|
|
3
|
+
}
|
|
4
|
+
export function acknowledgedDriverObjectives(plan) {
|
|
5
|
+
return plan.acknowledgedDriverObjectives ?? [];
|
|
6
|
+
}
|
|
7
|
+
// A differing driver objective is reported once; the plan remembers the exact text so every later
|
|
8
|
+
// checkpoint under the same driver stays quiet, while a driver rewritten to a third objective is
|
|
9
|
+
// reported again.
|
|
10
|
+
export function acknowledgeDriverObjective(plan, objective) {
|
|
11
|
+
if (objective === undefined)
|
|
12
|
+
return false;
|
|
13
|
+
const normalized = normalizeDriverObjective(objective);
|
|
14
|
+
if (!normalized || acknowledgedDriverObjectives(plan).includes(normalized))
|
|
15
|
+
return false;
|
|
16
|
+
plan.acknowledgedDriverObjectives = [...acknowledgedDriverObjectives(plan), normalized];
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function resolveEvidenceArtifacts(repoRoot: string, artifacts: readonly unknown[] | undefined): string[] | undefined;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { isAbsolute, relative, resolve, sep } from "node:path";
|
|
3
|
+
import { UlwLoopError } from "./types.js";
|
|
4
|
+
function fail(message, code, details) {
|
|
5
|
+
throw new UlwLoopError(message, code, { details });
|
|
6
|
+
}
|
|
7
|
+
function stored(repoRoot, absolute) {
|
|
8
|
+
const rel = relative(repoRoot, absolute);
|
|
9
|
+
const inside = rel !== "" && !rel.startsWith("..") && !isAbsolute(rel);
|
|
10
|
+
return inside ? rel.split(sep).join("/") : absolute;
|
|
11
|
+
}
|
|
12
|
+
// Artifacts are bound at record time: a cited path that does not exist is a claim without a file,
|
|
13
|
+
// so the whole record is refused before any state changes. Paths inside the session cwd persist
|
|
14
|
+
// repo-relative (portable across machines); paths outside persist absolute.
|
|
15
|
+
export function resolveEvidenceArtifacts(repoRoot, artifacts) {
|
|
16
|
+
if (artifacts === undefined)
|
|
17
|
+
return undefined;
|
|
18
|
+
const seen = new Set();
|
|
19
|
+
const resolved = [];
|
|
20
|
+
for (const [index, candidate] of artifacts.entries()) {
|
|
21
|
+
const path = typeof candidate === "string" ? candidate.trim() : "";
|
|
22
|
+
if (!path)
|
|
23
|
+
fail(`Artifact ${index + 1} must be a non-empty path.`, "ULW_LOOP_ARGUMENT_INVALID", { index });
|
|
24
|
+
const absolute = resolve(repoRoot, path);
|
|
25
|
+
if (!existsSync(absolute))
|
|
26
|
+
fail(`Evidence artifact does not exist: ${path} (resolved to ${absolute}).`, "ULW_LOOP_EVIDENCE_ARTIFACT_MISSING", {
|
|
27
|
+
path,
|
|
28
|
+
resolved: absolute,
|
|
29
|
+
});
|
|
30
|
+
const value = stored(repoRoot, absolute);
|
|
31
|
+
if (!seen.has(value)) {
|
|
32
|
+
seen.add(value);
|
|
33
|
+
resolved.push(value);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return resolved;
|
|
37
|
+
}
|
|
@@ -7,6 +7,7 @@ type RecordEvidenceArgs = {
|
|
|
7
7
|
readonly status: EvidenceStatus;
|
|
8
8
|
readonly evidence: string;
|
|
9
9
|
readonly notes?: string;
|
|
10
|
+
readonly artifacts?: readonly string[];
|
|
10
11
|
};
|
|
11
12
|
export declare function recordEvidence(repoRoot: string, args: RecordEvidenceArgs, scope?: UlwLoopScope): Promise<{
|
|
12
13
|
plan: UlwLoopPlan;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { resolveEvidenceArtifacts } from "./evidence-artifacts.js";
|
|
1
2
|
import { essentialCriteriaOf, hasAllCriteriaPass, hasEssentialCriteriaPass } from "./goal-status.js";
|
|
2
|
-
import {
|
|
3
|
+
import { commit } from "./plan-commit.js";
|
|
4
|
+
import { readUlwLoopPlan, withUlwLoopMutationLock } from "./plan-io.js";
|
|
3
5
|
import { iso, UlwLoopError } from "./types.js";
|
|
4
6
|
function ulwLoopFail(message, code, details) {
|
|
5
7
|
throw new UlwLoopError(message, code, { details });
|
|
@@ -38,6 +40,7 @@ export async function recordEvidence(repoRoot, args, scope) {
|
|
|
38
40
|
const goal = findGoal(plan, args.goalId);
|
|
39
41
|
const criterion = findCriterion(goal, args.criterionId);
|
|
40
42
|
const evidence = nonEmptyEvidence(args.evidence);
|
|
43
|
+
const artifacts = resolveEvidenceArtifacts(repoRoot, args.artifacts);
|
|
41
44
|
const kind = ledgerKind(args.status);
|
|
42
45
|
const prevStatus = criterion.status;
|
|
43
46
|
const capturedAt = iso();
|
|
@@ -46,9 +49,12 @@ export async function recordEvidence(repoRoot, args, scope) {
|
|
|
46
49
|
criterion.capturedAt = capturedAt;
|
|
47
50
|
if (args.notes !== undefined)
|
|
48
51
|
criterion.notes = args.notes;
|
|
52
|
+
if (artifacts !== undefined)
|
|
53
|
+
criterion.artifacts = artifacts;
|
|
54
|
+
else
|
|
55
|
+
delete criterion.artifacts;
|
|
49
56
|
goal.updatedAt = capturedAt;
|
|
50
57
|
plan.updatedAt = capturedAt;
|
|
51
|
-
await writePlan(repoRoot, plan, scope);
|
|
52
58
|
const ledgerEntry = {
|
|
53
59
|
at: capturedAt,
|
|
54
60
|
kind,
|
|
@@ -57,10 +63,11 @@ export async function recordEvidence(repoRoot, args, scope) {
|
|
|
57
63
|
criterionStatus: args.status,
|
|
58
64
|
evidence,
|
|
59
65
|
capturedEvidence: evidence,
|
|
66
|
+
...(artifacts === undefined ? {} : { artifacts }),
|
|
60
67
|
before: { status: prevStatus },
|
|
61
68
|
after: { goalId: goal.id, criterionId: criterion.id, status: args.status, evidence, capturedAt, prevStatus },
|
|
62
69
|
};
|
|
63
|
-
await
|
|
70
|
+
await commit(repoRoot, scope, { plan, entries: [ledgerEntry] });
|
|
64
71
|
return { plan, goal, criterion, ledgerEntry };
|
|
65
72
|
});
|
|
66
73
|
}
|
|
@@ -80,18 +87,23 @@ export async function markCriteriaPendingResetForGoal(repoRoot, goalId, scope) {
|
|
|
80
87
|
criterion.capturedEvidence = null;
|
|
81
88
|
delete criterion.capturedAt;
|
|
82
89
|
delete criterion.notes;
|
|
90
|
+
delete criterion.artifacts;
|
|
83
91
|
}
|
|
84
92
|
goal.updatedAt = now;
|
|
85
93
|
plan.updatedAt = now;
|
|
86
|
-
await
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
await commit(repoRoot, scope, {
|
|
95
|
+
plan,
|
|
96
|
+
entries: [
|
|
97
|
+
{
|
|
98
|
+
at: now,
|
|
99
|
+
kind: "criteria_revised",
|
|
100
|
+
goalId,
|
|
101
|
+
message: `Reset ${goal.successCriteria.length} criteria to pending.`,
|
|
102
|
+
before,
|
|
103
|
+
after: { resetCount: goal.successCriteria.length },
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
});
|
|
95
107
|
return { plan, resetCount: goal.successCriteria.length };
|
|
96
108
|
});
|
|
97
109
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type UlwLoopScope } from "./paths.js";
|
|
2
|
+
import type { UlwLoopLedgerEntry } from "./types.js";
|
|
3
|
+
export declare function readLedgerAt(dir: string): UlwLoopLedgerEntry[];
|
|
4
|
+
export declare function readLedger(repoRoot: string, scope?: UlwLoopScope): UlwLoopLedgerEntry[];
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { ulwLoopDir } from "./paths.js";
|
|
3
|
+
import { readOptional, readRecords, reconcilePlan } from "./plan-log.js";
|
|
4
|
+
export function readLedgerAt(dir) {
|
|
5
|
+
const entries = new Map();
|
|
6
|
+
const lines = (readOptional(join(dir, "ledger.jsonl")) ?? "").split(/\r?\n/);
|
|
7
|
+
for (const [index, line] of lines.entries()) {
|
|
8
|
+
if (line.trim().length === 0)
|
|
9
|
+
continue;
|
|
10
|
+
try {
|
|
11
|
+
const entry = JSON.parse(line);
|
|
12
|
+
entry.revision ??= 0;
|
|
13
|
+
entry.id ??= `legacy-${index + 1}`;
|
|
14
|
+
entries.set(entry.id, entry);
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
if (!(error instanceof SyntaxError))
|
|
18
|
+
throw error;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
for (const record of readRecords(dir))
|
|
22
|
+
for (const [seq, entry] of record.ledger.entries()) {
|
|
23
|
+
const id = entry.id ?? `${record.revision}-${seq}`;
|
|
24
|
+
entries.set(id, { ...entry, revision: record.revision, id });
|
|
25
|
+
}
|
|
26
|
+
const reset = reconcilePlan(dir)?.ledgerResetRevision ?? 0;
|
|
27
|
+
const sequence = (entry) => Number(entry.id?.split("-").at(-1) ?? 0);
|
|
28
|
+
return [...entries.values()]
|
|
29
|
+
.filter((entry) => (entry.revision ?? 0) >= reset)
|
|
30
|
+
.sort((a, b) => (a.revision ?? 0) - (b.revision ?? 0) || sequence(a) - sequence(b));
|
|
31
|
+
}
|
|
32
|
+
export function readLedger(repoRoot, scope) {
|
|
33
|
+
return readLedgerAt(ulwLoopDir(repoRoot, scope));
|
|
34
|
+
}
|
|
@@ -14,6 +14,7 @@ export declare function ulwLoopGoalsPath(repoRoot: string, scope?: UlwLoopScope)
|
|
|
14
14
|
export declare function ulwLoopLedgerPath(repoRoot: string, scope?: UlwLoopScope): string;
|
|
15
15
|
export declare function ulwLoopStateLockPath(repoRoot: string, scope?: UlwLoopScope): string;
|
|
16
16
|
export declare function repoRelative(absolutePath: string, repoRoot: string): string;
|
|
17
|
+
export declare function ulwLoopEvidenceRoot(scope?: UlwLoopScope): string;
|
|
17
18
|
export declare function ulwLoopAttemptEvidenceDir(goalId: string, attempt: number, scope?: UlwLoopScope): string;
|
|
18
19
|
interface AttemptPathApi {
|
|
19
20
|
relative(from: string, to: string): string;
|
|
@@ -62,6 +62,12 @@ export function repoRelative(absolutePath, repoRoot) {
|
|
|
62
62
|
return absolutePath.slice(backslashPrefix.length).split("\\").join("/");
|
|
63
63
|
return absolutePath.split("\\").join("/");
|
|
64
64
|
}
|
|
65
|
+
// The plan-level evidence root stays fixed for the whole run, unlike the per-goal attempt dir, so
|
|
66
|
+
// long lanes that span goals have one stable place to write artifacts.
|
|
67
|
+
export function ulwLoopEvidenceRoot(scope) {
|
|
68
|
+
const sessionId = normalizeUlwLoopSessionId(scope?.sessionId);
|
|
69
|
+
return sessionId === null ? ".omo/evidence" : `.omo/evidence/ulw/${sessionId}`;
|
|
70
|
+
}
|
|
65
71
|
// Both the status --json emitter and the checkpoint enforcement resolve the attempt dir through
|
|
66
72
|
// this function from the scope alone; a second resolution path (env, a literal placeholder)
|
|
67
73
|
// would let the gate reject its own advertised directory.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type UlwLoopScope } from "./paths.js";
|
|
2
|
+
import { type UlwLoopLedgerEntry, type UlwLoopPlan } from "./types.js";
|
|
3
|
+
interface CommitHooks {
|
|
4
|
+
readonly beforeMutation?: () => void | Promise<void>;
|
|
5
|
+
readonly beforeCommit?: () => void | Promise<void>;
|
|
6
|
+
readonly afterCommit?: () => void | Promise<void>;
|
|
7
|
+
readonly link?: (source: string, destination: string) => void;
|
|
8
|
+
readonly writeView?: (path: string, content: string) => Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
export declare function withCommitHooks<T>(value: CommitHooks, fn: () => Promise<T>): Promise<T>;
|
|
11
|
+
export declare function beforePlanMutation(): Promise<void>;
|
|
12
|
+
export declare function writeViewFile(path: string, content: string): Promise<void>;
|
|
13
|
+
export declare function commit(repoRoot: string, scope: UlwLoopScope | undefined, mutation: {
|
|
14
|
+
readonly plan: UlwLoopPlan;
|
|
15
|
+
readonly entries: readonly UlwLoopLedgerEntry[];
|
|
16
|
+
}): Promise<void>;
|
|
17
|
+
export declare function materializeSync(dir: string): void;
|
|
18
|
+
export declare function materialize(dir: string): Promise<void>;
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,107 @@
|
|
|
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 { ulwLoopDir, ulwLoopStateLockPath } from "./paths.js";
|
|
8
|
+
import { assertStateLockOwned, migrationEntries } from "./plan-io.js";
|
|
9
|
+
import { hasCode, readOptional, readRecords, reconcilePlan } from "./plan-log.js";
|
|
10
|
+
import { UlwLoopError } from "./types.js";
|
|
11
|
+
const hooks = new AsyncLocalStorage();
|
|
12
|
+
export function withCommitHooks(value, fn) {
|
|
13
|
+
return hooks.run(value, fn);
|
|
14
|
+
}
|
|
15
|
+
export async function beforePlanMutation() {
|
|
16
|
+
await hooks.getStore()?.beforeMutation?.();
|
|
17
|
+
}
|
|
18
|
+
export async function writeViewFile(path, content) {
|
|
19
|
+
await (hooks.getStore()?.writeView ?? writeFile)(path, content);
|
|
20
|
+
}
|
|
21
|
+
// link is the sole commit point; no copy fallback (Node copyFile is not atomic).
|
|
22
|
+
// A resumed zombie can publish first, but never overwrite an existing revision.
|
|
23
|
+
// Logical audit order is (revision, sequence), not materialization completion time.
|
|
24
|
+
export async function commit(repoRoot, scope, mutation) {
|
|
25
|
+
const { plan } = mutation;
|
|
26
|
+
const dir = ulwLoopDir(repoRoot, scope);
|
|
27
|
+
assertStateLockOwned(ulwLoopStateLockPath(repoRoot, scope));
|
|
28
|
+
await hooks.getStore()?.beforeCommit?.();
|
|
29
|
+
const next = (plan.revision ?? 0) + 1;
|
|
30
|
+
const brief = plan.brief ?? readOptional(join(dir, "brief.md")) ?? "";
|
|
31
|
+
const entries = [...migrationEntries(plan), ...mutation.entries].map((entry, seq) => ({
|
|
32
|
+
...entry,
|
|
33
|
+
revision: next,
|
|
34
|
+
id: `${next}-${seq}`,
|
|
35
|
+
}));
|
|
36
|
+
const record = {
|
|
37
|
+
version: 1,
|
|
38
|
+
revision: next,
|
|
39
|
+
plan: { ...plan, revision: next, brief },
|
|
40
|
+
ledger: entries,
|
|
41
|
+
};
|
|
42
|
+
mkdirSync(join(dir, "revisions"), { recursive: true });
|
|
43
|
+
mkdirSync(join(dir, "tmp"), { recursive: true });
|
|
44
|
+
const temp = join(dir, "tmp", `${process.pid}-${randomUUID()}.json`);
|
|
45
|
+
try {
|
|
46
|
+
writeFileSync(temp, `${JSON.stringify(record)}\n`, { flag: "wx" });
|
|
47
|
+
try {
|
|
48
|
+
(hooks.getStore()?.link ?? linkSync)(temp, join(dir, "revisions", `${String(next).padStart(8, "0")}.json`));
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
if (hasCode(error, "EEXIST"))
|
|
52
|
+
throw new UlwLoopError("Another writer published the read revision.", "ULW_LOOP_PUBLISH_CONFLICT", {
|
|
53
|
+
cause: error,
|
|
54
|
+
});
|
|
55
|
+
if (["EPERM", "ENOTSUP", "EXDEV"].some((code) => hasCode(error, code)))
|
|
56
|
+
throw new UlwLoopError("Immutable ulw-loop publication requires atomic hard links.", "ULW_LOOP_PUBLISH_UNSUPPORTED_FS", { cause: error });
|
|
57
|
+
throw error;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
finally {
|
|
61
|
+
rmSync(temp, { force: true });
|
|
62
|
+
}
|
|
63
|
+
plan.revision = next;
|
|
64
|
+
plan.brief = brief;
|
|
65
|
+
for (const [index, entry] of mutation.entries.entries())
|
|
66
|
+
Object.assign(entry, entries[index + entries.length - mutation.entries.length]);
|
|
67
|
+
await hooks.getStore()?.afterCommit?.();
|
|
68
|
+
await materialize(dir);
|
|
69
|
+
}
|
|
70
|
+
function viewContents(dir) {
|
|
71
|
+
const plan = reconcilePlan(dir);
|
|
72
|
+
if (plan === undefined || readRecords(dir).length === 0)
|
|
73
|
+
return [];
|
|
74
|
+
const ledger = readLedgerAt(dir);
|
|
75
|
+
const views = [
|
|
76
|
+
["goals.json", `${JSON.stringify(plan, null, 2)}\n`],
|
|
77
|
+
["ledger.jsonl", ledger.length === 0 ? "" : `${ledger.map((entry) => JSON.stringify(entry)).join("\n")}\n`],
|
|
78
|
+
["brief.md", plan.brief ?? readOptional(join(dir, "brief.md")) ?? ""],
|
|
79
|
+
];
|
|
80
|
+
return views.filter(([name, content]) => readOptional(join(dir, name)) !== content);
|
|
81
|
+
}
|
|
82
|
+
export function materializeSync(dir) {
|
|
83
|
+
for (const [name, content] of viewContents(dir)) {
|
|
84
|
+
mkdirSync(join(dir, "tmp"), { recursive: true });
|
|
85
|
+
const temp = join(dir, "tmp", `${process.pid}-${randomUUID()}-${name}`);
|
|
86
|
+
try {
|
|
87
|
+
writeFileSync(temp, content, { flag: "wx" });
|
|
88
|
+
renameSync(temp, join(dir, name));
|
|
89
|
+
}
|
|
90
|
+
finally {
|
|
91
|
+
rmSync(temp, { force: true });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
export async function materialize(dir) {
|
|
96
|
+
for (const [name, content] of viewContents(dir)) {
|
|
97
|
+
mkdirSync(join(dir, "tmp"), { recursive: true });
|
|
98
|
+
const temp = join(dir, "tmp", `${process.pid}-${randomUUID()}-${name}`);
|
|
99
|
+
try {
|
|
100
|
+
await writeViewFile(temp, content);
|
|
101
|
+
await rename(temp, join(dir, name));
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
rmSync(temp, { force: true });
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { type UlwLoopScope } from "./paths.js";
|
|
2
|
+
import type { SuccessCriterionInput } from "./success-criteria-input.js";
|
|
3
|
+
import type { UlwLoopToolkitSurface } from "./surface.js";
|
|
2
4
|
import type { UlwLoopCodexGoalMode, UlwLoopItem, UlwLoopPlan } from "./types.js";
|
|
3
5
|
export { deriveGoalCandidates, seedDefaultSuccessCriteria } from "./plan-goal-factory.js";
|
|
6
|
+
export type { SuccessCriterionInput } from "./success-criteria-input.js";
|
|
4
7
|
export type UlwLoopPlanSummary = {
|
|
5
8
|
readonly total: number;
|
|
6
9
|
readonly pending: number;
|
|
@@ -24,11 +27,12 @@ export declare function createUlwLoopPlan(repoRoot: string, args: {
|
|
|
24
27
|
codexGoalMode?: UlwLoopCodexGoalMode;
|
|
25
28
|
force?: boolean;
|
|
26
29
|
validationBatchesJson?: string;
|
|
27
|
-
}, scope?: UlwLoopScope): Promise<UlwLoopPlan>;
|
|
30
|
+
}, scope?: UlwLoopScope, surface?: UlwLoopToolkitSurface): Promise<UlwLoopPlan>;
|
|
28
31
|
export declare function addUlwLoopGoal(repoRoot: string, args: {
|
|
29
32
|
title: string;
|
|
30
33
|
objective: string;
|
|
31
|
-
|
|
34
|
+
successCriteria?: readonly SuccessCriterionInput[];
|
|
35
|
+
}, scope?: UlwLoopScope, surface?: UlwLoopToolkitSurface): Promise<{
|
|
32
36
|
plan: UlwLoopPlan;
|
|
33
37
|
goal: UlwLoopItem;
|
|
34
38
|
}>;
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
|
-
import { mkdir, writeFile } from "node:fs/promises";
|
|
3
1
|
import { aggregateCodexObjectiveForScope, isUlwLoopDone } from "./goal-status.js";
|
|
4
|
-
import {
|
|
2
|
+
import { ulwLoopBriefRelativePath, ulwLoopGoalsRelativePath, ulwLoopLedgerRelativePath, } from "./paths.js";
|
|
3
|
+
import { beforePlanMutation, commit } from "./plan-commit.js";
|
|
5
4
|
import { appendGoalToPlan, deriveGoalCandidates, makeGoal } from "./plan-goal-factory.js";
|
|
6
|
-
import {
|
|
5
|
+
import { planExists, readUlwLoopPlan, withUlwLoopMutationLock } from "./plan-io.js";
|
|
7
6
|
import { iso, UlwLoopError } from "./types.js";
|
|
8
7
|
import { parseValidationBatches } from "./validation-batch.js";
|
|
9
8
|
export { deriveGoalCandidates, seedDefaultSuccessCriteria } from "./plan-goal-factory.js";
|
|
@@ -22,18 +21,30 @@ function clearGoalBlockerFields(goal) {
|
|
|
22
21
|
])
|
|
23
22
|
delete goal[key];
|
|
24
23
|
}
|
|
25
|
-
export async function createUlwLoopPlan(repoRoot, args, scope) {
|
|
24
|
+
export async function createUlwLoopPlan(repoRoot, args, scope, surface = "lazycodex") {
|
|
26
25
|
return withUlwLoopMutationLock(repoRoot, scope, async () => {
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
let existing;
|
|
27
|
+
if (planExists(repoRoot, scope)) {
|
|
28
|
+
try {
|
|
29
|
+
existing = await readUlwLoopPlan(repoRoot, scope);
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
if (!args.force)
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (!args.force && existing !== undefined) {
|
|
29
37
|
if (isUlwLoopDone(existing))
|
|
30
|
-
throw completedPlanExistsError(scope);
|
|
38
|
+
throw completedPlanExistsError(scope, surface);
|
|
31
39
|
throw new UlwLoopError(`Refusing to overwrite existing ${ulwLoopGoalsRelativePath(scope)}; pass --force to recreate it.`, "ULW_LOOP_PLAN_EXISTS");
|
|
32
40
|
}
|
|
33
41
|
const now = iso();
|
|
34
|
-
const goals = deriveGoalCandidates(args.brief).map((goal, index) => makeGoal(goal.title, goal.objective, index, now));
|
|
42
|
+
const goals = deriveGoalCandidates(args.brief).map((goal, index) => makeGoal(goal.title, goal.objective, index, now, { surface }));
|
|
35
43
|
const plan = {
|
|
36
44
|
version: 1,
|
|
45
|
+
revision: existing?.revision ?? 0,
|
|
46
|
+
ledgerResetRevision: (existing?.revision ?? 0) + 1,
|
|
47
|
+
brief: args.brief.endsWith("\n") ? args.brief : `${args.brief}\n`,
|
|
37
48
|
evidenceLayoutVersion: 2,
|
|
38
49
|
createdAt: now,
|
|
39
50
|
updatedAt: now,
|
|
@@ -48,28 +59,39 @@ export async function createUlwLoopPlan(repoRoot, args, scope) {
|
|
|
48
59
|
plan.validationBatches = validationBatches;
|
|
49
60
|
if (plan.codexGoalMode === "aggregate")
|
|
50
61
|
plan.codexObjective = aggregateCodexObjectiveForScope(scope);
|
|
51
|
-
await
|
|
52
|
-
await
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
62
|
+
await beforePlanMutation();
|
|
63
|
+
await commit(repoRoot, scope, {
|
|
64
|
+
plan,
|
|
65
|
+
entries: [{ at: now, kind: "plan_created", message: `${goals.length} goal(s) created` }],
|
|
66
|
+
});
|
|
56
67
|
return plan;
|
|
57
68
|
});
|
|
58
69
|
}
|
|
59
|
-
function completedPlanExistsError(scope) {
|
|
70
|
+
function completedPlanExistsError(scope, surface) {
|
|
60
71
|
return new UlwLoopError([
|
|
61
72
|
`Existing ulw-loop aggregate is already complete at ${ulwLoopGoalsRelativePath(scope)}.`,
|
|
62
|
-
|
|
63
|
-
|
|
73
|
+
...(surface === "omo-senpi"
|
|
74
|
+
? [
|
|
75
|
+
"Start a new run under a fresh session id (a new senpi session) or call agentToolkit.createGoals({ brief, force: true }) to recreate.",
|
|
76
|
+
]
|
|
77
|
+
: [
|
|
78
|
+
"Start a new run with `omo-agent-toolkit ulw-loop create-goals --session-id <new-id> ...` to isolate fresh state.",
|
|
79
|
+
"Use --force only when you intentionally want to overwrite the completed evidence.",
|
|
80
|
+
]),
|
|
64
81
|
].join(" "), "ULW_LOOP_PLAN_EXISTS_COMPLETE");
|
|
65
82
|
}
|
|
66
|
-
export async function addUlwLoopGoal(repoRoot, args, scope) {
|
|
83
|
+
export async function addUlwLoopGoal(repoRoot, args, scope, surface = "lazycodex") {
|
|
67
84
|
return withUlwLoopMutationLock(repoRoot, scope, async () => {
|
|
68
85
|
const plan = await readUlwLoopPlan(repoRoot, scope);
|
|
69
86
|
const now = iso();
|
|
70
|
-
const goal = appendGoalToPlan(plan, args.title, args.objective, now
|
|
71
|
-
|
|
72
|
-
|
|
87
|
+
const goal = appendGoalToPlan(plan, args.title, args.objective, now, {
|
|
88
|
+
surface,
|
|
89
|
+
...(args.successCriteria === undefined ? {} : { successCriteria: args.successCriteria }),
|
|
90
|
+
});
|
|
91
|
+
await commit(repoRoot, scope, {
|
|
92
|
+
plan,
|
|
93
|
+
entries: [{ at: now, kind: "goal_added", goalId: goal.id, status: goal.status, message: goal.title }],
|
|
94
|
+
});
|
|
73
95
|
return { plan, goal };
|
|
74
96
|
});
|
|
75
97
|
}
|
|
@@ -82,17 +104,18 @@ export async function startNextUlwLoop(repoRoot, args = {}, scope) {
|
|
|
82
104
|
const existing = plan.goals.find((goal) => goal.status === "in_progress" && isScheduleEligible(goal));
|
|
83
105
|
if (existing)
|
|
84
106
|
return { plan, goal: existing, resumed: true };
|
|
107
|
+
const entries = [];
|
|
85
108
|
let next = plan.goals.find((goal) => goal.status === "pending" && isScheduleEligible(goal));
|
|
86
109
|
if (!next && args.retryFailed) {
|
|
87
110
|
next = plan.goals.find((goal) => goal.status === "failed" && !goal.nonRetriable && isScheduleEligible(goal));
|
|
88
111
|
if (next)
|
|
89
|
-
|
|
112
|
+
entries.push({
|
|
90
113
|
at: now,
|
|
91
114
|
kind: "goal_retried",
|
|
92
115
|
goalId: next.id,
|
|
93
116
|
status: "pending",
|
|
94
117
|
...(next.failureReason ? { message: next.failureReason } : {}),
|
|
95
|
-
}
|
|
118
|
+
});
|
|
96
119
|
}
|
|
97
120
|
if (!next)
|
|
98
121
|
return { done: true, plan };
|
|
@@ -103,8 +126,14 @@ export async function startNextUlwLoop(repoRoot, args = {}, scope) {
|
|
|
103
126
|
next.updatedAt = now;
|
|
104
127
|
plan.activeGoalId = next.id;
|
|
105
128
|
plan.updatedAt = now;
|
|
106
|
-
|
|
107
|
-
|
|
129
|
+
entries.push({
|
|
130
|
+
at: now,
|
|
131
|
+
kind: "goal_started",
|
|
132
|
+
goalId: next.id,
|
|
133
|
+
status: next.status,
|
|
134
|
+
message: `Attempt ${next.attempt}`,
|
|
135
|
+
});
|
|
136
|
+
await commit(repoRoot, scope, { plan, entries });
|
|
108
137
|
return { plan, goal: next, resumed: false };
|
|
109
138
|
});
|
|
110
139
|
}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
import { type SuccessCriterionInput } from "./success-criteria-input.js";
|
|
2
|
+
import type { UlwLoopToolkitSurface } from "./surface.js";
|
|
1
3
|
import type { UlwLoopItem, UlwLoopPlan, UlwLoopSuccessCriterion } from "./types.js";
|
|
2
|
-
export
|
|
4
|
+
export interface GoalSeedOptions {
|
|
5
|
+
readonly goalId?: string;
|
|
6
|
+
readonly surface?: UlwLoopToolkitSurface;
|
|
7
|
+
readonly successCriteria?: readonly SuccessCriterionInput[];
|
|
8
|
+
}
|
|
9
|
+
export declare function seedDefaultSuccessCriteria(goalIndex: number, objective: string, options?: Pick<GoalSeedOptions, "goalId" | "surface">): UlwLoopSuccessCriterion[];
|
|
3
10
|
export declare function deriveGoalCandidates(brief: string): Array<{
|
|
4
11
|
title: string;
|
|
5
12
|
objective: string;
|
|
6
13
|
}>;
|
|
7
|
-
export declare function makeGoal(title: string, objective: string, index: number, now: string): UlwLoopItem;
|
|
8
|
-
export declare function appendGoalToPlan(plan: UlwLoopPlan, title: string, objective: string, now: string): UlwLoopItem;
|
|
14
|
+
export declare function makeGoal(title: string, objective: string, index: number, now: string, options?: GoalSeedOptions): UlwLoopItem;
|
|
15
|
+
export declare function appendGoalToPlan(plan: UlwLoopPlan, title: string, objective: string, now: string, options?: GoalSeedOptions): UlwLoopItem;
|