@xmemo/client 0.4.152 → 0.4.154

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/package.json +1 -1
  2. package/src/cli.js +120 -14
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xmemo/client",
3
- "version": "0.4.152",
3
+ "version": "0.4.154",
4
4
  "description": "Privacy-first CLI and MCP setup helper for XMemo.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli.js CHANGED
@@ -11,7 +11,7 @@ const PACKAGE_NAME = '@xmemo/client';
11
11
  const FALLBACK_PACKAGE_NAME = '@yonro/xmemo-client';
12
12
  const COMMAND_NAME = 'xmemo';
13
13
  const LEGACY_COMMAND_NAME = 'memory-os';
14
- const CLI_VERSION = '0.4.152';
14
+ const CLI_VERSION = '0.4.154';
15
15
  const DEFAULT_SERVICE_URL = 'https://xmemo.dev';
16
16
  const TOKEN_ENV_VAR = 'XMEMO_KEY';
17
17
  const LEGACY_TOKEN_ENV_VAR = 'MEMORY_OS_MCP_TOKEN';
@@ -171,6 +171,13 @@ const MCP_CLIENTS = new Map([
171
171
  writeConfig: mergeTraeMcpConfig,
172
172
  configKind: 'json'
173
173
  }],
174
+ ['trae-solo', {
175
+ label: 'Trae Solo',
176
+ defaultConfigPath: defaultTraeSoloConfigPath,
177
+ buildSnippet: traeSoloJsonSnippet,
178
+ writeConfig: mergeTraeSoloMcpConfig,
179
+ configKind: 'json'
180
+ }],
174
181
  ['claude-code', {
175
182
  label: 'Claude Code',
176
183
  defaultConfigPath: defaultClaudecodeConfigPath,
@@ -206,6 +213,8 @@ const SETUP_CLIENT_ALIASES = new Map([
206
213
  ['qwencli', 'qwen'],
207
214
  ['qwen-cli', 'qwen'],
208
215
  ['trae', 'trae'],
216
+ ['traesolo', 'trae-solo'],
217
+ ['trae-solo', 'trae-solo'],
209
218
  ['claude-code', 'claude-code'],
210
219
  ['claudecode', 'claude-code'],
211
220
  ['claude-cli', 'claude-code'],
@@ -583,7 +592,7 @@ async function setupCommand(args, io) {
583
592
 
584
593
  if (setupAll) {
585
594
  setupPlan.detectedClients = [];
586
- const scanIds = ['codex', 'cursor', 'copilot-cli', 'gemini-cli', 'antigravity', 'antigravity-ide', 'antigravity2', 'antigravity-cli', 'windsurf', 'cline', 'continue', 'claude-desktop', 'qwen', 'opencode', 'trae'];
595
+ const scanIds = ['codex', 'cursor', 'copilot-cli', 'gemini-cli', 'antigravity', 'antigravity-ide', 'antigravity2', 'antigravity-cli', 'windsurf', 'cline', 'continue', 'claude-desktop', 'qwen', 'opencode', 'trae', 'trae-solo'];
587
596
  for (const scanId of scanIds) {
588
597
  const detection = await detectClient(scanId, io.env);
589
598
  if (detection.detected) {
@@ -1921,9 +1930,9 @@ function writeSetupSummary(plan, io) {
1921
1930
  writeLine(io.stdout, ' 1. Open or restart Qwen.');
1922
1931
  writeLine(io.stdout, ' 2. When Qwen connects to XMemo MCP, a browser window will automatically pop up requesting OAuth authorization.');
1923
1932
  writeLine(io.stdout, ' 3. Follow the page prompts to sign in and click "Authorize" to link Qwen.');
1924
- } else if (cid === 'trae') {
1925
- writeLine(io.stdout, '💡 Next steps for Trae:');
1926
- writeLine(io.stdout, ' 1. Restart Trae to load the new MCP configuration.');
1933
+ } else if (cid === 'trae' || cid === 'trae-solo') {
1934
+ writeLine(io.stdout, `💡 Next steps for ${plan.selectedClient.label}:`);
1935
+ writeLine(io.stdout, ` 1. Restart ${plan.selectedClient.label} to load the new MCP configuration.`);
1927
1936
  writeLine(io.stdout, ` 2. Make sure the ${TOKEN_ENV_VAR} environment variable is set in your user environment.`);
1928
1937
  if (plan.tokenPortalUrl) {
1929
1938
  writeLine(io.stdout, ` (Token portal: ${plan.tokenPortalUrl})`);
@@ -2973,7 +2982,7 @@ function supportedMcpClientIds() {
2973
2982
  }
2974
2983
 
2975
2984
  function supportedSetupClientIds() {
2976
- return ['codex', 'cursor', 'copilot', 'gemini', 'antigravity', 'antigravity-ide', 'antigravity2', 'antigravity-cli', 'windsurf', 'cline', 'continue', 'claude', 'qwen', 'opencode', 'trae'];
2985
+ return ['codex', 'cursor', 'copilot', 'gemini', 'antigravity', 'antigravity-ide', 'antigravity2', 'antigravity-cli', 'windsurf', 'cline', 'continue', 'claude', 'qwen', 'opencode', 'trae', 'trae-solo'];
2977
2986
  }
2978
2987
 
2979
2988
  function usesClientOAuth(clientId) {
@@ -3476,7 +3485,13 @@ function claudeJsonServerConfig(mcpUrl, identity = envReferenceIdentity('claude-
3476
3485
  args: [
3477
3486
  '-y',
3478
3487
  'mcp-remote',
3479
- mcpUrl
3488
+ mcpUrl,
3489
+ '--header',
3490
+ `Authorization:Bearer \${${TOKEN_ENV_VAR}}`,
3491
+ '--header',
3492
+ `X-Memory-OS-Agent-ID:${identity.agentId}`,
3493
+ '--header',
3494
+ `X-Memory-OS-Agent-Instance-ID:\${${AGENT_INSTANCE_ENV_VAR}}`
3480
3495
  ],
3481
3496
  env: {
3482
3497
  [TOKEN_ENV_VAR]: `\${env:${TOKEN_ENV_VAR}}`,
@@ -3624,7 +3639,13 @@ function zedJsonServerConfig(mcpUrl, identity = envReferenceIdentity('zed')) {
3624
3639
  args: [
3625
3640
  '-y',
3626
3641
  'mcp-remote',
3627
- mcpUrl
3642
+ mcpUrl,
3643
+ '--header',
3644
+ `Authorization:Bearer \${${TOKEN_ENV_VAR}}`,
3645
+ '--header',
3646
+ `X-Memory-OS-Agent-ID:${identity.agentId}`,
3647
+ '--header',
3648
+ `X-Memory-OS-Agent-Instance-ID:\${${AGENT_INSTANCE_ENV_VAR}}`
3628
3649
  ],
3629
3650
  env: {
3630
3651
  [TOKEN_ENV_VAR]: `\${env:${TOKEN_ENV_VAR}}`,
@@ -3746,6 +3767,12 @@ function hermesYamlSnippet(mcpUrl, identity = envReferenceIdentity('hermes')) {
3746
3767
  - -y
3747
3768
  - mcp-remote
3748
3769
  - ${mcpUrl}
3770
+ - --header
3771
+ - "Authorization:Bearer \${${TOKEN_ENV_VAR}}"
3772
+ - --header
3773
+ - "X-Memory-OS-Agent-ID:${identity.agentId}"
3774
+ - --header
3775
+ - "X-Memory-OS-Agent-Instance-ID:\${${AGENT_INSTANCE_ENV_VAR}}"
3749
3776
  env:
3750
3777
  ${TOKEN_ENV_VAR}: "\${env:${TOKEN_ENV_VAR}}"
3751
3778
  ${AGENT_INSTANCE_ENV_VAR}: "${identity.agentInstanceId}"
@@ -3831,17 +3858,33 @@ async function mergeQwenMcpConfig(configPath, mcpUrl, identity) {
3831
3858
  }
3832
3859
 
3833
3860
  function defaultTraeConfigPath(env) {
3861
+ if (process.platform === 'win32' && env.APPDATA) {
3862
+ return path.join(env.APPDATA, 'Trae', 'User', 'mcp.json');
3863
+ }
3834
3864
  const home = env.USERPROFILE || env.HOME || os.homedir();
3835
- return path.join(home, '.trae', 'mcp.json');
3865
+ if (process.platform === 'darwin') {
3866
+ return path.join(home, 'Library', 'Application Support', 'Trae', 'User', 'mcp.json');
3867
+ }
3868
+ return path.join(home, '.config', 'Trae', 'User', 'mcp.json');
3836
3869
  }
3837
3870
 
3838
3871
  function traeJsonServerConfig(mcpUrl, identity = envReferenceIdentity('trae')) {
3839
3872
  return {
3840
- url: mcpUrl,
3841
- headers: {
3842
- Authorization: `Bearer \${env:${TOKEN_ENV_VAR}}`,
3843
- [AGENT_ID_HEADER]: identity.agentId,
3844
- [AGENT_INSTANCE_HEADER]: identity.agentInstanceId
3873
+ command: 'npx',
3874
+ args: [
3875
+ '-y',
3876
+ 'mcp-remote',
3877
+ mcpUrl,
3878
+ '--header',
3879
+ `Authorization:Bearer \${${TOKEN_ENV_VAR}}`,
3880
+ '--header',
3881
+ `X-Memory-OS-Agent-ID:${identity.agentId}`,
3882
+ '--header',
3883
+ `X-Memory-OS-Agent-Instance-ID:\${${AGENT_INSTANCE_ENV_VAR}}`
3884
+ ],
3885
+ env: {
3886
+ [TOKEN_ENV_VAR]: `\${env:${TOKEN_ENV_VAR}}`,
3887
+ [AGENT_INSTANCE_ENV_VAR]: identity.agentInstanceId
3845
3888
  }
3846
3889
  };
3847
3890
  }
@@ -3878,6 +3921,69 @@ async function mergeTraeMcpConfig(configPath, mcpUrl, identity) {
3878
3921
  await bestEffortChmod(configPath, 0o600);
3879
3922
  }
3880
3923
 
3924
+ function defaultTraeSoloConfigPath(env) {
3925
+ if (process.platform === 'win32' && env.APPDATA) {
3926
+ return path.join(env.APPDATA, 'TRAE SOLO', 'User', 'mcp.json');
3927
+ }
3928
+ const home = env.USERPROFILE || env.HOME || os.homedir();
3929
+ if (process.platform === 'darwin') {
3930
+ return path.join(home, 'Library', 'Application Support', 'TRAE SOLO', 'User', 'mcp.json');
3931
+ }
3932
+ return path.join(home, '.config', 'TRAE SOLO', 'User', 'mcp.json');
3933
+ }
3934
+
3935
+ function traeSoloJsonServerConfig(mcpUrl, identity = envReferenceIdentity('trae-solo')) {
3936
+ return {
3937
+ command: 'npx',
3938
+ args: [
3939
+ '-y',
3940
+ 'mcp-remote',
3941
+ mcpUrl,
3942
+ '--header',
3943
+ `Authorization:Bearer \${${TOKEN_ENV_VAR}}`,
3944
+ '--header',
3945
+ `X-Memory-OS-Agent-ID:${identity.agentId}`,
3946
+ '--header',
3947
+ `X-Memory-OS-Agent-Instance-ID:\${${AGENT_INSTANCE_ENV_VAR}}`
3948
+ ],
3949
+ env: {
3950
+ [TOKEN_ENV_VAR]: `\${env:${TOKEN_ENV_VAR}}`,
3951
+ [AGENT_INSTANCE_ENV_VAR]: identity.agentInstanceId
3952
+ }
3953
+ };
3954
+ }
3955
+
3956
+ function traeSoloJsonConfig(mcpUrl, identity = envReferenceIdentity('trae-solo')) {
3957
+ return {
3958
+ mcpServers: {
3959
+ [MCP_SERVER_NAME]: traeSoloJsonServerConfig(mcpUrl, identity)
3960
+ }
3961
+ };
3962
+ }
3963
+
3964
+ function traeSoloJsonSnippet(mcpUrl, identity = envReferenceIdentity('trae-solo')) {
3965
+ return `${JSON.stringify(traeSoloJsonConfig(mcpUrl, identity), null, 2)}\n`;
3966
+ }
3967
+
3968
+ async function mergeTraeSoloMcpConfig(configPath, mcpUrl, identity) {
3969
+ const existing = await readTextIfExists(configPath);
3970
+ const parsed = existing.trim().length === 0 ? {} : parseJsonConfig(existing, configPath);
3971
+ if (!isPlainObject(parsed)) {
3972
+ throw new UsageError(`MCP JSON config must be an object: ${configPath}`);
3973
+ }
3974
+ if (!isPlainObject(parsed.mcpServers)) {
3975
+ parsed.mcpServers = {};
3976
+ }
3977
+ const existingName = existingJsonMcpServerName(parsed.mcpServers);
3978
+ if (existingName) {
3979
+ throw new UsageError(`MCP config already contains mcpServers.${existingName}. Edit ${configPath} manually to avoid duplicate server definitions.`);
3980
+ }
3981
+ parsed.mcpServers[MCP_SERVER_NAME] = traeSoloJsonServerConfig(mcpUrl, identity);
3982
+ await fs.mkdir(path.dirname(configPath), { recursive: true, mode: 0o700 });
3983
+ await fs.writeFile(configPath, `${JSON.stringify(parsed, null, 2)}\n`, { mode: 0o600 });
3984
+ await bestEffortChmod(configPath, 0o600);
3985
+ }
3986
+
3881
3987
  function defaultClaudecodeConfigPath(env) {
3882
3988
  const home = env.USERPROFILE || env.HOME || os.homedir();
3883
3989
  return path.join(home, '.claude.json');