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 +8 -0
- package/dist/cli.js +8 -0
- package/dist/commands/hello.js +18 -0
- package/dist/commands/status.d.ts +1 -0
- package/dist/commands/status.js +97 -0
- package/dist/context/flags.d.ts +1 -0
- package/dist/context/flags.js +4 -0
- package/package.json +1 -1
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")
|
package/dist/commands/hello.js
CHANGED
|
@@ -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
|
+
}
|
package/dist/context/flags.d.ts
CHANGED
package/dist/context/flags.js
CHANGED
|
@@ -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
|
}
|