@jakkrichm/create-nexus-devflow 2.9.4 → 2.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +3 -3
  2. package/dist/lib/dashboard-page.d.ts +1 -1
  3. package/dist/lib/dashboard-page.js +5 -1
  4. package/dist/lib/dashboard-page.js.map +1 -1
  5. package/dist/lib/project-config.d.ts +2 -0
  6. package/dist/lib/project-config.js +5 -2
  7. package/dist/lib/project-config.js.map +1 -1
  8. package/dist/lib/review.d.ts +38 -0
  9. package/dist/lib/review.js +429 -0
  10. package/dist/lib/review.js.map +1 -0
  11. package/dist/lib/status.d.ts +19 -2
  12. package/dist/lib/status.js +83 -15
  13. package/dist/lib/status.js.map +1 -1
  14. package/package.json +1 -1
  15. package/template/.agents/skills/audit/SKILL.md +119 -144
  16. package/template/.agents/skills/audit/reference/independent-review.md +128 -0
  17. package/template/.agents/skills/autopilot/SKILL.md +22 -1
  18. package/template/.agents/skills/browser-tests/SKILL.md +163 -0
  19. package/template/.agents/skills/check/SKILL.md +32 -23
  20. package/template/.agents/skills/complete/SKILL.md +28 -39
  21. package/template/.agents/skills/continuous/SKILL.md +12 -0
  22. package/template/.agents/skills/doctor/SKILL.md +8 -4
  23. package/template/.agents/skills/feature/SKILL.md +22 -1
  24. package/template/.agents/skills/implement/SKILL.md +21 -1
  25. package/template/.agents/skills/onboard/SKILL.md +17 -1
  26. package/template/.agents/skills/status/SKILL.md +12 -1
  27. package/template/.agents/skills/tests/SKILL.md +1 -1
  28. package/template/.agents/skills/try/SKILL.md +9 -24
  29. package/template/.claude/skills/audit/SKILL.md +119 -144
  30. package/template/.claude/skills/audit/reference/independent-review.md +128 -0
  31. package/template/.claude/skills/autopilot/SKILL.md +22 -1
  32. package/template/.claude/skills/browser-tests/SKILL.md +163 -0
  33. package/template/.claude/skills/check/SKILL.md +32 -23
  34. package/template/.claude/skills/complete/SKILL.md +28 -39
  35. package/template/.claude/skills/continuous/SKILL.md +12 -0
  36. package/template/.claude/skills/doctor/SKILL.md +9 -4
  37. package/template/.claude/skills/feature/SKILL.md +22 -1
  38. package/template/.claude/skills/implement/SKILL.md +21 -1
  39. package/template/.claude/skills/onboard/SKILL.md +17 -1
  40. package/template/.claude/skills/status/SKILL.md +12 -1
  41. package/template/.claude/skills/tests/SKILL.md +1 -1
  42. package/template/.claude/skills/try/SKILL.md +9 -24
  43. package/template/AGENTS.md +4 -4
  44. package/template/devflow/build-plan.md +6 -0
  45. package/template/devflow/config.json +2 -0
  46. package/template/devflow/context/coding-standards.md +8 -1
@@ -0,0 +1,429 @@
1
+ import { execFile } from "node:child_process";
2
+ import { createHash } from "node:crypto";
3
+ import fs from "node:fs/promises";
4
+ import path from "node:path";
5
+ import { promisify } from "node:util";
6
+ const DEFAULT_REVIEW_PATH = path.join("devflow", "context", "review.md");
7
+ const RESET_MARKER = "_No independent review requested.";
8
+ const FULL_SHA_PATTERN = /^[0-9a-f]{40}$/;
9
+ const HASH_PATTERN = /^[0-9a-f]{64}$/;
10
+ const BASE_REF_PATTERN = /^(?!.*(?:\.\.|\/\/|@\{))[A-Za-z0-9](?:[A-Za-z0-9._/-]*[A-Za-z0-9])?$/;
11
+ const FIELD_PATTERN = /^\*\*([^*]+):\*\*\s*(.*?)\s*$/;
12
+ const RUNTIME_DEFAULT_MODEL = "runtime default (exact model not known until reviewer starts)";
13
+ const execFileAsync = promisify(execFile);
14
+ async function resolveReviewPaths(projectRoot, taskSlug) {
15
+ if (taskSlug) {
16
+ const taskDir = path.join(projectRoot, "devflow", "context", taskSlug);
17
+ return {
18
+ reviewPath: path.join(taskDir, "review.md"),
19
+ specPath: path.join(taskDir, "spec.md"),
20
+ findingsPath: path.join(taskDir, "findings.md")
21
+ };
22
+ }
23
+ // Check if there are active task directories in devflow/context/{xxx-slug}/
24
+ const contextDir = path.join(projectRoot, "devflow", "context");
25
+ try {
26
+ const entries = await fs.readdir(contextDir, { withFileTypes: true });
27
+ const taskDirs = entries.filter((e) => e.isDirectory() && !e.name.startsWith("."));
28
+ if (taskDirs.length === 1 && taskDirs[0]) {
29
+ const taskDir = path.join(contextDir, taskDirs[0].name);
30
+ return {
31
+ reviewPath: path.join(taskDir, "review.md"),
32
+ specPath: path.join(taskDir, "spec.md"),
33
+ findingsPath: path.join(taskDir, "findings.md")
34
+ };
35
+ }
36
+ }
37
+ catch {
38
+ // Ignore and fallback
39
+ }
40
+ return {
41
+ reviewPath: path.join(projectRoot, DEFAULT_REVIEW_PATH),
42
+ specPath: path.join(projectRoot, "devflow", "context", "current-feature.md"),
43
+ findingsPath: path.join(projectRoot, "devflow", "context", "findings.md")
44
+ };
45
+ }
46
+ async function readIndependentReview(projectRoot, taskSlug) {
47
+ const { reviewPath, specPath, findingsPath } = await resolveReviewPaths(projectRoot, taskSlug);
48
+ try {
49
+ const stats = await fs.lstat(reviewPath);
50
+ if (stats.isSymbolicLink()) {
51
+ return malformedSummary({
52
+ code: "unsafe_review_path",
53
+ message: "Independent review file is a symbolic link and was not read."
54
+ });
55
+ }
56
+ if (!stats.isFile()) {
57
+ return malformedSummary({
58
+ code: "invalid_review_path",
59
+ message: "Independent review path is not a regular file."
60
+ });
61
+ }
62
+ const parsed = parseIndependentReview(await fs.readFile(reviewPath, "utf8"));
63
+ if (parsed.state === "none" || parsed.state === "malformed") {
64
+ return parsed;
65
+ }
66
+ return {
67
+ ...parsed,
68
+ freshness: await determineFreshness(projectRoot, parsed, specPath, reviewPath, findingsPath)
69
+ };
70
+ }
71
+ catch (error) {
72
+ if (getErrorCode(error) === "ENOENT") {
73
+ return emptySummary();
74
+ }
75
+ throw error;
76
+ }
77
+ }
78
+ function parseIndependentReview(markdown) {
79
+ if (markdown.includes(RESET_MARKER) && !/^\*\*Status:\*\*/m.test(markdown)) {
80
+ return emptySummary();
81
+ }
82
+ const fields = new Map();
83
+ for (const line of markdown.split(/\r?\n/)) {
84
+ const match = line.match(FIELD_PATTERN);
85
+ if (match?.[1]) {
86
+ fields.set(normalizeLabel(match[1]), (match[2] || "").trim());
87
+ }
88
+ }
89
+ const state = normalizeState(fields.get("status"));
90
+ const targetCommit = normalizeHash(fields.get("target commit"), FULL_SHA_PATTERN);
91
+ const baseCommit = normalizeHash(fields.get("base commit"), FULL_SHA_PATTERN);
92
+ const baseRef = normalizeBaseRef(fields.get("base ref"));
93
+ const specHash = normalizeHash(fields.get("spec hash"), HASH_PATTERN);
94
+ const preparedBy = normalizeAdapter(fields.get("prepared by"));
95
+ const builderModel = normalizeText(fields.get("builder model"));
96
+ const requestedReviewer = normalizeAdapter(fields.get("requested reviewer"));
97
+ const requestedModel = normalizeText(fields.get("requested model"));
98
+ const requestedAt = normalizeTimestamp(fields.get("requested at"));
99
+ const workflow = normalizeWorkflow(fields.get("workflow"));
100
+ const checkRequired = normalizeBoolean(fields.get("check required"));
101
+ const reviewerAdapter = normalizeAdapter(fields.get("reviewer adapter"));
102
+ const reviewerModel = normalizeReviewerModel(fields.get("reviewer model"));
103
+ const reviewerContext = normalizeText(fields.get("reviewer context"));
104
+ const reviewedAt = normalizeText(fields.get("reviewed at"));
105
+ const scope = normalizeText(fields.get("scope"));
106
+ const lenses = normalizeLenses(fields.get("lenses"));
107
+ const verdict = normalizeVerdict(fields.get("verdict"));
108
+ const checkResult = normalizeCheckResult(fields.get("check result"));
109
+ const completedSectionsValid = [
110
+ "commands",
111
+ "evidence",
112
+ "findings",
113
+ "remaining risk"
114
+ ].every((heading) => readSection(markdown, heading) !== null);
115
+ const commonFieldsValid = state !== null &&
116
+ targetCommit !== null &&
117
+ baseCommit !== null &&
118
+ baseRef !== null &&
119
+ specHash !== null &&
120
+ preparedBy !== null &&
121
+ builderModel !== null &&
122
+ requestedReviewer !== null &&
123
+ requestedModel !== null &&
124
+ requestedAt !== null &&
125
+ workflow !== null &&
126
+ checkRequired !== null;
127
+ const completedFieldsValid = reviewerAdapter !== null &&
128
+ reviewerModel !== null &&
129
+ reviewerContext?.toLowerCase() === "fresh session" &&
130
+ normalizeTimestamp(reviewedAt || undefined) !== null &&
131
+ (scope?.toLowerCase() === "current" || scope?.toLowerCase() === "current-feature") &&
132
+ ["quality", "security", "performance", "tests"].every((lens) => lenses.includes(lens)) &&
133
+ verdict === state &&
134
+ checkResult !== null &&
135
+ completedSectionsValid &&
136
+ (state !== "passed" || !checkRequired || checkResult === "passed") &&
137
+ (state !== "passed" || checkRequired || checkResult === "not-required" || checkResult === "passed");
138
+ if (!commonFieldsValid ||
139
+ ((state === "passed" || state === "changes-requested") && !completedFieldsValid)) {
140
+ return malformedSummary({
141
+ code: "malformed_review",
142
+ message: "Independent review record is missing or has invalid required fields."
143
+ });
144
+ }
145
+ return {
146
+ state,
147
+ freshness: "unknown",
148
+ targetCommit,
149
+ baseCommit,
150
+ baseRef,
151
+ specHash,
152
+ preparedBy,
153
+ builderModel,
154
+ requestedReviewer,
155
+ requestedModel,
156
+ requestedAt,
157
+ workflow,
158
+ checkRequired,
159
+ reviewerAdapter,
160
+ reviewerModel,
161
+ reviewerContext,
162
+ reviewedAt,
163
+ scope,
164
+ lenses,
165
+ verdict,
166
+ checkResult,
167
+ warnings: []
168
+ };
169
+ }
170
+ async function determineFreshness(projectRoot, review, specPath, reviewPath, findingsPath) {
171
+ if (!review.targetCommit || !review.baseCommit || !review.baseRef || !review.specHash) {
172
+ return "unknown";
173
+ }
174
+ if (review.reviewerAdapter &&
175
+ review.requestedReviewer &&
176
+ review.reviewerAdapter !== review.requestedReviewer) {
177
+ return "stale";
178
+ }
179
+ if (review.reviewerModel &&
180
+ review.requestedModel &&
181
+ review.requestedModel !== RUNTIME_DEFAULT_MODEL &&
182
+ review.reviewerModel !== review.requestedModel) {
183
+ return "stale";
184
+ }
185
+ const [head, currentWork, mergeBase, permittedBaseRefs] = await Promise.all([
186
+ runOptionalGit(projectRoot, ["rev-parse", "HEAD"]),
187
+ readOptionalRegularFile(specPath),
188
+ runOptionalGit(projectRoot, [
189
+ "merge-base",
190
+ review.baseRef,
191
+ review.targetCommit
192
+ ]),
193
+ readPermittedBaseRefs(projectRoot)
194
+ ]);
195
+ if (!head || currentWork === null) {
196
+ return "unknown";
197
+ }
198
+ if (review.baseCommit === review.targetCommit ||
199
+ !permittedBaseRefs.has(review.baseRef) ||
200
+ mergeBase !== review.baseCommit) {
201
+ return "stale";
202
+ }
203
+ const currentSpecHash = createHash("sha256").update(currentWork).digest("hex");
204
+ if (head !== review.targetCommit || currentSpecHash !== review.specHash) {
205
+ return "stale";
206
+ }
207
+ const relReviewPath = path.relative(projectRoot, reviewPath).replace(/\\/g, "/");
208
+ const relFindingsPath = path.relative(projectRoot, findingsPath).replace(/\\/g, "/");
209
+ const relevantDiff = await hasRelevantDiff(projectRoot, review.targetCommit, relReviewPath, relFindingsPath);
210
+ return relevantDiff === null ? "unknown" : relevantDiff ? "stale" : "current";
211
+ }
212
+ async function hasRelevantDiff(projectRoot, targetCommit, relReviewPath, relFindingsPath) {
213
+ try {
214
+ await execFileAsync("git", [
215
+ "-C",
216
+ projectRoot,
217
+ "diff",
218
+ "--quiet",
219
+ targetCommit,
220
+ "--",
221
+ ".",
222
+ `:(exclude)${relReviewPath}`,
223
+ `:(exclude)${relFindingsPath}`
224
+ ], { encoding: "utf8", maxBuffer: 1024 * 1024 });
225
+ }
226
+ catch (error) {
227
+ if (getErrorCode(error) === "1") {
228
+ return true;
229
+ }
230
+ return null;
231
+ }
232
+ const untracked = await runOptionalGit(projectRoot, [
233
+ "ls-files",
234
+ "--others",
235
+ "--exclude-standard",
236
+ "-z"
237
+ ]);
238
+ if (untracked === null) {
239
+ return null;
240
+ }
241
+ return untracked
242
+ .split("\0")
243
+ .filter(Boolean)
244
+ .some((file) => file !== relReviewPath && file !== relFindingsPath);
245
+ }
246
+ async function readOptionalRegularFile(filePath) {
247
+ try {
248
+ const stats = await fs.lstat(filePath);
249
+ if (stats.isSymbolicLink() || !stats.isFile()) {
250
+ return null;
251
+ }
252
+ return await fs.readFile(filePath, "utf8");
253
+ }
254
+ catch (error) {
255
+ if (getErrorCode(error) === "ENOENT") {
256
+ return null;
257
+ }
258
+ throw error;
259
+ }
260
+ }
261
+ async function runOptionalGit(projectRoot, args) {
262
+ try {
263
+ const result = await execFileAsync("git", ["-C", projectRoot, ...args], {
264
+ encoding: "utf8",
265
+ maxBuffer: 1024 * 1024
266
+ });
267
+ return result.stdout.trim();
268
+ }
269
+ catch {
270
+ return null;
271
+ }
272
+ }
273
+ async function readPermittedBaseRefs(projectRoot) {
274
+ const refs = new Set();
275
+ const remotes = await runOptionalGit(projectRoot, ["remote"]);
276
+ for (const remote of remotes?.split(/\r?\n/).filter(Boolean) || []) {
277
+ const remoteDefault = await runOptionalGit(projectRoot, [
278
+ "symbolic-ref",
279
+ "--quiet",
280
+ "--short",
281
+ `refs/remotes/${remote}/HEAD`
282
+ ]);
283
+ if (remoteDefault) {
284
+ refs.add(remoteDefault);
285
+ }
286
+ }
287
+ for (const localDefault of ["main", "master"]) {
288
+ if (await runOptionalGit(projectRoot, [
289
+ "rev-parse",
290
+ "--verify",
291
+ `${localDefault}^{commit}`
292
+ ])) {
293
+ refs.add(localDefault);
294
+ }
295
+ }
296
+ return refs;
297
+ }
298
+ function normalizeLabel(value) {
299
+ return value.trim().toLowerCase();
300
+ }
301
+ function normalizeState(value) {
302
+ const normalized = value?.trim().toLowerCase();
303
+ return normalized === "pending" ||
304
+ normalized === "passed" ||
305
+ normalized === "changes-requested"
306
+ ? normalized
307
+ : null;
308
+ }
309
+ function normalizeAdapter(value) {
310
+ const normalized = value?.trim().toLowerCase();
311
+ return normalized === "antigravity" ||
312
+ normalized === "claude" ||
313
+ normalized === "codex" ||
314
+ normalized === "copilot" ||
315
+ normalized === "opencode"
316
+ ? normalized
317
+ : null;
318
+ }
319
+ function normalizeHash(value, pattern) {
320
+ const normalized = value?.trim().toLowerCase() || "";
321
+ return pattern.test(normalized) ? normalized : null;
322
+ }
323
+ function normalizeBaseRef(value) {
324
+ const normalized = value?.trim() || "";
325
+ return BASE_REF_PATTERN.test(normalized) ? normalized : null;
326
+ }
327
+ function normalizeText(value) {
328
+ const normalized = value?.trim();
329
+ return normalized ? normalized : null;
330
+ }
331
+ function normalizeReviewerModel(value) {
332
+ const normalized = normalizeText(value);
333
+ return normalized === RUNTIME_DEFAULT_MODEL ? null : normalized;
334
+ }
335
+ function normalizeTimestamp(value) {
336
+ const normalized = normalizeText(value);
337
+ return normalized && !Number.isNaN(Date.parse(normalized)) ? normalized : null;
338
+ }
339
+ function normalizeWorkflow(value) {
340
+ const normalized = value?.trim().toLowerCase();
341
+ return normalized === "continuous" || normalized === "regular"
342
+ ? normalized
343
+ : null;
344
+ }
345
+ function normalizeBoolean(value) {
346
+ const normalized = value?.trim().toLowerCase();
347
+ return normalized === "yes" ? true : normalized === "no" ? false : null;
348
+ }
349
+ function normalizeLenses(value) {
350
+ return value
351
+ ? value.split(",").map((lens) => lens.trim().toLowerCase()).filter(Boolean)
352
+ : [];
353
+ }
354
+ function normalizeVerdict(value) {
355
+ const normalized = value?.trim().toLowerCase();
356
+ return normalized === "changes-requested" || normalized === "passed"
357
+ ? normalized
358
+ : null;
359
+ }
360
+ function normalizeCheckResult(value) {
361
+ const normalized = value?.trim().toLowerCase();
362
+ return normalized === "failed" ||
363
+ normalized === "not-required" ||
364
+ normalized === "passed" ||
365
+ normalized === "unavailable"
366
+ ? normalized
367
+ : null;
368
+ }
369
+ function readSection(markdown, heading) {
370
+ const lines = markdown.split(/\r?\n/);
371
+ const start = lines.findIndex((line) => line.trim().toLowerCase() === `## ${heading}`);
372
+ if (start === -1) {
373
+ return null;
374
+ }
375
+ const content = [];
376
+ for (let index = start + 1; index < lines.length; index += 1) {
377
+ const line = lines[index] || "";
378
+ if (/^##\s+/.test(line)) {
379
+ break;
380
+ }
381
+ content.push(line);
382
+ }
383
+ const normalized = content.join("\n").trim();
384
+ return normalized ? normalized : null;
385
+ }
386
+ function emptySummary() {
387
+ return {
388
+ state: "none",
389
+ freshness: "not-applicable",
390
+ targetCommit: null,
391
+ baseCommit: null,
392
+ baseRef: null,
393
+ specHash: null,
394
+ preparedBy: null,
395
+ builderModel: null,
396
+ requestedReviewer: null,
397
+ requestedModel: null,
398
+ requestedAt: null,
399
+ workflow: null,
400
+ checkRequired: null,
401
+ reviewerAdapter: null,
402
+ reviewerModel: null,
403
+ reviewerContext: null,
404
+ reviewedAt: null,
405
+ scope: null,
406
+ lenses: [],
407
+ verdict: null,
408
+ checkResult: null,
409
+ warnings: []
410
+ };
411
+ }
412
+ function malformedSummary(warning) {
413
+ return {
414
+ ...emptySummary(),
415
+ state: "malformed",
416
+ freshness: "unknown",
417
+ warnings: [warning]
418
+ };
419
+ }
420
+ function getErrorCode(error) {
421
+ return typeof error === "object" &&
422
+ error !== null &&
423
+ "code" in error &&
424
+ (typeof error.code === "string" || typeof error.code === "number")
425
+ ? String(error.code)
426
+ : undefined;
427
+ }
428
+ export { DEFAULT_REVIEW_PATH, parseIndependentReview, readIndependentReview };
429
+ //# sourceMappingURL=review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review.js","sourceRoot":"","sources":["../../lib/review.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,7 @@ import type { ProjectAdapter } from "./project-metadata.js";
6
6
  import type { IdeasSummary } from "./ideas.js";
7
7
  import type { ProjectConfig, ProjectConfigState } from "./project-config.js";
8
8
  import type { RunStateSummary } from "./run-state.js";
9
+ import type { ReviewCheckResult, ReviewFreshness, ReviewState } from "./review.js";
9
10
  type CompletionState = "blocked" | "needs_verification" | "ready";
10
11
  interface StatusWarning {
11
12
  code: string;
@@ -36,6 +37,21 @@ interface StatusFindings {
36
37
  active: Array<Pick<Finding, "id" | "severity" | "status" | "title">>;
37
38
  blockers: Array<Pick<Finding, "id" | "severity" | "status" | "title">>;
38
39
  }
40
+ interface StatusReview {
41
+ state: ReviewState;
42
+ freshness: ReviewFreshness;
43
+ verdict: "changes-requested" | "passed" | null;
44
+ checkResult: ReviewCheckResult | null;
45
+ targetCommit: string | null;
46
+ requestedReviewer: string | null;
47
+ requestedModel: string | null;
48
+ reviewerAdapter: string | null;
49
+ reviewerModel: string | null;
50
+ warnings: StatusWarning[];
51
+ }
52
+ interface StatusActiveRun extends ActiveRunSummary {
53
+ review: StatusReview;
54
+ }
39
55
  interface StatusNextAction {
40
56
  command: string | null;
41
57
  reason: string;
@@ -61,8 +77,9 @@ interface ProjectStatus {
61
77
  configuration: StatusConfiguration;
62
78
  activity: StatusActivity;
63
79
  currentWork: StatusCurrentWork;
64
- activeRuns: ActiveRunSummary[];
80
+ activeRuns: StatusActiveRun[];
65
81
  findings: StatusFindings;
82
+ review: StatusReview;
66
83
  ideas: IdeasSummary;
67
84
  git: GitStatusSummary;
68
85
  completion: StatusCompletion;
@@ -73,4 +90,4 @@ declare function readProjectStatus(startPath?: string): Promise<ProjectStatus>;
73
90
  declare function formatHumanStatus(status: ProjectStatus, options?: HumanStatusOptions): string;
74
91
  declare function shouldUseColor(isTTY?: boolean | undefined, environment?: NodeJS.ProcessEnv): boolean;
75
92
  export { formatHumanStatus, readProjectStatus, shouldUseColor };
76
- export type { CompletionState, HumanStatusOptions, ProjectStatus, StatusActivity, StatusCompletion, StatusCurrentWork, StatusFindings, StatusNextAction, StatusWarning };
93
+ export type { CompletionState, HumanStatusOptions, ProjectStatus, StatusActivity, StatusActiveRun, StatusCompletion, StatusCurrentWork, StatusFindings, StatusNextAction, StatusWarning };
@@ -7,6 +7,7 @@ import { readProjectMetadata } from "./project-metadata.js";
7
7
  import { readIdeas } from "./ideas.js";
8
8
  import { readProjectConfig } from "./project-config.js";
9
9
  import { readRunState } from "./run-state.js";
10
+ import { readIndependentReview } from "./review.js";
10
11
  async function readProjectStatus(startPath = process.cwd()) {
11
12
  const metadata = await readProjectMetadata(startPath);
12
13
  const [contextPaths, config, currentWork, activeRuns, findings, git, ideas, runState] = await Promise.all([
@@ -19,6 +20,16 @@ async function readProjectStatus(startPath = process.cwd()) {
19
20
  readIdeas(metadata.project.root),
20
21
  readRunState(metadata.project.root)
21
22
  ]);
23
+ const primaryRunId = currentWork.runId || (activeRuns.length === 1 ? activeRuns[0]?.runId : undefined);
24
+ const [review, activeRunReviews] = await Promise.all([
25
+ readIndependentReview(metadata.project.root, primaryRunId || undefined),
26
+ Promise.all(activeRuns.map((run) => readIndependentReview(metadata.project.root, run.runId)))
27
+ ]);
28
+ const statusReview = formatReview(review);
29
+ const statusActiveRuns = activeRuns.map((run, index) => ({
30
+ ...run,
31
+ review: formatReview(activeRunReviews[index] || review)
32
+ }));
22
33
  let stageMarkdown = "";
23
34
  try {
24
35
  stageMarkdown = await fs.readFile(contextPaths.stagePath, "utf8");
@@ -30,9 +41,10 @@ async function readProjectStatus(startPath = process.cwd()) {
30
41
  ...currentWork.warnings,
31
42
  ...findings.warnings,
32
43
  ...runState.warnings,
44
+ ...review.warnings,
33
45
  ...findDrift(currentWork, git)
34
46
  ];
35
- const completion = selectCompletion(currentWork, findings, git, stageMarkdown);
47
+ const completion = selectCompletion(currentWork, findings, git, stageMarkdown, review, config.values);
36
48
  const nextAction = selectNextAction(currentWork, findings, stageMarkdown);
37
49
  return {
38
50
  schemaVersion: metadata.schemaVersion,
@@ -62,8 +74,9 @@ async function readProjectStatus(startPath = process.cwd()) {
62
74
  feature: runState.feature
63
75
  },
64
76
  currentWork: formatCurrentWork(currentWork),
65
- activeRuns,
77
+ activeRuns: statusActiveRuns,
66
78
  findings: formatFindings(findings),
79
+ review: statusReview,
67
80
  ideas,
68
81
  git,
69
82
  completion,
@@ -101,7 +114,11 @@ function formatHumanStatus(status, options = {}) {
101
114
  if (status.activeRuns && status.activeRuns.length > 0) {
102
115
  lines.push(formatRow("Spec Queue", `${status.activeRuns.length} active (${status.activeRuns.map((r) => r.runId).join(", ")})`, style));
103
116
  }
104
- lines.push(formatRow("Findings", formatFindingsValue(status.findings, style), style), formatRow("Completion", formatCompletionValue(status.completion, style), style), "", formatSection("Git", style));
117
+ lines.push(formatRow("Findings", formatFindingsValue(status.findings, style), style));
118
+ if (status.review && status.review.state !== "none") {
119
+ lines.push(formatRow("Review", formatReviewValue(status.review, style), style));
120
+ }
121
+ lines.push(formatRow("Completion", formatCompletionValue(status.completion, style), style), "", formatSection("Git", style));
105
122
  appendGitLines(lines, status.git, style);
106
123
  if (status.warnings.length > 0) {
107
124
  lines.push("", formatSection("Attention", style));
@@ -126,7 +143,7 @@ function formatConfigValue(state) {
126
143
  return "built-in defaults";
127
144
  }
128
145
  function formatQualityGates(gates) {
129
- return `audit ${gates.audit}, check ${gates.check}, try guide ${gates.tryGuide}`;
146
+ return `audit ${gates.audit}, review ${gates.independentReview}, check ${gates.check}, try guide ${gates.tryGuide}`;
130
147
  }
131
148
  function shouldUseColor(isTTY = process.stdout.isTTY, environment = process.env) {
132
149
  return isTTY === true && !Object.hasOwn(environment, "NO_COLOR");
@@ -137,6 +154,39 @@ function formatSection(label, style) {
137
154
  function formatRow(label, value, style) {
138
155
  return ` ${style.cyan(label.padEnd(14))}${value}`;
139
156
  }
157
+ function formatReviewValue(review, style) {
158
+ const parts = [review.state];
159
+ if (review.verdict) {
160
+ parts.push(`verdict ${review.verdict}`);
161
+ }
162
+ if (review.checkResult) {
163
+ parts.push(`check ${review.checkResult}`);
164
+ }
165
+ parts.push(`freshness ${review.freshness}`);
166
+ if (review.reviewerModel) {
167
+ parts.push(`(${review.reviewerModel})`);
168
+ }
169
+ return review.freshness === "stale"
170
+ ? style.yellow(parts.join(", "))
171
+ : parts.join(", ");
172
+ }
173
+ function formatReview(review) {
174
+ return {
175
+ state: review.state,
176
+ freshness: review.freshness,
177
+ verdict: review.verdict,
178
+ checkResult: review.checkResult,
179
+ targetCommit: review.targetCommit,
180
+ requestedReviewer: review.requestedReviewer,
181
+ requestedModel: review.requestedModel,
182
+ reviewerAdapter: review.reviewerAdapter,
183
+ reviewerModel: review.reviewerModel,
184
+ warnings: review.warnings.map((warning) => ({
185
+ code: warning.code,
186
+ message: warning.message
187
+ }))
188
+ };
189
+ }
140
190
  function formatActivityValue(activity, style) {
141
191
  if (activity.state !== "recorded" || !activity.command) {
142
192
  return style.dim("none");
@@ -186,22 +236,22 @@ function formatFindingsValue(findings, style) {
186
236
  }
187
237
  const activeCounts = [...activeGroups.entries()].map(([label, ids]) => `${ids.length} ${label} (${ids.join(", ")})`);
188
238
  const resolvedCounts = ["closed", "accepted", "invalid"]
189
- .filter((status) => findings.byStatus[status] > 0)
190
- .map((status) => `${findings.byStatus[status]} ${status}`);
191
- const value = [...activeCounts, ...resolvedCounts].join(", ");
192
- if (findings.blockers.length > 0) {
193
- return style.red(value);
194
- }
195
- return findings.active.length > 0 ? style.yellow(value) : style.green(value);
239
+ .map((status) => {
240
+ const count = findings.byStatus[status] || 0;
241
+ return count > 0 ? `${count} ${status}` : null;
242
+ })
243
+ .filter(Boolean);
244
+ const parts = [...activeCounts, ...resolvedCounts];
245
+ return parts.join(", ");
196
246
  }
197
247
  function formatCompletionValue(completion, style) {
198
248
  if (completion.state === "ready") {
199
- return style.green("ready");
249
+ return style.green("ready to complete");
200
250
  }
201
251
  if (completion.state === "needs_verification") {
202
- return style.yellow("needs verification");
252
+ return style.yellow(`needs verification (${completion.blockers.join("; ")})`);
203
253
  }
204
- return style.red(`blocked: ${completion.blockers.join("; ")}`);
254
+ return style.red(`blocked (${completion.blockers.join("; ")})`);
205
255
  }
206
256
  function appendGitLines(lines, git, style) {
207
257
  if (!git.available) {
@@ -267,7 +317,7 @@ function formatFindings(findings) {
267
317
  blockers: findings.blockers.map(selectFinding)
268
318
  };
269
319
  }
270
- function selectCompletion(currentWork, findings, git, stageMarkdown) {
320
+ function selectCompletion(currentWork, findings, git, stageMarkdown, review, config) {
271
321
  const blockers = [];
272
322
  if (currentWork.state !== "active") {
273
323
  blockers.push("no active delivery run or living spec");
@@ -281,6 +331,24 @@ function selectCompletion(currentWork, findings, git, stageMarkdown) {
281
331
  if (!git.available) {
282
332
  blockers.push("Git repository is unavailable");
283
333
  }
334
+ if (review && config) {
335
+ const isGateActive = config.qualityGates.regular.independentReview !== "manual";
336
+ if (review.state === "malformed") {
337
+ blockers.push("independent review record is malformed");
338
+ }
339
+ else if (review.state === "changes-requested") {
340
+ blockers.push("independent review requested changes");
341
+ }
342
+ else if (review.state === "pending") {
343
+ blockers.push("independent review is pending");
344
+ }
345
+ else if (isGateActive && review.state === "none") {
346
+ blockers.push("independent review is required");
347
+ }
348
+ else if (review.state === "passed" && review.freshness !== "current") {
349
+ blockers.push("independent review receipt is stale");
350
+ }
351
+ }
284
352
  if (blockers.length > 0) {
285
353
  return { state: "blocked", blockers };
286
354
  }