sdd-cli 0.1.19 → 0.1.21
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 +41 -0
- package/dist/cli.js +58 -3
- package/dist/commands/ai-exec.js +3 -2
- package/dist/commands/ai-status.js +2 -1
- package/dist/commands/doctor.d.ts +1 -1
- package/dist/commands/doctor.js +218 -10
- package/dist/commands/gen-architecture.js +6 -5
- package/dist/commands/gen-best-practices.js +6 -5
- package/dist/commands/gen-functional-spec.js +6 -5
- package/dist/commands/gen-project-readme.js +6 -5
- package/dist/commands/gen-technical-spec.js +6 -5
- package/dist/commands/gen-utils.js +2 -1
- package/dist/commands/hello.js +27 -9
- package/dist/commands/import-issue.js +3 -2
- package/dist/commands/import-jira.d.ts +1 -0
- package/dist/commands/import-jira.js +127 -0
- package/dist/commands/learn-deliver.js +6 -5
- package/dist/commands/learn-refine.js +8 -7
- package/dist/commands/learn-start.js +3 -2
- package/dist/commands/list.js +19 -4
- package/dist/commands/pr-audit.js +6 -5
- package/dist/commands/pr-bridge-check.d.ts +1 -0
- package/dist/commands/pr-bridge-check.js +88 -0
- package/dist/commands/pr-bridge.d.ts +1 -0
- package/dist/commands/pr-bridge.js +124 -0
- package/dist/commands/pr-finish.js +6 -5
- package/dist/commands/pr-report.js +6 -5
- package/dist/commands/pr-respond.js +7 -6
- package/dist/commands/pr-risk.d.ts +1 -0
- package/dist/commands/pr-risk.js +112 -0
- package/dist/commands/pr-start.js +4 -3
- package/dist/commands/quickstart.js +10 -1
- package/dist/commands/req-archive.js +4 -3
- package/dist/commands/req-create.js +8 -7
- package/dist/commands/req-export.js +4 -3
- package/dist/commands/req-finish.js +9 -8
- package/dist/commands/req-lint.js +16 -6
- package/dist/commands/req-list.js +4 -3
- package/dist/commands/req-plan.js +12 -11
- package/dist/commands/req-refine.js +9 -8
- package/dist/commands/req-report.js +10 -9
- package/dist/commands/req-start.js +10 -9
- package/dist/commands/req-status.js +4 -3
- package/dist/commands/route.js +19 -4
- package/dist/commands/scope-list.d.ts +1 -0
- package/dist/commands/scope-list.js +16 -0
- package/dist/commands/scope-status.d.ts +1 -0
- package/dist/commands/scope-status.js +33 -0
- package/dist/commands/status.js +16 -7
- package/dist/commands/test-plan.js +6 -5
- package/dist/context/flags.d.ts +2 -0
- package/dist/context/flags.js +9 -1
- package/dist/errors.d.ts +2 -0
- package/dist/errors.js +10 -0
- package/dist/paths.js +4 -0
- package/dist/telemetry/local-metrics.d.ts +2 -0
- package/dist/telemetry/local-metrics.js +85 -0
- package/dist/workspace/index.d.ts +4 -0
- package/dist/workspace/index.js +129 -27
- package/package.json +24 -2
|
@@ -9,11 +9,12 @@ const path_1 = __importDefault(require("path"));
|
|
|
9
9
|
const prompt_1 = require("../ui/prompt");
|
|
10
10
|
const index_1 = require("../workspace/index");
|
|
11
11
|
const validate_1 = require("../validation/validate");
|
|
12
|
+
const errors_1 = require("../errors");
|
|
12
13
|
async function runReqLint() {
|
|
13
14
|
const projectName = await (0, prompt_1.askProjectName)();
|
|
14
15
|
const reqId = await (0, prompt_1.ask)("Requirement ID (REQ-...): ");
|
|
15
16
|
if (!projectName || !reqId) {
|
|
16
|
-
|
|
17
|
+
(0, errors_1.printError)("SDD-1247", "Project name and requirement ID are required.");
|
|
17
18
|
return;
|
|
18
19
|
}
|
|
19
20
|
const workspace = (0, index_1.getWorkspaceInfo)();
|
|
@@ -22,7 +23,7 @@ async function runReqLint() {
|
|
|
22
23
|
project = (0, index_1.getProjectInfo)(workspace, projectName);
|
|
23
24
|
}
|
|
24
25
|
catch (error) {
|
|
25
|
-
|
|
26
|
+
(0, errors_1.printError)("SDD-1248", error.message);
|
|
26
27
|
return;
|
|
27
28
|
}
|
|
28
29
|
const base = path_1.default.join(project.root, "requirements");
|
|
@@ -31,7 +32,7 @@ async function runReqLint() {
|
|
|
31
32
|
.map((status) => path_1.default.join(base, status, reqId))
|
|
32
33
|
.find((candidate) => fs_1.default.existsSync(candidate));
|
|
33
34
|
if (!dir) {
|
|
34
|
-
|
|
35
|
+
(0, errors_1.printError)("SDD-1249", "Requirement not found.");
|
|
35
36
|
return;
|
|
36
37
|
}
|
|
37
38
|
const schemaMap = {
|
|
@@ -49,12 +50,21 @@ async function runReqLint() {
|
|
|
49
50
|
if (!fs_1.default.existsSync(filePath)) {
|
|
50
51
|
continue;
|
|
51
52
|
}
|
|
52
|
-
|
|
53
|
+
let data;
|
|
54
|
+
try {
|
|
55
|
+
data = JSON.parse(fs_1.default.readFileSync(filePath, "utf-8"));
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
failures += 1;
|
|
59
|
+
(0, errors_1.printError)("SDD-1250", `Invalid JSON: ${file}`);
|
|
60
|
+
(0, errors_1.printError)("SDD-1250", error.message);
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
53
63
|
const result = (0, validate_1.validateJson)(schema, data);
|
|
54
64
|
if (!result.valid) {
|
|
55
65
|
failures += 1;
|
|
56
|
-
|
|
57
|
-
result.errors.forEach((error) =>
|
|
66
|
+
(0, errors_1.printError)("SDD-1250", `Invalid: ${file}`);
|
|
67
|
+
result.errors.forEach((error) => (0, errors_1.printError)("SDD-1250", error));
|
|
58
68
|
}
|
|
59
69
|
else {
|
|
60
70
|
console.log(`Valid: ${file}`);
|
|
@@ -8,11 +8,12 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const prompt_1 = require("../ui/prompt");
|
|
10
10
|
const index_1 = require("../workspace/index");
|
|
11
|
+
const errors_1 = require("../errors");
|
|
11
12
|
const STATUSES = ["backlog", "wip", "in-progress", "done", "archived"];
|
|
12
13
|
async function runReqList(statusFilter) {
|
|
13
14
|
const projectName = await (0, prompt_1.askProjectName)();
|
|
14
15
|
if (!projectName) {
|
|
15
|
-
|
|
16
|
+
(0, errors_1.printError)("SDD-1251", "Project name is required.");
|
|
16
17
|
return;
|
|
17
18
|
}
|
|
18
19
|
const workspace = (0, index_1.getWorkspaceInfo)();
|
|
@@ -21,12 +22,12 @@ async function runReqList(statusFilter) {
|
|
|
21
22
|
project = (0, index_1.getProjectInfo)(workspace, projectName);
|
|
22
23
|
}
|
|
23
24
|
catch (error) {
|
|
24
|
-
|
|
25
|
+
(0, errors_1.printError)("SDD-1252", error.message);
|
|
25
26
|
return;
|
|
26
27
|
}
|
|
27
28
|
const base = path_1.default.join(project.root, "requirements");
|
|
28
29
|
if (!fs_1.default.existsSync(base)) {
|
|
29
|
-
|
|
30
|
+
(0, errors_1.printError)("SDD-1253", "No requirements found for this project.");
|
|
30
31
|
return;
|
|
31
32
|
}
|
|
32
33
|
const statuses = statusFilter ? STATUSES.filter((status) => status === statusFilter) : STATUSES;
|
|
@@ -13,6 +13,7 @@ const render_1 = require("../templates/render");
|
|
|
13
13
|
const list_1 = require("../utils/list");
|
|
14
14
|
const gates_1 = require("../validation/gates");
|
|
15
15
|
const validate_1 = require("../validation/validate");
|
|
16
|
+
const errors_1 = require("../errors");
|
|
16
17
|
function findRequirementDir(projectRoot, reqId) {
|
|
17
18
|
const backlog = path_1.default.join(projectRoot, "requirements", "backlog", reqId);
|
|
18
19
|
const wip = path_1.default.join(projectRoot, "requirements", "wip", reqId);
|
|
@@ -31,7 +32,7 @@ async function runReqPlan(options) {
|
|
|
31
32
|
const projectName = options?.projectName ?? (await (0, prompt_1.askProjectName)());
|
|
32
33
|
const reqId = options?.reqId ?? (await (0, prompt_1.ask)("Requirement ID (REQ-...): "));
|
|
33
34
|
if (!projectName || !reqId) {
|
|
34
|
-
|
|
35
|
+
(0, errors_1.printError)("SDD-1211", "Project name and requirement ID are required.");
|
|
35
36
|
return null;
|
|
36
37
|
}
|
|
37
38
|
const workspace = (0, index_1.getWorkspaceInfo)();
|
|
@@ -40,31 +41,31 @@ async function runReqPlan(options) {
|
|
|
40
41
|
project = (0, index_1.getProjectInfo)(workspace, projectName);
|
|
41
42
|
}
|
|
42
43
|
catch (error) {
|
|
43
|
-
|
|
44
|
+
(0, errors_1.printError)("SDD-1212", error.message);
|
|
44
45
|
return null;
|
|
45
46
|
}
|
|
46
47
|
let requirementDir = findRequirementDir(project.root, reqId);
|
|
47
48
|
if (!requirementDir) {
|
|
48
|
-
|
|
49
|
+
(0, errors_1.printError)("SDD-1213", "Requirement not found in backlog or wip.");
|
|
49
50
|
return null;
|
|
50
51
|
}
|
|
51
52
|
const requirementJsonPath = path_1.default.join(requirementDir, "requirement.json");
|
|
52
53
|
if (!fs_1.default.existsSync(requirementJsonPath)) {
|
|
53
|
-
|
|
54
|
+
(0, errors_1.printError)("SDD-1214", "Missing requirement.json. Run `req create` first.");
|
|
54
55
|
return null;
|
|
55
56
|
}
|
|
56
57
|
const requirementJson = JSON.parse(fs_1.default.readFileSync(requirementJsonPath, "utf-8"));
|
|
57
58
|
let gates = (0, gates_1.checkRequirementGates)(requirementJson);
|
|
58
59
|
if (!gates.ok) {
|
|
59
|
-
|
|
60
|
-
gates.missing.forEach((field) =>
|
|
61
|
-
|
|
60
|
+
(0, errors_1.printError)("SDD-1217", "Requirement gates failed. Please update the requirement first.");
|
|
61
|
+
gates.missing.forEach((field) => (0, errors_1.printError)("SDD-1217", field));
|
|
62
|
+
(0, errors_1.printError)("SDD-1217", "Run `sdd-cli req refine` to complete missing fields.");
|
|
62
63
|
return null;
|
|
63
64
|
}
|
|
64
65
|
const requirementValidation = (0, validate_1.validateJson)("requirement.schema.json", requirementJson);
|
|
65
66
|
if (!requirementValidation.valid) {
|
|
66
|
-
|
|
67
|
-
requirementValidation.errors.forEach((error) =>
|
|
67
|
+
(0, errors_1.printError)("SDD-1215", "Requirement validation failed.");
|
|
68
|
+
requirementValidation.errors.forEach((error) => (0, errors_1.printError)("SDD-1215", error));
|
|
68
69
|
return null;
|
|
69
70
|
}
|
|
70
71
|
const wipDir = path_1.default.join(project.root, "requirements", "wip", reqId);
|
|
@@ -147,8 +148,8 @@ async function runReqPlan(options) {
|
|
|
147
148
|
];
|
|
148
149
|
const failures = validations.flatMap((result) => result.errors);
|
|
149
150
|
if (failures.length > 0) {
|
|
150
|
-
|
|
151
|
-
failures.forEach((error) =>
|
|
151
|
+
(0, errors_1.printError)("SDD-1216", "Spec validation failed.");
|
|
152
|
+
failures.forEach((error) => (0, errors_1.printError)("SDD-1216", error));
|
|
152
153
|
return null;
|
|
153
154
|
}
|
|
154
155
|
const functionalTemplate = (0, render_1.loadTemplate)("functional-spec");
|
|
@@ -13,6 +13,7 @@ const render_1 = require("../templates/render");
|
|
|
13
13
|
const list_1 = require("../utils/list");
|
|
14
14
|
const gates_1 = require("../validation/gates");
|
|
15
15
|
const validate_1 = require("../validation/validate");
|
|
16
|
+
const errors_1 = require("../errors");
|
|
16
17
|
function findRequirementFile(projectRoot, reqId) {
|
|
17
18
|
const base = path_1.default.join(projectRoot, "requirements");
|
|
18
19
|
const candidates = [
|
|
@@ -27,7 +28,7 @@ async function runReqRefine() {
|
|
|
27
28
|
const projectName = await (0, prompt_1.askProjectName)();
|
|
28
29
|
const reqId = await (0, prompt_1.ask)("Requirement ID (REQ-...): ");
|
|
29
30
|
if (!projectName || !reqId) {
|
|
30
|
-
|
|
31
|
+
(0, errors_1.printError)("SDD-1261", "Project name and requirement ID are required.");
|
|
31
32
|
return;
|
|
32
33
|
}
|
|
33
34
|
const workspace = (0, index_1.getWorkspaceInfo)();
|
|
@@ -36,12 +37,12 @@ async function runReqRefine() {
|
|
|
36
37
|
project = (0, index_1.getProjectInfo)(workspace, projectName);
|
|
37
38
|
}
|
|
38
39
|
catch (error) {
|
|
39
|
-
|
|
40
|
+
(0, errors_1.printError)("SDD-1262", error.message);
|
|
40
41
|
return;
|
|
41
42
|
}
|
|
42
43
|
const reqPath = findRequirementFile(project.root, reqId);
|
|
43
44
|
if (!reqPath) {
|
|
44
|
-
|
|
45
|
+
(0, errors_1.printError)("SDD-1263", "Requirement not found.");
|
|
45
46
|
return;
|
|
46
47
|
}
|
|
47
48
|
const raw = JSON.parse(fs_1.default.readFileSync(reqPath, "utf-8"));
|
|
@@ -79,7 +80,7 @@ async function runReqRefine() {
|
|
|
79
80
|
};
|
|
80
81
|
let gates = (0, gates_1.checkRequirementGates)(updated);
|
|
81
82
|
if (!gates.ok) {
|
|
82
|
-
|
|
83
|
+
(0, errors_1.printError)("SDD-1264", "Requirement gates failed. Please provide missing fields.");
|
|
83
84
|
for (const field of gates.missing) {
|
|
84
85
|
if (field === "objective") {
|
|
85
86
|
updated.objective = await (0, prompt_1.ask)(`Objective (${updated.objective}): `);
|
|
@@ -112,15 +113,15 @@ async function runReqRefine() {
|
|
|
112
113
|
updated.updatedAt = new Date().toISOString();
|
|
113
114
|
gates = (0, gates_1.checkRequirementGates)(updated);
|
|
114
115
|
if (!gates.ok) {
|
|
115
|
-
|
|
116
|
-
gates.missing.forEach((field) =>
|
|
116
|
+
(0, errors_1.printError)("SDD-1265", "Requirement gates still failing.");
|
|
117
|
+
gates.missing.forEach((field) => (0, errors_1.printError)("SDD-1265", field));
|
|
117
118
|
return;
|
|
118
119
|
}
|
|
119
120
|
}
|
|
120
121
|
const validation = (0, validate_1.validateJson)("requirement.schema.json", updated);
|
|
121
122
|
if (!validation.valid) {
|
|
122
|
-
|
|
123
|
-
validation.errors.forEach((error) =>
|
|
123
|
+
(0, errors_1.printError)("SDD-1266", "Requirement validation failed.");
|
|
124
|
+
validation.errors.forEach((error) => (0, errors_1.printError)("SDD-1266", error));
|
|
124
125
|
return;
|
|
125
126
|
}
|
|
126
127
|
fs_1.default.writeFileSync(reqPath, JSON.stringify(updated, null, 2), "utf-8");
|
|
@@ -8,6 +8,7 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const prompt_1 = require("../ui/prompt");
|
|
10
10
|
const index_1 = require("../workspace/index");
|
|
11
|
+
const errors_1 = require("../errors");
|
|
11
12
|
const REQUIRED_FILES = [
|
|
12
13
|
"requirement.json",
|
|
13
14
|
"functional-spec.json",
|
|
@@ -20,7 +21,7 @@ async function runReqReport() {
|
|
|
20
21
|
const projectName = await (0, prompt_1.askProjectName)();
|
|
21
22
|
const reqId = await (0, prompt_1.ask)("Requirement ID (REQ-...): ");
|
|
22
23
|
if (!projectName || !reqId) {
|
|
23
|
-
|
|
24
|
+
(0, errors_1.printError)("SDD-1257", "Project name and requirement ID are required.");
|
|
24
25
|
return;
|
|
25
26
|
}
|
|
26
27
|
const workspace = (0, index_1.getWorkspaceInfo)();
|
|
@@ -29,29 +30,29 @@ async function runReqReport() {
|
|
|
29
30
|
project = (0, index_1.getProjectInfo)(workspace, projectName);
|
|
30
31
|
}
|
|
31
32
|
catch (error) {
|
|
32
|
-
|
|
33
|
+
(0, errors_1.printError)("SDD-1258", error.message);
|
|
33
34
|
return;
|
|
34
35
|
}
|
|
35
36
|
const base = path_1.default.join(project.root, "requirements");
|
|
36
37
|
const statuses = ["backlog", "wip", "in-progress", "done", "archived"];
|
|
37
38
|
const dir = statuses.map((status) => path_1.default.join(base, status, reqId)).find((candidate) => fs_1.default.existsSync(candidate));
|
|
38
39
|
if (!dir) {
|
|
39
|
-
|
|
40
|
+
(0, errors_1.printError)("SDD-1259", "Requirement not found.");
|
|
40
41
|
return;
|
|
41
42
|
}
|
|
42
43
|
console.log(`Requirement report: ${reqId}`);
|
|
43
|
-
let
|
|
44
|
+
let absentCount = 0;
|
|
44
45
|
for (const file of REQUIRED_FILES) {
|
|
45
46
|
const exists = fs_1.default.existsSync(path_1.default.join(dir, file));
|
|
46
|
-
console.log(`${exists ? "OK" : "
|
|
47
|
+
console.log(`${exists ? "OK" : "ABSENT"}: ${file}`);
|
|
47
48
|
if (!exists)
|
|
48
|
-
|
|
49
|
+
absentCount += 1;
|
|
49
50
|
}
|
|
50
51
|
const projectReadmePath = path_1.default.join(project.root, "project-readme.json");
|
|
51
52
|
const projectReadmeExists = fs_1.default.existsSync(projectReadmePath);
|
|
52
|
-
console.log(`${projectReadmeExists ? "OK" : "
|
|
53
|
+
console.log(`${projectReadmeExists ? "OK" : "ABSENT"}: ../project-readme.json`);
|
|
53
54
|
if (!projectReadmeExists) {
|
|
54
|
-
|
|
55
|
+
absentCount += 1;
|
|
55
56
|
}
|
|
56
|
-
console.log(`
|
|
57
|
+
console.log(`Absent files: ${absentCount}`);
|
|
57
58
|
}
|
|
@@ -12,6 +12,7 @@ const index_1 = require("../workspace/index");
|
|
|
12
12
|
const render_1 = require("../templates/render");
|
|
13
13
|
const list_1 = require("../utils/list");
|
|
14
14
|
const validate_1 = require("../validation/validate");
|
|
15
|
+
const errors_1 = require("../errors");
|
|
15
16
|
function findRequirementDir(projectRoot, reqId) {
|
|
16
17
|
const backlog = path_1.default.join(projectRoot, "requirements", "backlog", reqId);
|
|
17
18
|
const wip = path_1.default.join(projectRoot, "requirements", "wip", reqId);
|
|
@@ -33,7 +34,7 @@ async function runReqStart(options) {
|
|
|
33
34
|
const projectName = options?.projectName ?? (await (0, prompt_1.askProjectName)());
|
|
34
35
|
const reqId = options?.reqId ?? (await (0, prompt_1.ask)("Requirement ID (REQ-...): "));
|
|
35
36
|
if (!projectName || !reqId) {
|
|
36
|
-
|
|
37
|
+
(0, errors_1.printError)("SDD-1221", "Project name and requirement ID are required.");
|
|
37
38
|
return null;
|
|
38
39
|
}
|
|
39
40
|
const workspace = (0, index_1.getWorkspaceInfo)();
|
|
@@ -42,12 +43,12 @@ async function runReqStart(options) {
|
|
|
42
43
|
project = (0, index_1.getProjectInfo)(workspace, projectName);
|
|
43
44
|
}
|
|
44
45
|
catch (error) {
|
|
45
|
-
|
|
46
|
+
(0, errors_1.printError)("SDD-1222", error.message);
|
|
46
47
|
return null;
|
|
47
48
|
}
|
|
48
49
|
let requirementDir = findRequirementDir(project.root, reqId);
|
|
49
50
|
if (!requirementDir) {
|
|
50
|
-
|
|
51
|
+
(0, errors_1.printError)("SDD-1223", "Requirement not found.");
|
|
51
52
|
return null;
|
|
52
53
|
}
|
|
53
54
|
const requirementPath = requirementDir;
|
|
@@ -59,16 +60,16 @@ async function runReqStart(options) {
|
|
|
59
60
|
];
|
|
60
61
|
const missing = requiredSpecs.filter((spec) => !fs_1.default.existsSync(path_1.default.join(requirementPath, spec.file)));
|
|
61
62
|
if (missing.length > 0) {
|
|
62
|
-
|
|
63
|
-
missing.forEach((spec) =>
|
|
63
|
+
(0, errors_1.printError)("SDD-1224", "Cannot start. Missing specs.");
|
|
64
|
+
missing.forEach((spec) => (0, errors_1.printError)("SDD-1224", spec.file));
|
|
64
65
|
return null;
|
|
65
66
|
}
|
|
66
67
|
for (const spec of requiredSpecs) {
|
|
67
68
|
const data = JSON.parse(fs_1.default.readFileSync(path_1.default.join(requirementPath, spec.file), "utf-8"));
|
|
68
69
|
const result = (0, validate_1.validateJson)(spec.schema, data);
|
|
69
70
|
if (!result.valid) {
|
|
70
|
-
|
|
71
|
-
result.errors.forEach((error) =>
|
|
71
|
+
(0, errors_1.printError)("SDD-1225", `Spec validation failed for ${spec.file}.`);
|
|
72
|
+
result.errors.forEach((error) => (0, errors_1.printError)("SDD-1225", error));
|
|
72
73
|
return null;
|
|
73
74
|
}
|
|
74
75
|
}
|
|
@@ -114,8 +115,8 @@ async function runReqStart(options) {
|
|
|
114
115
|
};
|
|
115
116
|
const validation = (0, validate_1.validateJson)("quality.schema.json", qualityJson);
|
|
116
117
|
if (!validation.valid) {
|
|
117
|
-
|
|
118
|
-
validation.errors.forEach((error) =>
|
|
118
|
+
(0, errors_1.printError)("SDD-1226", "Quality validation failed.");
|
|
119
|
+
validation.errors.forEach((error) => (0, errors_1.printError)("SDD-1226", error));
|
|
119
120
|
return null;
|
|
120
121
|
}
|
|
121
122
|
fs_1.default.writeFileSync(path_1.default.join(targetDir, "implementation-plan.md"), rendered, "utf-8");
|
|
@@ -8,11 +8,12 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const prompt_1 = require("../ui/prompt");
|
|
10
10
|
const index_1 = require("../workspace/index");
|
|
11
|
+
const errors_1 = require("../errors");
|
|
11
12
|
async function runReqStatus() {
|
|
12
13
|
const projectName = await (0, prompt_1.askProjectName)();
|
|
13
14
|
const reqId = await (0, prompt_1.ask)("Requirement ID (REQ-...): ");
|
|
14
15
|
if (!projectName || !reqId) {
|
|
15
|
-
|
|
16
|
+
(0, errors_1.printError)("SDD-1254", "Project name and requirement ID are required.");
|
|
16
17
|
return;
|
|
17
18
|
}
|
|
18
19
|
const workspace = (0, index_1.getWorkspaceInfo)();
|
|
@@ -21,7 +22,7 @@ async function runReqStatus() {
|
|
|
21
22
|
project = (0, index_1.getProjectInfo)(workspace, projectName);
|
|
22
23
|
}
|
|
23
24
|
catch (error) {
|
|
24
|
-
|
|
25
|
+
(0, errors_1.printError)("SDD-1255", error.message);
|
|
25
26
|
return;
|
|
26
27
|
}
|
|
27
28
|
const base = path_1.default.join(project.root, "requirements");
|
|
@@ -33,5 +34,5 @@ async function runReqStatus() {
|
|
|
33
34
|
return;
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
|
-
|
|
37
|
+
(0, errors_1.printError)("SDD-1256", "Requirement not found.");
|
|
37
38
|
}
|
package/dist/commands/route.js
CHANGED
|
@@ -4,10 +4,25 @@ exports.runRoute = runRoute;
|
|
|
4
4
|
const intent_1 = require("../router/intent");
|
|
5
5
|
const flow_1 = require("../router/flow");
|
|
6
6
|
const prompt_packs_1 = require("../router/prompt-packs");
|
|
7
|
+
const errors_1 = require("../errors");
|
|
7
8
|
function runRoute(input) {
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
const text = input.trim();
|
|
10
|
+
if (!text) {
|
|
11
|
+
(0, errors_1.printError)("SDD-1423", "Route input is required.");
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
let intent;
|
|
15
|
+
let flow;
|
|
16
|
+
let packs;
|
|
17
|
+
try {
|
|
18
|
+
intent = (0, intent_1.classifyIntent)(text);
|
|
19
|
+
flow = (0, flow_1.loadFlow)(intent.flow);
|
|
20
|
+
packs = (0, prompt_packs_1.loadPromptPacks)();
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
(0, errors_1.printError)("SDD-1424", `Unable to load route context: ${error.message}`);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
11
26
|
const packIds = intent_1.FLOW_PROMPT_PACKS[intent.flow] ?? [];
|
|
12
27
|
console.log(JSON.stringify(intent, null, 2));
|
|
13
28
|
if (flow) {
|
|
@@ -15,7 +30,7 @@ function runRoute(input) {
|
|
|
15
30
|
console.log(flow);
|
|
16
31
|
}
|
|
17
32
|
else {
|
|
18
|
-
|
|
33
|
+
(0, errors_1.printError)("SDD-1425", `No flow script found for ${intent.flow}.`);
|
|
19
34
|
}
|
|
20
35
|
if (packIds.length > 0) {
|
|
21
36
|
console.log("\n--- Prompt packs ---\n");
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runScopeList(): void;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runScopeList = runScopeList;
|
|
4
|
+
const index_1 = require("../workspace/index");
|
|
5
|
+
const errors_1 = require("../errors");
|
|
6
|
+
function runScopeList() {
|
|
7
|
+
const baseRoot = (0, index_1.getWorkspaceBaseRoot)();
|
|
8
|
+
const scopes = (0, index_1.listScopes)(baseRoot);
|
|
9
|
+
if (scopes.length === 0) {
|
|
10
|
+
(0, errors_1.printError)("SDD-1412", "No scopes available in workspace.");
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
console.log(`Workspace base: ${baseRoot}`);
|
|
14
|
+
console.log("Scopes:");
|
|
15
|
+
scopes.forEach((scope) => console.log(`- ${scope}`));
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runScopeStatus(scopeInput?: string): void;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runScopeStatus = runScopeStatus;
|
|
4
|
+
const flags_1 = require("../context/flags");
|
|
5
|
+
const index_1 = require("../workspace/index");
|
|
6
|
+
const errors_1 = require("../errors");
|
|
7
|
+
function runScopeStatus(scopeInput) {
|
|
8
|
+
const flags = (0, flags_1.getFlags)();
|
|
9
|
+
const scope = scopeInput?.trim() || flags.scope || "";
|
|
10
|
+
if (!scope) {
|
|
11
|
+
(0, errors_1.printError)("SDD-1411", "Scope is required. Use: sdd-cli scope status <scope-name>");
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const workspace = (0, index_1.getWorkspaceInfoForScope)(scope);
|
|
15
|
+
(0, index_1.ensureWorkspace)(workspace);
|
|
16
|
+
const projects = (0, index_1.listProjects)(workspace);
|
|
17
|
+
console.log(`Scope: ${scope}`);
|
|
18
|
+
console.log(`Workspace: ${workspace.root}`);
|
|
19
|
+
if (projects.length === 0) {
|
|
20
|
+
console.log("No projects found for scope.");
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const byStatus = projects.reduce((acc, project) => {
|
|
24
|
+
acc[project.status] = (acc[project.status] || 0) + 1;
|
|
25
|
+
return acc;
|
|
26
|
+
}, {});
|
|
27
|
+
console.log(`Projects: ${projects.length}`);
|
|
28
|
+
Object.keys(byStatus)
|
|
29
|
+
.sort()
|
|
30
|
+
.forEach((status) => {
|
|
31
|
+
console.log(`- ${status}: ${byStatus[status]}`);
|
|
32
|
+
});
|
|
33
|
+
}
|
package/dist/commands/status.js
CHANGED
|
@@ -8,6 +8,7 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
8
8
|
const path_1 = __importDefault(require("path"));
|
|
9
9
|
const flags_1 = require("../context/flags");
|
|
10
10
|
const index_1 = require("../workspace/index");
|
|
11
|
+
const errors_1 = require("../errors");
|
|
11
12
|
const REQUIREMENT_STATUSES = ["backlog", "wip", "in-progress", "done", "archived"];
|
|
12
13
|
function listRequirementIds(projectRoot, status) {
|
|
13
14
|
const dir = path_1.default.join(projectRoot, "requirements", status);
|
|
@@ -26,23 +27,28 @@ function latestId(ids) {
|
|
|
26
27
|
}
|
|
27
28
|
return ids[ids.length - 1];
|
|
28
29
|
}
|
|
30
|
+
function scopePrefix() {
|
|
31
|
+
const flags = (0, flags_1.getFlags)();
|
|
32
|
+
return flags.scope && flags.scope.trim().length > 0 ? `--scope "${flags.scope.trim()}" ` : "";
|
|
33
|
+
}
|
|
29
34
|
function recommendNext(projectName, counts, ids) {
|
|
35
|
+
const prefix = scopePrefix();
|
|
30
36
|
const nextInProgress = latestId(ids["in-progress"]);
|
|
31
37
|
if (nextInProgress) {
|
|
32
|
-
return `sdd-cli --project "${projectName}" req finish # then enter ${nextInProgress} when prompted`;
|
|
38
|
+
return `sdd-cli ${prefix}--project "${projectName}" req finish # then enter ${nextInProgress} when prompted`;
|
|
33
39
|
}
|
|
34
40
|
const nextWip = latestId(ids.wip);
|
|
35
41
|
if (nextWip) {
|
|
36
|
-
return `sdd-cli --project "${projectName}" req start # then enter ${nextWip} when prompted`;
|
|
42
|
+
return `sdd-cli ${prefix}--project "${projectName}" req start # then enter ${nextWip} when prompted`;
|
|
37
43
|
}
|
|
38
44
|
const nextBacklog = latestId(ids.backlog);
|
|
39
45
|
if (nextBacklog) {
|
|
40
|
-
return `sdd-cli --project "${projectName}" req plan # then enter ${nextBacklog} when prompted`;
|
|
46
|
+
return `sdd-cli ${prefix}--project "${projectName}" req plan # then enter ${nextBacklog} when prompted`;
|
|
41
47
|
}
|
|
42
48
|
if (counts.done > 0 && counts.archived === 0) {
|
|
43
|
-
return `sdd-cli --project "${projectName}" hello "start next requirement"`;
|
|
49
|
+
return `sdd-cli ${prefix}--project "${projectName}" hello "start next requirement"`;
|
|
44
50
|
}
|
|
45
|
-
return `sdd-cli --project "${projectName}" hello "continue"`;
|
|
51
|
+
return `sdd-cli ${prefix}--project "${projectName}" hello "continue"`;
|
|
46
52
|
}
|
|
47
53
|
function runStatus(showNext) {
|
|
48
54
|
const workspace = (0, index_1.getWorkspaceInfo)();
|
|
@@ -62,11 +68,11 @@ function runStatus(showNext) {
|
|
|
62
68
|
project = (0, index_1.getProjectInfo)(workspace, selectedName);
|
|
63
69
|
}
|
|
64
70
|
catch (error) {
|
|
65
|
-
|
|
71
|
+
(0, errors_1.printError)("SDD-1401", error.message);
|
|
66
72
|
return;
|
|
67
73
|
}
|
|
68
74
|
if (!fs_1.default.existsSync(project.root)) {
|
|
69
|
-
|
|
75
|
+
(0, errors_1.printError)("SDD-1402", `Selected project not found in workspace: ${project.name}`);
|
|
70
76
|
if (showNext) {
|
|
71
77
|
console.log('Next command: sdd-cli quickstart --example saas');
|
|
72
78
|
}
|
|
@@ -86,6 +92,9 @@ function runStatus(showNext) {
|
|
|
86
92
|
done: ids.done.length,
|
|
87
93
|
archived: ids.archived.length
|
|
88
94
|
};
|
|
95
|
+
if (flags.scope && flags.scope.trim().length > 0) {
|
|
96
|
+
console.log(`Scope: ${flags.scope.trim()}`);
|
|
97
|
+
}
|
|
89
98
|
console.log(`Project: ${project.name}`);
|
|
90
99
|
REQUIREMENT_STATUSES.forEach((status) => {
|
|
91
100
|
console.log(`- ${status}: ${counts[status]}`);
|
|
@@ -12,6 +12,7 @@ const render_1 = require("../templates/render");
|
|
|
12
12
|
const list_1 = require("../utils/list");
|
|
13
13
|
const validate_1 = require("../validation/validate");
|
|
14
14
|
const flags_1 = require("../context/flags");
|
|
15
|
+
const errors_1 = require("../errors");
|
|
15
16
|
function findRequirementDir(projectRoot, reqId) {
|
|
16
17
|
const base = path_1.default.join(projectRoot, "requirements");
|
|
17
18
|
const statuses = ["backlog", "wip", "in-progress", "done", "archived"];
|
|
@@ -32,7 +33,7 @@ async function runTestPlan(options) {
|
|
|
32
33
|
const projectName = options?.projectName ?? (await (0, prompt_1.askProjectName)());
|
|
33
34
|
const reqId = options?.reqId ?? (await (0, prompt_1.ask)("Requirement ID (REQ-...): "));
|
|
34
35
|
if (!projectName || !reqId) {
|
|
35
|
-
|
|
36
|
+
(0, errors_1.printError)("SDD-1271", "Project name and requirement ID are required.");
|
|
36
37
|
return null;
|
|
37
38
|
}
|
|
38
39
|
const workspace = (0, index_1.getWorkspaceInfo)();
|
|
@@ -41,12 +42,12 @@ async function runTestPlan(options) {
|
|
|
41
42
|
project = (0, index_1.getProjectInfo)(workspace, projectName);
|
|
42
43
|
}
|
|
43
44
|
catch (error) {
|
|
44
|
-
|
|
45
|
+
(0, errors_1.printError)("SDD-1272", error.message);
|
|
45
46
|
return null;
|
|
46
47
|
}
|
|
47
48
|
const requirementDir = findRequirementDir(project.root, reqId);
|
|
48
49
|
if (!requirementDir) {
|
|
49
|
-
|
|
50
|
+
(0, errors_1.printError)("SDD-1273", "Requirement not found.");
|
|
50
51
|
return null;
|
|
51
52
|
}
|
|
52
53
|
const seed = defaultSeed(options?.seedText);
|
|
@@ -66,8 +67,8 @@ async function runTestPlan(options) {
|
|
|
66
67
|
};
|
|
67
68
|
const validation = (0, validate_1.validateJson)("test-plan.schema.json", testPlanJson);
|
|
68
69
|
if (!validation.valid) {
|
|
69
|
-
|
|
70
|
-
validation.errors.forEach((error) =>
|
|
70
|
+
(0, errors_1.printError)("SDD-1274", "Test plan validation failed.");
|
|
71
|
+
validation.errors.forEach((error) => (0, errors_1.printError)("SDD-1274", error));
|
|
71
72
|
return null;
|
|
72
73
|
}
|
|
73
74
|
const template = (0, render_1.loadTemplate)("test-plan");
|
package/dist/context/flags.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ export type RuntimeFlags = {
|
|
|
8
8
|
fromStep?: string;
|
|
9
9
|
project?: string;
|
|
10
10
|
output?: string;
|
|
11
|
+
scope?: string;
|
|
12
|
+
metricsLocal?: boolean;
|
|
11
13
|
};
|
|
12
14
|
export declare function setFlags(next: Partial<RuntimeFlags>): void;
|
|
13
15
|
export declare function getFlags(): RuntimeFlags;
|
package/dist/context/flags.js
CHANGED
|
@@ -11,7 +11,9 @@ const flags = {
|
|
|
11
11
|
beginner: false,
|
|
12
12
|
fromStep: undefined,
|
|
13
13
|
project: undefined,
|
|
14
|
-
output: undefined
|
|
14
|
+
output: undefined,
|
|
15
|
+
scope: undefined,
|
|
16
|
+
metricsLocal: false
|
|
15
17
|
};
|
|
16
18
|
function setFlags(next) {
|
|
17
19
|
if ("approve" in next) {
|
|
@@ -41,6 +43,12 @@ function setFlags(next) {
|
|
|
41
43
|
if ("output" in next) {
|
|
42
44
|
flags.output = typeof next.output === "string" ? next.output : undefined;
|
|
43
45
|
}
|
|
46
|
+
if ("scope" in next) {
|
|
47
|
+
flags.scope = typeof next.scope === "string" ? next.scope : undefined;
|
|
48
|
+
}
|
|
49
|
+
if ("metricsLocal" in next) {
|
|
50
|
+
flags.metricsLocal = Boolean(next.metricsLocal);
|
|
51
|
+
}
|
|
44
52
|
}
|
|
45
53
|
function getFlags() {
|
|
46
54
|
return { ...flags };
|
package/dist/errors.d.ts
ADDED
package/dist/errors.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatError = formatError;
|
|
4
|
+
exports.printError = printError;
|
|
5
|
+
function formatError(code, message) {
|
|
6
|
+
return `[${code}] ${message}`;
|
|
7
|
+
}
|
|
8
|
+
function printError(code, message) {
|
|
9
|
+
console.log(formatError(code, message));
|
|
10
|
+
}
|
package/dist/paths.js
CHANGED
|
@@ -6,5 +6,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.getRepoRoot = getRepoRoot;
|
|
7
7
|
const path_1 = __importDefault(require("path"));
|
|
8
8
|
function getRepoRoot() {
|
|
9
|
+
const override = process.env.SDD_REPO_ROOT?.trim();
|
|
10
|
+
if (override) {
|
|
11
|
+
return path_1.default.resolve(override);
|
|
12
|
+
}
|
|
9
13
|
return path_1.default.resolve(__dirname, "..");
|
|
10
14
|
}
|