lazycodex-ai 5.0.0-beta.61 → 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
|
@@ -50,6 +50,9 @@ export interface UlwLoopValidationBatch {
|
|
|
50
50
|
}
|
|
51
51
|
export interface UlwLoopPlan {
|
|
52
52
|
version: 1;
|
|
53
|
+
revision?: number;
|
|
54
|
+
brief?: string;
|
|
55
|
+
ledgerResetRevision?: number;
|
|
53
56
|
evidenceLayoutVersion?: 2;
|
|
54
57
|
createdAt: string;
|
|
55
58
|
updatedAt: string;
|
|
@@ -136,6 +139,8 @@ export interface UlwLoopQualityGateSenpi extends UlwLoopQualityGateCommon {
|
|
|
136
139
|
}
|
|
137
140
|
export type UlwLoopQualityGate = UlwLoopQualityGateLazycodex | UlwLoopQualityGateSenpi;
|
|
138
141
|
export interface UlwLoopLedgerEntry {
|
|
142
|
+
revision?: number;
|
|
143
|
+
id?: string;
|
|
139
144
|
at: string;
|
|
140
145
|
kind: UlwLoopLedgerEventKind;
|
|
141
146
|
goalId?: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { essentialCriteriaOf, hasAllCriteriaPass, hasEssentialCriteriaPass } from "./goal-status.js";
|
|
2
|
-
import {
|
|
2
|
+
import { commit } from "./plan-commit.js";
|
|
3
|
+
import { readUlwLoopPlan, withUlwLoopMutationLock } from "./plan-io.js";
|
|
3
4
|
import { iso, UlwLoopError } from "./types.js";
|
|
4
5
|
function ulwLoopFail(message, code, details) {
|
|
5
6
|
throw new UlwLoopError(message, code, { details });
|
|
@@ -48,7 +49,6 @@ export async function recordEvidence(repoRoot, args, scope) {
|
|
|
48
49
|
criterion.notes = args.notes;
|
|
49
50
|
goal.updatedAt = capturedAt;
|
|
50
51
|
plan.updatedAt = capturedAt;
|
|
51
|
-
await writePlan(repoRoot, plan, scope);
|
|
52
52
|
const ledgerEntry = {
|
|
53
53
|
at: capturedAt,
|
|
54
54
|
kind,
|
|
@@ -60,7 +60,7 @@ export async function recordEvidence(repoRoot, args, scope) {
|
|
|
60
60
|
before: { status: prevStatus },
|
|
61
61
|
after: { goalId: goal.id, criterionId: criterion.id, status: args.status, evidence, capturedAt, prevStatus },
|
|
62
62
|
};
|
|
63
|
-
await
|
|
63
|
+
await commit(repoRoot, scope, { plan, entries: [ledgerEntry] });
|
|
64
64
|
return { plan, goal, criterion, ledgerEntry };
|
|
65
65
|
});
|
|
66
66
|
}
|
|
@@ -83,15 +83,19 @@ export async function markCriteriaPendingResetForGoal(repoRoot, goalId, scope) {
|
|
|
83
83
|
}
|
|
84
84
|
goal.updatedAt = now;
|
|
85
85
|
plan.updatedAt = now;
|
|
86
|
-
await
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
86
|
+
await commit(repoRoot, scope, {
|
|
87
|
+
plan,
|
|
88
|
+
entries: [
|
|
89
|
+
{
|
|
90
|
+
at: now,
|
|
91
|
+
kind: "criteria_revised",
|
|
92
|
+
goalId,
|
|
93
|
+
message: `Reset ${goal.successCriteria.length} criteria to pending.`,
|
|
94
|
+
before,
|
|
95
|
+
after: { resetCount: goal.successCriteria.length },
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
});
|
|
95
99
|
return { plan, resetCount: goal.successCriteria.length };
|
|
96
100
|
});
|
|
97
101
|
}
|
|
@@ -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
|
+
}
|
|
@@ -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,4 +1,5 @@
|
|
|
1
1
|
import { type UlwLoopScope } from "./paths.js";
|
|
2
|
+
import type { UlwLoopToolkitSurface } from "./surface.js";
|
|
2
3
|
import type { UlwLoopCodexGoalMode, UlwLoopItem, UlwLoopPlan } from "./types.js";
|
|
3
4
|
export { deriveGoalCandidates, seedDefaultSuccessCriteria } from "./plan-goal-factory.js";
|
|
4
5
|
export type UlwLoopPlanSummary = {
|
|
@@ -24,7 +25,7 @@ export declare function createUlwLoopPlan(repoRoot: string, args: {
|
|
|
24
25
|
codexGoalMode?: UlwLoopCodexGoalMode;
|
|
25
26
|
force?: boolean;
|
|
26
27
|
validationBatchesJson?: string;
|
|
27
|
-
}, scope?: UlwLoopScope): Promise<UlwLoopPlan>;
|
|
28
|
+
}, scope?: UlwLoopScope, surface?: UlwLoopToolkitSurface): Promise<UlwLoopPlan>;
|
|
28
29
|
export declare function addUlwLoopGoal(repoRoot: string, args: {
|
|
29
30
|
title: string;
|
|
30
31
|
objective: string;
|
|
@@ -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
42
|
const goals = deriveGoalCandidates(args.brief).map((goal, index) => makeGoal(goal.title, goal.objective, index, now));
|
|
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,19 +59,25 @@ 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
83
|
export async function addUlwLoopGoal(repoRoot, args, scope) {
|
|
@@ -68,8 +85,10 @@ export async function addUlwLoopGoal(repoRoot, args, scope) {
|
|
|
68
85
|
const plan = await readUlwLoopPlan(repoRoot, scope);
|
|
69
86
|
const now = iso();
|
|
70
87
|
const goal = appendGoalToPlan(plan, args.title, args.objective, now);
|
|
71
|
-
await
|
|
72
|
-
|
|
88
|
+
await commit(repoRoot, scope, {
|
|
89
|
+
plan,
|
|
90
|
+
entries: [{ at: now, kind: "goal_added", goalId: goal.id, status: goal.status, message: goal.title }],
|
|
91
|
+
});
|
|
73
92
|
return { plan, goal };
|
|
74
93
|
});
|
|
75
94
|
}
|
|
@@ -82,17 +101,18 @@ export async function startNextUlwLoop(repoRoot, args = {}, scope) {
|
|
|
82
101
|
const existing = plan.goals.find((goal) => goal.status === "in_progress" && isScheduleEligible(goal));
|
|
83
102
|
if (existing)
|
|
84
103
|
return { plan, goal: existing, resumed: true };
|
|
104
|
+
const entries = [];
|
|
85
105
|
let next = plan.goals.find((goal) => goal.status === "pending" && isScheduleEligible(goal));
|
|
86
106
|
if (!next && args.retryFailed) {
|
|
87
107
|
next = plan.goals.find((goal) => goal.status === "failed" && !goal.nonRetriable && isScheduleEligible(goal));
|
|
88
108
|
if (next)
|
|
89
|
-
|
|
109
|
+
entries.push({
|
|
90
110
|
at: now,
|
|
91
111
|
kind: "goal_retried",
|
|
92
112
|
goalId: next.id,
|
|
93
113
|
status: "pending",
|
|
94
114
|
...(next.failureReason ? { message: next.failureReason } : {}),
|
|
95
|
-
}
|
|
115
|
+
});
|
|
96
116
|
}
|
|
97
117
|
if (!next)
|
|
98
118
|
return { done: true, plan };
|
|
@@ -103,8 +123,14 @@ export async function startNextUlwLoop(repoRoot, args = {}, scope) {
|
|
|
103
123
|
next.updatedAt = now;
|
|
104
124
|
plan.activeGoalId = next.id;
|
|
105
125
|
plan.updatedAt = now;
|
|
106
|
-
|
|
107
|
-
|
|
126
|
+
entries.push({
|
|
127
|
+
at: now,
|
|
128
|
+
kind: "goal_started",
|
|
129
|
+
goalId: next.id,
|
|
130
|
+
status: next.status,
|
|
131
|
+
message: `Attempt ${next.attempt}`,
|
|
132
|
+
});
|
|
133
|
+
await commit(repoRoot, scope, { plan, entries });
|
|
108
134
|
return { plan, goal: next, resumed: false };
|
|
109
135
|
});
|
|
110
136
|
}
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { type UlwLoopScope } from "./paths.js";
|
|
2
|
-
import
|
|
2
|
+
import { type StateLockOptions } from "./state-lock.js";
|
|
3
|
+
import { type UlwLoopLedgerEntry, type UlwLoopPlan } from "./types.js";
|
|
4
|
+
export declare function readLedger(repoRoot: string, scope?: UlwLoopScope): UlwLoopLedgerEntry[];
|
|
5
|
+
export { planExists } from "./plan-log.js";
|
|
6
|
+
export declare function withMutationLockOptions<T>(options: StateLockOptions, fn: () => Promise<T>): Promise<T>;
|
|
7
|
+
export declare function assertStateLockOwned(lockPath: string): void;
|
|
8
|
+
export declare function migrationEntries(plan: UlwLoopPlan): readonly UlwLoopLedgerEntry[];
|
|
3
9
|
export declare function withUlwLoopMutationLock<T>(repoRoot: string, fn: () => Promise<T>): Promise<T>;
|
|
4
|
-
export declare function withUlwLoopMutationLock<T>(repoRoot: string, scope: UlwLoopScope | undefined, fn: () => Promise<T
|
|
10
|
+
export declare function withUlwLoopMutationLock<T>(repoRoot: string, scope: UlwLoopScope | undefined, fn: () => Promise<T>, options?: StateLockOptions): Promise<T>;
|
|
11
|
+
export declare function readUlwLoopPlanSync(repoRoot: string, scope?: UlwLoopScope): UlwLoopPlan;
|
|
5
12
|
export declare function readUlwLoopPlan(repoRoot: string, scope?: UlwLoopScope): Promise<UlwLoopPlan>;
|
|
6
13
|
export declare function listUlwLoopSessionIds(repoRoot: string): readonly string[];
|
|
7
14
|
export declare function writePlan(repoRoot: string, plan: UlwLoopPlan, scope?: UlwLoopScope): Promise<void>;
|
|
8
15
|
export declare function appendLedger(repoRoot: string, entry: UlwLoopLedgerEntry, scope?: UlwLoopScope): Promise<void>;
|
|
9
16
|
export declare function appendLedgerEntries(repoRoot: string, entries: readonly UlwLoopLedgerEntry[], scope?: UlwLoopScope): Promise<void>;
|
|
10
17
|
export declare function readSteeringLedgerEntries(repoRoot: string, scope?: UlwLoopScope): Promise<UlwLoopLedgerEntry[]>;
|
|
11
|
-
/**
|
|
12
|
-
* First accepted steering entry matching an idempotency key/prompt signature.
|
|
13
|
-
* A cheap substring probe on the raw line skips JSON.parse for the vast
|
|
14
|
-
* majority of entries, so dedup stays flat even on legacy multi-MB ledgers.
|
|
15
|
-
*/
|
|
16
18
|
export declare function findAcceptedSteeringLedgerEntry(repoRoot: string, key: string, scope?: UlwLoopScope): Promise<UlwLoopLedgerEntry | undefined>;
|