@braingrid/cli 0.2.60 → 0.2.62

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,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.62] - 2026-03-20
11
+
12
+ ### Changed
13
+
14
+ - **Deprecate breakdown command from setup** — removed the breakdown command from the setup flow as it is no longer needed
15
+
16
+ ## [0.2.61] - 2026-03-17
17
+
18
+ ### Added
19
+
20
+ - **`braingrid setup openclaw` command** — new setup command to configure OpenClaw integration
21
+
22
+ ### Changed
23
+
24
+ - **Simplify init by removing GitHubService dependency** — streamlined the init flow by eliminating unnecessary GitHub service coupling
25
+
10
26
  ## [0.2.60] - 2026-03-12
11
27
 
12
28
  ### Changed
package/dist/cli.js CHANGED
@@ -49,7 +49,8 @@ function createCompletion() {
49
49
  completion.on("setup", ({ reply }) => {
50
50
  reply([
51
51
  "claude-code",
52
- "cursor"
52
+ "cursor",
53
+ "openclaw"
53
54
  ]);
54
55
  });
55
56
  completion.on("project", ({ reply }) => {
@@ -226,7 +227,7 @@ async function axiosWithRetry(config2, options) {
226
227
 
227
228
  // src/build-config.ts
228
229
  var BUILD_ENV = true ? "production" : process.env.NODE_ENV === "test" ? "development" : "production";
229
- var CLI_VERSION = true ? "0.2.60" : "0.0.0-test";
230
+ var CLI_VERSION = true ? "0.2.62" : "0.0.0-test";
230
231
  var PRODUCTION_CONFIG = {
231
232
  apiUrl: "https://app.braingrid.ai",
232
233
  workosAuthUrl: "https://auth.braingrid.ai",
@@ -2496,71 +2497,6 @@ function createAuthenticatedAxios(auth) {
2496
2497
  return instance;
2497
2498
  }
2498
2499
 
2499
- // src/services/internal/github-service.ts
2500
- var GitHubService = class {
2501
- constructor(baseUrl, auth) {
2502
- this.baseUrl = baseUrl;
2503
- this.axios = createAuthenticatedAxios(auth);
2504
- }
2505
- getHeaders() {
2506
- return {
2507
- "Content-Type": "application/json"
2508
- };
2509
- }
2510
- /**
2511
- * List GitHub installations for the authenticated organization
2512
- *
2513
- * @param params - Optional pagination parameters
2514
- * @param params.page - Page number (default: 1, min: 1)
2515
- * @param params.limit - Number of installations per page (default: 20, min: 1, max: 100)
2516
- * @returns List of GitHub installations with pagination
2517
- * @throws {Error} On API errors (401, 404, 422, 500)
2518
- *
2519
- * @example
2520
- * ```typescript
2521
- * const result = await githubService.listInstallations({ page: 1, limit: 20 });
2522
- * console.log(result.installations);
2523
- * console.log(result.pagination);
2524
- * ```
2525
- */
2526
- async listInstallations(params) {
2527
- const url = `${this.baseUrl}/api/v1/github/installations`;
2528
- const headers = this.getHeaders();
2529
- const response = await this.axios.get(url, {
2530
- headers,
2531
- params
2532
- });
2533
- return response.data;
2534
- }
2535
- /**
2536
- * Get detailed information about a specific GitHub installation
2537
- *
2538
- * Supports both UUID and short ID formats (e.g., "GITHUB-1").
2539
- * Returns installation details including all associated repositories.
2540
- *
2541
- * @param installationId - Installation UUID or short ID (e.g., "GITHUB-1")
2542
- * @returns Detailed installation information with repositories
2543
- * @throws {Error} On API errors (401, 404, 422, 500)
2544
- *
2545
- * @example
2546
- * ```typescript
2547
- * // Using short ID
2548
- * const installation = await githubService.getInstallation('GITHUB-1');
2549
- *
2550
- * // Using UUID
2551
- * const installation = await githubService.getInstallation('550e8400-e29b-41d4-a716-446655440000');
2552
- *
2553
- * console.log(installation.repositories);
2554
- * ```
2555
- */
2556
- async getInstallation(installationId) {
2557
- const url = `${this.baseUrl}/api/v1/github/installations/${installationId}`;
2558
- const headers = this.getHeaders();
2559
- const response = await this.axios.get(url, { headers });
2560
- return response.data;
2561
- }
2562
- };
2563
-
2564
2500
  // src/services/internal/repository-service.ts
2565
2501
  var RepositoryService = class {
2566
2502
  constructor(baseUrl, auth) {
@@ -3624,10 +3560,6 @@ async function getLocalProjectId(cwd) {
3624
3560
  }
3625
3561
 
3626
3562
  // src/utils/repository-access.ts
3627
- function findInstallationForOwner(owner, installations) {
3628
- const normalizedOwner = owner.toLowerCase();
3629
- return installations.find((inst) => inst.account_name.toLowerCase() === normalizedOwner) || null;
3630
- }
3631
3563
  async function checkRepositoryAccess(repositoryService, owner, name) {
3632
3564
  try {
3633
3565
  const response = await repositoryService.listRepositories({
@@ -3791,7 +3723,12 @@ async function isUpdateAvailable() {
3791
3723
  function getUpdateCommand() {
3792
3724
  return `npm install -g ${PACKAGE_NAME}`;
3793
3725
  }
3726
+ var _suppressWarning = false;
3727
+ function suppressUpdateWarning() {
3728
+ _suppressWarning = true;
3729
+ }
3794
3730
  async function checkAndShowUpdateWarning() {
3731
+ if (_suppressWarning) return;
3795
3732
  try {
3796
3733
  const { available, currentVersion, latestVersion } = await isUpdateAvailable();
3797
3734
  if (available && latestVersion) {
@@ -4029,17 +3966,17 @@ async function handleSetupClaudeCode(opts) {
4029
3966
  name: "Claude Code",
4030
3967
  sourceDirs: [
4031
3968
  "claude-code/commands",
4032
- "claude-code/skills/braingrid-cli",
4033
- "claude-code/skills/build",
4034
- "claude-code/skills/frontend-design",
4035
- "claude-code/skills/ux"
3969
+ "claude-code/skills/bg-cli",
3970
+ "claude-code/skills/bg-build",
3971
+ "claude-code/skills/bg-frontend-design",
3972
+ "claude-code/skills/bg-ux-design"
4036
3973
  ],
4037
3974
  targetDirs: [
4038
3975
  ".claude/commands",
4039
- ".claude/skills/braingrid-cli",
4040
- ".claude/skills/build",
4041
- ".claude/skills/frontend-design",
4042
- ".claude/skills/ux"
3976
+ ".claude/skills/bg-cli",
3977
+ ".claude/skills/bg-build",
3978
+ ".claude/skills/bg-frontend-design",
3979
+ ".claude/skills/bg-ux-design"
4043
3980
  ],
4044
3981
  dirLabels: [
4045
3982
  { label: "Commands", countMode: "files" },
@@ -4053,7 +3990,14 @@ async function handleSetupClaudeCode(opts) {
4053
3990
  targetFile: "CLAUDE.md"
4054
3991
  },
4055
3992
  docsUrl: "https://docs.braingrid.ai/claude-code",
4056
- deprecatedFiles: [".claude/commands/build.md"]
3993
+ deprecatedFiles: [
3994
+ ".claude/commands/build.md",
3995
+ ".claude/commands/breakdown.md",
3996
+ ".claude/skills/braingrid-cli/skill.md",
3997
+ ".claude/skills/braingrid-cli/SKILL.md",
3998
+ ".claude/skills/build/skill.md",
3999
+ ".claude/skills/build/SKILL.md"
4000
+ ]
4057
4001
  };
4058
4002
  try {
4059
4003
  const setupResult = await _handleSetup(config2, opts);
@@ -4163,7 +4107,8 @@ async function handleSetupCursor(opts) {
4163
4107
  sourceFile: "cursor/AGENTS.md",
4164
4108
  targetFile: "AGENTS.md"
4165
4109
  },
4166
- docsUrl: "https://docs.braingrid.ai/cursor"
4110
+ docsUrl: "https://docs.braingrid.ai/cursor",
4111
+ deprecatedFiles: [".cursor/commands/breakdown.md", ".cursor/commands/build.md"]
4167
4112
  };
4168
4113
  try {
4169
4114
  const setupResult = await _handleSetup(config2, opts);
@@ -4190,6 +4135,61 @@ async function handleSetupCursor(opts) {
4190
4135
  };
4191
4136
  }
4192
4137
  }
4138
+ async function handleSetupOpenClaw(opts) {
4139
+ const config2 = {
4140
+ name: "OpenClaw",
4141
+ sourceDirs: [
4142
+ "claude-code/skills/braingrid-cli",
4143
+ "claude-code/skills/build",
4144
+ "claude-code/skills/frontend-design",
4145
+ "claude-code/skills/ux"
4146
+ ],
4147
+ targetDirs: [
4148
+ "skills/bg-cli",
4149
+ "skills/bg-build",
4150
+ "skills/bg-frontend-design",
4151
+ "skills/bg-ux-design"
4152
+ ],
4153
+ dirLabels: [
4154
+ { label: "Skills", countMode: "single" },
4155
+ { label: "Skills", countMode: "single" },
4156
+ { label: "Skills", countMode: "single" },
4157
+ { label: "Skills", countMode: "single" }
4158
+ ],
4159
+ injection: {
4160
+ sourceFile: "claude-code/CLAUDE.md",
4161
+ targetFile: "AGENTS.md"
4162
+ },
4163
+ docsUrl: "https://docs.braingrid.ai/openclaw"
4164
+ };
4165
+ try {
4166
+ const setupResult = await _handleSetup(config2, opts);
4167
+ if (!isSetupResult(setupResult)) {
4168
+ return setupResult;
4169
+ }
4170
+ const { installedPerDir, skipped } = setupResult.data;
4171
+ const displayPerDir = installedPerDir.map(
4172
+ (count, i) => config2.dirLabels[i].countMode === "single" ? Math.min(count, 1) : count
4173
+ );
4174
+ const totalInstalled = displayPerDir.reduce((a, b) => a + b, 0);
4175
+ log("INFO", "setup", "complete", `installed=${totalInstalled} skipped=${skipped}`);
4176
+ await flushLogger();
4177
+ closeLogger();
4178
+ return {
4179
+ success: true,
4180
+ message: buildSuccessMessage(config2, displayPerDir, "")
4181
+ };
4182
+ } catch (error) {
4183
+ const errorMessage = error instanceof Error ? error.message : String(error);
4184
+ log("ERROR", "setup", "fatal", `error=${errorMessage}`);
4185
+ await flushLogger();
4186
+ closeLogger();
4187
+ return {
4188
+ success: false,
4189
+ message: chalk10.red(`\u274C Setup failed: ${errorMessage}`)
4190
+ };
4191
+ }
4192
+ }
4193
4193
 
4194
4194
  // src/handlers/update.handlers.ts
4195
4195
  import { execSync as execSync3 } from "child_process";
@@ -4431,22 +4431,10 @@ function getServices() {
4431
4431
  const config2 = getConfig();
4432
4432
  const auth = new BraingridAuth(config2.apiUrl);
4433
4433
  const projectService = new ProjectService(config2.apiUrl, auth);
4434
- const githubService = new GitHubService(config2.apiUrl, auth);
4435
4434
  const repositoryService = new RepositoryService(config2.apiUrl, auth);
4436
- return { projectService, githubService, repositoryService, auth };
4435
+ return { projectService, repositoryService, auth };
4437
4436
  }
4438
- function promptToAddOrganization(owner, webUrl) {
4439
- return {
4440
- success: false,
4441
- message: chalk12.yellow("\u26A0\uFE0F No projects found for this repository.\n\n") + chalk12.dim(`Repository: ${owner}/*
4442
-
4443
- `) + chalk12.dim(`You have GitHub connected, but not for the "${owner}" organization.
4444
-
4445
- `) + chalk12.dim("To connect ") + chalk12.cyan(owner) + chalk12.dim(":\n") + chalk12.dim(" 1. Visit: ") + chalk12.cyan(`${webUrl}/integrations`) + chalk12.dim("\n") + chalk12.dim(' 2. Click "Add GitHub Organization"\n') + chalk12.dim(` 3. Select "${owner}"
4446
- `) + chalk12.dim(" 4. Run ") + chalk12.cyan("braingrid init") + chalk12.dim(" again")
4447
- };
4448
- }
4449
- async function promptToCreateProject(gitInfo, projectService, repositoryService) {
4437
+ async function promptToCreateProject(gitInfo, projectService, repositoryService, knownRepositoryId) {
4450
4438
  const webUrl = getConfig().getWebAppUrl();
4451
4439
  if (!gitInfo.owner || !gitInfo.name) {
4452
4440
  return {
@@ -4454,7 +4442,7 @@ async function promptToCreateProject(gitInfo, projectService, repositoryService)
4454
4442
  message: chalk12.red("\u274C Repository information is incomplete")
4455
4443
  };
4456
4444
  }
4457
- const repositoryId = await getRepositoryId(repositoryService, gitInfo.owner, gitInfo.name);
4445
+ const repositoryId = knownRepositoryId ?? await getRepositoryId(repositoryService, gitInfo.owner, gitInfo.name);
4458
4446
  if (!repositoryId) {
4459
4447
  return {
4460
4448
  success: false,
@@ -4509,7 +4497,7 @@ async function promptToGrantRepositoryAccess(gitInfo, webUrl, repositoryService,
4509
4497
  console.log(
4510
4498
  chalk12.yellow("\u26A0\uFE0F Repository found but BrainGrid needs access.\n\n") + chalk12.dim(`Repository: ${owner}/${name}
4511
4499
 
4512
- `) + chalk12.dim("Please grant BrainGrid access to this repository:\n") + chalk12.dim(" 1. Visit: ") + chalk12.cyan(`${webUrl}/integrations`) + chalk12.dim("\n") + chalk12.dim(
4500
+ `) + chalk12.dim("Please grant BrainGrid access to this repository:\n") + chalk12.dim(" 1. Visit: ") + chalk12.cyan(`${webUrl}/settings/integrations`) + chalk12.dim("\n") + chalk12.dim(
4513
4501
  ` 2. Click on your "${owner}" installation "Add/Remove" to grant BrainGrid access to your repository
4514
4502
  `
4515
4503
  ) + chalk12.dim(` 3. Select "${name}" and save
@@ -4525,44 +4513,45 @@ async function promptToGrantRepositoryAccess(gitInfo, webUrl, repositoryService,
4525
4513
  if (!accessGranted) {
4526
4514
  return {
4527
4515
  success: false,
4528
- message: chalk12.yellow("\n\u26A0\uFE0F Repository access not detected within 3 minutes.\n\n") + chalk12.dim("Please grant access at: ") + chalk12.cyan(`${webUrl}/integrations`) + chalk12.dim(" and run ") + chalk12.cyan("braingrid init") + chalk12.dim(" again.")
4516
+ message: chalk12.yellow("\n\u26A0\uFE0F Repository access not detected within 3 minutes.\n\n") + chalk12.dim("Please grant access at: ") + chalk12.cyan(`${webUrl}/settings/integrations`) + chalk12.dim(" and run ") + chalk12.cyan("braingrid init") + chalk12.dim(" again.")
4529
4517
  };
4530
4518
  }
4531
4519
  console.log(chalk12.green("\u2705 Repository access granted!\n"));
4532
4520
  return promptToCreateProject(gitInfo, projectService, repositoryService);
4533
4521
  }
4534
- async function handleNoProjectForRepository(owner, name, gitInfo, githubService, repositoryService, projectService, config2) {
4535
- let allInstallations;
4522
+ async function handleNoProjectForRepository(owner, name, gitInfo, repositoryService, projectService, config2) {
4523
+ const webUrl = config2.getWebAppUrl();
4536
4524
  try {
4537
- const installationsResponse = await githubService.listInstallations({ limit: 100 });
4538
- allInstallations = installationsResponse.installations;
4525
+ const response = await repositoryService.listRepositories({ owner, name, limit: 1 });
4526
+ if (response.repositories.length > 0) {
4527
+ return promptToCreateProject(
4528
+ gitInfo,
4529
+ projectService,
4530
+ repositoryService,
4531
+ response.repositories[0].id
4532
+ );
4533
+ }
4534
+ if (!response.has_github_installation && !response.has_oauth_connection) {
4535
+ return {
4536
+ success: false,
4537
+ message: chalk12.yellow("\u26A0\uFE0F No projects found for this repository.\n\n") + chalk12.dim(`Repository: ${owner}/${name}
4538
+
4539
+ `) + chalk12.dim("It looks like you haven't connected your GitHub account yet.\n") + chalk12.dim("Please connect GitHub at: ") + chalk12.cyan(`${webUrl}/settings/integrations`) + chalk12.dim("\n\nOnce connected, create a project and link it to this repository.")
4540
+ };
4541
+ }
4542
+ return promptToGrantRepositoryAccess(gitInfo, webUrl, repositoryService, projectService);
4539
4543
  } catch (error) {
4540
4544
  log(
4541
4545
  "WARN",
4542
4546
  "init",
4543
- "list_installations_failed",
4547
+ "list_repositories_failed",
4544
4548
  `error=${error instanceof Error ? error.message : String(error)}`
4545
4549
  );
4546
- allInstallations = [];
4547
- }
4548
- const webUrl = config2.getWebAppUrl();
4549
- if (allInstallations.length === 0) {
4550
4550
  return {
4551
4551
  success: false,
4552
- message: chalk12.yellow("\u26A0\uFE0F No projects found for this repository.\n\n") + chalk12.dim(`Repository: ${owner}/${name}
4553
-
4554
- `) + chalk12.dim("It looks like you haven't connected your GitHub account yet.\n") + chalk12.dim("Please connect GitHub at: ") + chalk12.cyan(`${webUrl}/integrations`) + chalk12.dim("\n\nOnce connected, create a project and link it to this repository.")
4552
+ message: chalk12.red("\u274C Failed to check repository access.\n\n") + chalk12.dim("Please try again or visit: ") + chalk12.cyan(`${webUrl}/settings/integrations`)
4555
4553
  };
4556
4554
  }
4557
- const ownerInstallation = findInstallationForOwner(owner, allInstallations);
4558
- if (!ownerInstallation) {
4559
- return promptToAddOrganization(owner, webUrl);
4560
- }
4561
- const hasRepoAccess = await checkRepositoryAccess(repositoryService, owner, name);
4562
- if (!hasRepoAccess) {
4563
- return promptToGrantRepositoryAccess(gitInfo, webUrl, repositoryService, projectService);
4564
- }
4565
- return promptToCreateProject(gitInfo, projectService, repositoryService);
4566
4555
  }
4567
4556
  function showSetupInstructions(scenario) {
4568
4557
  let message = "";
@@ -4707,6 +4696,7 @@ async function handleInit(opts) {
4707
4696
  if (shouldUpdate) {
4708
4697
  const result = await handleUpdate({});
4709
4698
  console.log(result.message);
4699
+ suppressUpdateWarning();
4710
4700
  try {
4711
4701
  const args = ["init"];
4712
4702
  if (opts.force) args.push("--force");
@@ -4732,7 +4722,7 @@ async function handleInit(opts) {
4732
4722
  `available=${updateInfo.available} current=${updateInfo.currentVersion}${updateInfo.latestVersion ? ` latest=${updateInfo.latestVersion}` : ""}`
4733
4723
  );
4734
4724
  const config2 = getConfig();
4735
- const { projectService, githubService, repositoryService, auth } = getServices();
4725
+ const { projectService, repositoryService, auth } = getServices();
4736
4726
  if (!await isGitInstalled()) {
4737
4727
  const shouldInstall = await confirm2({
4738
4728
  message: "Git is required but not installed. Would you like to install it now?",
@@ -4968,7 +4958,6 @@ async function handleInit(opts) {
4968
4958
  owner,
4969
4959
  name,
4970
4960
  gitInfo,
4971
- githubService,
4972
4961
  repositoryService,
4973
4962
  projectService,
4974
4963
  config2
@@ -4990,7 +4979,6 @@ async function handleInit(opts) {
4990
4979
  owner,
4991
4980
  name,
4992
4981
  gitInfo,
4993
- githubService,
4994
4982
  repositoryService,
4995
4983
  projectService,
4996
4984
  config2
@@ -8895,6 +8883,7 @@ var createSetupAction = (handler) => {
8895
8883
  var setup = program.command("setup").description("Setup BrainGrid integrations for AI coding tools");
8896
8884
  setup.command("claude-code").description("Install Claude Code integration").option("--force", "overwrite existing files without prompting").option("--dry-run", "show what would be done without making changes").action(createSetupAction(handleSetupClaudeCode));
8897
8885
  setup.command("cursor").description("Install Cursor integration").option("--force", "overwrite existing files without prompting").option("--dry-run", "show what would be done without making changes").action(createSetupAction(handleSetupCursor));
8886
+ setup.command("openclaw").description("Install OpenClaw integration").option("--force", "overwrite existing files without prompting").option("--dry-run", "show what would be done without making changes").action(createSetupAction(handleSetupOpenClaw));
8898
8887
  var project = program.command("project").description("Manage projects");
8899
8888
  project.command("list").description("List all projects").option("--format <format>", "output format (table, json, xml, markdown)", "table").option("--page <page>", "page number for pagination", "1").option("--limit <limit>", "number of projects per page", "20").action(async (opts) => {
8900
8889
  const result = await handleProjectList(opts);