brainclaw 0.19.5 → 0.19.7

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 (151) hide show
  1. package/LICENSE +0 -0
  2. package/README.md +22 -20
  3. package/dist/cli.js +0 -0
  4. package/dist/commands/accept.js +102 -104
  5. package/dist/commands/adapter-openclaw-import.js +0 -0
  6. package/dist/commands/add-step.js +3 -5
  7. package/dist/commands/agent-board.js +0 -0
  8. package/dist/commands/audit.js +0 -0
  9. package/dist/commands/bootstrap.js +0 -0
  10. package/dist/commands/capability.js +3 -5
  11. package/dist/commands/changes.js +0 -0
  12. package/dist/commands/check-constraints.js +0 -0
  13. package/dist/commands/claim-resource.js +0 -0
  14. package/dist/commands/claim.js +14 -12
  15. package/dist/commands/complete-step.js +3 -5
  16. package/dist/commands/constraint.js +3 -5
  17. package/dist/commands/context-diff.js +0 -0
  18. package/dist/commands/context.js +0 -0
  19. package/dist/commands/decision.js +3 -6
  20. package/dist/commands/delete-plan.js +3 -5
  21. package/dist/commands/diff.js +0 -0
  22. package/dist/commands/doctor.js +0 -0
  23. package/dist/commands/enable-agent.js +0 -0
  24. package/dist/commands/env.js +0 -0
  25. package/dist/commands/estimation-report.js +0 -0
  26. package/dist/commands/explore.js +0 -0
  27. package/dist/commands/export.js +0 -0
  28. package/dist/commands/handoff.js +3 -5
  29. package/dist/commands/history.js +0 -0
  30. package/dist/commands/hooks.js +0 -0
  31. package/dist/commands/init.js +0 -0
  32. package/dist/commands/install-hooks.js +0 -0
  33. package/dist/commands/instruction.js +16 -9
  34. package/dist/commands/list-agents.js +0 -0
  35. package/dist/commands/list-claims.js +0 -0
  36. package/dist/commands/list-instructions.js +0 -0
  37. package/dist/commands/list-plans.js +0 -0
  38. package/dist/commands/mcp-worker.js +0 -0
  39. package/dist/commands/mcp.js +11 -21
  40. package/dist/commands/memory.js +4 -7
  41. package/dist/commands/metrics.js +0 -0
  42. package/dist/commands/plan-resource.js +0 -0
  43. package/dist/commands/plan.js +3 -5
  44. package/dist/commands/prune-candidates.js +0 -0
  45. package/dist/commands/prune.js +27 -25
  46. package/dist/commands/pull.js +0 -0
  47. package/dist/commands/push.js +0 -0
  48. package/dist/commands/rebuild.js +0 -0
  49. package/dist/commands/reflect-runtime-note.js +0 -0
  50. package/dist/commands/reflect.js +3 -5
  51. package/dist/commands/register-agent.js +0 -0
  52. package/dist/commands/reject.js +0 -0
  53. package/dist/commands/release-claim.js +23 -20
  54. package/dist/commands/release-claims.js +22 -21
  55. package/dist/commands/review.js +0 -0
  56. package/dist/commands/rollback.js +2 -2
  57. package/dist/commands/runtime-note.js +0 -0
  58. package/dist/commands/runtime-status.js +0 -0
  59. package/dist/commands/search.js +0 -0
  60. package/dist/commands/session-end.js +0 -0
  61. package/dist/commands/session-start.js +0 -0
  62. package/dist/commands/set-trust.js +0 -0
  63. package/dist/commands/setup.js +0 -0
  64. package/dist/commands/show-candidate.js +0 -0
  65. package/dist/commands/star-candidate.js +0 -0
  66. package/dist/commands/status.js +0 -0
  67. package/dist/commands/sync.js +0 -0
  68. package/dist/commands/tool.js +3 -5
  69. package/dist/commands/trap.js +3 -5
  70. package/dist/commands/update-handoff.js +3 -5
  71. package/dist/commands/update-plan.js +3 -5
  72. package/dist/commands/upgrade.js +2 -2
  73. package/dist/commands/use-candidate.js +0 -0
  74. package/dist/commands/version.js +0 -0
  75. package/dist/commands/watch.js +0 -0
  76. package/dist/commands/whoami.js +0 -0
  77. package/dist/core/agent-context.js +0 -0
  78. package/dist/core/agent-files.js +0 -0
  79. package/dist/core/agent-integrations.js +0 -0
  80. package/dist/core/agent-inventory.js +0 -0
  81. package/dist/core/agent-registry.js +0 -0
  82. package/dist/core/ai-agent-detection.js +0 -0
  83. package/dist/core/audit.js +25 -25
  84. package/dist/core/bootstrap.js +0 -0
  85. package/dist/core/brainclaw-version.js +0 -0
  86. package/dist/core/candidates.js +10 -6
  87. package/dist/core/circuit-breaker.js +0 -0
  88. package/dist/core/claims.js +10 -8
  89. package/dist/core/config.js +0 -0
  90. package/dist/core/context-diff.js +0 -0
  91. package/dist/core/context.js +0 -0
  92. package/dist/core/contradictions.js +0 -0
  93. package/dist/core/coordination.js +2 -2
  94. package/dist/core/cross-project.js +0 -0
  95. package/dist/core/duplicates.js +0 -0
  96. package/dist/core/event-log.js +0 -0
  97. package/dist/core/events.js +0 -0
  98. package/dist/core/execution-context.js +0 -0
  99. package/dist/core/freshness.js +0 -0
  100. package/dist/core/global-registry.js +0 -0
  101. package/dist/core/host.js +0 -0
  102. package/dist/core/identity.js +0 -0
  103. package/dist/core/ids.js +0 -0
  104. package/dist/core/input-validation.js +0 -0
  105. package/dist/core/instructions.js +4 -2
  106. package/dist/core/io.js +8 -0
  107. package/dist/core/json-store.js +0 -0
  108. package/dist/core/lifecycle.js +0 -0
  109. package/dist/core/lock.js +18 -2
  110. package/dist/core/logger.js +0 -0
  111. package/dist/core/machine-profile.js +0 -0
  112. package/dist/core/markdown.js +0 -0
  113. package/dist/core/memory-git.js +0 -0
  114. package/dist/core/migration.js +0 -0
  115. package/dist/core/project-registry.js +0 -0
  116. package/dist/core/reflection-safety.js +0 -0
  117. package/dist/core/repo-analysis.js +0 -0
  118. package/dist/core/reputation.js +0 -0
  119. package/dist/core/runtime.js +18 -14
  120. package/dist/core/schema.js +0 -0
  121. package/dist/core/search.js +0 -0
  122. package/dist/core/security.js +0 -0
  123. package/dist/core/setup-state.js +0 -0
  124. package/dist/core/state.js +21 -4
  125. package/dist/core/store-resolution.js +0 -0
  126. package/dist/core/sync-remote.js +0 -0
  127. package/dist/core/traps.js +0 -0
  128. package/docs/adapters/openclaw.md +43 -0
  129. package/docs/cli.md +1230 -0
  130. package/docs/concepts/coordination.md +52 -0
  131. package/docs/concepts/memory.md +87 -0
  132. package/docs/concepts/plans-and-claims.md +139 -0
  133. package/docs/concepts/runtime-notes.md +38 -0
  134. package/docs/concepts/workspace-bootstrapping.md +40 -0
  135. package/docs/context-format-changelog.md +35 -0
  136. package/docs/context-format.md +48 -0
  137. package/docs/integrations/agents.md +169 -0
  138. package/docs/integrations/claude-code.md +23 -0
  139. package/docs/integrations/codex.md +23 -0
  140. package/docs/integrations/copilot.md +21 -0
  141. package/docs/integrations/cursor.md +23 -0
  142. package/docs/integrations/mcp.md +51 -0
  143. package/docs/integrations/overview.md +61 -0
  144. package/docs/mcp-schema-changelog.md +108 -0
  145. package/docs/product/positioning.md +97 -0
  146. package/docs/quickstart.md +99 -0
  147. package/docs/reputation.md +52 -0
  148. package/docs/review.md +43 -0
  149. package/docs/security.md +53 -0
  150. package/docs/storage.md +81 -0
  151. package/package.json +7 -6
package/LICENSE CHANGED
File without changes
package/README.md CHANGED
@@ -118,7 +118,7 @@ brainclaw plan create "Coordinate auth rollout" --priority high
118
118
  brainclaw context --json
119
119
  ```
120
120
 
121
- [Full quickstart guide](https://github.com/jberdah/brainclaw/blob/master/docs/quickstart.md)
121
+ Detailed Markdown guides are bundled in the npm package under `docs/`.
122
122
 
123
123
  ---
124
124
 
@@ -154,25 +154,27 @@ brainclaw can also expose collaboration views through MCP-readable tools, includ
154
154
 
155
155
  ---
156
156
 
157
- ## Documentation
158
-
159
- | | |
160
- |---|---|
161
- | [docs/quickstart.md](https://github.com/jberdah/brainclaw/blob/master/docs/quickstart.md) | Get started in 5 minutes |
162
- | [docs/cli.md](https://github.com/jberdah/brainclaw/blob/master/docs/cli.md) | Full command reference |
163
- | [docs/concepts/memory.md](https://github.com/jberdah/brainclaw/blob/master/docs/concepts/memory.md) | What "memory" means in brainclaw |
164
- | [docs/concepts/plans-and-claims.md](https://github.com/jberdah/brainclaw/blob/master/docs/concepts/plans-and-claims.md) | Coordination layer |
165
- | [docs/concepts/runtime-notes.md](https://github.com/jberdah/brainclaw/blob/master/docs/concepts/runtime-notes.md) | Ephemeral observations |
166
- | [docs/integrations/overview.md](https://github.com/jberdah/brainclaw/blob/master/docs/integrations/overview.md) | How to integrate with any agent |
167
- | [docs/integrations/cursor.md](https://github.com/jberdah/brainclaw/blob/master/docs/integrations/cursor.md) | Cursor |
168
- | [docs/integrations/claude-code.md](https://github.com/jberdah/brainclaw/blob/master/docs/integrations/claude-code.md) | Claude Code |
169
- | [docs/integrations/copilot.md](https://github.com/jberdah/brainclaw/blob/master/docs/integrations/copilot.md) | GitHub Copilot |
170
- | [docs/integrations/codex.md](https://github.com/jberdah/brainclaw/blob/master/docs/integrations/codex.md) | Codex |
171
- | [docs/integrations/mcp.md](https://github.com/jberdah/brainclaw/blob/master/docs/integrations/mcp.md) | MCP tools |
172
- | [docs/storage.md](https://github.com/jberdah/brainclaw/blob/master/docs/storage.md) | Storage model |
173
- | [docs/security.md](https://github.com/jberdah/brainclaw/blob/master/docs/security.md) | Security model |
174
- | [docs/review.md](https://github.com/jberdah/brainclaw/blob/master/docs/review.md) | Reflective review |
175
- | [docs/reputation.md](https://github.com/jberdah/brainclaw/blob/master/docs/reputation.md) | Reputation signals |
157
+ ## Documentation
158
+
159
+ The npm package includes the Markdown docs below under `docs/`. Public web docs on `brainclaw.dev` are still being rolled out, so the npm README does not depend on private GitHub links.
160
+
161
+ | | |
162
+ |---|---|
163
+ | `docs/quickstart.md` | Get started in 5 minutes |
164
+ | `docs/cli.md` | Full command reference |
165
+ | `docs/concepts/memory.md` | What "memory" means in brainclaw |
166
+ | `docs/concepts/plans-and-claims.md` | Coordination layer |
167
+ | `docs/concepts/runtime-notes.md` | Ephemeral observations |
168
+ | `docs/integrations/overview.md` | How to integrate with any agent |
169
+ | `docs/integrations/cursor.md` | Cursor |
170
+ | `docs/integrations/claude-code.md` | Claude Code |
171
+ | `docs/integrations/copilot.md` | GitHub Copilot |
172
+ | `docs/integrations/codex.md` | Codex |
173
+ | `docs/integrations/mcp.md` | MCP tools |
174
+ | `docs/storage.md` | Storage model |
175
+ | `docs/security.md` | Security model |
176
+ | `docs/review.md` | Reflective review |
177
+ | `docs/reputation.md` | Reputation signals |
176
178
 
177
179
  ---
178
180
 
package/dist/cli.js CHANGED
File without changes
@@ -1,7 +1,6 @@
1
- import { memoryExists, memoryPath, writeFileAtomic } from '../core/io.js';
1
+ import { memoryExists, withStoreLock } from '../core/io.js';
2
2
  import { loadCandidate, archiveCandidate, resolveIdOrAlias } from '../core/candidates.js';
3
- import { loadState, saveState } from '../core/state.js';
4
- import { generateMarkdown } from '../core/markdown.js';
3
+ import { loadState, persistState } from '../core/state.js';
5
4
  import { generateIdWithLabel, nowISO } from '../core/ids.js';
6
5
  import { generateTrapIdWithLabel } from '../core/traps.js';
7
6
  import { requireMinimumTrustLevel, requireRegisteredAgentIdentity } from '../core/agent-registry.js';
@@ -36,109 +35,108 @@ export function acceptCandidate(id, by, cwd, byId) {
36
35
  });
37
36
  requireMinimumTrustLevel(actorIdentity, 'trusted');
38
37
  const actor = actorIdentity.agent_name;
39
- const state = loadState(cwd);
40
38
  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;
39
+ withStoreLock(cwd, () => {
40
+ const state = loadState(cwd);
41
+ switch (candidate.type) {
42
+ case 'constraint': {
43
+ const { id: entryId, short_label } = generateIdWithLabel('active_constraints', cwd);
44
+ const entry = {
45
+ id: entryId,
46
+ short_label,
47
+ text: candidate.text,
48
+ created_at: candidate.created_at,
49
+ author: candidate.author,
50
+ author_id: candidate.author_id,
51
+ project_id: candidate.project_id,
52
+ host_id: candidate.host_id,
53
+ session_id: candidate.session_id,
54
+ status: 'active',
55
+ tags: candidate.tags,
56
+ };
57
+ state.active_constraints.push(entry);
58
+ promotedItemId = entryId;
59
+ break;
60
+ }
61
+ case 'decision': {
62
+ const { id: entryId, short_label } = generateIdWithLabel('recent_decisions', cwd);
63
+ const entry = {
64
+ id: entryId,
65
+ short_label,
66
+ text: candidate.text,
67
+ created_at: candidate.created_at,
68
+ author: candidate.author,
69
+ author_id: candidate.author_id,
70
+ project_id: candidate.project_id,
71
+ host_id: candidate.host_id,
72
+ session_id: candidate.session_id,
73
+ related_paths: candidate.related_paths,
74
+ plan_id: candidate.plan_id,
75
+ tags: candidate.tags,
76
+ };
77
+ state.recent_decisions.push(entry);
78
+ promotedItemId = entryId;
79
+ break;
80
+ }
81
+ case 'trap': {
82
+ const { id: entryId, short_label } = generateTrapIdWithLabel(cwd);
83
+ const entry = {
84
+ id: entryId,
85
+ short_label,
86
+ text: candidate.text,
87
+ created_at: candidate.created_at,
88
+ author: candidate.author,
89
+ author_id: candidate.author_id,
90
+ project_id: candidate.project_id,
91
+ host_id: candidate.host_id,
92
+ session_id: candidate.session_id,
93
+ status: 'active',
94
+ severity: candidate.severity ?? 'medium',
95
+ tags: candidate.tags,
96
+ plan_id: candidate.plan_id,
97
+ visibility: 'shared',
98
+ };
99
+ state.known_traps.push(entry);
100
+ promotedItemId = entryId;
101
+ break;
102
+ }
103
+ case 'handoff': {
104
+ const { id: entryId, short_label } = generateIdWithLabel('open_handoffs', cwd);
105
+ const entry = {
106
+ id: entryId,
107
+ short_label,
108
+ from: candidate.from ?? 'unknown',
109
+ to: candidate.to ?? 'unknown',
110
+ text: candidate.text,
111
+ created_at: candidate.created_at,
112
+ author: candidate.author,
113
+ author_id: candidate.author_id,
114
+ project_id: candidate.project_id,
115
+ host_id: candidate.host_id,
116
+ session_id: candidate.session_id,
117
+ status: 'open',
118
+ tags: candidate.tags,
119
+ };
120
+ state.open_handoffs.push(entry);
121
+ promotedItemId = entryId;
122
+ break;
123
+ }
61
124
  }
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);
125
+ persistState(state, cwd);
126
+ candidate.status = 'accepted';
127
+ candidate.resolved_at = nowISO();
128
+ candidate.resolved_by = actor;
129
+ archiveCandidate(candidate, 'accepted', cwd);
130
+ appendAuditEntry({
131
+ actor,
132
+ actor_id: actorIdentity.agent_id,
133
+ action: 'accept',
134
+ item_id: resolvedId,
135
+ item_type: candidate.type,
136
+ after: { type: candidate.type, text: candidate.text },
137
+ reason: 'trusted-agent',
138
+ }, cwd);
139
+ });
142
140
  return {
143
141
  candidate_id: resolvedId,
144
142
  candidate_type: candidate.type,
File without changes
@@ -1,7 +1,6 @@
1
- import { loadState, saveState } from '../core/state.js';
2
- import { memoryExists, memoryPath, writeFileAtomic } from '../core/io.js';
1
+ import { loadState, persistState } from '../core/state.js';
2
+ import { memoryExists } from '../core/io.js';
3
3
  import { generateId, nowISO } from '../core/ids.js';
4
- import { generateMarkdown } from '../core/markdown.js';
5
4
  import { validateCliInput } from '../core/input-validation.js';
6
5
  export function runAddStep(planId, text, options = {}) {
7
6
  if (!memoryExists()) {
@@ -25,8 +24,7 @@ export function runAddStep(planId, text, options = {}) {
25
24
  };
26
25
  plan.steps = [...(plan.steps ?? []), step];
27
26
  plan.updated_at = nowISO();
28
- saveState(state);
29
- writeFileAtomic(memoryPath('project.md'), generateMarkdown(state));
27
+ persistState(state);
30
28
  const total = plan.steps.length;
31
29
  const done = plan.steps.filter((s) => s.status === 'done').length;
32
30
  console.log(`✔ Step added: [${step.id}] ${text}`);
File without changes
File without changes
File without changes
@@ -1,7 +1,6 @@
1
- import { loadState, saveState } from '../core/state.js';
1
+ import { loadState, persistState } from '../core/state.js';
2
2
  import { resolveCurrentAgentName } from '../core/agent-registry.js';
3
- import { memoryExists, memoryPath, writeFileAtomic } from '../core/io.js';
4
- import { generateMarkdown } from '../core/markdown.js';
3
+ import { memoryExists } from '../core/io.js';
5
4
  import { generateIdWithLabel, nowISO } from '../core/ids.js';
6
5
  import { loadConfig } from '../core/config.js';
7
6
  import { scanText } from '../core/security.js';
@@ -80,8 +79,7 @@ function runCapabilityAdd(name, description, options, cwd) {
80
79
  // For now, store as decision to avoid schema migration
81
80
  // Will migrate to separate capability storage in v0.16
82
81
  state.recent_decisions.push(entry);
83
- saveState(state, cwd);
84
- writeFileAtomic(memoryPath('project.md', cwd), generateMarkdown(state));
82
+ persistState(state, cwd);
85
83
  console.log(`✔ Capability added: [${id}] ${name}`);
86
84
  console.log(' (Stored in decisions for now; will move to dedicated registry in v0.16)');
87
85
  }
File without changes
File without changes
File without changes
@@ -1,5 +1,5 @@
1
1
  import { buildOperationalIdentity } from '../core/identity.js';
2
- import { memoryExists, memoryPath, writeFileAtomic } from '../core/io.js';
2
+ import { memoryExists, memoryPath, withStoreLock, writeFileAtomic } from '../core/io.js';
3
3
  import { saveClaim, generateClaimId, listClaims } from '../core/claims.js';
4
4
  import { generateMarkdown } from '../core/markdown.js';
5
5
  import { loadState, saveState } from '../core/state.js';
@@ -72,18 +72,20 @@ export function runClaim(description, options) {
72
72
  status: 'active',
73
73
  expires_at: options.ttl ? parseTtl(options.ttl) : undefined,
74
74
  };
75
- if (plan) {
76
- if (!plan.assignee) {
77
- plan.assignee = actor.agent;
75
+ withStoreLock(options.cwd, () => {
76
+ if (plan) {
77
+ if (!plan.assignee) {
78
+ plan.assignee = actor.agent;
79
+ }
80
+ if (plan.status === 'todo') {
81
+ plan.status = 'in_progress';
82
+ }
83
+ plan.updated_at = nowISO();
84
+ saveState(state, options.cwd);
78
85
  }
79
- if (plan.status === 'todo') {
80
- plan.status = 'in_progress';
81
- }
82
- plan.updated_at = nowISO();
83
- saveState(state, options.cwd);
84
- }
85
- saveClaim(claim, options.cwd);
86
- writeFileAtomic(memoryPath('project.md', options.cwd), generateMarkdown(plan ? state : loadState(options.cwd), options.cwd));
86
+ saveClaim(claim, options.cwd);
87
+ writeFileAtomic(memoryPath('project.md', options.cwd), generateMarkdown(plan ? state : loadState(options.cwd), options.cwd));
88
+ });
87
89
  const planInfo = claim.plan_id ? ` [plan ${claim.plan_id}]` : '';
88
90
  const ttlInfo = claim.expires_at ? ` (expires ${claim.expires_at.slice(0, 16).replace('T', ' ')})` : '';
89
91
  const storeLabel = options.store && options.store !== 'local' ? ` [store:${options.store}]` : '';
@@ -1,7 +1,6 @@
1
- import { loadState, saveState } from '../core/state.js';
2
- import { memoryExists, memoryPath, writeFileAtomic } from '../core/io.js';
1
+ import { loadState, persistState } from '../core/state.js';
2
+ import { memoryExists } from '../core/io.js';
3
3
  import { nowISO } from '../core/ids.js';
4
- import { generateMarkdown } from '../core/markdown.js';
5
4
  export function runCompleteStep(planId, stepId) {
6
5
  if (!memoryExists()) {
7
6
  console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
@@ -21,8 +20,7 @@ export function runCompleteStep(planId, stepId) {
21
20
  step.status = 'done';
22
21
  step.updated_at = nowISO();
23
22
  plan.updated_at = nowISO();
24
- saveState(state);
25
- writeFileAtomic(memoryPath('project.md'), generateMarkdown(state));
23
+ persistState(state);
26
24
  const total = plan.steps.length;
27
25
  const done = plan.steps.filter((s) => s.status === 'done').length;
28
26
  console.log(`✔ Step completed: [${step.id}] ${step.text}`);
@@ -1,10 +1,9 @@
1
- import { loadState, saveState } from '../core/state.js';
1
+ import { loadState, persistState } from '../core/state.js';
2
2
  import { resolveCurrentAgentName } from '../core/agent-registry.js';
3
3
  import { loadConfig } from '../core/config.js';
4
- import { generateMarkdown } from '../core/markdown.js';
5
4
  import { generateIdWithLabel, nowISO } from '../core/ids.js';
6
5
  import { scanText } from '../core/security.js';
7
- import { memoryExists, memoryPath, writeFileAtomic } from '../core/io.js';
6
+ import { memoryExists } from '../core/io.js';
8
7
  import { validateCliInput } from '../core/input-validation.js';
9
8
  import { resolveTargetStore } from '../core/store-resolution.js';
10
9
  export function runConstraint(text, options = {}) {
@@ -37,8 +36,7 @@ export function runConstraint(text, options = {}) {
37
36
  related_paths: options.path,
38
37
  };
39
38
  state.active_constraints.push(entry);
40
- saveState(state, cwd);
41
- writeFileAtomic(memoryPath('project.md', cwd), generateMarkdown(state));
39
+ persistState(state, cwd);
42
40
  console.log(`✔ Constraint added: [${id}] ${text}`);
43
41
  }
44
42
  //# sourceMappingURL=constraint.js.map
File without changes
File without changes
@@ -1,10 +1,9 @@
1
- import { loadState, saveState } from '../core/state.js';
1
+ import { loadState, persistState } from '../core/state.js';
2
2
  import { resolveCurrentAgentName } from '../core/agent-registry.js';
3
3
  import { loadConfig } from '../core/config.js';
4
- import { generateMarkdown } from '../core/markdown.js';
5
4
  import { generateIdWithLabel, nowISO } from '../core/ids.js';
6
5
  import { scanText } from '../core/security.js';
7
- import { memoryExists, memoryPath, writeFileAtomic } from '../core/io.js';
6
+ import { memoryExists } from '../core/io.js';
8
7
  import { validateCliInput } from '../core/input-validation.js';
9
8
  import { resolveTargetStore } from '../core/store-resolution.js';
10
9
  export function runDecision(text, options = {}) {
@@ -37,9 +36,7 @@ export function runDecision(text, options = {}) {
37
36
  plan_id: options.plan,
38
37
  };
39
38
  state.recent_decisions.push(entry);
40
- saveState(state, cwd);
41
- // Rebuild markdown
42
- writeFileAtomic(memoryPath('project.md', cwd), generateMarkdown(state));
39
+ persistState(state, cwd);
43
40
  console.log(`✔ Decision added: [${id}] ${text}`);
44
41
  }
45
42
  //# sourceMappingURL=decision.js.map
@@ -1,6 +1,5 @@
1
- import { loadState, saveState } from '../core/state.js';
2
- import { memoryExists, memoryPath, writeFileAtomic } from '../core/io.js';
3
- import { generateMarkdown } from '../core/markdown.js';
1
+ import { loadState, persistState } from '../core/state.js';
2
+ import { memoryExists } from '../core/io.js';
4
3
  export function runDeletePlan(id, options = {}) {
5
4
  if (!memoryExists(options.cwd)) {
6
5
  console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
@@ -13,8 +12,7 @@ export function runDeletePlan(id, options = {}) {
13
12
  process.exit(1);
14
13
  }
15
14
  const [plan] = state.plan_items.splice(index, 1);
16
- saveState(state, options.cwd);
17
- writeFileAtomic(memoryPath('project.md', options.cwd), generateMarkdown(state, options.cwd));
15
+ persistState(state, options.cwd);
18
16
  console.log(`✔ Plan item deleted: [${plan.id}] ${plan.text}`);
19
17
  }
20
18
  //# sourceMappingURL=delete-plan.js.map
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -1,11 +1,10 @@
1
1
  import { execSync } from 'node:child_process';
2
- import { loadState, saveState } from '../core/state.js';
2
+ import { loadState, persistState } from '../core/state.js';
3
3
  import { resolveCurrentAgentName } from '../core/agent-registry.js';
4
4
  import { loadConfig } from '../core/config.js';
5
- import { generateMarkdown } from '../core/markdown.js';
6
5
  import { generateIdWithLabel, nowISO } from '../core/ids.js';
7
6
  import { scanText } from '../core/security.js';
8
- import { memoryExists, memoryPath, writeFileAtomic } from '../core/io.js';
7
+ import { memoryExists } from '../core/io.js';
9
8
  import { validateCliInput } from '../core/input-validation.js';
10
9
  import { resolveTargetStore } from '../core/store-resolution.js';
11
10
  export function runHandoff(text, options) {
@@ -56,8 +55,7 @@ export function runHandoff(text, options) {
56
55
  snapshot: diff ? { diff } : undefined,
57
56
  };
58
57
  state.open_handoffs.push(entry);
59
- saveState(state, cwd);
60
- writeFileAtomic(memoryPath('project.md', cwd), generateMarkdown(state, cwd));
58
+ persistState(state, cwd);
61
59
  console.log(`✔ Handoff added: [${id}] ${options.from} → ${options.to}: ${text}`);
62
60
  }
63
61
  //# sourceMappingURL=handoff.js.map
File without changes
File without changes
File without changes
File without changes
@@ -1,7 +1,7 @@
1
1
  import { resolveAgentScope, resolveCurrentAgentName } from '../core/agent-registry.js';
2
2
  import { loadConfig } from '../core/config.js';
3
3
  import { createInstruction } from '../core/instructions.js';
4
- import { memoryExists, memoryPath, writeFileAtomic } from '../core/io.js';
4
+ import { memoryExists, memoryPath, withStoreLock, writeFileAtomic } from '../core/io.js';
5
5
  import { generateMarkdown } from '../core/markdown.js';
6
6
  import { loadState } from '../core/state.js';
7
7
  import { scanText } from '../core/security.js';
@@ -25,14 +25,21 @@ export function runInstruction(text, options = {}) {
25
25
  process.exit(1);
26
26
  }
27
27
  }
28
- const entry = createInstruction(text, {
29
- layer,
30
- scope,
31
- tags: options.tag,
32
- author: options.author ?? resolveCurrentAgentName(cwd),
33
- supersedes: options.supersedes,
34
- }, cwd);
35
- writeFileAtomic(memoryPath('project.md', cwd), generateMarkdown(loadState(cwd)));
28
+ let entry;
29
+ withStoreLock(cwd, () => {
30
+ entry = createInstruction(text, {
31
+ layer,
32
+ scope,
33
+ tags: options.tag,
34
+ author: options.author ?? resolveCurrentAgentName(cwd),
35
+ supersedes: options.supersedes,
36
+ }, cwd);
37
+ writeFileAtomic(memoryPath('project.md', cwd), generateMarkdown(loadState(cwd)));
38
+ });
39
+ if (!entry) {
40
+ console.error('Error: failed to persist instruction.');
41
+ process.exit(1);
42
+ }
36
43
  console.log(`✔ Instruction added: [${entry.id}] <${entry.layer}${entry.scope ? `:${entry.scope}` : ''}> ${entry.text}`);
37
44
  }
38
45
  function resolveScope(layer, options, cwd) {
File without changes
File without changes
File without changes
File without changes
File without changes