brainclaw 1.20.0 → 1.20.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/dist/brainclaw-vscode.vsix +0 -0
- package/dist/commands/export.js +16 -10
- package/dist/core/instruction-templates.js +8 -5
- package/dist/core/surface-freshness.js +43 -19
- package/dist/facts.js +9 -9
- package/dist/facts.json +8 -8
- package/docs/mcp-schema-changelog.md +15 -0
- package/package.json +1 -1
|
Binary file
|
package/dist/commands/export.js
CHANGED
|
@@ -6,7 +6,7 @@ import { loadConfig, saveConfig } from '../core/config.js';
|
|
|
6
6
|
import { isAgentIntegrationName, upsertAgentIntegrationDeclaration } from '../core/agent-integrations.js';
|
|
7
7
|
import { resolveInstructions, loadInstructions } from '../core/instructions.js';
|
|
8
8
|
import { detectAiAgent } from '../core/ai-agent-detection.js';
|
|
9
|
-
import { AGENT_EXPORT_REGISTRY, resolveExportTarget, resolveExportTargetByFormat, writeExportFile, writeLiveCompanionFile, buildHygieneSection, describeAutoConfigWrite, writeExportCompanionFiles, collectExportGitignoreEntries, ensureGitignoreEntries, BRAINCLAW_EXCLUSIVE_DIRECTORIES, } from '../core/agent-files.js';
|
|
9
|
+
import { AGENT_EXPORT_REGISTRY, resolveExportTarget, resolveExportTargetByFormat, resolveLiveCompanionPath, writeExportFile, writeLiveCompanionFile, buildHygieneSection, describeAutoConfigWrite, writeExportCompanionFiles, collectExportGitignoreEntries, ensureGitignoreEntries, BRAINCLAW_EXCLUSIVE_DIRECTORIES, } from '../core/agent-files.js';
|
|
10
10
|
import { buildCoordinationSnapshot } from '../core/coordination.js';
|
|
11
11
|
import { listClaims } from '../core/claims.js';
|
|
12
12
|
import { listCandidates } from '../core/candidates.js';
|
|
@@ -187,18 +187,23 @@ export function refreshLiveCompanions(cwd) {
|
|
|
187
187
|
const instructions = getInstructionText({ project: undefined, agent: undefined }, effectiveCwd);
|
|
188
188
|
const activeClaims = listClaims(effectiveCwd).filter((c) => c.status === 'active');
|
|
189
189
|
const pendingCandidates = listCandidates('pending', effectiveCwd);
|
|
190
|
-
const seen = new Set();
|
|
191
|
-
const targets = AGENT_EXPORT_REGISTRY.filter((t) => {
|
|
192
|
-
if (seen.has(t.format))
|
|
193
|
-
return false;
|
|
194
|
-
seen.add(t.format);
|
|
195
|
-
return true;
|
|
196
|
-
});
|
|
197
190
|
let written = 0;
|
|
198
191
|
const errors = [];
|
|
199
192
|
const liveGitignoreEntries = [];
|
|
200
|
-
|
|
193
|
+
// trp_6a49f976 F1 (codex review): dedupe by RESOLVED LIVE PATH, never by
|
|
194
|
+
// stable export format. Format-dedup dropped every agents-md agent after
|
|
195
|
+
// codex — including mistral-vibe, whose REGISTERED live companion
|
|
196
|
+
// (.vibe/live.md) then never got refreshed, while the stale-surface
|
|
197
|
+
// advisory told the operator `brainclaw refresh` would fix exactly that
|
|
198
|
+
// file. A path counts as taken only once something was actually RENDERED
|
|
199
|
+
// for it, so a tier with no live companion (codex, Tier A) does not shadow
|
|
200
|
+
// a rendering agent that shares its default path (hermes → AGENTS.live.md).
|
|
201
|
+
const renderedLivePaths = new Set();
|
|
202
|
+
for (const target of AGENT_EXPORT_REGISTRY) {
|
|
201
203
|
try {
|
|
204
|
+
const livePath = resolveLiveCompanionPath(target.agentName, target.relativePath);
|
|
205
|
+
if (renderedLivePaths.has(livePath))
|
|
206
|
+
continue;
|
|
202
207
|
const profile = getAgentCapabilityProfile(target.agentName);
|
|
203
208
|
if (!profile)
|
|
204
209
|
continue;
|
|
@@ -214,7 +219,8 @@ export function refreshLiveCompanions(cwd) {
|
|
|
214
219
|
};
|
|
215
220
|
const live = renderLiveSection(input);
|
|
216
221
|
if (!live)
|
|
217
|
-
continue; //
|
|
222
|
+
continue; // no live companion for this tier
|
|
223
|
+
renderedLivePaths.add(livePath);
|
|
218
224
|
const writeResult = writeLiveCompanionFile(live.content, target.agentName, target.relativePath, effectiveCwd);
|
|
219
225
|
if (writeResult.created || writeResult.updated) {
|
|
220
226
|
written++;
|
|
@@ -220,15 +220,18 @@ function renderHeader(input) {
|
|
|
220
220
|
function renderLiveHeader(input) {
|
|
221
221
|
// pln#638 volet 2a — HONESTY FIX. This header used to say "auto-refreshed",
|
|
222
222
|
// but regeneration is EXPLICIT: it happens on session-end, handoff, and
|
|
223
|
-
// `
|
|
224
|
-
// MCP) read a file claiming to be fresh while being arbitrarily stale. A
|
|
225
|
-
// that is false for half the tiers is worse than no claim, so the header
|
|
223
|
+
// `brainclaw refresh`. An agent tier that never fires those events (no hooks,
|
|
224
|
+
// no MCP) read a file claiming to be fresh while being arbitrarily stale. A
|
|
225
|
+
// claim that is false for half the tiers is worse than no claim, so the header
|
|
226
226
|
// names the actual triggers and tells the reader how to force a refresh.
|
|
227
|
+
// trp_6a49f976: the 1.20.0 header cited `brainclaw export --write`, which the
|
|
228
|
+
// CLI rejects outright AND which never wrote a live companion — the honest
|
|
229
|
+
// recovery for THIS file is `brainclaw refresh`.
|
|
227
230
|
// Guarded by tests/unit/guidance-engine-consistency.test.ts.
|
|
228
231
|
return [
|
|
229
|
-
`> Brainclaw live state — do not edit. Regenerated on: session-end, handoff, \`brainclaw
|
|
232
|
+
`> Brainclaw live state — do not edit. Regenerated on: session-end, handoff, \`brainclaw refresh\`.`,
|
|
230
233
|
`> Written by brainclaw v${input.brainclawVersion} at ${new Date().toISOString().slice(0, 19)}`,
|
|
231
|
-
`> Older than your last session? It is stale — run \`brainclaw
|
|
234
|
+
`> Older than your last session? It is stale — run \`brainclaw refresh\`.`,
|
|
232
235
|
].join('\n');
|
|
233
236
|
}
|
|
234
237
|
// Kept deliberately small (pln#542): entry point + grammar + escalation
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* WHY THIS EXISTS. 2a made the live header HONEST: it stopped claiming
|
|
5
5
|
* "auto-refreshed" and started naming its real triggers (session-end, handoff,
|
|
6
|
-
* `
|
|
6
|
+
* `brainclaw refresh`) plus the version and timestamp that wrote it. Honesty alone
|
|
7
7
|
* does not help an agent tier that never fires any of those triggers, though — it
|
|
8
8
|
* just tells that tier, truthfully, that the file might be arbitrarily old. 2b
|
|
9
9
|
* closes the loop by USING the stamp: compare it against the running version and
|
|
@@ -63,16 +63,23 @@ export function assessSurfaceFreshness(content, currentVersion) {
|
|
|
63
63
|
return { kind: 'fresh', version };
|
|
64
64
|
return { kind: 'stale', stampedVersion: version, currentVersion };
|
|
65
65
|
}
|
|
66
|
+
/** The command that regenerates every stable surface. `export --write` alone is rejected by the CLI (a mode flag is required — see runExport). */
|
|
67
|
+
export const STABLE_SURFACE_REFRESH_COMMAND = 'brainclaw export --all --write';
|
|
68
|
+
/** The command that regenerates every live companion. */
|
|
69
|
+
export const LIVE_SURFACE_REFRESH_COMMAND = 'brainclaw refresh';
|
|
66
70
|
/**
|
|
67
71
|
* The set of surfaces this project could have on disk, derived from the export
|
|
68
72
|
* registries rather than listed here. Deduplicated because several agents share
|
|
69
|
-
* a target (four of them write AGENTS.md)
|
|
73
|
+
* a target (four of them write AGENTS.md); a path claimed by both registries
|
|
74
|
+
* counts as stable, since `export` regenerates it.
|
|
70
75
|
*/
|
|
71
|
-
function
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
])
|
|
76
|
+
function candidateSurfaces() {
|
|
77
|
+
const stable = new Set(AGENT_EXPORT_REGISTRY.map((t) => t.relativePath));
|
|
78
|
+
const live = new Set(LIVE_COMPANION_EXPORT_REGISTRY.map((t) => t.relativePath));
|
|
79
|
+
return [
|
|
80
|
+
...[...stable].map((relativePath) => ({ relativePath, kind: 'stable' })),
|
|
81
|
+
...[...live].filter((p) => !stable.has(p)).map((relativePath) => ({ relativePath, kind: 'live' })),
|
|
82
|
+
];
|
|
76
83
|
}
|
|
77
84
|
/**
|
|
78
85
|
* Scan the project's generated surfaces and report the ones stamped with a
|
|
@@ -85,7 +92,7 @@ function candidateSurfacePaths() {
|
|
|
85
92
|
*/
|
|
86
93
|
export function reconcileSurfaceFreshness(cwd, currentVersion) {
|
|
87
94
|
const result = { stale: [], freshCount: 0, unknownCount: 0 };
|
|
88
|
-
for (const relativePath of
|
|
95
|
+
for (const { relativePath, kind } of candidateSurfaces()) {
|
|
89
96
|
const full = path.join(cwd, relativePath);
|
|
90
97
|
let head;
|
|
91
98
|
try {
|
|
@@ -107,7 +114,7 @@ export function reconcileSurfaceFreshness(cwd, currentVersion) {
|
|
|
107
114
|
}
|
|
108
115
|
const verdict = assessSurfaceFreshness(head, currentVersion);
|
|
109
116
|
if (verdict.kind === 'stale')
|
|
110
|
-
result.stale.push({ relativePath, stampedVersion: verdict.stampedVersion });
|
|
117
|
+
result.stale.push({ relativePath, stampedVersion: verdict.stampedVersion, kind });
|
|
111
118
|
else if (verdict.kind === 'fresh')
|
|
112
119
|
result.freshCount += 1;
|
|
113
120
|
else
|
|
@@ -119,31 +126,48 @@ export function reconcileSurfaceFreshness(cwd, currentVersion) {
|
|
|
119
126
|
* Build the advisory for a stale-surface scan, or `undefined` when there is
|
|
120
127
|
* nothing to say.
|
|
121
128
|
*
|
|
122
|
-
* NO `next_actions`, deliberately. The recovery is
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
+
* NO `next_actions`, deliberately. The recovery is a CLI command, and there is
|
|
130
|
+
* no MCP tool that performs it — `bclaw_setup` is the onboarding wizard and
|
|
131
|
+
* takes no write flag. Pointing at it anyway would ship a next_action whose
|
|
132
|
+
* args the engine rejects, which is the precise class of drift this plan exists
|
|
133
|
+
* to eliminate; and per pln#634's own rule, a builder with no genuine follow-up
|
|
134
|
+
* returns nothing rather than inventing one. The command therefore travels in
|
|
135
|
+
* the message, where it is true.
|
|
136
|
+
*
|
|
137
|
+
* WHICH command depends on what is stale (trp_6a49f976): this advisory shipped
|
|
138
|
+
* in 1.20.0 recommending `brainclaw export --write`, which the CLI rejects
|
|
139
|
+
* (a mode flag is required) and which — even corrected to `--all` — never
|
|
140
|
+
* touches live companions, the very files the first real-world firing listed.
|
|
141
|
+
* The recovery must be per kind, and only for the kinds actually stale.
|
|
129
142
|
*/
|
|
130
143
|
export function staleSurfaceWarning(result, currentVersion) {
|
|
131
144
|
if (result.stale.length === 0)
|
|
132
145
|
return undefined;
|
|
133
146
|
const shown = result.stale.slice(0, 8);
|
|
134
147
|
const overflow = result.stale.length - shown.length;
|
|
148
|
+
const kinds = new Set(result.stale.map((s) => s.kind));
|
|
149
|
+
const commands = [
|
|
150
|
+
...(kinds.has('stable') ? [STABLE_SURFACE_REFRESH_COMMAND] : []),
|
|
151
|
+
...(kinds.has('live') ? [LIVE_SURFACE_REFRESH_COMMAND] : []),
|
|
152
|
+
];
|
|
153
|
+
const recovery = kinds.size === 2
|
|
154
|
+
? ` Run \`${STABLE_SURFACE_REFRESH_COMMAND}\` (stable surfaces) and \`${LIVE_SURFACE_REFRESH_COMMAND}\` (live companions) to refresh them.`
|
|
155
|
+
: ` Run \`${commands[0]}\` to refresh them.`;
|
|
135
156
|
return {
|
|
136
157
|
code: 'generated_surfaces_stale',
|
|
137
158
|
message: `${result.stale.length} generated guidance surface(s) were written by an older brainclaw than v${currentVersion}: `
|
|
138
159
|
+ shown.map((s) => `${s.relativePath} (v${s.stampedVersion})`).join(', ')
|
|
139
160
|
+ (overflow > 0 ? ` (+${overflow} more)` : '')
|
|
140
161
|
+ '. An agent tier that never triggers a regeneration is reading them as-is.'
|
|
141
|
-
+
|
|
162
|
+
+ recovery,
|
|
142
163
|
data: {
|
|
143
164
|
current_version: currentVersion,
|
|
144
|
-
stale_surfaces: shown.map((s) => ({ path: s.relativePath, stamped_version: s.stampedVersion })),
|
|
165
|
+
stale_surfaces: shown.map((s) => ({ path: s.relativePath, stamped_version: s.stampedVersion, kind: s.kind })),
|
|
145
166
|
...(overflow > 0 ? { stale_surfaces_omitted: overflow } : {}),
|
|
146
|
-
|
|
167
|
+
// Kept as a single runnable string for consumers that shipped against
|
|
168
|
+
// 1.20.0; refresh_commands is the structured form.
|
|
169
|
+
refresh_command: commands.join(' && '),
|
|
170
|
+
refresh_commands: commands,
|
|
147
171
|
},
|
|
148
172
|
};
|
|
149
173
|
}
|
package/dist/facts.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Generated by scripts/emit-site-facts.mjs at build time. Do not edit manually.
|
|
2
|
-
// Source: brainclaw v1.20.
|
|
2
|
+
// Source: brainclaw v1.20.1 on 2026-08-02T21:44:51.056Z
|
|
3
3
|
export const FACTS = {
|
|
4
|
-
"version": "1.20.
|
|
5
|
-
"generated_at": "2026-08-
|
|
4
|
+
"version": "1.20.1",
|
|
5
|
+
"generated_at": "2026-08-02T21:44:51.056Z",
|
|
6
6
|
"tools": {
|
|
7
7
|
"count": 67,
|
|
8
8
|
"published_count": 65,
|
|
@@ -474,7 +474,7 @@ export const FACTS = {
|
|
|
474
474
|
},
|
|
475
475
|
"bench": {
|
|
476
476
|
"schema": "brainclaw.bench.v1",
|
|
477
|
-
"generated_at": "2026-08-
|
|
477
|
+
"generated_at": "2026-08-02T21:44:48.979Z",
|
|
478
478
|
"node_version": "v24.18.0",
|
|
479
479
|
"platform": "linux-x64",
|
|
480
480
|
"repeats": 3,
|
|
@@ -483,7 +483,7 @@ export const FACTS = {
|
|
|
483
483
|
"name": "cold_onboard",
|
|
484
484
|
"volume": "empty",
|
|
485
485
|
"description": "fresh machine → init → first useful context. Baseline for time-to-first-value.",
|
|
486
|
-
"duration_ms_median":
|
|
486
|
+
"duration_ms_median": 76,
|
|
487
487
|
"payload_chars_median": 1640,
|
|
488
488
|
"payload_tokens_est_median": 410
|
|
489
489
|
},
|
|
@@ -491,15 +491,15 @@ export const FACTS = {
|
|
|
491
491
|
"name": "warm_work",
|
|
492
492
|
"volume": "medium",
|
|
493
493
|
"description": "bclaw_work consult over a real-shaped store (~200 plans / 500 handoffs / 450 claims).",
|
|
494
|
-
"duration_ms_median":
|
|
495
|
-
"payload_chars_median":
|
|
496
|
-
"payload_tokens_est_median":
|
|
494
|
+
"duration_ms_median": 121,
|
|
495
|
+
"payload_chars_median": 2626,
|
|
496
|
+
"payload_tokens_est_median": 657
|
|
497
497
|
},
|
|
498
498
|
{
|
|
499
499
|
"name": "first_edit",
|
|
500
500
|
"volume": "medium",
|
|
501
501
|
"description": "code_find + code_brief on the fresh-agent path (missing index, first touch).",
|
|
502
|
-
"duration_ms_median":
|
|
502
|
+
"duration_ms_median": 12,
|
|
503
503
|
"payload_chars_median": 499,
|
|
504
504
|
"payload_tokens_est_median": 125
|
|
505
505
|
}
|
package/dist/facts.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.20.
|
|
3
|
-
"generated_at": "2026-08-
|
|
2
|
+
"version": "1.20.1",
|
|
3
|
+
"generated_at": "2026-08-02T21:44:51.056Z",
|
|
4
4
|
"tools": {
|
|
5
5
|
"count": 67,
|
|
6
6
|
"published_count": 65,
|
|
@@ -472,7 +472,7 @@
|
|
|
472
472
|
},
|
|
473
473
|
"bench": {
|
|
474
474
|
"schema": "brainclaw.bench.v1",
|
|
475
|
-
"generated_at": "2026-08-
|
|
475
|
+
"generated_at": "2026-08-02T21:44:48.979Z",
|
|
476
476
|
"node_version": "v24.18.0",
|
|
477
477
|
"platform": "linux-x64",
|
|
478
478
|
"repeats": 3,
|
|
@@ -481,7 +481,7 @@
|
|
|
481
481
|
"name": "cold_onboard",
|
|
482
482
|
"volume": "empty",
|
|
483
483
|
"description": "fresh machine → init → first useful context. Baseline for time-to-first-value.",
|
|
484
|
-
"duration_ms_median":
|
|
484
|
+
"duration_ms_median": 76,
|
|
485
485
|
"payload_chars_median": 1640,
|
|
486
486
|
"payload_tokens_est_median": 410
|
|
487
487
|
},
|
|
@@ -489,15 +489,15 @@
|
|
|
489
489
|
"name": "warm_work",
|
|
490
490
|
"volume": "medium",
|
|
491
491
|
"description": "bclaw_work consult over a real-shaped store (~200 plans / 500 handoffs / 450 claims).",
|
|
492
|
-
"duration_ms_median":
|
|
493
|
-
"payload_chars_median":
|
|
494
|
-
"payload_tokens_est_median":
|
|
492
|
+
"duration_ms_median": 121,
|
|
493
|
+
"payload_chars_median": 2626,
|
|
494
|
+
"payload_tokens_est_median": 657
|
|
495
495
|
},
|
|
496
496
|
{
|
|
497
497
|
"name": "first_edit",
|
|
498
498
|
"volume": "medium",
|
|
499
499
|
"description": "code_find + code_brief on the fresh-agent path (missing index, first touch).",
|
|
500
|
-
"duration_ms_median":
|
|
500
|
+
"duration_ms_median": 12,
|
|
501
501
|
"payload_chars_median": 499,
|
|
502
502
|
"payload_tokens_est_median": 125
|
|
503
503
|
}
|
|
@@ -8,6 +8,21 @@ guarantees this changelog follows.
|
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
+
## [1.20.1] — 2026-08-02
|
|
12
|
+
|
|
13
|
+
**Changed — `generated_surfaces_stale` recovery data is now true, and structured (#163)**
|
|
14
|
+
- The VALUE of `data.refresh_command` changes: it was `brainclaw export --write`,
|
|
15
|
+
which the CLI rejects (a mode flag is required), and is now a runnable command
|
|
16
|
+
derived from what is actually stale — `brainclaw export --all --write` (stable
|
|
17
|
+
surfaces), `brainclaw refresh` (live companions), or both joined with ` && `
|
|
18
|
+
when both kinds are stale. The field keeps its type (string); consumers that
|
|
19
|
+
displayed it verbatim now display something that works.
|
|
20
|
+
- Additive fields on the same warning's `data`: `refresh_commands: string[]`
|
|
21
|
+
(the structured form of the above) and `kind: "stable" | "live"` on each
|
|
22
|
+
`stale_surfaces[]` entry.
|
|
23
|
+
- Read contract only: no tool added/removed/renamed, no inputSchema change,
|
|
24
|
+
no surface-fingerprint movement.
|
|
25
|
+
|
|
11
26
|
## [1.20.0] — 2026-08-02
|
|
12
27
|
|
|
13
28
|
**Fixed — 1.19.0 contract entries now actually emitted (#158)**
|