brainclaw 0.28.0 → 1.5.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.
Files changed (198) hide show
  1. package/README.md +193 -170
  2. package/dist/brainclaw-vscode.vsix +0 -0
  3. package/dist/cli.js +683 -23
  4. package/dist/commands/accept.js +3 -0
  5. package/dist/commands/add-step.js +11 -26
  6. package/dist/commands/agent-board.js +70 -3
  7. package/dist/commands/audit.js +19 -0
  8. package/dist/commands/check-policy.js +54 -0
  9. package/dist/commands/check-security-mcp.js +145 -0
  10. package/dist/commands/check-security.js +106 -0
  11. package/dist/commands/claim-resource.js +1 -0
  12. package/dist/commands/codev.js +672 -0
  13. package/dist/commands/compact.js +74 -0
  14. package/dist/commands/complete-step.js +16 -26
  15. package/dist/commands/constraint.js +8 -20
  16. package/dist/commands/decision.js +9 -20
  17. package/dist/commands/delete-plan.js +10 -12
  18. package/dist/commands/delete-step.js +16 -0
  19. package/dist/commands/dispatch.js +163 -0
  20. package/dist/commands/doctor.js +1122 -49
  21. package/dist/commands/enable-agent.js +1 -0
  22. package/dist/commands/export.js +280 -22
  23. package/dist/commands/handoff.js +33 -0
  24. package/dist/commands/harvest.js +189 -0
  25. package/dist/commands/hooks.js +82 -25
  26. package/dist/commands/inbox.js +169 -0
  27. package/dist/commands/init.js +38 -31
  28. package/dist/commands/install-hooks.js +71 -44
  29. package/dist/commands/link.js +89 -0
  30. package/dist/commands/list-claims.js +48 -3
  31. package/dist/commands/list-plans.js +129 -25
  32. package/dist/commands/loops-handlers.js +409 -0
  33. package/dist/commands/mcp-read-handlers.js +1628 -0
  34. package/dist/commands/mcp-schemas.generated.js +74 -0
  35. package/dist/commands/mcp.js +4244 -1475
  36. package/dist/commands/plan-resource.js +64 -0
  37. package/dist/commands/plan.js +12 -26
  38. package/dist/commands/prune.js +37 -2
  39. package/dist/commands/reflect.js +20 -7
  40. package/dist/commands/release-claim.js +11 -6
  41. package/dist/commands/release-notes.js +170 -0
  42. package/dist/commands/repair.js +210 -0
  43. package/dist/commands/run-profile.js +57 -0
  44. package/dist/commands/sequence.js +113 -0
  45. package/dist/commands/session-end.js +423 -14
  46. package/dist/commands/session-start.js +214 -41
  47. package/dist/commands/setup-security.js +103 -0
  48. package/dist/commands/setup.js +42 -4
  49. package/dist/commands/stale.js +109 -0
  50. package/dist/commands/switch.js +131 -10
  51. package/dist/commands/trap.js +14 -31
  52. package/dist/commands/update-handoff.js +63 -4
  53. package/dist/commands/update-plan.js +21 -28
  54. package/dist/commands/update-step.js +37 -0
  55. package/dist/commands/upgrade.js +313 -6
  56. package/dist/commands/usage.js +102 -0
  57. package/dist/commands/version.js +20 -0
  58. package/dist/commands/who.js +124 -0
  59. package/dist/commands/worktree.js +105 -0
  60. package/dist/core/actions.js +315 -0
  61. package/dist/core/agent-capability.js +610 -17
  62. package/dist/core/agent-context.js +7 -1
  63. package/dist/core/agent-files.js +1169 -85
  64. package/dist/core/agent-integrations.js +160 -5
  65. package/dist/core/agent-inventory.js +2 -0
  66. package/dist/core/agent-profiles.js +93 -0
  67. package/dist/core/agent-registry.js +162 -30
  68. package/dist/core/agentrun-reconciler.js +345 -0
  69. package/dist/core/agentruns.js +424 -0
  70. package/dist/core/ai-agent-detection.js +31 -10
  71. package/dist/core/archival.js +77 -0
  72. package/dist/core/assignment-sweeper.js +82 -0
  73. package/dist/core/assignments.js +367 -0
  74. package/dist/core/audit.js +30 -0
  75. package/dist/core/bootstrap.js +61 -10
  76. package/dist/core/brainclaw-version.js +94 -2
  77. package/dist/core/candidates.js +93 -2
  78. package/dist/core/claims.js +419 -0
  79. package/dist/core/codev-metrics.js +77 -0
  80. package/dist/core/codev-personas.js +31 -0
  81. package/dist/core/codev-plan-gen.js +35 -0
  82. package/dist/core/codev-prompts.js +74 -0
  83. package/dist/core/codev-responses.js +62 -0
  84. package/dist/core/codev-rounds.js +218 -0
  85. package/dist/core/config.js +4 -0
  86. package/dist/core/context.js +454 -34
  87. package/dist/core/coordination.js +201 -6
  88. package/dist/core/cross-project.js +230 -16
  89. package/dist/core/default-profiles/doctor.yaml +11 -0
  90. package/dist/core/default-profiles/janitor.yaml +11 -0
  91. package/dist/core/default-profiles/onboarder.yaml +11 -0
  92. package/dist/core/default-profiles/reviewer.yaml +13 -0
  93. package/dist/core/dispatcher.js +1189 -0
  94. package/dist/core/duplicates.js +2 -2
  95. package/dist/core/entity-operations.js +450 -0
  96. package/dist/core/entity-registry.js +344 -0
  97. package/dist/core/event-log.js +1 -0
  98. package/dist/core/events.js +106 -2
  99. package/dist/core/execution-adapters.js +154 -0
  100. package/dist/core/execution-context.js +63 -0
  101. package/dist/core/execution-profile.js +270 -0
  102. package/dist/core/execution.js +255 -0
  103. package/dist/core/facade-schema.js +81 -0
  104. package/dist/core/federation-cloud.js +99 -0
  105. package/dist/core/federation-message.js +52 -0
  106. package/dist/core/federation-transport.js +65 -0
  107. package/dist/core/gc-semantic.js +482 -0
  108. package/dist/core/governance.js +247 -0
  109. package/dist/core/guards.js +19 -0
  110. package/dist/core/ideation.js +72 -0
  111. package/dist/core/identity.js +252 -28
  112. package/dist/core/ids.js +6 -0
  113. package/dist/core/input-validation.js +2 -2
  114. package/dist/core/instruction-templates.js +344 -136
  115. package/dist/core/io.js +90 -11
  116. package/dist/core/lock.js +6 -2
  117. package/dist/core/loops/brief-assembly.js +213 -0
  118. package/dist/core/loops/facade-schema.js +148 -0
  119. package/dist/core/loops/index.js +7 -0
  120. package/dist/core/loops/iteration-engine.js +139 -0
  121. package/dist/core/loops/lock.js +385 -0
  122. package/dist/core/loops/store.js +201 -0
  123. package/dist/core/loops/types.js +403 -0
  124. package/dist/core/loops/verbs.js +534 -0
  125. package/dist/core/markdown.js +15 -3
  126. package/dist/core/memory-compactor.js +432 -0
  127. package/dist/core/memory-git.js +152 -8
  128. package/dist/core/messaging.js +278 -0
  129. package/dist/core/migration.js +32 -1
  130. package/dist/core/mutation-pipeline.js +4 -2
  131. package/dist/core/operations/memory-mutation.js +129 -0
  132. package/dist/core/operations/memory-write.js +78 -0
  133. package/dist/core/operations/plan.js +190 -0
  134. package/dist/core/policy.js +169 -0
  135. package/dist/core/repo-analysis.js +67 -0
  136. package/dist/core/reputation.js +9 -3
  137. package/dist/core/schema.js +546 -21
  138. package/dist/core/search.js +21 -2
  139. package/dist/core/security-cache.js +71 -0
  140. package/dist/core/security-guard.js +152 -0
  141. package/dist/core/security-scoring.js +86 -0
  142. package/dist/core/sequence.js +130 -0
  143. package/dist/core/socket-client.js +113 -0
  144. package/dist/core/staleness.js +246 -0
  145. package/dist/core/state.js +98 -22
  146. package/dist/core/store-resolution.js +54 -12
  147. package/dist/core/toml-writer.js +76 -0
  148. package/dist/core/upgrades/backup.js +232 -0
  149. package/dist/core/upgrades/health-check.js +169 -0
  150. package/dist/core/upgrades/patches/candidate-archive.js +145 -0
  151. package/dist/core/upgrades/patches/handoff-review-strip.js +128 -0
  152. package/dist/core/upgrades/patches/provenance-rollout.js +136 -0
  153. package/dist/core/upgrades/schema-version.js +97 -0
  154. package/dist/core/worktree.js +606 -0
  155. package/dist/facts.js +114 -0
  156. package/dist/facts.json +111 -0
  157. package/docs/architecture/project-refs.md +5 -1
  158. package/docs/cli.md +690 -43
  159. package/docs/concepts/ideation-loop.md +317 -0
  160. package/docs/concepts/loop-engine.md +456 -0
  161. package/docs/concepts/mcp-governance.md +268 -0
  162. package/docs/concepts/memory-staleness.md +122 -0
  163. package/docs/concepts/multi-agent-workflows.md +166 -0
  164. package/docs/concepts/plans-and-claims.md +31 -6
  165. package/docs/concepts/project-md-convention.md +35 -0
  166. package/docs/concepts/troubleshooting.md +220 -0
  167. package/docs/concepts/upgrade-cli.md +202 -0
  168. package/docs/concepts/upgrade-dogfood-procedure.md +114 -0
  169. package/docs/context-format-changelog.md +2 -2
  170. package/docs/context-format.md +2 -2
  171. package/docs/index.md +68 -0
  172. package/docs/integrations/agents.md +15 -16
  173. package/docs/integrations/cline.md +88 -0
  174. package/docs/integrations/codex.md +75 -23
  175. package/docs/integrations/continue.md +60 -0
  176. package/docs/integrations/copilot.md +67 -9
  177. package/docs/integrations/kilocode.md +72 -0
  178. package/docs/integrations/mcp.md +304 -21
  179. package/docs/integrations/mistral-vibe.md +122 -0
  180. package/docs/integrations/opencode.md +84 -0
  181. package/docs/integrations/overview.md +23 -8
  182. package/docs/integrations/roo.md +74 -0
  183. package/docs/integrations/windsurf.md +83 -0
  184. package/docs/mcp-schema-changelog.md +191 -1
  185. package/docs/playbooks/integration/index.md +121 -0
  186. package/docs/playbooks/productivity/index.md +102 -0
  187. package/docs/playbooks/team/index.md +122 -0
  188. package/docs/product/agent-first-model.md +184 -0
  189. package/docs/product/entity-model-audit.md +462 -0
  190. package/docs/quickstart-existing-project.md +135 -0
  191. package/docs/quickstart.md +124 -37
  192. package/docs/release-maintenance.md +79 -0
  193. package/docs/review.md +2 -0
  194. package/docs/server-operations.md +118 -0
  195. package/package.json +20 -12
  196. package/dist/commands/claude-desktop-extension.js +0 -18
  197. package/dist/commands/diff.js +0 -99
  198. package/dist/core/claude-desktop-extension.js +0 -224
@@ -16,23 +16,26 @@ alwaysApply: true
16
16
 
17
17
  # Brainclaw session bootstrap
18
18
 
19
- **At the start of every session, before doing anything else:**
19
+ Brainclaw is the shared coordination layer for this project. Use its MCP facades first — the CLI is only a fallback when MCP is unavailable.
20
20
 
21
- \`\`\`bash
22
- brainclaw context
23
- \`\`\`
21
+ ## At the start of every session
24
22
 
25
- This loads the shared project memory: active constraints, recent decisions, known traps,
26
- open plan items, active claims, and the last handoff.
23
+ Call \`bclaw_work(intent)\` it handles session setup, context load, and scope claim in a single call.
27
24
 
28
- **Before finishing any session:**
25
+ - \`bclaw_work(intent: "resume")\` when continuing an existing task.
26
+ - \`bclaw_work(intent: "execute", scope: "<path>", task: "<text>")\` when starting new work on a specific scope.
27
+ - \`bclaw_work(intent: "consult")\` to read context without claiming.
29
28
 
30
- \`\`\`bash
31
- brainclaw claim release <id> # release claims you opened
32
- brainclaw plan update <id> --status done # close plan items you completed
33
- # or in one shot:
34
- brainclaw session-end --auto-release
35
- \`\`\`
29
+ ## To coordinate with other agents
30
+
31
+ \`bclaw_coordinate(intent)\` \`assign\`, \`consult\`, \`review\`, or \`reroute\`.
32
+
33
+ ## Before finishing
34
+
35
+ - Release your claims: \`bclaw_release_claim(id)\`.
36
+ - Close out the session: \`bclaw_session_end\` (or let it auto-release via the session hook).
37
+
38
+ CLI fallback only: \`brainclaw context\` / \`brainclaw session-end --auto-release\` if MCP is not reachable.
36
39
  `;
37
40
  }
38
41
  /**
@@ -46,23 +49,53 @@ export function generateWindsurfHook(projectName) {
46
49
 
47
50
  ## SESSION START (always run first)
48
51
 
49
- Before responding to any request, execute:
52
+ Call the Brainclaw MCP facade before responding to any request:
50
53
 
51
- \`\`\`bash
52
- brainclaw context
53
- \`\`\`
54
+ - \`bclaw_work(intent: "resume")\` when continuing an existing task.
55
+ - \`bclaw_work(intent: "execute", scope: "<path>", task: "<text>")\` when starting new work on a specific scope.
56
+ - \`bclaw_work(intent: "consult")\` to read context without claiming.
54
57
 
55
- This gives you: active constraints, recent decisions, known traps, open plans, active claims,
56
- and the last handoff note. Do not skip this step.
58
+ This returns active constraints, recent decisions, known traps, open plans, active claims, and the last handoff. Do not skip.
59
+
60
+ ## COORDINATION
61
+
62
+ \`bclaw_coordinate(intent)\` to assign, consult, review, or reroute other agents.
57
63
 
58
64
  ## SESSION END (before finishing)
59
65
 
60
- \`\`\`bash
61
- brainclaw claim release <id> # for each claim you hold
62
- brainclaw plan update <id> --status done # for each plan item you completed
63
- # or:
64
- brainclaw session-end --auto-release
65
- \`\`\`
66
+ - \`bclaw_release_claim(id)\` for each claim you hold.
67
+ - \`bclaw_session_end\` to close the session (auto-releases remaining claims).
68
+
69
+ CLI fallback only when MCP is unavailable: \`brainclaw context\` / \`brainclaw session-end --auto-release\`.
70
+ `;
71
+ }
72
+ /**
73
+ * Generate a generic markdown session-trigger section.
74
+ */
75
+ export function generateMarkdownHook(agentName, projectName) {
76
+ return `# Brainclaw session trigger — ${projectName}
77
+ # This block is always active. ${agentName} reads this file on every activation.
78
+
79
+ ## SESSION START (always run first)
80
+
81
+ Call the Brainclaw MCP facade before responding to any request:
82
+
83
+ - \`bclaw_work(intent: "resume")\` when continuing an existing task.
84
+ - \`bclaw_work(intent: "execute", scope: "<path>", task: "<text>")\` when starting new work on a specific scope.
85
+ - \`bclaw_work(intent: "consult")\` to read context without claiming.
86
+
87
+ This returns active constraints, recent decisions, known traps, open plans, active claims, and the last handoff. Do not skip.
88
+
89
+ ## COORDINATION
90
+
91
+ \`bclaw_coordinate(intent)\` to assign, consult, review, or reroute other agents.
92
+
93
+ ## SESSION END (before finishing)
94
+
95
+ - \`bclaw_release_claim(id)\` for each claim you hold.
96
+ - \`bclaw_session_end\` to close the session (auto-releases remaining claims).
97
+
98
+ CLI fallback only when MCP is unavailable: \`brainclaw context\` / \`brainclaw session-end --auto-release\`.
66
99
  `;
67
100
  }
68
101
  export function writeHook(content, relativePath, cwd) {
@@ -108,6 +141,18 @@ export function runHooks(options = {}) {
108
141
  created: autoResult.created,
109
142
  });
110
143
  }
144
+ if (target === 'cline' || target === 'all') {
145
+ const content = generateMarkdownHook('Cline', config.project_name);
146
+ results.push(writeHook(content, '.clinerules/brainclaw.md', cwd));
147
+ }
148
+ if (target === 'codex' || target === 'all') {
149
+ const content = generateMarkdownHook('Codex', config.project_name);
150
+ results.push(writeHook(content, 'AGENTS.md', cwd));
151
+ }
152
+ if (target === 'github-copilot' || target === 'all') {
153
+ const content = generateMarkdownHook('GitHub Copilot', config.project_name);
154
+ results.push(writeHook(content, '.github/copilot-instructions.md', cwd));
155
+ }
111
156
  for (const r of results) {
112
157
  console.log(`✔ Hook written to ${r.relativePath} (${r.created ? 'created' : 'updated'})`);
113
158
  }
@@ -134,6 +179,18 @@ export function writeDetectedAgentHooks(agentName, projectName, cwd) {
134
179
  created: autoResult.created,
135
180
  });
136
181
  }
182
+ if (agentName === 'cline') {
183
+ const content = generateMarkdownHook('Cline', projectName);
184
+ results.push(writeHook(content, '.clinerules/brainclaw.md', cwd));
185
+ }
186
+ if (agentName === 'codex') {
187
+ const content = generateMarkdownHook('Codex', projectName);
188
+ results.push(writeHook(content, 'AGENTS.md', cwd));
189
+ }
190
+ if (agentName === 'github-copilot') {
191
+ const content = generateMarkdownHook('GitHub Copilot', projectName);
192
+ results.push(writeHook(content, '.github/copilot-instructions.md', cwd));
193
+ }
137
194
  return results;
138
195
  }
139
196
  //# sourceMappingURL=hooks.js.map
@@ -0,0 +1,169 @@
1
+ /**
2
+ * CLI command: brainclaw inbox
3
+ *
4
+ * Subcommands:
5
+ * brainclaw inbox — list pending messages
6
+ * brainclaw inbox --all — list all messages
7
+ * brainclaw inbox ack <id> — acknowledge a message
8
+ * brainclaw inbox send <to> <text> — send a message
9
+ *
10
+ * @module
11
+ */
12
+ import { memoryExists } from '../core/io.js';
13
+ import { readInbox, ackMessage, archiveMessage, sendMessage, getThread } from '../core/messaging.js';
14
+ import { resolveCurrentAgentName } from '../core/agent-registry.js';
15
+ import { resolveStoreChain } from '../core/store-resolution.js';
16
+ export function runInboxList(options) {
17
+ const cwd = options.cwd;
18
+ if (!memoryExists(cwd)) {
19
+ console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
20
+ process.exit(1);
21
+ }
22
+ const effectiveCwd = cwd ?? process.cwd();
23
+ const agent = options.agent ?? resolveCurrentAgentName(effectiveCwd) ?? 'unknown';
24
+ const status = options.all ? undefined : options.status ?? 'pending';
25
+ const msgType = options.type;
26
+ const threadId = options.thread;
27
+ let messages;
28
+ if (options.localOnly) {
29
+ const result = readInbox({ agent, status, type: msgType, thread_id: threadId, markAsRead: false }, effectiveCwd);
30
+ messages = result.messages;
31
+ }
32
+ else {
33
+ const chain = resolveStoreChain(effectiveCwd);
34
+ const seenIds = new Set();
35
+ messages = [];
36
+ for (const store of chain) {
37
+ try {
38
+ // Fetch all messages from this store (no pagination limit)
39
+ const storeResult = readInbox({ agent, status, type: msgType, thread_id: threadId, markAsRead: false, limit: 1_000_000 }, store.cwd);
40
+ for (const msg of storeResult.messages) {
41
+ if (!seenIds.has(msg.id)) {
42
+ seenIds.add(msg.id);
43
+ messages.push(msg);
44
+ }
45
+ }
46
+ }
47
+ catch { /* skip unreadable stores */ }
48
+ }
49
+ // Fallback when no chain found
50
+ if (messages.length === 0 && chain.length === 0) {
51
+ const result = readInbox({ agent, status, type: msgType, thread_id: threadId, markAsRead: false }, effectiveCwd);
52
+ messages = result.messages;
53
+ }
54
+ }
55
+ const total = messages.length;
56
+ if (options.json) {
57
+ console.log(JSON.stringify({ total, offset: 0, limit: total, messages }, null, 2));
58
+ return;
59
+ }
60
+ const label = status ? `${status} messages` : 'all messages';
61
+ console.log(`\n📬 Inbox for ${agent} — ${total} ${label}\n`);
62
+ if (messages.length === 0) {
63
+ console.log(' (no messages)');
64
+ }
65
+ for (const msg of messages) {
66
+ const ack = msg.requires_ack ? ' [ACK required]' : '';
67
+ const thread = msg.thread_id ? ` thread:${msg.thread_id}` : '';
68
+ const ref = msg.ref ? ` ref:${msg.ref}` : '';
69
+ console.log(` [${msg.short_label ?? msg.id}] ${msg.type} from ${msg.from} (${msg.status})${ack}${thread}${ref}`);
70
+ console.log(` ${msg.text.slice(0, 120)}${msg.text.length > 120 ? '...' : ''}`);
71
+ console.log('');
72
+ }
73
+ }
74
+ export function runInboxAck(messageId, options) {
75
+ const cwd = options.cwd;
76
+ if (!memoryExists(cwd)) {
77
+ console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
78
+ process.exit(1);
79
+ }
80
+ const effectiveCwd = cwd ?? process.cwd();
81
+ const agent = options.agent ?? resolveCurrentAgentName(effectiveCwd) ?? 'unknown';
82
+ try {
83
+ const result = ackMessage(messageId, agent, effectiveCwd);
84
+ if (options.json) {
85
+ console.log(JSON.stringify(result, null, 2));
86
+ }
87
+ else {
88
+ console.log(`✔ Message acknowledged: [${result.id}]`);
89
+ }
90
+ }
91
+ catch (err) {
92
+ console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
93
+ process.exit(1);
94
+ }
95
+ }
96
+ export function runInboxArchive(messageId, options) {
97
+ const cwd = options.cwd;
98
+ if (!memoryExists(cwd)) {
99
+ console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
100
+ process.exit(1);
101
+ }
102
+ const effectiveCwd = cwd ?? process.cwd();
103
+ const agent = options.agent ?? resolveCurrentAgentName(effectiveCwd) ?? 'unknown';
104
+ try {
105
+ const result = archiveMessage(messageId, agent, effectiveCwd);
106
+ if (options.json) {
107
+ console.log(JSON.stringify(result, null, 2));
108
+ }
109
+ else {
110
+ console.log(`✔ Message archived: [${result.id}]`);
111
+ }
112
+ }
113
+ catch (err) {
114
+ console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
115
+ process.exit(1);
116
+ }
117
+ }
118
+ export function runInboxSend(to, text, options) {
119
+ const cwd = options.cwd;
120
+ if (!memoryExists(cwd)) {
121
+ console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
122
+ process.exit(1);
123
+ }
124
+ const effectiveCwd = cwd ?? process.cwd();
125
+ const from = options.agent ?? resolveCurrentAgentName(effectiveCwd) ?? 'unknown';
126
+ const msgType = (options.type ?? 'info');
127
+ try {
128
+ const result = sendMessage({
129
+ from,
130
+ to,
131
+ type: msgType,
132
+ text,
133
+ ref: options.ref,
134
+ scope: options.scope,
135
+ thread_id: options.thread,
136
+ requires_ack: options.ack,
137
+ }, effectiveCwd);
138
+ if (options.json) {
139
+ console.log(JSON.stringify(result, null, 2));
140
+ }
141
+ else {
142
+ console.log(`✔ Message sent: [${result.shortLabel}] ${result.type} → ${result.to}`);
143
+ }
144
+ }
145
+ catch (err) {
146
+ console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
147
+ process.exit(1);
148
+ }
149
+ }
150
+ export function runInboxThread(threadId, options) {
151
+ const cwd = options.cwd;
152
+ if (!memoryExists(cwd)) {
153
+ console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
154
+ process.exit(1);
155
+ }
156
+ const effectiveCwd = cwd ?? process.cwd();
157
+ const messages = getThread(threadId, effectiveCwd);
158
+ if (options.json) {
159
+ console.log(JSON.stringify({ thread_id: threadId, total: messages.length, messages }, null, 2));
160
+ return;
161
+ }
162
+ console.log(`\nThread ${threadId} — ${messages.length} message(s)\n`);
163
+ for (const msg of messages) {
164
+ console.log(` [${msg.short_label ?? msg.id}] ${msg.from} → ${msg.to} (${msg.type}, ${msg.status})`);
165
+ console.log(` ${msg.text.slice(0, 120)}${msg.text.length > 120 ? '...' : ''}`);
166
+ console.log('');
167
+ }
168
+ }
169
+ //# sourceMappingURL=inbox.js.map
@@ -12,7 +12,7 @@ import { scanProject, upsertProject } from '../core/global-registry.js';
12
12
  import { analyzeRepository, scanWorkspaceBoundaries } from '../core/repo-analysis.js';
13
13
  import { renderBootstrapSummary, runBootstrapProfile } from '../core/bootstrap.js';
14
14
  import { isAgentIntegrationName, upsertAgentIntegrationDeclaration } from '../core/agent-integrations.js';
15
- import { describeAutoConfigWrite, ensureAgentFiles, ensureGitignoreEntries, writeDetectedAgentAutoConfig } from '../core/agent-files.js';
15
+ import { BRAINCLAW_EXCLUSIVE_DIRECTORIES, describeAutoConfigWrite, ensureAgentFiles, ensureGitignoreEntries, writeDetectedAgentAutoConfig } from '../core/agent-files.js';
16
16
  import { detectAiAgent, detectWslEnvironment } from '../core/ai-agent-detection.js';
17
17
  import { buildAiSurfaceInventory, renderAiSurfaceUsageHints } from '../core/ai-surface-inventory.js';
18
18
  import { ensureUserStore, hasCompletedSetup } from '../core/setup-state.js';
@@ -61,6 +61,8 @@ export async function runInit(options = {}) {
61
61
  const topology = resolveTopology(options.topology);
62
62
  const ignoreStrategy = topology === 'embedded' ? 'none' : 'project-gitignore';
63
63
  const skipAgentBootstrap = options.skipAgentBootstrap === true || process.env.BRAINCLAW_SKIP_AGENT_BOOTSTRAP === '1';
64
+ const testMode = process.env.BRAINCLAW_TEST_MODE === '1';
65
+ const skipAiSurfaceScan = testMode || options.noAiScan === true || options.aiScan === false;
64
66
  if (memoryExists(cwd) && !options.force) {
65
67
  console.error('Error: project memory already exists. Use --force to overwrite.');
66
68
  process.exit(1);
@@ -165,10 +167,11 @@ export async function runInit(options = {}) {
165
167
  // Add agent instruction files to .gitignore (they are generated, not source)
166
168
  if (!skipAgentBootstrap) {
167
169
  const generatedWorkspacePaths = detectedAutoConfig
170
+ .filter((item) => item.kind !== 'recommendation')
168
171
  .map((item) => item.relativePath)
169
172
  .filter((item) => item !== undefined)
170
173
  .filter((item) => !item.startsWith('.codeium/'));
171
- ensureGitignoreEntries(cwd, ['AGENTS.md', '.github/copilot-instructions.md', ...generatedWorkspacePaths]);
174
+ ensureGitignoreEntries(cwd, ['AGENTS.md', '.github/copilot-instructions.md', ...generatedWorkspacePaths, ...BRAINCLAW_EXCLUSIVE_DIRECTORIES]);
172
175
  }
173
176
  console.log(`✔ Initialized project memory in ${storageDir}/`);
174
177
  console.log('✔ Created project.md, config.yaml, and split state directories');
@@ -180,17 +183,19 @@ export async function runInit(options = {}) {
180
183
  if (detectedExport) {
181
184
  console.log(`\u2714 Agent instructions written to ${detectedExport.relativePath} (${detectedExport.created ? 'created' : 'updated'})`);
182
185
  }
183
- const visibleSurfaces = buildAiSurfaceInventory().filter((surface) => surface.status !== 'not_detected');
184
- if (visibleSurfaces.length > 0) {
185
- console.log('✔ Other AI work surfaces detected on this machine:');
186
- for (const surface of visibleSurfaces) {
187
- console.log(` - ${surface.display_name} [${surface.surface_kind}, ${surface.status}]`);
188
- }
189
- const usageHints = renderAiSurfaceUsageHints(visibleSurfaces);
190
- if (usageHints.length > 0) {
191
- console.log(' Suggested uses:');
192
- for (const line of usageHints) {
193
- console.log(` ${line}`);
186
+ if (!skipAiSurfaceScan) {
187
+ const visibleSurfaces = buildAiSurfaceInventory().filter((surface) => surface.status !== 'not_detected');
188
+ if (visibleSurfaces.length > 0) {
189
+ console.log('✔ Other AI work surfaces detected on this machine:');
190
+ for (const surface of visibleSurfaces) {
191
+ console.log(` - ${surface.display_name} [${surface.surface_kind}, ${surface.status}]`);
192
+ }
193
+ const usageHints = renderAiSurfaceUsageHints(visibleSurfaces);
194
+ if (usageHints.length > 0) {
195
+ console.log(' Suggested uses:');
196
+ for (const line of usageHints) {
197
+ console.log(` ${line}`);
198
+ }
194
199
  }
195
200
  }
196
201
  }
@@ -247,25 +252,27 @@ export async function runInit(options = {}) {
247
252
  }
248
253
  // Install post-merge hook for auto-release of claims after merge
249
254
  installPostMergeHookIfMissing(cwd);
250
- const onboardingPreflight = runBootstrapProfile({ cwd, refresh: true });
251
- console.log('');
252
- console.log('Onboarding preflight:');
253
- for (const line of renderBootstrapSummary(onboardingPreflight).split('\n')) {
254
- console.log(` ${line}`);
255
- }
256
- if (onboardingPreflight.importPlan.suggestion_count > 0) {
257
- console.log('');
258
- console.log(`Next step: run 'brainclaw bootstrap --apply' to import ${onboardingPreflight.importPlan.suggestion_count} suggested item(s) into canonical memory.`);
259
- console.log(`Rollback: run 'brainclaw bootstrap --uninstall' to deactivate the last bootstrap-managed import.`);
260
- }
261
- if ((onboardingPreflight.importPlan.interview?.question_count ?? 0) > 0) {
262
- console.log('');
263
- console.log(`Interview: run 'brainclaw bootstrap --interview --audience cli' for terminal agents or '--audience ide_chat' for IDE chat agents.`);
264
- console.log(`Apply confirmed answers: write a JSON answers file and run 'brainclaw bootstrap --answers-file <path> --apply'.`);
265
- }
266
- else if ((onboardingPreflight.profile.gaps?.length ?? 0) > 0) {
255
+ if (!testMode) {
256
+ const onboardingPreflight = runBootstrapProfile({ cwd, refresh: true });
267
257
  console.log('');
268
- console.log(`Next step: review the onboarding gaps, then use 'brainclaw bootstrap --json' as the basis for an interview/import flow.`);
258
+ console.log('Onboarding preflight:');
259
+ for (const line of renderBootstrapSummary(onboardingPreflight).split('\n')) {
260
+ console.log(` ${line}`);
261
+ }
262
+ if (onboardingPreflight.importPlan.suggestion_count > 0) {
263
+ console.log('');
264
+ console.log(`Next step: run 'brainclaw bootstrap --apply' to import ${onboardingPreflight.importPlan.suggestion_count} suggested item(s) into canonical memory.`);
265
+ console.log(`Rollback: run 'brainclaw bootstrap --uninstall' to deactivate the last bootstrap-managed import.`);
266
+ }
267
+ if ((onboardingPreflight.importPlan.interview?.question_count ?? 0) > 0) {
268
+ console.log('');
269
+ console.log(`Interview: run 'brainclaw bootstrap --interview --audience cli' for terminal agents or '--audience ide_chat' for IDE chat agents.`);
270
+ console.log(`Apply confirmed answers: write a JSON answers file and run 'brainclaw bootstrap --answers-file <path> --apply'.`);
271
+ }
272
+ else if ((onboardingPreflight.profile.gaps?.length ?? 0) > 0) {
273
+ console.log('');
274
+ console.log(`Next step: review the onboarding gaps, then use 'brainclaw bootstrap --json' as the basis for an interview/import flow.`);
275
+ }
269
276
  }
270
277
  console.log('');
271
278
  console.log(`Tip: run 'brainclaw context --json' to load the shared memory into your agent session.`);
@@ -31,6 +31,54 @@ export function runInstallHooks(options = {}) {
31
31
  console.log(`✔ post-merge hook installed at ${postMergePath}`);
32
32
  console.log(' Auto-releases claims whose scope was touched by the merge.');
33
33
  }
34
+ // Claude Code preToolUse hook (claim-warning)
35
+ const claudeHookPath = path.join(hooksDir, 'claude-pre-tool.sh');
36
+ if (!fs.existsSync(claudeHookPath) || options.force) {
37
+ fs.writeFileSync(claudeHookPath, generateClaudePreToolScript(), { encoding: 'utf-8', mode: 0o755 });
38
+ console.log(`✔ Claude Code preToolUse hook generated at ${claudeHookPath}`);
39
+ console.log(' To activate, add to .claude/settings.json hooks: { "PreToolUse": ".git/hooks/claude-pre-tool.sh" }');
40
+ }
41
+ }
42
+ function generateClaudePreToolScript() {
43
+ return `#!/bin/sh
44
+ # brainclaw Claude Code preToolUse hook
45
+ # Generated by: brainclaw install-hooks
46
+ exec node -e "
47
+ const fs = require('fs');
48
+ const path = require('path');
49
+ const { execSync } = require('child_process');
50
+
51
+ const toolName = process.env.CLAUDE_TOOL_NAME || process.argv[2] || process.env.TOOL_NAME || '';
52
+ const isWrite = /edit|write|replace|bash|str_replace/i.test(toolName);
53
+
54
+ if (!isWrite || !toolName) process.exit(0);
55
+
56
+ try {
57
+ const BCLAW_CMD = fs.existsSync(path.join(process.cwd(), 'node_modules', '.bin', 'brainclaw'))
58
+ ? 'npx brainclaw' : 'brainclaw';
59
+ const out = execSync(BCLAW_CMD + ' claim list --json', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] });
60
+ const claims = JSON.parse(out);
61
+ if (claims && claims.length > 0) process.exit(0);
62
+ } catch (e) {
63
+ // ignore if brainclaw not found or fails
64
+ process.exit(0);
65
+ }
66
+
67
+ const sessionMark = path.join(process.cwd(), '.brainclaw', 'tmp', 'claude_warned');
68
+ if (!fs.existsSync(path.dirname(sessionMark))) fs.mkdirSync(path.dirname(sessionMark), { recursive: true });
69
+
70
+ if (fs.existsSync(sessionMark)) {
71
+ const mtime = fs.statSync(sessionMark).mtimeMs;
72
+ if (Date.now() - mtime < 2 * 60 * 60 * 1000) {
73
+ process.exit(0); // already warned this session
74
+ }
75
+ }
76
+ fs.writeFileSync(sessionMark, Date.now().toString());
77
+
78
+ process.stderr.write('\\n[Brainclaw] ⚠️ WARNING: You are about to use an Edit/Write tool (' + toolName + ') but you have NO active claim.\\n');
79
+ process.stderr.write('[Brainclaw] Consider running \\\`brainclaw claim create <scope>\\\` to lock your work and avoid conflicts.\\n\\n');
80
+ " 2>&1 || exit 0
81
+ `;
34
82
  }
35
83
  function generatePostMergeScript() {
36
84
  return `#!/bin/sh
@@ -48,6 +96,7 @@ else
48
96
  fi
49
97
 
50
98
  $BCLAW_CMD release-claims --from-git-diff 2>/dev/null || true
99
+ $BCLAW_CMD worktree clean 2>/dev/null || true
51
100
  `;
52
101
  }
53
102
  function findGitRoot(cwd) {
@@ -62,54 +111,32 @@ function findGitRoot(cwd) {
62
111
  }
63
112
  }
64
113
  function generateHookScript() {
114
+ // Use node directly to avoid sh.exe pipe issues on Windows (SIGPIPE).
115
+ // The script is a self-contained node -e that runs both checks.
65
116
  return `#!/bin/sh
66
- # brainclaw pre-commit hook
67
- # 1. Blocks commits if sensitive content is detected in .brainclaw/
68
- # 2. Blocks commits if staged files are covered by an active constraint
69
- # Generated by: brainclaw install-hooks
117
+ # brainclaw pre-commit hook — generated by brainclaw install-hooks
118
+ # Runs via node to avoid sh.exe SIGPIPE issues on Windows.
119
+ exec node -e "
120
+ const { execSync } = require('child_process');
121
+ const staged = execSync('git diff --cached --name-only', { encoding: 'utf-8' }).trim();
122
+ if (!staged) process.exit(0);
70
123
 
71
- if ! command -v node >/dev/null 2>&1; then
72
- echo "brainclaw hook: node not found, skipping check."
73
- exit 0
74
- fi
75
-
76
- BCLAW_CMD=""
77
- if command -v brainclaw >/dev/null 2>&1; then
78
- BCLAW_CMD="brainclaw"
79
- elif command -v bclaw >/dev/null 2>&1; then
80
- BCLAW_CMD="bclaw"
81
- else
82
- BCLAW_CMD="npx --no brainclaw"
83
- fi
84
-
85
- # Check 1: sensitive content in .brainclaw/
86
- RESULT=$($BCLAW_CMD doctor --json 2>/dev/null) || {
87
- echo "brainclaw hook: could not run doctor check, skipping."
88
- exit 0
124
+ // Check 1: reject staged .brainclaw/ files
125
+ const brainclawFiles = staged.split('\\\\n').filter(f => f.startsWith('.brainclaw/'));
126
+ if (brainclawFiles.length > 0) {
127
+ process.stderr.write('\\\\nbrainclaw: .brainclaw/ files are staged — blocked.\\\\n');
128
+ brainclawFiles.forEach(f => process.stderr.write(' ' + f + '\\\\n'));
129
+ process.stderr.write(' Fix: git reset HEAD .brainclaw/\\\\n\\\\n');
130
+ process.exit(1);
89
131
  }
90
132
 
91
- echo "$RESULT" | node -e "
92
- const chunks = [];
93
- process.stdin.on('data', d => chunks.push(d));
94
- process.stdin.on('end', () => {
95
- try {
96
- const data = JSON.parse(chunks.join(''));
97
- const issues = (data.checks || []).filter(c =>
98
- (c.name === 'state_security' || c.name === 'candidate_security') &&
99
- c.status !== 'ok'
100
- );
101
- if (issues.length > 0) {
102
- process.stderr.write('\\nbrainclaw: sensitive content in .brainclaw/ — commit blocked.\\n');
103
- issues.forEach(c => process.stderr.write(' ⚠ ' + c.message + '\\n'));
104
- process.stderr.write(' Fix: review with \`brainclaw doctor\`\\n\\n');
105
- process.exit(1);
106
- }
107
- } catch (_) { /* skip parse errors */ }
108
- });
109
- " || exit 1
110
-
111
- # Check 2: active constraint violations on staged files
112
- $BCLAW_CMD check-constraints --staged 2>&1 || exit 1
133
+ // Check 2: active constraint violations
134
+ try {
135
+ execSync('brainclaw check-constraints --staged', { stdio: 'inherit' });
136
+ } catch (e) {
137
+ if (e.status) process.exit(e.status);
138
+ }
139
+ " 2>&1 || exit $?
113
140
  `;
114
141
  }
115
142
  //# sourceMappingURL=install-hooks.js.map
@@ -0,0 +1,89 @@
1
+ import { requireInitialized } from '../core/guards.js';
2
+ import { resolveTargetStore } from '../core/store-resolution.js';
3
+ import { addCrossProjectLink, removeCrossProjectLink, resolveCrossProjectLinks, } from '../core/cross-project.js';
4
+ export function runLink(subcommand, args, options = {}) {
5
+ const cwd = resolveTargetStore(options.cwd ?? process.cwd(), options.store ?? 'local');
6
+ requireInitialized(cwd);
7
+ switch (subcommand) {
8
+ case 'add': {
9
+ const target = args[0];
10
+ if (!target) {
11
+ console.error('Error: link add requires <path>');
12
+ console.error('Usage: brainclaw link add <path> [--name <slug>] [--role publisher|subscriber] [--channels candidate,handoff,runtime_note] [--force]');
13
+ process.exit(1);
14
+ }
15
+ try {
16
+ const link = addCrossProjectLink({
17
+ path: target,
18
+ name: options.name,
19
+ role: options.role,
20
+ channels: options.channels,
21
+ force: options.force,
22
+ cwd,
23
+ });
24
+ if (options.json) {
25
+ console.log(JSON.stringify(link, null, 2));
26
+ }
27
+ else {
28
+ console.log(`✔ Linked '${link.name ?? link.path}' (path=${link.path}, role=${link.role}${link.channels?.length ? `, channels=${link.channels.join(',')}` : ''})`);
29
+ }
30
+ }
31
+ catch (err) {
32
+ console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
33
+ process.exit(1);
34
+ }
35
+ break;
36
+ }
37
+ case 'list':
38
+ case 'ls': {
39
+ const links = resolveCrossProjectLinks(cwd);
40
+ if (options.json) {
41
+ console.log(JSON.stringify(links, null, 2));
42
+ return;
43
+ }
44
+ if (links.length === 0) {
45
+ console.log('No cross-project links configured.');
46
+ console.log('Add one with: brainclaw link add <path> [--role publisher|subscriber]');
47
+ return;
48
+ }
49
+ console.log(`\n${links.length} cross-project link(s):\n`);
50
+ for (const link of links) {
51
+ const availability = link.available ? '✓' : '✗ (target not initialised)';
52
+ const channels = link.channels?.length ? ` [${link.channels.join(',')}]` : '';
53
+ console.log(` ${link.projectName} ${availability}`);
54
+ console.log(` path: ${link.path}`);
55
+ console.log(` abs: ${link.absolutePath}`);
56
+ console.log(` role: ${link.role}${channels}`);
57
+ }
58
+ console.log('');
59
+ break;
60
+ }
61
+ case 'remove':
62
+ case 'rm': {
63
+ const target = args[0];
64
+ if (!target) {
65
+ console.error('Error: link remove requires <name|path>');
66
+ process.exit(1);
67
+ }
68
+ try {
69
+ const removed = removeCrossProjectLink(target, cwd);
70
+ if (options.json) {
71
+ console.log(JSON.stringify(removed, null, 2));
72
+ }
73
+ else {
74
+ console.log(`✔ Removed cross-project link '${removed.name ?? removed.path}'`);
75
+ }
76
+ }
77
+ catch (err) {
78
+ console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
79
+ process.exit(1);
80
+ }
81
+ break;
82
+ }
83
+ default:
84
+ console.error(`Unknown link subcommand: ${subcommand}`);
85
+ console.error('Usage: brainclaw link <add|list|remove> ...');
86
+ process.exit(1);
87
+ }
88
+ }
89
+ //# sourceMappingURL=link.js.map