@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/CHANGELOG.md +34 -0
- package/dist/cli.js +236 -178
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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(
|
|
6031
|
-
console.log(
|
|
6032
|
-
console.log(
|
|
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(
|
|
5939
|
+
console.log(chalk12.cyan("\n New Files:"));
|
|
6037
5940
|
for (const op of newFiles) {
|
|
6038
|
-
console.log(
|
|
5941
|
+
console.log(chalk12.dim(` ${op.targetPath}`));
|
|
6039
5942
|
}
|
|
6040
5943
|
}
|
|
6041
5944
|
if (existingFiles.length > 0) {
|
|
6042
|
-
console.log(
|
|
5945
|
+
console.log(chalk12.yellow("\n Existing Files (will prompt):"));
|
|
6043
5946
|
for (const op of existingFiles) {
|
|
6044
|
-
console.log(
|
|
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:
|
|
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
|
-
|
|
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(
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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 ?
|
|
6051
|
+
const statusLineMessage = statusLineInstalled ? chalk12.dim(" Status line: .claude/statusline.sh\n") : "";
|
|
6149
6052
|
return {
|
|
6150
6053
|
success: true,
|
|
6151
|
-
message:
|
|
6054
|
+
message: chalk12.green(`\u2705 ${config.name} integration installed successfully!
|
|
6152
6055
|
|
|
6153
|
-
`) +
|
|
6154
|
-
`) + statusLineMessage +
|
|
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
|
-
`) +
|
|
6157
|
-
`) +
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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) {
|