lazycodex-ai 5.0.0-beta.57 → 5.0.0-beta.60
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 +18 -22
- package/dist/cli-node/index.js +18 -22
- 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-template.d.ts +5 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-template.js +4 -3
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.d.ts +5 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.js +2 -2
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.d.ts +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.js +38 -39
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +163 -36
- package/packages/omo-codex/plugin/components/ulw-loop/dist/sdk/factory.d.ts +2 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/sdk/factory.js +125 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/sdk/manifest.d.ts +46 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/sdk/manifest.js +28 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/sdk/types.d.ts +127 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/sdk/types.js +1 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/sdk.d.ts +3 -0
- package/packages/omo-codex/plugin/components/ulw-loop/dist/sdk.js +3 -0
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +4 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-template.ts +8 -2
- package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +6 -2
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-subcommands.ts +50 -48
- package/packages/omo-codex/plugin/components/ulw-loop/src/sdk/factory.ts +159 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/sdk/manifest.ts +42 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/sdk/types.ts +140 -0
- package/packages/omo-codex/plugin/components/ulw-loop/src/sdk.ts +3 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/sdk-contract.test.ts +137 -0
- package/packages/omo-codex/plugin/components/ulw-loop/test/sdk-session-context.test.ts +148 -0
- 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/skills/ulw-loop/SKILL.md +4 -0
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +2 -2
- package/packages/shared-skills/skills/ulw-plan/scripts/scaffold-plan.mjs +1 -1
|
@@ -3,15 +3,11 @@ import { hasFlag, parseCodexGoalJson, parseRecordEvidenceArgs, positionalText, r
|
|
|
3
3
|
import { blockedDecisionHandoff, normalizeCodexGoalMode, printJson, printStatus } from "./cli-output.js";
|
|
4
4
|
import { parseSteeringProposals, printSteerBatchResult, printSteerResult } from "./cli-steering.js";
|
|
5
5
|
import { buildCodexGoalInstruction } from "./codex-goal-instruction.js";
|
|
6
|
-
import { recordEvidence } from "./evidence.js";
|
|
7
6
|
import { isEssentialCriterion } from "./goal-status.js";
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import { readUlwLoopPlan } from "./plan-io.js";
|
|
11
|
-
import { recordFinalReviewBlockers } from "./review-blockers.js";
|
|
12
|
-
import { statusNextActions } from "./status-next-actions.js";
|
|
13
|
-
import { steerUlwLoop } from "./steering.js";
|
|
7
|
+
import { summarizeUlwLoopPlan } from "./plan-crud.js";
|
|
8
|
+
import { createAgentToolkit } from "./sdk.js";
|
|
14
9
|
import { steerUlwLoopBatch } from "./steering-batch.js";
|
|
10
|
+
import { resolveToolkitSurface } from "./surface.js";
|
|
15
11
|
import { UlwLoopError } from "./types.js";
|
|
16
12
|
export async function createGoals(repoRoot, argv, json, scope) {
|
|
17
13
|
const briefFile = readValue(argv, "--brief-file");
|
|
@@ -23,12 +19,12 @@ export async function createGoals(repoRoot, argv, json, scope) {
|
|
|
23
19
|
throw new UlwLoopError("Missing brief text. Pass --brief, --brief-file, --from-stdin, or positional text.", "ULW_LOOP_BRIEF_REQUIRED");
|
|
24
20
|
}
|
|
25
21
|
const validationBatchesJson = readValue(argv, "--validation-batch-json");
|
|
26
|
-
const plan = await
|
|
22
|
+
const plan = unwrap(await toolkitFor(repoRoot, scope).createGoals({
|
|
27
23
|
brief,
|
|
28
24
|
codexGoalMode: normalizeCodexGoalMode(readValue(argv, "--codex-goal-mode")),
|
|
29
25
|
force: hasFlag(argv, "--force"),
|
|
30
26
|
...(validationBatchesJson === undefined ? {} : { validationBatchesJson }),
|
|
31
|
-
}
|
|
27
|
+
}));
|
|
32
28
|
if (json)
|
|
33
29
|
printJson({ ok: true, plan, summary: summarizeUlwLoopPlan(plan) });
|
|
34
30
|
else {
|
|
@@ -37,26 +33,15 @@ export async function createGoals(repoRoot, argv, json, scope) {
|
|
|
37
33
|
return 0;
|
|
38
34
|
}
|
|
39
35
|
export async function status(repoRoot, json, scope) {
|
|
40
|
-
const
|
|
41
|
-
if (json)
|
|
42
|
-
|
|
43
|
-
const currentAttemptDir = plan.evidenceLayoutVersion === 2 && active
|
|
44
|
-
? ulwLoopAttemptEvidenceDir(active.id, active.attempt, scope)
|
|
45
|
-
: undefined;
|
|
46
|
-
printJson({
|
|
47
|
-
ok: true,
|
|
48
|
-
plan,
|
|
49
|
-
summary: summarizeUlwLoopPlan(plan),
|
|
50
|
-
...(currentAttemptDir === undefined ? {} : { currentAttemptDir }),
|
|
51
|
-
nextActions: statusNextActions(plan),
|
|
52
|
-
});
|
|
53
|
-
}
|
|
36
|
+
const status = unwrap(await toolkitFor(repoRoot, scope).status());
|
|
37
|
+
if (json)
|
|
38
|
+
printJson({ ok: true, ...status });
|
|
54
39
|
else
|
|
55
|
-
printStatus(plan);
|
|
40
|
+
printStatus(status.plan);
|
|
56
41
|
return 0;
|
|
57
42
|
}
|
|
58
43
|
export async function completeGoals(repoRoot, argv, json, scope) {
|
|
59
|
-
const result = await
|
|
44
|
+
const result = unwrap(await toolkitFor(repoRoot, scope).completeGoals({ retryFailed: hasFlag(argv, "--retry-failed") }));
|
|
60
45
|
if ("done" in result) {
|
|
61
46
|
const handoff = blockedDecisionHandoff(result.plan);
|
|
62
47
|
if (json) {
|
|
@@ -84,7 +69,7 @@ export async function steer(repoRoot, argv, json, scope) {
|
|
|
84
69
|
const proposals = await parseSteeringProposals(argv);
|
|
85
70
|
const single = proposals[0];
|
|
86
71
|
if (single !== undefined && proposals.length === 1 && readValue(argv, "--proposals-json") === undefined) {
|
|
87
|
-
const result = await
|
|
72
|
+
const result = unwrap(await toolkitFor(repoRoot, scope).steer(single));
|
|
88
73
|
printSteerResult(result, json);
|
|
89
74
|
return result.accepted ? 0 : 1;
|
|
90
75
|
}
|
|
@@ -93,7 +78,10 @@ export async function steer(repoRoot, argv, json, scope) {
|
|
|
93
78
|
return result.accepted ? 0 : 1;
|
|
94
79
|
}
|
|
95
80
|
export async function addGoal(repoRoot, argv, json, scope) {
|
|
96
|
-
const result = await
|
|
81
|
+
const result = unwrap(await toolkitFor(repoRoot, scope).addGoal({
|
|
82
|
+
title: required(argv, "--title"),
|
|
83
|
+
objective: required(argv, "--objective"),
|
|
84
|
+
}));
|
|
97
85
|
if (json)
|
|
98
86
|
printJson({ ok: true, plan: result.plan, goal: result.goal, summary: summarizeUlwLoopPlan(result.plan) });
|
|
99
87
|
else {
|
|
@@ -104,16 +92,16 @@ export async function addGoal(repoRoot, argv, json, scope) {
|
|
|
104
92
|
}
|
|
105
93
|
export async function criteria(repoRoot, argv, json, scope) {
|
|
106
94
|
const goalId = required(argv, "--goal-id");
|
|
107
|
-
const
|
|
95
|
+
const result = unwrap(await toolkitFor(repoRoot, scope).criteria({ goalId }));
|
|
108
96
|
if (json)
|
|
109
|
-
printJson({ ok: true, goalId:
|
|
97
|
+
printJson({ ok: true, goalId: result.goalId, criteria: result.criteria });
|
|
110
98
|
else {
|
|
111
|
-
process.stdout.write(`criteria for ${
|
|
99
|
+
process.stdout.write(`criteria for ${result.goalId}:\n${result.criteria.map(formatCriterionForCli).join("\n")}\n`);
|
|
112
100
|
}
|
|
113
101
|
return 0;
|
|
114
102
|
}
|
|
115
103
|
export async function captureEvidence(repoRoot, argv, json, scope) {
|
|
116
|
-
const result = await
|
|
104
|
+
const result = unwrap(await toolkitFor(repoRoot, scope).recordEvidence(parseRecordEvidenceArgs(argv)));
|
|
117
105
|
if (json)
|
|
118
106
|
printJson({ ok: true, ...result, summary: summarizeUlwLoopPlan(result.plan) });
|
|
119
107
|
else {
|
|
@@ -126,13 +114,13 @@ export async function reviewBlockers(repoRoot, argv, json, scope) {
|
|
|
126
114
|
if (codexGoalJson === undefined) {
|
|
127
115
|
throw new UlwLoopError("Missing --codex-goal-json.", "ULW_LOOP_CODEX_GOAL_JSON_REQUIRED");
|
|
128
116
|
}
|
|
129
|
-
const result = await
|
|
117
|
+
const result = unwrap(await toolkitFor(repoRoot, scope).recordReviewBlockers({
|
|
130
118
|
goalId: required(argv, "--goal-id"),
|
|
131
119
|
title: required(argv, "--title"),
|
|
132
120
|
objective: required(argv, "--objective"),
|
|
133
121
|
evidence: required(argv, "--evidence"),
|
|
134
122
|
codexGoalJson,
|
|
135
|
-
}
|
|
123
|
+
}));
|
|
136
124
|
if (json) {
|
|
137
125
|
printJson({
|
|
138
126
|
ok: true,
|
|
@@ -150,6 +138,23 @@ export async function reviewBlockers(repoRoot, argv, json, scope) {
|
|
|
150
138
|
}
|
|
151
139
|
return 0;
|
|
152
140
|
}
|
|
141
|
+
// Every subcommand runs through the SDK so state logic lives in one place; the CLI keeps only argv
|
|
142
|
+
// parsing and the legacy output shapes. A failed envelope is rethrown as the typed error the CLI's
|
|
143
|
+
// JSON error path already prints.
|
|
144
|
+
function toolkitFor(repoRoot, scope) {
|
|
145
|
+
const sessionId = scope?.sessionId?.trim();
|
|
146
|
+
if (sessionId === undefined || sessionId.length === 0) {
|
|
147
|
+
throw new UlwLoopError("Missing --session-id.", "ULW_LOOP_SESSION_ID_REQUIRED", {
|
|
148
|
+
details: { flag: "--session-id" },
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
return createAgentToolkit({ cwd: repoRoot, sessionId, surface: resolveToolkitSurface() });
|
|
152
|
+
}
|
|
153
|
+
function unwrap(response) {
|
|
154
|
+
if (response.ok)
|
|
155
|
+
return response.result;
|
|
156
|
+
throw new UlwLoopError(response.error.message, response.error.code);
|
|
157
|
+
}
|
|
153
158
|
function formatCriterionForCli(criterion) {
|
|
154
159
|
const marker = isEssentialCriterion(criterion) ? "essential" : "non-essential";
|
|
155
160
|
return `- ${criterion.id} [${criterion.status}] [${marker}] (${criterion.userModel}) ${criterion.scenario} evidence: ${criterion.capturedEvidence ?? "pending"}`;
|
|
@@ -160,9 +165,3 @@ function required(argv, flag) {
|
|
|
160
165
|
return value;
|
|
161
166
|
throw new UlwLoopError(`Missing ${flag}.`, "ULW_LOOP_ARGUMENT_MISSING", { details: { flag } });
|
|
162
167
|
}
|
|
163
|
-
function findGoal(plan, goalId) {
|
|
164
|
-
const goal = plan.goals.find((candidate) => candidate.id === goalId);
|
|
165
|
-
if (goal !== undefined)
|
|
166
|
-
return goal;
|
|
167
|
-
throw new UlwLoopError(`Unknown ulw-loop id: ${goalId}.`, "ULW_LOOP_GOAL_NOT_FOUND", { details: { goalId } });
|
|
168
|
-
}
|
|
@@ -1569,7 +1569,7 @@ function buildLedger(now, args, goal, qualityGate, codexGoal, aggregateCompletio
|
|
|
1569
1569
|
entry.requiredExternalDecision = goal.requiredExternalDecision;
|
|
1570
1570
|
return entry;
|
|
1571
1571
|
}
|
|
1572
|
-
async function checkpointUlwLoop(repoRoot, args, scope) {
|
|
1572
|
+
async function checkpointUlwLoop(repoRoot, args, scope, dependencies) {
|
|
1573
1573
|
return withUlwLoopMutationLock(repoRoot, scope, async () => {
|
|
1574
1574
|
const plan = await readUlwLoopPlan(repoRoot, scope);
|
|
1575
1575
|
const goal = findGoal2(plan, args.goalId);
|
|
@@ -1621,7 +1621,7 @@ async function checkpointUlwLoop(repoRoot, args, scope) {
|
|
|
1621
1621
|
qualityGate = validateQualityGate(await readJsonInput2(args.qualityGateJson, repoRoot), {
|
|
1622
1622
|
repoRoot,
|
|
1623
1623
|
fs: QUALITY_GATE_FS,
|
|
1624
|
-
reviewerSurface: resolveToolkitSurface(),
|
|
1624
|
+
reviewerSurface: dependencies?.surface ?? resolveToolkitSurface(),
|
|
1625
1625
|
...plan.evidenceLayoutVersion === 2 ? { currentAttemptDir: ulwLoopAttemptEvidenceDir(goal.id, goal.attempt, scope) } : {}
|
|
1626
1626
|
});
|
|
1627
1627
|
requireBatchGate(plan, goal, qualityGate);
|
|
@@ -1740,8 +1740,9 @@ function gateTemplate(surface, base) {
|
|
|
1740
1740
|
};
|
|
1741
1741
|
return common;
|
|
1742
1742
|
}
|
|
1743
|
-
async function checkpointTemplate(repoRoot, scope, goalId) {
|
|
1743
|
+
async function checkpointTemplate(repoRoot, scope, goalId, dependencies) {
|
|
1744
1744
|
const plan = await readUlwLoopPlan(repoRoot, scope);
|
|
1745
|
+
const surface = dependencies?.surface ?? resolveToolkitSurface();
|
|
1745
1746
|
const targetId = goalId ?? plan.activeGoalId;
|
|
1746
1747
|
const active = plan.goals.find((goal) => goal.id === targetId);
|
|
1747
1748
|
if (goalId !== undefined && active === undefined)
|
|
@@ -1753,13 +1754,13 @@ async function checkpointTemplate(repoRoot, scope, goalId) {
|
|
|
1753
1754
|
"Fill every <replace:...> value with plausible non-empty evidence and use real, non-empty artifact files.",
|
|
1754
1755
|
'Passing codex-goal-json example: {"goal":{"objective":"<plan codexObjective verbatim>","status":"complete"}}.',
|
|
1755
1756
|
'Passing quality-gate-json example requires gateReview {"by":"category:deep","recommendation":"APPROVE","evidence":"review passed","reportPath":"<attemptDir>/gate-review.md","blockers":[],"notes":[]}, manualQa.artifactRefs objects, iteration, and criteriaCoverage.',
|
|
1756
|
-
...
|
|
1757
|
+
...surface === "lazycodex" ? [
|
|
1757
1758
|
"Self-review defaults: manualQa.by and gateReview.by are main-session. Alternatives: manualQa.by accepts lazycodex-qa-executor; gateReview.by accepts lazycodex-gate-reviewer, category:deep, category:unspecified-high, or category:unspecified-low. Optional codeReview.by accepts lazycodex-code-reviewer or main-session."
|
|
1758
1759
|
] : [],
|
|
1759
1760
|
...hasAttempt ? [] : ["This plan is evidence-layout v1; artifacts go under .omo/evidence/."]
|
|
1760
1761
|
].join(" ");
|
|
1761
1762
|
return {
|
|
1762
|
-
qualityGateTemplate: gateTemplate(
|
|
1763
|
+
qualityGateTemplate: gateTemplate(surface, attemptDir),
|
|
1763
1764
|
codexGoalTemplate: {
|
|
1764
1765
|
goal: { objective: plan.codexObjective ?? "<replace:codex objective>", status: "complete" }
|
|
1765
1766
|
},
|
|
@@ -3039,6 +3040,129 @@ function ledgerEntry(proposal, audit, at) {
|
|
|
3039
3040
|
return entry;
|
|
3040
3041
|
}
|
|
3041
3042
|
|
|
3043
|
+
// components/ulw-loop/src/sdk/manifest.ts
|
|
3044
|
+
var ULW_LOOP_MANIFEST = {
|
|
3045
|
+
version: 1,
|
|
3046
|
+
name: "ulw-loop",
|
|
3047
|
+
operations: [
|
|
3048
|
+
{ name: "help", mutating: false },
|
|
3049
|
+
{ name: "create-goals", mutating: true },
|
|
3050
|
+
{ name: "status", mutating: false },
|
|
3051
|
+
{ name: "complete-goals", mutating: true },
|
|
3052
|
+
{ name: "checkpoint", mutating: true },
|
|
3053
|
+
{ name: "steer", mutating: true },
|
|
3054
|
+
{ name: "add-goal", mutating: true },
|
|
3055
|
+
{ name: "criteria", mutating: false },
|
|
3056
|
+
{ name: "record-evidence", mutating: true },
|
|
3057
|
+
{ name: "record-review-blockers", mutating: true }
|
|
3058
|
+
]
|
|
3059
|
+
};
|
|
3060
|
+
|
|
3061
|
+
// components/ulw-loop/src/sdk/factory.ts
|
|
3062
|
+
function validateContext(context) {
|
|
3063
|
+
if (!context.cwd.trim())
|
|
3064
|
+
throw new UlwLoopError("cwd is required.", "ULW_LOOP_CWD_REQUIRED");
|
|
3065
|
+
if (!context.sessionId.trim())
|
|
3066
|
+
throw new UlwLoopError("ULW_LOOP_SESSION_ID_REQUIRED: sessionId is required.", "ULW_LOOP_SESSION_ID_REQUIRED");
|
|
3067
|
+
if (context.surface !== "omo-senpi" && context.surface !== "lazycodex")
|
|
3068
|
+
throw new UlwLoopError("surface must be omo-senpi or lazycodex.", "ULW_LOOP_SURFACE_INVALID");
|
|
3069
|
+
}
|
|
3070
|
+
function errorDetails(error) {
|
|
3071
|
+
const details = error.details === undefined ? undefined : Object.fromEntries(Object.entries(error.details).map(([key, value]) => [key, String(value)]));
|
|
3072
|
+
return details === undefined ? { code: error.code, message: error.message } : { code: error.code, message: error.message, details };
|
|
3073
|
+
}
|
|
3074
|
+
function failure(operation, error) {
|
|
3075
|
+
return { ok: false, operation, error: errorDetails(error) };
|
|
3076
|
+
}
|
|
3077
|
+
function caught(operation, error) {
|
|
3078
|
+
return failure(operation, error instanceof UlwLoopError ? error : new UlwLoopError(error.message, "ULW_LOOP_ERROR"));
|
|
3079
|
+
}
|
|
3080
|
+
function isKnownRequest(request) {
|
|
3081
|
+
return ULW_LOOP_MANIFEST.operations.some((operation) => operation.name === request.operation);
|
|
3082
|
+
}
|
|
3083
|
+
function unreachable(value) {
|
|
3084
|
+
throw new UlwLoopError(`Unhandled operation: ${String(value)}`, "ULW_LOOP_OPERATION_UNHANDLED");
|
|
3085
|
+
}
|
|
3086
|
+
function nextActionsFrom(result) {
|
|
3087
|
+
if (!("nextActions" in result) || !Array.isArray(result.nextActions))
|
|
3088
|
+
return [];
|
|
3089
|
+
return result.nextActions.filter((action) => typeof action === "string").slice(0, 8);
|
|
3090
|
+
}
|
|
3091
|
+
function createAgentToolkit(context, deps = {}) {
|
|
3092
|
+
validateContext(context);
|
|
3093
|
+
const scope = { sessionId: context.sessionId };
|
|
3094
|
+
const notify = async (operation, response) => {
|
|
3095
|
+
if (deps.hooks?.onOperation !== undefined)
|
|
3096
|
+
await deps.hooks.onOperation({ operation, context, response });
|
|
3097
|
+
return response;
|
|
3098
|
+
};
|
|
3099
|
+
const invoke = async (operation, fn) => {
|
|
3100
|
+
try {
|
|
3101
|
+
const result = await fn();
|
|
3102
|
+
const nextActions = typeof result === "object" && result !== null ? nextActionsFrom(result) : [];
|
|
3103
|
+
return await notify(operation, { ok: true, operation, result, nextActions });
|
|
3104
|
+
} catch (error) {
|
|
3105
|
+
const response = caught(operation, error instanceof Error ? error : new Error("ULW_LOOP_ERROR"));
|
|
3106
|
+
return notify(operation, response);
|
|
3107
|
+
}
|
|
3108
|
+
};
|
|
3109
|
+
const toolkit = {
|
|
3110
|
+
dispatch: async (request) => {
|
|
3111
|
+
if (!isKnownRequest(request))
|
|
3112
|
+
return failure(request.operation, new UlwLoopError(`Unknown operation: ${request.operation}`, "ULW_LOOP_OPERATION_UNKNOWN"));
|
|
3113
|
+
switch (request.operation) {
|
|
3114
|
+
case "help":
|
|
3115
|
+
return toolkit.help();
|
|
3116
|
+
case "create-goals":
|
|
3117
|
+
return toolkit.createGoals(request.args);
|
|
3118
|
+
case "status":
|
|
3119
|
+
return toolkit.status();
|
|
3120
|
+
case "complete-goals":
|
|
3121
|
+
return toolkit.completeGoals(request.args);
|
|
3122
|
+
case "checkpoint":
|
|
3123
|
+
return toolkit.checkpoint(request.args);
|
|
3124
|
+
case "steer":
|
|
3125
|
+
return toolkit.steer(request.args);
|
|
3126
|
+
case "add-goal":
|
|
3127
|
+
return toolkit.addGoal(request.args);
|
|
3128
|
+
case "criteria":
|
|
3129
|
+
return toolkit.criteria(request.args);
|
|
3130
|
+
case "record-evidence":
|
|
3131
|
+
return toolkit.recordEvidence(request.args);
|
|
3132
|
+
case "record-review-blockers":
|
|
3133
|
+
return toolkit.recordReviewBlockers(request.args);
|
|
3134
|
+
default:
|
|
3135
|
+
return unreachable(request);
|
|
3136
|
+
}
|
|
3137
|
+
},
|
|
3138
|
+
help: () => invoke("help", async () => ULW_LOOP_MANIFEST),
|
|
3139
|
+
createGoals: (args) => invoke("create-goals", () => createUlwLoopPlan(context.cwd, args, scope)),
|
|
3140
|
+
status: () => invoke("status", async () => {
|
|
3141
|
+
const plan = await readUlwLoopPlan(context.cwd, scope);
|
|
3142
|
+
const active = plan.goals.find((goal) => goal.id === plan.activeGoalId);
|
|
3143
|
+
return {
|
|
3144
|
+
plan,
|
|
3145
|
+
summary: summarizeUlwLoopPlan(plan),
|
|
3146
|
+
nextActions: statusNextActions(plan),
|
|
3147
|
+
...active === undefined || plan.evidenceLayoutVersion !== 2 ? {} : { currentAttemptDir: ulwLoopAttemptEvidenceDir(active.id, active.attempt, scope) }
|
|
3148
|
+
};
|
|
3149
|
+
}),
|
|
3150
|
+
completeGoals: (args = {}) => invoke("complete-goals", () => startNextUlwLoop(context.cwd, args, scope)),
|
|
3151
|
+
checkpoint: (args) => invoke("checkpoint", () => args.printTemplate === true ? checkpointTemplate(context.cwd, scope, args.goalId, { surface: context.surface }) : checkpointUlwLoop(context.cwd, args, scope, { surface: context.surface })),
|
|
3152
|
+
steer: (args) => invoke("steer", () => steerUlwLoop(context.cwd, args, scope)),
|
|
3153
|
+
addGoal: (args) => invoke("add-goal", () => addUlwLoopGoal(context.cwd, args, scope)),
|
|
3154
|
+
criteria: (args) => invoke("criteria", async () => {
|
|
3155
|
+
const plan = await readUlwLoopPlan(context.cwd, scope);
|
|
3156
|
+
const goal = plan.goals.find((candidate) => candidate.id === args.goalId);
|
|
3157
|
+
if (goal === undefined)
|
|
3158
|
+
throw new UlwLoopError(`Unknown ulw-loop id: ${args.goalId}.`, "ULW_LOOP_GOAL_NOT_FOUND");
|
|
3159
|
+
return { goalId: goal.id, criteria: goal.successCriteria };
|
|
3160
|
+
}),
|
|
3161
|
+
recordEvidence: (args) => invoke("record-evidence", () => recordEvidence(context.cwd, args, scope)),
|
|
3162
|
+
recordReviewBlockers: (args) => invoke("record-review-blockers", () => recordFinalReviewBlockers(context.cwd, args, scope))
|
|
3163
|
+
};
|
|
3164
|
+
return toolkit;
|
|
3165
|
+
}
|
|
3042
3166
|
// components/ulw-loop/src/steering-batch.ts
|
|
3043
3167
|
async function steerUlwLoopBatch(repoRoot, proposals, scope) {
|
|
3044
3168
|
return withUlwLoopMutationLock(repoRoot, scope, async () => {
|
|
@@ -3128,12 +3252,12 @@ async function createGoals(repoRoot, argv, json, scope) {
|
|
|
3128
3252
|
throw new UlwLoopError("Missing brief text. Pass --brief, --brief-file, --from-stdin, or positional text.", "ULW_LOOP_BRIEF_REQUIRED");
|
|
3129
3253
|
}
|
|
3130
3254
|
const validationBatchesJson = readValue(argv, "--validation-batch-json");
|
|
3131
|
-
const plan = await
|
|
3255
|
+
const plan = unwrap(await toolkitFor(repoRoot, scope).createGoals({
|
|
3132
3256
|
brief,
|
|
3133
3257
|
codexGoalMode: normalizeCodexGoalMode(readValue(argv, "--codex-goal-mode")),
|
|
3134
3258
|
force: hasFlag(argv, "--force"),
|
|
3135
3259
|
...validationBatchesJson === undefined ? {} : { validationBatchesJson }
|
|
3136
|
-
}
|
|
3260
|
+
}));
|
|
3137
3261
|
if (json)
|
|
3138
3262
|
printJson({ ok: true, plan, summary: summarizeUlwLoopPlan(plan) });
|
|
3139
3263
|
else {
|
|
@@ -3146,23 +3270,15 @@ ledger: ${plan.ledgerPath}
|
|
|
3146
3270
|
return 0;
|
|
3147
3271
|
}
|
|
3148
3272
|
async function status(repoRoot, json, scope) {
|
|
3149
|
-
const
|
|
3150
|
-
if (json)
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
ok: true,
|
|
3155
|
-
plan,
|
|
3156
|
-
summary: summarizeUlwLoopPlan(plan),
|
|
3157
|
-
...currentAttemptDir === undefined ? {} : { currentAttemptDir },
|
|
3158
|
-
nextActions: statusNextActions(plan)
|
|
3159
|
-
});
|
|
3160
|
-
} else
|
|
3161
|
-
printStatus(plan);
|
|
3273
|
+
const status = unwrap(await toolkitFor(repoRoot, scope).status());
|
|
3274
|
+
if (json)
|
|
3275
|
+
printJson({ ok: true, ...status });
|
|
3276
|
+
else
|
|
3277
|
+
printStatus(status.plan);
|
|
3162
3278
|
return 0;
|
|
3163
3279
|
}
|
|
3164
3280
|
async function completeGoals(repoRoot, argv, json, scope) {
|
|
3165
|
-
const result = await
|
|
3281
|
+
const result = unwrap(await toolkitFor(repoRoot, scope).completeGoals({ retryFailed: hasFlag(argv, "--retry-failed") }));
|
|
3166
3282
|
if ("done" in result) {
|
|
3167
3283
|
const handoff = blockedDecisionHandoff(result.plan);
|
|
3168
3284
|
if (json) {
|
|
@@ -3191,7 +3307,7 @@ async function steer(repoRoot, argv, json, scope) {
|
|
|
3191
3307
|
const proposals = await parseSteeringProposals(argv);
|
|
3192
3308
|
const single = proposals[0];
|
|
3193
3309
|
if (single !== undefined && proposals.length === 1 && readValue(argv, "--proposals-json") === undefined) {
|
|
3194
|
-
const result = await
|
|
3310
|
+
const result = unwrap(await toolkitFor(repoRoot, scope).steer(single));
|
|
3195
3311
|
printSteerResult(result, json);
|
|
3196
3312
|
return result.accepted ? 0 : 1;
|
|
3197
3313
|
}
|
|
@@ -3200,7 +3316,10 @@ async function steer(repoRoot, argv, json, scope) {
|
|
|
3200
3316
|
return result.accepted ? 0 : 1;
|
|
3201
3317
|
}
|
|
3202
3318
|
async function addGoal(repoRoot, argv, json, scope) {
|
|
3203
|
-
const result = await
|
|
3319
|
+
const result = unwrap(await toolkitFor(repoRoot, scope).addGoal({
|
|
3320
|
+
title: required4(argv, "--title"),
|
|
3321
|
+
objective: required4(argv, "--objective")
|
|
3322
|
+
}));
|
|
3204
3323
|
if (json)
|
|
3205
3324
|
printJson({ ok: true, plan: result.plan, goal: result.goal, summary: summarizeUlwLoopPlan(result.plan) });
|
|
3206
3325
|
else {
|
|
@@ -3212,19 +3331,19 @@ async function addGoal(repoRoot, argv, json, scope) {
|
|
|
3212
3331
|
}
|
|
3213
3332
|
async function criteria(repoRoot, argv, json, scope) {
|
|
3214
3333
|
const goalId = required4(argv, "--goal-id");
|
|
3215
|
-
const
|
|
3334
|
+
const result = unwrap(await toolkitFor(repoRoot, scope).criteria({ goalId }));
|
|
3216
3335
|
if (json)
|
|
3217
|
-
printJson({ ok: true, goalId:
|
|
3336
|
+
printJson({ ok: true, goalId: result.goalId, criteria: result.criteria });
|
|
3218
3337
|
else {
|
|
3219
|
-
process.stdout.write(`criteria for ${
|
|
3220
|
-
${
|
|
3338
|
+
process.stdout.write(`criteria for ${result.goalId}:
|
|
3339
|
+
${result.criteria.map(formatCriterionForCli).join(`
|
|
3221
3340
|
`)}
|
|
3222
3341
|
`);
|
|
3223
3342
|
}
|
|
3224
3343
|
return 0;
|
|
3225
3344
|
}
|
|
3226
3345
|
async function captureEvidence(repoRoot, argv, json, scope) {
|
|
3227
|
-
const result = await
|
|
3346
|
+
const result = unwrap(await toolkitFor(repoRoot, scope).recordEvidence(parseRecordEvidenceArgs(argv)));
|
|
3228
3347
|
if (json)
|
|
3229
3348
|
printJson({ ok: true, ...result, summary: summarizeUlwLoopPlan(result.plan) });
|
|
3230
3349
|
else {
|
|
@@ -3238,13 +3357,13 @@ async function reviewBlockers(repoRoot, argv, json, scope) {
|
|
|
3238
3357
|
if (codexGoalJson === undefined) {
|
|
3239
3358
|
throw new UlwLoopError("Missing --codex-goal-json.", "ULW_LOOP_CODEX_GOAL_JSON_REQUIRED");
|
|
3240
3359
|
}
|
|
3241
|
-
const result = await
|
|
3360
|
+
const result = unwrap(await toolkitFor(repoRoot, scope).recordReviewBlockers({
|
|
3242
3361
|
goalId: required4(argv, "--goal-id"),
|
|
3243
3362
|
title: required4(argv, "--title"),
|
|
3244
3363
|
objective: required4(argv, "--objective"),
|
|
3245
3364
|
evidence: required4(argv, "--evidence"),
|
|
3246
3365
|
codexGoalJson
|
|
3247
|
-
}
|
|
3366
|
+
}));
|
|
3248
3367
|
if (json) {
|
|
3249
3368
|
printJson({
|
|
3250
3369
|
ok: true,
|
|
@@ -3262,6 +3381,20 @@ async function reviewBlockers(repoRoot, argv, json, scope) {
|
|
|
3262
3381
|
}
|
|
3263
3382
|
return 0;
|
|
3264
3383
|
}
|
|
3384
|
+
function toolkitFor(repoRoot, scope) {
|
|
3385
|
+
const sessionId = scope?.sessionId?.trim();
|
|
3386
|
+
if (sessionId === undefined || sessionId.length === 0) {
|
|
3387
|
+
throw new UlwLoopError("Missing --session-id.", "ULW_LOOP_SESSION_ID_REQUIRED", {
|
|
3388
|
+
details: { flag: "--session-id" }
|
|
3389
|
+
});
|
|
3390
|
+
}
|
|
3391
|
+
return createAgentToolkit({ cwd: repoRoot, sessionId, surface: resolveToolkitSurface() });
|
|
3392
|
+
}
|
|
3393
|
+
function unwrap(response) {
|
|
3394
|
+
if (response.ok)
|
|
3395
|
+
return response.result;
|
|
3396
|
+
throw new UlwLoopError(response.error.message, response.error.code);
|
|
3397
|
+
}
|
|
3265
3398
|
function formatCriterionForCli(criterion) {
|
|
3266
3399
|
const marker = isEssentialCriterion(criterion) ? "essential" : "non-essential";
|
|
3267
3400
|
return `- ${criterion.id} [${criterion.status}] [${marker}] (${criterion.userModel}) ${criterion.scenario} evidence: ${criterion.capturedEvidence ?? "pending"}`;
|
|
@@ -3272,12 +3405,6 @@ function required4(argv, flag) {
|
|
|
3272
3405
|
return value;
|
|
3273
3406
|
throw new UlwLoopError(`Missing ${flag}.`, "ULW_LOOP_ARGUMENT_MISSING", { details: { flag } });
|
|
3274
3407
|
}
|
|
3275
|
-
function findGoal3(plan, goalId) {
|
|
3276
|
-
const goal = plan.goals.find((candidate) => candidate.id === goalId);
|
|
3277
|
-
if (goal !== undefined)
|
|
3278
|
-
return goal;
|
|
3279
|
-
throw new UlwLoopError(`Unknown ulw-loop id: ${goalId}.`, "ULW_LOOP_GOAL_NOT_FOUND", { details: { goalId } });
|
|
3280
|
-
}
|
|
3281
3408
|
|
|
3282
3409
|
// components/ulw-loop/src/cli-commands.ts
|
|
3283
3410
|
var ULW_LOOP_SUBCOMMANDS = [
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { checkpointUlwLoop } from "../checkpoint.js";
|
|
2
|
+
import { checkpointTemplate } from "../checkpoint-template.js";
|
|
3
|
+
import { recordEvidence } from "../evidence.js";
|
|
4
|
+
import { ulwLoopAttemptEvidenceDir } from "../paths.js";
|
|
5
|
+
import { addUlwLoopGoal, createUlwLoopPlan, startNextUlwLoop, summarizeUlwLoopPlan } from "../plan-crud.js";
|
|
6
|
+
import { readUlwLoopPlan } from "../plan-io.js";
|
|
7
|
+
import { recordFinalReviewBlockers } from "../review-blockers.js";
|
|
8
|
+
import { UlwLoopError } from "../runtime.js";
|
|
9
|
+
import { statusNextActions } from "../status-next-actions.js";
|
|
10
|
+
import { steerUlwLoop } from "../steering.js";
|
|
11
|
+
import { ULW_LOOP_MANIFEST } from "./manifest.js";
|
|
12
|
+
function validateContext(context) {
|
|
13
|
+
if (!context.cwd.trim())
|
|
14
|
+
throw new UlwLoopError("cwd is required.", "ULW_LOOP_CWD_REQUIRED");
|
|
15
|
+
if (!context.sessionId.trim())
|
|
16
|
+
throw new UlwLoopError("ULW_LOOP_SESSION_ID_REQUIRED: sessionId is required.", "ULW_LOOP_SESSION_ID_REQUIRED");
|
|
17
|
+
if (context.surface !== "omo-senpi" && context.surface !== "lazycodex")
|
|
18
|
+
throw new UlwLoopError("surface must be omo-senpi or lazycodex.", "ULW_LOOP_SURFACE_INVALID");
|
|
19
|
+
}
|
|
20
|
+
function errorDetails(error) {
|
|
21
|
+
const details = error.details === undefined
|
|
22
|
+
? undefined
|
|
23
|
+
: Object.fromEntries(Object.entries(error.details).map(([key, value]) => [key, String(value)]));
|
|
24
|
+
return details === undefined
|
|
25
|
+
? { code: error.code, message: error.message }
|
|
26
|
+
: { code: error.code, message: error.message, details };
|
|
27
|
+
}
|
|
28
|
+
function failure(operation, error) {
|
|
29
|
+
return { ok: false, operation, error: errorDetails(error) };
|
|
30
|
+
}
|
|
31
|
+
function caught(operation, error) {
|
|
32
|
+
return failure(operation, error instanceof UlwLoopError ? error : new UlwLoopError(error.message, "ULW_LOOP_ERROR"));
|
|
33
|
+
}
|
|
34
|
+
function isKnownRequest(request) {
|
|
35
|
+
return ULW_LOOP_MANIFEST.operations.some((operation) => operation.name === request.operation);
|
|
36
|
+
}
|
|
37
|
+
function unreachable(value) {
|
|
38
|
+
throw new UlwLoopError(`Unhandled operation: ${String(value)}`, "ULW_LOOP_OPERATION_UNHANDLED");
|
|
39
|
+
}
|
|
40
|
+
function nextActionsFrom(result) {
|
|
41
|
+
if (!("nextActions" in result) || !Array.isArray(result.nextActions))
|
|
42
|
+
return [];
|
|
43
|
+
return result.nextActions.filter((action) => typeof action === "string").slice(0, 8);
|
|
44
|
+
}
|
|
45
|
+
export function createAgentToolkit(context, deps = {}) {
|
|
46
|
+
validateContext(context);
|
|
47
|
+
const scope = { sessionId: context.sessionId };
|
|
48
|
+
const notify = async (operation, response) => {
|
|
49
|
+
if (deps.hooks?.onOperation !== undefined)
|
|
50
|
+
await deps.hooks.onOperation({ operation, context, response });
|
|
51
|
+
return response;
|
|
52
|
+
};
|
|
53
|
+
const invoke = async (operation, fn) => {
|
|
54
|
+
try {
|
|
55
|
+
const result = await fn();
|
|
56
|
+
const nextActions = typeof result === "object" && result !== null ? nextActionsFrom(result) : [];
|
|
57
|
+
return await notify(operation, { ok: true, operation, result, nextActions });
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
const response = caught(operation, error instanceof Error ? error : new Error("ULW_LOOP_ERROR"));
|
|
61
|
+
return notify(operation, response);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const toolkit = {
|
|
65
|
+
dispatch: async (request) => {
|
|
66
|
+
if (!isKnownRequest(request))
|
|
67
|
+
return failure(request.operation, new UlwLoopError(`Unknown operation: ${request.operation}`, "ULW_LOOP_OPERATION_UNKNOWN"));
|
|
68
|
+
switch (request.operation) {
|
|
69
|
+
case "help":
|
|
70
|
+
return toolkit.help();
|
|
71
|
+
case "create-goals":
|
|
72
|
+
return toolkit.createGoals(request.args);
|
|
73
|
+
case "status":
|
|
74
|
+
return toolkit.status();
|
|
75
|
+
case "complete-goals":
|
|
76
|
+
return toolkit.completeGoals(request.args);
|
|
77
|
+
case "checkpoint":
|
|
78
|
+
return toolkit.checkpoint(request.args);
|
|
79
|
+
case "steer":
|
|
80
|
+
return toolkit.steer(request.args);
|
|
81
|
+
case "add-goal":
|
|
82
|
+
return toolkit.addGoal(request.args);
|
|
83
|
+
case "criteria":
|
|
84
|
+
return toolkit.criteria(request.args);
|
|
85
|
+
case "record-evidence":
|
|
86
|
+
return toolkit.recordEvidence(request.args);
|
|
87
|
+
case "record-review-blockers":
|
|
88
|
+
return toolkit.recordReviewBlockers(request.args);
|
|
89
|
+
default:
|
|
90
|
+
return unreachable(request);
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
help: () => invoke("help", async () => ULW_LOOP_MANIFEST),
|
|
94
|
+
createGoals: (args) => invoke("create-goals", () => createUlwLoopPlan(context.cwd, args, scope)),
|
|
95
|
+
status: () => invoke("status", async () => {
|
|
96
|
+
const plan = await readUlwLoopPlan(context.cwd, scope);
|
|
97
|
+
const active = plan.goals.find((goal) => goal.id === plan.activeGoalId);
|
|
98
|
+
return {
|
|
99
|
+
plan,
|
|
100
|
+
summary: summarizeUlwLoopPlan(plan),
|
|
101
|
+
nextActions: statusNextActions(plan),
|
|
102
|
+
// Attempt directories are an evidence-layout v2 concept; a v1 plan must not advertise one.
|
|
103
|
+
...(active === undefined || plan.evidenceLayoutVersion !== 2
|
|
104
|
+
? {}
|
|
105
|
+
: { currentAttemptDir: ulwLoopAttemptEvidenceDir(active.id, active.attempt, scope) }),
|
|
106
|
+
};
|
|
107
|
+
}),
|
|
108
|
+
completeGoals: (args = {}) => invoke("complete-goals", () => startNextUlwLoop(context.cwd, args, scope)),
|
|
109
|
+
checkpoint: (args) => invoke("checkpoint", () => args.printTemplate === true
|
|
110
|
+
? checkpointTemplate(context.cwd, scope, args.goalId, { surface: context.surface })
|
|
111
|
+
: checkpointUlwLoop(context.cwd, args, scope, { surface: context.surface })),
|
|
112
|
+
steer: (args) => invoke("steer", () => steerUlwLoop(context.cwd, args, scope)),
|
|
113
|
+
addGoal: (args) => invoke("add-goal", () => addUlwLoopGoal(context.cwd, args, scope)),
|
|
114
|
+
criteria: (args) => invoke("criteria", async () => {
|
|
115
|
+
const plan = await readUlwLoopPlan(context.cwd, scope);
|
|
116
|
+
const goal = plan.goals.find((candidate) => candidate.id === args.goalId);
|
|
117
|
+
if (goal === undefined)
|
|
118
|
+
throw new UlwLoopError(`Unknown ulw-loop id: ${args.goalId}.`, "ULW_LOOP_GOAL_NOT_FOUND");
|
|
119
|
+
return { goalId: goal.id, criteria: goal.successCriteria };
|
|
120
|
+
}),
|
|
121
|
+
recordEvidence: (args) => invoke("record-evidence", () => recordEvidence(context.cwd, args, scope)),
|
|
122
|
+
recordReviewBlockers: (args) => invoke("record-review-blockers", () => recordFinalReviewBlockers(context.cwd, args, scope)),
|
|
123
|
+
};
|
|
124
|
+
return toolkit;
|
|
125
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export declare const ULW_LOOP_OPERATIONS: readonly ["help", "create-goals", "status", "complete-goals", "checkpoint", "steer", "add-goal", "criteria", "record-evidence", "record-review-blockers"];
|
|
2
|
+
export type UlwLoopOperation = (typeof ULW_LOOP_OPERATIONS)[number];
|
|
3
|
+
export interface ToolkitOperationManifest {
|
|
4
|
+
readonly name: UlwLoopOperation;
|
|
5
|
+
readonly mutating: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface ToolkitManifest {
|
|
8
|
+
readonly version: 1;
|
|
9
|
+
readonly name: "ulw-loop";
|
|
10
|
+
readonly operations: readonly ToolkitOperationManifest[];
|
|
11
|
+
}
|
|
12
|
+
export declare const ULW_LOOP_MANIFEST: {
|
|
13
|
+
version: 1;
|
|
14
|
+
name: "ulw-loop";
|
|
15
|
+
operations: ({
|
|
16
|
+
name: "help";
|
|
17
|
+
mutating: false;
|
|
18
|
+
} | {
|
|
19
|
+
name: "create-goals";
|
|
20
|
+
mutating: true;
|
|
21
|
+
} | {
|
|
22
|
+
name: "status";
|
|
23
|
+
mutating: false;
|
|
24
|
+
} | {
|
|
25
|
+
name: "complete-goals";
|
|
26
|
+
mutating: true;
|
|
27
|
+
} | {
|
|
28
|
+
name: "checkpoint";
|
|
29
|
+
mutating: true;
|
|
30
|
+
} | {
|
|
31
|
+
name: "steer";
|
|
32
|
+
mutating: true;
|
|
33
|
+
} | {
|
|
34
|
+
name: "add-goal";
|
|
35
|
+
mutating: true;
|
|
36
|
+
} | {
|
|
37
|
+
name: "criteria";
|
|
38
|
+
mutating: false;
|
|
39
|
+
} | {
|
|
40
|
+
name: "record-evidence";
|
|
41
|
+
mutating: true;
|
|
42
|
+
} | {
|
|
43
|
+
name: "record-review-blockers";
|
|
44
|
+
mutating: true;
|
|
45
|
+
})[];
|
|
46
|
+
};
|