@xmemo/client 0.4.131 → 0.4.133
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 +18 -10
- package/package.json +1 -1
- package/src/cli.js +89 -25
package/README.md
CHANGED
|
@@ -31,7 +31,9 @@ to print the exact command without changing anything.
|
|
|
31
31
|
xmemo update
|
|
32
32
|
xmemo setup codex
|
|
33
33
|
xmemo setup codex --yes
|
|
34
|
-
xmemo
|
|
34
|
+
xmemo setup cursor
|
|
35
|
+
xmemo setup cursor --yes
|
|
36
|
+
xmemo setup copilot
|
|
35
37
|
xmemo doctor
|
|
36
38
|
xmemo discovery show
|
|
37
39
|
xmemo setup
|
|
@@ -44,7 +46,7 @@ xmemo env example --shell bash
|
|
|
44
46
|
xmemo mcp list
|
|
45
47
|
xmemo mcp config --client generic
|
|
46
48
|
xmemo profile status codex
|
|
47
|
-
xmemo
|
|
49
|
+
xmemo smoke --client codex
|
|
48
50
|
xmemo privacy
|
|
49
51
|
```
|
|
50
52
|
|
|
@@ -142,12 +144,13 @@ Generate and write a client config from discovery:
|
|
|
142
144
|
```bash
|
|
143
145
|
xmemo setup codex --yes
|
|
144
146
|
xmemo setup codex --url "https://your-private-service.example" --yes
|
|
145
|
-
xmemo setup
|
|
146
|
-
xmemo setup
|
|
147
|
+
xmemo setup cursor --yes
|
|
148
|
+
xmemo setup copilot
|
|
147
149
|
```
|
|
148
150
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
+
`xmemo setup <client>` is the unified setup entry point. Without `--yes` it
|
|
152
|
+
previews what will happen. With `--yes`, write-capable clients apply the
|
|
153
|
+
user-scoped config. Generated config references `XMEMO_KEY`; it does not embed
|
|
151
154
|
the token value. Write-capable client configs also include stable non-secret
|
|
152
155
|
agent identity headers where the client format supports them.
|
|
153
156
|
|
|
@@ -192,7 +195,7 @@ directly. The recommended personal-user path is therefore local proxy mode:
|
|
|
192
195
|
|
|
193
196
|
```bash
|
|
194
197
|
xmemo login
|
|
195
|
-
xmemo
|
|
198
|
+
xmemo setup copilot
|
|
196
199
|
xmemo mcp proxy
|
|
197
200
|
```
|
|
198
201
|
|
|
@@ -200,6 +203,9 @@ The generated Copilot CLI template points at `http://127.0.0.1:8765/mcp` and
|
|
|
200
203
|
does not include token or identity headers. `xmemo mcp proxy` reads the token
|
|
201
204
|
saved by `xmemo login` or `xmemo token add --from-stdin`, adds the XMemo bearer
|
|
202
205
|
token and local agent identity, then forwards requests to `https://xmemo.dev/mcp`.
|
|
206
|
+
Copilot CLI does not currently document a stable cross-platform config file for
|
|
207
|
+
third-party tools to edit, so `xmemo setup copilot` prints the template and next
|
|
208
|
+
command instead of writing directly.
|
|
203
209
|
If you specifically want the older environment-variable template, run:
|
|
204
210
|
|
|
205
211
|
```bash
|
|
@@ -267,13 +273,15 @@ absence of embedded token values.
|
|
|
267
273
|
|
|
268
274
|
### Cursor
|
|
269
275
|
|
|
270
|
-
|
|
276
|
+
Recommended Cursor setup:
|
|
271
277
|
|
|
272
278
|
```bash
|
|
273
|
-
xmemo
|
|
279
|
+
xmemo setup cursor
|
|
280
|
+
xmemo setup cursor --yes
|
|
274
281
|
```
|
|
275
282
|
|
|
276
|
-
|
|
283
|
+
`setup cursor` previews the Cursor MCP config. `setup cursor --yes` merges it
|
|
284
|
+
into the default Cursor user config path. The lower-level equivalent remains:
|
|
277
285
|
|
|
278
286
|
```bash
|
|
279
287
|
xmemo mcp add cursor --url "$XMEMO_URL" --write
|
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.133';
|
|
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';
|
|
@@ -44,6 +44,13 @@ const MCP_CLIENTS = new Map([
|
|
|
44
44
|
}]
|
|
45
45
|
]);
|
|
46
46
|
|
|
47
|
+
const SETUP_CLIENT_ALIASES = new Map([
|
|
48
|
+
['codex', 'codex'],
|
|
49
|
+
['cursor', 'cursor'],
|
|
50
|
+
['copilot', 'copilot-cli'],
|
|
51
|
+
['copilot-cli', 'copilot-cli']
|
|
52
|
+
]);
|
|
53
|
+
|
|
47
54
|
class UsageError extends Error {
|
|
48
55
|
constructor(message) {
|
|
49
56
|
super(message);
|
|
@@ -150,7 +157,7 @@ function writeHelp(io) {
|
|
|
150
157
|
writeLine(io.stdout, ` ${COMMAND_NAME} update [--dry-run] [--json]`);
|
|
151
158
|
writeLine(io.stdout, ` ${COMMAND_NAME} doctor [--base-url <https://api.example.com>] [--json]`);
|
|
152
159
|
writeLine(io.stdout, ` ${COMMAND_NAME} discovery show [--base-url <https://api.example.com>] [--json]`);
|
|
153
|
-
writeLine(io.stdout, ` ${COMMAND_NAME} setup
|
|
160
|
+
writeLine(io.stdout, ` ${COMMAND_NAME} setup <codex|cursor|copilot> [--url <https://api.example.com>] [--write|--yes] [--json]`);
|
|
154
161
|
writeLine(io.stdout, ` ${COMMAND_NAME} login [--from-stdin] [--base-url <url>] [--timeout-ms <ms>] [--http-timeout-ms <ms>] [--json]`);
|
|
155
162
|
writeLine(io.stdout, ` ${COMMAND_NAME} auth status [--verify] [--base-url <url>] [--json]`);
|
|
156
163
|
writeLine(io.stdout, ` ${COMMAND_NAME} status [--url <https://api.example.com>] [--json]`);
|
|
@@ -361,7 +368,7 @@ async function setupCommand(args, io) {
|
|
|
361
368
|
const outputJson = hasFlag(optionArgs, '--json');
|
|
362
369
|
const shortClientSetup = Boolean(positionalClientId);
|
|
363
370
|
const writeConfig = hasFlag(optionArgs, '--write') || (shortClientSetup && hasFlag(optionArgs, '--yes'));
|
|
364
|
-
const clientId = positionalClientId ?? optionValue(optionArgs, '--client');
|
|
371
|
+
const clientId = normalizeSetupClientId(positionalClientId ?? optionValue(optionArgs, '--client'));
|
|
365
372
|
const timeoutMs = parsePositiveInteger(optionValue(optionArgs, '--timeout-ms') ?? '5000', '--timeout-ms');
|
|
366
373
|
const installProfile = shortClientSetup
|
|
367
374
|
&& clientId === 'codex'
|
|
@@ -383,24 +390,32 @@ async function setupCommand(args, io) {
|
|
|
383
390
|
const setupPlan = buildSetupPlan({ baseUrl, discoveryUrl, statusUrl, discovery, status });
|
|
384
391
|
|
|
385
392
|
if (clientId) {
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
393
|
+
if (clientId === 'copilot-cli') {
|
|
394
|
+
if (writeConfig) {
|
|
395
|
+
throw new UsageError(`Copilot CLI setup cannot be written automatically yet. Run \`${COMMAND_NAME} setup copilot\` to print the local proxy template, then add it with Copilot CLI MCP management.`);
|
|
396
|
+
}
|
|
397
|
+
const proxyPort = parsePositiveInteger(optionValue(optionArgs, '--port') ?? String(DEFAULT_PROXY_PORT), '--port');
|
|
398
|
+
setupPlan.selectedClient = copilotSetupPlan(setupPlan.mcpUrl, proxyPort);
|
|
399
|
+
} else {
|
|
400
|
+
const client = MCP_CLIENTS.get(clientId);
|
|
401
|
+
if (!client) {
|
|
402
|
+
throw new UsageError(`Unsupported MCP client: ${clientId}. Supported clients: ${supportedSetupClientIds().join(', ')}.`);
|
|
403
|
+
}
|
|
390
404
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
405
|
+
const identity = writeConfig ? await agentIdentity(clientId, io.env) : envReferenceIdentity(clientId);
|
|
406
|
+
setupPlan.selectedClient = clientSetupPlan(clientId, client, setupPlan.mcpUrl, io.env, identity);
|
|
407
|
+
if (writeConfig) {
|
|
408
|
+
await client.writeConfig(setupPlan.selectedClient.configPath, setupPlan.mcpUrl, identity);
|
|
409
|
+
setupPlan.selectedClient.written = true;
|
|
410
|
+
}
|
|
397
411
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
412
|
+
if (clientId === 'codex' && shortClientSetup) {
|
|
413
|
+
const profileTarget = optionValue(optionArgs, '--profile-target')
|
|
414
|
+
?? optionValue(optionArgs, '--target')
|
|
415
|
+
?? defaultCodexProfileTarget();
|
|
416
|
+
const profileResult = await codexProfileInstallResult(profileTarget, { write: installProfile });
|
|
417
|
+
setupPlan.selectedClient.codexProfile = profileResult;
|
|
418
|
+
}
|
|
404
419
|
}
|
|
405
420
|
}
|
|
406
421
|
|
|
@@ -647,6 +662,11 @@ function writeCredentialStatus(report, io, { mode }) {
|
|
|
647
662
|
writeLine(io.stdout, `${PRODUCT_NAME} auth status`);
|
|
648
663
|
writeLine(io.stdout, `Logged in: ${report.loggedIn ? 'yes' : 'no'}`);
|
|
649
664
|
writeLine(io.stdout, `Credential source: ${report.tokenSource}`);
|
|
665
|
+
if (report.account) {
|
|
666
|
+
writeLine(io.stdout, `Account: ${formatAccount(report.account)}`);
|
|
667
|
+
}
|
|
668
|
+
writeLine(io.stdout, report.loggedIn ? 'Credential is ready; token value remains hidden.' : `Run \`${COMMAND_NAME} login\` to sign in.`);
|
|
669
|
+
return;
|
|
650
670
|
}
|
|
651
671
|
writeLine(io.stdout, `Environment token: ${report.environmentToken.present ? 'present' : 'missing'} (${report.environmentToken.variable})`);
|
|
652
672
|
writeLine(io.stdout, `User credential file: ${report.userCredentialFile.present ? 'present' : 'missing'} (${report.userCredentialFile.path})`);
|
|
@@ -1405,6 +1425,28 @@ function clientSetupPlan(clientId, client, mcpUrl, env, identity) {
|
|
|
1405
1425
|
};
|
|
1406
1426
|
}
|
|
1407
1427
|
|
|
1428
|
+
function copilotSetupPlan(mcpUrl, proxyPort) {
|
|
1429
|
+
const proxyUrl = `http://${DEFAULT_PROXY_HOST}:${proxyPort}/mcp`;
|
|
1430
|
+
const template = mcpLocalProxyTemplate('copilot-cli', proxyUrl);
|
|
1431
|
+
return {
|
|
1432
|
+
id: 'copilot-cli',
|
|
1433
|
+
label: 'Copilot CLI',
|
|
1434
|
+
configKind: 'local-proxy',
|
|
1435
|
+
configPath: 'Copilot CLI MCP config',
|
|
1436
|
+
serverName: template.serverName,
|
|
1437
|
+
mcpUrl,
|
|
1438
|
+
proxyUrl,
|
|
1439
|
+
tokenEnvVar: TOKEN_ENV_VAR,
|
|
1440
|
+
requiresCredential: template.requiresCredential,
|
|
1441
|
+
requiresLocalCommand: template.requiresLocalCommand,
|
|
1442
|
+
template: template.snippet,
|
|
1443
|
+
agentId: template.agentIdentity.agentId,
|
|
1444
|
+
writesTokenValue: false,
|
|
1445
|
+
writeSupported: false,
|
|
1446
|
+
written: false
|
|
1447
|
+
};
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1408
1450
|
function writeSetupSummary(plan, io) {
|
|
1409
1451
|
writeLine(io.stdout, `${PRODUCT_NAME} setup discovery: ${plan.baseUrl}`);
|
|
1410
1452
|
writeLine(io.stdout, ` API: ${plan.apiBase}`);
|
|
@@ -1431,7 +1473,16 @@ function writeSetupSummary(plan, io) {
|
|
|
1431
1473
|
writeLine(io.stdout, ` Written: ${plan.selectedClient.written}`);
|
|
1432
1474
|
writeLine(io.stdout, ` Token value embedded: ${plan.selectedClient.writesTokenValue}`);
|
|
1433
1475
|
writeLine(io.stdout, ` Agent ID: ${plan.selectedClient.agentId}`);
|
|
1434
|
-
|
|
1476
|
+
if (plan.selectedClient.agentInstanceIdPath) {
|
|
1477
|
+
writeLine(io.stdout, ` Agent instance ID stored: ${plan.selectedClient.agentInstanceIdPath}`);
|
|
1478
|
+
}
|
|
1479
|
+
if (plan.selectedClient.configKind === 'local-proxy') {
|
|
1480
|
+
writeLine(io.stdout, ` Local proxy: ${plan.selectedClient.requiresLocalCommand}`);
|
|
1481
|
+
writeLine(io.stdout, ' MCP template:');
|
|
1482
|
+
writeLine(io.stdout, JSON.stringify(plan.selectedClient.template, null, 2));
|
|
1483
|
+
writeLine(io.stdout, ` Next: add the template with Copilot CLI MCP management, then keep \`${plan.selectedClient.requiresLocalCommand}\` running while you use Copilot CLI.`);
|
|
1484
|
+
return;
|
|
1485
|
+
}
|
|
1435
1486
|
if (plan.selectedClient.codexProfile) {
|
|
1436
1487
|
const profile = plan.selectedClient.codexProfile;
|
|
1437
1488
|
writeLine(io.stdout, ` Codex profile target: ${profile.targetPath}`);
|
|
@@ -1442,7 +1493,7 @@ function writeSetupSummary(plan, io) {
|
|
|
1442
1493
|
}
|
|
1443
1494
|
}
|
|
1444
1495
|
if (!plan.selectedClient.written) {
|
|
1445
|
-
writeLine(io.stdout, ` Next: ${COMMAND_NAME}
|
|
1496
|
+
writeLine(io.stdout, ` Next: ${COMMAND_NAME} setup ${plan.selectedClient.id} --url ${plan.baseUrl} --yes`);
|
|
1446
1497
|
}
|
|
1447
1498
|
return;
|
|
1448
1499
|
}
|
|
@@ -1450,7 +1501,7 @@ function writeSetupSummary(plan, io) {
|
|
|
1450
1501
|
writeLine(io.stdout, '');
|
|
1451
1502
|
writeLine(io.stdout, 'Next steps:');
|
|
1452
1503
|
writeLine(io.stdout, ` 1. Create a scoped token in the token portal and store it in ${plan.tokenEnvVar}.`);
|
|
1453
|
-
writeLine(io.stdout, ` 2. Configure a client, for example: ${COMMAND_NAME} setup --url ${plan.baseUrl} --
|
|
1504
|
+
writeLine(io.stdout, ` 2. Configure a client, for example: ${COMMAND_NAME} setup codex --url ${plan.baseUrl} --yes`);
|
|
1454
1505
|
writeLine(io.stdout, ` 3. Run ${COMMAND_NAME} status to smoke-test the service without sending the token.`);
|
|
1455
1506
|
}
|
|
1456
1507
|
|
|
@@ -1899,6 +1950,10 @@ function supportedMcpClientIds() {
|
|
|
1899
1950
|
return Array.from(MCP_CLIENTS.keys());
|
|
1900
1951
|
}
|
|
1901
1952
|
|
|
1953
|
+
function supportedSetupClientIds() {
|
|
1954
|
+
return ['codex', 'cursor', 'copilot'];
|
|
1955
|
+
}
|
|
1956
|
+
|
|
1902
1957
|
function credentialsPath(env) {
|
|
1903
1958
|
return path.join(configRoot(env), 'credentials.json');
|
|
1904
1959
|
}
|
|
@@ -1985,11 +2040,20 @@ function positionalClientArg(args) {
|
|
|
1985
2040
|
return null;
|
|
1986
2041
|
}
|
|
1987
2042
|
|
|
1988
|
-
|
|
1989
|
-
|
|
2043
|
+
return normalizeSetupClientId(candidate);
|
|
2044
|
+
}
|
|
2045
|
+
|
|
2046
|
+
function normalizeSetupClientId(candidate) {
|
|
2047
|
+
if (!candidate) {
|
|
2048
|
+
return null;
|
|
2049
|
+
}
|
|
2050
|
+
|
|
2051
|
+
const normalized = SETUP_CLIENT_ALIASES.get(candidate);
|
|
2052
|
+
if (!normalized) {
|
|
2053
|
+
throw new UsageError(`Unsupported setup client: ${candidate}. Supported clients: ${supportedSetupClientIds().join(', ')}.`);
|
|
1990
2054
|
}
|
|
1991
2055
|
|
|
1992
|
-
return
|
|
2056
|
+
return normalized;
|
|
1993
2057
|
}
|
|
1994
2058
|
|
|
1995
2059
|
function optionValue(args, name) {
|