sdd-cli 0.1.7 → 0.1.8

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.
@@ -9,6 +9,62 @@ const prompt_map_1 = require("../router/prompt-map");
9
9
  const req_create_1 = require("./req-create");
10
10
  const flags_1 = require("../context/flags");
11
11
  const route_1 = require("./route");
12
+ function buildAutopilotDraft(input, flow, domain) {
13
+ const cleanInput = input.trim();
14
+ const objective = cleanInput.length > 0 ? cleanInput : "Deliver a clear first requirement draft.";
15
+ const scopeByFlow = {
16
+ BUG_FIX: "Reproduce issue, isolate root cause, define fix",
17
+ PR_REVIEW: "Review feedback, plan responses, track actions",
18
+ SOFTWARE_FEATURE: "Core feature behavior and acceptance flow",
19
+ DATA_SCIENCE: "Dataset, modeling approach, and evaluation plan",
20
+ DESIGN: "Core design goals, accessibility, and deliverables",
21
+ HUMANITIES: "Research question, sources, and analytical lens",
22
+ BUSINESS: "Business objective, model assumptions, and constraints",
23
+ LEGAL: "Applicable legal constraints and compliance requirements",
24
+ LEARN: "Learning objective, structure, and practice outputs",
25
+ GENERIC: "Core user need and initial delivery scope"
26
+ };
27
+ const outByFlow = {
28
+ BUG_FIX: "Unrelated refactors not needed for this fix",
29
+ PR_REVIEW: "Changes outside current PR scope",
30
+ SOFTWARE_FEATURE: "Future enhancements after MVP",
31
+ DATA_SCIENCE: "Production hardening beyond first iteration",
32
+ DESIGN: "Full rebrand outside stated objective",
33
+ HUMANITIES: "Unrelated historical periods or disciplines",
34
+ BUSINESS: "Additional markets not in initial launch",
35
+ LEGAL: "Jurisdictions outside selected compliance scope",
36
+ LEARN: "Advanced topics outside current learning target",
37
+ GENERIC: "Additional ideas to evaluate in next iteration"
38
+ };
39
+ const actorByDomain = {
40
+ bug_fix: "developer, qa",
41
+ pr_review: "reviewer, contributor",
42
+ software: "end user, product owner, developer",
43
+ data_science: "analyst, data scientist, stakeholder",
44
+ design: "designer, end user, stakeholder",
45
+ humanities: "researcher, reader",
46
+ business: "customer, business owner, operator",
47
+ legal: "legal team, compliance owner",
48
+ learning: "learner, mentor",
49
+ generic: "user, stakeholder"
50
+ };
51
+ const safeFlow = scopeByFlow[flow] ? flow : "GENERIC";
52
+ const safeDomain = actorByDomain[domain] ? domain : "generic";
53
+ return {
54
+ domain: safeDomain === "generic" ? "software" : safeDomain,
55
+ actors: actorByDomain[safeDomain],
56
+ objective,
57
+ scope_in: scopeByFlow[safeFlow],
58
+ scope_out: outByFlow[safeFlow],
59
+ acceptance_criteria: "A baseline requirement is generated and ready for refinement with stakeholders",
60
+ nfr_security: "Follow secure defaults and data handling best practices",
61
+ nfr_performance: "Set practical baseline targets for first delivery",
62
+ nfr_availability: "Keep workflow usable and stable for normal usage",
63
+ constraints: "Timebox first iteration, keep implementation simple",
64
+ risks: "Ambiguity in requirements, underestimated scope",
65
+ links: ""
66
+ };
67
+ }
12
68
  async function runHello(input, runQuestions) {
13
69
  function loadWorkspace() {
14
70
  const workspace = (0, index_1.getWorkspaceInfo)();
@@ -67,6 +123,7 @@ async function runHello(input, runQuestions) {
67
123
  }
68
124
  const intent = (0, intent_1.classifyIntent)(text);
69
125
  console.log(`Detected intent: ${intent.intent} -> ${intent.flow}`);
126
+ console.log("Step 1/3: Intent detected.");
70
127
  const showRoute = await (0, prompt_1.confirm)("View route details now? (y/n) ");
71
128
  if (showRoute) {
72
129
  (0, route_1.runRoute)(text);
@@ -75,6 +132,7 @@ async function runHello(input, runQuestions) {
75
132
  console.log("Next: run `sdd-cli route <your input>` to view details.");
76
133
  }
77
134
  const shouldRunQuestions = runQuestions ?? (await (0, prompt_1.confirm)("Run prompt questions now? (y/n) "));
135
+ console.log("Step 2/3: Requirement setup.");
78
136
  if (shouldRunQuestions) {
79
137
  const packs = (0, prompt_packs_1.loadPromptPacks)();
80
138
  const packIds = intent_1.FLOW_PROMPT_PACKS[intent.flow] ?? [];
@@ -99,13 +157,30 @@ async function runHello(input, runQuestions) {
99
157
  console.log(JSON.stringify(mapped, null, 2));
100
158
  const ok = await (0, prompt_1.confirm)("Generate requirement draft now? (y/n) ");
101
159
  if (ok) {
102
- await (0, req_create_1.runReqCreate)(mapped);
160
+ const created = await (0, req_create_1.runReqCreate)(mapped, { autofill: true });
161
+ if (created) {
162
+ console.log(`Step 3/3: Draft created (${created.reqId}).`);
163
+ console.log("Next suggested command: sdd-cli req refine");
164
+ }
103
165
  }
104
166
  }
105
167
  }
106
168
  else {
107
- console.log("\nNext steps:");
108
- console.log("- Run `sdd-cli route \"<your input>\"` to review the flow.");
109
- console.log("- Run `sdd-cli req create` to draft a requirement.");
169
+ const auto = await (0, prompt_1.confirm)("Create a first requirement draft automatically now? (y/n) ");
170
+ if (auto) {
171
+ const draft = buildAutopilotDraft(text, intent.flow, intent.domain);
172
+ const created = await (0, req_create_1.runReqCreate)(draft, { autofill: true });
173
+ if (created) {
174
+ console.log(`Step 3/3: Draft created (${created.reqId}).`);
175
+ console.log("Next suggested commands:");
176
+ console.log("- sdd-cli req refine");
177
+ console.log("- sdd-cli req plan");
178
+ }
179
+ }
180
+ else {
181
+ console.log("\nNext steps:");
182
+ console.log("- Run `sdd-cli route \"<your input>\"` to review the flow.");
183
+ console.log("- Run `sdd-cli req create` to draft a requirement.");
184
+ }
110
185
  }
111
186
  }
@@ -1,4 +1,7 @@
1
1
  export type RequirementDraft = {
2
+ project_name?: string;
3
+ domain?: string;
4
+ actors?: string;
2
5
  objective?: string;
3
6
  scope_in?: string;
4
7
  scope_out?: string;
@@ -6,5 +9,16 @@ export type RequirementDraft = {
6
9
  nfr_security?: string;
7
10
  nfr_performance?: string;
8
11
  nfr_availability?: string;
12
+ constraints?: string;
13
+ risks?: string;
14
+ links?: string;
9
15
  };
10
- export declare function runReqCreate(draft?: RequirementDraft): Promise<void>;
16
+ export type ReqCreateOptions = {
17
+ autofill?: boolean;
18
+ };
19
+ export type ReqCreateResult = {
20
+ reqId: string;
21
+ requirementDir: string;
22
+ projectRoot: string;
23
+ };
24
+ export declare function runReqCreate(draft?: RequirementDraft, options?: ReqCreateOptions): Promise<ReqCreateResult | null>;
@@ -17,20 +17,26 @@ function generateId() {
17
17
  const stamp = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, "0")}${String(now.getDate()).padStart(2, "0")}${String(now.getHours()).padStart(2, "0")}${String(now.getMinutes()).padStart(2, "0")}`;
18
18
  return `REQ-${stamp}`;
19
19
  }
20
- async function runReqCreate(draft) {
21
- const projectName = await (0, prompt_1.askProjectName)();
22
- const domain = await (0, prompt_1.ask)("Domain (software, legal, design, learning, etc): ");
23
- const actors = await (0, prompt_1.ask)("Actors - comma separated: ");
24
- let objective = draft?.objective ?? (await (0, prompt_1.ask)("Objective: "));
25
- let scopeIn = draft?.scope_in ?? (await (0, prompt_1.ask)("Scope (in) - comma separated: "));
26
- let scopeOut = draft?.scope_out ?? (await (0, prompt_1.ask)("Scope (out) - comma separated: "));
27
- let acceptance = draft?.acceptance_criteria ?? (await (0, prompt_1.ask)("Acceptance criteria - comma separated: "));
28
- let nfrSecurity = draft?.nfr_security ?? (await (0, prompt_1.ask)("NFR security: "));
29
- let nfrPerformance = draft?.nfr_performance ?? (await (0, prompt_1.ask)("NFR performance: "));
30
- let nfrAvailability = draft?.nfr_availability ?? (await (0, prompt_1.ask)("NFR availability: "));
31
- const constraints = await (0, prompt_1.ask)("Constraints - comma separated: ");
32
- const risks = await (0, prompt_1.ask)("Risks - comma separated: ");
33
- const links = await (0, prompt_1.ask)("Links - comma separated: ");
20
+ async function runReqCreate(draft, options) {
21
+ const auto = Boolean(options?.autofill);
22
+ const projectName = draft?.project_name?.trim() || (await (0, prompt_1.askProjectName)());
23
+ if (!projectName) {
24
+ console.log("Project name is required.");
25
+ return null;
26
+ }
27
+ const domain = draft?.domain ?? (auto ? "software" : await (0, prompt_1.ask)("Domain (software, legal, design, learning, etc): "));
28
+ const actors = draft?.actors ?? (auto ? "user, stakeholder" : await (0, prompt_1.ask)("Actors - comma separated: "));
29
+ let objective = draft?.objective ?? (auto ? "Initial requirement draft from user intent." : await (0, prompt_1.ask)("Objective: "));
30
+ let scopeIn = draft?.scope_in ?? (auto ? "core workflow" : await (0, prompt_1.ask)("Scope (in) - comma separated: "));
31
+ let scopeOut = draft?.scope_out ?? (auto ? "out-of-scope details to refine later" : await (0, prompt_1.ask)("Scope (out) - comma separated: "));
32
+ let acceptance = draft?.acceptance_criteria ??
33
+ (auto ? "A first working draft is generated and reviewable by stakeholders" : await (0, prompt_1.ask)("Acceptance criteria - comma separated: "));
34
+ let nfrSecurity = draft?.nfr_security ?? (auto ? "Apply baseline secure defaults" : await (0, prompt_1.ask)("NFR security: "));
35
+ let nfrPerformance = draft?.nfr_performance ?? (auto ? "Reasonable default performance budget" : await (0, prompt_1.ask)("NFR performance: "));
36
+ let nfrAvailability = draft?.nfr_availability ?? (auto ? "Service remains available during normal usage" : await (0, prompt_1.ask)("NFR availability: "));
37
+ const constraints = draft?.constraints ?? (auto ? "" : await (0, prompt_1.ask)("Constraints - comma separated: "));
38
+ const risks = draft?.risks ?? (auto ? "" : await (0, prompt_1.ask)("Risks - comma separated: "));
39
+ const links = draft?.links ?? (auto ? "" : await (0, prompt_1.ask)("Links - comma separated: "));
34
40
  const workspace = (0, index_1.getWorkspaceInfo)();
35
41
  let project;
36
42
  try {
@@ -38,7 +44,7 @@ async function runReqCreate(draft) {
38
44
  }
39
45
  catch (error) {
40
46
  console.log(error.message);
41
- return;
47
+ return null;
42
48
  }
43
49
  const metadata = (0, index_1.createProject)(workspace, project.name, domain || "software");
44
50
  const reqId = generateId();
@@ -67,21 +73,40 @@ async function runReqCreate(draft) {
67
73
  let gates = (0, gates_1.checkRequirementGates)(requirementJson);
68
74
  if (!gates.ok) {
69
75
  console.log("Requirement gates failed. Please provide missing fields:");
70
- for (const field of gates.missing) {
71
- if (field === "objective")
72
- objective = await (0, prompt_1.ask)("Objective: ");
73
- if (field === "scope.in")
74
- scopeIn = await (0, prompt_1.ask)("Scope (in) - comma separated: ");
75
- if (field === "scope.out")
76
- scopeOut = await (0, prompt_1.ask)("Scope (out) - comma separated: ");
77
- if (field === "acceptanceCriteria")
78
- acceptance = await (0, prompt_1.ask)("Acceptance criteria - comma separated: ");
79
- if (field === "nfrs.security")
80
- nfrSecurity = await (0, prompt_1.ask)("NFR security: ");
81
- if (field === "nfrs.performance")
82
- nfrPerformance = await (0, prompt_1.ask)("NFR performance: ");
83
- if (field === "nfrs.availability")
84
- nfrAvailability = await (0, prompt_1.ask)("NFR availability: ");
76
+ if (auto) {
77
+ if (gates.missing.includes("objective"))
78
+ objective = "Initial requirement draft from user intent.";
79
+ if (gates.missing.includes("scope.in"))
80
+ scopeIn = "core workflow";
81
+ if (gates.missing.includes("scope.out"))
82
+ scopeOut = "out-of-scope details to refine later";
83
+ if (gates.missing.includes("acceptanceCriteria")) {
84
+ acceptance = "A first working draft is generated and reviewable by stakeholders";
85
+ }
86
+ if (gates.missing.includes("nfrs.security"))
87
+ nfrSecurity = "Apply baseline secure defaults";
88
+ if (gates.missing.includes("nfrs.performance"))
89
+ nfrPerformance = "Reasonable default performance budget";
90
+ if (gates.missing.includes("nfrs.availability"))
91
+ nfrAvailability = "Service remains available during normal usage";
92
+ }
93
+ else {
94
+ for (const field of gates.missing) {
95
+ if (field === "objective")
96
+ objective = await (0, prompt_1.ask)("Objective: ");
97
+ if (field === "scope.in")
98
+ scopeIn = await (0, prompt_1.ask)("Scope (in) - comma separated: ");
99
+ if (field === "scope.out")
100
+ scopeOut = await (0, prompt_1.ask)("Scope (out) - comma separated: ");
101
+ if (field === "acceptanceCriteria")
102
+ acceptance = await (0, prompt_1.ask)("Acceptance criteria - comma separated: ");
103
+ if (field === "nfrs.security")
104
+ nfrSecurity = await (0, prompt_1.ask)("NFR security: ");
105
+ if (field === "nfrs.performance")
106
+ nfrPerformance = await (0, prompt_1.ask)("NFR performance: ");
107
+ if (field === "nfrs.availability")
108
+ nfrAvailability = await (0, prompt_1.ask)("NFR availability: ");
109
+ }
85
110
  }
86
111
  requirementJson = {
87
112
  ...requirementJson,
@@ -102,14 +127,14 @@ async function runReqCreate(draft) {
102
127
  if (!gates.ok) {
103
128
  console.log("Requirement gates still failing. Missing:");
104
129
  gates.missing.forEach((field) => console.log(`- ${field}`));
105
- return;
130
+ return null;
106
131
  }
107
132
  }
108
133
  const validation = (0, validate_1.validateJson)("requirement.schema.json", requirementJson);
109
134
  if (!validation.valid) {
110
135
  console.log("Requirement validation failed:");
111
136
  validation.errors.forEach((error) => console.log(`- ${error}`));
112
- return;
137
+ return null;
113
138
  }
114
139
  const requirementDir = path_1.default.join(project.root, "requirements", "backlog", reqId);
115
140
  fs_1.default.mkdirSync(requirementDir, { recursive: true });
@@ -148,4 +173,5 @@ async function runReqCreate(draft) {
148
173
  console.log(`Created requirement in ${requirementDir}`);
149
174
  console.log(`Project metadata stored in ${path_1.default.join(project.root, "metadata.json")}`);
150
175
  console.log(`Project status: ${metadata.status}`);
176
+ return { reqId, requirementDir, projectRoot: project.root };
151
177
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sdd-cli",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
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": {