@braingrid/cli 0.2.40 → 0.2.42

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,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.42] - 2026-02-17
11
+
12
+ ### Added
13
+
14
+ - **SessionStart and TaskCompleted hook installation** — `braingrid setup claude-code` now installs two additional hook scripts: `check-stale-build-sentinel.sh` (SessionStart) for cleaning up stale build sentinels, and `task-completed-validate.sh` (TaskCompleted) for commit validation before marking tasks complete
15
+ - **Sync script updated** — `sync-claude-code-to-braingrid.sh` now syncs 16 files (up from 14), including the two new hook scripts
16
+
17
+ ## [0.2.41] - 2026-02-17
18
+
19
+ ### Fixed
20
+
21
+ - **Tasks invisible to teammates in parallel build mode** — reordered `/build` command to discover tasks and select mode before calling `TaskCreate`; in parallel mode, `TeamCreate` now runs first so tasks land in the team's task list instead of the default session list
22
+ - **Acceptance criteria format** — checklist files now use `## Acceptance Criteria` heading with `- []` list items; updated `verify-acceptance-criteria.sh` grep patterns to match new format
23
+ - **Renamed teammate agents** — parallel build teammates renamed from `builder-{n}` to `braingrid-builder-{n}` for clarity
24
+
25
+ ### Changed
26
+
27
+ - **Update handler uses subprocess for IDE setup** — `braingrid update` now runs IDE setup via a spawned subprocess so the newly installed binary is used instead of the old code still loaded in memory
28
+
10
29
  ## [0.2.40] - 2026-02-17
11
30
 
12
31
  ### Fixed
package/dist/cli.js CHANGED
@@ -222,7 +222,7 @@ async function axiosWithRetry(config2, options) {
222
222
 
223
223
  // src/build-config.ts
224
224
  var BUILD_ENV = true ? "production" : process.env.NODE_ENV === "test" ? "development" : "production";
225
- var CLI_VERSION = true ? "0.2.40" : "0.0.0-test";
225
+ var CLI_VERSION = true ? "0.2.42" : "0.0.0-test";
226
226
  var PRODUCTION_CONFIG = {
227
227
  apiUrl: "https://app.braingrid.ai",
228
228
  workosAuthUrl: "https://auth.braingrid.ai",
@@ -2679,7 +2679,7 @@ async function copyBraingridReadme(targetPath = ".braingrid/README.md") {
2679
2679
  return false;
2680
2680
  }
2681
2681
  }
2682
- async function updateClaudeSettings(settingsPath = ".claude/settings.json", scriptPath2 = ".claude/statusline.sh", hookScriptPath = ".claude/hooks/sync-braingrid-task.sh", createHookScriptPath = ".claude/hooks/create-braingrid-task.sh", verifyHookScriptPath = ".claude/hooks/verify-acceptance-criteria.sh", postTaskUpdatePromptPath = ".claude/hooks/post-task-update-prompt.sh", preTaskCreatePath = ".claude/hooks/pre-task-create-naming.sh", preTaskUpdatePath = ".claude/hooks/pre-task-update-instructions.sh") {
2682
+ async function updateClaudeSettings(settingsPath = ".claude/settings.json", scriptPath2 = ".claude/statusline.sh", hookScriptPath = ".claude/hooks/sync-braingrid-task.sh", createHookScriptPath = ".claude/hooks/create-braingrid-task.sh", verifyHookScriptPath = ".claude/hooks/verify-acceptance-criteria.sh", postTaskUpdatePromptPath = ".claude/hooks/post-task-update-prompt.sh", preTaskCreatePath = ".claude/hooks/pre-task-create-naming.sh", preTaskUpdatePath = ".claude/hooks/pre-task-update-instructions.sh", sessionStartPath = ".claude/hooks/check-stale-build-sentinel.sh", taskCompletedPath = ".claude/hooks/task-completed-validate.sh") {
2683
2683
  try {
2684
2684
  let settings = {};
2685
2685
  try {
@@ -2782,11 +2782,39 @@ async function updateClaudeSettings(settingsPath = ".claude/settings.json", scri
2782
2782
  (entry) => entry.hooks?.some((h) => h.command?.includes("verify-acceptance-criteria"))
2783
2783
  );
2784
2784
  const mergedStop = hasVerifyHook ? existingStop : [...existingStop, ourStopHookEntry];
2785
+ const ourSessionStartEntry = {
2786
+ hooks: [
2787
+ {
2788
+ type: "command",
2789
+ command: sessionStartPath
2790
+ }
2791
+ ]
2792
+ };
2793
+ const existingSessionStart = Array.isArray(existingHooks.SessionStart) ? existingHooks.SessionStart : [];
2794
+ const hasSessionStartHook = existingSessionStart.some(
2795
+ (entry) => entry.hooks?.some((h) => h.command?.includes("check-stale-build-sentinel"))
2796
+ );
2797
+ const mergedSessionStart = hasSessionStartHook ? existingSessionStart : [...existingSessionStart, ourSessionStartEntry];
2798
+ const ourTaskCompletedEntry = {
2799
+ hooks: [
2800
+ {
2801
+ type: "command",
2802
+ command: taskCompletedPath
2803
+ }
2804
+ ]
2805
+ };
2806
+ const existingTaskCompleted = Array.isArray(existingHooks.TaskCompleted) ? existingHooks.TaskCompleted : [];
2807
+ const hasTaskCompletedHook = existingTaskCompleted.some(
2808
+ (entry) => entry.hooks?.some((h) => h.command?.includes("task-completed-validate"))
2809
+ );
2810
+ const mergedTaskCompleted = hasTaskCompletedHook ? existingTaskCompleted : [...existingTaskCompleted, ourTaskCompletedEntry];
2785
2811
  settings.hooks = {
2786
2812
  ...existingHooks,
2787
2813
  PreToolUse: mergedPreToolUse,
2788
2814
  PostToolUse: mergedPostToolUse,
2789
- Stop: mergedStop
2815
+ Stop: mergedStop,
2816
+ SessionStart: mergedSessionStart,
2817
+ TaskCompleted: mergedTaskCompleted
2790
2818
  };
2791
2819
  const parentDir = path2.dirname(settingsPath);
2792
2820
  await fs2.mkdir(parentDir, { recursive: true });
@@ -3645,8 +3673,34 @@ async function handleSetupClaudeCode(opts) {
3645
3673
  error instanceof Error ? error.message : String(error)
3646
3674
  );
3647
3675
  }
3676
+ let sessionStartInstalled = false;
3677
+ try {
3678
+ const sessionStartContent = await fetchFileFromGitHub(
3679
+ "claude-code/hooks/check-stale-build-sentinel.sh"
3680
+ );
3681
+ await installHookScript(sessionStartContent, ".claude/hooks/check-stale-build-sentinel.sh");
3682
+ sessionStartInstalled = true;
3683
+ } catch (error) {
3684
+ console.error(
3685
+ chalk8.yellow("\u26A0\uFE0F Failed to install session-start hook:"),
3686
+ error instanceof Error ? error.message : String(error)
3687
+ );
3688
+ }
3689
+ let taskCompletedInstalled = false;
3690
+ try {
3691
+ const taskCompletedContent = await fetchFileFromGitHub(
3692
+ "claude-code/hooks/task-completed-validate.sh"
3693
+ );
3694
+ await installHookScript(taskCompletedContent, ".claude/hooks/task-completed-validate.sh");
3695
+ taskCompletedInstalled = true;
3696
+ } catch (error) {
3697
+ console.error(
3698
+ chalk8.yellow("\u26A0\uFE0F Failed to install task-completed hook:"),
3699
+ error instanceof Error ? error.message : String(error)
3700
+ );
3701
+ }
3648
3702
  const statusLineMessage = statusLineInstalled ? chalk8.dim(" Status line: .claude/statusline.sh\n") : "";
3649
- const hooksMessage = (syncHookInstalled ? chalk8.dim(" Hook script: .claude/hooks/sync-braingrid-task.sh\n") : "") + (createHookInstalled ? chalk8.dim(" Hook script: .claude/hooks/create-braingrid-task.sh\n") : "") + (verifyHookInstalled ? chalk8.dim(" Hook script: .claude/hooks/verify-acceptance-criteria.sh\n") : "") + (preTaskCreateInstalled ? chalk8.dim(" Hook script: .claude/hooks/pre-task-create-naming.sh\n") : "") + (preTaskUpdateInstalled ? chalk8.dim(" Hook script: .claude/hooks/pre-task-update-instructions.sh\n") : "") + (postTaskUpdateInstalled ? chalk8.dim(" Hook script: .claude/hooks/post-task-update-prompt.sh\n") : "");
3703
+ const hooksMessage = (syncHookInstalled ? chalk8.dim(" Hook script: .claude/hooks/sync-braingrid-task.sh\n") : "") + (createHookInstalled ? chalk8.dim(" Hook script: .claude/hooks/create-braingrid-task.sh\n") : "") + (verifyHookInstalled ? chalk8.dim(" Hook script: .claude/hooks/verify-acceptance-criteria.sh\n") : "") + (preTaskCreateInstalled ? chalk8.dim(" Hook script: .claude/hooks/pre-task-create-naming.sh\n") : "") + (preTaskUpdateInstalled ? chalk8.dim(" Hook script: .claude/hooks/pre-task-update-instructions.sh\n") : "") + (postTaskUpdateInstalled ? chalk8.dim(" Hook script: .claude/hooks/post-task-update-prompt.sh\n") : "") + (sessionStartInstalled ? chalk8.dim(" Hook script: .claude/hooks/check-stale-build-sentinel.sh\n") : "") + (taskCompletedInstalled ? chalk8.dim(" Hook script: .claude/hooks/task-completed-validate.sh\n") : "");
3650
3704
  return {
3651
3705
  success: true,
3652
3706
  message: buildSuccessMessage(config2, displayPerDir, statusLineMessage + hooksMessage)
@@ -3694,6 +3748,7 @@ async function handleSetupCursor(opts) {
3694
3748
  }
3695
3749
 
3696
3750
  // src/handlers/update.handlers.ts
3751
+ import { execSync as execSync2 } from "child_process";
3697
3752
  import { confirm } from "@inquirer/prompts";
3698
3753
  import chalk9 from "chalk";
3699
3754
 
@@ -3802,6 +3857,18 @@ function executeUpdate(pm, packageName) {
3802
3857
  }
3803
3858
 
3804
3859
  // src/handlers/update.handlers.ts
3860
+ function runSetupSubprocess(subcommand) {
3861
+ try {
3862
+ const output = execSync2(`braingrid setup ${subcommand} --force`, {
3863
+ stdio: "pipe",
3864
+ timeout: 6e4
3865
+ });
3866
+ return output.toString();
3867
+ } catch (error) {
3868
+ const msg = error instanceof Error ? error.message : String(error);
3869
+ return chalk9.yellow(`\u26A0\uFE0F Setup ${subcommand} failed: ${msg}`);
3870
+ }
3871
+ }
3805
3872
  async function promptForIdeUpdates() {
3806
3873
  const cliTools = await checkInstalledCliTools();
3807
3874
  const claudeInstalled = cliTools.find((t) => t.command === "claude")?.installed;
@@ -3813,9 +3880,8 @@ async function promptForIdeUpdates() {
3813
3880
  default: true
3814
3881
  });
3815
3882
  if (shouldUpdate) {
3816
- const result = await handleSetupClaudeCode({ force: true });
3817
3883
  setupOutput += `
3818
- ${result.message}`;
3884
+ ${runSetupSubprocess("claude-code")}`;
3819
3885
  }
3820
3886
  }
3821
3887
  if (cursorInstalled) {
@@ -3824,9 +3890,8 @@ ${result.message}`;
3824
3890
  default: true
3825
3891
  });
3826
3892
  if (shouldUpdate) {
3827
- const result = await handleSetupCursor({ force: true });
3828
3893
  setupOutput += `
3829
- ${result.message}`;
3894
+ ${runSetupSubprocess("cursor")}`;
3830
3895
  }
3831
3896
  }
3832
3897
  return setupOutput;