lace-mcp 0.0.2-alpha.4 → 0.0.2-alpha.6
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/cli.js +71 -54
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -51,7 +51,7 @@ function getClaudeDesktopConfigPath() {
|
|
|
51
51
|
}
|
|
52
52
|
function getEditorConfigPath(target) {
|
|
53
53
|
const home = homedir();
|
|
54
|
-
if (target === "claude") return join(home, ".claude
|
|
54
|
+
if (target === "claude") return join(home, ".claude.json");
|
|
55
55
|
if (target === "claude-desktop") return getClaudeDesktopConfigPath();
|
|
56
56
|
if (target === "cursor") return join(home, ".cursor", "mcp.json");
|
|
57
57
|
return join(home, ".codex", "config.toml");
|
|
@@ -256,17 +256,37 @@ import { execSync as execSync2 } from "node:child_process";
|
|
|
256
256
|
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
257
257
|
import { homedir as homedir2 } from "node:os";
|
|
258
258
|
import { join as join3, resolve } from "node:path";
|
|
259
|
+
import { createInterface } from "node:readline";
|
|
259
260
|
function parseFlags(args) {
|
|
260
261
|
const flags = {};
|
|
261
262
|
for (let i = 0; i < args.length; i++) {
|
|
262
263
|
if (args[i] === "--token" && args[i + 1]) flags.token = args[++i];
|
|
263
264
|
else if (args[i] === "--org" && args[i + 1]) flags.org = args[++i];
|
|
264
265
|
else if (args[i] === "--api-base" && args[i + 1]) flags.apiBase = args[++i];
|
|
265
|
-
|
|
266
|
-
|
|
266
|
+
else if (args[i] === "--scope" && args[i + 1]) flags.scope = args[++i];
|
|
267
|
+
}
|
|
268
|
+
const scope = SCOPES.includes(flags.scope) ? flags.scope : void 0;
|
|
269
|
+
return { ...flags, scope };
|
|
270
|
+
}
|
|
271
|
+
function promptScope(target) {
|
|
272
|
+
const available = target === "claude" ? SCOPES : ["user", "project"];
|
|
273
|
+
return new Promise((promptResolve) => {
|
|
274
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
275
|
+
console.log("\n Where should Lace be installed?\n");
|
|
276
|
+
for (let i = 0; i < available.length; i++) {
|
|
277
|
+
console.log(` ${i + 1}. ${SCOPE_LABELS[available[i]]}`);
|
|
278
|
+
}
|
|
279
|
+
rl.question("\n > ", (answer) => {
|
|
280
|
+
rl.close();
|
|
281
|
+
const idx = parseInt(answer.trim(), 10) - 1;
|
|
282
|
+
const scope = available[idx] ?? available[0];
|
|
283
|
+
if (!available[idx]) console.log(` Defaulting to ${scope}`);
|
|
284
|
+
console.log("");
|
|
285
|
+
promptResolve(scope);
|
|
286
|
+
});
|
|
287
|
+
});
|
|
267
288
|
}
|
|
268
|
-
async function resolveCredentials(
|
|
269
|
-
const flags = parseFlags(args);
|
|
289
|
+
async function resolveCredentials(flags) {
|
|
270
290
|
if (flags.token && flags.org) {
|
|
271
291
|
return { apiBase: flags.apiBase ?? DEFAULT_API_BASE, token: flags.token, orgId: flags.org };
|
|
272
292
|
}
|
|
@@ -338,64 +358,48 @@ alwaysApply: false
|
|
|
338
358
|
|
|
339
359
|
${body}`;
|
|
340
360
|
}
|
|
341
|
-
function
|
|
361
|
+
function installSkillFile(dir, filename, label, transform2) {
|
|
342
362
|
const content = loadSkillContent();
|
|
343
363
|
if (!content) return;
|
|
344
|
-
const
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
const existing = readFileSync2(skillPath, "utf8");
|
|
364
|
+
const filePath = join3(dir, filename);
|
|
365
|
+
if (existsSync2(filePath)) {
|
|
366
|
+
const existing = readFileSync2(filePath, "utf8");
|
|
348
367
|
if (extractSkillVersion(existing) >= SKILL_VERSION) {
|
|
349
|
-
console.log(
|
|
368
|
+
console.log(` \u2713 ${label} already up to date`);
|
|
350
369
|
return;
|
|
351
370
|
}
|
|
352
371
|
}
|
|
353
|
-
mkdirSync2(
|
|
354
|
-
writeFileSync2(
|
|
355
|
-
console.log(` \u2713
|
|
372
|
+
mkdirSync2(dir, { recursive: true });
|
|
373
|
+
writeFileSync2(filePath, injectVersion(transform2(content)));
|
|
374
|
+
console.log(` \u2713 ${label} written to ${filePath}`);
|
|
375
|
+
}
|
|
376
|
+
function installClaudeSkill() {
|
|
377
|
+
installSkillFile(join3(homedir2(), ".claude", "skills", "lace"), "SKILL.md", "/lace skill", (c) => c.trimStart());
|
|
356
378
|
}
|
|
357
379
|
function installCursorRule() {
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
if (extractSkillVersion(existing) >= SKILL_VERSION) {
|
|
365
|
-
console.log(" \u2713 Cursor rule already up to date");
|
|
366
|
-
return;
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
mkdirSync2(rulesDir, { recursive: true });
|
|
370
|
-
writeFileSync2(rulePath, injectVersion(buildCursorRule(extractSkillBody(content))));
|
|
371
|
-
console.log(` \u2713 Cursor rule written to ${rulePath}`);
|
|
380
|
+
installSkillFile(
|
|
381
|
+
join3(homedir2(), ".cursor", "rules"),
|
|
382
|
+
"lace.mdc",
|
|
383
|
+
"Cursor rule",
|
|
384
|
+
(c) => buildCursorRule(extractSkillBody(c))
|
|
385
|
+
);
|
|
372
386
|
}
|
|
373
387
|
function installCodexSkill() {
|
|
374
|
-
|
|
375
|
-
if (!content) return;
|
|
376
|
-
const skillDir = join3(homedir2(), ".agents", "skills", "lace");
|
|
377
|
-
const skillPath = join3(skillDir, "SKILL.md");
|
|
378
|
-
if (existsSync2(skillPath)) {
|
|
379
|
-
const existing = readFileSync2(skillPath, "utf8");
|
|
380
|
-
if (extractSkillVersion(existing) >= SKILL_VERSION) {
|
|
381
|
-
console.log(" \u2713 Codex skill already up to date");
|
|
382
|
-
return;
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
mkdirSync2(skillDir, { recursive: true });
|
|
386
|
-
writeFileSync2(skillPath, injectVersion(extractSkillBody(content)));
|
|
387
|
-
console.log(` \u2713 Codex skill written to ${skillPath}`);
|
|
388
|
+
installSkillFile(join3(homedir2(), ".agents", "skills", "lace"), "SKILL.md", "Codex skill", extractSkillBody);
|
|
388
389
|
}
|
|
389
390
|
function mcpArgs(editor) {
|
|
390
391
|
return ["-y", `${PACKAGE_NAME}@latest`, "mcp", "--editor", editor];
|
|
391
392
|
}
|
|
392
|
-
function installClaude(env) {
|
|
393
|
+
function installClaude(env, scope = "user") {
|
|
393
394
|
try {
|
|
394
395
|
const envFlags = Object.entries(env).map(([key, value]) => `-e ${key}=${value}`).join(" ");
|
|
395
|
-
execSync2(
|
|
396
|
-
stdio
|
|
397
|
-
|
|
398
|
-
|
|
396
|
+
execSync2(
|
|
397
|
+
`claude mcp add lace --transport stdio --scope ${scope} ${envFlags} -- npx ${mcpArgs("claude").join(" ")}`,
|
|
398
|
+
{
|
|
399
|
+
stdio: "inherit"
|
|
400
|
+
}
|
|
401
|
+
);
|
|
402
|
+
console.log(` \u2713 MCP server registered via claude CLI (scope: ${scope})`);
|
|
399
403
|
} catch {
|
|
400
404
|
const configPath = getEditorConfigPath("claude");
|
|
401
405
|
writeJsonMcpEntry(configPath, { command: "npx", args: mcpArgs("claude"), env });
|
|
@@ -408,8 +412,12 @@ function installClaudeDesktop(env) {
|
|
|
408
412
|
writeJsonMcpEntry(configPath, { command: npx, args: mcpArgs("claude-desktop"), env });
|
|
409
413
|
installClaudeSkill();
|
|
410
414
|
}
|
|
411
|
-
function
|
|
412
|
-
|
|
415
|
+
function getCursorConfigPath(scope) {
|
|
416
|
+
if (scope === "project") return join3(process.cwd(), ".cursor", "mcp.json");
|
|
417
|
+
return getEditorConfigPath("cursor");
|
|
418
|
+
}
|
|
419
|
+
function installCursor(env, scope = "user") {
|
|
420
|
+
const configPath = getCursorConfigPath(scope);
|
|
413
421
|
writeJsonMcpEntry(configPath, { command: "npx", args: mcpArgs("cursor"), env });
|
|
414
422
|
installCursorRule();
|
|
415
423
|
}
|
|
@@ -435,20 +443,23 @@ async function main() {
|
|
|
435
443
|
const args = process.argv.slice(2);
|
|
436
444
|
const target = args[0] === "install" ? args[1] : args[0];
|
|
437
445
|
if (!target || !TARGETS.includes(target)) {
|
|
438
|
-
console.error(`Usage: npx ${PACKAGE_NAME} install <${TARGETS.join("|")}
|
|
446
|
+
console.error(`Usage: npx ${PACKAGE_NAME} install <${TARGETS.join("|")}> [--scope user|project|local]`);
|
|
439
447
|
process.exit(1);
|
|
440
448
|
}
|
|
449
|
+
const flags = parseFlags(args);
|
|
441
450
|
console.log(`
|
|
442
451
|
Installing Lace MCP for ${target}...`);
|
|
443
|
-
const credentials = await resolveCredentials(
|
|
452
|
+
const credentials = await resolveCredentials(flags);
|
|
444
453
|
const env = credentialsToEnv(credentials);
|
|
445
|
-
|
|
454
|
+
const scopeTargets = ["claude", "cursor"];
|
|
455
|
+
const scope = flags.scope ?? (scopeTargets.includes(target) ? await promptScope(target) : "user");
|
|
456
|
+
if (target === "claude") installClaude(env, scope);
|
|
446
457
|
else if (target === "claude-desktop") installClaudeDesktop(env);
|
|
447
|
-
else if (target === "cursor") installCursor(env);
|
|
458
|
+
else if (target === "cursor") installCursor(env, scope);
|
|
448
459
|
else installCodex(env);
|
|
449
460
|
console.log('\nDone. Start a new session and say "implement the Lace decision" or type /lace.\n');
|
|
450
461
|
}
|
|
451
|
-
var TARGETS, PACKAGE_NAME, SKILL_VERSION;
|
|
462
|
+
var TARGETS, PACKAGE_NAME, SCOPES, SCOPE_LABELS, SKILL_VERSION;
|
|
452
463
|
var init_install = __esm({
|
|
453
464
|
"src/install.ts"() {
|
|
454
465
|
"use strict";
|
|
@@ -457,6 +468,12 @@ var init_install = __esm({
|
|
|
457
468
|
init_paths();
|
|
458
469
|
TARGETS = ["claude", "claude-desktop", "cursor", "codex"];
|
|
459
470
|
PACKAGE_NAME = "lace-mcp";
|
|
471
|
+
SCOPES = ["user", "project", "local"];
|
|
472
|
+
SCOPE_LABELS = {
|
|
473
|
+
user: "User \u2014 available in all projects",
|
|
474
|
+
project: "Project \u2014 this project only (shared via .mcp.json)",
|
|
475
|
+
local: "Local \u2014 this machine only (not shared)"
|
|
476
|
+
};
|
|
460
477
|
SKILL_VERSION = 1;
|
|
461
478
|
}
|
|
462
479
|
});
|