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.
- package/README.md +193 -170
- package/dist/brainclaw-vscode.vsix +0 -0
- package/dist/cli.js +683 -23
- package/dist/commands/accept.js +3 -0
- package/dist/commands/add-step.js +11 -26
- package/dist/commands/agent-board.js +70 -3
- package/dist/commands/audit.js +19 -0
- package/dist/commands/check-policy.js +54 -0
- package/dist/commands/check-security-mcp.js +145 -0
- package/dist/commands/check-security.js +106 -0
- package/dist/commands/claim-resource.js +1 -0
- package/dist/commands/codev.js +672 -0
- package/dist/commands/compact.js +74 -0
- package/dist/commands/complete-step.js +16 -26
- package/dist/commands/constraint.js +8 -20
- package/dist/commands/decision.js +9 -20
- package/dist/commands/delete-plan.js +10 -12
- package/dist/commands/delete-step.js +16 -0
- package/dist/commands/dispatch.js +163 -0
- package/dist/commands/doctor.js +1122 -49
- package/dist/commands/enable-agent.js +1 -0
- package/dist/commands/export.js +280 -22
- package/dist/commands/handoff.js +33 -0
- package/dist/commands/harvest.js +189 -0
- package/dist/commands/hooks.js +82 -25
- package/dist/commands/inbox.js +169 -0
- package/dist/commands/init.js +38 -31
- package/dist/commands/install-hooks.js +71 -44
- package/dist/commands/link.js +89 -0
- package/dist/commands/list-claims.js +48 -3
- package/dist/commands/list-plans.js +129 -25
- package/dist/commands/loops-handlers.js +409 -0
- package/dist/commands/mcp-read-handlers.js +1628 -0
- package/dist/commands/mcp-schemas.generated.js +74 -0
- package/dist/commands/mcp.js +4244 -1475
- package/dist/commands/plan-resource.js +64 -0
- package/dist/commands/plan.js +12 -26
- package/dist/commands/prune.js +37 -2
- package/dist/commands/reflect.js +20 -7
- package/dist/commands/release-claim.js +11 -6
- package/dist/commands/release-notes.js +170 -0
- package/dist/commands/repair.js +210 -0
- package/dist/commands/run-profile.js +57 -0
- package/dist/commands/sequence.js +113 -0
- package/dist/commands/session-end.js +423 -14
- package/dist/commands/session-start.js +214 -41
- package/dist/commands/setup-security.js +103 -0
- package/dist/commands/setup.js +42 -4
- package/dist/commands/stale.js +109 -0
- package/dist/commands/switch.js +131 -10
- package/dist/commands/trap.js +14 -31
- package/dist/commands/update-handoff.js +63 -4
- package/dist/commands/update-plan.js +21 -28
- package/dist/commands/update-step.js +37 -0
- package/dist/commands/upgrade.js +313 -6
- package/dist/commands/usage.js +102 -0
- package/dist/commands/version.js +20 -0
- package/dist/commands/who.js +124 -0
- package/dist/commands/worktree.js +105 -0
- package/dist/core/actions.js +315 -0
- package/dist/core/agent-capability.js +610 -17
- package/dist/core/agent-context.js +7 -1
- package/dist/core/agent-files.js +1169 -85
- package/dist/core/agent-integrations.js +160 -5
- package/dist/core/agent-inventory.js +2 -0
- package/dist/core/agent-profiles.js +93 -0
- package/dist/core/agent-registry.js +162 -30
- package/dist/core/agentrun-reconciler.js +345 -0
- package/dist/core/agentruns.js +424 -0
- package/dist/core/ai-agent-detection.js +31 -10
- package/dist/core/archival.js +77 -0
- package/dist/core/assignment-sweeper.js +82 -0
- package/dist/core/assignments.js +367 -0
- package/dist/core/audit.js +30 -0
- package/dist/core/bootstrap.js +61 -10
- package/dist/core/brainclaw-version.js +94 -2
- package/dist/core/candidates.js +93 -2
- package/dist/core/claims.js +419 -0
- package/dist/core/codev-metrics.js +77 -0
- package/dist/core/codev-personas.js +31 -0
- package/dist/core/codev-plan-gen.js +35 -0
- package/dist/core/codev-prompts.js +74 -0
- package/dist/core/codev-responses.js +62 -0
- package/dist/core/codev-rounds.js +218 -0
- package/dist/core/config.js +4 -0
- package/dist/core/context.js +454 -34
- package/dist/core/coordination.js +201 -6
- package/dist/core/cross-project.js +230 -16
- package/dist/core/default-profiles/doctor.yaml +11 -0
- package/dist/core/default-profiles/janitor.yaml +11 -0
- package/dist/core/default-profiles/onboarder.yaml +11 -0
- package/dist/core/default-profiles/reviewer.yaml +13 -0
- package/dist/core/dispatcher.js +1189 -0
- package/dist/core/duplicates.js +2 -2
- package/dist/core/entity-operations.js +450 -0
- package/dist/core/entity-registry.js +344 -0
- package/dist/core/event-log.js +1 -0
- package/dist/core/events.js +106 -2
- package/dist/core/execution-adapters.js +154 -0
- package/dist/core/execution-context.js +63 -0
- package/dist/core/execution-profile.js +270 -0
- package/dist/core/execution.js +255 -0
- package/dist/core/facade-schema.js +81 -0
- package/dist/core/federation-cloud.js +99 -0
- package/dist/core/federation-message.js +52 -0
- package/dist/core/federation-transport.js +65 -0
- package/dist/core/gc-semantic.js +482 -0
- package/dist/core/governance.js +247 -0
- package/dist/core/guards.js +19 -0
- package/dist/core/ideation.js +72 -0
- package/dist/core/identity.js +252 -28
- package/dist/core/ids.js +6 -0
- package/dist/core/input-validation.js +2 -2
- package/dist/core/instruction-templates.js +344 -136
- package/dist/core/io.js +90 -11
- package/dist/core/lock.js +6 -2
- package/dist/core/loops/brief-assembly.js +213 -0
- package/dist/core/loops/facade-schema.js +148 -0
- package/dist/core/loops/index.js +7 -0
- package/dist/core/loops/iteration-engine.js +139 -0
- package/dist/core/loops/lock.js +385 -0
- package/dist/core/loops/store.js +201 -0
- package/dist/core/loops/types.js +403 -0
- package/dist/core/loops/verbs.js +534 -0
- package/dist/core/markdown.js +15 -3
- package/dist/core/memory-compactor.js +432 -0
- package/dist/core/memory-git.js +152 -8
- package/dist/core/messaging.js +278 -0
- package/dist/core/migration.js +32 -1
- package/dist/core/mutation-pipeline.js +4 -2
- package/dist/core/operations/memory-mutation.js +129 -0
- package/dist/core/operations/memory-write.js +78 -0
- package/dist/core/operations/plan.js +190 -0
- package/dist/core/policy.js +169 -0
- package/dist/core/repo-analysis.js +67 -0
- package/dist/core/reputation.js +9 -3
- package/dist/core/schema.js +546 -21
- package/dist/core/search.js +21 -2
- package/dist/core/security-cache.js +71 -0
- package/dist/core/security-guard.js +152 -0
- package/dist/core/security-scoring.js +86 -0
- package/dist/core/sequence.js +130 -0
- package/dist/core/socket-client.js +113 -0
- package/dist/core/staleness.js +246 -0
- package/dist/core/state.js +98 -22
- package/dist/core/store-resolution.js +54 -12
- package/dist/core/toml-writer.js +76 -0
- package/dist/core/upgrades/backup.js +232 -0
- package/dist/core/upgrades/health-check.js +169 -0
- package/dist/core/upgrades/patches/candidate-archive.js +145 -0
- package/dist/core/upgrades/patches/handoff-review-strip.js +128 -0
- package/dist/core/upgrades/patches/provenance-rollout.js +136 -0
- package/dist/core/upgrades/schema-version.js +97 -0
- package/dist/core/worktree.js +606 -0
- package/dist/facts.js +114 -0
- package/dist/facts.json +111 -0
- package/docs/architecture/project-refs.md +5 -1
- package/docs/cli.md +690 -43
- package/docs/concepts/ideation-loop.md +317 -0
- package/docs/concepts/loop-engine.md +456 -0
- package/docs/concepts/mcp-governance.md +268 -0
- package/docs/concepts/memory-staleness.md +122 -0
- package/docs/concepts/multi-agent-workflows.md +166 -0
- package/docs/concepts/plans-and-claims.md +31 -6
- package/docs/concepts/project-md-convention.md +35 -0
- package/docs/concepts/troubleshooting.md +220 -0
- package/docs/concepts/upgrade-cli.md +202 -0
- package/docs/concepts/upgrade-dogfood-procedure.md +114 -0
- package/docs/context-format-changelog.md +2 -2
- package/docs/context-format.md +2 -2
- package/docs/index.md +68 -0
- package/docs/integrations/agents.md +15 -16
- package/docs/integrations/cline.md +88 -0
- package/docs/integrations/codex.md +75 -23
- package/docs/integrations/continue.md +60 -0
- package/docs/integrations/copilot.md +67 -9
- package/docs/integrations/kilocode.md +72 -0
- package/docs/integrations/mcp.md +304 -21
- package/docs/integrations/mistral-vibe.md +122 -0
- package/docs/integrations/opencode.md +84 -0
- package/docs/integrations/overview.md +23 -8
- package/docs/integrations/roo.md +74 -0
- package/docs/integrations/windsurf.md +83 -0
- package/docs/mcp-schema-changelog.md +191 -1
- package/docs/playbooks/integration/index.md +121 -0
- package/docs/playbooks/productivity/index.md +102 -0
- package/docs/playbooks/team/index.md +122 -0
- package/docs/product/agent-first-model.md +184 -0
- package/docs/product/entity-model-audit.md +462 -0
- package/docs/quickstart-existing-project.md +135 -0
- package/docs/quickstart.md +124 -37
- package/docs/release-maintenance.md +79 -0
- package/docs/review.md +2 -0
- package/docs/server-operations.md +118 -0
- package/package.json +20 -12
- package/dist/commands/claude-desktop-extension.js +0 -18
- package/dist/commands/diff.js +0 -99
- package/dist/core/claude-desktop-extension.js +0 -224
package/dist/commands/hooks.js
CHANGED
|
@@ -16,23 +16,26 @@ alwaysApply: true
|
|
|
16
16
|
|
|
17
17
|
# Brainclaw session bootstrap
|
|
18
18
|
|
|
19
|
-
|
|
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
|
-
|
|
22
|
-
brainclaw context
|
|
23
|
-
\`\`\`
|
|
21
|
+
## At the start of every session
|
|
24
22
|
|
|
25
|
-
|
|
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
|
-
|
|
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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
|
|
52
|
+
Call the Brainclaw MCP facade before responding to any request:
|
|
50
53
|
|
|
51
|
-
|
|
52
|
-
|
|
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
|
|
56
|
-
|
|
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
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
package/dist/commands/init.js
CHANGED
|
@@ -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
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
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
|
-
|
|
251
|
-
|
|
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(
|
|
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
|
-
#
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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
|