vexp-cli 2.2.4 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-config.js +416 -165
- package/dist/cli.js +6 -2
- package/dist/doctor.js +233 -23
- package/dist/serve.js +56 -2
- package/mcp/mcp-server.cjs +29 -29
- package/package.json +6 -6
package/dist/agent-config.js
CHANGED
|
@@ -95,6 +95,13 @@ const VEXP_TOOLS = [
|
|
|
95
95
|
"save_observation",
|
|
96
96
|
"get_token_savings",
|
|
97
97
|
];
|
|
98
|
+
let activeGuardMode = "off";
|
|
99
|
+
export function setGuardMode(mode) {
|
|
100
|
+
activeGuardMode = mode;
|
|
101
|
+
}
|
|
102
|
+
export function guardMode() {
|
|
103
|
+
return activeGuardMode;
|
|
104
|
+
}
|
|
98
105
|
// ---------------------------------------------------------------------------
|
|
99
106
|
// Agent detectors - mirrors VS Code extension's AGENT_DETECTORS
|
|
100
107
|
// ---------------------------------------------------------------------------
|
|
@@ -313,15 +320,27 @@ export function configureAgents(workspaceRoot, binaryPath, version, agentFilter,
|
|
|
313
320
|
const wrote = configureClaudeCodeGlobal(binaryPath, mcpServerPath, workspaceRoot);
|
|
314
321
|
if (wrote)
|
|
315
322
|
mcpConfigs.push("~/.claude.json");
|
|
316
|
-
//
|
|
317
|
-
|
|
318
|
-
if (
|
|
323
|
+
// Guard is OPT-IN from 2.3 (see GuardMode): strict installs the
|
|
324
|
+
// PreToolUse deny hook; default removes any previously installed one.
|
|
325
|
+
if (guardMode() === "strict") {
|
|
326
|
+
const hookResult = installClaudeCodeHook(workspaceRoot);
|
|
327
|
+
if (hookResult) {
|
|
328
|
+
results.push({
|
|
329
|
+
agent: "Claude Code Hook",
|
|
330
|
+
configFile: ".claude/hooks/vexp-guard.sh",
|
|
331
|
+
content: VEXP_GUARD_HOOK,
|
|
332
|
+
alreadyExists: false,
|
|
333
|
+
action: hookResult,
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
else if (uninstallClaudeCodeHook(workspaceRoot)) {
|
|
319
338
|
results.push({
|
|
320
339
|
agent: "Claude Code Hook",
|
|
321
340
|
configFile: ".claude/hooks/vexp-guard.sh",
|
|
322
|
-
content:
|
|
341
|
+
content: "",
|
|
323
342
|
alreadyExists: false,
|
|
324
|
-
action:
|
|
343
|
+
action: "removed",
|
|
325
344
|
});
|
|
326
345
|
}
|
|
327
346
|
}
|
|
@@ -360,34 +379,56 @@ export function configureAgents(workspaceRoot, binaryPath, version, agentFilter,
|
|
|
360
379
|
// Kilo v7 vendors opencode, so it takes the same guard plugin — the rules
|
|
361
380
|
// markdown alone was demonstrably not enough (a reported session loaded
|
|
362
381
|
// vexp.md, quoted it back, and still read five files by hand).
|
|
363
|
-
|
|
364
|
-
|
|
382
|
+
if (guardMode() === "strict") {
|
|
383
|
+
const kilo = installKiloPlugin(workspaceRoot);
|
|
384
|
+
if (kilo.plugin) {
|
|
385
|
+
results.push({
|
|
386
|
+
agent: "Kilo Code Guard",
|
|
387
|
+
configFile: path.join(".kilo", "plugins", "vexp-guard.js"),
|
|
388
|
+
content: VEXP_OPENCODE_GUARD,
|
|
389
|
+
alreadyExists: kilo.plugin === "updated",
|
|
390
|
+
action: kilo.plugin,
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
if (kilo.registered)
|
|
394
|
+
mcpConfigs.push(path.relative(workspaceRoot, kiloConfigTarget(workspaceRoot)));
|
|
395
|
+
}
|
|
396
|
+
else if (uninstallKiloPlugin(workspaceRoot)) {
|
|
365
397
|
results.push({
|
|
366
398
|
agent: "Kilo Code Guard",
|
|
367
399
|
configFile: path.join(".kilo", "plugins", "vexp-guard.js"),
|
|
368
|
-
content:
|
|
369
|
-
alreadyExists:
|
|
370
|
-
action:
|
|
400
|
+
content: "",
|
|
401
|
+
alreadyExists: false,
|
|
402
|
+
action: "removed",
|
|
371
403
|
});
|
|
372
404
|
}
|
|
373
|
-
if (kilo.registered)
|
|
374
|
-
mcpConfigs.push(path.relative(workspaceRoot, kiloConfigTarget(workspaceRoot)));
|
|
375
405
|
}
|
|
376
406
|
// Cursor: preToolUse hook matching Grep. Text search only - Cursor's native
|
|
377
407
|
// semantic search is not hookable.
|
|
378
408
|
if (detector.agent === "Cursor") {
|
|
379
|
-
|
|
380
|
-
|
|
409
|
+
if (guardMode() === "strict") {
|
|
410
|
+
const cur = installCursorHook(workspaceRoot);
|
|
411
|
+
if (cur.hook) {
|
|
412
|
+
results.push({
|
|
413
|
+
agent: "Cursor Guard",
|
|
414
|
+
configFile: path.join(".cursor", "hooks", "vexp-guard.js"),
|
|
415
|
+
content: VEXP_CURSOR_GUARD,
|
|
416
|
+
alreadyExists: cur.hook === "updated",
|
|
417
|
+
action: cur.hook,
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
if (cur.registered)
|
|
421
|
+
mcpConfigs.push(path.join(".cursor", "hooks.json"));
|
|
422
|
+
}
|
|
423
|
+
else if (uninstallCursorHook(workspaceRoot)) {
|
|
381
424
|
results.push({
|
|
382
425
|
agent: "Cursor Guard",
|
|
383
426
|
configFile: path.join(".cursor", "hooks", "vexp-guard.js"),
|
|
384
|
-
content:
|
|
385
|
-
alreadyExists:
|
|
386
|
-
action:
|
|
427
|
+
content: "",
|
|
428
|
+
alreadyExists: false,
|
|
429
|
+
action: "removed",
|
|
387
430
|
});
|
|
388
431
|
}
|
|
389
|
-
if (cur.registered)
|
|
390
|
-
mcpConfigs.push(path.join(".cursor", "hooks.json"));
|
|
391
432
|
}
|
|
392
433
|
// Opencode: MCP lives under the `mcp` key in opencode.json(c) — opencode
|
|
393
434
|
// carries no `mcpConfigFile`, so without this call the generic writer above
|
|
@@ -398,14 +439,25 @@ export function configureAgents(workspaceRoot, binaryPath, version, agentFilter,
|
|
|
398
439
|
const wroteMcp = configureOpencodeMcp(workspaceRoot, binaryPath, mcpServerPath);
|
|
399
440
|
if (wroteMcp)
|
|
400
441
|
mcpConfigs.push(wroteMcp);
|
|
401
|
-
|
|
402
|
-
|
|
442
|
+
if (guardMode() === "strict") {
|
|
443
|
+
const pluginResult = installOpencodePlugin(workspaceRoot);
|
|
444
|
+
if (pluginResult) {
|
|
445
|
+
results.push({
|
|
446
|
+
agent: "Opencode Guard",
|
|
447
|
+
configFile: ".opencode/plugins/vexp-guard.js",
|
|
448
|
+
content: VEXP_OPENCODE_GUARD,
|
|
449
|
+
alreadyExists: pluginResult === "updated",
|
|
450
|
+
action: pluginResult,
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
else if (uninstallOpencodePlugin(workspaceRoot)) {
|
|
403
455
|
results.push({
|
|
404
456
|
agent: "Opencode Guard",
|
|
405
457
|
configFile: ".opencode/plugins/vexp-guard.js",
|
|
406
|
-
content:
|
|
407
|
-
alreadyExists:
|
|
408
|
-
action:
|
|
458
|
+
content: "",
|
|
459
|
+
alreadyExists: false,
|
|
460
|
+
action: "removed",
|
|
409
461
|
});
|
|
410
462
|
}
|
|
411
463
|
}
|
|
@@ -555,7 +607,10 @@ export function configureSelectedAgents(workspaceRoot, binaryPath, version, sele
|
|
|
555
607
|
const wrote = configureClaudeCodeGlobal(binaryPath, mcpServerPath, workspaceRoot);
|
|
556
608
|
if (wrote)
|
|
557
609
|
mcpConfigs.push("~/.claude.json");
|
|
558
|
-
|
|
610
|
+
if (guardMode() === "strict")
|
|
611
|
+
installClaudeCodeHook(workspaceRoot);
|
|
612
|
+
else
|
|
613
|
+
uninstallClaudeCodeHook(workspaceRoot);
|
|
559
614
|
}
|
|
560
615
|
if (detector.agent === "Codex") {
|
|
561
616
|
const wrote = configureCodexGlobal(binaryPath, mcpServerPath, workspaceRoot);
|
|
@@ -581,10 +636,16 @@ export function configureSelectedAgents(workspaceRoot, binaryPath, version, sele
|
|
|
581
636
|
const wrote = configureOpencodeMcp(workspaceRoot, binaryPath, mcpServerPath);
|
|
582
637
|
if (wrote)
|
|
583
638
|
mcpConfigs.push(wrote);
|
|
584
|
-
|
|
639
|
+
if (guardMode() === "strict")
|
|
640
|
+
installOpencodePlugin(workspaceRoot);
|
|
641
|
+
else
|
|
642
|
+
uninstallOpencodePlugin(workspaceRoot);
|
|
585
643
|
}
|
|
586
644
|
if (detector.agent === "Cursor") {
|
|
587
|
-
|
|
645
|
+
if (guardMode() === "strict")
|
|
646
|
+
installCursorHook(workspaceRoot);
|
|
647
|
+
else
|
|
648
|
+
uninstallCursorHook(workspaceRoot);
|
|
588
649
|
}
|
|
589
650
|
// Kilo carries no `mcpConfigFile` (its MCP lives under the `mcp` key inside
|
|
590
651
|
// kilo.jsonc), so without this branch the generic writer above skips it and
|
|
@@ -594,7 +655,10 @@ export function configureSelectedAgents(workspaceRoot, binaryPath, version, sele
|
|
|
594
655
|
const wrote = configureKiloMcp(workspaceRoot, binaryPath, mcpServerPath);
|
|
595
656
|
if (wrote)
|
|
596
657
|
mcpConfigs.push(wrote);
|
|
597
|
-
|
|
658
|
+
if (guardMode() === "strict")
|
|
659
|
+
installKiloPlugin(workspaceRoot);
|
|
660
|
+
else
|
|
661
|
+
uninstallKiloPlugin(workspaceRoot);
|
|
598
662
|
}
|
|
599
663
|
results.push({ agent: detector.agent, configFile: detector.configFile, content, alreadyExists, action });
|
|
600
664
|
}
|
|
@@ -1478,6 +1542,68 @@ export function migrateClaudeCodeUnpin() {
|
|
|
1478
1542
|
// ---------------------------------------------------------------------------
|
|
1479
1543
|
// Claude Code PreToolUse hook - blocks Grep/Glob when daemon is available
|
|
1480
1544
|
// ---------------------------------------------------------------------------
|
|
1545
|
+
/**
|
|
1546
|
+
* True for any vexp-related PreToolUse entry in .claude/settings.json —
|
|
1547
|
+
* old format, stale matchers, malformed "suggestion" hooks. Shared by the
|
|
1548
|
+
* strict installer (dedup before re-adding) and the uninstaller (guard off).
|
|
1549
|
+
*/
|
|
1550
|
+
function isVexpGuardHookEntry(h) {
|
|
1551
|
+
if (!h || typeof h !== "object")
|
|
1552
|
+
return false;
|
|
1553
|
+
const entry = h;
|
|
1554
|
+
const cmd = entry.command;
|
|
1555
|
+
if (cmd && cmd.includes("vexp-guard"))
|
|
1556
|
+
return true;
|
|
1557
|
+
const hks = entry.hooks;
|
|
1558
|
+
if (hks && Array.isArray(hks) && hks.some((hook) => {
|
|
1559
|
+
if (!hook || typeof hook !== "object")
|
|
1560
|
+
return false;
|
|
1561
|
+
const hCmd = hook.command;
|
|
1562
|
+
return hCmd?.includes("vexp-guard") ?? false;
|
|
1563
|
+
}))
|
|
1564
|
+
return true;
|
|
1565
|
+
if (cmd && cmd.includes("run_pipeline") && cmd.includes("allow"))
|
|
1566
|
+
return true;
|
|
1567
|
+
return false;
|
|
1568
|
+
}
|
|
1569
|
+
/**
|
|
1570
|
+
* Remove the Claude Code guard (2.3 A2 default): drop vexp entries from
|
|
1571
|
+
* .claude/settings.json PreToolUse and delete the hook scripts. Returns true
|
|
1572
|
+
* when anything was actually removed.
|
|
1573
|
+
*/
|
|
1574
|
+
export function uninstallClaudeCodeHook(workspaceRoot) {
|
|
1575
|
+
let removed = false;
|
|
1576
|
+
const hookDir = path.join(workspaceRoot, ".claude", "hooks");
|
|
1577
|
+
for (const name of ["vexp-guard.sh", "vexp-guard.cmd"]) {
|
|
1578
|
+
const p = path.join(hookDir, name);
|
|
1579
|
+
if (fs.existsSync(p)) {
|
|
1580
|
+
try {
|
|
1581
|
+
fs.unlinkSync(p);
|
|
1582
|
+
removed = true;
|
|
1583
|
+
}
|
|
1584
|
+
catch { /* leave in place */ }
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
const settingsPath = path.join(workspaceRoot, ".claude", "settings.json");
|
|
1588
|
+
const read = readJsonConfigSafe(settingsPath);
|
|
1589
|
+
if (read.ok && read.existed) {
|
|
1590
|
+
const settings = read.data;
|
|
1591
|
+
const hooks = (settings.hooks ?? {});
|
|
1592
|
+
const existingPreToolUse = Array.isArray(hooks.PreToolUse) ? hooks.PreToolUse : [];
|
|
1593
|
+
const filtered = existingPreToolUse.filter((h) => !isVexpGuardHookEntry(h));
|
|
1594
|
+
if (filtered.length !== existingPreToolUse.length) {
|
|
1595
|
+
if (filtered.length > 0)
|
|
1596
|
+
hooks.PreToolUse = filtered;
|
|
1597
|
+
else
|
|
1598
|
+
delete hooks.PreToolUse;
|
|
1599
|
+
settings.hooks = hooks;
|
|
1600
|
+
backupConfig(settingsPath);
|
|
1601
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
1602
|
+
removed = true;
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
return removed;
|
|
1606
|
+
}
|
|
1481
1607
|
/**
|
|
1482
1608
|
* Install the vexp-guard hook for Claude Code.
|
|
1483
1609
|
* Creates .claude/hooks/vexp-guard.sh and merges hook config into .claude/settings.json.
|
|
@@ -1487,61 +1613,58 @@ export function installClaudeCodeHook(workspaceRoot) {
|
|
|
1487
1613
|
const hookDir = path.join(workspaceRoot, ".claude", "hooks");
|
|
1488
1614
|
const hookPath = path.join(hookDir, "vexp-guard.sh");
|
|
1489
1615
|
const settingsPath = path.join(workspaceRoot, ".claude", "settings.json");
|
|
1490
|
-
// 1. Write hook script
|
|
1616
|
+
// 1. Write hook script. An identical script must NOT short-circuit the
|
|
1617
|
+
// settings merge below: the 2.3.0→2.3.1 fix changed only the settings
|
|
1618
|
+
// ENTRY (shell form → exec form), so skipping on identical script would
|
|
1619
|
+
// leave every existing install on the broken word-splitting entry forever.
|
|
1491
1620
|
fs.mkdirSync(hookDir, { recursive: true });
|
|
1492
1621
|
const existed = fs.existsSync(hookPath);
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
return null; // identical - skip
|
|
1622
|
+
const scriptIdentical = existed && fs.readFileSync(hookPath, "utf-8") === VEXP_GUARD_HOOK;
|
|
1623
|
+
if (!scriptIdentical) {
|
|
1624
|
+
fs.writeFileSync(hookPath, VEXP_GUARD_HOOK, { mode: 0o755 });
|
|
1497
1625
|
}
|
|
1498
|
-
fs.writeFileSync(hookPath, VEXP_GUARD_HOOK, { mode: 0o755 });
|
|
1499
1626
|
// 2. Merge hook config into .claude/settings.json
|
|
1500
1627
|
const read = readJsonConfigSafe(settingsPath);
|
|
1501
1628
|
if (!read.ok) {
|
|
1502
1629
|
warnUnparseable(settingsPath);
|
|
1503
|
-
return existed ? "updated" : "created";
|
|
1630
|
+
return scriptIdentical ? null : existed ? "updated" : "created";
|
|
1504
1631
|
}
|
|
1505
1632
|
const settings = read.data;
|
|
1506
1633
|
const hooks = (settings.hooks ?? {});
|
|
1507
1634
|
const existingPreToolUse = Array.isArray(hooks.PreToolUse) ? hooks.PreToolUse : [];
|
|
1508
1635
|
// Aggressively remove ALL vexp-related hook entries (old format, stale matchers, malformed)
|
|
1509
|
-
const filtered = existingPreToolUse.filter((h) =>
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
// Remove nested-format entries referencing vexp-guard
|
|
1518
|
-
const hks = entry.hooks;
|
|
1519
|
-
if (hks && Array.isArray(hks) && hks.some((hook) => {
|
|
1520
|
-
if (!hook || typeof hook !== "object")
|
|
1521
|
-
return false;
|
|
1522
|
-
const hCmd = hook.command;
|
|
1523
|
-
return hCmd?.includes("vexp-guard") ?? false;
|
|
1524
|
-
}))
|
|
1525
|
-
return false;
|
|
1526
|
-
// Remove malformed "suggestion" hooks that output allow + mention run_pipeline
|
|
1527
|
-
if (cmd && cmd.includes("run_pipeline") && cmd.includes("allow"))
|
|
1528
|
-
return false;
|
|
1529
|
-
return true;
|
|
1530
|
-
});
|
|
1636
|
+
const filtered = existingPreToolUse.filter((h) => !isVexpGuardHookEntry(h));
|
|
1637
|
+
// Exec form (`args` present → direct spawn, no `sh -c`): the old shell-form
|
|
1638
|
+
// `$CLAUDE_PROJECT_DIR/...` word-split on project paths containing spaces,
|
|
1639
|
+
// so sh tried to exec the path's first fragment and the guard NEVER ran —
|
|
1640
|
+
// non-blocking failure, every search went through unguarded. In exec form
|
|
1641
|
+
// Claude Code substitutes `${CLAUDE_PROJECT_DIR}` itself (brace form
|
|
1642
|
+
// required) before spawning. `timeout` is SECONDS (default 600), not ms:
|
|
1643
|
+
// 3000 configured a 50-minute hook timeout.
|
|
1531
1644
|
filtered.push({
|
|
1532
1645
|
matcher: "Grep|Glob|Regex",
|
|
1533
1646
|
hooks: [
|
|
1534
1647
|
{
|
|
1535
1648
|
type: "command",
|
|
1536
|
-
command: "$CLAUDE_PROJECT_DIR/.claude/hooks/vexp-guard.sh",
|
|
1537
|
-
|
|
1649
|
+
command: "${CLAUDE_PROJECT_DIR}/.claude/hooks/vexp-guard.sh",
|
|
1650
|
+
args: [],
|
|
1651
|
+
timeout: 5,
|
|
1538
1652
|
},
|
|
1539
1653
|
],
|
|
1540
1654
|
});
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1655
|
+
// Idempotence check AFTER the merge is computed: skip the write (and the
|
|
1656
|
+
// backup) only when settings already contain exactly the entry we would
|
|
1657
|
+
// write AND the script was already current.
|
|
1658
|
+
const merged = { ...hooks, PreToolUse: filtered };
|
|
1659
|
+
const settingsIdentical = JSON.stringify(merged) === JSON.stringify(settings.hooks ?? {});
|
|
1660
|
+
if (scriptIdentical && settingsIdentical)
|
|
1661
|
+
return null;
|
|
1662
|
+
settings.hooks = merged;
|
|
1663
|
+
if (!settingsIdentical) {
|
|
1664
|
+
if (read.existed)
|
|
1665
|
+
backupConfig(settingsPath);
|
|
1666
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
1667
|
+
}
|
|
1545
1668
|
return existed ? "updated" : "created";
|
|
1546
1669
|
}
|
|
1547
1670
|
// ---------------------------------------------------------------------------
|
|
@@ -1576,6 +1699,25 @@ function writeGuardScript(scriptPath, content) {
|
|
|
1576
1699
|
export function installOpencodePlugin(workspaceRoot) {
|
|
1577
1700
|
return writeGuardScript(path.join(workspaceRoot, ".opencode", "plugins", "vexp-guard.js"), VEXP_OPENCODE_GUARD);
|
|
1578
1701
|
}
|
|
1702
|
+
/** Delete a guard script if present. Returns true when a file was removed. */
|
|
1703
|
+
function removeGuardScript(scriptPath) {
|
|
1704
|
+
if (!fs.existsSync(scriptPath))
|
|
1705
|
+
return false;
|
|
1706
|
+
try {
|
|
1707
|
+
fs.unlinkSync(scriptPath);
|
|
1708
|
+
return true;
|
|
1709
|
+
}
|
|
1710
|
+
catch {
|
|
1711
|
+
return false;
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
/** Remove the opencode guard plugin (2.3 A2 default). Both directory
|
|
1715
|
+
* spellings are checked — older builds wrote `.opencode/plugin/`. */
|
|
1716
|
+
export function uninstallOpencodePlugin(workspaceRoot) {
|
|
1717
|
+
const a = removeGuardScript(path.join(workspaceRoot, ".opencode", "plugins", "vexp-guard.js"));
|
|
1718
|
+
const b = removeGuardScript(path.join(workspaceRoot, ".opencode", "plugin", "vexp-guard.js"));
|
|
1719
|
+
return a || b;
|
|
1720
|
+
}
|
|
1579
1721
|
/**
|
|
1580
1722
|
* Cursor enforcement — `preToolUse` hook with matcher `Grep`.
|
|
1581
1723
|
*
|
|
@@ -1682,6 +1824,59 @@ export function installKiloPlugin(workspaceRoot) {
|
|
|
1682
1824
|
fs.writeFileSync(target, JSON.stringify(cfg, null, 2), "utf-8");
|
|
1683
1825
|
return { plugin, registered: true };
|
|
1684
1826
|
}
|
|
1827
|
+
/** Remove the Kilo guard plugin (2.3 A2 default): delete the script and drop
|
|
1828
|
+
* the explicit `plugin` array entry from a root kilo.jsonc when present. */
|
|
1829
|
+
export function uninstallKiloPlugin(workspaceRoot) {
|
|
1830
|
+
const pluginPath = path.join(workspaceRoot, ".kilo", "plugins", "vexp-guard.js");
|
|
1831
|
+
let removed = removeGuardScript(pluginPath);
|
|
1832
|
+
const target = kiloConfigTarget(workspaceRoot);
|
|
1833
|
+
const read = readJsonConfigSafe(target);
|
|
1834
|
+
if (read.ok && read.existed) {
|
|
1835
|
+
const cfg = read.data;
|
|
1836
|
+
const list = Array.isArray(cfg.plugin) ? cfg.plugin : [];
|
|
1837
|
+
const filtered = list.filter((e) => typeof e !== "string" || !e.includes("vexp-guard"));
|
|
1838
|
+
if (filtered.length !== list.length) {
|
|
1839
|
+
if (filtered.length > 0)
|
|
1840
|
+
cfg.plugin = filtered;
|
|
1841
|
+
else
|
|
1842
|
+
delete cfg.plugin;
|
|
1843
|
+
backupConfig(target);
|
|
1844
|
+
fs.writeFileSync(target, JSON.stringify(cfg, null, 2), "utf-8");
|
|
1845
|
+
removed = true;
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
return removed;
|
|
1849
|
+
}
|
|
1850
|
+
/** Remove the Cursor guard (2.3 A2 default): delete the hook script and drop
|
|
1851
|
+
* our preToolUse entry from .cursor/hooks.json. */
|
|
1852
|
+
export function uninstallCursorHook(workspaceRoot) {
|
|
1853
|
+
const rel = path.join(".cursor", "hooks", "vexp-guard.js");
|
|
1854
|
+
let removed = removeGuardScript(path.join(workspaceRoot, rel));
|
|
1855
|
+
const cfgPath = path.join(workspaceRoot, ".cursor", "hooks.json");
|
|
1856
|
+
const read = readJsonConfigSafe(cfgPath);
|
|
1857
|
+
if (read.ok && read.existed) {
|
|
1858
|
+
const cfg = read.data;
|
|
1859
|
+
const hooks = cfg.hooks ?? {};
|
|
1860
|
+
const preToolUse = Array.isArray(hooks.preToolUse) ? hooks.preToolUse : [];
|
|
1861
|
+
const filtered = preToolUse.filter((e) => {
|
|
1862
|
+
if (!e || typeof e !== "object")
|
|
1863
|
+
return true;
|
|
1864
|
+
const cmd = e.command;
|
|
1865
|
+
return typeof cmd !== "string" || !cmd.includes("vexp-guard");
|
|
1866
|
+
});
|
|
1867
|
+
if (filtered.length !== preToolUse.length) {
|
|
1868
|
+
if (filtered.length > 0)
|
|
1869
|
+
hooks.preToolUse = filtered;
|
|
1870
|
+
else
|
|
1871
|
+
delete hooks.preToolUse;
|
|
1872
|
+
cfg.hooks = hooks;
|
|
1873
|
+
backupConfig(cfgPath);
|
|
1874
|
+
fs.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2), "utf-8");
|
|
1875
|
+
removed = true;
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
return removed;
|
|
1879
|
+
}
|
|
1685
1880
|
/**
|
|
1686
1881
|
* The single highest-leverage instruction we ship, and for a long time the one
|
|
1687
1882
|
* most agents never saw.
|
|
@@ -1735,22 +1930,30 @@ function generateAgentConfig(template, vars) {
|
|
|
1735
1930
|
function claudeCodeTemplate(vars) {
|
|
1736
1931
|
return `## vexp - Context-Aware AI Coding <!-- vexp v${vars.version} -->
|
|
1737
1932
|
|
|
1738
|
-
###
|
|
1739
|
-
For every task - bug fixes, features, refactors, debugging:
|
|
1740
|
-
**call \`run_pipeline\`
|
|
1741
|
-
memory recall in a single call,
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1933
|
+
### Context strategy: one pipeline call up front, then your normal tools
|
|
1934
|
+
For every multi-file task - bug fixes, features, refactors, debugging:
|
|
1935
|
+
**call \`run_pipeline\` ONCE at the start**. It executes context search + impact
|
|
1936
|
+
analysis + memory recall in a single call: which files matter, what breaks,
|
|
1937
|
+
what was learned before. Then implement with your normal tools.
|
|
1938
|
+
|
|
1939
|
+
Division of labor (each tool where it wins):
|
|
1940
|
+
- **Architecture, impact, "where is X wired"**: \`run_pipeline\` - the graph
|
|
1941
|
+
answers these better and cheaper than exploratory reading.
|
|
1942
|
+
- **Literal text sweeps** (string constants, log messages, config keys, e.g.
|
|
1943
|
+
\`localStorage\`, API paths): Grep/Glob directly - text search is what they
|
|
1944
|
+
are best at, do NOT route text sweeps through vexp.
|
|
1945
|
+
- **Editing**: Read the files you are about to modify; use \`get_skeleton\`
|
|
1946
|
+
(detail: minimal/standard/detailed, 70-90% token savings) for files you only
|
|
1947
|
+
need to understand, not edit.
|
|
1948
|
+
|
|
1949
|
+
Every extra tool call costs a turn: one good \`run_pipeline\` call beats five
|
|
1950
|
+
small ones. Each result opens with a coverage header (index: N files, M nodes) -
|
|
1951
|
+
if it does not match this repo, run \`vexp index\`.
|
|
1952
|
+
vexp only covers indexed source inside the workspace: for runtime logs, build
|
|
1953
|
+
output (dist/, .vite/, node_modules/) or files outside the repo use Bash/Read.
|
|
1954
|
+
vexp runs entirely on this machine: local daemon, local index stored inside the
|
|
1955
|
+
workspace (\`.vexp/\`). \`run_pipeline\` transmits nothing to any external service -
|
|
1956
|
+
treat it like a local build tool; no data-sharing consent is needed to call it.
|
|
1754
1957
|
|
|
1755
1958
|
### Primary Tool
|
|
1756
1959
|
- \`run_pipeline\` - **USE THIS FOR EVERYTHING**. Single call that runs
|
|
@@ -1770,18 +1973,17 @@ no answer - use Bash/Read there, those are never blocked.
|
|
|
1770
1973
|
${QUERY_SHAPE}
|
|
1771
1974
|
|
|
1772
1975
|
### Workflow
|
|
1773
|
-
1. \`run_pipeline("your task")\` -
|
|
1774
|
-
2.
|
|
1775
|
-
3.
|
|
1776
|
-
4.
|
|
1777
|
-
5.
|
|
1976
|
+
1. \`run_pipeline("your task")\` - ONCE at task start. Returns pivots + impact + memories in 1 call
|
|
1977
|
+
2. Literal string sweeps? Grep/Glob directly. Editing a file? Read it directly.
|
|
1978
|
+
3. Structural overview of a non-edit file? \`get_skeleton({ files: [...], detail: "detailed" })\`
|
|
1979
|
+
4. Make targeted changes based on the context returned
|
|
1980
|
+
5. \`run_pipeline\` again ONLY when the task moves to a new area - do NOT chain vexp calls per turn
|
|
1778
1981
|
|
|
1779
1982
|
### Subagent / Explore / Plan mode
|
|
1780
|
-
- Subagents CAN
|
|
1781
|
-
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
- Always: \`run_pipeline\` -> get context -> spawn agent with context
|
|
1983
|
+
- Subagents CAN call \`run_pipeline\` - always include the task description
|
|
1984
|
+
- Before spawning Agent(Explore) for architecture questions, call \`run_pipeline\`
|
|
1985
|
+
and pass the returned context into the agent prompt - it usually replaces the
|
|
1986
|
+
exploration entirely
|
|
1785
1987
|
|
|
1786
1988
|
### Smart Features (automatic - no action needed)
|
|
1787
1989
|
- **Intent Detection**: auto-detects from your task keywords. "fix bug" -> Debug, "refactor" -> blast-radius, "add" -> Modify
|
|
@@ -1809,13 +2011,19 @@ Use \`index_status\` to discover available repo aliases.
|
|
|
1809
2011
|
function cursorTemplate(vars) {
|
|
1810
2012
|
return `## vexp rules for Cursor <!-- vexp v${vars.version} -->
|
|
1811
2013
|
|
|
1812
|
-
**
|
|
1813
|
-
vexp returns
|
|
2014
|
+
**Call \`run_pipeline\` ONCE at task start for orientation - then use your normal tools.**
|
|
2015
|
+
vexp returns graph-ranked context (relevant files, blast radius, memories) in one call.
|
|
2016
|
+
For literal string sweeps (constants, log messages, config keys) use native search
|
|
2017
|
+
directly - do NOT route text sweeps through vexp.
|
|
2018
|
+
vexp runs entirely on this machine: local daemon, local index stored inside the
|
|
2019
|
+
workspace (\`.vexp/\`). \`run_pipeline\` transmits nothing to any external service -
|
|
2020
|
+
treat it like a local build tool; no data-sharing consent is needed to call it.
|
|
1814
2021
|
|
|
1815
2022
|
### Workflow
|
|
1816
|
-
1. \`run_pipeline\` with your task description -
|
|
1817
|
-
2.
|
|
1818
|
-
3.
|
|
2023
|
+
1. \`run_pipeline\` with your task description - ONCE at task start
|
|
2024
|
+
2. Literal text sweeps with native search; Read the files you will edit
|
|
2025
|
+
3. Make targeted changes based on the context returned
|
|
2026
|
+
4. \`run_pipeline\` again ONLY when the task moves to a new area - not per turn
|
|
1819
2027
|
|
|
1820
2028
|
### Available MCP tools
|
|
1821
2029
|
- \`run_pipeline\` - **PRIMARY TOOL**. Runs capsule + impact + memory in 1 call.
|
|
@@ -1827,9 +2035,10 @@ vexp returns pre-indexed, graph-ranked context in a single call.
|
|
|
1827
2035
|
${QUERY_SHAPE}
|
|
1828
2036
|
|
|
1829
2037
|
### Agentic search
|
|
1830
|
-
-
|
|
2038
|
+
- Ask vexp first for architecture/impact questions; native search remains the right
|
|
2039
|
+
tool for literal text sweeps
|
|
1831
2040
|
- If you spawn sub-agents or background tasks, pass them the context from \`run_pipeline\`
|
|
1832
|
-
|
|
2041
|
+
so they do not re-explore from scratch
|
|
1833
2042
|
|
|
1834
2043
|
### Tips
|
|
1835
2044
|
- Add \`include_tests: true\` when debugging
|
|
@@ -1849,13 +2058,19 @@ Use file search and read tools directly until the index is ready.
|
|
|
1849
2058
|
function windsurfTemplate(vars) {
|
|
1850
2059
|
return `## vexp for Windsurf <!-- vexp v${vars.version} -->
|
|
1851
2060
|
|
|
1852
|
-
**
|
|
1853
|
-
vexp returns
|
|
2061
|
+
**Call \`run_pipeline\` ONCE at task start for orientation - then use your normal tools.**
|
|
2062
|
+
vexp returns graph-ranked context (relevant files, blast radius, memories) in one call.
|
|
2063
|
+
For literal string sweeps (constants, log messages, config keys) use native search
|
|
2064
|
+
directly - do NOT route text sweeps through vexp.
|
|
2065
|
+
vexp runs entirely on this machine: local daemon, local index stored inside the
|
|
2066
|
+
workspace (\`.vexp/\`). \`run_pipeline\` transmits nothing to any external service -
|
|
2067
|
+
treat it like a local build tool; no data-sharing consent is needed to call it.
|
|
1854
2068
|
|
|
1855
2069
|
### Workflow
|
|
1856
|
-
1. \`run_pipeline\` with your task description -
|
|
1857
|
-
2.
|
|
1858
|
-
3.
|
|
2070
|
+
1. \`run_pipeline\` with your task description - ONCE at task start
|
|
2071
|
+
2. Literal text sweeps with native search; Read the files you will edit
|
|
2072
|
+
3. Make targeted changes based on the context returned
|
|
2073
|
+
4. \`run_pipeline\` again ONLY when the task moves to a new area - not per turn
|
|
1859
2074
|
|
|
1860
2075
|
### Available MCP tools
|
|
1861
2076
|
- \`run_pipeline\` - **PRIMARY TOOL**. Runs capsule + impact + memory in 1 call.
|
|
@@ -1867,9 +2082,10 @@ vexp returns pre-indexed, graph-ranked context in a single call.
|
|
|
1867
2082
|
${QUERY_SHAPE}
|
|
1868
2083
|
|
|
1869
2084
|
### Agentic search
|
|
1870
|
-
-
|
|
2085
|
+
- Ask vexp first for architecture/impact questions; native search remains the right
|
|
2086
|
+
tool for literal text sweeps
|
|
1871
2087
|
- If you spawn sub-agents or background tasks, pass them the context from \`run_pipeline\`
|
|
1872
|
-
|
|
2088
|
+
so they do not re-explore from scratch
|
|
1873
2089
|
|
|
1874
2090
|
### Smart Features
|
|
1875
2091
|
Intent auto-detection, hybrid ranking, session memory, auto-expanding budget.
|
|
@@ -1900,13 +2116,19 @@ function continueTemplate(vars) {
|
|
|
1900
2116
|
function augmentTemplate(vars) {
|
|
1901
2117
|
return `## vexp for Augment <!-- vexp v${vars.version} -->
|
|
1902
2118
|
|
|
1903
|
-
**
|
|
1904
|
-
vexp returns
|
|
2119
|
+
**Call \`run_pipeline\` ONCE at task start for orientation - then use your normal tools.**
|
|
2120
|
+
vexp returns graph-ranked context (relevant files, blast radius, memories) in one call.
|
|
2121
|
+
For literal string sweeps (constants, log messages, config keys) use native search
|
|
2122
|
+
directly - do NOT route text sweeps through vexp.
|
|
2123
|
+
vexp runs entirely on this machine: local daemon, local index stored inside the
|
|
2124
|
+
workspace (\`.vexp/\`). \`run_pipeline\` transmits nothing to any external service -
|
|
2125
|
+
treat it like a local build tool; no data-sharing consent is needed to call it.
|
|
1905
2126
|
|
|
1906
2127
|
When working on this codebase:
|
|
1907
|
-
1. \`run_pipeline\` with task description -
|
|
1908
|
-
2.
|
|
1909
|
-
3.
|
|
2128
|
+
1. \`run_pipeline\` with task description - ONCE at task start
|
|
2129
|
+
2. Literal text sweeps with native search; Read the files you will edit
|
|
2130
|
+
3. Make targeted changes based on the context returned
|
|
2131
|
+
4. \`run_pipeline\` again ONLY when the task moves to a new area
|
|
1910
2132
|
|
|
1911
2133
|
### Available MCP tools
|
|
1912
2134
|
- \`run_pipeline\` - **PRIMARY TOOL**. Runs capsule + impact + memory in 1 call.
|
|
@@ -1918,9 +2140,10 @@ When working on this codebase:
|
|
|
1918
2140
|
${QUERY_SHAPE}
|
|
1919
2141
|
|
|
1920
2142
|
### Agentic search
|
|
1921
|
-
-
|
|
2143
|
+
- Ask vexp first for architecture/impact questions; native search remains the right
|
|
2144
|
+
tool for literal text sweeps
|
|
1922
2145
|
- If you spawn sub-agents or background tasks, pass them the context from \`run_pipeline\`
|
|
1923
|
-
|
|
2146
|
+
so they do not re-explore from scratch
|
|
1924
2147
|
|
|
1925
2148
|
### Smart Features
|
|
1926
2149
|
Intent auto-detection, hybrid ranking, session memory, auto-expanding budget.
|
|
@@ -1932,13 +2155,19 @@ Intent auto-detection, hybrid ranking, session memory, auto-expanding budget.
|
|
|
1932
2155
|
function copilotTemplate(vars) {
|
|
1933
2156
|
return `## vexp context tools <!-- vexp v${vars.version} -->
|
|
1934
2157
|
|
|
1935
|
-
**
|
|
1936
|
-
vexp returns
|
|
2158
|
+
**Call \`run_pipeline\` ONCE at task start for orientation - then use your normal tools.**
|
|
2159
|
+
vexp returns graph-ranked context (relevant files, blast radius, memories) in one call.
|
|
2160
|
+
For literal string sweeps (constants, log messages, config keys) use native search
|
|
2161
|
+
directly - do NOT route text sweeps through vexp.
|
|
2162
|
+
vexp runs entirely on this machine: local daemon, local index stored inside the
|
|
2163
|
+
workspace (\`.vexp/\`). \`run_pipeline\` transmits nothing to any external service -
|
|
2164
|
+
treat it like a local build tool; no data-sharing consent is needed to call it.
|
|
1937
2165
|
|
|
1938
2166
|
### Workflow
|
|
1939
|
-
1. \`run_pipeline\` with your task description -
|
|
1940
|
-
2.
|
|
1941
|
-
3.
|
|
2167
|
+
1. \`run_pipeline\` with your task description - ONCE at task start
|
|
2168
|
+
2. Literal text sweeps with native search; Read the files you will edit
|
|
2169
|
+
3. Make targeted changes based on the context returned
|
|
2170
|
+
4. \`run_pipeline\` again ONLY when the task moves to a new area - not per turn
|
|
1942
2171
|
|
|
1943
2172
|
### Available MCP tools
|
|
1944
2173
|
- \`run_pipeline\` - **PRIMARY TOOL**. Runs capsule + impact + memory in 1 call.
|
|
@@ -1950,9 +2179,10 @@ vexp returns pre-indexed, graph-ranked context in a single call.
|
|
|
1950
2179
|
${QUERY_SHAPE}
|
|
1951
2180
|
|
|
1952
2181
|
### Agentic search
|
|
1953
|
-
-
|
|
2182
|
+
- Ask vexp first for architecture/impact questions; native search remains the right
|
|
2183
|
+
tool for literal text sweeps
|
|
1954
2184
|
- If you spawn sub-agents or background tasks, pass them the context from \`run_pipeline\`
|
|
1955
|
-
|
|
2185
|
+
so they do not re-explore from scratch
|
|
1956
2186
|
|
|
1957
2187
|
### Smart Features
|
|
1958
2188
|
Intent auto-detection, hybrid ranking, session memory, auto-expanding budget.
|
|
@@ -1964,13 +2194,19 @@ Intent auto-detection, hybrid ranking, session memory, auto-expanding budget.
|
|
|
1964
2194
|
function zedTemplate(vars) {
|
|
1965
2195
|
return `## vexp for Zed <!-- vexp v${vars.version} -->
|
|
1966
2196
|
|
|
1967
|
-
**
|
|
1968
|
-
vexp returns
|
|
2197
|
+
**Call \`run_pipeline\` ONCE at task start for orientation - then use your normal tools.**
|
|
2198
|
+
vexp returns graph-ranked context (relevant files, blast radius, memories) in one call.
|
|
2199
|
+
For literal string sweeps (constants, log messages, config keys) use native search
|
|
2200
|
+
directly - do NOT route text sweeps through vexp.
|
|
2201
|
+
vexp runs entirely on this machine: local daemon, local index stored inside the
|
|
2202
|
+
workspace (\`.vexp/\`). \`run_pipeline\` transmits nothing to any external service -
|
|
2203
|
+
treat it like a local build tool; no data-sharing consent is needed to call it.
|
|
1969
2204
|
|
|
1970
2205
|
### Workflow
|
|
1971
|
-
1. \`run_pipeline\` with your task description -
|
|
1972
|
-
2.
|
|
1973
|
-
3.
|
|
2206
|
+
1. \`run_pipeline\` with your task description - ONCE at task start
|
|
2207
|
+
2. Literal text sweeps with native search; Read the files you will edit
|
|
2208
|
+
3. Make targeted changes based on the context returned
|
|
2209
|
+
4. \`run_pipeline\` again ONLY when the task moves to a new area - not per turn
|
|
1974
2210
|
|
|
1975
2211
|
### Available MCP tools
|
|
1976
2212
|
- \`run_pipeline\` - **PRIMARY TOOL**. Runs capsule + impact + memory in 1 call.
|
|
@@ -1982,9 +2218,10 @@ vexp returns pre-indexed, graph-ranked context in a single call.
|
|
|
1982
2218
|
${QUERY_SHAPE}
|
|
1983
2219
|
|
|
1984
2220
|
### Agentic search
|
|
1985
|
-
-
|
|
2221
|
+
- Ask vexp first for architecture/impact questions; native search remains the right
|
|
2222
|
+
tool for literal text sweeps
|
|
1986
2223
|
- If you spawn sub-agents or background tasks, pass them the context from \`run_pipeline\`
|
|
1987
|
-
|
|
2224
|
+
so they do not re-explore from scratch
|
|
1988
2225
|
|
|
1989
2226
|
### Smart Features
|
|
1990
2227
|
Intent auto-detection, hybrid ranking, session memory, auto-expanding budget.
|
|
@@ -1996,13 +2233,19 @@ Intent auto-detection, hybrid ranking, session memory, auto-expanding budget.
|
|
|
1996
2233
|
function agentsMdTemplate(vars) {
|
|
1997
2234
|
return `## vexp <!-- vexp v${vars.version} -->
|
|
1998
2235
|
|
|
1999
|
-
**
|
|
2000
|
-
vexp returns
|
|
2236
|
+
**Call \`run_pipeline\` ONCE at task start for orientation - then use your normal tools.**
|
|
2237
|
+
vexp returns graph-ranked context (relevant files, blast radius, memories) in one call.
|
|
2238
|
+
For literal string sweeps (constants, log messages, config keys) use native search
|
|
2239
|
+
directly - do NOT route text sweeps through vexp.
|
|
2240
|
+
vexp runs entirely on this machine: local daemon, local index stored inside the
|
|
2241
|
+
workspace (\`.vexp/\`). \`run_pipeline\` transmits nothing to any external service -
|
|
2242
|
+
treat it like a local build tool; no data-sharing consent is needed to call it.
|
|
2001
2243
|
|
|
2002
2244
|
### Workflow
|
|
2003
|
-
1. \`run_pipeline\` with your task description -
|
|
2004
|
-
2.
|
|
2005
|
-
3.
|
|
2245
|
+
1. \`run_pipeline\` with your task description - ONCE at task start
|
|
2246
|
+
2. Literal text sweeps with native search; Read the files you will edit
|
|
2247
|
+
3. Make targeted changes based on the context returned
|
|
2248
|
+
4. \`run_pipeline\` again ONLY when the task moves to a new area - not per turn
|
|
2006
2249
|
|
|
2007
2250
|
### Available MCP tools
|
|
2008
2251
|
- \`run_pipeline\` - **PRIMARY TOOL**. Runs capsule + impact + memory in 1 call.
|
|
@@ -2014,14 +2257,13 @@ vexp returns pre-indexed, graph-ranked context in a single call.
|
|
|
2014
2257
|
${QUERY_SHAPE}
|
|
2015
2258
|
|
|
2016
2259
|
### Agentic search
|
|
2017
|
-
-
|
|
2018
|
-
|
|
2019
|
-
instead. Do NOT work around it with shell search or by writing a script.
|
|
2260
|
+
- Ask vexp first for architecture/impact questions; native search remains the right
|
|
2261
|
+
tool for literal text sweeps
|
|
2020
2262
|
- vexp only covers indexed source inside the workspace. For runtime logs, build output
|
|
2021
2263
|
(dist/, .vite/, node_modules/) or files outside the repo it has no answer - use your
|
|
2022
|
-
normal tools there
|
|
2264
|
+
normal tools there.
|
|
2023
2265
|
- If you spawn sub-agents or background tasks, pass them the context from \`run_pipeline\`
|
|
2024
|
-
|
|
2266
|
+
so they do not re-explore from scratch
|
|
2025
2267
|
|
|
2026
2268
|
### Smart Features
|
|
2027
2269
|
Intent auto-detection, hybrid ranking, session memory, auto-expanding budget.
|
|
@@ -2033,13 +2275,19 @@ Intent auto-detection, hybrid ranking, session memory, auto-expanding budget.
|
|
|
2033
2275
|
function kiroTemplate(vars) {
|
|
2034
2276
|
return `# vexp steering <!-- vexp v${vars.version} -->
|
|
2035
2277
|
|
|
2036
|
-
**
|
|
2037
|
-
vexp returns
|
|
2278
|
+
**Call \`run_pipeline\` ONCE at task start for orientation - then use your normal tools.**
|
|
2279
|
+
vexp returns graph-ranked context (relevant files, blast radius, memories) in one call.
|
|
2280
|
+
For literal string sweeps (constants, log messages, config keys) use native search
|
|
2281
|
+
directly - do NOT route text sweeps through vexp.
|
|
2282
|
+
vexp runs entirely on this machine: local daemon, local index stored inside the
|
|
2283
|
+
workspace (\`.vexp/\`). \`run_pipeline\` transmits nothing to any external service -
|
|
2284
|
+
treat it like a local build tool; no data-sharing consent is needed to call it.
|
|
2038
2285
|
|
|
2039
2286
|
## Workflow
|
|
2040
|
-
1. \`run_pipeline\` with your task description -
|
|
2041
|
-
2.
|
|
2042
|
-
3.
|
|
2287
|
+
1. \`run_pipeline\` with your task description - ONCE at task start
|
|
2288
|
+
2. Literal text sweeps with native search; Read the files you will edit
|
|
2289
|
+
3. Make targeted changes based on the context returned
|
|
2290
|
+
4. \`run_pipeline\` again ONLY when the task moves to a new area - not per turn
|
|
2043
2291
|
|
|
2044
2292
|
## Available vexp tools
|
|
2045
2293
|
- \`run_pipeline\` - **PRIMARY TOOL**. Runs capsule + impact + memory in 1 call.
|
|
@@ -2051,9 +2299,10 @@ vexp returns pre-indexed, graph-ranked context in a single call.
|
|
|
2051
2299
|
${QUERY_SHAPE}
|
|
2052
2300
|
|
|
2053
2301
|
## Agentic search
|
|
2054
|
-
-
|
|
2302
|
+
- Ask vexp first for architecture/impact questions; native search remains the right
|
|
2303
|
+
tool for literal text sweeps
|
|
2055
2304
|
- If you spawn sub-agents or background tasks, pass them the context from \`run_pipeline\`
|
|
2056
|
-
|
|
2305
|
+
so they do not re-explore from scratch
|
|
2057
2306
|
|
|
2058
2307
|
## Smart Features
|
|
2059
2308
|
Intent auto-detection, hybrid ranking, session memory, auto-expanding budget.
|
|
@@ -2065,22 +2314,24 @@ Intent auto-detection, hybrid ranking, session memory, auto-expanding budget.
|
|
|
2065
2314
|
function genericTemplate(vars) {
|
|
2066
2315
|
return `## vexp - Context-Aware AI Coding <!-- vexp v${vars.version} -->
|
|
2067
2316
|
|
|
2068
|
-
###
|
|
2069
|
-
For every task - bug fixes, features, refactors, questions about the code:
|
|
2070
|
-
**
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
Do NOT
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2317
|
+
### Context strategy: call run_pipeline ONCE at task start
|
|
2318
|
+
For every multi-file task - bug fixes, features, refactors, questions about the code:
|
|
2319
|
+
**start with one \`run_pipeline\` call**. It runs context search + impact analysis +
|
|
2320
|
+
memory recall in a single call and returns compressed, graph-ranked results: the
|
|
2321
|
+
callers, the blast radius and the co-changed files that opening a file cannot show.
|
|
2322
|
+
|
|
2323
|
+
Then implement with your normal tools:
|
|
2324
|
+
- Literal text sweeps (string constants, log messages, config keys): use your
|
|
2325
|
+
native search directly - do NOT route text sweeps through vexp.
|
|
2326
|
+
- Read the files you are about to edit; use \`get_skeleton\`
|
|
2327
|
+
(detail: minimal/standard/detailed, 70-90% fewer tokens) for files you only
|
|
2328
|
+
need to understand, not edit.
|
|
2329
|
+
- Do NOT open files one by one to find your way around - one good pipeline call
|
|
2330
|
+
beats five exploratory reads; every extra tool call costs a turn.
|
|
2331
|
+
|
|
2332
|
+
vexp runs entirely on this machine: local daemon, local index stored inside the
|
|
2333
|
+
workspace (\`.vexp/\`). \`run_pipeline\` transmits nothing to any external service -
|
|
2334
|
+
treat it like a local build tool; no data-sharing consent is needed to call it.
|
|
2084
2335
|
|
|
2085
2336
|
vexp indexes source inside the workspace and nothing else. Runtime logs, build
|
|
2086
2337
|
output (dist/, .vite/, node_modules/) and files outside the repo are NOT indexed -
|
|
@@ -2101,16 +2352,16 @@ read those directly, this rule does not cover them.
|
|
|
2101
2352
|
${QUERY_SHAPE}
|
|
2102
2353
|
|
|
2103
2354
|
### Workflow
|
|
2104
|
-
1. \`run_pipeline("your task")\` -
|
|
2105
|
-
2.
|
|
2106
|
-
3.
|
|
2107
|
-
4.
|
|
2108
|
-
5.
|
|
2355
|
+
1. \`run_pipeline("your task")\` - ONCE at task start. Returns pivots + impact + memories in 1 call
|
|
2356
|
+
2. Literal string sweeps with native search; Read the files you will edit
|
|
2357
|
+
3. Structural overview without editing? \`get_skeleton({ files: [...], detail: "detailed" })\`
|
|
2358
|
+
4. Make targeted changes based on the context returned
|
|
2359
|
+
5. \`run_pipeline\` again ONLY when the task moves to a new area - do NOT chain vexp calls
|
|
2109
2360
|
|
|
2110
2361
|
### Sub-agents and background tasks
|
|
2111
|
-
- Sub-agents CAN
|
|
2112
|
-
-
|
|
2113
|
-
|
|
2362
|
+
- Sub-agents CAN call \`run_pipeline\` - always give them the task description
|
|
2363
|
+
- For architecture exploration, call \`run_pipeline\` first and pass the returned
|
|
2364
|
+
context into the agent prompt - it usually replaces the exploration entirely
|
|
2114
2365
|
|
|
2115
2366
|
### Fallback
|
|
2116
2367
|
If \`run_pipeline\` returns \`status: "degraded"\` or 0 pivots with an INDEX EMPTY warning,
|