@xmemo/client 0.4.152 → 0.4.153

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 +75 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xmemo/client",
3
- "version": "0.4.152",
3
+ "version": "0.4.153",
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.153';
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) {
@@ -3831,8 +3840,14 @@ async function mergeQwenMcpConfig(configPath, mcpUrl, identity) {
3831
3840
  }
3832
3841
 
3833
3842
  function defaultTraeConfigPath(env) {
3843
+ if (process.platform === 'win32' && env.APPDATA) {
3844
+ return path.join(env.APPDATA, 'Trae', 'User', 'mcp.json');
3845
+ }
3834
3846
  const home = env.USERPROFILE || env.HOME || os.homedir();
3835
- return path.join(home, '.trae', 'mcp.json');
3847
+ if (process.platform === 'darwin') {
3848
+ return path.join(home, 'Library', 'Application Support', 'Trae', 'User', 'mcp.json');
3849
+ }
3850
+ return path.join(home, '.config', 'Trae', 'User', 'mcp.json');
3836
3851
  }
3837
3852
 
3838
3853
  function traeJsonServerConfig(mcpUrl, identity = envReferenceIdentity('trae')) {
@@ -3878,6 +3893,59 @@ async function mergeTraeMcpConfig(configPath, mcpUrl, identity) {
3878
3893
  await bestEffortChmod(configPath, 0o600);
3879
3894
  }
3880
3895
 
3896
+ function defaultTraeSoloConfigPath(env) {
3897
+ if (process.platform === 'win32' && env.APPDATA) {
3898
+ return path.join(env.APPDATA, 'TRAE SOLO', 'User', 'mcp.json');
3899
+ }
3900
+ const home = env.USERPROFILE || env.HOME || os.homedir();
3901
+ if (process.platform === 'darwin') {
3902
+ return path.join(home, 'Library', 'Application Support', 'TRAE SOLO', 'User', 'mcp.json');
3903
+ }
3904
+ return path.join(home, '.config', 'TRAE SOLO', 'User', 'mcp.json');
3905
+ }
3906
+
3907
+ function traeSoloJsonServerConfig(mcpUrl, identity = envReferenceIdentity('trae-solo')) {
3908
+ return {
3909
+ url: mcpUrl,
3910
+ headers: {
3911
+ Authorization: `Bearer \${env:${TOKEN_ENV_VAR}}`,
3912
+ [AGENT_ID_HEADER]: identity.agentId,
3913
+ [AGENT_INSTANCE_HEADER]: identity.agentInstanceId
3914
+ }
3915
+ };
3916
+ }
3917
+
3918
+ function traeSoloJsonConfig(mcpUrl, identity = envReferenceIdentity('trae-solo')) {
3919
+ return {
3920
+ mcpServers: {
3921
+ [MCP_SERVER_NAME]: traeSoloJsonServerConfig(mcpUrl, identity)
3922
+ }
3923
+ };
3924
+ }
3925
+
3926
+ function traeSoloJsonSnippet(mcpUrl, identity = envReferenceIdentity('trae-solo')) {
3927
+ return `${JSON.stringify(traeSoloJsonConfig(mcpUrl, identity), null, 2)}\n`;
3928
+ }
3929
+
3930
+ async function mergeTraeSoloMcpConfig(configPath, mcpUrl, identity) {
3931
+ const existing = await readTextIfExists(configPath);
3932
+ const parsed = existing.trim().length === 0 ? {} : parseJsonConfig(existing, configPath);
3933
+ if (!isPlainObject(parsed)) {
3934
+ throw new UsageError(`MCP JSON config must be an object: ${configPath}`);
3935
+ }
3936
+ if (!isPlainObject(parsed.mcpServers)) {
3937
+ parsed.mcpServers = {};
3938
+ }
3939
+ const existingName = existingJsonMcpServerName(parsed.mcpServers);
3940
+ if (existingName) {
3941
+ throw new UsageError(`MCP config already contains mcpServers.${existingName}. Edit ${configPath} manually to avoid duplicate server definitions.`);
3942
+ }
3943
+ parsed.mcpServers[MCP_SERVER_NAME] = traeSoloJsonServerConfig(mcpUrl, identity);
3944
+ await fs.mkdir(path.dirname(configPath), { recursive: true, mode: 0o700 });
3945
+ await fs.writeFile(configPath, `${JSON.stringify(parsed, null, 2)}\n`, { mode: 0o600 });
3946
+ await bestEffortChmod(configPath, 0o600);
3947
+ }
3948
+
3881
3949
  function defaultClaudecodeConfigPath(env) {
3882
3950
  const home = env.USERPROFILE || env.HOME || os.homedir();
3883
3951
  return path.join(home, '.claude.json');