sdd-cli 0.1.15 → 0.1.17
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 +14 -0
- package/dist/cli.js +15 -0
- package/dist/commands/hello.js +18 -0
- package/dist/commands/quickstart.d.ts +1 -0
- package/dist/commands/quickstart.js +30 -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
|
@@ -112,6 +112,10 @@ Then:
|
|
|
112
112
|
```
|
|
113
113
|
sdd-cli hello
|
|
114
114
|
```
|
|
115
|
+
Or run a zero-friction demo:
|
|
116
|
+
```
|
|
117
|
+
sdd-cli quickstart --example saas
|
|
118
|
+
```
|
|
115
119
|
|
|
116
120
|
Package name on npm is `sdd-cli` (CLI commands remain `sdd-cli` and `sdd`).
|
|
117
121
|
|
|
@@ -149,8 +153,10 @@ Use `--questions` when you want the manual question-by-question flow.
|
|
|
149
153
|
|
|
150
154
|
### Core
|
|
151
155
|
- `sdd-cli hello` -- interactive session, project picker, full guided flow
|
|
156
|
+
- `sdd-cli quickstart` -- one-command demo flow with built-in examples
|
|
152
157
|
- `sdd-cli init` -- create SDD workspace and config
|
|
153
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
|
|
154
160
|
- `sdd-cli doctor` -- validate completeness and consistency
|
|
155
161
|
|
|
156
162
|
### Router
|
|
@@ -187,6 +193,9 @@ Use `--questions` when you want the manual question-by-question flow.
|
|
|
187
193
|
- `--parallel` -- generate in parallel
|
|
188
194
|
- `--questions` -- use manual question-driven discovery flow
|
|
189
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`
|
|
190
199
|
- `--alias sdd` -- optional alias to run as `sdd`
|
|
191
200
|
|
|
192
201
|
## Beginner quickstart
|
|
@@ -215,6 +224,11 @@ sdd-cli hello "I want a simple booking system for appointments"
|
|
|
215
224
|
- Preview autopilot steps without writing files:
|
|
216
225
|
`sdd-cli --dry-run hello "<your intent>"`
|
|
217
226
|
|
|
227
|
+
## Execution tracking
|
|
228
|
+
|
|
229
|
+
- Adoption execution tracker: `AGENTS.md`
|
|
230
|
+
- 90-day roadmap: `docs/ADOPTION_ROADMAP_90D.md`
|
|
231
|
+
|
|
218
232
|
## Where files are stored (clean repos)
|
|
219
233
|
|
|
220
234
|
By default, the tool writes to a dedicated workspace, not into your repo:
|
package/dist/cli.js
CHANGED
|
@@ -44,6 +44,8 @@ const hello_1 = require("./commands/hello");
|
|
|
44
44
|
const init_1 = require("./commands/init");
|
|
45
45
|
const route_1 = require("./commands/route");
|
|
46
46
|
const doctor_1 = require("./commands/doctor");
|
|
47
|
+
const quickstart_1 = require("./commands/quickstart");
|
|
48
|
+
const status_1 = require("./commands/status");
|
|
47
49
|
const paths_1 = require("./paths");
|
|
48
50
|
const flags_1 = require("./context/flags");
|
|
49
51
|
const prompt_1 = require("./ui/prompt");
|
|
@@ -67,6 +69,7 @@ program
|
|
|
67
69
|
.option("--parallel", "Generate in parallel when supported")
|
|
68
70
|
.option("--non-interactive", "Run with defaults and without prompt confirmations")
|
|
69
71
|
.option("--dry-run", "Preview autopilot steps without writing artifacts")
|
|
72
|
+
.option("--beginner", "Enable extra step-by-step guidance in hello flow")
|
|
70
73
|
.option("--from-step <step>", "Resume or start autopilot from step: create|plan|start|test|finish")
|
|
71
74
|
.option("--project <name>", "Select or name the project")
|
|
72
75
|
.option("--output <path>", "Override workspace output root");
|
|
@@ -78,6 +81,7 @@ program.hook("preAction", (thisCommand, actionCommand) => {
|
|
|
78
81
|
parallel: Boolean(opts.parallel),
|
|
79
82
|
nonInteractive: Boolean(opts.nonInteractive),
|
|
80
83
|
dryRun: Boolean(opts.dryRun),
|
|
84
|
+
beginner: Boolean(opts.beginner),
|
|
81
85
|
fromStep: typeof opts.fromStep === "string" ? opts.fromStep : undefined,
|
|
82
86
|
project: typeof opts.project === "string" ? opts.project : undefined,
|
|
83
87
|
output: typeof opts.output === "string" ? opts.output : undefined
|
|
@@ -97,6 +101,12 @@ program
|
|
|
97
101
|
.command("init")
|
|
98
102
|
.description("Initialize workspace and config")
|
|
99
103
|
.action(() => (0, init_1.runInit)());
|
|
104
|
+
program
|
|
105
|
+
.command("quickstart")
|
|
106
|
+
.description("Run a zero-friction autopilot demo flow")
|
|
107
|
+
.option("--example <name>", "Example prompt: saas|bugfix|api|ecommerce|mobile")
|
|
108
|
+
.option("--list-examples", "List available example prompts")
|
|
109
|
+
.action((options) => (0, quickstart_1.runQuickstart)(options.example, options.listExamples));
|
|
100
110
|
program
|
|
101
111
|
.command("list")
|
|
102
112
|
.description("List flows, templates, and projects")
|
|
@@ -104,6 +114,11 @@ program
|
|
|
104
114
|
const { runList } = await Promise.resolve().then(() => __importStar(require("./commands/list")));
|
|
105
115
|
runList();
|
|
106
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)));
|
|
107
122
|
const req = program.command("req").description("Requirement lifecycle commands");
|
|
108
123
|
req
|
|
109
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 runQuickstart(example?: string, listExamples?: boolean): Promise<void>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runQuickstart = runQuickstart;
|
|
4
|
+
const flags_1 = require("../context/flags");
|
|
5
|
+
const hello_1 = require("./hello");
|
|
6
|
+
const QUICKSTART_EXAMPLES = {
|
|
7
|
+
saas: "Build a SaaS onboarding workflow for first-time users",
|
|
8
|
+
bugfix: "Fix a high-priority login failure with reproducible steps and tests",
|
|
9
|
+
api: "Design a REST API for order management with validation and error handling",
|
|
10
|
+
ecommerce: "Create an ecommerce checkout flow with payments and order confirmation",
|
|
11
|
+
mobile: "Plan a mobile app feature for push notifications and user preferences"
|
|
12
|
+
};
|
|
13
|
+
function normalizeExample(example) {
|
|
14
|
+
const value = (example || "saas").trim().toLowerCase();
|
|
15
|
+
return QUICKSTART_EXAMPLES[value] ? value : "saas";
|
|
16
|
+
}
|
|
17
|
+
async function runQuickstart(example, listExamples) {
|
|
18
|
+
if (listExamples) {
|
|
19
|
+
console.log("Quickstart examples:");
|
|
20
|
+
Object.entries(QUICKSTART_EXAMPLES).forEach(([key, prompt]) => {
|
|
21
|
+
console.log(`- ${key}: ${prompt}`);
|
|
22
|
+
});
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const selected = normalizeExample(example);
|
|
26
|
+
const seed = QUICKSTART_EXAMPLES[selected];
|
|
27
|
+
console.log(`Running quickstart example: ${selected}`);
|
|
28
|
+
(0, flags_1.setFlags)({ nonInteractive: true });
|
|
29
|
+
await (0, hello_1.runHello)(seed, false);
|
|
30
|
+
}
|
|
@@ -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
|
}
|