@aipper/aiws 0.0.45 → 0.0.47
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.js +61 -2
- package/dist/cli.js.map +1 -1
- package/dist/commands/goal-advance.d.ts +38 -0
- package/dist/commands/goal-advance.js +269 -0
- package/dist/commands/goal-advance.js.map +1 -0
- package/dist/commands/goal-help.d.ts +1 -0
- package/dist/commands/goal-help.js +32 -0
- package/dist/commands/goal-help.js.map +1 -0
- package/dist/commands/goal-validate-state.d.ts +107 -0
- package/dist/commands/goal-validate-state.js +429 -0
- package/dist/commands/goal-validate-state.js.map +1 -0
- package/dist/commands/goal-validate.d.ts +16 -0
- package/dist/commands/goal-validate.js +100 -0
- package/dist/commands/goal-validate.js.map +1 -0
- package/dist/commands/init.d.ts +7 -2
- package/dist/commands/init.js +60 -1
- package/dist/commands/init.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Valid phase sequence for goal state machine.
|
|
3
|
+
* Phases must be completed in order; no gaps allowed.
|
|
4
|
+
*/
|
|
5
|
+
export declare const VALID_PHASES: readonly string[];
|
|
6
|
+
export interface GoalCheckpoint {
|
|
7
|
+
status: "pending" | "in_progress" | "complete" | "failed";
|
|
8
|
+
attempts: number;
|
|
9
|
+
completed_at: string | null;
|
|
10
|
+
error: string | null;
|
|
11
|
+
}
|
|
12
|
+
export interface GoalGroup {
|
|
13
|
+
id?: string;
|
|
14
|
+
title?: string;
|
|
15
|
+
scope?: string;
|
|
16
|
+
status: "pending" | "in_progress" | "complete";
|
|
17
|
+
phase?: string | null;
|
|
18
|
+
dependencies?: string[];
|
|
19
|
+
}
|
|
20
|
+
export interface GoalState {
|
|
21
|
+
/** Schema version (v2 adds groups and timestamps) */
|
|
22
|
+
version?: string;
|
|
23
|
+
goal_id: string;
|
|
24
|
+
/** Overall goal status (active/complete/archived) */
|
|
25
|
+
status?: string;
|
|
26
|
+
/** Current phase in the state machine */
|
|
27
|
+
current_phase?: string;
|
|
28
|
+
/** Per-phase checkpoints with status and timing */
|
|
29
|
+
checkpoints: Record<string, GoalCheckpoint>;
|
|
30
|
+
/** Optional group topology for structuring sub-goals */
|
|
31
|
+
groups?: Record<string, GoalGroup>;
|
|
32
|
+
created_at?: string;
|
|
33
|
+
updated_at?: string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Validate a goal state's structural integrity.
|
|
37
|
+
*
|
|
38
|
+
* Checks performed:
|
|
39
|
+
* a) All required phase checkpoints exist
|
|
40
|
+
* b) Phase sequence: no completed phase with a prior pending phase (no gaps)
|
|
41
|
+
* c) Completed phases must have completed_at set
|
|
42
|
+
* d) Group DAG has no cycles and all dependencies resolve to known groups
|
|
43
|
+
* e) Group statuses are valid (pending/in_progress/complete)
|
|
44
|
+
* f) Groups with a `phase` set must have that parent phase complete
|
|
45
|
+
*/
|
|
46
|
+
export declare function validateGoalState(state: GoalState): {
|
|
47
|
+
valid: boolean;
|
|
48
|
+
errors: string[];
|
|
49
|
+
warnings: string[];
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Read and parse a goal state JSON file.
|
|
53
|
+
* @param statePath - Full path to the state file (e.g., `.aiws/goals/G-014.state.json`)
|
|
54
|
+
*/
|
|
55
|
+
export declare function readGoalState(statePath: string): Promise<GoalState>;
|
|
56
|
+
/**
|
|
57
|
+
* Atomically write a goal state to disk using tmp-file-then-rename.
|
|
58
|
+
* @param statePath - Full path to the state file to write
|
|
59
|
+
* @param state - The goal state to persist
|
|
60
|
+
*/
|
|
61
|
+
export declare function writeGoalState(statePath: string, state: GoalState): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Determine the next phase in the goal state machine.
|
|
64
|
+
*
|
|
65
|
+
* Logic:
|
|
66
|
+
* 1. If current phase checkpoint is not `complete` → stay on that phase
|
|
67
|
+
* 2. If groups exist: walk groups in topological order; find first pending group
|
|
68
|
+
* and its first pending phase
|
|
69
|
+
* 3. If no groups: advance through the flat VALID_PHASES sequence
|
|
70
|
+
* 4. If all phases (and groups) are complete → signal done
|
|
71
|
+
*/
|
|
72
|
+
export declare function computeNextPhase(state: GoalState): {
|
|
73
|
+
phase: string;
|
|
74
|
+
groupId: string | null;
|
|
75
|
+
done: boolean;
|
|
76
|
+
reason: string;
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Per-phase guidance descriptions for AI consumption.
|
|
80
|
+
* Maps each VALID_PHASE to a brief "what to do in this phase" instruction.
|
|
81
|
+
*/
|
|
82
|
+
export declare const PHASE_GUIDANCE: Record<string, string>;
|
|
83
|
+
/**
|
|
84
|
+
* Get next-actions guidance for the current phase of a goal state.
|
|
85
|
+
* Returns a structured description telling the AI what to do next.
|
|
86
|
+
*/
|
|
87
|
+
export declare function getPhaseGuidance(goalId: string, state: GoalState): {
|
|
88
|
+
phase: string;
|
|
89
|
+
description: string;
|
|
90
|
+
needsUserInput: boolean;
|
|
91
|
+
blockers: string[];
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Collect pending (non-complete) phases from checkpoints.
|
|
95
|
+
*/
|
|
96
|
+
export declare function listPendingPhases(state: GoalState): string[];
|
|
97
|
+
/**
|
|
98
|
+
* Find all goal state files in a directory.
|
|
99
|
+
* Scans for `*.state.json` files.
|
|
100
|
+
*/
|
|
101
|
+
export declare function scanGoalStateFiles(goalDir: string): Promise<string[]>;
|
|
102
|
+
/**
|
|
103
|
+
* Resolve a goal state file path from a directory and optional goal ID.
|
|
104
|
+
* If goalId is provided, returns the path to `<goalId>.state.json`.
|
|
105
|
+
* If not provided and exactly one `.state.json` exists, returns that path.
|
|
106
|
+
*/
|
|
107
|
+
export declare function resolveGoalStatePath(goalDir: string, goalId?: string): Promise<string | null>;
|
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import crypto from "node:crypto";
|
|
4
|
+
import { pathExists } from "../fs.js";
|
|
5
|
+
/**
|
|
6
|
+
* Valid phase sequence for goal state machine.
|
|
7
|
+
* Phases must be completed in order; no gaps allowed.
|
|
8
|
+
*/
|
|
9
|
+
export const VALID_PHASES = [
|
|
10
|
+
"intake",
|
|
11
|
+
"goal_def",
|
|
12
|
+
"dep_check",
|
|
13
|
+
"ws_analysis",
|
|
14
|
+
"plan",
|
|
15
|
+
"dev",
|
|
16
|
+
"review",
|
|
17
|
+
"finish",
|
|
18
|
+
];
|
|
19
|
+
/**
|
|
20
|
+
* Validate a goal state's structural integrity.
|
|
21
|
+
*
|
|
22
|
+
* Checks performed:
|
|
23
|
+
* a) All required phase checkpoints exist
|
|
24
|
+
* b) Phase sequence: no completed phase with a prior pending phase (no gaps)
|
|
25
|
+
* c) Completed phases must have completed_at set
|
|
26
|
+
* d) Group DAG has no cycles and all dependencies resolve to known groups
|
|
27
|
+
* e) Group statuses are valid (pending/in_progress/complete)
|
|
28
|
+
* f) Groups with a `phase` set must have that parent phase complete
|
|
29
|
+
*/
|
|
30
|
+
export function validateGoalState(state) {
|
|
31
|
+
const errors = [];
|
|
32
|
+
const warnings = [];
|
|
33
|
+
// a) All required phase checkpoints exist
|
|
34
|
+
for (const phase of VALID_PHASES) {
|
|
35
|
+
const cp = state.checkpoints[phase];
|
|
36
|
+
if (!cp) {
|
|
37
|
+
errors.push(`Missing required phase checkpoint: ${phase}`);
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const validStatuses = new Set(["pending", "in_progress", "complete"]);
|
|
41
|
+
if (!validStatuses.has(cp.status)) {
|
|
42
|
+
errors.push(`Phase ${phase} has invalid status: ${cp.status}`);
|
|
43
|
+
}
|
|
44
|
+
if (typeof cp.attempts !== "number") {
|
|
45
|
+
errors.push(`Phase ${phase} is missing numeric attempts field`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// b) Phase sequence: no completed phase if a prior phase is still pending
|
|
49
|
+
let foundPending = false;
|
|
50
|
+
for (const phase of VALID_PHASES) {
|
|
51
|
+
const cp = state.checkpoints[phase];
|
|
52
|
+
if (!cp)
|
|
53
|
+
continue;
|
|
54
|
+
if (foundPending && cp.status === "complete") {
|
|
55
|
+
errors.push(`Phase ${phase} is complete but prior phase(s) are not yet complete (gap in sequence)`);
|
|
56
|
+
}
|
|
57
|
+
if (cp.status === "pending") {
|
|
58
|
+
foundPending = true;
|
|
59
|
+
}
|
|
60
|
+
// in_progress also counts as "not done" for gap detection
|
|
61
|
+
if (cp.status === "in_progress") {
|
|
62
|
+
foundPending = true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// c) Completed phases must have completed_at
|
|
66
|
+
for (const phase of VALID_PHASES) {
|
|
67
|
+
const cp = state.checkpoints[phase];
|
|
68
|
+
if (!cp)
|
|
69
|
+
continue;
|
|
70
|
+
if (cp.status === "complete" && !cp.completed_at) {
|
|
71
|
+
errors.push(`Phase ${phase} is complete but missing completed_at`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// d) Group DAG validation
|
|
75
|
+
const groups = state.groups;
|
|
76
|
+
if (groups && Object.keys(groups).length > 0) {
|
|
77
|
+
const groupIds = new Set(Object.keys(groups));
|
|
78
|
+
// All dependencies must resolve to known groups
|
|
79
|
+
for (const [gid, group] of Object.entries(groups)) {
|
|
80
|
+
const deps = group.dependencies;
|
|
81
|
+
if (deps && Array.isArray(deps)) {
|
|
82
|
+
for (const dep of deps) {
|
|
83
|
+
if (!groupIds.has(dep)) {
|
|
84
|
+
errors.push(`Group ${gid} depends on unknown group: ${dep}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Cycle detection via DFS
|
|
90
|
+
const visited = new Set();
|
|
91
|
+
const inStack = new Set();
|
|
92
|
+
function hasCycle(node) {
|
|
93
|
+
if (inStack.has(node))
|
|
94
|
+
return true;
|
|
95
|
+
if (visited.has(node))
|
|
96
|
+
return false;
|
|
97
|
+
visited.add(node);
|
|
98
|
+
inStack.add(node);
|
|
99
|
+
const g = groups[node];
|
|
100
|
+
if (g) {
|
|
101
|
+
const deps = g.dependencies;
|
|
102
|
+
if (deps && Array.isArray(deps)) {
|
|
103
|
+
for (const dep of deps) {
|
|
104
|
+
if (hasCycle(dep))
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
inStack.delete(node);
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
for (const gid of groupIds) {
|
|
113
|
+
if (hasCycle(gid)) {
|
|
114
|
+
errors.push(`Group dependency cycle detected involving group: ${gid}`);
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// e) Group statuses must be valid
|
|
119
|
+
const validGroupStatuses = new Set(["pending", "in_progress", "complete"]);
|
|
120
|
+
for (const [gid, group] of Object.entries(groups)) {
|
|
121
|
+
if (!validGroupStatuses.has(group.status)) {
|
|
122
|
+
errors.push(`Group ${gid} has invalid status: ${group.status}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// f) Groups with a phase set must have that parent phase complete
|
|
126
|
+
for (const [gid, group] of Object.entries(groups)) {
|
|
127
|
+
const groupPhase = group.phase;
|
|
128
|
+
if (groupPhase) {
|
|
129
|
+
const parentCp = state.checkpoints[groupPhase];
|
|
130
|
+
if (!parentCp) {
|
|
131
|
+
errors.push(`Group ${gid} references unknown phase: ${groupPhase}`);
|
|
132
|
+
}
|
|
133
|
+
else if (parentCp.status !== "complete") {
|
|
134
|
+
errors.push(`Group ${gid} has phase ${groupPhase} but that phase is not yet complete`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// Validate current_phase if set
|
|
140
|
+
if (state.current_phase &&
|
|
141
|
+
state.current_phase !== "complete" &&
|
|
142
|
+
!VALID_PHASES.includes(state.current_phase)) {
|
|
143
|
+
warnings.push(`current_phase "${state.current_phase}" is not in the standard phase sequence`);
|
|
144
|
+
}
|
|
145
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Read and parse a goal state JSON file.
|
|
149
|
+
* @param statePath - Full path to the state file (e.g., `.aiws/goals/G-014.state.json`)
|
|
150
|
+
*/
|
|
151
|
+
export async function readGoalState(statePath) {
|
|
152
|
+
const content = await fs.readFile(statePath, "utf8");
|
|
153
|
+
return JSON.parse(content);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Atomically write a goal state to disk using tmp-file-then-rename.
|
|
157
|
+
* @param statePath - Full path to the state file to write
|
|
158
|
+
* @param state - The goal state to persist
|
|
159
|
+
*/
|
|
160
|
+
export async function writeGoalState(statePath, state) {
|
|
161
|
+
const dir = path.dirname(statePath);
|
|
162
|
+
const tmpId = crypto.randomBytes(4).toString("hex");
|
|
163
|
+
const tmpPath = path.join(dir, `.tmp-${tmpId}.json`);
|
|
164
|
+
const updated = {
|
|
165
|
+
...state,
|
|
166
|
+
updated_at: new Date().toISOString(),
|
|
167
|
+
};
|
|
168
|
+
await fs.writeFile(tmpPath, JSON.stringify(updated, null, 2), "utf8");
|
|
169
|
+
await fs.rename(tmpPath, statePath);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Determine the next phase in the goal state machine.
|
|
173
|
+
*
|
|
174
|
+
* Logic:
|
|
175
|
+
* 1. If current phase checkpoint is not `complete` → stay on that phase
|
|
176
|
+
* 2. If groups exist: walk groups in topological order; find first pending group
|
|
177
|
+
* and its first pending phase
|
|
178
|
+
* 3. If no groups: advance through the flat VALID_PHASES sequence
|
|
179
|
+
* 4. If all phases (and groups) are complete → signal done
|
|
180
|
+
*/
|
|
181
|
+
export function computeNextPhase(state) {
|
|
182
|
+
const currentPhase = state.current_phase ?? VALID_PHASES[0];
|
|
183
|
+
// Special case: "complete" current_phase means everything is done,
|
|
184
|
+
// or we treat it as all phases completed
|
|
185
|
+
if (currentPhase === "complete") {
|
|
186
|
+
// Check if there are still pending phases
|
|
187
|
+
for (const phase of VALID_PHASES) {
|
|
188
|
+
const cp = state.checkpoints[phase];
|
|
189
|
+
if (cp && cp.status !== "complete") {
|
|
190
|
+
return {
|
|
191
|
+
phase,
|
|
192
|
+
groupId: null,
|
|
193
|
+
done: false,
|
|
194
|
+
reason: `Current phase marked complete but phase ${phase} is still ${cp.status}`,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return { phase: "finish", groupId: null, done: true, reason: "All phases complete" };
|
|
199
|
+
}
|
|
200
|
+
// If current phase checkpoint is not complete, stay on it
|
|
201
|
+
const currentCp = state.checkpoints[currentPhase];
|
|
202
|
+
if (currentCp && currentCp.status !== "complete") {
|
|
203
|
+
return {
|
|
204
|
+
phase: currentPhase,
|
|
205
|
+
groupId: null,
|
|
206
|
+
done: false,
|
|
207
|
+
reason: "Current phase not yet complete",
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
// Pre-group phases: intake, goal_def, dep_check, ws_analysis
|
|
211
|
+
// These MUST all be completed in order before entering any group-based pipeline phase.
|
|
212
|
+
const PRE_GROUP_PHASES = VALID_PHASES.slice(0, VALID_PHASES.indexOf("plan"));
|
|
213
|
+
const groups = state.groups;
|
|
214
|
+
// Check if there are any incomplete pre-group phases
|
|
215
|
+
for (const phase of PRE_GROUP_PHASES) {
|
|
216
|
+
const cp = state.checkpoints[phase];
|
|
217
|
+
if (!cp || cp.status !== "complete") {
|
|
218
|
+
return {
|
|
219
|
+
phase,
|
|
220
|
+
groupId: null,
|
|
221
|
+
done: false,
|
|
222
|
+
reason: `Pre-group phase needs execution: ${phase}`,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// All pre-group phases are complete. If no groups, advance sequentially through remaining pipeline phases.
|
|
227
|
+
const currentIdx = VALID_PHASES.indexOf(currentPhase);
|
|
228
|
+
if (!groups || Object.keys(groups).length === 0) {
|
|
229
|
+
if (currentIdx < VALID_PHASES.length - 1) {
|
|
230
|
+
const nextPhase = VALID_PHASES[currentIdx + 1];
|
|
231
|
+
return {
|
|
232
|
+
phase: nextPhase,
|
|
233
|
+
groupId: null,
|
|
234
|
+
done: false,
|
|
235
|
+
reason: `Advancing to next phase: ${nextPhase}`,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
// All flat phases complete
|
|
239
|
+
return { phase: currentPhase, groupId: null, done: true, reason: "All phases complete" };
|
|
240
|
+
}
|
|
241
|
+
// Groups exist: walk in topological order, find first pending group
|
|
242
|
+
const sorted = topologicalSort(groups);
|
|
243
|
+
for (const gid of sorted) {
|
|
244
|
+
const group = groups[gid];
|
|
245
|
+
if (!group)
|
|
246
|
+
continue;
|
|
247
|
+
if (group.status !== "complete") {
|
|
248
|
+
// Group is not complete — find its first pending phase
|
|
249
|
+
// Groups use the plan/dev/review/finish sub-sequence
|
|
250
|
+
const groupPhases = ["plan", "dev", "review", "finish"];
|
|
251
|
+
for (const phase of groupPhases) {
|
|
252
|
+
const cp = state.checkpoints[phase];
|
|
253
|
+
if (!cp || cp.status !== "complete") {
|
|
254
|
+
return {
|
|
255
|
+
phase,
|
|
256
|
+
groupId: gid,
|
|
257
|
+
done: false,
|
|
258
|
+
reason: `Group ${gid} needs phase ${phase}`,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
// All group phases done but group not marked complete
|
|
263
|
+
return {
|
|
264
|
+
phase: "finish",
|
|
265
|
+
groupId: gid,
|
|
266
|
+
done: false,
|
|
267
|
+
reason: `Group ${gid} phases done but group not marked complete`,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
// All groups complete
|
|
272
|
+
return { phase: currentPhase, groupId: null, done: true, reason: "All groups complete" };
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Topological sort of groups by dependency DAG.
|
|
276
|
+
* Returns group IDs in dependency order (dependencies first).
|
|
277
|
+
*/
|
|
278
|
+
function topologicalSort(groups) {
|
|
279
|
+
const sorted = [];
|
|
280
|
+
const visited = new Set();
|
|
281
|
+
const visiting = new Set();
|
|
282
|
+
function visit(node) {
|
|
283
|
+
if (visited.has(node))
|
|
284
|
+
return;
|
|
285
|
+
if (visiting.has(node))
|
|
286
|
+
return; // cycle protection
|
|
287
|
+
visiting.add(node);
|
|
288
|
+
const g = groups[node];
|
|
289
|
+
if (g) {
|
|
290
|
+
const deps = g.dependencies;
|
|
291
|
+
if (deps && Array.isArray(deps)) {
|
|
292
|
+
for (const dep of deps) {
|
|
293
|
+
visit(dep);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
visiting.delete(node);
|
|
298
|
+
visited.add(node);
|
|
299
|
+
sorted.push(node);
|
|
300
|
+
}
|
|
301
|
+
for (const id of Object.keys(groups)) {
|
|
302
|
+
visit(id);
|
|
303
|
+
}
|
|
304
|
+
return sorted;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Per-phase guidance descriptions for AI consumption.
|
|
308
|
+
* Maps each VALID_PHASE to a brief "what to do in this phase" instruction.
|
|
309
|
+
*/
|
|
310
|
+
export const PHASE_GUIDANCE = {
|
|
311
|
+
intake: "Run workspace context scan (diff/log/branch/stash), then run the intake workflow: ask clarifying questions to identify scope, boundaries, constraints, and acceptance criteria. Output an intake draft to .aiws/plan/.",
|
|
312
|
+
goal_def: "Define the goal objective: write `.aiws/goals/<goal-id>.md` with target base branch, dependency chain, scope, boundaries, and verification criteria. Create `.aiws/goals/<goal-id>.state.json` with `status=active`.",
|
|
313
|
+
dep_check: "Check upstream dependency chain health: examine each change branch between current and main. Verify artifact completeness (proposal/tasks/design exist), task completion rate, review status (no HIGH blockers), and truth drift (`aiws validate .`).",
|
|
314
|
+
ws_analysis: "Analyze workspace state for conflicts: check dirty files (`git diff --stat`), submodule status, existing change artifacts (`git branch --list 'change/*'`), unpushed commits, stash. Classify each item as HIGH/MED/LOW/NONE. HIGH items block progress until user resolves.",
|
|
315
|
+
plan: "Create execution plan: run `aiws change start <goal-id> --allow-dirty` to create change branch, then write proposal.md and plan file, then run plan-verify. Do NOT implement code.",
|
|
316
|
+
dev: "Implement the plan: write code per the plan/spec. Verify with `lsp_diagnostics` on changed files. Ensure lints and type checks pass. Do NOT commit or create PR.",
|
|
317
|
+
review: "Review implementation: audit code quality, verify requirements coverage, check for HIGH blockers, validate against acceptance criteria. Produce evidence files (review/review.md, review/findings.csv). Do NOT modify code.",
|
|
318
|
+
finish: "Complete the change: commit changes (follow commit conventions), merge change branch to target, push. Update goal state to `status=complete`.",
|
|
319
|
+
};
|
|
320
|
+
/**
|
|
321
|
+
* Get next-actions guidance for the current phase of a goal state.
|
|
322
|
+
* Returns a structured description telling the AI what to do next.
|
|
323
|
+
*/
|
|
324
|
+
export function getPhaseGuidance(goalId, state) {
|
|
325
|
+
const phase = state.current_phase ?? VALID_PHASES[0];
|
|
326
|
+
const baseDesc = PHASE_GUIDANCE[phase] ?? "Unknown phase — refer to ws-goal-contract.md";
|
|
327
|
+
const blockers = [];
|
|
328
|
+
const cp = state.checkpoints[phase];
|
|
329
|
+
if (cp?.status === "complete") {
|
|
330
|
+
return {
|
|
331
|
+
phase,
|
|
332
|
+
description: "Current phase already complete. Run `aiws goal advance` to move to the next phase.",
|
|
333
|
+
needsUserInput: false,
|
|
334
|
+
blockers: [],
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
if (phase === "dep_check" || phase === "ws_analysis") {
|
|
338
|
+
const depCp = state.checkpoints["dep_check"];
|
|
339
|
+
if (depCp?.status === "failed") {
|
|
340
|
+
blockers.push("Dependency chain check failed — user must resolve upstream issues");
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return {
|
|
344
|
+
phase,
|
|
345
|
+
description: baseDesc.replace(/<goal-id>/g, goalId),
|
|
346
|
+
needsUserInput: blockers.length > 0,
|
|
347
|
+
blockers,
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Collect pending (non-complete) phases from checkpoints.
|
|
352
|
+
*/
|
|
353
|
+
export function listPendingPhases(state) {
|
|
354
|
+
const pending = [];
|
|
355
|
+
for (const phase of VALID_PHASES) {
|
|
356
|
+
const cp = state.checkpoints[phase];
|
|
357
|
+
if (!cp || cp.status !== "complete") {
|
|
358
|
+
pending.push(phase);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return pending;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Find all goal state files in a directory.
|
|
365
|
+
* Scans for `*.state.json` files.
|
|
366
|
+
*/
|
|
367
|
+
export async function scanGoalStateFiles(goalDir) {
|
|
368
|
+
let entries;
|
|
369
|
+
try {
|
|
370
|
+
entries = await fs.readdir(goalDir);
|
|
371
|
+
}
|
|
372
|
+
catch {
|
|
373
|
+
return [];
|
|
374
|
+
}
|
|
375
|
+
const files = [];
|
|
376
|
+
for (const entry of entries) {
|
|
377
|
+
if (entry.endsWith(".state.json") && !entry.startsWith(".tmp-")) {
|
|
378
|
+
files.push(path.join(goalDir, entry));
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
return files.sort();
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Resolve a goal state file path from a directory and optional goal ID.
|
|
385
|
+
* If goalId is provided, returns the path to `<goalId>.state.json`.
|
|
386
|
+
* If not provided and exactly one `.state.json` exists, returns that path.
|
|
387
|
+
*/
|
|
388
|
+
export async function resolveGoalStatePath(goalDir, goalId) {
|
|
389
|
+
if (goalId) {
|
|
390
|
+
const p = path.join(goalDir, `${goalId}.state.json`);
|
|
391
|
+
if (await pathExists(p)) {
|
|
392
|
+
return p;
|
|
393
|
+
}
|
|
394
|
+
return null;
|
|
395
|
+
}
|
|
396
|
+
// No goalId: find active goal (status=active) or the newest state file
|
|
397
|
+
const files = await scanGoalStateFiles(goalDir);
|
|
398
|
+
if (files.length === 0)
|
|
399
|
+
return null;
|
|
400
|
+
// Prefer a goal with active status
|
|
401
|
+
for (const f of files) {
|
|
402
|
+
try {
|
|
403
|
+
const state = await readGoalState(f);
|
|
404
|
+
if (state.status === "active") {
|
|
405
|
+
return f;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
catch {
|
|
409
|
+
// skip unreadable files
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
// Fall back to the most recently modified file
|
|
413
|
+
let best = files[0];
|
|
414
|
+
let bestMtime = 0;
|
|
415
|
+
for (const f of files) {
|
|
416
|
+
try {
|
|
417
|
+
const st = await fs.stat(f);
|
|
418
|
+
if (st.mtimeMs > bestMtime) {
|
|
419
|
+
bestMtime = st.mtimeMs;
|
|
420
|
+
best = f;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
catch {
|
|
424
|
+
// skip
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
return best;
|
|
428
|
+
}
|
|
429
|
+
//# sourceMappingURL=goal-validate-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"goal-validate-state.js","sourceRoot":"","sources":["../../src/commands/goal-validate-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface GoalValidateStateOptions {
|
|
2
|
+
/** Directory containing goal state files (e.g., `.aiws/goals/`) */
|
|
3
|
+
goalDir: string;
|
|
4
|
+
/** Optional goal ID. If omitted, validate all goals */
|
|
5
|
+
goalId?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* `aiws goal validate-state` command handler.
|
|
9
|
+
*
|
|
10
|
+
* Validates one or all goal state files and reports errors/warnings.
|
|
11
|
+
* Exit code 0 if all valid, 1 if any errors found.
|
|
12
|
+
*/
|
|
13
|
+
export declare function goalValidateStateCommand(options: GoalValidateStateOptions): Promise<{
|
|
14
|
+
ok: boolean;
|
|
15
|
+
output: string;
|
|
16
|
+
}>;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { readGoalState, validateGoalState, scanGoalStateFiles, resolveGoalStatePath, } from "./goal-validate-state.js";
|
|
2
|
+
/**
|
|
3
|
+
* `aiws goal validate-state` command handler.
|
|
4
|
+
*
|
|
5
|
+
* Validates one or all goal state files and reports errors/warnings.
|
|
6
|
+
* Exit code 0 if all valid, 1 if any errors found.
|
|
7
|
+
*/
|
|
8
|
+
export async function goalValidateStateCommand(options) {
|
|
9
|
+
if (options.goalId) {
|
|
10
|
+
return validateSingleGoal(options.goalDir, options.goalId);
|
|
11
|
+
}
|
|
12
|
+
return validateAllGoals(options.goalDir);
|
|
13
|
+
}
|
|
14
|
+
async function validateSingleGoal(goalDir, goalId) {
|
|
15
|
+
const statePath = await resolveGoalStatePath(goalDir, goalId);
|
|
16
|
+
if (!statePath) {
|
|
17
|
+
return {
|
|
18
|
+
ok: false,
|
|
19
|
+
output: `Goal state file not found for "${goalId}" in ${goalDir}`,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
let state;
|
|
23
|
+
try {
|
|
24
|
+
state = await readGoalState(statePath);
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
return {
|
|
28
|
+
ok: false,
|
|
29
|
+
output: `Failed to read ${statePath}: ${String(err)}`,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const result = validateGoalState(state);
|
|
33
|
+
const lines = [];
|
|
34
|
+
lines.push(`Goal: ${state.goal_id || goalId}`);
|
|
35
|
+
lines.push(` File: ${statePath}`);
|
|
36
|
+
lines.push(` Status: ${result.valid ? "PASS" : "FAIL"}`);
|
|
37
|
+
if (result.errors.length > 0) {
|
|
38
|
+
lines.push(` Errors (${result.errors.length}):`);
|
|
39
|
+
for (const err of result.errors) {
|
|
40
|
+
lines.push(` - ${err}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (result.warnings.length > 0) {
|
|
44
|
+
lines.push(` Warnings (${result.warnings.length}):`);
|
|
45
|
+
for (const warn of result.warnings) {
|
|
46
|
+
lines.push(` - ${warn}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
ok: result.valid,
|
|
51
|
+
output: lines.join("\n"),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
async function validateAllGoals(goalDir) {
|
|
55
|
+
const files = await scanGoalStateFiles(goalDir);
|
|
56
|
+
if (files.length === 0) {
|
|
57
|
+
return {
|
|
58
|
+
ok: true,
|
|
59
|
+
output: `No goal state files found in ${goalDir}`,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
const lines = [];
|
|
63
|
+
let hasErrors = false;
|
|
64
|
+
let totalGoals = 0;
|
|
65
|
+
let passed = 0;
|
|
66
|
+
let failed = 0;
|
|
67
|
+
for (const file of files) {
|
|
68
|
+
totalGoals++;
|
|
69
|
+
let state;
|
|
70
|
+
try {
|
|
71
|
+
state = await readGoalState(file);
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
lines.push(`[FAIL] ${file}: Failed to read: ${String(err)}`);
|
|
75
|
+
failed++;
|
|
76
|
+
hasErrors = true;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const result = validateGoalState(state);
|
|
80
|
+
const goalLabel = state.goal_id || file;
|
|
81
|
+
if (result.valid) {
|
|
82
|
+
lines.push(`[PASS] ${goalLabel}${result.warnings.length > 0 ? ` (${result.warnings.length} warnings)` : ""}`);
|
|
83
|
+
passed++;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
lines.push(`[FAIL] ${goalLabel}: ${result.errors.length} error(s)`);
|
|
87
|
+
for (const err of result.errors) {
|
|
88
|
+
lines.push(` - ${err}`);
|
|
89
|
+
}
|
|
90
|
+
failed++;
|
|
91
|
+
hasErrors = true;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
lines.push(`\nSummary: ${totalGoals} goal(s) — ${passed} passed, ${failed} failed`);
|
|
95
|
+
return {
|
|
96
|
+
ok: !hasErrors,
|
|
97
|
+
output: lines.join("\n"),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=goal-validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"goal-validate.js","sourceRoot":"","sources":["../../src/commands/goal-validate.ts"],"names":[],"mappings":"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"}
|