spacecode 2.12.4 → 2.12.6
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 +132 -44
- package/package.json +1 -1
package/dist/repl.mjs
CHANGED
|
@@ -6509,6 +6509,9 @@ function parseImportsConfig(text, path13) {
|
|
|
6509
6509
|
}
|
|
6510
6510
|
return { config };
|
|
6511
6511
|
}
|
|
6512
|
+
function serializeImportsConfig(config) {
|
|
6513
|
+
return JSON.stringify({ version: 1, categories: config.categories, models: config.models }, null, 2);
|
|
6514
|
+
}
|
|
6512
6515
|
var IMPORT_CATEGORIES, MODEL_KEYS;
|
|
6513
6516
|
var init_imports_config = __esm({
|
|
6514
6517
|
"../agent/src/import/imports-config.ts"() {
|
|
@@ -6526,6 +6529,35 @@ var init_imports_config = __esm({
|
|
|
6526
6529
|
}
|
|
6527
6530
|
});
|
|
6528
6531
|
|
|
6532
|
+
// ../agent/src/import/enable-categories.ts
|
|
6533
|
+
function enableImportCategories(existingText, path13, wanted) {
|
|
6534
|
+
const loaded = parseImportsConfig(existingText, path13);
|
|
6535
|
+
if (loaded.error) return { ok: false, error: loaded.error };
|
|
6536
|
+
const mentioned = /* @__PURE__ */ new Set();
|
|
6537
|
+
if (existingText !== null) {
|
|
6538
|
+
const categories = JSON.parse(existingText).categories;
|
|
6539
|
+
for (const key of Object.keys(categories ?? {})) mentioned.add(key);
|
|
6540
|
+
}
|
|
6541
|
+
const enabled = [];
|
|
6542
|
+
const keptOff = [];
|
|
6543
|
+
for (const category of wanted) {
|
|
6544
|
+
if (enabled.includes(category) || keptOff.includes(category)) continue;
|
|
6545
|
+
if (mentioned.has(category)) {
|
|
6546
|
+
if (!loaded.config.categories[category]) keptOff.push(category);
|
|
6547
|
+
continue;
|
|
6548
|
+
}
|
|
6549
|
+
loaded.config.categories[category] = true;
|
|
6550
|
+
enabled.push(category);
|
|
6551
|
+
}
|
|
6552
|
+
return { ok: true, text: serializeImportsConfig(loaded.config), enabled, keptOff };
|
|
6553
|
+
}
|
|
6554
|
+
var init_enable_categories = __esm({
|
|
6555
|
+
"../agent/src/import/enable-categories.ts"() {
|
|
6556
|
+
"use strict";
|
|
6557
|
+
init_imports_config();
|
|
6558
|
+
}
|
|
6559
|
+
});
|
|
6560
|
+
|
|
6529
6561
|
// ../agent/src/import/permission-rules.ts
|
|
6530
6562
|
function splitCommand(cmd) {
|
|
6531
6563
|
const segments2 = [];
|
|
@@ -7300,6 +7332,7 @@ var init_src = __esm({
|
|
|
7300
7332
|
init_source_changes();
|
|
7301
7333
|
init_mcp_tool_cache();
|
|
7302
7334
|
init_imports_config();
|
|
7335
|
+
init_enable_categories();
|
|
7303
7336
|
init_permission_rules();
|
|
7304
7337
|
init_command_args();
|
|
7305
7338
|
init_command_file();
|
|
@@ -7862,6 +7895,7 @@ var import_claude_exports = {};
|
|
|
7862
7895
|
__export(import_claude_exports, {
|
|
7863
7896
|
runImportClaude: () => runImportClaude
|
|
7864
7897
|
});
|
|
7898
|
+
import { join as join6 } from "node:path";
|
|
7865
7899
|
async function runImportClaude(deps) {
|
|
7866
7900
|
const flags = deps.argv.filter((a) => a !== "import-claude");
|
|
7867
7901
|
const unknown = flags.filter((f) => !["--dry-run", "--overwrite", "--adapt", "--no-adapt", "--yes", "--restore-original"].includes(f));
|
|
@@ -7965,6 +7999,7 @@ ${USAGE}`);
|
|
|
7965
7999
|
deps.log(` FAILED ${a.kind}/${a.name}: ${detail}`);
|
|
7966
8000
|
}
|
|
7967
8001
|
}
|
|
8002
|
+
await enableImportedCategories(deps, report.assets);
|
|
7968
8003
|
deps.log(`Done: ${imported} imported, ${skipped} unchanged${failed ? ", some items need attention (see above)" : ""}.`);
|
|
7969
8004
|
return failed ? 1 : 0;
|
|
7970
8005
|
}
|
|
@@ -7973,7 +8008,30 @@ function summarizeKinds(assets) {
|
|
|
7973
8008
|
for (const a of assets) counts.set(a.kind, (counts.get(a.kind) ?? 0) + 1);
|
|
7974
8009
|
return [...counts].map(([kind, n]) => `${n} ${kind}`).join(", ");
|
|
7975
8010
|
}
|
|
7976
|
-
|
|
8011
|
+
async function enableImportedCategories(deps, assets) {
|
|
8012
|
+
const wanted = [...new Set(assets.map((a) => KIND_CATEGORY[a.kind]).filter((c) => c !== void 0))];
|
|
8013
|
+
if (wanted.length === 0 || !deps.writeFileAtomic) return;
|
|
8014
|
+
const path13 = join6(deps.env.SPACECODE_CONFIG_DIR?.trim() || join6(deps.homedir(), ".spacecode"), "imports.json");
|
|
8015
|
+
try {
|
|
8016
|
+
const existing = await deps.readFile(path13).catch((err) => {
|
|
8017
|
+
if (err.code === "ENOENT") return null;
|
|
8018
|
+
throw err;
|
|
8019
|
+
});
|
|
8020
|
+
const result = enableImportCategories(existing, path13, wanted);
|
|
8021
|
+
if (!result.ok) {
|
|
8022
|
+
deps.log(` imports.json NOT changed (${result.error}); imported ${wanted.join(", ")} stay off until you fix it`);
|
|
8023
|
+
return;
|
|
8024
|
+
}
|
|
8025
|
+
if (result.enabled.length > 0) {
|
|
8026
|
+
await deps.writeFileAtomic(path13, result.text);
|
|
8027
|
+
deps.log(` enabled in ${path13}: ${result.enabled.join(", ")} (set a category to false there to turn it off)`);
|
|
8028
|
+
}
|
|
8029
|
+
if (result.keptOff.length > 0) deps.log(` ${path13} keeps ${result.keptOff.join(", ")} off, as you set; set it to true to use what was imported`);
|
|
8030
|
+
} catch (err) {
|
|
8031
|
+
deps.log(` imports.json NOT changed (${err instanceof Error ? err.message : String(err)}); imported ${wanted.join(", ")} stay off`);
|
|
8032
|
+
}
|
|
8033
|
+
}
|
|
8034
|
+
var USAGE, KIND_CATEGORY;
|
|
7977
8035
|
var init_import_claude = __esm({
|
|
7978
8036
|
"src/import-claude.ts"() {
|
|
7979
8037
|
"use strict";
|
|
@@ -7982,6 +8040,7 @@ var init_import_claude = __esm({
|
|
|
7982
8040
|
init_profile_runtime();
|
|
7983
8041
|
init_import_adapt();
|
|
7984
8042
|
USAGE = "Usage: spacecode import claude [--dry-run] [--overwrite] [--no-adapt] [--yes] [--restore-original]";
|
|
8043
|
+
KIND_CATEGORY = { command: "commands", skill: "skills", mcp: "mcp" };
|
|
7985
8044
|
}
|
|
7986
8045
|
});
|
|
7987
8046
|
|
|
@@ -8406,15 +8465,26 @@ var init_mcp_manager = __esm({
|
|
|
8406
8465
|
});
|
|
8407
8466
|
|
|
8408
8467
|
// src/mcp/approve-mcp.ts
|
|
8468
|
+
function unsetVars(d, env3) {
|
|
8469
|
+
const texts = d.transport === "http" ? [d.url, ...Object.values(d.env)] : [d.command, ...d.args, ...Object.values(d.env)];
|
|
8470
|
+
return [...new Set(texts.flatMap((t) => expandRefs(t, env3).missing))].sort();
|
|
8471
|
+
}
|
|
8409
8472
|
async function runApproveMcp(deps) {
|
|
8410
8473
|
const { defs, statusLines } = await loadMcpDefs(deps);
|
|
8411
8474
|
if (!deps.quiet) for (const l of statusLines) deps.log(l);
|
|
8412
8475
|
const stdio = defs;
|
|
8413
|
-
|
|
8476
|
+
let todo = [];
|
|
8414
8477
|
for (const d of stdio) {
|
|
8415
8478
|
const key = approvalKey(d);
|
|
8416
8479
|
if (await deps.trust.stdioStatus(key) === "unapproved") todo.push(d);
|
|
8417
8480
|
}
|
|
8481
|
+
if (deps.quiet && deps.procEnv && todo.length > 0) {
|
|
8482
|
+
const env3 = deps.procEnv;
|
|
8483
|
+
const ready = todo.filter((d) => unsetVars(d, env3).length === 0);
|
|
8484
|
+
const waiting = todo.length - ready.length;
|
|
8485
|
+
if (waiting > 0) deps.log(`${waiting} imported MCP server(s) wait for environment variables (see \`spacecode approve-mcp\`); they are not asked about until those are set.`);
|
|
8486
|
+
todo = ready;
|
|
8487
|
+
}
|
|
8418
8488
|
if (todo.length === 0) {
|
|
8419
8489
|
if (!deps.quiet) deps.log(stdio.length === 0 ? "No stdio MCP servers to approve." : "Every stdio MCP server is already approved on this machine.");
|
|
8420
8490
|
return 0;
|
|
@@ -8423,6 +8493,13 @@ async function runApproveMcp(deps) {
|
|
|
8423
8493
|
deps.log(`${todo.length} MCP server(s) need approval, but this is not an interactive terminal: nothing was approved.`);
|
|
8424
8494
|
return 1;
|
|
8425
8495
|
}
|
|
8496
|
+
if (deps.quiet && todo.length > STARTUP_PROMPT_LIMIT) {
|
|
8497
|
+
const answer = (await deps.ask(`${todo.length} imported MCP servers can be approved now. Review them one by one? [y/N] `) ?? "").trim().toLowerCase();
|
|
8498
|
+
if (answer !== "y" && answer !== "yes") {
|
|
8499
|
+
deps.log("Skipped. Run `spacecode approve-mcp` when you want to review them; nothing spawns until then.");
|
|
8500
|
+
return 0;
|
|
8501
|
+
}
|
|
8502
|
+
}
|
|
8426
8503
|
if (deps.quiet) deps.log(`
|
|
8427
8504
|
${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).`);
|
|
8428
8505
|
let approved = 0;
|
|
@@ -8447,12 +8524,14 @@ MCP server ${show(d.name)} (${d.origin} definition) wants to run on this machine
|
|
|
8447
8524
|
${approved} of ${todo.length} approved.`);
|
|
8448
8525
|
return 0;
|
|
8449
8526
|
}
|
|
8450
|
-
var show;
|
|
8527
|
+
var STARTUP_PROMPT_LIMIT, show;
|
|
8451
8528
|
var init_approve_mcp = __esm({
|
|
8452
8529
|
"src/mcp/approve-mcp.ts"() {
|
|
8453
8530
|
"use strict";
|
|
8531
|
+
init_src();
|
|
8454
8532
|
init_mcp_loader();
|
|
8455
8533
|
init_mcp_manager();
|
|
8534
|
+
STARTUP_PROMPT_LIMIT = 3;
|
|
8456
8535
|
show = (s) => JSON.stringify(s);
|
|
8457
8536
|
}
|
|
8458
8537
|
});
|
|
@@ -8486,7 +8565,8 @@ async function runApproveMcpOnNode(opts) {
|
|
|
8486
8565
|
}
|
|
8487
8566
|
} } : {},
|
|
8488
8567
|
log: (line) => console.log(line),
|
|
8489
|
-
quiet: opts.quiet
|
|
8568
|
+
quiet: opts.quiet,
|
|
8569
|
+
procEnv: process.env
|
|
8490
8570
|
});
|
|
8491
8571
|
} finally {
|
|
8492
8572
|
rl?.close();
|
|
@@ -43742,7 +43822,7 @@ var require_core = __commonJS({
|
|
|
43742
43822
|
return match && match.index === 0;
|
|
43743
43823
|
}
|
|
43744
43824
|
var BACKREF_RE = /\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;
|
|
43745
|
-
function
|
|
43825
|
+
function join17(regexps, separator = "|") {
|
|
43746
43826
|
let numCaptures = 0;
|
|
43747
43827
|
return regexps.map((regex2) => {
|
|
43748
43828
|
numCaptures += 1;
|
|
@@ -44046,7 +44126,7 @@ var require_core = __commonJS({
|
|
|
44046
44126
|
this.exec = () => null;
|
|
44047
44127
|
}
|
|
44048
44128
|
const terminators = this.regexes.map((el) => el[1]);
|
|
44049
|
-
this.matcherRe = langRe(
|
|
44129
|
+
this.matcherRe = langRe(join17(terminators), true);
|
|
44050
44130
|
this.lastIndex = 0;
|
|
44051
44131
|
}
|
|
44052
44132
|
/** @param {string} s */
|
|
@@ -103364,7 +103444,7 @@ var init_local_toolset = __esm({
|
|
|
103364
103444
|
// src/project-card-scan.ts
|
|
103365
103445
|
import { execFile as execFile3 } from "node:child_process";
|
|
103366
103446
|
import { readdir as readdir3, readFile as readFile5 } from "node:fs/promises";
|
|
103367
|
-
import { join as
|
|
103447
|
+
import { join as join8 } from "node:path";
|
|
103368
103448
|
function digestLines(md) {
|
|
103369
103449
|
return md.split("\n").map((l) => l.trim()).filter((l) => l && !/^#\s/.test(l) && !/^[|\s:-]+$/.test(l) && !/^\|\s*(area|task|priority|date|issue|id)\b/i.test(l)).slice(0, 12);
|
|
103370
103450
|
}
|
|
@@ -103402,11 +103482,11 @@ async function scanProject(cwd2, io = nodeScanIo) {
|
|
|
103402
103482
|
const topLevel = root.filter((e) => !SKIP.has(e.name)).map((e) => ({ path: e.name, isDir: e.isDir }));
|
|
103403
103483
|
const childDirs = {};
|
|
103404
103484
|
for (const d of topLevel.filter((e) => e.isDir && ["apps", "packages", "services", "libs", "src"].includes(e.path))) {
|
|
103405
|
-
const kids = await attempt(`list ${d.path}`, () => io.readdir(
|
|
103485
|
+
const kids = await attempt(`list ${d.path}`, () => io.readdir(join8(cwd2, d.path)), []);
|
|
103406
103486
|
childDirs[d.path] = kids.filter((k2) => !SKIP.has(k2.name) && !k2.name.startsWith(".")).map((k2) => k2.isDir ? k2.name : k2.name).slice(0, 20);
|
|
103407
103487
|
}
|
|
103408
103488
|
let manifest;
|
|
103409
|
-
const pkgText = await attempt("read package.json", () => io.readFile(
|
|
103489
|
+
const pkgText = await attempt("read package.json", () => io.readFile(join8(cwd2, "package.json")), null);
|
|
103410
103490
|
if (pkgText) {
|
|
103411
103491
|
try {
|
|
103412
103492
|
const pkg = JSON.parse(pkgText);
|
|
@@ -103421,17 +103501,17 @@ async function scanProject(cwd2, io = nodeScanIo) {
|
|
|
103421
103501
|
}
|
|
103422
103502
|
const docs = [];
|
|
103423
103503
|
for (const e of topLevel.filter((t) => !t.isDir && /\.md$/i.test(t.path)).slice(0, MAX_DOCS)) {
|
|
103424
|
-
const text = await attempt(`read ${e.path}`, () => io.readFile(
|
|
103504
|
+
const text = await attempt(`read ${e.path}`, () => io.readFile(join8(cwd2, e.path)), null);
|
|
103425
103505
|
const title = text ? firstHeading(text) : null;
|
|
103426
103506
|
if (title) docs.push({ path: e.path, title });
|
|
103427
103507
|
}
|
|
103428
103508
|
const digests = [];
|
|
103429
103509
|
for (const name of DIGEST_FILES.filter((n) => topLevel.some((t) => t.path === n))) {
|
|
103430
|
-
const text = await attempt(`read ${name}`, () => io.readFile(
|
|
103510
|
+
const text = await attempt(`read ${name}`, () => io.readFile(join8(cwd2, name)), null);
|
|
103431
103511
|
const lines2 = text ? digestLines(text) : [];
|
|
103432
103512
|
if (lines2.length) digests.push({ path: name, lines: lines2 });
|
|
103433
103513
|
}
|
|
103434
|
-
const todo = await attempt("read TODO.md", () => io.readFile(
|
|
103514
|
+
const todo = await attempt("read TODO.md", () => io.readFile(join8(cwd2, "TODO.md")), null);
|
|
103435
103515
|
const log = await io.git(cwd2, ["log", "--oneline", "-8"]);
|
|
103436
103516
|
const status = await io.git(cwd2, ["status", "--porcelain"]);
|
|
103437
103517
|
const branch = await io.git(cwd2, ["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
@@ -103517,11 +103597,11 @@ var init_project_card_runtime = __esm({
|
|
|
103517
103597
|
});
|
|
103518
103598
|
|
|
103519
103599
|
// src/prompt-runtime.ts
|
|
103520
|
-
import { join as
|
|
103600
|
+
import { join as join9 } from "node:path";
|
|
103521
103601
|
async function load(deps) {
|
|
103522
103602
|
if (deps.env.SPACECODE_PROMPTS === "off") return { templates: {}, statusLine: "prompts: built-in defaults (SPACECODE_PROMPTS=off)" };
|
|
103523
|
-
const dir = deps.env.SPACECODE_CONFIG_DIR?.trim() ||
|
|
103524
|
-
const file =
|
|
103603
|
+
const dir = deps.env.SPACECODE_CONFIG_DIR?.trim() || join9(deps.homedir(), ".spacecode");
|
|
103604
|
+
const file = join9(dir, "prompts-cache.json");
|
|
103525
103605
|
const fromDisk = async (why) => {
|
|
103526
103606
|
try {
|
|
103527
103607
|
const raw = JSON.parse(await deps.readFile(file));
|
|
@@ -103999,7 +104079,7 @@ var init_recording_chunks = __esm({
|
|
|
103999
104079
|
// src/recording/recorder.ts
|
|
104000
104080
|
import { createHash as createHash4 } from "node:crypto";
|
|
104001
104081
|
import { mkdir as mkdir4, readFile as readFile7, rename as rename4, rm as rm2, writeFile as writeFile4, readdir as readdir5, stat as stat3 } from "node:fs/promises";
|
|
104002
|
-
import { join as
|
|
104082
|
+
import { join as join10 } from "node:path";
|
|
104003
104083
|
function projectHash(root) {
|
|
104004
104084
|
return createHash4("sha256").update(root).digest("hex");
|
|
104005
104085
|
}
|
|
@@ -104010,7 +104090,7 @@ function createRecorder(deps) {
|
|
|
104010
104090
|
let inflight = null;
|
|
104011
104091
|
let retryAttempt = 0;
|
|
104012
104092
|
let timerArmed = false;
|
|
104013
|
-
const stateFile = (sessionId) =>
|
|
104093
|
+
const stateFile = (sessionId) => join10(deps.dir, `${sessionId}.json`);
|
|
104014
104094
|
async function save(sessionId, st) {
|
|
104015
104095
|
await mkdir4(deps.dir, { recursive: true, mode: 448 });
|
|
104016
104096
|
const tmp = `${stateFile(sessionId)}.${deps.randomId()}.tmp`;
|
|
@@ -104025,9 +104105,9 @@ function createRecorder(deps) {
|
|
|
104025
104105
|
st = JSON.parse(await readFile7(stateFile(sessionId), "utf8"));
|
|
104026
104106
|
} catch (e) {
|
|
104027
104107
|
if (e.code !== "ENOENT") {
|
|
104028
|
-
const bad =
|
|
104108
|
+
const bad = join10(deps.dir, "bad");
|
|
104029
104109
|
await mkdir4(bad, { recursive: true, mode: 448 });
|
|
104030
|
-
await rename4(stateFile(sessionId),
|
|
104110
|
+
await rename4(stateFile(sessionId), join10(bad, `${sessionId}.${deps.now()}.json`)).catch((err) => deps.log(`recording: could not quarantine ${sessionId}: ${String(err)}`));
|
|
104031
104111
|
lastError = `recording state for ${sessionId} was unreadable and was quarantined`;
|
|
104032
104112
|
deps.log(`recording: ${lastError}`);
|
|
104033
104113
|
}
|
|
@@ -104218,7 +104298,7 @@ var init_recorder = __esm({
|
|
|
104218
104298
|
|
|
104219
104299
|
// src/recording/recording-runtime.ts
|
|
104220
104300
|
import { mkdir as mkdir5, readFile as readFile8, writeFile as writeFile5, stat as stat4 } from "node:fs/promises";
|
|
104221
|
-
import { join as
|
|
104301
|
+
import { join as join11, sep as sep2 } from "node:path";
|
|
104222
104302
|
function matchesExclude(pattern, root) {
|
|
104223
104303
|
const re3 = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "\0").replace(/\*/g, `[^${sep2 === "\\" ? "\\\\" : "/"}]*`).replace(/\u0000/g, ".*");
|
|
104224
104304
|
return new RegExp(`^${re3}(?:[/\\\\].*)?$`).test(root);
|
|
@@ -104233,8 +104313,8 @@ async function exists(path13) {
|
|
|
104233
104313
|
}
|
|
104234
104314
|
}
|
|
104235
104315
|
function createRecordingRuntime(deps) {
|
|
104236
|
-
const dir =
|
|
104237
|
-
const noticeFile =
|
|
104316
|
+
const dir = join11(deps.configDir, "recordings");
|
|
104317
|
+
const noticeFile = join11(dir, ".notice");
|
|
104238
104318
|
let recorder = null;
|
|
104239
104319
|
let standingOff;
|
|
104240
104320
|
let sessionOff = false;
|
|
@@ -104242,7 +104322,7 @@ function createRecordingRuntime(deps) {
|
|
|
104242
104322
|
if (deps.env.SPACECODE_RECORD?.trim().toLowerCase() === "off") return "SPACECODE_RECORD=off";
|
|
104243
104323
|
let cfg = {};
|
|
104244
104324
|
try {
|
|
104245
|
-
cfg = JSON.parse(await readFile8(
|
|
104325
|
+
cfg = JSON.parse(await readFile8(join11(deps.configDir, "config.json"), "utf8"));
|
|
104246
104326
|
} catch (e) {
|
|
104247
104327
|
if (e.code !== "ENOENT") return `~/.spacecode/config.json is unreadable (${e instanceof Error ? e.message : String(e)}); fix it to record`;
|
|
104248
104328
|
}
|
|
@@ -104250,7 +104330,7 @@ function createRecordingRuntime(deps) {
|
|
|
104250
104330
|
const excludes = Array.isArray(cfg.recording?.exclude) ? cfg.recording.exclude.filter((x2) => typeof x2 === "string") : [];
|
|
104251
104331
|
const hit = excludes.find((p) => matchesExclude(p, deps.projectRoot));
|
|
104252
104332
|
if (hit) return `this folder matches recording.exclude (${hit})`;
|
|
104253
|
-
if (await exists(
|
|
104333
|
+
if (await exists(join11(deps.projectRoot, ".spacecode", "norecord"))) return "this repo has .spacecode/norecord";
|
|
104254
104334
|
return null;
|
|
104255
104335
|
}
|
|
104256
104336
|
async function noticeShown() {
|
|
@@ -104392,9 +104472,9 @@ var init_skills_command = __esm({
|
|
|
104392
104472
|
|
|
104393
104473
|
// src/mcp/tool-cache-file.ts
|
|
104394
104474
|
import { readFile as readFile9 } from "node:fs/promises";
|
|
104395
|
-
import { join as
|
|
104475
|
+
import { join as join12 } from "node:path";
|
|
104396
104476
|
function nodeToolCache(configDir) {
|
|
104397
|
-
const path13 =
|
|
104477
|
+
const path13 = join12(configDir, "mcp-tools-cache.json");
|
|
104398
104478
|
return {
|
|
104399
104479
|
read: async () => {
|
|
104400
104480
|
try {
|
|
@@ -104417,7 +104497,7 @@ var init_tool_cache_file = __esm({
|
|
|
104417
104497
|
|
|
104418
104498
|
// src/permission-rules-loader.ts
|
|
104419
104499
|
import { readFile as readFile10 } from "node:fs/promises";
|
|
104420
|
-
import { join as
|
|
104500
|
+
import { join as join13 } from "node:path";
|
|
104421
104501
|
async function readOrNull2(path13) {
|
|
104422
104502
|
try {
|
|
104423
104503
|
return await readFile10(path13, "utf8");
|
|
@@ -104428,7 +104508,7 @@ async function readOrNull2(path13) {
|
|
|
104428
104508
|
}
|
|
104429
104509
|
async function loadPermissionRules(deps) {
|
|
104430
104510
|
const none = (line) => ({ rules: void 0, defaultMode: void 0, statusLines: [line] });
|
|
104431
|
-
const configPath =
|
|
104511
|
+
const configPath = join13(deps.configDir, "imports.json");
|
|
104432
104512
|
try {
|
|
104433
104513
|
const loaded = parseImportsConfig(await readOrNull2(configPath), configPath);
|
|
104434
104514
|
if (loaded.error) return none("permission rules: off (imports.json unreadable)");
|
|
@@ -104437,13 +104517,13 @@ async function loadPermissionRules(deps) {
|
|
|
104437
104517
|
return none(`permission rules: off (imports.json not read: ${err instanceof Error ? err.message : String(err)})`);
|
|
104438
104518
|
}
|
|
104439
104519
|
const lines2 = [];
|
|
104440
|
-
const files = [{ scope: "user", path:
|
|
104520
|
+
const files = [{ scope: "user", path: join13(deps.homeDir, ".claude", "settings.json") }];
|
|
104441
104521
|
try {
|
|
104442
104522
|
const sources2 = await readRepoSources(deps.cwd);
|
|
104443
104523
|
if (sources2[".claude/settings.json"] !== void 0 || sources2[".claude/settings.local.json"] !== void 0) {
|
|
104444
104524
|
const status = await createNodeTrustStore(deps.configDir).repoStatus(deps.cwd, sources2);
|
|
104445
104525
|
if (status === "trusted" || status === "session") {
|
|
104446
|
-
files.push({ scope: "repo", path:
|
|
104526
|
+
files.push({ scope: "repo", path: join13(deps.cwd, ".claude", "settings.json") }, { scope: "local", path: join13(deps.cwd, ".claude", "settings.local.json") });
|
|
104447
104527
|
} else lines2.push(`permission rules: repo settings NOT loaded (${status === "never" ? "marked never trust" : "untrusted repo"})`);
|
|
104448
104528
|
}
|
|
104449
104529
|
} catch (err) {
|
|
@@ -104520,7 +104600,7 @@ var init_import_reload = __esm({
|
|
|
104520
104600
|
});
|
|
104521
104601
|
|
|
104522
104602
|
// src/command-loader.ts
|
|
104523
|
-
import { join as
|
|
104603
|
+
import { join as join14 } from "node:path";
|
|
104524
104604
|
async function userCommands(deps, lines2) {
|
|
104525
104605
|
try {
|
|
104526
104606
|
const apiKey = await resolveApiKey({ env: deps.env, readFile: deps.readFile, homedir: deps.homedir });
|
|
@@ -104575,7 +104655,7 @@ async function repoCommands(deps, lines2) {
|
|
|
104575
104655
|
}
|
|
104576
104656
|
}
|
|
104577
104657
|
async function loadCommands(deps) {
|
|
104578
|
-
const configPath =
|
|
104658
|
+
const configPath = join14(deps.configDir, "imports.json");
|
|
104579
104659
|
try {
|
|
104580
104660
|
const loaded = parseImportsConfig(await deps.readFile(configPath).catch((err) => {
|
|
104581
104661
|
if (err.code === "ENOENT") return null;
|
|
@@ -104727,7 +104807,7 @@ var init_core_turn = __esm({
|
|
|
104727
104807
|
// src/core/core-mode.ts
|
|
104728
104808
|
import { execFile as execFile4 } from "node:child_process";
|
|
104729
104809
|
import { mkdir as mkdir6, writeFile as writeFile6 } from "node:fs/promises";
|
|
104730
|
-
import { join as
|
|
104810
|
+
import { join as join15 } from "node:path";
|
|
104731
104811
|
function githubHttpsUrl(remote) {
|
|
104732
104812
|
const t = remote.trim();
|
|
104733
104813
|
const m2 = t.match(/^(?:git@github\.com:|ssh:\/\/git@github\.com\/|https:\/\/(?:[^@/]+@)?github\.com\/)([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+?)(?:\.git)?\/?$/);
|
|
@@ -104753,10 +104833,10 @@ function shareableGithubToken(env3) {
|
|
|
104753
104833
|
function patchApplier(executor, cwd2, runId) {
|
|
104754
104834
|
return async ({ taskId, patch }) => {
|
|
104755
104835
|
const top = await gitOut(cwd2, ["rev-parse", "--show-toplevel"]) ?? cwd2;
|
|
104756
|
-
const gitDir = await gitOut(cwd2, ["rev-parse", "--absolute-git-dir"]) ??
|
|
104757
|
-
const dir =
|
|
104836
|
+
const gitDir = await gitOut(cwd2, ["rev-parse", "--absolute-git-dir"]) ?? join15(top, ".git");
|
|
104837
|
+
const dir = join15(gitDir, "spacecode-core", runId.replace(/[^A-Za-z0-9_.-]/g, "_"));
|
|
104758
104838
|
await mkdir6(dir, { recursive: true });
|
|
104759
|
-
const file =
|
|
104839
|
+
const file = join15(dir, `${taskId.replace(/[^A-Za-z0-9_.-]/g, "_")}.patch`);
|
|
104760
104840
|
await writeFile6(file, patch, { encoding: "utf-8", mode: 384 });
|
|
104761
104841
|
const res = await executor.execute("bash", { command: `git -C ${sq(top)} apply --3way ${sq(file)}` });
|
|
104762
104842
|
return res.is_error ? { applied: false, detail: `${res.output.slice(0, 200).trim() || "git apply failed"}; patch kept at ${file}` } : { applied: true, detail: "git apply --3way" };
|
|
@@ -104805,7 +104885,7 @@ var init_core_mode = __esm({
|
|
|
104805
104885
|
// src/useReplController.ts
|
|
104806
104886
|
import { readFile as readFile11, writeFile as writeFile7, mkdir as mkdir7 } from "node:fs/promises";
|
|
104807
104887
|
import { homedir as homedir2 } from "node:os";
|
|
104808
|
-
import { join as
|
|
104888
|
+
import { join as join16 } from "node:path";
|
|
104809
104889
|
import { execFile as execFile5 } from "node:child_process";
|
|
104810
104890
|
function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mentionsOpt, sessions, resumeLatest: resumeLatest2, onViewTurns, onViewResume, isEscOwned }) {
|
|
104811
104891
|
const { exit } = use_app_default();
|
|
@@ -104846,7 +104926,7 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
104846
104926
|
const recordingRef = (0, import_react30.useRef)(null);
|
|
104847
104927
|
const recording = () => recordingRef.current ??= createRecordingRuntime({
|
|
104848
104928
|
env: process.env,
|
|
104849
|
-
configDir: process.env.SPACECODE_CONFIG_DIR?.trim() ||
|
|
104929
|
+
configDir: process.env.SPACECODE_CONFIG_DIR?.trim() || join16(homedir2(), ".spacecode"),
|
|
104850
104930
|
projectRoot,
|
|
104851
104931
|
fetch,
|
|
104852
104932
|
baseUrl: backendUrl(process.env),
|
|
@@ -104874,7 +104954,7 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
104874
104954
|
(0, import_react30.useEffect)(() => {
|
|
104875
104955
|
let live2 = true;
|
|
104876
104956
|
loadCommands({
|
|
104877
|
-
configDir: process.env.SPACECODE_CONFIG_DIR?.trim() ||
|
|
104957
|
+
configDir: process.env.SPACECODE_CONFIG_DIR?.trim() || join16(homedir2(), ".spacecode"),
|
|
104878
104958
|
cwd: process.cwd(),
|
|
104879
104959
|
env: process.env,
|
|
104880
104960
|
readFile: (p) => readFile11(p, "utf-8"),
|
|
@@ -105097,7 +105177,7 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
105097
105177
|
notice(formatContextReport({ contextTokens: estimateTotalTokens("", history), maxContextTokens: DEFAULT_MAX_CONTEXT_TOKENS }));
|
|
105098
105178
|
return;
|
|
105099
105179
|
case "import": {
|
|
105100
|
-
const configDir = process.env.SPACECODE_CONFIG_DIR?.trim() ||
|
|
105180
|
+
const configDir = process.env.SPACECODE_CONFIG_DIR?.trim() || join16(homedir2(), ".spacecode");
|
|
105101
105181
|
const deps = { configDir, cwd: process.cwd() };
|
|
105102
105182
|
const [sub, ...rest] = slash.args.split(/\s+/).filter(Boolean);
|
|
105103
105183
|
if (sub !== "reload" || rest.length > 1 || rest[0] !== void 0 && rest[0] !== "trust") {
|
|
@@ -105305,7 +105385,7 @@ ${list2.map((c) => ` /${c.name} (${c.scope})${c.description ? ` ${c.descripti
|
|
|
105305
105385
|
let keepForRetry = false;
|
|
105306
105386
|
try {
|
|
105307
105387
|
if (loadedSourcesRef.current) {
|
|
105308
|
-
const configDir = process.env.SPACECODE_CONFIG_DIR?.trim() ||
|
|
105388
|
+
const configDir = process.env.SPACECODE_CONFIG_DIR?.trim() || join16(homedir2(), ".spacecode");
|
|
105309
105389
|
try {
|
|
105310
105390
|
const check = await checkRepoSources({ configDir, cwd: process.cwd() }, loadedSourcesRef.current);
|
|
105311
105391
|
if (check.changes.changed) {
|
|
@@ -105332,7 +105412,7 @@ ${list2.map((c) => ` /${c.name} (${c.scope})${c.description ? ` ${c.descripti
|
|
|
105332
105412
|
cwd: process.cwd(),
|
|
105333
105413
|
gitRoot: gitTopLevel,
|
|
105334
105414
|
importGate: async () => {
|
|
105335
|
-
const configDir = process.env.SPACECODE_CONFIG_DIR?.trim() ||
|
|
105415
|
+
const configDir = process.env.SPACECODE_CONFIG_DIR?.trim() || join16(homedir2(), ".spacecode");
|
|
105336
105416
|
const fingerprint = fingerprintSources(await readRepoSources(process.cwd()), sha256);
|
|
105337
105417
|
const gate = await importGateStatus({ configDir, cwd: process.cwd(), interactive: Boolean(process.stdin.isTTY) });
|
|
105338
105418
|
const loaded = await loadPermissionRules({ configDir, homeDir: homedir2(), cwd: process.cwd() });
|
|
@@ -105344,7 +105424,7 @@ ${list2.map((c) => ` /${c.name} (${c.scope})${c.description ? ` ${c.descripti
|
|
|
105344
105424
|
});
|
|
105345
105425
|
profileRef.current = await profilePromiseRef.current;
|
|
105346
105426
|
if (mcpRef.current === null && (profileRef.current?.mcpDefs?.length ?? 0) > 0) {
|
|
105347
|
-
const configDir = process.env.SPACECODE_CONFIG_DIR?.trim() ||
|
|
105427
|
+
const configDir = process.env.SPACECODE_CONFIG_DIR?.trim() || join16(homedir2(), ".spacecode");
|
|
105348
105428
|
const trust = createNodeTrustStore(configDir);
|
|
105349
105429
|
const manager = new McpManager({
|
|
105350
105430
|
defs: profileRef.current.mcpDefs,
|
|
@@ -105354,7 +105434,7 @@ ${list2.map((c) => ` /${c.name} (${c.scope})${c.description ? ` ${c.descripti
|
|
|
105354
105434
|
...rulesRef.current ? { rules: rulesRef.current } : {},
|
|
105355
105435
|
permissions,
|
|
105356
105436
|
confirm: askUser,
|
|
105357
|
-
audit: new FileAuditLog(
|
|
105437
|
+
audit: new FileAuditLog(join16(homedir2(), ".spacecode", "audit.jsonl")),
|
|
105358
105438
|
clientVersion: process.env.SPACECODE_VERSION ?? "0",
|
|
105359
105439
|
toolCache: nodeToolCache(configDir)
|
|
105360
105440
|
});
|
|
@@ -106120,6 +106200,14 @@ if (process.argv[2] === "import" || process.argv[2] === "import-claude") {
|
|
|
106120
106200
|
homedir: os6.homedir,
|
|
106121
106201
|
cwd: process.cwd(),
|
|
106122
106202
|
gitRoot,
|
|
106203
|
+
writeFileAtomic: async (path13, data) => {
|
|
106204
|
+
const { mkdir: mkdir8, writeFile: writeFile8, rename: rename5 } = await import("node:fs/promises");
|
|
106205
|
+
const { dirname: dirname4 } = await import("node:path");
|
|
106206
|
+
await mkdir8(dirname4(path13), { recursive: true });
|
|
106207
|
+
const tmp = `${path13}.${process.pid}.tmp`;
|
|
106208
|
+
await writeFile8(tmp, data, { mode: 384 });
|
|
106209
|
+
await rename5(tmp, path13);
|
|
106210
|
+
},
|
|
106123
106211
|
fetch,
|
|
106124
106212
|
log: (line) => console.log(line),
|
|
106125
106213
|
confirm: async (question) => {
|