@braingrid/cli 0.2.18 → 0.2.20

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/dist/cli.js CHANGED
@@ -422,7 +422,7 @@ import axios3, { AxiosError as AxiosError2 } from "axios";
422
422
 
423
423
  // src/build-config.ts
424
424
  var BUILD_ENV = true ? "production" : process.env.NODE_ENV === "test" ? "development" : "production";
425
- var CLI_VERSION = true ? "0.2.18" : "0.0.0-test";
425
+ var CLI_VERSION = true ? "0.2.20" : "0.0.0-test";
426
426
  var PRODUCTION_CONFIG = {
427
427
  apiUrl: "https://app.braingrid.ai",
428
428
  workosAuthUrl: "https://auth.braingrid.ai",
@@ -3914,6 +3914,9 @@ async function handleRequirementList(opts) {
3914
3914
  break;
3915
3915
  }
3916
3916
  }
3917
+ if (response.pagination?.has_more) {
3918
+ output += "\n" + chalk7.yellow("\u26A0\uFE0F More requirements exist. Use --limit to see more.");
3919
+ }
3917
3920
  return {
3918
3921
  success: true,
3919
3922
  message: output,
@@ -4522,11 +4525,19 @@ async function getCurrentTask(taskService, projectId, requirementId) {
4522
4525
  const response = await taskService.listTasks(projectId, requirementId);
4523
4526
  const inProgress = response.tasks.find((t) => t.status === "IN_PROGRESS");
4524
4527
  if (inProgress) {
4525
- return { success: true, taskId: inProgress.number };
4528
+ const warning = response.pagination?.has_more ? "Note: More tasks exist beyond current page." : void 0;
4529
+ return { success: true, taskId: inProgress.number, warning };
4526
4530
  }
4527
4531
  const planned = response.tasks.find((t) => t.status === "PLANNED");
4528
4532
  if (planned) {
4529
- return { success: true, taskId: planned.number };
4533
+ const warning = response.pagination?.has_more ? "Note: More tasks exist beyond current page." : void 0;
4534
+ return { success: true, taskId: planned.number, warning };
4535
+ }
4536
+ if (response.pagination?.has_more) {
4537
+ return {
4538
+ success: false,
4539
+ error: "No active task found in current page. More tasks exist - use --limit to fetch more."
4540
+ };
4530
4541
  }
4531
4542
  return {
4532
4543
  success: false,
@@ -4561,7 +4572,10 @@ async function handleTaskList(opts) {
4561
4572
  }
4562
4573
  const requirementId = requirementResult.requirementId;
4563
4574
  stopSpinner = showSpinner("Loading tasks", chalk8.gray);
4564
- const response = await taskService.listTasks(projectId, requirementId);
4575
+ const response = await taskService.listTasks(projectId, requirementId, {
4576
+ page: opts.page ? parseInt(opts.page, 10) : 1,
4577
+ limit: opts.limit ? parseInt(opts.limit, 10) : 20
4578
+ });
4565
4579
  stopSpinner();
4566
4580
  stopSpinner = null;
4567
4581
  if (response.tasks.length === 0) {
@@ -4575,12 +4589,15 @@ async function handleTaskList(opts) {
4575
4589
  const requirementShortId = opts.requirement || requirementId;
4576
4590
  const format = opts.format || "markdown";
4577
4591
  const config = getConfig();
4578
- const output = formatTasksListOutput(response.tasks, format, true, {
4592
+ let output = formatTasksListOutput(response.tasks, format, true, {
4579
4593
  requirementId,
4580
4594
  projectShortId,
4581
4595
  requirementShortId,
4582
4596
  apiUrl: config.apiUrl
4583
4597
  });
4598
+ if (response.pagination?.has_more) {
4599
+ output += "\n" + chalk8.yellow("\u26A0\uFE0F More tasks exist. Use --limit to see more.");
4600
+ }
4584
4601
  return {
4585
4602
  success: true,
4586
4603
  message: output,
@@ -4624,7 +4641,10 @@ async function handleTaskSummary(opts) {
4624
4641
  }
4625
4642
  const requirementId = requirementResult.requirementId;
4626
4643
  stopSpinner = showSpinner("Loading tasks", chalk8.gray);
4627
- const response = await taskService.listTasks(projectId, requirementId);
4644
+ const response = await taskService.listTasks(projectId, requirementId, {
4645
+ page: opts.page ? parseInt(opts.page, 10) : 1,
4646
+ limit: opts.limit ? parseInt(opts.limit, 10) : 20
4647
+ });
4628
4648
  stopSpinner();
4629
4649
  stopSpinner = null;
4630
4650
  if (response.tasks.length === 0) {
@@ -4637,12 +4657,15 @@ async function handleTaskSummary(opts) {
4637
4657
  const projectShortId = projectId;
4638
4658
  const requirementShortId = opts.requirement || requirementId;
4639
4659
  const config = getConfig();
4640
- const output = formatTasksListOutput(response.tasks, "table", false, {
4660
+ let output = formatTasksListOutput(response.tasks, "table", false, {
4641
4661
  requirementId,
4642
4662
  projectShortId,
4643
4663
  requirementShortId,
4644
4664
  apiUrl: config.apiUrl
4645
4665
  });
4666
+ if (response.pagination?.has_more) {
4667
+ output += "\n" + chalk8.yellow("\u26A0\uFE0F More tasks exist. Use --limit to see more.");
4668
+ }
4646
4669
  return {
4647
4670
  success: true,
4648
4671
  message: output,
@@ -4695,6 +4718,7 @@ async function handleTaskShow(id, opts) {
4695
4718
  }
4696
4719
  const requirementId = requirementResult.requirementId;
4697
4720
  let taskId;
4721
+ let taskWarning;
4698
4722
  if (id) {
4699
4723
  taskId = normalizeTaskId(id);
4700
4724
  } else {
@@ -4706,6 +4730,7 @@ async function handleTaskShow(id, opts) {
4706
4730
  };
4707
4731
  }
4708
4732
  taskId = currentTask.taskId;
4733
+ taskWarning = currentTask.warning;
4709
4734
  }
4710
4735
  const config = getConfig();
4711
4736
  stopSpinner = showSpinner("Loading task", chalk8.gray);
@@ -4740,6 +4765,9 @@ async function handleTaskShow(id, opts) {
4740
4765
  break;
4741
4766
  }
4742
4767
  }
4768
+ if (taskWarning) {
4769
+ output += "\n" + chalk8.yellow(`\u26A0\uFE0F ${taskWarning}`);
4770
+ }
4743
4771
  return {
4744
4772
  success: true,
4745
4773
  message: output,
@@ -4849,6 +4877,7 @@ async function handleTaskUpdate(id, opts) {
4849
4877
  }
4850
4878
  const requirementId = requirementResult.requirementId;
4851
4879
  let taskId;
4880
+ let taskWarning;
4852
4881
  if (id) {
4853
4882
  taskId = normalizeTaskId(id);
4854
4883
  } else {
@@ -4860,6 +4889,7 @@ async function handleTaskUpdate(id, opts) {
4860
4889
  };
4861
4890
  }
4862
4891
  taskId = currentTask.taskId;
4892
+ taskWarning = currentTask.warning;
4863
4893
  }
4864
4894
  const config = getConfig();
4865
4895
  stopSpinner = showSpinner("Updating task", chalk8.gray);
@@ -4869,7 +4899,7 @@ async function handleTaskUpdate(id, opts) {
4869
4899
  });
4870
4900
  stopSpinner();
4871
4901
  stopSpinner = null;
4872
- const output = formatTaskOutput(task2, {
4902
+ let output = formatTaskOutput(task2, {
4873
4903
  showContent: true,
4874
4904
  successMessage: `Updated task ${task2.number}`,
4875
4905
  apiUrl: config.apiUrl,
@@ -4877,6 +4907,9 @@ async function handleTaskUpdate(id, opts) {
4877
4907
  requirementShortId: opts?.requirement || requirementId,
4878
4908
  requirementId
4879
4909
  });
4910
+ if (taskWarning) {
4911
+ output += "\n" + chalk8.yellow(`\u26A0\uFE0F ${taskWarning}`);
4912
+ }
4880
4913
  return {
4881
4914
  success: true,
4882
4915
  message: output,
@@ -5227,7 +5260,7 @@ async function handleStatus() {
5227
5260
 
5228
5261
  // src/handlers/init.handlers.ts
5229
5262
  import chalk15 from "chalk";
5230
- import { confirm, select as select3, input } from "@inquirer/prompts";
5263
+ import { confirm as confirm2, select as select3, input } from "@inquirer/prompts";
5231
5264
 
5232
5265
  // src/services/internal/github-service.ts
5233
5266
  var GitHubService = class {
@@ -5495,7 +5528,8 @@ function getManualInstallInstructions() {
5495
5528
  }
5496
5529
 
5497
5530
  // src/handlers/update.handlers.ts
5498
- import chalk12 from "chalk";
5531
+ import chalk13 from "chalk";
5532
+ import { confirm } from "@inquirer/prompts";
5499
5533
 
5500
5534
  // src/utils/package-manager.ts
5501
5535
  import { execSync } from "child_process";
@@ -5631,139 +5665,8 @@ function compareVersions(v1, v2) {
5631
5665
  return 0;
5632
5666
  }
5633
5667
 
5634
- // src/handlers/update.handlers.ts
5635
- async function handleUpdate(opts) {
5636
- try {
5637
- const currentVersion = getCurrentVersion();
5638
- let output = chalk12.bold.cyan("\n\u{1F504} BrainGrid CLI Update\n\n");
5639
- output += `${chalk12.bold("Current version:")} ${currentVersion}
5640
- `;
5641
- output += chalk12.dim("Checking for updates...\n");
5642
- const latestVersion = await getLatestVersion();
5643
- output += `${chalk12.bold("Latest version:")} ${latestVersion}
5644
-
5645
- `;
5646
- const comparison = compareVersions(currentVersion, latestVersion);
5647
- if (comparison === 0) {
5648
- output += chalk12.green("\u2705 You are already on the latest version!\n");
5649
- return {
5650
- success: true,
5651
- message: output,
5652
- data: { currentVersion, latestVersion, upToDate: true }
5653
- };
5654
- }
5655
- if (comparison > 0) {
5656
- output += chalk12.yellow("\u26A0\uFE0F You are on a newer version than what is published.\n");
5657
- output += chalk12.dim(" This is expected if you are developing locally.\n");
5658
- return {
5659
- success: true,
5660
- message: output,
5661
- data: { currentVersion, latestVersion, upToDate: false }
5662
- };
5663
- }
5664
- output += chalk12.yellow(`\u2B06\uFE0F Update available: ${currentVersion} \u2192 ${latestVersion}
5665
-
5666
- `);
5667
- if (opts.check) {
5668
- output += chalk12.dim("Run ") + chalk12.cyan("braingrid update") + chalk12.dim(" to update\n");
5669
- return {
5670
- success: true,
5671
- message: output,
5672
- data: { currentVersion, latestVersion, upToDate: false }
5673
- };
5674
- }
5675
- output += chalk12.dim("Detecting package manager...\n");
5676
- const packageManager = await detectPackageManager(PACKAGE_NAME);
5677
- output += `${chalk12.bold("Package manager:")} ${packageManager}
5678
-
5679
- `;
5680
- const updateCommand = getUpdateCommand(packageManager, PACKAGE_NAME);
5681
- output += chalk12.dim("Running: ") + chalk12.cyan(updateCommand) + "\n\n";
5682
- console.log(output);
5683
- executeUpdate(packageManager, PACKAGE_NAME);
5684
- return {
5685
- success: true,
5686
- message: chalk12.green("\n\u2705 Successfully updated BrainGrid CLI!\n"),
5687
- data: { currentVersion, latestVersion, packageManager }
5688
- };
5689
- } catch (error) {
5690
- return {
5691
- success: false,
5692
- message: formatError(error)
5693
- };
5694
- }
5695
- }
5696
-
5697
- // src/utils/update-checker.ts
5698
- import chalk13 from "chalk";
5699
- var CACHE_TTL_MS = 12 * 60 * 60 * 1e3;
5700
- var CACHE_SERVICE = "braingrid-cli";
5701
- var CACHE_ACCOUNT = "update-cache";
5702
- async function getCache() {
5703
- try {
5704
- const cached = await credentialStore.getPassword(CACHE_SERVICE, CACHE_ACCOUNT);
5705
- if (!cached) return null;
5706
- return JSON.parse(cached);
5707
- } catch {
5708
- return null;
5709
- }
5710
- }
5711
- async function setCache(cache) {
5712
- try {
5713
- await credentialStore.setPassword(CACHE_SERVICE, CACHE_ACCOUNT, JSON.stringify(cache));
5714
- } catch {
5715
- }
5716
- }
5717
- function isCacheValid(cache) {
5718
- const now = Date.now();
5719
- return now - cache.checkedAt < CACHE_TTL_MS;
5720
- }
5721
- async function getLatestVersionCached() {
5722
- const cache = await getCache();
5723
- if (cache && isCacheValid(cache)) {
5724
- return cache.latestVersion;
5725
- }
5726
- try {
5727
- const latestVersion = await getLatestVersion(5e3);
5728
- await setCache({
5729
- latestVersion,
5730
- checkedAt: Date.now()
5731
- });
5732
- return latestVersion;
5733
- } catch {
5734
- return cache?.latestVersion ?? null;
5735
- }
5736
- }
5737
- async function isUpdateAvailable() {
5738
- const currentVersion = getCurrentVersion();
5739
- const latestVersion = await getLatestVersionCached();
5740
- if (!latestVersion) {
5741
- return { available: false, currentVersion, latestVersion: null };
5742
- }
5743
- const comparison = compareVersions(currentVersion, latestVersion);
5744
- return {
5745
- available: comparison < 0,
5746
- // Update available if current < latest
5747
- currentVersion,
5748
- latestVersion
5749
- };
5750
- }
5751
- function getUpdateCommand2() {
5752
- return `npm install -g ${PACKAGE_NAME}`;
5753
- }
5754
- async function checkAndShowUpdateWarning() {
5755
- try {
5756
- const { available, currentVersion, latestVersion } = await isUpdateAvailable();
5757
- if (available && latestVersion) {
5758
- const warning = "\n" + chalk13.yellow(`\u26A0\uFE0F Update available: ${currentVersion} \u2192 ${latestVersion}`) + "\n" + chalk13.dim(` Run \`${getUpdateCommand2()}\` to update`) + "\n";
5759
- console.log(warning);
5760
- }
5761
- } catch {
5762
- }
5763
- }
5764
-
5765
5668
  // src/handlers/setup.handlers.ts
5766
- import chalk14 from "chalk";
5669
+ import chalk12 from "chalk";
5767
5670
  import { select as select2 } from "@inquirer/prompts";
5768
5671
  import * as path4 from "path";
5769
5672
  import * as fs4 from "fs/promises";
@@ -5981,7 +5884,7 @@ async function checkPrerequisites() {
5981
5884
  } catch {
5982
5885
  return {
5983
5886
  success: false,
5984
- message: chalk14.red("\u274C GitHub CLI is not installed.\n\n") + chalk14.dim("Install instructions:\n") + chalk14.dim(" macOS: ") + chalk14.cyan("brew install gh") + chalk14.dim("\n") + chalk14.dim(" Windows: ") + chalk14.cyan("winget install GitHub.CLI") + chalk14.dim("\n") + chalk14.dim(" Linux: See ") + chalk14.cyan("https://cli.github.com/manual/installation") + chalk14.dim("\n\n") + chalk14.dim("After installing, run: ") + chalk14.cyan("gh auth login")
5887
+ message: chalk12.red("\u274C GitHub CLI is not installed.\n\n") + chalk12.dim("Install instructions:\n") + chalk12.dim(" macOS: ") + chalk12.cyan("brew install gh") + chalk12.dim("\n") + chalk12.dim(" Windows: ") + chalk12.cyan("winget install GitHub.CLI") + chalk12.dim("\n") + chalk12.dim(" Linux: See ") + chalk12.cyan("https://cli.github.com/manual/installation") + chalk12.dim("\n\n") + chalk12.dim("After installing, run: ") + chalk12.cyan("gh auth login")
5985
5888
  };
5986
5889
  }
5987
5890
  try {
@@ -5989,7 +5892,7 @@ async function checkPrerequisites() {
5989
5892
  } catch {
5990
5893
  return {
5991
5894
  success: false,
5992
- message: chalk14.red("\u274C Not authenticated with GitHub CLI.\n\n") + chalk14.dim("Please run: ") + chalk14.cyan("gh auth login")
5895
+ message: chalk12.red("\u274C Not authenticated with GitHub CLI.\n\n") + chalk12.dim("Please run: ") + chalk12.cyan("gh auth login")
5993
5896
  };
5994
5897
  }
5995
5898
  return null;
@@ -6016,7 +5919,7 @@ async function getFileList(sourcePaths, targetPaths) {
6016
5919
  }
6017
5920
  } catch (error) {
6018
5921
  console.warn(
6019
- chalk14.yellow(`\u26A0\uFE0F Could not list directory: ${sourceDir}`),
5922
+ chalk12.yellow(`\u26A0\uFE0F Could not list directory: ${sourceDir}`),
6020
5923
  error instanceof Error ? error.message : String(error)
6021
5924
  );
6022
5925
  }
@@ -6027,28 +5930,28 @@ async function getFileList(sourcePaths, targetPaths) {
6027
5930
  return operations;
6028
5931
  }
6029
5932
  function displayInstallationPlan(operations, injectionFile) {
6030
- console.log(chalk14.bold("\n\u{1F4CB} Installation Plan:\n"));
6031
- console.log(chalk14.cyan(" Content Injection:"));
6032
- console.log(chalk14.dim(` ${injectionFile}`));
5933
+ console.log(chalk12.bold("\n\u{1F4CB} Installation Plan:\n"));
5934
+ console.log(chalk12.cyan(" Content Injection:"));
5935
+ console.log(chalk12.dim(` ${injectionFile}`));
6033
5936
  const newFiles = operations.filter((op) => !op.exists);
6034
5937
  const existingFiles = operations.filter((op) => op.exists);
6035
5938
  if (newFiles.length > 0) {
6036
- console.log(chalk14.cyan("\n New Files:"));
5939
+ console.log(chalk12.cyan("\n New Files:"));
6037
5940
  for (const op of newFiles) {
6038
- console.log(chalk14.dim(` ${op.targetPath}`));
5941
+ console.log(chalk12.dim(` ${op.targetPath}`));
6039
5942
  }
6040
5943
  }
6041
5944
  if (existingFiles.length > 0) {
6042
- console.log(chalk14.yellow("\n Existing Files (will prompt):"));
5945
+ console.log(chalk12.yellow("\n Existing Files (will prompt):"));
6043
5946
  for (const op of existingFiles) {
6044
- console.log(chalk14.dim(` ${op.targetPath}`));
5947
+ console.log(chalk12.dim(` ${op.targetPath}`));
6045
5948
  }
6046
5949
  }
6047
5950
  console.log("");
6048
5951
  }
6049
5952
  async function promptForConflict(filePath) {
6050
5953
  const answer = await select2({
6051
- message: chalk14.yellow(`File exists: ${filePath}`),
5954
+ message: chalk12.yellow(`File exists: ${filePath}`),
6052
5955
  choices: [
6053
5956
  { name: "[O]verwrite - Replace this file", value: "overwrite" },
6054
5957
  { name: "[S]kip - Keep existing file", value: "skip" },
@@ -6079,7 +5982,7 @@ async function installFiles(operations, force) {
6079
5982
  installed++;
6080
5983
  } catch (error) {
6081
5984
  console.error(
6082
- chalk14.red(`Failed to copy ${operation.targetPath}:`),
5985
+ chalk12.red(`Failed to copy ${operation.targetPath}:`),
6083
5986
  error instanceof Error ? error.message : String(error)
6084
5987
  );
6085
5988
  skipped++;
@@ -6093,7 +5996,7 @@ async function _handleSetup(config, opts) {
6093
5996
  if (prerequisiteError) {
6094
5997
  return prerequisiteError;
6095
5998
  }
6096
- console.log(chalk14.bold(`\u{1F680} Setting up ${config.name} integration...
5999
+ console.log(chalk12.bold(`\u{1F680} Setting up ${config.name} integration...
6097
6000
  `));
6098
6001
  const operations = await getFileList(config.sourceDirs, config.targetDirs);
6099
6002
  const injectionFileExists = await fileExists(config.injection.targetFile);
@@ -6110,7 +6013,7 @@ async function _handleSetup(config, opts) {
6110
6013
  if (opts.dryRun) {
6111
6014
  return {
6112
6015
  success: true,
6113
- message: chalk14.green("\u2705 Dry-run complete. No files were modified.\n\n") + chalk14.dim(`Would install ${operations.length} files.`)
6016
+ message: chalk12.green("\u2705 Dry-run complete. No files were modified.\n\n") + chalk12.dim(`Would install ${operations.length} files.`)
6114
6017
  };
6115
6018
  }
6116
6019
  const copyOps = operations.filter((op) => op.type === "copy");
@@ -6118,7 +6021,7 @@ async function _handleSetup(config, opts) {
6118
6021
  if (result.cancelled) {
6119
6022
  return {
6120
6023
  success: false,
6121
- message: chalk14.yellow("\u26A0\uFE0F Installation cancelled.\n\n") + chalk14.dim(`Installed: ${result.installed}, Skipped: ${result.skipped}`),
6024
+ message: chalk12.yellow("\u26A0\uFE0F Installation cancelled.\n\n") + chalk12.dim(`Installed: ${result.installed}, Skipped: ${result.skipped}`),
6122
6025
  code: "CANCELLED"
6123
6026
  };
6124
6027
  }
@@ -6127,7 +6030,7 @@ async function _handleSetup(config, opts) {
6127
6030
  await injectContentIntoFile(config.injection.targetFile, content);
6128
6031
  } catch (error) {
6129
6032
  console.error(
6130
- chalk14.red(`Failed to inject content into ${config.injection.targetFile}:`),
6033
+ chalk12.red(`Failed to inject content into ${config.injection.targetFile}:`),
6131
6034
  error instanceof Error ? error.message : String(error)
6132
6035
  );
6133
6036
  }
@@ -6140,27 +6043,27 @@ async function _handleSetup(config, opts) {
6140
6043
  statusLineInstalled = true;
6141
6044
  } catch (error) {
6142
6045
  console.error(
6143
- chalk14.yellow("\u26A0\uFE0F Failed to install status line script:"),
6046
+ chalk12.yellow("\u26A0\uFE0F Failed to install status line script:"),
6144
6047
  error instanceof Error ? error.message : String(error)
6145
6048
  );
6146
6049
  }
6147
6050
  }
6148
- const statusLineMessage = statusLineInstalled ? chalk14.dim(" Status line: .claude/statusline.sh\n") : "";
6051
+ const statusLineMessage = statusLineInstalled ? chalk12.dim(" Status line: .claude/statusline.sh\n") : "";
6149
6052
  return {
6150
6053
  success: true,
6151
- message: chalk14.green(`\u2705 ${config.name} integration installed successfully!
6054
+ message: chalk12.green(`\u2705 ${config.name} integration installed successfully!
6152
6055
 
6153
- `) + chalk14.dim("Files installed:\n") + chalk14.dim(` Commands: ${result.installed} files
6154
- `) + statusLineMessage + chalk14.dim(` Content injected into: ${config.injection.targetFile}
6056
+ `) + chalk12.dim("Files installed:\n") + chalk12.dim(` Commands: ${result.installed} files
6057
+ `) + statusLineMessage + chalk12.dim(` Content injected into: ${config.injection.targetFile}
6155
6058
 
6156
- `) + chalk14.dim("Next steps:\n") + chalk14.dim(" 1. Review the integration files\n") + chalk14.dim(` 2. Open ${config.name}
6157
- `) + chalk14.dim(" 3. Try the /specify or /breakdown commands\n") + chalk14.dim(" 4. Learn more: ") + chalk14.cyan(config.docsUrl)
6059
+ `) + chalk12.dim("Next steps:\n") + chalk12.dim(" 1. Review the integration files\n") + chalk12.dim(` 2. Open ${config.name}
6060
+ `) + chalk12.dim(" 3. Try the /specify or /breakdown commands\n") + chalk12.dim(" 4. Learn more: ") + chalk12.cyan(config.docsUrl)
6158
6061
  };
6159
6062
  } catch (error) {
6160
6063
  const errorMessage = error instanceof Error ? error.message : String(error);
6161
6064
  return {
6162
6065
  success: false,
6163
- message: chalk14.red(`\u274C Setup failed: ${errorMessage}`)
6066
+ message: chalk12.red(`\u274C Setup failed: ${errorMessage}`)
6164
6067
  };
6165
6068
  }
6166
6069
  }
@@ -6191,6 +6094,161 @@ async function handleSetupCursor(opts) {
6191
6094
  return _handleSetup(config, opts);
6192
6095
  }
6193
6096
 
6097
+ // src/handlers/update.handlers.ts
6098
+ async function handleUpdate(opts) {
6099
+ try {
6100
+ const currentVersion = getCurrentVersion();
6101
+ let output = chalk13.bold.cyan("\n\u{1F504} BrainGrid CLI Update\n\n");
6102
+ output += `${chalk13.bold("Current version:")} ${currentVersion}
6103
+ `;
6104
+ output += chalk13.dim("Checking for updates...\n");
6105
+ const latestVersion = await getLatestVersion();
6106
+ output += `${chalk13.bold("Latest version:")} ${latestVersion}
6107
+
6108
+ `;
6109
+ const comparison = compareVersions(currentVersion, latestVersion);
6110
+ if (comparison === 0) {
6111
+ output += chalk13.green("\u2705 You are already on the latest version!\n");
6112
+ return {
6113
+ success: true,
6114
+ message: output,
6115
+ data: { currentVersion, latestVersion, upToDate: true }
6116
+ };
6117
+ }
6118
+ if (comparison > 0) {
6119
+ output += chalk13.yellow("\u26A0\uFE0F You are on a newer version than what is published.\n");
6120
+ output += chalk13.dim(" This is expected if you are developing locally.\n");
6121
+ return {
6122
+ success: true,
6123
+ message: output,
6124
+ data: { currentVersion, latestVersion, upToDate: false }
6125
+ };
6126
+ }
6127
+ output += chalk13.yellow(`\u2B06\uFE0F Update available: ${currentVersion} \u2192 ${latestVersion}
6128
+
6129
+ `);
6130
+ if (opts.check) {
6131
+ output += chalk13.dim("Run ") + chalk13.cyan("braingrid update") + chalk13.dim(" to update\n");
6132
+ return {
6133
+ success: true,
6134
+ message: output,
6135
+ data: { currentVersion, latestVersion, upToDate: false }
6136
+ };
6137
+ }
6138
+ output += chalk13.dim("Detecting package manager...\n");
6139
+ const packageManager = await detectPackageManager(PACKAGE_NAME);
6140
+ output += `${chalk13.bold("Package manager:")} ${packageManager}
6141
+
6142
+ `;
6143
+ const updateCommand = getUpdateCommand(packageManager, PACKAGE_NAME);
6144
+ output += chalk13.dim("Running: ") + chalk13.cyan(updateCommand) + "\n\n";
6145
+ console.log(output);
6146
+ executeUpdate(packageManager, PACKAGE_NAME);
6147
+ const cliTools = await checkInstalledCliTools();
6148
+ const claudeInstalled = cliTools.find((t) => t.command === "claude")?.installed;
6149
+ const cursorInstalled = cliTools.find((t) => t.command === "cursor")?.installed;
6150
+ let setupOutput = "";
6151
+ if (claudeInstalled) {
6152
+ const shouldUpdate = await confirm({
6153
+ message: "Claude Code detected. Update BrainGrid integration?",
6154
+ default: true
6155
+ });
6156
+ if (shouldUpdate) {
6157
+ const result = await handleSetupClaudeCode({ force: true });
6158
+ setupOutput += "\n" + result.message;
6159
+ }
6160
+ }
6161
+ if (cursorInstalled) {
6162
+ const shouldUpdate = await confirm({
6163
+ message: "Cursor detected. Update BrainGrid integration?",
6164
+ default: true
6165
+ });
6166
+ if (shouldUpdate) {
6167
+ const result = await handleSetupCursor({ force: true });
6168
+ setupOutput += "\n" + result.message;
6169
+ }
6170
+ }
6171
+ return {
6172
+ success: true,
6173
+ message: chalk13.green("\n\u2705 Successfully updated BrainGrid CLI!\n") + setupOutput,
6174
+ data: { currentVersion, latestVersion, packageManager }
6175
+ };
6176
+ } catch (error) {
6177
+ return {
6178
+ success: false,
6179
+ message: formatError(error)
6180
+ };
6181
+ }
6182
+ }
6183
+
6184
+ // src/utils/update-checker.ts
6185
+ import chalk14 from "chalk";
6186
+ var CACHE_TTL_MS = 12 * 60 * 60 * 1e3;
6187
+ var CACHE_SERVICE = "braingrid-cli";
6188
+ var CACHE_ACCOUNT = "update-cache";
6189
+ async function getCache() {
6190
+ try {
6191
+ const cached = await credentialStore.getPassword(CACHE_SERVICE, CACHE_ACCOUNT);
6192
+ if (!cached) return null;
6193
+ return JSON.parse(cached);
6194
+ } catch {
6195
+ return null;
6196
+ }
6197
+ }
6198
+ async function setCache(cache) {
6199
+ try {
6200
+ await credentialStore.setPassword(CACHE_SERVICE, CACHE_ACCOUNT, JSON.stringify(cache));
6201
+ } catch {
6202
+ }
6203
+ }
6204
+ function isCacheValid(cache) {
6205
+ const now = Date.now();
6206
+ return now - cache.checkedAt < CACHE_TTL_MS;
6207
+ }
6208
+ async function getLatestVersionCached() {
6209
+ const cache = await getCache();
6210
+ if (cache && isCacheValid(cache)) {
6211
+ return cache.latestVersion;
6212
+ }
6213
+ try {
6214
+ const latestVersion = await getLatestVersion(5e3);
6215
+ await setCache({
6216
+ latestVersion,
6217
+ checkedAt: Date.now()
6218
+ });
6219
+ return latestVersion;
6220
+ } catch {
6221
+ return cache?.latestVersion ?? null;
6222
+ }
6223
+ }
6224
+ async function isUpdateAvailable() {
6225
+ const currentVersion = getCurrentVersion();
6226
+ const latestVersion = await getLatestVersionCached();
6227
+ if (!latestVersion) {
6228
+ return { available: false, currentVersion, latestVersion: null };
6229
+ }
6230
+ const comparison = compareVersions(currentVersion, latestVersion);
6231
+ return {
6232
+ available: comparison < 0,
6233
+ // Update available if current < latest
6234
+ currentVersion,
6235
+ latestVersion
6236
+ };
6237
+ }
6238
+ function getUpdateCommand2() {
6239
+ return `npm install -g ${PACKAGE_NAME}`;
6240
+ }
6241
+ async function checkAndShowUpdateWarning() {
6242
+ try {
6243
+ const { available, currentVersion, latestVersion } = await isUpdateAvailable();
6244
+ if (available && latestVersion) {
6245
+ const warning = "\n" + chalk14.yellow(`\u26A0\uFE0F Update available: ${currentVersion} \u2192 ${latestVersion}`) + "\n" + chalk14.dim(` Run \`${getUpdateCommand2()}\` to update`) + "\n";
6246
+ console.log(warning);
6247
+ }
6248
+ } catch {
6249
+ }
6250
+ }
6251
+
6194
6252
  // src/handlers/init.handlers.ts
6195
6253
  import { access as access3 } from "fs/promises";
6196
6254
 
@@ -6303,7 +6361,7 @@ async function promptToCreateProject(gitInfo, projectService, repositoryService)
6303
6361
  chalk15.yellow("\u26A0\uFE0F Repository accessible but no project exists.\n\n") + chalk15.dim(`Repository: ${gitInfo.owner}/${gitInfo.name}
6304
6362
  `)
6305
6363
  );
6306
- const shouldCreate = await confirm({
6364
+ const shouldCreate = await confirm2({
6307
6365
  message: `Would you like to create a project for ${gitInfo.name} now?`,
6308
6366
  default: true
6309
6367
  });
@@ -6424,7 +6482,7 @@ function showSetupInstructions(scenario) {
6424
6482
  async function handleNoGitRepository() {
6425
6483
  const canAutomate = await canUseGhAutomation();
6426
6484
  if (canAutomate) {
6427
- const shouldSetup = await confirm({
6485
+ const shouldSetup = await confirm2({
6428
6486
  message: "Would you like to initialize git and create a GitHub repository?",
6429
6487
  default: true
6430
6488
  });
@@ -6477,7 +6535,7 @@ async function handleNoGitRepository() {
6477
6535
  async function handleNoGitRemote() {
6478
6536
  const canAutomate = await canUseGhAutomation();
6479
6537
  if (canAutomate) {
6480
- const shouldCreate = await confirm({
6538
+ const shouldCreate = await confirm2({
6481
6539
  message: "Would you like to create a GitHub repository now?",
6482
6540
  default: true
6483
6541
  });
@@ -6526,7 +6584,7 @@ async function handleInit(opts) {
6526
6584
  chalk15.yellow(`
6527
6585
  \u26A0\uFE0F A new version of BrainGrid CLI is available: `) + chalk15.dim(`${updateInfo.currentVersion} \u2192 `) + chalk15.green(updateInfo.latestVersion) + "\n"
6528
6586
  );
6529
- const shouldUpdate = await confirm({
6587
+ const shouldUpdate = await confirm2({
6530
6588
  message: "Would you like to update now?",
6531
6589
  default: true
6532
6590
  });
@@ -6543,7 +6601,7 @@ async function handleInit(opts) {
6543
6601
  const config = getConfig();
6544
6602
  const { projectService, githubService, repositoryService, auth } = getServices4();
6545
6603
  if (!await isGitInstalled()) {
6546
- const shouldInstall = await confirm({
6604
+ const shouldInstall = await confirm2({
6547
6605
  message: "Git is required but not installed. Would you like to install it now?",
6548
6606
  default: true
6549
6607
  });
@@ -6575,7 +6633,7 @@ async function handleInit(opts) {
6575
6633
  console.log(
6576
6634
  chalk15.dim(" It enables seamless GitHub integration and repository management.\n")
6577
6635
  );
6578
- const shouldInstallGh = await confirm({
6636
+ const shouldInstallGh = await confirm2({
6579
6637
  message: "Would you like to install GitHub CLI now?",
6580
6638
  default: true
6581
6639
  });
@@ -6612,7 +6670,7 @@ async function handleInit(opts) {
6612
6670
  }
6613
6671
  const isAuthenticated = await auth.isAuthenticated();
6614
6672
  if (!isAuthenticated) {
6615
- const shouldLogin = await confirm({
6673
+ const shouldLogin = await confirm2({
6616
6674
  message: "You need to be authenticated. Would you like to log in / sign up now?",
6617
6675
  default: true
6618
6676
  });
@@ -6759,7 +6817,7 @@ async function handleInit(opts) {
6759
6817
  const projectInfo = chalk15.bold("\n\u{1F4E6} BrainGrid Project Found\n\n") + chalk15.dim("Project: ") + chalk15.cyan(project2.name) + "\n" + chalk15.dim("ID: ") + chalk15.gray(project2.short_id) + "\n" + (project2.description ? chalk15.dim("Description: ") + chalk15.gray(project2.description) + "\n" : "") + chalk15.dim("Repository: ") + chalk15.gray(project2.repository?.full_name || "N/A") + "\n\n";
6760
6818
  console.log(projectInfo);
6761
6819
  if (!opts.force) {
6762
- const shouldInit = await confirm({
6820
+ const shouldInit = await confirm2({
6763
6821
  message: "Initialize this repository with the above project?",
6764
6822
  default: true
6765
6823
  });
@@ -6796,7 +6854,7 @@ async function handleInit(opts) {
6796
6854
  const claudeSetupExists = await fileExists2(".claude/commands/specify.md");
6797
6855
  if (!claudeSetupExists) {
6798
6856
  console.log("");
6799
- const setupClaude = await confirm({
6857
+ const setupClaude = await confirm2({
6800
6858
  message: "Claude Code detected. Install BrainGrid integration? (slash commands, skills, status line)",
6801
6859
  default: true
6802
6860
  });
@@ -6826,7 +6884,7 @@ async function handleInit(opts) {
6826
6884
  const cursorSetupExists = await fileExists2(".cursor/commands/specify.md");
6827
6885
  if (!cursorSetupExists) {
6828
6886
  console.log("");
6829
- const setupCursor = await confirm({
6887
+ const setupCursor = await confirm2({
6830
6888
  message: "Cursor detected. Install BrainGrid integration? (slash commands, rules, context)",
6831
6889
  default: true
6832
6890
  });
@@ -7207,14 +7265,14 @@ requirement.command("build [id]").description(
7207
7265
  }
7208
7266
  });
7209
7267
  var task = program.command("task").description("Manage tasks");
7210
- task.command("list").description("List tasks for a requirement").option("-r, --requirement <id>", "requirement ID (REQ-456, auto-detects project if initialized)").option("-p, --project <id>", "project ID (PROJ-123, optional if project is initialized)").option("--format <format>", "output format (table, json, xml, markdown)", "markdown").action(async (opts) => {
7268
+ task.command("list").description("List tasks for a requirement").option("-r, --requirement <id>", "requirement ID (REQ-456, auto-detects project if initialized)").option("-p, --project <id>", "project ID (PROJ-123, optional if project is initialized)").option("--format <format>", "output format (table, json, xml, markdown)", "markdown").option("--page <page>", "page number for pagination", "1").option("--limit <limit>", "number of tasks per page", "20").action(async (opts) => {
7211
7269
  const result = await handleTaskList(opts);
7212
7270
  console.log(result.message);
7213
7271
  if (!result.success) {
7214
7272
  process.exit(1);
7215
7273
  }
7216
7274
  });
7217
- task.command("summary").description("Show task summary table (quick overview without content)").option("-r, --requirement <id>", "requirement ID (REQ-456, auto-detects project if initialized)").option("-p, --project <id>", "project ID (PROJ-123, optional if project is initialized)").action(async (opts) => {
7275
+ task.command("summary").description("Show task summary table (quick overview without content)").option("-r, --requirement <id>", "requirement ID (REQ-456, auto-detects project if initialized)").option("-p, --project <id>", "project ID (PROJ-123, optional if project is initialized)").option("--page <page>", "page number for pagination", "1").option("--limit <limit>", "number of tasks per page", "20").action(async (opts) => {
7218
7276
  const result = await handleTaskSummary(opts);
7219
7277
  console.log(result.message);
7220
7278
  if (!result.success) {