vibe-splain 3.4.0 → 3.4.2
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 +25 -19
- package/dist/commands/hook.d.ts +9 -0
- package/dist/commands/hook.js +84 -0
- package/dist/commands/install.d.ts +5 -0
- package/dist/commands/install.js +58 -9
- package/dist/commands/network.d.ts +1 -0
- package/dist/commands/network.js +91 -0
- package/dist/commands/scan.d.ts +13 -0
- package/dist/commands/scan.js +97 -0
- package/dist/export/ExportOrchestrator.js +8 -6
- package/dist/export/renderers/AgentMarkdownRenderer.d.ts +1 -2
- package/dist/export/renderers/AgentMarkdownRenderer.js +1 -17
- package/dist/hook/preToolUse.d.ts +30 -0
- package/dist/hook/preToolUse.js +81 -0
- package/dist/hook-entry.d.ts +2 -0
- package/dist/hook-entry.js +8 -0
- package/dist/hook.d.ts +1 -0
- package/dist/hook.js +337 -0
- package/dist/index.js +2679 -1389
- package/dist/mcp/server.js +9 -10
- package/dist/mcp/tools/explainSpecialistScope.d.ts +15 -0
- package/dist/mcp/tools/explainSpecialistScope.js +30 -0
- package/dist/mcp/tools/hydration/get_evidence_slice.js +1 -3
- package/dist/mcp/tools/prepareTaskContext.d.ts +38 -0
- package/dist/mcp/tools/prepareTaskContext.js +93 -0
- package/dist/mcp/tools/scan_project.d.ts +15 -0
- package/dist/mcp/tools/scan_project.js +16 -13
- package/dist/ui/index.html +3 -3
- package/package.json +1 -1
package/dist/mcp/server.js
CHANGED
|
@@ -11,17 +11,16 @@ import { handleGetStrategicOverview, getStrategicOverviewTool } from './tools/ge
|
|
|
11
11
|
import { handleInspectPillar, inspectPillarTool } from './tools/inspect_pillar.js';
|
|
12
12
|
import { handleGetWildDiscoveries, getWildDiscoveriesTool } from './tools/get_wild_discoveries.js';
|
|
13
13
|
import { handleMarkStale, markStaleTool } from './tools/mark_stale.js';
|
|
14
|
-
import { handleGetCallChain, getCallChainTool } from './tools/get_call_chain.js';
|
|
15
14
|
import { handleGetFileSkeleton, getFileSkeletonTool } from './tools/get_file_skeleton.js';
|
|
16
15
|
import { handleReadFile, readFileTool } from './tools/read_file.js';
|
|
17
|
-
import { handleApplyPatch, applyPatchTool } from './tools/apply_patch.js';
|
|
18
16
|
import { handleCreateWorkOrder, createWorkOrderTool, handleSpawnWorker, spawnWorkerTool } from './tools/work_orders.js';
|
|
19
|
-
import { handleSubmitReceipt, submitReceiptTool } from './tools/submit_receipt.js';
|
|
20
17
|
import { handleSetSessionScope, setSessionScopeTool } from './tools/set_session_scope.js';
|
|
21
18
|
import { handleYieldForScopeExpansion, yieldForScopeExpansionTool } from './tools/yield_for_scope_expansion.js';
|
|
22
19
|
import { handleGetStartHere, getStartHereTool } from './tools/hydration/get_start_here.js';
|
|
23
20
|
import { handleGetProjectSummary, getProjectSummaryTool } from './tools/hydration/get_project_summary.js';
|
|
24
21
|
import { handleGetEvidenceSlice, getEvidenceSliceTool } from './tools/hydration/get_evidence_slice.js';
|
|
22
|
+
import { handlePrepareTaskContext, prepareTaskContextTool } from './tools/prepareTaskContext.js';
|
|
23
|
+
import { handleExplainSpecialistScope, explainSpecialistScopeTool } from './tools/explainSpecialistScope.js';
|
|
25
24
|
// ⚠️ CRITICAL: Never use console.log() anywhere in this codebase.
|
|
26
25
|
// stdout is owned by the MCP SDK for protocol messages.
|
|
27
26
|
// Use console.error() for all diagnostic output.
|
|
@@ -30,7 +29,6 @@ const ALL_TOOLS = [
|
|
|
30
29
|
getProjectMapTool,
|
|
31
30
|
setProjectBriefTool,
|
|
32
31
|
getFileContextTool,
|
|
33
|
-
getCallChainTool,
|
|
34
32
|
writeDecisionCardTool,
|
|
35
33
|
getStrategicOverviewTool,
|
|
36
34
|
inspectPillarTool,
|
|
@@ -42,21 +40,21 @@ const ALL_TOOLS = [
|
|
|
42
40
|
getStartHereTool,
|
|
43
41
|
getProjectSummaryTool,
|
|
44
42
|
getEvidenceSliceTool,
|
|
45
|
-
// Phase 3: Delegation
|
|
43
|
+
// Phase 3: Worker Delegation
|
|
46
44
|
createWorkOrderTool,
|
|
47
45
|
spawnWorkerTool,
|
|
48
|
-
applyPatchTool,
|
|
49
|
-
submitReceiptTool,
|
|
50
46
|
// Phase 4: Scope & Escalation
|
|
51
47
|
setSessionScopeTool,
|
|
52
48
|
yieldForScopeExpansionTool,
|
|
49
|
+
// Specialist Network v0
|
|
50
|
+
prepareTaskContextTool,
|
|
51
|
+
explainSpecialistScopeTool,
|
|
53
52
|
];
|
|
54
53
|
const TOOL_HANDLERS = {
|
|
55
54
|
scan_project: handleScanProject,
|
|
56
55
|
get_project_map: handleGetProjectMap,
|
|
57
56
|
set_project_brief: handleSetProjectBrief,
|
|
58
57
|
get_file_context: handleGetFileContext,
|
|
59
|
-
get_call_chain: handleGetCallChain,
|
|
60
58
|
write_decision_card: handleWriteDecisionCard,
|
|
61
59
|
get_strategic_overview: handleGetStrategicOverview,
|
|
62
60
|
inspect_pillar: handleInspectPillar,
|
|
@@ -71,11 +69,12 @@ const TOOL_HANDLERS = {
|
|
|
71
69
|
// Phase 3
|
|
72
70
|
create_work_order: handleCreateWorkOrder,
|
|
73
71
|
spawn_worker: handleSpawnWorker,
|
|
74
|
-
apply_patch: handleApplyPatch,
|
|
75
|
-
submit_receipt: handleSubmitReceipt,
|
|
76
72
|
// Phase 4
|
|
77
73
|
set_session_scope: handleSetSessionScope,
|
|
78
74
|
yield_for_scope_expansion: handleYieldForScopeExpansion,
|
|
75
|
+
// Specialist Network v0
|
|
76
|
+
vibe_prepare_task_context: handlePrepareTaskContext,
|
|
77
|
+
vibe_explain_specialist_scope: handleExplainSpecialistScope,
|
|
79
78
|
};
|
|
80
79
|
export async function startMCPServer(options = {}) {
|
|
81
80
|
// Initialize Tree-Sitter WASM once at startup
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const explainSpecialistScopeTool: {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
inputSchema: {
|
|
5
|
+
type: "object";
|
|
6
|
+
properties: {
|
|
7
|
+
specialist_id: {
|
|
8
|
+
type: string;
|
|
9
|
+
description: string;
|
|
10
|
+
};
|
|
11
|
+
};
|
|
12
|
+
required: string[];
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
export declare function handleExplainSpecialistScope(args: Record<string, unknown>, options?: any): Promise<unknown>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { getSpecialistProfile, isSpecialistId } from '@vibe-splain/brain';
|
|
2
|
+
export const explainSpecialistScopeTool = {
|
|
3
|
+
name: 'vibe_explain_specialist_scope',
|
|
4
|
+
description: 'Explains the jurisdiction scope card and profile definitions for a given specialist ID.',
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: 'object',
|
|
7
|
+
properties: {
|
|
8
|
+
specialist_id: {
|
|
9
|
+
type: 'string',
|
|
10
|
+
description: 'Specialist ID to explain (control_flow | data_transform | integration_contracts | generic_repo)',
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
required: ['specialist_id'],
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
export async function handleExplainSpecialistScope(args, options = {}) {
|
|
17
|
+
const specialistId = args.specialist_id;
|
|
18
|
+
if (!specialistId)
|
|
19
|
+
throw new Error('specialist_id is required');
|
|
20
|
+
if (!isSpecialistId(specialistId)) {
|
|
21
|
+
throw new Error(`Invalid specialist ID: "${specialistId}". Must be one of: control_flow, data_transform, integration_contracts, generic_repo.`);
|
|
22
|
+
}
|
|
23
|
+
console.error(`[vibe-splain] Fetching scope profile for specialist: "${specialistId}"`);
|
|
24
|
+
const profile = getSpecialistProfile(specialistId);
|
|
25
|
+
return {
|
|
26
|
+
ok: true,
|
|
27
|
+
profile
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=explainSpecialistScope.js.map
|
|
@@ -27,8 +27,7 @@ export async function handleGetEvidenceSlice(args) {
|
|
|
27
27
|
// 1. Verify pointer, lifetime, hash
|
|
28
28
|
const { content, row } = await hydratePointer(projectRoot, pointerId);
|
|
29
29
|
const rawText = content.toString('utf8');
|
|
30
|
-
//
|
|
31
|
-
// file_read and file_skeleton blobs embed the source filePath — enforce it.
|
|
30
|
+
// Scope enforcement: if a Worker scope is active, enforce it for file-type artifacts
|
|
32
31
|
const scope = SessionScope.get();
|
|
33
32
|
if (scope && (row.artifactName === 'file_read' || row.artifactName === 'file_skeleton')) {
|
|
34
33
|
try {
|
|
@@ -38,7 +37,6 @@ export async function handleGetEvidenceSlice(args) {
|
|
|
38
37
|
}
|
|
39
38
|
}
|
|
40
39
|
catch (e) {
|
|
41
|
-
// If it's a ScopeViolation, re-throw; JSON parse failures are ignored.
|
|
42
40
|
if (e.name === 'ScopeViolation')
|
|
43
41
|
throw e;
|
|
44
42
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export declare const prepareTaskContextTool: {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
inputSchema: {
|
|
5
|
+
type: "object";
|
|
6
|
+
properties: {
|
|
7
|
+
projectRoot: {
|
|
8
|
+
type: string;
|
|
9
|
+
description: string;
|
|
10
|
+
};
|
|
11
|
+
task: {
|
|
12
|
+
type: string;
|
|
13
|
+
description: string;
|
|
14
|
+
};
|
|
15
|
+
files: {
|
|
16
|
+
type: string;
|
|
17
|
+
items: {
|
|
18
|
+
type: string;
|
|
19
|
+
};
|
|
20
|
+
description: string;
|
|
21
|
+
};
|
|
22
|
+
error_trace: {
|
|
23
|
+
type: string;
|
|
24
|
+
description: string;
|
|
25
|
+
};
|
|
26
|
+
intended_behavior: {
|
|
27
|
+
type: string;
|
|
28
|
+
description: string;
|
|
29
|
+
};
|
|
30
|
+
max_files: {
|
|
31
|
+
type: string;
|
|
32
|
+
description: string;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
required: string[];
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
export declare function handlePrepareTaskContext(args: Record<string, unknown>, options?: any): Promise<unknown>;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { join } from 'path';
|
|
2
|
+
import { readFile, writeFile, mkdir } from 'fs/promises';
|
|
3
|
+
import { buildExpertNetworkPacket } from '@vibe-splain/brain';
|
|
4
|
+
export const prepareTaskContextTool = {
|
|
5
|
+
name: 'vibe_prepare_task_context',
|
|
6
|
+
description: 'Prepares the ExpertNetworkPacket for a given task, selecting relevant files, routing to a specialist panel, analyzing risk warnings, and slicing scopes without running model inference.',
|
|
7
|
+
inputSchema: {
|
|
8
|
+
type: 'object',
|
|
9
|
+
properties: {
|
|
10
|
+
projectRoot: {
|
|
11
|
+
type: 'string',
|
|
12
|
+
description: 'Absolute path to the project root directory',
|
|
13
|
+
},
|
|
14
|
+
task: {
|
|
15
|
+
type: 'string',
|
|
16
|
+
description: 'Description of the task or issue to resolve',
|
|
17
|
+
},
|
|
18
|
+
files: {
|
|
19
|
+
type: 'array',
|
|
20
|
+
items: { type: 'string' },
|
|
21
|
+
description: 'Optional list of files to explicitly focus on',
|
|
22
|
+
},
|
|
23
|
+
error_trace: {
|
|
24
|
+
type: 'string',
|
|
25
|
+
description: 'Optional error stack trace or exception output',
|
|
26
|
+
},
|
|
27
|
+
intended_behavior: {
|
|
28
|
+
type: 'string',
|
|
29
|
+
description: 'Optional description of the intended behavior',
|
|
30
|
+
},
|
|
31
|
+
max_files: {
|
|
32
|
+
type: 'number',
|
|
33
|
+
description: 'Optional maximum files to select',
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
required: ['projectRoot', 'task'],
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
export async function handlePrepareTaskContext(args, options = {}) {
|
|
40
|
+
const projectRoot = args.projectRoot;
|
|
41
|
+
const task = args.task;
|
|
42
|
+
const files = args.files;
|
|
43
|
+
const errorTrace = args.error_trace;
|
|
44
|
+
const intendedBehavior = args.intended_behavior;
|
|
45
|
+
const maxFiles = args.max_files;
|
|
46
|
+
if (!projectRoot)
|
|
47
|
+
throw new Error('projectRoot is required');
|
|
48
|
+
if (!task)
|
|
49
|
+
throw new Error('task is required');
|
|
50
|
+
console.error(`[vibe-splain] Preparing task context for task: "${task}"`);
|
|
51
|
+
// Try to load scan artifact
|
|
52
|
+
let scanArtifact = null;
|
|
53
|
+
const artifactPath = join(projectRoot, '.vibe-splainer', 'analysis.json');
|
|
54
|
+
try {
|
|
55
|
+
const raw = await readFile(artifactPath, 'utf8');
|
|
56
|
+
scanArtifact = JSON.parse(raw);
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
console.error(`[vibe-splain] No scan artifact found at ${artifactPath}, proceeding with fallback routing.`);
|
|
60
|
+
}
|
|
61
|
+
// Build the packet
|
|
62
|
+
const packet = buildExpertNetworkPacket({
|
|
63
|
+
task,
|
|
64
|
+
projectRoot,
|
|
65
|
+
scanArtifact,
|
|
66
|
+
files,
|
|
67
|
+
errorTrace,
|
|
68
|
+
intendedBehavior,
|
|
69
|
+
maxFiles
|
|
70
|
+
});
|
|
71
|
+
// Save network packet locally
|
|
72
|
+
const networkDir = join(projectRoot, '.vibe-splainer', 'network');
|
|
73
|
+
const packetsDir = join(networkDir, 'packets');
|
|
74
|
+
try {
|
|
75
|
+
await mkdir(packetsDir, { recursive: true });
|
|
76
|
+
// Save latest
|
|
77
|
+
const latestPath = join(networkDir, 'latest_packet.json');
|
|
78
|
+
await writeFile(latestPath, JSON.stringify(packet, null, 2), 'utf8');
|
|
79
|
+
// Save timestamped
|
|
80
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
81
|
+
const timestampedPath = join(packetsDir, `${timestamp}.json`);
|
|
82
|
+
await writeFile(timestampedPath, JSON.stringify(packet, null, 2), 'utf8');
|
|
83
|
+
console.error(`[vibe-splain] Network packets saved under ${networkDir}`);
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
console.error('[vibe-splain] Failed to save network packets locally:', err.message);
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
ok: true,
|
|
90
|
+
packet
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=prepareTaskContext.js.map
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { scanProject } from '@vibe-splain/brain';
|
|
2
|
+
import type { Dossier } from '@vibe-splain/brain';
|
|
1
3
|
export declare const scanProjectTool: {
|
|
2
4
|
name: string;
|
|
3
5
|
description: string;
|
|
@@ -12,4 +14,17 @@ export declare const scanProjectTool: {
|
|
|
12
14
|
required: string[];
|
|
13
15
|
};
|
|
14
16
|
};
|
|
17
|
+
/**
|
|
18
|
+
* Shared scan core: run the brain pipeline, build the dossier, and write the
|
|
19
|
+
* artifact bundle. Both the MCP `scan_project` tool and the headless CLI `scan`
|
|
20
|
+
* command call this — there is exactly one scan path. Side-effects beyond
|
|
21
|
+
* artifact writing (e.g. the staleness watcher) are the caller's concern.
|
|
22
|
+
*/
|
|
23
|
+
export interface ScanRun {
|
|
24
|
+
result: Awaited<ReturnType<typeof scanProject>>;
|
|
25
|
+
dossier: Dossier;
|
|
26
|
+
scanId: string;
|
|
27
|
+
manifestPointer: unknown;
|
|
28
|
+
}
|
|
29
|
+
export declare function performScan(projectRoot: string, options?: any): Promise<ScanRun>;
|
|
15
30
|
export declare function handleScanProject(args: Record<string, unknown>, options?: any): Promise<unknown>;
|
|
@@ -15,11 +15,7 @@ export const scanProjectTool = {
|
|
|
15
15
|
required: ['projectRoot'],
|
|
16
16
|
},
|
|
17
17
|
};
|
|
18
|
-
export async function
|
|
19
|
-
const projectRoot = args.projectRoot;
|
|
20
|
-
if (!projectRoot)
|
|
21
|
-
throw new Error('projectRoot is required');
|
|
22
|
-
console.error(`[vibe-splain] Scanning project: ${projectRoot}`);
|
|
18
|
+
export async function performScan(projectRoot, options = {}) {
|
|
23
19
|
const result = await scanProject(projectRoot);
|
|
24
20
|
// Preserve any existing cards; replace the structural map every scan.
|
|
25
21
|
const existing = await readDossier(projectRoot);
|
|
@@ -54,17 +50,25 @@ export async function handleScanProject(args, options = {}) {
|
|
|
54
50
|
budget: options.budget ? parseInt(options.budget, 10) : undefined,
|
|
55
51
|
scope: options.scope,
|
|
56
52
|
}, result.store, result.graph, scanId);
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
return { result, dossier, scanId, manifestPointer };
|
|
54
|
+
}
|
|
55
|
+
export async function handleScanProject(args, options = {}) {
|
|
56
|
+
const projectRoot = args.projectRoot;
|
|
57
|
+
if (!projectRoot)
|
|
58
|
+
throw new Error('projectRoot is required');
|
|
59
|
+
console.error(`[vibe-splain] Scanning project: ${projectRoot}`);
|
|
60
|
+
const { result, scanId, manifestPointer } = await performScan(projectRoot, options);
|
|
61
|
+
// Watch the real-source files for staleness. MCP serve mode keeps this alive
|
|
62
|
+
// for the session; headless callers pass watch:false so the persistent
|
|
63
|
+
// chokidar watcher never pins the event loop open and the process can exit.
|
|
64
|
+
if (options.watch !== false) {
|
|
65
|
+
await startWatcher(projectRoot, result.files.map(f => f.path));
|
|
66
|
+
}
|
|
59
67
|
console.error(`[vibe-splain] Scan complete. ${result.totalFilesScanned} files, ${result.realSourceCount} real-source, ${result.wildCandidates.length} wild candidates.`);
|
|
60
68
|
const validation = result.validation ?? { passed: true, errors: 0, warnings: 0, reportPath: '.vibe-splainer/validation_report.json' };
|
|
61
|
-
let statusMsg = 'Scan complete.';
|
|
62
|
-
if (!validation.passed) {
|
|
63
|
-
statusMsg = `SCAN QUALITY WARNING: ${validation.errors} errors and ${validation.warnings} warnings found in validation report. Delta Engine automation may be blocked.`;
|
|
64
|
-
}
|
|
65
69
|
return {
|
|
66
70
|
ok: true,
|
|
67
|
-
message:
|
|
71
|
+
message: 'Scan complete.',
|
|
68
72
|
scanId,
|
|
69
73
|
manifestPointer,
|
|
70
74
|
validation: result.fullValidationReport || {
|
|
@@ -75,7 +79,6 @@ export async function handleScanProject(args, options = {}) {
|
|
|
75
79
|
},
|
|
76
80
|
artifacts: {
|
|
77
81
|
analysis: '.vibe-splainer/analysis.json',
|
|
78
|
-
deltaTargets: '.vibe-splainer/delta_targets.json',
|
|
79
82
|
dossier: '.vibe-splainer/dossier.json',
|
|
80
83
|
graph: '.vibe-splainer/graph.json',
|
|
81
84
|
html: '.vibe-splainer/ui/index.html',
|