vibe-splain 3.4.2 → 4.0.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 +110 -158
- package/dist/commands/install.d.ts +0 -5
- package/dist/commands/install.js +5 -55
- package/dist/commands/serve.js +1 -1
- package/dist/export/ArtifactBundleWriter.js +3 -3
- package/dist/export/ExportOrchestrator.d.ts +2 -20
- package/dist/export/ExportOrchestrator.js +5 -116
- package/dist/export/Watcher.js +5 -5
- package/dist/export/renderers/AgentMarkdownRenderer.d.ts +1 -1
- package/dist/export/renderers/GraphRenderer.d.ts +2 -2
- package/dist/export/renderers/HtmlRenderer.d.ts +1 -1
- package/dist/export/renderers/HtmlRenderer.js +1 -1
- package/dist/export/renderers/JsonRenderer.d.ts +1 -1
- package/dist/export/renderers/RawAnalysisRenderer.d.ts +1 -1
- package/dist/export/renderers/Renderer.d.ts +1 -1
- package/dist/export/renderers/ValidationRenderer.d.ts +1 -1
- package/dist/index.js +1425 -6511
- package/dist/mcp/server.js +6 -46
- package/dist/mcp/tools/get_file_context.js +1 -1
- package/dist/mcp/tools/get_project_map.js +1 -1
- package/dist/mcp/tools/get_strategic_overview.js +1 -1
- package/dist/mcp/tools/get_wild_discoveries.js +1 -1
- package/dist/mcp/tools/inspect_pillar.js +1 -1
- package/dist/mcp/tools/mark_stale.js +1 -1
- package/dist/mcp/tools/scan_project.d.ts +2 -3
- package/dist/mcp/tools/scan_project.js +12 -13
- package/dist/mcp/tools/set_project_brief.js +1 -1
- package/dist/mcp/tools/write_decision_card.d.ts +1 -1
- package/dist/mcp/tools/write_decision_card.js +2 -2
- package/dist/ui/index.html +1 -1
- package/package.json +9 -14
- 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/hook.d.ts +0 -9
- package/dist/commands/hook.js +0 -84
- 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/preToolUse.d.ts +0 -30
- package/dist/hook/preToolUse.js +0 -81
- package/dist/hook-entry.d.ts +0 -2
- package/dist/hook-entry.js +0 -8
- package/dist/hook.d.ts +0 -1
- package/dist/hook.js +0 -337
- package/dist/mcp/BudgetGuard.d.ts +0 -13
- package/dist/mcp/BudgetGuard.js +0 -55
- package/dist/mcp/SessionScope.d.ts +0 -26
- package/dist/mcp/SessionScope.js +0 -56
- 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/get_file_skeleton.d.ts +0 -23
- package/dist/mcp/tools/get_file_skeleton.js +0 -124
- package/dist/mcp/tools/hydration/get_evidence_slice.d.ts +0 -31
- package/dist/mcp/tools/hydration/get_evidence_slice.js +0 -57
- package/dist/mcp/tools/hydration/get_project_summary.d.ts +0 -23
- package/dist/mcp/tools/hydration/get_project_summary.js +0 -58
- package/dist/mcp/tools/hydration/get_start_here.d.ts +0 -23
- package/dist/mcp/tools/hydration/get_start_here.js +0 -52
- package/dist/mcp/tools/prepareTaskContext.d.ts +0 -38
- package/dist/mcp/tools/prepareTaskContext.js +0 -93
- package/dist/mcp/tools/read_file.d.ts +0 -31
- package/dist/mcp/tools/read_file.js +0 -90
- 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/store/BlobStore.d.ts +0 -22
- package/dist/store/BlobStore.js +0 -96
- package/dist/store/PointerStore.d.ts +0 -52
- package/dist/store/PointerStore.js +0 -154
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibe-splain",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
|
+
"description": "Static-analysis dossier engine for codebases: Tree-Sitter powered architectural analysis and interactive UI. Language-agnostic core, optimized for TypeScript/JavaScript.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "abp2204",
|
|
8
|
-
"homepage": "https://github.com/abp2204/
|
|
8
|
+
"homepage": "https://github.com/abp2204/vibesplain#readme",
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
11
|
-
"url": "git+https://github.com/abp2204/
|
|
11
|
+
"url": "git+https://github.com/abp2204/vibesplain.git",
|
|
12
12
|
"directory": "packages/cli"
|
|
13
13
|
},
|
|
14
14
|
"bugs": {
|
|
15
|
-
"url": "https://github.com/abp2204/
|
|
15
|
+
"url": "https://github.com/abp2204/vibesplain/issues"
|
|
16
16
|
},
|
|
17
17
|
"keywords": [
|
|
18
18
|
"mcp",
|
|
@@ -30,33 +30,28 @@
|
|
|
30
30
|
"node": ">=18"
|
|
31
31
|
},
|
|
32
32
|
"bin": {
|
|
33
|
-
"
|
|
33
|
+
"vibesplain": "dist/index.js"
|
|
34
34
|
},
|
|
35
35
|
"scripts": {
|
|
36
36
|
"build": "tsc && node build.mjs"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
40
|
-
"better-sqlite3": "^12.10.0",
|
|
41
40
|
"chokidar": "^3.6.0",
|
|
42
41
|
"commander": "^12.0.0",
|
|
43
42
|
"fs-extra": "^11.0.0",
|
|
44
43
|
"tar": "^7.5.16",
|
|
45
44
|
"tree-sitter-wasms": "^0.1.11",
|
|
46
|
-
"web-tree-sitter": "^0.22.0"
|
|
45
|
+
"web-tree-sitter": "^0.22.0",
|
|
46
|
+
"uuid": "^9.0.0"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@types/better-sqlite3": "^7.6.13",
|
|
50
49
|
"@types/fs-extra": "^11.0.0",
|
|
51
|
-
"@types/minimatch": "^5.1.2",
|
|
52
50
|
"@types/tar": "^6.1.13",
|
|
53
51
|
"@types/uuid": "^9.0.0",
|
|
54
|
-
"async-mutex": "^0.5.0",
|
|
55
52
|
"esbuild": "^0.28.0",
|
|
56
|
-
"minimatch": "^10.2.5",
|
|
57
53
|
"tsx": "^4.22.4",
|
|
58
|
-
"typescript": "^5.4.0"
|
|
59
|
-
"uuid": "^9.0.0"
|
|
54
|
+
"typescript": "^5.4.0"
|
|
60
55
|
},
|
|
61
56
|
"files": [
|
|
62
57
|
"dist/",
|
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
|
package/dist/commands/hook.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export interface HookCommandResult {
|
|
2
|
-
/** JSON to print to stdout, or null to print nothing (defer / exit 0). */
|
|
3
|
-
stdout: string | null;
|
|
4
|
-
}
|
|
5
|
-
export declare function findProjectRoot(start: string | undefined): string | null;
|
|
6
|
-
/** Pure-ish core: raw stdin string in, hook decision (as a string or null) out. */
|
|
7
|
-
export declare function runHookCommand(rawStdin: string): Promise<HookCommandResult>;
|
|
8
|
-
/** CLI entrypoint: read all of stdin, run the gate, emit the result. */
|
|
9
|
-
export declare function hookPreToolUseCommand(): Promise<void>;
|
package/dist/commands/hook.js
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
// `vibe-splain hook pretooluse` — the deterministic PreToolUse gate, wired to stdio.
|
|
2
|
-
//
|
|
3
|
-
// Claude Code pipes a JSON describing the tool call about to run onto stdin; we
|
|
4
|
-
// decide whether to escalate and, if so, write hook JSON to stdout. On a safe
|
|
5
|
-
// edit (or any non-edit tool, unscanned repo, etc.) we print nothing and exit 0,
|
|
6
|
-
// deferring to normal permission flow.
|
|
7
|
-
//
|
|
8
|
-
// NOTE on the console.log ban: that rule protects the MCP *server's* stdout.
|
|
9
|
-
// This is a separate, short-lived process whose stdout IS the hook protocol —
|
|
10
|
-
// writing JSON here is correct. Diagnostics still go to stderr.
|
|
11
|
-
import { existsSync, writeFileSync, readFileSync } from 'fs';
|
|
12
|
-
import { dirname, join } from 'path';
|
|
13
|
-
import { tmpdir } from 'os';
|
|
14
|
-
import { decidePreToolUse } from '../hook/preToolUse.js';
|
|
15
|
-
// Walk up from `start` looking for the directory that holds a `.vibe-splainer` scan.
|
|
16
|
-
// Returns null if none is found — an unscanned repo means the gate is inert.
|
|
17
|
-
export function findProjectRoot(start) {
|
|
18
|
-
let dir = start || process.cwd();
|
|
19
|
-
// Bound the walk so a stray cwd can't traverse the whole filesystem.
|
|
20
|
-
for (let i = 0; i < 64; i++) {
|
|
21
|
-
if (existsSync(join(dir, '.vibe-splainer', 'analysis.json')))
|
|
22
|
-
return dir;
|
|
23
|
-
const parent = dirname(dir);
|
|
24
|
-
if (parent === dir)
|
|
25
|
-
break;
|
|
26
|
-
dir = parent;
|
|
27
|
-
}
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
/** Pure-ish core: raw stdin string in, hook decision (as a string or null) out. */
|
|
31
|
-
export async function runHookCommand(rawStdin) {
|
|
32
|
-
let input;
|
|
33
|
-
try {
|
|
34
|
-
input = JSON.parse(rawStdin);
|
|
35
|
-
}
|
|
36
|
-
catch {
|
|
37
|
-
return { stdout: null }; // malformed input → never block the agent
|
|
38
|
-
}
|
|
39
|
-
const root = findProjectRoot(input.cwd);
|
|
40
|
-
const gatePath = root ? join(root, '.vibe-splainer', 'gate.json') : null;
|
|
41
|
-
const gateExists = gatePath ? existsSync(gatePath) : false;
|
|
42
|
-
let gateIndex = null;
|
|
43
|
-
if (gateExists) {
|
|
44
|
-
try {
|
|
45
|
-
gateIndex = JSON.parse(readFileSync(gatePath, 'utf8'));
|
|
46
|
-
}
|
|
47
|
-
catch { }
|
|
48
|
-
}
|
|
49
|
-
const sessionId = input.session_id || 'default';
|
|
50
|
-
const warnFile = join(tmpdir(), `vibe-splain-warn-${sessionId}`);
|
|
51
|
-
const warningShown = existsSync(warnFile);
|
|
52
|
-
const result = decidePreToolUse(input, gateIndex, { warningShown });
|
|
53
|
-
if (result.action === 'defer')
|
|
54
|
-
return { stdout: null };
|
|
55
|
-
if (!gateIndex && result.action === 'emit') {
|
|
56
|
-
try {
|
|
57
|
-
writeFileSync(warnFile, '1');
|
|
58
|
-
}
|
|
59
|
-
catch { }
|
|
60
|
-
}
|
|
61
|
-
return { stdout: JSON.stringify(result.output) };
|
|
62
|
-
}
|
|
63
|
-
/** CLI entrypoint: read all of stdin, run the gate, emit the result. */
|
|
64
|
-
export async function hookPreToolUseCommand() {
|
|
65
|
-
const raw = await readStdin();
|
|
66
|
-
const { stdout } = await runHookCommand(raw);
|
|
67
|
-
if (stdout)
|
|
68
|
-
process.stdout.write(stdout);
|
|
69
|
-
// No stdout on defer; exit code stays 0.
|
|
70
|
-
}
|
|
71
|
-
function readStdin() {
|
|
72
|
-
return new Promise((resolve) => {
|
|
73
|
-
let data = '';
|
|
74
|
-
if (process.stdin.isTTY) {
|
|
75
|
-
resolve('');
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
process.stdin.setEncoding('utf8');
|
|
79
|
-
process.stdin.on('data', (chunk) => { data += chunk; });
|
|
80
|
-
process.stdin.on('end', () => resolve(data));
|
|
81
|
-
process.stdin.on('error', () => resolve(data));
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
//# sourceMappingURL=hook.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
|