@xevy/cli 0.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/README.md +71 -0
- package/bin/xevy.mjs +256 -0
- package/package.json +35 -0
package/README.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# @xevy/cli
|
|
2
|
+
|
|
3
|
+
The **`xevy`** command — one step to get Xevy working in your AI agent.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npx @xevy/cli setup
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
`xevy setup` installs the **Xevy SDLC agent skills** and the **Xevy MCP server**
|
|
10
|
+
into your user-global agent config, for [Cursor, Claude Code, and 50+ other
|
|
11
|
+
agents](https://github.com/vercel-labs/skills#supported-agents).
|
|
12
|
+
|
|
13
|
+
## No API key — OAuth like any MCP
|
|
14
|
+
|
|
15
|
+
The Xevy MCP server signs in with **OAuth**, completed inside your agent the
|
|
16
|
+
first time it connects. There is no API key to find in a dashboard, paste, or
|
|
17
|
+
store on disk.
|
|
18
|
+
|
|
19
|
+
- **Cursor:** Settings → MCP → `xevy` → connect
|
|
20
|
+
- **Claude Code:** browser sign-in on the first MCP call
|
|
21
|
+
|
|
22
|
+
## What it does (and doesn't)
|
|
23
|
+
|
|
24
|
+
- ✅ Installs skills globally (`~/.cursor/skills`, `~/.claude/skills`, `~/.agents/skills`, …)
|
|
25
|
+
- ✅ Writes the MCP server to your agent's **global** config
|
|
26
|
+
- ❌ No per-repo files, no project detection, no repo linking
|
|
27
|
+
|
|
28
|
+
To link a specific repository to a Xevy project later, run the bundled
|
|
29
|
+
`xevy-setup` skill from inside your agent (it uses the MCP tools over OAuth).
|
|
30
|
+
|
|
31
|
+
## Install permanently
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm i -g @xevy/cli
|
|
35
|
+
xevy setup
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Options
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
xevy setup [options]
|
|
42
|
+
|
|
43
|
+
-a, --agent <name> Target agent (repeatable). Default: cursor, claude-code
|
|
44
|
+
--base <url> Xevy host (default: XEVY_BASE or https://xevy.ai)
|
|
45
|
+
--skills-only Install skills only (skip MCP)
|
|
46
|
+
--mcp-only Configure the OAuth MCP server only (skip skills)
|
|
47
|
+
--copy Copy skill files instead of symlinking
|
|
48
|
+
-v, --version Print the CLI version
|
|
49
|
+
-h, --help Show help
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Examples
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npx @xevy/cli setup # skills + MCP, global
|
|
56
|
+
npx @xevy/cli setup -a cursor # Cursor only
|
|
57
|
+
npx @xevy/cli setup --mcp-only # just the OAuth MCP
|
|
58
|
+
XEVY_BASE=https://xevy.vyte.dev npx @xevy/cli setup # non-default host
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## How it works
|
|
62
|
+
|
|
63
|
+
Under the hood `xevy setup` drives two well-known primitives:
|
|
64
|
+
|
|
65
|
+
- [`npx skills`](https://github.com/vercel-labs/skills) — installs the skills
|
|
66
|
+
- [`npx add-mcp`](https://github.com/neondatabase/add-mcp) — writes the MCP config
|
|
67
|
+
|
|
68
|
+
Skills are sourced from the pinned [`@xevy/skills`](https://www.npmjs.com/package/@xevy/skills)
|
|
69
|
+
dependency, so this CLI stays in step with the published skills.
|
|
70
|
+
|
|
71
|
+
Docs: <https://xevy.ai/docs/mcp>
|
package/bin/xevy.mjs
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @xevy/cli — the `xevy` command.
|
|
4
|
+
*
|
|
5
|
+
* `xevy setup` installs the Xevy SDLC agent skills and the Xevy MCP server
|
|
6
|
+
* globally, for Cursor / Claude Code / 50+ agents. The MCP server authenticates
|
|
7
|
+
* via OAuth (completed inside the agent on first connect) — there is NO API key
|
|
8
|
+
* to find, paste, or store. No repo/project detection or linking happens here.
|
|
9
|
+
*
|
|
10
|
+
* Under the hood it drives the same primitives the Xevy docs recommend:
|
|
11
|
+
* • `npx skills add <dir>` — copies/symlinks the skills into agent scopes
|
|
12
|
+
* • `npx add-mcp <url>` — writes the agent MCP config (OAuth on connect)
|
|
13
|
+
* Skills are sourced from the pinned `@xevy/skills` dependency, so this CLI
|
|
14
|
+
* stays in step with the published skills without duplicating them.
|
|
15
|
+
*
|
|
16
|
+
* Usage:
|
|
17
|
+
* npx @xevy/cli setup Install skills + MCP globally (OAuth)
|
|
18
|
+
* npx @xevy/cli setup -a cursor Only a specific agent (repeatable)
|
|
19
|
+
* npx @xevy/cli setup --mcp-only Configure the OAuth MCP server only
|
|
20
|
+
* npx @xevy/cli --version
|
|
21
|
+
*/
|
|
22
|
+
import { spawnSync } from "node:child_process";
|
|
23
|
+
import { createRequire } from "node:module";
|
|
24
|
+
import fs from "node:fs";
|
|
25
|
+
import os from "node:os";
|
|
26
|
+
import path from "node:path";
|
|
27
|
+
import { fileURLToPath } from "node:url";
|
|
28
|
+
|
|
29
|
+
const require = createRequire(import.meta.url);
|
|
30
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
31
|
+
const pkgRoot = path.resolve(here, "..");
|
|
32
|
+
|
|
33
|
+
const DEFAULT_BASE = "https://xevy.ai";
|
|
34
|
+
const DEFAULT_AGENTS = ["cursor", "claude-code"];
|
|
35
|
+
const isWindows = process.platform === "win32";
|
|
36
|
+
|
|
37
|
+
const PI_PACKAGE = "@mariozechner/pi-coding-agent";
|
|
38
|
+
const PI_EXTENSION_DIR = path.join(os.homedir(), ".pi", "agent", "extensions");
|
|
39
|
+
const MODEL_EXTENSION_FILE = "xevy-model.ts";
|
|
40
|
+
|
|
41
|
+
function readCliVersion() {
|
|
42
|
+
try {
|
|
43
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(pkgRoot, "package.json"), "utf-8"));
|
|
44
|
+
return String(pkg.version || "0.0.0");
|
|
45
|
+
} catch {
|
|
46
|
+
return "0.0.0";
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function die(msg) {
|
|
51
|
+
console.error(`✗ ${msg}`);
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function usage() {
|
|
56
|
+
console.log(`Xevy CLI — install Xevy agent skills + OAuth MCP.
|
|
57
|
+
|
|
58
|
+
xevy setup [options] Install skills + MCP globally (OAuth, no API key)
|
|
59
|
+
xevy pi [options] Install the pi agent (if missing) + the xevy-model.ts extension
|
|
60
|
+
|
|
61
|
+
Options:
|
|
62
|
+
-a, --agent <name> Target agent (repeatable). Default: ${DEFAULT_AGENTS.join(", ")}
|
|
63
|
+
--base <url> Xevy host (default: XEVY_BASE or ${DEFAULT_BASE})
|
|
64
|
+
--skills-only Install skills only (skip MCP)
|
|
65
|
+
--mcp-only Configure the OAuth MCP server only (skip skills)
|
|
66
|
+
--copy Copy skill files instead of symlinking
|
|
67
|
+
-v, --version Print the CLI version
|
|
68
|
+
-h, --help Show this help
|
|
69
|
+
|
|
70
|
+
Notes:
|
|
71
|
+
• Everything installs to your user-global scope — no per-repo files, no
|
|
72
|
+
project detection or linking.
|
|
73
|
+
• The MCP server signs in with OAuth from inside your agent on first
|
|
74
|
+
connect. There is no API key to paste.
|
|
75
|
+
|
|
76
|
+
Examples:
|
|
77
|
+
npx @xevy/cli setup
|
|
78
|
+
npx @xevy/cli setup -a cursor
|
|
79
|
+
npx @xevy/cli pi
|
|
80
|
+
XEVY_BASE=https://xevy.vyte.dev npx @xevy/cli setup`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function parseArgv(argv) {
|
|
84
|
+
const opts = {
|
|
85
|
+
command: "setup",
|
|
86
|
+
agents: [],
|
|
87
|
+
base: process.env.XEVY_BASE?.replace(/\/$/, "") || DEFAULT_BASE,
|
|
88
|
+
skillsOnly: false,
|
|
89
|
+
mcpOnly: false,
|
|
90
|
+
copy: false,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const args = [...argv];
|
|
94
|
+
if (args.length > 0 && !args[0].startsWith("-")) {
|
|
95
|
+
const cmd = args.shift();
|
|
96
|
+
if (cmd === "setup" || cmd === "pi") {
|
|
97
|
+
opts.command = cmd;
|
|
98
|
+
} else if (cmd === "help") {
|
|
99
|
+
opts.command = "help";
|
|
100
|
+
return opts;
|
|
101
|
+
} else {
|
|
102
|
+
die(`Unknown command: ${cmd}. Try \`xevy --help\`.`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
while (args.length > 0) {
|
|
107
|
+
const a = args.shift();
|
|
108
|
+
if (a === "-h" || a === "--help") return { ...opts, command: "help" };
|
|
109
|
+
if (a === "-v" || a === "--version") return { ...opts, command: "version" };
|
|
110
|
+
if (a === "-a" || a === "--agent") {
|
|
111
|
+
const v = args.shift();
|
|
112
|
+
if (!v) die("Missing value for --agent");
|
|
113
|
+
opts.agents.push(v);
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (a === "--base") {
|
|
117
|
+
const v = args.shift();
|
|
118
|
+
if (!v) die("Missing value for --base");
|
|
119
|
+
opts.base = v.replace(/\/$/, "");
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
if (a === "--skills-only") { opts.skillsOnly = true; continue; }
|
|
123
|
+
if (a === "--mcp-only") { opts.mcpOnly = true; continue; }
|
|
124
|
+
if (a === "--copy") { opts.copy = true; continue; }
|
|
125
|
+
die(`Unknown option: ${a}. Try \`xevy --help\`.`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (opts.skillsOnly && opts.mcpOnly) {
|
|
129
|
+
die("--skills-only and --mcp-only are mutually exclusive.");
|
|
130
|
+
}
|
|
131
|
+
if (opts.agents.length === 0) opts.agents = [...DEFAULT_AGENTS];
|
|
132
|
+
return opts;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function quoteArg(a) {
|
|
136
|
+
return /[\s"]/.test(a) ? `"${a.replace(/"/g, '\\"')}"` : a;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function run(cmd, args, { label } = {}) {
|
|
140
|
+
const title = label || [cmd, ...args].join(" ");
|
|
141
|
+
console.log(`→ ${title}`);
|
|
142
|
+
const command = isWindows && cmd === "npx" ? "npx.cmd" : cmd;
|
|
143
|
+
const finalArgs = isWindows ? args.map(quoteArg) : args;
|
|
144
|
+
const r = spawnSync(command, finalArgs, { stdio: "inherit", shell: isWindows, env: process.env });
|
|
145
|
+
if (r.error) die(r.error.message);
|
|
146
|
+
if (r.status !== 0) die(`Command failed (${r.status}): ${title}`);
|
|
147
|
+
return r;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Resolve the on-disk root of the pinned @xevy/skills dependency. */
|
|
151
|
+
function resolveSkillsRoot() {
|
|
152
|
+
try {
|
|
153
|
+
return path.dirname(require.resolve("@xevy/skills/package.json"));
|
|
154
|
+
} catch {
|
|
155
|
+
die("Could not locate the bundled @xevy/skills package. Reinstall @xevy/cli and try again.");
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function installSkills(opts) {
|
|
160
|
+
const skillsRoot = resolveSkillsRoot();
|
|
161
|
+
const args = ["--yes", "skills", "add", skillsRoot, "-g", "-y", "-s", "*"];
|
|
162
|
+
if (opts.copy) args.push("--copy");
|
|
163
|
+
for (const a of opts.agents) args.push("-a", a);
|
|
164
|
+
run("npx", args, { label: "npx skills add (Xevy skills, global)" });
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function installMcp(opts) {
|
|
168
|
+
const mcpUrl = `${opts.base}/mcp`;
|
|
169
|
+
const args = ["--yes", "add-mcp", mcpUrl, "-n", "xevy", "-g", "-y"];
|
|
170
|
+
for (const a of opts.agents) args.push("-a", a);
|
|
171
|
+
run("npx", args, { label: `npx add-mcp ${mcpUrl} (OAuth, global)` });
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function setup(opts) {
|
|
175
|
+
console.log("Setting up Xevy (global, OAuth — no API key)\n");
|
|
176
|
+
|
|
177
|
+
if (!opts.mcpOnly) installSkills(opts);
|
|
178
|
+
if (!opts.skillsOnly) installMcp(opts);
|
|
179
|
+
|
|
180
|
+
console.log("\n✓ Xevy setup complete.");
|
|
181
|
+
if (!opts.skillsOnly) {
|
|
182
|
+
console.log(" • Complete OAuth in your agent on first connect:");
|
|
183
|
+
console.log(" Cursor: Settings → MCP → xevy → connect");
|
|
184
|
+
console.log(" Claude Code: browser sign-in on first MCP call");
|
|
185
|
+
}
|
|
186
|
+
if (opts.base !== DEFAULT_BASE) {
|
|
187
|
+
console.log(` • Host: ${opts.base} (set XEVY_BASE in your agent env too, then restart).`);
|
|
188
|
+
}
|
|
189
|
+
console.log(` • Docs: ${opts.base}/docs/mcp`);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function hasPi() {
|
|
193
|
+
const r = spawnSync(isWindows ? "pi.cmd" : "pi", ["--version"], { stdio: "ignore", shell: isWindows });
|
|
194
|
+
return !r.error && r.status === 0;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function ensurePi() {
|
|
198
|
+
if (hasPi()) {
|
|
199
|
+
console.log("→ pi agent already installed");
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
console.log(`→ pi agent not found — installing ${PI_PACKAGE} globally…`);
|
|
203
|
+
run("npm", ["install", "-g", PI_PACKAGE], { label: `npm install -g ${PI_PACKAGE}` });
|
|
204
|
+
if (!hasPi()) {
|
|
205
|
+
die("pi is still not on PATH after install. Ensure your npm global bin dir is on PATH, then re-run `xevy pi`.");
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async function installModelExtension(opts) {
|
|
210
|
+
const url = `${opts.base}/${MODEL_EXTENSION_FILE}`;
|
|
211
|
+
console.log(`→ Downloading model extension ${url}`);
|
|
212
|
+
|
|
213
|
+
let source;
|
|
214
|
+
try {
|
|
215
|
+
const res = await fetch(url);
|
|
216
|
+
if (!res.ok) die(`Failed to download ${url} (HTTP ${res.status}).`);
|
|
217
|
+
source = await res.text();
|
|
218
|
+
} catch (error) {
|
|
219
|
+
die(`Could not fetch ${url}: ${error instanceof Error ? error.message : String(error)}`);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Guard against a wrong --base returning the SPA HTML instead of the extension.
|
|
223
|
+
if (!source.includes("xevyModelExtension") || !source.includes("registerCommand")) {
|
|
224
|
+
die(`Downloaded ${url} does not look like the xevy-model extension (wrong --base?).`);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
fs.mkdirSync(PI_EXTENSION_DIR, { recursive: true });
|
|
228
|
+
const dest = path.join(PI_EXTENSION_DIR, MODEL_EXTENSION_FILE);
|
|
229
|
+
fs.writeFileSync(dest, source, "utf-8");
|
|
230
|
+
console.log(`✓ Installed ${dest}`);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async function piSetup(opts) {
|
|
234
|
+
console.log("Setting up the pi agent + Xevy model extension\n");
|
|
235
|
+
|
|
236
|
+
ensurePi();
|
|
237
|
+
await installModelExtension(opts);
|
|
238
|
+
|
|
239
|
+
console.log("\n✓ pi + xevy-model.ts ready.");
|
|
240
|
+
console.log(" • In pi, run /agent-model to set or clear a per-agent model.");
|
|
241
|
+
console.log(" • If pi is already running, use /reload to load the extension.");
|
|
242
|
+
if (opts.base !== DEFAULT_BASE) {
|
|
243
|
+
console.log(` • Source host: ${opts.base}`);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
async function main() {
|
|
248
|
+
const opts = parseArgv(process.argv.slice(2));
|
|
249
|
+
|
|
250
|
+
if (opts.command === "help") return usage();
|
|
251
|
+
if (opts.command === "version") return console.log(readCliVersion());
|
|
252
|
+
if (opts.command === "setup") return setup(opts);
|
|
253
|
+
if (opts.command === "pi") return piSetup(opts);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
main().catch((error) => die(error instanceof Error ? error.message : String(error)));
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@xevy/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Xevy CLI — one command (`xevy setup`) installs the Xevy SDLC agent skills and the OAuth MCP server globally for Cursor, Claude Code, and 50+ agents. No API key required.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"xevy",
|
|
8
|
+
"cli",
|
|
9
|
+
"setup",
|
|
10
|
+
"mcp",
|
|
11
|
+
"oauth",
|
|
12
|
+
"agent-skills",
|
|
13
|
+
"cursor",
|
|
14
|
+
"claude-code",
|
|
15
|
+
"sdlc"
|
|
16
|
+
],
|
|
17
|
+
"homepage": "https://xevy.ai/docs/mcp",
|
|
18
|
+
"license": "UNLICENSED",
|
|
19
|
+
"bin": {
|
|
20
|
+
"xevy": "bin/xevy.mjs"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"bin",
|
|
24
|
+
"README.md"
|
|
25
|
+
],
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=18"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@xevy/skills": "^0.1.18"
|
|
31
|
+
},
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public"
|
|
34
|
+
}
|
|
35
|
+
}
|