spacecode 2.8.0 → 2.8.1
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 +50 -24
- package/package.json +1 -1
package/dist/repl.mjs
CHANGED
|
@@ -3852,7 +3852,7 @@ function buildSystemPrompt(options) {
|
|
|
3852
3852
|
${toolLines.join("\n")}
|
|
3853
3853
|
|
|
3854
3854
|
## Tool usage
|
|
3855
|
-
${options.projectCard ? "- A project card below already
|
|
3855
|
+
${options.projectCard ? "- A project card below already holds the layout, commands, doc titles and excerpts, recent commits, branch and uncommitted changes. Do not re-list directories, re-run git status/log/diff, or re-read a doc just to see what the card shows; open a file only to go beyond its excerpt." : "- Use list_directory to orient yourself in the codebase before diving in."}
|
|
3856
3856
|
- Use search to find files by concept ("auth middleware", "billing webhook").
|
|
3857
3857
|
- Use bash for running commands, not for reading files. Use read_file instead.
|
|
3858
3858
|
- Prefer read_file + edit_file over write_file for existing files.
|
|
@@ -3921,13 +3921,17 @@ function sections(i) {
|
|
|
3921
3921
|
if (docs.length) out.push({ key: "docs", lines: docs });
|
|
3922
3922
|
const commits = i.recentCommits.slice(0, 8).map((c) => `- ${c}`);
|
|
3923
3923
|
if (commits.length) out.push({ key: "commits", lines: commits });
|
|
3924
|
+
const changeLines = [...i.changes?.vsMain ? [`- vs main: ${cut(i.changes.vsMain, 160)}`] : [], ...(i.changes?.files ?? []).slice(0, 15).map((f) => `- ${cut(f, 120)}`)];
|
|
3925
|
+
if (changeLines.length) out.push({ key: "changes", lines: changeLines });
|
|
3926
|
+
const digests = (i.digests ?? []).slice(0, 5).flatMap((d) => [`#### ${d.path}`, ...d.lines.slice(0, 6).map((l) => `- ${cut(l, 110)}`)]);
|
|
3927
|
+
if (digests.length) out.push({ key: "digests", lines: digests });
|
|
3924
3928
|
const backlog = i.backlog.slice(0, 6).map((b2) => `- ${cut(b2, 160)}`);
|
|
3925
3929
|
if (backlog.length) out.push({ key: "backlog", lines: backlog });
|
|
3926
3930
|
return out;
|
|
3927
3931
|
}
|
|
3928
|
-
function renderProjectCard(input, budgetChars =
|
|
3932
|
+
function renderProjectCard(input, budgetChars = 7e3) {
|
|
3929
3933
|
let secs = sections(input);
|
|
3930
|
-
for (const drop of ["backlog", "docs", "commits", "commands"]) {
|
|
3934
|
+
for (const drop of ["backlog", "digests", "changes", "docs", "commits", "commands"]) {
|
|
3931
3935
|
if (render(secs).length <= budgetChars) return render(secs);
|
|
3932
3936
|
secs = secs.filter((s) => s.key !== drop);
|
|
3933
3937
|
}
|
|
@@ -3953,6 +3957,8 @@ var init_project_card = __esm({
|
|
|
3953
3957
|
commands: "Commands",
|
|
3954
3958
|
docs: "Docs",
|
|
3955
3959
|
commits: "Recent commits",
|
|
3960
|
+
changes: "Uncommitted changes and branch vs main",
|
|
3961
|
+
digests: "Doc excerpts (opening lines; read the file for the rest)",
|
|
3956
3962
|
backlog: "Open work noted in repo files (context, NOT tasks to start)"
|
|
3957
3963
|
};
|
|
3958
3964
|
render = (secs) => [HEADER, ...secs.map((s) => `### ${TITLES[s.key]}
|
|
@@ -5050,13 +5056,13 @@ function createCodegenTools(fileStore, config) {
|
|
|
5050
5056
|
if (!buildRes.ok) {
|
|
5051
5057
|
throw new Error(`Failed to fetch build result: ${buildRes.status}`);
|
|
5052
5058
|
}
|
|
5053
|
-
const
|
|
5054
|
-
if (!
|
|
5059
|
+
const build2 = await buildRes.json();
|
|
5060
|
+
if (!build2.result) {
|
|
5055
5061
|
throw new Error("Build completed but no files in result");
|
|
5056
5062
|
}
|
|
5057
5063
|
let files;
|
|
5058
5064
|
try {
|
|
5059
|
-
const parsed = JSON.parse(
|
|
5065
|
+
const parsed = JSON.parse(build2.result);
|
|
5060
5066
|
files = parsed.files ?? [];
|
|
5061
5067
|
} catch {
|
|
5062
5068
|
throw new Error("Failed to parse build result");
|
|
@@ -9188,11 +9194,11 @@ var init_base = __esm({
|
|
|
9188
9194
|
}
|
|
9189
9195
|
const parts = os.release().split(".");
|
|
9190
9196
|
const major = Number(parts[0]);
|
|
9191
|
-
const
|
|
9197
|
+
const build2 = Number(parts[2] ?? 0);
|
|
9192
9198
|
if (major < 10) {
|
|
9193
9199
|
return true;
|
|
9194
9200
|
}
|
|
9195
|
-
if (major === 10 &&
|
|
9201
|
+
if (major === 10 && build2 < 10586) {
|
|
9196
9202
|
return true;
|
|
9197
9203
|
}
|
|
9198
9204
|
return false;
|
|
@@ -42998,7 +43004,7 @@ var require_colors = __commonJS({
|
|
|
42998
43004
|
}
|
|
42999
43005
|
return str.replace(matchOperatorsRe, "\\$&");
|
|
43000
43006
|
};
|
|
43001
|
-
function
|
|
43007
|
+
function build2(_styles) {
|
|
43002
43008
|
var builder = function builder2() {
|
|
43003
43009
|
return applyStyle2.apply(builder2, arguments);
|
|
43004
43010
|
};
|
|
@@ -43013,7 +43019,7 @@ var require_colors = __commonJS({
|
|
|
43013
43019
|
ansiStyles3[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles3[key].close), "g");
|
|
43014
43020
|
ret[key] = {
|
|
43015
43021
|
get: function() {
|
|
43016
|
-
return
|
|
43022
|
+
return build2(this._styles.concat(key));
|
|
43017
43023
|
}
|
|
43018
43024
|
};
|
|
43019
43025
|
});
|
|
@@ -43072,7 +43078,7 @@ var require_colors = __commonJS({
|
|
|
43072
43078
|
Object.keys(styles5).forEach(function(name) {
|
|
43073
43079
|
ret[name] = {
|
|
43074
43080
|
get: function() {
|
|
43075
|
-
return
|
|
43081
|
+
return build2([name]);
|
|
43076
43082
|
}
|
|
43077
43083
|
};
|
|
43078
43084
|
});
|
|
@@ -103698,6 +103704,9 @@ var init_local_toolset = __esm({
|
|
|
103698
103704
|
import { execFile as execFile3 } from "node:child_process";
|
|
103699
103705
|
import { readdir as readdir3, readFile as readFile4 } from "node:fs/promises";
|
|
103700
103706
|
import { join as join7 } from "node:path";
|
|
103707
|
+
function digestLines(md) {
|
|
103708
|
+
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);
|
|
103709
|
+
}
|
|
103701
103710
|
function firstHeading(md) {
|
|
103702
103711
|
for (const line of md.split("\n", 40)) {
|
|
103703
103712
|
const m2 = /^#{1,3}\s+(.+?)\s*$/.exec(line);
|
|
@@ -103755,10 +103764,19 @@ async function scanProject(cwd2, io = nodeScanIo) {
|
|
|
103755
103764
|
const title = text ? firstHeading(text) : null;
|
|
103756
103765
|
if (title) docs.push({ path: e.path, title });
|
|
103757
103766
|
}
|
|
103767
|
+
const digests = [];
|
|
103768
|
+
for (const name of DIGEST_FILES.filter((n) => topLevel.some((t) => t.path === n))) {
|
|
103769
|
+
const text = await attempt(`read ${name}`, () => io.readFile(join7(cwd2, name)), null);
|
|
103770
|
+
const lines2 = text ? digestLines(text) : [];
|
|
103771
|
+
if (lines2.length) digests.push({ path: name, lines: lines2 });
|
|
103772
|
+
}
|
|
103758
103773
|
const todo = await attempt("read TODO.md", () => io.readFile(join7(cwd2, "TODO.md")), null);
|
|
103759
103774
|
const log = await io.git(cwd2, ["log", "--oneline", "-8"]);
|
|
103760
103775
|
const status = await io.git(cwd2, ["status", "--porcelain"]);
|
|
103761
103776
|
const branch = await io.git(cwd2, ["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
103777
|
+
const onBranch = branch?.trim();
|
|
103778
|
+
const vsMainRaw = onBranch && onBranch !== "main" && onBranch !== "HEAD" ? await io.git(cwd2, ["diff", "--shortstat", "main...HEAD"]) : null;
|
|
103779
|
+
const vsMain = vsMainRaw?.trim() ? `${vsMainRaw.trim()} (branch ${onBranch})` : void 0;
|
|
103762
103780
|
return {
|
|
103763
103781
|
problems,
|
|
103764
103782
|
input: {
|
|
@@ -103770,17 +103788,20 @@ async function scanProject(cwd2, io = nodeScanIo) {
|
|
|
103770
103788
|
childDirs,
|
|
103771
103789
|
recentCommits: (log ?? "").split("\n").filter(Boolean),
|
|
103772
103790
|
docs,
|
|
103773
|
-
backlog: todo ? backlogLines(todo) : []
|
|
103791
|
+
backlog: todo ? backlogLines(todo) : [],
|
|
103792
|
+
changes: { files: (status ?? "").split("\n").filter(Boolean), ...vsMain ? { vsMain } : {} },
|
|
103793
|
+
digests
|
|
103774
103794
|
}
|
|
103775
103795
|
};
|
|
103776
103796
|
}
|
|
103777
|
-
var SKIP, MAX_DOCS, MAX_BACKLOG, nodeScanIo;
|
|
103797
|
+
var SKIP, MAX_DOCS, MAX_BACKLOG, DIGEST_FILES, nodeScanIo;
|
|
103778
103798
|
var init_project_card_scan = __esm({
|
|
103779
103799
|
"src/project-card-scan.ts"() {
|
|
103780
103800
|
"use strict";
|
|
103781
103801
|
SKIP = /* @__PURE__ */ new Set(["node_modules", ".git", "dist", "build", ".next", ".wrangler", ".turbo", "coverage", ".worktrees", ".superpowers", ".remember"]);
|
|
103782
103802
|
MAX_DOCS = 15;
|
|
103783
103803
|
MAX_BACKLOG = 6;
|
|
103804
|
+
DIGEST_FILES = ["CLAUDE.md", "TODO.md", "BUGS.md", "ISSUES.md", "CHANGELOG.md", "README.md"];
|
|
103784
103805
|
nodeScanIo = {
|
|
103785
103806
|
async readdir(path12) {
|
|
103786
103807
|
const entries = await readdir3(path12, { withFileTypes: true });
|
|
@@ -103802,25 +103823,27 @@ var init_project_card_scan = __esm({
|
|
|
103802
103823
|
});
|
|
103803
103824
|
|
|
103804
103825
|
// src/project-card-runtime.ts
|
|
103805
|
-
async function
|
|
103806
|
-
const env3 = deps.env ?? process.env;
|
|
103807
|
-
const now = deps.now ?? Date.now;
|
|
103808
|
-
if (env3.SPACECODE_PROJECT_CARD === "off") return { text: "", statusLine: "project card: disabled (SPACECODE_PROJECT_CARD=off)" };
|
|
103809
|
-
if (cached && cached.cwd === cwd2 && now() - cached.at < TTL_MS) return cached.state;
|
|
103810
|
-
let state;
|
|
103826
|
+
async function build(cwd2, io) {
|
|
103811
103827
|
try {
|
|
103812
|
-
const { input, problems } = await scanProject(cwd2,
|
|
103828
|
+
const { input, problems } = await scanProject(cwd2, io);
|
|
103813
103829
|
const text = renderProjectCard(input);
|
|
103814
|
-
|
|
103830
|
+
return {
|
|
103815
103831
|
text,
|
|
103816
103832
|
statusLine: `project card: ${text.length} chars, ${input.topLevel.length} top-level entries${problems.length ? `, ${problems.length} scan problem(s): ${problems.join("; ")}` : ""}`
|
|
103817
103833
|
};
|
|
103818
103834
|
} catch (err) {
|
|
103819
103835
|
console.error("[project-card] scan failed; the REPL runs without a card", err instanceof Error ? err.message : String(err));
|
|
103820
|
-
|
|
103836
|
+
return { text: "", statusLine: `project card: not built (${err instanceof Error ? err.message : String(err)})` };
|
|
103821
103837
|
}
|
|
103822
|
-
|
|
103823
|
-
|
|
103838
|
+
}
|
|
103839
|
+
function loadProjectCard(cwd2, deps = {}) {
|
|
103840
|
+
const env3 = deps.env ?? process.env;
|
|
103841
|
+
const now = deps.now ?? Date.now;
|
|
103842
|
+
if (env3.SPACECODE_PROJECT_CARD === "off") return Promise.resolve({ text: "", statusLine: "project card: disabled (SPACECODE_PROJECT_CARD=off)" });
|
|
103843
|
+
if (cached && cached.cwd === cwd2 && now() - cached.at < TTL_MS) return cached.pending;
|
|
103844
|
+
const pending = build(cwd2, deps.io ?? nodeScanIo);
|
|
103845
|
+
cached = { cwd: cwd2, at: now(), pending };
|
|
103846
|
+
return pending;
|
|
103824
103847
|
}
|
|
103825
103848
|
var TTL_MS, cached;
|
|
103826
103849
|
var init_project_card_runtime = __esm({
|
|
@@ -104829,6 +104852,9 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
104829
104852
|
return () => clearInterval(timer);
|
|
104830
104853
|
}, [turnStartedAt]);
|
|
104831
104854
|
const projectRoot = (0, import_react30.useMemo)(() => process.cwd(), []);
|
|
104855
|
+
(0, import_react30.useEffect)(() => {
|
|
104856
|
+
void loadProjectCard(projectRoot);
|
|
104857
|
+
}, [projectRoot]);
|
|
104832
104858
|
const sessionIdRef = (0, import_react30.useRef)(null);
|
|
104833
104859
|
const sessionCreatedAtRef = (0, import_react30.useRef)(null);
|
|
104834
104860
|
const sessionTokensRef = (0, import_react30.useRef)({ input: 0, output: 0 });
|