@girardmedia/bootspring 2.3.1 → 2.3.3

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.
@@ -1395,9 +1395,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
1395
1395
  if (fn) {
1396
1396
  this._exitCallback = fn;
1397
1397
  } else {
1398
- this._exitCallback = (err2) => {
1399
- if (err2.code !== "commander.executeSubCommandAsync") {
1400
- throw err2;
1398
+ this._exitCallback = (err) => {
1399
+ if (err.code !== "commander.executeSubCommandAsync") {
1400
+ throw err;
1401
1401
  } else {
1402
1402
  }
1403
1403
  };
@@ -1473,12 +1473,12 @@ Expecting one of '${allowedValues.join("', '")}'`);
1473
1473
  _callParseArg(target, value, previous, invalidArgumentMessage) {
1474
1474
  try {
1475
1475
  return target.parseArg(value, previous);
1476
- } catch (err2) {
1477
- if (err2.code === "commander.invalidArgument") {
1478
- const message = `${invalidArgumentMessage} ${err2.message}`;
1479
- this.error(message, { exitCode: err2.exitCode, code: err2.code });
1476
+ } catch (err) {
1477
+ if (err.code === "commander.invalidArgument") {
1478
+ const message = `${invalidArgumentMessage} ${err.message}`;
1479
+ this.error(message, { exitCode: err.exitCode, code: err.code });
1480
1480
  }
1481
- throw err2;
1481
+ throw err;
1482
1482
  }
1483
1483
  }
1484
1484
  /**
@@ -1937,7 +1937,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1937
1937
  let resolvedScriptPath;
1938
1938
  try {
1939
1939
  resolvedScriptPath = fs54.realpathSync(this._scriptPath);
1940
- } catch (err2) {
1940
+ } catch (err) {
1941
1941
  resolvedScriptPath = this._scriptPath;
1942
1942
  }
1943
1943
  executableDir = path55.resolve(
@@ -2001,15 +2001,15 @@ Expecting one of '${allowedValues.join("', '")}'`);
2001
2001
  );
2002
2002
  }
2003
2003
  });
2004
- proc.on("error", (err2) => {
2005
- if (err2.code === "ENOENT") {
2004
+ proc.on("error", (err) => {
2005
+ if (err.code === "ENOENT") {
2006
2006
  const executableDirMessage = executableDir ? `searched for local subcommand relative to directory '${executableDir}'` : "no directory for search for local subcommand, use .executableDir() to supply a custom directory";
2007
2007
  const executableMissing = `'${executableFile}' does not exist
2008
2008
  - if '${subcommand._name}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
2009
2009
  - if the default executable name is not suitable, use the executableFile option to supply a custom name or path
2010
2010
  - ${executableDirMessage}`;
2011
2011
  throw new Error(executableMissing);
2012
- } else if (err2.code === "EACCES") {
2012
+ } else if (err.code === "EACCES") {
2013
2013
  throw new Error(`'${executableFile}' not executable`);
2014
2014
  }
2015
2015
  if (!exitCallback) {
@@ -2020,7 +2020,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2020
2020
  "commander.executeSubCommandAsync",
2021
2021
  "(error)"
2022
2022
  );
2023
- wrappedError.nestedError = err2;
2023
+ wrappedError.nestedError = err;
2024
2024
  exitCallback(wrappedError);
2025
2025
  }
2026
2026
  });
@@ -3398,8 +3398,8 @@ function getCredentials() {
3398
3398
  }
3399
3399
  return decrypted;
3400
3400
  }
3401
- } catch (err2) {
3402
- console.error("[bootspring] Failed to read credentials:", err2.message);
3401
+ } catch (err) {
3402
+ console.error("[bootspring] Failed to read credentials:", err.message);
3403
3403
  }
3404
3404
  return null;
3405
3405
  }
@@ -3813,11 +3813,11 @@ async function request(method, path310, data = null, options = {}) {
3813
3813
  }
3814
3814
  });
3815
3815
  });
3816
- req.on("error", (err2) => {
3817
- if (err2.code === "ECONNREFUSED") {
3816
+ req.on("error", (err) => {
3817
+ if (err.code === "ECONNREFUSED") {
3818
3818
  reject(new Error("Cannot connect to Bootspring API."));
3819
3819
  } else {
3820
- reject(new Error(redactSensitiveString(err2.message || String(err2))));
3820
+ reject(new Error(redactSensitiveString(err.message || String(err))));
3821
3821
  }
3822
3822
  });
3823
3823
  if (data && method !== "GET") req.write(JSON.stringify(data));
@@ -4582,8 +4582,8 @@ ${COLORS.bold}Your Projects${COLORS.reset}
4582
4582
  console.log(` ${COLORS.dim}ID:${COLORS.reset} ${p.id} ${COLORS.dim}Role:${COLORS.reset} ${p.role || "owner"}
4583
4583
  `);
4584
4584
  });
4585
- } catch (err2) {
4586
- print.error(`Failed to list projects: ${err2.message}`);
4585
+ } catch (err) {
4586
+ print.error(`Failed to list projects: ${err.message}`);
4587
4587
  }
4588
4588
  });
4589
4589
  projectCmd.command("create [name]").alias("new").description("Create a new project").option("-d, --description <desc>", "Project description").option("-f, --framework <framework>", "Project framework (e.g., nextjs, nodejs)").option("--repo <url>", "Repository URL").action(async (name, options) => {
@@ -4602,8 +4602,8 @@ ${COLORS.bold}Your Projects${COLORS.reset}
4602
4602
  print.success(`Project "${response.name}" created successfully!`);
4603
4603
  console.log(`${COLORS.dim}ID:${COLORS.reset} ${response.id}`);
4604
4604
  console.log(`${COLORS.dim}Slug:${COLORS.reset} ${response.slug}`);
4605
- } catch (err2) {
4606
- print.error(`Failed to create project: ${err2.message}`);
4605
+ } catch (err) {
4606
+ print.error(`Failed to create project: ${err.message}`);
4607
4607
  }
4608
4608
  });
4609
4609
  projectCmd.command("info").alias("current").description("Show current project info").action(async () => {
@@ -4639,12 +4639,12 @@ ${COLORS.bold}Current Project Context${COLORS.reset}`);
4639
4639
  role: options.role
4640
4640
  });
4641
4641
  print.success(`Invitation sent to ${email} (role: ${options.role})`);
4642
- } catch (err2) {
4643
- if (err2.status === 403) {
4642
+ } catch (err) {
4643
+ if (err.status === 403) {
4644
4644
  print.warning("Project invitations require a paid Bootspring plan.");
4645
4645
  print.dim("Upgrade: https://bootspring.com/pricing");
4646
4646
  } else {
4647
- print.error(`Failed to invite: ${err2.message}`);
4647
+ print.error(`Failed to invite: ${err.message}`);
4648
4648
  }
4649
4649
  }
4650
4650
  });
@@ -4670,8 +4670,8 @@ ${COLORS.bold}Project Members${COLORS.reset} (${current.name})
4670
4670
  console.log(` ${m.email || m.name || m.id} ${roleColor}${role}${COLORS.reset}`);
4671
4671
  }
4672
4672
  console.log("");
4673
- } catch (err2) {
4674
- print.error(`Failed to list members: ${err2.message}`);
4673
+ } catch (err) {
4674
+ print.error(`Failed to list members: ${err.message}`);
4675
4675
  }
4676
4676
  });
4677
4677
  projectCmd.command("invitations").alias("invites").description("List pending invitations").action(async () => {
@@ -4694,8 +4694,8 @@ ${COLORS.bold}Pending Invitations${COLORS.reset}
4694
4694
  console.log(` ${inv.email} ${COLORS.dim}role: ${inv.role || "member"} sent: ${inv.createdAt || "unknown"}${COLORS.reset}`);
4695
4695
  }
4696
4696
  console.log("");
4697
- } catch (err2) {
4698
- print.error(`Failed to list invitations: ${err2.message}`);
4697
+ } catch (err) {
4698
+ print.error(`Failed to list invitations: ${err.message}`);
4699
4699
  }
4700
4700
  });
4701
4701
  projectCmd.command("accept <invitationId>").description("Accept a project invitation").action(async (invitationId) => {
@@ -4706,8 +4706,8 @@ ${COLORS.bold}Pending Invitations${COLORS.reset}
4706
4706
  try {
4707
4707
  await api_client_exports.request("POST", `/invitations/${encodeURIComponent(invitationId)}/accept`);
4708
4708
  print.success("Invitation accepted!");
4709
- } catch (err2) {
4710
- print.error(`Failed to accept invitation: ${err2.message}`);
4709
+ } catch (err) {
4710
+ print.error(`Failed to accept invitation: ${err.message}`);
4711
4711
  }
4712
4712
  });
4713
4713
  projectCmd.command("decline <invitationId>").description("Decline a project invitation").action(async (invitationId) => {
@@ -4718,8 +4718,8 @@ ${COLORS.bold}Pending Invitations${COLORS.reset}
4718
4718
  try {
4719
4719
  await api_client_exports.request("POST", `/invitations/${encodeURIComponent(invitationId)}/decline`);
4720
4720
  print.success("Invitation declined.");
4721
- } catch (err2) {
4722
- print.error(`Failed to decline invitation: ${err2.message}`);
4721
+ } catch (err) {
4722
+ print.error(`Failed to decline invitation: ${err.message}`);
4723
4723
  }
4724
4724
  });
4725
4725
  projectCmd.command("update-member <email>").description("Update member role").option("--role <role>", "New role (admin, member, viewer)", "member").action(async (email, options) => {
@@ -4734,8 +4734,8 @@ ${COLORS.bold}Pending Invitations${COLORS.reset}
4734
4734
  role: options.role
4735
4735
  });
4736
4736
  print.success(`Updated ${email} to role: ${options.role}`);
4737
- } catch (err2) {
4738
- print.error(`Failed to update member: ${err2.message}`);
4737
+ } catch (err) {
4738
+ print.error(`Failed to update member: ${err.message}`);
4739
4739
  }
4740
4740
  });
4741
4741
  projectCmd.command("remove-member <email>").description("Remove a project member").action(async (email) => {
@@ -4749,8 +4749,8 @@ ${COLORS.bold}Pending Invitations${COLORS.reset}
4749
4749
  email
4750
4750
  });
4751
4751
  print.success(`Removed ${email} from project.`);
4752
- } catch (err2) {
4753
- print.error(`Failed to remove member: ${err2.message}`);
4752
+ } catch (err) {
4753
+ print.error(`Failed to remove member: ${err.message}`);
4754
4754
  }
4755
4755
  });
4756
4756
  projectCmd.command("transfer <email>").description("Transfer project ownership").action(async (email) => {
@@ -4764,11 +4764,11 @@ ${COLORS.bold}Pending Invitations${COLORS.reset}
4764
4764
  newOwnerEmail: email
4765
4765
  });
4766
4766
  print.success(`Ownership transferred to ${email}.`);
4767
- } catch (err2) {
4768
- if (err2.status === 403) {
4767
+ } catch (err) {
4768
+ if (err.status === 403) {
4769
4769
  print.warning("Only the project owner can transfer ownership.");
4770
4770
  } else {
4771
- print.error(`Failed to transfer project: ${err2.message}`);
4771
+ print.error(`Failed to transfer project: ${err.message}`);
4772
4772
  }
4773
4773
  }
4774
4774
  });
@@ -4797,8 +4797,8 @@ ${COLORS.bold}Project Activity${COLORS.reset} (${current.name})
4797
4797
  }
4798
4798
  }
4799
4799
  console.log("");
4800
- } catch (err2) {
4801
- print.error(`Failed to load activity: ${err2.message}`);
4800
+ } catch (err) {
4801
+ print.error(`Failed to load activity: ${err.message}`);
4802
4802
  }
4803
4803
  });
4804
4804
  projectCmd.command("notifications").description("Show membership change notifications").action(async () => {
@@ -4823,8 +4823,8 @@ ${COLORS.bold}Notifications${COLORS.reset}
4823
4823
  if (time) print.dim(` ${time}`);
4824
4824
  }
4825
4825
  console.log("");
4826
- } catch (err2) {
4827
- print.error(`Failed to load notifications: ${err2.message}`);
4826
+ } catch (err) {
4827
+ print.error(`Failed to load notifications: ${err.message}`);
4828
4828
  }
4829
4829
  });
4830
4830
  }
@@ -5112,12 +5112,12 @@ ${COLORS.cyan}${COLORS.bold}MCP Connectors${COLORS.reset}
5112
5112
  if (c.description) console.log(` ${COLORS.dim}${c.description}${COLORS.reset}`);
5113
5113
  });
5114
5114
  console.log();
5115
- } catch (err2) {
5116
- if (err2.status === 403) {
5115
+ } catch (err) {
5116
+ if (err.status === 403) {
5117
5117
  print.warning("This feature requires a paid Bootspring plan.");
5118
5118
  print.dim("Upgrade: https://bootspring.com/pricing");
5119
5119
  } else {
5120
- print.error(`Failed to fetch connectors: ${err2.message}`);
5120
+ print.error(`Failed to fetch connectors: ${err.message}`);
5121
5121
  }
5122
5122
  }
5123
5123
  });
@@ -5195,12 +5195,12 @@ ${COLORS.bold}Resources (${resources.length})${COLORS.reset}`);
5195
5195
  print.warning("No tools or resources registered.");
5196
5196
  }
5197
5197
  console.log();
5198
- } catch (err2) {
5199
- if (err2.status === 403) {
5198
+ } catch (err) {
5199
+ if (err.status === 403) {
5200
5200
  print.warning("This feature requires a paid Bootspring plan.");
5201
5201
  print.dim("Upgrade: https://bootspring.com/pricing");
5202
5202
  } else {
5203
- print.error(`Failed to fetch MCP status: ${err2.message}`);
5203
+ print.error(`Failed to fetch MCP status: ${err.message}`);
5204
5204
  }
5205
5205
  }
5206
5206
  }
@@ -5230,12 +5230,12 @@ ${COLORS.cyan}${COLORS.bold}Bootspring MCP Test${COLORS.reset}
5230
5230
  }
5231
5231
  }
5232
5232
  console.log();
5233
- } catch (err2) {
5234
- if (err2.status === 403) {
5233
+ } catch (err) {
5234
+ if (err.status === 403) {
5235
5235
  print.warning("This feature requires a paid Bootspring plan.");
5236
5236
  print.dim("Upgrade: https://bootspring.com/pricing");
5237
5237
  } else {
5238
- print.error(`Connection failed: ${err2.message}`);
5238
+ print.error(`Connection failed: ${err.message}`);
5239
5239
  print.dim("Ensure your API key is valid and the server is reachable.");
5240
5240
  }
5241
5241
  }
@@ -5286,7 +5286,7 @@ ${COLORS.bold}${cat}${COLORS.reset}`);
5286
5286
  });
5287
5287
  }
5288
5288
  console.log();
5289
- } catch (_err) {
5289
+ } catch (err) {
5290
5290
  print.error(`Failed to list agents: ${err.message}`);
5291
5291
  }
5292
5292
  }
@@ -5305,8 +5305,14 @@ ${COLORS.bold}Expertise${COLORS.reset}`);
5305
5305
  agent.expertise.forEach((e) => console.log(` ${COLORS.green}\u25CF${COLORS.reset} ${e}`));
5306
5306
  }
5307
5307
  console.log();
5308
- } catch (_err) {
5309
- print.error(`Agent not found: ${name}`);
5308
+ } catch (err) {
5309
+ if (err.status === 404) {
5310
+ print.error(`Agent not found: ${name}`);
5311
+ } else if (err.status === 403) {
5312
+ print.warning("This feature requires a paid Bootspring plan.");
5313
+ } else {
5314
+ print.error(`Failed to load agent: ${err.message || "Unknown error"}`);
5315
+ }
5310
5316
  }
5311
5317
  }
5312
5318
  async function invokeAgent(name, topic) {
@@ -5324,7 +5330,7 @@ ${COLORS.bold}Agent Context:${COLORS.reset}`);
5324
5330
  console.log(response.context);
5325
5331
  console.log(`${COLORS.dim}\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500${COLORS.reset}
5326
5332
  `);
5327
- } catch (_err) {
5333
+ } catch (err) {
5328
5334
  print.error(`Failed to invoke agent: ${err.message}`);
5329
5335
  }
5330
5336
  }
@@ -5355,7 +5361,7 @@ ${COLORS.bold}${cat}${COLORS.reset}`);
5355
5361
  });
5356
5362
  }
5357
5363
  console.log();
5358
- } catch (_err) {
5364
+ } catch (err) {
5359
5365
  if (err.status === 403) {
5360
5366
  print.warning("This feature requires a paid Bootspring plan.");
5361
5367
  print.dim("Upgrade: https://bootspring.com/pricing");
@@ -5412,7 +5418,7 @@ ${COLORS.bold}${cat}${COLORS.reset}`);
5412
5418
  });
5413
5419
  }
5414
5420
  console.log();
5415
- } catch (_err) {
5421
+ } catch (err) {
5416
5422
  print.error(`Failed to list skills: ${err.message}`);
5417
5423
  }
5418
5424
  }
@@ -5430,8 +5436,14 @@ ${COLORS.cyan}${COLORS.bold}\u26A1 ${response.name || id}${COLORS.reset}`);
5430
5436
  `);
5431
5437
  console.log(response.content);
5432
5438
  console.log();
5433
- } catch (_err) {
5434
- print.error(`Skill not found: ${id}`);
5439
+ } catch (err) {
5440
+ if (err.status === 404) {
5441
+ print.error(`Skill not found: ${id}`);
5442
+ } else if (err.status === 403) {
5443
+ print.warning("This feature requires a paid Bootspring plan.");
5444
+ } else {
5445
+ print.error(`Failed to load skill: ${err.message || "Unknown error"}`);
5446
+ }
5435
5447
  }
5436
5448
  }
5437
5449
  async function searchSkills(query) {
@@ -5466,7 +5478,7 @@ ${COLORS.bold}${cat}${COLORS.reset}`);
5466
5478
  });
5467
5479
  }
5468
5480
  console.log();
5469
- } catch (_err) {
5481
+ } catch (err) {
5470
5482
  if (err.status === 403) {
5471
5483
  print.warning("This feature requires a paid Bootspring plan.");
5472
5484
  print.dim("Upgrade: https://bootspring.com/pricing");
@@ -5704,8 +5716,8 @@ ${COLORS.bold}Limits & Usage${COLORS.reset}`);
5704
5716
  console.log(`${COLORS.dim}Projects:${COLORS.reset} ${usage.projects} / ${limits.projects}`);
5705
5717
  console.log(`${COLORS.dim}API Calls:${COLORS.reset} ${usage.apiCalls} / ${limits.apiCalls}`);
5706
5718
  console.log();
5707
- } catch (err2) {
5708
- print.error(`Failed to fetch billing status: ${err2.message}`);
5719
+ } catch (err) {
5720
+ print.error(`Failed to fetch billing status: ${err.message}`);
5709
5721
  }
5710
5722
  }
5711
5723
  async function showUsage() {
@@ -5721,8 +5733,8 @@ ${COLORS.bold}Detailed Usage${COLORS.reset}`);
5721
5733
  console.log(`${COLORS.dim}Total Requests:${COLORS.reset} ${usage.totalRequests}`);
5722
5734
  console.log(`${COLORS.dim}Agent Invocations:${COLORS.reset} ${usage.agentInvokes}`);
5723
5735
  console.log();
5724
- } catch (err2) {
5725
- print.error(`Failed to fetch usage: ${err2.message}`);
5736
+ } catch (err) {
5737
+ print.error(`Failed to fetch usage: ${err.message}`);
5726
5738
  }
5727
5739
  }
5728
5740
  async function upgrade() {
@@ -5749,8 +5761,8 @@ async function portal() {
5749
5761
  ${COLORS.bold}Billing Portal:${COLORS.reset}`);
5750
5762
  console.log(` ${COLORS.cyan}${url}${COLORS.reset}
5751
5763
  `);
5752
- } catch (err2) {
5753
- print.error(`Failed to get portal URL: ${err2.message}`);
5764
+ } catch (err) {
5765
+ print.error(`Failed to get portal URL: ${err.message}`);
5754
5766
  }
5755
5767
  }
5756
5768
 
@@ -7631,8 +7643,8 @@ function registerBuildCommand(program3) {
7631
7643
  if (!fs7.existsSync(dir)) fs7.mkdirSync(dir, { recursive: true });
7632
7644
  fs7.writeFileSync(todoFile, todoContent);
7633
7645
  print.success(`Migrated ${tasks.length} tasks to planning/TODO.md`);
7634
- } catch (err2) {
7635
- print.error(`Migration failed: ${err2.message}`);
7646
+ } catch (err) {
7647
+ print.error(`Migration failed: ${err.message}`);
7636
7648
  }
7637
7649
  });
7638
7650
  build.command("backfill").aliases(["recover", "hydrate", "bootstrap"]).description("Recover build artifacts from existing codebase").action(() => {
@@ -7697,6 +7709,8 @@ function registerBuildCommand(program3) {
7697
7709
  init_cjs_shims();
7698
7710
  var fs8 = __toESM(require("fs"), 1);
7699
7711
  var path9 = __toESM(require("path"), 1);
7712
+ var os3 = __toESM(require("os"), 1);
7713
+ var import_child_process2 = require("child_process");
7700
7714
  init_dist();
7701
7715
  init_dist2();
7702
7716
  function registerHealthCommand(program3) {
@@ -7744,17 +7758,97 @@ function registerHealthCommand(program3) {
7744
7758
  } else {
7745
7759
  checks.push({ name: "AI Context", status: "warn", message: "Run `bootspring generate` to create CLAUDE.md" });
7746
7760
  }
7761
+ const homeDir = os3.homedir();
7762
+ const projectMcp = path9.join(cwd, ".mcp.json");
7763
+ const globalSettings = path9.join(homeDir, ".claude", "settings.json");
7764
+ if (fs8.existsSync(projectMcp)) {
7765
+ try {
7766
+ const mcpConfig = JSON.parse(fs8.readFileSync(projectMcp, "utf-8"));
7767
+ if (mcpConfig.mcpServers?.bootspring) {
7768
+ const cmd = mcpConfig.mcpServers.bootspring.command;
7769
+ const args = mcpConfig.mcpServers.bootspring.args || [];
7770
+ checks.push({ name: "MCP Config (project)", status: "pass", message: `${cmd} ${args.join(" ")}` });
7771
+ } else {
7772
+ checks.push({ name: "MCP Config (project)", status: "warn", message: ".mcp.json exists but no bootspring server entry" });
7773
+ }
7774
+ } catch {
7775
+ checks.push({ name: "MCP Config (project)", status: "fail", message: ".mcp.json is invalid JSON" });
7776
+ }
7777
+ } else if (fs8.existsSync(globalSettings)) {
7778
+ try {
7779
+ const settings = JSON.parse(fs8.readFileSync(globalSettings, "utf-8"));
7780
+ if (settings.mcpServers?.bootspring) {
7781
+ checks.push({ name: "MCP Config (global)", status: "pass", message: "Bootspring MCP in ~/.claude/settings.json" });
7782
+ } else {
7783
+ checks.push({ name: "MCP Config", status: "warn", message: "No bootspring MCP server configured. Run `bootspring doctor --fix-claude-config`" });
7784
+ }
7785
+ } catch {
7786
+ checks.push({ name: "MCP Config (global)", status: "fail", message: "~/.claude/settings.json is invalid JSON" });
7787
+ }
7788
+ } else {
7789
+ checks.push({ name: "MCP Config", status: "warn", message: "No MCP config found. Run `bootspring doctor --fix-claude-config`" });
7790
+ }
7791
+ try {
7792
+ const result = (0, import_child_process2.execSync)(
7793
+ `echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"health","version":"1.0.0"}}}' | bootspring mcp 2>/dev/null | head -1`,
7794
+ { timeout: 1e4, encoding: "utf-8" }
7795
+ ).trim();
7796
+ if (result) {
7797
+ const parsed = JSON.parse(result);
7798
+ if (parsed.result?.serverInfo) {
7799
+ checks.push({ name: "MCP Server", status: "pass", message: `${parsed.result.serverInfo.name} v${parsed.result.serverInfo.version}` });
7800
+ } else {
7801
+ checks.push({ name: "MCP Server", status: "warn", message: "Server responded but no serverInfo" });
7802
+ }
7803
+ } else {
7804
+ checks.push({ name: "MCP Server", status: "warn", message: "No response from MCP server (stdout may be corrupted)" });
7805
+ }
7806
+ } catch {
7807
+ checks.push({ name: "MCP Server", status: "warn", message: "MCP server not reachable. Check `bootspring mcp status`" });
7808
+ }
7809
+ if (auth_exports.isAuthenticated()) {
7810
+ checks.push({ name: "Authentication", status: "pass", message: "Logged in" });
7811
+ } else {
7812
+ checks.push({ name: "Authentication", status: "warn", message: "Not logged in. Run `bootspring auth login`" });
7813
+ }
7814
+ const skillFile = path9.join(homeDir, ".claude", "skills", "bootspring", "SKILL.md");
7815
+ const commandsDir = path9.join(homeDir, ".claude", "commands");
7816
+ if (fs8.existsSync(skillFile)) {
7817
+ checks.push({ name: "Bootspring Skill", status: "pass", message: "SKILL.md installed" });
7818
+ } else {
7819
+ checks.push({ name: "Bootspring Skill", status: "warn", message: "Not installed. Run `bootspring doctor setup`" });
7820
+ }
7821
+ if (fs8.existsSync(path9.join(commandsDir, "build.md"))) {
7822
+ checks.push({ name: "Slash Commands", status: "pass", message: "Installed" });
7823
+ } else {
7824
+ checks.push({ name: "Slash Commands", status: "warn", message: "Not installed. Run `bootspring doctor setup`" });
7825
+ }
7826
+ const buildStatePath = path9.join(cwd, "planning", "BUILD_STATE.json");
7827
+ const todoPath = path9.join(cwd, "planning", "TODO.md");
7828
+ if (fs8.existsSync(buildStatePath)) {
7829
+ try {
7830
+ const state = JSON.parse(fs8.readFileSync(buildStatePath, "utf-8"));
7831
+ const total = state.implementationQueue?.length || 0;
7832
+ const done = state.implementationQueue?.filter((t) => t.status === "completed").length || 0;
7833
+ checks.push({ name: "Build State", status: "pass", message: `${done}/${total} tasks complete` });
7834
+ } catch {
7835
+ checks.push({ name: "Build State", status: "warn", message: "BUILD_STATE.json exists but is invalid" });
7836
+ }
7837
+ } else if (fs8.existsSync(todoPath)) {
7838
+ checks.push({ name: "Build Plan", status: "pass", message: "TODO.md present (no BUILD_STATE.json yet)" });
7839
+ }
7747
7840
  }
7748
7841
  if (!opts.local) {
7842
+ const apiFailLevel = opts.api ? "fail" : "warn";
7749
7843
  try {
7750
7844
  const status = await api_client_exports.healthCheck();
7751
7845
  if (status.connected) {
7752
7846
  checks.push({ name: "API Connection", status: "pass", message: `Connected (v${status.version || "unknown"})` });
7753
7847
  } else {
7754
- checks.push({ name: "API Connection", status: "fail", message: "Cannot connect" });
7848
+ checks.push({ name: "API Connection", status: apiFailLevel, message: "Cannot connect" });
7755
7849
  }
7756
7850
  } catch {
7757
- checks.push({ name: "API Connection", status: "fail", message: "Connection failed" });
7851
+ checks.push({ name: "API Connection", status: apiFailLevel, message: "Connection failed" });
7758
7852
  }
7759
7853
  }
7760
7854
  let passCount = 0;
@@ -7917,9 +8011,9 @@ function registerDashboardCommand(program3) {
7917
8011
  }
7918
8012
  }
7919
8013
  try {
7920
- const { execSync: execSync9 } = await import("child_process");
7921
- const branch = execSync9("git rev-parse --abbrev-ref HEAD", { cwd, encoding: "utf-8" }).trim();
7922
- const commitCount = execSync9("git rev-list --count HEAD", { cwd, encoding: "utf-8" }).trim();
8014
+ const { execSync: execSync10 } = await import("child_process");
8015
+ const branch = execSync10("git rev-parse --abbrev-ref HEAD", { cwd, encoding: "utf-8" }).trim();
8016
+ const commitCount = execSync10("git rev-list --count HEAD", { cwd, encoding: "utf-8" }).trim();
7923
8017
  print.info(`Branch: ${branch} (${commitCount} commits)`);
7924
8018
  } catch {
7925
8019
  print.dim("Git: not available");
@@ -9117,7 +9211,7 @@ function registerDeployCommand(program3) {
9117
9211
 
9118
9212
  // src/commands/quality.ts
9119
9213
  init_cjs_shims();
9120
- var import_child_process2 = require("child_process");
9214
+ var import_child_process3 = require("child_process");
9121
9215
  var fs15 = __toESM(require("fs"), 1);
9122
9216
  var path16 = __toESM(require("path"), 1);
9123
9217
  init_dist();
@@ -9208,7 +9302,7 @@ function resolveCommand(check) {
9208
9302
  function runCheck(check) {
9209
9303
  const command = resolveCommand(check);
9210
9304
  try {
9211
- const output = (0, import_child_process2.execSync)(command, {
9305
+ const output = (0, import_child_process3.execSync)(command, {
9212
9306
  cwd: process.cwd(),
9213
9307
  encoding: "utf-8",
9214
9308
  stdio: ["pipe", "pipe", "pipe"],
@@ -9216,8 +9310,8 @@ function runCheck(check) {
9216
9310
  });
9217
9311
  return { passed: true, output };
9218
9312
  } catch (error) {
9219
- const err2 = error;
9220
- return { passed: false, output: err2.stdout || err2.stderr || "Check failed" };
9313
+ const err = error;
9314
+ return { passed: false, output: err.stdout || err.stderr || "Check failed" };
9221
9315
  }
9222
9316
  }
9223
9317
  function runGate(gateId, opts) {
@@ -9380,7 +9474,7 @@ function registerQualityCommand(program3) {
9380
9474
 
9381
9475
  // src/commands/security.ts
9382
9476
  init_cjs_shims();
9383
- var import_child_process3 = require("child_process");
9477
+ var import_child_process4 = require("child_process");
9384
9478
  var fs16 = __toESM(require("fs"), 1);
9385
9479
  var path17 = __toESM(require("path"), 1);
9386
9480
  init_dist();
@@ -9443,7 +9537,7 @@ function runDependencyAudit() {
9443
9537
  return summary;
9444
9538
  }
9445
9539
  try {
9446
- const output = (0, import_child_process3.execSync)("npm audit --json 2>/dev/null || true", {
9540
+ const output = (0, import_child_process4.execSync)("npm audit --json 2>/dev/null || true", {
9447
9541
  cwd,
9448
9542
  encoding: "utf-8",
9449
9543
  maxBuffer: 10 * 1024 * 1024
@@ -9604,7 +9698,7 @@ function registerSecurityCommand(program3) {
9604
9698
 
9605
9699
  // src/commands/doctor.ts
9606
9700
  init_cjs_shims();
9607
- var import_child_process4 = require("child_process");
9701
+ var import_child_process5 = require("child_process");
9608
9702
  var fs17 = __toESM(require("fs"), 1);
9609
9703
  var path18 = __toESM(require("path"), 1);
9610
9704
  init_dist();
@@ -9613,10 +9707,10 @@ function runCheck2(name, fn) {
9613
9707
  const result = fn();
9614
9708
  return { name, result };
9615
9709
  } catch (error) {
9616
- const err2 = error;
9710
+ const err = error;
9617
9711
  return {
9618
9712
  name,
9619
- result: { status: "fail", detail: `Error: ${err2.message}` }
9713
+ result: { status: "fail", detail: `Error: ${err.message}` }
9620
9714
  };
9621
9715
  }
9622
9716
  }
@@ -9649,7 +9743,7 @@ function checkNodeVersion() {
9649
9743
  }
9650
9744
  function checkNpmVersion() {
9651
9745
  try {
9652
- const version = (0, import_child_process4.execSync)("npm --version", { encoding: "utf-8" }).trim();
9746
+ const version = (0, import_child_process5.execSync)("npm --version", { encoding: "utf-8" }).trim();
9653
9747
  const major = parseInt(version.split(".")[0], 10);
9654
9748
  if (major >= 9) {
9655
9749
  return { status: "pass", detail: `npm ${version}` };
@@ -9669,7 +9763,7 @@ function checkNpmVersion() {
9669
9763
  }
9670
9764
  function checkPnpmVersion() {
9671
9765
  try {
9672
- const version = (0, import_child_process4.execSync)("pnpm --version", { encoding: "utf-8" }).trim();
9766
+ const version = (0, import_child_process5.execSync)("pnpm --version", { encoding: "utf-8" }).trim();
9673
9767
  return { status: "pass", detail: `pnpm ${version}` };
9674
9768
  } catch {
9675
9769
  return {
@@ -9681,7 +9775,7 @@ function checkPnpmVersion() {
9681
9775
  }
9682
9776
  function checkGitInstallation() {
9683
9777
  try {
9684
- const version = (0, import_child_process4.execSync)("git --version", { encoding: "utf-8" }).trim();
9778
+ const version = (0, import_child_process5.execSync)("git --version", { encoding: "utf-8" }).trim();
9685
9779
  return { status: "pass", detail: version };
9686
9780
  } catch {
9687
9781
  return {
@@ -9695,7 +9789,7 @@ function checkGitRepo() {
9695
9789
  const cwd = process.cwd();
9696
9790
  if (fs17.existsSync(path18.join(cwd, ".git"))) {
9697
9791
  try {
9698
- const branch = (0, import_child_process4.execSync)("git branch --show-current", {
9792
+ const branch = (0, import_child_process5.execSync)("git branch --show-current", {
9699
9793
  cwd,
9700
9794
  encoding: "utf-8"
9701
9795
  }).trim();
@@ -9751,7 +9845,7 @@ function checkDependencies() {
9751
9845
  }
9752
9846
  function checkDiskSpace() {
9753
9847
  try {
9754
- const output = (0, import_child_process4.execSync)("df -h . | tail -1", { encoding: "utf-8" }).trim();
9848
+ const output = (0, import_child_process5.execSync)("df -h . | tail -1", { encoding: "utf-8" }).trim();
9755
9849
  const parts = output.split(/\s+/);
9756
9850
  const available = parts[3] || "unknown";
9757
9851
  const usePercent = parts[4] || "unknown";
@@ -9780,7 +9874,7 @@ function checkTypeScript() {
9780
9874
  return { status: "warn", detail: "No tsconfig.json found (not a TypeScript project)" };
9781
9875
  }
9782
9876
  try {
9783
- const version = (0, import_child_process4.execSync)("npx tsc --version", {
9877
+ const version = (0, import_child_process5.execSync)("npx tsc --version", {
9784
9878
  cwd,
9785
9879
  encoding: "utf-8",
9786
9880
  timeout: 1e4
@@ -11494,7 +11588,7 @@ function registerDocsCommand(program3) {
11494
11588
  init_cjs_shims();
11495
11589
  var fs25 = __toESM(require("fs"), 1);
11496
11590
  var path26 = __toESM(require("path"), 1);
11497
- var import_child_process5 = require("child_process");
11591
+ var import_child_process6 = require("child_process");
11498
11592
  init_dist();
11499
11593
  var WORKSPACE_DIR = ".bootspring-workspace";
11500
11594
  var WORKSPACE_FILE = "workspace.json";
@@ -11698,7 +11792,7 @@ function registerWorkspaceCommand(program3) {
11698
11792
  for (const project of projects) {
11699
11793
  const spinner = createSpinner(`${project.name}...`).start();
11700
11794
  try {
11701
- (0, import_child_process5.execSync)(`bootspring ${workflowName}`, {
11795
+ (0, import_child_process6.execSync)(`bootspring ${workflowName}`, {
11702
11796
  cwd: project.absolutePath,
11703
11797
  encoding: "utf-8",
11704
11798
  timeout: parseInt(opts.timeout, 10),
@@ -11784,13 +11878,13 @@ function registerOrgCommand(program3) {
11784
11878
  if (o.memberCount != null) print.dim(` Members: ${o.memberCount}`);
11785
11879
  }
11786
11880
  console.log("");
11787
- } catch (err2) {
11881
+ } catch (err) {
11788
11882
  spinner.stop();
11789
- if (err2.status === 403) {
11883
+ if (err.status === 403) {
11790
11884
  print.warning("This feature requires a paid plan.");
11791
11885
  print.dim("Upgrade: https://bootspring.com/pricing");
11792
11886
  } else {
11793
- print.error(`Failed: ${err2.message}`);
11887
+ print.error(`Failed: ${err.message}`);
11794
11888
  }
11795
11889
  }
11796
11890
  });
@@ -11818,13 +11912,13 @@ function registerOrgCommand(program3) {
11818
11912
  if (o.policy?.profile) console.log(` Policy: ${getProfileBadge(o.policy.profile)}`);
11819
11913
  if (o.owner) console.log(` Owner: ${o.owner.email || o.owner.name || o.owner.id}`);
11820
11914
  console.log("");
11821
- } catch (err2) {
11915
+ } catch (err) {
11822
11916
  spinner.stop();
11823
- if (err2.status === 403) {
11917
+ if (err.status === 403) {
11824
11918
  print.warning("This feature requires a paid plan.");
11825
11919
  print.dim("Upgrade: https://bootspring.com/pricing");
11826
11920
  } else {
11827
- print.error(`Failed: ${err2.message}`);
11921
+ print.error(`Failed: ${err.message}`);
11828
11922
  }
11829
11923
  }
11830
11924
  });
@@ -11867,13 +11961,13 @@ function registerOrgCommand(program3) {
11867
11961
  }
11868
11962
  console.log("");
11869
11963
  }
11870
- } catch (err2) {
11964
+ } catch (err) {
11871
11965
  spinner.stop();
11872
- if (err2.status === 403) {
11966
+ if (err.status === 403) {
11873
11967
  print.warning("This feature requires a paid plan.");
11874
11968
  print.dim("Upgrade: https://bootspring.com/pricing");
11875
11969
  } else {
11876
- print.error(`Failed: ${err2.message}`);
11970
+ print.error(`Failed: ${err.message}`);
11877
11971
  }
11878
11972
  }
11879
11973
  });
@@ -11898,13 +11992,13 @@ function registerOrgCommand(program3) {
11898
11992
  try {
11899
11993
  await api_client_exports.request("PUT", `/organizations/${resolvedOrgId}/policy`, { profile });
11900
11994
  spinner.succeed(`Policy updated to "${profile}" for ${resolvedOrgId}`);
11901
- } catch (err2) {
11995
+ } catch (err) {
11902
11996
  spinner.stop();
11903
- if (err2.status === 403) {
11997
+ if (err.status === 403) {
11904
11998
  print.warning("This feature requires a paid plan.");
11905
11999
  print.dim("Upgrade: https://bootspring.com/pricing");
11906
12000
  } else {
11907
- print.error(`Failed: ${err2.message}`);
12001
+ print.error(`Failed: ${err.message}`);
11908
12002
  }
11909
12003
  }
11910
12004
  });
@@ -11962,13 +12056,13 @@ function registerOrgCommand(program3) {
11962
12056
  }
11963
12057
  console.log("");
11964
12058
  print.dim(`Total: ${members.length} member${members.length !== 1 ? "s" : ""}`);
11965
- } catch (err2) {
12059
+ } catch (err) {
11966
12060
  spinner.stop();
11967
- if (err2.status === 403) {
12061
+ if (err.status === 403) {
11968
12062
  print.warning("This feature requires a paid plan.");
11969
12063
  print.dim("Upgrade: https://bootspring.com/pricing");
11970
12064
  } else {
11971
- print.error(`Failed: ${err2.message}`);
12065
+ print.error(`Failed: ${err.message}`);
11972
12066
  }
11973
12067
  }
11974
12068
  });
@@ -11999,13 +12093,13 @@ function registerOrgCommand(program3) {
11999
12093
  }
12000
12094
  }
12001
12095
  console.log("");
12002
- } catch (err2) {
12096
+ } catch (err) {
12003
12097
  spinner.stop();
12004
- if (err2.status === 403) {
12098
+ if (err.status === 403) {
12005
12099
  print.warning("This feature requires a paid plan.");
12006
12100
  print.dim("Upgrade: https://bootspring.com/pricing");
12007
12101
  } else {
12008
- print.error(`Failed: ${err2.message}`);
12102
+ print.error(`Failed: ${err.message}`);
12009
12103
  }
12010
12104
  }
12011
12105
  });
@@ -12018,7 +12112,7 @@ function registerOrgCommand(program3) {
12018
12112
  init_cjs_shims();
12019
12113
  var fs26 = __toESM(require("fs"), 1);
12020
12114
  var path27 = __toESM(require("path"), 1);
12021
- var import_child_process6 = require("child_process");
12115
+ var import_child_process7 = require("child_process");
12022
12116
  init_dist();
12023
12117
  var MONITORING_PROVIDERS = {
12024
12118
  sentry: {
@@ -12126,7 +12220,7 @@ function collectMetrics(projectRoot) {
12126
12220
  const dirPath = path27.join(projectRoot, dir);
12127
12221
  if (fs26.existsSync(dirPath)) {
12128
12222
  try {
12129
- const output = (0, import_child_process6.execSync)(`du -sk "${dirPath}"`, {
12223
+ const output = (0, import_child_process7.execSync)(`du -sk "${dirPath}"`, {
12130
12224
  cwd: projectRoot,
12131
12225
  encoding: "utf-8",
12132
12226
  stdio: ["pipe", "pipe", "pipe"]
@@ -14349,7 +14443,7 @@ Generated: ${(/* @__PURE__ */ new Date()).toISOString()}`);
14349
14443
  init_cjs_shims();
14350
14444
  var fs35 = __toESM(require("fs"), 1);
14351
14445
  var path36 = __toESM(require("path"), 1);
14352
- var import_child_process7 = require("child_process");
14446
+ var import_child_process8 = require("child_process");
14353
14447
  init_dist();
14354
14448
  function getConnectionPath() {
14355
14449
  return path36.join(process.cwd(), ".bootspring", "github.json");
@@ -14375,7 +14469,7 @@ function saveConnection(conn) {
14375
14469
  }
14376
14470
  function isGhInstalled() {
14377
14471
  try {
14378
- (0, import_child_process7.execSync)("gh --version", { stdio: "pipe" });
14472
+ (0, import_child_process8.execSync)("gh --version", { stdio: "pipe" });
14379
14473
  return true;
14380
14474
  } catch {
14381
14475
  return false;
@@ -14383,7 +14477,7 @@ function isGhInstalled() {
14383
14477
  }
14384
14478
  function isGhAuthenticated() {
14385
14479
  try {
14386
- (0, import_child_process7.execSync)("gh auth status", { stdio: "pipe" });
14480
+ (0, import_child_process8.execSync)("gh auth status", { stdio: "pipe" });
14387
14481
  return true;
14388
14482
  } catch {
14389
14483
  return false;
@@ -14391,7 +14485,7 @@ function isGhAuthenticated() {
14391
14485
  }
14392
14486
  function detectRepoFromGit() {
14393
14487
  try {
14394
- const remote = (0, import_child_process7.execSync)("git remote get-url origin", { stdio: "pipe" }).toString().trim();
14488
+ const remote = (0, import_child_process8.execSync)("git remote get-url origin", { stdio: "pipe" }).toString().trim();
14395
14489
  const httpsMatch = remote.match(/github\.com\/([^/]+)\/([^/.]+)/);
14396
14490
  const sshMatch = remote.match(/github\.com:([^/]+)\/([^/.]+)/);
14397
14491
  const match = httpsMatch || sshMatch;
@@ -14408,7 +14502,7 @@ function detectRepoFromGit() {
14408
14502
  }
14409
14503
  function getRecentCommits(limit = 5) {
14410
14504
  try {
14411
- const log = (0, import_child_process7.execSync)(
14505
+ const log = (0, import_child_process8.execSync)(
14412
14506
  `git log --oneline --format="%H|%s|%an|%ai" -${limit}`,
14413
14507
  { stdio: "pipe" }
14414
14508
  ).toString().trim();
@@ -15049,12 +15143,12 @@ ${generateBadges(results)}`);
15049
15143
  history: state.history
15050
15144
  });
15051
15145
  print.success("Metrics synced to remote dashboard.");
15052
- } catch (err2) {
15053
- if (err2.status === 403) {
15146
+ } catch (err) {
15147
+ if (err.status === 403) {
15054
15148
  print.warning("Metrics sync requires a paid Bootspring plan.");
15055
15149
  print.dim("Upgrade: https://bootspring.com/pricing");
15056
15150
  } else {
15057
- print.error(`Sync failed: ${err2.message}`);
15151
+ print.error(`Sync failed: ${err.message}`);
15058
15152
  }
15059
15153
  }
15060
15154
  });
@@ -15277,8 +15371,8 @@ function registerMvpCommand(program3) {
15277
15371
  }
15278
15372
  referenced.push({ source: analysis.path, reason: `Quality: ${analysis.qualityScore}%` });
15279
15373
  }
15280
- } catch (err2) {
15281
- errors.push({ file: path39.relative(cwd, filePath), error: err2.message });
15374
+ } catch (err) {
15375
+ errors.push({ file: path39.relative(cwd, filePath), error: err.message });
15282
15376
  }
15283
15377
  }
15284
15378
  if (imported.length > 0) {
@@ -15305,8 +15399,8 @@ function registerMvpCommand(program3) {
15305
15399
  }
15306
15400
  if (errors.length > 0) {
15307
15401
  console.log(`Errors (${errors.length}):`);
15308
- for (const err2 of errors) {
15309
- print.error(`${err2.file}: ${err2.error}`);
15402
+ for (const err of errors) {
15403
+ print.error(`${err.file}: ${err.error}`);
15310
15404
  }
15311
15405
  console.log("");
15312
15406
  }
@@ -16023,8 +16117,8 @@ function registerLearnCommand(program3) {
16023
16117
  console.log(` Quality Patterns: ${learnings.qualityPatterns.length} patterns`);
16024
16118
  }
16025
16119
  console.log("");
16026
- } catch (err2) {
16027
- spinner.fail(`Failed to learn from organization: ${err2.message}`);
16120
+ } catch (err) {
16121
+ spinner.fail(`Failed to learn from organization: ${err.message}`);
16028
16122
  }
16029
16123
  });
16030
16124
  org.command("recommend").description("Get recommendations for new projects").option("--type <type>", "Project type").option("--features <features>", "Comma-separated features").action(async (opts) => {
@@ -16220,8 +16314,8 @@ function registerLearnCommand(program3) {
16220
16314
  console.log("");
16221
16315
  }
16222
16316
  }
16223
- } catch (err2) {
16224
- spinner.fail(`Analysis failed: ${err2.message}`);
16317
+ } catch (err) {
16318
+ spinner.fail(`Analysis failed: ${err.message}`);
16225
16319
  }
16226
16320
  });
16227
16321
  antipattern.command("list").description("List known anti-patterns").action(async () => {
@@ -16368,8 +16462,8 @@ function registerLearnCommand(program3) {
16368
16462
  console.log(`${COLORS.dim}Sources: ${activeSources.join(", ")}${COLORS.reset}
16369
16463
  `);
16370
16464
  }
16371
- } catch (err2) {
16372
- spinner.fail(`Failed to generate recommendations: ${err2.message}`);
16465
+ } catch (err) {
16466
+ spinner.fail(`Failed to generate recommendations: ${err.message}`);
16373
16467
  }
16374
16468
  });
16375
16469
  recommend.command("quick <question...>").description("Get quick answer to a question").action(async (question) => {
@@ -16419,8 +16513,8 @@ function registerLearnCommand(program3) {
16419
16513
  }
16420
16514
  }
16421
16515
  console.log("");
16422
- } catch (err2) {
16423
- console.log(`${COLORS.red}Failed: ${err2.message}${COLORS.reset}`);
16516
+ } catch (err) {
16517
+ console.log(`${COLORS.red}Failed: ${err.message}${COLORS.reset}`);
16424
16518
  }
16425
16519
  });
16426
16520
  recommend.command("report").description("Generate recommendation report").action(async () => {
@@ -16451,15 +16545,15 @@ function registerLearnCommand(program3) {
16451
16545
  console.log(` - [${rec.type}] ${rec.title} (${rec.confidenceLevel})`);
16452
16546
  }
16453
16547
  console.log("");
16454
- } catch (err2) {
16455
- console.log(`${COLORS.red}Failed to generate report: ${err2.message}${COLORS.reset}`);
16548
+ } catch (err) {
16549
+ console.log(`${COLORS.red}Failed to generate report: ${err.message}${COLORS.reset}`);
16456
16550
  }
16457
16551
  });
16458
16552
  }
16459
16553
 
16460
16554
  // src/commands/memory.ts
16461
16555
  init_cjs_shims();
16462
- var import_child_process8 = require("child_process");
16556
+ var import_child_process9 = require("child_process");
16463
16557
  init_dist();
16464
16558
  var MEMORY_CATEGORIES = {
16465
16559
  bugfix: { icon: "\u{1F41B}", label: "Bug Fixes", patterns: [/^fix/i, /^bugfix/i, /\bfix\b/i] },
@@ -16475,7 +16569,7 @@ var MEMORY_CATEGORIES = {
16475
16569
  };
16476
16570
  function isGitRepo() {
16477
16571
  try {
16478
- (0, import_child_process8.execSync)("git rev-parse --is-inside-work-tree", { encoding: "utf-8", stdio: "pipe" });
16572
+ (0, import_child_process9.execSync)("git rev-parse --is-inside-work-tree", { encoding: "utf-8", stdio: "pipe" });
16479
16573
  return true;
16480
16574
  } catch {
16481
16575
  return false;
@@ -16499,9 +16593,8 @@ function extractLearnings(options = {}) {
16499
16593
  return { learnings: [], total: 0, error: "Not a git repository" };
16500
16594
  }
16501
16595
  try {
16502
- const format = "--format=%H|%s|%ai";
16503
16596
  const sinceFlag = since ? `--since="${since}"` : "";
16504
- const output = (0, import_child_process8.execSync)(`git log ${format} ${sinceFlag} -n ${limit}`, {
16597
+ const output = (0, import_child_process9.execSync)(`git log --format='%H|%s|%ai' ${sinceFlag} -n ${limit}`, {
16505
16598
  encoding: "utf-8",
16506
16599
  stdio: ["pipe", "pipe", "pipe"]
16507
16600
  }).trim();
@@ -16523,8 +16616,8 @@ function extractLearnings(options = {}) {
16523
16616
  (l) => l.summary.length > 5 && !l.summary.startsWith("Merge ") && !l.summary.startsWith("merge ")
16524
16617
  );
16525
16618
  return { learnings: filtered, total: lines.length };
16526
- } catch (err2) {
16527
- return { learnings: [], total: 0, error: err2.message };
16619
+ } catch (err) {
16620
+ return { learnings: [], total: 0, error: err.message };
16528
16621
  }
16529
16622
  }
16530
16623
  function groupByCategory(learnings) {
@@ -16540,15 +16633,15 @@ function groupByCategory(learnings) {
16540
16633
  function getRepoStats() {
16541
16634
  if (!isGitRepo()) return null;
16542
16635
  try {
16543
- const totalOutput = (0, import_child_process8.execSync)("git rev-list --count HEAD", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
16636
+ const totalOutput = (0, import_child_process9.execSync)("git rev-list --count HEAD", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
16544
16637
  const totalCommits = parseInt(totalOutput, 10) || 0;
16545
- const contributorsOutput = (0, import_child_process8.execSync)("git shortlog -sn --all", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
16638
+ const contributorsOutput = (0, import_child_process9.execSync)("git shortlog -sn --all", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
16546
16639
  const contributors = contributorsOutput.split("\n").filter(Boolean).length;
16547
- const weeklyOutput = (0, import_child_process8.execSync)('git rev-list --count --since="1 week ago" HEAD', { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
16640
+ const weeklyOutput = (0, import_child_process9.execSync)('git rev-list --count --since="1 week ago" HEAD', { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
16548
16641
  const weeklyPace = parseInt(weeklyOutput, 10) || 0;
16549
16642
  let firstCommit;
16550
16643
  try {
16551
- firstCommit = (0, import_child_process8.execSync)("git log --reverse --format=%ai | head -1", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
16644
+ firstCommit = (0, import_child_process9.execSync)("git log --reverse --format=%ai | head -1", { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }).trim();
16552
16645
  } catch {
16553
16646
  }
16554
16647
  return { totalCommits, contributors, weeklyPace, firstCommit };
@@ -16647,7 +16740,7 @@ function registerMemoryCommand(program3) {
16647
16740
  }
16648
16741
  try {
16649
16742
  const limit = parseInt(opts.limit, 10) || 50;
16650
- const output = (0, import_child_process8.execSync)(`git log --name-only --format="" -n ${limit}`, {
16743
+ const output = (0, import_child_process9.execSync)(`git log --name-only --format="" -n ${limit}`, {
16651
16744
  encoding: "utf-8",
16652
16745
  stdio: ["pipe", "pipe", "pipe"]
16653
16746
  }).trim();
@@ -16664,8 +16757,8 @@ function registerMemoryCommand(program3) {
16664
16757
  ... and ${sorted.length - 20} more files`);
16665
16758
  }
16666
16759
  console.log("");
16667
- } catch (err2) {
16668
- print.error(err2.message);
16760
+ } catch (err) {
16761
+ print.error(err.message);
16669
16762
  }
16670
16763
  });
16671
16764
  memory.command("export").description("Export learnings as JSON").option("--limit <n>", "Number of commits", "50").option("--since <date>", "How far back to look", "3 months ago").action((opts) => {
@@ -17172,18 +17265,18 @@ function requireAuth() {
17172
17265
  print.error('Not logged in. Run "bootspring auth login" first.');
17173
17266
  return false;
17174
17267
  }
17175
- function handleApiError(err2, context) {
17176
- if (err2.status === 403) {
17268
+ function handleApiError(err, context) {
17269
+ if (err.status === 403) {
17177
17270
  print.warning("This feature requires a paid Bootspring plan.");
17178
17271
  print.dim("Upgrade: https://bootspring.com/pricing");
17179
17272
  return;
17180
17273
  }
17181
- if (err2.message?.includes("Cannot connect") || err2.code === "ECONNREFUSED") {
17274
+ if (err.message?.includes("Cannot connect") || err.code === "ECONNREFUSED") {
17182
17275
  print.error("Cannot connect to Bootspring API.");
17183
17276
  print.dim("Check your internet connection or try again later.");
17184
17277
  return;
17185
17278
  }
17186
- print.error(`${context}: ${err2.message}`);
17279
+ print.error(`${context}: ${err.message}`);
17187
17280
  }
17188
17281
  function registerOrchestratorCommand(program3) {
17189
17282
  const orchestrator = program3.command("orchestrator").description("Hosted workflow orchestration");
@@ -17208,9 +17301,9 @@ function registerOrchestratorCommand(program3) {
17208
17301
  }
17209
17302
  console.log("");
17210
17303
  }
17211
- } catch (err2) {
17304
+ } catch (err) {
17212
17305
  spinner.fail("Failed to fetch workflows");
17213
- handleApiError(err2, "Failed to list workflows");
17306
+ handleApiError(err, "Failed to list workflows");
17214
17307
  }
17215
17308
  });
17216
17309
  orchestrator.command("workflow [id]").description("Show workflow details").action(async (id) => {
@@ -17244,9 +17337,9 @@ function registerOrchestratorCommand(program3) {
17244
17337
  console.log(` ${workflow.agents.join(", ")}`);
17245
17338
  console.log("");
17246
17339
  }
17247
- } catch (err2) {
17340
+ } catch (err) {
17248
17341
  spinner.fail("Failed to load workflow");
17249
- handleApiError(err2, `Failed to fetch workflow "${id}"`);
17342
+ handleApiError(err, `Failed to fetch workflow "${id}"`);
17250
17343
  }
17251
17344
  });
17252
17345
  orchestrator.command("analyze [task]").description("Analyze project context").action(async (task) => {
@@ -17285,9 +17378,9 @@ function registerOrchestratorCommand(program3) {
17285
17378
  }
17286
17379
  console.log("");
17287
17380
  }
17288
- } catch (err2) {
17381
+ } catch (err) {
17289
17382
  spinner.fail("Analysis failed");
17290
- handleApiError(err2, "Failed to analyze context");
17383
+ handleApiError(err, "Failed to analyze context");
17291
17384
  }
17292
17385
  });
17293
17386
  orchestrator.command("suggest [task]").description("Get hosted suggestions").action(async (task) => {
@@ -17320,9 +17413,9 @@ function registerOrchestratorCommand(program3) {
17320
17413
  console.log(` ${COLORS.cyan}${suggestion.type || "suggestion"}${COLORS.reset} ${COLORS.dim}${JSON.stringify(suggestion)}${COLORS.reset}`);
17321
17414
  }
17322
17415
  console.log("");
17323
- } catch (err2) {
17416
+ } catch (err) {
17324
17417
  spinner.fail("Failed to get suggestions");
17325
- handleApiError(err2, "Failed to get suggestions");
17418
+ handleApiError(err, "Failed to get suggestions");
17326
17419
  }
17327
17420
  });
17328
17421
  orchestrator.command("start <id>").description("Start a hosted workflow").action(async (id) => {
@@ -17347,9 +17440,9 @@ function registerOrchestratorCommand(program3) {
17347
17440
  });
17348
17441
  console.log("");
17349
17442
  }
17350
- } catch (err2) {
17443
+ } catch (err) {
17351
17444
  spinner.fail("Failed to start workflow");
17352
- handleApiError(err2, `Failed to start workflow "${id}"`);
17445
+ handleApiError(err, `Failed to start workflow "${id}"`);
17353
17446
  }
17354
17447
  });
17355
17448
  orchestrator.command("status").description("Show orchestrator access").action(async () => {
@@ -17366,9 +17459,9 @@ function registerOrchestratorCommand(program3) {
17366
17459
  console.log(` ${COLORS.bold}Hosted workflows:${COLORS.reset} ${workflows.length}`);
17367
17460
  console.log(` ${COLORS.bold}Accessible:${COLORS.reset} ${accessible}`);
17368
17461
  console.log("");
17369
- } catch (err2) {
17462
+ } catch (err) {
17370
17463
  spinner.fail("Failed to fetch status");
17371
- handleApiError(err2, "Failed to fetch orchestrator status");
17464
+ handleApiError(err, "Failed to fetch orchestrator status");
17372
17465
  }
17373
17466
  });
17374
17467
  orchestrator.command("next").description("Advance to next workflow step").option("--workflow <id>", "Specify workflow ID (uses active workflow if omitted)").action(async (opts) => {
@@ -17392,9 +17485,9 @@ function registerOrchestratorCommand(program3) {
17392
17485
  spinner.info("No next step available");
17393
17486
  }
17394
17487
  console.log("");
17395
- } catch (err2) {
17488
+ } catch (err) {
17396
17489
  spinner.fail("Failed to advance");
17397
- handleApiError(err2, "Failed to advance workflow");
17490
+ handleApiError(err, "Failed to advance workflow");
17398
17491
  }
17399
17492
  });
17400
17493
  orchestrator.command("checkpoint [workflow] [step]").description("Mark workflow completion signal").option("--message <msg>", "Checkpoint message").action(async (workflow, step, opts) => {
@@ -17411,9 +17504,9 @@ function registerOrchestratorCommand(program3) {
17411
17504
  console.log(` ${COLORS.dim}Progress: ${response.progress}%${COLORS.reset}`);
17412
17505
  }
17413
17506
  console.log("");
17414
- } catch (err2) {
17507
+ } catch (err) {
17415
17508
  spinner.fail("Checkpoint failed");
17416
- handleApiError(err2, "Failed to record checkpoint");
17509
+ handleApiError(err, "Failed to record checkpoint");
17417
17510
  }
17418
17511
  });
17419
17512
  orchestrator.command("agents").description("List available agents").action(async () => {
@@ -17436,9 +17529,9 @@ function registerOrchestratorCommand(program3) {
17436
17529
  }
17437
17530
  console.log("");
17438
17531
  }
17439
- } catch (err2) {
17532
+ } catch (err) {
17440
17533
  spinner.fail("Failed to fetch agents");
17441
- handleApiError(err2, "Failed to list agents");
17534
+ handleApiError(err, "Failed to list agents");
17442
17535
  }
17443
17536
  });
17444
17537
  orchestrator.action(() => {
@@ -17619,7 +17712,7 @@ function registerPreseedFromCodebaseCommand(program3) {
17619
17712
  init_cjs_shims();
17620
17713
  var fs45 = __toESM(require("fs"), 1);
17621
17714
  var path46 = __toESM(require("path"), 1);
17622
- var os3 = __toESM(require("os"), 1);
17715
+ var os4 = __toESM(require("os"), 1);
17623
17716
  init_dist();
17624
17717
  function detectEnvironment() {
17625
17718
  return {
@@ -17627,7 +17720,7 @@ function detectEnvironment() {
17627
17720
  isVSCode: !!process.env["VSCODE_PID"] || (process.env["TERM_PROGRAM"] || "").includes("vscode"),
17628
17721
  isCursor: !!process.env["CURSOR_TRACE_ID"],
17629
17722
  isInteractive: !!(process.stdin.isTTY && process.stdout.isTTY),
17630
- platform: os3.platform()
17723
+ platform: os4.platform()
17631
17724
  };
17632
17725
  }
17633
17726
  function detectProjectContext(projectRoot) {
@@ -18083,7 +18176,7 @@ function registerTaskCommand(program3) {
18083
18176
 
18084
18177
  // src/commands/update.ts
18085
18178
  init_cjs_shims();
18086
- var import_child_process9 = require("child_process");
18179
+ var import_child_process10 = require("child_process");
18087
18180
  var fs47 = __toESM(require("fs"), 1);
18088
18181
  var path48 = __toESM(require("path"), 1);
18089
18182
  init_dist();
@@ -18101,7 +18194,7 @@ function getCurrentVersion() {
18101
18194
  }
18102
18195
  function getLatestVersion() {
18103
18196
  try {
18104
- const result = (0, import_child_process9.execSync)(`npm view ${PACKAGE_NAME} version 2>/dev/null`, {
18197
+ const result = (0, import_child_process10.execSync)(`npm view ${PACKAGE_NAME} version 2>/dev/null`, {
18105
18198
  encoding: "utf-8",
18106
18199
  timeout: 1e4,
18107
18200
  stdio: ["pipe", "pipe", "pipe"]
@@ -18124,7 +18217,7 @@ function compareVersions(a, b) {
18124
18217
  }
18125
18218
  function getInstallContext() {
18126
18219
  try {
18127
- const globalPrefix = (0, import_child_process9.execSync)("npm config get prefix", {
18220
+ const globalPrefix = (0, import_child_process10.execSync)("npm config get prefix", {
18128
18221
  encoding: "utf-8",
18129
18222
  stdio: ["pipe", "pipe", "pipe"]
18130
18223
  }).trim();
@@ -18178,7 +18271,7 @@ function registerUpdateCommand(program3) {
18178
18271
  const spinner = createSpinner(`Updating ${target}`).start();
18179
18272
  try {
18180
18273
  const cmd = context.mode === "global" ? `npm install -g ${PACKAGE_NAME}@latest` : `npm install ${PACKAGE_NAME}@latest`;
18181
- (0, import_child_process9.execSync)(cmd, {
18274
+ (0, import_child_process10.execSync)(cmd, {
18182
18275
  encoding: "utf-8",
18183
18276
  stdio: ["pipe", "pipe", "pipe"],
18184
18277
  timeout: 6e4
@@ -18564,8 +18657,8 @@ var FileWatcher = class extends import_events.EventEmitter {
18564
18657
  }
18565
18658
  });
18566
18659
  this.watchers.push(watcher);
18567
- } catch (err2) {
18568
- this.emit("error", { type, error: err2 });
18660
+ } catch (err) {
18661
+ this.emit("error", { type, error: err });
18569
18662
  }
18570
18663
  }
18571
18664
  watchDirectory(dirPath, type) {
@@ -18578,8 +18671,8 @@ var FileWatcher = class extends import_events.EventEmitter {
18578
18671
  }
18579
18672
  });
18580
18673
  this.watchers.push(watcher);
18581
- } catch (err2) {
18582
- this.emit("error", { type, error: err2 });
18674
+ } catch (err) {
18675
+ this.emit("error", { type, error: err });
18583
18676
  }
18584
18677
  }
18585
18678
  debouncedHandle(filePath, type) {
@@ -18623,8 +18716,8 @@ var FileWatcher = class extends import_events.EventEmitter {
18623
18716
  }
18624
18717
  }
18625
18718
  }
18626
- } catch (err2) {
18627
- this.emit("error", { type, filePath, error: err2 });
18719
+ } catch (err) {
18720
+ this.emit("error", { type, filePath, error: err });
18628
18721
  }
18629
18722
  }
18630
18723
  loadTodoState(filePath) {
@@ -18693,8 +18786,8 @@ function registerWatchCommand(program3) {
18693
18786
  console.log(`${COLORS.dim}${parts.join(" | ")}${COLORS.reset}`);
18694
18787
  console.log("");
18695
18788
  });
18696
- watcher.on("error", (err2) => {
18697
- console.log(`${COLORS.red}Error:${COLORS.reset} ${err2.type} - ${err2.error?.message || "Unknown error"}`);
18789
+ watcher.on("error", (err) => {
18790
+ console.log(`${COLORS.red}Error:${COLORS.reset} ${err.type} - ${err.error?.message || "Unknown error"}`);
18698
18791
  });
18699
18792
  watcher.start();
18700
18793
  process.on("SIGINT", () => {
@@ -18961,7 +19054,7 @@ async function showTypes() {
18961
19054
  init_cjs_shims();
18962
19055
  var fs51 = __toESM(require("fs"), 1);
18963
19056
  var path53 = __toESM(require("path"), 1);
18964
- var os4 = __toESM(require("os"), 1);
19057
+ var os5 = __toESM(require("os"), 1);
18965
19058
  init_dist();
18966
19059
  init_dist2();
18967
19060
  function registerManagerCommand(program3) {
@@ -18999,7 +19092,7 @@ function getKnownProjects() {
18999
19092
  }
19000
19093
  } catch {
19001
19094
  }
19002
- const workspaceFile = path53.join(os4.homedir(), ".bootspring", "workspace.json");
19095
+ const workspaceFile = path53.join(os5.homedir(), ".bootspring", "workspace.json");
19003
19096
  if (fs51.existsSync(workspaceFile)) {
19004
19097
  try {
19005
19098
  const workspace = JSON.parse(fs51.readFileSync(workspaceFile, "utf-8"));
@@ -19107,8 +19200,8 @@ async function scanProjects(dir) {
19107
19200
  found.push({ name: entry.name, path: dirPath });
19108
19201
  }
19109
19202
  }
19110
- } catch (err2) {
19111
- print.error(`Scan failed: ${err2.message}`);
19203
+ } catch (err) {
19204
+ print.error(`Scan failed: ${err.message}`);
19112
19205
  return;
19113
19206
  }
19114
19207
  print.success(`Found ${found.length} project(s)`);
@@ -19126,10 +19219,10 @@ async function scanProjects(dir) {
19126
19219
  // src/commands/setup.ts
19127
19220
  init_cjs_shims();
19128
19221
  var fs53 = __toESM(require("fs"), 1);
19129
- var os5 = __toESM(require("os"), 1);
19222
+ var os6 = __toESM(require("os"), 1);
19130
19223
  var path54 = __toESM(require("path"), 1);
19131
19224
  init_dist();
19132
- var HOME = os5.homedir();
19225
+ var HOME = os6.homedir();
19133
19226
  function registerSetupCommand(program3) {
19134
19227
  const setup = program3.command("setup").description("Configure MCP for Claude Code, Codex, and Gemini CLI");
19135
19228
  setup.command("assistants").description("Install MCP entries for all supported assistants (default)").action(async () => {
@@ -19166,8 +19259,8 @@ function upsertJsonMcp(name, configPath, assistant) {
19166
19259
  fs53.writeFileSync(configPath, `${JSON.stringify(settings, null, 2)}
19167
19260
  `, "utf-8");
19168
19261
  return { name, path: configPath, status: "updated" };
19169
- } catch (err2) {
19170
- return { name, path: configPath, status: "error", reason: err2.message };
19262
+ } catch (err) {
19263
+ return { name, path: configPath, status: "error", reason: err.message };
19171
19264
  }
19172
19265
  }
19173
19266
  function upsertCodexToml() {
@@ -19189,8 +19282,8 @@ env = { BOOTSPRING_ASSISTANT = "codex" }
19189
19282
  ${block}` : block;
19190
19283
  fs53.writeFileSync(configPath, content, "utf-8");
19191
19284
  return { name: "Codex", path: configPath, status: "updated" };
19192
- } catch (err2) {
19193
- return { name: "Codex", path: configPath, status: "error", reason: err2.message };
19285
+ } catch (err) {
19286
+ return { name: "Codex", path: configPath, status: "error", reason: err.message };
19194
19287
  }
19195
19288
  }
19196
19289
  function printResult(result) {
@@ -19255,8 +19348,8 @@ ${COLORS.cyan}${COLORS.bold}Bootspring Setup Status${COLORS.reset}
19255
19348
  status: settings.mcpServers?.bootspring?.command ? "unchanged" : "error",
19256
19349
  reason: settings.mcpServers?.bootspring?.command ? void 0 : "bootspring entry missing"
19257
19350
  });
19258
- } catch (err2) {
19259
- checks.push({ name: "Claude Code", path: claudePath, status: "error", reason: err2.message });
19351
+ } catch (err) {
19352
+ checks.push({ name: "Claude Code", path: claudePath, status: "error", reason: err.message });
19260
19353
  }
19261
19354
  } else {
19262
19355
  checks.push({ name: "Claude Code", path: claudePath, status: "error", reason: "config missing" });
@@ -19286,8 +19379,8 @@ ${COLORS.cyan}${COLORS.bold}Bootspring Setup Status${COLORS.reset}
19286
19379
  status: settings.mcpServers?.bootspring?.command ? "unchanged" : "error",
19287
19380
  reason: settings.mcpServers?.bootspring?.command ? void 0 : "bootspring entry missing"
19288
19381
  });
19289
- } catch (err2) {
19290
- checks.push({ name: "Gemini CLI", path: geminiPath, status: "error", reason: err2.message });
19382
+ } catch (err) {
19383
+ checks.push({ name: "Gemini CLI", path: geminiPath, status: "error", reason: err.message });
19291
19384
  }
19292
19385
  } else {
19293
19386
  checks.push({ name: "Gemini CLI", path: geminiPath, status: "error", reason: "config missing" });
package/dist/core.js CHANGED
@@ -1600,7 +1600,7 @@ var require_package = __commonJS({
1600
1600
  "package.json"(exports2, module2) {
1601
1601
  module2.exports = {
1602
1602
  name: "@girardmedia/bootspring",
1603
- version: "2.3.1",
1603
+ version: "2.3.3",
1604
1604
  description: "Thin client for Bootspring cloud MCP, hosted agents, and paywalled workflow intelligence",
1605
1605
  keywords: [
1606
1606
  "ai",
@@ -45,7 +45,7 @@ var require_package = __commonJS({
45
45
  "package.json"(exports2, module2) {
46
46
  module2.exports = {
47
47
  name: "@girardmedia/bootspring",
48
- version: "2.3.1",
48
+ version: "2.3.3",
49
49
  description: "Thin client for Bootspring cloud MCP, hosted agents, and paywalled workflow intelligence",
50
50
  keywords: [
51
51
  "ai",
@@ -2220,7 +2220,10 @@ async function resolveTools() {
2220
2220
  }
2221
2221
  try {
2222
2222
  const response = await api.listMcpTools();
2223
- return Array.isArray(response) ? response : response.tools || FALLBACK_TOOLS;
2223
+ const apiTools = Array.isArray(response) ? response : response.tools || [];
2224
+ const apiNames = new Set(apiTools.map((t) => t.name));
2225
+ const missing = FALLBACK_TOOLS.filter((t) => !apiNames.has(t.name));
2226
+ return [...apiTools, ...missing];
2224
2227
  } catch {
2225
2228
  return FALLBACK_TOOLS;
2226
2229
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@girardmedia/bootspring",
3
- "version": "2.3.1",
3
+ "version": "2.3.3",
4
4
  "description": "Thin client for Bootspring cloud MCP, hosted agents, and paywalled workflow intelligence",
5
5
  "keywords": [
6
6
  "ai",