@vovy-ai/go 0.2.1 → 0.3.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 +85 -8
- package/package.json +4 -3
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) {
|
|
@@ -154,6 +212,7 @@ 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,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vovy-ai/go",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Free, forever, drop-in MCP server + skill pack that teaches non-technical founders to vibe code safely. npx @vovy-ai/go install",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"vibe-coding",
|
|
@@ -43,12 +43,13 @@
|
|
|
43
43
|
],
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@vovy-ai/host-detect": "0.1.1",
|
|
46
|
-
"@vovy-ai/skills": "0.
|
|
46
|
+
"@vovy-ai/skills": "0.4.0"
|
|
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.0"
|
|
52
53
|
},
|
|
53
54
|
"scripts": {
|
|
54
55
|
"build": "tsup src/index.ts --format esm --dts --clean",
|