spacecode 2.5.2 → 2.5.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/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/repl.mjs +252 -24
- package/package.json +1 -1
package/dist/repl.mjs
CHANGED
|
@@ -4580,9 +4580,22 @@ function guardHost(inner, opts) {
|
|
|
4580
4580
|
await log(kind, subject, d, false);
|
|
4581
4581
|
throw new PolicyViolation(d.rule, `Blocked by policy (${d.rule}): ${d.reason}`);
|
|
4582
4582
|
}
|
|
4583
|
+
const verdict = opts.rules?.evaluate(kind === "exec" ? "bash" : kind, subject);
|
|
4584
|
+
const ruleTag = verdict?.rule ? `${verdict.rule} [${verdict.scope}]` : "";
|
|
4585
|
+
if (verdict?.effect === "deny") {
|
|
4586
|
+
d = { action: "deny", rule: "rule-deny", reason: `denied by imported rule ${ruleTag}` };
|
|
4587
|
+
await log(kind, subject, d, false);
|
|
4588
|
+
throw new PolicyViolation(d.rule, `Blocked by policy (${d.rule}): ${d.reason}`);
|
|
4589
|
+
}
|
|
4583
4590
|
if (kind !== "exec" && opts.permissions?.mode === "default") {
|
|
4584
4591
|
d = { action: "confirm", rule: "confirm-edit", reason: "modifies a file" };
|
|
4585
4592
|
}
|
|
4593
|
+
if (verdict?.effect === "ask") {
|
|
4594
|
+
d = { action: "confirm", rule: "rule-ask", reason: `imported rule ${ruleTag} asks first${opts.confirm ? "" : "; no way to ask (headless), so refused"}` };
|
|
4595
|
+
} else if (verdict?.effect === "allow" && d.action === "confirm") {
|
|
4596
|
+
await log(kind, subject, { action: "allow", rule: "rule-allow", reason: `allowed by imported rule ${ruleTag} (would be ${d.rule})` }, true);
|
|
4597
|
+
return;
|
|
4598
|
+
}
|
|
4586
4599
|
if (d.action === "confirm" && kind === "exec" && opts.permissions?.allowsCommand(subject)) {
|
|
4587
4600
|
await log(kind, subject, { action: "allow", rule: "allow-session", reason: "approved earlier this session" }, true);
|
|
4588
4601
|
return;
|
|
@@ -4606,7 +4619,15 @@ function guardHost(inner, opts) {
|
|
|
4606
4619
|
return {
|
|
4607
4620
|
kind: inner.kind,
|
|
4608
4621
|
files: {
|
|
4609
|
-
readFile: (p) =>
|
|
4622
|
+
readFile: async (p) => {
|
|
4623
|
+
const v2 = opts.rules?.evaluate("read_file", p.replace(/^\.\//, ""));
|
|
4624
|
+
if (v2?.effect === "deny") {
|
|
4625
|
+
const d = { action: "deny", rule: "rule-deny", reason: `denied by imported rule ${v2.rule} [${v2.scope}]` };
|
|
4626
|
+
await log("read_file", p, d, false);
|
|
4627
|
+
throw new PolicyViolation(d.rule, `Blocked by policy (${d.rule}): ${d.reason}`);
|
|
4628
|
+
}
|
|
4629
|
+
return inner.files.readFile(p);
|
|
4630
|
+
},
|
|
4610
4631
|
listDirectory: (p) => inner.files.listDirectory(p),
|
|
4611
4632
|
writeFile: async (p, c) => {
|
|
4612
4633
|
await gate("write_file", p, allow, { oldText: "", newText: c });
|
|
@@ -5572,6 +5593,132 @@ var init_imports_config = __esm({
|
|
|
5572
5593
|
}
|
|
5573
5594
|
});
|
|
5574
5595
|
|
|
5596
|
+
// ../agent/src/import/permission-rules.ts
|
|
5597
|
+
function splitCommand(cmd) {
|
|
5598
|
+
const segments2 = [];
|
|
5599
|
+
let cur = "";
|
|
5600
|
+
let quote = null;
|
|
5601
|
+
let compound = false;
|
|
5602
|
+
const flush = () => {
|
|
5603
|
+
const s = cur.trim();
|
|
5604
|
+
if (s) segments2.push(s);
|
|
5605
|
+
cur = "";
|
|
5606
|
+
};
|
|
5607
|
+
for (let i = 0; i < cmd.length; i++) {
|
|
5608
|
+
const ch = cmd[i];
|
|
5609
|
+
if (quote) {
|
|
5610
|
+
cur += ch;
|
|
5611
|
+
if (ch === quote) quote = null;
|
|
5612
|
+
} else if (ch === '"' || ch === "'") {
|
|
5613
|
+
quote = ch;
|
|
5614
|
+
cur += ch;
|
|
5615
|
+
} else if (";&|\n`()<>".includes(ch) || ch === "$" && cmd[i + 1] === "(") {
|
|
5616
|
+
compound = true;
|
|
5617
|
+
flush();
|
|
5618
|
+
} else {
|
|
5619
|
+
cur += ch;
|
|
5620
|
+
}
|
|
5621
|
+
}
|
|
5622
|
+
if (quote) return { compound: true, segments: [cmd.trim()] };
|
|
5623
|
+
flush();
|
|
5624
|
+
return compound ? { compound, segments: segments2 } : { compound, segments: [cmd.trim()] };
|
|
5625
|
+
}
|
|
5626
|
+
function matchesBash(pattern, cmd, effect) {
|
|
5627
|
+
const { compound, segments: segments2 } = splitCommand(cmd);
|
|
5628
|
+
if (compound && effect === "allow") return false;
|
|
5629
|
+
const prefix = pattern.endsWith(":*") ? pattern.slice(0, -2).trim() : null;
|
|
5630
|
+
const hit = (s) => prefix === null ? s === pattern.trim() : s === prefix || s.startsWith(prefix) && /\s/.test(s[prefix.length] ?? "");
|
|
5631
|
+
return segments2.some(hit);
|
|
5632
|
+
}
|
|
5633
|
+
function globToRegExp(glob) {
|
|
5634
|
+
let re3 = "";
|
|
5635
|
+
for (let i = 0; i < glob.length; i++) {
|
|
5636
|
+
const ch = glob[i];
|
|
5637
|
+
if (ch === "*") {
|
|
5638
|
+
if (glob[i + 1] === "*") {
|
|
5639
|
+
re3 += ".*";
|
|
5640
|
+
i++;
|
|
5641
|
+
if (glob[i + 1] === "/") i++;
|
|
5642
|
+
} else re3 += "[^/]*";
|
|
5643
|
+
} else if (ch === "?") re3 += "[^/]";
|
|
5644
|
+
else re3 += ch.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
5645
|
+
}
|
|
5646
|
+
return new RegExp("^" + re3 + "$");
|
|
5647
|
+
}
|
|
5648
|
+
function compile(text, effect, scope) {
|
|
5649
|
+
const m2 = /^([A-Za-z0-9_-]+)(?:\((.*)\))?$/s.exec(text.trim());
|
|
5650
|
+
if (!m2) return "malformed rule";
|
|
5651
|
+
const [, name, rawArg] = m2;
|
|
5652
|
+
const arg = rawArg === void 0 || rawArg.trim() === "" ? null : rawArg.trim();
|
|
5653
|
+
const tools = name.startsWith("mcp__") ? [name] : TOOL_MAP[name];
|
|
5654
|
+
if (!tools) return `unsupported tool ${name}`;
|
|
5655
|
+
if (arg === null) return { effect, scope, text, tools, arg, test: () => true };
|
|
5656
|
+
if (name === "Bash") return { effect, scope, text, tools, arg, test: (s, e) => matchesBash(arg, s, e) };
|
|
5657
|
+
if (name.startsWith("mcp__")) return "argument patterns are not supported for MCP tools";
|
|
5658
|
+
const re3 = globToRegExp(arg);
|
|
5659
|
+
return { effect, scope, text, tools, arg, test: (s) => re3.test(s) };
|
|
5660
|
+
}
|
|
5661
|
+
function buildRuleSet(sources) {
|
|
5662
|
+
const rules = [];
|
|
5663
|
+
const skipped = [];
|
|
5664
|
+
const counts = {};
|
|
5665
|
+
for (const s of ["user", "repo", "local"]) counts[s] = { allow: 0, deny: 0, ask: 0 };
|
|
5666
|
+
for (const src of sources) {
|
|
5667
|
+
for (const effect of ["deny", "ask", "allow"]) {
|
|
5668
|
+
for (const text of src[effect] ?? []) {
|
|
5669
|
+
const c = typeof text === "string" ? compile(text, effect, src.scope) : "malformed rule";
|
|
5670
|
+
if (typeof c === "string") skipped.push({ text: String(text), scope: src.scope, reason: c });
|
|
5671
|
+
else {
|
|
5672
|
+
rules.push(c);
|
|
5673
|
+
counts[src.scope][effect]++;
|
|
5674
|
+
}
|
|
5675
|
+
}
|
|
5676
|
+
}
|
|
5677
|
+
}
|
|
5678
|
+
const frozen = Object.freeze(rules);
|
|
5679
|
+
return {
|
|
5680
|
+
skipped,
|
|
5681
|
+
counts,
|
|
5682
|
+
evaluate(tool, subject) {
|
|
5683
|
+
for (const effect of ["deny", "ask", "allow"]) {
|
|
5684
|
+
const r = frozen.find((c) => c.effect === effect && c.tools.includes(tool) && c.test(subject, effect));
|
|
5685
|
+
if (r) return { effect, rule: r.text, scope: r.scope };
|
|
5686
|
+
}
|
|
5687
|
+
return { effect: "none" };
|
|
5688
|
+
}
|
|
5689
|
+
};
|
|
5690
|
+
}
|
|
5691
|
+
function defaultModeFor(mode) {
|
|
5692
|
+
switch (mode) {
|
|
5693
|
+
case void 0:
|
|
5694
|
+
case "default":
|
|
5695
|
+
return { mode: "default" };
|
|
5696
|
+
case "acceptEdits":
|
|
5697
|
+
return { mode: "accept-edits" };
|
|
5698
|
+
case "plan":
|
|
5699
|
+
return { mode: "plan" };
|
|
5700
|
+
case "bypassPermissions":
|
|
5701
|
+
return { mode: "yolo" };
|
|
5702
|
+
default:
|
|
5703
|
+
return { mode: null, reason: `unmappable defaultMode "${mode}"` };
|
|
5704
|
+
}
|
|
5705
|
+
}
|
|
5706
|
+
var TOOL_MAP;
|
|
5707
|
+
var init_permission_rules = __esm({
|
|
5708
|
+
"../agent/src/import/permission-rules.ts"() {
|
|
5709
|
+
"use strict";
|
|
5710
|
+
TOOL_MAP = {
|
|
5711
|
+
Bash: ["bash"],
|
|
5712
|
+
Read: ["read_file"],
|
|
5713
|
+
Edit: ["edit_file", "write_file"],
|
|
5714
|
+
Write: ["edit_file", "write_file"],
|
|
5715
|
+
MultiEdit: ["edit_file", "write_file"],
|
|
5716
|
+
Glob: ["list_directory"],
|
|
5717
|
+
Grep: ["search"]
|
|
5718
|
+
};
|
|
5719
|
+
}
|
|
5720
|
+
});
|
|
5721
|
+
|
|
5575
5722
|
// ../agent/src/index.ts
|
|
5576
5723
|
var init_src = __esm({
|
|
5577
5724
|
"../agent/src/index.ts"() {
|
|
@@ -5611,13 +5758,14 @@ var init_src = __esm({
|
|
|
5611
5758
|
init_instructions_tool();
|
|
5612
5759
|
init_trust();
|
|
5613
5760
|
init_imports_config();
|
|
5761
|
+
init_permission_rules();
|
|
5614
5762
|
}
|
|
5615
5763
|
});
|
|
5616
5764
|
|
|
5617
5765
|
// src/api-key.ts
|
|
5618
5766
|
import { join } from "node:path";
|
|
5619
5767
|
async function resolveApiKey(deps) {
|
|
5620
|
-
const { env: env3, readFile:
|
|
5768
|
+
const { env: env3, readFile: readFile7, homedir: homedir3 } = deps;
|
|
5621
5769
|
for (const name of ["SPACECODE_API_KEY", "ANTHROPIC_API_KEY"]) {
|
|
5622
5770
|
const value = env3[name]?.trim();
|
|
5623
5771
|
if (value) return value;
|
|
@@ -5626,7 +5774,7 @@ async function resolveApiKey(deps) {
|
|
|
5626
5774
|
const file = join(dir, "auth.json");
|
|
5627
5775
|
let raw;
|
|
5628
5776
|
try {
|
|
5629
|
-
raw = await
|
|
5777
|
+
raw = await readFile7(file);
|
|
5630
5778
|
} catch (err) {
|
|
5631
5779
|
if (err.code === "ENOENT") return null;
|
|
5632
5780
|
throw new Error(`Cannot read ${file}: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -34655,7 +34803,7 @@ var init_source = __esm({
|
|
|
34655
34803
|
object.level = options.level === void 0 ? colorLevel : options.level;
|
|
34656
34804
|
};
|
|
34657
34805
|
chalkFactory = (options) => {
|
|
34658
|
-
const chalk2 = (...
|
|
34806
|
+
const chalk2 = (...strings2) => strings2.join(" ");
|
|
34659
34807
|
applyOptions(chalk2, options);
|
|
34660
34808
|
Object.setPrototypeOf(chalk2, createChalk.prototype);
|
|
34661
34809
|
return chalk2;
|
|
@@ -41089,7 +41237,7 @@ var require_core = __commonJS({
|
|
|
41089
41237
|
return match && match.index === 0;
|
|
41090
41238
|
}
|
|
41091
41239
|
var BACKREF_RE = /\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;
|
|
41092
|
-
function
|
|
41240
|
+
function join7(regexps, separator = "|") {
|
|
41093
41241
|
let numCaptures = 0;
|
|
41094
41242
|
return regexps.map((regex2) => {
|
|
41095
41243
|
numCaptures += 1;
|
|
@@ -41393,7 +41541,7 @@ var require_core = __commonJS({
|
|
|
41393
41541
|
this.exec = () => null;
|
|
41394
41542
|
}
|
|
41395
41543
|
const terminators = this.regexes.map((el) => el[1]);
|
|
41396
|
-
this.matcherRe = langRe(
|
|
41544
|
+
this.matcherRe = langRe(join7(terminators), true);
|
|
41397
41545
|
this.lastIndex = 0;
|
|
41398
41546
|
}
|
|
41399
41547
|
/** @param {string} s */
|
|
@@ -84320,12 +84468,12 @@ var require_source = __commonJS({
|
|
|
84320
84468
|
return openAll + string + closeAll;
|
|
84321
84469
|
};
|
|
84322
84470
|
var template;
|
|
84323
|
-
var chalkTag = (chalk3, ...
|
|
84324
|
-
const [firstString] =
|
|
84471
|
+
var chalkTag = (chalk3, ...strings2) => {
|
|
84472
|
+
const [firstString] = strings2;
|
|
84325
84473
|
if (!isArray(firstString) || !isArray(firstString.raw)) {
|
|
84326
|
-
return
|
|
84474
|
+
return strings2.join(" ");
|
|
84327
84475
|
}
|
|
84328
|
-
const arguments_ =
|
|
84476
|
+
const arguments_ = strings2.slice(1);
|
|
84329
84477
|
const parts = [firstString.raw[0]];
|
|
84330
84478
|
for (let i = 1; i < firstString.length; i++) {
|
|
84331
84479
|
parts.push(
|
|
@@ -100673,6 +100821,7 @@ function createLocalToolset(opts) {
|
|
|
100673
100821
|
audit: new FileAuditLog(auditFile),
|
|
100674
100822
|
mode: opts.yolo ? "yolo" : "enforce",
|
|
100675
100823
|
permissions: opts.permissions,
|
|
100824
|
+
...opts.rules ? { rules: opts.rules } : {},
|
|
100676
100825
|
confirm: opts.confirm
|
|
100677
100826
|
});
|
|
100678
100827
|
const { handlers: githubHandlers } = createGitHubTools((command) => host.exec(command));
|
|
@@ -101104,10 +101253,83 @@ var init_import_gate = __esm({
|
|
|
101104
101253
|
}
|
|
101105
101254
|
});
|
|
101106
101255
|
|
|
101256
|
+
// src/permission-rules-loader.ts
|
|
101257
|
+
import { readFile as readFile5 } from "node:fs/promises";
|
|
101258
|
+
import { join as join5 } from "node:path";
|
|
101259
|
+
async function readOrNull2(path12) {
|
|
101260
|
+
try {
|
|
101261
|
+
return await readFile5(path12, "utf8");
|
|
101262
|
+
} catch (err) {
|
|
101263
|
+
if (err.code === "ENOENT") return null;
|
|
101264
|
+
throw err;
|
|
101265
|
+
}
|
|
101266
|
+
}
|
|
101267
|
+
async function loadPermissionRules(deps) {
|
|
101268
|
+
const none = (line) => ({ rules: void 0, defaultMode: void 0, statusLines: [line] });
|
|
101269
|
+
const configPath = join5(deps.configDir, "imports.json");
|
|
101270
|
+
try {
|
|
101271
|
+
const loaded = parseImportsConfig(await readOrNull2(configPath), configPath);
|
|
101272
|
+
if (loaded.error) return none("permission rules: off (imports.json unreadable)");
|
|
101273
|
+
if (!loaded.config.categories.permissions) return none("permission rules: off (imports.json has permissions off)");
|
|
101274
|
+
} catch (err) {
|
|
101275
|
+
return none(`permission rules: off (imports.json not read: ${err instanceof Error ? err.message : String(err)})`);
|
|
101276
|
+
}
|
|
101277
|
+
const lines2 = [];
|
|
101278
|
+
const files = [{ scope: "user", path: join5(deps.homeDir, ".claude", "settings.json") }];
|
|
101279
|
+
try {
|
|
101280
|
+
const sources2 = {};
|
|
101281
|
+
for (const name of REPO_SOURCE_FILES) {
|
|
101282
|
+
const text = await readOrNull2(join5(deps.cwd, name));
|
|
101283
|
+
if (text !== null) sources2[name] = text;
|
|
101284
|
+
}
|
|
101285
|
+
if (sources2[".claude/settings.json"] !== void 0 || sources2[".claude/settings.local.json"] !== void 0) {
|
|
101286
|
+
const status = await createNodeTrustStore(deps.configDir).repoStatus(deps.cwd, sources2);
|
|
101287
|
+
if (status === "trusted" || status === "session") {
|
|
101288
|
+
files.push({ scope: "repo", path: join5(deps.cwd, ".claude", "settings.json") }, { scope: "local", path: join5(deps.cwd, ".claude", "settings.local.json") });
|
|
101289
|
+
} else lines2.push(`permission rules: repo settings NOT loaded (${status === "never" ? "marked never trust" : "untrusted repo"})`);
|
|
101290
|
+
}
|
|
101291
|
+
} catch (err) {
|
|
101292
|
+
lines2.push(`permission rules: repo settings NOT loaded (trust check failed: ${err instanceof Error ? err.message : String(err)})`);
|
|
101293
|
+
}
|
|
101294
|
+
const sources = [];
|
|
101295
|
+
let defaultMode;
|
|
101296
|
+
for (const f of files) {
|
|
101297
|
+
try {
|
|
101298
|
+
const text = await readOrNull2(f.path);
|
|
101299
|
+
if (text === null) continue;
|
|
101300
|
+
const parsed = JSON.parse(text);
|
|
101301
|
+
const perms = parsed?.permissions;
|
|
101302
|
+
if (!perms || typeof perms !== "object") continue;
|
|
101303
|
+
sources.push({ scope: f.scope, allow: strings(perms.allow), deny: strings(perms.deny), ask: strings(perms.ask) });
|
|
101304
|
+
if (typeof perms.defaultMode === "string") {
|
|
101305
|
+
const m2 = defaultModeFor(perms.defaultMode);
|
|
101306
|
+
if (m2.mode) defaultMode = m2.mode;
|
|
101307
|
+
else lines2.push(`permission rules: ${f.path}: ${m2.reason}`);
|
|
101308
|
+
}
|
|
101309
|
+
} catch (err) {
|
|
101310
|
+
lines2.push(`permission rules: ${f.path} NOT loaded (${err instanceof Error ? err.message : String(err)})`);
|
|
101311
|
+
}
|
|
101312
|
+
}
|
|
101313
|
+
const rules = buildRuleSet(sources);
|
|
101314
|
+
const parts = ["user", "repo", "local"].filter((s) => sources.some((x2) => x2.scope === s)).map((s) => `${s} ${rules.counts[s].allow} allow/${rules.counts[s].deny} deny/${rules.counts[s].ask} ask`);
|
|
101315
|
+
lines2.unshift(`permission rules: ${parts.length ? parts.join(", ") : "none found"}${defaultMode ? `; default mode ${defaultMode}` : ""}`);
|
|
101316
|
+
for (const s of rules.skipped) lines2.push(`permission rules: skipped [${s.scope}] "${s.text}" (${s.reason})`);
|
|
101317
|
+
return { rules, defaultMode, statusLines: lines2 };
|
|
101318
|
+
}
|
|
101319
|
+
var strings;
|
|
101320
|
+
var init_permission_rules_loader = __esm({
|
|
101321
|
+
"src/permission-rules-loader.ts"() {
|
|
101322
|
+
"use strict";
|
|
101323
|
+
init_src();
|
|
101324
|
+
init_import_gate();
|
|
101325
|
+
strings = (v2) => Array.isArray(v2) ? v2.filter((x2) => typeof x2 === "string") : void 0;
|
|
101326
|
+
}
|
|
101327
|
+
});
|
|
101328
|
+
|
|
101107
101329
|
// src/useReplController.ts
|
|
101108
|
-
import { readFile as
|
|
101330
|
+
import { readFile as readFile6, writeFile as writeFile4, mkdir as mkdir4 } from "node:fs/promises";
|
|
101109
101331
|
import { homedir as homedir2 } from "node:os";
|
|
101110
|
-
import { join as
|
|
101332
|
+
import { join as join6 } from "node:path";
|
|
101111
101333
|
import { execFile as execFile3 } from "node:child_process";
|
|
101112
101334
|
function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mentionsOpt, sessions, resumeLatest: resumeLatest2, onViewTurns, onViewResume, isEscOwned }) {
|
|
101113
101335
|
const { exit } = use_app_default();
|
|
@@ -101149,6 +101371,7 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
101149
101371
|
const abortRef = (0, import_react30.useRef)(null);
|
|
101150
101372
|
const pendingRef = (0, import_react30.useRef)(null);
|
|
101151
101373
|
const toolsetRef = (0, import_react30.useRef)(null);
|
|
101374
|
+
const rulesRef = (0, import_react30.useRef)(void 0);
|
|
101152
101375
|
(0, import_react30.useEffect)(() => {
|
|
101153
101376
|
sessionTokensRef.current = sessionTokens;
|
|
101154
101377
|
}, [sessionTokens]);
|
|
@@ -101201,6 +101424,7 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
101201
101424
|
cwd: process.cwd(),
|
|
101202
101425
|
permissions,
|
|
101203
101426
|
onTodos: setTodos,
|
|
101427
|
+
...rulesRef.current ? { rules: rulesRef.current } : {},
|
|
101204
101428
|
...profileRef.current && profileRef.current.tools.length > 0 ? { extra: { tools: profileRef.current.tools, handlers: profileRef.current.handlers } } : {},
|
|
101205
101429
|
confirm: (req) => new Promise((resolve2) => {
|
|
101206
101430
|
const item = {
|
|
@@ -101400,7 +101624,7 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
101400
101624
|
}
|
|
101401
101625
|
setIsRunning(true);
|
|
101402
101626
|
try {
|
|
101403
|
-
const apiKey2 = await resolveApiKey({ env: process.env, readFile: (p) =>
|
|
101627
|
+
const apiKey2 = await resolveApiKey({ env: process.env, readFile: (p) => readFile6(p, "utf-8"), homedir: homedir2 });
|
|
101404
101628
|
if (!apiKey2) {
|
|
101405
101629
|
notice(MISSING_KEY_MESSAGE);
|
|
101406
101630
|
return;
|
|
@@ -101422,7 +101646,7 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
101422
101646
|
}
|
|
101423
101647
|
case "model": {
|
|
101424
101648
|
try {
|
|
101425
|
-
const apiKey2 = await resolveApiKey({ env: process.env, readFile: (p) =>
|
|
101649
|
+
const apiKey2 = await resolveApiKey({ env: process.env, readFile: (p) => readFile6(p, "utf-8"), homedir: homedir2 });
|
|
101426
101650
|
if (!apiKey2) {
|
|
101427
101651
|
notice(MISSING_KEY_MESSAGE);
|
|
101428
101652
|
return;
|
|
@@ -101464,7 +101688,7 @@ ${tools.map((t) => ` ${t.name}`).join("\n")}`);
|
|
|
101464
101688
|
try {
|
|
101465
101689
|
apiKey = await resolveApiKey({
|
|
101466
101690
|
env: process.env,
|
|
101467
|
-
readFile: (p) =>
|
|
101691
|
+
readFile: (p) => readFile6(p, "utf-8"),
|
|
101468
101692
|
homedir: homedir2
|
|
101469
101693
|
});
|
|
101470
101694
|
} catch (err) {
|
|
@@ -101500,7 +101724,7 @@ ${tools.map((t) => ` ${t.name}`).join("\n")}`);
|
|
|
101500
101724
|
try {
|
|
101501
101725
|
profilePromiseRef.current ??= prepareProfile({
|
|
101502
101726
|
env: process.env,
|
|
101503
|
-
readFile: (p) =>
|
|
101727
|
+
readFile: (p) => readFile6(p, "utf-8"),
|
|
101504
101728
|
writeFile: (p, d) => writeFile4(p, d, { encoding: "utf-8", mode: 384 }),
|
|
101505
101729
|
mkdir: async (p) => {
|
|
101506
101730
|
await mkdir4(p, { recursive: true });
|
|
@@ -101509,11 +101733,14 @@ ${tools.map((t) => ` ${t.name}`).join("\n")}`);
|
|
|
101509
101733
|
fetch,
|
|
101510
101734
|
cwd: process.cwd(),
|
|
101511
101735
|
gitRoot: gitTopLevel,
|
|
101512
|
-
importGate: () =>
|
|
101513
|
-
configDir
|
|
101514
|
-
cwd: process.cwd(),
|
|
101515
|
-
|
|
101516
|
-
|
|
101736
|
+
importGate: async () => {
|
|
101737
|
+
const configDir = process.env.SPACECODE_CONFIG_DIR?.trim() || join6(homedir2(), ".spacecode");
|
|
101738
|
+
const gate = await importGateStatus({ configDir, cwd: process.cwd(), interactive: Boolean(process.stdin.isTTY) });
|
|
101739
|
+
const loaded = await loadPermissionRules({ configDir, homeDir: homedir2(), cwd: process.cwd() });
|
|
101740
|
+
rulesRef.current = loaded.rules;
|
|
101741
|
+
if (loaded.defaultMode && !yolo2) permissions.set(loaded.defaultMode);
|
|
101742
|
+
return [...gate, ...loaded.statusLines];
|
|
101743
|
+
}
|
|
101517
101744
|
});
|
|
101518
101745
|
profileRef.current = await profilePromiseRef.current;
|
|
101519
101746
|
const toolset = createToolset();
|
|
@@ -101641,6 +101868,7 @@ var init_useReplController = __esm({
|
|
|
101641
101868
|
init_api_key();
|
|
101642
101869
|
init_profile_runtime();
|
|
101643
101870
|
init_import_gate();
|
|
101871
|
+
init_permission_rules_loader();
|
|
101644
101872
|
init_slash_commands();
|
|
101645
101873
|
init_useEventAccumulator();
|
|
101646
101874
|
gitTopLevel = () => new Promise((resolve2) => {
|
|
@@ -102225,7 +102453,7 @@ function clearOnResize(stdout) {
|
|
|
102225
102453
|
var import_jsx_runtime14 = __toESM(require_jsx_runtime(), 1);
|
|
102226
102454
|
if (process.argv[2] === "import-claude") {
|
|
102227
102455
|
const { runImportClaude: runImportClaude2 } = await Promise.resolve().then(() => (init_import_claude(), import_claude_exports));
|
|
102228
|
-
const { readFile:
|
|
102456
|
+
const { readFile: readFile7, readdir: readdir3 } = await import("node:fs/promises");
|
|
102229
102457
|
const { execFile: execFile4 } = await import("node:child_process");
|
|
102230
102458
|
const gitRoot = () => new Promise((resolve2) => {
|
|
102231
102459
|
execFile4("git", ["rev-parse", "--show-toplevel"], { cwd: process.cwd() }, (err, stdout) => resolve2(err ? null : stdout.trim() || null));
|
|
@@ -102233,8 +102461,8 @@ if (process.argv[2] === "import-claude") {
|
|
|
102233
102461
|
const code = await runImportClaude2({
|
|
102234
102462
|
argv: process.argv.slice(2),
|
|
102235
102463
|
env: process.env,
|
|
102236
|
-
fs: { readFile: (p) =>
|
|
102237
|
-
readFile: (p) =>
|
|
102464
|
+
fs: { readFile: (p) => readFile7(p, "utf-8"), readdir: (p) => readdir3(p) },
|
|
102465
|
+
readFile: (p) => readFile7(p, "utf-8"),
|
|
102238
102466
|
homedir: os5.homedir,
|
|
102239
102467
|
cwd: process.cwd(),
|
|
102240
102468
|
gitRoot,
|