vibe-splain 3.4.2 → 3.5.0
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 +5 -5
- package/dist/hook.js +0 -0
- package/dist/index.js +1780 -3520
- package/dist/mcp/server.js +1 -24
- package/package.json +2 -2
- package/dist/commands/bundle.d.ts +0 -4
- package/dist/commands/bundle.js +0 -68
- package/dist/commands/export.d.ts +0 -1
- package/dist/commands/export.js +0 -19
- package/dist/commands/gc.d.ts +0 -3
- package/dist/commands/gc.js +0 -59
- package/dist/commands/importBundle.d.ts +0 -4
- package/dist/commands/importBundle.js +0 -80
- package/dist/commands/network.d.ts +0 -1
- package/dist/commands/network.js +0 -91
- package/dist/commands/scan.d.ts +0 -13
- package/dist/commands/scan.js +0 -97
- package/dist/export/renderers/DeltaRenderer.d.ts +0 -6
- package/dist/export/renderers/DeltaRenderer.js +0 -22
- package/dist/hook-entry.d.ts +0 -2
- package/dist/hook-entry.js +0 -8
- package/dist/mcp/tools/apply_patch.d.ts +0 -37
- package/dist/mcp/tools/apply_patch.js +0 -103
- package/dist/mcp/tools/explainSpecialistScope.d.ts +0 -15
- package/dist/mcp/tools/explainSpecialistScope.js +0 -30
- package/dist/mcp/tools/get_call_chain.d.ts +0 -42
- package/dist/mcp/tools/get_call_chain.js +0 -50
- package/dist/mcp/tools/prepareTaskContext.d.ts +0 -38
- package/dist/mcp/tools/prepareTaskContext.js +0 -93
- package/dist/mcp/tools/set_session_scope.d.ts +0 -19
- package/dist/mcp/tools/set_session_scope.js +0 -40
- package/dist/mcp/tools/submit_receipt.d.ts +0 -68
- package/dist/mcp/tools/submit_receipt.js +0 -94
- package/dist/mcp/tools/work_orders.d.ts +0 -79
- package/dist/mcp/tools/work_orders.js +0 -126
- package/dist/mcp/tools/yield_for_scope_expansion.d.ts +0 -29
- package/dist/mcp/tools/yield_for_scope_expansion.js +0 -59
package/dist/mcp/server.js
CHANGED
|
@@ -13,14 +13,9 @@ import { handleGetWildDiscoveries, getWildDiscoveriesTool } from './tools/get_wi
|
|
|
13
13
|
import { handleMarkStale, markStaleTool } from './tools/mark_stale.js';
|
|
14
14
|
import { handleGetFileSkeleton, getFileSkeletonTool } from './tools/get_file_skeleton.js';
|
|
15
15
|
import { handleReadFile, readFileTool } from './tools/read_file.js';
|
|
16
|
-
import { handleCreateWorkOrder, createWorkOrderTool, handleSpawnWorker, spawnWorkerTool } from './tools/work_orders.js';
|
|
17
|
-
import { handleSetSessionScope, setSessionScopeTool } from './tools/set_session_scope.js';
|
|
18
|
-
import { handleYieldForScopeExpansion, yieldForScopeExpansionTool } from './tools/yield_for_scope_expansion.js';
|
|
19
16
|
import { handleGetStartHere, getStartHereTool } from './tools/hydration/get_start_here.js';
|
|
20
17
|
import { handleGetProjectSummary, getProjectSummaryTool } from './tools/hydration/get_project_summary.js';
|
|
21
18
|
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';
|
|
24
19
|
// ⚠️ CRITICAL: Never use console.log() anywhere in this codebase.
|
|
25
20
|
// stdout is owned by the MCP SDK for protocol messages.
|
|
26
21
|
// Use console.error() for all diagnostic output.
|
|
@@ -40,15 +35,6 @@ const ALL_TOOLS = [
|
|
|
40
35
|
getStartHereTool,
|
|
41
36
|
getProjectSummaryTool,
|
|
42
37
|
getEvidenceSliceTool,
|
|
43
|
-
// Phase 3: Worker Delegation
|
|
44
|
-
createWorkOrderTool,
|
|
45
|
-
spawnWorkerTool,
|
|
46
|
-
// Phase 4: Scope & Escalation
|
|
47
|
-
setSessionScopeTool,
|
|
48
|
-
yieldForScopeExpansionTool,
|
|
49
|
-
// Specialist Network v0
|
|
50
|
-
prepareTaskContextTool,
|
|
51
|
-
explainSpecialistScopeTool,
|
|
52
38
|
];
|
|
53
39
|
const TOOL_HANDLERS = {
|
|
54
40
|
scan_project: handleScanProject,
|
|
@@ -66,21 +52,12 @@ const TOOL_HANDLERS = {
|
|
|
66
52
|
get_start_here: handleGetStartHere,
|
|
67
53
|
get_project_summary: handleGetProjectSummary,
|
|
68
54
|
get_evidence_slice: handleGetEvidenceSlice,
|
|
69
|
-
// Phase 3
|
|
70
|
-
create_work_order: handleCreateWorkOrder,
|
|
71
|
-
spawn_worker: handleSpawnWorker,
|
|
72
|
-
// Phase 4
|
|
73
|
-
set_session_scope: handleSetSessionScope,
|
|
74
|
-
yield_for_scope_expansion: handleYieldForScopeExpansion,
|
|
75
|
-
// Specialist Network v0
|
|
76
|
-
vibe_prepare_task_context: handlePrepareTaskContext,
|
|
77
|
-
vibe_explain_specialist_scope: handleExplainSpecialistScope,
|
|
78
55
|
};
|
|
79
56
|
export async function startMCPServer(options = {}) {
|
|
80
57
|
// Initialize Tree-Sitter WASM once at startup
|
|
81
58
|
await initParser();
|
|
82
59
|
console.error('[vibe-splain] Tree-Sitter parser initialized');
|
|
83
|
-
const server = new Server({ name: 'vibe-splain', version: '3.
|
|
60
|
+
const server = new Server({ name: 'vibe-splain', version: '3.5.0' }, { capabilities: { tools: {}, prompts: {} } });
|
|
84
61
|
// Register prompts
|
|
85
62
|
server.setRequestHandler(ListPromptsRequestSchema, async () => ({
|
|
86
63
|
prompts: [
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibe-splain",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "3.5.0",
|
|
4
|
+
"description": "Static-analysis MRI for codebases: a Tree-Sitter dossier engine and deterministic PreToolUse safety gate for coding agents. Language-agnostic core, optimized for TypeScript/JavaScript.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "abp2204",
|
package/dist/commands/bundle.js
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import { join } from 'path';
|
|
2
|
-
import { writeFile, mkdir, copyFile, rm } from 'fs/promises';
|
|
3
|
-
import { existsSync } from 'fs';
|
|
4
|
-
import * as tar from 'tar';
|
|
5
|
-
import { PointerStore } from '../store/PointerStore.js';
|
|
6
|
-
import { BlobStore } from '../store/BlobStore.js';
|
|
7
|
-
export async function bundleCommand(scanId, opts = {}) {
|
|
8
|
-
const root = opts.projectRoot ?? process.cwd();
|
|
9
|
-
const outputPath = opts.output ?? join(root, `vibe-bundle-${scanId}.tar.gz`);
|
|
10
|
-
console.error(`[vibe-splain bundle] Bundling scan ${scanId} from ${root}`);
|
|
11
|
-
const pointerStore = PointerStore.open(root);
|
|
12
|
-
const blobStore = new BlobStore(root);
|
|
13
|
-
const pointers = pointerStore.listPointersByScan(scanId);
|
|
14
|
-
if (pointers.length === 0) {
|
|
15
|
-
throw new Error(`No pointers found for scanId "${scanId}"`);
|
|
16
|
-
}
|
|
17
|
-
// Stage bundle into a temp directory with predictable layout
|
|
18
|
-
const stagingDir = join(root, '.vibe-splainer', 'tmp', `bundle-stage-${scanId}`);
|
|
19
|
-
const blobsStageDir = join(stagingDir, 'blobs');
|
|
20
|
-
await mkdir(blobsStageDir, { recursive: true });
|
|
21
|
-
try {
|
|
22
|
-
// Build manifest for the bundle
|
|
23
|
-
const bundleManifest = {
|
|
24
|
-
schemaVersion: '1.0.0',
|
|
25
|
-
scanId,
|
|
26
|
-
exportedAt: new Date().toISOString(),
|
|
27
|
-
projectRoot: root,
|
|
28
|
-
pointers: pointers.map(p => ({
|
|
29
|
-
pointerId: p.pointerId,
|
|
30
|
-
scanId: p.scanId,
|
|
31
|
-
artifactName: p.artifactName,
|
|
32
|
-
contentHash: p.contentHash,
|
|
33
|
-
blobFile: `blobs/${p.contentHash.replace('sha256:', 'sha256_')}`,
|
|
34
|
-
schemaVersion: p.schemaVersion,
|
|
35
|
-
createdAt: p.createdAt,
|
|
36
|
-
expiresAt: p.expiresAt,
|
|
37
|
-
})),
|
|
38
|
-
};
|
|
39
|
-
await writeFile(join(stagingDir, 'bundle-manifest.json'), JSON.stringify(bundleManifest, null, 2), 'utf8');
|
|
40
|
-
// Copy blobs (deduplicated by contentHash)
|
|
41
|
-
const seen = new Set();
|
|
42
|
-
for (const p of pointers) {
|
|
43
|
-
const hex = p.contentHash.replace('sha256:', '');
|
|
44
|
-
if (seen.has(hex))
|
|
45
|
-
continue;
|
|
46
|
-
seen.add(hex);
|
|
47
|
-
const srcPath = p.blobPath;
|
|
48
|
-
if (!existsSync(srcPath)) {
|
|
49
|
-
console.error(`[vibe-splain bundle] Warning: blob missing for ${p.pointerId}: ${srcPath}`);
|
|
50
|
-
continue;
|
|
51
|
-
}
|
|
52
|
-
await copyFile(srcPath, join(blobsStageDir, `sha256_${hex}`));
|
|
53
|
-
}
|
|
54
|
-
// Create tarball from staging directory
|
|
55
|
-
await tar.create({
|
|
56
|
-
gzip: true,
|
|
57
|
-
file: outputPath,
|
|
58
|
-
cwd: stagingDir,
|
|
59
|
-
portable: true,
|
|
60
|
-
}, ['.']);
|
|
61
|
-
console.error(`[vibe-splain bundle] Bundle written: ${outputPath}`);
|
|
62
|
-
console.error(`[vibe-splain bundle] ${pointers.length} pointers, ${seen.size} blobs`);
|
|
63
|
-
}
|
|
64
|
-
finally {
|
|
65
|
-
await rm(stagingDir, { recursive: true, force: true });
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
//# sourceMappingURL=bundle.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function exportCommand(projectRoot: string, options: any): Promise<void>;
|
package/dist/commands/export.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { readDossier } from '@vibe-splain/brain';
|
|
2
|
-
import { ExportOrchestrator } from '../export/ExportOrchestrator.js';
|
|
3
|
-
export async function exportCommand(projectRoot, options) {
|
|
4
|
-
const root = projectRoot || process.cwd();
|
|
5
|
-
console.error(`[vibe-splain] Exporting dossier for ${root}`);
|
|
6
|
-
const dossier = await readDossier(root);
|
|
7
|
-
if (!dossier) {
|
|
8
|
-
console.error('[vibe-splain] Dossier not found. Run scan first.');
|
|
9
|
-
process.exit(1);
|
|
10
|
-
}
|
|
11
|
-
const orchestrator = new ExportOrchestrator(root);
|
|
12
|
-
await orchestrator.writeBundle(dossier, {
|
|
13
|
-
format: options.format,
|
|
14
|
-
budget: options.budget ? parseInt(options.budget, 10) : undefined,
|
|
15
|
-
scope: options.scope,
|
|
16
|
-
});
|
|
17
|
-
console.error('[vibe-splain] Export complete.');
|
|
18
|
-
}
|
|
19
|
-
//# sourceMappingURL=export.js.map
|
package/dist/commands/gc.d.ts
DELETED
package/dist/commands/gc.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { join } from 'path';
|
|
2
|
-
import { rm, readdir } from 'fs/promises';
|
|
3
|
-
import { PointerStore } from '../store/PointerStore.js';
|
|
4
|
-
import { BlobStore } from '../store/BlobStore.js';
|
|
5
|
-
const DEFAULT_KEEP_SCANS = 3;
|
|
6
|
-
export async function gcCommand(projectRoot, opts = {}) {
|
|
7
|
-
const root = projectRoot ?? process.cwd();
|
|
8
|
-
const keepScans = opts.keepScans ?? DEFAULT_KEEP_SCANS;
|
|
9
|
-
console.error(`[vibe-splain gc] Running GC on ${root} (keeping last ${keepScans} scans)`);
|
|
10
|
-
const pointerStore = PointerStore.open(root);
|
|
11
|
-
const blobStore = new BlobStore(root);
|
|
12
|
-
// 1. Get all scan IDs ordered by createdAt desc
|
|
13
|
-
const allScanIds = pointerStore.listAllScanIds();
|
|
14
|
-
console.error(`[vibe-splain gc] Found ${allScanIds.length} scans`);
|
|
15
|
-
// Keep the N most recent by taking last N from sorted list
|
|
16
|
-
// Scan IDs contain timestamps, sort lexicographically descending
|
|
17
|
-
const sorted = [...allScanIds].sort().reverse();
|
|
18
|
-
const keepIds = sorted.slice(0, keepScans);
|
|
19
|
-
const deleteIds = sorted.slice(keepScans);
|
|
20
|
-
if (deleteIds.length === 0) {
|
|
21
|
-
console.error('[vibe-splain gc] Nothing to collect');
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
// 2. Collect all blob paths still referenced by kept pointers before deletion
|
|
25
|
-
const keptPointers = keepIds.flatMap(id => pointerStore.listPointersByScan(id));
|
|
26
|
-
const referencedBlobs = new Set(keptPointers.map(p => p.blobPath));
|
|
27
|
-
// 3. Delete old scan pointers
|
|
28
|
-
const deleted = await pointerStore.gcScanPointers(keepIds);
|
|
29
|
-
console.error(`[vibe-splain gc] Deleted ${deleted} pointer rows`);
|
|
30
|
-
// 4. Delete unreferenced blobs (reference count = 0)
|
|
31
|
-
const allBlobs = await blobStore.listBlobPaths();
|
|
32
|
-
let blobsDeleted = 0;
|
|
33
|
-
for (const blobPath of allBlobs) {
|
|
34
|
-
if (!referencedBlobs.has(blobPath)) {
|
|
35
|
-
try {
|
|
36
|
-
await rm(blobPath);
|
|
37
|
-
blobsDeleted++;
|
|
38
|
-
}
|
|
39
|
-
catch {
|
|
40
|
-
// ignore — may have already been deleted
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
console.error(`[vibe-splain gc] Deleted ${blobsDeleted} unreferenced blobs`);
|
|
45
|
-
// 5. Clean up tmp dir
|
|
46
|
-
const tmpDir = join(root, '.vibe-splainer', 'tmp');
|
|
47
|
-
try {
|
|
48
|
-
const tmpFiles = await readdir(tmpDir);
|
|
49
|
-
for (const f of tmpFiles) {
|
|
50
|
-
await rm(join(tmpDir, f), { force: true });
|
|
51
|
-
}
|
|
52
|
-
console.error(`[vibe-splain gc] Cleaned ${tmpFiles.length} tmp files`);
|
|
53
|
-
}
|
|
54
|
-
catch {
|
|
55
|
-
// tmp dir may not exist
|
|
56
|
-
}
|
|
57
|
-
console.error('[vibe-splain gc] Done');
|
|
58
|
-
}
|
|
59
|
-
//# sourceMappingURL=gc.js.map
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { join } from 'path';
|
|
2
|
-
import { readFile, mkdir, rm } from 'fs/promises';
|
|
3
|
-
import { existsSync } from 'fs';
|
|
4
|
-
import * as tar from 'tar';
|
|
5
|
-
import { createHash } from 'crypto';
|
|
6
|
-
import { BlobStore } from '../store/BlobStore.js';
|
|
7
|
-
import { PointerStore } from '../store/PointerStore.js';
|
|
8
|
-
export async function importBundleCommand(tarballPath, opts = {}) {
|
|
9
|
-
const root = opts.projectRoot ?? process.cwd();
|
|
10
|
-
const namespace = opts.namespace ?? `imported_${Date.now()}`;
|
|
11
|
-
console.error(`[vibe-splain import] Importing ${tarballPath} into ${root} (namespace: ${namespace})`);
|
|
12
|
-
if (!existsSync(tarballPath)) {
|
|
13
|
-
throw new Error(`Tarball not found: ${tarballPath}`);
|
|
14
|
-
}
|
|
15
|
-
// Extract to a temp directory
|
|
16
|
-
const extractDir = join(root, '.vibe-splainer', 'tmp', `import-${namespace}`);
|
|
17
|
-
await mkdir(extractDir, { recursive: true });
|
|
18
|
-
try {
|
|
19
|
-
await tar.extract({
|
|
20
|
-
file: tarballPath,
|
|
21
|
-
cwd: extractDir,
|
|
22
|
-
});
|
|
23
|
-
// Read bundle manifest
|
|
24
|
-
const manifestPath = join(extractDir, 'bundle-manifest.json');
|
|
25
|
-
if (!existsSync(manifestPath)) {
|
|
26
|
-
throw new Error('Invalid bundle: missing bundle-manifest.json');
|
|
27
|
-
}
|
|
28
|
-
const manifestRaw = await readFile(manifestPath, 'utf8');
|
|
29
|
-
const manifest = JSON.parse(manifestRaw);
|
|
30
|
-
if (manifest.schemaVersion !== '1.0.0') {
|
|
31
|
-
throw new Error(`Unsupported bundle schema version: ${manifest.schemaVersion}`);
|
|
32
|
-
}
|
|
33
|
-
const blobStore = new BlobStore(root);
|
|
34
|
-
const pointerStore = PointerStore.open(root);
|
|
35
|
-
await blobStore.ensureDirs();
|
|
36
|
-
let imported = 0;
|
|
37
|
-
let hashErrors = 0;
|
|
38
|
-
for (const entry of manifest.pointers) {
|
|
39
|
-
const blobSrcPath = join(extractDir, entry.blobFile);
|
|
40
|
-
if (!existsSync(blobSrcPath)) {
|
|
41
|
-
console.error(`[vibe-splain import] Missing blob for pointer ${entry.pointerId}: ${entry.blobFile}`);
|
|
42
|
-
hashErrors++;
|
|
43
|
-
continue;
|
|
44
|
-
}
|
|
45
|
-
// Verify hash before importing
|
|
46
|
-
const content = await readFile(blobSrcPath);
|
|
47
|
-
const actualHash = `sha256:${createHash('sha256').update(content).digest('hex')}`;
|
|
48
|
-
if (actualHash !== entry.contentHash) {
|
|
49
|
-
console.error(`[vibe-splain import] Hash mismatch for ${entry.pointerId}: expected ${entry.contentHash}, got ${actualHash}`);
|
|
50
|
-
hashErrors++;
|
|
51
|
-
continue;
|
|
52
|
-
}
|
|
53
|
-
// Write blob to local store (atomic)
|
|
54
|
-
const { blobPath } = await blobStore.writeAtomic(content);
|
|
55
|
-
// Insert pointer under bundle namespace alias
|
|
56
|
-
const namespacedPointerId = `${namespace}::${entry.pointerId}`;
|
|
57
|
-
const namespacedScanId = `${namespace}::${entry.scanId}`;
|
|
58
|
-
await pointerStore.insertPointer({
|
|
59
|
-
pointerId: namespacedPointerId,
|
|
60
|
-
scanId: namespacedScanId,
|
|
61
|
-
artifactName: entry.artifactName,
|
|
62
|
-
contentHash: entry.contentHash,
|
|
63
|
-
blobPath,
|
|
64
|
-
schemaVersion: entry.schemaVersion,
|
|
65
|
-
createdAt: entry.createdAt,
|
|
66
|
-
expiresAt: entry.expiresAt,
|
|
67
|
-
});
|
|
68
|
-
imported++;
|
|
69
|
-
}
|
|
70
|
-
if (hashErrors > 0) {
|
|
71
|
-
console.error(`[vibe-splain import] Warning: ${hashErrors} blobs failed hash verification and were skipped`);
|
|
72
|
-
}
|
|
73
|
-
console.error(`[vibe-splain import] Imported ${imported}/${manifest.pointers.length} pointers under namespace "${namespace}"`);
|
|
74
|
-
console.error(`[vibe-splain import] Original scanId: ${manifest.scanId} → namespaced as: ${namespace}::${manifest.scanId}`);
|
|
75
|
-
}
|
|
76
|
-
finally {
|
|
77
|
-
await rm(extractDir, { recursive: true, force: true });
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
//# sourceMappingURL=importBundle.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function networkPlanCommand(task: string, options: any): Promise<void>;
|
package/dist/commands/network.js
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { join, resolve } from 'path';
|
|
2
|
-
import { readFile, writeFile, mkdir } from 'fs/promises';
|
|
3
|
-
import { buildExpertNetworkPacket } from '@vibe-splain/brain';
|
|
4
|
-
export async function networkPlanCommand(task, options) {
|
|
5
|
-
const projectRoot = options.root ? resolve(options.root) : process.cwd();
|
|
6
|
-
const maxFiles = options.maxFiles ? parseInt(options.maxFiles, 10) : 8;
|
|
7
|
-
// Try to load scan artifact
|
|
8
|
-
let scanArtifact = null;
|
|
9
|
-
const artifactPath = options.scanArtifact
|
|
10
|
-
? resolve(options.scanArtifact)
|
|
11
|
-
: join(projectRoot, '.vibe-splainer', 'analysis.json');
|
|
12
|
-
try {
|
|
13
|
-
const raw = await readFile(artifactPath, 'utf8');
|
|
14
|
-
scanArtifact = JSON.parse(raw);
|
|
15
|
-
}
|
|
16
|
-
catch (err) {
|
|
17
|
-
if (options.scanArtifact) {
|
|
18
|
-
console.error(`[vibe-splain] Error reading scan artifact at ${artifactPath}:`, err.message);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
// Build the packet
|
|
22
|
-
const packet = buildExpertNetworkPacket({
|
|
23
|
-
task,
|
|
24
|
-
projectRoot,
|
|
25
|
-
scanArtifact,
|
|
26
|
-
errorTrace: options.errorTrace,
|
|
27
|
-
intendedBehavior: options.intendedBehavior,
|
|
28
|
-
maxFiles
|
|
29
|
-
});
|
|
30
|
-
// Save artifacts
|
|
31
|
-
const networkDir = join(projectRoot, '.vibe-splainer', 'network');
|
|
32
|
-
const packetsDir = join(networkDir, 'packets');
|
|
33
|
-
try {
|
|
34
|
-
await mkdir(packetsDir, { recursive: true });
|
|
35
|
-
// Save latest
|
|
36
|
-
const latestPath = join(networkDir, 'latest_packet.json');
|
|
37
|
-
await writeFile(latestPath, JSON.stringify(packet, null, 2), 'utf8');
|
|
38
|
-
// Save timestamped
|
|
39
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
40
|
-
const timestampedPath = join(packetsDir, `${timestamp}.json`);
|
|
41
|
-
await writeFile(timestampedPath, JSON.stringify(packet, null, 2), 'utf8');
|
|
42
|
-
if (options.json) {
|
|
43
|
-
process.stdout.write(JSON.stringify(packet, null, 2) + '\n');
|
|
44
|
-
}
|
|
45
|
-
else {
|
|
46
|
-
process.stdout.write('────────────────────────────────────────────────────────\n');
|
|
47
|
-
process.stdout.write(' Vibe-Splain Specialist Network — Task Plan\n');
|
|
48
|
-
process.stdout.write('────────────────────────────────────────────────────────\n');
|
|
49
|
-
process.stdout.write(`Task: "${packet.task}"\n`);
|
|
50
|
-
process.stdout.write(`Project Root: ${packet.projectRoot}\n`);
|
|
51
|
-
process.stdout.write(`Primary Specialist: ${packet.route.primarySpecialist}\n`);
|
|
52
|
-
process.stdout.write(`Panel: ${packet.route.panel.join(', ')}\n`);
|
|
53
|
-
process.stdout.write(`Confidence: ${packet.route.confidence}\n`);
|
|
54
|
-
process.stdout.write(`Reason: ${packet.route.reason}\n`);
|
|
55
|
-
process.stdout.write('\nSelected Files:\n');
|
|
56
|
-
if (packet.selectedFiles.length > 0) {
|
|
57
|
-
packet.selectedFiles.forEach(f => {
|
|
58
|
-
process.stdout.write(` • ${f.path} [blastRadius: ${f.blastRadius}]\n`);
|
|
59
|
-
process.stdout.write(` Reason: ${f.reason}\n`);
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
else {
|
|
63
|
-
process.stdout.write(' (No files selected)\n');
|
|
64
|
-
}
|
|
65
|
-
process.stdout.write('\nRisk Warnings:\n');
|
|
66
|
-
if (packet.riskWarnings.length > 0) {
|
|
67
|
-
packet.riskWarnings.forEach(w => {
|
|
68
|
-
const levelLabel = w.level === 'critical' ? '🔴 CRITICAL' : (w.level === 'warning' ? '🟡 WARNING' : 'ℹ️ INFO');
|
|
69
|
-
process.stdout.write(` • [${levelLabel}] ${w.message}\n`);
|
|
70
|
-
process.stdout.write(` Reason: ${w.reason}\n`);
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
else {
|
|
74
|
-
process.stdout.write(' (No risks identified)\n');
|
|
75
|
-
}
|
|
76
|
-
process.stdout.write('\nSmallest Safe Change Policy:\n');
|
|
77
|
-
process.stdout.write(` ${packet.smallestSafeChangePolicy.summary}\n`);
|
|
78
|
-
process.stdout.write('\nSaved Artifacts:\n');
|
|
79
|
-
process.stdout.write(` • Latest: ${latestPath}\n`);
|
|
80
|
-
process.stdout.write(` • Packet: ${timestampedPath}\n`);
|
|
81
|
-
process.stdout.write('────────────────────────────────────────────────────────\n');
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
catch (err) {
|
|
85
|
-
console.error('[vibe-splain] Error saving network artifacts:', err.message);
|
|
86
|
-
if (options.json) {
|
|
87
|
-
process.stdout.write(JSON.stringify(packet, null, 2) + '\n');
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
//# sourceMappingURL=network.js.map
|
package/dist/commands/scan.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
interface ScanOptions {
|
|
2
|
-
root?: string;
|
|
3
|
-
out?: string;
|
|
4
|
-
json?: boolean;
|
|
5
|
-
}
|
|
6
|
-
/**
|
|
7
|
-
* Headless one-shot scan. Reuses the exact MCP scan pipeline (performScan),
|
|
8
|
-
* relocates the artifact bundle to --out, and prints a summary. The gravity
|
|
9
|
-
* formula is selected by the ROZE_GRAVITY_V2 env var, never a CLI flag — v2 is
|
|
10
|
-
* still an experimental candidate (see CONTEXT.md / Phase 0).
|
|
11
|
-
*/
|
|
12
|
-
export declare function scanCommand(options?: ScanOptions): Promise<void>;
|
|
13
|
-
export {};
|
package/dist/commands/scan.js
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import { resolve, join, dirname } from 'path';
|
|
2
|
-
import { rm, rename, mkdir, writeFile } from 'fs/promises';
|
|
3
|
-
import { performScan } from '../mcp/tools/scan_project.js';
|
|
4
|
-
/**
|
|
5
|
-
* Headless one-shot scan. Reuses the exact MCP scan pipeline (performScan),
|
|
6
|
-
* relocates the artifact bundle to --out, and prints a summary. The gravity
|
|
7
|
-
* formula is selected by the ROZE_GRAVITY_V2 env var, never a CLI flag — v2 is
|
|
8
|
-
* still an experimental candidate (see CONTEXT.md / Phase 0).
|
|
9
|
-
*/
|
|
10
|
-
export async function scanCommand(options = {}) {
|
|
11
|
-
const root = resolve(options.root || '.');
|
|
12
|
-
const gravityMode = process.env.ROZE_GRAVITY_V2 === '1' ? 'v2_candidate' : 'v1_default';
|
|
13
|
-
console.error(`[roze] Scanning ${root} (gravity mode: ${gravityMode})...`);
|
|
14
|
-
const { result, scanId } = await performScan(root);
|
|
15
|
-
// The pipeline always writes to <root>/.roze. Relocate to --out if different
|
|
16
|
-
// so v1 and v2 runs can coexist for comparison.
|
|
17
|
-
const defaultDir = join(root, '.roze');
|
|
18
|
-
const outDir = resolve(options.out || defaultDir);
|
|
19
|
-
if (outDir !== defaultDir) {
|
|
20
|
-
await rm(outDir, { recursive: true, force: true });
|
|
21
|
-
await mkdir(dirname(outDir), { recursive: true });
|
|
22
|
-
await rename(defaultDir, outDir);
|
|
23
|
-
}
|
|
24
|
-
// Persist the gravity mode so v1/v2 scans are self-identifying.
|
|
25
|
-
const meta = {
|
|
26
|
-
gravityMode,
|
|
27
|
-
scannedAt: new Date().toISOString(),
|
|
28
|
-
root,
|
|
29
|
-
scanId,
|
|
30
|
-
totalFilesScanned: result.totalFilesScanned,
|
|
31
|
-
realSourceCount: result.realSourceCount,
|
|
32
|
-
wildCandidateCount: result.wildCandidates.length,
|
|
33
|
-
};
|
|
34
|
-
await writeFile(join(outDir, 'scan_meta.json'), JSON.stringify(meta, null, 2));
|
|
35
|
-
// Build gravity/heat lookups from the scored files for display.
|
|
36
|
-
const gravityByPath = new Map(result.files.map(f => [f.relativePath, f.gravity]));
|
|
37
|
-
const heatByPath = new Map(result.files.map(f => [f.relativePath, f.heat]));
|
|
38
|
-
const topGravity = result.map.topGravity.slice(0, 12).map(p => ({
|
|
39
|
-
path: p,
|
|
40
|
-
gravity: Math.round(gravityByPath.get(p) ?? 0),
|
|
41
|
-
}));
|
|
42
|
-
const topHeat = result.map.topHeat.slice(0, 12).map(p => ({
|
|
43
|
-
path: p,
|
|
44
|
-
heat: Math.round(heatByPath.get(p) ?? 0),
|
|
45
|
-
}));
|
|
46
|
-
const wildDiscovery = result.wildCandidates.slice(0, 12).map(f => ({
|
|
47
|
-
path: f.relativePath,
|
|
48
|
-
heat: Math.round(f.heat),
|
|
49
|
-
gravity: Math.round(f.gravity),
|
|
50
|
-
topSmells: f.smells.filter(s => s.severity >= 3).slice(0, 3).map(s => s.note),
|
|
51
|
-
}));
|
|
52
|
-
const specialistMap = result.map.pillars.map(p => ({
|
|
53
|
-
name: p.name,
|
|
54
|
-
fileCount: p.memberFiles.length,
|
|
55
|
-
}));
|
|
56
|
-
const summary = {
|
|
57
|
-
gravityMode,
|
|
58
|
-
root,
|
|
59
|
-
outDir,
|
|
60
|
-
dossier: join(outDir, 'dossier.json'),
|
|
61
|
-
analysis: join(outDir, 'analysis.json'),
|
|
62
|
-
stack: result.map.stack,
|
|
63
|
-
totalFilesScanned: result.totalFilesScanned,
|
|
64
|
-
realSourceCount: result.realSourceCount,
|
|
65
|
-
topGravity,
|
|
66
|
-
topHeat,
|
|
67
|
-
wildDiscovery,
|
|
68
|
-
specialistMap,
|
|
69
|
-
};
|
|
70
|
-
if (options.json) {
|
|
71
|
-
process.stdout.write(JSON.stringify(summary, null, 2) + '\n');
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
const lines = [];
|
|
75
|
-
lines.push('');
|
|
76
|
-
lines.push(`roze scan — gravity mode: ${gravityMode}`);
|
|
77
|
-
lines.push(` root: ${root}`);
|
|
78
|
-
lines.push(` stack: ${result.map.stack.join(', ') || '(none detected)'}`);
|
|
79
|
-
lines.push(` files: ${result.totalFilesScanned} scanned, ${result.realSourceCount} real-source`);
|
|
80
|
-
lines.push('');
|
|
81
|
-
lines.push('Top Gravity (Start Here):');
|
|
82
|
-
topGravity.forEach((f, i) => lines.push(` ${String(i + 1).padStart(2)}. [${String(f.gravity).padStart(3)}] ${f.path}`));
|
|
83
|
-
lines.push('');
|
|
84
|
-
lines.push('Top Heat (Wild Discovery):');
|
|
85
|
-
topHeat.forEach((f, i) => lines.push(` ${String(i + 1).padStart(2)}. [${String(f.heat).padStart(3)}] ${f.path}`));
|
|
86
|
-
lines.push('');
|
|
87
|
-
lines.push('Specialist Map (pillars):');
|
|
88
|
-
specialistMap.forEach(p => lines.push(` - ${p.name} (${p.fileCount} files)`));
|
|
89
|
-
lines.push('');
|
|
90
|
-
lines.push(`Artifacts written to: ${outDir}`);
|
|
91
|
-
lines.push(` dossier: ${join(outDir, 'dossier.json')}`);
|
|
92
|
-
lines.push(` analysis: ${join(outDir, 'analysis.json')}`);
|
|
93
|
-
lines.push(` meta: ${join(outDir, 'scan_meta.json')} (gravityMode: ${gravityMode})`);
|
|
94
|
-
lines.push('');
|
|
95
|
-
process.stdout.write(lines.join('\n'));
|
|
96
|
-
}
|
|
97
|
-
//# sourceMappingURL=scan.js.map
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import type { DossierViewModel, AnalysisStore } from '@vibe-splain/brain';
|
|
2
|
-
import type { Renderer } from './Renderer.js';
|
|
3
|
-
import type { Artifact } from '../ArtifactBundleWriter.js';
|
|
4
|
-
export declare class DeltaRenderer implements Renderer {
|
|
5
|
-
render(_viewModel: DossierViewModel, store: AnalysisStore): Artifact[];
|
|
6
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
export class DeltaRenderer {
|
|
2
|
-
render(_viewModel, store) {
|
|
3
|
-
const deltaTargets = Object.values(store.files)
|
|
4
|
-
.filter(pf => pf.isRealSource)
|
|
5
|
-
.sort((a, b) => b.gravity - a.gravity)
|
|
6
|
-
.map(pf => ({
|
|
7
|
-
path: pf.relativePath,
|
|
8
|
-
gravity: Math.round(pf.gravity),
|
|
9
|
-
isLoadBearing: pf.canonicalLoadBearing,
|
|
10
|
-
blastRadius: pf.importedBy,
|
|
11
|
-
pillarHint: pf.pillarHint,
|
|
12
|
-
}));
|
|
13
|
-
return [
|
|
14
|
-
{
|
|
15
|
-
type: 'delta',
|
|
16
|
-
path: 'delta_targets.json',
|
|
17
|
-
content: JSON.stringify(deltaTargets, null, 2),
|
|
18
|
-
}
|
|
19
|
-
];
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
//# sourceMappingURL=DeltaRenderer.js.map
|
package/dist/hook-entry.d.ts
DELETED
package/dist/hook-entry.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// Lean entrypoint for the PreToolUse hook. Bundled separately from the main CLI
|
|
3
|
-
// so it pulls in ONLY the gate-index reader + decision logic — no Tree-Sitter
|
|
4
|
-
// WASM, no MCP SDK, no chokidar. Keeps per-edit startup near the bare-Node floor
|
|
5
|
-
// (~40–60ms) instead of loading the full scanner bundle (~260ms+).
|
|
6
|
-
import { hookPreToolUseCommand } from './commands/hook.js';
|
|
7
|
-
hookPreToolUseCommand();
|
|
8
|
-
//# sourceMappingURL=hook-entry.js.map
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
export declare class StalePatchError extends Error {
|
|
2
|
-
readonly filePath: string;
|
|
3
|
-
readonly expectedHash: string;
|
|
4
|
-
readonly actualHash: string;
|
|
5
|
-
constructor(filePath: string, expectedHash: string, actualHash: string);
|
|
6
|
-
}
|
|
7
|
-
export declare const applyPatchTool: {
|
|
8
|
-
name: string;
|
|
9
|
-
description: string;
|
|
10
|
-
inputSchema: {
|
|
11
|
-
type: "object";
|
|
12
|
-
properties: {
|
|
13
|
-
projectRoot: {
|
|
14
|
-
type: string;
|
|
15
|
-
description: string;
|
|
16
|
-
};
|
|
17
|
-
filePath: {
|
|
18
|
-
type: string;
|
|
19
|
-
description: string;
|
|
20
|
-
};
|
|
21
|
-
newContent: {
|
|
22
|
-
type: string;
|
|
23
|
-
description: string;
|
|
24
|
-
};
|
|
25
|
-
expectedPrePatchHash: {
|
|
26
|
-
type: string;
|
|
27
|
-
description: string;
|
|
28
|
-
};
|
|
29
|
-
scanId: {
|
|
30
|
-
type: string;
|
|
31
|
-
description: string;
|
|
32
|
-
};
|
|
33
|
-
};
|
|
34
|
-
required: string[];
|
|
35
|
-
};
|
|
36
|
-
};
|
|
37
|
-
export declare function handleApplyPatch(args: Record<string, unknown>): Promise<unknown>;
|