spacecode 2.12.0 → 2.12.3

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/repl.mjs CHANGED
@@ -6904,6 +6904,164 @@ var init_mcp_rpc_pending = __esm({
6904
6904
  }
6905
6905
  });
6906
6906
 
6907
+ // ../agent/src/import/mcp-sse-parser.ts
6908
+ function createSseParser(onData) {
6909
+ let buffer = "";
6910
+ let dataLines = [];
6911
+ let skipLf = false;
6912
+ function handleLine(line) {
6913
+ if (line === "") {
6914
+ if (dataLines.length === 0) return;
6915
+ const payload = dataLines.join("\n");
6916
+ dataLines = [];
6917
+ onData(payload);
6918
+ return;
6919
+ }
6920
+ if (line.startsWith(":")) return;
6921
+ const colon = line.indexOf(":");
6922
+ if (colon === -1) {
6923
+ if (line === "data") dataLines.push("");
6924
+ return;
6925
+ }
6926
+ if (line.slice(0, colon) !== "data") return;
6927
+ const value = line.slice(colon + 1);
6928
+ dataLines.push(value.startsWith(" ") ? value.slice(1) : value);
6929
+ }
6930
+ return {
6931
+ push(chunk) {
6932
+ buffer += chunk;
6933
+ let start = 0;
6934
+ for (let i = 0; i < buffer.length; i++) {
6935
+ const ch = buffer[i];
6936
+ if (skipLf && i === start && ch === "\n") {
6937
+ skipLf = false;
6938
+ start = i + 1;
6939
+ continue;
6940
+ }
6941
+ skipLf = false;
6942
+ if (ch === "\n") {
6943
+ handleLine(buffer.slice(start, i));
6944
+ start = i + 1;
6945
+ } else if (ch === "\r") {
6946
+ handleLine(buffer.slice(start, i));
6947
+ start = i + 1;
6948
+ if (buffer[i + 1] === "\n") i++, start++;
6949
+ else if (i + 1 === buffer.length) skipLf = true;
6950
+ }
6951
+ }
6952
+ buffer = buffer.slice(start);
6953
+ },
6954
+ end() {
6955
+ buffer = "";
6956
+ dataLines = [];
6957
+ skipLf = false;
6958
+ }
6959
+ };
6960
+ }
6961
+ var init_mcp_sse_parser = __esm({
6962
+ "../agent/src/import/mcp-sse-parser.ts"() {
6963
+ "use strict";
6964
+ }
6965
+ });
6966
+
6967
+ // ../agent/src/import/mcp-http-transport.ts
6968
+ function createHttpTransport(opts) {
6969
+ const aborter = new AbortController();
6970
+ let sessionId = null;
6971
+ let closed = false;
6972
+ let reported = false;
6973
+ const fail = (reason) => {
6974
+ if (closed || reported) return;
6975
+ reported = true;
6976
+ closed = true;
6977
+ aborter.abort();
6978
+ opts.onClose(reason);
6979
+ };
6980
+ const deliver = (parsed) => {
6981
+ for (const m2 of Array.isArray(parsed) ? parsed : [parsed]) opts.onMessage(m2);
6982
+ };
6983
+ const headers = () => ({
6984
+ ...opts.headers,
6985
+ "content-type": "application/json",
6986
+ accept: "application/json, text/event-stream",
6987
+ "mcp-protocol-version": opts.protocolVersion,
6988
+ ...sessionId !== null ? { "mcp-session-id": sessionId } : {}
6989
+ });
6990
+ async function readStream(res) {
6991
+ if (!res.body) return;
6992
+ const decoder = new TextDecoder();
6993
+ const parser = createSseParser((data) => {
6994
+ let parsed;
6995
+ try {
6996
+ parsed = JSON.parse(data);
6997
+ } catch (err) {
6998
+ if (!(err instanceof SyntaxError)) throw err;
6999
+ return;
7000
+ }
7001
+ deliver(parsed);
7002
+ });
7003
+ for await (const chunk of res.body) parser.push(decoder.decode(chunk, { stream: true }));
7004
+ parser.push(decoder.decode());
7005
+ parser.end();
7006
+ }
7007
+ async function post(message) {
7008
+ const hadSession = sessionId !== null;
7009
+ let res;
7010
+ try {
7011
+ res = await opts.fetch(opts.url, { method: "POST", headers: headers(), body: JSON.stringify(message), signal: aborter.signal });
7012
+ } catch (err) {
7013
+ return fail(`request failed: ${err instanceof Error ? err.name : "error"}`);
7014
+ }
7015
+ if (closed) return;
7016
+ if (res.status === 401 || res.status === 403) return fail("needs authorization (OAuth is not supported)");
7017
+ if (res.status === 404 && hadSession) return fail("session expired");
7018
+ if (res.status >= 400) return fail(`HTTP ${res.status}`);
7019
+ const sid = res.headers.get("mcp-session-id");
7020
+ if (sessionId === null && sid) sessionId = sid;
7021
+ if (res.status === 202) return;
7022
+ const type = (res.headers.get("content-type") ?? "").toLowerCase();
7023
+ try {
7024
+ if (type.startsWith("text/event-stream")) await readStream(res);
7025
+ else if (type.startsWith("application/json")) {
7026
+ let parsed;
7027
+ try {
7028
+ parsed = JSON.parse(await res.text());
7029
+ } catch (err) {
7030
+ if (!(err instanceof SyntaxError)) throw err;
7031
+ return fail("invalid JSON in response");
7032
+ }
7033
+ deliver(parsed);
7034
+ }
7035
+ } catch (err) {
7036
+ fail(`request failed: ${err instanceof Error ? err.name : "error"}`);
7037
+ }
7038
+ }
7039
+ return {
7040
+ send(message) {
7041
+ if (closed) throw new Error(CLOSED);
7042
+ void post(message);
7043
+ },
7044
+ async close() {
7045
+ if (closed) return;
7046
+ closed = true;
7047
+ aborter.abort();
7048
+ if (sessionId === null) return;
7049
+ try {
7050
+ await opts.fetch(opts.url, { method: "DELETE", headers: { ...opts.headers, "mcp-protocol-version": opts.protocolVersion, "mcp-session-id": sessionId } });
7051
+ } catch {
7052
+ }
7053
+ }
7054
+ };
7055
+ }
7056
+ var CLOSED;
7057
+ var init_mcp_http_transport = __esm({
7058
+ "../agent/src/import/mcp-http-transport.ts"() {
7059
+ "use strict";
7060
+ init_mcp_sse_parser();
7061
+ CLOSED = "MCP server connection is closed";
7062
+ }
7063
+ });
7064
+
6907
7065
  // ../agent/src/import/mcp-rpc.ts
6908
7066
  function createRpcSession(deps) {
6909
7067
  const pending = new PendingRequests();
@@ -7152,6 +7310,8 @@ var init_src = __esm({
7152
7310
  init_claude_json_mcp();
7153
7311
  init_mcp_rpc_message();
7154
7312
  init_mcp_rpc_pending();
7313
+ init_mcp_sse_parser();
7314
+ init_mcp_http_transport();
7155
7315
  init_mcp_rpc();
7156
7316
  init_mcp_tool_result();
7157
7317
  init_mcp_client();
@@ -7809,7 +7969,7 @@ var init_import_claude = __esm({
7809
7969
  init_api_key();
7810
7970
  init_profile_runtime();
7811
7971
  init_import_adapt();
7812
- USAGE = "Usage: spacecode import-claude [--dry-run] [--overwrite] [--no-adapt] [--yes] [--restore-original]";
7972
+ USAGE = "Usage: spacecode import claude [--dry-run] [--overwrite] [--no-adapt] [--yes] [--restore-original]";
7813
7973
  }
7814
7974
  });
7815
7975
 
@@ -7924,6 +8084,18 @@ var init_stdio_transport = __esm({
7924
8084
  function approvalEnv(env3) {
7925
8085
  return Object.entries(env3).map(([k2, v2]) => `${k2}=${v2}`).sort();
7926
8086
  }
8087
+ function approvalKey(def) {
8088
+ const envNames = approvalEnv(def.env);
8089
+ return def.transport === "http" ? { command: `mcp-http:${def.url}`, args: [], envNames } : { command: def.command, args: def.args, envNames };
8090
+ }
8091
+ function isSafeMcpUrl(url) {
8092
+ try {
8093
+ const u3 = new URL(url);
8094
+ return u3.protocol === "https:" || u3.protocol === "http:" && ["localhost", "127.0.0.1", "[::1]"].includes(u3.hostname);
8095
+ } catch {
8096
+ return false;
8097
+ }
8098
+ }
7927
8099
  function mcpToolName(server, tool) {
7928
8100
  return `mcp__${sanitize2(server)}__${sanitize2(tool)}`;
7929
8101
  }
@@ -7981,11 +8153,10 @@ var init_mcp_manager = __esm({
7981
8153
  }
7982
8154
  for (const def of this.deps.defs) {
7983
8155
  try {
7984
- if (def.transport !== "stdio") continue;
7985
- const envNames = approvalEnv(def.env);
7986
- if (!await this.deps.isStdioApproved({ command: def.command, args: def.args, envNames })) continue;
7987
- if (!expandServerEnv({ command: def.command, args: def.args, env: def.env }, this.deps.env).ok) continue;
7988
- const hit = getCachedTools(this.cache, serverCacheKey({ name: def.name, command: def.command, args: def.args, envNames }, tc.hash));
8156
+ const key = approvalKey(def);
8157
+ if (!await this.deps.isStdioApproved(key)) continue;
8158
+ if (!expandServerEnv({ command: def.transport === "http" ? def.url : def.command, args: def.args, env: def.env }, this.deps.env).ok) continue;
8159
+ const hit = getCachedTools(this.cache, serverCacheKey({ name: def.name, ...key }, tc.hash));
7989
8160
  if (hit) this.cachedTools.set(def.name, this.usable(def.name, hit).tools);
7990
8161
  } catch (err) {
7991
8162
  this.cacheNotes.push(`${def.name}: cached tools skipped (${err instanceof Error ? err.message : String(err)})`);
@@ -8038,7 +8209,7 @@ var init_mcp_manager = __esm({
8038
8209
  if (!tc) return Promise.resolve();
8039
8210
  this.cacheWrite = this.cacheWrite.then(async () => {
8040
8211
  try {
8041
- const key = serverCacheKey({ name: def.name, command: def.command, args: def.args, envNames: approvalEnv(def.env) }, tc.hash);
8212
+ const key = serverCacheKey({ name: def.name, ...approvalKey(def) }, tc.hash);
8042
8213
  const next = putCachedTools(this.cache, key, tools.map((t) => ({ name: t.name, description: t.description, inputSchema: t.inputSchema })));
8043
8214
  if (next === this.cache) return;
8044
8215
  await tc.write(serializeToolCache(next));
@@ -8053,38 +8224,56 @@ var init_mcp_manager = __esm({
8053
8224
  const name = def.name;
8054
8225
  const skip = (reason) => void this.servers.set(name, { name, def, status: "skipped", reason });
8055
8226
  const fail = (reason) => void this.servers.set(name, { name, def, status: "failed", reason });
8056
- if (def.transport !== "stdio") return skip("http servers are not supported yet");
8057
- const envNames = approvalEnv(def.env);
8227
+ const http = def.transport === "http";
8228
+ if (http && !isSafeMcpUrl(def.url)) return skip("its URL must be https (or localhost)");
8229
+ const key = approvalKey(def);
8058
8230
  let approved;
8059
8231
  try {
8060
- approved = await this.deps.isStdioApproved({ command: def.command, args: def.args, envNames });
8232
+ approved = await this.deps.isStdioApproved(key);
8061
8233
  } catch (err) {
8062
8234
  return fail(`approval check failed: ${err instanceof Error ? err.message : String(err)}`);
8063
8235
  }
8064
- if (!approved) return skip(`its command is not approved on this machine (${def.origin} definition)`);
8065
- const expanded = expandServerEnv({ command: def.command, args: def.args, env: def.env }, this.deps.env);
8236
+ if (!approved) return skip(`its ${http ? "URL and headers are" : "command is"} not approved on this machine (${def.origin} definition)`);
8237
+ const expanded = expandServerEnv({ command: http ? def.url : def.command, args: def.args, env: def.env }, this.deps.env);
8066
8238
  if (!expanded.ok) return skip(`set ${expanded.missing.join(", ")} in your environment`);
8239
+ if (http && !isSafeMcpUrl(expanded.command)) return skip("its URL must be https (or localhost)");
8067
8240
  this.servers.set(name, { name, def, status: "connecting" });
8068
8241
  let transport;
8069
8242
  try {
8070
8243
  let session2;
8071
8244
  let closeReason = null;
8072
- transport = (this.deps.start ?? startStdioTransport)({
8073
- command: expanded.command,
8074
- args: expanded.args,
8075
- env: expanded.env,
8076
- cwd: this.deps.cwd,
8077
- onMessage: (m2) => void session2.handleMessage(m2),
8078
- onClose: (reason) => {
8079
- closeReason = reason;
8080
- session2.close(reason);
8081
- const cur = this.servers.get(name);
8082
- if (cur?.status === "ready") this.servers.set(name, { name, def, status: "failed", reason: `server ${reason}` });
8083
- }
8084
- });
8085
- const t = transport;
8245
+ const onClose = (reason) => {
8246
+ closeReason = reason;
8247
+ session2.close(reason);
8248
+ const cur = this.servers.get(name);
8249
+ if (cur?.status === "ready") this.servers.set(name, { name, def, status: "failed", reason: `server ${reason}` });
8250
+ };
8251
+ let send;
8252
+ if (http) {
8253
+ const t = createHttpTransport({
8254
+ url: expanded.command,
8255
+ headers: expanded.env,
8256
+ fetch: this.deps.fetch ?? ((url, init) => fetch(url, { ...init, redirect: "error" })),
8257
+ protocolVersion: MCP_PROTOCOL_VERSION,
8258
+ onMessage: (m2) => void session2.handleMessage(m2),
8259
+ onClose
8260
+ });
8261
+ transport = t;
8262
+ send = (m2) => t.send(m2);
8263
+ } else {
8264
+ const t = (this.deps.start ?? startStdioTransport)({
8265
+ command: expanded.command,
8266
+ args: expanded.args,
8267
+ env: expanded.env,
8268
+ cwd: this.deps.cwd,
8269
+ onMessage: (m2) => void session2.handleMessage(m2),
8270
+ onClose
8271
+ });
8272
+ transport = t;
8273
+ send = (m2) => t.send(m2);
8274
+ }
8086
8275
  session2 = createRpcSession({
8087
- send: (m2) => t.send(m2),
8276
+ send,
8088
8277
  setTimer: (fn, ms) => setTimeout(fn, ms),
8089
8278
  clearTimer: (h) => clearTimeout(h)
8090
8279
  });
@@ -8208,10 +8397,10 @@ var init_mcp_manager = __esm({
8208
8397
  async function runApproveMcp(deps) {
8209
8398
  const { defs, statusLines } = await loadMcpDefs(deps);
8210
8399
  if (!deps.quiet) for (const l of statusLines) deps.log(l);
8211
- const stdio = defs.filter((d) => d.transport === "stdio");
8400
+ const stdio = defs;
8212
8401
  const todo = [];
8213
8402
  for (const d of stdio) {
8214
- const key = { command: d.command, args: d.args, envNames: approvalEnv(d.env) };
8403
+ const key = approvalKey(d);
8215
8404
  if (await deps.trust.stdioStatus(key) === "unapproved") todo.push(d);
8216
8405
  }
8217
8406
  if (todo.length === 0) {
@@ -8226,13 +8415,18 @@ async function runApproveMcp(deps) {
8226
8415
  ${todo.length} imported MCP server(s) want to run a command on this machine. Nothing spawns until you approve it (you can also run \`spacecode approve-mcp\` later).`);
8227
8416
  let approved = 0;
8228
8417
  for (const d of todo) {
8229
- deps.log(`
8418
+ deps.log(
8419
+ d.transport === "http" ? `
8420
+ MCP server ${show(d.name)} (${d.origin} definition) wants to connect from this machine to:
8421
+ ${show(d.url)}
8422
+ headers it will send (NAME=where the value comes from): ${approvalEnv(d.env).join(", ") || "(none)"}` : `
8230
8423
  MCP server ${show(d.name)} (${d.origin} definition) wants to run on this machine:
8231
8424
  ${show(d.command)} ${d.args.map(show).join(" ")}
8232
- environment it will receive (NAME=where the value comes from): ${approvalEnv(d.env).join(", ") || "(none)"}`);
8233
- const answer = (await deps.ask("Approve this command? [y/N] ") ?? "").trim().toLowerCase();
8425
+ environment it will receive (NAME=where the value comes from): ${approvalEnv(d.env).join(", ") || "(none)"}`
8426
+ );
8427
+ const answer = (await deps.ask("Approve? [y/N] ") ?? "").trim().toLowerCase();
8234
8428
  if (answer === "y" || answer === "yes") {
8235
- await deps.trust.approveStdio({ command: d.command, args: d.args, envNames: approvalEnv(d.env) });
8429
+ await deps.trust.approveStdio(approvalKey(d));
8236
8430
  deps.log(" approved");
8237
8431
  approved++;
8238
8432
  } else deps.log(" not approved");
@@ -35864,7 +36058,7 @@ var require_websocket_server = __commonJS({
35864
36058
  var keyRegex = /^[+/0-9A-Za-z]{22}==$/;
35865
36059
  var RUNNING = 0;
35866
36060
  var CLOSING = 1;
35867
- var CLOSED = 2;
36061
+ var CLOSED2 = 2;
35868
36062
  var WebSocketServer2 = class extends EventEmitter3 {
35869
36063
  /**
35870
36064
  * Create a `WebSocketServer` instance.
@@ -35993,7 +36187,7 @@ var require_websocket_server = __commonJS({
35993
36187
  * @public
35994
36188
  */
35995
36189
  close(cb) {
35996
- if (this._state === CLOSED) {
36190
+ if (this._state === CLOSED2) {
35997
36191
  if (cb) {
35998
36192
  this.once("close", () => {
35999
36193
  cb(new Error("The server is not running"));
@@ -36217,7 +36411,7 @@ var require_websocket_server = __commonJS({
36217
36411
  };
36218
36412
  }
36219
36413
  function emitClose(server) {
36220
- server._state = CLOSED;
36414
+ server._state = CLOSED2;
36221
36415
  server.emit("close");
36222
36416
  }
36223
36417
  function socketOnError() {
@@ -104173,7 +104367,7 @@ Skills are loaded on demand with the skill tool; bodies are not in the prompt. /
104173
104367
  (a) => a.kind === "skill" && (a.name === name || a.name.startsWith(`${name}.`) && a.description.startsWith(SIBLING_PREFIX))
104174
104368
  );
104175
104369
  for (const a of assets) await deps.client.delete("skill", a.name);
104176
- return `Deleted skill "${name}" and ${assets.length - 1} file(s) from the profile. Re-running import-claude would import it again.`;
104370
+ return `Deleted skill "${name}" and ${assets.length - 1} file(s) from the profile. Re-running "spacecode import claude" would import it again.`;
104177
104371
  }
104178
104372
  return "Usage: /skills | /skills show <name> [file] | /skills delete <name>";
104179
104373
  }
@@ -104418,9 +104612,24 @@ async function runCoreTurn(d, prompt) {
104418
104612
  ...body === void 0 ? {} : { body: JSON.stringify(body) },
104419
104613
  signal: d.signal
104420
104614
  });
104421
- if (!res.ok) throw new CoreTurnError(`core run request failed (${res.status}) ${method} ${path13.split("?")[0]}`);
104615
+ if (!res.ok) throw new CoreTurnError(`core run request failed (${res.status}) ${method} ${path13.split("?")[0]}`, res.status);
104422
104616
  return res.json();
104423
104617
  };
104618
+ const poll = async (path13) => {
104619
+ for (let attempt = 0; ; attempt++) {
104620
+ try {
104621
+ return await call("GET", path13);
104622
+ } catch (err) {
104623
+ const transient = err instanceof CoreTurnError && err.status !== void 0 && err.status >= 500;
104624
+ if (!transient || d.signal.aborted) throw err;
104625
+ if (attempt >= POLL_RETRIES) throw new CoreTurnError(`${err.message} (gave up after ${POLL_RETRIES} retries)`, err.status);
104626
+ d.emit({ type: "text", seq: ++seq, content: `(run service answered ${err.status}; retry ${attempt + 1}/${POLL_RETRIES})
104627
+
104628
+ ` });
104629
+ await d.sleep(Math.min(8e3, 1e3 * 2 ** attempt));
104630
+ }
104631
+ }
104632
+ };
104424
104633
  let runId = d.getRunId();
104425
104634
  if (!runId) {
104426
104635
  const created = await call("POST", "", {
@@ -104442,7 +104651,7 @@ async function runCoreTurn(d, prompt) {
104442
104651
  let state = null;
104443
104652
  for (; ; ) {
104444
104653
  if (d.signal.aborted) throw new CoreTurnError("aborted");
104445
- const events = (await call("GET", `/${runId}/events?after=${cur.after}&limit=200`)).events;
104654
+ const events = (await poll(`/${runId}/events?after=${cur.after}&limit=200`)).events;
104446
104655
  for (const e of events) {
104447
104656
  cur.after = Math.max(cur.after, e.seq);
104448
104657
  if (!e.applied) continue;
@@ -104454,7 +104663,7 @@ async function runCoreTurn(d, prompt) {
104454
104663
  }
104455
104664
  if (e.type === "verifier_result" && Array.isArray(p.problems) && p.problems.length > 0) say(`task ${String(p.taskId)}: verifier: ${p.problems.join("; ")}`);
104456
104665
  }
104457
- state = (await call("GET", `/${runId}`)).state;
104666
+ state = (await poll(`/${runId}`)).state;
104458
104667
  const now = {};
104459
104668
  for (const id of state.order) now[id] = state.tasks[id].status;
104460
104669
  const changed = state.order.filter((id) => now[id] !== cur.known[id]);
@@ -104485,7 +104694,7 @@ async function runCoreTurn(d, prompt) {
104485
104694
  cur.tokensBase = state.tokensUsed;
104486
104695
  return { success: (state.status === "done" || state.status === "needs_user") && patchFailures === 0, text: lastText, tokens };
104487
104696
  }
104488
- var newRunCursor, TERMINAL, DEFAULT_BUDGET, DEFAULT_MAX_WAIT_MS, CoreTurnError;
104697
+ var newRunCursor, TERMINAL, DEFAULT_BUDGET, DEFAULT_MAX_WAIT_MS, CoreTurnError, POLL_RETRIES;
104489
104698
  var init_core_turn = __esm({
104490
104699
  "src/core/core-turn.ts"() {
104491
104700
  "use strict";
@@ -104494,7 +104703,12 @@ var init_core_turn = __esm({
104494
104703
  DEFAULT_BUDGET = 5e5;
104495
104704
  DEFAULT_MAX_WAIT_MS = 30 * 6e4;
104496
104705
  CoreTurnError = class extends Error {
104706
+ constructor(message, status) {
104707
+ super(message);
104708
+ this.status = status;
104709
+ }
104497
104710
  };
104711
+ POLL_RETRIES = 5;
104498
104712
  }
104499
104713
  });
104500
104714
 
@@ -105873,7 +106087,13 @@ function clearOnResize(stdout) {
105873
106087
 
105874
106088
  // src/index.tsx
105875
106089
  var import_jsx_runtime14 = __toESM(require_jsx_runtime(), 1);
105876
- if (process.argv[2] === "import-claude") {
106090
+ if (process.argv[2] === "import" || process.argv[2] === "import-claude") {
106091
+ const importArgs = process.argv[2] === "import" ? process.argv.slice(4) : process.argv.slice(3);
106092
+ const importAgent = process.argv[2] === "import" ? process.argv[3] : "claude";
106093
+ if (importAgent !== "claude") {
106094
+ console.error(`Unknown agent "${importAgent ?? ""}". Supported: claude`);
106095
+ process.exit(2);
106096
+ }
105877
106097
  const { runImportClaude: runImportClaude2 } = await Promise.resolve().then(() => (init_import_claude(), import_claude_exports));
105878
106098
  const { readFile: readFile12, readdir: readdir6 } = await import("node:fs/promises");
105879
106099
  const { execFile: execFile6 } = await import("node:child_process");
@@ -105881,7 +106101,7 @@ if (process.argv[2] === "import-claude") {
105881
106101
  execFile6("git", ["rev-parse", "--show-toplevel"], { cwd: process.cwd() }, (err, stdout) => resolve2(err ? null : stdout.trim() || null));
105882
106102
  });
105883
106103
  const code = await runImportClaude2({
105884
- argv: process.argv.slice(2),
106104
+ argv: ["import-claude", ...importArgs],
105885
106105
  env: process.env,
105886
106106
  fs: { readFile: (p) => readFile12(p, "utf-8"), readdir: (p) => readdir6(p) },
105887
106107
  readFile: (p) => readFile12(p, "utf-8"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spacecode",
3
- "version": "2.12.0",
3
+ "version": "2.12.3",
4
4
  "description": "SpaceCode - launch cloud dev environments with AI coding agents",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",