@xmemo/client 0.4.138 → 0.4.139
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 +7 -0
- package/package.json +1 -1
- package/src/cli.js +184 -4
package/README.md
CHANGED
|
@@ -310,6 +310,11 @@ absence of embedded token values.
|
|
|
310
310
|
|
|
311
311
|
### Cursor
|
|
312
312
|
|
|
313
|
+
Cursor marketplace plugin assets live in `.cursor-plugin/marketplace.json` and
|
|
314
|
+
`plugins/xmemo/`. The marketplace plugin is OAuth-first and its `mcp.json` stores
|
|
315
|
+
only `https://xmemo.dev/mcp`; it must not contain `Authorization`, `Bearer`, or
|
|
316
|
+
`XMEMO_KEY`.
|
|
317
|
+
|
|
313
318
|
Recommended Cursor setup:
|
|
314
319
|
|
|
315
320
|
```bash
|
|
@@ -331,6 +336,8 @@ Cursor configs include
|
|
|
331
336
|
non-secret and stored under the user's XMemo CLI config directory. By default,
|
|
332
337
|
the setup prompt also installs a Cursor behavior profile at
|
|
333
338
|
`~/.cursor/memory-profile.md`; answer `n` or pass `--no-profile` to skip it.
|
|
339
|
+
Use this direct-key setup only for local/manual installs where Cursor OAuth is
|
|
340
|
+
unavailable; public plugin submission should use the OAuth-first plugin config.
|
|
334
341
|
|
|
335
342
|
### Gemini CLI
|
|
336
343
|
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -10,7 +10,7 @@ const PACKAGE_NAME = '@xmemo/client';
|
|
|
10
10
|
const FALLBACK_PACKAGE_NAME = '@yonro/xmemo-client';
|
|
11
11
|
const COMMAND_NAME = 'xmemo';
|
|
12
12
|
const LEGACY_COMMAND_NAME = 'memory-os';
|
|
13
|
-
const CLI_VERSION = '0.4.
|
|
13
|
+
const CLI_VERSION = '0.4.139';
|
|
14
14
|
const DEFAULT_SERVICE_URL = 'https://xmemo.dev';
|
|
15
15
|
const TOKEN_ENV_VAR = 'XMEMO_KEY';
|
|
16
16
|
const LEGACY_TOKEN_ENV_VAR = 'MEMORY_OS_MCP_TOKEN';
|
|
@@ -64,6 +64,27 @@ const MCP_CLIENTS = new Map([
|
|
|
64
64
|
buildSnippet: antigravityJsonSnippet,
|
|
65
65
|
writeConfig: mergeAntigravityMcpConfig,
|
|
66
66
|
configKind: 'json'
|
|
67
|
+
}],
|
|
68
|
+
['antigravity-ide', {
|
|
69
|
+
label: 'Antigravity IDE',
|
|
70
|
+
defaultConfigPath: defaultAntigravityIdeConfigPath,
|
|
71
|
+
buildSnippet: antigravityIdeJsonSnippet,
|
|
72
|
+
writeConfig: mergeAntigravityIdeMcpConfig,
|
|
73
|
+
configKind: 'json'
|
|
74
|
+
}],
|
|
75
|
+
['antigravity2', {
|
|
76
|
+
label: 'Antigravity 2.0',
|
|
77
|
+
defaultConfigPath: defaultAntigravity2ConfigPath,
|
|
78
|
+
buildSnippet: antigravity2JsonSnippet,
|
|
79
|
+
writeConfig: mergeAntigravity2McpConfig,
|
|
80
|
+
configKind: 'json'
|
|
81
|
+
}],
|
|
82
|
+
['antigravity-cli', {
|
|
83
|
+
label: 'Antigravity CLI',
|
|
84
|
+
defaultConfigPath: defaultAntigravityCliConfigPath,
|
|
85
|
+
buildSnippet: antigravityCliJsonSnippet,
|
|
86
|
+
writeConfig: mergeAntigravityCliMcpConfig,
|
|
87
|
+
configKind: 'json'
|
|
67
88
|
}]
|
|
68
89
|
]);
|
|
69
90
|
|
|
@@ -74,7 +95,10 @@ const SETUP_CLIENT_ALIASES = new Map([
|
|
|
74
95
|
['copilot-cli', 'copilot-cli'],
|
|
75
96
|
['gemini', 'gemini-cli'],
|
|
76
97
|
['gemini-cli', 'gemini-cli'],
|
|
77
|
-
['antigravity', 'antigravity']
|
|
98
|
+
['antigravity', 'antigravity'],
|
|
99
|
+
['antigravity-ide', 'antigravity-ide'],
|
|
100
|
+
['antigravity2', 'antigravity2'],
|
|
101
|
+
['antigravity-cli', 'antigravity-cli']
|
|
78
102
|
]);
|
|
79
103
|
|
|
80
104
|
class UsageError extends Error {
|
|
@@ -1418,6 +1442,18 @@ function mcpConfigTemplate(clientId, mcpUrl) {
|
|
|
1418
1442
|
return oauthJsonMcpTemplate(clientId, mcpUrl, antigravityJsonConfig(mcpUrl));
|
|
1419
1443
|
}
|
|
1420
1444
|
|
|
1445
|
+
if (clientId === 'antigravity-ide') {
|
|
1446
|
+
return oauthJsonMcpTemplate(clientId, mcpUrl, antigravityIdeJsonConfig(mcpUrl));
|
|
1447
|
+
}
|
|
1448
|
+
|
|
1449
|
+
if (clientId === 'antigravity2') {
|
|
1450
|
+
return oauthJsonMcpTemplate(clientId, mcpUrl, antigravity2JsonConfig(mcpUrl));
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
if (clientId === 'antigravity-cli') {
|
|
1454
|
+
return oauthJsonMcpTemplate(clientId, mcpUrl, antigravityCliJsonConfig(mcpUrl));
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1421
1457
|
return {
|
|
1422
1458
|
client: clientId,
|
|
1423
1459
|
serverName: MCP_SERVER_NAME,
|
|
@@ -2329,6 +2365,135 @@ async function mergeAntigravityMcpConfig(configPath, mcpUrl, identity) {
|
|
|
2329
2365
|
await bestEffortChmod(configPath, 0o600);
|
|
2330
2366
|
}
|
|
2331
2367
|
|
|
2368
|
+
function antigravityIdeJsonServerConfig(mcpUrl) {
|
|
2369
|
+
return {
|
|
2370
|
+
type: 'http',
|
|
2371
|
+
url: mcpUrl
|
|
2372
|
+
};
|
|
2373
|
+
}
|
|
2374
|
+
|
|
2375
|
+
function antigravityIdeJsonConfig(mcpUrl) {
|
|
2376
|
+
return {
|
|
2377
|
+
mcpServers: {
|
|
2378
|
+
[MCP_SERVER_NAME]: antigravityIdeJsonServerConfig(mcpUrl)
|
|
2379
|
+
}
|
|
2380
|
+
};
|
|
2381
|
+
}
|
|
2382
|
+
|
|
2383
|
+
function antigravityIdeJsonSnippet(mcpUrl, identity = envReferenceIdentity('antigravity-ide')) {
|
|
2384
|
+
return `${JSON.stringify(antigravityIdeJsonConfig(mcpUrl), null, 2)}\n`;
|
|
2385
|
+
}
|
|
2386
|
+
|
|
2387
|
+
async function mergeAntigravityIdeMcpConfig(configPath, mcpUrl, identity) {
|
|
2388
|
+
const existing = await readTextIfExists(configPath);
|
|
2389
|
+
const parsed = existing.trim().length === 0 ? {} : parseJsonConfig(existing, configPath);
|
|
2390
|
+
|
|
2391
|
+
if (!isPlainObject(parsed)) {
|
|
2392
|
+
throw new UsageError(`MCP JSON config must be an object: ${configPath}`);
|
|
2393
|
+
}
|
|
2394
|
+
|
|
2395
|
+
if (!isPlainObject(parsed.mcpServers)) {
|
|
2396
|
+
parsed.mcpServers = {};
|
|
2397
|
+
}
|
|
2398
|
+
|
|
2399
|
+
const existingName = existingJsonMcpServerName(parsed.mcpServers);
|
|
2400
|
+
if (existingName) {
|
|
2401
|
+
throw new UsageError(`MCP config already contains mcpServers.${existingName}. Edit ${configPath} manually to avoid duplicate server definitions.`);
|
|
2402
|
+
}
|
|
2403
|
+
|
|
2404
|
+
parsed.mcpServers[MCP_SERVER_NAME] = antigravityIdeJsonServerConfig(mcpUrl);
|
|
2405
|
+
await fs.mkdir(path.dirname(configPath), { recursive: true, mode: 0o700 });
|
|
2406
|
+
await fs.writeFile(configPath, `${JSON.stringify(parsed, null, 2)}\n`, { mode: 0o600 });
|
|
2407
|
+
await bestEffortChmod(configPath, 0o600);
|
|
2408
|
+
}
|
|
2409
|
+
|
|
2410
|
+
function antigravity2JsonServerConfig(mcpUrl) {
|
|
2411
|
+
return {
|
|
2412
|
+
type: 'http',
|
|
2413
|
+
url: mcpUrl
|
|
2414
|
+
};
|
|
2415
|
+
}
|
|
2416
|
+
|
|
2417
|
+
function antigravity2JsonConfig(mcpUrl) {
|
|
2418
|
+
return {
|
|
2419
|
+
mcpServers: {
|
|
2420
|
+
[MCP_SERVER_NAME]: antigravity2JsonServerConfig(mcpUrl)
|
|
2421
|
+
}
|
|
2422
|
+
};
|
|
2423
|
+
}
|
|
2424
|
+
|
|
2425
|
+
function antigravity2JsonSnippet(mcpUrl, identity = envReferenceIdentity('antigravity2')) {
|
|
2426
|
+
return `${JSON.stringify(antigravity2JsonConfig(mcpUrl), null, 2)}\n`;
|
|
2427
|
+
}
|
|
2428
|
+
|
|
2429
|
+
async function mergeAntigravity2McpConfig(configPath, mcpUrl, identity) {
|
|
2430
|
+
const existing = await readTextIfExists(configPath);
|
|
2431
|
+
const parsed = existing.trim().length === 0 ? {} : parseJsonConfig(existing, configPath);
|
|
2432
|
+
|
|
2433
|
+
if (!isPlainObject(parsed)) {
|
|
2434
|
+
throw new UsageError(`MCP JSON config must be an object: ${configPath}`);
|
|
2435
|
+
}
|
|
2436
|
+
|
|
2437
|
+
if (!isPlainObject(parsed.mcpServers)) {
|
|
2438
|
+
parsed.mcpServers = {};
|
|
2439
|
+
}
|
|
2440
|
+
|
|
2441
|
+
const existingName = existingJsonMcpServerName(parsed.mcpServers);
|
|
2442
|
+
if (existingName) {
|
|
2443
|
+
throw new UsageError(`MCP config already contains mcpServers.${existingName}. Edit ${configPath} manually to avoid duplicate server definitions.`);
|
|
2444
|
+
}
|
|
2445
|
+
|
|
2446
|
+
parsed.mcpServers[MCP_SERVER_NAME] = antigravity2JsonServerConfig(mcpUrl);
|
|
2447
|
+
await fs.mkdir(path.dirname(configPath), { recursive: true, mode: 0o700 });
|
|
2448
|
+
await fs.writeFile(configPath, `${JSON.stringify(parsed, null, 2)}\n`, { mode: 0o600 });
|
|
2449
|
+
await bestEffortChmod(configPath, 0o600);
|
|
2450
|
+
}
|
|
2451
|
+
|
|
2452
|
+
function antigravityCliJsonServerConfig(mcpUrl, identity = envReferenceIdentity('antigravity-cli')) {
|
|
2453
|
+
return {
|
|
2454
|
+
httpUrl: mcpUrl,
|
|
2455
|
+
headers: {
|
|
2456
|
+
[AGENT_ID_HEADER]: identity.agentId,
|
|
2457
|
+
[AGENT_INSTANCE_HEADER]: identity.agentInstanceId
|
|
2458
|
+
}
|
|
2459
|
+
};
|
|
2460
|
+
}
|
|
2461
|
+
|
|
2462
|
+
function antigravityCliJsonConfig(mcpUrl, identity = envReferenceIdentity('antigravity-cli')) {
|
|
2463
|
+
return {
|
|
2464
|
+
mcpServers: {
|
|
2465
|
+
[MCP_SERVER_NAME]: antigravityCliJsonServerConfig(mcpUrl, identity)
|
|
2466
|
+
}
|
|
2467
|
+
};
|
|
2468
|
+
}
|
|
2469
|
+
|
|
2470
|
+
function antigravityCliJsonSnippet(mcpUrl, identity = envReferenceIdentity('antigravity-cli')) {
|
|
2471
|
+
return `${JSON.stringify(antigravityCliJsonConfig(mcpUrl, identity), null, 2)}\n`;
|
|
2472
|
+
}
|
|
2473
|
+
|
|
2474
|
+
async function mergeAntigravityCliMcpConfig(configPath, mcpUrl, identity) {
|
|
2475
|
+
const existing = await readTextIfExists(configPath);
|
|
2476
|
+
const parsed = existing.trim().length === 0 ? {} : parseJsonConfig(existing, configPath);
|
|
2477
|
+
|
|
2478
|
+
if (!isPlainObject(parsed)) {
|
|
2479
|
+
throw new UsageError(`MCP JSON config must be an object: ${configPath}`);
|
|
2480
|
+
}
|
|
2481
|
+
|
|
2482
|
+
if (!isPlainObject(parsed.mcpServers)) {
|
|
2483
|
+
parsed.mcpServers = {};
|
|
2484
|
+
}
|
|
2485
|
+
|
|
2486
|
+
const existingName = existingJsonMcpServerName(parsed.mcpServers);
|
|
2487
|
+
if (existingName) {
|
|
2488
|
+
throw new UsageError(`MCP config already contains mcpServers.${existingName}. Edit ${configPath} manually to avoid duplicate server definitions.`);
|
|
2489
|
+
}
|
|
2490
|
+
|
|
2491
|
+
parsed.mcpServers[MCP_SERVER_NAME] = antigravityCliJsonServerConfig(mcpUrl, identity);
|
|
2492
|
+
await fs.mkdir(path.dirname(configPath), { recursive: true, mode: 0o700 });
|
|
2493
|
+
await fs.writeFile(configPath, `${JSON.stringify(parsed, null, 2)}\n`, { mode: 0o600 });
|
|
2494
|
+
await bestEffortChmod(configPath, 0o600);
|
|
2495
|
+
}
|
|
2496
|
+
|
|
2332
2497
|
|
|
2333
2498
|
async function mergeGeminiMcpConfig(configPath, mcpUrl, identity) {
|
|
2334
2499
|
const existing = await readTextIfExists(configPath);
|
|
@@ -2485,11 +2650,11 @@ function supportedMcpClientIds() {
|
|
|
2485
2650
|
}
|
|
2486
2651
|
|
|
2487
2652
|
function supportedSetupClientIds() {
|
|
2488
|
-
return ['codex', 'cursor', 'copilot', 'gemini', 'antigravity'];
|
|
2653
|
+
return ['codex', 'cursor', 'copilot', 'gemini', 'antigravity', 'antigravity-ide', 'antigravity2', 'antigravity-cli'];
|
|
2489
2654
|
}
|
|
2490
2655
|
|
|
2491
2656
|
function usesClientOAuth(clientId) {
|
|
2492
|
-
return clientId === 'gemini-cli' || clientId === 'antigravity';
|
|
2657
|
+
return clientId === 'gemini-cli' || clientId === 'antigravity' || clientId === 'antigravity-ide' || clientId === 'antigravity2' || clientId === 'antigravity-cli';
|
|
2493
2658
|
}
|
|
2494
2659
|
|
|
2495
2660
|
function credentialsPath(env) {
|
|
@@ -2537,6 +2702,21 @@ function defaultAntigravityConfigPath(env) {
|
|
|
2537
2702
|
return path.join(home, '.gemini', 'antigravity', 'mcp_config.json');
|
|
2538
2703
|
}
|
|
2539
2704
|
|
|
2705
|
+
function defaultAntigravityIdeConfigPath(env) {
|
|
2706
|
+
const home = env.USERPROFILE || env.HOME || os.homedir();
|
|
2707
|
+
return path.join(home, '.antigravity-ide', 'mcp.json');
|
|
2708
|
+
}
|
|
2709
|
+
|
|
2710
|
+
function defaultAntigravity2ConfigPath(env) {
|
|
2711
|
+
const home = env.USERPROFILE || env.HOME || os.homedir();
|
|
2712
|
+
return path.join(home, '.antigravity2', 'mcp.json');
|
|
2713
|
+
}
|
|
2714
|
+
|
|
2715
|
+
function defaultAntigravityCliConfigPath(env) {
|
|
2716
|
+
const home = env.USERPROFILE || env.HOME || os.homedir();
|
|
2717
|
+
return path.join(home, '.antigravity', 'settings.json');
|
|
2718
|
+
}
|
|
2719
|
+
|
|
2540
2720
|
function defaultCopilotConfigPath(env) {
|
|
2541
2721
|
const home = env.USERPROFILE || env.HOME || os.homedir();
|
|
2542
2722
|
return path.join(env.COPILOT_HOME ?? path.join(home, '.copilot'), 'mcp-config.json');
|