sdd-cli 0.1.16 → 0.1.18

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 CHANGED
@@ -156,6 +156,7 @@ Use `--questions` when you want the manual question-by-question flow.
156
156
  - `sdd-cli quickstart` -- one-command demo flow with built-in examples
157
157
  - `sdd-cli init` -- create SDD workspace and config
158
158
  - `sdd-cli list` -- list flows, router flows, templates, prompt packs, and projects
159
+ - `sdd-cli status --next` -- show current project state and exact next command
159
160
  - `sdd-cli doctor` -- validate completeness and consistency
160
161
 
161
162
  ### Router
@@ -192,6 +193,9 @@ Use `--questions` when you want the manual question-by-question flow.
192
193
  - `--parallel` -- generate in parallel
193
194
  - `--questions` -- use manual question-driven discovery flow
194
195
  - `--non-interactive` -- run without confirmations (script/CI friendly)
196
+ - `--beginner` -- show extra step-by-step explanations during hello autopilot
197
+ - `--dry-run` -- preview autopilot stages without writing artifacts
198
+ - `--from-step` -- resume autopilot from `create|plan|start|test|finish`
195
199
  - `--alias sdd` -- optional alias to run as `sdd`
196
200
 
197
201
  ## Beginner quickstart
@@ -209,6 +213,10 @@ sdd-cli hello "I want a simple booking system for appointments"
209
213
  5) Check output in:
210
214
  `<workspace>/<project>/requirements/done/<REQ-ID>/`
211
215
 
216
+ For a full onboarding walkthrough, see:
217
+ - `docs/FIRST_15_MINUTES.md`
218
+ - `examples/transcripts/FIRST_15_MINUTES.md`
219
+
212
220
  ## Recovery quick commands
213
221
 
214
222
  - Continue an existing project:
package/dist/cli.js CHANGED
@@ -45,6 +45,7 @@ const init_1 = require("./commands/init");
45
45
  const route_1 = require("./commands/route");
46
46
  const doctor_1 = require("./commands/doctor");
47
47
  const quickstart_1 = require("./commands/quickstart");
48
+ const status_1 = require("./commands/status");
48
49
  const paths_1 = require("./paths");
49
50
  const flags_1 = require("./context/flags");
50
51
  const prompt_1 = require("./ui/prompt");
@@ -68,6 +69,7 @@ program
68
69
  .option("--parallel", "Generate in parallel when supported")
69
70
  .option("--non-interactive", "Run with defaults and without prompt confirmations")
70
71
  .option("--dry-run", "Preview autopilot steps without writing artifacts")
72
+ .option("--beginner", "Enable extra step-by-step guidance in hello flow")
71
73
  .option("--from-step <step>", "Resume or start autopilot from step: create|plan|start|test|finish")
72
74
  .option("--project <name>", "Select or name the project")
73
75
  .option("--output <path>", "Override workspace output root");
@@ -79,6 +81,7 @@ program.hook("preAction", (thisCommand, actionCommand) => {
79
81
  parallel: Boolean(opts.parallel),
80
82
  nonInteractive: Boolean(opts.nonInteractive),
81
83
  dryRun: Boolean(opts.dryRun),
84
+ beginner: Boolean(opts.beginner),
82
85
  fromStep: typeof opts.fromStep === "string" ? opts.fromStep : undefined,
83
86
  project: typeof opts.project === "string" ? opts.project : undefined,
84
87
  output: typeof opts.output === "string" ? opts.output : undefined
@@ -111,6 +114,11 @@ program
111
114
  const { runList } = await Promise.resolve().then(() => __importStar(require("./commands/list")));
112
115
  runList();
113
116
  });
117
+ program
118
+ .command("status")
119
+ .description("Show project requirement counts and next recommended command")
120
+ .option("--next", "Print exact next command to run")
121
+ .action((options) => (0, status_1.runStatus)(Boolean(options.next)));
114
122
  const req = program.command("req").description("Requirement lifecycle commands");
115
123
  req
116
124
  .command("create")
@@ -23,6 +23,12 @@ function printWhy(message) {
23
23
  function printRecoveryNext(project, step, hint) {
24
24
  console.log(`Next command: sdd-cli --project "${project}" --from-step ${step} hello "${hint}"`);
25
25
  }
26
+ function printBeginnerTip(enabled, tip) {
27
+ if (!enabled) {
28
+ return;
29
+ }
30
+ console.log(` [Beginner] ${tip}`);
31
+ }
26
32
  function deriveProjectName(input, flow) {
27
33
  const seed = input
28
34
  .trim()
@@ -107,8 +113,12 @@ async function runHello(input, runQuestions) {
107
113
  const shouldRunQuestions = runQuestions === true;
108
114
  const autoGuidedMode = !shouldRunQuestions && (runtimeFlags.nonInteractive || hasDirectIntent);
109
115
  const dryRun = runtimeFlags.dryRun;
116
+ const beginnerMode = runtimeFlags.beginner;
110
117
  console.log("Hello from sdd-cli.");
111
118
  console.log(`Workspace: ${workspace.root}`);
119
+ if (beginnerMode) {
120
+ printBeginnerTip(true, "I will explain each step and tell you what happens next.");
121
+ }
112
122
  if (autoGuidedMode) {
113
123
  printWhy("Auto-guided mode active: using current workspace defaults.");
114
124
  }
@@ -193,6 +203,7 @@ async function runHello(input, runQuestions) {
193
203
  console.log(`Detected intent: ${intent.intent} -> ${intent.flow}`);
194
204
  printStep("Step 1/7", "Intent detected");
195
205
  printWhy("I classified your goal and selected the best starting flow.");
206
+ printBeginnerTip(beginnerMode, "Intent helps me pick the right workflow and defaults.");
196
207
  const showRoute = runQuestions === true ? await (0, prompt_1.confirm)("View route details now? (y/n) ") : false;
197
208
  if (showRoute && runQuestions === true) {
198
209
  (0, route_1.runRoute)(text);
@@ -202,6 +213,7 @@ async function runHello(input, runQuestions) {
202
213
  }
203
214
  printStep("Step 2/7", "Requirement setup");
204
215
  printWhy("I will gather enough context to generate a valid first draft.");
216
+ printBeginnerTip(beginnerMode, "A requirement draft defines scope, acceptance criteria, and constraints.");
205
217
  if (shouldRunQuestions) {
206
218
  const packs = (0, prompt_packs_1.loadPromptPacks)();
207
219
  const packIds = intent_1.FLOW_PROMPT_PACKS[intent.flow] ?? [];
@@ -277,6 +289,7 @@ async function runHello(input, runQuestions) {
277
289
  const stepIndex = autopilot_checkpoint_1.AUTOPILOT_STEPS.indexOf(startStep);
278
290
  if (dryRun) {
279
291
  printWhy("Dry run active: previewing autopilot plan without writing files.");
292
+ printBeginnerTip(beginnerMode, "Dry run is safe: it shows plan only and does not change files.");
280
293
  for (let i = stepIndex; i < autopilot_checkpoint_1.AUTOPILOT_STEPS.length; i += 1) {
281
294
  const step = autopilot_checkpoint_1.AUTOPILOT_STEPS[i];
282
295
  console.log(`Would run step: ${step}`);
@@ -289,6 +302,7 @@ async function runHello(input, runQuestions) {
289
302
  if (step === "create") {
290
303
  printStep("Step 3/7", "Creating requirement draft automatically");
291
304
  printWhy("This creates your baseline scope, acceptance criteria, and NFRs.");
305
+ printBeginnerTip(beginnerMode, "After this, your requirement is ready for planning artifacts.");
292
306
  const created = await (0, req_create_1.runReqCreate)(draft, { autofill: true });
293
307
  if (!created) {
294
308
  console.log("Autopilot stopped at requirement creation.");
@@ -300,6 +314,7 @@ async function runHello(input, runQuestions) {
300
314
  if (step === "plan") {
301
315
  printStep("Step 4/7", `Planning requirement ${reqId}`);
302
316
  printWhy("I am generating functional, technical, architecture, and test artifacts.");
317
+ printBeginnerTip(beginnerMode, "Planning creates the blueprint before implementation.");
303
318
  const planned = await (0, req_plan_1.runReqPlan)({
304
319
  projectName: activeProject,
305
320
  reqId,
@@ -315,6 +330,7 @@ async function runHello(input, runQuestions) {
315
330
  if (step === "start") {
316
331
  printStep("Step 5/7", `Preparing implementation plan for ${reqId}`);
317
332
  printWhy("This stage defines milestones, tasks, quality thresholds, and decisions.");
333
+ printBeginnerTip(beginnerMode, "Start phase prepares execution details and quality guardrails.");
318
334
  const started = await (0, req_start_1.runReqStart)({
319
335
  projectName: activeProject,
320
336
  reqId,
@@ -330,6 +346,7 @@ async function runHello(input, runQuestions) {
330
346
  if (step === "test") {
331
347
  printStep("Step 6/7", `Updating test plan for ${reqId}`);
332
348
  printWhy("I am ensuring critical paths, edge cases, and regression tests are documented.");
349
+ printBeginnerTip(beginnerMode, "Testing focus reduces regressions before delivery.");
333
350
  const tested = await (0, test_plan_1.runTestPlan)({
334
351
  projectName: activeProject,
335
352
  reqId,
@@ -345,6 +362,7 @@ async function runHello(input, runQuestions) {
345
362
  if (step === "finish") {
346
363
  printStep("Step 7/7", `Finalizing requirement ${reqId}`);
347
364
  printWhy("I will move artifacts to done state and generate project-level summary files.");
365
+ printBeginnerTip(beginnerMode, "Finish locks outputs and leaves a reusable delivery record.");
348
366
  const finished = await (0, req_finish_1.runReqFinish)({
349
367
  projectName: activeProject,
350
368
  reqId,
@@ -0,0 +1 @@
1
+ export declare function runStatus(showNext?: boolean): void;
@@ -0,0 +1,97 @@
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.runStatus = runStatus;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const flags_1 = require("../context/flags");
10
+ const index_1 = require("../workspace/index");
11
+ const REQUIREMENT_STATUSES = ["backlog", "wip", "in-progress", "done", "archived"];
12
+ function listRequirementIds(projectRoot, status) {
13
+ const dir = path_1.default.join(projectRoot, "requirements", status);
14
+ if (!fs_1.default.existsSync(dir)) {
15
+ return [];
16
+ }
17
+ return fs_1.default
18
+ .readdirSync(dir, { withFileTypes: true })
19
+ .filter((entry) => entry.isDirectory())
20
+ .map((entry) => entry.name)
21
+ .sort();
22
+ }
23
+ function latestId(ids) {
24
+ if (ids.length === 0) {
25
+ return null;
26
+ }
27
+ return ids[ids.length - 1];
28
+ }
29
+ function recommendNext(projectName, counts, ids) {
30
+ const nextInProgress = latestId(ids["in-progress"]);
31
+ if (nextInProgress) {
32
+ return `sdd-cli --project "${projectName}" req finish # then enter ${nextInProgress} when prompted`;
33
+ }
34
+ const nextWip = latestId(ids.wip);
35
+ if (nextWip) {
36
+ return `sdd-cli --project "${projectName}" req start # then enter ${nextWip} when prompted`;
37
+ }
38
+ const nextBacklog = latestId(ids.backlog);
39
+ if (nextBacklog) {
40
+ return `sdd-cli --project "${projectName}" req plan # then enter ${nextBacklog} when prompted`;
41
+ }
42
+ if (counts.done > 0 && counts.archived === 0) {
43
+ return `sdd-cli --project "${projectName}" hello "start next requirement"`;
44
+ }
45
+ return `sdd-cli --project "${projectName}" hello "continue"`;
46
+ }
47
+ function runStatus(showNext) {
48
+ const workspace = (0, index_1.getWorkspaceInfo)();
49
+ (0, index_1.ensureWorkspace)(workspace);
50
+ const projects = (0, index_1.listProjects)(workspace);
51
+ const flags = (0, flags_1.getFlags)();
52
+ const selectedName = flags.project && flags.project.trim().length > 0 ? flags.project.trim() : projects[0]?.name;
53
+ if (!selectedName) {
54
+ console.log("No projects found.");
55
+ if (showNext) {
56
+ console.log('Next command: sdd-cli quickstart --example saas');
57
+ }
58
+ return;
59
+ }
60
+ let project;
61
+ try {
62
+ project = (0, index_1.getProjectInfo)(workspace, selectedName);
63
+ }
64
+ catch (error) {
65
+ console.log(error.message);
66
+ return;
67
+ }
68
+ if (!fs_1.default.existsSync(project.root)) {
69
+ console.log("No projects found.");
70
+ if (showNext) {
71
+ console.log('Next command: sdd-cli quickstart --example saas');
72
+ }
73
+ return;
74
+ }
75
+ const ids = {
76
+ backlog: listRequirementIds(project.root, "backlog"),
77
+ wip: listRequirementIds(project.root, "wip"),
78
+ "in-progress": listRequirementIds(project.root, "in-progress"),
79
+ done: listRequirementIds(project.root, "done"),
80
+ archived: listRequirementIds(project.root, "archived")
81
+ };
82
+ const counts = {
83
+ backlog: ids.backlog.length,
84
+ wip: ids.wip.length,
85
+ "in-progress": ids["in-progress"].length,
86
+ done: ids.done.length,
87
+ archived: ids.archived.length
88
+ };
89
+ console.log(`Project: ${project.name}`);
90
+ REQUIREMENT_STATUSES.forEach((status) => {
91
+ console.log(`- ${status}: ${counts[status]}`);
92
+ });
93
+ if (showNext) {
94
+ const recommendation = recommendNext(project.name, counts, ids);
95
+ console.log(`Next command: ${recommendation}`);
96
+ }
97
+ }
@@ -4,6 +4,7 @@ export type RuntimeFlags = {
4
4
  parallel: boolean;
5
5
  nonInteractive: boolean;
6
6
  dryRun: boolean;
7
+ beginner: boolean;
7
8
  fromStep?: string;
8
9
  project?: string;
9
10
  output?: string;
@@ -8,6 +8,7 @@ const flags = {
8
8
  parallel: false,
9
9
  nonInteractive: false,
10
10
  dryRun: false,
11
+ beginner: false,
11
12
  fromStep: undefined,
12
13
  project: undefined,
13
14
  output: undefined
@@ -28,6 +29,9 @@ function setFlags(next) {
28
29
  if ("dryRun" in next) {
29
30
  flags.dryRun = Boolean(next.dryRun);
30
31
  }
32
+ if ("beginner" in next) {
33
+ flags.beginner = Boolean(next.beginner);
34
+ }
31
35
  if ("fromStep" in next) {
32
36
  flags.fromStep = typeof next.fromStep === "string" ? next.fromStep : undefined;
33
37
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sdd-cli",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
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": {