vectorvesper 2.0.7 → 2.1.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/dist/index.js
CHANGED
|
@@ -993,7 +993,7 @@ Remove ${slug}
|
|
|
993
993
|
import fs6 from "fs";
|
|
994
994
|
import path6 from "path";
|
|
995
995
|
import pc8 from "picocolors";
|
|
996
|
-
var CLI_VERSION = true ? "2.0
|
|
996
|
+
var CLI_VERSION = true ? "2.1.0" : "0.0.0-dev";
|
|
997
997
|
async function infoCommand() {
|
|
998
998
|
console.log(pc8.bold(pc8.cyan("\nVector Vesper Diagnostics\n")));
|
|
999
999
|
const projectInfo = detectProject();
|
|
@@ -1291,7 +1291,7 @@ async function whoamiCommand() {
|
|
|
1291
1291
|
}
|
|
1292
1292
|
|
|
1293
1293
|
// src/index.ts
|
|
1294
|
-
var version = true ? "2.0
|
|
1294
|
+
var version = true ? "2.1.0" : "0.0.0-dev";
|
|
1295
1295
|
var program = new Command();
|
|
1296
1296
|
program.name("vv").description("Vector Vesper CLI \u2014 add visual components to your React project").version(version).option("--verbose", "Show detailed debug output").hook("preAction", (thisCommand) => {
|
|
1297
1297
|
const opts = thisCommand.opts();
|
|
@@ -1330,7 +1330,7 @@ program.command("whoami", { hidden: true }).description("Show current authentica
|
|
|
1330
1330
|
await whoamiCommand();
|
|
1331
1331
|
});
|
|
1332
1332
|
program.command("mcp [action]").description("Run as an MCP server (stdio) for AI coding agents. `vv mcp status` checks the setup.").option("--stdio", "Force server mode even from an interactive terminal").action(async (action, options) => {
|
|
1333
|
-
const { mcpCommand } = await import("./mcp-
|
|
1333
|
+
const { mcpCommand } = await import("./mcp-OURIIFET.js");
|
|
1334
1334
|
await mcpCommand(action, options);
|
|
1335
1335
|
});
|
|
1336
1336
|
process.on("unhandledRejection", (error) => {
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
loadHookManifest
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-CPZKZO3A.js";
|
|
4
4
|
import {
|
|
5
5
|
getAuthToken
|
|
6
6
|
} from "./chunk-SFP5K3ZO.js";
|
|
7
7
|
|
|
8
8
|
// src/commands/mcp.ts
|
|
9
9
|
import pc from "picocolors";
|
|
10
|
-
var VERSION = true ? "2.0
|
|
10
|
+
var VERSION = true ? "2.1.0" : "0.0.0-dev";
|
|
11
11
|
var CONFIG_SNIPPET = `{
|
|
12
12
|
"mcpServers": {
|
|
13
13
|
"vectorvesper": {
|
|
@@ -33,7 +33,14 @@ function printStatus() {
|
|
|
33
33
|
console.log(pc.bold(pc.cyan(" Vector Vesper MCP\n")));
|
|
34
34
|
console.log(` ${pc.bold("CLI version:")} ${VERSION}`);
|
|
35
35
|
if (manifest) {
|
|
36
|
-
|
|
36
|
+
const hookCount = manifest.hooks.filter((h) => h.category !== "core").length;
|
|
37
|
+
const coreCount = manifest.hooks.length - hookCount;
|
|
38
|
+
const patternCount = manifest.patterns?.length ?? 0;
|
|
39
|
+
console.log(
|
|
40
|
+
` ${ok(
|
|
41
|
+
`Hook manifest: ${hookCount} hooks, ${coreCount} core primitives, ${patternCount} patterns, engine v${manifest.engineVersion}`
|
|
42
|
+
)}`
|
|
43
|
+
);
|
|
37
44
|
console.log(` ${pc.dim(`Contract level: ${manifest.contractLevel}`)}`);
|
|
38
45
|
} else {
|
|
39
46
|
console.log(` ${bad("Hook manifest: MISSING")}`);
|
|
@@ -53,7 +60,7 @@ function printStatus() {
|
|
|
53
60
|
console.log("");
|
|
54
61
|
console.log(
|
|
55
62
|
pc.dim(
|
|
56
|
-
" Tools: list_hooks \xB7 get_hook \xB7 list_components \xB7 get_component \xB7 get_setup_guidance \xB7 search \xB7 check_motion"
|
|
63
|
+
" Tools: list_hooks \xB7 get_hook \xB7 list_patterns \xB7 get_pattern \xB7 list_components \xB7 get_component \xB7 get_setup_guidance \xB7 search \xB7 check_motion"
|
|
57
64
|
)
|
|
58
65
|
);
|
|
59
66
|
console.log("");
|
|
@@ -67,7 +74,7 @@ function printInteractiveHelp() {
|
|
|
67
74
|
console.log(" started from a terminal it would just wait for a client that never connects.");
|
|
68
75
|
console.log("");
|
|
69
76
|
console.log(` ${pc.bold("Check your setup:")} ${pc.cyan("vv mcp status")}`);
|
|
70
|
-
console.log(` ${pc.bold("Add to Claude Code:")} ${pc.cyan("claude mcp add vectorvesper -- npx -y vectorvesper mcp")}`);
|
|
77
|
+
console.log(` ${pc.bold("Add to Claude Code:")} ${pc.cyan("claude mcp add vectorvesper -- npx -y vectorvesper@latest mcp")}`);
|
|
71
78
|
console.log("");
|
|
72
79
|
console.log(pc.dim(" To run the server here anyway (for debugging): vv mcp --stdio"));
|
|
73
80
|
console.log("");
|
|
@@ -94,7 +101,7 @@ ${pc.red("\u2717")} Unknown argument "${action}" for \`vv mcp\`.
|
|
|
94
101
|
return;
|
|
95
102
|
}
|
|
96
103
|
protectStdout();
|
|
97
|
-
const { startMcpServer } = await import("./server-
|
|
104
|
+
const { startMcpServer } = await import("./server-ROPGTSDI.js");
|
|
98
105
|
try {
|
|
99
106
|
await startMcpServer();
|
|
100
107
|
} catch (error) {
|
|
@@ -4,8 +4,9 @@ import {
|
|
|
4
4
|
} from "./chunk-5YSVDVLK.js";
|
|
5
5
|
import {
|
|
6
6
|
findHook,
|
|
7
|
+
findPattern,
|
|
7
8
|
loadHookManifest
|
|
8
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-CPZKZO3A.js";
|
|
9
10
|
import {
|
|
10
11
|
getAuthToken
|
|
11
12
|
} from "./chunk-SFP5K3ZO.js";
|
|
@@ -399,7 +400,7 @@ async function checkMotionFiles(files, cwd) {
|
|
|
399
400
|
}
|
|
400
401
|
|
|
401
402
|
// src/mcp/server.ts
|
|
402
|
-
var VERSION = true ? "2.0
|
|
403
|
+
var VERSION = true ? "2.1.0" : "0.0.0-dev";
|
|
403
404
|
function text(body) {
|
|
404
405
|
return { content: [{ type: "text", text: body }] };
|
|
405
406
|
}
|
|
@@ -584,6 +585,41 @@ ${c.docsUrl}`);
|
|
|
584
585
|
);
|
|
585
586
|
return out.join("\n");
|
|
586
587
|
}
|
|
588
|
+
function formatPatternSummary(p) {
|
|
589
|
+
return `**${p.name}** \u2014 ${p.tagline}
|
|
590
|
+
Composes: ${p.uses.map((u) => `\`${u}\``).join(" + ")}`;
|
|
591
|
+
}
|
|
592
|
+
function formatPatternDetail(p) {
|
|
593
|
+
const out = [];
|
|
594
|
+
out.push(`# ${p.title} \`${p.name}\``);
|
|
595
|
+
out.push(`> ${p.tagline}`);
|
|
596
|
+
out.push("");
|
|
597
|
+
out.push(`**The problem it removes:** ${p.problem}`);
|
|
598
|
+
out.push("");
|
|
599
|
+
out.push(
|
|
600
|
+
`**Composes:** ${p.uses.map((u) => `\`${u}\``).join(" + ")} \u2014 call \`get_hook\` on any of these you have not already read; the pattern assumes their contracts.`
|
|
601
|
+
);
|
|
602
|
+
out.push("\n## Wiring order");
|
|
603
|
+
p.wiring.forEach((step, i) => out.push(`${i + 1}. ${step}`));
|
|
604
|
+
out.push("\n## Complete example");
|
|
605
|
+
out.push("```tsx");
|
|
606
|
+
out.push(p.code);
|
|
607
|
+
out.push("```");
|
|
608
|
+
out.push("\n## Pitfalls");
|
|
609
|
+
for (const pit of p.pitfalls) {
|
|
610
|
+
const caught = pit.rule ? ` *(caught by \`check_motion\`: ${pit.rule})*` : "";
|
|
611
|
+
out.push(`- **${pit.mistake}** \u2014 ${pit.consequence}${caught}`);
|
|
612
|
+
}
|
|
613
|
+
out.push("\n## Verify");
|
|
614
|
+
p.verify.forEach((step, i) => out.push(`${i + 1}. ${step}`));
|
|
615
|
+
if (p.docsUrl) out.push(`
|
|
616
|
+
## Docs
|
|
617
|
+
${p.docsUrl}`);
|
|
618
|
+
out.push(
|
|
619
|
+
"\n---\n**After writing your version, run `check_motion` on the file(s).** The pitfalls above are the findings it looks for; a clean report is how you confirm the composition held."
|
|
620
|
+
);
|
|
621
|
+
return out.join("\n");
|
|
622
|
+
}
|
|
587
623
|
function severityMark(s) {
|
|
588
624
|
return s === "error" ? "\u2717 error" : s === "warning" ? "\u25B2 warning" : "\xB7 note";
|
|
589
625
|
}
|
|
@@ -629,10 +665,10 @@ async function registerTools(server) {
|
|
|
629
665
|
server.registerTool(
|
|
630
666
|
"list_hooks",
|
|
631
667
|
{
|
|
632
|
-
title: "List motion hooks",
|
|
633
|
-
description: "List every React hook in the @vectorvesper/motion runtime, with the problem each one solves. Start here when deciding which primitive fits a motion task.",
|
|
668
|
+
title: "List motion hooks and core primitives",
|
|
669
|
+
description: "List every React hook in the @vectorvesper/motion runtime, with the problem each one solves, plus the core primitives (frame conductor, sensor bus, math, devtools) that custom effects are built on. Start here when deciding which primitive fits a motion task.",
|
|
634
670
|
inputSchema: {
|
|
635
|
-
category: z.enum(["sensor", "governor", "gate", "interaction", "media", "effect"]).optional().describe(
|
|
671
|
+
category: z.enum(["sensor", "governor", "gate", "interaction", "media", "effect", "core"]).optional().describe('Filter to one category. "core" lists the custom-effect primitives.')
|
|
636
672
|
}
|
|
637
673
|
},
|
|
638
674
|
async ({ category }) => {
|
|
@@ -642,16 +678,32 @@ async function registerTools(server) {
|
|
|
642
678
|
"Hook manifest unavailable \u2014 this CLI build is missing dist/hooks.json. Reinstall with `npm i -g vectorvesper@latest`."
|
|
643
679
|
);
|
|
644
680
|
}
|
|
645
|
-
const
|
|
646
|
-
if (!
|
|
647
|
-
const
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
681
|
+
const all = category ? manifest.hooks.filter((h) => h.category === category) : manifest.hooks;
|
|
682
|
+
if (!all.length) return text(`No hooks in category "${category}".`);
|
|
683
|
+
const reactHooks = all.filter((h) => h.category !== "core");
|
|
684
|
+
const core = all.filter((h) => h.category === "core");
|
|
685
|
+
const patternCount = manifest.patterns?.length ?? 0;
|
|
686
|
+
const lines = [];
|
|
687
|
+
if (reactHooks.length) {
|
|
688
|
+
lines.push(
|
|
689
|
+
`${reactHooks.length} hook${reactHooks.length === 1 ? "" : "s"} in @vectorvesper/motion v${manifest.engineVersion}`,
|
|
690
|
+
"",
|
|
691
|
+
...reactHooks.map(formatHookSummary)
|
|
692
|
+
);
|
|
693
|
+
}
|
|
694
|
+
if (core.length) {
|
|
695
|
+
if (lines.length) lines.push("");
|
|
696
|
+
lines.push(
|
|
697
|
+
`**Core primitives** \u2014 the layer custom effects are built on. Never start a private requestAnimationFrame loop; subscribe to the conductor instead.`,
|
|
698
|
+
"",
|
|
699
|
+
...core.map(formatHookSummary)
|
|
700
|
+
);
|
|
701
|
+
}
|
|
702
|
+
lines.push(
|
|
651
703
|
"",
|
|
652
|
-
"Call `get_hook` for the full contract of any of these before writing code with it."
|
|
653
|
-
|
|
654
|
-
return text(
|
|
704
|
+
"Call `get_hook` for the full contract of any of these before writing code with it." + (patternCount > 0 ? ` For compositions \u2014 scrollytelling, predictive cards, custom effects \u2014 call \`list_patterns\` (${patternCount} available).` : "")
|
|
705
|
+
);
|
|
706
|
+
return text(lines.join("\n"));
|
|
655
707
|
}
|
|
656
708
|
);
|
|
657
709
|
server.registerTool(
|
|
@@ -673,6 +725,53 @@ async function registerTools(server) {
|
|
|
673
725
|
return text(formatHookDetail(hook));
|
|
674
726
|
}
|
|
675
727
|
);
|
|
728
|
+
server.registerTool(
|
|
729
|
+
"list_patterns",
|
|
730
|
+
{
|
|
731
|
+
title: "List composition patterns",
|
|
732
|
+
description: "List the composition patterns \u2014 hooks and core primitives wired together into things people build: scrollytelling video, predictive media cards, adaptive shader heroes, custom frame effects. Use these when a task combines primitives, or when no single hook covers it; a pattern carries the wiring order, complete code, the pitfalls (each mapped to the check_motion rule that catches it), and how to verify the result.",
|
|
733
|
+
inputSchema: {}
|
|
734
|
+
},
|
|
735
|
+
async () => {
|
|
736
|
+
const manifest = loadHookManifest();
|
|
737
|
+
if (!manifest) {
|
|
738
|
+
return text(
|
|
739
|
+
"Hook manifest unavailable \u2014 this CLI build is missing dist/hooks.json. Reinstall with `npm i -g vectorvesper@latest`."
|
|
740
|
+
);
|
|
741
|
+
}
|
|
742
|
+
const patterns = manifest.patterns ?? [];
|
|
743
|
+
if (!patterns.length) {
|
|
744
|
+
return text("This manifest carries no patterns. Reinstall with `npm i -g vectorvesper@latest`.");
|
|
745
|
+
}
|
|
746
|
+
const body = [
|
|
747
|
+
`${patterns.length} composition pattern${patterns.length === 1 ? "" : "s"} (engine v${manifest.engineVersion})`,
|
|
748
|
+
"",
|
|
749
|
+
...patterns.map(formatPatternSummary),
|
|
750
|
+
"",
|
|
751
|
+
"Call `get_pattern` for the wiring order, complete code, pitfalls, and verification steps. Building something none of these cover? Start from `custom-frame-effect` \u2014 it is the canonical skeleton every custom effect follows."
|
|
752
|
+
].join("\n");
|
|
753
|
+
return text(body);
|
|
754
|
+
}
|
|
755
|
+
);
|
|
756
|
+
server.registerTool(
|
|
757
|
+
"get_pattern",
|
|
758
|
+
{
|
|
759
|
+
title: "Get a composition pattern",
|
|
760
|
+
description: "Full recipe for one composition: the primitives it combines, the wiring order, one complete runnable example, the pitfalls (each naming the check_motion rule that catches it), and the verification steps. Read this BEFORE writing a multi-primitive feature \u2014 and read `custom-frame-effect` before building any effect the hooks do not cover.",
|
|
761
|
+
inputSchema: {
|
|
762
|
+
name: z.string().describe('Pattern name, e.g. "scrollytelling-video" or "custom-frame-effect".')
|
|
763
|
+
}
|
|
764
|
+
},
|
|
765
|
+
async ({ name }) => {
|
|
766
|
+
const pattern = findPattern(name);
|
|
767
|
+
if (!pattern) {
|
|
768
|
+
const manifest = loadHookManifest();
|
|
769
|
+
const available = manifest?.patterns?.map((p) => p.name).join(", ") ?? "none loaded";
|
|
770
|
+
return text(`No pattern named "${name}". Available: ${available}`);
|
|
771
|
+
}
|
|
772
|
+
return text(formatPatternDetail(pattern));
|
|
773
|
+
}
|
|
774
|
+
);
|
|
676
775
|
server.registerTool(
|
|
677
776
|
"list_components",
|
|
678
777
|
{
|
|
@@ -779,8 +878,8 @@ Hook discovery still works offline \u2014 try \`list_hooks\`.`
|
|
|
779
878
|
server.registerTool(
|
|
780
879
|
"search",
|
|
781
880
|
{
|
|
782
|
-
title: "Search
|
|
783
|
-
description: 'Keyword search across
|
|
881
|
+
title: "Search primitives, patterns and components",
|
|
882
|
+
description: 'Keyword search across everything: React hooks, the core primitives, multi-hook composition patterns, and installable components. Use this when you know the effect you want ("magnetic button", "scroll video", "lazy 3d scene") but not which primitive provides it. A **pattern** result is usually the one to follow for anything combining two or more primitives \u2014 it carries the wiring order and the failure modes that using each hook correctly in isolation still gets wrong.',
|
|
784
883
|
inputSchema: { query: z.string().describe("What you are trying to build.") }
|
|
785
884
|
},
|
|
786
885
|
async ({ query }) => {
|
|
@@ -794,8 +893,17 @@ Hook discovery still works offline \u2014 try \`list_hooks\`.`
|
|
|
794
893
|
const results = [];
|
|
795
894
|
const manifest = loadHookManifest();
|
|
796
895
|
for (const h of manifest?.hooks ?? []) {
|
|
797
|
-
const
|
|
798
|
-
|
|
896
|
+
const kind = h.category === "core" ? "core" : "hook";
|
|
897
|
+
const s = score(
|
|
898
|
+
[h.name, h.tagline, h.problem, h.summary, h.category, ...h.aliases ?? [], ...h.exports ?? []].join(" ")
|
|
899
|
+
);
|
|
900
|
+
if (s > 0) results.push({ score: s, line: `**${kind}** \`${h.name}\` \u2014 ${h.tagline}` });
|
|
901
|
+
}
|
|
902
|
+
for (const p of manifest?.patterns ?? []) {
|
|
903
|
+
const s = score(
|
|
904
|
+
[p.name, p.title, p.tagline, p.problem, ...p.aliases ?? [], ...p.uses].join(" ")
|
|
905
|
+
);
|
|
906
|
+
if (s > 0) results.push({ score: s, line: `**pattern** \`${p.name}\` \u2014 ${p.tagline}` });
|
|
799
907
|
}
|
|
800
908
|
try {
|
|
801
909
|
const index = await fetchRegistryIndex();
|
|
@@ -819,7 +927,7 @@ Hook discovery still works offline \u2014 try \`list_hooks\`.`
|
|
|
819
927
|
"",
|
|
820
928
|
...results.slice(0, 12).map((r) => r.line),
|
|
821
929
|
"",
|
|
822
|
-
"Then call `get_hook` or `get_component` for the full contract before writing code."
|
|
930
|
+
"Then call `get_hook`, `get_pattern`, or `get_component` for the full contract before writing code."
|
|
823
931
|
].join("\n")
|
|
824
932
|
);
|
|
825
933
|
}
|
|
@@ -848,7 +956,7 @@ async function startMcpServer() {
|
|
|
848
956
|
const server = new McpServerCtor(
|
|
849
957
|
{ name: "vectorvesper", version: VERSION },
|
|
850
958
|
{
|
|
851
|
-
instructions:
|
|
959
|
+
instructions: 'Vector Vesper\'s motion runtime and component registry.\n\nBefore writing any animation, scroll, pointer or WebGL code in this project, call `search` or `list_hooks` to check whether a Vector Vesper primitive already covers it, then `get_hook` / `get_component` for the contract. The contract states whether something needs a client boundary, whether it owns an element\'s transform, and what it conflicts with \u2014 details that do not surface as compile errors but do surface as jank.\n\nWhen the task COMBINES primitives (scrollytelling, a predictive media card, an adaptive hero, a marquee) call `list_patterns` / `get_pattern` first: a pattern carries the wiring order, one complete example, the pitfalls with the `check_motion` rule that catches each, and how to verify. When no hook or pattern covers the task, build a custom effect on the runtime: `get_pattern("custom-frame-effect")` is the canonical skeleton, and `get_hook("FrameConductor")`, `get_hook("SensorBus")` and `get_hook("damp")` are the core primitives it rides on. Never start a private requestAnimationFrame loop \u2014 subscribing to the shared conductor is always the answer.\n\nAfter writing animation, scroll, pointer or WebGL code, call `check_motion` on the file(s) you changed. It reports the same failure class the contracts warn about \u2014 an unmanaged frame loop, missing cleanup, state written every frame, a transform animated by two owners, motion with no reduced-motion guard, a browser API at module scope \u2014 checked against what you actually wrote. This is how you confirm the contract was followed; none of it shows up as a type or build error.\n\nHooks are consumed by importing `@vectorvesper/motion`. Never reimplement or inline a hook: a copy runs its own requestAnimationFrame loop instead of joining the shared frame conductor, which removes the coordination the runtime exists to provide, and nothing errors when that happens.\n\nIf asked how a hook works internally, call `get_hook` \u2014 its `How it works inside` section explains the architecture, the frame lane, and the smoothing constants directly. Prefer that over reading `node_modules/@vectorvesper/motion`: it is the same design stated at the level the question is actually about, and it stays correct as the package is bundled and rebundled.'
|
|
852
960
|
}
|
|
853
961
|
);
|
|
854
962
|
await registerTools(server);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vectorvesper",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Add WebGL, React Three Fiber & advanced motion components to your project via CLI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -44,6 +44,8 @@
|
|
|
44
44
|
"typecheck": "tsc --noEmit",
|
|
45
45
|
"test": "vitest run",
|
|
46
46
|
"test:watch": "vitest",
|
|
47
|
+
"test:mcp": "node scripts/mcp-e2e/harness.mjs --local",
|
|
48
|
+
"test:mcp:published": "node scripts/mcp-e2e/harness.mjs",
|
|
47
49
|
"postbuild": "node scripts/bundle-manifest.mjs",
|
|
48
50
|
"prepublishOnly": "npm run build"
|
|
49
51
|
},
|