spacecode 2.5.6 → 2.5.7
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/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/repl.mjs +119 -0
- package/package.json +1 -1
package/dist/repl.mjs
CHANGED
|
@@ -4988,6 +4988,76 @@ var init_skill_file = __esm({
|
|
|
4988
4988
|
}
|
|
4989
4989
|
});
|
|
4990
4990
|
|
|
4991
|
+
// ../agent/src/import/claude-json-mcp.ts
|
|
4992
|
+
function normalizeClaudeJsonMcp(text, projectPaths) {
|
|
4993
|
+
const errors = [];
|
|
4994
|
+
let parsed;
|
|
4995
|
+
try {
|
|
4996
|
+
parsed = JSON.parse(text);
|
|
4997
|
+
} catch (err) {
|
|
4998
|
+
if (!(err instanceof SyntaxError)) throw err;
|
|
4999
|
+
return { servers: [], errors: ["not valid JSON"] };
|
|
5000
|
+
}
|
|
5001
|
+
const root = asObject(parsed) ?? {};
|
|
5002
|
+
const serverMap = /* @__PURE__ */ new Map();
|
|
5003
|
+
const processEntry = (name, raw, scope) => {
|
|
5004
|
+
const entry = asObject(raw);
|
|
5005
|
+
if (!entry) {
|
|
5006
|
+
errors.push(`${name}: not an object`);
|
|
5007
|
+
return;
|
|
5008
|
+
}
|
|
5009
|
+
const hasUrl = typeof entry.url === "string";
|
|
5010
|
+
const hasCommand = typeof entry.command === "string";
|
|
5011
|
+
let transport;
|
|
5012
|
+
let url = "";
|
|
5013
|
+
let command = "";
|
|
5014
|
+
let args = [];
|
|
5015
|
+
if (hasUrl && !hasCommand) {
|
|
5016
|
+
transport = "http";
|
|
5017
|
+
url = entry.url;
|
|
5018
|
+
} else if (hasCommand) {
|
|
5019
|
+
transport = "stdio";
|
|
5020
|
+
command = entry.command;
|
|
5021
|
+
if (Array.isArray(entry.args)) args = entry.args.filter((a) => typeof a === "string");
|
|
5022
|
+
} else {
|
|
5023
|
+
errors.push(`${name}: needs a command or a url`);
|
|
5024
|
+
return;
|
|
5025
|
+
}
|
|
5026
|
+
const rawEnv = transport === "http" ? asObject(entry.headers) : asObject(entry.env);
|
|
5027
|
+
const env3 = {};
|
|
5028
|
+
const literalKeys = /* @__PURE__ */ new Set();
|
|
5029
|
+
if (rawEnv) {
|
|
5030
|
+
for (const [k2, v2] of Object.entries(rawEnv)) {
|
|
5031
|
+
if (typeof v2 !== "string") continue;
|
|
5032
|
+
if (v2.includes("${")) {
|
|
5033
|
+
env3[k2] = v2;
|
|
5034
|
+
} else {
|
|
5035
|
+
env3[k2] = "${" + literalVarName(name, k2) + "}";
|
|
5036
|
+
literalKeys.add(k2);
|
|
5037
|
+
}
|
|
5038
|
+
}
|
|
5039
|
+
}
|
|
5040
|
+
serverMap.set(name, { name, scope, transport, command, args, url, env: env3, literalKeys: [...literalKeys].sort() });
|
|
5041
|
+
};
|
|
5042
|
+
for (const [name, raw] of Object.entries(asObject(root.mcpServers) ?? {})) processEntry(name, raw, "user");
|
|
5043
|
+
const projects = asObject(root.projects) ?? {};
|
|
5044
|
+
for (const p of projectPaths) {
|
|
5045
|
+
const servers = asObject(asObject(projects[p])?.mcpServers);
|
|
5046
|
+
if (!servers) continue;
|
|
5047
|
+
for (const [name, raw] of Object.entries(servers)) processEntry(name, raw, "project");
|
|
5048
|
+
}
|
|
5049
|
+
return { servers: [...serverMap.values()].sort((a, b2) => a.name < b2.name ? -1 : a.name > b2.name ? 1 : 0), errors };
|
|
5050
|
+
}
|
|
5051
|
+
var sanitize, literalVarName, asObject;
|
|
5052
|
+
var init_claude_json_mcp = __esm({
|
|
5053
|
+
"../agent/src/import/claude-json-mcp.ts"() {
|
|
5054
|
+
"use strict";
|
|
5055
|
+
sanitize = (s) => s.toUpperCase().replace(/[^A-Z0-9_]/g, "_");
|
|
5056
|
+
literalVarName = (server, key) => `MCP_${sanitize(server)}_${sanitize(key)}`;
|
|
5057
|
+
asObject = (v2) => v2 && typeof v2 === "object" && !Array.isArray(v2) ? v2 : void 0;
|
|
5058
|
+
}
|
|
5059
|
+
});
|
|
5060
|
+
|
|
4991
5061
|
// ../agent/src/import/tool-names.ts
|
|
4992
5062
|
function translateToolNames(text) {
|
|
4993
5063
|
const counts = /* @__PURE__ */ new Map();
|
|
@@ -5169,6 +5239,7 @@ async function readClaudeAssets({ fs: fs6, home, projectDirs }) {
|
|
|
5169
5239
|
}
|
|
5170
5240
|
await readCommands(fs6, home, report);
|
|
5171
5241
|
await readSkills(fs6, home, report);
|
|
5242
|
+
await readMcpServers(fs6, home, projectDirs, report);
|
|
5172
5243
|
for (const dir of projectDirs) {
|
|
5173
5244
|
const memDir = `${home}/.claude/projects/${claudeProjectSlug(dir)}/memory`;
|
|
5174
5245
|
let entries;
|
|
@@ -5311,12 +5382,51 @@ async function readSkills(fs6, home, report) {
|
|
|
5311
5382
|
report.assets.push({ kind: "skill", name: parsed.name, description: parsed.description, content: text, source: skillPath }, ...siblings);
|
|
5312
5383
|
}
|
|
5313
5384
|
}
|
|
5385
|
+
async function readMcpServers(fs6, home, projectDirs, report) {
|
|
5386
|
+
const path12 = `${home}/.claude.json`;
|
|
5387
|
+
const text = await readOptional(fs6, path12, report);
|
|
5388
|
+
if (text === null) return;
|
|
5389
|
+
const { servers, errors } = normalizeClaudeJsonMcp(text, projectDirs);
|
|
5390
|
+
for (const e of errors) report.errors.push({ path: path12, message: e });
|
|
5391
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5392
|
+
for (const s of servers) {
|
|
5393
|
+
if (!NAME_RE3.test(s.name)) {
|
|
5394
|
+
report.errors.push({ path: path12, message: `MCP server name "${s.name}" must use only letters, digits, . _ - (max 100)` });
|
|
5395
|
+
continue;
|
|
5396
|
+
}
|
|
5397
|
+
if (seen.has(s.name.toLowerCase())) {
|
|
5398
|
+
report.errors.push({ path: path12, message: `MCP server name collision on "${s.name}" (names are case-insensitive)` });
|
|
5399
|
+
continue;
|
|
5400
|
+
}
|
|
5401
|
+
seen.add(s.name.toLowerCase());
|
|
5402
|
+
const { literalKeys, ...def } = s;
|
|
5403
|
+
const content = JSON.stringify(def, null, 2);
|
|
5404
|
+
if (Buffer.byteLength(content, "utf8") > MAX_ASSET_BYTES) {
|
|
5405
|
+
report.errors.push({ path: path12, message: `MCP server "${s.name}" skipped: over the ${MAX_ASSET_BYTES} byte asset limit` });
|
|
5406
|
+
continue;
|
|
5407
|
+
}
|
|
5408
|
+
if (literalKeys.length > 0) {
|
|
5409
|
+
report.notes.push(`MCP server "${s.name}": literal values for ${literalKeys.join(", ")} were NOT imported; set ${literalKeys.map((k2) => literalVarName(s.name, k2)).join(", ")} in your environment`);
|
|
5410
|
+
}
|
|
5411
|
+
if (s.transport === "http" && /[?@]/.test(s.url.replace(/^https?:\/\//, ""))) {
|
|
5412
|
+
report.notes.push(`MCP server "${s.name}": its url contains a query string or credentials, which are stored as written; move any token into a header or environment variable`);
|
|
5413
|
+
}
|
|
5414
|
+
report.assets.push({
|
|
5415
|
+
kind: "mcp",
|
|
5416
|
+
name: s.name,
|
|
5417
|
+
description: s.transport === "stdio" ? `stdio: ${s.command}` : `http: ${s.url}`,
|
|
5418
|
+
content,
|
|
5419
|
+
source: `${path12} (${s.scope})`
|
|
5420
|
+
});
|
|
5421
|
+
}
|
|
5422
|
+
}
|
|
5314
5423
|
var MAX_ASSET_BYTES, NAME_RE3, COMMAND_NAME_RE, SKILL_NAME_RE, MAX_SKILL_FILES;
|
|
5315
5424
|
var init_claude_sources = __esm({
|
|
5316
5425
|
"../agent/src/import/claude-sources.ts"() {
|
|
5317
5426
|
"use strict";
|
|
5318
5427
|
init_command_file();
|
|
5319
5428
|
init_skill_file();
|
|
5429
|
+
init_claude_json_mcp();
|
|
5320
5430
|
init_skill_source();
|
|
5321
5431
|
MAX_ASSET_BYTES = 256 * 1024;
|
|
5322
5432
|
NAME_RE3 = /^[A-Za-z0-9._-]{1,100}$/;
|
|
@@ -6135,6 +6245,13 @@ var init_mcp_json_summary = __esm({
|
|
|
6135
6245
|
}
|
|
6136
6246
|
});
|
|
6137
6247
|
|
|
6248
|
+
// ../agent/src/import/mcp-env-expand.ts
|
|
6249
|
+
var init_mcp_env_expand = __esm({
|
|
6250
|
+
"../agent/src/import/mcp-env-expand.ts"() {
|
|
6251
|
+
"use strict";
|
|
6252
|
+
}
|
|
6253
|
+
});
|
|
6254
|
+
|
|
6138
6255
|
// ../agent/src/index.ts
|
|
6139
6256
|
var init_src = __esm({
|
|
6140
6257
|
"../agent/src/index.ts"() {
|
|
@@ -6184,6 +6301,8 @@ var init_src = __esm({
|
|
|
6184
6301
|
init_skill_tool();
|
|
6185
6302
|
init_skill_source();
|
|
6186
6303
|
init_mcp_json_summary();
|
|
6304
|
+
init_mcp_env_expand();
|
|
6305
|
+
init_claude_json_mcp();
|
|
6187
6306
|
}
|
|
6188
6307
|
});
|
|
6189
6308
|
|