sdd-cli 0.1.9 → 0.1.11
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 +32 -14
- package/dist/cli.js +2 -0
- package/dist/commands/hello.js +44 -11
- package/dist/context/flags.d.ts +1 -0
- package/dist/context/flags.js +4 -0
- package/dist/ui/prompt.js +9 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -117,31 +117,32 @@ Package name on npm is `sdd-cli` (CLI commands remain `sdd-cli` and `sdd`).
|
|
|
117
117
|
|
|
118
118
|
Project names must use letters, numbers, spaces, `-` or `_`, and cannot include path separators.
|
|
119
119
|
|
|
120
|
-
The `hello` command is the entry point: it connects to AI, lists active projects, and offers to create a new one or continue.
|
|
120
|
+
The `hello` command is the entry point: it connects to AI, lists active projects, and offers to create a new one or continue.
|
|
121
|
+
Default behavior is now a guided autopilot from discovery to completion with minimal prompts.
|
|
122
|
+
Use `--questions` when you want the manual question-by-question flow.
|
|
121
123
|
|
|
122
124
|
## The happy path (end-to-end flow)
|
|
123
125
|
|
|
124
126
|
1) **Start**
|
|
125
127
|
`sdd-cli hello` connects to AI, shows active projects, and asks if you want to start new or continue.
|
|
126
|
-
It also asks for project name, domain, output location, language profile, and quality level.
|
|
127
128
|
|
|
128
|
-
2) **
|
|
129
|
-
|
|
129
|
+
2) **Autopilot Discovery**
|
|
130
|
+
Creates a requirement draft in backlog with validated defaults.
|
|
130
131
|
|
|
131
|
-
3) **
|
|
132
|
-
|
|
132
|
+
3) **Autopilot Planning**
|
|
133
|
+
Generates functional spec, technical spec, architecture, and test plan drafts.
|
|
133
134
|
|
|
134
|
-
4) **
|
|
135
|
-
|
|
135
|
+
4) **Autopilot Start**
|
|
136
|
+
Creates implementation plan and quality artifacts; moves requirement to `in-progress`.
|
|
136
137
|
|
|
137
|
-
5) **
|
|
138
|
-
|
|
138
|
+
5) **Autopilot Verify**
|
|
139
|
+
Updates/validates test-plan artifacts.
|
|
139
140
|
|
|
140
|
-
6) **
|
|
141
|
-
|
|
141
|
+
6) **Autopilot Finish**
|
|
142
|
+
Finalizes requirement, writes project-level README artifacts, and moves requirement to `done`.
|
|
142
143
|
|
|
143
|
-
7) **
|
|
144
|
-
`sdd-cli
|
|
144
|
+
7) **Manual Detail (optional)**
|
|
145
|
+
Run `sdd-cli hello --questions` when you prefer detailed prompt packs before drafting.
|
|
145
146
|
|
|
146
147
|
## Commands (proposed)
|
|
147
148
|
|
|
@@ -183,8 +184,25 @@ The `hello` command is the entry point: it connects to AI, lists active projects
|
|
|
183
184
|
- `--output <path>` -- override workspace output
|
|
184
185
|
- `--project <name>` -- set project name
|
|
185
186
|
- `--parallel` -- generate in parallel
|
|
187
|
+
- `--questions` -- use manual question-driven discovery flow
|
|
188
|
+
- `--non-interactive` -- run without confirmations (script/CI friendly)
|
|
186
189
|
- `--alias sdd` -- optional alias to run as `sdd`
|
|
187
190
|
|
|
191
|
+
## Beginner quickstart
|
|
192
|
+
|
|
193
|
+
1) Install:
|
|
194
|
+
```
|
|
195
|
+
npm install -g sdd-cli
|
|
196
|
+
```
|
|
197
|
+
2) Run:
|
|
198
|
+
```
|
|
199
|
+
sdd-cli hello "I want a simple booking system for appointments"
|
|
200
|
+
```
|
|
201
|
+
3) Follow minimal prompts (workspace/project confirmation).
|
|
202
|
+
4) Let autopilot complete the full flow.
|
|
203
|
+
5) Check output in:
|
|
204
|
+
`<workspace>/<project>/requirements/done/<REQ-ID>/`
|
|
205
|
+
|
|
188
206
|
## Where files are stored (clean repos)
|
|
189
207
|
|
|
190
208
|
By default, the tool writes to a dedicated workspace, not into your repo:
|
package/dist/cli.js
CHANGED
|
@@ -65,6 +65,7 @@ program
|
|
|
65
65
|
.option("--approve", "Skip confirmations if gates pass")
|
|
66
66
|
.option("--improve", "Trigger self-audit and regenerate")
|
|
67
67
|
.option("--parallel", "Generate in parallel when supported")
|
|
68
|
+
.option("--non-interactive", "Run with defaults and without prompt confirmations")
|
|
68
69
|
.option("--project <name>", "Select or name the project")
|
|
69
70
|
.option("--output <path>", "Override workspace output root");
|
|
70
71
|
program.hook("preAction", (thisCommand, actionCommand) => {
|
|
@@ -73,6 +74,7 @@ program.hook("preAction", (thisCommand, actionCommand) => {
|
|
|
73
74
|
approve: Boolean(opts.approve),
|
|
74
75
|
improve: Boolean(opts.improve),
|
|
75
76
|
parallel: Boolean(opts.parallel),
|
|
77
|
+
nonInteractive: Boolean(opts.nonInteractive),
|
|
76
78
|
project: typeof opts.project === "string" ? opts.project : undefined,
|
|
77
79
|
output: typeof opts.output === "string" ? opts.output : undefined
|
|
78
80
|
});
|
package/dist/commands/hello.js
CHANGED
|
@@ -13,6 +13,27 @@ 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
|
+
function printStep(step, description) {
|
|
17
|
+
console.log(`${step}: ${description}`);
|
|
18
|
+
}
|
|
19
|
+
function printWhy(message) {
|
|
20
|
+
console.log(` -> ${message}`);
|
|
21
|
+
}
|
|
22
|
+
function deriveProjectName(input, flow) {
|
|
23
|
+
const seed = input
|
|
24
|
+
.trim()
|
|
25
|
+
.toLowerCase()
|
|
26
|
+
.replace(/[^a-z0-9 _-]+/g, " ")
|
|
27
|
+
.replace(/\s+/g, " ")
|
|
28
|
+
.trim()
|
|
29
|
+
.split(" ")
|
|
30
|
+
.filter((token) => token.length > 0)
|
|
31
|
+
.slice(0, 4)
|
|
32
|
+
.join("-");
|
|
33
|
+
const date = new Date().toISOString().slice(0, 10).replace(/-/g, "");
|
|
34
|
+
const base = seed.length > 0 ? seed : flow.toLowerCase();
|
|
35
|
+
return `autopilot-${base}-${date}`;
|
|
36
|
+
}
|
|
16
37
|
function buildAutopilotDraft(input, flow, domain) {
|
|
17
38
|
const cleanInput = input.trim();
|
|
18
39
|
const objective = cleanInput.length > 0 ? cleanInput : "Deliver a clear first requirement draft.";
|
|
@@ -127,16 +148,18 @@ async function runHello(input, runQuestions) {
|
|
|
127
148
|
}
|
|
128
149
|
const intent = (0, intent_1.classifyIntent)(text);
|
|
129
150
|
console.log(`Detected intent: ${intent.intent} -> ${intent.flow}`);
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
151
|
+
printStep("Step 1/7", "Intent detected");
|
|
152
|
+
printWhy("I classified your goal and selected the best starting flow.");
|
|
153
|
+
const showRoute = runQuestions === true ? await (0, prompt_1.confirm)("View route details now? (y/n) ") : false;
|
|
154
|
+
if (showRoute && runQuestions === true) {
|
|
133
155
|
(0, route_1.runRoute)(text);
|
|
134
156
|
}
|
|
135
157
|
else {
|
|
136
158
|
console.log("Next: run `sdd-cli route <your input>` to view details.");
|
|
137
159
|
}
|
|
138
160
|
const shouldRunQuestions = runQuestions === true;
|
|
139
|
-
|
|
161
|
+
printStep("Step 2/7", "Requirement setup");
|
|
162
|
+
printWhy("I will gather enough context to generate a valid first draft.");
|
|
140
163
|
if (shouldRunQuestions) {
|
|
141
164
|
const packs = (0, prompt_packs_1.loadPromptPacks)();
|
|
142
165
|
const packIds = intent_1.FLOW_PROMPT_PACKS[intent.flow] ?? [];
|
|
@@ -163,28 +186,35 @@ async function runHello(input, runQuestions) {
|
|
|
163
186
|
if (ok) {
|
|
164
187
|
const created = await (0, req_create_1.runReqCreate)(mapped, { autofill: true });
|
|
165
188
|
if (created) {
|
|
166
|
-
|
|
189
|
+
printStep("Step 3/7", `Draft created (${created.reqId})`);
|
|
167
190
|
console.log("Next suggested command: sdd-cli req refine");
|
|
168
191
|
}
|
|
169
192
|
}
|
|
170
193
|
}
|
|
171
194
|
}
|
|
172
195
|
else {
|
|
173
|
-
|
|
196
|
+
let activeProject = (0, flags_1.getFlags)().project;
|
|
197
|
+
if (!activeProject) {
|
|
198
|
+
const quickProject = await (0, prompt_1.ask)("Project name (optional, press Enter to auto-generate): ");
|
|
199
|
+
activeProject = quickProject || deriveProjectName(text, intent.flow);
|
|
200
|
+
}
|
|
174
201
|
if (!activeProject) {
|
|
175
202
|
console.log("Project name is required to run autopilot.");
|
|
176
203
|
return;
|
|
177
204
|
}
|
|
205
|
+
printWhy(`Using project: ${activeProject}`);
|
|
178
206
|
(0, flags_1.setFlags)({ project: activeProject });
|
|
179
207
|
const draft = buildAutopilotDraft(text, intent.flow, intent.domain);
|
|
180
208
|
draft.project_name = activeProject;
|
|
181
|
-
|
|
209
|
+
printStep("Step 3/7", "Creating requirement draft automatically");
|
|
210
|
+
printWhy("This creates your baseline scope, acceptance criteria, and NFRs.");
|
|
182
211
|
const created = await (0, req_create_1.runReqCreate)(draft, { autofill: true });
|
|
183
212
|
if (!created) {
|
|
184
213
|
console.log("Autopilot stopped at requirement creation.");
|
|
185
214
|
return;
|
|
186
215
|
}
|
|
187
|
-
|
|
216
|
+
printStep("Step 4/7", `Planning requirement ${created.reqId}`);
|
|
217
|
+
printWhy("I am generating functional, technical, architecture, and test artifacts.");
|
|
188
218
|
const planned = await (0, req_plan_1.runReqPlan)({
|
|
189
219
|
projectName: activeProject,
|
|
190
220
|
reqId: created.reqId,
|
|
@@ -195,7 +225,8 @@ async function runHello(input, runQuestions) {
|
|
|
195
225
|
console.log("Autopilot stopped at planning.");
|
|
196
226
|
return;
|
|
197
227
|
}
|
|
198
|
-
|
|
228
|
+
printStep("Step 5/7", `Preparing implementation plan for ${created.reqId}`);
|
|
229
|
+
printWhy("This stage defines milestones, tasks, quality thresholds, and decisions.");
|
|
199
230
|
const started = await (0, req_start_1.runReqStart)({
|
|
200
231
|
projectName: activeProject,
|
|
201
232
|
reqId: created.reqId,
|
|
@@ -206,7 +237,8 @@ async function runHello(input, runQuestions) {
|
|
|
206
237
|
console.log("Autopilot stopped at start phase.");
|
|
207
238
|
return;
|
|
208
239
|
}
|
|
209
|
-
|
|
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.");
|
|
210
242
|
const tested = await (0, test_plan_1.runTestPlan)({
|
|
211
243
|
projectName: activeProject,
|
|
212
244
|
reqId: created.reqId,
|
|
@@ -217,7 +249,8 @@ async function runHello(input, runQuestions) {
|
|
|
217
249
|
console.log("Autopilot stopped at test planning.");
|
|
218
250
|
return;
|
|
219
251
|
}
|
|
220
|
-
|
|
252
|
+
printStep("Step 7/7", `Finalizing requirement ${created.reqId}`);
|
|
253
|
+
printWhy("I will move artifacts to done state and generate project-level summary files.");
|
|
221
254
|
const finished = await (0, req_finish_1.runReqFinish)({
|
|
222
255
|
projectName: activeProject,
|
|
223
256
|
reqId: created.reqId,
|
package/dist/context/flags.d.ts
CHANGED
package/dist/context/flags.js
CHANGED
|
@@ -6,6 +6,7 @@ const flags = {
|
|
|
6
6
|
approve: false,
|
|
7
7
|
improve: false,
|
|
8
8
|
parallel: false,
|
|
9
|
+
nonInteractive: false,
|
|
9
10
|
project: undefined,
|
|
10
11
|
output: undefined
|
|
11
12
|
};
|
|
@@ -19,6 +20,9 @@ function setFlags(next) {
|
|
|
19
20
|
if ("parallel" in next) {
|
|
20
21
|
flags.parallel = Boolean(next.parallel);
|
|
21
22
|
}
|
|
23
|
+
if ("nonInteractive" in next) {
|
|
24
|
+
flags.nonInteractive = Boolean(next.nonInteractive);
|
|
25
|
+
}
|
|
22
26
|
if ("project" in next) {
|
|
23
27
|
flags.project = typeof next.project === "string" ? next.project : undefined;
|
|
24
28
|
}
|
package/dist/ui/prompt.js
CHANGED
|
@@ -13,6 +13,10 @@ const flags_1 = require("../context/flags");
|
|
|
13
13
|
let queuedAnswers = null;
|
|
14
14
|
let rl = null;
|
|
15
15
|
function shouldUseQueuedAnswers() {
|
|
16
|
+
const flags = (0, flags_1.getFlags)();
|
|
17
|
+
if (flags.nonInteractive || process.env.SDD_NON_INTERACTIVE === "1") {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
16
20
|
if (process.env.SDD_STDIN === "1") {
|
|
17
21
|
return true;
|
|
18
22
|
}
|
|
@@ -55,6 +59,10 @@ function closePrompt() {
|
|
|
55
59
|
}
|
|
56
60
|
process.on("exit", () => closePrompt());
|
|
57
61
|
function ask(question) {
|
|
62
|
+
const flags = (0, flags_1.getFlags)();
|
|
63
|
+
if (flags.nonInteractive || process.env.SDD_NON_INTERACTIVE === "1") {
|
|
64
|
+
return Promise.resolve("");
|
|
65
|
+
}
|
|
58
66
|
if (shouldUseQueuedAnswers()) {
|
|
59
67
|
const queue = getQueuedAnswers();
|
|
60
68
|
const answer = queue.shift() ?? "";
|
|
@@ -76,7 +84,7 @@ async function askProjectName(prompt = "Project name: ") {
|
|
|
76
84
|
}
|
|
77
85
|
async function confirm(question) {
|
|
78
86
|
const flags = (0, flags_1.getFlags)();
|
|
79
|
-
if (flags.approve) {
|
|
87
|
+
if (flags.approve || flags.nonInteractive || process.env.SDD_NON_INTERACTIVE === "1") {
|
|
80
88
|
return true;
|
|
81
89
|
}
|
|
82
90
|
const response = await ask(question);
|