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.
Files changed (2) hide show
  1. package/dist/cli.js +63 -8
  2. 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", "settings.json");
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 { token, orgId } = await exchangeAuthCode(apiBase, code, state);
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 = createInterface({ input: process.stdin, output: process.stderr });
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} lace -- npx ${mcpArgs("claude").join(" ")}`,
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) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lace-mcp",
3
- "version": "0.0.2-alpha.5",
3
+ "version": "0.0.2-alpha.7",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist/cli.js",