brainclaw 1.8.0 → 1.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +592 -505
- package/dist/brainclaw-vscode.vsix +0 -0
- package/dist/cli.js +138 -13
- package/dist/commands/add-step.js +1 -1
- package/dist/commands/bootstrap.js +2 -26
- package/dist/commands/check-security-mcp.js +50 -33
- package/dist/commands/check-security.js +86 -43
- package/dist/commands/claim.js +22 -21
- package/dist/commands/confirm.js +26 -0
- package/dist/commands/context-diff.js +1 -1
- package/dist/commands/dispatch-watch.js +142 -0
- package/dist/commands/doctor.js +113 -2
- package/dist/commands/estimation-report.js +115 -16
- package/dist/commands/harvest.js +286 -23
- package/dist/commands/hooks.js +73 -73
- package/dist/commands/init.js +124 -22
- package/dist/commands/install-hooks.js +78 -78
- package/dist/commands/loops-handlers.js +4 -0
- package/dist/commands/mcp-read-handlers.js +253 -41
- package/dist/commands/mcp.js +664 -102
- package/dist/commands/memory.js +21 -17
- package/dist/commands/migrate.js +81 -17
- package/dist/commands/prune.js +78 -4
- package/dist/commands/reflect.js +26 -20
- package/dist/commands/register-agent.js +57 -1
- package/dist/commands/repair.js +20 -0
- package/dist/commands/session-end.js +15 -6
- package/dist/commands/session-start.js +18 -1
- package/dist/commands/setup-security.js +39 -18
- package/dist/commands/setup.js +26 -27
- package/dist/commands/stale.js +16 -2
- package/dist/commands/switch.js +26 -5
- package/dist/commands/uninstall.js +126 -34
- package/dist/commands/update-step.js +6 -0
- package/dist/commands/version.js +1 -1
- package/dist/commands/worktree.js +60 -0
- package/dist/core/actions.js +12 -3
- package/dist/core/agent-capability.js +30 -17
- package/dist/core/agent-files.js +963 -666
- package/dist/core/agent-integrations.js +0 -3
- package/dist/core/agent-inventory.js +67 -0
- package/dist/core/agent-registry.js +163 -29
- package/dist/core/agentrun-reconciler.js +33 -2
- package/dist/core/agentruns.js +7 -1
- package/dist/core/ai-agent-detection.js +31 -44
- package/dist/core/archival.js +15 -9
- package/dist/core/assignment-reconciler.js +56 -0
- package/dist/core/assignment-sweeper.js +127 -4
- package/dist/core/assignments.js +69 -11
- package/dist/core/bootstrap.js +233 -67
- package/dist/core/brainclaw-version.js +22 -0
- package/dist/core/candidates.js +21 -1
- package/dist/core/claims.js +313 -150
- package/dist/core/codev-prompts.js +38 -38
- package/dist/core/config.js +6 -1
- package/dist/core/context-diff.js +148 -20
- package/dist/core/context.js +129 -8
- package/dist/core/coordination.js +22 -3
- package/dist/core/default-profiles/doctor.yaml +11 -11
- package/dist/core/default-profiles/janitor.yaml +11 -11
- package/dist/core/default-profiles/onboarder.yaml +11 -11
- package/dist/core/default-profiles/reviewer.yaml +13 -13
- package/dist/core/dispatch-status.js +79 -5
- package/dist/core/dispatcher.js +65 -12
- package/dist/core/entity-operations.js +74 -27
- package/dist/core/entity-registry.js +31 -5
- package/dist/core/event-log.js +138 -21
- package/dist/core/events/checkpoint.js +258 -0
- package/dist/core/events/genesis.js +220 -0
- package/dist/core/events/journal.js +507 -0
- package/dist/core/events/materialize.js +126 -0
- package/dist/core/events/registry-post-image.js +110 -0
- package/dist/core/events/verify.js +109 -0
- package/dist/core/execution-adapters.js +23 -0
- package/dist/core/execution.js +1 -1
- package/dist/core/facade-schema.js +38 -0
- package/dist/core/gc-semantic.js +130 -5
- package/dist/core/handoff-snapshot.js +68 -0
- package/dist/core/ids.js +19 -8
- package/dist/core/instruction-templates.js +34 -115
- package/dist/core/io.js +39 -3
- package/dist/core/json-store.js +10 -1
- package/dist/core/lock.js +153 -28
- package/dist/core/loops/bootstrap-acquire.js +25 -1
- package/dist/core/loops/facade-schema.js +2 -0
- package/dist/core/loops/hooks/survey-signals-baseline.js +36 -0
- package/dist/core/loops/index.js +1 -0
- package/dist/core/loops/presets/bootstrap.js +7 -0
- package/dist/core/loops/store.js +17 -0
- package/dist/core/loops/verbs.js +24 -2
- package/dist/core/markdown.js +8 -76
- package/dist/core/mcp-command-resolution.js +245 -0
- package/dist/core/memory-compactor.js +5 -3
- package/dist/core/memory-lifecycle.js +282 -0
- package/dist/core/merge-risk.js +150 -0
- package/dist/core/messaging.js +10 -3
- package/dist/core/migration.js +11 -1
- package/dist/core/observer-mode.js +26 -0
- package/dist/core/operations/memory-mutation.js +90 -65
- package/dist/core/operations/plan.js +27 -1
- package/dist/core/protocol-skills.js +210 -0
- package/dist/core/reflection-safety.js +6 -7
- package/dist/core/reputation.js +84 -2
- package/dist/core/runtime-signals.js +72 -10
- package/dist/core/runtime.js +84 -1
- package/dist/core/schema.js +114 -0
- package/dist/core/search.js +19 -2
- package/dist/core/security-detectors.js +125 -0
- package/dist/core/security-extract.js +189 -0
- package/dist/core/security-guard.js +217 -139
- package/dist/core/security-packages.js +121 -0
- package/dist/core/security-scoring.js +76 -9
- package/dist/core/security.js +34 -2
- package/dist/core/sequence.js +11 -2
- package/dist/core/setup-flow.js +141 -13
- package/dist/core/spawn-check.js +16 -2
- package/dist/core/staleness.js +73 -2
- package/dist/core/state.js +250 -54
- package/dist/core/store-resolution.js +45 -12
- package/dist/core/worktree.js +90 -26
- package/dist/facts.js +8 -8
- package/dist/facts.json +7 -7
- package/docs/PROTOCOL.md +223 -0
- package/docs/adapters/openclaw.md +43 -43
- package/docs/architecture/project-refs.md +328 -328
- package/docs/cli.md +2097 -2096
- package/docs/concepts/coordination.md +52 -52
- package/docs/concepts/coordinator-runbook.md +129 -0
- package/docs/concepts/dispatch-lifecycle.md +245 -245
- package/docs/concepts/event-log-store.md +928 -0
- package/docs/concepts/ideation-loop.md +317 -317
- package/docs/concepts/loop-engine.md +520 -511
- package/docs/concepts/mcp-governance.md +268 -268
- package/docs/concepts/memory.md +89 -88
- package/docs/concepts/multi-agent-workflows.md +167 -167
- package/docs/concepts/observer-protocol.md +361 -0
- package/docs/concepts/parallel-merge-protocol.md +71 -0
- package/docs/concepts/plans-and-claims.md +217 -174
- package/docs/concepts/project-md-convention.md +35 -35
- package/docs/concepts/runtime-notes.md +38 -38
- package/docs/concepts/skills.md +78 -0
- package/docs/concepts/troubleshooting.md +254 -254
- package/docs/concepts/workspace-bootstrapping.md +142 -81
- package/docs/context-format-changelog.md +35 -35
- package/docs/context-format.md +48 -48
- package/docs/index.md +65 -65
- package/docs/integrations/agents.md +162 -162
- package/docs/integrations/claude-code.md +23 -23
- package/docs/integrations/cline.md +87 -88
- package/docs/integrations/codex.md +2 -2
- package/docs/integrations/continue.md +60 -60
- package/docs/integrations/copilot.md +82 -80
- package/docs/integrations/cursor.md +23 -23
- package/docs/integrations/kilocode.md +72 -72
- package/docs/integrations/mcp.md +377 -377
- package/docs/integrations/mistral-vibe.md +122 -122
- package/docs/integrations/openclaw.md +99 -98
- package/docs/integrations/opencode.md +84 -84
- package/docs/integrations/overview.md +122 -122
- package/docs/integrations/roo.md +74 -74
- package/docs/integrations/windsurf.md +83 -83
- package/docs/mcp-schema-changelog.md +360 -329
- package/docs/playbooks/integration/index.md +121 -121
- package/docs/playbooks/orchestration.md +37 -0
- package/docs/playbooks/productivity/index.md +99 -99
- package/docs/playbooks/team/index.md +117 -117
- package/docs/product/agent-first-model.md +184 -184
- package/docs/product/entity-model-audit.md +462 -462
- package/docs/product/positioning.md +86 -86
- package/docs/quickstart-existing-project.md +107 -107
- package/docs/quickstart.md +148 -147
- package/docs/release-maintenance.md +79 -79
- package/docs/reputation.md +52 -52
- package/docs/review.md +45 -45
- package/docs/security.md +212 -53
- package/docs/server-operations.md +118 -118
- package/docs/storage.md +110 -108
- package/package.json +86 -69
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Journal genesis migration + rollback (pln#543 step 4, spec §4 phase 1).
|
|
3
|
+
*
|
|
4
|
+
* Genesis seeds the v2 journal from the current v1 projection store: one
|
|
5
|
+
* `journal_note` kind `genesis` followed by one `backfill` record per live
|
|
6
|
+
* memory entity (entity_rev 1), all under a single lock hold. It is the
|
|
7
|
+
* baseline the journal grows from and that materialize/verify check against.
|
|
8
|
+
*
|
|
9
|
+
* Discipline (matches the house upgrade rule, feedback_no_init_force):
|
|
10
|
+
* - MANDATORY backup before writing — projections copied to a timestamped
|
|
11
|
+
* park dir; nothing is ever deleted.
|
|
12
|
+
* - Refuses to clobber an existing genesis unless `force` (which parks the
|
|
13
|
+
* prior journal first — park-don't-delete).
|
|
14
|
+
* - Rollback parks the journal directory; projections are untouched (in
|
|
15
|
+
* dual mode they were always the source of truth), so it is a safe,
|
|
16
|
+
* reversible "stop using the journal" operation.
|
|
17
|
+
*/
|
|
18
|
+
import fs from 'node:fs';
|
|
19
|
+
import path from 'node:path';
|
|
20
|
+
import { memoryDir } from '../io.js';
|
|
21
|
+
import { loadState } from '../state.js';
|
|
22
|
+
import { preparePersistedDocument } from '../migration.js';
|
|
23
|
+
import { nowISO } from '../ids.js';
|
|
24
|
+
import { logger } from '../logger.js';
|
|
25
|
+
import { forceAppendJournalRecords, journalDir, readJournalRecords, resolveJournalMode, } from './journal.js';
|
|
26
|
+
import { REGISTRY_FAMILIES } from './registry-post-image.js';
|
|
27
|
+
import { listClaims } from '../claims.js';
|
|
28
|
+
import { listAssignments } from '../assignments.js';
|
|
29
|
+
import { listAgentRuns } from '../agentruns.js';
|
|
30
|
+
import { listActionRequired } from '../actions.js';
|
|
31
|
+
import { listCandidates } from '../candidates.js';
|
|
32
|
+
import { listSequences } from '../sequence.js';
|
|
33
|
+
import { listSharedJournaledRuntimeNotes } from '../runtime.js';
|
|
34
|
+
const MEMORY_FAMILIES = [
|
|
35
|
+
{ collection: 'active_constraints', itemType: 'constraint' },
|
|
36
|
+
{ collection: 'recent_decisions', itemType: 'decision' },
|
|
37
|
+
{ collection: 'known_traps', itemType: 'trap' },
|
|
38
|
+
{ collection: 'open_handoffs', itemType: 'handoff' },
|
|
39
|
+
{ collection: 'plan_items', itemType: 'plan' },
|
|
40
|
+
];
|
|
41
|
+
/** True once a `journal_note` kind `genesis` exists in the journal. */
|
|
42
|
+
export function hasGenesis(cwd) {
|
|
43
|
+
return readJournalRecords(cwd).some(r => r.action === 'journal_note' && r.payload?.kind === 'genesis');
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Copy the live projection store to a timestamped park dir. Returns the path.
|
|
47
|
+
* `ts` is injected (the codebase forbids Date.now()/new Date() in some layers;
|
|
48
|
+
* callers pass nowISO()-derived stamps) — defaults to a lexically-sortable ISO.
|
|
49
|
+
*/
|
|
50
|
+
export function backupStore(cwd, stamp) {
|
|
51
|
+
const base = memoryDir(cwd);
|
|
52
|
+
const memorySrc = path.join(base, 'memory');
|
|
53
|
+
const safeStamp = stamp.replace(/[:.]/g, '-');
|
|
54
|
+
const backupDir = path.join(base, 'migration-backups', `genesis-${safeStamp}`);
|
|
55
|
+
fs.mkdirSync(backupDir, { recursive: true });
|
|
56
|
+
if (fs.existsSync(memorySrc)) {
|
|
57
|
+
fs.cpSync(memorySrc, path.join(backupDir, 'memory'), { recursive: true });
|
|
58
|
+
}
|
|
59
|
+
return backupDir;
|
|
60
|
+
}
|
|
61
|
+
export function runGenesisMigration(options = {}) {
|
|
62
|
+
const cwd = options.cwd ?? process.cwd();
|
|
63
|
+
const state = loadState(cwd);
|
|
64
|
+
const perFamily = {};
|
|
65
|
+
const backfill = [];
|
|
66
|
+
for (const { collection, itemType } of MEMORY_FAMILIES) {
|
|
67
|
+
const items = state[collection];
|
|
68
|
+
perFamily[itemType] = items.length;
|
|
69
|
+
for (const item of items) {
|
|
70
|
+
backfill.push({
|
|
71
|
+
action: 'backfill',
|
|
72
|
+
item_type: itemType,
|
|
73
|
+
item_id: item.id,
|
|
74
|
+
agent: 'system',
|
|
75
|
+
payload: preparePersistedDocument(itemType, item),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const total = backfill.length;
|
|
80
|
+
if (options.dryRun) {
|
|
81
|
+
return { status: 'dry_run', backfilled: total, per_family: perFamily };
|
|
82
|
+
}
|
|
83
|
+
if (hasGenesis(cwd)) {
|
|
84
|
+
if (!options.force) {
|
|
85
|
+
return { status: 'already_present', backfilled: 0, per_family: perFamily };
|
|
86
|
+
}
|
|
87
|
+
parkJournal(cwd, nowISO());
|
|
88
|
+
}
|
|
89
|
+
// Genesis is the phase-1 (dual) seed (spec §4). Running it with the flag
|
|
90
|
+
// off lays the seed but mutations after will not dual-write — the journal
|
|
91
|
+
// then silently diverges from projections until BRAINCLAW_JOURNAL_MODE is
|
|
92
|
+
// flipped to dual. Warn so the operator flips the flag (or accepts the
|
|
93
|
+
// seed-then-flip sequence deliberately).
|
|
94
|
+
if (resolveJournalMode(cwd) === 'off') {
|
|
95
|
+
logger.warn('runGenesisMigration: BRAINCLAW_JOURNAL_MODE=off — genesis will seed the journal, but subsequent mutations will not dual-write, so the journal will diverge from projections until you set BRAINCLAW_JOURNAL_MODE=dual.');
|
|
96
|
+
}
|
|
97
|
+
const backupPath = backupStore(cwd, nowISO());
|
|
98
|
+
// genesis note first, then the backfill batch — all under one lock hold via
|
|
99
|
+
// a single forced append call (appendLocked stamps them with consecutive seqs).
|
|
100
|
+
const genesisNote = {
|
|
101
|
+
action: 'journal_note',
|
|
102
|
+
item_type: 'journal',
|
|
103
|
+
agent: 'system',
|
|
104
|
+
payload: {
|
|
105
|
+
kind: 'genesis',
|
|
106
|
+
migrated_from: 'v1',
|
|
107
|
+
backfill_count: total,
|
|
108
|
+
per_family: perFamily,
|
|
109
|
+
backup_path: backupPath,
|
|
110
|
+
at: nowISO(),
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
const written = forceAppendJournalRecords([genesisNote, ...backfill], cwd);
|
|
114
|
+
// Locate the genesis note by action+kind, not array position: appendLocked
|
|
115
|
+
// can prepend a `seq_repair` or `journal_note kind torn_tail_adjudicated`
|
|
116
|
+
// when meta is stale or the prior segment tail is torn, which would shift
|
|
117
|
+
// written[0] off the genesis note and report the wrong genesis_seq.
|
|
118
|
+
const genesisSeq = written.find(r => r.action === 'journal_note' && r.payload?.kind === 'genesis')?.seq;
|
|
119
|
+
logger.debug(`journal genesis: ${total} entities backfilled at seq ${genesisSeq}, backup ${backupPath}`);
|
|
120
|
+
return { status: 'migrated', genesis_seq: genesisSeq, backfilled: total, backup_path: backupPath, per_family: perFamily };
|
|
121
|
+
}
|
|
122
|
+
// ── Registry genesis supplement (pln#568 slice 3 — cutover signal O2) ──────
|
|
123
|
+
/**
|
|
124
|
+
* The registry / coordination families backfilled by the registry genesis
|
|
125
|
+
* supplement, each mapped to its projection reader. Mirrors verify.ts's
|
|
126
|
+
* VERIFIED_REGISTRY_FAMILIES so a supplemented store passes `doctor
|
|
127
|
+
* --verify-journal` with zero registry drift. Runtime notes are shared-only
|
|
128
|
+
* (private/machine never enter the shared journal, pln#568).
|
|
129
|
+
*/
|
|
130
|
+
const REGISTRY_GENESIS_FAMILIES = [
|
|
131
|
+
{ family: 'claim', list: listClaims },
|
|
132
|
+
// listActionRequired performs the server's sweep-on-read expiration, which can
|
|
133
|
+
// update dependent assignments/runs. Run it before snapshotting those families
|
|
134
|
+
// so the supplement cannot append stale assignment/run post-images after the
|
|
135
|
+
// sweep's fresh journal records. Dry-run disables the sweep to honor the
|
|
136
|
+
// no-write contract.
|
|
137
|
+
{ family: 'action', list: (cwd, options) => listActionRequired(cwd, {}, { expireStale: !options.dryRun }) },
|
|
138
|
+
{ family: 'assignment', list: (cwd) => listAssignments(cwd) },
|
|
139
|
+
{ family: 'agent_run', list: (cwd) => listAgentRuns(cwd) },
|
|
140
|
+
{ family: 'candidate', list: (cwd) => listCandidates('pending', cwd) },
|
|
141
|
+
{ family: 'runtime_note', list: listSharedJournaledRuntimeNotes },
|
|
142
|
+
{ family: 'sequence', list: listSequences },
|
|
143
|
+
];
|
|
144
|
+
/** True once a `journal_note` kind `registry_genesis` exists — the cutover
|
|
145
|
+
* signal (O2) the observer reads to trust the journal as AUTHORITATIVE for the
|
|
146
|
+
* registry families (drop the board_summary MCP seed). */
|
|
147
|
+
export function hasRegistryGenesis(cwd) {
|
|
148
|
+
return readJournalRecords(cwd).some(r => r.action === 'journal_note' && r.payload?.kind === 'registry_genesis');
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Backfill the registry / coordination families into the journal and emit the
|
|
152
|
+
* `registry_genesis` cutover marker (pln#568 slice 3). INCREMENTAL by design:
|
|
153
|
+
* it appends to the existing journal (preserving the memory genesis + all
|
|
154
|
+
* accumulated post-image history) rather than parking/re-seeding — a re-genesis
|
|
155
|
+
* would reset seq to 1 and break live observers' seq cursors. Idempotent: a
|
|
156
|
+
* second run no-ops once the marker is present.
|
|
157
|
+
*
|
|
158
|
+
* The marker is the safe authority signal: an observer must not switch a
|
|
159
|
+
* registry family from the MCP seed to the journal until EVERY pre-existing
|
|
160
|
+
* entity has a post-image, else it undercounts (the trp#559 badge regression).
|
|
161
|
+
* This backfill establishes that guarantee, then the marker announces it.
|
|
162
|
+
*/
|
|
163
|
+
export function runRegistryGenesisSupplement(options = {}) {
|
|
164
|
+
const cwd = options.cwd ?? process.cwd();
|
|
165
|
+
const perFamily = {};
|
|
166
|
+
const backfill = [];
|
|
167
|
+
for (const { family, list } of REGISTRY_GENESIS_FAMILIES) {
|
|
168
|
+
const spec = REGISTRY_FAMILIES[family];
|
|
169
|
+
const items = list(cwd, options);
|
|
170
|
+
perFamily[spec.journalItemType] = items.length;
|
|
171
|
+
for (const item of items) {
|
|
172
|
+
backfill.push({
|
|
173
|
+
action: 'backfill',
|
|
174
|
+
item_type: spec.journalItemType,
|
|
175
|
+
item_id: item.id,
|
|
176
|
+
agent: 'system',
|
|
177
|
+
payload: preparePersistedDocument(spec.docType, item),
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
const total = backfill.length;
|
|
182
|
+
if (options.dryRun) {
|
|
183
|
+
return { status: 'dry_run', backfilled: total, per_family: perFamily };
|
|
184
|
+
}
|
|
185
|
+
if (hasRegistryGenesis(cwd)) {
|
|
186
|
+
return { status: 'already_present', backfilled: 0, per_family: perFamily };
|
|
187
|
+
}
|
|
188
|
+
const marker = {
|
|
189
|
+
action: 'journal_note',
|
|
190
|
+
item_type: 'journal',
|
|
191
|
+
agent: 'system',
|
|
192
|
+
payload: { kind: 'registry_genesis', backfill_count: total, per_family: perFamily, at: nowISO() },
|
|
193
|
+
};
|
|
194
|
+
forceAppendJournalRecords([...backfill, marker], cwd);
|
|
195
|
+
logger.debug(`registry genesis: ${total} registry entities backfilled, cutover marker emitted`);
|
|
196
|
+
return { status: 'migrated', backfilled: total, per_family: perFamily };
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Park the journal directory (events/) to a timestamped archive — the
|
|
200
|
+
* reversible "stop using the journal" operation. Projections are untouched.
|
|
201
|
+
* Returns the park path, or undefined if there was no journal.
|
|
202
|
+
*/
|
|
203
|
+
export function parkJournal(cwd, stamp) {
|
|
204
|
+
const dir = journalDir(cwd);
|
|
205
|
+
if (!fs.existsSync(dir))
|
|
206
|
+
return undefined;
|
|
207
|
+
const safeStamp = stamp.replace(/[:.]/g, '-');
|
|
208
|
+
const parked = path.join(memoryDir(cwd), 'migration-backups', `journal-parked-${safeStamp}`);
|
|
209
|
+
fs.mkdirSync(path.dirname(parked), { recursive: true });
|
|
210
|
+
fs.renameSync(dir, parked);
|
|
211
|
+
return parked;
|
|
212
|
+
}
|
|
213
|
+
export function rollbackJournal(options = {}) {
|
|
214
|
+
const cwd = options.cwd ?? process.cwd();
|
|
215
|
+
const parked = parkJournal(cwd, nowISO());
|
|
216
|
+
return parked
|
|
217
|
+
? { status: 'rolled_back', parked_path: parked }
|
|
218
|
+
: { status: 'nothing_to_roll_back' };
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=genesis.js.map
|