@vovy-ai/go 0.2.1 → 0.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/README.md +9 -5
- package/dist/index.js +86 -9
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @vovy-ai/go
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The `vovy` CLI — one command drops project-aware skills, scope-aware code search, and git-committed project memory into the AI coding tool you already use. Free forever.
|
|
4
4
|
|
|
5
5
|
```
|
|
6
6
|
npx @vovy-ai/go install
|
|
@@ -11,24 +11,28 @@ That's it. It detects which AI coding tool you have installed — [Claude Code](
|
|
|
11
11
|
```
|
|
12
12
|
npx @vovy-ai/go doctor # check everything is installed correctly
|
|
13
13
|
npx @vovy-ai/go uninstall # remove everything Vovy wrote, cleanly
|
|
14
|
+
npx @vovy-ai/go statusline # one-line badge for your tool's status bar
|
|
14
15
|
```
|
|
15
16
|
|
|
16
17
|
Installed globally (`npm i -g @vovy-ai/go`), the command is just `vovy`.
|
|
17
18
|
|
|
18
|
-
`npx @vovy-ai/go doctor` also reports a deterministic "always-on token footprint" — every installed skill file plus every registered MCP tool definition, the tokens a session pays whether or not any of it ever fires.
|
|
19
|
+
`npx @vovy-ai/go doctor` also reports a deterministic "always-on token footprint" — every installed skill file plus every registered MCP tool definition, the tokens a session pays whether or not any of it ever fires — and tells you which Context Engine backend your project gets: `typescript` (scope-aware, resolved through your project's own TypeScript) or `tree-sitter` (name-matching fallback), with the one-line upgrade if you're on the fallback.
|
|
19
20
|
|
|
20
21
|
It's MIT-licensed and runs entirely on your machine — no account, no API key, nothing phoning home.
|
|
21
22
|
|
|
22
23
|
## What it installs
|
|
23
24
|
|
|
24
|
-
|
|
25
|
+
Five skills plus a local MCP server that give AI coding assistants deterministic project context, durable memory, and safety rails:
|
|
25
26
|
|
|
26
27
|
| Skill | What it does |
|
|
27
28
|
|---|---|
|
|
28
|
-
| **Prompt Rescoper** | Rewrites vague, oversized requests into a small, reviewable spec before any code is written. |
|
|
29
|
+
| **Prompt Rescoper** | Rewrites vague, oversized requests into a small, reviewable spec — including how the change will be verified and what imperfections are acceptable — before any code is written. |
|
|
29
30
|
| **Project Skill Drafter** | Analyzes your actual project and drafts a project-specific skill so future requests already know your stack. |
|
|
30
31
|
| **Founder Explainer** | Explains destructive/high-stakes actions in plain English before they happen, and flags common vibe-coding security mistakes. |
|
|
31
|
-
| **Context Scoper** |
|
|
32
|
+
| **Context Scoper** | Finds the exact symbol, method, or file before reading whole files — via your project's own TypeScript when available (scope-aware, so two same-named functions don't get confused), tree-sitter otherwise. Includes `impact`: "what breaks if I change this", walked transitively. |
|
|
33
|
+
| **Memory Keeper** | Records decisions (with what was rejected and why), mistakes (with how to avoid repeating them), and constraints (with the why) into `.vovy/memory/` — plain markdown, committed to git, so rationale survives across sessions, machines, teammates, and AI tools. |
|
|
34
|
+
|
|
35
|
+
With `--scope project`, skill descriptions are tailored to your detected stack (a Next.js + TypeScript project gets descriptions that say so), which helps them trigger at the right moments at zero extra token cost.
|
|
32
36
|
|
|
33
37
|
Full docs, architecture, and source: **[github.com/Vovy-AI/vovy-cli](https://github.com/Vovy-AI/vovy-cli)**
|
|
34
38
|
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,8 @@ import { parseArgs } from "util";
|
|
|
7
7
|
import { ADAPTERS as ADAPTERS2 } from "@vovy-ai/host-detect";
|
|
8
8
|
|
|
9
9
|
// src/commands/doctor.ts
|
|
10
|
+
import { createRequire } from "module";
|
|
11
|
+
import { join } from "path";
|
|
10
12
|
import { getAllSkills as getAllSkills2 } from "@vovy-ai/skills";
|
|
11
13
|
|
|
12
14
|
// src/commands/install.ts
|
|
@@ -14,7 +16,7 @@ import {
|
|
|
14
16
|
writeMcpConfig,
|
|
15
17
|
writeSkillFile
|
|
16
18
|
} from "@vovy-ai/host-detect";
|
|
17
|
-
import { getAllSkills } from "@vovy-ai/skills";
|
|
19
|
+
import { detectProjectContext, getAllSkills } from "@vovy-ai/skills";
|
|
18
20
|
|
|
19
21
|
// src/targets.ts
|
|
20
22
|
import { ADAPTERS, getAdapter } from "@vovy-ai/host-detect";
|
|
@@ -28,7 +30,7 @@ var VOVY_MCP_ENTRY = { id: "vovy", command: "npx", args: ["-y", "@vovy-ai/mcp-se
|
|
|
28
30
|
function runInstall(opts) {
|
|
29
31
|
const scope = opts.scope ?? "user";
|
|
30
32
|
const targets = resolveTargets(opts.env, opts.hosts);
|
|
31
|
-
const skills = getAllSkills();
|
|
33
|
+
const skills = getAllSkills(scope === "project" ? detectProjectContext(opts.env.cwd) : void 0);
|
|
32
34
|
return targets.map((adapter) => {
|
|
33
35
|
const skillResults = skills.map((skill) => ({
|
|
34
36
|
skillId: skill.id,
|
|
@@ -62,7 +64,12 @@ var MCP_TOOL_METADATA = [
|
|
|
62
64
|
{
|
|
63
65
|
name: "search_codebase",
|
|
64
66
|
title: "Search Codebase",
|
|
65
|
-
description: `Deterministic, non-LLM symbol search over a JS/TS/JSX/TSX project
|
|
67
|
+
description: `Deterministic, non-LLM symbol search over a JS/TS/JSX/TSX project (no embeddings, no network access). Use this BEFORE reading whole files to answer a 'where is X handled' / 'what calls Y' / 'is it safe to change Z' question \u2014 it finds the exact symbol, method, or file first, so you read one function instead of one whole file. Covers class methods, interface members, and object-literal methods, not just top-level declarations. Actions: "overview" (declarations and their members in one file, needs filePath), "find_symbol" (declaration sites of a name across the project, needs query), "find_references" (usage sites of a name, excluding declarations, needs query), "impact" (transitive blast radius: who references this symbol, who references THOSE callers, and so on, depth-tagged \u2014 the 'what breaks if I change this' answer; needs query, optional maxDepth default 3), "pattern" (plain regex/text search fallback for non-code content, needs query). Every response names the \`backend\` that answered: "typescript" means results were resolved through the real type checker and each reference carries the declaration it resolves to; "tree-sitter" means results are identifier-name matches (never inside a string or comment, unlike grep) that cannot distinguish two same-named symbols in different scopes \u2014 treat those as candidates, not proof, and treat "impact" tails as over-approximate.`
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: "project_memory",
|
|
71
|
+
title: "Project Memory",
|
|
72
|
+
description: `Records and recalls this project's decisions, mistakes, and constraints as plain markdown under .vovy/memory/, committed to git \u2014 so rationale survives across sessions, tools, and teammates with no server or account. Actions: "record" (save an entry; needs type: "decision" | "mistake" | "constraint", title, body \u2014 for decisions include what was REJECTED and why, for mistakes include why it happened and how to avoid it, for constraints include the why behind the rule), "recall" (deterministic keyword search over saved entries; needs query \u2014 use BEFORE starting non-trivial work and before revisiting any past choice), "list" (every entry's title and type, no bodies). Never pass secrets, API keys, or passwords in a body \u2014 entries are committed to git, and record refuses content that looks like a credential.`
|
|
66
73
|
}
|
|
67
74
|
];
|
|
68
75
|
function estimateTokens(text) {
|
|
@@ -83,6 +90,26 @@ function computeTokenFootprint() {
|
|
|
83
90
|
totalEstTokens: skillsEstTokens + toolsEstTokens
|
|
84
91
|
};
|
|
85
92
|
}
|
|
93
|
+
function probeContextBackend(cwd) {
|
|
94
|
+
if (process.env.VOVY_CONTEXT_BACKEND === "tree-sitter") {
|
|
95
|
+
return {
|
|
96
|
+
backend: "tree-sitter",
|
|
97
|
+
reason: "forced by VOVY_CONTEXT_BACKEND \u2014 name-matching only, unset to restore scope-aware search"
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
createRequire(join(cwd, "package.json")).resolve("typescript");
|
|
102
|
+
return {
|
|
103
|
+
backend: "typescript",
|
|
104
|
+
reason: "this project's own TypeScript \u2014 scope-aware, references name the declaration they resolve to"
|
|
105
|
+
};
|
|
106
|
+
} catch {
|
|
107
|
+
return {
|
|
108
|
+
backend: "tree-sitter",
|
|
109
|
+
reason: "no typescript resolvable from this project \u2014 name matches only; `npm i -D typescript` upgrades search_codebase to scope-aware results"
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
86
113
|
function runDoctor(env, hosts, scope) {
|
|
87
114
|
const dryRunResults = runInstall({ env, hosts, scope, dryRun: true });
|
|
88
115
|
const totalSkillCount = getAllSkills2().length;
|
|
@@ -103,11 +130,42 @@ function runDoctor(env, hosts, scope) {
|
|
|
103
130
|
healthy: entries.length === totalSkillCount && entries.every((e) => e.status === "ok") && (mcp === null || mcp.status === "ok")
|
|
104
131
|
};
|
|
105
132
|
});
|
|
106
|
-
return {
|
|
133
|
+
return {
|
|
134
|
+
reports,
|
|
135
|
+
tokenFootprint: computeTokenFootprint(),
|
|
136
|
+
contextBackend: probeContextBackend(env.cwd)
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// src/commands/statusline.ts
|
|
141
|
+
import { existsSync, readdirSync } from "fs";
|
|
142
|
+
import { join as join2 } from "path";
|
|
143
|
+
function buildStatusline(env) {
|
|
144
|
+
const { reports, contextBackend } = runDoctor(env);
|
|
145
|
+
const healthy = reports.filter((r) => r.healthy).length;
|
|
146
|
+
const skills = reports.length === 0 ? "not installed" : `skills ${healthy}/${reports.length} host${reports.length === 1 ? "" : "s"} ok`;
|
|
147
|
+
const parts = [`[vovy] ${skills}`, `engine:${contextBackend.backend}`];
|
|
148
|
+
const memoryCount = countMemoryEntries(env.cwd);
|
|
149
|
+
if (memoryCount > 0) parts.push(`memory:${memoryCount}`);
|
|
150
|
+
return parts.join(" \xB7 ");
|
|
151
|
+
}
|
|
152
|
+
function countMemoryEntries(cwd) {
|
|
153
|
+
const memoryDir = join2(cwd, ".vovy", "memory");
|
|
154
|
+
if (!existsSync(memoryDir)) return 0;
|
|
155
|
+
let count = 0;
|
|
156
|
+
for (const typeDir of ["decisions", "mistakes", "constraints"]) {
|
|
157
|
+
const dir = join2(memoryDir, typeDir);
|
|
158
|
+
if (!existsSync(dir)) continue;
|
|
159
|
+
try {
|
|
160
|
+
count += readdirSync(dir).filter((f) => f.endsWith(".md")).length;
|
|
161
|
+
} catch {
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return count;
|
|
107
165
|
}
|
|
108
166
|
|
|
109
167
|
// src/commands/uninstall.ts
|
|
110
|
-
import { existsSync, readFileSync, rmSync, writeFileSync } from "fs";
|
|
168
|
+
import { existsSync as existsSync2, readFileSync, rmSync, writeFileSync } from "fs";
|
|
111
169
|
import {
|
|
112
170
|
removeCodexMcpEntry,
|
|
113
171
|
removeJsonMcpEntry
|
|
@@ -122,14 +180,14 @@ function runUninstall(opts) {
|
|
|
122
180
|
const removedSkillPaths = [];
|
|
123
181
|
for (const skill of SKILL_MANIFEST) {
|
|
124
182
|
const path = adapter.skillFilePath(opts.env, scope, skill.id);
|
|
125
|
-
if (
|
|
183
|
+
if (existsSync2(path)) {
|
|
126
184
|
removedSkillPaths.push(path);
|
|
127
185
|
if (!dryRun) rmSync(path, { force: true });
|
|
128
186
|
}
|
|
129
187
|
}
|
|
130
188
|
let removedMcpEntry = null;
|
|
131
189
|
const mcpPath = adapter.mcpConfigPath(opts.env, scope);
|
|
132
|
-
if (mcpPath &&
|
|
190
|
+
if (mcpPath && existsSync2(mcpPath)) {
|
|
133
191
|
const existing = readFileSync(mcpPath, "utf8");
|
|
134
192
|
const next = adapter.id === "codex" ? removeCodexMcpEntry(existing, VOVY_ID) : removeJsonMcpEntry(existing, VOVY_ID);
|
|
135
193
|
if (next !== null) {
|
|
@@ -148,12 +206,13 @@ function realEnv() {
|
|
|
148
206
|
}
|
|
149
207
|
|
|
150
208
|
// src/index.ts
|
|
151
|
-
var HELP = `Vovy \u2014
|
|
209
|
+
var HELP = `Vovy \u2014 drop-in skills for vibe coding safely with the AI tool you already use. Run via \`npx @vovy-ai/go\` (or \`vovy\` if installed globally).
|
|
152
210
|
|
|
153
211
|
Usage:
|
|
154
212
|
npx @vovy-ai/go install [options] Write Vovy's skills into detected (or specified) host tools
|
|
155
213
|
npx @vovy-ai/go doctor [options] Check whether Vovy is correctly installed, without changing anything
|
|
156
214
|
npx @vovy-ai/go uninstall [options] Remove everything Vovy's installer wrote
|
|
215
|
+
npx @vovy-ai/go statusline One-line status for a host's status bar (engine, skills, memory)
|
|
157
216
|
|
|
158
217
|
Options:
|
|
159
218
|
--host <ids> Comma-separated host ids to target instead of auto-detecting.
|
|
@@ -220,12 +279,24 @@ ${adapter.label}:`);
|
|
|
220
279
|
console.log(
|
|
221
280
|
flags.dryRun ? "\nDry run only \u2014 nothing was written. Re-run without --dry-run to apply." : "\nDone. Vovy's skills are now available in your tool(s) above."
|
|
222
281
|
);
|
|
282
|
+
if (!flags.dryRun && reports.some((r) => r.adapter.id === "claude-code")) {
|
|
283
|
+
console.log(
|
|
284
|
+
`
|
|
285
|
+
Optional: a Vovy status-bar badge for Claude Code (shows engine + memory at a glance).
|
|
286
|
+
Add to ~/.claude/settings.json:
|
|
287
|
+
"statusLine": { "type": "command", "command": "npx -y @vovy-ai/go statusline" }
|
|
288
|
+
(Faster variant: npm i -g @vovy-ai/go, then use "vovy statusline" as the command.)`
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function cmdStatusline() {
|
|
293
|
+
console.log(buildStatusline(realEnv()));
|
|
223
294
|
}
|
|
224
295
|
function cmdDoctor(argv) {
|
|
225
296
|
const flags = parseCommonFlags(argv);
|
|
226
297
|
if (flags.help) return console.log(HELP);
|
|
227
298
|
const env = realEnv();
|
|
228
|
-
const { reports, tokenFootprint } = runDoctor(env, flags.hosts, flags.scope);
|
|
299
|
+
const { reports, tokenFootprint, contextBackend } = runDoctor(env, flags.hosts, flags.scope);
|
|
229
300
|
if (reports.length === 0) {
|
|
230
301
|
console.log("No supported host tools detected on this machine \u2014 nothing to check.");
|
|
231
302
|
return;
|
|
@@ -244,6 +315,10 @@ ${adapter.label}: ${healthy ? "OK" : "needs `npx @vovy-ai/go install`"}`);
|
|
|
244
315
|
}
|
|
245
316
|
console.log(
|
|
246
317
|
`
|
|
318
|
+
search_codebase backend for this directory: ${contextBackend.backend} (${contextBackend.reason})`
|
|
319
|
+
);
|
|
320
|
+
console.log(
|
|
321
|
+
`
|
|
247
322
|
Estimated always-on token footprint: ~${tokenFootprint.totalEstTokens} tokens (${tokenFootprint.skillCount} skill files ~${tokenFootprint.skillsEstTokens}, ${tokenFootprint.toolCount} MCP tool definitions ~${tokenFootprint.toolsEstTokens}) \u2014 what every session pays whether or not a skill fires. chars/4 estimate, not an exact tokenizer count.`
|
|
248
323
|
);
|
|
249
324
|
process.exitCode = allHealthy ? 0 : 1;
|
|
@@ -284,6 +359,8 @@ async function main() {
|
|
|
284
359
|
return cmdDoctor(rest);
|
|
285
360
|
case "uninstall":
|
|
286
361
|
return cmdUninstall(rest);
|
|
362
|
+
case "statusline":
|
|
363
|
+
return cmdStatusline();
|
|
287
364
|
case "--help":
|
|
288
365
|
case "-h":
|
|
289
366
|
case void 0:
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vovy-ai/go",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"description": "Drop-in MCP server + skill pack that teaches non-technical founders to vibe code safely — free forever. npx @vovy-ai/go install",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"vibe-coding",
|
|
7
7
|
"ai-coding-assistant",
|
|
@@ -42,13 +42,14 @@
|
|
|
42
42
|
"dist"
|
|
43
43
|
],
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@vovy-ai/host-detect": "0.1.
|
|
46
|
-
"@vovy-ai/skills": "0.
|
|
45
|
+
"@vovy-ai/host-detect": "0.1.2",
|
|
46
|
+
"@vovy-ai/skills": "0.4.1"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"tsup": "^8.3.5",
|
|
50
50
|
"typescript": "^5.7.2",
|
|
51
|
-
"vitest": "^2.1.8"
|
|
51
|
+
"vitest": "^2.1.8",
|
|
52
|
+
"@vovy-ai/mcp-server": "0.3.1"
|
|
52
53
|
},
|
|
53
54
|
"scripts": {
|
|
54
55
|
"build": "tsup src/index.ts --format esm --dts --clean",
|