brainclaw 0.19.2

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 (128) hide show
  1. package/LICENSE +74 -0
  2. package/README.md +226 -0
  3. package/dist/cli.js +1037 -0
  4. package/dist/commands/accept.js +149 -0
  5. package/dist/commands/adapter-openclaw-import.js +75 -0
  6. package/dist/commands/add-step.js +35 -0
  7. package/dist/commands/agent-board.js +106 -0
  8. package/dist/commands/audit.js +35 -0
  9. package/dist/commands/bootstrap.js +34 -0
  10. package/dist/commands/capability.js +104 -0
  11. package/dist/commands/changes.js +112 -0
  12. package/dist/commands/check-constraints.js +63 -0
  13. package/dist/commands/claim-resource.js +54 -0
  14. package/dist/commands/claim.js +92 -0
  15. package/dist/commands/complete-step.js +34 -0
  16. package/dist/commands/constraint.js +44 -0
  17. package/dist/commands/context-diff.js +32 -0
  18. package/dist/commands/context.js +63 -0
  19. package/dist/commands/decision.js +45 -0
  20. package/dist/commands/delete-plan.js +20 -0
  21. package/dist/commands/diff.js +99 -0
  22. package/dist/commands/doctor.js +1275 -0
  23. package/dist/commands/enable-agent.js +63 -0
  24. package/dist/commands/env.js +46 -0
  25. package/dist/commands/estimation-report.js +167 -0
  26. package/dist/commands/explore.js +47 -0
  27. package/dist/commands/export.js +381 -0
  28. package/dist/commands/handoff.js +63 -0
  29. package/dist/commands/history.js +22 -0
  30. package/dist/commands/hooks.js +123 -0
  31. package/dist/commands/init.js +356 -0
  32. package/dist/commands/install-hooks.js +115 -0
  33. package/dist/commands/instruction.js +56 -0
  34. package/dist/commands/list-agents.js +44 -0
  35. package/dist/commands/list-claims.js +45 -0
  36. package/dist/commands/list-instructions.js +50 -0
  37. package/dist/commands/list-plans.js +48 -0
  38. package/dist/commands/mcp-worker.js +12 -0
  39. package/dist/commands/mcp.js +2272 -0
  40. package/dist/commands/memory.js +283 -0
  41. package/dist/commands/metrics.js +175 -0
  42. package/dist/commands/plan-resource.js +62 -0
  43. package/dist/commands/plan.js +76 -0
  44. package/dist/commands/prune-candidates.js +36 -0
  45. package/dist/commands/prune.js +48 -0
  46. package/dist/commands/pull.js +25 -0
  47. package/dist/commands/push.js +28 -0
  48. package/dist/commands/rebuild.js +14 -0
  49. package/dist/commands/reflect-runtime-note.js +74 -0
  50. package/dist/commands/reflect.js +286 -0
  51. package/dist/commands/register-agent.js +29 -0
  52. package/dist/commands/reject.js +52 -0
  53. package/dist/commands/release-claim.js +41 -0
  54. package/dist/commands/release-claims.js +67 -0
  55. package/dist/commands/review.js +242 -0
  56. package/dist/commands/rollback.js +156 -0
  57. package/dist/commands/runtime-note.js +144 -0
  58. package/dist/commands/runtime-status.js +49 -0
  59. package/dist/commands/search.js +36 -0
  60. package/dist/commands/session-end.js +187 -0
  61. package/dist/commands/session-start.js +147 -0
  62. package/dist/commands/set-trust.js +92 -0
  63. package/dist/commands/setup.js +446 -0
  64. package/dist/commands/show-candidate.js +31 -0
  65. package/dist/commands/star-candidate.js +28 -0
  66. package/dist/commands/status.js +133 -0
  67. package/dist/commands/sync.js +159 -0
  68. package/dist/commands/tool.js +126 -0
  69. package/dist/commands/trap.js +74 -0
  70. package/dist/commands/update-handoff.js +23 -0
  71. package/dist/commands/update-plan.js +37 -0
  72. package/dist/commands/upgrade.js +382 -0
  73. package/dist/commands/use-candidate.js +35 -0
  74. package/dist/commands/version.js +96 -0
  75. package/dist/commands/watch.js +215 -0
  76. package/dist/commands/whoami.js +104 -0
  77. package/dist/core/agent-context.js +340 -0
  78. package/dist/core/agent-files.js +874 -0
  79. package/dist/core/agent-integrations.js +135 -0
  80. package/dist/core/agent-inventory.js +401 -0
  81. package/dist/core/agent-registry.js +420 -0
  82. package/dist/core/ai-agent-detection.js +140 -0
  83. package/dist/core/audit.js +85 -0
  84. package/dist/core/bootstrap.js +658 -0
  85. package/dist/core/brainclaw-version.js +433 -0
  86. package/dist/core/candidates.js +137 -0
  87. package/dist/core/circuit-breaker.js +118 -0
  88. package/dist/core/claims.js +72 -0
  89. package/dist/core/config.js +86 -0
  90. package/dist/core/context-diff.js +122 -0
  91. package/dist/core/context.js +1212 -0
  92. package/dist/core/contradictions.js +270 -0
  93. package/dist/core/coordination.js +86 -0
  94. package/dist/core/cross-project.js +99 -0
  95. package/dist/core/duplicates.js +72 -0
  96. package/dist/core/event-log.js +152 -0
  97. package/dist/core/events.js +56 -0
  98. package/dist/core/execution-context.js +204 -0
  99. package/dist/core/freshness.js +87 -0
  100. package/dist/core/global-registry.js +182 -0
  101. package/dist/core/host.js +10 -0
  102. package/dist/core/identity.js +151 -0
  103. package/dist/core/ids.js +56 -0
  104. package/dist/core/input-validation.js +81 -0
  105. package/dist/core/instructions.js +117 -0
  106. package/dist/core/io.js +191 -0
  107. package/dist/core/json-store.js +63 -0
  108. package/dist/core/lifecycle.js +45 -0
  109. package/dist/core/lock.js +129 -0
  110. package/dist/core/logger.js +49 -0
  111. package/dist/core/machine-profile.js +332 -0
  112. package/dist/core/markdown.js +120 -0
  113. package/dist/core/memory-git.js +133 -0
  114. package/dist/core/migration.js +247 -0
  115. package/dist/core/project-registry.js +64 -0
  116. package/dist/core/reflection-safety.js +21 -0
  117. package/dist/core/repo-analysis.js +133 -0
  118. package/dist/core/reputation.js +409 -0
  119. package/dist/core/runtime.js +134 -0
  120. package/dist/core/schema.js +580 -0
  121. package/dist/core/search.js +115 -0
  122. package/dist/core/security.js +66 -0
  123. package/dist/core/setup-state.js +50 -0
  124. package/dist/core/state.js +83 -0
  125. package/dist/core/store-resolution.js +119 -0
  126. package/dist/core/sync-remote.js +83 -0
  127. package/dist/core/traps.js +86 -0
  128. package/package.json +60 -0
@@ -0,0 +1,149 @@
1
+ import { memoryExists, memoryPath, writeFileAtomic } from '../core/io.js';
2
+ import { loadCandidate, archiveCandidate, resolveIdOrAlias } from '../core/candidates.js';
3
+ import { loadState, saveState } from '../core/state.js';
4
+ import { generateMarkdown } from '../core/markdown.js';
5
+ import { generateIdWithLabel, nowISO } from '../core/ids.js';
6
+ import { generateTrapIdWithLabel } from '../core/traps.js';
7
+ import { requireMinimumTrustLevel, requireRegisteredAgentIdentity } from '../core/agent-registry.js';
8
+ import { appendAuditEntry } from '../core/audit.js';
9
+ export function runAccept(id, by, cwd) {
10
+ try {
11
+ const result = acceptCandidate(id, by, cwd);
12
+ console.log(`✔ Promoted to ${result.candidate_type} [${result.promoted_item_id}]`);
13
+ console.log(`✔ Candidate [${id}] accepted and archived.`);
14
+ }
15
+ catch (e) {
16
+ const msg = e instanceof Error ? e.message : String(e);
17
+ console.error(`Error: ${msg}`);
18
+ process.exit(1);
19
+ }
20
+ }
21
+ export function acceptCandidate(id, by, cwd, byId) {
22
+ if (!memoryExists(cwd)) {
23
+ throw new Error('.brainclaw/ not found. Run `brainclaw init` first.');
24
+ }
25
+ const resolvedId = resolveIdOrAlias(id, cwd);
26
+ const candidate = loadCandidate(resolvedId, cwd);
27
+ if (candidate.status !== 'pending') {
28
+ throw new Error(`Candidate '${id}' is already ${candidate.status}.`);
29
+ }
30
+ const actorIdentity = requireRegisteredAgentIdentity({
31
+ agentName: by,
32
+ agentId: byId,
33
+ cwd,
34
+ allowCurrent: true,
35
+ allowEnv: true,
36
+ });
37
+ requireMinimumTrustLevel(actorIdentity, 'trusted');
38
+ const actor = actorIdentity.agent_name;
39
+ const state = loadState(cwd);
40
+ let promotedItemId = '';
41
+ // Promote candidate into canonical state based on type
42
+ switch (candidate.type) {
43
+ case 'constraint': {
44
+ const { id: entryId, short_label } = generateIdWithLabel('active_constraints', cwd);
45
+ const entry = {
46
+ id: entryId,
47
+ short_label,
48
+ text: candidate.text,
49
+ created_at: candidate.created_at,
50
+ author: candidate.author,
51
+ author_id: candidate.author_id,
52
+ project_id: candidate.project_id,
53
+ host_id: candidate.host_id,
54
+ session_id: candidate.session_id,
55
+ status: 'active',
56
+ tags: candidate.tags,
57
+ };
58
+ state.active_constraints.push(entry);
59
+ promotedItemId = entryId;
60
+ break;
61
+ }
62
+ case 'decision': {
63
+ const { id: entryId, short_label } = generateIdWithLabel('recent_decisions', cwd);
64
+ const entry = {
65
+ id: entryId,
66
+ short_label,
67
+ text: candidate.text,
68
+ created_at: candidate.created_at,
69
+ author: candidate.author,
70
+ author_id: candidate.author_id,
71
+ project_id: candidate.project_id,
72
+ host_id: candidate.host_id,
73
+ session_id: candidate.session_id,
74
+ related_paths: candidate.related_paths,
75
+ plan_id: candidate.plan_id,
76
+ tags: candidate.tags,
77
+ };
78
+ state.recent_decisions.push(entry);
79
+ promotedItemId = entryId;
80
+ break;
81
+ }
82
+ case 'trap': {
83
+ const { id: entryId, short_label } = generateTrapIdWithLabel(cwd);
84
+ const entry = {
85
+ id: entryId,
86
+ short_label,
87
+ text: candidate.text,
88
+ created_at: candidate.created_at,
89
+ author: candidate.author,
90
+ author_id: candidate.author_id,
91
+ project_id: candidate.project_id,
92
+ host_id: candidate.host_id,
93
+ session_id: candidate.session_id,
94
+ status: 'active',
95
+ severity: candidate.severity ?? 'medium',
96
+ tags: candidate.tags,
97
+ plan_id: candidate.plan_id,
98
+ visibility: 'shared',
99
+ };
100
+ state.known_traps.push(entry);
101
+ promotedItemId = entryId;
102
+ break;
103
+ }
104
+ case 'handoff': {
105
+ const { id: entryId, short_label } = generateIdWithLabel('open_handoffs', cwd);
106
+ const entry = {
107
+ id: entryId,
108
+ short_label,
109
+ from: candidate.from ?? 'unknown',
110
+ to: candidate.to ?? 'unknown',
111
+ text: candidate.text,
112
+ created_at: candidate.created_at,
113
+ author: candidate.author,
114
+ author_id: candidate.author_id,
115
+ project_id: candidate.project_id,
116
+ host_id: candidate.host_id,
117
+ session_id: candidate.session_id,
118
+ status: 'open',
119
+ tags: candidate.tags,
120
+ };
121
+ state.open_handoffs.push(entry);
122
+ promotedItemId = entryId;
123
+ break;
124
+ }
125
+ }
126
+ saveState(state, cwd);
127
+ writeFileAtomic(memoryPath('project.md', cwd), generateMarkdown(state, cwd));
128
+ // Archive candidate (use resolved hash ID)
129
+ candidate.status = 'accepted';
130
+ candidate.resolved_at = nowISO();
131
+ candidate.resolved_by = actor;
132
+ archiveCandidate(candidate, 'accepted', cwd);
133
+ appendAuditEntry({
134
+ actor,
135
+ actor_id: actorIdentity.agent_id,
136
+ action: 'accept',
137
+ item_id: resolvedId,
138
+ item_type: candidate.type,
139
+ after: { type: candidate.type, text: candidate.text },
140
+ reason: 'trusted-agent',
141
+ }, cwd);
142
+ return {
143
+ candidate_id: resolvedId,
144
+ candidate_type: candidate.type,
145
+ promoted_item_id: promotedItemId,
146
+ actor,
147
+ };
148
+ }
149
+ //# sourceMappingURL=accept.js.map
@@ -0,0 +1,75 @@
1
+ import fs from 'node:fs';
2
+ import { memoryExists } from '../core/io.js';
3
+ import { runReflect } from './reflect.js';
4
+ import { RuntimeEventSchema } from '../core/schema.js';
5
+ import { listRuntimeEventsBySession } from '../core/events.js';
6
+ import { logger } from '../core/logger.js';
7
+ export function runAdapterOpenclawImport(file, options = {}) {
8
+ if (!memoryExists()) {
9
+ console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
10
+ process.exit(1);
11
+ }
12
+ if (!file && !options.session) {
13
+ console.error('Error: provide either <file> or --session <id>.');
14
+ process.exit(1);
15
+ }
16
+ if (options.dryRun) {
17
+ const events = options.session
18
+ ? listRuntimeEventsBySession(options.session)
19
+ : listRuntimeEventsFromFile(file);
20
+ printDryRunSummary(events, options.session);
21
+ return;
22
+ }
23
+ runReflect(undefined, {
24
+ batch: file,
25
+ session: options.session,
26
+ source: options.source ?? 'openclaw',
27
+ author: options.author,
28
+ });
29
+ }
30
+ function listRuntimeEventsFromFile(file) {
31
+ if (!fs.existsSync(file)) {
32
+ throw new Error(`batch file not found: ${file}`);
33
+ }
34
+ const parsed = JSON.parse(fs.readFileSync(file, 'utf-8'));
35
+ const rawEvents = Array.isArray(parsed)
36
+ ? parsed
37
+ : parsed && typeof parsed === 'object' && Array.isArray(parsed.events)
38
+ ? parsed.events
39
+ : [parsed];
40
+ const events = [];
41
+ for (const raw of rawEvents) {
42
+ try {
43
+ events.push(RuntimeEventSchema.parse(raw));
44
+ }
45
+ catch (err) {
46
+ logger.debug('Ignoring malformed OpenClaw event record:', err);
47
+ }
48
+ }
49
+ return events;
50
+ }
51
+ function printDryRunSummary(events, session) {
52
+ const byType = new Map();
53
+ for (const event of events) {
54
+ byType.set(event.event_type, (byType.get(event.event_type) ?? 0) + 1);
55
+ }
56
+ if (session) {
57
+ console.log(`Dry-run for OpenClaw session '${session}':`);
58
+ }
59
+ else {
60
+ console.log('Dry-run for OpenClaw file import:');
61
+ }
62
+ console.log(` events: ${events.length}`);
63
+ for (const [type, count] of [...byType.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
64
+ console.log(` - ${type}: ${count}`);
65
+ }
66
+ if (events.length > 0) {
67
+ console.log(' sample:');
68
+ for (const event of events.slice(0, 3)) {
69
+ console.log(` [${event.id}] ${event.event_type} :: ${event.text}`);
70
+ }
71
+ }
72
+ console.log(' note: actual import enforces strict mode — sensitive content blocks candidate creation.');
73
+ console.log('No candidates were created (dry-run).');
74
+ }
75
+ //# sourceMappingURL=adapter-openclaw-import.js.map
@@ -0,0 +1,35 @@
1
+ import { loadState, saveState } from '../core/state.js';
2
+ import { memoryExists, memoryPath, writeFileAtomic } from '../core/io.js';
3
+ import { generateId, nowISO } from '../core/ids.js';
4
+ import { generateMarkdown } from '../core/markdown.js';
5
+ import { validateCliInput } from '../core/input-validation.js';
6
+ export function runAddStep(planId, text, options = {}) {
7
+ if (!memoryExists()) {
8
+ console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
9
+ process.exit(1);
10
+ }
11
+ validateCliInput(text);
12
+ const state = loadState();
13
+ const plan = state.plan_items.find((p) => p.id === planId || p.short_label === planId);
14
+ if (!plan) {
15
+ console.error(`Error: Plan '${planId}' not found.`);
16
+ process.exit(1);
17
+ }
18
+ const step = {
19
+ id: generateId('plan_steps'),
20
+ text,
21
+ status: 'todo',
22
+ assignee: options.assignee,
23
+ created_at: nowISO(),
24
+ updated_at: nowISO(),
25
+ };
26
+ plan.steps = [...(plan.steps ?? []), step];
27
+ plan.updated_at = nowISO();
28
+ saveState(state);
29
+ writeFileAtomic(memoryPath('project.md'), generateMarkdown(state));
30
+ const total = plan.steps.length;
31
+ const done = plan.steps.filter((s) => s.status === 'done').length;
32
+ console.log(`✔ Step added: [${step.id}] ${text}`);
33
+ console.log(` Plan [${plan.id}] progress: ${done}/${total} steps done`);
34
+ }
35
+ //# sourceMappingURL=add-step.js.map
@@ -0,0 +1,106 @@
1
+ import { buildCoordinationSnapshot } from '../core/coordination.js';
2
+ import { listAgentIdentities } from '../core/agent-registry.js';
3
+ import { memoryExists } from '../core/io.js';
4
+ export function runAgentBoard(options = {}) {
5
+ if (!memoryExists()) {
6
+ console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
7
+ process.exit(1);
8
+ }
9
+ const board = buildCoordinationSnapshot({
10
+ agent: options.agent,
11
+ project: options.project,
12
+ target: options.for,
13
+ host: options.host,
14
+ allHosts: options.allHosts,
15
+ includeReputation: options.withReputation,
16
+ includeSessionMeta: options.includeSessionMeta,
17
+ });
18
+ if (options.json) {
19
+ console.log(JSON.stringify(board, null, 2));
20
+ return;
21
+ }
22
+ console.log(`Agent board${board.agent ? ` for ${board.agent}` : ''}${board.project ? ` (${board.project})` : ''}`);
23
+ console.log('');
24
+ console.log(`Current host: ${board.current_host}`);
25
+ if (board.all_hosts) {
26
+ console.log('Host filter: all-hosts');
27
+ }
28
+ else if (board.host_filter) {
29
+ console.log(`Host filter: ${board.host_filter}`);
30
+ }
31
+ if (options.withReputation && board.reputation_summary) {
32
+ console.log(`Reputation: tracked=${board.reputation_summary.tracked_agents}, avg_trust=${board.reputation_summary.avg_internal_trust}`);
33
+ if (board.agent_reputation) {
34
+ console.log(`Agent trust: ${board.agent_reputation.internal_trust} (cq=${board.agent_reputation.contribution_quality}, rv=${board.agent_reputation.review_reliability}, ct=${board.agent_reputation.continuity_hygiene})`);
35
+ }
36
+ }
37
+ console.log('');
38
+ console.log(`Active plans: ${board.active_plans.length}`);
39
+ for (const plan of board.active_plans.slice(0, 10)) {
40
+ const claims = plan.claims.length ? ` claims=${plan.claims.map((claim) => claim.agent).join(',')}` : '';
41
+ console.log(` [${plan.id}] ${plan.text} (${plan.status}, ${plan.priority})${claims}`);
42
+ }
43
+ console.log('');
44
+ console.log(`Active claims: ${board.active_claims.length}`);
45
+ for (const claim of board.active_claims.slice(0, 10)) {
46
+ console.log(` [${claim.id}] ${claim.agent} -> ${claim.scope}${claim.plan_id ? ` (plan ${claim.plan_id})` : ''}`);
47
+ }
48
+ console.log('');
49
+ const sessionMetaHint = board.session_meta_hidden > 0 ? ` (+${board.session_meta_hidden} session lifecycle notes hidden — use --include-session-meta to show)` : '';
50
+ console.log(`Runtime notes: ${board.runtime_notes.length}${sessionMetaHint}`);
51
+ for (const note of board.runtime_notes.slice(-10)) {
52
+ const scope = note.visibility === 'shared' ? 'shared' : `${note.visibility}:${note.host_id ?? 'unknown-host'}`;
53
+ console.log(` [${note.id}] ${note.agent}: ${note.text}${note.plan_id ? ` (plan ${note.plan_id})` : ''} [${scope}]`);
54
+ }
55
+ console.log('');
56
+ console.log(`Open handoffs: ${board.open_handoffs.length}`);
57
+ for (const handoff of board.open_handoffs.slice(0, 10)) {
58
+ console.log(` [${handoff.id}] ${handoff.from} -> ${handoff.to}: ${handoff.text}${handoff.plan_id ? ` (plan ${handoff.plan_id})` : ''}`);
59
+ }
60
+ console.log('');
61
+ console.log(`Resolved instructions: ${board.resolved_instructions.length}`);
62
+ for (const instruction of board.resolved_instructions.slice(0, 10)) {
63
+ console.log(` [${instruction.id}] <${instruction.layer}${instruction.scope ? `:${instruction.scope}` : ''}> ${instruction.text}`);
64
+ }
65
+ // Capability routing
66
+ if (options.capabilities || options.suggest) {
67
+ const agents = listAgentIdentities();
68
+ if (agents.length === 0) {
69
+ console.log('');
70
+ console.log('No agents registered.');
71
+ return;
72
+ }
73
+ if (options.suggest) {
74
+ const query = options.suggest.toLowerCase();
75
+ const scored = agents
76
+ .map(a => ({
77
+ name: a.agent_name,
78
+ capabilities: a.capabilities ?? [],
79
+ score: (a.capabilities ?? []).filter(c => c.toLowerCase().includes(query)).length,
80
+ trust_level: a.trust_level ?? 'contributor',
81
+ }))
82
+ .filter(a => a.score > 0)
83
+ .sort((a, b) => b.score - a.score);
84
+ console.log('');
85
+ if (scored.length === 0) {
86
+ console.log(`No agents have capabilities matching '${options.suggest}'.`);
87
+ }
88
+ else {
89
+ console.log(`Suggested agents for '${options.suggest}':`);
90
+ for (const a of scored) {
91
+ console.log(` ${a.name} (${a.trust_level}) — ${a.capabilities.join(', ')}`);
92
+ }
93
+ }
94
+ }
95
+ else {
96
+ console.log('');
97
+ console.log(`Registered agents: ${agents.length}`);
98
+ for (const a of agents) {
99
+ const caps = (a.capabilities ?? []).length > 0 ? ` — ${a.capabilities.join(', ')}` : '';
100
+ const fingerprint = a.identity_key?.fingerprint ? ` fp=${a.identity_key.fingerprint.slice(0, 12)}` : '';
101
+ console.log(` ${a.agent_name} (${a.trust_level ?? 'contributor'})${caps}${fingerprint}`);
102
+ }
103
+ }
104
+ }
105
+ }
106
+ //# sourceMappingURL=agent-board.js.map
@@ -0,0 +1,35 @@
1
+ import { readAuditLog } from '../core/audit.js';
2
+ import { memoryExists } from '../core/io.js';
3
+ export function runAuditCommand(options = {}) {
4
+ if (!memoryExists()) {
5
+ console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
6
+ process.exit(1);
7
+ }
8
+ const entries = readAuditLog({
9
+ since: options.since,
10
+ actor: options.actor,
11
+ action: options.action,
12
+ });
13
+ const limited = options.limit ? entries.slice(-options.limit) : entries;
14
+ if (options.json) {
15
+ console.log(JSON.stringify(limited, null, 2));
16
+ return;
17
+ }
18
+ if (limited.length === 0) {
19
+ console.log('No audit entries found.');
20
+ return;
21
+ }
22
+ console.log(`Audit log — ${limited.length} entries:`);
23
+ console.log('');
24
+ for (const entry of limited) {
25
+ const parts = [entry.timestamp, `[${entry.actor}]`, entry.action];
26
+ if (entry.item_id)
27
+ parts.push(`→ ${entry.item_id}`);
28
+ if (entry.item_type)
29
+ parts.push(`(${entry.item_type})`);
30
+ if (entry.reason)
31
+ parts.push(`| ${entry.reason}`);
32
+ console.log(parts.join(' '));
33
+ }
34
+ }
35
+ //# sourceMappingURL=audit.js.map
@@ -0,0 +1,34 @@
1
+ import { memoryExists } from '../core/io.js';
2
+ import { renderBootstrapSummary, runBootstrapProfile } from '../core/bootstrap.js';
3
+ export function runBootstrap(options = {}) {
4
+ const cwd = options.cwd ?? process.cwd();
5
+ if (!memoryExists(cwd)) {
6
+ console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
7
+ process.exit(1);
8
+ }
9
+ try {
10
+ const result = runBootstrapProfile({
11
+ target: options.for,
12
+ refresh: options.refresh,
13
+ cwd,
14
+ });
15
+ if (options.json) {
16
+ console.log(JSON.stringify({
17
+ summary: result.profile.summary,
18
+ target: result.profile.target,
19
+ repo_fingerprint: result.profile.repo_fingerprint,
20
+ sources_scanned: result.profile.sources_scanned,
21
+ seed_count: result.profile.seed_count,
22
+ seeds: result.seeds,
23
+ reused_profile: result.reusedProfile,
24
+ }, null, 2));
25
+ return;
26
+ }
27
+ console.log(renderBootstrapSummary(result));
28
+ }
29
+ catch (error) {
30
+ console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
31
+ process.exit(1);
32
+ }
33
+ }
34
+ //# sourceMappingURL=bootstrap.js.map
@@ -0,0 +1,104 @@
1
+ import { loadState, saveState } from '../core/state.js';
2
+ import { resolveCurrentAgentName } from '../core/agent-registry.js';
3
+ import { memoryExists, memoryPath, writeFileAtomic } from '../core/io.js';
4
+ import { generateMarkdown } from '../core/markdown.js';
5
+ import { generateIdWithLabel, nowISO } from '../core/ids.js';
6
+ import { loadConfig } from '../core/config.js';
7
+ import { scanText } from '../core/security.js';
8
+ import { validateCliInput } from '../core/input-validation.js';
9
+ import { resolveTargetStore } from '../core/store-resolution.js';
10
+ export function runCapability(subcommand, args, options = {}) {
11
+ const cwd = resolveTargetStore(options.cwd ?? process.cwd(), options.store ?? 'local');
12
+ if (!memoryExists(cwd)) {
13
+ console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
14
+ process.exit(1);
15
+ }
16
+ if (subcommand === 'list') {
17
+ runCapabilityList(cwd);
18
+ }
19
+ else if (subcommand === 'add') {
20
+ const name = args[0];
21
+ const description = args[1];
22
+ if (!name || !description) {
23
+ console.error('Error: capability add requires <name> <description>');
24
+ process.exit(1);
25
+ }
26
+ runCapabilityAdd(name, description, options, cwd);
27
+ }
28
+ else if (subcommand === 'describe') {
29
+ const capId = args[0];
30
+ if (!capId) {
31
+ console.error('Error: capability describe requires <id>');
32
+ process.exit(1);
33
+ }
34
+ runCapabilityDescribe(capId, cwd);
35
+ }
36
+ else {
37
+ console.error(`Unknown capability subcommand: ${subcommand}`);
38
+ process.exit(1);
39
+ }
40
+ }
41
+ function runCapabilityList(cwd) {
42
+ const state = loadState(cwd);
43
+ const capabilities = state.active_constraints
44
+ .filter((c) => c.tags.includes('capability'))
45
+ .map((c) => ({ id: c.id, name: c.text.split('\n')[0], tags: c.tags }));
46
+ if (capabilities.length === 0) {
47
+ console.log('No capabilities registered yet.');
48
+ return;
49
+ }
50
+ console.log(`\n${capabilities.length} capability(ies):\n`);
51
+ capabilities.forEach((cap) => {
52
+ console.log(` [${cap.id}] ${cap.name}`);
53
+ if (cap.tags.length > 1) {
54
+ console.log(` tags: ${cap.tags.filter((t) => t !== 'capability').join(', ')}`);
55
+ }
56
+ });
57
+ console.log('');
58
+ }
59
+ function runCapabilityAdd(name, description, options, cwd) {
60
+ validateCliInput(name + ' ' + description, options.tag);
61
+ const config = loadConfig(cwd);
62
+ const warnings = scanText(name + ': ' + description, config);
63
+ for (const w of warnings) {
64
+ console.warn(`⚠ ${w.message}`);
65
+ if (w.level === 'block') {
66
+ console.error('Blocked: strict redaction is enabled. Entry not added.');
67
+ process.exit(1);
68
+ }
69
+ }
70
+ const state = loadState(cwd);
71
+ const { id, short_label } = generateIdWithLabel('recent_decisions');
72
+ const entry = {
73
+ id,
74
+ short_label,
75
+ text: name,
76
+ created_at: nowISO(),
77
+ author: options.author ?? resolveCurrentAgentName(cwd),
78
+ tags: ['capability', ...(options.tag ?? [])],
79
+ };
80
+ // For now, store as decision to avoid schema migration
81
+ // Will migrate to separate capability storage in v0.16
82
+ state.recent_decisions.push(entry);
83
+ saveState(state, cwd);
84
+ writeFileAtomic(memoryPath('project.md', cwd), generateMarkdown(state));
85
+ console.log(`✔ Capability added: [${id}] ${name}`);
86
+ console.log(' (Stored in decisions for now; will move to dedicated registry in v0.16)');
87
+ }
88
+ function runCapabilityDescribe(capId, cwd) {
89
+ const state = loadState(cwd);
90
+ const decision = state.recent_decisions.find((d) => d.id === capId || d.short_label === capId);
91
+ if (!decision) {
92
+ console.error(`Error: capability '${capId}' not found`);
93
+ process.exit(1);
94
+ }
95
+ console.log(`\nCapability: ${decision.text}`);
96
+ console.log(`ID: ${decision.id}`);
97
+ console.log(`Author: ${decision.author}`);
98
+ console.log(`Created: ${decision.created_at}`);
99
+ if (decision.tags.length > 1) {
100
+ console.log(`Tags: ${decision.tags.filter((t) => t !== 'capability').join(', ')}`);
101
+ }
102
+ console.log('');
103
+ }
104
+ //# sourceMappingURL=capability.js.map
@@ -0,0 +1,112 @@
1
+ import { memoryExists } from '../core/io.js';
2
+ import { getVisibleMemoryVersion, readContextMarker, writeContextMarker } from '../core/freshness.js';
3
+ import { loadState } from '../core/state.js';
4
+ import { listCandidates, listArchivedCandidates } from '../core/candidates.js';
5
+ import { nowISO } from '../core/ids.js';
6
+ import { logger } from '../core/logger.js';
7
+ export function runDiff(options = {}) {
8
+ if (!memoryExists()) {
9
+ console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
10
+ process.exit(1);
11
+ }
12
+ const usingMarker = !options.since;
13
+ let since;
14
+ const marker = usingMarker ? readContextMarker() : undefined;
15
+ if (options.since) {
16
+ since = new Date(options.since);
17
+ if (isNaN(since.getTime())) {
18
+ console.error(`Error: invalid date '${options.since}'. Use ISO 8601 format, e.g. 2026-03-14T10:00:00Z`);
19
+ process.exit(1);
20
+ }
21
+ }
22
+ else {
23
+ if (!marker) {
24
+ console.error('Error: no --since date provided and no .last-context marker found.');
25
+ console.error('Hint: Run `brainclaw context` first to set the marker, or use:');
26
+ console.error(' brainclaw diff --since <ISO date>');
27
+ process.exit(1);
28
+ }
29
+ since = new Date(marker.read_at);
30
+ if (isNaN(since.getTime())) {
31
+ console.error('Error: invalid date in .last-context marker.');
32
+ process.exit(1);
33
+ }
34
+ }
35
+ const sinceISO = since.toISOString();
36
+ const state = loadState();
37
+ const makeEntry = (section, type) => (e) => ({
38
+ id: e.id, entry_type: type, section, text: e.text, created_at: e.created_at,
39
+ });
40
+ const stateEntries = [
41
+ ...state.active_constraints.filter(e => e.created_at > sinceISO).map(makeEntry('active_constraints', 'constraint')),
42
+ ...state.recent_decisions.filter(e => e.created_at > sinceISO).map(makeEntry('recent_decisions', 'decision')),
43
+ ...state.known_traps.filter(e => e.created_at > sinceISO).map(makeEntry('known_traps', 'trap')),
44
+ ...state.open_handoffs.filter(e => e.created_at > sinceISO).map(makeEntry('open_handoffs', 'handoff')),
45
+ ].sort((a, b) => a.created_at.localeCompare(b.created_at));
46
+ const newPending = listCandidates('pending').filter(c => c.created_at > sinceISO);
47
+ const newAccepted = listArchivedCandidates('accepted').filter(c => (c.resolved_at ?? c.created_at) > sinceISO);
48
+ const total = stateEntries.length + newPending.length + newAccepted.length;
49
+ if (options.json) {
50
+ console.log(JSON.stringify({
51
+ since: sinceISO,
52
+ checked_at: new Date().toISOString(),
53
+ total_changes: total,
54
+ state_entries: stateEntries,
55
+ new_candidates: newPending,
56
+ accepted_candidates: newAccepted,
57
+ }, null, 2));
58
+ }
59
+ else {
60
+ if (total === 0) {
61
+ console.log(`No changes in .brainclaw/ since ${sinceISO}`);
62
+ }
63
+ else {
64
+ console.log(`Changes since ${sinceISO}:`);
65
+ if (marker?.memory_version) {
66
+ const currentVersion = getVisibleMemoryVersion();
67
+ if (marker.memory_version !== currentVersion) {
68
+ console.log(`Visible memory version changed: ${marker.memory_version} -> ${currentVersion}`);
69
+ console.log('');
70
+ }
71
+ }
72
+ console.log('');
73
+ if (stateEntries.length > 0) {
74
+ console.log(`New canonical entries (${stateEntries.length}):`);
75
+ for (const e of stateEntries) {
76
+ console.log(` + [${e.id}] (${e.entry_type}) ${e.text}`);
77
+ }
78
+ }
79
+ if (newPending.length > 0) {
80
+ if (stateEntries.length > 0)
81
+ console.log('');
82
+ console.log(`New candidates pending review (${newPending.length}):`);
83
+ for (const c of newPending) {
84
+ console.log(` ? [${c.id}] (${c.type}) ${c.text}`);
85
+ }
86
+ }
87
+ if (newAccepted.length > 0) {
88
+ console.log('');
89
+ console.log(`Candidates accepted into memory (${newAccepted.length}):`);
90
+ for (const c of newAccepted) {
91
+ console.log(` \u2714 [${c.id}] (${c.type}) ${c.text}`);
92
+ }
93
+ }
94
+ }
95
+ }
96
+ if (usingMarker) {
97
+ try {
98
+ writeContextMarker({
99
+ read_at: nowISO(),
100
+ memory_version: getVisibleMemoryVersion(),
101
+ host_id: marker?.host_id,
102
+ target: marker?.target,
103
+ project: marker?.project,
104
+ all_hosts: marker?.all_hosts,
105
+ });
106
+ }
107
+ catch (err) {
108
+ logger.debug('Failed to write context marker:', err);
109
+ }
110
+ }
111
+ }
112
+ //# sourceMappingURL=changes.js.map