brainclaw 0.29.2 → 1.5.4

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 (197) hide show
  1. package/LICENSE +21 -74
  2. package/README.md +199 -176
  3. package/dist/brainclaw-vscode.vsix +0 -0
  4. package/dist/cli.js +710 -25
  5. package/dist/commands/accept.js +3 -0
  6. package/dist/commands/add-step.js +11 -26
  7. package/dist/commands/agent-board.js +70 -3
  8. package/dist/commands/audit.js +19 -0
  9. package/dist/commands/check-policy.js +54 -0
  10. package/dist/commands/check-security-mcp.js +145 -0
  11. package/dist/commands/check-security.js +106 -0
  12. package/dist/commands/claim-resource.js +1 -0
  13. package/dist/commands/codev.js +672 -0
  14. package/dist/commands/compact.js +74 -0
  15. package/dist/commands/complete-step.js +16 -26
  16. package/dist/commands/constraint.js +8 -20
  17. package/dist/commands/decision.js +9 -20
  18. package/dist/commands/delete-plan.js +10 -12
  19. package/dist/commands/delete-step.js +16 -0
  20. package/dist/commands/dispatch.js +163 -0
  21. package/dist/commands/doctor.js +1122 -49
  22. package/dist/commands/enable-agent.js +1 -0
  23. package/dist/commands/export.js +280 -22
  24. package/dist/commands/handoff.js +33 -0
  25. package/dist/commands/harvest.js +189 -0
  26. package/dist/commands/hooks.js +82 -25
  27. package/dist/commands/inbox.js +169 -0
  28. package/dist/commands/init.js +38 -31
  29. package/dist/commands/install-hooks.js +71 -44
  30. package/dist/commands/link.js +89 -0
  31. package/dist/commands/list-claims.js +48 -3
  32. package/dist/commands/list-plans.js +129 -25
  33. package/dist/commands/loops-handlers.js +409 -0
  34. package/dist/commands/mcp-read-handlers.js +1628 -0
  35. package/dist/commands/mcp-schemas.generated.js +269 -0
  36. package/dist/commands/mcp.js +4224 -1501
  37. package/dist/commands/plan-resource.js +64 -0
  38. package/dist/commands/plan.js +12 -26
  39. package/dist/commands/prune.js +37 -2
  40. package/dist/commands/reflect.js +20 -7
  41. package/dist/commands/release-claim.js +11 -6
  42. package/dist/commands/release-notes.js +170 -0
  43. package/dist/commands/repair.js +210 -0
  44. package/dist/commands/run-profile.js +57 -0
  45. package/dist/commands/sequence.js +113 -0
  46. package/dist/commands/session-end.js +423 -14
  47. package/dist/commands/session-start.js +214 -41
  48. package/dist/commands/setup-security.js +103 -0
  49. package/dist/commands/setup.js +42 -4
  50. package/dist/commands/stale.js +109 -0
  51. package/dist/commands/switch.js +100 -2
  52. package/dist/commands/trap.js +14 -31
  53. package/dist/commands/update-handoff.js +63 -4
  54. package/dist/commands/update-plan.js +21 -28
  55. package/dist/commands/update-step.js +37 -0
  56. package/dist/commands/upgrade.js +313 -6
  57. package/dist/commands/usage.js +102 -0
  58. package/dist/commands/version.js +20 -0
  59. package/dist/commands/who.js +33 -5
  60. package/dist/commands/worktree.js +105 -0
  61. package/dist/core/actions.js +315 -0
  62. package/dist/core/agent-capability.js +610 -17
  63. package/dist/core/agent-context.js +7 -1
  64. package/dist/core/agent-files.js +1169 -85
  65. package/dist/core/agent-integrations.js +160 -5
  66. package/dist/core/agent-inventory.js +2 -0
  67. package/dist/core/agent-profiles.js +93 -0
  68. package/dist/core/agent-registry.js +162 -30
  69. package/dist/core/agentrun-reconciler.js +345 -0
  70. package/dist/core/agentruns.js +424 -0
  71. package/dist/core/ai-agent-detection.js +31 -10
  72. package/dist/core/archival.js +77 -0
  73. package/dist/core/assignment-sweeper.js +82 -0
  74. package/dist/core/assignments.js +367 -0
  75. package/dist/core/audit.js +30 -0
  76. package/dist/core/brainclaw-version.js +94 -2
  77. package/dist/core/candidates.js +93 -2
  78. package/dist/core/claims.js +419 -0
  79. package/dist/core/codev-metrics.js +77 -0
  80. package/dist/core/codev-personas.js +31 -0
  81. package/dist/core/codev-plan-gen.js +35 -0
  82. package/dist/core/codev-prompts.js +74 -0
  83. package/dist/core/codev-responses.js +62 -0
  84. package/dist/core/codev-rounds.js +218 -0
  85. package/dist/core/config.js +4 -0
  86. package/dist/core/context.js +381 -34
  87. package/dist/core/coordination.js +201 -6
  88. package/dist/core/cross-project.js +230 -16
  89. package/dist/core/default-profiles/doctor.yaml +11 -0
  90. package/dist/core/default-profiles/janitor.yaml +11 -0
  91. package/dist/core/default-profiles/onboarder.yaml +11 -0
  92. package/dist/core/default-profiles/reviewer.yaml +13 -0
  93. package/dist/core/dispatcher.js +1189 -0
  94. package/dist/core/duplicates.js +2 -2
  95. package/dist/core/entity-operations.js +450 -0
  96. package/dist/core/entity-registry.js +344 -0
  97. package/dist/core/events.js +106 -2
  98. package/dist/core/execution-adapters.js +154 -0
  99. package/dist/core/execution-context.js +63 -0
  100. package/dist/core/execution-profile.js +270 -0
  101. package/dist/core/execution.js +255 -0
  102. package/dist/core/facade-schema.js +81 -0
  103. package/dist/core/federation-cloud.js +99 -0
  104. package/dist/core/federation-message.js +52 -0
  105. package/dist/core/federation-transport.js +65 -0
  106. package/dist/core/gc-semantic.js +482 -0
  107. package/dist/core/governance.js +247 -0
  108. package/dist/core/guards.js +19 -0
  109. package/dist/core/ideation.js +72 -0
  110. package/dist/core/identity.js +110 -25
  111. package/dist/core/ids.js +6 -0
  112. package/dist/core/input-validation.js +2 -2
  113. package/dist/core/instruction-templates.js +344 -136
  114. package/dist/core/io.js +90 -11
  115. package/dist/core/lock.js +6 -2
  116. package/dist/core/loops/brief-assembly.js +213 -0
  117. package/dist/core/loops/facade-schema.js +148 -0
  118. package/dist/core/loops/index.js +7 -0
  119. package/dist/core/loops/iteration-engine.js +139 -0
  120. package/dist/core/loops/lock.js +385 -0
  121. package/dist/core/loops/store.js +201 -0
  122. package/dist/core/loops/types.js +403 -0
  123. package/dist/core/loops/verbs.js +534 -0
  124. package/dist/core/markdown.js +15 -3
  125. package/dist/core/memory-compactor.js +432 -0
  126. package/dist/core/memory-git.js +152 -8
  127. package/dist/core/messaging.js +278 -0
  128. package/dist/core/migration.js +32 -1
  129. package/dist/core/mutation-pipeline.js +4 -2
  130. package/dist/core/operations/memory-mutation.js +129 -0
  131. package/dist/core/operations/memory-write.js +78 -0
  132. package/dist/core/operations/plan.js +190 -0
  133. package/dist/core/policy.js +169 -0
  134. package/dist/core/reputation.js +9 -3
  135. package/dist/core/schema.js +491 -6
  136. package/dist/core/search.js +21 -2
  137. package/dist/core/security-cache.js +71 -0
  138. package/dist/core/security-guard.js +152 -0
  139. package/dist/core/security-scoring.js +86 -0
  140. package/dist/core/sequence.js +130 -0
  141. package/dist/core/socket-client.js +113 -0
  142. package/dist/core/staleness.js +246 -0
  143. package/dist/core/state.js +98 -22
  144. package/dist/core/store-resolution.js +43 -11
  145. package/dist/core/toml-writer.js +76 -0
  146. package/dist/core/upgrades/backup.js +232 -0
  147. package/dist/core/upgrades/health-check.js +169 -0
  148. package/dist/core/upgrades/patches/candidate-archive.js +145 -0
  149. package/dist/core/upgrades/patches/handoff-review-strip.js +128 -0
  150. package/dist/core/upgrades/patches/provenance-rollout.js +136 -0
  151. package/dist/core/upgrades/schema-version.js +97 -0
  152. package/dist/core/worktree.js +606 -0
  153. package/dist/facts.js +114 -0
  154. package/dist/facts.json +111 -0
  155. package/docs/architecture/project-refs.md +5 -1
  156. package/docs/cli.md +690 -43
  157. package/docs/concepts/ideation-loop.md +317 -0
  158. package/docs/concepts/loop-engine.md +456 -0
  159. package/docs/concepts/mcp-governance.md +268 -0
  160. package/docs/concepts/memory-staleness.md +122 -0
  161. package/docs/concepts/multi-agent-workflows.md +166 -0
  162. package/docs/concepts/plans-and-claims.md +31 -6
  163. package/docs/concepts/project-md-convention.md +35 -0
  164. package/docs/concepts/troubleshooting.md +220 -0
  165. package/docs/concepts/upgrade-cli.md +202 -0
  166. package/docs/concepts/upgrade-dogfood-procedure.md +114 -0
  167. package/docs/context-format-changelog.md +2 -2
  168. package/docs/context-format.md +2 -2
  169. package/docs/index.md +68 -0
  170. package/docs/integrations/agents.md +15 -16
  171. package/docs/integrations/cline.md +88 -0
  172. package/docs/integrations/codex.md +75 -23
  173. package/docs/integrations/continue.md +60 -0
  174. package/docs/integrations/copilot.md +67 -9
  175. package/docs/integrations/kilocode.md +72 -0
  176. package/docs/integrations/mcp.md +304 -21
  177. package/docs/integrations/mistral-vibe.md +122 -0
  178. package/docs/integrations/opencode.md +84 -0
  179. package/docs/integrations/overview.md +23 -8
  180. package/docs/integrations/roo.md +74 -0
  181. package/docs/integrations/windsurf.md +83 -0
  182. package/docs/mcp-schema-changelog.md +191 -1
  183. package/docs/playbooks/integration/index.md +121 -0
  184. package/docs/playbooks/productivity/index.md +102 -0
  185. package/docs/playbooks/team/index.md +122 -0
  186. package/docs/product/agent-first-model.md +184 -0
  187. package/docs/product/entity-model-audit.md +462 -0
  188. package/docs/product/positioning.md +10 -10
  189. package/docs/quickstart-existing-project.md +135 -0
  190. package/docs/quickstart.md +124 -37
  191. package/docs/release-maintenance.md +79 -0
  192. package/docs/review.md +2 -0
  193. package/docs/server-operations.md +118 -0
  194. package/package.json +21 -13
  195. package/dist/commands/claude-desktop-extension.js +0 -18
  196. package/dist/commands/diff.js +0 -99
  197. package/dist/core/claude-desktop-extension.js +0 -224
@@ -0,0 +1,315 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { JsonStore } from './json-store.js';
4
+ import { resolveEntityDir } from './io.js';
5
+ import { mutate } from './mutation-pipeline.js';
6
+ import { nowISO, generateIdWithLabel } from './ids.js';
7
+ import { ActionRequiredSchema, } from './schema.js';
8
+ import { saveVersionedJsonFile } from './migration.js';
9
+ import { appendAuditEntry } from './audit.js';
10
+ import { createRuntimeEvent } from './events.js';
11
+ import { loadAssignment, transitionAssignment } from './assignments.js';
12
+ import { loadAgentRun, transitionAgentRun } from './agentruns.js';
13
+ function actionsDir(cwd, mode = 'read') {
14
+ return resolveEntityDir('actions', cwd ?? process.cwd(), mode);
15
+ }
16
+ function ensureActionsDir(cwd) {
17
+ const dir = actionsDir(cwd, 'write');
18
+ if (!fs.existsSync(dir)) {
19
+ fs.mkdirSync(dir, { recursive: true });
20
+ }
21
+ }
22
+ function actionStore(cwd) {
23
+ return new JsonStore({
24
+ dirPath: actionsDir(cwd, 'read'),
25
+ documentType: 'action_required',
26
+ getId: (action) => action.id,
27
+ sort: (a, b) => a.created_at.localeCompare(b.created_at),
28
+ });
29
+ }
30
+ export function loadActionRequired(id, cwd) {
31
+ return actionStore(cwd).load(id);
32
+ }
33
+ /** Default TTL for pending actions (1 hour). */
34
+ const ACTION_DEFAULT_TTL_MS = 60 * 60 * 1000;
35
+ /**
36
+ * Expire stale pending actions on read.
37
+ * Called lazily during list() to avoid needing a separate sweeper process.
38
+ */
39
+ function expireStaleActions(actions, cwd) {
40
+ const now = Date.now();
41
+ for (const action of actions) {
42
+ if (action.status !== 'pending')
43
+ continue;
44
+ const expiresAt = action.expires_at
45
+ ? new Date(action.expires_at).getTime()
46
+ : new Date(action.created_at).getTime() + ACTION_DEFAULT_TTL_MS;
47
+ if (now > expiresAt) {
48
+ action.status = 'expired';
49
+ action.updated_at = nowISO();
50
+ try {
51
+ saveActionRequired(action, cwd);
52
+ }
53
+ catch { /* best-effort */ }
54
+ const expiryReason = `Action required expired: ${action.title}`;
55
+ try {
56
+ const run = action.run_id ? loadAgentRun(action.run_id, cwd) : undefined;
57
+ if (run && !['completed', 'failed', 'cancelled', 'timed_out', 'interrupted'].includes(run.status)) {
58
+ transitionAgentRun(run.id, 'timed_out', {
59
+ actor: action.agent,
60
+ actor_id: action.agent_id,
61
+ session_id: action.session_id,
62
+ status_reason: expiryReason,
63
+ }, cwd);
64
+ }
65
+ }
66
+ catch { /* best-effort */ }
67
+ try {
68
+ const assignment = loadAssignment(action.assignment_id, cwd);
69
+ if (assignment && assignment.status === 'blocked') {
70
+ transitionAssignment(assignment.id, 'failed', {
71
+ actor: action.agent,
72
+ actor_id: action.agent_id,
73
+ session_id: action.session_id,
74
+ status_reason: expiryReason,
75
+ error_message: expiryReason,
76
+ }, cwd);
77
+ }
78
+ }
79
+ catch { /* best-effort */ }
80
+ try {
81
+ appendAuditEntry({
82
+ actor: action.agent,
83
+ actor_id: action.agent_id,
84
+ action: 'update',
85
+ item_id: action.id,
86
+ item_type: 'state',
87
+ before: { status: 'pending' },
88
+ after: { status: 'expired' },
89
+ scope: action.scope,
90
+ session_id: action.session_id,
91
+ }, cwd);
92
+ }
93
+ catch { /* best-effort */ }
94
+ try {
95
+ createRuntimeEvent({
96
+ agent: action.agent,
97
+ agent_id: action.agent_id,
98
+ session_id: action.session_id,
99
+ event_type: 'observation',
100
+ text: `Action expired: ${action.title}`,
101
+ tags: ['agent-runtime', 'action-expired', `kind:${action.kind}`],
102
+ assignment_id: action.assignment_id,
103
+ run_id: action.run_id,
104
+ claim_id: action.claim_id,
105
+ plan_id: action.plan_id,
106
+ sequence_id: action.sequence_id,
107
+ scope: action.scope,
108
+ status: action.status,
109
+ status_reason: expiryReason,
110
+ metadata: {
111
+ protocol: 'brainclaw.agent_runtime.action_required.v1',
112
+ action_id: action.id,
113
+ outcome: 'expired',
114
+ },
115
+ }, cwd);
116
+ }
117
+ catch { /* best-effort */ }
118
+ }
119
+ }
120
+ return actions;
121
+ }
122
+ export function listActionRequired(cwd, filter = {}) {
123
+ let actions = actionStore(cwd).list();
124
+ // Sweep-on-read: expire stale pending actions
125
+ actions = expireStaleActions(actions, cwd);
126
+ if (filter.status)
127
+ actions = actions.filter((action) => action.status === filter.status);
128
+ if (filter.kind)
129
+ actions = actions.filter((action) => action.kind === filter.kind);
130
+ if (filter.agent)
131
+ actions = actions.filter((action) => action.agent === filter.agent);
132
+ if (filter.assignment_id)
133
+ actions = actions.filter((action) => action.assignment_id === filter.assignment_id);
134
+ if (filter.run_id)
135
+ actions = actions.filter((action) => action.run_id === filter.run_id);
136
+ if (filter.claim_id)
137
+ actions = actions.filter((action) => action.claim_id === filter.claim_id);
138
+ if (filter.plan_id)
139
+ actions = actions.filter((action) => action.plan_id === filter.plan_id);
140
+ if (filter.sequence_id)
141
+ actions = actions.filter((action) => action.sequence_id === filter.sequence_id);
142
+ return actions;
143
+ }
144
+ function saveActionRequired(action, cwd) {
145
+ mutate({ cwd }, () => {
146
+ ensureActionsDir(cwd);
147
+ const filepath = path.join(actionsDir(cwd, 'write'), `${action.id}.json`);
148
+ saveVersionedJsonFile('action_required', filepath, ActionRequiredSchema.parse(action));
149
+ });
150
+ }
151
+ export function createActionRequired(options, cwd) {
152
+ const generated = generateIdWithLabel('actions', cwd);
153
+ const now = nowISO();
154
+ const action = ActionRequiredSchema.parse({
155
+ schema_version: 1,
156
+ id: generated.id,
157
+ short_label: generated.short_label,
158
+ assignment_id: options.assignment_id,
159
+ run_id: options.run_id,
160
+ claim_id: options.claim_id,
161
+ message_id: options.message_id,
162
+ plan_id: options.plan_id,
163
+ sequence_id: options.sequence_id,
164
+ agent: options.agent,
165
+ agent_id: options.agent_id,
166
+ session_id: options.session_id,
167
+ kind: options.kind,
168
+ status: 'pending',
169
+ scope: options.scope,
170
+ title: options.title,
171
+ prompt: options.prompt,
172
+ options: options.options ?? [],
173
+ response_schema: options.response_schema,
174
+ created_at: now,
175
+ updated_at: now,
176
+ expires_at: new Date(Date.now() + (options.ttl_ms ?? ACTION_DEFAULT_TTL_MS)).toISOString(),
177
+ tags: options.tags ?? [],
178
+ });
179
+ saveActionRequired(action, cwd);
180
+ appendAuditEntry({
181
+ actor: options.agent,
182
+ actor_id: options.agent_id,
183
+ action: 'create',
184
+ item_id: action.id,
185
+ item_type: 'state',
186
+ after: { kind: action.kind, assignment_id: action.assignment_id, run_id: action.run_id },
187
+ scope: action.scope,
188
+ session_id: action.session_id,
189
+ }, cwd);
190
+ createRuntimeEvent({
191
+ agent: options.agent,
192
+ agent_id: options.agent_id,
193
+ session_id: options.session_id,
194
+ event_type: 'observation',
195
+ text: `Action required: ${action.title}`,
196
+ tags: ['agent-runtime', 'action-required', `kind:${action.kind}`],
197
+ assignment_id: action.assignment_id,
198
+ run_id: action.run_id,
199
+ claim_id: action.claim_id,
200
+ plan_id: action.plan_id,
201
+ sequence_id: action.sequence_id,
202
+ scope: action.scope,
203
+ status: action.status,
204
+ status_reason: action.prompt,
205
+ metadata: {
206
+ protocol: 'brainclaw.agent_runtime.action_required.v1',
207
+ action_id: action.id,
208
+ kind: action.kind,
209
+ },
210
+ }, cwd);
211
+ return action;
212
+ }
213
+ export function resolveActionRequired(id, options, cwd) {
214
+ // Wrap the entire load-check-mutate-save cycle in mutate() to prevent
215
+ // TOCTOU races where two supervisors resolve the same action concurrently.
216
+ // The inner saveActionRequired also calls mutate(), but the lock is reentrant.
217
+ return mutate({ cwd }, () => {
218
+ const action = loadActionRequired(id, cwd);
219
+ if (!action) {
220
+ throw new Error(`ActionRequired not found: ${id}`);
221
+ }
222
+ if (action.status !== 'pending') {
223
+ throw new Error(`ActionRequired ${id} is already ${action.status}`);
224
+ }
225
+ const now = nowISO();
226
+ action.status = options.outcome;
227
+ action.updated_at = now;
228
+ action.resolved_at = now;
229
+ action.response = {
230
+ outcome: options.outcome,
231
+ text: options.text,
232
+ payload: options.payload,
233
+ responded_by: options.responded_by,
234
+ responded_by_id: options.responded_by_id,
235
+ responded_at: now,
236
+ };
237
+ saveActionRequired(action, cwd);
238
+ appendAuditEntry({
239
+ actor: options.responded_by,
240
+ actor_id: options.responded_by_id,
241
+ action: 'update',
242
+ item_id: action.id,
243
+ item_type: 'state',
244
+ before: { status: 'pending' },
245
+ after: { status: action.status },
246
+ scope: action.scope,
247
+ session_id: options.session_id,
248
+ }, cwd);
249
+ const runtimeStatusMessage = options.text ?? `${action.kind} ${options.outcome}`;
250
+ if (action.run_id) {
251
+ const run = loadAgentRun(action.run_id, cwd);
252
+ if (run) {
253
+ if (options.outcome === 'resolved' && ['blocked', 'waiting_input'].includes(run.status)) {
254
+ transitionAgentRun(run.id, 'running', {
255
+ actor: options.responded_by,
256
+ actor_id: options.responded_by_id,
257
+ session_id: options.session_id,
258
+ status_reason: runtimeStatusMessage,
259
+ }, cwd);
260
+ }
261
+ else if (options.outcome !== 'resolved' && !['completed', 'failed', 'cancelled', 'timed_out', 'interrupted'].includes(run.status)) {
262
+ transitionAgentRun(run.id, 'cancelled', {
263
+ actor: options.responded_by,
264
+ actor_id: options.responded_by_id,
265
+ session_id: options.session_id,
266
+ status_reason: runtimeStatusMessage,
267
+ }, cwd);
268
+ }
269
+ }
270
+ }
271
+ const assignment = loadAssignment(action.assignment_id, cwd);
272
+ if (assignment) {
273
+ if (options.outcome === 'resolved' && assignment.status === 'blocked') {
274
+ transitionAssignment(assignment.id, 'started', {
275
+ actor: options.responded_by,
276
+ actor_id: options.responded_by_id,
277
+ session_id: options.session_id,
278
+ status_reason: runtimeStatusMessage,
279
+ }, cwd);
280
+ }
281
+ else if (options.outcome !== 'resolved' && assignment.status === 'blocked') {
282
+ transitionAssignment(assignment.id, 'failed', {
283
+ actor: options.responded_by,
284
+ actor_id: options.responded_by_id,
285
+ session_id: options.session_id,
286
+ status_reason: runtimeStatusMessage,
287
+ error_message: runtimeStatusMessage,
288
+ }, cwd);
289
+ }
290
+ }
291
+ createRuntimeEvent({
292
+ agent: options.responded_by,
293
+ agent_id: options.responded_by_id,
294
+ session_id: options.session_id,
295
+ event_type: 'observation',
296
+ text: `Action ${options.outcome}: ${action.title}`,
297
+ tags: ['agent-runtime', 'action-response', `kind:${action.kind}`],
298
+ assignment_id: action.assignment_id,
299
+ run_id: action.run_id,
300
+ claim_id: action.claim_id,
301
+ plan_id: action.plan_id,
302
+ sequence_id: action.sequence_id,
303
+ scope: action.scope,
304
+ status: action.status,
305
+ status_reason: runtimeStatusMessage,
306
+ metadata: {
307
+ protocol: 'brainclaw.agent_runtime.action_required.v1',
308
+ action_id: action.id,
309
+ outcome: options.outcome,
310
+ },
311
+ }, cwd);
312
+ return action;
313
+ });
314
+ }
315
+ //# sourceMappingURL=actions.js.map