@braingrid/cli 0.2.59 → 0.2.61

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.61] - 2026-03-17
11
+
12
+ ### Added
13
+
14
+ - **`braingrid setup openclaw` command** — new setup command to configure OpenClaw integration
15
+
16
+ ### Changed
17
+
18
+ - **Simplify init by removing GitHubService dependency** — streamlined the init flow by eliminating unnecessary GitHub service coupling
19
+
20
+ ## [0.2.60] - 2026-03-12
21
+
22
+ ### Changed
23
+
24
+ - **Rename skill.md to SKILL.md** — standardized skill file naming to uppercase for consistency across all skill directories
25
+
10
26
  ## [0.2.59] - 2026-03-11
11
27
 
12
28
  ### Fixed
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.59" : "0.0.0-test";
230
+ var CLI_VERSION = true ? "0.2.61" : "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,13 @@ 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/skills/braingrid-cli/skill.md",
3996
+ ".claude/skills/braingrid-cli/SKILL.md",
3997
+ ".claude/skills/build/skill.md",
3998
+ ".claude/skills/build/SKILL.md"
3999
+ ]
4057
4000
  };
4058
4001
  try {
4059
4002
  const setupResult = await _handleSetup(config2, opts);
@@ -4190,6 +4133,61 @@ async function handleSetupCursor(opts) {
4190
4133
  };
4191
4134
  }
4192
4135
  }
4136
+ async function handleSetupOpenClaw(opts) {
4137
+ const config2 = {
4138
+ name: "OpenClaw",
4139
+ sourceDirs: [
4140
+ "claude-code/skills/braingrid-cli",
4141
+ "claude-code/skills/build",
4142
+ "claude-code/skills/frontend-design",
4143
+ "claude-code/skills/ux"
4144
+ ],
4145
+ targetDirs: [
4146
+ "skills/bg-cli",
4147
+ "skills/bg-build",
4148
+ "skills/bg-frontend-design",
4149
+ "skills/bg-ux-design"
4150
+ ],
4151
+ dirLabels: [
4152
+ { label: "Skills", countMode: "single" },
4153
+ { label: "Skills", countMode: "single" },
4154
+ { label: "Skills", countMode: "single" },
4155
+ { label: "Skills", countMode: "single" }
4156
+ ],
4157
+ injection: {
4158
+ sourceFile: "claude-code/CLAUDE.md",
4159
+ targetFile: "AGENTS.md"
4160
+ },
4161
+ docsUrl: "https://docs.braingrid.ai/openclaw"
4162
+ };
4163
+ try {
4164
+ const setupResult = await _handleSetup(config2, opts);
4165
+ if (!isSetupResult(setupResult)) {
4166
+ return setupResult;
4167
+ }
4168
+ const { installedPerDir, skipped } = setupResult.data;
4169
+ const displayPerDir = installedPerDir.map(
4170
+ (count, i) => config2.dirLabels[i].countMode === "single" ? Math.min(count, 1) : count
4171
+ );
4172
+ const totalInstalled = displayPerDir.reduce((a, b) => a + b, 0);
4173
+ log("INFO", "setup", "complete", `installed=${totalInstalled} skipped=${skipped}`);
4174
+ await flushLogger();
4175
+ closeLogger();
4176
+ return {
4177
+ success: true,
4178
+ message: buildSuccessMessage(config2, displayPerDir, "")
4179
+ };
4180
+ } catch (error) {
4181
+ const errorMessage = error instanceof Error ? error.message : String(error);
4182
+ log("ERROR", "setup", "fatal", `error=${errorMessage}`);
4183
+ await flushLogger();
4184
+ closeLogger();
4185
+ return {
4186
+ success: false,
4187
+ message: chalk10.red(`\u274C Setup failed: ${errorMessage}`)
4188
+ };
4189
+ }
4190
+ }
4193
4191
 
4194
4192
  // src/handlers/update.handlers.ts
4195
4193
  import { execSync as execSync3 } from "child_process";
@@ -4431,22 +4429,10 @@ function getServices() {
4431
4429
  const config2 = getConfig();
4432
4430
  const auth = new BraingridAuth(config2.apiUrl);
4433
4431
  const projectService = new ProjectService(config2.apiUrl, auth);
4434
- const githubService = new GitHubService(config2.apiUrl, auth);
4435
4432
  const repositoryService = new RepositoryService(config2.apiUrl, auth);
4436
- return { projectService, githubService, repositoryService, auth };
4433
+ return { projectService, repositoryService, auth };
4437
4434
  }
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) {
4435
+ async function promptToCreateProject(gitInfo, projectService, repositoryService, knownRepositoryId) {
4450
4436
  const webUrl = getConfig().getWebAppUrl();
4451
4437
  if (!gitInfo.owner || !gitInfo.name) {
4452
4438
  return {
@@ -4454,7 +4440,7 @@ async function promptToCreateProject(gitInfo, projectService, repositoryService)
4454
4440
  message: chalk12.red("\u274C Repository information is incomplete")
4455
4441
  };
4456
4442
  }
4457
- const repositoryId = await getRepositoryId(repositoryService, gitInfo.owner, gitInfo.name);
4443
+ const repositoryId = knownRepositoryId ?? await getRepositoryId(repositoryService, gitInfo.owner, gitInfo.name);
4458
4444
  if (!repositoryId) {
4459
4445
  return {
4460
4446
  success: false,
@@ -4509,7 +4495,7 @@ async function promptToGrantRepositoryAccess(gitInfo, webUrl, repositoryService,
4509
4495
  console.log(
4510
4496
  chalk12.yellow("\u26A0\uFE0F Repository found but BrainGrid needs access.\n\n") + chalk12.dim(`Repository: ${owner}/${name}
4511
4497
 
4512
- `) + chalk12.dim("Please grant BrainGrid access to this repository:\n") + chalk12.dim(" 1. Visit: ") + chalk12.cyan(`${webUrl}/integrations`) + chalk12.dim("\n") + chalk12.dim(
4498
+ `) + 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
4499
  ` 2. Click on your "${owner}" installation "Add/Remove" to grant BrainGrid access to your repository
4514
4500
  `
4515
4501
  ) + chalk12.dim(` 3. Select "${name}" and save
@@ -4525,44 +4511,45 @@ async function promptToGrantRepositoryAccess(gitInfo, webUrl, repositoryService,
4525
4511
  if (!accessGranted) {
4526
4512
  return {
4527
4513
  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.")
4514
+ 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
4515
  };
4530
4516
  }
4531
4517
  console.log(chalk12.green("\u2705 Repository access granted!\n"));
4532
4518
  return promptToCreateProject(gitInfo, projectService, repositoryService);
4533
4519
  }
4534
- async function handleNoProjectForRepository(owner, name, gitInfo, githubService, repositoryService, projectService, config2) {
4535
- let allInstallations;
4520
+ async function handleNoProjectForRepository(owner, name, gitInfo, repositoryService, projectService, config2) {
4521
+ const webUrl = config2.getWebAppUrl();
4536
4522
  try {
4537
- const installationsResponse = await githubService.listInstallations({ limit: 100 });
4538
- allInstallations = installationsResponse.installations;
4523
+ const response = await repositoryService.listRepositories({ owner, name, limit: 1 });
4524
+ if (response.repositories.length > 0) {
4525
+ return promptToCreateProject(
4526
+ gitInfo,
4527
+ projectService,
4528
+ repositoryService,
4529
+ response.repositories[0].id
4530
+ );
4531
+ }
4532
+ if (!response.has_github_installation && !response.has_oauth_connection) {
4533
+ return {
4534
+ success: false,
4535
+ message: chalk12.yellow("\u26A0\uFE0F No projects found for this repository.\n\n") + chalk12.dim(`Repository: ${owner}/${name}
4536
+
4537
+ `) + 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.")
4538
+ };
4539
+ }
4540
+ return promptToGrantRepositoryAccess(gitInfo, webUrl, repositoryService, projectService);
4539
4541
  } catch (error) {
4540
4542
  log(
4541
4543
  "WARN",
4542
4544
  "init",
4543
- "list_installations_failed",
4545
+ "list_repositories_failed",
4544
4546
  `error=${error instanceof Error ? error.message : String(error)}`
4545
4547
  );
4546
- allInstallations = [];
4547
- }
4548
- const webUrl = config2.getWebAppUrl();
4549
- if (allInstallations.length === 0) {
4550
4548
  return {
4551
4549
  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.")
4550
+ message: chalk12.red("\u274C Failed to check repository access.\n\n") + chalk12.dim("Please try again or visit: ") + chalk12.cyan(`${webUrl}/settings/integrations`)
4555
4551
  };
4556
4552
  }
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
4553
  }
4567
4554
  function showSetupInstructions(scenario) {
4568
4555
  let message = "";
@@ -4707,6 +4694,7 @@ async function handleInit(opts) {
4707
4694
  if (shouldUpdate) {
4708
4695
  const result = await handleUpdate({});
4709
4696
  console.log(result.message);
4697
+ suppressUpdateWarning();
4710
4698
  try {
4711
4699
  const args = ["init"];
4712
4700
  if (opts.force) args.push("--force");
@@ -4732,7 +4720,7 @@ async function handleInit(opts) {
4732
4720
  `available=${updateInfo.available} current=${updateInfo.currentVersion}${updateInfo.latestVersion ? ` latest=${updateInfo.latestVersion}` : ""}`
4733
4721
  );
4734
4722
  const config2 = getConfig();
4735
- const { projectService, githubService, repositoryService, auth } = getServices();
4723
+ const { projectService, repositoryService, auth } = getServices();
4736
4724
  if (!await isGitInstalled()) {
4737
4725
  const shouldInstall = await confirm2({
4738
4726
  message: "Git is required but not installed. Would you like to install it now?",
@@ -4968,7 +4956,6 @@ async function handleInit(opts) {
4968
4956
  owner,
4969
4957
  name,
4970
4958
  gitInfo,
4971
- githubService,
4972
4959
  repositoryService,
4973
4960
  projectService,
4974
4961
  config2
@@ -4990,7 +4977,6 @@ async function handleInit(opts) {
4990
4977
  owner,
4991
4978
  name,
4992
4979
  gitInfo,
4993
- githubService,
4994
4980
  repositoryService,
4995
4981
  projectService,
4996
4982
  config2
@@ -8895,6 +8881,7 @@ var createSetupAction = (handler) => {
8895
8881
  var setup = program.command("setup").description("Setup BrainGrid integrations for AI coding tools");
8896
8882
  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
8883
  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));
8884
+ 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
8885
  var project = program.command("project").description("Manage projects");
8899
8886
  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
8887
  const result = await handleProjectList(opts);