sdd-cli 0.1.11 → 0.1.12

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 CHANGED
@@ -66,6 +66,7 @@ program
66
66
  .option("--improve", "Trigger self-audit and regenerate")
67
67
  .option("--parallel", "Generate in parallel when supported")
68
68
  .option("--non-interactive", "Run with defaults and without prompt confirmations")
69
+ .option("--from-step <step>", "Resume or start autopilot from step: create|plan|start|test|finish")
69
70
  .option("--project <name>", "Select or name the project")
70
71
  .option("--output <path>", "Override workspace output root");
71
72
  program.hook("preAction", (thisCommand, actionCommand) => {
@@ -75,6 +76,7 @@ program.hook("preAction", (thisCommand, actionCommand) => {
75
76
  improve: Boolean(opts.improve),
76
77
  parallel: Boolean(opts.parallel),
77
78
  nonInteractive: Boolean(opts.nonInteractive),
79
+ fromStep: typeof opts.fromStep === "string" ? opts.fromStep : undefined,
78
80
  project: typeof opts.project === "string" ? opts.project : undefined,
79
81
  output: typeof opts.output === "string" ? opts.output : undefined
80
82
  });
@@ -0,0 +1,16 @@
1
+ export declare const AUTOPILOT_STEPS: readonly ["create", "plan", "start", "test", "finish"];
2
+ export type AutopilotStep = (typeof AUTOPILOT_STEPS)[number];
3
+ export type AutopilotCheckpoint = {
4
+ project: string;
5
+ reqId: string;
6
+ seedText: string;
7
+ flow: string;
8
+ domain: string;
9
+ lastCompleted: AutopilotStep;
10
+ updatedAt: string;
11
+ };
12
+ export declare function normalizeStep(step?: string): AutopilotStep | null;
13
+ export declare function loadCheckpoint(projectName: string): AutopilotCheckpoint | null;
14
+ export declare function saveCheckpoint(projectName: string, checkpoint: AutopilotCheckpoint): void;
15
+ export declare function clearCheckpoint(projectName: string): void;
16
+ export declare function nextStep(step: AutopilotStep): AutopilotStep | null;
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.AUTOPILOT_STEPS = void 0;
7
+ exports.normalizeStep = normalizeStep;
8
+ exports.loadCheckpoint = loadCheckpoint;
9
+ exports.saveCheckpoint = saveCheckpoint;
10
+ exports.clearCheckpoint = clearCheckpoint;
11
+ exports.nextStep = nextStep;
12
+ const fs_1 = __importDefault(require("fs"));
13
+ const path_1 = __importDefault(require("path"));
14
+ const index_1 = require("../workspace/index");
15
+ exports.AUTOPILOT_STEPS = ["create", "plan", "start", "test", "finish"];
16
+ function checkpointPath(projectName) {
17
+ const workspace = (0, index_1.getWorkspaceInfo)();
18
+ const project = (0, index_1.getProjectInfo)(workspace, projectName);
19
+ return path_1.default.join(project.root, ".autopilot-checkpoint.json");
20
+ }
21
+ function normalizeStep(step) {
22
+ if (!step)
23
+ return null;
24
+ const raw = step.trim().toLowerCase();
25
+ const map = {
26
+ create: "create",
27
+ plan: "plan",
28
+ start: "start",
29
+ test: "test",
30
+ "test-plan": "test",
31
+ finish: "finish"
32
+ };
33
+ return map[raw] ?? null;
34
+ }
35
+ function loadCheckpoint(projectName) {
36
+ const file = checkpointPath(projectName);
37
+ if (!fs_1.default.existsSync(file)) {
38
+ return null;
39
+ }
40
+ try {
41
+ return JSON.parse(fs_1.default.readFileSync(file, "utf-8"));
42
+ }
43
+ catch {
44
+ return null;
45
+ }
46
+ }
47
+ function saveCheckpoint(projectName, checkpoint) {
48
+ const file = checkpointPath(projectName);
49
+ fs_1.default.mkdirSync(path_1.default.dirname(file), { recursive: true });
50
+ fs_1.default.writeFileSync(file, JSON.stringify(checkpoint, null, 2), "utf-8");
51
+ }
52
+ function clearCheckpoint(projectName) {
53
+ const file = checkpointPath(projectName);
54
+ if (fs_1.default.existsSync(file)) {
55
+ fs_1.default.rmSync(file, { force: true });
56
+ }
57
+ }
58
+ function nextStep(step) {
59
+ const idx = exports.AUTOPILOT_STEPS.indexOf(step);
60
+ if (idx < 0 || idx + 1 >= exports.AUTOPILOT_STEPS.length) {
61
+ return null;
62
+ }
63
+ return exports.AUTOPILOT_STEPS[idx + 1];
64
+ }
@@ -13,6 +13,7 @@ const req_start_1 = require("./req-start");
13
13
  const req_finish_1 = require("./req-finish");
14
14
  const route_1 = require("./route");
15
15
  const test_plan_1 = require("./test-plan");
16
+ const autopilot_checkpoint_1 = require("./autopilot-checkpoint");
16
17
  function printStep(step, description) {
17
18
  console.log(`${step}: ${description}`);
18
19
  }
@@ -113,7 +114,7 @@ async function runHello(input, runQuestions) {
113
114
  projects = reloaded.projects;
114
115
  console.log(`Workspace updated: ${workspace.root}`);
115
116
  }
116
- const flags = (0, flags_1.getFlags)();
117
+ const runtimeFlags = (0, flags_1.getFlags)();
117
118
  if (projects.length > 0) {
118
119
  console.log("Active projects:");
119
120
  projects.forEach((project) => {
@@ -122,7 +123,7 @@ async function runHello(input, runQuestions) {
122
123
  const choice = await (0, prompt_1.ask)("Start new or continue? (new/continue) ");
123
124
  const normalized = choice.trim().toLowerCase();
124
125
  if (normalized === "continue") {
125
- const selected = flags.project || (await (0, prompt_1.ask)("Project to continue: "));
126
+ const selected = runtimeFlags.project || (await (0, prompt_1.ask)("Project to continue: "));
126
127
  if (!selected) {
127
128
  console.log("No project selected. Continuing with new flow.");
128
129
  }
@@ -141,7 +142,23 @@ async function runHello(input, runQuestions) {
141
142
  else {
142
143
  console.log("No active projects found.");
143
144
  }
144
- const text = input || (await (0, prompt_1.ask)("Describe what you want to do: "));
145
+ let text = input || (await (0, prompt_1.ask)("Describe what you want to do: "));
146
+ const shouldRunQuestions = runQuestions === true;
147
+ let checkpoint = null;
148
+ let fromStep = (0, autopilot_checkpoint_1.normalizeStep)(runtimeFlags.fromStep);
149
+ let activeProjectForCheckpoint = runtimeFlags.project;
150
+ if (!shouldRunQuestions && activeProjectForCheckpoint) {
151
+ checkpoint = (0, autopilot_checkpoint_1.loadCheckpoint)(activeProjectForCheckpoint);
152
+ if (!text && checkpoint?.seedText) {
153
+ text = checkpoint.seedText;
154
+ }
155
+ if (!fromStep && checkpoint?.lastCompleted) {
156
+ const candidate = (0, autopilot_checkpoint_1.nextStep)(checkpoint.lastCompleted);
157
+ if (candidate) {
158
+ fromStep = candidate;
159
+ }
160
+ }
161
+ }
145
162
  if (!text) {
146
163
  console.log("No input provided. Try again with a short description.");
147
164
  return;
@@ -157,7 +174,6 @@ async function runHello(input, runQuestions) {
157
174
  else {
158
175
  console.log("Next: run `sdd-cli route <your input>` to view details.");
159
176
  }
160
- const shouldRunQuestions = runQuestions === true;
161
177
  printStep("Step 2/7", "Requirement setup");
162
178
  printWhy("I will gather enough context to generate a valid first draft.");
163
179
  if (shouldRunQuestions) {
@@ -204,64 +220,110 @@ async function runHello(input, runQuestions) {
204
220
  }
205
221
  printWhy(`Using project: ${activeProject}`);
206
222
  (0, flags_1.setFlags)({ project: activeProject });
207
- const draft = buildAutopilotDraft(text, intent.flow, intent.domain);
208
- draft.project_name = activeProject;
209
- printStep("Step 3/7", "Creating requirement draft automatically");
210
- printWhy("This creates your baseline scope, acceptance criteria, and NFRs.");
211
- const created = await (0, req_create_1.runReqCreate)(draft, { autofill: true });
212
- if (!created) {
213
- console.log("Autopilot stopped at requirement creation.");
214
- return;
223
+ checkpoint = (0, autopilot_checkpoint_1.loadCheckpoint)(activeProject);
224
+ if (checkpoint && !fromStep) {
225
+ const candidate = (0, autopilot_checkpoint_1.nextStep)(checkpoint.lastCompleted);
226
+ if (candidate) {
227
+ fromStep = candidate;
228
+ }
215
229
  }
216
- printStep("Step 4/7", `Planning requirement ${created.reqId}`);
217
- printWhy("I am generating functional, technical, architecture, and test artifacts.");
218
- const planned = await (0, req_plan_1.runReqPlan)({
219
- projectName: activeProject,
220
- reqId: created.reqId,
221
- autofill: true,
222
- seedText: text
223
- });
224
- if (!planned) {
225
- console.log("Autopilot stopped at planning.");
230
+ if (fromStep && !autopilot_checkpoint_1.AUTOPILOT_STEPS.includes(fromStep)) {
231
+ console.log(`Invalid --from-step value. Use one of: ${autopilot_checkpoint_1.AUTOPILOT_STEPS.join(", ")}`);
226
232
  return;
227
233
  }
228
- printStep("Step 5/7", `Preparing implementation plan for ${created.reqId}`);
229
- printWhy("This stage defines milestones, tasks, quality thresholds, and decisions.");
230
- const started = await (0, req_start_1.runReqStart)({
231
- projectName: activeProject,
232
- reqId: created.reqId,
233
- autofill: true,
234
- seedText: text
235
- });
236
- if (!started) {
237
- console.log("Autopilot stopped at start phase.");
234
+ const draft = buildAutopilotDraft(text, intent.flow, intent.domain);
235
+ draft.project_name = activeProject;
236
+ let reqId = checkpoint?.reqId ?? "";
237
+ const startStep = fromStep ?? "create";
238
+ if (startStep !== "create" && !reqId) {
239
+ console.log("No checkpoint found for resume. Run full autopilot first or use --from-step create.");
238
240
  return;
239
241
  }
240
- printStep("Step 6/7", `Updating test plan for ${created.reqId}`);
241
- printWhy("I am ensuring critical paths, edge cases, and regression tests are documented.");
242
- const tested = await (0, test_plan_1.runTestPlan)({
243
- projectName: activeProject,
244
- reqId: created.reqId,
245
- autofill: true,
246
- seedText: text
247
- });
248
- if (!tested) {
249
- console.log("Autopilot stopped at test planning.");
250
- return;
242
+ if (fromStep) {
243
+ printWhy(`Resuming autopilot from step: ${fromStep}`);
251
244
  }
252
- printStep("Step 7/7", `Finalizing requirement ${created.reqId}`);
253
- printWhy("I will move artifacts to done state and generate project-level summary files.");
254
- const finished = await (0, req_finish_1.runReqFinish)({
255
- projectName: activeProject,
256
- reqId: created.reqId,
257
- autofill: true,
258
- seedText: text
259
- });
260
- if (!finished) {
261
- console.log("Autopilot stopped at finish phase.");
262
- return;
245
+ const stepIndex = autopilot_checkpoint_1.AUTOPILOT_STEPS.indexOf(startStep);
246
+ for (let i = stepIndex; i < autopilot_checkpoint_1.AUTOPILOT_STEPS.length; i += 1) {
247
+ const step = autopilot_checkpoint_1.AUTOPILOT_STEPS[i];
248
+ if (step === "create") {
249
+ printStep("Step 3/7", "Creating requirement draft automatically");
250
+ printWhy("This creates your baseline scope, acceptance criteria, and NFRs.");
251
+ const created = await (0, req_create_1.runReqCreate)(draft, { autofill: true });
252
+ if (!created) {
253
+ console.log("Autopilot stopped at requirement creation.");
254
+ return;
255
+ }
256
+ reqId = created.reqId;
257
+ }
258
+ if (step === "plan") {
259
+ printStep("Step 4/7", `Planning requirement ${reqId}`);
260
+ printWhy("I am generating functional, technical, architecture, and test artifacts.");
261
+ const planned = await (0, req_plan_1.runReqPlan)({
262
+ projectName: activeProject,
263
+ reqId,
264
+ autofill: true,
265
+ seedText: text
266
+ });
267
+ if (!planned) {
268
+ console.log("Autopilot stopped at planning.");
269
+ return;
270
+ }
271
+ }
272
+ if (step === "start") {
273
+ printStep("Step 5/7", `Preparing implementation plan for ${reqId}`);
274
+ printWhy("This stage defines milestones, tasks, quality thresholds, and decisions.");
275
+ const started = await (0, req_start_1.runReqStart)({
276
+ projectName: activeProject,
277
+ reqId,
278
+ autofill: true,
279
+ seedText: text
280
+ });
281
+ if (!started) {
282
+ console.log("Autopilot stopped at start phase.");
283
+ return;
284
+ }
285
+ }
286
+ if (step === "test") {
287
+ printStep("Step 6/7", `Updating test plan for ${reqId}`);
288
+ printWhy("I am ensuring critical paths, edge cases, and regression tests are documented.");
289
+ const tested = await (0, test_plan_1.runTestPlan)({
290
+ projectName: activeProject,
291
+ reqId,
292
+ autofill: true,
293
+ seedText: text
294
+ });
295
+ if (!tested) {
296
+ console.log("Autopilot stopped at test planning.");
297
+ return;
298
+ }
299
+ }
300
+ if (step === "finish") {
301
+ printStep("Step 7/7", `Finalizing requirement ${reqId}`);
302
+ printWhy("I will move artifacts to done state and generate project-level summary files.");
303
+ const finished = await (0, req_finish_1.runReqFinish)({
304
+ projectName: activeProject,
305
+ reqId,
306
+ autofill: true,
307
+ seedText: text
308
+ });
309
+ if (!finished) {
310
+ console.log("Autopilot stopped at finish phase.");
311
+ return;
312
+ }
313
+ (0, autopilot_checkpoint_1.clearCheckpoint)(activeProject);
314
+ console.log(`Autopilot completed successfully for ${reqId}.`);
315
+ console.log(`Artifacts finalized at: ${finished.doneDir}`);
316
+ return;
317
+ }
318
+ (0, autopilot_checkpoint_1.saveCheckpoint)(activeProject, {
319
+ project: activeProject,
320
+ reqId,
321
+ seedText: text,
322
+ flow: intent.flow,
323
+ domain: intent.domain,
324
+ lastCompleted: step,
325
+ updatedAt: new Date().toISOString()
326
+ });
263
327
  }
264
- console.log(`Autopilot completed successfully for ${created.reqId}.`);
265
- console.log(`Artifacts finalized at: ${finished.doneDir}`);
266
328
  }
267
329
  }
@@ -3,6 +3,7 @@ export type RuntimeFlags = {
3
3
  improve: boolean;
4
4
  parallel: boolean;
5
5
  nonInteractive: boolean;
6
+ fromStep?: string;
6
7
  project?: string;
7
8
  output?: string;
8
9
  };
@@ -7,6 +7,7 @@ const flags = {
7
7
  improve: false,
8
8
  parallel: false,
9
9
  nonInteractive: false,
10
+ fromStep: undefined,
10
11
  project: undefined,
11
12
  output: undefined
12
13
  };
@@ -23,6 +24,9 @@ function setFlags(next) {
23
24
  if ("nonInteractive" in next) {
24
25
  flags.nonInteractive = Boolean(next.nonInteractive);
25
26
  }
27
+ if ("fromStep" in next) {
28
+ flags.fromStep = typeof next.fromStep === "string" ? next.fromStep : undefined;
29
+ }
26
30
  if ("project" in next) {
27
31
  flags.project = typeof next.project === "string" ? next.project : undefined;
28
32
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sdd-cli",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "SDD-first, AI-native CLI for end-to-end delivery.",
5
5
  "homepage": "https://github.com/jdsalasca/sdd-tool#readme",
6
6
  "repository": {