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.
Files changed (179) hide show
  1. package/dist/cli/doctor/checks/browser-provider.d.ts +2 -0
  2. package/dist/cli/index.js +64 -35
  3. package/dist/cli-node/index.js +64 -35
  4. package/package.json +2 -6
  5. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  6. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +2 -0
  7. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  8. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  9. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  10. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  11. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  12. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  13. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  14. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  15. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
  16. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  17. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  18. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  19. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  20. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  21. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  22. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  23. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  24. package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +2 -2
  25. package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +5 -4
  26. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  27. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  28. package/packages/omo-codex/plugin/components/ultrawork/src/directive-content.ts +1 -1
  29. package/packages/omo-codex/plugin/components/ulw-execute-continuation/directive.md +1 -1
  30. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
  31. package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
  32. package/packages/omo-codex/plugin/components/ulw-loop/CHANGELOG.md +13 -0
  33. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +5 -4
  34. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.js +5 -4
  35. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +582 -322
  36. package/packages/omo-codex/plugin/components/ulw-loop/dist/domain-types.d.ts +5 -0
  37. package/packages/omo-codex/plugin/components/ulw-loop/dist/evidence.js +16 -12
  38. package/packages/omo-codex/plugin/components/ulw-loop/dist/ledger.d.ts +4 -0
  39. package/packages/omo-codex/plugin/components/ulw-loop/dist/ledger.js +34 -0
  40. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-commit.d.ts +19 -0
  41. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-commit.js +107 -0
  42. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.d.ts +2 -1
  43. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-crud.js +48 -22
  44. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.d.ts +9 -7
  45. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.js +105 -114
  46. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-log.d.ts +15 -0
  47. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-log.js +86 -0
  48. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-missing-recovery.d.ts +5 -1
  49. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-missing-recovery.js +15 -3
  50. package/packages/omo-codex/plugin/components/ulw-loop/dist/review-blockers.js +3 -4
  51. package/packages/omo-codex/plugin/components/ulw-loop/dist/sdk/factory.js +12 -5
  52. package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-budget-io.d.ts +5 -0
  53. package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-budget-io.js +67 -0
  54. package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-guard.js +8 -62
  55. package/packages/omo-codex/plugin/components/ulw-loop/dist/state-lock.d.ts +11 -1
  56. package/packages/omo-codex/plugin/components/ulw-loop/dist/state-lock.js +120 -88
  57. package/packages/omo-codex/plugin/components/ulw-loop/dist/status-next-actions.d.ts +3 -2
  58. package/packages/omo-codex/plugin/components/ulw-loop/dist/status-next-actions.js +18 -10
  59. package/packages/omo-codex/plugin/components/ulw-loop/dist/steering-batch.js +4 -4
  60. package/packages/omo-codex/plugin/components/ulw-loop/dist/steering.js +5 -5
  61. package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +8 -17
  62. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
  63. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  64. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +2 -2
  65. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +5 -4
  66. package/packages/omo-codex/plugin/components/ulw-loop/src/domain-types.ts +5 -0
  67. package/packages/omo-codex/plugin/components/ulw-loop/src/evidence.ts +16 -16
  68. package/packages/omo-codex/plugin/components/ulw-loop/src/ledger.ts +33 -0
  69. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-commit.ts +124 -0
  70. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-crud.ts +58 -51
  71. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-io.ts +126 -140
  72. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-log.ts +84 -0
  73. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-missing-recovery.ts +26 -3
  74. package/packages/omo-codex/plugin/components/ulw-loop/src/review-blockers.ts +3 -3
  75. package/packages/omo-codex/plugin/components/ulw-loop/src/sdk/factory.ts +30 -5
  76. package/packages/omo-codex/plugin/components/ulw-loop/src/spawn-budget-io.ts +59 -0
  77. package/packages/omo-codex/plugin/components/ulw-loop/src/spawn-guard.ts +8 -59
  78. package/packages/omo-codex/plugin/components/ulw-loop/src/state-lock.ts +129 -111
  79. package/packages/omo-codex/plugin/components/ulw-loop/src/status-next-actions.ts +19 -10
  80. package/packages/omo-codex/plugin/components/ulw-loop/src/steering-batch.ts +4 -4
  81. package/packages/omo-codex/plugin/components/ulw-loop/src/steering.ts +5 -4
  82. package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +8 -16
  83. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/barrier.ts +13 -0
  84. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/commit-child.ts +65 -0
  85. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/commit-cli-qa.mjs +76 -0
  86. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/commit-crash.ts +23 -0
  87. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/commit-mutations.mjs +58 -0
  88. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/commit-writer.ts +65 -0
  89. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/lease-clock.ts +23 -0
  90. package/packages/omo-codex/plugin/components/ulw-loop/test/plan-commit-log.test.ts +252 -0
  91. package/packages/omo-codex/plugin/components/ulw-loop/test/plan-commit-recovery.test.ts +190 -0
  92. package/packages/omo-codex/plugin/components/ulw-loop/test/plan-io.test.ts +50 -35
  93. package/packages/omo-codex/plugin/components/ulw-loop/test/plan-log-newest.test.ts +72 -0
  94. package/packages/omo-codex/plugin/components/ulw-loop/test/sdk-completed-plan.test.ts +43 -0
  95. package/packages/omo-codex/plugin/components/ulw-loop/test/sdk-session-context.test.ts +21 -0
  96. package/packages/omo-codex/plugin/components/ulw-loop/test/state-lock.test.ts +92 -0
  97. package/packages/omo-codex/plugin/components/ulw-loop/test/status-next-actions-surface.test.ts +133 -0
  98. package/packages/omo-codex/plugin/components/ulw-loop/test/steering-batch.test.ts +12 -12
  99. package/packages/omo-codex/plugin/components/ulw-loop/test/steering.test.ts +4 -1
  100. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  101. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  102. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  103. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  104. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  105. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  106. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  107. package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
  108. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  109. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  110. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  111. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  112. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  113. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  114. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  115. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
  116. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  117. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  118. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  119. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  120. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  121. package/packages/omo-codex/plugin/package-lock.json +12 -12
  122. package/packages/omo-codex/plugin/package.json +1 -1
  123. package/packages/omo-codex/plugin/scripts/sync-skills.d.mts +4 -0
  124. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +15 -7
  125. package/packages/omo-codex/plugin/skills/ast-grep/SKILL.md +12 -0
  126. package/packages/omo-codex/plugin/skills/debugging/references/tools/playwright-cli.md +79 -161
  127. package/packages/omo-codex/plugin/skills/frontend/SKILL.md +1 -1
  128. package/packages/omo-codex/plugin/skills/frontend/references/design/aside.md +1 -1
  129. package/packages/omo-codex/plugin/skills/frontend/references/design/clone-from-url.md +1 -1
  130. package/packages/omo-codex/plugin/skills/frontend/scripts/perfection/lighthouse-audit.py +2 -2
  131. package/packages/omo-codex/plugin/skills/review-work/SKILL.md +1 -1
  132. package/packages/omo-codex/plugin/skills/ultimate-browsing/ATTRIBUTION.md +1 -82
  133. package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +17 -29
  134. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +2 -1
  135. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/templates/package.json +2 -2
  136. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/templates/playwright_mobile_chrome.js +5 -2
  137. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/templates/playwright_real_chrome.js +8 -6
  138. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_stealth.py +86 -0
  139. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_templates.py +4 -7
  140. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/chrome-stealth.md +86 -100
  141. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +9 -3
  142. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/playwright.md +16 -13
  143. package/packages/omo-codex/plugin/skills/ultimate-browsing/scripts/extract_cookies.py +3 -3
  144. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +5 -4
  145. package/packages/omo-codex/plugin/skills/ulw-execute/SKILL.md +1 -1
  146. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +2 -2
  147. package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +3 -3
  148. package/packages/omo-codex/plugin/skills/visual-qa/AGENTS.md +1 -1
  149. package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +1 -1
  150. package/packages/omo-codex/plugin/skills/visual-qa/references/browser-setup.md +75 -0
  151. package/packages/omo-codex/scripts/install-dist/install-local.mjs +4 -2
  152. package/packages/prompts-core/prompts/ultrawork/codex.md +5 -4
  153. package/packages/shared-skills/skills/ast-grep/SKILL.md +12 -0
  154. package/packages/shared-skills/skills/debugging/references/tools/playwright-cli.md +79 -161
  155. package/packages/shared-skills/skills/frontend/SKILL.md +1 -1
  156. package/packages/shared-skills/skills/frontend/references/design/aside.md +1 -1
  157. package/packages/shared-skills/skills/frontend/references/design/clone-from-url.md +1 -1
  158. package/packages/shared-skills/skills/frontend/scripts/perfection/lighthouse-audit.py +2 -2
  159. package/packages/shared-skills/skills/review-work/SKILL.md +1 -1
  160. package/packages/shared-skills/skills/ultimate-browsing/ATTRIBUTION.md +1 -82
  161. package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +17 -29
  162. package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +2 -1
  163. package/packages/shared-skills/skills/ultimate-browsing/engine/templates/package.json +2 -2
  164. package/packages/shared-skills/skills/ultimate-browsing/engine/templates/playwright_mobile_chrome.js +5 -2
  165. package/packages/shared-skills/skills/ultimate-browsing/engine/templates/playwright_real_chrome.js +8 -6
  166. package/packages/shared-skills/skills/ultimate-browsing/engine/tests/test_playwright_stealth.py +86 -0
  167. package/packages/shared-skills/skills/ultimate-browsing/engine/tests/test_playwright_templates.py +4 -7
  168. package/packages/shared-skills/skills/ultimate-browsing/references/chrome-stealth.md +86 -100
  169. package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +9 -3
  170. package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/playwright.md +16 -13
  171. package/packages/shared-skills/skills/ultimate-browsing/scripts/extract_cookies.py +3 -3
  172. package/packages/shared-skills/skills/ulw-execute/SKILL.md +1 -1
  173. package/packages/shared-skills/skills/ulw-plan/scripts/scaffold-plan.mjs +1 -1
  174. package/packages/shared-skills/skills/ulw-research/SKILL.md +3 -3
  175. package/packages/shared-skills/skills/visual-qa/AGENTS.md +1 -1
  176. package/packages/shared-skills/skills/visual-qa/SKILL.md +1 -1
  177. package/packages/shared-skills/skills/visual-qa/references/browser-setup.md +75 -0
  178. package/packages/omo-codex/plugin/skills/visual-qa/references/agent-browser-setup.md +0 -45
  179. 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 { appendLedger, readUlwLoopPlan, withUlwLoopMutationLock, writePlan } from "./plan-io.js";
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 appendLedger(repoRoot, ledgerEntry, scope);
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 writePlan(repoRoot, plan, scope);
87
- await appendLedger(repoRoot, {
88
- at: now,
89
- kind: "criteria_revised",
90
- goalId,
91
- message: `Reset ${goal.successCriteria.length} criteria to pending.`,
92
- before,
93
- after: { resetCount: goal.successCriteria.length },
94
- }, scope);
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 { ulwLoopBriefPath, ulwLoopBriefRelativePath, ulwLoopDir, ulwLoopGoalsPath, ulwLoopGoalsRelativePath, ulwLoopLedgerPath, ulwLoopLedgerRelativePath, } from "./paths.js";
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 { appendLedger, readUlwLoopPlan, withUlwLoopMutationLock, writePlan } from "./plan-io.js";
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
- if (!args.force && existsSync(ulwLoopGoalsPath(repoRoot, scope))) {
28
- const existing = await readUlwLoopPlan(repoRoot, scope);
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 mkdir(ulwLoopDir(repoRoot, scope), { recursive: true });
52
- await writeFile(ulwLoopBriefPath(repoRoot, scope), args.brief.endsWith("\n") ? args.brief : `${args.brief}\n`, "utf8");
53
- await writePlan(repoRoot, plan, scope);
54
- await writeFile(ulwLoopLedgerPath(repoRoot, scope), "", "utf8");
55
- await appendLedger(repoRoot, { at: now, kind: "plan_created", message: `${goals.length} goal(s) created` }, scope);
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
- "Start a new run with `omo-agent-toolkit ulw-loop create-goals --session-id <new-id> ...` to isolate fresh state.",
63
- "Use --force only when you intentionally want to overwrite the completed evidence.",
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 writePlan(repoRoot, plan, scope);
72
- await appendLedger(repoRoot, { at: now, kind: "goal_added", goalId: goal.id, status: goal.status, message: goal.title }, scope);
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
- await appendLedger(repoRoot, {
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
- }, scope);
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
- await writePlan(repoRoot, plan, scope);
107
- await appendLedger(repoRoot, { at: now, kind: "goal_started", goalId: next.id, status: next.status, message: `Attempt ${next.attempt}` }, scope);
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 type { UlwLoopLedgerEntry, UlwLoopPlan } from "./types.js";
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>): 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>;