spacecode 2.9.0 → 2.10.0
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 +2 -2
- package/dist/repl.mjs +106 -0
- package/package.json +1 -1
package/dist/repl.mjs
CHANGED
|
@@ -7252,6 +7252,28 @@ var init_trust = __esm({
|
|
|
7252
7252
|
}
|
|
7253
7253
|
});
|
|
7254
7254
|
|
|
7255
|
+
// ../agent/src/import/source-changes.ts
|
|
7256
|
+
function fingerprintSources(files, hash) {
|
|
7257
|
+
const fingerprint = {};
|
|
7258
|
+
for (const [path12, content] of Object.entries(files)) fingerprint[path12] = hash(content);
|
|
7259
|
+
return fingerprint;
|
|
7260
|
+
}
|
|
7261
|
+
function diffSources(before, after) {
|
|
7262
|
+
const has2 = (o, k2) => Object.hasOwn(o, k2);
|
|
7263
|
+
const added = Object.keys(after).filter((k2) => !has2(before, k2)).sort();
|
|
7264
|
+
const removed = Object.keys(before).filter((k2) => !has2(after, k2)).sort();
|
|
7265
|
+
const modified = Object.keys(after).filter((k2) => has2(before, k2) && before[k2] !== after[k2]).sort();
|
|
7266
|
+
return { added, modified, removed, changed: added.length + modified.length + removed.length > 0 };
|
|
7267
|
+
}
|
|
7268
|
+
function formatSourceChanges(c) {
|
|
7269
|
+
return [...c.added.map((p) => `added: ${p}`), ...c.modified.map((p) => `modified: ${p}`), ...c.removed.map((p) => `removed: ${p}`)];
|
|
7270
|
+
}
|
|
7271
|
+
var init_source_changes = __esm({
|
|
7272
|
+
"../agent/src/import/source-changes.ts"() {
|
|
7273
|
+
"use strict";
|
|
7274
|
+
}
|
|
7275
|
+
});
|
|
7276
|
+
|
|
7255
7277
|
// ../agent/src/import/imports-config.ts
|
|
7256
7278
|
function allOffConfig() {
|
|
7257
7279
|
return {
|
|
@@ -7986,6 +8008,7 @@ __export(src_exports, {
|
|
|
7986
8008
|
createSkillTool: () => createSkillTool,
|
|
7987
8009
|
createTodoTool: () => createTodoTool,
|
|
7988
8010
|
defaultModeFor: () => defaultModeFor,
|
|
8011
|
+
diffSources: () => diffSources,
|
|
7989
8012
|
estimateTokens: () => estimateTokens,
|
|
7990
8013
|
estimateTotalTokens: () => estimateTotalTokens,
|
|
7991
8014
|
expandCommand: () => expandCommand,
|
|
@@ -7993,8 +8016,10 @@ __export(src_exports, {
|
|
|
7993
8016
|
expandServerEnv: () => expandServerEnv,
|
|
7994
8017
|
extractRuleLines: () => extractRuleLines,
|
|
7995
8018
|
findUnsupported: () => findUnsupported,
|
|
8019
|
+
fingerprintSources: () => fingerprintSources,
|
|
7996
8020
|
flattenMessageText: () => flattenMessageText,
|
|
7997
8021
|
formatSkillBody: () => formatSkillBody,
|
|
8022
|
+
formatSourceChanges: () => formatSourceChanges,
|
|
7998
8023
|
formatToolResult: () => formatToolResult,
|
|
7999
8024
|
guardHost: () => guardHost,
|
|
8000
8025
|
isReadOnlyCommand: () => isReadOnlyCommand,
|
|
@@ -8060,6 +8085,7 @@ var init_src = __esm({
|
|
|
8060
8085
|
init_adapt_plan();
|
|
8061
8086
|
init_instructions_tool();
|
|
8062
8087
|
init_trust();
|
|
8088
|
+
init_source_changes();
|
|
8063
8089
|
init_imports_config();
|
|
8064
8090
|
init_permission_rules();
|
|
8065
8091
|
init_command_args();
|
|
@@ -103444,6 +103470,7 @@ var init_slash_commands = __esm({
|
|
|
103444
103470
|
{ name: "turns", description: "Browse earlier turns and open their steps (shortcut: ctrl+o)" },
|
|
103445
103471
|
{ name: "commands", description: "List the slash commands imported from Claude Code" },
|
|
103446
103472
|
{ name: "skills", description: "List imported skills; /skills show <name> [file], /skills delete <name>" },
|
|
103473
|
+
{ name: "import", description: "Re-check imported Claude Code sources: /import reload shows changes; /import reload trust applies them" },
|
|
103447
103474
|
{ name: "tools", description: "List the tools available to the agent" },
|
|
103448
103475
|
{ name: "exit", description: "Quit the REPL (alias: /quit)" },
|
|
103449
103476
|
{ name: "quit", description: "Quit the REPL" }
|
|
@@ -105043,6 +105070,41 @@ var init_permission_rules_loader = __esm({
|
|
|
105043
105070
|
}
|
|
105044
105071
|
});
|
|
105045
105072
|
|
|
105073
|
+
// src/import-reload.ts
|
|
105074
|
+
async function checkRepoSources(deps, loaded) {
|
|
105075
|
+
const files = await readRepoSources(deps.cwd);
|
|
105076
|
+
const current = fingerprintSources(files, sha2562);
|
|
105077
|
+
const status = Object.keys(files).length === 0 ? "untrusted" : await createNodeTrustStore(deps.configDir).repoStatus(deps.cwd, files);
|
|
105078
|
+
return { current, changes: diffSources(loaded, current), trusted: status === "trusted" || status === "session" };
|
|
105079
|
+
}
|
|
105080
|
+
async function describeReload(deps, loaded) {
|
|
105081
|
+
const check = await checkRepoSources(deps, loaded);
|
|
105082
|
+
if (!check.changes.changed) return ["No change in the repo import sources since they were loaded."];
|
|
105083
|
+
const files = await readRepoSources(deps.cwd);
|
|
105084
|
+
return [
|
|
105085
|
+
"Repo import sources changed since they were loaded:",
|
|
105086
|
+
...formatSourceChanges(check.changes).map((l) => ` ${l}`),
|
|
105087
|
+
"",
|
|
105088
|
+
"Trusting the new state would load:",
|
|
105089
|
+
...describeRepoSources(files).length ? describeRepoSources(files) : [" (nothing)"],
|
|
105090
|
+
"",
|
|
105091
|
+
"Run /import reload trust to trust it and apply the rules and commands. MCP servers and skills apply on the next start."
|
|
105092
|
+
];
|
|
105093
|
+
}
|
|
105094
|
+
async function trustCurrentSources(deps) {
|
|
105095
|
+
const files = await readRepoSources(deps.cwd);
|
|
105096
|
+
await createNodeTrustStore(deps.configDir).setRepo(deps.cwd, files, "trusted");
|
|
105097
|
+
return fingerprintSources(files, sha2562);
|
|
105098
|
+
}
|
|
105099
|
+
var init_import_reload = __esm({
|
|
105100
|
+
"src/import-reload.ts"() {
|
|
105101
|
+
"use strict";
|
|
105102
|
+
init_src();
|
|
105103
|
+
init_import_gate();
|
|
105104
|
+
init_repo_trust_prompt();
|
|
105105
|
+
}
|
|
105106
|
+
});
|
|
105107
|
+
|
|
105046
105108
|
// src/command-loader.ts
|
|
105047
105109
|
import { join as join12 } from "node:path";
|
|
105048
105110
|
async function userCommands(deps, lines2) {
|
|
@@ -105196,6 +105258,7 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
105196
105258
|
const pendingRef = (0, import_react30.useRef)(null);
|
|
105197
105259
|
const toolsetRef = (0, import_react30.useRef)(null);
|
|
105198
105260
|
const rulesRef = (0, import_react30.useRef)(void 0);
|
|
105261
|
+
const loadedSourcesRef = (0, import_react30.useRef)(null);
|
|
105199
105262
|
const [commandsLoaded, setCommandsLoaded] = (0, import_react30.useState)({ commands: [], statusLines: [] });
|
|
105200
105263
|
(0, import_react30.useEffect)(() => {
|
|
105201
105264
|
let live2 = true;
|
|
@@ -105420,6 +105483,29 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
105420
105483
|
case "context":
|
|
105421
105484
|
notice(formatContextReport({ contextTokens: estimateTotalTokens("", history), maxContextTokens: DEFAULT_MAX_CONTEXT_TOKENS }));
|
|
105422
105485
|
return;
|
|
105486
|
+
case "import": {
|
|
105487
|
+
const configDir = process.env.SPACECODE_CONFIG_DIR?.trim() || join13(homedir2(), ".spacecode");
|
|
105488
|
+
const deps = { configDir, cwd: process.cwd() };
|
|
105489
|
+
const [sub, ...rest] = slash.args.split(/\s+/).filter(Boolean);
|
|
105490
|
+
if (sub !== "reload" || rest.length > 1 || rest[0] !== void 0 && rest[0] !== "trust") {
|
|
105491
|
+
notice("Usage: /import reload (show changes to the repo import sources) or /import reload trust (trust the new state and apply it).");
|
|
105492
|
+
return;
|
|
105493
|
+
}
|
|
105494
|
+
try {
|
|
105495
|
+
const baseline = loadedSourcesRef.current ?? fingerprintSources(await readRepoSources(process.cwd()), sha2562);
|
|
105496
|
+
if (rest[0] === "trust") {
|
|
105497
|
+
loadedSourcesRef.current = await trustCurrentSources(deps);
|
|
105498
|
+
const loaded = await loadPermissionRules({ configDir, homeDir: homedir2(), cwd: process.cwd() });
|
|
105499
|
+
rulesRef.current = loaded.rules;
|
|
105500
|
+
const cmds = await loadCommands({ configDir, cwd: process.cwd(), env: process.env, readFile: (p) => readFile9(p, "utf-8"), homedir: homedir2, fetch, builtins: SLASH_COMMANDS.map((c) => c.name) });
|
|
105501
|
+
setCommandsLoaded(cmds);
|
|
105502
|
+
notice(["Trusted the repo import sources as they are now.", ...loaded.statusLines, ...cmds.statusLines, "MCP servers and skills apply on the next start."].join("\n"));
|
|
105503
|
+
} else notice((await describeReload(deps, baseline)).join("\n"));
|
|
105504
|
+
} catch (err) {
|
|
105505
|
+
notice(`/import reload failed (${err instanceof Error ? err.message : String(err)}); nothing was changed.`);
|
|
105506
|
+
}
|
|
105507
|
+
return;
|
|
105508
|
+
}
|
|
105423
105509
|
case "record":
|
|
105424
105510
|
notice(await recording().command(slash.args));
|
|
105425
105511
|
return;
|
|
@@ -105605,6 +105691,22 @@ ${list2.map((c) => ` /${c.name} (${c.scope})${c.description ? ` ${c.descripti
|
|
|
105605
105691
|
let failed = false;
|
|
105606
105692
|
let keepForRetry = false;
|
|
105607
105693
|
try {
|
|
105694
|
+
if (loadedSourcesRef.current) {
|
|
105695
|
+
const configDir = process.env.SPACECODE_CONFIG_DIR?.trim() || join13(homedir2(), ".spacecode");
|
|
105696
|
+
try {
|
|
105697
|
+
const check = await checkRepoSources({ configDir, cwd: process.cwd() }, loadedSourcesRef.current);
|
|
105698
|
+
if (check.changes.changed) {
|
|
105699
|
+
const loaded = await loadPermissionRules({ configDir, homeDir: homedir2(), cwd: process.cwd() });
|
|
105700
|
+
rulesRef.current = loaded.rules;
|
|
105701
|
+
loadedSourcesRef.current = check.current;
|
|
105702
|
+
const lead = check.trusted ? "Repo import sources changed since they were loaded; the new state is already trusted, so its permission rules now apply:" : "Repo import sources changed since they were loaded; repo permission rules are dropped until you trust the new state:";
|
|
105703
|
+
notice([lead, ...formatSourceChanges(check.changes).map((l) => ` ${l}`), ...check.trusted ? [] : ["Run /import reload to review, /import reload trust to apply."]].join("\n"));
|
|
105704
|
+
}
|
|
105705
|
+
} catch (err) {
|
|
105706
|
+
rulesRef.current = void 0;
|
|
105707
|
+
notice(`Repo import source check failed (${err instanceof Error ? err.message : String(err)}); repo permission rules are dropped.`);
|
|
105708
|
+
}
|
|
105709
|
+
}
|
|
105608
105710
|
profilePromiseRef.current ??= prepareProfile({
|
|
105609
105711
|
env: process.env,
|
|
105610
105712
|
readFile: (p) => readFile9(p, "utf-8"),
|
|
@@ -105618,9 +105720,11 @@ ${list2.map((c) => ` /${c.name} (${c.scope})${c.description ? ` ${c.descripti
|
|
|
105618
105720
|
gitRoot: gitTopLevel,
|
|
105619
105721
|
importGate: async () => {
|
|
105620
105722
|
const configDir = process.env.SPACECODE_CONFIG_DIR?.trim() || join13(homedir2(), ".spacecode");
|
|
105723
|
+
const fingerprint = fingerprintSources(await readRepoSources(process.cwd()), sha2562);
|
|
105621
105724
|
const gate = await importGateStatus({ configDir, cwd: process.cwd(), interactive: Boolean(process.stdin.isTTY) });
|
|
105622
105725
|
const loaded = await loadPermissionRules({ configDir, homeDir: homedir2(), cwd: process.cwd() });
|
|
105623
105726
|
rulesRef.current = loaded.rules;
|
|
105727
|
+
loadedSourcesRef.current = fingerprint;
|
|
105624
105728
|
if (loaded.defaultMode && !yolo2) permissions.set(loaded.defaultMode);
|
|
105625
105729
|
return [...gate, ...loaded.statusLines];
|
|
105626
105730
|
}
|
|
@@ -105780,6 +105884,8 @@ var init_useReplController = __esm({
|
|
|
105780
105884
|
init_mcp_manager();
|
|
105781
105885
|
init_import_gate();
|
|
105782
105886
|
init_permission_rules_loader();
|
|
105887
|
+
init_import_reload();
|
|
105888
|
+
init_src();
|
|
105783
105889
|
init_command_loader();
|
|
105784
105890
|
init_slash_commands();
|
|
105785
105891
|
init_useEventAccumulator();
|