lazycodex-ai 5.0.0-beta.53 → 5.0.0-beta.55
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/index.js +53 -19
- package/dist/cli-node/index.js +53 -19
- package/package.json +1 -1
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- 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/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +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/dist/checkpoint-codex-validation.d.ts +5 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-codex-validation.js +14 -34
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-continuation.js +1 -4
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-reconciliation.d.ts +0 -18
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-reconciliation.js +1 -88
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.d.ts +2 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.js +10 -3
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-arg-parser.js +2 -2
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.js +2 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +86 -174
- package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-snapshot.d.ts +2 -18
- package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-snapshot.js +23 -33
- package/packages/omo-codex/plugin/components/ulw-loop/dist/review-blockers.d.ts +2 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/review-blockers.js +16 -9
- 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/src/checkpoint-codex-validation.ts +18 -59
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-continuation.ts +1 -6
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-reconciliation.ts +1 -124
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +11 -3
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-arg-parser.ts +10 -4
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-subcommands.ts +2 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-snapshot.ts +31 -50
- package/packages/omo-codex/plugin/components/ulw-loop/src/review-blockers.ts +29 -10
- package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint-final.test.ts +0 -82
- package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint.test.ts +16 -22
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-checkpoint.test.ts +27 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-json-errors.test.ts +25 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/codex-goal-snapshot.test.ts +34 -11
- package/packages/omo-codex/plugin/components/ulw-loop/test/guided-recovery.test.ts +9 -47
- package/packages/omo-codex/plugin/components/ulw-loop/test/review-blockers.test.ts +9 -7
- 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/scripts/install-dist/install-local.mjs +2 -2
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// components/ulw-loop/src/checkpoint.ts
|
|
4
|
-
import { existsSync as
|
|
5
|
-
import { readFile as
|
|
4
|
+
import { existsSync as existsSync3, statSync as statSync2 } from "node:fs";
|
|
5
|
+
import { readFile as readFile4 } from "node:fs/promises";
|
|
6
6
|
import { resolve as resolve3 } from "node:path";
|
|
7
7
|
|
|
8
|
-
// components/ulw-loop/src/checkpoint-reconciliation.ts
|
|
9
|
-
import { existsSync as existsSync2 } from "node:fs";
|
|
10
|
-
import { readFile as readFile2 } from "node:fs/promises";
|
|
11
|
-
|
|
12
8
|
// components/ulw-loop/src/codex-goal-snapshot.ts
|
|
13
9
|
import { existsSync } from "node:fs";
|
|
14
10
|
import { readFile } from "node:fs/promises";
|
|
@@ -20,16 +16,25 @@ function safeObject(value) {
|
|
|
20
16
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
21
17
|
}
|
|
22
18
|
function safeString(value) {
|
|
19
|
+
return typeof value === "string" ? value : "";
|
|
20
|
+
}
|
|
21
|
+
function safeStatusString(value) {
|
|
23
22
|
return typeof value === "string" ? value.trim() : "";
|
|
24
23
|
}
|
|
25
24
|
function normalizeStatus(value) {
|
|
26
|
-
const status =
|
|
25
|
+
const status = safeStatusString(value).toLowerCase();
|
|
27
26
|
if (status === "complete" || status === "completed" || status === "done")
|
|
28
27
|
return "complete";
|
|
29
28
|
if (status === "cancelled" || status === "canceled")
|
|
30
29
|
return "cancelled";
|
|
31
30
|
if (status === "failed" || status === "failure")
|
|
32
31
|
return "failed";
|
|
32
|
+
if (status === "paused")
|
|
33
|
+
return "paused";
|
|
34
|
+
if (status === "usage_limited")
|
|
35
|
+
return "usage_limited";
|
|
36
|
+
if (status === "budget_limited")
|
|
37
|
+
return "budget_limited";
|
|
33
38
|
if (status === "active" || status === "in_progress" || status === "pending" || status === "running")
|
|
34
39
|
return "active";
|
|
35
40
|
return "unknown";
|
|
@@ -75,46 +80,32 @@ function reconcileCodexGoalSnapshot(snapshot, options) {
|
|
|
75
80
|
const effectiveSnapshot = snapshot ?? { available: false, raw: null };
|
|
76
81
|
const errors = [];
|
|
77
82
|
const warnings = [];
|
|
83
|
+
const expected = options.expectedObjective;
|
|
84
|
+
const normalizedExpected = normalizeObjective(expected);
|
|
78
85
|
if (!effectiveSnapshot.available) {
|
|
79
|
-
|
|
80
|
-
if (options.requireSnapshot)
|
|
81
|
-
errors.push(message);
|
|
82
|
-
else
|
|
83
|
-
warnings.push(message);
|
|
86
|
+
warnings.push(`call get_goal; if none, create_goal with codexObjective "${expected}" verbatim`);
|
|
84
87
|
return { ok: errors.length === 0, snapshot: effectiveSnapshot, warnings, errors };
|
|
85
88
|
}
|
|
86
|
-
const
|
|
87
|
-
|
|
89
|
+
const accepted = new Set([
|
|
90
|
+
normalizedExpected,
|
|
91
|
+
...(options.acceptedObjectives ?? []).map((objective) => normalizeObjective(objective))
|
|
92
|
+
].filter(Boolean));
|
|
88
93
|
const actual = normalizeObjective(effectiveSnapshot.objective ?? "");
|
|
89
|
-
if (!actual) {
|
|
90
|
-
|
|
91
|
-
} else if (!accepted.has(actual)) {
|
|
92
|
-
errors.push(`Codex goal objective mismatch: expected "${expected}", got "${actual}".`);
|
|
94
|
+
if (actual && !accepted.has(normalizeObjective(actual))) {
|
|
95
|
+
warnings.push(`driver_objective_differs: expected "${expected}", got "${actual}".`);
|
|
93
96
|
}
|
|
94
|
-
const allowed = options.allowedStatuses ?? (options.requireComplete ? ["complete"] : ["active", "complete"]);
|
|
95
97
|
const actualStatus = effectiveSnapshot.status ?? "unknown";
|
|
96
|
-
if (
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
if (options.requireComplete && actualStatus !== "complete") {
|
|
100
|
-
errors.push('Codex goal is not complete; call update_goal({status: "complete"}) only after the objective is actually complete, then pass the fresh get_goal JSON.');
|
|
98
|
+
if (actualStatus === "paused" || actualStatus === "usage_limited" || actualStatus === "budget_limited") {
|
|
99
|
+
warnings.push("/goal resume or raise the budget");
|
|
101
100
|
}
|
|
101
|
+
if (actualStatus === "complete")
|
|
102
|
+
warnings.push(`driver closed early: call create_goal with codexObjective "${expected}" verbatim`);
|
|
102
103
|
return { ok: errors.length === 0, snapshot: effectiveSnapshot, warnings, errors };
|
|
103
104
|
}
|
|
104
105
|
function formatCodexGoalReconciliation(reconciliation) {
|
|
105
106
|
const parts = [...reconciliation.errors, ...reconciliation.warnings];
|
|
106
107
|
return parts.join(" ");
|
|
107
108
|
}
|
|
108
|
-
function codexGoalMismatchRecovery(expectedObjective, snapshot) {
|
|
109
|
-
const receivedObjective = snapshot?.objective ?? "";
|
|
110
|
-
const message = [
|
|
111
|
-
"Recovery: the Codex goal objective must equal the plan's codexObjective exactly — copy the expected value below into update_goal and re-run get_goal.",
|
|
112
|
-
`expected codexObjective: ${expectedObjective}`,
|
|
113
|
-
`received objective: ${receivedObjective || "(none)"}`
|
|
114
|
-
].join(`
|
|
115
|
-
`);
|
|
116
|
-
return { message, details: { expectedObjective, receivedObjective } };
|
|
117
|
-
}
|
|
118
109
|
|
|
119
110
|
// components/ulw-loop/src/paths.ts
|
|
120
111
|
import { isAbsolute, join, relative, sep } from "node:path";
|
|
@@ -308,114 +299,21 @@ function hasEssentialCriteriaPass(goal) {
|
|
|
308
299
|
return criteria.length > 0 && criteria.every((criterion) => criterion.status === "pass");
|
|
309
300
|
}
|
|
310
301
|
|
|
311
|
-
// components/ulw-loop/src/checkpoint-reconciliation.ts
|
|
312
|
-
function codexSnapshotMismatchError(input) {
|
|
313
|
-
const { reconciliation, snapshot, taskScopedHint } = input;
|
|
314
|
-
const hint = taskScopedHint?.aggregate === true && snapshot?.status === "complete" && snapshot.objective !== undefined ? buildTaskScopedAggregateReconciliationHint(taskScopedHint.goal, taskScopedHint.final) : "";
|
|
315
|
-
const recovery = codexGoalMismatchRecovery(input.expectedObjective, snapshot);
|
|
316
|
-
return new UlwLoopError(`${formatCodexGoalReconciliation(reconciliation)}${hint}
|
|
317
|
-
${recovery.message}`, "ulw_loop_codex_snapshot_mismatch", { details: recovery.details });
|
|
318
|
-
}
|
|
319
|
-
function normalizeObjective2(value) {
|
|
320
|
-
return value.replace(/\s+/g, " ").trim();
|
|
321
|
-
}
|
|
322
|
-
function textMentionsUlwLoopPlanArtifact(value) {
|
|
323
|
-
const normalized = (value ?? "").toLowerCase();
|
|
324
|
-
return normalized.includes(ULW_LOOP_DIR.toLowerCase()) || normalized.includes(ULW_LOOP_GOALS.toLowerCase()) || normalized.includes(ULW_LOOP_LEDGER.toLowerCase());
|
|
325
|
-
}
|
|
326
|
-
function textMentionsGoalId(value, goalId) {
|
|
327
|
-
return (value ?? "").toLowerCase().includes(goalId.toLowerCase());
|
|
328
|
-
}
|
|
329
|
-
function textHasCompletionValidationEvidence(value) {
|
|
330
|
-
const normalized = (value ?? "").toLowerCase();
|
|
331
|
-
const done = /\b(?:planned work|implementation|deliverables?|scope|task|work)\b/.test(normalized) && /\b(?:done|complete|completed|finished|shipped)\b/.test(normalized);
|
|
332
|
-
const verified = /\b(?:validation|verification|tests?|build|lint|review|quality gate|code-review)\b/.test(normalized) && /\b(?:passed|complete|completed|clean|green|approve|approved|clear)\b/.test(normalized);
|
|
333
|
-
return done && verified;
|
|
334
|
-
}
|
|
335
|
-
async function snapshotObjectiveMapsToUlwLoopPlan(repoRoot, snapshotObjective, scope) {
|
|
336
|
-
const actual = normalizeObjective2(snapshotObjective).toLowerCase();
|
|
337
|
-
if (textMentionsUlwLoopPlanArtifact(actual))
|
|
338
|
-
return true;
|
|
339
|
-
if (actual.length < 24 || !existsSync2(ulwLoopBriefPath(repoRoot, scope)))
|
|
340
|
-
return false;
|
|
341
|
-
try {
|
|
342
|
-
const brief = normalizeObjective2(await readFile2(ulwLoopBriefPath(repoRoot, scope), "utf8")).toLowerCase();
|
|
343
|
-
return brief.length >= 24 && (brief.includes(actual) || actual.includes(brief));
|
|
344
|
-
} catch (error) {
|
|
345
|
-
if (error instanceof Error)
|
|
346
|
-
return false;
|
|
347
|
-
throw error;
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
async function canReconcileCompletedTaskScopedAggregateSnapshot(repoRoot, plan, goal, snapshotObjective, evidence, scope) {
|
|
351
|
-
if (codexGoalMode(plan) !== "aggregate")
|
|
352
|
-
return false;
|
|
353
|
-
if (goal.status !== "in_progress" || plan.activeGoalId !== goal.id)
|
|
354
|
-
return false;
|
|
355
|
-
if (isFinalRunCompletionCandidate(plan, goal)) {
|
|
356
|
-
return snapshotObjectiveMapsToUlwLoopPlan(repoRoot, snapshotObjective, scope);
|
|
357
|
-
}
|
|
358
|
-
if (!textMentionsUlwLoopPlanArtifact(evidence) || !textMentionsGoalId(evidence, goal.id))
|
|
359
|
-
return false;
|
|
360
|
-
if (!textHasCompletionValidationEvidence(evidence))
|
|
361
|
-
return false;
|
|
362
|
-
return snapshotObjectiveMapsToUlwLoopPlan(repoRoot, snapshotObjective, scope);
|
|
363
|
-
}
|
|
364
|
-
async function canReconcileActiveFinalTaskScopedAggregateSnapshot(repoRoot, plan, goal, snapshotObjective, evidence, scope) {
|
|
365
|
-
if (codexGoalMode(plan) !== "aggregate")
|
|
366
|
-
return false;
|
|
367
|
-
if (goal.status !== "in_progress" || plan.activeGoalId !== goal.id)
|
|
368
|
-
return false;
|
|
369
|
-
if (!isFinalRunCompletionCandidate(plan, goal))
|
|
370
|
-
return false;
|
|
371
|
-
if (!textHasCompletionValidationEvidence(evidence))
|
|
372
|
-
return false;
|
|
373
|
-
return snapshotObjectiveMapsToUlwLoopPlan(repoRoot, snapshotObjective, scope);
|
|
374
|
-
}
|
|
375
|
-
function buildCompletedLegacyGoalRemediation(goal) {
|
|
376
|
-
return [
|
|
377
|
-
"If get_goal returns a different completed legacy/thread objective, do not repeat --status complete in this thread.",
|
|
378
|
-
`Record a non-terminal blocker with: omo-agent-toolkit ulw-loop checkpoint --goal-id ${goal.id} --status blocked --evidence "<completed legacy Codex goal blocks create_goal in this thread>" --codex-goal-json "<different completed get_goal JSON or path>".`,
|
|
379
|
-
"Then continue only from a Codex goal context with no active/completed conflicting goal, in the same repo/worktree, and create the intended goal there."
|
|
380
|
-
].join(" ");
|
|
381
|
-
}
|
|
382
|
-
function buildTaskScopedAggregateReconciliationHint(goal, final) {
|
|
383
|
-
if (final) {
|
|
384
|
-
return ` Final task-scoped aggregate reconciliation requires the checkpoint goal to be the active in-progress final OMO goal and the completed get_goal objective to map to the ulw-loop brief or artifact. ${buildCompletedLegacyGoalRemediation(goal)}`;
|
|
385
|
-
}
|
|
386
|
-
return ` Completed task-scoped aggregate reconciliation requires the checkpoint goal to be the active in-progress OMO goal, evidence that names that active OMO goal id, names .omo/ulw-loop/goals.json or ledger.jsonl, includes completed implementation plus validation/review evidence, and a get_goal objective that maps to the ulw-loop brief/artifact. ${buildCompletedLegacyGoalRemediation(goal)}`;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
302
|
// components/ulw-loop/src/checkpoint-codex-validation.ts
|
|
390
|
-
function normalizeObjective3(value) {
|
|
391
|
-
return value.replace(/\s+/g, " ").trim();
|
|
392
|
-
}
|
|
393
303
|
async function validateCheckpointCodexGoal(input) {
|
|
394
|
-
const aggregate = codexGoalMode(input.plan) === "aggregate";
|
|
395
|
-
const final = isFinalRunCompletionCandidate(input.plan, input.goal);
|
|
396
304
|
const snapshot = await readCodexGoalSnapshotInput(input.raw, input.repoRoot);
|
|
397
|
-
const
|
|
305
|
+
const expected = expectedCodexObjective(input.plan, input.goal);
|
|
398
306
|
const reconciliation = reconcileCodexGoalSnapshot(snapshot, {
|
|
399
|
-
expectedObjective,
|
|
400
|
-
...aggregate ? { acceptedObjectives: compatibleCodexObjectives(input.plan) } : {}
|
|
401
|
-
allowedStatuses: aggregate ? final ? ["complete"] : ["active"] : ["complete"],
|
|
402
|
-
requireSnapshot: true,
|
|
403
|
-
requireComplete: !aggregate || final
|
|
404
|
-
});
|
|
405
|
-
if (reconciliation.ok)
|
|
406
|
-
return reconciliation.snapshot.raw;
|
|
407
|
-
const objective = snapshot?.objective;
|
|
408
|
-
const mismatchedTaskObjective = snapshot?.available === true && objective !== undefined && normalizeObjective3(objective) !== normalizeObjective3(expectedObjective);
|
|
409
|
-
const completedTaskScoped = mismatchedTaskObjective && snapshot.status === "complete" && await canReconcileCompletedTaskScopedAggregateSnapshot(input.repoRoot, input.plan, input.goal, objective, input.evidence, input.scope);
|
|
410
|
-
const activeFinalTaskScoped = mismatchedTaskObjective && snapshot.status === "active" && await canReconcileActiveFinalTaskScopedAggregateSnapshot(input.repoRoot, input.plan, input.goal, objective, input.evidence, input.scope);
|
|
411
|
-
if (completedTaskScoped || activeFinalTaskScoped)
|
|
412
|
-
return reconciliation.snapshot.raw;
|
|
413
|
-
throw codexSnapshotMismatchError({
|
|
414
|
-
reconciliation,
|
|
415
|
-
snapshot,
|
|
416
|
-
expectedObjective,
|
|
417
|
-
taskScopedHint: { goal: input.goal, aggregate, final }
|
|
307
|
+
expectedObjective: expected,
|
|
308
|
+
...codexGoalMode(input.plan) === "aggregate" ? { acceptedObjectives: compatibleCodexObjectives(input.plan) } : {}
|
|
418
309
|
});
|
|
310
|
+
if (!reconciliation.ok)
|
|
311
|
+
throw new CodexGoalSnapshotError(formatCodexGoalReconciliation(reconciliation));
|
|
312
|
+
return {
|
|
313
|
+
raw: snapshot?.raw,
|
|
314
|
+
nextActions: reconciliation.warnings,
|
|
315
|
+
warnings: reconciliation.warnings.filter((warning) => warning.startsWith("driver_objective_differs"))
|
|
316
|
+
};
|
|
419
317
|
}
|
|
420
318
|
function combineCheckpointValidationErrors(codexError, gateError) {
|
|
421
319
|
return new UlwLoopError(`${codexError.message}
|
|
@@ -427,7 +325,7 @@ ${gateError.message}`, "ULW_LOOP_QUALITY_GATE_INVALID", {
|
|
|
427
325
|
// components/ulw-loop/src/plan-io.ts
|
|
428
326
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
429
327
|
import { createReadStream, readdirSync } from "node:fs";
|
|
430
|
-
import { appendFile, mkdir, readFile as
|
|
328
|
+
import { appendFile, mkdir, readFile as readFile2, rename, writeFile } from "node:fs/promises";
|
|
431
329
|
import { createInterface } from "node:readline";
|
|
432
330
|
|
|
433
331
|
// components/ulw-loop/src/plan-missing-recovery.ts
|
|
@@ -694,7 +592,7 @@ async function readUlwLoopPlan(repoRoot, scope) {
|
|
|
694
592
|
const path = ulwLoopGoalsPath(repoRoot, scope);
|
|
695
593
|
let raw;
|
|
696
594
|
try {
|
|
697
|
-
raw = await
|
|
595
|
+
raw = await readFile2(path, "utf8");
|
|
698
596
|
} catch (error) {
|
|
699
597
|
if (!hasCode2(error, "ENOENT"))
|
|
700
598
|
throw error;
|
|
@@ -1113,7 +1011,7 @@ function adversarialVerdict(row, field) {
|
|
|
1113
1011
|
}
|
|
1114
1012
|
|
|
1115
1013
|
// components/ulw-loop/src/surface.ts
|
|
1116
|
-
import { existsSync as
|
|
1014
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
|
|
1117
1015
|
import { dirname as dirname2, join as join2 } from "node:path";
|
|
1118
1016
|
import { fileURLToPath } from "node:url";
|
|
1119
1017
|
var REVIEWER_ROLES_BY_SURFACE = {
|
|
@@ -1173,7 +1071,7 @@ function resolveToolkitSurface(options) {
|
|
|
1173
1071
|
}
|
|
1174
1072
|
function readMarkerSurface(markerPath) {
|
|
1175
1073
|
try {
|
|
1176
|
-
if (!
|
|
1074
|
+
if (!existsSync2(markerPath))
|
|
1177
1075
|
return null;
|
|
1178
1076
|
const parsed = JSON.parse(readFileSync2(markerPath, "utf8"));
|
|
1179
1077
|
return parseSurface(parsed["surface"]);
|
|
@@ -1376,7 +1274,7 @@ function parseAdversarialCases(value, byId) {
|
|
|
1376
1274
|
}
|
|
1377
1275
|
|
|
1378
1276
|
// components/ulw-loop/src/cli-arg-parser.ts
|
|
1379
|
-
import { readFile as
|
|
1277
|
+
import { readFile as readFile3 } from "node:fs/promises";
|
|
1380
1278
|
var VALUE_FLAGS = new Set("--brief --brief-file --session-id --codex-goal-mode --validation-batch-json --goal --goal-id --criterion-id --status --evidence --notes --codex-goal-json --quality-gate-json --kind --rationale --title --objective --target-goal-id --source --after-json --directive-json --directive-file --idempotency-key --proposals-json".split(" "));
|
|
1381
1279
|
var SUBCOMMANDS = new Set("create-goals status complete-goals criteria record-evidence checkpoint steer add-goal record-review-blockers".split(" "));
|
|
1382
1280
|
function hasFlag(argv, flag) {
|
|
@@ -1424,7 +1322,7 @@ async function readJsonInput(value) {
|
|
|
1424
1322
|
if (value === undefined)
|
|
1425
1323
|
return;
|
|
1426
1324
|
try {
|
|
1427
|
-
return JSON.parse(looksLikeJson(value) ? value : await
|
|
1325
|
+
return JSON.parse(looksLikeJson(value) ? value : await readFile3(value, "utf8"));
|
|
1428
1326
|
} catch (error) {
|
|
1429
1327
|
const message = error instanceof Error ? error.message : "unknown error";
|
|
1430
1328
|
throw new UlwLoopError(`Invalid JSON input: ${message}`, "ULW_LOOP_JSON_INPUT_INVALID", { cause: error });
|
|
@@ -1433,13 +1331,13 @@ async function readJsonInput(value) {
|
|
|
1433
1331
|
async function parseCodexGoalJson(value) {
|
|
1434
1332
|
if (value === undefined)
|
|
1435
1333
|
return;
|
|
1436
|
-
const raw = looksLikeJson(value) ? value : await readFile4(value, "utf8");
|
|
1437
1334
|
try {
|
|
1335
|
+
const raw = looksLikeJson(value) ? value : await readFile3(value, "utf8");
|
|
1438
1336
|
JSON.parse(raw);
|
|
1439
1337
|
return raw;
|
|
1440
1338
|
} catch (error) {
|
|
1441
1339
|
const message = error instanceof Error ? error.message : "unknown error";
|
|
1442
|
-
throw new UlwLoopError(`Invalid --codex-goal-json: ${message}`, "ULW_LOOP_CODEX_GOAL_JSON_INVALID", { cause: error });
|
|
1340
|
+
throw new UlwLoopError(`Invalid --codex-goal-json: ${looksLikeJson(value) ? message : "neither valid JSON nor a readable path"}`, "ULW_LOOP_CODEX_GOAL_JSON_INVALID", { cause: error });
|
|
1443
1341
|
}
|
|
1444
1342
|
}
|
|
1445
1343
|
function required(argv, flag, code) {
|
|
@@ -1585,7 +1483,7 @@ function fail(message, code = "ULW_LOOP_VALIDATION_BATCH_INVALID") {
|
|
|
1585
1483
|
}
|
|
1586
1484
|
|
|
1587
1485
|
// components/ulw-loop/src/checkpoint.ts
|
|
1588
|
-
var QUALITY_GATE_FS = { existsSync:
|
|
1486
|
+
var QUALITY_GATE_FS = { existsSync: existsSync3, statSync: statSync2 };
|
|
1589
1487
|
function ulwLoopFail2(message, code) {
|
|
1590
1488
|
throw new UlwLoopError(message, code);
|
|
1591
1489
|
}
|
|
@@ -1608,10 +1506,10 @@ async function readJsonInput2(raw, repoRoot) {
|
|
|
1608
1506
|
throw error;
|
|
1609
1507
|
}
|
|
1610
1508
|
const path = resolve3(repoRoot, trimmed);
|
|
1611
|
-
if (!
|
|
1509
|
+
if (!existsSync3(path))
|
|
1612
1510
|
return ulwLoopFail2("Quality gate JSON is neither valid JSON nor a readable path.", "ulw_loop_json_input_invalid");
|
|
1613
1511
|
try {
|
|
1614
|
-
return JSON.parse(await
|
|
1512
|
+
return JSON.parse(await readFile4(path, "utf8"));
|
|
1615
1513
|
} catch (error) {
|
|
1616
1514
|
return ulwLoopFail2(`Quality gate path does not contain valid JSON${error instanceof Error ? `: ${error.message}` : "."}`, "ulw_loop_json_input_invalid");
|
|
1617
1515
|
}
|
|
@@ -1680,6 +1578,8 @@ async function checkpointUlwLoop(repoRoot, args, scope) {
|
|
|
1680
1578
|
let aggregateCompletion;
|
|
1681
1579
|
let qualityGate;
|
|
1682
1580
|
let codexGoal;
|
|
1581
|
+
let nextActions = [];
|
|
1582
|
+
let warnings = [];
|
|
1683
1583
|
if (args.status === "complete") {
|
|
1684
1584
|
const aggregate = codexGoalMode(plan) === "aggregate";
|
|
1685
1585
|
const final = isFinalRunCompletionCandidate(plan, goal);
|
|
@@ -1694,7 +1594,7 @@ async function checkpointUlwLoop(repoRoot, args, scope) {
|
|
|
1694
1594
|
requireAllCriteriaPass(goal);
|
|
1695
1595
|
let codexValidationError;
|
|
1696
1596
|
try {
|
|
1697
|
-
|
|
1597
|
+
const validation = await validateCheckpointCodexGoal({
|
|
1698
1598
|
repoRoot,
|
|
1699
1599
|
plan,
|
|
1700
1600
|
goal,
|
|
@@ -1702,6 +1602,9 @@ async function checkpointUlwLoop(repoRoot, args, scope) {
|
|
|
1702
1602
|
evidence,
|
|
1703
1603
|
...scope === undefined ? {} : { scope }
|
|
1704
1604
|
});
|
|
1605
|
+
codexGoal = validation.raw;
|
|
1606
|
+
nextActions = validation.nextActions;
|
|
1607
|
+
warnings = validation.warnings;
|
|
1705
1608
|
} catch (error) {
|
|
1706
1609
|
if (!(error instanceof UlwLoopError))
|
|
1707
1610
|
throw error;
|
|
@@ -1743,6 +1646,8 @@ async function checkpointUlwLoop(repoRoot, args, scope) {
|
|
|
1743
1646
|
goal.updatedAt = now;
|
|
1744
1647
|
if (aggregateCompletion !== undefined)
|
|
1745
1648
|
plan.aggregateCompletion = aggregateCompletion;
|
|
1649
|
+
if (aggregateCompletion !== undefined)
|
|
1650
|
+
nextActions = [...nextActions, 'aggregate complete — now update_goal({status:"complete"})'];
|
|
1746
1651
|
plan.updatedAt = now;
|
|
1747
1652
|
await writePlan(repoRoot, plan, scope);
|
|
1748
1653
|
const ledgerEntry = buildLedger(now, args, goal, qualityGate, codexGoal, aggregateCompletion);
|
|
@@ -1750,7 +1655,7 @@ async function checkpointUlwLoop(repoRoot, args, scope) {
|
|
|
1750
1655
|
const closedBatch = args.status === "complete" ? batchClosedBy(plan, goal.id) : undefined;
|
|
1751
1656
|
if (closedBatch !== undefined)
|
|
1752
1657
|
await appendLedger(repoRoot, { at: now, kind: "batch_closed", goalId: goal.id, message: closedBatch.batchId }, scope);
|
|
1753
|
-
return aggregateCompletion === undefined ? { plan, goal, ledgerEntry } : { plan, goal, ledgerEntry, aggregateCompletion };
|
|
1658
|
+
return aggregateCompletion === undefined ? { plan, goal, ledgerEntry, nextActions, warnings } : { plan, goal, ledgerEntry, aggregateCompletion, nextActions, warnings };
|
|
1754
1659
|
});
|
|
1755
1660
|
}
|
|
1756
1661
|
|
|
@@ -2085,14 +1990,14 @@ function joinLines(lines) {
|
|
|
2085
1990
|
}
|
|
2086
1991
|
|
|
2087
1992
|
// components/ulw-loop/src/plan-crud.ts
|
|
2088
|
-
import { existsSync as
|
|
1993
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
2089
1994
|
import { mkdir as mkdir2, writeFile as writeFile2 } from "node:fs/promises";
|
|
2090
1995
|
|
|
2091
1996
|
// components/ulw-loop/src/plan-goal-factory.ts
|
|
2092
1997
|
function cleanLine(line) {
|
|
2093
1998
|
return line.replace(/^\s*(?:[-*+]\s+|\d+[.)]\s+)/, "").trim();
|
|
2094
1999
|
}
|
|
2095
|
-
function
|
|
2000
|
+
function normalizeObjective2(value) {
|
|
2096
2001
|
return value.replace(/\s+/g, " ").trim();
|
|
2097
2002
|
}
|
|
2098
2003
|
function titleFromObjective(objective, fallback) {
|
|
@@ -2113,7 +2018,7 @@ function truncateObjective(objective) {
|
|
|
2113
2018
|
return objective.length > 80 ? `${objective.slice(0, 77).trimEnd()}...` : objective;
|
|
2114
2019
|
}
|
|
2115
2020
|
function seedDefaultSuccessCriteria(goalIndex, objective) {
|
|
2116
|
-
const subject = truncateObjective(
|
|
2021
|
+
const subject = truncateObjective(normalizeObjective2(objective) || `Goal ${goalIndex + 1}`);
|
|
2117
2022
|
const rows = [
|
|
2118
2023
|
[
|
|
2119
2024
|
"C001",
|
|
@@ -2148,8 +2053,8 @@ function seedDefaultSuccessCriteria(goalIndex, objective) {
|
|
|
2148
2053
|
}));
|
|
2149
2054
|
}
|
|
2150
2055
|
function deriveGoalCandidates(brief) {
|
|
2151
|
-
const bulletGoals = brief.split(/\r?\n/).map((line) => ({ original: line, cleaned:
|
|
2152
|
-
const paragraphs = brief.split(/\n\s*\n/).map(
|
|
2056
|
+
const bulletGoals = brief.split(/\r?\n/).map((line) => ({ original: line, cleaned: normalizeObjective2(cleanLine(line)) })).filter(({ cleaned }) => cleaned.length > 0 && cleaned.length <= 1200).filter(({ original, cleaned }, index, all) => /^\s*(?:[-*+]\s+|\d+[.)]\s+)/.test(original) && all.findIndex((candidate) => candidate.cleaned === cleaned) === index).map(({ cleaned }) => cleaned);
|
|
2057
|
+
const paragraphs = brief.split(/\n\s*\n/).map(normalizeObjective2).filter((paragraph) => paragraph.length > 0 && !paragraph.startsWith("#"));
|
|
2153
2058
|
const selected = (bulletGoals.length > 0 ? bulletGoals : paragraphs).length > 0 ? bulletGoals.length > 0 ? bulletGoals : paragraphs : ["Complete the requested project objective."];
|
|
2154
2059
|
return selected.map((objective, index) => ({
|
|
2155
2060
|
title: titleFromObjective(objective, `Goal ${index + 1}`),
|
|
@@ -2195,7 +2100,7 @@ function clearGoalBlockerFields2(goal) {
|
|
|
2195
2100
|
}
|
|
2196
2101
|
async function createUlwLoopPlan(repoRoot, args, scope) {
|
|
2197
2102
|
return withUlwLoopMutationLock(repoRoot, scope, async () => {
|
|
2198
|
-
if (!args.force &&
|
|
2103
|
+
if (!args.force && existsSync4(ulwLoopGoalsPath(repoRoot, scope))) {
|
|
2199
2104
|
const existing = await readUlwLoopPlan(repoRoot, scope);
|
|
2200
2105
|
if (isUlwLoopDone(existing))
|
|
2201
2106
|
throw completedPlanExistsError(scope);
|
|
@@ -2327,10 +2232,7 @@ async function checkpoint(repoRoot, argv, json, scope) {
|
|
|
2327
2232
|
const goalId = required2(argv, "--goal-id");
|
|
2328
2233
|
const statusValue = checkpointStatus(required2(argv, "--status"));
|
|
2329
2234
|
const evidence = required2(argv, "--evidence");
|
|
2330
|
-
const codexGoalJson = await parseCodexGoalJson(
|
|
2331
|
-
if (statusValue === "complete" && codexGoalJson === undefined) {
|
|
2332
|
-
throw new UlwLoopError("Missing --codex-goal-json.", "ULW_LOOP_CODEX_GOAL_JSON_REQUIRED");
|
|
2333
|
-
}
|
|
2235
|
+
const codexGoalJson = await parseCodexGoalJson(readValue(argv, "--codex-goal-json"));
|
|
2334
2236
|
const qualityGateJson = readValue(argv, "--quality-gate-json");
|
|
2335
2237
|
const args = {
|
|
2336
2238
|
goalId,
|
|
@@ -2376,7 +2278,7 @@ function checkpointStatus(value) {
|
|
|
2376
2278
|
}
|
|
2377
2279
|
|
|
2378
2280
|
// components/ulw-loop/src/cli-subcommands.ts
|
|
2379
|
-
import { readFile as
|
|
2281
|
+
import { readFile as readFile5 } from "node:fs/promises";
|
|
2380
2282
|
|
|
2381
2283
|
// components/ulw-loop/src/cli-steering.ts
|
|
2382
2284
|
var SOURCES = ["user_prompt_submit", "finding", "cli"];
|
|
@@ -2723,11 +2625,12 @@ async function recordFinalReviewBlockers(repoRoot, args, scope) {
|
|
|
2723
2625
|
if (!isFinalRunCompletionCandidate(plan, goal))
|
|
2724
2626
|
ulwLoopError(`${goal.id} is not final.`, "ulw_loop_not_final_story");
|
|
2725
2627
|
const snapshot = await readCodexGoalSnapshotInput(args.codexGoalJson, repoRoot);
|
|
2726
|
-
const
|
|
2727
|
-
|
|
2728
|
-
|
|
2628
|
+
const reconciliation = reconcileCodexGoalSnapshot(snapshot, {
|
|
2629
|
+
expectedObjective: expectedCodexObjective(plan, goal),
|
|
2630
|
+
acceptedObjectives: compatibleCodexObjectives(plan)
|
|
2631
|
+
});
|
|
2729
2632
|
if (!reconciliation.ok)
|
|
2730
|
-
throw
|
|
2633
|
+
throw new CodexGoalSnapshotError(formatCodexGoalReconciliation(reconciliation));
|
|
2731
2634
|
const now = iso();
|
|
2732
2635
|
for (const field of BLOCKER_FIELDS)
|
|
2733
2636
|
Reflect.deleteProperty(goal, field);
|
|
@@ -2739,7 +2642,7 @@ async function recordFinalReviewBlockers(repoRoot, args, scope) {
|
|
|
2739
2642
|
delete plan.activeGoalId;
|
|
2740
2643
|
const newGoal = appendBlockerGoal(plan, args, now);
|
|
2741
2644
|
plan.updatedAt = now;
|
|
2742
|
-
const codexGoal =
|
|
2645
|
+
const codexGoal = snapshot?.raw;
|
|
2743
2646
|
const blockedEntry = { at: now, kind: "goal_review_blocked", goalId: goal.id, status: goal.status, evidence: args.evidence, codexGoal };
|
|
2744
2647
|
const addedEntry = { at: now, kind: "goal_added", goalId: newGoal.id, status: newGoal.status, evidence: args.evidence, message: newGoal.title };
|
|
2745
2648
|
const summaryEntry = { at: now, kind: "goal_review_blocked", goalId: goal.id, status: goal.status, evidence: args.evidence, codexGoal, message: `Review blockers recorded; appended ${newGoal.id}.` };
|
|
@@ -2748,7 +2651,14 @@ async function recordFinalReviewBlockers(repoRoot, args, scope) {
|
|
|
2748
2651
|
await writePlan(repoRoot, plan, scope);
|
|
2749
2652
|
for (const entry of ledgerEntries)
|
|
2750
2653
|
await appendLedger(repoRoot, entry, scope);
|
|
2751
|
-
return {
|
|
2654
|
+
return {
|
|
2655
|
+
plan,
|
|
2656
|
+
blockedGoal: goal,
|
|
2657
|
+
newGoal,
|
|
2658
|
+
ledgerEntries,
|
|
2659
|
+
nextActions: reconciliation.warnings,
|
|
2660
|
+
warnings: reconciliation.warnings.filter((warning) => warning.startsWith("driver_objective_differs"))
|
|
2661
|
+
};
|
|
2752
2662
|
});
|
|
2753
2663
|
}
|
|
2754
2664
|
|
|
@@ -3213,7 +3123,7 @@ function ledgerEntry2(proposal, audit, at) {
|
|
|
3213
3123
|
// components/ulw-loop/src/cli-subcommands.ts
|
|
3214
3124
|
async function createGoals(repoRoot, argv, json, scope) {
|
|
3215
3125
|
const briefFile = readValue(argv, "--brief-file");
|
|
3216
|
-
const brief = readValue(argv, "--brief") ?? (briefFile === undefined ? undefined : await
|
|
3126
|
+
const brief = readValue(argv, "--brief") ?? (briefFile === undefined ? undefined : await readFile5(briefFile, "utf8")) ?? (hasFlag(argv, "--from-stdin") ? await readStdin() : undefined) ?? positionalText(argv);
|
|
3217
3127
|
if (!brief.trim()) {
|
|
3218
3128
|
throw new UlwLoopError("Missing brief text. Pass --brief, --brief-file, --from-stdin, or positional text.", "ULW_LOOP_BRIEF_REQUIRED");
|
|
3219
3129
|
}
|
|
@@ -3342,6 +3252,8 @@ async function reviewBlockers(repoRoot, argv, json, scope) {
|
|
|
3342
3252
|
blockedGoal: result.blockedGoal,
|
|
3343
3253
|
goal: result.newGoal,
|
|
3344
3254
|
ledgerEntries: result.ledgerEntries,
|
|
3255
|
+
nextActions: result.nextActions,
|
|
3256
|
+
warnings: result.warnings,
|
|
3345
3257
|
summary: summarizeUlwLoopPlan(result.plan)
|
|
3346
3258
|
});
|
|
3347
3259
|
} else {
|
|
@@ -3479,7 +3391,7 @@ function commandScope(repoRoot, argv) {
|
|
|
3479
3391
|
import { readFileSync as readFileSync4 } from "node:fs";
|
|
3480
3392
|
|
|
3481
3393
|
// components/ulw-loop/src/ultrawork-skill-pointer.ts
|
|
3482
|
-
import { existsSync as
|
|
3394
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3 } from "node:fs";
|
|
3483
3395
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
3484
3396
|
var ULTRAWORK_SKILL_POINTER_TEMPLATE = `<ultrawork-mode>
|
|
3485
3397
|
ULTRAWORK MODE IS ACTIVE FOR THIS TASK.
|
|
@@ -3520,7 +3432,7 @@ function buildUltraworkSkillPointer(skillFilePath) {
|
|
|
3520
3432
|
}
|
|
3521
3433
|
function buildUltraworkAdditionalContext(options = {}) {
|
|
3522
3434
|
const skillFilePath = options.skillFilePath === undefined ? resolveUltraworkSkillFilePath() : options.skillFilePath;
|
|
3523
|
-
if (skillFilePath !== null &&
|
|
3435
|
+
if (skillFilePath !== null && existsSync5(skillFilePath)) {
|
|
3524
3436
|
return buildUltraworkSkillPointer(skillFilePath);
|
|
3525
3437
|
}
|
|
3526
3438
|
return ULTRAWORK_DIRECTIVE;
|
|
@@ -3768,7 +3680,7 @@ function readAll(stdin) {
|
|
|
3768
3680
|
|
|
3769
3681
|
// components/ulw-loop/src/spawn-guard.ts
|
|
3770
3682
|
import { randomBytes } from "node:crypto";
|
|
3771
|
-
import { existsSync as
|
|
3683
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync5, renameSync, statSync as statSync3, writeFileSync } from "node:fs";
|
|
3772
3684
|
import { dirname as dirname3, join as join3 } from "node:path";
|
|
3773
3685
|
var SPAWN_TOOL_TOKENS = new Set(["spawn_agent", "collaborationspawn_agent", "collaboration.spawn_agent"]);
|
|
3774
3686
|
var DEFAULT_FANOUT_LIMIT = 24;
|
|
@@ -4002,7 +3914,7 @@ function reviewSpawnLimit() {
|
|
|
4002
3914
|
}
|
|
4003
3915
|
function isNonEmptyFile(path) {
|
|
4004
3916
|
try {
|
|
4005
|
-
return
|
|
3917
|
+
return existsSync6(path) && statSync3(path).size > 0;
|
|
4006
3918
|
} catch (error) {
|
|
4007
3919
|
if (error instanceof Error)
|
|
4008
3920
|
return false;
|
|
@@ -4047,7 +3959,7 @@ function readPlan(goalsPath) {
|
|
|
4047
3959
|
}
|
|
4048
3960
|
|
|
4049
3961
|
// components/ulw-loop/src/stop-resume-hook.ts
|
|
4050
|
-
import { existsSync as
|
|
3962
|
+
import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync2 } from "node:fs";
|
|
4051
3963
|
import { isAbsolute as isAbsolute2, join as join4, resolve as resolve4, sep as sep2 } from "node:path";
|
|
4052
3964
|
var RESUME_CAP = 2;
|
|
4053
3965
|
var CONTEXT_PRESSURE_MARKERS2 = [
|
|
@@ -4167,7 +4079,7 @@ function countLedgerLines(ledgerPath) {
|
|
|
4167
4079
|
}
|
|
4168
4080
|
function readCounter(counterPath) {
|
|
4169
4081
|
try {
|
|
4170
|
-
if (!
|
|
4082
|
+
if (!existsSync7(counterPath))
|
|
4171
4083
|
return null;
|
|
4172
4084
|
const parsed = JSON.parse(readFileSync6(counterPath, "utf8"));
|
|
4173
4085
|
if (typeof parsed["count"] !== "number" || typeof parsed["ledgerLineCount"] !== "number")
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type CodexGoalSnapshotStatus = "active" | "complete" | "cancelled" | "failed" | "unknown";
|
|
1
|
+
export type CodexGoalSnapshotStatus = "active" | "complete" | "paused" | "usage_limited" | "budget_limited" | "cancelled" | "failed" | "unknown";
|
|
2
2
|
export interface CodexGoalSnapshot {
|
|
3
3
|
available: boolean;
|
|
4
4
|
objective?: string;
|
|
@@ -13,10 +13,7 @@ export interface CodexGoalReconciliation {
|
|
|
13
13
|
}
|
|
14
14
|
export interface ReconcileCodexGoalOptions {
|
|
15
15
|
expectedObjective: string;
|
|
16
|
-
acceptedObjectives?: readonly string[];
|
|
17
|
-
allowedStatuses?: readonly CodexGoalSnapshotStatus[];
|
|
18
|
-
requireSnapshot?: boolean;
|
|
19
|
-
requireComplete?: boolean;
|
|
16
|
+
readonly acceptedObjectives?: readonly string[];
|
|
20
17
|
}
|
|
21
18
|
export declare class CodexGoalSnapshotError extends Error {
|
|
22
19
|
}
|
|
@@ -24,16 +21,3 @@ export declare function parseCodexGoalSnapshot(value: unknown): CodexGoalSnapsho
|
|
|
24
21
|
export declare function readCodexGoalSnapshotInput(raw: string | undefined, cwd?: string): Promise<CodexGoalSnapshot | null>;
|
|
25
22
|
export declare function reconcileCodexGoalSnapshot(snapshot: CodexGoalSnapshot | null | undefined, options: ReconcileCodexGoalOptions): CodexGoalReconciliation;
|
|
26
23
|
export declare function formatCodexGoalReconciliation(reconciliation: CodexGoalReconciliation): string;
|
|
27
|
-
export interface CodexGoalMismatchRecovery {
|
|
28
|
-
readonly message: string;
|
|
29
|
-
readonly details: {
|
|
30
|
-
readonly expectedObjective: string;
|
|
31
|
-
readonly receivedObjective: string;
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* The reconciliation errors normalize whitespace for comparison, which makes the
|
|
36
|
-
* quoted objective unusable as a copy source. Recovery therefore carries the
|
|
37
|
-
* plan's `codexObjective` verbatim so the agent can paste it into `update_goal`.
|
|
38
|
-
*/
|
|
39
|
-
export declare function codexGoalMismatchRecovery(expectedObjective: string, snapshot: CodexGoalSnapshot | null | undefined): CodexGoalMismatchRecovery;
|