lace-mcp 0.0.2-alpha.5 → 0.0.2-alpha.7
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 +63 -8
- 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");
|
|
@@ -77,6 +77,7 @@ import { execSync } from "node:child_process";
|
|
|
77
77
|
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
78
78
|
import { platform as platform2 } from "node:os";
|
|
79
79
|
import { join as join2 } from "node:path";
|
|
80
|
+
import { createInterface } from "node:readline";
|
|
80
81
|
function getAuthFilePath() {
|
|
81
82
|
return join2(LACE_DATA, AUTH_FILE_NAME);
|
|
82
83
|
}
|
|
@@ -158,6 +159,33 @@ async function exchangeAuthCode(apiBase, code, state) {
|
|
|
158
159
|
throw new Error(`Failed to exchange auth code: ${err instanceof Error ? err.message : "network error"}`);
|
|
159
160
|
}
|
|
160
161
|
}
|
|
162
|
+
async function switchOrg(apiBase, currentToken, orgId) {
|
|
163
|
+
const res = await fetch(`${apiBase}/authkit/mcp-token`, {
|
|
164
|
+
method: "POST",
|
|
165
|
+
headers: { "Content-Type": "application/json" },
|
|
166
|
+
body: JSON.stringify({ currentToken, orgId }),
|
|
167
|
+
signal: AbortSignal.timeout(AUTH_FETCH_TIMEOUT_MS)
|
|
168
|
+
});
|
|
169
|
+
if (!res.ok) throw new Error(`Org switch failed: ${res.status}`);
|
|
170
|
+
return await res.json();
|
|
171
|
+
}
|
|
172
|
+
function promptOrg(organizations) {
|
|
173
|
+
return new Promise((resolve2) => {
|
|
174
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
175
|
+
console.log("\n Which organization?\n");
|
|
176
|
+
for (let i = 0; i < organizations.length; i++) {
|
|
177
|
+
console.log(` ${i + 1}. ${organizations[i].name}`);
|
|
178
|
+
}
|
|
179
|
+
rl.question("\n > ", (answer) => {
|
|
180
|
+
rl.close();
|
|
181
|
+
const idx = parseInt(answer.trim(), 10) - 1;
|
|
182
|
+
const org = organizations[idx] ?? organizations[0];
|
|
183
|
+
if (!organizations[idx]) console.log(` Defaulting to ${org.name}`);
|
|
184
|
+
console.log("");
|
|
185
|
+
resolve2(org.id);
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
}
|
|
161
189
|
async function browserLogin(apiBase = DEFAULT_API_BASE) {
|
|
162
190
|
const { authUrl, state } = await startAuthFlow(apiBase);
|
|
163
191
|
console.log("\n Opening browser to sign in...");
|
|
@@ -165,7 +193,17 @@ async function browserLogin(apiBase = DEFAULT_API_BASE) {
|
|
|
165
193
|
console.log(` \u2192 ${authUrl}
|
|
166
194
|
`);
|
|
167
195
|
const code = await pollForAuthCode(apiBase, state);
|
|
168
|
-
const
|
|
196
|
+
const exchangeResult = await exchangeAuthCode(apiBase, code, state);
|
|
197
|
+
let { token, orgId } = exchangeResult;
|
|
198
|
+
const organizations = exchangeResult.organizations ?? [];
|
|
199
|
+
if (organizations.length > 1) {
|
|
200
|
+
const selectedOrgId = await promptOrg(organizations);
|
|
201
|
+
if (selectedOrgId !== orgId) {
|
|
202
|
+
const switched = await switchOrg(apiBase, token, selectedOrgId);
|
|
203
|
+
token = switched.token;
|
|
204
|
+
orgId = switched.orgId;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
169
207
|
const credentials = { apiBase, token, orgId };
|
|
170
208
|
saveCachedCredentials(credentials);
|
|
171
209
|
console.log(" \u2713 Signed in successfully\n");
|
|
@@ -256,7 +294,7 @@ import { execSync as execSync2 } from "node:child_process";
|
|
|
256
294
|
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
257
295
|
import { homedir as homedir2 } from "node:os";
|
|
258
296
|
import { join as join3, resolve } from "node:path";
|
|
259
|
-
import { createInterface } from "node:readline";
|
|
297
|
+
import { createInterface as createInterface2 } from "node:readline";
|
|
260
298
|
function parseFlags(args) {
|
|
261
299
|
const flags = {};
|
|
262
300
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -271,7 +309,7 @@ function parseFlags(args) {
|
|
|
271
309
|
function promptScope(target) {
|
|
272
310
|
const available = target === "claude" ? SCOPES : ["user", "project"];
|
|
273
311
|
return new Promise((promptResolve) => {
|
|
274
|
-
const rl =
|
|
312
|
+
const rl = createInterface2({ input: process.stdin, output: process.stderr });
|
|
275
313
|
console.log("\n Where should Lace be installed?\n");
|
|
276
314
|
for (let i = 0; i < available.length; i++) {
|
|
277
315
|
console.log(` ${i + 1}. ${SCOPE_LABELS[available[i]]}`);
|
|
@@ -336,6 +374,21 @@ function readJsonConfig(configPath) {
|
|
|
336
374
|
}
|
|
337
375
|
return {};
|
|
338
376
|
}
|
|
377
|
+
function refreshJsonMcpEntry(configPath, env) {
|
|
378
|
+
const config2 = readJsonConfig(configPath);
|
|
379
|
+
const mcpServers = config2.mcpServers;
|
|
380
|
+
if (!mcpServers?.lace) return;
|
|
381
|
+
mcpServers.lace.env = env;
|
|
382
|
+
writeFileSync2(configPath, JSON.stringify(config2, null, 2));
|
|
383
|
+
}
|
|
384
|
+
function refreshAllLaceConfigs(env) {
|
|
385
|
+
const claudeUserPath = getEditorConfigPath("claude");
|
|
386
|
+
refreshJsonMcpEntry(claudeUserPath, env);
|
|
387
|
+
const projectMcpPath = join3(process.cwd(), ".mcp.json");
|
|
388
|
+
refreshJsonMcpEntry(projectMcpPath, env);
|
|
389
|
+
const cursorUserPath = getEditorConfigPath("cursor");
|
|
390
|
+
refreshJsonMcpEntry(cursorUserPath, env);
|
|
391
|
+
}
|
|
339
392
|
function writeJsonMcpEntry(configPath, entry) {
|
|
340
393
|
const dir = resolve(configPath, "..");
|
|
341
394
|
mkdirSync2(dir, { recursive: true });
|
|
@@ -394,7 +447,7 @@ function installClaude(env, scope = "user") {
|
|
|
394
447
|
try {
|
|
395
448
|
const envFlags = Object.entries(env).map(([key, value]) => `-e ${key}=${value}`).join(" ");
|
|
396
449
|
execSync2(
|
|
397
|
-
`claude mcp add --transport stdio --scope ${scope} ${envFlags}
|
|
450
|
+
`claude mcp add lace --transport stdio --scope ${scope} ${envFlags} -- npx ${mcpArgs("claude").join(" ")}`,
|
|
398
451
|
{
|
|
399
452
|
stdio: "inherit"
|
|
400
453
|
}
|
|
@@ -402,14 +455,14 @@ function installClaude(env, scope = "user") {
|
|
|
402
455
|
console.log(` \u2713 MCP server registered via claude CLI (scope: ${scope})`);
|
|
403
456
|
} catch {
|
|
404
457
|
const configPath = getEditorConfigPath("claude");
|
|
405
|
-
writeJsonMcpEntry(configPath, { command: "npx", args: mcpArgs("claude"), env });
|
|
458
|
+
writeJsonMcpEntry(configPath, { type: "stdio", command: "npx", args: mcpArgs("claude"), env });
|
|
406
459
|
}
|
|
407
460
|
installClaudeSkill();
|
|
408
461
|
}
|
|
409
462
|
function installClaudeDesktop(env) {
|
|
410
463
|
const npx = resolveNpxPath();
|
|
411
464
|
const configPath = getEditorConfigPath("claude-desktop");
|
|
412
|
-
writeJsonMcpEntry(configPath, { command: npx, args: mcpArgs("claude-desktop"), env });
|
|
465
|
+
writeJsonMcpEntry(configPath, { type: "stdio", command: npx, args: mcpArgs("claude-desktop"), env });
|
|
413
466
|
installClaudeSkill();
|
|
414
467
|
}
|
|
415
468
|
function getCursorConfigPath(scope) {
|
|
@@ -418,7 +471,7 @@ function getCursorConfigPath(scope) {
|
|
|
418
471
|
}
|
|
419
472
|
function installCursor(env, scope = "user") {
|
|
420
473
|
const configPath = getCursorConfigPath(scope);
|
|
421
|
-
writeJsonMcpEntry(configPath, { command: "npx", args: mcpArgs("cursor"), env });
|
|
474
|
+
writeJsonMcpEntry(configPath, { type: "stdio", command: "npx", args: mcpArgs("cursor"), env });
|
|
422
475
|
installCursorRule();
|
|
423
476
|
}
|
|
424
477
|
function installCodex(env) {
|
|
@@ -457,6 +510,7 @@ Installing Lace MCP for ${target}...`);
|
|
|
457
510
|
else if (target === "claude-desktop") installClaudeDesktop(env);
|
|
458
511
|
else if (target === "cursor") installCursor(env, scope);
|
|
459
512
|
else installCodex(env);
|
|
513
|
+
refreshAllLaceConfigs(env);
|
|
460
514
|
console.log('\nDone. Start a new session and say "implement the Lace decision" or type /lace.\n');
|
|
461
515
|
}
|
|
462
516
|
var TARGETS, PACKAGE_NAME, SCOPES, SCOPE_LABELS, SKILL_VERSION;
|
|
@@ -519,6 +573,7 @@ function uninstallClaude() {
|
|
|
519
573
|
} catch {
|
|
520
574
|
removeJsonMcpEntry(getEditorConfigPath("claude"));
|
|
521
575
|
}
|
|
576
|
+
removeJsonMcpEntry(join4(process.cwd(), ".mcp.json"));
|
|
522
577
|
removeSkillFile("claude");
|
|
523
578
|
}
|
|
524
579
|
function uninstallTarget(target) {
|