sdd-cli 0.1.2 → 0.1.3
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 +126 -89
- package/dist/cli.js +7 -3
- package/dist/commands/doctor.js +11 -2
- package/dist/commands/gen-architecture.js +14 -4
- package/dist/commands/gen-best-practices.js +12 -2
- package/dist/commands/gen-functional-spec.js +13 -3
- package/dist/commands/gen-project-readme.js +15 -5
- package/dist/commands/gen-technical-spec.js +13 -3
- package/dist/commands/gen-utils.js +9 -1
- package/dist/commands/hello.js +21 -3
- package/dist/commands/learn-deliver.js +17 -3
- package/dist/commands/learn-refine.js +32 -11
- package/dist/commands/learn-start.js +9 -2
- package/dist/commands/learn-utils.js +7 -4
- package/dist/commands/pr-audit.js +17 -3
- package/dist/commands/pr-finish.js +17 -3
- package/dist/commands/pr-report.js +17 -3
- package/dist/commands/pr-respond.js +17 -3
- package/dist/commands/pr-start.js +9 -2
- package/dist/commands/pr-utils.js +8 -5
- package/dist/commands/req-archive.js +14 -6
- package/dist/commands/req-create.js +71 -14
- package/dist/commands/req-export.js +11 -3
- package/dist/commands/req-finish.js +28 -13
- package/dist/commands/req-lint.js +10 -2
- package/dist/commands/req-list.js +10 -2
- package/dist/commands/req-plan.js +34 -12
- package/dist/commands/req-refine.js +54 -5
- package/dist/commands/req-report.js +10 -2
- package/dist/commands/req-start.js +29 -12
- package/dist/commands/req-status.js +10 -2
- package/dist/commands/test-plan.js +13 -5
- package/dist/context/flags.d.ts +2 -0
- package/dist/context/flags.js +5 -1
- package/dist/providers/codex.js +2 -2
- package/dist/router/prompt-map.js +17 -5
- package/dist/ui/prompt.d.ts +1 -0
- package/dist/ui/prompt.js +8 -0
- package/dist/validation/gates.d.ts +19 -0
- package/dist/validation/gates.js +41 -0
- package/dist/validation/validate.js +24 -4
- package/dist/workspace/index.d.ts +6 -0
- package/dist/workspace/index.js +41 -10
- package/flows/ADMISSIONS_ADMIN.md +34 -33
- package/flows/ART.md +34 -33
- package/flows/COURT_SYSTEM.md +34 -33
- package/flows/DATA_SCIENTIST.md +34 -33
- package/flows/ECOMMERCE.md +34 -33
- package/flows/ECONOMICS.md +34 -33
- package/flows/GRAPHIC_DESIGN.md +34 -33
- package/flows/HISTORY.md +34 -33
- package/flows/LAWYER.md +35 -34
- package/flows/PROGRAMMER.md +34 -33
- package/flows/RETAIL_STORE.md +34 -33
- package/flows/SOCIOLOGY.md +34 -33
- package/flows/STATE_ADMIN.md +34 -33
- package/flows/STUDENT_UNIVERSITY.md +34 -33
- package/flows/TAXES_ADMIN.md +34 -33
- package/flows/TEACHER.md +34 -33
- package/package.json +13 -3
- package/router/BUSINESS.flow.md +58 -57
- package/router/DATA_SCIENCE.flow.md +59 -58
- package/router/DESIGN.flow.md +59 -58
- package/router/HUMANITIES.flow.md +59 -58
- package/router/LEGAL.flow.md +59 -58
- package/router/SOFTWARE_FEATURE.flow.md +60 -59
|
@@ -10,12 +10,19 @@ const prompt_1 = require("../ui/prompt");
|
|
|
10
10
|
const list_1 = require("../utils/list");
|
|
11
11
|
const learn_utils_1 = require("./learn-utils");
|
|
12
12
|
async function runLearnDeliver() {
|
|
13
|
-
const projectName = await (0, prompt_1.
|
|
13
|
+
const projectName = await (0, prompt_1.askProjectName)();
|
|
14
14
|
if (!projectName) {
|
|
15
15
|
console.log("Project name is required.");
|
|
16
16
|
return;
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
let sessions = [];
|
|
19
|
+
try {
|
|
20
|
+
sessions = (0, learn_utils_1.listLearnSessions)(projectName);
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
console.log(error.message);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
19
26
|
if (sessions.length > 0) {
|
|
20
27
|
console.log("Available sessions:");
|
|
21
28
|
sessions.forEach((session) => console.log(`- ${session}`));
|
|
@@ -25,7 +32,14 @@ async function runLearnDeliver() {
|
|
|
25
32
|
console.log("Session ID is required.");
|
|
26
33
|
return;
|
|
27
34
|
}
|
|
28
|
-
|
|
35
|
+
let loaded;
|
|
36
|
+
try {
|
|
37
|
+
loaded = (0, learn_utils_1.loadLearnSession)(projectName, sessionId);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
console.log(error.message);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
29
43
|
if (!loaded) {
|
|
30
44
|
console.log("Learning session not found.");
|
|
31
45
|
return;
|
|
@@ -10,12 +10,19 @@ const prompt_1 = require("../ui/prompt");
|
|
|
10
10
|
const list_1 = require("../utils/list");
|
|
11
11
|
const learn_utils_1 = require("./learn-utils");
|
|
12
12
|
async function runLearnRefine() {
|
|
13
|
-
const projectName = await (0, prompt_1.
|
|
13
|
+
const projectName = await (0, prompt_1.askProjectName)();
|
|
14
14
|
if (!projectName) {
|
|
15
15
|
console.log("Project name is required.");
|
|
16
16
|
return;
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
let sessions = [];
|
|
19
|
+
try {
|
|
20
|
+
sessions = (0, learn_utils_1.listLearnSessions)(projectName);
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
console.log(error.message);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
19
26
|
if (sessions.length > 0) {
|
|
20
27
|
console.log("Available sessions:");
|
|
21
28
|
sessions.forEach((session) => console.log(`- ${session}`));
|
|
@@ -25,7 +32,14 @@ async function runLearnRefine() {
|
|
|
25
32
|
console.log("Session ID is required.");
|
|
26
33
|
return;
|
|
27
34
|
}
|
|
28
|
-
|
|
35
|
+
let loaded;
|
|
36
|
+
try {
|
|
37
|
+
loaded = (0, learn_utils_1.loadLearnSession)(projectName, sessionId);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
console.log(error.message);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
29
43
|
if (!loaded) {
|
|
30
44
|
console.log("Learning session not found.");
|
|
31
45
|
return;
|
|
@@ -36,14 +50,21 @@ async function runLearnRefine() {
|
|
|
36
50
|
const focusAreas = await (0, prompt_1.ask)("Focus areas - comma separated: ");
|
|
37
51
|
const timeAvailable = await (0, prompt_1.ask)(`Time available (${loaded.session.timeAvailable}): `);
|
|
38
52
|
const constraints = await (0, prompt_1.ask)("Constraints - comma separated: ");
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
53
|
+
let updated;
|
|
54
|
+
try {
|
|
55
|
+
updated = (0, learn_utils_1.updateLearnSession)(projectName, sessionId, {
|
|
56
|
+
purpose: purpose || loaded.session.purpose,
|
|
57
|
+
depth: depth || loaded.session.depth,
|
|
58
|
+
format: format || loaded.session.format,
|
|
59
|
+
focusAreas: focusAreas ? (0, list_1.parseList)(focusAreas) : loaded.session.focusAreas,
|
|
60
|
+
timeAvailable: timeAvailable || loaded.session.timeAvailable,
|
|
61
|
+
constraints: constraints ? (0, list_1.parseList)(constraints) : loaded.session.constraints
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
console.log(error.message);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
47
68
|
if (!updated) {
|
|
48
69
|
console.log("Failed to update session.");
|
|
49
70
|
return;
|
|
@@ -10,7 +10,7 @@ const prompt_1 = require("../ui/prompt");
|
|
|
10
10
|
const list_1 = require("../utils/list");
|
|
11
11
|
const learn_utils_1 = require("./learn-utils");
|
|
12
12
|
async function runLearnStart() {
|
|
13
|
-
const projectName = await (0, prompt_1.
|
|
13
|
+
const projectName = await (0, prompt_1.askProjectName)();
|
|
14
14
|
const topic = await (0, prompt_1.ask)("Topic to learn: ");
|
|
15
15
|
if (!projectName || !topic) {
|
|
16
16
|
console.log("Project name and topic are required.");
|
|
@@ -22,7 +22,14 @@ async function runLearnStart() {
|
|
|
22
22
|
const focusAreas = await (0, prompt_1.ask)("Focus areas - comma separated: ");
|
|
23
23
|
const timeAvailable = await (0, prompt_1.ask)("Time available: ");
|
|
24
24
|
const constraints = await (0, prompt_1.ask)("Constraints - comma separated: ");
|
|
25
|
-
|
|
25
|
+
let created;
|
|
26
|
+
try {
|
|
27
|
+
created = (0, learn_utils_1.createLearnSession)(projectName, topic, "learning");
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
console.log(error.message);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
26
33
|
(0, learn_utils_1.updateLearnSession)(projectName, created.session.id, {
|
|
27
34
|
purpose: purpose || "N/A",
|
|
28
35
|
depth: depth || "N/A",
|
|
@@ -20,7 +20,8 @@ function sanitizeId(value) {
|
|
|
20
20
|
}
|
|
21
21
|
function createLearnSession(projectName, topic, domain = "learning") {
|
|
22
22
|
const workspace = (0, index_1.getWorkspaceInfo)();
|
|
23
|
-
(0, index_1.
|
|
23
|
+
const project = (0, index_1.getProjectInfo)(workspace, projectName);
|
|
24
|
+
(0, index_1.ensureProject)(workspace, project.name, domain);
|
|
24
25
|
const stamp = new Date().toISOString().replace(/[:.]/g, "").slice(0, 13);
|
|
25
26
|
const id = `LEARN-${sanitizeId(topic)}-${stamp}`;
|
|
26
27
|
const now = new Date().toISOString();
|
|
@@ -36,14 +37,15 @@ function createLearnSession(projectName, topic, domain = "learning") {
|
|
|
36
37
|
createdAt: now,
|
|
37
38
|
updatedAt: now
|
|
38
39
|
};
|
|
39
|
-
const sessionDir = path_1.default.join(
|
|
40
|
+
const sessionDir = path_1.default.join(project.root, "learning", id);
|
|
40
41
|
fs_1.default.mkdirSync(sessionDir, { recursive: true });
|
|
41
42
|
fs_1.default.writeFileSync(path_1.default.join(sessionDir, "session.json"), JSON.stringify(session, null, 2), "utf-8");
|
|
42
43
|
return { session, dir: sessionDir };
|
|
43
44
|
}
|
|
44
45
|
function loadLearnSession(projectName, sessionId) {
|
|
45
46
|
const workspace = (0, index_1.getWorkspaceInfo)();
|
|
46
|
-
const
|
|
47
|
+
const project = (0, index_1.getProjectInfo)(workspace, projectName);
|
|
48
|
+
const sessionDir = path_1.default.join(project.root, "learning", sessionId);
|
|
47
49
|
const sessionPath = path_1.default.join(sessionDir, "session.json");
|
|
48
50
|
if (!fs_1.default.existsSync(sessionPath)) {
|
|
49
51
|
return null;
|
|
@@ -53,7 +55,8 @@ function loadLearnSession(projectName, sessionId) {
|
|
|
53
55
|
}
|
|
54
56
|
function listLearnSessions(projectName) {
|
|
55
57
|
const workspace = (0, index_1.getWorkspaceInfo)();
|
|
56
|
-
const
|
|
58
|
+
const project = (0, index_1.getProjectInfo)(workspace, projectName);
|
|
59
|
+
const root = path_1.default.join(project.root, "learning");
|
|
57
60
|
if (!fs_1.default.existsSync(root)) {
|
|
58
61
|
return [];
|
|
59
62
|
}
|
|
@@ -11,12 +11,19 @@ const render_1 = require("../templates/render");
|
|
|
11
11
|
const list_1 = require("../utils/list");
|
|
12
12
|
const pr_utils_1 = require("./pr-utils");
|
|
13
13
|
async function runPrAudit() {
|
|
14
|
-
const projectName = await (0, prompt_1.
|
|
14
|
+
const projectName = await (0, prompt_1.askProjectName)();
|
|
15
15
|
if (!projectName) {
|
|
16
16
|
console.log("Project name is required.");
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
19
|
-
|
|
19
|
+
let available = [];
|
|
20
|
+
try {
|
|
21
|
+
available = (0, pr_utils_1.listPrReviews)(projectName);
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
console.log(error.message);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
20
27
|
if (available.length > 0) {
|
|
21
28
|
console.log("Available PR reviews:");
|
|
22
29
|
available.forEach((item) => console.log(`- ${item}`));
|
|
@@ -26,7 +33,14 @@ async function runPrAudit() {
|
|
|
26
33
|
console.log("PR ID is required.");
|
|
27
34
|
return;
|
|
28
35
|
}
|
|
29
|
-
|
|
36
|
+
let prDir;
|
|
37
|
+
try {
|
|
38
|
+
prDir = (0, pr_utils_1.resolvePrDir)(projectName, prId);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
console.log(error.message);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
30
44
|
if (!fs_1.default.existsSync(prDir)) {
|
|
31
45
|
console.log(`PR review not found at ${prDir}`);
|
|
32
46
|
return;
|
|
@@ -11,12 +11,19 @@ const render_1 = require("../templates/render");
|
|
|
11
11
|
const list_1 = require("../utils/list");
|
|
12
12
|
const pr_utils_1 = require("./pr-utils");
|
|
13
13
|
async function runPrFinish() {
|
|
14
|
-
const projectName = await (0, prompt_1.
|
|
14
|
+
const projectName = await (0, prompt_1.askProjectName)();
|
|
15
15
|
if (!projectName) {
|
|
16
16
|
console.log("Project name is required.");
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
19
|
-
|
|
19
|
+
let available = [];
|
|
20
|
+
try {
|
|
21
|
+
available = (0, pr_utils_1.listPrReviews)(projectName);
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
console.log(error.message);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
20
27
|
if (available.length > 0) {
|
|
21
28
|
console.log("Available PR reviews:");
|
|
22
29
|
available.forEach((item) => console.log(`- ${item}`));
|
|
@@ -26,7 +33,14 @@ async function runPrFinish() {
|
|
|
26
33
|
console.log("PR ID is required.");
|
|
27
34
|
return;
|
|
28
35
|
}
|
|
29
|
-
|
|
36
|
+
let prDir;
|
|
37
|
+
try {
|
|
38
|
+
prDir = (0, pr_utils_1.resolvePrDir)(projectName, prId);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
console.log(error.message);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
30
44
|
if (!fs_1.default.existsSync(prDir)) {
|
|
31
45
|
console.log(`PR review not found at ${prDir}`);
|
|
32
46
|
return;
|
|
@@ -11,12 +11,19 @@ const render_1 = require("../templates/render");
|
|
|
11
11
|
const list_1 = require("../utils/list");
|
|
12
12
|
const pr_utils_1 = require("./pr-utils");
|
|
13
13
|
async function runPrReport() {
|
|
14
|
-
const projectName = await (0, prompt_1.
|
|
14
|
+
const projectName = await (0, prompt_1.askProjectName)();
|
|
15
15
|
if (!projectName) {
|
|
16
16
|
console.log("Project name is required.");
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
19
|
-
|
|
19
|
+
let available = [];
|
|
20
|
+
try {
|
|
21
|
+
available = (0, pr_utils_1.listPrReviews)(projectName);
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
console.log(error.message);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
20
27
|
if (available.length > 0) {
|
|
21
28
|
console.log("Available PR reviews:");
|
|
22
29
|
available.forEach((item) => console.log(`- ${item}`));
|
|
@@ -26,7 +33,14 @@ async function runPrReport() {
|
|
|
26
33
|
console.log("PR ID is required.");
|
|
27
34
|
return;
|
|
28
35
|
}
|
|
29
|
-
|
|
36
|
+
let prDir;
|
|
37
|
+
try {
|
|
38
|
+
prDir = (0, pr_utils_1.resolvePrDir)(projectName, prId);
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
console.log(error.message);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
30
44
|
if (!fs_1.default.existsSync(prDir)) {
|
|
31
45
|
console.log(`PR review not found at ${prDir}`);
|
|
32
46
|
return;
|
|
@@ -18,12 +18,19 @@ function sanitizeId(value) {
|
|
|
18
18
|
.replace(/^-|-$/g, "");
|
|
19
19
|
}
|
|
20
20
|
async function runPrRespond() {
|
|
21
|
-
const projectName = await (0, prompt_1.
|
|
21
|
+
const projectName = await (0, prompt_1.askProjectName)();
|
|
22
22
|
if (!projectName) {
|
|
23
23
|
console.log("Project name is required.");
|
|
24
24
|
return;
|
|
25
25
|
}
|
|
26
|
-
|
|
26
|
+
let available = [];
|
|
27
|
+
try {
|
|
28
|
+
available = (0, pr_utils_1.listPrReviews)(projectName);
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
console.log(error.message);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
27
34
|
if (available.length > 0) {
|
|
28
35
|
console.log("Available PR reviews:");
|
|
29
36
|
available.forEach((item) => console.log(`- ${item}`));
|
|
@@ -33,7 +40,14 @@ async function runPrRespond() {
|
|
|
33
40
|
console.log("PR ID is required.");
|
|
34
41
|
return;
|
|
35
42
|
}
|
|
36
|
-
|
|
43
|
+
let prDir;
|
|
44
|
+
try {
|
|
45
|
+
prDir = (0, pr_utils_1.resolvePrDir)(projectName, prId);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
console.log(error.message);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
37
51
|
if (!fs_1.default.existsSync(prDir)) {
|
|
38
52
|
console.log(`PR review not found at ${prDir}`);
|
|
39
53
|
return;
|
|
@@ -11,7 +11,7 @@ const render_1 = require("../templates/render");
|
|
|
11
11
|
const list_1 = require("../utils/list");
|
|
12
12
|
const pr_utils_1 = require("./pr-utils");
|
|
13
13
|
async function runPrStart() {
|
|
14
|
-
const projectName = await (0, prompt_1.
|
|
14
|
+
const projectName = await (0, prompt_1.askProjectName)();
|
|
15
15
|
if (!projectName) {
|
|
16
16
|
console.log("Project name is required.");
|
|
17
17
|
return;
|
|
@@ -35,7 +35,14 @@ async function runPrStart() {
|
|
|
35
35
|
const avgTime = await (0, prompt_1.ask)("Avg time to resolve: ");
|
|
36
36
|
const testsRun = await (0, prompt_1.ask)("Tests run: ");
|
|
37
37
|
const notes = await (0, prompt_1.ask)("Notes - comma separated: ");
|
|
38
|
-
|
|
38
|
+
let context;
|
|
39
|
+
try {
|
|
40
|
+
context = (0, pr_utils_1.ensurePrReviewDir)(projectName, prLink, prIdInput);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
console.log(error.message);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
39
46
|
const reviewMeta = {
|
|
40
47
|
id: context.prId,
|
|
41
48
|
link: prLink,
|
|
@@ -26,23 +26,26 @@ function sanitizeId(value) {
|
|
|
26
26
|
}
|
|
27
27
|
function ensurePrReviewDir(projectName, prLink, prIdInput) {
|
|
28
28
|
const workspace = (0, index_1.getWorkspaceInfo)();
|
|
29
|
-
(0, index_1.
|
|
29
|
+
const project = (0, index_1.getProjectInfo)(workspace, projectName);
|
|
30
|
+
(0, index_1.ensureProject)(workspace, project.name, "software");
|
|
30
31
|
const derived = extractPrId(prLink);
|
|
31
32
|
const rawId = prIdInput?.trim() || derived || `PR-${Date.now()}`;
|
|
32
33
|
const prId = sanitizeId(rawId);
|
|
33
|
-
const prDir = path_1.default.join(
|
|
34
|
+
const prDir = path_1.default.join(project.root, "pr-reviews", prId);
|
|
34
35
|
if (!fs_1.default.existsSync(prDir)) {
|
|
35
36
|
fs_1.default.mkdirSync(prDir, { recursive: true });
|
|
36
37
|
}
|
|
37
|
-
return { projectName, prId, prDir };
|
|
38
|
+
return { projectName: project.name, prId, prDir };
|
|
38
39
|
}
|
|
39
40
|
function resolvePrDir(projectName, prId) {
|
|
40
41
|
const workspace = (0, index_1.getWorkspaceInfo)();
|
|
41
|
-
|
|
42
|
+
const project = (0, index_1.getProjectInfo)(workspace, projectName);
|
|
43
|
+
return path_1.default.join(project.root, "pr-reviews", prId);
|
|
42
44
|
}
|
|
43
45
|
function listPrReviews(projectName) {
|
|
44
46
|
const workspace = (0, index_1.getWorkspaceInfo)();
|
|
45
|
-
const
|
|
47
|
+
const project = (0, index_1.getProjectInfo)(workspace, projectName);
|
|
48
|
+
const root = path_1.default.join(project.root, "pr-reviews");
|
|
46
49
|
if (!fs_1.default.existsSync(root)) {
|
|
47
50
|
return [];
|
|
48
51
|
}
|
|
@@ -8,26 +8,34 @@ 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
|
-
function findDoneRequirement(
|
|
12
|
-
const done = path_1.default.join(
|
|
11
|
+
function findDoneRequirement(projectRoot, reqId) {
|
|
12
|
+
const done = path_1.default.join(projectRoot, "requirements", "done", reqId);
|
|
13
13
|
return fs_1.default.existsSync(done) ? done : null;
|
|
14
14
|
}
|
|
15
15
|
async function runReqArchive() {
|
|
16
|
-
const projectName = await (0, prompt_1.
|
|
16
|
+
const projectName = await (0, prompt_1.askProjectName)();
|
|
17
17
|
const reqId = await (0, prompt_1.ask)("Requirement ID (REQ-...): ");
|
|
18
18
|
if (!projectName || !reqId) {
|
|
19
19
|
console.log("Project name and requirement ID are required.");
|
|
20
20
|
return;
|
|
21
21
|
}
|
|
22
22
|
const workspace = (0, index_1.getWorkspaceInfo)();
|
|
23
|
-
|
|
23
|
+
let project;
|
|
24
|
+
try {
|
|
25
|
+
project = (0, index_1.getProjectInfo)(workspace, projectName);
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
console.log(error.message);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const doneDir = findDoneRequirement(project.root, reqId);
|
|
24
32
|
if (!doneDir) {
|
|
25
33
|
console.log("Requirement not found in done.");
|
|
26
34
|
return;
|
|
27
35
|
}
|
|
28
|
-
const archiveDir = path_1.default.join(
|
|
36
|
+
const archiveDir = path_1.default.join(project.root, "requirements", "archived", reqId);
|
|
29
37
|
fs_1.default.mkdirSync(path_1.default.dirname(archiveDir), { recursive: true });
|
|
30
38
|
fs_1.default.renameSync(doneDir, archiveDir);
|
|
31
|
-
(0, index_1.updateProjectStatus)(workspace,
|
|
39
|
+
(0, index_1.updateProjectStatus)(workspace, project.name, "archived");
|
|
32
40
|
console.log(`Archived requirement in ${archiveDir}`);
|
|
33
41
|
}
|
|
@@ -10,6 +10,7 @@ const prompt_1 = require("../ui/prompt");
|
|
|
10
10
|
const index_1 = require("../workspace/index");
|
|
11
11
|
const render_1 = require("../templates/render");
|
|
12
12
|
const list_1 = require("../utils/list");
|
|
13
|
+
const gates_1 = require("../validation/gates");
|
|
13
14
|
const validate_1 = require("../validation/validate");
|
|
14
15
|
function generateId() {
|
|
15
16
|
const now = new Date();
|
|
@@ -17,26 +18,34 @@ function generateId() {
|
|
|
17
18
|
return `REQ-${stamp}`;
|
|
18
19
|
}
|
|
19
20
|
async function runReqCreate(draft) {
|
|
20
|
-
const projectName = await (0, prompt_1.
|
|
21
|
+
const projectName = await (0, prompt_1.askProjectName)();
|
|
21
22
|
const domain = await (0, prompt_1.ask)("Domain (software, legal, design, learning, etc): ");
|
|
22
23
|
const actors = await (0, prompt_1.ask)("Actors - comma separated: ");
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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: "));
|
|
30
31
|
const constraints = await (0, prompt_1.ask)("Constraints - comma separated: ");
|
|
31
32
|
const risks = await (0, prompt_1.ask)("Risks - comma separated: ");
|
|
32
33
|
const links = await (0, prompt_1.ask)("Links - comma separated: ");
|
|
33
34
|
const workspace = (0, index_1.getWorkspaceInfo)();
|
|
34
|
-
|
|
35
|
+
let project;
|
|
36
|
+
try {
|
|
37
|
+
project = (0, index_1.getProjectInfo)(workspace, projectName);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
console.log(error.message);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const metadata = (0, index_1.createProject)(workspace, project.name, domain || "software");
|
|
35
44
|
const reqId = generateId();
|
|
36
45
|
const status = "backlog";
|
|
37
|
-
|
|
46
|
+
let requirementJson = {
|
|
38
47
|
id: reqId,
|
|
39
|
-
title:
|
|
48
|
+
title: project.name,
|
|
40
49
|
objective: objective || "N/A",
|
|
41
50
|
status,
|
|
42
51
|
actors: (0, list_1.parseList)(actors),
|
|
@@ -55,17 +64,58 @@ async function runReqCreate(draft) {
|
|
|
55
64
|
links: (0, list_1.parseList)(links),
|
|
56
65
|
updatedAt: new Date().toISOString()
|
|
57
66
|
};
|
|
67
|
+
let gates = (0, gates_1.checkRequirementGates)(requirementJson);
|
|
68
|
+
if (!gates.ok) {
|
|
69
|
+
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: ");
|
|
85
|
+
}
|
|
86
|
+
requirementJson = {
|
|
87
|
+
...requirementJson,
|
|
88
|
+
objective: objective || "N/A",
|
|
89
|
+
scope: {
|
|
90
|
+
in: (0, list_1.parseList)(scopeIn),
|
|
91
|
+
out: (0, list_1.parseList)(scopeOut)
|
|
92
|
+
},
|
|
93
|
+
acceptanceCriteria: (0, list_1.parseList)(acceptance),
|
|
94
|
+
nfrs: {
|
|
95
|
+
security: nfrSecurity || "N/A",
|
|
96
|
+
performance: nfrPerformance || "N/A",
|
|
97
|
+
availability: nfrAvailability || "N/A"
|
|
98
|
+
},
|
|
99
|
+
updatedAt: new Date().toISOString()
|
|
100
|
+
};
|
|
101
|
+
gates = (0, gates_1.checkRequirementGates)(requirementJson);
|
|
102
|
+
if (!gates.ok) {
|
|
103
|
+
console.log("Requirement gates still failing. Missing:");
|
|
104
|
+
gates.missing.forEach((field) => console.log(`- ${field}`));
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
58
108
|
const validation = (0, validate_1.validateJson)("requirement.schema.json", requirementJson);
|
|
59
109
|
if (!validation.valid) {
|
|
60
110
|
console.log("Requirement validation failed:");
|
|
61
111
|
validation.errors.forEach((error) => console.log(`- ${error}`));
|
|
62
112
|
return;
|
|
63
113
|
}
|
|
64
|
-
const requirementDir = path_1.default.join(
|
|
114
|
+
const requirementDir = path_1.default.join(project.root, "requirements", "backlog", reqId);
|
|
65
115
|
fs_1.default.mkdirSync(requirementDir, { recursive: true });
|
|
66
116
|
const template = (0, render_1.loadTemplate)("requirement");
|
|
67
117
|
const rendered = (0, render_1.renderTemplate)(template, {
|
|
68
|
-
title:
|
|
118
|
+
title: project.name,
|
|
69
119
|
id: reqId,
|
|
70
120
|
objective: objective || "N/A",
|
|
71
121
|
actors: (0, list_1.formatList)(actors),
|
|
@@ -81,6 +131,13 @@ async function runReqCreate(draft) {
|
|
|
81
131
|
});
|
|
82
132
|
fs_1.default.writeFileSync(path_1.default.join(requirementDir, "requirement.md"), rendered, "utf-8");
|
|
83
133
|
fs_1.default.writeFileSync(path_1.default.join(requirementDir, "requirement.json"), JSON.stringify(requirementJson, null, 2), "utf-8");
|
|
134
|
+
const summaryTemplate = (0, render_1.loadTemplate)("summary");
|
|
135
|
+
const summary = (0, render_1.renderTemplate)(summaryTemplate, {
|
|
136
|
+
objective: objective || "N/A",
|
|
137
|
+
decisions: "TBD",
|
|
138
|
+
open_questions: "TBD"
|
|
139
|
+
});
|
|
140
|
+
fs_1.default.writeFileSync(path_1.default.join(requirementDir, "summary.md"), summary, "utf-8");
|
|
84
141
|
const changelogTemplate = (0, render_1.loadTemplate)("changelog");
|
|
85
142
|
const changelog = (0, render_1.renderTemplate)(changelogTemplate, { date: new Date().toISOString() });
|
|
86
143
|
fs_1.default.writeFileSync(path_1.default.join(requirementDir, "changelog.md"), changelog, "utf-8");
|
|
@@ -89,6 +146,6 @@ async function runReqCreate(draft) {
|
|
|
89
146
|
fs_1.default.writeFileSync(progressLogPath, "# Progress Log\n\n", "utf-8");
|
|
90
147
|
}
|
|
91
148
|
console.log(`Created requirement in ${requirementDir}`);
|
|
92
|
-
console.log(`Project metadata stored in ${path_1.default.join(
|
|
149
|
+
console.log(`Project metadata stored in ${path_1.default.join(project.root, "metadata.json")}`);
|
|
93
150
|
console.log(`Project status: ${metadata.status}`);
|
|
94
151
|
}
|
|
@@ -9,7 +9,7 @@ const path_1 = __importDefault(require("path"));
|
|
|
9
9
|
const prompt_1 = require("../ui/prompt");
|
|
10
10
|
const index_1 = require("../workspace/index");
|
|
11
11
|
async function runReqExport() {
|
|
12
|
-
const projectName = await (0, prompt_1.
|
|
12
|
+
const projectName = await (0, prompt_1.askProjectName)();
|
|
13
13
|
const reqId = await (0, prompt_1.ask)("Requirement ID (REQ-...): ");
|
|
14
14
|
const outputDir = await (0, prompt_1.ask)("Output directory: ");
|
|
15
15
|
if (!projectName || !reqId || !outputDir) {
|
|
@@ -17,14 +17,22 @@ async function runReqExport() {
|
|
|
17
17
|
return;
|
|
18
18
|
}
|
|
19
19
|
const workspace = (0, index_1.getWorkspaceInfo)();
|
|
20
|
-
|
|
20
|
+
let project;
|
|
21
|
+
try {
|
|
22
|
+
project = (0, index_1.getProjectInfo)(workspace, projectName);
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
console.log(error.message);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const base = path_1.default.join(project.root, "requirements");
|
|
21
29
|
const statuses = ["backlog", "wip", "in-progress", "done", "archived"];
|
|
22
30
|
const sourceDir = statuses.map((status) => path_1.default.join(base, status, reqId)).find((candidate) => fs_1.default.existsSync(candidate));
|
|
23
31
|
if (!sourceDir) {
|
|
24
32
|
console.log("Requirement not found.");
|
|
25
33
|
return;
|
|
26
34
|
}
|
|
27
|
-
const targetDir = path_1.default.join(outputDir, `${
|
|
35
|
+
const targetDir = path_1.default.join(outputDir, `${project.name}-${reqId}`);
|
|
28
36
|
fs_1.default.mkdirSync(targetDir, { recursive: true });
|
|
29
37
|
for (const entry of fs_1.default.readdirSync(sourceDir)) {
|
|
30
38
|
const srcPath = path_1.default.join(sourceDir, entry);
|