brainclaw 0.19.12 → 0.20.0

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 (40) hide show
  1. package/README.md +42 -11
  2. package/dist/cli.js +55 -1
  3. package/dist/commands/claude-desktop-extension.js +18 -0
  4. package/dist/commands/context.js +3 -1
  5. package/dist/commands/doctor.js +12 -5
  6. package/dist/commands/export.js +44 -0
  7. package/dist/commands/init.js +22 -6
  8. package/dist/commands/list-surface-tasks.js +39 -0
  9. package/dist/commands/mcp.js +86 -5
  10. package/dist/commands/reconcile.js +138 -0
  11. package/dist/commands/setup.js +19 -0
  12. package/dist/commands/status.js +17 -12
  13. package/dist/commands/surface-task-resource.js +35 -0
  14. package/dist/commands/surface-task.js +57 -0
  15. package/dist/commands/uninstall.js +145 -0
  16. package/dist/commands/update-surface-task.js +30 -0
  17. package/dist/core/agent-capability.js +184 -0
  18. package/dist/core/agent-context.js +24 -6
  19. package/dist/core/agent-files.js +18 -18
  20. package/dist/core/ai-surface-inventory.js +321 -0
  21. package/dist/core/ai-surface-tasks.js +40 -0
  22. package/dist/core/bootstrap.js +177 -0
  23. package/dist/core/claude-desktop-extension.js +224 -0
  24. package/dist/core/context.js +47 -24
  25. package/dist/core/ids.js +1 -0
  26. package/dist/core/instruction-templates.js +308 -0
  27. package/dist/core/io.js +1 -0
  28. package/dist/core/machine-profile.js +7 -1
  29. package/dist/core/migration.js +3 -1
  30. package/dist/core/schema.js +34 -0
  31. package/dist/core/setup-flow.js +191 -0
  32. package/dist/core/setup-state.js +30 -1
  33. package/dist/core/store-resolution.js +58 -0
  34. package/dist/core/workspace-projects.js +115 -0
  35. package/docs/architecture/project-refs.md +305 -0
  36. package/docs/cli.md +133 -1
  37. package/docs/integrations/agents.md +102 -150
  38. package/docs/integrations/overview.md +71 -45
  39. package/docs/quickstart.md +44 -111
  40. package/package.json +1 -1
@@ -0,0 +1,138 @@
1
+ import readline from 'node:readline/promises';
2
+ import { stdin as input, stdout as output } from 'node:process';
3
+ import path from 'node:path';
4
+ import { buildMachineProfile, saveMachineProfile } from '../core/machine-profile.js';
5
+ import { buildAgentInventory, saveAgentInventory } from '../core/agent-inventory.js';
6
+ import { applyBootstrapImport, runBootstrapProfile } from '../core/bootstrap.js';
7
+ import { loadConfig } from '../core/config.js';
8
+ import { memoryExists } from '../core/io.js';
9
+ import { summarizeWorkspaceProjects } from '../core/workspace-projects.js';
10
+ export async function runReconcile(options = {}) {
11
+ const cwd = path.resolve(options.cwd ?? process.cwd());
12
+ if (!memoryExists(cwd)) {
13
+ console.error('Error: .brainclaw/ not found in the current directory. Run `brainclaw init` first.');
14
+ process.exit(1);
15
+ }
16
+ const rootConfig = loadConfig(cwd);
17
+ const workspaceSummary = summarizeWorkspaceProjects(cwd, rootConfig);
18
+ const storeTargets = [
19
+ cwd,
20
+ ...workspaceSummary.uses_folder_resolution
21
+ ? workspaceSummary.discovered_projects
22
+ .filter((project) => project.source !== 'config')
23
+ .map((project) => project.path)
24
+ : [],
25
+ ];
26
+ const uniqueTargets = [...new Set(storeTargets.map((store) => path.resolve(store)))];
27
+ if (options.json && options.dryRun) {
28
+ console.log(JSON.stringify({
29
+ cwd,
30
+ mode: 'dry_run',
31
+ workspace_summary: workspaceSummary,
32
+ planned_actions: {
33
+ machine_profile_refresh: !options.skipMachineProfile,
34
+ agent_inventory_refresh: !options.skipAgentInventory,
35
+ bootstrap_refresh: uniqueTargets.map((store) => ({
36
+ cwd: store,
37
+ relative_path: path.relative(cwd, store) || '.',
38
+ apply_bootstrap: Boolean(options.applyBootstrap),
39
+ })),
40
+ },
41
+ }, null, 2));
42
+ return;
43
+ }
44
+ if (options.applyBootstrap) {
45
+ await confirmBootstrapApply(options.yes);
46
+ }
47
+ const machineProfilePath = !options.skipMachineProfile
48
+ ? saveMachineProfile(buildMachineProfile())
49
+ : null;
50
+ const agentInventoryPath = !options.skipAgentInventory
51
+ ? saveAgentInventory(buildAgentInventory())
52
+ : null;
53
+ const stores = [];
54
+ for (const store of uniqueTargets) {
55
+ const config = loadConfig(store);
56
+ if (options.applyBootstrap) {
57
+ const result = applyBootstrapImport({ cwd: store, refresh: true });
58
+ stores.push({
59
+ cwd: store,
60
+ relative_path: path.relative(cwd, store) || '.',
61
+ project_name: config.project_name,
62
+ project_mode: config.project_mode,
63
+ project_strategy: config.projects.strategy,
64
+ bootstrap_refreshed: true,
65
+ bootstrap_applied: true,
66
+ workspace_kind: result.proposal.workspace_kind,
67
+ onboarding_mode: result.proposal.onboarding_mode,
68
+ confidence: result.proposal.confidence,
69
+ suggestion_count: result.proposal.suggestion_count,
70
+ created_count: result.createdCount,
71
+ skipped_count: result.skippedCount,
72
+ });
73
+ continue;
74
+ }
75
+ const result = runBootstrapProfile({ cwd: store, refresh: true });
76
+ stores.push({
77
+ cwd: store,
78
+ relative_path: path.relative(cwd, store) || '.',
79
+ project_name: config.project_name,
80
+ project_mode: config.project_mode,
81
+ project_strategy: config.projects.strategy,
82
+ bootstrap_refreshed: true,
83
+ bootstrap_applied: false,
84
+ workspace_kind: result.profile.workspace_kind,
85
+ onboarding_mode: result.profile.onboarding_mode,
86
+ confidence: result.profile.confidence,
87
+ suggestion_count: result.importPlan.suggestion_count,
88
+ });
89
+ }
90
+ if (options.json) {
91
+ console.log(JSON.stringify({
92
+ cwd,
93
+ mode: options.applyBootstrap ? 'apply' : 'refresh',
94
+ workspace_summary: workspaceSummary,
95
+ machine_profile_refreshed: !options.skipMachineProfile,
96
+ machine_profile_path: machineProfilePath,
97
+ agent_inventory_refreshed: !options.skipAgentInventory,
98
+ agent_inventory_path: agentInventoryPath,
99
+ stores,
100
+ }, null, 2));
101
+ return;
102
+ }
103
+ if (!options.skipMachineProfile) {
104
+ console.log(`✔ Machine profile refreshed: ${machineProfilePath}`);
105
+ }
106
+ if (!options.skipAgentInventory) {
107
+ console.log(`✔ Agent inventory refreshed: ${agentInventoryPath}`);
108
+ }
109
+ console.log('');
110
+ console.log(`Reconciled ${stores.length} store(s):`);
111
+ for (const store of stores) {
112
+ const suffix = store.bootstrap_applied
113
+ ? `${store.created_count ?? 0} created, ${store.skipped_count ?? 0} skipped`
114
+ : `${store.suggestion_count ?? 0} bootstrap suggestion(s) available`;
115
+ console.log(` - ${store.relative_path} (${store.project_name}) — ${store.onboarding_mode ?? 'unknown'}, confidence=${store.confidence ?? 'unknown'}, ${suffix}`);
116
+ }
117
+ }
118
+ async function confirmBootstrapApply(yes) {
119
+ if (yes) {
120
+ return;
121
+ }
122
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
123
+ console.error('Error: bootstrap apply across multiple stores requires --yes in non-interactive mode.');
124
+ process.exit(1);
125
+ }
126
+ const rl = readline.createInterface({ input, output });
127
+ try {
128
+ const answer = await rl.question('Apply bootstrap suggestions across all selected stores? [y/N] ');
129
+ if (answer.trim().toLowerCase() !== 'y') {
130
+ console.error('Cancelled.');
131
+ process.exit(1);
132
+ }
133
+ }
134
+ finally {
135
+ rl.close();
136
+ }
137
+ }
138
+ //# sourceMappingURL=reconcile.js.map
@@ -4,6 +4,7 @@ import readline from 'node:readline/promises';
4
4
  import { spawnSync } from 'node:child_process';
5
5
  import { runInit } from './init.js';
6
6
  import { detectAiAgent } from '../core/ai-agent-detection.js';
7
+ import { buildAiSurfaceInventory, renderAiSurfaceUsageHints } from '../core/ai-surface-inventory.js';
7
8
  import { buildMachineProfile, saveMachineProfile, loadMachineProfile } from '../core/machine-profile.js';
8
9
  import { buildAgentInventory, saveAgentInventory, loadAgentInventory } from '../core/agent-inventory.js';
9
10
  import { ensureClaudeCodeUserSettings, ensureClaudeCodeUserCommand, ensureCursorMcpConfig, ensureWindsurfMcpConfig, ensureAntigravityMcpConfig, ensureContinueUserMcpConfig, ensureCodexMcpConfig, writeDetectedAgentAutoConfig, describeAutoConfigWrite, ensureGitignoreEntries, collectWorkspaceGitignoreEntries, } from '../core/agent-files.js';
@@ -388,6 +389,7 @@ export async function runSetup(options = {}) {
388
389
  // Step 4: Agent detection & selection
389
390
  const detectedAi = detectAiAgent(env);
390
391
  const detectedName = detectedAi?.name;
392
+ const detectedSurfaces = buildAiSurfaceInventory();
391
393
  console.log('');
392
394
  if (detectedName) {
393
395
  console.log(`Detected AI agent: ${detectedName}`);
@@ -395,6 +397,23 @@ export async function runSetup(options = {}) {
395
397
  else {
396
398
  console.log('No AI agent detected automatically.');
397
399
  }
400
+ const visibleSurfaces = detectedSurfaces.filter((surface) => surface.status !== 'not_detected');
401
+ if (visibleSurfaces.length > 0) {
402
+ console.log('Other AI work surfaces on this machine:');
403
+ for (const surface of visibleSurfaces) {
404
+ console.log(` - ${surface.display_name} [${surface.surface_kind}, ${surface.status}]`);
405
+ }
406
+ const usageHints = renderAiSurfaceUsageHints(visibleSurfaces);
407
+ if (usageHints.length > 0) {
408
+ console.log('');
409
+ console.log('Suggested uses:');
410
+ for (const line of usageHints) {
411
+ console.log(` ${line}`);
412
+ }
413
+ }
414
+ console.log('');
415
+ console.log('These surfaces are tracked separately from coding agents and will use tailored onboarding flows.');
416
+ }
398
417
  console.log('Supported agents:');
399
418
  ALL_KNOWN_AGENTS.forEach((a, i) => {
400
419
  const tag = a === detectedName ? ' ← detected' : '';
@@ -9,7 +9,8 @@ import { loadState } from '../core/state.js';
9
9
  import { isTrapActive, listOperationalTraps } from '../core/traps.js';
10
10
  import { generateMarkdown } from '../core/markdown.js';
11
11
  import { memoryExists } from '../core/io.js';
12
- function printHumanStatus(state, config) {
12
+ import { summarizeWorkspaceProjects } from '../core/workspace-projects.js';
13
+ function printHumanStatus(state, config, cwd) {
13
14
  const activePlans = state.plan_items.filter((plan) => plan.status !== 'done' && plan.status !== 'dropped');
14
15
  const activeInstructions = loadInstructions().filter((entry) => entry.active);
15
16
  const activeClaims = listClaims().filter((claim) => claim.status === 'active');
@@ -21,6 +22,7 @@ function printHumanStatus(state, config) {
21
22
  const activeSharedTraps = state.known_traps.filter((trap) => isTrapActive(trap));
22
23
  const resolvedSharedTraps = state.known_traps.filter((trap) => trap.status === 'resolved');
23
24
  const activeMachineTraps = machineTraps.filter((trap) => isTrapActive(trap));
25
+ const workspaceProjects = summarizeWorkspaceProjects(cwd, config);
24
26
  const counts = {
25
27
  instructions: activeInstructions.length,
26
28
  claims: activeClaims.length,
@@ -50,7 +52,7 @@ function printHumanStatus(state, config) {
50
52
  console.log(` Traps : ${activeSharedTraps.length} active shared, ${resolvedSharedTraps.length} resolved shared, ${activeMachineTraps.length} active machine-local (${currentHost})`);
51
53
  console.log(` Handoffs : ${counts.handoffs}`);
52
54
  if (config.project_mode === 'multi-project') {
53
- console.log(` Projects : ${config.projects.known.length}`);
55
+ console.log(` Projects : ${workspaceProjects.effective_project_count} effective (${workspaceProjects.strategy})`);
54
56
  }
55
57
  // Show recent items (last 3 per section)
56
58
  const sections = [
@@ -84,24 +86,27 @@ function printHumanStatus(state, config) {
84
86
  }
85
87
  }
86
88
  export function runStatus(options = {}) {
87
- if (!memoryExists()) {
89
+ const cwd = process.cwd();
90
+ if (!memoryExists(cwd)) {
88
91
  console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
89
92
  process.exit(1);
90
93
  }
91
- const config = loadConfig();
92
- const state = loadState();
94
+ const config = loadConfig(cwd);
95
+ const state = loadState(cwd);
93
96
  const currentHost = resolveCurrentHostId();
94
- const sharedRuntimeNotes = listRuntimeNotes({ visibility: 'shared' });
95
- const machineRuntimeNotes = listRuntimeNotes({ visibility: 'machine' });
96
- const machineTraps = listOperationalTraps({ visibility: 'machine' });
97
+ const sharedRuntimeNotes = listRuntimeNotes({ visibility: 'shared' }, cwd);
98
+ const machineRuntimeNotes = listRuntimeNotes({ visibility: 'machine' }, cwd);
99
+ const machineTraps = listOperationalTraps({ visibility: 'machine' }, cwd);
97
100
  const activeSharedTraps = state.known_traps.filter((trap) => isTrapActive(trap));
98
101
  const resolvedSharedTraps = state.known_traps.filter((trap) => trap.status === 'resolved');
99
102
  const activeMachineTraps = machineTraps.filter((trap) => isTrapActive(trap));
100
- const registeredAgents = listAgentIdentities();
101
- const reputation = buildReputationSnapshot();
103
+ const registeredAgents = listAgentIdentities(cwd);
104
+ const reputation = buildReputationSnapshot(cwd);
105
+ const workspaceProjects = summarizeWorkspaceProjects(cwd, config);
102
106
  if (options.json) {
103
107
  console.log(JSON.stringify({
104
108
  config,
109
+ workspace_projects: workspaceProjects,
105
110
  agents: {
106
111
  current_name: config.current_agent,
107
112
  current_id: config.current_agent_id,
@@ -125,9 +130,9 @@ export function runStatus(options = {}) {
125
130
  return;
126
131
  }
127
132
  if (options.markdown) {
128
- console.log(generateMarkdown(state));
133
+ console.log(generateMarkdown(state, cwd));
129
134
  return;
130
135
  }
131
- printHumanStatus(state, config);
136
+ printHumanStatus(state, config, cwd);
132
137
  }
133
138
  //# sourceMappingURL=status.js.map
@@ -0,0 +1,35 @@
1
+ import { runSurfaceTask } from './surface-task.js';
2
+ import { runListSurfaceTasks } from './list-surface-tasks.js';
3
+ import { runUpdateSurfaceTask } from './update-surface-task.js';
4
+ export function runSurfaceTaskResource(subcommand, args, options = {}) {
5
+ const normalized = subcommand.trim().toLowerCase();
6
+ if (normalized === 'create') {
7
+ const title = args.join(' ').trim();
8
+ if (!title) {
9
+ console.error('Error: surface-task create requires <title>.');
10
+ process.exit(1);
11
+ }
12
+ runSurfaceTask(title, options);
13
+ return;
14
+ }
15
+ if (normalized === 'list' || normalized === 'ls') {
16
+ runListSurfaceTasks(options);
17
+ return;
18
+ }
19
+ if (normalized === 'update') {
20
+ const id = args[0];
21
+ if (!id) {
22
+ console.error('Error: surface-task update requires <id>.');
23
+ process.exit(1);
24
+ }
25
+ runUpdateSurfaceTask(id, options);
26
+ return;
27
+ }
28
+ const legacyTitle = [subcommand, ...args].join(' ').trim();
29
+ if (!legacyTitle) {
30
+ console.error('Error: missing surface-task subcommand or title.');
31
+ process.exit(1);
32
+ }
33
+ runSurfaceTask(legacyTitle, options);
34
+ }
35
+ //# sourceMappingURL=surface-task-resource.js.map
@@ -0,0 +1,57 @@
1
+ import { buildOperationalIdentity } from '../core/identity.js';
2
+ import { memoryExists } from '../core/io.js';
3
+ import { generateIdWithLabel, nowISO } from '../core/ids.js';
4
+ import { requireMinimumTrustLevel, requireRegisteredAgentIdentity } from '../core/agent-registry.js';
5
+ import { saveAiSurfaceTask } from '../core/ai-surface-tasks.js';
6
+ export function runSurfaceTask(title, options = {}) {
7
+ if (!memoryExists(options.cwd)) {
8
+ console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
9
+ process.exit(1);
10
+ }
11
+ if (!options.target) {
12
+ console.error('Error: surface-task create requires --target <surface>.');
13
+ process.exit(1);
14
+ }
15
+ if (!options.instructions?.trim()) {
16
+ console.error('Error: surface-task create requires --instructions <text>.');
17
+ process.exit(1);
18
+ }
19
+ const registeredAgent = requireRegisteredAgentIdentity({
20
+ agentName: options.agent,
21
+ agentId: options.agentId,
22
+ cwd: options.cwd,
23
+ allowCurrent: true,
24
+ allowEnv: true,
25
+ });
26
+ requireMinimumTrustLevel(registeredAgent, 'contributor');
27
+ const actor = buildOperationalIdentity(registeredAgent.agent_name, options.cwd, {
28
+ agentId: registeredAgent.agent_id,
29
+ });
30
+ const ids = generateIdWithLabel('ai_surface_tasks', options.cwd);
31
+ const timestamp = nowISO();
32
+ const task = {
33
+ id: ids.id,
34
+ short_label: ids.short_label,
35
+ title: title.trim(),
36
+ instructions: options.instructions.trim(),
37
+ target_surface: options.target.trim(),
38
+ kind: options.kind ?? 'custom',
39
+ created_at: timestamp,
40
+ updated_at: timestamp,
41
+ author: actor.agent,
42
+ author_id: actor.agent_id,
43
+ project_id: actor.project_id,
44
+ session_id: actor.session_id,
45
+ status: 'queued',
46
+ requested_outputs: options.output ?? [],
47
+ related_paths: options.path,
48
+ tags: options.tag ?? [],
49
+ };
50
+ saveAiSurfaceTask(task, options.cwd);
51
+ console.log(`✔ Surface task queued: [${task.id}] ${task.title}`);
52
+ console.log(` Target: ${task.target_surface} (${task.kind})`);
53
+ if (task.requested_outputs.length > 0) {
54
+ console.log(` Outputs: ${task.requested_outputs.join(', ')}`);
55
+ }
56
+ }
57
+ //# sourceMappingURL=surface-task.js.map
@@ -0,0 +1,145 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import readline from 'node:readline/promises';
4
+ import { MEMORY_DIR, memoryExists } from '../core/io.js';
5
+ import { BRAINCLAW_SECTION_START, BRAINCLAW_SECTION_END, AGENT_EXPORT_REGISTRY, } from '../core/agent-files.js';
6
+ import { resolveHomeDir } from '../core/setup-state.js';
7
+ /**
8
+ * Remove brainclaw from a project and/or machine.
9
+ *
10
+ * --project: removes .brainclaw/, agent instruction files, MCP configs,
11
+ * and brainclaw sections from shared instruction files.
12
+ * --machine: removes ~/.brainclaw/ and global agent configs.
13
+ */
14
+ export async function runUninstall(options) {
15
+ const cwd = options.cwd ?? process.cwd();
16
+ if (!options.project && !options.machine) {
17
+ console.error('Error: specify --project, --machine, or both.');
18
+ process.exit(1);
19
+ }
20
+ if (options.project) {
21
+ await uninstallProject(cwd, options.yes);
22
+ }
23
+ if (options.machine) {
24
+ await uninstallMachine(options.yes);
25
+ }
26
+ }
27
+ async function uninstallProject(cwd, skipConfirm) {
28
+ if (!memoryExists(cwd)) {
29
+ console.log('No .brainclaw/ found in this project. Nothing to uninstall.');
30
+ return;
31
+ }
32
+ if (!skipConfirm && process.stdin.isTTY) {
33
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
34
+ try {
35
+ const answer = (await rl.question('Remove brainclaw from this project? This deletes .brainclaw/ and all generated agent files. [y/N]: ')).trim().toLowerCase();
36
+ if (answer !== 'y' && answer !== 'yes') {
37
+ console.log('Aborted.');
38
+ return;
39
+ }
40
+ }
41
+ finally {
42
+ rl.close();
43
+ }
44
+ }
45
+ // Remove .brainclaw/ directory
46
+ const brainclawDir = path.join(cwd, MEMORY_DIR);
47
+ if (fs.existsSync(brainclawDir)) {
48
+ fs.rmSync(brainclawDir, { recursive: true, force: true });
49
+ console.log(`✔ Removed ${MEMORY_DIR}/`);
50
+ }
51
+ // Remove dedicated agent files (non-shared, brainclaw-owned)
52
+ const dedicatedFiles = AGENT_EXPORT_REGISTRY
53
+ .map((entry) => entry.relativePath)
54
+ .filter((p) => p.includes('/'));
55
+ for (const relativePath of dedicatedFiles) {
56
+ const fullPath = path.join(cwd, relativePath);
57
+ if (fs.existsSync(fullPath)) {
58
+ fs.unlinkSync(fullPath);
59
+ console.log(`✔ Removed ${relativePath}`);
60
+ }
61
+ }
62
+ // Remove brainclaw sections from shared files
63
+ const sharedFiles = [
64
+ 'CLAUDE.md',
65
+ '.windsurfrules',
66
+ 'AGENTS.md',
67
+ 'GEMINI.md',
68
+ '.github/copilot-instructions.md',
69
+ ];
70
+ for (const relativePath of sharedFiles) {
71
+ const fullPath = path.join(cwd, relativePath);
72
+ if (!fs.existsSync(fullPath))
73
+ continue;
74
+ const content = fs.readFileSync(fullPath, 'utf-8');
75
+ const startIdx = content.indexOf(BRAINCLAW_SECTION_START);
76
+ const endIdx = content.indexOf(BRAINCLAW_SECTION_END);
77
+ if (startIdx !== -1 && endIdx !== -1) {
78
+ const before = content.slice(0, startIdx).trimEnd();
79
+ const after = content.slice(endIdx + BRAINCLAW_SECTION_END.length).trimStart();
80
+ const cleaned = [before, after].filter(Boolean).join('\n\n');
81
+ if (cleaned.trim().length === 0) {
82
+ fs.unlinkSync(fullPath);
83
+ console.log(`✔ Removed ${relativePath} (was brainclaw-only)`);
84
+ }
85
+ else {
86
+ fs.writeFileSync(fullPath, cleaned + '\n', 'utf-8');
87
+ console.log(`✔ Removed brainclaw section from ${relativePath}`);
88
+ }
89
+ }
90
+ }
91
+ // Remove companion config files
92
+ const companionFiles = [
93
+ '.mcp.json',
94
+ '.claude/commands/brainclaw.md',
95
+ '.claude/settings.local.json',
96
+ '.claude/.bclaw-session',
97
+ '.cursor/rules/brainclaw-mcp-shim.mdc',
98
+ '.vscode/cline_mcp_settings.json',
99
+ '.roo/mcp.json',
100
+ '.continue/config.json',
101
+ 'opencode.json',
102
+ '.github/skills/brainclaw-context/SKILL.md',
103
+ ];
104
+ for (const relativePath of companionFiles) {
105
+ const fullPath = path.join(cwd, relativePath);
106
+ if (fs.existsSync(fullPath)) {
107
+ fs.unlinkSync(fullPath);
108
+ console.log(`✔ Removed ${relativePath}`);
109
+ }
110
+ }
111
+ console.log('✔ Project uninstall complete.');
112
+ }
113
+ async function uninstallMachine(skipConfirm) {
114
+ const home = resolveHomeDir();
115
+ if (!home) {
116
+ console.log('Cannot determine home directory. Nothing to uninstall.');
117
+ return;
118
+ }
119
+ const userStore = path.join(home, '.brainclaw');
120
+ if (!fs.existsSync(userStore)) {
121
+ console.log('No ~/.brainclaw/ found. Nothing to uninstall.');
122
+ return;
123
+ }
124
+ if (!skipConfirm && process.stdin.isTTY) {
125
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
126
+ try {
127
+ const answer = (await rl.question('Remove brainclaw global config (~/.brainclaw/)? [y/N]: ')).trim().toLowerCase();
128
+ if (answer !== 'y' && answer !== 'yes') {
129
+ console.log('Aborted.');
130
+ return;
131
+ }
132
+ }
133
+ finally {
134
+ rl.close();
135
+ }
136
+ }
137
+ fs.rmSync(userStore, { recursive: true, force: true });
138
+ console.log('✔ Removed ~/.brainclaw/');
139
+ // Note: global MCP configs in ~/.claude/settings.json, ~/.cursor/mcp.json etc.
140
+ // are NOT removed automatically — they may contain non-brainclaw entries.
141
+ console.log('Note: global agent MCP configs (e.g. ~/.claude/settings.json) were not modified.');
142
+ console.log('Remove brainclaw entries manually if needed.');
143
+ console.log('✔ Machine uninstall complete.');
144
+ }
145
+ //# sourceMappingURL=uninstall.js.map
@@ -0,0 +1,30 @@
1
+ import { memoryExists } from '../core/io.js';
2
+ import { loadAiSurfaceTask, saveAiSurfaceTask } from '../core/ai-surface-tasks.js';
3
+ import { nowISO } from '../core/ids.js';
4
+ export function runUpdateSurfaceTask(id, options = {}) {
5
+ if (!memoryExists(options.cwd)) {
6
+ console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
7
+ process.exit(1);
8
+ }
9
+ const task = loadAiSurfaceTask(id, options.cwd);
10
+ const timestamp = nowISO();
11
+ if (options.status) {
12
+ task.status = options.status;
13
+ if (options.status === 'in_progress' && !task.claimed_at) {
14
+ task.claimed_at = timestamp;
15
+ }
16
+ if ((options.status === 'completed' || options.status === 'failed' || options.status === 'cancelled') && !task.completed_at) {
17
+ task.completed_at = timestamp;
18
+ }
19
+ }
20
+ if (options.result !== undefined) {
21
+ task.result_note = options.result;
22
+ }
23
+ if (options.output && options.output.length > 0) {
24
+ task.requested_outputs = options.output;
25
+ }
26
+ task.updated_at = timestamp;
27
+ saveAiSurfaceTask(task, options.cwd);
28
+ console.log(`✔ Surface task updated: [${task.id}] ${task.title}`);
29
+ }
30
+ //# sourceMappingURL=update-surface-task.js.map