brainclaw 1.9.0 → 1.9.1
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/README.md +585 -499
- package/dist/brainclaw-vscode.vsix +0 -0
- package/dist/commands/harvest.js +1 -1
- package/dist/commands/hooks.js +73 -73
- package/dist/commands/init.js +1 -1
- package/dist/commands/install-hooks.js +78 -78
- package/dist/commands/mcp-read-handlers.js +57 -14
- package/dist/commands/mcp.js +79 -13
- package/dist/commands/switch.js +26 -5
- package/dist/commands/version.js +1 -1
- package/dist/core/agent-capability.js +19 -4
- package/dist/core/agent-files.js +119 -119
- package/dist/core/codev-prompts.js +38 -38
- package/dist/core/default-profiles/doctor.yaml +11 -11
- package/dist/core/default-profiles/janitor.yaml +11 -11
- package/dist/core/default-profiles/onboarder.yaml +11 -11
- package/dist/core/default-profiles/reviewer.yaml +13 -13
- package/dist/core/dispatcher.js +1 -1
- package/dist/core/entity-operations.js +29 -3
- package/dist/core/execution.js +1 -1
- package/dist/core/loops/verbs.js +0 -1
- package/dist/core/messaging.js +2 -2
- package/dist/core/protocol-skills.js +164 -164
- package/dist/core/runtime-signals.js +1 -1
- package/dist/core/search.js +19 -2
- package/dist/core/security-guard.js +207 -207
- package/dist/core/spawn-check.js +16 -2
- package/dist/core/staleness.js +1 -1
- package/dist/core/store-resolution.js +26 -7
- package/dist/core/worktree.js +18 -18
- package/dist/facts.js +3 -3
- package/dist/facts.json +2 -2
- package/docs/PROTOCOL.md +1 -1
- package/docs/adapters/openclaw.md +43 -43
- package/docs/architecture/project-refs.md +328 -328
- package/docs/cli.md +2093 -2093
- package/docs/concepts/coordination.md +52 -52
- package/docs/concepts/coordinator-runbook.md +129 -129
- package/docs/concepts/dispatch-lifecycle.md +245 -245
- package/docs/concepts/event-log-store.md +928 -928
- package/docs/concepts/ideation-loop.md +317 -317
- package/docs/concepts/loop-engine.md +520 -511
- package/docs/concepts/mcp-governance.md +268 -268
- package/docs/concepts/memory.md +84 -84
- package/docs/concepts/multi-agent-workflows.md +167 -167
- package/docs/concepts/observer-protocol.md +361 -361
- package/docs/concepts/plans-and-claims.md +217 -217
- package/docs/concepts/project-md-convention.md +35 -35
- package/docs/concepts/runtime-notes.md +38 -38
- package/docs/concepts/troubleshooting.md +254 -254
- package/docs/concepts/workspace-bootstrapping.md +142 -142
- package/docs/context-format-changelog.md +35 -35
- package/docs/context-format.md +48 -48
- package/docs/index.md +65 -65
- package/docs/integrations/agents.md +158 -158
- package/docs/integrations/claude-code.md +23 -23
- package/docs/integrations/cline.md +77 -77
- package/docs/integrations/continue.md +55 -55
- package/docs/integrations/copilot.md +68 -68
- package/docs/integrations/cursor.md +23 -23
- package/docs/integrations/kilocode.md +72 -72
- package/docs/integrations/mcp.md +377 -377
- package/docs/integrations/mistral-vibe.md +122 -122
- package/docs/integrations/openclaw.md +92 -92
- package/docs/integrations/opencode.md +84 -84
- package/docs/integrations/overview.md +115 -115
- package/docs/integrations/roo.md +71 -71
- package/docs/integrations/windsurf.md +77 -77
- package/docs/mcp-schema-changelog.md +360 -356
- package/docs/playbooks/integration/index.md +121 -121
- package/docs/playbooks/orchestration.md +37 -0
- package/docs/playbooks/productivity/index.md +99 -99
- package/docs/playbooks/team/index.md +117 -117
- package/docs/product/agent-first-model.md +184 -184
- package/docs/product/entity-model-audit.md +462 -462
- package/docs/product/positioning.md +86 -86
- package/docs/quickstart-existing-project.md +107 -107
- package/docs/quickstart.md +183 -183
- package/docs/release-maintenance.md +79 -79
- package/docs/reputation.md +52 -52
- package/docs/review.md +45 -45
- package/docs/security.md +212 -212
- package/docs/server-operations.md +118 -118
- package/docs/storage.md +106 -106
- package/package.json +80 -65
- package/docs/concepts/event-log-store-critique-A.md +0 -333
- package/docs/concepts/event-log-store-critique-B.md +0 -353
- package/docs/concepts/event-log-store-phase0-measurements.md +0 -58
- package/docs/concepts/event-log-store-proposal-A.md +0 -365
- package/docs/concepts/event-log-store-proposal-B.md +0 -404
- package/docs/concepts/identity-model-proposal.md +0 -371
|
Binary file
|
package/dist/commands/harvest.js
CHANGED
|
@@ -299,7 +299,7 @@ export function harvestLaneResults(options = {}) {
|
|
|
299
299
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
300
300
|
// pln#534 — worktree-as-contract: integrate a worker's lane on its behalf.
|
|
301
301
|
//
|
|
302
|
-
// LEVER #1 from
|
|
302
|
+
// LEVER #1 from a cross-project field session. The worker's contract is
|
|
303
303
|
// reduced to "edit files in this worktree + drop LANE-RESULT.json". brainclaw
|
|
304
304
|
// carries the rest for a worker that cannot (a sandboxed agent whose root
|
|
305
305
|
// excludes `.git`, i.e. dispatchCanCommit=false): it COMMITS the worktree diff
|
package/dist/commands/hooks.js
CHANGED
|
@@ -9,33 +9,33 @@ import { BRAINCLAW_SECTION_START, BRAINCLAW_SECTION_END, upsertBrainclawSection,
|
|
|
9
9
|
* deterministically into every agent conversation.
|
|
10
10
|
*/
|
|
11
11
|
export function generateCursorHook(projectName) {
|
|
12
|
-
return `---
|
|
13
|
-
description: brainclaw session bootstrap for ${projectName}
|
|
14
|
-
alwaysApply: true
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
# Brainclaw session bootstrap
|
|
18
|
-
|
|
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
|
-
|
|
21
|
-
## At the start of every session
|
|
22
|
-
|
|
23
|
-
Call \`bclaw_work(intent)\` — it handles session setup, context load, and scope claim in a single call.
|
|
24
|
-
|
|
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.
|
|
28
|
-
|
|
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.
|
|
12
|
+
return `---
|
|
13
|
+
description: brainclaw session bootstrap for ${projectName}
|
|
14
|
+
alwaysApply: true
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# Brainclaw session bootstrap
|
|
18
|
+
|
|
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
|
+
|
|
21
|
+
## At the start of every session
|
|
22
|
+
|
|
23
|
+
Call \`bclaw_work(intent)\` — it handles session setup, context load, and scope claim in a single call.
|
|
24
|
+
|
|
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.
|
|
28
|
+
|
|
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.
|
|
39
39
|
`;
|
|
40
40
|
}
|
|
41
41
|
/**
|
|
@@ -44,58 +44,58 @@ CLI fallback only: \`brainclaw context\` / \`brainclaw session-end --auto-releas
|
|
|
44
44
|
* delimited "SESSION START" block acts as a deterministic trigger.
|
|
45
45
|
*/
|
|
46
46
|
export function generateWindsurfHook(projectName) {
|
|
47
|
-
return `# Brainclaw session trigger — ${projectName}
|
|
48
|
-
# This block is always active. Windsurf Cascade reads .windsurfrules on every activation.
|
|
49
|
-
|
|
50
|
-
## SESSION START (always run first)
|
|
51
|
-
|
|
52
|
-
Call the Brainclaw MCP facade before responding to any request:
|
|
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.
|
|
57
|
-
|
|
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.
|
|
63
|
-
|
|
64
|
-
## SESSION END (before finishing)
|
|
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\`.
|
|
47
|
+
return `# Brainclaw session trigger — ${projectName}
|
|
48
|
+
# This block is always active. Windsurf Cascade reads .windsurfrules on every activation.
|
|
49
|
+
|
|
50
|
+
## SESSION START (always run first)
|
|
51
|
+
|
|
52
|
+
Call the Brainclaw MCP facade before responding to any request:
|
|
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.
|
|
57
|
+
|
|
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.
|
|
63
|
+
|
|
64
|
+
## SESSION END (before finishing)
|
|
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
70
|
`;
|
|
71
71
|
}
|
|
72
72
|
/**
|
|
73
73
|
* Generate a generic markdown session-trigger section.
|
|
74
74
|
*/
|
|
75
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\`.
|
|
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\`.
|
|
99
99
|
`;
|
|
100
100
|
}
|
|
101
101
|
export function writeHook(content, relativePath, cwd) {
|
package/dist/commands/init.js
CHANGED
|
@@ -117,7 +117,7 @@ export async function runInit(options = {}) {
|
|
|
117
117
|
});
|
|
118
118
|
// Auto-detect and register the AI coding agent running in this environment
|
|
119
119
|
const detectedAi = skipAgentBootstrap ? undefined : detectAiAgent();
|
|
120
|
-
|
|
120
|
+
const registeredAiAgent = detectedAi
|
|
121
121
|
? registerAgentIdentity({
|
|
122
122
|
agentName: detectedAi.name,
|
|
123
123
|
kind: detectedAi.kind,
|
|
@@ -40,63 +40,63 @@ export function runInstallHooks(options = {}) {
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
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
|
|
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
81
|
`;
|
|
82
82
|
}
|
|
83
83
|
function generatePostMergeScript() {
|
|
84
|
-
return `#!/bin/sh
|
|
85
|
-
# brainclaw post-merge hook
|
|
86
|
-
# Auto-releases claims whose scope overlaps with files changed by the merge
|
|
87
|
-
# Generated by: brainclaw install-hooks
|
|
88
|
-
|
|
89
|
-
BCLAW_CMD=""
|
|
90
|
-
if command -v brainclaw >/dev/null 2>&1; then
|
|
91
|
-
BCLAW_CMD="brainclaw"
|
|
92
|
-
elif command -v bclaw >/dev/null 2>&1; then
|
|
93
|
-
BCLAW_CMD="bclaw"
|
|
94
|
-
else
|
|
95
|
-
BCLAW_CMD="npx --no brainclaw"
|
|
96
|
-
fi
|
|
97
|
-
|
|
98
|
-
$BCLAW_CMD release-claims --from-git-diff 2>/dev/null || true
|
|
99
|
-
$BCLAW_CMD worktree clean 2>/dev/null || true
|
|
84
|
+
return `#!/bin/sh
|
|
85
|
+
# brainclaw post-merge hook
|
|
86
|
+
# Auto-releases claims whose scope overlaps with files changed by the merge
|
|
87
|
+
# Generated by: brainclaw install-hooks
|
|
88
|
+
|
|
89
|
+
BCLAW_CMD=""
|
|
90
|
+
if command -v brainclaw >/dev/null 2>&1; then
|
|
91
|
+
BCLAW_CMD="brainclaw"
|
|
92
|
+
elif command -v bclaw >/dev/null 2>&1; then
|
|
93
|
+
BCLAW_CMD="bclaw"
|
|
94
|
+
else
|
|
95
|
+
BCLAW_CMD="npx --no brainclaw"
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
$BCLAW_CMD release-claims --from-git-diff 2>/dev/null || true
|
|
99
|
+
$BCLAW_CMD worktree clean 2>/dev/null || true
|
|
100
100
|
`;
|
|
101
101
|
}
|
|
102
102
|
function findGitRoot(cwd) {
|
|
@@ -113,30 +113,30 @@ function findGitRoot(cwd) {
|
|
|
113
113
|
function generateHookScript() {
|
|
114
114
|
// Use node directly to avoid sh.exe pipe issues on Windows (SIGPIPE).
|
|
115
115
|
// The script is a self-contained node -e that runs both checks.
|
|
116
|
-
return `#!/bin/sh
|
|
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);
|
|
123
|
-
|
|
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);
|
|
131
|
-
}
|
|
132
|
-
|
|
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 $?
|
|
116
|
+
return `#!/bin/sh
|
|
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);
|
|
123
|
+
|
|
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);
|
|
131
|
+
}
|
|
132
|
+
|
|
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 $?
|
|
140
140
|
`;
|
|
141
141
|
}
|
|
142
142
|
//# sourceMappingURL=install-hooks.js.map
|
|
@@ -6,7 +6,7 @@ import { buildContext } from '../core/context.js';
|
|
|
6
6
|
import { buildExecutionContext, renderExecutionContextSummary } from '../core/execution-context.js';
|
|
7
7
|
import { checkBrainclawInstallableUpdate, renderBrainclawInstallableUpdateNotice } from '../core/brainclaw-version.js';
|
|
8
8
|
import { loadConfig } from '../core/config.js';
|
|
9
|
-
import { loadAllSessions, loadCurrentSession, saveCurrentSession, gcStaleSessions } from '../core/identity.js';
|
|
9
|
+
import { loadAllSessions, loadCurrentSession, loadSessionById, saveCurrentSession, gcStaleSessions } from '../core/identity.js';
|
|
10
10
|
import { loadState } from '../core/state.js';
|
|
11
11
|
import { listArchivedCandidates, listCandidates, resolvedSource } from '../core/candidates.js';
|
|
12
12
|
import { listClaims, assessClaimLiveness } from '../core/claims.js';
|
|
@@ -27,13 +27,13 @@ import { checkPolicy } from '../core/policy.js';
|
|
|
27
27
|
import { buildGovernanceReport, renderGovernanceMarkdown } from '../core/governance.js';
|
|
28
28
|
import { inferProjectFromTarget, loadInstructions, resolveInstructions } from '../core/instructions.js';
|
|
29
29
|
import { buildReputationSnapshot, toPublicReputationSummary } from '../core/reputation.js';
|
|
30
|
-
import { search } from '../core/search.js';
|
|
30
|
+
import { countLegacySearchMatches, search } from '../core/search.js';
|
|
31
31
|
import { buildEstimationReport } from './estimation-report.js';
|
|
32
32
|
import { runDoctor } from './doctor.js';
|
|
33
33
|
import { buildProjectDiscovery, saveDiscoveryProfile, loadDiscoveryProfile, renderDiscoverySummary } from '../core/project-discovery.js';
|
|
34
34
|
import { listCapabilities, listTools as listRegistryTools } from '../core/registries.js';
|
|
35
|
-
import {
|
|
36
|
-
import {
|
|
35
|
+
import { listAvailableProjectsForSession, switchProject } from './switch.js';
|
|
36
|
+
import { resolveEffectiveCwdInfo } from '../core/store-resolution.js';
|
|
37
37
|
import { resolveProjectCwd } from '../core/cross-project.js';
|
|
38
38
|
import { readUnseenEvents, buildNotificationSummary } from '../core/event-log.js';
|
|
39
39
|
import { boundListResult, DEFAULT_FIND_CHAR_BUDGET } from '../core/entity-operations.js';
|
|
@@ -100,9 +100,12 @@ function getReviewAssignee(tags) {
|
|
|
100
100
|
}
|
|
101
101
|
export function handleMcpReadToolCall(name, args = {}, context = {}) {
|
|
102
102
|
const baseCwd = context.cwd ?? process.cwd();
|
|
103
|
-
|
|
104
|
-
? baseCwd
|
|
105
|
-
:
|
|
103
|
+
const effective = name === 'bclaw_switch'
|
|
104
|
+
? { cwd: baseCwd, active_source: 'cwd', resolved_project: undefined }
|
|
105
|
+
: context.effectiveScope ?? resolveEffectiveCwdInfo({ baseCwd, sessionId: context.connectionSessionId });
|
|
106
|
+
let cwd = effective.cwd;
|
|
107
|
+
let activeSource = effective.active_source;
|
|
108
|
+
let resolvedProject = effective.resolved_project;
|
|
106
109
|
// If a project param is provided, resolve it to an actual cwd override.
|
|
107
110
|
// resolveProjectCwd unifies cross_project_links (siblings/peers) AND
|
|
108
111
|
// workspace store-chain children. Throws on unknown project — surfaces
|
|
@@ -115,6 +118,14 @@ export function handleMcpReadToolCall(name, args = {}, context = {}) {
|
|
|
115
118
|
let projectRoutingApplied = false;
|
|
116
119
|
if (targetProjectArg) {
|
|
117
120
|
cwd = resolveProjectCwd(targetProjectArg, cwd);
|
|
121
|
+
activeSource = 'explicit';
|
|
122
|
+
try {
|
|
123
|
+
const config = loadConfig(cwd);
|
|
124
|
+
resolvedProject = { path: cwd, name: config.project_name };
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
resolvedProject = { path: cwd };
|
|
128
|
+
}
|
|
118
129
|
projectRoutingApplied = true;
|
|
119
130
|
}
|
|
120
131
|
if (name === 'bclaw_get_context') {
|
|
@@ -631,13 +642,25 @@ export function handleMcpReadToolCall(name, args = {}, context = {}) {
|
|
|
631
642
|
}
|
|
632
643
|
const offset = Math.max(0, Number(args.offset) || 0);
|
|
633
644
|
const limit = typeof args.limit === 'number' ? args.limit : 10;
|
|
645
|
+
const includeLegacy = args.includeLegacy === true || (typeof args.filter === 'object' && args.filter?.includeLegacy === true);
|
|
634
646
|
const allResults = search({
|
|
635
647
|
query,
|
|
636
648
|
section: (args.section ?? args.type),
|
|
637
649
|
since: args.since,
|
|
638
|
-
maxResults:
|
|
650
|
+
maxResults: Number.MAX_SAFE_INTEGER,
|
|
651
|
+
includeLegacy,
|
|
639
652
|
cwd,
|
|
640
653
|
});
|
|
654
|
+
const excludedLegacy = includeLegacy
|
|
655
|
+
? 0
|
|
656
|
+
: countLegacySearchMatches({
|
|
657
|
+
query,
|
|
658
|
+
section: (args.section ?? args.type),
|
|
659
|
+
since: args.since,
|
|
660
|
+
maxResults: offset + limit,
|
|
661
|
+
includeLegacy: true,
|
|
662
|
+
cwd,
|
|
663
|
+
});
|
|
641
664
|
const total = allResults.length;
|
|
642
665
|
const page = allResults.slice(offset, offset + limit);
|
|
643
666
|
// trp#449 class — bound the page by size (pln#542). budget_tokens tightens
|
|
@@ -647,16 +670,34 @@ export function handleMcpReadToolCall(name, args = {}, context = {}) {
|
|
|
647
670
|
const bounded = boundListResult({ entity: 'search_result', total, items: page }, offset, charBudget);
|
|
648
671
|
const lines = bounded.items.map((result) => `[${result.id}] (${result.section}) score=${result.score.toFixed(2)}: ${result.text.slice(0, 120)}`);
|
|
649
672
|
const nextActions = bounded.has_more
|
|
650
|
-
? [{
|
|
673
|
+
? [{
|
|
674
|
+
tool: 'bclaw_search',
|
|
675
|
+
args: {
|
|
676
|
+
query,
|
|
677
|
+
offset: bounded.next_offset,
|
|
678
|
+
limit,
|
|
679
|
+
...(args.project ? { project: args.project } : {}),
|
|
680
|
+
...(args.section ? { section: args.section } : {}),
|
|
681
|
+
...(args.type ? { type: args.type } : {}),
|
|
682
|
+
...(args.since ? { since: args.since } : {}),
|
|
683
|
+
...(args.budget_tokens ? { budget_tokens: args.budget_tokens } : {}),
|
|
684
|
+
...(includeLegacy ? { includeLegacy: true } : {}),
|
|
685
|
+
},
|
|
686
|
+
when: 'to fetch the next page',
|
|
687
|
+
}]
|
|
651
688
|
: [];
|
|
689
|
+
const legacyNote = excludedLegacy > 0 ? ` (${excludedLegacy} legacy result(s) excluded; pass includeLegacy=true to include them)` : '';
|
|
652
690
|
return {
|
|
653
|
-
content: [{ type: 'text', text: bounded.items.length > 0 ? lines.join('\n') :
|
|
691
|
+
content: [{ type: 'text', text: bounded.items.length > 0 ? `${lines.join('\n')}${legacyNote}` : `No results found.${legacyNote}` }],
|
|
654
692
|
structuredContent: {
|
|
655
693
|
total,
|
|
656
694
|
offset,
|
|
657
695
|
limit,
|
|
658
696
|
results: bounded.items,
|
|
659
697
|
returned: bounded.returned,
|
|
698
|
+
excluded_legacy: excludedLegacy,
|
|
699
|
+
resolved_project: resolvedProject ?? { path: cwd },
|
|
700
|
+
active_source: activeSource,
|
|
660
701
|
has_more: bounded.has_more,
|
|
661
702
|
...(bounded.next_offset !== undefined ? { next_offset: bounded.next_offset } : {}),
|
|
662
703
|
...(bounded.omitted_for_size ? { omitted_for_size: bounded.omitted_for_size } : {}),
|
|
@@ -1034,7 +1075,7 @@ export function handleMcpReadToolCall(name, args = {}, context = {}) {
|
|
|
1034
1075
|
}
|
|
1035
1076
|
catch { /* defensive: never block events query on reconcile failure */ }
|
|
1036
1077
|
}
|
|
1037
|
-
|
|
1078
|
+
const events = queryRuntimeEvents({
|
|
1038
1079
|
...(id ? { id } : {}),
|
|
1039
1080
|
...(assignmentId ? { assignment_id: assignmentId } : {}),
|
|
1040
1081
|
...(runId ? { run_id: runId } : {}),
|
|
@@ -1422,7 +1463,7 @@ export function handleMcpReadToolCall(name, args = {}, context = {}) {
|
|
|
1422
1463
|
if (name === 'bclaw_switch') {
|
|
1423
1464
|
if (args.list === true) {
|
|
1424
1465
|
try {
|
|
1425
|
-
const result =
|
|
1466
|
+
const result = listAvailableProjectsForSession(cwd, context.connectionSessionId);
|
|
1426
1467
|
const lines = result.projects.map(p => {
|
|
1427
1468
|
const marker = p.active ? '→' : ' ';
|
|
1428
1469
|
const label = p.name ? `${p.name} (${p.relative_path})` : p.relative_path;
|
|
@@ -1439,7 +1480,9 @@ export function handleMcpReadToolCall(name, args = {}, context = {}) {
|
|
|
1439
1480
|
}
|
|
1440
1481
|
if (args.clear === true) {
|
|
1441
1482
|
try {
|
|
1442
|
-
const session =
|
|
1483
|
+
const session = context.connectionSessionId
|
|
1484
|
+
? loadSessionById(context.connectionSessionId, cwd)
|
|
1485
|
+
: loadCurrentSession(cwd);
|
|
1443
1486
|
if (session?.active_project) {
|
|
1444
1487
|
const { active_project: _removed, ...rest } = session;
|
|
1445
1488
|
saveCurrentSession(rest, cwd);
|
|
@@ -1458,7 +1501,7 @@ export function handleMcpReadToolCall(name, args = {}, context = {}) {
|
|
|
1458
1501
|
return createToolErrorResponse('validation_error', 'Missing required argument: project (or use list=true / clear=true)');
|
|
1459
1502
|
}
|
|
1460
1503
|
try {
|
|
1461
|
-
const result = switchProject(projectRef, { cwd, sessionOnly: true });
|
|
1504
|
+
const result = switchProject(projectRef, { cwd, sessionOnly: true, sessionId: context.connectionSessionId });
|
|
1462
1505
|
const text = `✔ Switched to ${result.name ? `"${result.name}"` : result.path} (${result.scope}-scoped)`;
|
|
1463
1506
|
return {
|
|
1464
1507
|
content: [{ type: 'text', text }],
|