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.
Files changed (60) hide show
  1. package/README.md +41 -0
  2. package/dist/cli.js +58 -3
  3. package/dist/commands/ai-exec.js +3 -2
  4. package/dist/commands/ai-status.js +2 -1
  5. package/dist/commands/doctor.d.ts +1 -1
  6. package/dist/commands/doctor.js +218 -10
  7. package/dist/commands/gen-architecture.js +6 -5
  8. package/dist/commands/gen-best-practices.js +6 -5
  9. package/dist/commands/gen-functional-spec.js +6 -5
  10. package/dist/commands/gen-project-readme.js +6 -5
  11. package/dist/commands/gen-technical-spec.js +6 -5
  12. package/dist/commands/gen-utils.js +2 -1
  13. package/dist/commands/hello.js +27 -9
  14. package/dist/commands/import-issue.js +3 -2
  15. package/dist/commands/import-jira.d.ts +1 -0
  16. package/dist/commands/import-jira.js +127 -0
  17. package/dist/commands/learn-deliver.js +6 -5
  18. package/dist/commands/learn-refine.js +8 -7
  19. package/dist/commands/learn-start.js +3 -2
  20. package/dist/commands/list.js +19 -4
  21. package/dist/commands/pr-audit.js +6 -5
  22. package/dist/commands/pr-bridge-check.d.ts +1 -0
  23. package/dist/commands/pr-bridge-check.js +88 -0
  24. package/dist/commands/pr-bridge.d.ts +1 -0
  25. package/dist/commands/pr-bridge.js +124 -0
  26. package/dist/commands/pr-finish.js +6 -5
  27. package/dist/commands/pr-report.js +6 -5
  28. package/dist/commands/pr-respond.js +7 -6
  29. package/dist/commands/pr-risk.d.ts +1 -0
  30. package/dist/commands/pr-risk.js +112 -0
  31. package/dist/commands/pr-start.js +4 -3
  32. package/dist/commands/quickstart.js +10 -1
  33. package/dist/commands/req-archive.js +4 -3
  34. package/dist/commands/req-create.js +8 -7
  35. package/dist/commands/req-export.js +4 -3
  36. package/dist/commands/req-finish.js +9 -8
  37. package/dist/commands/req-lint.js +16 -6
  38. package/dist/commands/req-list.js +4 -3
  39. package/dist/commands/req-plan.js +12 -11
  40. package/dist/commands/req-refine.js +9 -8
  41. package/dist/commands/req-report.js +10 -9
  42. package/dist/commands/req-start.js +10 -9
  43. package/dist/commands/req-status.js +4 -3
  44. package/dist/commands/route.js +19 -4
  45. package/dist/commands/scope-list.d.ts +1 -0
  46. package/dist/commands/scope-list.js +16 -0
  47. package/dist/commands/scope-status.d.ts +1 -0
  48. package/dist/commands/scope-status.js +33 -0
  49. package/dist/commands/status.js +16 -7
  50. package/dist/commands/test-plan.js +6 -5
  51. package/dist/context/flags.d.ts +2 -0
  52. package/dist/context/flags.js +9 -1
  53. package/dist/errors.d.ts +2 -0
  54. package/dist/errors.js +10 -0
  55. package/dist/paths.js +4 -0
  56. package/dist/telemetry/local-metrics.d.ts +2 -0
  57. package/dist/telemetry/local-metrics.js +85 -0
  58. package/dist/workspace/index.d.ts +4 -0
  59. package/dist/workspace/index.js +129 -27
  60. package/package.json +24 -2
@@ -13,11 +13,12 @@ const validate_1 = require("../validation/validate");
13
13
  const gen_utils_1 = require("./gen-utils");
14
14
  const flags_1 = require("../context/flags");
15
15
  const index_1 = require("../workspace/index");
16
+ const errors_1 = require("../errors");
16
17
  async function runGenTechnicalSpec() {
17
18
  const projectName = await (0, prompt_1.askProjectName)();
18
19
  const reqId = await (0, prompt_1.ask)("Requirement ID (REQ-...): ");
19
20
  if (!projectName || !reqId) {
20
- console.log("Project name and requirement ID are required.");
21
+ (0, errors_1.printError)("SDD-1621", "Project name and requirement ID are required.");
21
22
  return;
22
23
  }
23
24
  const workspace = (0, index_1.getWorkspaceInfo)();
@@ -26,12 +27,12 @@ async function runGenTechnicalSpec() {
26
27
  project = (0, index_1.getProjectInfo)(workspace, projectName);
27
28
  }
28
29
  catch (error) {
29
- console.log(error.message);
30
+ (0, errors_1.printError)("SDD-1622", error.message);
30
31
  return;
31
32
  }
32
33
  const requirementDir = (0, gen_utils_1.findRequirementDir)(project.name, reqId);
33
34
  if (!requirementDir) {
34
- console.log("Requirement not found.");
35
+ (0, errors_1.printError)("SDD-1623", "Requirement not found.");
35
36
  return;
36
37
  }
37
38
  const stack = await (0, prompt_1.ask)("Tech stack - comma separated: ");
@@ -54,8 +55,8 @@ async function runGenTechnicalSpec() {
54
55
  };
55
56
  const validation = (0, validate_1.validateJson)("technical-spec.schema.json", technicalJson);
56
57
  if (!validation.valid) {
57
- console.log("Technical spec validation failed:");
58
- validation.errors.forEach((error) => console.log(`- ${error}`));
58
+ (0, errors_1.printError)("SDD-1624", "Technical spec validation failed.");
59
+ validation.errors.forEach((error) => (0, errors_1.printError)("SDD-1624", error));
59
60
  return;
60
61
  }
61
62
  const template = (0, render_1.loadTemplate)("technical-spec");
@@ -11,6 +11,7 @@ const fs_1 = __importDefault(require("fs"));
11
11
  const path_1 = __importDefault(require("path"));
12
12
  const index_1 = require("../workspace/index");
13
13
  const flags_1 = require("../context/flags");
14
+ const errors_1 = require("../errors");
14
15
  function findRequirementDir(projectName, reqId) {
15
16
  const workspace = (0, index_1.getWorkspaceInfo)();
16
17
  let project;
@@ -18,7 +19,7 @@ function findRequirementDir(projectName, reqId) {
18
19
  project = (0, index_1.getProjectInfo)(workspace, projectName);
19
20
  }
20
21
  catch (error) {
21
- console.log(error.message);
22
+ (0, errors_1.printError)("SDD-1605", error.message);
22
23
  return null;
23
24
  }
24
25
  const base = path_1.default.join(project.root, "requirements");
@@ -13,6 +13,8 @@ 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
+ const local_metrics_1 = require("../telemetry/local-metrics");
17
+ const errors_1 = require("../errors");
16
18
  const autopilot_checkpoint_1 = require("./autopilot-checkpoint");
17
19
  function printStep(step, description) {
18
20
  console.log(`${step}: ${description}`);
@@ -101,6 +103,10 @@ function buildAutopilotDraft(input, flow, domain) {
101
103
  };
102
104
  }
103
105
  async function runHello(input, runQuestions) {
106
+ (0, local_metrics_1.recordActivationMetric)("started", {
107
+ directIntent: input.trim().length > 0,
108
+ questionMode: runQuestions === true
109
+ });
104
110
  function loadWorkspace() {
105
111
  const workspace = (0, index_1.getWorkspaceInfo)();
106
112
  (0, index_1.ensureWorkspace)(workspace);
@@ -181,7 +187,12 @@ async function runHello(input, runQuestions) {
181
187
  }
182
188
  let text = input || (await (0, prompt_1.ask)("Describe what you want to do: "));
183
189
  let checkpoint = null;
184
- let fromStep = (0, autopilot_checkpoint_1.normalizeStep)(runtimeFlags.fromStep);
190
+ const rawFromStep = runtimeFlags.fromStep?.trim();
191
+ let fromStep = (0, autopilot_checkpoint_1.normalizeStep)(rawFromStep);
192
+ if (rawFromStep && !fromStep) {
193
+ (0, errors_1.printError)("SDD-1003", `Invalid --from-step value. Use one of: ${autopilot_checkpoint_1.AUTOPILOT_STEPS.join(", ")}`);
194
+ return;
195
+ }
185
196
  let activeProjectForCheckpoint = runtimeFlags.project;
186
197
  if (!shouldRunQuestions && activeProjectForCheckpoint) {
187
198
  checkpoint = (0, autopilot_checkpoint_1.loadCheckpoint)(activeProjectForCheckpoint);
@@ -196,7 +207,7 @@ async function runHello(input, runQuestions) {
196
207
  }
197
208
  }
198
209
  if (!text) {
199
- console.log("No input provided. Try again with a short description.");
210
+ (0, errors_1.printError)("SDD-1001", "No input provided. Try again with a short description.");
200
211
  return;
201
212
  }
202
213
  const intent = (0, intent_1.classifyIntent)(text);
@@ -215,7 +226,14 @@ async function runHello(input, runQuestions) {
215
226
  printWhy("I will gather enough context to generate a valid first draft.");
216
227
  printBeginnerTip(beginnerMode, "A requirement draft defines scope, acceptance criteria, and constraints.");
217
228
  if (shouldRunQuestions) {
218
- const packs = (0, prompt_packs_1.loadPromptPacks)();
229
+ let packs;
230
+ try {
231
+ packs = (0, prompt_packs_1.loadPromptPacks)();
232
+ }
233
+ catch (error) {
234
+ (0, errors_1.printError)("SDD-1012", `Unable to load prompt packs: ${error.message}`);
235
+ return;
236
+ }
219
237
  const packIds = intent_1.FLOW_PROMPT_PACKS[intent.flow] ?? [];
220
238
  const answers = {};
221
239
  for (const packId of packIds) {
@@ -258,7 +276,7 @@ async function runHello(input, runQuestions) {
258
276
  }
259
277
  }
260
278
  if (!activeProject) {
261
- console.log("Project name is required to run autopilot.");
279
+ (0, errors_1.printError)("SDD-1002", "Project name is required to run autopilot.");
262
280
  return;
263
281
  }
264
282
  printWhy(`Using project: ${activeProject}`);
@@ -270,16 +288,12 @@ async function runHello(input, runQuestions) {
270
288
  fromStep = candidate;
271
289
  }
272
290
  }
273
- if (fromStep && !autopilot_checkpoint_1.AUTOPILOT_STEPS.includes(fromStep)) {
274
- console.log(`Invalid --from-step value. Use one of: ${autopilot_checkpoint_1.AUTOPILOT_STEPS.join(", ")}`);
275
- return;
276
- }
277
291
  const draft = buildAutopilotDraft(text, intent.flow, intent.domain);
278
292
  draft.project_name = activeProject;
279
293
  let reqId = checkpoint?.reqId ?? "";
280
294
  const startStep = fromStep ?? "create";
281
295
  if (startStep !== "create" && !reqId) {
282
- console.log("No checkpoint found for resume. Run full autopilot first or use --from-step create.");
296
+ (0, errors_1.printError)("SDD-1004", "No checkpoint found for resume. Run full autopilot first or use --from-step create.");
283
297
  printRecoveryNext(activeProject, "create", text);
284
298
  return;
285
299
  }
@@ -375,6 +389,10 @@ async function runHello(input, runQuestions) {
375
389
  return;
376
390
  }
377
391
  (0, autopilot_checkpoint_1.clearCheckpoint)(activeProject);
392
+ (0, local_metrics_1.recordActivationMetric)("completed", {
393
+ project: activeProject,
394
+ reqId
395
+ });
378
396
  console.log(`Autopilot completed successfully for ${reqId}.`);
379
397
  console.log(`Artifacts finalized at: ${finished.doneDir}`);
380
398
  return;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.runImportIssue = runImportIssue;
4
4
  const hello_1 = require("./hello");
5
+ const errors_1 = require("../errors");
5
6
  function parseGitHubIssueUrl(input) {
6
7
  const trimmed = input.trim();
7
8
  const match = trimmed.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/issues\/(\d+)(?:[/?#].*)?$/i);
@@ -36,7 +37,7 @@ function buildSeedText(issue) {
36
37
  async function runImportIssue(issueUrl) {
37
38
  const ref = parseGitHubIssueUrl(issueUrl);
38
39
  if (!ref) {
39
- console.log("Invalid GitHub issue URL. Expected format: https://github.com/<owner>/<repo>/issues/<number>");
40
+ (0, errors_1.printError)("SDD-1101", "Invalid GitHub issue URL. Expected format: https://github.com/<owner>/<repo>/issues/<number>");
40
41
  return;
41
42
  }
42
43
  console.log(`Importing issue ${ref.owner}/${ref.repo}#${ref.number} ...`);
@@ -47,6 +48,6 @@ async function runImportIssue(issueUrl) {
47
48
  await (0, hello_1.runHello)(seedText, false);
48
49
  }
49
50
  catch (error) {
50
- console.log(error.message);
51
+ (0, errors_1.printError)("SDD-1102", error.message);
51
52
  }
52
53
  }
@@ -0,0 +1 @@
1
+ export declare function runImportJira(ticketInput: string): Promise<void>;
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runImportJira = runImportJira;
4
+ const hello_1 = require("./hello");
5
+ const errors_1 = require("../errors");
6
+ function parseJiraTicket(input) {
7
+ const trimmed = input.trim();
8
+ if (!trimmed) {
9
+ return null;
10
+ }
11
+ const keyOnly = trimmed.match(/^([a-z][a-z0-9_]*-\d+)$/i);
12
+ if (keyOnly) {
13
+ return { key: keyOnly[1].toUpperCase() };
14
+ }
15
+ const browseUrl = trimmed.match(/^https?:\/\/([^/]+)\/browse\/([a-z][a-z0-9_]*-\d+)(?:[/?#].*)?$/i);
16
+ if (browseUrl) {
17
+ const parsed = new URL(trimmed);
18
+ return {
19
+ key: browseUrl[2].toUpperCase(),
20
+ siteBase: `${parsed.protocol}//${parsed.host}`
21
+ };
22
+ }
23
+ return null;
24
+ }
25
+ function collectAdfText(node, chunks) {
26
+ if (!node || typeof node !== "object") {
27
+ return;
28
+ }
29
+ const obj = node;
30
+ if (typeof obj.text === "string") {
31
+ chunks.push(obj.text);
32
+ }
33
+ if (Array.isArray(obj.content)) {
34
+ for (const child of obj.content) {
35
+ collectAdfText(child, chunks);
36
+ }
37
+ }
38
+ }
39
+ function toDescriptionText(value) {
40
+ if (typeof value === "string") {
41
+ return value;
42
+ }
43
+ if (!value || typeof value !== "object") {
44
+ return "";
45
+ }
46
+ const chunks = [];
47
+ collectAdfText(value, chunks);
48
+ return chunks.join(" ").trim();
49
+ }
50
+ function getJiraApiBase(ref) {
51
+ if (process.env.SDD_JIRA_API_BASE && process.env.SDD_JIRA_API_BASE.trim().length > 0) {
52
+ return [process.env.SDD_JIRA_API_BASE.trim().replace(/\/$/, "")];
53
+ }
54
+ if (ref.siteBase) {
55
+ const site = ref.siteBase.replace(/\/$/, "");
56
+ return [`${site}/rest/api/3`, `${site}/rest/api/2`];
57
+ }
58
+ return [];
59
+ }
60
+ function getJiraAuthHeader() {
61
+ if (process.env.SDD_JIRA_AUTH && process.env.SDD_JIRA_AUTH.trim().length > 0) {
62
+ return process.env.SDD_JIRA_AUTH.trim();
63
+ }
64
+ const email = process.env.SDD_JIRA_EMAIL || "";
65
+ const token = process.env.SDD_JIRA_TOKEN || "";
66
+ if (email.trim().length > 0 && token.trim().length > 0) {
67
+ const basic = Buffer.from(`${email.trim()}:${token.trim()}`, "utf-8").toString("base64");
68
+ return `Basic ${basic}`;
69
+ }
70
+ return null;
71
+ }
72
+ async function fetchJiraTicket(ref) {
73
+ const apiBases = getJiraApiBase(ref);
74
+ if (apiBases.length === 0) {
75
+ throw new Error("Jira API base is required. Set SDD_JIRA_API_BASE or provide a full browse URL: https://<site>/browse/PROJ-123");
76
+ }
77
+ const auth = getJiraAuthHeader();
78
+ let lastStatus = 0;
79
+ for (const base of apiBases) {
80
+ const endpoint = `${base}/issue/${encodeURIComponent(ref.key)}`;
81
+ const headers = {
82
+ Accept: "application/json",
83
+ "User-Agent": "sdd-cli"
84
+ };
85
+ if (auth) {
86
+ headers.Authorization = auth;
87
+ }
88
+ const response = await fetch(endpoint, { headers });
89
+ if (!response.ok) {
90
+ lastStatus = response.status;
91
+ continue;
92
+ }
93
+ const payload = (await response.json());
94
+ const key = (payload.key || ref.key).toUpperCase();
95
+ const summary = payload.fields?.summary?.trim() || `Ticket ${key}`;
96
+ const description = toDescriptionText(payload.fields?.description);
97
+ let sourceUrl = `${key}`;
98
+ if (ref.siteBase) {
99
+ sourceUrl = `${ref.siteBase.replace(/\/$/, "")}/browse/${key}`;
100
+ }
101
+ else if (process.env.SDD_JIRA_SITE_BASE && process.env.SDD_JIRA_SITE_BASE.trim().length > 0) {
102
+ sourceUrl = `${process.env.SDD_JIRA_SITE_BASE.trim().replace(/\/$/, "")}/browse/${key}`;
103
+ }
104
+ return { key, summary, description, sourceUrl };
105
+ }
106
+ throw new Error(`Failed to fetch Jira ticket (${lastStatus || "unknown status"}).`);
107
+ }
108
+ function buildSeedText(ticket) {
109
+ const bodySnippet = ticket.description.trim().slice(0, 400).replace(/\s+/g, " ");
110
+ return `Resolve Jira ticket: ${ticket.key} ${ticket.summary}. Context: ${bodySnippet}. Source: ${ticket.sourceUrl}`;
111
+ }
112
+ async function runImportJira(ticketInput) {
113
+ const ref = parseJiraTicket(ticketInput);
114
+ if (!ref) {
115
+ (0, errors_1.printError)("SDD-1111", "Invalid Jira ticket. Expected format: PROJ-123 or https://<your-jira-site>/browse/PROJ-123");
116
+ return;
117
+ }
118
+ console.log(`Importing Jira ticket ${ref.key} ...`);
119
+ try {
120
+ const ticket = await fetchJiraTicket(ref);
121
+ console.log(`Imported: ${ticket.summary}`);
122
+ await (0, hello_1.runHello)(buildSeedText(ticket), false);
123
+ }
124
+ catch (error) {
125
+ (0, errors_1.printError)("SDD-1112", error.message);
126
+ }
127
+ }
@@ -9,10 +9,11 @@ const path_1 = __importDefault(require("path"));
9
9
  const prompt_1 = require("../ui/prompt");
10
10
  const list_1 = require("../utils/list");
11
11
  const learn_utils_1 = require("./learn-utils");
12
+ const errors_1 = require("../errors");
12
13
  async function runLearnDeliver() {
13
14
  const projectName = await (0, prompt_1.askProjectName)();
14
15
  if (!projectName) {
15
- console.log("Project name is required.");
16
+ (0, errors_1.printError)("SDD-1731", "Project name is required.");
16
17
  return;
17
18
  }
18
19
  let sessions = [];
@@ -20,7 +21,7 @@ async function runLearnDeliver() {
20
21
  sessions = (0, learn_utils_1.listLearnSessions)(projectName);
21
22
  }
22
23
  catch (error) {
23
- console.log(error.message);
24
+ (0, errors_1.printError)("SDD-1732", error.message);
24
25
  return;
25
26
  }
26
27
  if (sessions.length > 0) {
@@ -29,7 +30,7 @@ async function runLearnDeliver() {
29
30
  }
30
31
  const sessionId = await (0, prompt_1.ask)("Session ID: ");
31
32
  if (!sessionId) {
32
- console.log("Session ID is required.");
33
+ (0, errors_1.printError)("SDD-1733", "Session ID is required.");
33
34
  return;
34
35
  }
35
36
  let loaded;
@@ -37,11 +38,11 @@ async function runLearnDeliver() {
37
38
  loaded = (0, learn_utils_1.loadLearnSession)(projectName, sessionId);
38
39
  }
39
40
  catch (error) {
40
- console.log(error.message);
41
+ (0, errors_1.printError)("SDD-1734", error.message);
41
42
  return;
42
43
  }
43
44
  if (!loaded) {
44
- console.log("Learning session not found.");
45
+ (0, errors_1.printError)("SDD-1735", "Learning session not found.");
45
46
  return;
46
47
  }
47
48
  const brief = await (0, prompt_1.ask)("Brief summary: ");
@@ -9,10 +9,11 @@ const path_1 = __importDefault(require("path"));
9
9
  const prompt_1 = require("../ui/prompt");
10
10
  const list_1 = require("../utils/list");
11
11
  const learn_utils_1 = require("./learn-utils");
12
+ const errors_1 = require("../errors");
12
13
  async function runLearnRefine() {
13
14
  const projectName = await (0, prompt_1.askProjectName)();
14
15
  if (!projectName) {
15
- console.log("Project name is required.");
16
+ (0, errors_1.printError)("SDD-1721", "Project name is required.");
16
17
  return;
17
18
  }
18
19
  let sessions = [];
@@ -20,7 +21,7 @@ async function runLearnRefine() {
20
21
  sessions = (0, learn_utils_1.listLearnSessions)(projectName);
21
22
  }
22
23
  catch (error) {
23
- console.log(error.message);
24
+ (0, errors_1.printError)("SDD-1722", error.message);
24
25
  return;
25
26
  }
26
27
  if (sessions.length > 0) {
@@ -29,7 +30,7 @@ async function runLearnRefine() {
29
30
  }
30
31
  const sessionId = await (0, prompt_1.ask)("Session ID: ");
31
32
  if (!sessionId) {
32
- console.log("Session ID is required.");
33
+ (0, errors_1.printError)("SDD-1723", "Session ID is required.");
33
34
  return;
34
35
  }
35
36
  let loaded;
@@ -37,11 +38,11 @@ async function runLearnRefine() {
37
38
  loaded = (0, learn_utils_1.loadLearnSession)(projectName, sessionId);
38
39
  }
39
40
  catch (error) {
40
- console.log(error.message);
41
+ (0, errors_1.printError)("SDD-1724", error.message);
41
42
  return;
42
43
  }
43
44
  if (!loaded) {
44
- console.log("Learning session not found.");
45
+ (0, errors_1.printError)("SDD-1725", "Learning session not found.");
45
46
  return;
46
47
  }
47
48
  const purpose = await (0, prompt_1.ask)(`Purpose (${loaded.session.purpose}): `);
@@ -62,11 +63,11 @@ async function runLearnRefine() {
62
63
  });
63
64
  }
64
65
  catch (error) {
65
- console.log(error.message);
66
+ (0, errors_1.printError)("SDD-1726", error.message);
66
67
  return;
67
68
  }
68
69
  if (!updated) {
69
- console.log("Failed to update session.");
70
+ (0, errors_1.printError)("SDD-1727", "Failed to update session.");
70
71
  return;
71
72
  }
72
73
  const sessionMd = [
@@ -9,11 +9,12 @@ const path_1 = __importDefault(require("path"));
9
9
  const prompt_1 = require("../ui/prompt");
10
10
  const list_1 = require("../utils/list");
11
11
  const learn_utils_1 = require("./learn-utils");
12
+ const errors_1 = require("../errors");
12
13
  async function runLearnStart() {
13
14
  const projectName = await (0, prompt_1.askProjectName)();
14
15
  const topic = await (0, prompt_1.ask)("Topic to learn: ");
15
16
  if (!projectName || !topic) {
16
- console.log("Project name and topic are required.");
17
+ (0, errors_1.printError)("SDD-1711", "Project name and topic are required.");
17
18
  return;
18
19
  }
19
20
  const purpose = await (0, prompt_1.ask)("Why do you want to learn this? ");
@@ -27,7 +28,7 @@ async function runLearnStart() {
27
28
  created = (0, learn_utils_1.createLearnSession)(projectName, topic, "learning");
28
29
  }
29
30
  catch (error) {
30
- console.log(error.message);
31
+ (0, errors_1.printError)("SDD-1712", error.message);
31
32
  return;
32
33
  }
33
34
  (0, learn_utils_1.updateLearnSession)(projectName, created.session.id, {
@@ -9,6 +9,7 @@ const path_1 = __importDefault(require("path"));
9
9
  const paths_1 = require("../paths");
10
10
  const prompt_packs_1 = require("../router/prompt-packs");
11
11
  const index_1 = require("../workspace/index");
12
+ const errors_1 = require("../errors");
12
13
  function listDirectoryNames(dir, ext) {
13
14
  if (!fs_1.default.existsSync(dir)) {
14
15
  return [];
@@ -48,7 +49,14 @@ function runList() {
48
49
  else {
49
50
  templates.forEach((template) => console.log(`- ${template}`));
50
51
  }
51
- const packs = (0, prompt_packs_1.loadPromptPacks)();
52
+ let packs;
53
+ try {
54
+ packs = (0, prompt_packs_1.loadPromptPacks)();
55
+ }
56
+ catch (error) {
57
+ (0, errors_1.printError)("SDD-1421", `Unable to load prompt packs: ${error.message}`);
58
+ return;
59
+ }
52
60
  console.log("Prompt packs:");
53
61
  if (packs.length === 0) {
54
62
  console.log("- none");
@@ -56,9 +64,16 @@ function runList() {
56
64
  else {
57
65
  packs.forEach((pack) => console.log(`- ${pack.id}`));
58
66
  }
59
- const workspace = (0, index_1.getWorkspaceInfo)();
60
- (0, index_1.ensureWorkspace)(workspace);
61
- const projects = (0, index_1.listProjects)(workspace);
67
+ let projects;
68
+ try {
69
+ const workspace = (0, index_1.getWorkspaceInfo)();
70
+ (0, index_1.ensureWorkspace)(workspace);
71
+ projects = (0, index_1.listProjects)(workspace);
72
+ }
73
+ catch (error) {
74
+ (0, errors_1.printError)("SDD-1422", error.message);
75
+ return;
76
+ }
62
77
  console.log("Projects:");
63
78
  if (projects.length === 0) {
64
79
  console.log("- none");
@@ -10,10 +10,11 @@ const prompt_1 = require("../ui/prompt");
10
10
  const render_1 = require("../templates/render");
11
11
  const list_1 = require("../utils/list");
12
12
  const pr_utils_1 = require("./pr-utils");
13
+ const errors_1 = require("../errors");
13
14
  async function runPrAudit() {
14
15
  const projectName = await (0, prompt_1.askProjectName)();
15
16
  if (!projectName) {
16
- console.log("Project name is required.");
17
+ (0, errors_1.printError)("SDD-1346", "Project name is required.");
17
18
  return;
18
19
  }
19
20
  let available = [];
@@ -21,7 +22,7 @@ async function runPrAudit() {
21
22
  available = (0, pr_utils_1.listPrReviews)(projectName);
22
23
  }
23
24
  catch (error) {
24
- console.log(error.message);
25
+ (0, errors_1.printError)("SDD-1347", error.message);
25
26
  return;
26
27
  }
27
28
  if (available.length > 0) {
@@ -30,7 +31,7 @@ async function runPrAudit() {
30
31
  }
31
32
  const prId = await (0, prompt_1.ask)("PR ID: ");
32
33
  if (!prId) {
33
- console.log("PR ID is required.");
34
+ (0, errors_1.printError)("SDD-1348", "PR ID is required.");
34
35
  return;
35
36
  }
36
37
  let prDir;
@@ -38,11 +39,11 @@ async function runPrAudit() {
38
39
  prDir = (0, pr_utils_1.resolvePrDir)(projectName, prId);
39
40
  }
40
41
  catch (error) {
41
- console.log(error.message);
42
+ (0, errors_1.printError)("SDD-1349", error.message);
42
43
  return;
43
44
  }
44
45
  if (!fs_1.default.existsSync(prDir)) {
45
- console.log(`PR review not found at ${prDir}`);
46
+ (0, errors_1.printError)("SDD-1350", `PR review not found at ${prDir}`);
46
47
  return;
47
48
  }
48
49
  const prLink = await (0, prompt_1.ask)("PR link: ");
@@ -0,0 +1 @@
1
+ export declare function runPrBridgeCheck(): Promise<void>;
@@ -0,0 +1,88 @@
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.runPrBridgeCheck = runPrBridgeCheck;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const prompt_1 = require("../ui/prompt");
10
+ const gen_utils_1 = require("./gen-utils");
11
+ const errors_1 = require("../errors");
12
+ async function runPrBridgeCheck() {
13
+ const projectName = await (0, prompt_1.askProjectName)();
14
+ if (!projectName) {
15
+ (0, errors_1.printError)("SDD-1331", "Project name is required.");
16
+ return;
17
+ }
18
+ const reqId = await (0, prompt_1.ask)("Requirement ID (REQ-...): ");
19
+ if (!reqId) {
20
+ (0, errors_1.printError)("SDD-1332", "Requirement ID is required.");
21
+ return;
22
+ }
23
+ const requirementDir = (0, gen_utils_1.findRequirementDir)(projectName, reqId);
24
+ if (!requirementDir) {
25
+ (0, errors_1.printError)("SDD-1333", `Requirement not found: ${reqId}`);
26
+ return;
27
+ }
28
+ const linksPath = path_1.default.join(requirementDir, "pr-links.json");
29
+ if (!fs_1.default.existsSync(linksPath)) {
30
+ (0, errors_1.printError)("SDD-1334", "No pr-links.json found for this requirement.");
31
+ return;
32
+ }
33
+ let links = [];
34
+ try {
35
+ links = JSON.parse(fs_1.default.readFileSync(linksPath, "utf-8"));
36
+ }
37
+ catch {
38
+ (0, errors_1.printError)("SDD-1335", "Unable to parse pr-links.json.");
39
+ return;
40
+ }
41
+ const checks = links.map((link) => {
42
+ const prId = link.prId || "unknown";
43
+ const prDir = link.prDir || "";
44
+ const bridgeDir = path_1.default.join(requirementDir, "pr-review", prId);
45
+ const prDirExists = prDir.length > 0 && fs_1.default.existsSync(prDir);
46
+ const bridgeExists = fs_1.default.existsSync(bridgeDir);
47
+ const copiedArtifacts = Array.isArray(link.copiedArtifacts) ? link.copiedArtifacts : [];
48
+ const missingArtifacts = copiedArtifacts.filter((name) => !fs_1.default.existsSync(path_1.default.join(bridgeDir, name)));
49
+ return {
50
+ prId,
51
+ prDir,
52
+ prDirExists,
53
+ bridgeDir,
54
+ bridgeExists,
55
+ missingArtifacts,
56
+ ok: prDirExists && bridgeExists && missingArtifacts.length === 0
57
+ };
58
+ });
59
+ const okCount = checks.filter((item) => item.ok).length;
60
+ const report = {
61
+ requirement: reqId,
62
+ checkedAt: new Date().toISOString(),
63
+ total: checks.length,
64
+ ok: okCount,
65
+ failed: checks.length - okCount,
66
+ checks
67
+ };
68
+ fs_1.default.writeFileSync(path_1.default.join(requirementDir, "pr-bridge-integrity.json"), JSON.stringify(report, null, 2), "utf-8");
69
+ const lines = [
70
+ `# PR Bridge Integrity: ${reqId}`,
71
+ "",
72
+ `- Total links: ${report.total}`,
73
+ `- OK: ${report.ok}`,
74
+ `- Failed: ${report.failed}`,
75
+ "",
76
+ "## Details"
77
+ ];
78
+ checks.forEach((item) => {
79
+ lines.push(`- ${item.prId}: ok=${item.ok} prDirExists=${item.prDirExists} bridgeExists=${item.bridgeExists} missingArtifacts=${item.missingArtifacts.join(", ") || "none"}`);
80
+ });
81
+ fs_1.default.writeFileSync(path_1.default.join(requirementDir, "pr-bridge-integrity.md"), `${lines.join("\n")}\n`, "utf-8");
82
+ if (report.failed > 0) {
83
+ (0, errors_1.printError)("SDD-1336", `Bridge integrity failed for ${report.failed} linked PR(s).`);
84
+ process.exitCode = 1;
85
+ return;
86
+ }
87
+ console.log(`PR bridge integrity OK for ${reqId}.`);
88
+ }
@@ -0,0 +1 @@
1
+ export declare function runPrBridge(): Promise<void>;