@quinteroac/agents-coding-toolkit 0.1.0-preview → 0.1.1-preview.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.
- package/README.md +1 -1
- package/package.json +13 -4
- package/scaffold/.agents/skills/execute-refactor-item/tmpl_SKILL.md +59 -0
- package/scaffold/.agents/skills/plan-refactor/tmpl_SKILL.md +89 -9
- package/scaffold/.agents/skills/refine-refactor-plan/tmpl_SKILL.md +30 -0
- package/scaffold/.agents/tmpl_state_rules.md +0 -1
- package/scaffold/schemas/tmpl_refactor-execution-progress.ts +16 -0
- package/scaffold/schemas/tmpl_refactor-prd.ts +14 -0
- package/scaffold/schemas/tmpl_state.ts +1 -0
- package/schemas/refactor-execution-progress.ts +16 -0
- package/schemas/refactor-prd.ts +14 -0
- package/schemas/state.test.ts +58 -0
- package/schemas/state.ts +1 -0
- package/schemas/test-plan.test.ts +1 -1
- package/src/cli.test.ts +57 -0
- package/src/cli.ts +180 -56
- package/src/commands/approve-project-context.ts +13 -6
- package/src/commands/approve-refactor-plan.test.ts +254 -0
- package/src/commands/approve-refactor-plan.ts +200 -0
- package/src/commands/approve-requirement.test.ts +224 -0
- package/src/commands/approve-requirement.ts +75 -16
- package/src/commands/approve-test-plan.test.ts +2 -2
- package/src/commands/approve-test-plan.ts +21 -7
- package/src/commands/create-issue.test.ts +2 -2
- package/src/commands/create-project-context.ts +31 -25
- package/src/commands/create-prototype.test.ts +31 -13
- package/src/commands/create-prototype.ts +17 -7
- package/src/commands/create-test-plan.ts +8 -6
- package/src/commands/define-refactor-plan.test.ts +208 -0
- package/src/commands/define-refactor-plan.ts +96 -0
- package/src/commands/define-requirement.ts +15 -9
- package/src/commands/execute-refactor.test.ts +954 -0
- package/src/commands/execute-refactor.ts +336 -0
- package/src/commands/execute-test-plan.test.ts +9 -2
- package/src/commands/execute-test-plan.ts +13 -6
- package/src/commands/refine-project-context.ts +9 -7
- package/src/commands/refine-refactor-plan.test.ts +210 -0
- package/src/commands/refine-refactor-plan.ts +95 -0
- package/src/commands/refine-requirement.ts +9 -6
- package/src/commands/refine-test-plan.test.ts +2 -2
- package/src/commands/refine-test-plan.ts +9 -6
- package/src/commands/write-json.ts +102 -97
- package/src/force-flag.test.ts +144 -0
- package/src/guardrail.test.ts +411 -0
- package/src/guardrail.ts +104 -0
- package/src/install.test.ts +7 -5
- package/src/pack.test.ts +2 -1
- package/scaffold/.agents/flow/tmpl_README.md +0 -7
- package/scaffold/.agents/flow/tmpl_iteration_close_checklist.example.md +0 -11
- package/schemas/test-plan.ts +0 -20
package/src/cli.ts
CHANGED
|
@@ -2,20 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { parseAgentArg } from "./agent";
|
|
5
|
+
import { GuardrailAbortError } from "./guardrail";
|
|
5
6
|
import { runApproveProjectContext } from "./commands/approve-project-context";
|
|
7
|
+
import { runApproveRefactorPlan } from "./commands/approve-refactor-plan";
|
|
6
8
|
import { runApproveRequirement } from "./commands/approve-requirement";
|
|
7
9
|
import { runApproveTestPlan } from "./commands/approve-test-plan";
|
|
8
10
|
import { runCreateIssue, runCreateIssueFromTestReport } from "./commands/create-issue";
|
|
9
11
|
import { runCreateProjectContext } from "./commands/create-project-context";
|
|
10
12
|
import { runCreatePrototype } from "./commands/create-prototype";
|
|
11
13
|
import { runCreateTestPlan } from "./commands/create-test-plan";
|
|
14
|
+
import { runDefineRefactorPlan } from "./commands/define-refactor-plan";
|
|
12
15
|
import { runDefineRequirement } from "./commands/define-requirement";
|
|
13
16
|
import { runDestroy } from "./commands/destroy";
|
|
14
17
|
import { runExecuteAutomatedFix } from "./commands/execute-automated-fix";
|
|
15
18
|
import { runExecuteManualFix } from "./commands/execute-manual-fix";
|
|
19
|
+
import { runExecuteRefactor } from "./commands/execute-refactor";
|
|
16
20
|
import { runExecuteTestPlan } from "./commands/execute-test-plan";
|
|
17
21
|
import { runInit } from "./commands/init";
|
|
18
22
|
import { runRefineProjectContext } from "./commands/refine-project-context";
|
|
23
|
+
import { runRefineRefactorPlan } from "./commands/refine-refactor-plan";
|
|
19
24
|
import { runRefineRequirement } from "./commands/refine-requirement";
|
|
20
25
|
import { runRefineTestPlan } from "./commands/refine-test-plan";
|
|
21
26
|
import { runStartIteration } from "./commands/start-iteration";
|
|
@@ -76,13 +81,21 @@ function parseOptionalIntegerFlag(
|
|
|
76
81
|
return { value: parsed, remainingArgs };
|
|
77
82
|
}
|
|
78
83
|
|
|
84
|
+
function parseForce(args: string[]): { force: boolean; remainingArgs: string[] } {
|
|
85
|
+
const force = args.includes("--force");
|
|
86
|
+
return {
|
|
87
|
+
force,
|
|
88
|
+
remainingArgs: args.filter((arg) => arg !== "--force"),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
79
92
|
function printUsage() {
|
|
80
93
|
console.log(`Usage: nvst <command> [options]
|
|
81
94
|
|
|
82
95
|
Commands:
|
|
83
96
|
init Initialize toolkit files in the current directory
|
|
84
97
|
start iteration Start a new iteration (archives previous if exists)
|
|
85
|
-
create project-context --agent <provider> [--mode strict|yolo]
|
|
98
|
+
create project-context --agent <provider> [--mode strict|yolo] [--force]
|
|
86
99
|
Generate/update .agents/PROJECT_CONTEXT.md via agent
|
|
87
100
|
create test-plan --agent <provider> [--force]
|
|
88
101
|
Generate test plan document for current iteration
|
|
@@ -96,20 +109,28 @@ Commands:
|
|
|
96
109
|
Mark project context as approved
|
|
97
110
|
approve test-plan
|
|
98
111
|
Mark test plan as approved and generate structured TP JSON
|
|
112
|
+
approve refactor-plan
|
|
113
|
+
Mark refactor plan as approved and generate structured refactor PRD JSON
|
|
99
114
|
refine project-context --agent <provider> [--challenge]
|
|
100
115
|
Refine project context via agent (editor or challenge mode)
|
|
101
|
-
define requirement --agent <provider>
|
|
116
|
+
define requirement --agent <provider> [--force]
|
|
102
117
|
Create requirement document via agent
|
|
103
|
-
|
|
118
|
+
define refactor-plan --agent <provider> [--force]
|
|
119
|
+
Create refactor plan document via agent
|
|
120
|
+
refine requirement --agent <provider> [--challenge] [--force]
|
|
104
121
|
Refine requirement document via agent
|
|
105
|
-
refine test-plan --agent <provider> [--challenge]
|
|
122
|
+
refine test-plan --agent <provider> [--challenge] [--force]
|
|
106
123
|
Refine test plan document via agent
|
|
107
|
-
|
|
124
|
+
refine refactor-plan --agent <provider> [--challenge] [--force]
|
|
125
|
+
Refine refactor plan document via agent
|
|
126
|
+
execute test-plan --agent <provider> [--force]
|
|
108
127
|
Execute approved structured test-plan JSON via agent
|
|
109
128
|
execute automated-fix --agent <provider> [--iterations <N>] [--retry-on-fail <N>]
|
|
110
129
|
Attempt automated fixes for open issues in current iteration
|
|
111
130
|
execute manual-fix --agent <provider>
|
|
112
131
|
Find manual-fix issues for current iteration and confirm execution
|
|
132
|
+
execute refactor --agent <provider> [--force]
|
|
133
|
+
Execute approved refactor items via agent in order
|
|
113
134
|
approve requirement
|
|
114
135
|
Mark requirement definition as approved
|
|
115
136
|
write-json --schema <name> --out <path> [--data '<json>']
|
|
@@ -122,7 +143,7 @@ Options:
|
|
|
122
143
|
--iterations Maximum prototype passes (integer >= 1)
|
|
123
144
|
--retry-on-fail Retry attempts per failed story (integer >= 0)
|
|
124
145
|
--stop-on-critical Stop execution after critical failures
|
|
125
|
-
--force
|
|
146
|
+
--force Bypass flow guardrail confirmation (and overwrite test-plan output)
|
|
126
147
|
--challenge Run refine in challenger mode
|
|
127
148
|
--clean When used with destroy, also removes .agents/flow/archived
|
|
128
149
|
-h, --help Show this help message
|
|
@@ -153,8 +174,9 @@ async function main() {
|
|
|
153
174
|
}
|
|
154
175
|
|
|
155
176
|
if (command === "init") {
|
|
156
|
-
|
|
157
|
-
|
|
177
|
+
const { remainingArgs: unknownArgs } = parseForce(args);
|
|
178
|
+
if (unknownArgs.length > 0) {
|
|
179
|
+
console.error(`Unknown option(s) for init: ${unknownArgs.join(" ")}`);
|
|
158
180
|
printUsage();
|
|
159
181
|
process.exitCode = 1;
|
|
160
182
|
return;
|
|
@@ -164,8 +186,9 @@ async function main() {
|
|
|
164
186
|
}
|
|
165
187
|
|
|
166
188
|
if (command === "destroy") {
|
|
167
|
-
const
|
|
168
|
-
const
|
|
189
|
+
const { remainingArgs: argsWithoutForce } = parseForce(args);
|
|
190
|
+
const clean = argsWithoutForce.includes("--clean");
|
|
191
|
+
const unknownArgs = argsWithoutForce.filter((arg) => arg !== "--clean");
|
|
169
192
|
if (unknownArgs.length > 0) {
|
|
170
193
|
console.error(`Unknown option(s) for destroy: ${unknownArgs.join(" ")}`);
|
|
171
194
|
printUsage();
|
|
@@ -177,7 +200,8 @@ async function main() {
|
|
|
177
200
|
}
|
|
178
201
|
|
|
179
202
|
if (command === "start") {
|
|
180
|
-
|
|
203
|
+
const { remainingArgs: argsWithoutForce } = parseForce(args);
|
|
204
|
+
if (argsWithoutForce[0] !== "iteration" || argsWithoutForce.length !== 1) {
|
|
181
205
|
console.error(`Usage for start: nvst start iteration`);
|
|
182
206
|
printUsage();
|
|
183
207
|
process.exitCode = 1;
|
|
@@ -203,15 +227,16 @@ async function main() {
|
|
|
203
227
|
try {
|
|
204
228
|
const { provider, remainingArgs: postAgentArgs } = parseAgentArg(args.slice(1));
|
|
205
229
|
const { mode, remainingArgs: postModeArgs } = parseMode(postAgentArgs);
|
|
230
|
+
const { force, remainingArgs: postForceArgs } = parseForce(postModeArgs);
|
|
206
231
|
|
|
207
|
-
if (
|
|
208
|
-
console.error(`Unknown option(s) for create project-context: ${
|
|
232
|
+
if (postForceArgs.length > 0) {
|
|
233
|
+
console.error(`Unknown option(s) for create project-context: ${postForceArgs.join(" ")}`);
|
|
209
234
|
printUsage();
|
|
210
235
|
process.exitCode = 1;
|
|
211
236
|
return;
|
|
212
237
|
}
|
|
213
238
|
|
|
214
|
-
await runCreateProjectContext({ provider, mode });
|
|
239
|
+
await runCreateProjectContext({ provider, mode, force });
|
|
215
240
|
return;
|
|
216
241
|
} catch (error) {
|
|
217
242
|
console.error(error instanceof Error ? error.message : String(error));
|
|
@@ -234,8 +259,9 @@ async function main() {
|
|
|
234
259
|
remainingArgs: postRetryArgs,
|
|
235
260
|
} = parseOptionalIntegerFlag(postIterationsArgs, "--retry-on-fail", 0);
|
|
236
261
|
|
|
237
|
-
const
|
|
238
|
-
const
|
|
262
|
+
const { force, remainingArgs: postForceArgs } = parseForce(postRetryArgs);
|
|
263
|
+
const stopOnCritical = postForceArgs.includes("--stop-on-critical");
|
|
264
|
+
const unknownArgs = postForceArgs.filter((arg) => arg !== "--stop-on-critical");
|
|
239
265
|
if (unknownArgs.length > 0) {
|
|
240
266
|
console.error(`Unknown option(s) for create prototype: ${unknownArgs.join(" ")}`);
|
|
241
267
|
printUsage();
|
|
@@ -243,7 +269,7 @@ async function main() {
|
|
|
243
269
|
return;
|
|
244
270
|
}
|
|
245
271
|
|
|
246
|
-
await runCreatePrototype({ provider, iterations, retryOnFail, stopOnCritical });
|
|
272
|
+
await runCreatePrototype({ provider, iterations, retryOnFail, stopOnCritical, force });
|
|
247
273
|
return;
|
|
248
274
|
} catch (error) {
|
|
249
275
|
console.error(error instanceof Error ? error.message : String(error));
|
|
@@ -278,9 +304,10 @@ async function main() {
|
|
|
278
304
|
|
|
279
305
|
if (subcommand === "issue") {
|
|
280
306
|
const subArgs = args.slice(1);
|
|
307
|
+
const { remainingArgs: subArgsWithoutForce } = parseForce(subArgs);
|
|
281
308
|
|
|
282
309
|
// Check for --help before parsing
|
|
283
|
-
if (
|
|
310
|
+
if (subArgsWithoutForce.includes("--help") || subArgsWithoutForce.includes("-h")) {
|
|
284
311
|
console.log(`Usage for create issue:
|
|
285
312
|
nvst create issue --agent <provider> Create issues interactively via agent
|
|
286
313
|
nvst create issue --test-execution-report Derive issues from test execution results
|
|
@@ -292,8 +319,8 @@ Providers: claude, codex, gemini, cursor`);
|
|
|
292
319
|
|
|
293
320
|
try {
|
|
294
321
|
// Check for --test-execution-report flag
|
|
295
|
-
if (
|
|
296
|
-
const remaining =
|
|
322
|
+
if (subArgsWithoutForce.includes("--test-execution-report")) {
|
|
323
|
+
const remaining = subArgsWithoutForce.filter((a) => a !== "--test-execution-report");
|
|
297
324
|
if (remaining.length > 0) {
|
|
298
325
|
console.error(`Unknown option(s) for create issue --test-execution-report: ${remaining.join(" ")}`);
|
|
299
326
|
printUsage();
|
|
@@ -304,7 +331,7 @@ Providers: claude, codex, gemini, cursor`);
|
|
|
304
331
|
return;
|
|
305
332
|
}
|
|
306
333
|
|
|
307
|
-
const { provider, remainingArgs: postAgentArgs } = parseAgentArg(
|
|
334
|
+
const { provider, remainingArgs: postAgentArgs } = parseAgentArg(subArgsWithoutForce);
|
|
308
335
|
|
|
309
336
|
if (postAgentArgs.length > 0) {
|
|
310
337
|
console.error(`Unknown option(s) for create issue: ${postAgentArgs.join(" ")}`);
|
|
@@ -330,37 +357,67 @@ Providers: claude, codex, gemini, cursor`);
|
|
|
330
357
|
}
|
|
331
358
|
|
|
332
359
|
if (command === "define") {
|
|
333
|
-
if (args.length === 0
|
|
334
|
-
console.error(`Usage for define: nvst define requirement --agent <provider>`);
|
|
360
|
+
if (args.length === 0) {
|
|
361
|
+
console.error(`Usage for define: nvst define <requirement|refactor-plan> --agent <provider>`);
|
|
335
362
|
printUsage();
|
|
336
363
|
process.exitCode = 1;
|
|
337
364
|
return;
|
|
338
365
|
}
|
|
339
366
|
|
|
340
|
-
|
|
341
|
-
|
|
367
|
+
const subcommand = args[0];
|
|
368
|
+
|
|
369
|
+
if (subcommand === "requirement") {
|
|
370
|
+
try {
|
|
371
|
+
const { provider, remainingArgs: postAgentArgs } = parseAgentArg(args.slice(1));
|
|
372
|
+
const { force, remainingArgs: postForceArgs } = parseForce(postAgentArgs);
|
|
373
|
+
if (postForceArgs.length > 0) {
|
|
374
|
+
console.error(`Unknown option(s) for define requirement: ${postForceArgs.join(" ")}`);
|
|
375
|
+
printUsage();
|
|
376
|
+
process.exitCode = 1;
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
342
379
|
|
|
343
|
-
|
|
344
|
-
|
|
380
|
+
await runDefineRequirement({ provider, force });
|
|
381
|
+
return;
|
|
382
|
+
} catch (error) {
|
|
383
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
345
384
|
printUsage();
|
|
346
385
|
process.exitCode = 1;
|
|
347
386
|
return;
|
|
348
387
|
}
|
|
388
|
+
}
|
|
349
389
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
390
|
+
if (subcommand === "refactor-plan") {
|
|
391
|
+
try {
|
|
392
|
+
const { provider, remainingArgs: postAgentArgs } = parseAgentArg(args.slice(1));
|
|
393
|
+
const { force, remainingArgs: postForceArgs } = parseForce(postAgentArgs);
|
|
394
|
+
if (postForceArgs.length > 0) {
|
|
395
|
+
console.error(`Unknown option(s) for define refactor-plan: ${postForceArgs.join(" ")}`);
|
|
396
|
+
printUsage();
|
|
397
|
+
process.exitCode = 1;
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
await runDefineRefactorPlan({ provider, force });
|
|
402
|
+
return;
|
|
403
|
+
} catch (error) {
|
|
404
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
405
|
+
printUsage();
|
|
406
|
+
process.exitCode = 1;
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
357
409
|
}
|
|
410
|
+
|
|
411
|
+
console.error(`Unknown define subcommand: ${subcommand}`);
|
|
412
|
+
printUsage();
|
|
413
|
+
process.exitCode = 1;
|
|
414
|
+
return;
|
|
358
415
|
}
|
|
359
416
|
|
|
360
417
|
if (command === "refine") {
|
|
361
418
|
if (args.length === 0) {
|
|
362
419
|
console.error(
|
|
363
|
-
`Usage for refine: nvst refine <requirement|project-context|test-plan> --agent <provider> [--challenge]`,
|
|
420
|
+
`Usage for refine: nvst refine <requirement|project-context|test-plan|refactor-plan> --agent <provider> [--challenge]`,
|
|
364
421
|
);
|
|
365
422
|
printUsage();
|
|
366
423
|
process.exitCode = 1;
|
|
@@ -372,8 +429,9 @@ Providers: claude, codex, gemini, cursor`);
|
|
|
372
429
|
if (subcommand === "requirement") {
|
|
373
430
|
try {
|
|
374
431
|
const { provider, remainingArgs: postAgentArgs } = parseAgentArg(args.slice(1));
|
|
375
|
-
const
|
|
376
|
-
const
|
|
432
|
+
const { force, remainingArgs: postForceArgs } = parseForce(postAgentArgs);
|
|
433
|
+
const challenge = postForceArgs.includes("--challenge");
|
|
434
|
+
const unknownArgs = postForceArgs.filter((arg) => arg !== "--challenge");
|
|
377
435
|
|
|
378
436
|
if (unknownArgs.length > 0) {
|
|
379
437
|
console.error(`Unknown option(s) for refine requirement: ${unknownArgs.join(" ")}`);
|
|
@@ -382,7 +440,7 @@ Providers: claude, codex, gemini, cursor`);
|
|
|
382
440
|
return;
|
|
383
441
|
}
|
|
384
442
|
|
|
385
|
-
await runRefineRequirement({ provider, challenge });
|
|
443
|
+
await runRefineRequirement({ provider, challenge, force });
|
|
386
444
|
return;
|
|
387
445
|
} catch (error) {
|
|
388
446
|
console.error(error instanceof Error ? error.message : String(error));
|
|
@@ -395,8 +453,9 @@ Providers: claude, codex, gemini, cursor`);
|
|
|
395
453
|
if (subcommand === "project-context") {
|
|
396
454
|
try {
|
|
397
455
|
const { provider, remainingArgs: postAgentArgs } = parseAgentArg(args.slice(1));
|
|
398
|
-
const
|
|
399
|
-
const
|
|
456
|
+
const { force, remainingArgs: postForceArgs } = parseForce(postAgentArgs);
|
|
457
|
+
const challenge = postForceArgs.includes("--challenge");
|
|
458
|
+
const unknownArgs = postForceArgs.filter((arg) => arg !== "--challenge");
|
|
400
459
|
|
|
401
460
|
if (unknownArgs.length > 0) {
|
|
402
461
|
console.error(
|
|
@@ -407,7 +466,7 @@ Providers: claude, codex, gemini, cursor`);
|
|
|
407
466
|
return;
|
|
408
467
|
}
|
|
409
468
|
|
|
410
|
-
await runRefineProjectContext({ provider, challenge });
|
|
469
|
+
await runRefineProjectContext({ provider, challenge, force });
|
|
411
470
|
return;
|
|
412
471
|
} catch (error) {
|
|
413
472
|
console.error(error instanceof Error ? error.message : String(error));
|
|
@@ -420,8 +479,9 @@ Providers: claude, codex, gemini, cursor`);
|
|
|
420
479
|
if (subcommand === "test-plan") {
|
|
421
480
|
try {
|
|
422
481
|
const { provider, remainingArgs: postAgentArgs } = parseAgentArg(args.slice(1));
|
|
423
|
-
const
|
|
424
|
-
const
|
|
482
|
+
const { force, remainingArgs: postForceArgs } = parseForce(postAgentArgs);
|
|
483
|
+
const challenge = postForceArgs.includes("--challenge");
|
|
484
|
+
const unknownArgs = postForceArgs.filter((arg) => arg !== "--challenge");
|
|
425
485
|
|
|
426
486
|
if (unknownArgs.length > 0) {
|
|
427
487
|
console.error(`Unknown option(s) for refine test-plan: ${unknownArgs.join(" ")}`);
|
|
@@ -430,7 +490,31 @@ Providers: claude, codex, gemini, cursor`);
|
|
|
430
490
|
return;
|
|
431
491
|
}
|
|
432
492
|
|
|
433
|
-
await runRefineTestPlan({ provider, challenge });
|
|
493
|
+
await runRefineTestPlan({ provider, challenge, force });
|
|
494
|
+
return;
|
|
495
|
+
} catch (error) {
|
|
496
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
497
|
+
printUsage();
|
|
498
|
+
process.exitCode = 1;
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
if (subcommand === "refactor-plan") {
|
|
504
|
+
try {
|
|
505
|
+
const { provider, remainingArgs: postAgentArgs } = parseAgentArg(args.slice(1));
|
|
506
|
+
const { force, remainingArgs: postForceArgs } = parseForce(postAgentArgs);
|
|
507
|
+
const challenge = postForceArgs.includes("--challenge");
|
|
508
|
+
const unknownArgs = postForceArgs.filter((arg) => arg !== "--challenge");
|
|
509
|
+
|
|
510
|
+
if (unknownArgs.length > 0) {
|
|
511
|
+
console.error(`Unknown option(s) for refine refactor-plan: ${unknownArgs.join(" ")}`);
|
|
512
|
+
printUsage();
|
|
513
|
+
process.exitCode = 1;
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
await runRefineRefactorPlan({ provider, challenge, force });
|
|
434
518
|
return;
|
|
435
519
|
} catch (error) {
|
|
436
520
|
console.error(error instanceof Error ? error.message : String(error));
|
|
@@ -447,27 +531,39 @@ Providers: claude, codex, gemini, cursor`);
|
|
|
447
531
|
}
|
|
448
532
|
|
|
449
533
|
if (command === "approve") {
|
|
450
|
-
if (args.length
|
|
451
|
-
console.error(`Usage for approve: nvst approve <requirement|project-context|test-plan>`);
|
|
534
|
+
if (args.length === 0) {
|
|
535
|
+
console.error(`Usage for approve: nvst approve <requirement|project-context|test-plan|refactor-plan>`);
|
|
452
536
|
printUsage();
|
|
453
537
|
process.exitCode = 1;
|
|
454
538
|
return;
|
|
455
539
|
}
|
|
456
540
|
|
|
457
541
|
const subcommand = args[0];
|
|
542
|
+
const { force, remainingArgs: unknownArgs } = parseForce(args.slice(1));
|
|
543
|
+
if (unknownArgs.length > 0) {
|
|
544
|
+
console.error(`Unknown option(s) for approve ${subcommand}: ${unknownArgs.join(" ")}`);
|
|
545
|
+
printUsage();
|
|
546
|
+
process.exitCode = 1;
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
458
549
|
|
|
459
550
|
if (subcommand === "requirement") {
|
|
460
|
-
await runApproveRequirement();
|
|
551
|
+
await runApproveRequirement({ force });
|
|
461
552
|
return;
|
|
462
553
|
}
|
|
463
554
|
|
|
464
555
|
if (subcommand === "project-context") {
|
|
465
|
-
await runApproveProjectContext();
|
|
556
|
+
await runApproveProjectContext({ force });
|
|
466
557
|
return;
|
|
467
558
|
}
|
|
468
559
|
|
|
469
560
|
if (subcommand === "test-plan") {
|
|
470
|
-
await runApproveTestPlan();
|
|
561
|
+
await runApproveTestPlan({ force });
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
if (subcommand === "refactor-plan") {
|
|
566
|
+
await runApproveRefactorPlan({ force });
|
|
471
567
|
return;
|
|
472
568
|
}
|
|
473
569
|
|
|
@@ -490,14 +586,15 @@ Providers: claude, codex, gemini, cursor`);
|
|
|
490
586
|
if (subcommand === "test-plan") {
|
|
491
587
|
try {
|
|
492
588
|
const { provider, remainingArgs: postAgentArgs } = parseAgentArg(args.slice(1));
|
|
493
|
-
|
|
494
|
-
|
|
589
|
+
const { force, remainingArgs: postForceArgs } = parseForce(postAgentArgs);
|
|
590
|
+
if (postForceArgs.length > 0) {
|
|
591
|
+
console.error(`Unknown option(s) for execute test-plan: ${postForceArgs.join(" ")}`);
|
|
495
592
|
printUsage();
|
|
496
593
|
process.exitCode = 1;
|
|
497
594
|
return;
|
|
498
595
|
}
|
|
499
596
|
|
|
500
|
-
await runExecuteTestPlan({ provider });
|
|
597
|
+
await runExecuteTestPlan({ provider, force });
|
|
501
598
|
return;
|
|
502
599
|
} catch (error) {
|
|
503
600
|
console.error(error instanceof Error ? error.message : String(error));
|
|
@@ -519,8 +616,9 @@ Providers: claude, codex, gemini, cursor`);
|
|
|
519
616
|
remainingArgs: postRetryArgs,
|
|
520
617
|
} = parseOptionalIntegerFlag(postIterationsArgs, "--retry-on-fail", 0);
|
|
521
618
|
|
|
522
|
-
|
|
523
|
-
|
|
619
|
+
const { remainingArgs: postForceArgs } = parseForce(postRetryArgs);
|
|
620
|
+
if (postForceArgs.length > 0) {
|
|
621
|
+
console.error(`Unknown option(s) for execute automated-fix: ${postForceArgs.join(" ")}`);
|
|
524
622
|
printUsage();
|
|
525
623
|
process.exitCode = 1;
|
|
526
624
|
return;
|
|
@@ -539,8 +637,9 @@ Providers: claude, codex, gemini, cursor`);
|
|
|
539
637
|
if (subcommand === "manual-fix") {
|
|
540
638
|
try {
|
|
541
639
|
const { provider, remainingArgs: postAgentArgs } = parseAgentArg(args.slice(1));
|
|
542
|
-
|
|
543
|
-
|
|
640
|
+
const { remainingArgs: postForceArgs } = parseForce(postAgentArgs);
|
|
641
|
+
if (postForceArgs.length > 0) {
|
|
642
|
+
console.error(`Unknown option(s) for execute manual-fix: ${postForceArgs.join(" ")}`);
|
|
544
643
|
printUsage();
|
|
545
644
|
process.exitCode = 1;
|
|
546
645
|
return;
|
|
@@ -556,6 +655,27 @@ Providers: claude, codex, gemini, cursor`);
|
|
|
556
655
|
}
|
|
557
656
|
}
|
|
558
657
|
|
|
658
|
+
if (subcommand === "refactor") {
|
|
659
|
+
try {
|
|
660
|
+
const { provider, remainingArgs: postAgentArgs } = parseAgentArg(args.slice(1));
|
|
661
|
+
const { force, remainingArgs: postForceArgs } = parseForce(postAgentArgs);
|
|
662
|
+
if (postForceArgs.length > 0) {
|
|
663
|
+
console.error(`Unknown option(s) for execute refactor: ${postForceArgs.join(" ")}`);
|
|
664
|
+
printUsage();
|
|
665
|
+
process.exitCode = 1;
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
await runExecuteRefactor({ provider, force });
|
|
670
|
+
return;
|
|
671
|
+
} catch (error) {
|
|
672
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
673
|
+
printUsage();
|
|
674
|
+
process.exitCode = 1;
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
559
679
|
console.error(`Unknown execute subcommand: ${subcommand}`);
|
|
560
680
|
printUsage();
|
|
561
681
|
process.exitCode = 1;
|
|
@@ -573,6 +693,10 @@ Providers: claude, codex, gemini, cursor`);
|
|
|
573
693
|
}
|
|
574
694
|
|
|
575
695
|
main().catch((error) => {
|
|
696
|
+
if (error instanceof GuardrailAbortError) {
|
|
697
|
+
// exitCode already set and "Aborted." already written by assertGuardrail
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
576
700
|
console.error("nvst failed:", error);
|
|
577
701
|
process.exitCode = 1;
|
|
578
702
|
});
|
|
@@ -1,18 +1,25 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
2
|
|
|
3
|
+
import { assertGuardrail } from "../guardrail";
|
|
3
4
|
import { exists, readState, writeState } from "../state";
|
|
4
5
|
|
|
5
|
-
export
|
|
6
|
+
export interface ApproveProjectContextOptions {
|
|
7
|
+
force?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export async function runApproveProjectContext(opts: ApproveProjectContextOptions = {}): Promise<void> {
|
|
11
|
+
const { force = false } = opts;
|
|
6
12
|
const projectRoot = process.cwd();
|
|
7
13
|
const state = await readState(projectRoot);
|
|
8
14
|
|
|
9
15
|
// US-002-AC01: Validate status is pending_approval
|
|
10
16
|
const projectContext = state.phases.prototype.project_context;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
17
|
+
await assertGuardrail(
|
|
18
|
+
state,
|
|
19
|
+
projectContext.status !== "pending_approval",
|
|
20
|
+
`Cannot approve project context from status '${projectContext.status}'. Expected pending_approval.`,
|
|
21
|
+
{ force },
|
|
22
|
+
);
|
|
16
23
|
|
|
17
24
|
// US-002-AC01: Validate project context file exists
|
|
18
25
|
const contextFile = projectContext.file;
|