brainclaw 1.9.1 → 1.10.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 +78 -25
- package/dist/brainclaw-vscode.vsix +0 -0
- package/dist/cli.js +18 -1
- package/dist/commands/code-map.js +129 -0
- package/dist/commands/codev.js +7 -0
- package/dist/commands/dispatch-watch.js +1 -1
- package/dist/commands/doctor.js +3 -5
- package/dist/commands/loops-handlers.js +4 -1
- package/dist/commands/mcp-read-handlers.js +8 -0
- package/dist/commands/mcp.js +121 -1
- package/dist/commands/metrics.js +0 -1
- package/dist/commands/release-claims.js +1 -1
- package/dist/commands/run-profile.js +3 -2
- package/dist/commands/sequence.js +1 -1
- package/dist/commands/switch.js +100 -89
- package/dist/commands/sync.js +1 -1
- package/dist/commands/upgrade.js +0 -7
- package/dist/core/agent-context.js +1 -1
- package/dist/core/agent-files.js +13 -2
- package/dist/core/agent-integrations.js +3 -3
- package/dist/core/agent-registry.js +2 -2
- package/dist/core/assignments.js +12 -0
- package/dist/core/brainclaw-version.js +2 -2
- package/dist/core/code-map/backend.js +176 -0
- package/dist/core/code-map/core.js +81 -0
- package/dist/core/code-map/drafts.js +2 -0
- package/dist/core/code-map/extractor.js +29 -0
- package/dist/core/code-map/finalizer.js +191 -0
- package/dist/core/code-map/freshness.js +144 -0
- package/dist/core/code-map/ids.js +0 -0
- package/dist/core/code-map/importable.js +35 -0
- package/dist/core/code-map/indexes.js +197 -0
- package/dist/core/code-map/lang/java/imports.scm +17 -0
- package/dist/core/code-map/lang/java/index.js +254 -0
- package/dist/core/code-map/lang/java/tags.scm +48 -0
- package/dist/core/code-map/lang/php/imports.scm +21 -0
- package/dist/core/code-map/lang/php/index.js +251 -0
- package/dist/core/code-map/lang/php/tags.scm +44 -0
- package/dist/core/code-map/lang/provider.js +9 -0
- package/dist/core/code-map/lang/providers.js +24 -0
- package/dist/core/code-map/lang/python/imports.scm +90 -0
- package/dist/core/code-map/lang/python/index.js +364 -0
- package/dist/core/code-map/lang/python/tags.scm +81 -0
- package/dist/core/code-map/lang/query-runtime.js +374 -0
- package/dist/core/code-map/lang/registry.js +125 -0
- package/dist/core/code-map/lang/typescript/imports.scm +90 -0
- package/dist/core/code-map/lang/typescript/index.js +306 -0
- package/dist/core/code-map/lang/typescript/tags.js.scm +106 -0
- package/dist/core/code-map/lang/typescript/tags.scm +151 -0
- package/dist/core/code-map/lock.js +210 -0
- package/dist/core/code-map/materialized.js +51 -0
- package/dist/core/code-map/memory-reader.js +59 -0
- package/dist/core/code-map/paths.js +53 -0
- package/dist/core/code-map/query.js +599 -0
- package/dist/core/code-map/refresh.js +0 -0
- package/dist/core/code-map/resolve.js +177 -0
- package/dist/core/code-map/store.js +206 -0
- package/dist/core/code-map/types.js +293 -0
- package/dist/core/code-map/vocabulary.js +57 -0
- package/dist/core/code-map/wasm-loader.js +294 -0
- package/dist/core/code-map/work-section.js +206 -0
- package/dist/core/codev-rounds.js +4 -0
- package/dist/core/context.js +1 -1
- package/dist/core/cross-project.js +1 -1
- package/dist/core/dispatcher.js +0 -2
- package/dist/core/entity-operations.js +0 -3
- package/dist/core/execution-adapters.js +11 -10
- package/dist/core/execution-profile.js +58 -0
- package/dist/core/facade-schema.js +9 -0
- package/dist/core/ids.js +1 -1
- package/dist/core/instruction-templates.js +2 -0
- package/dist/core/instructions.js +0 -1
- package/dist/core/loops/lock.js +0 -3
- package/dist/core/mcp-command-resolution.js +3 -1
- package/dist/core/protocol-skills.js +5 -3
- package/dist/core/security-detectors.js +2 -2
- package/dist/core/security-extract.js +2 -2
- package/dist/core/store-resolution.js +41 -4
- package/dist/facts.js +9 -5
- package/dist/facts.json +8 -4
- package/dist/vendor/web-tree-sitter/tree-sitter.js +3980 -0
- package/dist/vendor/web-tree-sitter/tree-sitter.wasm +0 -0
- package/dist/wasm/tree-sitter-java.wasm +0 -0
- package/dist/wasm/tree-sitter-javascript.wasm +0 -0
- package/dist/wasm/tree-sitter-php.wasm +0 -0
- package/dist/wasm/tree-sitter-python.wasm +0 -0
- package/dist/wasm/tree-sitter-tsx.wasm +0 -0
- package/dist/wasm/tree-sitter-typescript.wasm +0 -0
- package/dist/wasm/tree-sitter.wasm +0 -0
- package/docs/cli.md +46 -8
- package/docs/code-map.md +209 -0
- package/docs/integrations/mcp.md +13 -6
- package/docs/mcp-schema-changelog.md +7 -3
- package/docs/quickstart.md +1 -1
- package/package.json +11 -6
|
@@ -247,6 +247,64 @@ export function buildClaimEnvPrefix(claimId, options) {
|
|
|
247
247
|
default: return `BRAINCLAW_CLAIM_ID=${claimId} `;
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
|
+
/**
|
|
251
|
+
* F7 (trp_0e5150d3): build the env for a SPAWNED worker so it is an INDEPENDENT
|
|
252
|
+
* agent, not a clone of the coordinator. The coordinator's process.env carries
|
|
253
|
+
* identity-bearing state (BRAINCLAW_AGENT*, BRAINCLAW_SESSION_ID, BRAINCLAW_PROJECT);
|
|
254
|
+
* inherited by an MCP-capable worker it would make the worker read/mutate the
|
|
255
|
+
* coordinator's session-scoped active project and identify AS the coordinator.
|
|
256
|
+
*
|
|
257
|
+
* Merge order (Codex cadrage review — batch 2): baseEnv → extraEnv (git
|
|
258
|
+
* attribution + invoke.env) → worker identity (agent name, claim) → SCRUB the
|
|
259
|
+
* forbidden coordinator keys LAST, so a deliberate or accidental extraEnv cannot
|
|
260
|
+
* reintroduce them. This helper is the SINGLE place worker env is built; every
|
|
261
|
+
* agent-spawn site must route through it.
|
|
262
|
+
*
|
|
263
|
+
* BRAINCLAW_CWD is intentionally PRESERVED (D1 = (a)): a worker's worktree lives
|
|
264
|
+
* outside the monorepo and has no .brainclaw, so it must anchor to the shared
|
|
265
|
+
* monorepo-root store the coordinator pointed at; the claim scopes the work. A
|
|
266
|
+
* caller override via extraEnv.BRAINCLAW_CWD is honoured (deliberate, not leaked).
|
|
267
|
+
*/
|
|
268
|
+
export function buildWorkerIdentityEnv(baseEnv, options = {}) {
|
|
269
|
+
const env = {};
|
|
270
|
+
for (const [key, value] of Object.entries(baseEnv)) {
|
|
271
|
+
if (typeof value === 'string')
|
|
272
|
+
env[key] = value;
|
|
273
|
+
}
|
|
274
|
+
if (options.extraEnv) {
|
|
275
|
+
for (const [key, value] of Object.entries(options.extraEnv)) {
|
|
276
|
+
if (typeof value === 'string')
|
|
277
|
+
env[key] = value;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
// Worker identity — truthful attribution, mirrors buildGitAttributionEnv.
|
|
281
|
+
const agent = options.agent?.trim();
|
|
282
|
+
if (agent) {
|
|
283
|
+
env.BRAINCLAW_AGENT = agent;
|
|
284
|
+
env.BRAINCLAW_AGENT_NAME = agent;
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
// No target agent → don't leak the coordinator's identity either.
|
|
288
|
+
delete env.BRAINCLAW_AGENT;
|
|
289
|
+
delete env.BRAINCLAW_AGENT_NAME;
|
|
290
|
+
}
|
|
291
|
+
// Claim ownership is explicit: adopt the supplied claim, otherwise DELETE any
|
|
292
|
+
// inherited parent BRAINCLAW_CLAIM_ID so an unclaimed/dry-run worker (e.g. the
|
|
293
|
+
// codev/codev-rounds call sites that pass only { agent }) never adopts the
|
|
294
|
+
// coordinator's claim (Codex final review F7 finding).
|
|
295
|
+
if (options.claimId && options.claimId !== '(dry-run)') {
|
|
296
|
+
env.BRAINCLAW_CLAIM_ID = options.claimId;
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
delete env.BRAINCLAW_CLAIM_ID;
|
|
300
|
+
}
|
|
301
|
+
// SCRUB LAST — coordinator identity must never survive into the worker, even if
|
|
302
|
+
// baseEnv or extraEnv set it. (BRAINCLAW_CWD is deliberately NOT scrubbed.)
|
|
303
|
+
delete env.BRAINCLAW_AGENT_ID;
|
|
304
|
+
delete env.BRAINCLAW_SESSION_ID;
|
|
305
|
+
delete env.BRAINCLAW_PROJECT;
|
|
306
|
+
return env;
|
|
307
|
+
}
|
|
250
308
|
// ── Verification helper (used by setup / doctor) ───────────────────────────
|
|
251
309
|
/**
|
|
252
310
|
* Try `node --version` from the resolved profile's `node_path` to confirm
|
|
@@ -196,5 +196,14 @@ export const FacadeResponseSchema = z.object({
|
|
|
196
196
|
* remains for the bootstrap hint; new consumers should read this array.
|
|
197
197
|
*/
|
|
198
198
|
next_actions: z.array(NextActionSchema).optional(),
|
|
199
|
+
/**
|
|
200
|
+
* Code Map P0 (spec §10): opt-in, present ONLY when the project's Code Map
|
|
201
|
+
* manifest carries `code_map_enabled: true`. Absent for every project that
|
|
202
|
+
* has not turned Code Map on (the P0 default), so existing bclaw_work callers
|
|
203
|
+
* are unaffected and the off-path adds no work. Shape mirrors
|
|
204
|
+
* CodeMapWorkSection: { enabled, matches, freshness_badge, missing_index?,
|
|
205
|
+
* lock_wait_ms? }. Passthrough so the section can evolve without a schema bump.
|
|
206
|
+
*/
|
|
207
|
+
code_map: z.object({}).passthrough().optional(),
|
|
199
208
|
});
|
|
200
209
|
//# sourceMappingURL=facade-schema.js.map
|
package/dist/core/ids.js
CHANGED
|
@@ -48,7 +48,7 @@ export function getNextShortLabel(prefix, cwd, preferredDirName) {
|
|
|
48
48
|
}
|
|
49
49
|
catch (error) {
|
|
50
50
|
if (!(error instanceof Error) || !('code' in error) || error.code !== 'ENOENT') {
|
|
51
|
-
throw new Error(`Could not read short-label counter ${fp}: ${error instanceof Error ? error.message : String(error)}
|
|
51
|
+
throw new Error(`Could not read short-label counter ${fp}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
const next = (counter[prefix] ?? 0) + 1;
|
|
@@ -233,6 +233,7 @@ function renderSessionProtocol() {
|
|
|
233
233
|
'1. Call `bclaw_work(intent)` (consult|execute|resume|review) — one call handles session, context, and claim (execute). Every response carries `next_actions` with the exact follow-up calls: follow those instead of memorizing the API.',
|
|
234
234
|
'2. Canonical grammar for memory objects: `bclaw_find` / `bclaw_get` / `bclaw_create` / `bclaw_update` / `bclaw_remove` / `bclaw_transition` (entity, …).',
|
|
235
235
|
'3. Do not assume project state without reading brainclaw context first.',
|
|
236
|
+
'4. Before editing unfamiliar code, orient with the **Code Map**: `bclaw_code_brief(target=<symbol|path>)` for a ranked reading list + related decisions/traps, `bclaw_code_find(query=<name>)` to locate a symbol/class/component. Don\'t grep the repo blind when a symbol index already answers "where is X / what should I read first". A `missing_index`/stale badge means run `bclaw_code_refresh` first.',
|
|
236
237
|
'',
|
|
237
238
|
'Escalation (only when orchestrating other agents): `bclaw_coordinate(intent=review|consult|assign)`. Verify any dispatch with `bclaw_dispatch_status(target_id)` — trust its sentinel-based verdict, not the tracked pid. Details: `docs/concepts/dispatch-lifecycle.md`.',
|
|
238
239
|
].join('\n');
|
|
@@ -322,6 +323,7 @@ function renderAvailableTools() {
|
|
|
322
323
|
'**Session/claims:** `bclaw_session_start`, `bclaw_session_end`, `bclaw_claim`, `bclaw_release_claim` · **steps:** `bclaw_add_step`, `bclaw_complete_step`, `bclaw_update_step`, `bclaw_delete_step` · **sequences:** `bclaw_list_sequences`, `bclaw_create_sequence`, `bclaw_update_sequence`, `bclaw_delete_sequence`',
|
|
323
324
|
'**Inbox:** `bclaw_read_inbox`, `bclaw_ack_message`, `bclaw_send_message`, `bclaw_correct_handoff` · **capture:** `bclaw_write_note`, `bclaw_quick_capture(text, type?)` · **search:** `bclaw_search` · **setup:** `bclaw_setup`, `bclaw_bootstrap`, `bclaw_switch`, `bclaw_release_notes`',
|
|
324
325
|
'**Escalation (orchestrators):** `bclaw_coordinate(intent=review|consult|assign|ideate)` · `bclaw_dispatch(intent=execute)` on an active sequence · `bclaw_loop(intent=turn|complete_turn|advance|close)` to drive turns · `bclaw_dispatch_status(target_id)` to verify',
|
|
326
|
+
'**Code discovery (Code Map):** `bclaw_code_find(query)` locate a symbol/class/component · `bclaw_code_brief(target)` ranked reading list + related memory before editing · `bclaw_code_status` / `bclaw_code_refresh` check freshness / rebuild the symbol+import index. **Reach for these before `rg`/grep on unfamiliar code** — and if your harness defers MCP tools, `tool_search` for `bclaw_code_*` first rather than falling back to a blind grep. See `docs/code-map.md`.',
|
|
325
327
|
'',
|
|
326
328
|
'Responses are self-teaching — follow their `next_actions`. Full catalog + stability contract: `docs/integrations/mcp.md`, `docs/concepts/mcp-governance.md`.',
|
|
327
329
|
].join('\n');
|
package/dist/core/loops/lock.js
CHANGED
|
@@ -167,9 +167,6 @@ function loadIdempotencyRecord(kind, key, cwd) {
|
|
|
167
167
|
function readLockBlob(lockPath) {
|
|
168
168
|
return readJsonIfExists(lockPath) ?? null;
|
|
169
169
|
}
|
|
170
|
-
function writeLockAtomic(lockPath, blob) {
|
|
171
|
-
writeJsonAtomic(lockPath, blob);
|
|
172
|
-
}
|
|
173
170
|
function processIsAlive(pid) {
|
|
174
171
|
try {
|
|
175
172
|
// Signal 0 just checks for the process's existence without actually sending a signal.
|
|
@@ -216,7 +216,9 @@ export function brainclawMcpEntry(agentName, existing, workspacePath) {
|
|
|
216
216
|
export function quoteShellArg(arg) {
|
|
217
217
|
if (/^[A-Za-z0-9_./:=+-]+$/.test(arg))
|
|
218
218
|
return arg;
|
|
219
|
-
|
|
219
|
+
// Escape backslashes before quotes — otherwise an input like `\"` would
|
|
220
|
+
// collapse to a quote that breaks out of the quoted argument.
|
|
221
|
+
return `"${arg.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
|
|
220
222
|
}
|
|
221
223
|
/**
|
|
222
224
|
* Resolve the brainclaw CLI invocation for hook configs.
|
|
@@ -34,16 +34,18 @@ reachable (cold start, or a worktree without \`.brainclaw/\`).
|
|
|
34
34
|
|
|
35
35
|
1. \`bclaw_work(intent='consult')\` — loads project memory and reports active claims. Read \`bootstrap_recommended\`: if true the project has no usable PROJECT.md (see \`brainclaw-multi-agent\` → bootstrap loop).
|
|
36
36
|
2. If you will edit a scope, claim it: \`bclaw_work(intent='execute', scope='<path-or-feature>')\`. The response's \`claim_id\` is yours; \`claim_status='created'\` = new, \`'existing'\` = resumed.
|
|
37
|
-
3.
|
|
38
|
-
4.
|
|
37
|
+
3. Before editing unfamiliar code, orient with the **Code Map** instead of grepping blind: \`bclaw_code_brief(target='<symbol|path>')\` for a ranked reading list — the defining file, its importers, and related decisions/traps — or \`bclaw_code_find(query='<name>')\` to locate a symbol/class/component. A \`missing_index\`/stale badge means run \`bclaw_code_refresh\` first.
|
|
38
|
+
4. Do the work. Honor the \`warnings\` array (claim conflicts, sensitive paths, high-severity traps on your scope).
|
|
39
|
+
5. When done (committed, tested), \`bclaw_session_end(autoRelease: true)\` — closes the session record and releases your remaining claims. \`autoRelease\` defaults to false; pass it explicitly or claims survive the session.
|
|
39
40
|
|
|
40
|
-
CLI fallback: \`brainclaw context --json\` · \`brainclaw claim create "<desc>" --scope <path>\` · \`brainclaw session-end --auto-release\`.
|
|
41
|
+
CLI fallback: \`brainclaw context --json\` · \`brainclaw code-map brief <symbol>\` / \`brainclaw code-map find <name>\` · \`brainclaw claim create "<desc>" --scope <path>\` · \`brainclaw session-end --auto-release\`.
|
|
41
42
|
|
|
42
43
|
## Anti-rationalizations
|
|
43
44
|
|
|
44
45
|
- **"I'm just exploring, I'll skip session-end."** → A live claim outlives a crash. The next agent sees your stale claim and is blocked. Calling \`bclaw_session_end(autoRelease: true)\` is the zero-cost guarantee — without the flag the claim survives.
|
|
45
46
|
- **"I know the project, I don't need to consult."** → State changes between sessions (commits, new traps, new constraints). Consult is cheap and surfaces what you'd miss.
|
|
46
47
|
- **"I'll claim later once I know the exact scope."** → Claim-before-edit IS the contract; it is exactly what prevents races with parallel agents.
|
|
48
|
+
- **"I'll just grep for it."** → On an unfamiliar or large repo, grep floods you with noise and misses the blast radius. \`bclaw_code_brief\` returns the defining file + its importers + related memory in one ranked call; fall back to grep only when the Code Map index is missing.
|
|
47
49
|
|
|
48
50
|
## Red flags
|
|
49
51
|
|
|
@@ -26,7 +26,7 @@ export const BUILTIN_DETECTORS = [
|
|
|
26
26
|
{ id: 'aws_access_key', label: 'AWS access key ID', pattern: /\bAKIA[0-9A-Z]{16}\b/ },
|
|
27
27
|
{ id: 'aws_temp_access_key', label: 'AWS temporary access key ID', pattern: /\bASIA[0-9A-Z]{16}\b/ },
|
|
28
28
|
// Google
|
|
29
|
-
{ id: 'google_api_key', label: 'Google API key', pattern: /\bAIza[0-9A-Za-z_
|
|
29
|
+
{ id: 'google_api_key', label: 'Google API key', pattern: /\bAIza[0-9A-Za-z_-]{35}\b/ },
|
|
30
30
|
// Slack
|
|
31
31
|
{ id: 'slack_token', label: 'Slack token', pattern: /\bxox[abprs]-[0-9A-Za-z-]{10,}\b/ },
|
|
32
32
|
{ id: 'slack_webhook', label: 'Slack webhook', pattern: /https:\/\/hooks\.slack\.com\/services\/T[A-Z0-9]{8,}\/B[A-Z0-9]{8,}\/[A-Za-z0-9]{24,}/ },
|
|
@@ -80,7 +80,7 @@ export function shannonEntropy(s) {
|
|
|
80
80
|
return h;
|
|
81
81
|
}
|
|
82
82
|
const SECRET_KEYWORD_CONTEXT = /(?:api[_-]?key|secret|token|password|passwd|auth|bearer|access[_-]?key|private[_-]?key)/i;
|
|
83
|
-
const HIGH_ENTROPY_CANDIDATE = /[A-Za-z0-9_
|
|
83
|
+
const HIGH_ENTROPY_CANDIDATE = /[A-Za-z0-9_+/=-]{16,}/g;
|
|
84
84
|
/**
|
|
85
85
|
* Entropy-based detection. Scans `text` for token-shaped substrings near
|
|
86
86
|
* a sensitive keyword. Two-stage gating keeps false positives low:
|
|
@@ -126,7 +126,7 @@ export function parseLockfile(filePath) {
|
|
|
126
126
|
parsed = JSON.parse(raw);
|
|
127
127
|
}
|
|
128
128
|
catch (err) {
|
|
129
|
-
throw new Error(`Failed to parse lockfile ${filePath}: ${err.message}
|
|
129
|
+
throw new Error(`Failed to parse lockfile ${filePath}: ${err.message}`, { cause: err });
|
|
130
130
|
}
|
|
131
131
|
if (!parsed || typeof parsed !== 'object')
|
|
132
132
|
return [];
|
|
@@ -175,7 +175,7 @@ function readFileOrThrow(p, label) {
|
|
|
175
175
|
return fs.readFileSync(p, 'utf-8');
|
|
176
176
|
}
|
|
177
177
|
catch (err) {
|
|
178
|
-
throw new Error(`Could not read ${label} at ${p}: ${err.message}
|
|
178
|
+
throw new Error(`Could not read ${label} at ${p}: ${err.message}`, { cause: err });
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
function resolveSibling(parent, nested) {
|
|
@@ -94,8 +94,10 @@ export function resolveTargetStore(cwd = process.cwd(), target = 'local', option
|
|
|
94
94
|
* 2. BRAINCLAW_CWD env var → workspace anchor injected by MCP configs
|
|
95
95
|
* 3. BRAINCLAW_PROJECT env var → resolved by name/path from workspace anchor
|
|
96
96
|
* 4. Session-scoped active project (from .current-session under the anchor)
|
|
97
|
-
* 5.
|
|
98
|
-
*
|
|
97
|
+
* 5. cwd_child — the child project the agent is physically inside, under the anchor
|
|
98
|
+
* 5b. cwd_child (no anchor) — same, ceiling = discovered workspace root (F2)
|
|
99
|
+
* 6. Global active-project.json in workspace root
|
|
100
|
+
* 7. Workspace anchor or process.cwd()
|
|
99
101
|
*/
|
|
100
102
|
export function resolveEffectiveCwd(options = {}) {
|
|
101
103
|
return resolveEffectiveCwdInfo(options).cwd;
|
|
@@ -138,7 +140,42 @@ export function resolveEffectiveCwdInfo(options = {}) {
|
|
|
138
140
|
return { cwd: sp.path, active_source: 'session', resolved_project: { path: sp.path, name: sp.name } };
|
|
139
141
|
}
|
|
140
142
|
}
|
|
141
|
-
// 5.
|
|
143
|
+
// 5. cwd_child — when anchored and the agent is physically inside a child store
|
|
144
|
+
// STRICTLY under the anchor, resolve THAT child rather than the shared global
|
|
145
|
+
// pointer or the anchor root. This is the independence rule: physical location
|
|
146
|
+
// beats a shared/stale global (an agent working in apps/api resolves api, not the
|
|
147
|
+
// monorepo root, and is not hijacked by another agent's global switch).
|
|
148
|
+
//
|
|
149
|
+
// GUARD (Codex review): only fire when baseCwd differs from the anchor AND is
|
|
150
|
+
// at/below it. `findClosestStoreBelow` walks UP to the ceiling but does NOT prove
|
|
151
|
+
// baseCwd sits below it — without the `isAtOrBelow` guard a baseCwd OUTSIDE the
|
|
152
|
+
// anchor could match an unrelated `.brainclaw` before hitting the filesystem root.
|
|
153
|
+
if (baseCwd !== anchorCwd && isAtOrBelow(baseCwd, anchorCwd)) {
|
|
154
|
+
const child = findClosestStoreBelow(baseCwd, anchorCwd);
|
|
155
|
+
if (child && path.resolve(child) !== path.resolve(anchorCwd)) {
|
|
156
|
+
return { cwd: child, active_source: 'cwd_child', resolved_project: projectInfo(child) };
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// 5b. cwd_child (NO anchor) — F2 [trp_71accb07]: even without a BRAINCLAW_CWD
|
|
160
|
+
// anchor, an agent physically inside a child project must resolve THAT
|
|
161
|
+
// child rather than a stale/shared global pointer set by another agent.
|
|
162
|
+
// Ceiling = the discovered workspace root via resolveWorkspaceRoot(baseCwd)
|
|
163
|
+
// — NOT os.homedir() (that would revive the F6 boundary edge and could let
|
|
164
|
+
// an unrelated home store influence a monorepo worker). Same containment
|
|
165
|
+
// guard as the anchored case (isAtOrBelow + a child strictly below).
|
|
166
|
+
// For a single-project repo this is a strict no-op: findClosestStoreBelow
|
|
167
|
+
// walks UP to the ceiling EXCLUSIVELY, so it can never return the lone root
|
|
168
|
+
// store (Codex cadrage non-regression proof, batch 2).
|
|
169
|
+
if (!hasEnvWorkspace) {
|
|
170
|
+
const physicalRoot = resolveWorkspaceRoot(baseCwd, options.storeChainOptions);
|
|
171
|
+
if (physicalRoot && isAtOrBelow(baseCwd, physicalRoot)) {
|
|
172
|
+
const child = findClosestStoreBelow(baseCwd, physicalRoot);
|
|
173
|
+
if (child && path.resolve(child) !== path.resolve(physicalRoot)) {
|
|
174
|
+
return { cwd: child, active_source: 'cwd_child', resolved_project: projectInfo(child) };
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
// 6. Global active-project.json from workspace root
|
|
142
179
|
const wsRoot = hasEnvWorkspace ? anchorCwd : resolveWorkspaceRoot(anchorCwd, options.storeChainOptions);
|
|
143
180
|
if (wsRoot) {
|
|
144
181
|
const active = loadActiveProject(wsRoot);
|
|
@@ -146,7 +183,7 @@ export function resolveEffectiveCwdInfo(options = {}) {
|
|
|
146
183
|
return { cwd: active.path, active_source: 'global', resolved_project: { path: active.path, name: active.name } };
|
|
147
184
|
}
|
|
148
185
|
}
|
|
149
|
-
//
|
|
186
|
+
// 7. Default
|
|
150
187
|
return { cwd: anchorCwd, active_source: 'cwd', resolved_project: projectInfo(anchorCwd) };
|
|
151
188
|
}
|
|
152
189
|
function projectInfo(cwd) {
|
package/dist/facts.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// Generated by scripts/emit-site-facts.mjs at build time. Do not edit manually.
|
|
2
|
-
// Source: brainclaw v1.
|
|
2
|
+
// Source: brainclaw v1.10.1 on 2026-06-21T19:26:16.599Z
|
|
3
3
|
export const FACTS = {
|
|
4
|
-
"version": "1.
|
|
5
|
-
"generated_at": "2026-06-
|
|
4
|
+
"version": "1.10.1",
|
|
5
|
+
"generated_at": "2026-06-21T19:26:16.599Z",
|
|
6
6
|
"tools": {
|
|
7
|
-
"count":
|
|
8
|
-
"published_count":
|
|
7
|
+
"count": 66,
|
|
8
|
+
"published_count": 65,
|
|
9
9
|
"names": [
|
|
10
10
|
"bclaw_bootstrap",
|
|
11
11
|
"bclaw_release_notes",
|
|
@@ -31,6 +31,10 @@ export const FACTS = {
|
|
|
31
31
|
"bclaw_read_inbox",
|
|
32
32
|
"bclaw_get_thread",
|
|
33
33
|
"bclaw_dispatch_status",
|
|
34
|
+
"bclaw_code_status",
|
|
35
|
+
"bclaw_code_find",
|
|
36
|
+
"bclaw_code_brief",
|
|
37
|
+
"bclaw_code_refresh",
|
|
34
38
|
"bclaw_dispatch",
|
|
35
39
|
"bclaw_send_message",
|
|
36
40
|
"bclaw_ack_message",
|
package/dist/facts.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "1.
|
|
3
|
-
"generated_at": "2026-06-
|
|
2
|
+
"version": "1.10.1",
|
|
3
|
+
"generated_at": "2026-06-21T19:26:16.599Z",
|
|
4
4
|
"tools": {
|
|
5
|
-
"count":
|
|
6
|
-
"published_count":
|
|
5
|
+
"count": 66,
|
|
6
|
+
"published_count": 65,
|
|
7
7
|
"names": [
|
|
8
8
|
"bclaw_bootstrap",
|
|
9
9
|
"bclaw_release_notes",
|
|
@@ -29,6 +29,10 @@
|
|
|
29
29
|
"bclaw_read_inbox",
|
|
30
30
|
"bclaw_get_thread",
|
|
31
31
|
"bclaw_dispatch_status",
|
|
32
|
+
"bclaw_code_status",
|
|
33
|
+
"bclaw_code_find",
|
|
34
|
+
"bclaw_code_brief",
|
|
35
|
+
"bclaw_code_refresh",
|
|
32
36
|
"bclaw_dispatch",
|
|
33
37
|
"bclaw_send_message",
|
|
34
38
|
"bclaw_ack_message",
|