brainclaw 1.5.3 → 1.5.5
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/LICENSE +21 -74
- package/README.md +62 -38
- package/dist/brainclaw-vscode.vsix +0 -0
- package/dist/cli.js +72 -6
- package/dist/commands/assignment-resource.js +182 -0
- package/dist/commands/init.js +158 -22
- package/dist/commands/mcp-read-handlers.js +8 -4
- package/dist/commands/mcp-schemas.generated.js +196 -1
- package/dist/commands/mcp.js +12 -5
- package/dist/commands/setup.js +87 -48
- package/dist/commands/switch.js +4 -0
- package/dist/core/agentruns.js +10 -0
- package/dist/core/assignments.js +29 -10
- package/dist/core/context.js +1 -1
- package/dist/core/coordination.js +1 -1
- package/dist/core/entity-operations.js +38 -1
- package/dist/core/entity-registry.js +11 -10
- package/dist/core/schema.js +3 -0
- package/dist/core/store-resolution.js +26 -16
- package/dist/facts.js +3 -3
- package/dist/facts.json +2 -2
- package/docs/cli.md +115 -30
- package/docs/integrations/agents.md +14 -14
- package/docs/integrations/codex.md +15 -12
- package/docs/integrations/mcp.md +10 -4
- package/docs/integrations/overview.md +12 -3
- package/docs/mcp-schema-changelog.md +1 -1
- package/docs/playbooks/productivity/index.md +3 -3
- package/docs/product/positioning.md +10 -10
- package/docs/quickstart-existing-project.md +48 -28
- package/docs/quickstart.md +42 -28
- package/package.json +2 -2
package/dist/commands/init.js
CHANGED
|
@@ -4,7 +4,7 @@ import readline from 'node:readline/promises';
|
|
|
4
4
|
import { registerAgentIdentity, resolveDefaultAgentName, resolveExistingCurrentAgent } from '../core/agent-registry.js';
|
|
5
5
|
import { MEMORY_DIR, memoryExists, ensureMemoryDir, memoryPath, writeFileAtomic } from '../core/io.js';
|
|
6
6
|
import { emptyState, loadState, saveState } from '../core/state.js';
|
|
7
|
-
import { defaultConfig, saveConfig } from '../core/config.js';
|
|
7
|
+
import { defaultConfig, loadConfig, saveConfig } from '../core/config.js';
|
|
8
8
|
import { generateMarkdown } from '../core/markdown.js';
|
|
9
9
|
import { initMemoryRepo } from '../core/memory-git.js';
|
|
10
10
|
import { buildProjectIdentity, resolveExistingProjectIdentity, saveProjectIdentity } from '../core/project-registry.js';
|
|
@@ -18,6 +18,7 @@ import { buildAiSurfaceInventory, renderAiSurfaceUsageHints } from '../core/ai-s
|
|
|
18
18
|
import { ensureUserStore, hasCompletedSetup } from '../core/setup-state.js';
|
|
19
19
|
import { writeDetectedAgentExport } from './export.js';
|
|
20
20
|
import { writeDetectedAgentHooks } from './hooks.js';
|
|
21
|
+
import { ConfigSchema } from '../core/schema.js';
|
|
21
22
|
export async function runInit(options = {}) {
|
|
22
23
|
const cwd = options.cwd ?? process.cwd();
|
|
23
24
|
const containingMemoryStore = resolveContainingMemoryStore(cwd);
|
|
@@ -58,22 +59,20 @@ export async function runInit(options = {}) {
|
|
|
58
59
|
const existingIdentity = resolveExistingProjectIdentity(cwd);
|
|
59
60
|
const existingCurrentAgent = resolveExistingCurrentAgent(cwd);
|
|
60
61
|
const storageDir = resolveStorageDir(options.storageDir);
|
|
61
|
-
const
|
|
62
|
-
const
|
|
62
|
+
const projectMemoryExists = memoryExists(cwd);
|
|
63
|
+
const existingConfig = projectMemoryExists ? loadExistingConfig(cwd, storageDir) : undefined;
|
|
64
|
+
const topology = resolveTopology(options.topology, existingConfig?.topology);
|
|
65
|
+
const ignoreStrategy = resolveIgnoreStrategy(topology, existingConfig?.ignore_strategy);
|
|
63
66
|
const skipAgentBootstrap = options.skipAgentBootstrap === true || process.env.BRAINCLAW_SKIP_AGENT_BOOTSTRAP === '1';
|
|
64
67
|
const testMode = process.env.BRAINCLAW_TEST_MODE === '1';
|
|
65
68
|
const skipAiSurfaceScan = testMode || options.noAiScan === true || options.aiScan === false;
|
|
66
|
-
if (memoryExists(cwd) && !options.force) {
|
|
67
|
-
console.error('Error: project memory already exists. Use --force to overwrite.');
|
|
68
|
-
process.exit(1);
|
|
69
|
-
}
|
|
70
69
|
// Derive project name from directory
|
|
71
70
|
const projectName = path.basename(cwd);
|
|
72
71
|
const shouldAnalyzeRepo = options.analyzeRepo !== false
|
|
73
72
|
&& process.env.BRAINCLAW_SKIP_REPO_ANALYSIS !== '1';
|
|
74
73
|
const analysis = shouldAnalyzeRepo ? analyzeRepository(cwd) : undefined;
|
|
75
|
-
const projectMode = await resolveProjectMode(options, analysis);
|
|
76
|
-
const projectStrategy = await resolveProjectStrategy(options, projectMode);
|
|
74
|
+
const projectMode = await resolveProjectMode(options, analysis, existingConfig?.project_mode);
|
|
75
|
+
const projectStrategy = await resolveProjectStrategy(options, projectMode, existingConfig?.projects?.strategy);
|
|
77
76
|
ensureMemoryDir(cwd, storageDir);
|
|
78
77
|
const currentAgent = registerAgentIdentity({
|
|
79
78
|
agentName: existingCurrentAgent?.agent_name ?? resolveDefaultAgentName(),
|
|
@@ -112,19 +111,21 @@ export async function runInit(options = {}) {
|
|
|
112
111
|
storageDir,
|
|
113
112
|
topology,
|
|
114
113
|
});
|
|
115
|
-
const config =
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
114
|
+
const config = buildInitConfig({
|
|
115
|
+
projectName,
|
|
116
|
+
projectIdentity,
|
|
117
|
+
currentAgent: {
|
|
118
|
+
name: currentAgent.agent_name,
|
|
119
|
+
id: currentAgent.agent_id,
|
|
120
|
+
},
|
|
119
121
|
projectMode,
|
|
120
122
|
projectStrategy,
|
|
121
123
|
storageDir,
|
|
122
124
|
topology,
|
|
123
125
|
ignoreStrategy,
|
|
126
|
+
existingConfig: options.force ? undefined : existingConfig,
|
|
127
|
+
compact: options.compact === true,
|
|
124
128
|
});
|
|
125
|
-
if (options.compact) {
|
|
126
|
-
config.markdown = { max_items_per_section: 20, compact_mode: true };
|
|
127
|
-
}
|
|
128
129
|
if (detectedAi && isAgentIntegrationName(detectedAi.name)) {
|
|
129
130
|
upsertAgentIntegrationDeclaration(config, detectedAi.name, 'detected');
|
|
130
131
|
}
|
|
@@ -173,8 +174,19 @@ export async function runInit(options = {}) {
|
|
|
173
174
|
.filter((item) => !item.startsWith('.codeium/'));
|
|
174
175
|
ensureGitignoreEntries(cwd, ['AGENTS.md', '.github/copilot-instructions.md', ...generatedWorkspacePaths, ...BRAINCLAW_EXCLUSIVE_DIRECTORIES]);
|
|
175
176
|
}
|
|
176
|
-
|
|
177
|
-
|
|
177
|
+
if (projectMemoryExists) {
|
|
178
|
+
console.log(`✔ Refreshed existing project memory in ${storageDir}/`);
|
|
179
|
+
if (options.force) {
|
|
180
|
+
console.log('✔ Existing memory preserved; rebuilt managed configuration and agent integration files from defaults');
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
console.log('✔ Existing memory preserved; refreshed managed configuration and agent integration files');
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
console.log(`✔ Initialized project memory in ${storageDir}/`);
|
|
188
|
+
console.log('✔ Created project.md, config.yaml, and split state directories');
|
|
189
|
+
}
|
|
178
190
|
console.log(`✔ Project ID: ${projectIdentity.project_id}`);
|
|
179
191
|
console.log(`✔ Current agent: ${currentAgent.agent_name} (${currentAgent.agent_id})`);
|
|
180
192
|
if (registeredAiAgent) {
|
|
@@ -275,6 +287,12 @@ export async function runInit(options = {}) {
|
|
|
275
287
|
}
|
|
276
288
|
}
|
|
277
289
|
console.log('');
|
|
290
|
+
if (projectMemoryExists) {
|
|
291
|
+
console.log(`Tip: run 'brainclaw enable-agent <agent-name>' when you want to explicitly add another agent to this existing project.`);
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
console.log(`Tip: run 'brainclaw init' again later to refresh the detected agent's integration files on this project.`);
|
|
295
|
+
}
|
|
278
296
|
console.log(`Tip: run 'brainclaw context --json' to load the shared memory into your agent session.`);
|
|
279
297
|
}
|
|
280
298
|
function installPostMergeHookIfMissing(cwd) {
|
|
@@ -342,8 +360,19 @@ function looksLikeBrainclawStore(storePath) {
|
|
|
342
360
|
|| fs.existsSync(path.join(storePath, 'project.identity.json'))
|
|
343
361
|
|| fs.existsSync(path.join(storePath, '.git'));
|
|
344
362
|
}
|
|
345
|
-
function resolveTopology(topology) {
|
|
346
|
-
return topology ?? 'embedded';
|
|
363
|
+
function resolveTopology(topology, existingTopology) {
|
|
364
|
+
return topology ?? existingTopology ?? 'embedded';
|
|
365
|
+
}
|
|
366
|
+
function resolveIgnoreStrategy(topology, existingIgnoreStrategy) {
|
|
367
|
+
return existingIgnoreStrategy ?? (topology === 'embedded' ? 'none' : 'project-gitignore');
|
|
368
|
+
}
|
|
369
|
+
function loadExistingConfig(cwd, storageDir) {
|
|
370
|
+
try {
|
|
371
|
+
return loadConfig(cwd, storageDir);
|
|
372
|
+
}
|
|
373
|
+
catch {
|
|
374
|
+
return undefined;
|
|
375
|
+
}
|
|
347
376
|
}
|
|
348
377
|
function ensureProjectGitignore(cwd, storageDir) {
|
|
349
378
|
const gitignorePath = path.join(cwd, '.gitignore');
|
|
@@ -358,10 +387,13 @@ function ensureProjectGitignore(cwd, storageDir) {
|
|
|
358
387
|
: `${current.replace(/\s*$/, '')}\n${ignoreLine}\n`;
|
|
359
388
|
fs.writeFileSync(gitignorePath, next, 'utf-8');
|
|
360
389
|
}
|
|
361
|
-
async function resolveProjectMode(options, analysis) {
|
|
390
|
+
async function resolveProjectMode(options, analysis, existingProjectMode) {
|
|
362
391
|
if (options.projectMode) {
|
|
363
392
|
return options.projectMode;
|
|
364
393
|
}
|
|
394
|
+
if (existingProjectMode) {
|
|
395
|
+
return existingProjectMode;
|
|
396
|
+
}
|
|
365
397
|
if (options.yes || !process.stdin.isTTY || !process.stdout.isTTY) {
|
|
366
398
|
return 'auto';
|
|
367
399
|
}
|
|
@@ -384,13 +416,16 @@ async function resolveProjectMode(options, analysis) {
|
|
|
384
416
|
rl.close();
|
|
385
417
|
}
|
|
386
418
|
}
|
|
387
|
-
async function resolveProjectStrategy(options, projectMode) {
|
|
419
|
+
async function resolveProjectStrategy(options, projectMode, existingProjectStrategy) {
|
|
388
420
|
if (options.projectStrategy) {
|
|
389
421
|
return options.projectStrategy;
|
|
390
422
|
}
|
|
391
423
|
if (projectMode !== 'multi-project') {
|
|
392
424
|
return 'manual';
|
|
393
425
|
}
|
|
426
|
+
if (existingProjectStrategy) {
|
|
427
|
+
return existingProjectStrategy;
|
|
428
|
+
}
|
|
394
429
|
if (options.yes || !process.stdin.isTTY || !process.stdout.isTTY) {
|
|
395
430
|
return 'manual';
|
|
396
431
|
}
|
|
@@ -438,4 +473,105 @@ function parseProjectStrategy(value) {
|
|
|
438
473
|
return undefined;
|
|
439
474
|
}
|
|
440
475
|
}
|
|
476
|
+
function buildInitConfig(input) {
|
|
477
|
+
const fallbackConfig = defaultConfig(input.projectName, {
|
|
478
|
+
projectId: input.projectIdentity.project_id,
|
|
479
|
+
currentAgent: input.currentAgent.name,
|
|
480
|
+
currentAgentId: input.currentAgent.id,
|
|
481
|
+
projectMode: input.projectMode,
|
|
482
|
+
projectStrategy: input.projectStrategy,
|
|
483
|
+
storageDir: input.storageDir,
|
|
484
|
+
topology: input.topology,
|
|
485
|
+
ignoreStrategy: input.ignoreStrategy,
|
|
486
|
+
});
|
|
487
|
+
const config = input.existingConfig
|
|
488
|
+
? mergeConfigWithDefaults(input.existingConfig, fallbackConfig)
|
|
489
|
+
: fallbackConfig;
|
|
490
|
+
const projects = config.projects ?? fallbackConfig.projects;
|
|
491
|
+
config.project_name = input.projectName;
|
|
492
|
+
config.project_id = input.projectIdentity.project_id;
|
|
493
|
+
config.current_agent = input.currentAgent.name;
|
|
494
|
+
config.current_agent_id = input.currentAgent.id;
|
|
495
|
+
config.storage_dir = input.storageDir;
|
|
496
|
+
config.topology = input.topology;
|
|
497
|
+
config.ignore_strategy = input.ignoreStrategy;
|
|
498
|
+
config.project_mode = input.projectMode;
|
|
499
|
+
config.projects = {
|
|
500
|
+
...projects,
|
|
501
|
+
strategy: input.projectStrategy,
|
|
502
|
+
known: projects.known ?? fallbackConfig.projects.known,
|
|
503
|
+
};
|
|
504
|
+
if (input.compact) {
|
|
505
|
+
const markdown = config.markdown ?? fallbackConfig.markdown ?? {
|
|
506
|
+
max_items_per_section: 20,
|
|
507
|
+
compact_mode: false,
|
|
508
|
+
};
|
|
509
|
+
config.markdown = {
|
|
510
|
+
...markdown,
|
|
511
|
+
compact_mode: true,
|
|
512
|
+
max_items_per_section: Math.min(markdown.max_items_per_section, 20),
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
return config;
|
|
516
|
+
}
|
|
517
|
+
function mergeConfigWithDefaults(existingConfig, fallbackConfig) {
|
|
518
|
+
return ConfigSchema.parse({
|
|
519
|
+
...fallbackConfig,
|
|
520
|
+
...existingConfig,
|
|
521
|
+
projects: {
|
|
522
|
+
...fallbackConfig.projects,
|
|
523
|
+
...(existingConfig.projects ?? {}),
|
|
524
|
+
known: existingConfig.projects?.known ?? fallbackConfig.projects.known,
|
|
525
|
+
},
|
|
526
|
+
redaction: {
|
|
527
|
+
...fallbackConfig.redaction,
|
|
528
|
+
...(existingConfig.redaction ?? {}),
|
|
529
|
+
patterns: existingConfig.redaction?.patterns ?? fallbackConfig.redaction.patterns,
|
|
530
|
+
},
|
|
531
|
+
security: existingConfig.security
|
|
532
|
+
? {
|
|
533
|
+
...fallbackConfig.security,
|
|
534
|
+
...existingConfig.security,
|
|
535
|
+
}
|
|
536
|
+
: fallbackConfig.security,
|
|
537
|
+
markdown: existingConfig.markdown
|
|
538
|
+
? {
|
|
539
|
+
...fallbackConfig.markdown,
|
|
540
|
+
...existingConfig.markdown,
|
|
541
|
+
}
|
|
542
|
+
: fallbackConfig.markdown,
|
|
543
|
+
reflective_memory: existingConfig.reflective_memory
|
|
544
|
+
? {
|
|
545
|
+
...fallbackConfig.reflective_memory,
|
|
546
|
+
...existingConfig.reflective_memory,
|
|
547
|
+
}
|
|
548
|
+
: fallbackConfig.reflective_memory,
|
|
549
|
+
governance: fallbackConfig.governance
|
|
550
|
+
? {
|
|
551
|
+
...fallbackConfig.governance,
|
|
552
|
+
...existingConfig.governance,
|
|
553
|
+
curators: existingConfig.governance?.curators ?? fallbackConfig.governance.curators,
|
|
554
|
+
}
|
|
555
|
+
: existingConfig.governance,
|
|
556
|
+
reputation: existingConfig.reputation
|
|
557
|
+
? {
|
|
558
|
+
...fallbackConfig.reputation,
|
|
559
|
+
...existingConfig.reputation,
|
|
560
|
+
}
|
|
561
|
+
: fallbackConfig.reputation,
|
|
562
|
+
agent_integrations: {
|
|
563
|
+
...fallbackConfig.agent_integrations,
|
|
564
|
+
...(existingConfig.agent_integrations ?? {}),
|
|
565
|
+
declarations: existingConfig.agent_integrations?.declarations ?? fallbackConfig.agent_integrations.declarations,
|
|
566
|
+
},
|
|
567
|
+
claims: existingConfig.claims
|
|
568
|
+
? {
|
|
569
|
+
...fallbackConfig.claims,
|
|
570
|
+
...existingConfig.claims,
|
|
571
|
+
}
|
|
572
|
+
: fallbackConfig.claims,
|
|
573
|
+
sensitive_paths: existingConfig.sensitive_paths ?? fallbackConfig.sensitive_paths,
|
|
574
|
+
cross_project_links: existingConfig.cross_project_links ?? fallbackConfig.cross_project_links,
|
|
575
|
+
});
|
|
576
|
+
}
|
|
441
577
|
//# sourceMappingURL=init.js.map
|
|
@@ -68,20 +68,24 @@ function getReviewAssignee(tags) {
|
|
|
68
68
|
return undefined;
|
|
69
69
|
}
|
|
70
70
|
export function handleMcpReadToolCall(name, args = {}, context = {}) {
|
|
71
|
-
|
|
71
|
+
const baseCwd = context.cwd ?? process.cwd();
|
|
72
|
+
let cwd = name === 'bclaw_switch'
|
|
73
|
+
? baseCwd
|
|
74
|
+
: resolveEffectiveCwd({ baseCwd });
|
|
72
75
|
// If a project param is provided, resolve it to an actual cwd override.
|
|
73
76
|
// resolveProjectCwd unifies cross_project_links (siblings/peers) AND
|
|
74
77
|
// workspace store-chain children. Throws on unknown project — surfaces
|
|
75
78
|
// visibly as a tool error rather than silently falling back to the
|
|
76
79
|
// current project, which would mislead the caller.
|
|
77
80
|
const projectArg = args.project;
|
|
78
|
-
|
|
79
|
-
|
|
81
|
+
const targetProjectArg = name === 'bclaw_switch' ? undefined : projectArg;
|
|
82
|
+
if (targetProjectArg) {
|
|
83
|
+
cwd = resolveProjectCwd(targetProjectArg, cwd);
|
|
80
84
|
}
|
|
81
85
|
if (name === 'bclaw_get_context') {
|
|
82
86
|
const result = buildContext({
|
|
83
87
|
target: args.path,
|
|
84
|
-
project:
|
|
88
|
+
project: targetProjectArg,
|
|
85
89
|
agent: args.agent,
|
|
86
90
|
host: args.host,
|
|
87
91
|
allHosts: args.allHosts,
|
|
@@ -20,12 +20,207 @@ export const generatedSchemas = {
|
|
|
20
20
|
"all",
|
|
21
21
|
"any"
|
|
22
22
|
]
|
|
23
|
+
},
|
|
24
|
+
"context_filter": {
|
|
25
|
+
"minItems": 1,
|
|
26
|
+
"type": "array",
|
|
27
|
+
"items": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"enum": [
|
|
30
|
+
"traps",
|
|
31
|
+
"feedback",
|
|
32
|
+
"runtime_notes",
|
|
33
|
+
"decisions",
|
|
34
|
+
"constraints",
|
|
35
|
+
"handoffs",
|
|
36
|
+
"plans",
|
|
37
|
+
"candidates",
|
|
38
|
+
"project_vision",
|
|
39
|
+
"critique_history",
|
|
40
|
+
"revision_history",
|
|
41
|
+
"synthesis_artifact",
|
|
42
|
+
"*"
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"advance_gate": {
|
|
47
|
+
"$ref": "#/$defs/__schema0"
|
|
23
48
|
}
|
|
24
49
|
},
|
|
25
50
|
"required": [
|
|
26
51
|
"name"
|
|
27
52
|
],
|
|
28
|
-
"additionalProperties": false
|
|
53
|
+
"additionalProperties": false,
|
|
54
|
+
"$defs": {
|
|
55
|
+
"__schema0": {
|
|
56
|
+
"anyOf": [
|
|
57
|
+
{
|
|
58
|
+
"oneOf": [
|
|
59
|
+
{
|
|
60
|
+
"type": "object",
|
|
61
|
+
"properties": {
|
|
62
|
+
"kind": {
|
|
63
|
+
"type": "string",
|
|
64
|
+
"const": "phase_reached"
|
|
65
|
+
},
|
|
66
|
+
"phase": {
|
|
67
|
+
"type": "string",
|
|
68
|
+
"minLength": 1
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"required": [
|
|
72
|
+
"kind",
|
|
73
|
+
"phase"
|
|
74
|
+
],
|
|
75
|
+
"additionalProperties": false
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"type": "object",
|
|
79
|
+
"properties": {
|
|
80
|
+
"kind": {
|
|
81
|
+
"type": "string",
|
|
82
|
+
"const": "reviewer_green"
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
"required": [
|
|
86
|
+
"kind"
|
|
87
|
+
],
|
|
88
|
+
"additionalProperties": false
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"type": "object",
|
|
92
|
+
"properties": {
|
|
93
|
+
"kind": {
|
|
94
|
+
"type": "string",
|
|
95
|
+
"const": "max_iterations"
|
|
96
|
+
},
|
|
97
|
+
"n": {
|
|
98
|
+
"type": "integer",
|
|
99
|
+
"exclusiveMinimum": 0,
|
|
100
|
+
"maximum": 9007199254740991
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
"required": [
|
|
104
|
+
"kind",
|
|
105
|
+
"n"
|
|
106
|
+
],
|
|
107
|
+
"additionalProperties": false
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"type": "object",
|
|
111
|
+
"properties": {
|
|
112
|
+
"kind": {
|
|
113
|
+
"type": "string",
|
|
114
|
+
"const": "artifact_produced"
|
|
115
|
+
},
|
|
116
|
+
"phase": {
|
|
117
|
+
"type": "string",
|
|
118
|
+
"minLength": 1
|
|
119
|
+
},
|
|
120
|
+
"type": {
|
|
121
|
+
"type": "string",
|
|
122
|
+
"minLength": 1
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
"required": [
|
|
126
|
+
"kind",
|
|
127
|
+
"phase",
|
|
128
|
+
"type"
|
|
129
|
+
],
|
|
130
|
+
"additionalProperties": false
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"type": "object",
|
|
134
|
+
"properties": {
|
|
135
|
+
"kind": {
|
|
136
|
+
"type": "string",
|
|
137
|
+
"const": "min_artifacts_by_type"
|
|
138
|
+
},
|
|
139
|
+
"type": {
|
|
140
|
+
"type": "string",
|
|
141
|
+
"minLength": 1
|
|
142
|
+
},
|
|
143
|
+
"n": {
|
|
144
|
+
"type": "integer",
|
|
145
|
+
"exclusiveMinimum": 0,
|
|
146
|
+
"maximum": 9007199254740991
|
|
147
|
+
},
|
|
148
|
+
"scope": {
|
|
149
|
+
"type": "string",
|
|
150
|
+
"enum": [
|
|
151
|
+
"phase",
|
|
152
|
+
"loop"
|
|
153
|
+
]
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
"required": [
|
|
157
|
+
"kind",
|
|
158
|
+
"type",
|
|
159
|
+
"n",
|
|
160
|
+
"scope"
|
|
161
|
+
],
|
|
162
|
+
"additionalProperties": false
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"type": "object",
|
|
166
|
+
"properties": {
|
|
167
|
+
"kind": {
|
|
168
|
+
"type": "string",
|
|
169
|
+
"const": "manual"
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
"required": [
|
|
173
|
+
"kind"
|
|
174
|
+
],
|
|
175
|
+
"additionalProperties": false
|
|
176
|
+
}
|
|
177
|
+
]
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"type": "object",
|
|
181
|
+
"properties": {
|
|
182
|
+
"kind": {
|
|
183
|
+
"type": "string",
|
|
184
|
+
"const": "any"
|
|
185
|
+
},
|
|
186
|
+
"conditions": {
|
|
187
|
+
"minItems": 1,
|
|
188
|
+
"type": "array",
|
|
189
|
+
"items": {
|
|
190
|
+
"$ref": "#/$defs/__schema0"
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
"required": [
|
|
195
|
+
"kind",
|
|
196
|
+
"conditions"
|
|
197
|
+
],
|
|
198
|
+
"additionalProperties": false
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
"type": "object",
|
|
202
|
+
"properties": {
|
|
203
|
+
"kind": {
|
|
204
|
+
"type": "string",
|
|
205
|
+
"const": "all"
|
|
206
|
+
},
|
|
207
|
+
"conditions": {
|
|
208
|
+
"minItems": 1,
|
|
209
|
+
"type": "array",
|
|
210
|
+
"items": {
|
|
211
|
+
"$ref": "#/$defs/__schema0"
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
"required": [
|
|
216
|
+
"kind",
|
|
217
|
+
"conditions"
|
|
218
|
+
],
|
|
219
|
+
"additionalProperties": false
|
|
220
|
+
}
|
|
221
|
+
]
|
|
222
|
+
}
|
|
223
|
+
}
|
|
29
224
|
},
|
|
30
225
|
"LoopSlotInput": {
|
|
31
226
|
"type": "object",
|
package/dist/commands/mcp.js
CHANGED
|
@@ -54,6 +54,8 @@ export const SCHEMA_VERSION = '1.0.0';
|
|
|
54
54
|
export const MCP_PROTOCOL_VERSIONS = ['2025-11-25', '2024-11-05'];
|
|
55
55
|
export const MCP_SERVER_NOT_INITIALIZED = -32002;
|
|
56
56
|
const MCP_RUNTIME_REPAIR_COMMAND = 'brainclaw doctor --repair';
|
|
57
|
+
const { $defs: loopPhaseDefs, ...loopPhaseItemSchema } = generatedSchemas.LoopPhase;
|
|
58
|
+
const loopSlotInputItemSchema = generatedSchemas.LoopSlotInput;
|
|
57
59
|
export const MCP_READ_TOOLS = [
|
|
58
60
|
{
|
|
59
61
|
name: 'bclaw_bootstrap',
|
|
@@ -917,6 +919,7 @@ const MCP_WRITE_TOOLS = [
|
|
|
917
919
|
annotations: { tier: 'facade', category: 'loops', headlessApproval: 'auto', experimental: true, schemaSource: 'zod-derived' },
|
|
918
920
|
inputSchema: {
|
|
919
921
|
type: 'object',
|
|
922
|
+
...(loopPhaseDefs ? { $defs: loopPhaseDefs } : {}),
|
|
920
923
|
properties: {
|
|
921
924
|
intent: {
|
|
922
925
|
type: 'string',
|
|
@@ -927,8 +930,8 @@ const MCP_WRITE_TOOLS = [
|
|
|
927
930
|
kind: { type: 'string', enum: ['review', 'ideation', 'implementation', 'research', 'debug'], description: 'Loop kind for open / list filter.' },
|
|
928
931
|
title: { type: 'string', description: 'Human-readable title (open).' },
|
|
929
932
|
goal: { type: 'string', description: 'Optional goal statement (open).' },
|
|
930
|
-
phases: { type: 'array', items:
|
|
931
|
-
slots: { type: 'array', items:
|
|
933
|
+
phases: { type: 'array', items: loopPhaseItemSchema, description: 'Optional phase list override (open). Items derived from LoopPhaseSchema (zod source) — see mcp-schemas.generated.ts.' },
|
|
934
|
+
slots: { type: 'array', items: loopSlotInputItemSchema, description: 'Optional initial slot specs (open). Items derived from LoopSlotInputSchema (zod source). Each item carries at least { role }.' },
|
|
932
935
|
linked: { type: 'object', description: 'Optional top-level plan/sequence refs (open).' },
|
|
933
936
|
stop_condition: { type: 'object', description: 'Optional stop_condition override (open). Composite any/all supported.' },
|
|
934
937
|
mode: { type: 'string', enum: ['asymmetric', 'symmetric'], description: 'Review mode selector for open (review kind only).' },
|
|
@@ -4884,7 +4887,7 @@ async function _executeMcpToolCallInner(payload) {
|
|
|
4884
4887
|
// dispatch analysis / review.
|
|
4885
4888
|
const { listAssignments: listAsgn } = await import('../core/assignments.js');
|
|
4886
4889
|
const predecessors = listAsgn(dispatchCwd, { claim_id: oldClaim.id })
|
|
4887
|
-
.filter((a) => a.status !== 'completed' && a.status !== 'expired' && a.status !== 'rerouted');
|
|
4890
|
+
.filter((a) => a.status !== 'completed' && a.status !== 'cancelled' && a.status !== 'expired' && a.status !== 'rerouted');
|
|
4888
4891
|
for (const predecessor of predecessors) {
|
|
4889
4892
|
try {
|
|
4890
4893
|
transitionAssignment(predecessor.id, 'rerouted', {
|
|
@@ -5492,7 +5495,10 @@ async function _executeMcpToolCallInner(payload) {
|
|
|
5492
5495
|
* break tool execution.
|
|
5493
5496
|
*/
|
|
5494
5497
|
export async function executeMcpToolCall(payload) {
|
|
5495
|
-
const
|
|
5498
|
+
const baseCwd = payload.cwd;
|
|
5499
|
+
const cwd = payload.name === 'bclaw_switch'
|
|
5500
|
+
? baseCwd
|
|
5501
|
+
: resolveEffectiveCwd({ baseCwd });
|
|
5496
5502
|
const envClaimId = process.env.BRAINCLAW_CLAIM_ID?.trim() || undefined;
|
|
5497
5503
|
// ── Auto-session ────────────────────────────────────────────────────────────
|
|
5498
5504
|
let autoSessionId;
|
|
@@ -5519,7 +5525,7 @@ export async function executeMcpToolCall(payload) {
|
|
|
5519
5525
|
// no longer show session_id="unknown".
|
|
5520
5526
|
try {
|
|
5521
5527
|
const { listAssignments: listA, saveAssignment: saveA } = await import('../core/assignments.js');
|
|
5522
|
-
const active = listA(cwd, { claim_id: envClaimId }).filter((a) => !['completed', 'expired', 'rerouted'].includes(a.status));
|
|
5528
|
+
const active = listA(cwd, { claim_id: envClaimId }).filter((a) => !['completed', 'cancelled', 'expired', 'rerouted'].includes(a.status));
|
|
5523
5529
|
for (const a of active) {
|
|
5524
5530
|
if (!a.session_id) {
|
|
5525
5531
|
a.session_id = autoSessionId;
|
|
@@ -5542,6 +5548,7 @@ export async function executeMcpToolCall(payload) {
|
|
|
5542
5548
|
// ── Delegate to inner handler ───────────────────────────────────────────────
|
|
5543
5549
|
const outcome = await _executeMcpToolCallInner({
|
|
5544
5550
|
...payload,
|
|
5551
|
+
cwd,
|
|
5545
5552
|
connectionSessionId: effectiveConnectionSessionId,
|
|
5546
5553
|
});
|
|
5547
5554
|
// Apply legacy deprecation warning uniformly (Phase 3 slice 3g). Read tools
|