spacecode 2.5.0 → 2.5.2
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 +277 -37
- package/package.json +1 -1
package/dist/repl.mjs
CHANGED
|
@@ -5320,7 +5320,7 @@ function applyPlan(input, decisions, maxCoreChars = MAX_CORE_CHARS) {
|
|
|
5320
5320
|
if (!bySlug.has(d.slug)) throw new AdaptPlanError(`plan names unknown section "${d.slug}"`);
|
|
5321
5321
|
if (seen.has(d.slug)) throw new AdaptPlanError(`plan decides section "${d.slug}" twice`);
|
|
5322
5322
|
seen.add(d.slug);
|
|
5323
|
-
if (d.decision === "drop" && !(d.reason && d.reason.trim())) throw new AdaptPlanError(`
|
|
5323
|
+
if (d.decision === "drop" && !(d.reason && d.reason.trim())) throw new AdaptPlanError(`flagged section "${d.slug}" has no reason`);
|
|
5324
5324
|
if (d.decision === "on_demand" && !(d.summary && d.summary.trim())) throw new AdaptPlanError(`on-demand section "${d.slug}" has no summary`);
|
|
5325
5325
|
}
|
|
5326
5326
|
const missing = input.sections.filter((s) => !seen.has(s.slug)).map((s) => s.slug);
|
|
@@ -5331,13 +5331,17 @@ function applyPlan(input, decisions, maxCoreChars = MAX_CORE_CHARS) {
|
|
|
5331
5331
|
const assemble = () => {
|
|
5332
5332
|
const kept = [];
|
|
5333
5333
|
const onDemand2 = [];
|
|
5334
|
-
const
|
|
5334
|
+
const flagged2 = [];
|
|
5335
5335
|
const index = [];
|
|
5336
5336
|
for (const d of decisions) {
|
|
5337
5337
|
const s = bySlug.get(d.slug);
|
|
5338
5338
|
if (keptSlugs.has(d.slug)) kept.push(s.text);
|
|
5339
|
-
else if (d.decision === "drop")
|
|
5340
|
-
|
|
5339
|
+
else if (d.decision === "drop") {
|
|
5340
|
+
const reason = d.reason.trim().replace(/\s+/g, " ");
|
|
5341
|
+
flagged2.push({ slug: s.slug, title: s.title, reason, unsupported: s.unsupported });
|
|
5342
|
+
onDemand2.push({ slug: s.slug, title: s.title, text: s.text });
|
|
5343
|
+
index.push(`- ${s.slug}: ${s.title} \u2014 written for Claude Code, may not apply here (${reason})`);
|
|
5344
|
+
} else {
|
|
5341
5345
|
onDemand2.push({ slug: s.slug, title: s.title, text: s.text });
|
|
5342
5346
|
index.push(`- ${s.slug}: ${s.title} \u2014 ${summaries.get(s.slug) || `read when working on: ${s.title}`}`);
|
|
5343
5347
|
}
|
|
@@ -5347,19 +5351,19 @@ function applyPlan(input, decisions, maxCoreChars = MAX_CORE_CHARS) {
|
|
|
5347
5351
|
Use the instructions_read tool with a section name to read one before acting in that area:
|
|
5348
5352
|
${index.join("\n")}
|
|
5349
5353
|
` : "";
|
|
5350
|
-
return { core: input.preamble + kept.join("") + indexBlock, onDemand: onDemand2,
|
|
5354
|
+
return { core: input.preamble + kept.join("") + indexBlock, onDemand: onDemand2, flagged: flagged2 };
|
|
5351
5355
|
};
|
|
5352
|
-
let { core, onDemand,
|
|
5356
|
+
let { core, onDemand, flagged } = assemble();
|
|
5353
5357
|
while (core.length > maxCoreChars && keptSlugs.size > 0) {
|
|
5354
5358
|
const largest = [...keptSlugs].map((slug) => bySlug.get(slug)).sort((a, b2) => b2.chars - a.chars)[0];
|
|
5355
5359
|
keptSlugs.delete(largest.slug);
|
|
5356
5360
|
demoted.push({ slug: largest.slug, title: largest.title });
|
|
5357
|
-
({ core, onDemand,
|
|
5361
|
+
({ core, onDemand, flagged } = assemble());
|
|
5358
5362
|
}
|
|
5359
5363
|
if (core.length > maxCoreChars) throw new AdaptPlanError(`core is ${core.length} chars, over the ${maxCoreChars} budget even with every section on demand`);
|
|
5360
5364
|
const translated = input.preamble + input.sections.map((s) => s.text).join("");
|
|
5361
|
-
const coverage = checkCoverage(translated, [core, ...onDemand.map((o) => o.text)],
|
|
5362
|
-
return { core, onDemand,
|
|
5365
|
+
const coverage = checkCoverage(translated, [core, ...onDemand.map((o) => o.text)], []);
|
|
5366
|
+
return { core, onDemand, flagged, coverage, coreChars: core.length, demoted };
|
|
5363
5367
|
}
|
|
5364
5368
|
var AdaptPlanError, MAX_CORE_CHARS;
|
|
5365
5369
|
var init_adapt_plan = __esm({
|
|
@@ -5409,6 +5413,165 @@ var init_instructions_tool = __esm({
|
|
|
5409
5413
|
}
|
|
5410
5414
|
});
|
|
5411
5415
|
|
|
5416
|
+
// ../agent/src/import/trust.ts
|
|
5417
|
+
var TrustError, TrustStore;
|
|
5418
|
+
var init_trust = __esm({
|
|
5419
|
+
"../agent/src/import/trust.ts"() {
|
|
5420
|
+
"use strict";
|
|
5421
|
+
TrustError = class extends Error {
|
|
5422
|
+
};
|
|
5423
|
+
TrustStore = class {
|
|
5424
|
+
fs;
|
|
5425
|
+
storePath;
|
|
5426
|
+
hashFn;
|
|
5427
|
+
// session decisions are kept in memory only: key = `${realPath}|${contentHash}`
|
|
5428
|
+
sessionMap = /* @__PURE__ */ new Set();
|
|
5429
|
+
constructor(deps) {
|
|
5430
|
+
this.fs = deps.fs;
|
|
5431
|
+
this.storePath = deps.path;
|
|
5432
|
+
this.hashFn = deps.hash;
|
|
5433
|
+
}
|
|
5434
|
+
async repoStatus(repoPath, files) {
|
|
5435
|
+
const realPath = await this.fs.realPath(repoPath);
|
|
5436
|
+
const contentHash = this.computeContentHash(files);
|
|
5437
|
+
const store = await this.readStore();
|
|
5438
|
+
const entry = store.repos[realPath];
|
|
5439
|
+
if (entry?.decision === "never") return "never";
|
|
5440
|
+
if (this.sessionMap.has(`${realPath}|${contentHash}`)) return "session";
|
|
5441
|
+
if (entry?.decision === "trusted" && entry.contentHash === contentHash) return "trusted";
|
|
5442
|
+
return "untrusted";
|
|
5443
|
+
}
|
|
5444
|
+
async setRepo(repoPath, files, decision) {
|
|
5445
|
+
const realPath = await this.fs.realPath(repoPath);
|
|
5446
|
+
const contentHash = this.computeContentHash(files);
|
|
5447
|
+
if (decision === "session") {
|
|
5448
|
+
this.sessionMap.add(`${realPath}|${contentHash}`);
|
|
5449
|
+
return;
|
|
5450
|
+
}
|
|
5451
|
+
await this.writeStore({ repos: { [realPath]: { decision, contentHash } }, stdio: {} });
|
|
5452
|
+
}
|
|
5453
|
+
async stdioStatus(def) {
|
|
5454
|
+
const store = await this.readStore();
|
|
5455
|
+
return store.stdio[this.computeStdioHash(def)] ? "approved" : "unapproved";
|
|
5456
|
+
}
|
|
5457
|
+
async approveStdio(def) {
|
|
5458
|
+
await this.writeStore({ repos: {}, stdio: { [this.computeStdioHash(def)]: true } });
|
|
5459
|
+
}
|
|
5460
|
+
computeContentHash(files) {
|
|
5461
|
+
const sorted = {};
|
|
5462
|
+
for (const key of Object.keys(files).sort()) sorted[key] = files[key];
|
|
5463
|
+
return this.hashFn(JSON.stringify(sorted));
|
|
5464
|
+
}
|
|
5465
|
+
computeStdioHash(def) {
|
|
5466
|
+
return this.hashFn(JSON.stringify([def.command, def.args, [...def.envNames].sort()]));
|
|
5467
|
+
}
|
|
5468
|
+
async readStore() {
|
|
5469
|
+
const text = await this.fs.readText(this.storePath);
|
|
5470
|
+
if (text === null) return { version: 1, repos: {}, stdio: {} };
|
|
5471
|
+
let parsed;
|
|
5472
|
+
try {
|
|
5473
|
+
parsed = JSON.parse(text);
|
|
5474
|
+
} catch (e) {
|
|
5475
|
+
throw new TrustError(`Failed to parse trust store at ${this.storePath}: ${String(e)}`);
|
|
5476
|
+
}
|
|
5477
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
5478
|
+
throw new TrustError(`Malformed trust store at ${this.storePath}`);
|
|
5479
|
+
}
|
|
5480
|
+
const obj = parsed;
|
|
5481
|
+
if (obj.version !== 1) {
|
|
5482
|
+
throw new TrustError(`Unsupported trust store version at ${this.storePath}`);
|
|
5483
|
+
}
|
|
5484
|
+
const repos = obj.repos ?? {};
|
|
5485
|
+
const stdio = obj.stdio ?? {};
|
|
5486
|
+
if (typeof repos !== "object" || repos === null) {
|
|
5487
|
+
throw new TrustError(`Malformed repos section in trust store at ${this.storePath}`);
|
|
5488
|
+
}
|
|
5489
|
+
if (typeof stdio !== "object" || stdio === null) {
|
|
5490
|
+
throw new TrustError(`Malformed stdio section in trust store at ${this.storePath}`);
|
|
5491
|
+
}
|
|
5492
|
+
return { version: 1, repos, stdio };
|
|
5493
|
+
}
|
|
5494
|
+
/** Re-reads immediately before the write and merges, so concurrent writers keep each other's entries. */
|
|
5495
|
+
async writeStore(delta) {
|
|
5496
|
+
const current = await this.readStore();
|
|
5497
|
+
const repos = { ...current.repos };
|
|
5498
|
+
for (const [key, next] of Object.entries(delta.repos)) {
|
|
5499
|
+
if (current.repos[key]?.decision === "never" && next.decision === "trusted") continue;
|
|
5500
|
+
repos[key] = next;
|
|
5501
|
+
}
|
|
5502
|
+
const store = { version: 1, repos, stdio: { ...current.stdio, ...delta.stdio } };
|
|
5503
|
+
await this.fs.writeTextAtomic(this.storePath, JSON.stringify(store, null, 2));
|
|
5504
|
+
}
|
|
5505
|
+
};
|
|
5506
|
+
}
|
|
5507
|
+
});
|
|
5508
|
+
|
|
5509
|
+
// ../agent/src/import/imports-config.ts
|
|
5510
|
+
function allOffConfig() {
|
|
5511
|
+
return {
|
|
5512
|
+
categories: {
|
|
5513
|
+
instructions: false,
|
|
5514
|
+
memory: false,
|
|
5515
|
+
permissions: false,
|
|
5516
|
+
commands: false,
|
|
5517
|
+
mcp: false,
|
|
5518
|
+
skills: false,
|
|
5519
|
+
agents: false
|
|
5520
|
+
},
|
|
5521
|
+
models: {}
|
|
5522
|
+
};
|
|
5523
|
+
}
|
|
5524
|
+
function isPlainObject(value) {
|
|
5525
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5526
|
+
}
|
|
5527
|
+
function parseImportsConfig(text, path12) {
|
|
5528
|
+
if (text === null) return { config: allOffConfig() };
|
|
5529
|
+
const fail = (reason) => ({ config: allOffConfig(), error: `${path12}: ${reason}` });
|
|
5530
|
+
let parsed;
|
|
5531
|
+
try {
|
|
5532
|
+
parsed = JSON.parse(text);
|
|
5533
|
+
} catch {
|
|
5534
|
+
return fail("invalid JSON");
|
|
5535
|
+
}
|
|
5536
|
+
if (!isPlainObject(parsed)) return fail("top-level JSON must be an object");
|
|
5537
|
+
if (parsed.version !== 1) return fail(`unsupported version ${String(parsed.version)}`);
|
|
5538
|
+
const config = allOffConfig();
|
|
5539
|
+
if (parsed.categories !== void 0) {
|
|
5540
|
+
if (!isPlainObject(parsed.categories)) return fail("categories must be an object");
|
|
5541
|
+
for (const [key, value] of Object.entries(parsed.categories)) {
|
|
5542
|
+
if (!IMPORT_CATEGORIES.includes(key)) return fail(`unknown category key "${key}"`);
|
|
5543
|
+
if (typeof value !== "boolean") return fail(`category "${key}" must be a boolean`);
|
|
5544
|
+
config.categories[key] = value;
|
|
5545
|
+
}
|
|
5546
|
+
}
|
|
5547
|
+
if (parsed.models !== void 0) {
|
|
5548
|
+
if (!isPlainObject(parsed.models)) return fail("models must be an object");
|
|
5549
|
+
for (const key of MODEL_KEYS) {
|
|
5550
|
+
const value = parsed.models[key];
|
|
5551
|
+
if (value === void 0) continue;
|
|
5552
|
+
if (typeof value !== "string" || value.trim() === "") return fail(`model "${key}" must be a non-empty string`);
|
|
5553
|
+
config.models[key] = value;
|
|
5554
|
+
}
|
|
5555
|
+
}
|
|
5556
|
+
return { config };
|
|
5557
|
+
}
|
|
5558
|
+
var IMPORT_CATEGORIES, MODEL_KEYS;
|
|
5559
|
+
var init_imports_config = __esm({
|
|
5560
|
+
"../agent/src/import/imports-config.ts"() {
|
|
5561
|
+
"use strict";
|
|
5562
|
+
IMPORT_CATEGORIES = [
|
|
5563
|
+
"instructions",
|
|
5564
|
+
"memory",
|
|
5565
|
+
"permissions",
|
|
5566
|
+
"commands",
|
|
5567
|
+
"mcp",
|
|
5568
|
+
"skills",
|
|
5569
|
+
"agents"
|
|
5570
|
+
];
|
|
5571
|
+
MODEL_KEYS = ["main", "agent", "skill", "router"];
|
|
5572
|
+
}
|
|
5573
|
+
});
|
|
5574
|
+
|
|
5412
5575
|
// ../agent/src/index.ts
|
|
5413
5576
|
var init_src = __esm({
|
|
5414
5577
|
"../agent/src/index.ts"() {
|
|
@@ -5446,13 +5609,15 @@ var init_src = __esm({
|
|
|
5446
5609
|
init_coverage();
|
|
5447
5610
|
init_adapt_plan();
|
|
5448
5611
|
init_instructions_tool();
|
|
5612
|
+
init_trust();
|
|
5613
|
+
init_imports_config();
|
|
5449
5614
|
}
|
|
5450
5615
|
});
|
|
5451
5616
|
|
|
5452
5617
|
// src/api-key.ts
|
|
5453
5618
|
import { join } from "node:path";
|
|
5454
5619
|
async function resolveApiKey(deps) {
|
|
5455
|
-
const { env: env3, readFile:
|
|
5620
|
+
const { env: env3, readFile: readFile6, homedir: homedir3 } = deps;
|
|
5456
5621
|
for (const name of ["SPACECODE_API_KEY", "ANTHROPIC_API_KEY"]) {
|
|
5457
5622
|
const value = env3[name]?.trim();
|
|
5458
5623
|
if (value) return value;
|
|
@@ -5461,7 +5626,7 @@ async function resolveApiKey(deps) {
|
|
|
5461
5626
|
const file = join(dir, "auth.json");
|
|
5462
5627
|
let raw;
|
|
5463
5628
|
try {
|
|
5464
|
-
raw = await
|
|
5629
|
+
raw = await readFile6(file);
|
|
5465
5630
|
} catch (err) {
|
|
5466
5631
|
if (err.code === "ENOENT") return null;
|
|
5467
5632
|
throw new Error(`Cannot read ${file}: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -5514,10 +5679,17 @@ function fileCache(deps) {
|
|
|
5514
5679
|
};
|
|
5515
5680
|
}
|
|
5516
5681
|
async function prepareProfile(deps) {
|
|
5682
|
+
let state;
|
|
5517
5683
|
try {
|
|
5518
|
-
|
|
5684
|
+
state = await prepareProfileUnsafe(deps);
|
|
5519
5685
|
} catch (err) {
|
|
5520
|
-
|
|
5686
|
+
state = EMPTY([`profile: not loaded (unexpected error: ${err instanceof Error ? err.message : String(err)})`]);
|
|
5687
|
+
}
|
|
5688
|
+
if (!deps.importGate) return state;
|
|
5689
|
+
try {
|
|
5690
|
+
return { ...state, statusLines: [...state.statusLines, ...await deps.importGate()] };
|
|
5691
|
+
} catch (err) {
|
|
5692
|
+
return { ...state, statusLines: [...state.statusLines, `imports: gate failed (${err instanceof Error ? err.message : String(err)}); nothing from repos loads`] };
|
|
5521
5693
|
}
|
|
5522
5694
|
}
|
|
5523
5695
|
async function prepareProfileUnsafe(deps) {
|
|
@@ -5569,16 +5741,11 @@ async function sha12(text) {
|
|
|
5569
5741
|
return [...new Uint8Array(d)].slice(0, 6).map((b2) => b2.toString(16).padStart(2, "0")).join("");
|
|
5570
5742
|
}
|
|
5571
5743
|
function formatAdaptReport(r, before, replaced) {
|
|
5572
|
-
const lines2 = [`Adapted instructions: ${before} chars -> core ${r.coreChars} chars + ${r.onDemand.length} on-demand section(s), ${r.
|
|
5744
|
+
const lines2 = [`Adapted instructions: ${before} chars -> core ${r.coreChars} chars + ${r.onDemand.length} on-demand section(s), ${r.flagged.length} of them flagged as Claude Code-specific. Nothing is removed.`];
|
|
5573
5745
|
for (const x2 of replaced) lines2.push(` tool name ${x2.from} -> ${x2.to} (${x2.count}x)`);
|
|
5574
5746
|
for (const d of r.demoted) lines2.push(` demoted ${d.slug}: kept by the model but moved on demand to fit the core budget`);
|
|
5575
5747
|
for (const o of r.onDemand) lines2.push(` on demand ${o.slug} (${o.text.length} chars)`);
|
|
5576
|
-
for (const d of r.
|
|
5577
|
-
if (r.coverage.droppedRules.length > 0) {
|
|
5578
|
-
lines2.push(` ${r.coverage.droppedRules.length} rule line(s) exist only in dropped sections:`);
|
|
5579
|
-
for (const rule of r.coverage.droppedRules.slice(0, 12)) lines2.push(` - ${rule.slice(0, 140)}`);
|
|
5580
|
-
if (r.coverage.droppedRules.length > 12) lines2.push(` ... and ${r.coverage.droppedRules.length - 12} more`);
|
|
5581
|
-
}
|
|
5748
|
+
for (const d of r.flagged) lines2.push(` flagged ${d.slug}: ${d.reason}${d.unsupported.length ? ` [${d.unsupported.join("; ")}]` : ""}`);
|
|
5582
5749
|
return lines2;
|
|
5583
5750
|
}
|
|
5584
5751
|
async function adaptInstructions(deps, original) {
|
|
@@ -32204,7 +32371,7 @@ var require_websocket = __commonJS({
|
|
|
32204
32371
|
var http = __require("http");
|
|
32205
32372
|
var net = __require("net");
|
|
32206
32373
|
var tls = __require("tls");
|
|
32207
|
-
var { randomBytes: randomBytes2, createHash } = __require("crypto");
|
|
32374
|
+
var { randomBytes: randomBytes2, createHash: createHash2 } = __require("crypto");
|
|
32208
32375
|
var { Duplex, Readable } = __require("stream");
|
|
32209
32376
|
var { URL: URL2 } = __require("url");
|
|
32210
32377
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -32872,7 +33039,7 @@ var require_websocket = __commonJS({
|
|
|
32872
33039
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
32873
33040
|
return;
|
|
32874
33041
|
}
|
|
32875
|
-
const digest =
|
|
33042
|
+
const digest = createHash2("sha1").update(key + GUID).digest("base64");
|
|
32876
33043
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
32877
33044
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
32878
33045
|
return;
|
|
@@ -33241,7 +33408,7 @@ var require_websocket_server = __commonJS({
|
|
|
33241
33408
|
var EventEmitter3 = __require("events");
|
|
33242
33409
|
var http = __require("http");
|
|
33243
33410
|
var { Duplex } = __require("stream");
|
|
33244
|
-
var { createHash } = __require("crypto");
|
|
33411
|
+
var { createHash: createHash2 } = __require("crypto");
|
|
33245
33412
|
var extension2 = require_extension();
|
|
33246
33413
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
33247
33414
|
var subprotocol2 = require_subprotocol();
|
|
@@ -33548,7 +33715,7 @@ var require_websocket_server = __commonJS({
|
|
|
33548
33715
|
);
|
|
33549
33716
|
}
|
|
33550
33717
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
33551
|
-
const digest =
|
|
33718
|
+
const digest = createHash2("sha1").update(key + GUID).digest("base64");
|
|
33552
33719
|
const headers = [
|
|
33553
33720
|
"HTTP/1.1 101 Switching Protocols",
|
|
33554
33721
|
"Upgrade: websocket",
|
|
@@ -40922,7 +41089,7 @@ var require_core = __commonJS({
|
|
|
40922
41089
|
return match && match.index === 0;
|
|
40923
41090
|
}
|
|
40924
41091
|
var BACKREF_RE = /\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;
|
|
40925
|
-
function
|
|
41092
|
+
function join6(regexps, separator = "|") {
|
|
40926
41093
|
let numCaptures = 0;
|
|
40927
41094
|
return regexps.map((regex2) => {
|
|
40928
41095
|
numCaptures += 1;
|
|
@@ -41226,7 +41393,7 @@ var require_core = __commonJS({
|
|
|
41226
41393
|
this.exec = () => null;
|
|
41227
41394
|
}
|
|
41228
41395
|
const terminators = this.regexes.map((el) => el[1]);
|
|
41229
|
-
this.matcherRe = langRe(
|
|
41396
|
+
this.matcherRe = langRe(join6(terminators), true);
|
|
41230
41397
|
this.lastIndex = 0;
|
|
41231
41398
|
}
|
|
41232
41399
|
/** @param {string} s */
|
|
@@ -100871,9 +101038,76 @@ var init_node_mentions = __esm({
|
|
|
100871
101038
|
}
|
|
100872
101039
|
});
|
|
100873
101040
|
|
|
101041
|
+
// src/import-gate.ts
|
|
101042
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
101043
|
+
import { chmod as chmod3, mkdir as mkdir3, readFile as readFile4, realpath as realpath2, rename as rename3, writeFile as writeFile3 } from "node:fs/promises";
|
|
101044
|
+
import { dirname as dirname3, join as join4 } from "node:path";
|
|
101045
|
+
async function readOrNull(path12) {
|
|
101046
|
+
try {
|
|
101047
|
+
return await readFile4(path12, "utf8");
|
|
101048
|
+
} catch (err) {
|
|
101049
|
+
if (err.code === "ENOENT") return null;
|
|
101050
|
+
throw err;
|
|
101051
|
+
}
|
|
101052
|
+
}
|
|
101053
|
+
async function writeTextAtomic(path12, text) {
|
|
101054
|
+
await mkdir3(dirname3(path12), { recursive: true });
|
|
101055
|
+
const tmp = `${path12}.${process.pid}.${randomUUID()}.tmp`;
|
|
101056
|
+
await writeFile3(tmp, text, { mode: 384 });
|
|
101057
|
+
await chmod3(tmp, 384);
|
|
101058
|
+
await rename3(tmp, path12);
|
|
101059
|
+
}
|
|
101060
|
+
function nodeTrustFs() {
|
|
101061
|
+
return { readText: readOrNull, writeTextAtomic, realPath: (p) => realpath2(p) };
|
|
101062
|
+
}
|
|
101063
|
+
function createNodeTrustStore(configDir) {
|
|
101064
|
+
return new TrustStore({ fs: nodeTrustFs(), path: join4(configDir, "trust.json"), hash: sha256 });
|
|
101065
|
+
}
|
|
101066
|
+
async function importGateStatus(deps) {
|
|
101067
|
+
const lines2 = [];
|
|
101068
|
+
const configPath = join4(deps.configDir, "imports.json");
|
|
101069
|
+
try {
|
|
101070
|
+
const loaded = parseImportsConfig(await readOrNull(configPath), configPath);
|
|
101071
|
+
if (loaded.error) lines2.push(`imports: ${loaded.error} (every category off)`);
|
|
101072
|
+
else {
|
|
101073
|
+
const on = IMPORT_CATEGORIES.filter((c) => loaded.config.categories[c]);
|
|
101074
|
+
lines2.push(on.length ? `imports: on for ${on.join(", ")}` : "imports: every category off (default)");
|
|
101075
|
+
}
|
|
101076
|
+
} catch (err) {
|
|
101077
|
+
lines2.push(`imports: not read (${err instanceof Error ? err.message : String(err)}); every category off`);
|
|
101078
|
+
}
|
|
101079
|
+
try {
|
|
101080
|
+
const files = {};
|
|
101081
|
+
for (const name of REPO_SOURCE_FILES) {
|
|
101082
|
+
const text = await readOrNull(join4(deps.cwd, name));
|
|
101083
|
+
if (text !== null) files[name] = text;
|
|
101084
|
+
}
|
|
101085
|
+
const found = Object.keys(files);
|
|
101086
|
+
if (found.length === 0) return lines2;
|
|
101087
|
+
const status = await createNodeTrustStore(deps.configDir).repoStatus(deps.cwd, files);
|
|
101088
|
+
const names = found.join(", ");
|
|
101089
|
+
if (status === "trusted" || status === "session") lines2.push(`repo sources: ${names} (trusted${status === "session" ? " for this session" : ""})`);
|
|
101090
|
+
else if (status === "never") lines2.push(`repo sources: ${names} NOT loaded (marked never trust)`);
|
|
101091
|
+
else lines2.push(`repo sources: ${names} NOT loaded (untrusted${deps.interactive ? "" : ", non-interactive run"})`);
|
|
101092
|
+
} catch (err) {
|
|
101093
|
+
lines2.push(`repo sources: NOT loaded (trust check failed: ${err instanceof Error ? err.message : String(err)})`);
|
|
101094
|
+
}
|
|
101095
|
+
return lines2;
|
|
101096
|
+
}
|
|
101097
|
+
var REPO_SOURCE_FILES, sha256;
|
|
101098
|
+
var init_import_gate = __esm({
|
|
101099
|
+
"src/import-gate.ts"() {
|
|
101100
|
+
"use strict";
|
|
101101
|
+
init_src();
|
|
101102
|
+
REPO_SOURCE_FILES = [".mcp.json", ".claude/settings.json", ".claude/settings.local.json", "CLAUDE.local.md"];
|
|
101103
|
+
sha256 = (text) => createHash("sha256").update(text).digest("hex");
|
|
101104
|
+
}
|
|
101105
|
+
});
|
|
101106
|
+
|
|
100874
101107
|
// src/useReplController.ts
|
|
100875
|
-
import { readFile as
|
|
101108
|
+
import { readFile as readFile5, writeFile as writeFile4, mkdir as mkdir4 } from "node:fs/promises";
|
|
100876
101109
|
import { homedir as homedir2 } from "node:os";
|
|
101110
|
+
import { join as join5 } from "node:path";
|
|
100877
101111
|
import { execFile as execFile3 } from "node:child_process";
|
|
100878
101112
|
function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mentionsOpt, sessions, resumeLatest: resumeLatest2, onViewTurns, onViewResume, isEscOwned }) {
|
|
100879
101113
|
const { exit } = use_app_default();
|
|
@@ -101166,7 +101400,7 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
101166
101400
|
}
|
|
101167
101401
|
setIsRunning(true);
|
|
101168
101402
|
try {
|
|
101169
|
-
const apiKey2 = await resolveApiKey({ env: process.env, readFile: (p) =>
|
|
101403
|
+
const apiKey2 = await resolveApiKey({ env: process.env, readFile: (p) => readFile5(p, "utf-8"), homedir: homedir2 });
|
|
101170
101404
|
if (!apiKey2) {
|
|
101171
101405
|
notice(MISSING_KEY_MESSAGE);
|
|
101172
101406
|
return;
|
|
@@ -101188,7 +101422,7 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
101188
101422
|
}
|
|
101189
101423
|
case "model": {
|
|
101190
101424
|
try {
|
|
101191
|
-
const apiKey2 = await resolveApiKey({ env: process.env, readFile: (p) =>
|
|
101425
|
+
const apiKey2 = await resolveApiKey({ env: process.env, readFile: (p) => readFile5(p, "utf-8"), homedir: homedir2 });
|
|
101192
101426
|
if (!apiKey2) {
|
|
101193
101427
|
notice(MISSING_KEY_MESSAGE);
|
|
101194
101428
|
return;
|
|
@@ -101230,7 +101464,7 @@ ${tools.map((t) => ` ${t.name}`).join("\n")}`);
|
|
|
101230
101464
|
try {
|
|
101231
101465
|
apiKey = await resolveApiKey({
|
|
101232
101466
|
env: process.env,
|
|
101233
|
-
readFile: (p) =>
|
|
101467
|
+
readFile: (p) => readFile5(p, "utf-8"),
|
|
101234
101468
|
homedir: homedir2
|
|
101235
101469
|
});
|
|
101236
101470
|
} catch (err) {
|
|
@@ -101266,15 +101500,20 @@ ${tools.map((t) => ` ${t.name}`).join("\n")}`);
|
|
|
101266
101500
|
try {
|
|
101267
101501
|
profilePromiseRef.current ??= prepareProfile({
|
|
101268
101502
|
env: process.env,
|
|
101269
|
-
readFile: (p) =>
|
|
101270
|
-
writeFile: (p, d) =>
|
|
101503
|
+
readFile: (p) => readFile5(p, "utf-8"),
|
|
101504
|
+
writeFile: (p, d) => writeFile4(p, d, { encoding: "utf-8", mode: 384 }),
|
|
101271
101505
|
mkdir: async (p) => {
|
|
101272
|
-
await
|
|
101506
|
+
await mkdir4(p, { recursive: true });
|
|
101273
101507
|
},
|
|
101274
101508
|
homedir: homedir2,
|
|
101275
101509
|
fetch,
|
|
101276
101510
|
cwd: process.cwd(),
|
|
101277
|
-
gitRoot: gitTopLevel
|
|
101511
|
+
gitRoot: gitTopLevel,
|
|
101512
|
+
importGate: () => importGateStatus({
|
|
101513
|
+
configDir: process.env.SPACECODE_CONFIG_DIR?.trim() || join5(homedir2(), ".spacecode"),
|
|
101514
|
+
cwd: process.cwd(),
|
|
101515
|
+
interactive: Boolean(process.stdin.isTTY)
|
|
101516
|
+
})
|
|
101278
101517
|
});
|
|
101279
101518
|
profileRef.current = await profilePromiseRef.current;
|
|
101280
101519
|
const toolset = createToolset();
|
|
@@ -101401,6 +101640,7 @@ var init_useReplController = __esm({
|
|
|
101401
101640
|
init_node_mentions();
|
|
101402
101641
|
init_api_key();
|
|
101403
101642
|
init_profile_runtime();
|
|
101643
|
+
init_import_gate();
|
|
101404
101644
|
init_slash_commands();
|
|
101405
101645
|
init_useEventAccumulator();
|
|
101406
101646
|
gitTopLevel = () => new Promise((resolve2) => {
|
|
@@ -101985,7 +102225,7 @@ function clearOnResize(stdout) {
|
|
|
101985
102225
|
var import_jsx_runtime14 = __toESM(require_jsx_runtime(), 1);
|
|
101986
102226
|
if (process.argv[2] === "import-claude") {
|
|
101987
102227
|
const { runImportClaude: runImportClaude2 } = await Promise.resolve().then(() => (init_import_claude(), import_claude_exports));
|
|
101988
|
-
const { readFile:
|
|
102228
|
+
const { readFile: readFile6, readdir: readdir3 } = await import("node:fs/promises");
|
|
101989
102229
|
const { execFile: execFile4 } = await import("node:child_process");
|
|
101990
102230
|
const gitRoot = () => new Promise((resolve2) => {
|
|
101991
102231
|
execFile4("git", ["rev-parse", "--show-toplevel"], { cwd: process.cwd() }, (err, stdout) => resolve2(err ? null : stdout.trim() || null));
|
|
@@ -101993,8 +102233,8 @@ if (process.argv[2] === "import-claude") {
|
|
|
101993
102233
|
const code = await runImportClaude2({
|
|
101994
102234
|
argv: process.argv.slice(2),
|
|
101995
102235
|
env: process.env,
|
|
101996
|
-
fs: { readFile: (p) =>
|
|
101997
|
-
readFile: (p) =>
|
|
102236
|
+
fs: { readFile: (p) => readFile6(p, "utf-8"), readdir: (p) => readdir3(p) },
|
|
102237
|
+
readFile: (p) => readFile6(p, "utf-8"),
|
|
101998
102238
|
homedir: os5.homedir,
|
|
101999
102239
|
cwd: process.cwd(),
|
|
102000
102240
|
gitRoot,
|