@xmemo/client 0.4.155 → 0.4.157
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 +37 -7
- package/package.json +3 -2
- package/plugins/kiro/.kiro-plugin/power.json +35 -0
- package/plugins/kiro/CHANGELOG.md +9 -0
- package/plugins/kiro/LICENSE +7 -0
- package/plugins/kiro/POWER.md +147 -0
- package/plugins/kiro/README.md +31 -0
- package/plugins/kiro/SETUP.md +234 -0
- package/plugins/kiro/assets/logo.svg +27 -0
- package/plugins/kiro/mcp.json +7 -0
- package/plugins/kiro/steering/xmemo-memory.md +32 -0
- package/src/cli.js +23 -3996
- package/src/commands/auth.js +230 -0
- package/src/commands/diagnostics.js +197 -0
- package/src/commands/mcp.js +188 -0
- package/src/commands/profile.js +57 -0
- package/src/commands/setup.js +191 -0
- package/src/commands/update.js +58 -0
- package/src/config/env.js +82 -0
- package/src/config/paths.js +26 -0
- package/src/config/profile.js +533 -0
- package/src/core/args.js +63 -0
- package/src/core/constants.js +32 -0
- package/src/core/errors.js +6 -0
- package/src/core/io.js +16 -0
- package/src/core/runtime.js +144 -0
- package/src/core/version.js +1 -0
- package/src/mcp/clients/detect.js +51 -0
- package/src/mcp/clients/registry.js +68 -0
- package/src/mcp/clients.js +81 -0
- package/src/mcp/core/names.js +13 -0
- package/src/mcp/core/templates.js +156 -0
- package/src/mcp/formats/json.js +355 -0
- package/src/mcp/formats/toml.js +148 -0
- package/src/mcp/formats/yaml.js +72 -0
- package/src/mcp/identity/device.js +78 -0
- package/src/mcp/identity/paths.js +155 -0
- package/src/mcp/proxy/copilot.js +44 -0
- package/src/mcp/proxy/server.js +112 -0
- package/src/network/auth.js +200 -0
- package/src/network/base-url.js +13 -0
- package/src/network/discovery.js +103 -0
- package/src/network/http.js +161 -0
- package/src/ui/help.js +59 -0
- package/src/ui/setup.js +244 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
4
|
+
|
|
5
|
+
import { UsageError } from './errors.js';
|
|
6
|
+
import { writeLine } from './io.js';
|
|
7
|
+
|
|
8
|
+
export function npmExecutable() {
|
|
9
|
+
return os.platform() === 'win32' ? 'npm.cmd' : 'npm';
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export async function runProcess(command, args, io, { stream = true } = {}) {
|
|
13
|
+
const spawnFn = io.spawn ?? spawn;
|
|
14
|
+
return await new Promise((resolve, reject) => {
|
|
15
|
+
const child = spawnFn(command, args, {
|
|
16
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
17
|
+
shell: os.platform() === 'win32'
|
|
18
|
+
});
|
|
19
|
+
let stdout = '';
|
|
20
|
+
let stderr = '';
|
|
21
|
+
child.stdout?.on('data', (chunk) => {
|
|
22
|
+
const text = String(chunk);
|
|
23
|
+
stdout += text;
|
|
24
|
+
if (stream) {
|
|
25
|
+
io.stdout.write(text);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
child.stderr?.on('data', (chunk) => {
|
|
29
|
+
const text = String(chunk);
|
|
30
|
+
stderr += text;
|
|
31
|
+
if (stream) {
|
|
32
|
+
io.stderr.write(text);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
child.on('error', reject);
|
|
36
|
+
child.on('close', (code) => {
|
|
37
|
+
resolve({ code: code ?? 0, stdout, stderr });
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function waitForShutdown(server, io) {
|
|
43
|
+
await new Promise((resolve) => {
|
|
44
|
+
let resolved = false;
|
|
45
|
+
const finish = async () => {
|
|
46
|
+
if (resolved) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
resolved = true;
|
|
50
|
+
await closeServer(server);
|
|
51
|
+
resolve();
|
|
52
|
+
};
|
|
53
|
+
const onSigint = () => {
|
|
54
|
+
writeLine(io.stdout, 'Shutting down XMemo MCP proxy...');
|
|
55
|
+
void finish();
|
|
56
|
+
};
|
|
57
|
+
process.once('SIGINT', onSigint);
|
|
58
|
+
process.once('SIGTERM', onSigint);
|
|
59
|
+
server.once('close', () => {
|
|
60
|
+
process.off('SIGINT', onSigint);
|
|
61
|
+
process.off('SIGTERM', onSigint);
|
|
62
|
+
if (!resolved) {
|
|
63
|
+
resolved = true;
|
|
64
|
+
resolve();
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export async function closeServer(server) {
|
|
71
|
+
await new Promise((resolve, reject) => {
|
|
72
|
+
server.close((error) => {
|
|
73
|
+
if (error) {
|
|
74
|
+
reject(error);
|
|
75
|
+
} else {
|
|
76
|
+
resolve();
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export async function readAll(stream) {
|
|
83
|
+
let content = '';
|
|
84
|
+
for await (const chunk of stream) {
|
|
85
|
+
content += chunk;
|
|
86
|
+
}
|
|
87
|
+
return content;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export async function fileExists(filePath) {
|
|
91
|
+
try {
|
|
92
|
+
await fs.access(filePath);
|
|
93
|
+
return true;
|
|
94
|
+
} catch {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export async function readTextIfExists(filePath) {
|
|
100
|
+
try {
|
|
101
|
+
return await fs.readFile(filePath, 'utf8');
|
|
102
|
+
} catch (error) {
|
|
103
|
+
if (error.code === 'ENOENT') {
|
|
104
|
+
return '';
|
|
105
|
+
}
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function parseJsonConfig(content, configPath) {
|
|
111
|
+
try {
|
|
112
|
+
return JSON.parse(content);
|
|
113
|
+
} catch (error) {
|
|
114
|
+
throw new UsageError(`Invalid JSON in ${configPath}: ${error.message}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export async function bestEffortChmod(filePath, mode) {
|
|
119
|
+
try {
|
|
120
|
+
await fs.chmod(filePath, mode);
|
|
121
|
+
} catch {
|
|
122
|
+
// Windows and managed environments may ignore POSIX chmod.
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function isPlainObject(value) {
|
|
127
|
+
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function escapeTomlString(value) {
|
|
131
|
+
return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
export function unescapeTomlString(value) {
|
|
135
|
+
return value.replace(/\\"/g, '"').replace(/\\\\/g, '\\');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export function escapeRegExp(value) {
|
|
139
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export async function sleep(ms) {
|
|
143
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
144
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const CLI_VERSION = '0.4.156';
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
import { fileExists } from '../../core/runtime.js';
|
|
5
|
+
import { defaultCopilotConfigPath } from '../identity/paths.js';
|
|
6
|
+
|
|
7
|
+
export async function detectClient(clientId, env, mcpClients) {
|
|
8
|
+
let filePaths = [];
|
|
9
|
+
if (clientId === 'copilot-cli' || clientId === 'copilot') {
|
|
10
|
+
if (process.platform === 'win32' && env.APPDATA) {
|
|
11
|
+
filePaths.push(path.join(env.APPDATA, 'Code', 'User', 'mcp.json'));
|
|
12
|
+
} else {
|
|
13
|
+
const home = env.HOME || os.homedir();
|
|
14
|
+
if (process.platform === 'darwin') {
|
|
15
|
+
filePaths.push(path.join(home, 'Library', 'Application Support', 'Code', 'User', 'mcp.json'));
|
|
16
|
+
}
|
|
17
|
+
filePaths.push(path.join(home, '.config', 'Code', 'User', 'mcp.json'));
|
|
18
|
+
}
|
|
19
|
+
filePaths.push(defaultCopilotConfigPath(env));
|
|
20
|
+
} else {
|
|
21
|
+
const client = mcpClients.get(clientId);
|
|
22
|
+
if (client) {
|
|
23
|
+
filePaths.push(client.defaultConfigPath(env));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (clientId === 'cline') {
|
|
28
|
+
if (process.platform === 'win32' && env.APPDATA) {
|
|
29
|
+
filePaths.push(path.join(env.APPDATA, 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json'));
|
|
30
|
+
} else {
|
|
31
|
+
const home = env.HOME || os.homedir();
|
|
32
|
+
if (process.platform === 'darwin') {
|
|
33
|
+
filePaths.push(path.join(home, 'Library', 'Application Support', 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json'));
|
|
34
|
+
}
|
|
35
|
+
filePaths.push(path.join(home, '.config', 'Code', 'User', 'globalStorage', 'saoudrizwan.claude-dev', 'settings', 'cline_mcp_settings.json'));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
for (const filePath of filePaths) {
|
|
40
|
+
if (await fileExists(filePath)) {
|
|
41
|
+
return { detected: true, path: filePath };
|
|
42
|
+
}
|
|
43
|
+
const parentDir = path.dirname(filePath);
|
|
44
|
+
if (await fileExists(parentDir)) {
|
|
45
|
+
return { detected: true, path: filePath };
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return { detected: false };
|
|
50
|
+
}
|
|
51
|
+
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { JSON_MCP_CLIENT_DEFINITIONS } from '../formats/json.js';
|
|
2
|
+
|
|
3
|
+
export function createMcpClients(deps) {
|
|
4
|
+
const clients = new Map();
|
|
5
|
+
|
|
6
|
+
clients.set('codex', {
|
|
7
|
+
label: 'Codex',
|
|
8
|
+
defaultConfigPath: deps.defaultCodexConfigPath,
|
|
9
|
+
buildSnippet: deps.codexTomlSnippet,
|
|
10
|
+
writeConfig: deps.appendTomlServerConfig,
|
|
11
|
+
configKind: 'toml'
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
for (const definition of deps.JSON_MCP_CLIENT_DEFINITIONS) {
|
|
15
|
+
if (definition.id === 'qwen') {
|
|
16
|
+
clients.set('hermes', hermesClient(deps));
|
|
17
|
+
}
|
|
18
|
+
clients.set(definition.id, jsonClient(definition, deps));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (!clients.has('hermes')) {
|
|
22
|
+
clients.set('hermes', hermesClient(deps));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return clients;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function jsonClient(definition, deps) {
|
|
29
|
+
return {
|
|
30
|
+
label: definition.label,
|
|
31
|
+
defaultConfigPath: deps[definition.defaultConfigPath],
|
|
32
|
+
buildSnippet: (mcpUrl, identity) => deps.jsonClientSnippet(definition.id, mcpUrl, identity),
|
|
33
|
+
writeConfig: (configPath, mcpUrl, identity) => deps.mergeJsonClientMcpConfig(definition.id, configPath, mcpUrl, identity),
|
|
34
|
+
configKind: definition.configKind,
|
|
35
|
+
authentication: definition.authentication
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function hermesClient(deps) {
|
|
40
|
+
return {
|
|
41
|
+
label: 'Hermes',
|
|
42
|
+
defaultConfigPath: deps.defaultHermesConfigPath,
|
|
43
|
+
buildSnippet: deps.hermesYamlSnippet,
|
|
44
|
+
writeConfig: deps.mergeHermesMcpConfig,
|
|
45
|
+
configKind: 'yaml'
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function supportedMcpClients(mcpClients) {
|
|
50
|
+
const clients = Array.from(mcpClients.entries()).map(([id, client]) => ({
|
|
51
|
+
id,
|
|
52
|
+
label: client.label,
|
|
53
|
+
configKind: client.configKind
|
|
54
|
+
}));
|
|
55
|
+
clients.push({ id: 'copilot-cli', label: 'Copilot CLI', configKind: 'local-proxy' });
|
|
56
|
+
return clients;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function supportedMcpClientIds(mcpClients) {
|
|
60
|
+
return Array.from(mcpClients.keys());
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function usesClientOAuth(clientId) {
|
|
64
|
+
return JSON_MCP_CLIENT_DEFINITIONS.some(
|
|
65
|
+
(definition) => definition.id === clientId && definition.authentication === 'oauth'
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import {
|
|
2
|
+
appendTomlServerConfig,
|
|
3
|
+
codexTomlSnippet
|
|
4
|
+
} from './formats/toml.js';
|
|
5
|
+
import {
|
|
6
|
+
hermesYamlSnippet,
|
|
7
|
+
mergeHermesMcpConfig
|
|
8
|
+
} from './formats/yaml.js';
|
|
9
|
+
import {
|
|
10
|
+
JSON_MCP_CLIENT_DEFINITIONS,
|
|
11
|
+
jsonClientSnippet,
|
|
12
|
+
mergeJsonClientMcpConfig
|
|
13
|
+
} from './formats/json.js';
|
|
14
|
+
import {
|
|
15
|
+
defaultAntigravity2ConfigPath,
|
|
16
|
+
defaultAntigravityCliConfigPath,
|
|
17
|
+
defaultAntigravityConfigPath,
|
|
18
|
+
defaultAntigravityIdeConfigPath,
|
|
19
|
+
defaultClaudeConfigPath,
|
|
20
|
+
defaultClaudecodeConfigPath,
|
|
21
|
+
defaultClineConfigPath,
|
|
22
|
+
defaultCodexConfigPath,
|
|
23
|
+
defaultContinueConfigPath,
|
|
24
|
+
defaultCursorConfigPath,
|
|
25
|
+
defaultGeminiConfigPath,
|
|
26
|
+
defaultHermesConfigPath,
|
|
27
|
+
defaultJetbrainsConfigPath,
|
|
28
|
+
defaultKiroConfigPath,
|
|
29
|
+
defaultOpencodeConfigPath,
|
|
30
|
+
defaultOpenclawConfigPath,
|
|
31
|
+
defaultQwenConfigPath,
|
|
32
|
+
defaultTraeConfigPath,
|
|
33
|
+
defaultTraeSoloConfigPath,
|
|
34
|
+
defaultWindsurfConfigPath,
|
|
35
|
+
defaultZedConfigPath
|
|
36
|
+
} from '../config/paths.js';
|
|
37
|
+
import {
|
|
38
|
+
createMcpClients,
|
|
39
|
+
supportedMcpClientIds as registrySupportedMcpClientIds,
|
|
40
|
+
supportedMcpClients as registrySupportedMcpClients
|
|
41
|
+
} from './clients/registry.js';
|
|
42
|
+
|
|
43
|
+
export const MCP_CLIENTS = createMcpClients({
|
|
44
|
+
JSON_MCP_CLIENT_DEFINITIONS,
|
|
45
|
+
defaultCodexConfigPath,
|
|
46
|
+
codexTomlSnippet,
|
|
47
|
+
appendTomlServerConfig,
|
|
48
|
+
defaultHermesConfigPath,
|
|
49
|
+
hermesYamlSnippet,
|
|
50
|
+
mergeHermesMcpConfig,
|
|
51
|
+
jsonClientSnippet,
|
|
52
|
+
mergeJsonClientMcpConfig,
|
|
53
|
+
defaultCursorConfigPath,
|
|
54
|
+
defaultGeminiConfigPath,
|
|
55
|
+
defaultAntigravityConfigPath,
|
|
56
|
+
defaultAntigravityIdeConfigPath,
|
|
57
|
+
defaultAntigravity2ConfigPath,
|
|
58
|
+
defaultAntigravityCliConfigPath,
|
|
59
|
+
defaultWindsurfConfigPath,
|
|
60
|
+
defaultClineConfigPath,
|
|
61
|
+
defaultContinueConfigPath,
|
|
62
|
+
defaultClaudeConfigPath,
|
|
63
|
+
defaultOpenclawConfigPath,
|
|
64
|
+
defaultKiroConfigPath,
|
|
65
|
+
defaultZedConfigPath,
|
|
66
|
+
defaultJetbrainsConfigPath,
|
|
67
|
+
defaultOpencodeConfigPath,
|
|
68
|
+
defaultQwenConfigPath,
|
|
69
|
+
defaultTraeConfigPath,
|
|
70
|
+
defaultTraeSoloConfigPath,
|
|
71
|
+
defaultClaudecodeConfigPath
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
export function supportedMcpClients() {
|
|
75
|
+
return registrySupportedMcpClients(MCP_CLIENTS);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function supportedMcpClientIds() {
|
|
79
|
+
return registrySupportedMcpClientIds(MCP_CLIENTS);
|
|
80
|
+
}
|
|
81
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LEGACY_MCP_SERVER_NAMES,
|
|
3
|
+
MCP_SERVER_NAME
|
|
4
|
+
} from '../../core/constants.js';
|
|
5
|
+
|
|
6
|
+
export function knownMcpServerNames() {
|
|
7
|
+
return [MCP_SERVER_NAME, ...LEGACY_MCP_SERVER_NAMES];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function existingJsonMcpServerName(mcpServers) {
|
|
11
|
+
return knownMcpServerNames().find((name) => mcpServers[name]);
|
|
12
|
+
}
|
|
13
|
+
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AGENT_ID_HEADER,
|
|
3
|
+
AGENT_INSTANCE_ENV_VAR,
|
|
4
|
+
AGENT_INSTANCE_HEADER,
|
|
5
|
+
COMMAND_NAME,
|
|
6
|
+
DEFAULT_PROXY_PORT,
|
|
7
|
+
MCP_SERVER_NAME,
|
|
8
|
+
TOKEN_ENV_VAR
|
|
9
|
+
} from '../../core/constants.js';
|
|
10
|
+
import { codexTomlSnippet } from '../formats/toml.js';
|
|
11
|
+
import {
|
|
12
|
+
jsonClientConfig,
|
|
13
|
+
jsonMcpClientDefinition
|
|
14
|
+
} from '../formats/json.js';
|
|
15
|
+
|
|
16
|
+
export function mcpConfigTemplate(clientId, mcpUrl, options = {}) {
|
|
17
|
+
if (clientId === 'codex') {
|
|
18
|
+
return {
|
|
19
|
+
client: clientId,
|
|
20
|
+
serverName: MCP_SERVER_NAME,
|
|
21
|
+
snippetFormat: 'toml',
|
|
22
|
+
snippet: codexTomlSnippet(mcpUrl),
|
|
23
|
+
requiresEnv: [TOKEN_ENV_VAR],
|
|
24
|
+
optionalEnv: [AGENT_INSTANCE_ENV_VAR],
|
|
25
|
+
agentIdentity: {
|
|
26
|
+
agentId: 'codex',
|
|
27
|
+
agentIdHeader: AGENT_ID_HEADER,
|
|
28
|
+
agentInstanceEnvVar: AGENT_INSTANCE_ENV_VAR,
|
|
29
|
+
agentInstanceHeader: AGENT_INSTANCE_HEADER
|
|
30
|
+
},
|
|
31
|
+
agentInstanceGeneration: agentInstanceGenerationPolicy(clientId, options),
|
|
32
|
+
writesTokenValue: false
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const jsonDefinition = jsonMcpClientDefinition(clientId);
|
|
37
|
+
if (jsonDefinition) {
|
|
38
|
+
return jsonDefinition.authentication === 'oauth'
|
|
39
|
+
? oauthJsonMcpTemplate(clientId, mcpUrl, jsonClientConfig(clientId, mcpUrl), options)
|
|
40
|
+
: bearerJsonMcpTemplate(clientId, mcpUrl, jsonClientConfig(clientId, mcpUrl), options);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
client: clientId,
|
|
45
|
+
serverName: MCP_SERVER_NAME,
|
|
46
|
+
snippetFormat: 'json',
|
|
47
|
+
snippet: {
|
|
48
|
+
mcpServers: {
|
|
49
|
+
[MCP_SERVER_NAME]: {
|
|
50
|
+
type: 'http',
|
|
51
|
+
url: mcpUrl,
|
|
52
|
+
headers: {
|
|
53
|
+
Authorization: `Bearer \${${TOKEN_ENV_VAR}}`,
|
|
54
|
+
[AGENT_ID_HEADER]: clientId,
|
|
55
|
+
[AGENT_INSTANCE_HEADER]: `\${${AGENT_INSTANCE_ENV_VAR}}`
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
requiresEnv: [TOKEN_ENV_VAR],
|
|
61
|
+
optionalEnv: [AGENT_INSTANCE_ENV_VAR],
|
|
62
|
+
agentIdentity: {
|
|
63
|
+
agentId: clientId,
|
|
64
|
+
agentIdHeader: AGENT_ID_HEADER,
|
|
65
|
+
agentInstanceEnvVar: AGENT_INSTANCE_ENV_VAR,
|
|
66
|
+
agentInstanceHeader: AGENT_INSTANCE_HEADER
|
|
67
|
+
},
|
|
68
|
+
agentInstanceGeneration: agentInstanceGenerationPolicy(clientId, options),
|
|
69
|
+
writesTokenValue: false
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function mcpLocalProxyTemplate(clientId, proxyUrl, options = {}) {
|
|
74
|
+
return {
|
|
75
|
+
client: clientId,
|
|
76
|
+
serverName: MCP_SERVER_NAME,
|
|
77
|
+
snippetFormat: 'json',
|
|
78
|
+
snippet: {
|
|
79
|
+
mcpServers: {
|
|
80
|
+
[MCP_SERVER_NAME]: {
|
|
81
|
+
type: 'http',
|
|
82
|
+
url: proxyUrl
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
requiresCredential: [`${COMMAND_NAME} login`, `${COMMAND_NAME} token add --from-stdin`],
|
|
87
|
+
requiresLocalCommand: `${COMMAND_NAME} mcp proxy --port ${new URL(proxyUrl).port || DEFAULT_PROXY_PORT}`,
|
|
88
|
+
agentIdentity: {
|
|
89
|
+
agentId: clientId,
|
|
90
|
+
agentIdHeader: AGENT_ID_HEADER,
|
|
91
|
+
agentInstanceEnvVar: AGENT_INSTANCE_ENV_VAR,
|
|
92
|
+
agentInstanceHeader: AGENT_INSTANCE_HEADER
|
|
93
|
+
},
|
|
94
|
+
agentInstanceGeneration: agentInstanceGenerationPolicy(clientId, options),
|
|
95
|
+
writesTokenValue: false
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function agentInstanceGenerationPolicy(clientId, options = {}) {
|
|
100
|
+
const automaticCommand = options.mcpClients?.has(clientId)
|
|
101
|
+
? `${COMMAND_NAME} mcp add ${clientId} --write`
|
|
102
|
+
: clientId === 'copilot-cli'
|
|
103
|
+
? `${COMMAND_NAME} setup copilot --write`
|
|
104
|
+
: null;
|
|
105
|
+
return {
|
|
106
|
+
requiredForHeaders: true,
|
|
107
|
+
stablePerInstall: true,
|
|
108
|
+
automaticCommand,
|
|
109
|
+
generatedPattern: `xmemo-${clientId}-<uuid>`,
|
|
110
|
+
storagePath: `~/.config/xmemo/agent-instances/${clientId}.json`,
|
|
111
|
+
manualEnvVar: AGENT_INSTANCE_ENV_VAR
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function bearerJsonMcpTemplate(clientId, mcpUrl, snippet, options) {
|
|
116
|
+
return {
|
|
117
|
+
client: clientId,
|
|
118
|
+
serverName: MCP_SERVER_NAME,
|
|
119
|
+
snippetFormat: 'json',
|
|
120
|
+
snippet,
|
|
121
|
+
requiresEnv: [TOKEN_ENV_VAR],
|
|
122
|
+
optionalEnv: [AGENT_INSTANCE_ENV_VAR],
|
|
123
|
+
authentication: 'env-bearer',
|
|
124
|
+
agentIdentity: {
|
|
125
|
+
agentId: clientId,
|
|
126
|
+
agentIdHeader: AGENT_ID_HEADER,
|
|
127
|
+
agentInstanceEnvVar: AGENT_INSTANCE_ENV_VAR,
|
|
128
|
+
agentInstanceHeader: AGENT_INSTANCE_HEADER
|
|
129
|
+
},
|
|
130
|
+
agentInstanceGeneration: agentInstanceGenerationPolicy(clientId, options),
|
|
131
|
+
mcpUrl,
|
|
132
|
+
writesTokenValue: false
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function oauthJsonMcpTemplate(clientId, mcpUrl, snippet, options) {
|
|
137
|
+
return {
|
|
138
|
+
client: clientId,
|
|
139
|
+
serverName: MCP_SERVER_NAME,
|
|
140
|
+
snippetFormat: 'json',
|
|
141
|
+
snippet,
|
|
142
|
+
requiresEnv: [],
|
|
143
|
+
optionalEnv: [AGENT_INSTANCE_ENV_VAR],
|
|
144
|
+
authentication: 'oauth',
|
|
145
|
+
agentIdentity: {
|
|
146
|
+
agentId: clientId,
|
|
147
|
+
agentIdHeader: AGENT_ID_HEADER,
|
|
148
|
+
agentInstanceEnvVar: AGENT_INSTANCE_ENV_VAR,
|
|
149
|
+
agentInstanceHeader: AGENT_INSTANCE_HEADER
|
|
150
|
+
},
|
|
151
|
+
agentInstanceGeneration: agentInstanceGenerationPolicy(clientId, options),
|
|
152
|
+
mcpUrl,
|
|
153
|
+
writesTokenValue: false
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|