@braingrid/cli 0.2.55 → 0.2.56

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/CHANGELOG.md CHANGED
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.56] - 2026-03-03
11
+
12
+ ### Changed
13
+
14
+ - **`/build` converted from command to skill** — moved `.claude/commands/build.md` to `.claude/skills/build/skill.md` with skill-style frontmatter; setup handler now auto-detects and removes the deprecated command file on install, init, and update paths
15
+ - **Removed `braingrid requirement build` and `braingrid requirement breakdown` CLI commands** — build workflow now handled entirely by the `/build` skill; `/specify` and `/save-requirement` updated to reference the skill
16
+ - **Updated E2E and unit tests** — setup tests now expect 5 skill directories and validate deprecated file cleanup
17
+
10
18
  ## [0.2.55] - 2026-02-26
11
19
 
12
20
  ### Fixed
package/README.md CHANGED
@@ -46,7 +46,7 @@ npm install -g @braingrid/cli
46
46
  braingrid setup claude-code
47
47
  ```
48
48
 
49
- Installs slash commands (`/specify`, `/breakdown`, `/build`), BrainGrid skill, and status line showing your project/requirement/task context in real-time.
49
+ Installs slash commands (`/specify`, `/build`), BrainGrid skill, and status line showing your project/requirement/task context in real-time.
50
50
 
51
51
  [→ Full Claude Code setup guide](./.braingrid/README.md)
52
52
 
@@ -71,11 +71,8 @@ braingrid init
71
71
  # 2. Create a requirement with AI refinement
72
72
  braingrid specify --prompt "Add user authentication"
73
73
 
74
- # 3. Break down requirement into tasks with AI
75
- braingrid requirement breakdown REQ-1
76
-
77
- # 4. Build requirement with all tasks (markdown with full content)
78
- braingrid requirement build REQ-1
74
+ # 3. Show requirement with all tasks (markdown with full content)
75
+ braingrid requirement show REQ-1 --format markdown
79
76
  ```
80
77
 
81
78
  ---
@@ -145,15 +142,15 @@ braingrid setup cursor --dry-run
145
142
  **What gets installed:**
146
143
 
147
144
  - **Claude Code integration:**
148
- - Commands in `.claude/commands/` (specify, breakdown, build, save-requirement)
149
- - Skills in `.claude/skills/braingrid-cli/`
145
+ - Commands in `.claude/commands/` (specify, save-requirement)
146
+ - Skills in `.claude/skills/` (braingrid-cli, build, frontend-design, ux)
150
147
  - Status line script at `.claude/statusline.sh`
151
148
  - Hook script at `.claude/hooks/sync-braingrid-task.sh` for task status sync
152
149
  - Settings in `.claude/settings.json` (configures status line and hooks)
153
150
  - Content injected into `CLAUDE.md` (or creates it if it doesn't exist)
154
151
 
155
152
  - **Cursor integration:**
156
- - Commands in `.cursor/commands/` (specify, breakdown, build, save-requirement)
153
+ - Commands in `.cursor/commands/` (specify, build, save-requirement)
157
154
  - Rules in `.cursor/rules/`
158
155
  - Content injected into `AGENTS.md` (or creates it if it doesn't exist)
159
156
 
@@ -216,8 +213,6 @@ braingrid requirement create --name "Name" [--content "Description"] [--assigned
216
213
  braingrid requirement show [id]
217
214
  braingrid requirement update [id] [--status IDEA|PLANNED|IN_PROGRESS|REVIEW|COMPLETED|CANCELLED] [--name "New Name"] [--content "markdown"]
218
215
  braingrid requirement delete [id] [--force]
219
- braingrid requirement breakdown [id] [--format markdown|json|xml]
220
- braingrid requirement build [id] [--format markdown|json|xml]
221
216
  braingrid requirement create-branch [id] [--name <branch-name>] [--base <branch>]
222
217
  braingrid requirement review [id] [--pr <number>]
223
218
 
@@ -335,7 +330,7 @@ eval "$(braingrid completion zsh)"
335
330
  ### What Gets Completed
336
331
 
337
332
  - **Commands**: `login`, `logout`, `project`, `requirement`, `task`, etc.
338
- - **Subcommands**: `list`, `show`, `create`, `update`, `delete`, `breakdown`, `build`, `create-branch`, `review`, `summary`, `specify`, `tag`
333
+ - **Subcommands**: `list`, `show`, `create`, `update`, `delete`, `create-branch`, `review`, `summary`, `specify`, `tag`
339
334
  - **Options**: `--help`, `--format`, `--status`, `--project`, `--requirement`
340
335
  - **Values**: Status values (`IDEA`, `PLANNED`, `IN_PROGRESS`, etc.), format options (`table`, `json`, `xml`, `markdown`)
341
336
 
package/dist/cli.js CHANGED
@@ -15,7 +15,7 @@ import {
15
15
 
16
16
  // src/cli.ts
17
17
  import { existsSync } from "fs";
18
- import { resolve } from "path";
18
+ import { resolve as resolve2 } from "path";
19
19
  import { fileURLToPath } from "url";
20
20
  import { config } from "dotenv";
21
21
  import { createRequire } from "module";
@@ -63,8 +63,6 @@ function createCompletion() {
63
63
  });
64
64
  completion.on("requirement", ({ reply }) => {
65
65
  reply([
66
- "breakdown",
67
- "build",
68
66
  "create",
69
67
  "create-branch",
70
68
  "delete",
@@ -155,7 +153,7 @@ var DEFAULT_OPTIONS = {
155
153
  // No-op by default
156
154
  };
157
155
  async function sleep(ms) {
158
- return new Promise((resolve2) => setTimeout(resolve2, ms));
156
+ return new Promise((resolve3) => setTimeout(resolve3, ms));
159
157
  }
160
158
  function calculateDelay(attempt, initialDelay, maxDelay, backoffMultiplier) {
161
159
  const exponentialDelay = initialDelay * backoffMultiplier ** (attempt - 1);
@@ -228,7 +226,7 @@ async function axiosWithRetry(config2, options) {
228
226
 
229
227
  // src/build-config.ts
230
228
  var BUILD_ENV = true ? "production" : process.env.NODE_ENV === "test" ? "development" : "production";
231
- var CLI_VERSION = true ? "0.2.55" : "0.0.0-test";
229
+ var CLI_VERSION = true ? "0.2.56" : "0.0.0-test";
232
230
  var PRODUCTION_CONFIG = {
233
231
  apiUrl: "https://app.braingrid.ai",
234
232
  workosAuthUrl: "https://auth.braingrid.ai",
@@ -619,7 +617,7 @@ var OAuth2Handler = class {
619
617
  * Start local HTTP server to handle OAuth callback
620
618
  */
621
619
  async startCallbackServer(port) {
622
- return new Promise((resolve2) => {
620
+ return new Promise((resolve3) => {
623
621
  this.server = createServer((req, res) => {
624
622
  const url = new URL(req.url || "", `http://127.0.0.1:${port}`);
625
623
  if (url.pathname === "/callback") {
@@ -722,7 +720,7 @@ var OAuth2Handler = class {
722
720
  });
723
721
  this.server.listen(port, "0.0.0.0", () => {
724
722
  logger.debug(`Callback server listening on http://127.0.0.1:${port}`);
725
- resolve2();
723
+ resolve3();
726
724
  });
727
725
  });
728
726
  }
@@ -787,7 +785,7 @@ var OAuth2Handler = class {
787
785
  * Wait for the authorization code from the callback
788
786
  */
789
787
  async waitForAuthorizationCode(timeoutMs = 3e5) {
790
- return new Promise((resolve2, reject) => {
788
+ return new Promise((resolve3, reject) => {
791
789
  const startTime = Date.now();
792
790
  const checkInterval = setInterval(() => {
793
791
  if (this.abortController?.signal.aborted) {
@@ -802,7 +800,7 @@ var OAuth2Handler = class {
802
800
  }
803
801
  if (this.authorizationCode) {
804
802
  clearInterval(checkInterval);
805
- resolve2(this.authorizationCode);
803
+ resolve3(this.authorizationCode);
806
804
  return;
807
805
  }
808
806
  if (Date.now() - startTime > timeoutMs) {
@@ -2706,19 +2704,19 @@ function closeLogger() {
2706
2704
  logFile = null;
2707
2705
  }
2708
2706
  function flushLogger() {
2709
- return new Promise((resolve2) => {
2707
+ return new Promise((resolve3) => {
2710
2708
  if (!logStream) {
2711
- resolve2();
2709
+ resolve3();
2712
2710
  return;
2713
2711
  }
2714
2712
  if (logStream.writableLength === 0) {
2715
- resolve2();
2713
+ resolve3();
2716
2714
  return;
2717
2715
  }
2718
- const timeout = setTimeout(resolve2, 1e3);
2716
+ const timeout = setTimeout(resolve3, 1e3);
2719
2717
  logStream.once("drain", () => {
2720
2718
  clearTimeout(timeout);
2721
- resolve2();
2719
+ resolve3();
2722
2720
  });
2723
2721
  });
2724
2722
  }
@@ -2782,7 +2780,7 @@ async function withRetry(fn, retries = MAX_RETRIES, delay = INITIAL_RETRY_DELAY)
2782
2780
  throw error;
2783
2781
  }
2784
2782
  log("WARN", "github-api", "retry", `attempt=${MAX_RETRIES - retries + 1} delay=${delay}ms`);
2785
- await new Promise((resolve2) => setTimeout(resolve2, delay));
2783
+ await new Promise((resolve3) => setTimeout(resolve3, delay));
2786
2784
  return withRetry(fn, retries - 1, delay * 2);
2787
2785
  }
2788
2786
  }
@@ -3670,7 +3668,7 @@ async function waitWithSpinner(message, checkFn, intervalMs = 3e3, maxAttempts =
3670
3668
  return true;
3671
3669
  }
3672
3670
  if (attempt < maxAttempts - 1) {
3673
- await new Promise((resolve2) => setTimeout(resolve2, intervalMs));
3671
+ await new Promise((resolve3) => setTimeout(resolve3, intervalMs));
3674
3672
  }
3675
3673
  }
3676
3674
  if (spinnerInterval) clearInterval(spinnerInterval);
@@ -3976,6 +3974,18 @@ async function _handleSetup(config2, opts) {
3976
3974
  if (readmeCopied) {
3977
3975
  log("INFO", "setup", "readme", "path=.braingrid/README.md");
3978
3976
  }
3977
+ if (config2.deprecatedFiles?.length) {
3978
+ for (const file of config2.deprecatedFiles) {
3979
+ try {
3980
+ if (await fileExists(file)) {
3981
+ await fs5.unlink(path7.resolve(file));
3982
+ log("INFO", "setup", "cleanup", `removed=${file}`);
3983
+ console.log(chalk10.dim(` Removed deprecated: ${file}`));
3984
+ }
3985
+ } catch (_error) {
3986
+ }
3987
+ }
3988
+ }
3979
3989
  return {
3980
3990
  success: true,
3981
3991
  data: {
@@ -4008,12 +4018,14 @@ async function handleSetupClaudeCode(opts) {
4008
4018
  sourceDirs: [
4009
4019
  "claude-code/commands",
4010
4020
  "claude-code/skills/braingrid-cli",
4021
+ "claude-code/skills/build",
4011
4022
  "claude-code/skills/frontend-design",
4012
4023
  "claude-code/skills/ux"
4013
4024
  ],
4014
4025
  targetDirs: [
4015
4026
  ".claude/commands",
4016
4027
  ".claude/skills/braingrid-cli",
4028
+ ".claude/skills/build",
4017
4029
  ".claude/skills/frontend-design",
4018
4030
  ".claude/skills/ux"
4019
4031
  ],
@@ -4021,13 +4033,15 @@ async function handleSetupClaudeCode(opts) {
4021
4033
  { label: "Commands", countMode: "files" },
4022
4034
  { label: "Skills", countMode: "single" },
4023
4035
  { label: "Skills", countMode: "single" },
4036
+ { label: "Skills", countMode: "single" },
4024
4037
  { label: "Skills", countMode: "single" }
4025
4038
  ],
4026
4039
  injection: {
4027
4040
  sourceFile: "claude-code/CLAUDE.md",
4028
4041
  targetFile: "CLAUDE.md"
4029
4042
  },
4030
- docsUrl: "https://docs.braingrid.ai/claude-code"
4043
+ docsUrl: "https://docs.braingrid.ai/claude-code",
4044
+ deprecatedFiles: [".claude/commands/build.md"]
4031
4045
  };
4032
4046
  try {
4033
4047
  const setupResult = await _handleSetup(config2, opts);
@@ -5749,84 +5763,6 @@ function formatRequirementListXml(requirements, pagination) {
5749
5763
  xml += "</requirements>\n";
5750
5764
  return xml;
5751
5765
  }
5752
- function formatRequirementBreakdownMarkdown(requirementShortId, tasks) {
5753
- let md = `# Breakdown: ${requirementShortId}
5754
-
5755
- `;
5756
- md += `Generated ${tasks.length} task${tasks.length !== 1 ? "s" : ""}
5757
-
5758
- `;
5759
- if (tasks.length === 0) {
5760
- md += "_No tasks generated._\n";
5761
- return md;
5762
- }
5763
- for (const task2 of tasks) {
5764
- md += `## Task ${task2.number}: ${task2.title}
5765
-
5766
- `;
5767
- md += `- **Status:** ${task2.status}
5768
- `;
5769
- md += `- **ID:** ${task2.id}
5770
- `;
5771
- if (task2.blocked_by.length > 0) {
5772
- md += `- **Blocked by:** ${task2.blocked_by.join(", ")}
5773
- `;
5774
- }
5775
- if (task2.content) {
5776
- md += `
5777
- ### Content
5778
-
5779
- ${task2.content}
5780
- `;
5781
- }
5782
- md += "\n";
5783
- }
5784
- return md;
5785
- }
5786
- function formatRequirementBreakdownXml(requirementShortId, tasks) {
5787
- let xml = '<?xml version="1.0" encoding="UTF-8"?>\n';
5788
- xml += "<breakdown>\n";
5789
- xml += ` <requirement_short_id>${escapeXml(requirementShortId)}</requirement_short_id>
5790
- `;
5791
- xml += ` <task_count>${tasks.length}</task_count>
5792
- `;
5793
- xml += " <tasks>\n";
5794
- for (const task2 of tasks) {
5795
- xml += " <task>\n";
5796
- xml += ` <number>${escapeXml(task2.number)}</number>
5797
- `;
5798
- xml += ` <title>${escapeXml(task2.title)}</title>
5799
- `;
5800
- xml += ` <status>${escapeXml(task2.status)}</status>
5801
- `;
5802
- xml += ` <id>${escapeXml(task2.id)}</id>
5803
- `;
5804
- if (task2.content) {
5805
- xml += ` <content>${escapeXml(task2.content)}</content>
5806
- `;
5807
- }
5808
- if (task2.blocked_by.length > 0) {
5809
- xml += " <blocked_by>\n";
5810
- for (const blocker of task2.blocked_by) {
5811
- xml += ` <task>${escapeXml(blocker)}</task>
5812
- `;
5813
- }
5814
- xml += " </blocked_by>\n";
5815
- }
5816
- if (task2.assigned_to) {
5817
- xml += ` <assigned_to>${escapeXml(task2.assigned_to)}</assigned_to>
5818
- `;
5819
- }
5820
- xml += ` <created_at>${escapeXml(task2.created_at)}</created_at>
5821
- `;
5822
- xml += ` <updated_at>${escapeXml(task2.updated_at)}</updated_at>
5823
- `;
5824
- xml += " </task>\n";
5825
- }
5826
- xml += " </tasks>\n";
5827
- xml += "</breakdown>\n";
5828
- return xml;
5829
- }
5830
5766
  function formatRequirementBuildMarkdown(requirement2, options) {
5831
5767
  const statusEmoji = getRequirementStatusEmoji(requirement2.status);
5832
5768
  let md = `# ${statusEmoji} ${requirement2.name}
@@ -5897,7 +5833,7 @@ ${requirement2.content}
5897
5833
  `;
5898
5834
  if (tasks.length === 0) {
5899
5835
  md += "_No tasks available_\n\n";
5900
- md += "\u{1F4A1} _Run `braingrid requirement breakdown [id]` to generate tasks using AI_\n";
5836
+ md += "\u{1F4A1} _No tasks have been created yet for this requirement._\n";
5901
5837
  } else {
5902
5838
  for (let i = 0; i < tasks.length; i++) {
5903
5839
  const task2 = tasks[i];
@@ -5968,20 +5904,6 @@ ${task2.content}
5968
5904
  }
5969
5905
  return md;
5970
5906
  }
5971
- function formatRequirementBuildJson(requirement2) {
5972
- const tasks = requirement2.tasks || [];
5973
- if (tasks.length === 0) {
5974
- return JSON.stringify(
5975
- {
5976
- ...requirement2,
5977
- _hint: "Run 'braingrid requirement breakdown [id]' to generate tasks using AI"
5978
- },
5979
- null,
5980
- 2
5981
- );
5982
- }
5983
- return JSON.stringify(requirement2, null, 2);
5984
- }
5985
5907
  function formatRequirementBuildXml(requirement2) {
5986
5908
  let xml = '<?xml version="1.0" encoding="UTF-8"?>\n';
5987
5909
  xml += "<requirement>\n";
@@ -6036,7 +5958,7 @@ function formatRequirementBuildXml(requirement2) {
6036
5958
  xml += ` <tasks count="${tasks.length}">
6037
5959
  `;
6038
5960
  if (tasks.length === 0) {
6039
- xml += ` <hint>Run 'braingrid requirement breakdown [id]' to generate tasks using AI</hint>
5961
+ xml += ` <hint>No tasks have been created yet for this requirement.</hint>
6040
5962
  `;
6041
5963
  } else {
6042
5964
  for (const task2 of tasks) {
@@ -6887,12 +6809,6 @@ var RequirementService = class {
6887
6809
  const headers = this.getHeaders();
6888
6810
  await this.axios.delete(url, { headers });
6889
6811
  }
6890
- async breakdownRequirement(projectId, requirementId, data) {
6891
- const url = `${this.baseUrl}/api/v1/projects/${projectId}/requirements/${requirementId}/breakdown`;
6892
- const headers = this.getHeaders();
6893
- const response = await this.axios.post(url, data, { headers });
6894
- return response.data;
6895
- }
6896
6812
  async createGitBranch(projectId, requirementId, data) {
6897
6813
  const url = `${this.baseUrl}/api/v1/projects/${projectId}/requirements/${requirementId}/create-git-branch`;
6898
6814
  const headers = this.getHeaders();
@@ -6906,12 +6822,12 @@ var RequirementService = class {
6906
6822
  headers,
6907
6823
  responseType: "stream"
6908
6824
  });
6909
- return new Promise((resolve2, reject) => {
6825
+ return new Promise((resolve3, reject) => {
6910
6826
  response.data.on("data", (chunk) => {
6911
6827
  onChunk(chunk.toString());
6912
6828
  });
6913
6829
  response.data.on("end", () => {
6914
- resolve2();
6830
+ resolve3();
6915
6831
  });
6916
6832
  response.data.on("error", (error) => {
6917
6833
  reject(error);
@@ -7497,192 +7413,6 @@ async function handleRequirementDelete(opts) {
7497
7413
  };
7498
7414
  }
7499
7415
  }
7500
- async function handleRequirementBreakdown(opts) {
7501
- let stop;
7502
- try {
7503
- const { requirementService, auth } = getServices3();
7504
- const isAuthenticated = await auth.isAuthenticated();
7505
- if (!isAuthenticated) {
7506
- return {
7507
- success: false,
7508
- message: chalk16.red("\u274C Not authenticated. Please run `braingrid login` first.")
7509
- };
7510
- }
7511
- const format = opts.format || "table";
7512
- if (!["table", "json", "xml", "markdown"].includes(format)) {
7513
- return {
7514
- success: false,
7515
- message: chalk16.red(
7516
- `\u274C Invalid format: ${format}. Supported formats: table, json, xml, markdown`
7517
- )
7518
- };
7519
- }
7520
- const requirementResult = await workspaceManager.getRequirement(opts.id);
7521
- if (!requirementResult.success) {
7522
- return {
7523
- success: false,
7524
- message: requirementResult.error
7525
- };
7526
- }
7527
- const requirementId = requirementResult.requirementId;
7528
- const workspace = await workspaceManager.getProject(opts.project);
7529
- if (!workspace.success) {
7530
- return {
7531
- success: false,
7532
- message: workspace.error
7533
- };
7534
- }
7535
- const projectId = workspace.projectId;
7536
- const normalizedId = normalizeRequirementId(requirementId);
7537
- stop = showSpinner("Checking requirement...", chalk16.gray);
7538
- const requirement2 = await requirementService.getProjectRequirement(projectId, normalizedId);
7539
- stop();
7540
- const taskCount = requirement2.tasks?.length ?? requirement2.task_progress?.total ?? 0;
7541
- if (taskCount > 0) {
7542
- const shortId = requirement2.short_id || normalizedId;
7543
- return {
7544
- success: false,
7545
- message: chalk16.red(
7546
- `\u274C Cannot breakdown requirement ${shortId} - it already has ${taskCount} task(s)
7547
-
7548
- `
7549
- ) + "The breakdown command is only for initial task generation from requirements.\nOnce tasks exist, you should manage them individually.\n\n" + chalk16.bold("To add more tasks to this requirement:\n") + chalk16.cyan(` braingrid task create -r ${shortId} --title "Task title"
7550
-
7551
- `) + chalk16.bold("To view existing tasks:\n") + chalk16.cyan(` braingrid task list -r ${shortId}`)
7552
- };
7553
- }
7554
- stop = showSpinner("Breaking down requirement into tasks...");
7555
- const response = await requirementService.breakdownRequirement(projectId, normalizedId, {});
7556
- stop();
7557
- let output;
7558
- switch (format) {
7559
- case "json": {
7560
- output = JSON.stringify(response, null, 2);
7561
- break;
7562
- }
7563
- case "xml": {
7564
- output = formatRequirementBreakdownXml(response.requirement_short_id, response.tasks);
7565
- break;
7566
- }
7567
- case "markdown": {
7568
- output = formatRequirementBreakdownMarkdown(response.requirement_short_id, response.tasks);
7569
- break;
7570
- }
7571
- default: {
7572
- output = chalk16.green(
7573
- `\u2705 Generated ${response.tasks.length} tasks for ${response.requirement_short_id}
7574
-
7575
- `
7576
- );
7577
- output += "Number Status Title\n";
7578
- output += `${"\u2500".repeat(80)}
7579
- `;
7580
- for (const task2 of response.tasks) {
7581
- const statusEmoji = getRequirementStatusEmoji(task2.status);
7582
- const number = task2.number.padEnd(6);
7583
- const statusText = task2.status.padEnd(12);
7584
- const title = task2.title.substring(0, 55);
7585
- output += `${number} ${statusEmoji} ${statusText} ${title}
7586
- `;
7587
- }
7588
- break;
7589
- }
7590
- }
7591
- return {
7592
- success: true,
7593
- message: output,
7594
- data: response
7595
- };
7596
- } catch (error) {
7597
- stop?.();
7598
- if (error && typeof error === "object" && "response" in error) {
7599
- return {
7600
- success: false,
7601
- message: handleError(
7602
- error,
7603
- `breaking down requirement ${opts.id || "unknown"}`
7604
- )
7605
- };
7606
- }
7607
- const errorMessage = error instanceof Error ? error.message : String(error);
7608
- return {
7609
- success: false,
7610
- message: chalk16.red(`\u274C Error breaking down requirement: ${errorMessage}`)
7611
- };
7612
- }
7613
- }
7614
- async function handleRequirementBuild(opts) {
7615
- let stopSpinner = null;
7616
- try {
7617
- const { requirementService, auth, config: config2 } = getServices3();
7618
- const isAuthenticated = await auth.isAuthenticated();
7619
- if (!isAuthenticated) {
7620
- return {
7621
- success: false,
7622
- message: chalk16.red("\u274C Not authenticated. Please run `braingrid login` first.")
7623
- };
7624
- }
7625
- const format = opts.format || "markdown";
7626
- if (!["markdown", "json", "xml"].includes(format)) {
7627
- return {
7628
- success: false,
7629
- message: chalk16.red("\u274C Invalid format. Must be one of: markdown, json, xml")
7630
- };
7631
- }
7632
- const requirementResult = await workspaceManager.getRequirement(opts.id);
7633
- if (!requirementResult.success) {
7634
- return {
7635
- success: false,
7636
- message: requirementResult.error
7637
- };
7638
- }
7639
- const requirementId = requirementResult.requirementId;
7640
- const workspace = await workspaceManager.getProject(opts.project);
7641
- if (!workspace.success) {
7642
- return {
7643
- success: false,
7644
- message: workspace.error
7645
- };
7646
- }
7647
- const projectId = workspace.projectId;
7648
- const normalizedId = normalizeRequirementId(requirementId);
7649
- stopSpinner = showSpinner("Building requirement with tasks", chalk16.gray);
7650
- const requirement2 = await requirementService.getProjectRequirement(projectId, normalizedId);
7651
- stopSpinner();
7652
- stopSpinner = null;
7653
- let output;
7654
- switch (format) {
7655
- case "json": {
7656
- output = formatRequirementBuildJson(requirement2);
7657
- break;
7658
- }
7659
- case "xml": {
7660
- output = formatRequirementBuildXml(requirement2);
7661
- break;
7662
- }
7663
- default: {
7664
- output = formatRequirementBuildMarkdown(requirement2, {
7665
- apiUrl: config2.apiUrl,
7666
- projectShortId: projectId
7667
- });
7668
- break;
7669
- }
7670
- }
7671
- return {
7672
- success: true,
7673
- message: output,
7674
- data: requirement2
7675
- };
7676
- } catch (error) {
7677
- if (stopSpinner) {
7678
- stopSpinner();
7679
- }
7680
- return {
7681
- success: false,
7682
- message: formatError(error, getResourceContext("requirement", opts.id || "unknown"))
7683
- };
7684
- }
7685
- }
7686
7416
  function slugify(text) {
7687
7417
  return text.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").substring(0, 40);
7688
7418
  }
@@ -9042,9 +8772,9 @@ function formatTaskSpecifyMarkdown(response, _apiUrl) {
9042
8772
 
9043
8773
  // src/cli.ts
9044
8774
  var __dirname = fileURLToPath(new URL(".", import.meta.url));
9045
- var packageRoot = resolve(__dirname, "..");
8775
+ var packageRoot = resolve2(__dirname, "..");
9046
8776
  var envFile = process.env.NODE_ENV ? `.env.${process.env.NODE_ENV}` : ".env";
9047
- var envPath = resolve(packageRoot, envFile);
8777
+ var envPath = resolve2(packageRoot, envFile);
9048
8778
  if (existsSync(envPath)) {
9049
8779
  config({ path: envPath, quiet: true });
9050
8780
  }
@@ -9210,30 +8940,6 @@ requirement.command("delete [id]").description("Delete a requirement (auto-detec
9210
8940
  process.exit(1);
9211
8941
  }
9212
8942
  });
9213
- requirement.command("breakdown [id]").description(
9214
- "Break down a requirement into actionable tasks using AI (auto-detects ID from git branch if not provided)"
9215
- ).option(
9216
- "-p, --project <id>",
9217
- "project ID (auto-detects from .braingrid/project.json if not provided)"
9218
- ).option("--format <format>", "output format (table, json, xml, markdown)", "markdown").action(async (id, opts) => {
9219
- const result = await handleRequirementBreakdown({ ...opts, id });
9220
- console.log(result.message);
9221
- if (!result.success) {
9222
- process.exit(1);
9223
- }
9224
- });
9225
- requirement.command("build [id]").description(
9226
- "Build requirement with all tasks in specified format (auto-detects ID from git branch if not provided)"
9227
- ).option(
9228
- "-p, --project <id>",
9229
- "project ID (auto-detects from .braingrid/project.json if not provided)"
9230
- ).option("--format <format>", "output format (markdown, json, xml)", "markdown").action(async (id, opts) => {
9231
- const result = await handleRequirementBuild({ ...opts, id });
9232
- console.log(result.message);
9233
- if (!result.success) {
9234
- process.exit(1);
9235
- }
9236
- });
9237
8943
  requirement.command("create-branch [id]").description(
9238
8944
  "Create a GitHub branch for a requirement (auto-detects ID from git branch if not provided)"
9239
8945
  ).option(