spacecode 2.1.0 → 2.2.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/repl.mjs CHANGED
@@ -1404,7 +1404,7 @@ var require_react_development = __commonJS({
1404
1404
  var dispatcher = resolveDispatcher();
1405
1405
  return dispatcher.useReducer(reducer, initialArg, init);
1406
1406
  }
1407
- function useRef4(initialValue) {
1407
+ function useRef5(initialValue) {
1408
1408
  var dispatcher = resolveDispatcher();
1409
1409
  return dispatcher.useRef(initialValue);
1410
1410
  }
@@ -1416,7 +1416,7 @@ var require_react_development = __commonJS({
1416
1416
  var dispatcher = resolveDispatcher();
1417
1417
  return dispatcher.useInsertionEffect(create2, deps);
1418
1418
  }
1419
- function useLayoutEffect2(create2, deps) {
1419
+ function useLayoutEffect3(create2, deps) {
1420
1420
  var dispatcher = resolveDispatcher();
1421
1421
  return dispatcher.useLayoutEffect(create2, deps);
1422
1422
  }
@@ -2195,10 +2195,10 @@ var require_react_development = __commonJS({
2195
2195
  exports.useId = useId;
2196
2196
  exports.useImperativeHandle = useImperativeHandle;
2197
2197
  exports.useInsertionEffect = useInsertionEffect;
2198
- exports.useLayoutEffect = useLayoutEffect2;
2198
+ exports.useLayoutEffect = useLayoutEffect3;
2199
2199
  exports.useMemo = useMemo8;
2200
2200
  exports.useReducer = useReducer;
2201
- exports.useRef = useRef4;
2201
+ exports.useRef = useRef5;
2202
2202
  exports.useState = useState10;
2203
2203
  exports.useSyncExternalStore = useSyncExternalStore;
2204
2204
  exports.useTransition = useTransition;
@@ -2255,7 +2255,7 @@ var require_react_jsx_runtime_development = __commonJS({
2255
2255
  if (process.env.NODE_ENV !== "production") {
2256
2256
  (function() {
2257
2257
  "use strict";
2258
- var React19 = require_react();
2258
+ var React20 = require_react();
2259
2259
  var REACT_ELEMENT_TYPE = /* @__PURE__ */ Symbol.for("react.element");
2260
2260
  var REACT_PORTAL_TYPE = /* @__PURE__ */ Symbol.for("react.portal");
2261
2261
  var REACT_FRAGMENT_TYPE = /* @__PURE__ */ Symbol.for("react.fragment");
@@ -2281,7 +2281,7 @@ var require_react_jsx_runtime_development = __commonJS({
2281
2281
  }
2282
2282
  return null;
2283
2283
  }
2284
- var ReactSharedInternals = React19.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
2284
+ var ReactSharedInternals = React20.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
2285
2285
  function error(format) {
2286
2286
  {
2287
2287
  {
@@ -3131,10 +3131,10 @@ var require_react_jsx_runtime_development = __commonJS({
3131
3131
  return jsxWithValidation(type, props, key, false);
3132
3132
  }
3133
3133
  }
3134
- var jsx12 = jsxWithValidationDynamic;
3134
+ var jsx13 = jsxWithValidationDynamic;
3135
3135
  var jsxs12 = jsxWithValidationStatic;
3136
3136
  exports.Fragment = REACT_FRAGMENT_TYPE;
3137
- exports.jsx = jsx12;
3137
+ exports.jsx = jsx13;
3138
3138
  exports.jsxs = jsxs12;
3139
3139
  })();
3140
3140
  }
@@ -10823,9 +10823,9 @@ var require_react_reconciler_development = __commonJS({
10823
10823
  module.exports = function $$$reconciler($$$hostConfig) {
10824
10824
  var exports2 = {};
10825
10825
  "use strict";
10826
- var React19 = require_react();
10826
+ var React20 = require_react();
10827
10827
  var Scheduler = require_scheduler();
10828
- var ReactSharedInternals = React19.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
10828
+ var ReactSharedInternals = React20.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
10829
10829
  var suppressWarning = false;
10830
10830
  function setSuppressWarning(newSuppressWarning) {
10831
10831
  {
@@ -25702,10 +25702,10 @@ var require_react_reconciler_development = __commonJS({
25702
25702
  var setErrorHandler = null;
25703
25703
  var setSuspenseHandler = null;
25704
25704
  {
25705
- var copyWithDeleteImpl = function(obj, path11, index2) {
25706
- var key = path11[index2];
25705
+ var copyWithDeleteImpl = function(obj, path12, index2) {
25706
+ var key = path12[index2];
25707
25707
  var updated = isArray(obj) ? obj.slice() : assign({}, obj);
25708
- if (index2 + 1 === path11.length) {
25708
+ if (index2 + 1 === path12.length) {
25709
25709
  if (isArray(updated)) {
25710
25710
  updated.splice(key, 1);
25711
25711
  } else {
@@ -25713,11 +25713,11 @@ var require_react_reconciler_development = __commonJS({
25713
25713
  }
25714
25714
  return updated;
25715
25715
  }
25716
- updated[key] = copyWithDeleteImpl(obj[key], path11, index2 + 1);
25716
+ updated[key] = copyWithDeleteImpl(obj[key], path12, index2 + 1);
25717
25717
  return updated;
25718
25718
  };
25719
- var copyWithDelete = function(obj, path11) {
25720
- return copyWithDeleteImpl(obj, path11, 0);
25719
+ var copyWithDelete = function(obj, path12) {
25720
+ return copyWithDeleteImpl(obj, path12, 0);
25721
25721
  };
25722
25722
  var copyWithRenameImpl = function(obj, oldPath, newPath, index2) {
25723
25723
  var oldKey = oldPath[index2];
@@ -25755,17 +25755,17 @@ var require_react_reconciler_development = __commonJS({
25755
25755
  }
25756
25756
  return copyWithRenameImpl(obj, oldPath, newPath, 0);
25757
25757
  };
25758
- var copyWithSetImpl = function(obj, path11, index2, value) {
25759
- if (index2 >= path11.length) {
25758
+ var copyWithSetImpl = function(obj, path12, index2, value) {
25759
+ if (index2 >= path12.length) {
25760
25760
  return value;
25761
25761
  }
25762
- var key = path11[index2];
25762
+ var key = path12[index2];
25763
25763
  var updated = isArray(obj) ? obj.slice() : assign({}, obj);
25764
- updated[key] = copyWithSetImpl(obj[key], path11, index2 + 1, value);
25764
+ updated[key] = copyWithSetImpl(obj[key], path12, index2 + 1, value);
25765
25765
  return updated;
25766
25766
  };
25767
- var copyWithSet = function(obj, path11, value) {
25768
- return copyWithSetImpl(obj, path11, 0, value);
25767
+ var copyWithSet = function(obj, path12, value) {
25768
+ return copyWithSetImpl(obj, path12, 0, value);
25769
25769
  };
25770
25770
  var findHook = function(fiber, id) {
25771
25771
  var currentHook2 = fiber.memoizedState;
@@ -25775,10 +25775,10 @@ var require_react_reconciler_development = __commonJS({
25775
25775
  }
25776
25776
  return currentHook2;
25777
25777
  };
25778
- overrideHookState = function(fiber, id, path11, value) {
25778
+ overrideHookState = function(fiber, id, path12, value) {
25779
25779
  var hook = findHook(fiber, id);
25780
25780
  if (hook !== null) {
25781
- var newState = copyWithSet(hook.memoizedState, path11, value);
25781
+ var newState = copyWithSet(hook.memoizedState, path12, value);
25782
25782
  hook.memoizedState = newState;
25783
25783
  hook.baseState = newState;
25784
25784
  fiber.memoizedProps = assign({}, fiber.memoizedProps);
@@ -25788,10 +25788,10 @@ var require_react_reconciler_development = __commonJS({
25788
25788
  }
25789
25789
  }
25790
25790
  };
25791
- overrideHookStateDeletePath = function(fiber, id, path11) {
25791
+ overrideHookStateDeletePath = function(fiber, id, path12) {
25792
25792
  var hook = findHook(fiber, id);
25793
25793
  if (hook !== null) {
25794
- var newState = copyWithDelete(hook.memoizedState, path11);
25794
+ var newState = copyWithDelete(hook.memoizedState, path12);
25795
25795
  hook.memoizedState = newState;
25796
25796
  hook.baseState = newState;
25797
25797
  fiber.memoizedProps = assign({}, fiber.memoizedProps);
@@ -25814,8 +25814,8 @@ var require_react_reconciler_development = __commonJS({
25814
25814
  }
25815
25815
  }
25816
25816
  };
25817
- overrideProps = function(fiber, path11, value) {
25818
- fiber.pendingProps = copyWithSet(fiber.memoizedProps, path11, value);
25817
+ overrideProps = function(fiber, path12, value) {
25818
+ fiber.pendingProps = copyWithSet(fiber.memoizedProps, path12, value);
25819
25819
  if (fiber.alternate) {
25820
25820
  fiber.alternate.pendingProps = fiber.pendingProps;
25821
25821
  }
@@ -25824,8 +25824,8 @@ var require_react_reconciler_development = __commonJS({
25824
25824
  scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp);
25825
25825
  }
25826
25826
  };
25827
- overridePropsDeletePath = function(fiber, path11) {
25828
- fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path11);
25827
+ overridePropsDeletePath = function(fiber, path12) {
25828
+ fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path12);
25829
25829
  if (fiber.alternate) {
25830
25830
  fiber.alternate.pendingProps = fiber.pendingProps;
25831
25831
  }
@@ -33426,7 +33426,7 @@ var init_Text = __esm({
33426
33426
  });
33427
33427
 
33428
33428
  // ../../node_modules/ink/build/components/ErrorOverview.js
33429
- import * as fs from "node:fs";
33429
+ import * as fs2 from "node:fs";
33430
33430
  import { cwd } from "node:process";
33431
33431
  function ErrorOverview({ error }) {
33432
33432
  const stack = error.stack ? error.stack.split("\n").slice(1) : void 0;
@@ -33434,8 +33434,8 @@ function ErrorOverview({ error }) {
33434
33434
  const filePath = cleanupPath(origin?.file);
33435
33435
  let excerpt;
33436
33436
  let lineWidth = 0;
33437
- if (filePath && origin?.line && fs.existsSync(filePath)) {
33438
- const sourceCode = fs.readFileSync(filePath, "utf8");
33437
+ if (filePath && origin?.line && fs2.existsSync(filePath)) {
33438
+ const sourceCode = fs2.readFileSync(filePath, "utf8");
33439
33439
  excerpt = dist_default3(sourceCode, origin.line);
33440
33440
  if (excerpt) {
33441
33441
  for (const { line } of excerpt) {
@@ -33530,8 +33530,8 @@ var init_ErrorOverview = __esm({
33530
33530
  init_dist3();
33531
33531
  init_Box();
33532
33532
  init_Text();
33533
- cleanupPath = (path11) => {
33534
- return path11?.replace(`file://${cwd()}/`, "");
33533
+ cleanupPath = (path12) => {
33534
+ return path12?.replace(`file://${cwd()}/`, "");
33535
33535
  };
33536
33536
  stackUtils = new import_stack_utils.default({
33537
33537
  cwd: cwd(),
@@ -36759,7 +36759,7 @@ var require_has_flag = __commonJS({
36759
36759
  var require_supports_colors = __commonJS({
36760
36760
  "../../node_modules/@colors/colors/lib/system/supports-colors.js"(exports, module) {
36761
36761
  "use strict";
36762
- var os5 = __require("os");
36762
+ var os6 = __require("os");
36763
36763
  var hasFlag2 = require_has_flag();
36764
36764
  var env3 = process.env;
36765
36765
  var forceColor = void 0;
@@ -36797,7 +36797,7 @@ var require_supports_colors = __commonJS({
36797
36797
  }
36798
36798
  var min = forceColor ? 1 : 0;
36799
36799
  if (process.platform === "win32") {
36800
- var osRelease = os5.release().split(".");
36800
+ var osRelease = os6.release().split(".");
36801
36801
  if (Number(process.versions.node.split(".")[0]) >= 8 && Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
36802
36802
  return Number(osRelease[2]) >= 14931 ? 3 : 2;
36803
36803
  }
@@ -37189,7 +37189,7 @@ var require_colors = __commonJS({
37189
37189
  var colors = {};
37190
37190
  module["exports"] = colors;
37191
37191
  colors.themes = {};
37192
- var util = __require("util");
37192
+ var util3 = __require("util");
37193
37193
  var ansiStyles3 = colors.styles = require_styles();
37194
37194
  var defineProps = Object.defineProperties;
37195
37195
  var newLineRegex = new RegExp(/[\r\n]+/g);
@@ -37252,7 +37252,7 @@ var require_colors = __commonJS({
37252
37252
  if (arg != null && arg.constructor === String) {
37253
37253
  return arg;
37254
37254
  } else {
37255
- return util.inspect(arg);
37255
+ return util3.inspect(arg);
37256
37256
  }
37257
37257
  }).join(" ");
37258
37258
  if (!colors.enabled || !str) {
@@ -80882,15 +80882,15 @@ var require_route = __commonJS({
80882
80882
  };
80883
80883
  }
80884
80884
  function wrapConversion(toModel, graph) {
80885
- const path11 = [graph[toModel].parent, toModel];
80885
+ const path12 = [graph[toModel].parent, toModel];
80886
80886
  let fn = conversions[graph[toModel].parent][toModel];
80887
80887
  let cur = graph[toModel].parent;
80888
80888
  while (graph[cur].parent) {
80889
- path11.unshift(graph[cur].parent);
80889
+ path12.unshift(graph[cur].parent);
80890
80890
  fn = link2(conversions[graph[cur].parent][cur], fn);
80891
80891
  cur = graph[cur].parent;
80892
80892
  }
80893
- fn.conversion = path11;
80893
+ fn.conversion = path12;
80894
80894
  return fn;
80895
80895
  }
80896
80896
  module.exports = function(fromModel) {
@@ -81130,7 +81130,7 @@ var require_has_flag2 = __commonJS({
81130
81130
  var require_supports_color = __commonJS({
81131
81131
  "../../node_modules/supports-color/index.js"(exports, module) {
81132
81132
  "use strict";
81133
- var os5 = __require("os");
81133
+ var os6 = __require("os");
81134
81134
  var tty2 = __require("tty");
81135
81135
  var hasFlag2 = require_has_flag2();
81136
81136
  var { env: env3 } = process;
@@ -81178,7 +81178,7 @@ var require_supports_color = __commonJS({
81178
81178
  return min;
81179
81179
  }
81180
81180
  if (process.platform === "win32") {
81181
- const osRelease = os5.release().split(".");
81181
+ const osRelease = os6.release().split(".");
81182
81182
  if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
81183
81183
  return Number(osRelease[2]) >= 14931 ? 3 : 2;
81184
81184
  }
@@ -96159,10 +96159,10 @@ var init_session_store = __esm({
96159
96159
  if (!ID.test(id)) throw new SessionError(this.dir, `Invalid session id ${JSON.stringify(id)}`);
96160
96160
  return path.join(this.dir, `${id}.jsonl`);
96161
96161
  }
96162
- async save(session) {
96163
- const file = this.fileFor(session.meta.id);
96164
- const meta = { ...session.meta, updatedAt: this.now().toISOString() };
96165
- const body = [meta, ...session.messages].map((entry) => JSON.stringify(redactCredentials(entry))).join("\n") + "\n";
96162
+ async save(session2) {
96163
+ const file = this.fileFor(session2.meta.id);
96164
+ const meta = { ...session2.meta, updatedAt: this.now().toISOString() };
96165
+ const body = [meta, ...session2.messages].map((entry) => JSON.stringify(redactCredentials(entry))).join("\n") + "\n";
96166
96166
  const bytes = Buffer.byteLength(body);
96167
96167
  if (bytes > MAX_SESSION_BYTES) {
96168
96168
  throw new SessionError(file, `Session is ${bytes} bytes, over the ${MAX_SESSION_BYTES}-byte cap; use /compact or /clear`);
@@ -96191,9 +96191,9 @@ var init_session_store = __esm({
96191
96191
  if (err instanceof SessionError) throw err;
96192
96192
  throw new SessionError(file, `Could not read session: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
96193
96193
  }
96194
- const session = parseSession(file, text);
96195
- if (session.meta.id !== id) throw new SessionError(file, `Session header id "${session.meta.id}" does not match the file name`);
96196
- return session;
96194
+ const session2 = parseSession(file, text);
96195
+ if (session2.meta.id !== id) throw new SessionError(file, `Session header id "${session2.meta.id}" does not match the file name`);
96196
+ return session2;
96197
96197
  }
96198
96198
  /** Newest first. Unreadable files are reported, not skipped silently. */
96199
96199
  async list() {
@@ -97276,17 +97276,17 @@ function isSubsequence(needle, hay) {
97276
97276
  for (let j2 = 0; j2 < hay.length && i < needle.length; j2++) if (hay[j2] === needle[i]) i++;
97277
97277
  return i === needle.length;
97278
97278
  }
97279
- function tier(path11, q2) {
97280
- const base = path11.slice(path11.lastIndexOf("/") + 1);
97279
+ function tier(path12, q2) {
97280
+ const base = path12.slice(path12.lastIndexOf("/") + 1);
97281
97281
  if (base.startsWith(q2)) return 0;
97282
97282
  if (base.includes(q2)) return 1;
97283
- if (path11.includes(q2)) return 2;
97283
+ if (path12.includes(q2)) return 2;
97284
97284
  return 3;
97285
97285
  }
97286
97286
  function rankPaths(paths, query, limit = 8) {
97287
97287
  if (query === "") return paths.slice(0, limit);
97288
97288
  const q2 = query.toLowerCase();
97289
- return paths.map((path11) => ({ path: path11, lower: path11.toLowerCase() })).filter(({ lower }) => isSubsequence(q2, lower)).map(({ path: path11, lower }) => ({ path: path11, rank: tier(lower, q2) })).sort((a, b2) => a.rank - b2.rank || a.path.length - b2.path.length || (a.path < b2.path ? -1 : a.path > b2.path ? 1 : 0)).slice(0, limit).map((m2) => m2.path);
97289
+ return paths.map((path12) => ({ path: path12, lower: path12.toLowerCase() })).filter(({ lower }) => isSubsequence(q2, lower)).map(({ path: path12, lower }) => ({ path: path12, rank: tier(lower, q2) })).sort((a, b2) => a.rank - b2.rank || a.path.length - b2.path.length || (a.path < b2.path ? -1 : a.path > b2.path ? 1 : 0)).slice(0, limit).map((m2) => m2.path);
97290
97290
  }
97291
97291
  var init_mention_rank = __esm({
97292
97292
  "src/editor/mention-rank.ts"() {
@@ -97303,9 +97303,9 @@ function activeMention(text, cursor) {
97303
97303
  const explicit = token[1] === "!";
97304
97304
  return { start, query: token.slice(explicit ? 2 : 1), explicit };
97305
97305
  }
97306
- function insertMention(text, cursor, mention, path11) {
97307
- if (/\s/.test(path11)) return { text, cursor };
97308
- const inserted = `@${mention.explicit ? "!" : ""}${path11}`;
97306
+ function insertMention(text, cursor, mention, path12) {
97307
+ if (/\s/.test(path12)) return { text, cursor };
97308
+ const inserted = `@${mention.explicit ? "!" : ""}${path12}`;
97309
97309
  const head = text.slice(0, mention.start) + inserted;
97310
97310
  const next = text[cursor];
97311
97311
  if (next !== void 0 && /\s/.test(next)) return { text: head + text.slice(cursor), cursor: head.length + 1 };
@@ -97392,8 +97392,9 @@ function validateSubmission(text) {
97392
97392
  function withCursor(row, col) {
97393
97393
  return `${row.slice(0, col)}\x1B[7m${row[col] ?? " "}\x1B[27m${row.slice(col + 1)}`;
97394
97394
  }
97395
- function PromptEditor({ onSubmit, disabled, history, listFiles: listFiles2, onTab, locked = false, promptGlyph: promptGlyph2 = ">", onEmptyEnter }) {
97395
+ function PromptEditor({ onSubmit, disabled, history, listFiles: listFiles2, onTab, locked = false, promptGlyph: promptGlyph2 = ">", onEmptyEnter, unicode = true, fullWidth = false }) {
97396
97396
  const { exit } = use_app_default();
97397
+ const { columns } = useTerminalSize();
97397
97398
  const { isRawModeSupported } = use_stdin_default();
97398
97399
  const [buf, setBuf] = (0, import_react29.useState)(() => createBuffer());
97399
97400
  const [hint, setHint] = (0, import_react29.useState)(null);
@@ -97545,24 +97546,27 @@ function PromptEditor({ onSubmit, disabled, history, listFiles: listFiles2, onTa
97545
97546
  if (!isRawModeSupported) {
97546
97547
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { ...paint("delete"), children: 'Interactive input needs a TTY (stdin is not a terminal). Use `spacecode -p "<prompt>"` for headless runs.' });
97547
97548
  }
97548
- if (disabled && buf.text === "") return null;
97549
97549
  const rows = lines(buf);
97550
97550
  const { line, col } = lineCol(buf);
97551
97551
  const matches = shell ? [] : slashMatches(buf.text, SLASH_COMMANDS);
97552
97552
  const picks = mention && files ? rankPaths(files, mention.query, PICKER_ROWS) : [];
97553
97553
  const pickAt = Math.min(sel, Math.max(picks.length - 1, 0));
97554
97554
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { flexDirection: "column", children: [
97555
- rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { children: [
97555
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box_default, { flexDirection: "column", borderStyle: unicode ? "round" : "classic", borderColor: paint("secondary").color, borderDimColor: disabled, paddingX: 1, width: fullWidth ? columns : Math.min(columns, MAX_STATIC_LINE), children: rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { children: [
97556
97556
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { ...paint(shell ? "action" : "agent"), bold: true, dimColor: disabled, children: i === 0 ? shell ? "! " : `${promptGlyph2} ` : " " }),
97557
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { dimColor: disabled, children: i === line && !disabled ? withCursor(row, col) : row })
97558
- ] }, i)),
97557
+ disabled && !locked && buf.text === "" ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { ...paint("secondary"), children: "turn running - type to queue your next prompt" }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { dimColor: disabled, children: i === line && !disabled ? withCursor(row, col) : row })
97558
+ ] }, i)) }),
97559
97559
  matches.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { ...paint("secondary"), children: [
97560
- matches.map((c) => `/${c.name} \u2014 ${c.description}`).join(" "),
97560
+ matches.map((c) => `/${c.name} ${unicode ? "\u2014" : "-"} ${c.description}`).join(" "),
97561
97561
  " (Tab to complete)"
97562
97562
  ] }),
97563
97563
  shell && buf.text === "" && !disabled && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { ...paint("secondary"), children: "shell mode: runs on your machine, not sent to the model (Backspace exits)" }),
97564
- picks.map((p, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { ...i === pickAt ? paint("action") : paint("secondary"), children: `${i === pickAt ? "\u203A" : " "} ${p}` }, p)),
97565
- picks.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { ...paint("secondary"), children: "(\u2191/\u2193 select, Tab or Enter to insert)" }),
97564
+ picks.map((p, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { ...i === pickAt ? paint("action") : paint("secondary"), children: `${i === pickAt ? unicode ? "\u203A" : ">" : " "} ${p}` }, p)),
97565
+ picks.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { ...paint("secondary"), children: [
97566
+ "(",
97567
+ unicode ? "\u2191/\u2193" : "up/down",
97568
+ " select, Tab or Enter to insert)"
97569
+ ] }),
97566
97570
  hint && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { ...paint("delete"), children: hint })
97567
97571
  ] });
97568
97572
  }
@@ -97579,6 +97583,8 @@ var init_PromptEditor = __esm({
97579
97583
  init_slash_menu();
97580
97584
  init_slash_commands();
97581
97585
  init_theme();
97586
+ init_hints();
97587
+ await init_useTerminalSize();
97582
97588
  import_jsx_runtime9 = __toESM(require_jsx_runtime(), 1);
97583
97589
  PICKER_ROWS = 6;
97584
97590
  }
@@ -98155,8 +98161,8 @@ async function runAgentLoop(prompt, config, executor, emit, signal, existingMess
98155
98161
  const toolInput = block.input ?? {};
98156
98162
  const startTime = Date.now();
98157
98163
  let result;
98158
- const onOutput = (id, stream, text) => {
98159
- emitToolOutput(emit, { type: "tool_output", id, stream, text });
98164
+ const onOutput = (_reportedId, stream, text) => {
98165
+ emitToolOutput(emit, { type: "tool_output", id: toolId, stream, text });
98160
98166
  };
98161
98167
  try {
98162
98168
  result = await executor.execute(toolName, toolInput, onOutput);
@@ -98358,9 +98364,9 @@ function createFileTools(store) {
98358
98364
  readCache.clear();
98359
98365
  listCache.clear();
98360
98366
  }
98361
- function invalidatePath(path11) {
98362
- readCache.delete(path11);
98363
- const parent = path11.includes("/") ? path11.slice(0, path11.lastIndexOf("/") + 1) : "";
98367
+ function invalidatePath(path12) {
98368
+ readCache.delete(path12);
98369
+ const parent = path12.includes("/") ? path12.slice(0, path12.lastIndexOf("/") + 1) : "";
98364
98370
  listCache.delete(parent);
98365
98371
  listCache.delete("");
98366
98372
  listCache.delete(".");
@@ -98368,36 +98374,36 @@ function createFileTools(store) {
98368
98374
  }
98369
98375
  const handlers = {
98370
98376
  read_file: async (input) => {
98371
- const path11 = input.path;
98372
- const cached = readCache.get(path11);
98377
+ const path12 = input.path;
98378
+ const cached = readCache.get(path12);
98373
98379
  if (cached !== void 0) {
98374
98380
  return { output: cached };
98375
98381
  }
98376
- const content = await store.readFile(path11);
98382
+ const content = await store.readFile(path12);
98377
98383
  if (content === null) {
98378
- return { output: `File not found: ${path11}`, is_error: true };
98384
+ return { output: `File not found: ${path12}`, is_error: true };
98379
98385
  }
98380
- readCache.set(path11, content);
98386
+ readCache.set(path12, content);
98381
98387
  return { output: content };
98382
98388
  },
98383
98389
  write_file: async (input) => {
98384
- const path11 = input.path;
98390
+ const path12 = input.path;
98385
98391
  const content = input.content;
98386
- await store.writeFile(path11, content);
98387
- invalidatePath(path11);
98388
- readCache.set(path11, content);
98389
- return { output: `Written: ${path11}` };
98392
+ await store.writeFile(path12, content);
98393
+ invalidatePath(path12);
98394
+ readCache.set(path12, content);
98395
+ return { output: `Written: ${path12}` };
98390
98396
  },
98391
98397
  edit_file: async (input) => {
98392
- const path11 = input.path;
98398
+ const path12 = input.path;
98393
98399
  const oldStr = input.old_string;
98394
98400
  const newStr = input.new_string;
98395
- let content = readCache.get(path11);
98401
+ let content = readCache.get(path12);
98396
98402
  if (content === void 0) {
98397
- const stored = await store.readFile(path11);
98403
+ const stored = await store.readFile(path12);
98398
98404
  if (stored === null) {
98399
98405
  return {
98400
- output: `File not found: ${path11}. Did you read the file first?`,
98406
+ output: `File not found: ${path12}. Did you read the file first?`,
98401
98407
  is_error: true
98402
98408
  };
98403
98409
  }
@@ -98407,41 +98413,41 @@ function createFileTools(store) {
98407
98413
  if (lineNumbers.length === 0) {
98408
98414
  const lineCount = content.split("\n").length;
98409
98415
  return {
98410
- output: `old_string not found in ${path11}. The file has ${lineCount} lines. Did you read the file first?`,
98416
+ output: `old_string not found in ${path12}. The file has ${lineCount} lines. Did you read the file first?`,
98411
98417
  is_error: true
98412
98418
  };
98413
98419
  }
98414
98420
  if (lineNumbers.length > 1) {
98415
98421
  const locations = lineNumbers.map((ln) => ` - line ${ln}`).join("\n");
98416
98422
  return {
98417
- output: `old_string matches ${lineNumbers.length} locations in ${path11}:
98423
+ output: `old_string matches ${lineNumbers.length} locations in ${path12}:
98418
98424
  ${locations}
98419
98425
  Include more surrounding context to make old_string unique.`,
98420
98426
  is_error: true
98421
98427
  };
98422
98428
  }
98423
- const result = await store.editFile(path11, oldStr, newStr);
98429
+ const result = await store.editFile(path12, oldStr, newStr);
98424
98430
  if (!result.success) {
98425
98431
  return { output: result.error, is_error: true };
98426
98432
  }
98427
- invalidatePath(path11);
98428
- const updated = await store.readFile(path11);
98429
- if (updated !== null) readCache.set(path11, updated);
98430
- return { output: `Edited: ${path11}` };
98433
+ invalidatePath(path12);
98434
+ const updated = await store.readFile(path12);
98435
+ if (updated !== null) readCache.set(path12, updated);
98436
+ return { output: `Edited: ${path12}` };
98431
98437
  },
98432
98438
  list_directory: async (input) => {
98433
- const path11 = input.path;
98434
- const cached = listCache.get(path11);
98439
+ const path12 = input.path;
98440
+ const cached = listCache.get(path12);
98435
98441
  if (cached !== void 0) {
98436
98442
  if (cached.length === 0) {
98437
- return { output: `Empty or not found: ${path11}` };
98443
+ return { output: `Empty or not found: ${path12}` };
98438
98444
  }
98439
98445
  return { output: cached.join("\n") };
98440
98446
  }
98441
- const entries = await store.listDirectory(path11);
98442
- listCache.set(path11, entries);
98447
+ const entries = await store.listDirectory(path12);
98448
+ listCache.set(path12, entries);
98443
98449
  if (entries.length === 0) {
98444
- return { output: `Empty or not found: ${path11}` };
98450
+ return { output: `Empty or not found: ${path12}` };
98445
98451
  }
98446
98452
  return { output: entries.join("\n") };
98447
98453
  }
@@ -98778,7 +98784,7 @@ var init_host = __esm({
98778
98784
 
98779
98785
  // ../agent/src/host/local-host.ts
98780
98786
  import { execFile as execFile2 } from "node:child_process";
98781
- import { promises as fs2 } from "node:fs";
98787
+ import { promises as fs3 } from "node:fs";
98782
98788
  import * as path3 from "node:path";
98783
98789
  var LocalHost;
98784
98790
  var init_local_host = __esm({
@@ -98805,18 +98811,18 @@ var init_local_host = __esm({
98805
98811
  async resolve(p) {
98806
98812
  const abs = path3.resolve(this.root, p);
98807
98813
  if (!_LocalHost.inside(this.root, abs)) throw new Error(`Path escapes workspace root: ${p}`);
98808
- const realRoot = await fs2.realpath(this.root);
98814
+ const realRoot = await fs3.realpath(this.root);
98809
98815
  let probe = abs;
98810
98816
  for (; ; ) {
98811
98817
  try {
98812
- const real = await fs2.realpath(probe);
98818
+ const real = await fs3.realpath(probe);
98813
98819
  if (!_LocalHost.inside(realRoot, real)) {
98814
98820
  throw new Error(`Path escapes workspace root via symlink: ${p}`);
98815
98821
  }
98816
98822
  break;
98817
98823
  } catch (err) {
98818
98824
  if (err.code !== "ENOENT") throw err;
98819
- const st = await fs2.lstat(probe).catch((e) => {
98825
+ const st = await fs3.lstat(probe).catch((e) => {
98820
98826
  if (e.code === "ENOENT") return null;
98821
98827
  throw e;
98822
98828
  });
@@ -98830,7 +98836,7 @@ var init_local_host = __esm({
98830
98836
  }
98831
98837
  async readFile(p) {
98832
98838
  try {
98833
- return await fs2.readFile(await this.resolve(p), "utf8");
98839
+ return await fs3.readFile(await this.resolve(p), "utf8");
98834
98840
  } catch (err) {
98835
98841
  if (err.code === "ENOENT") return null;
98836
98842
  throw err;
@@ -98838,8 +98844,8 @@ var init_local_host = __esm({
98838
98844
  }
98839
98845
  async writeFile(p, content) {
98840
98846
  const abs = await this.resolve(p);
98841
- await fs2.mkdir(path3.dirname(abs), { recursive: true });
98842
- await fs2.writeFile(abs, content, "utf8");
98847
+ await fs3.mkdir(path3.dirname(abs), { recursive: true });
98848
+ await fs3.writeFile(abs, content, "utf8");
98843
98849
  }
98844
98850
  async editFile(p, oldStr, newStr) {
98845
98851
  const content = await this.readFile(p);
@@ -98854,7 +98860,7 @@ var init_local_host = __esm({
98854
98860
  }
98855
98861
  async listDirectory(p) {
98856
98862
  try {
98857
- const entries = await fs2.readdir(await this.resolve(p), { withFileTypes: true });
98863
+ const entries = await fs3.readdir(await this.resolve(p), { withFileTypes: true });
98858
98864
  return entries.map((e) => e.isDirectory() ? `${e.name}/` : e.name);
98859
98865
  } catch (err) {
98860
98866
  if (err.code === "ENOENT") return [];
@@ -99129,7 +99135,7 @@ var init_policy = __esm({
99129
99135
  });
99130
99136
 
99131
99137
  // ../agent/src/host/audit-log.ts
99132
- import { promises as fs3 } from "node:fs";
99138
+ import { promises as fs4 } from "node:fs";
99133
99139
  import * as path4 from "node:path";
99134
99140
  function truncate(e) {
99135
99141
  return e.subject.length > MAX_SUBJECT ? { ...e, subject: e.subject.slice(0, MAX_SUBJECT) + "...[truncated]" } : e;
@@ -99144,8 +99150,8 @@ var init_audit_log = __esm({
99144
99150
  this.file = file;
99145
99151
  }
99146
99152
  async record(entry) {
99147
- await fs3.mkdir(path4.dirname(this.file), { recursive: true });
99148
- await fs3.appendFile(this.file, JSON.stringify(truncate(entry)) + "\n", { mode: 384 });
99153
+ await fs4.mkdir(path4.dirname(this.file), { recursive: true });
99154
+ await fs4.appendFile(this.file, JSON.stringify(truncate(entry)) + "\n", { mode: 384 });
99149
99155
  }
99150
99156
  };
99151
99157
  }
@@ -99885,10 +99891,10 @@ async function readGitignore(cwd2) {
99885
99891
  }
99886
99892
  }
99887
99893
  function createNodeMentions(cwd2) {
99888
- const fs4 = createNodeMentionFS(cwd2);
99894
+ const fs6 = createNodeMentionFS(cwd2);
99889
99895
  return {
99890
99896
  async attach(text) {
99891
- const result = await resolveMentions(text, { cwd: cwd2, fs: fs4, ignored: await readGitignore(cwd2) });
99897
+ const result = await resolveMentions(text, { cwd: cwd2, fs: fs6, ignored: await readGitignore(cwd2) });
99892
99898
  return formatMentionPrompt(text, result);
99893
99899
  },
99894
99900
  async list() {
@@ -99955,6 +99961,7 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
99955
99961
  const [turns, setTurns] = (0, import_react30.useState)([]);
99956
99962
  const turnIdRef = (0, import_react30.useRef)(0);
99957
99963
  const [isRunning, setIsRunning] = (0, import_react30.useState)(false);
99964
+ const [livePrompt, setLivePrompt] = (0, import_react30.useState)(null);
99958
99965
  const [history, setHistory] = (0, import_react30.useState)([]);
99959
99966
  const [turnTokens, setTurnTokens] = (0, import_react30.useState)(null);
99960
99967
  const [sessionTokens, setSessionTokens] = (0, import_react30.useState)({ input: 0, output: 0 });
@@ -100319,6 +100326,7 @@ ${tools.map((t) => ` ${t.name}`).join("\n")}`);
100319
100326
  return;
100320
100327
  }
100321
100328
  setIsRunning(true);
100329
+ setLivePrompt(prompt);
100322
100330
  setNotices([]);
100323
100331
  setEvents([]);
100324
100332
  setTurnTokens(null);
@@ -100385,6 +100393,7 @@ ${tools.map((t) => ` ${t.name}`).join("\n")}`);
100385
100393
  retained
100386
100394
  );
100387
100395
  setTurnStartedAt(null);
100396
+ setLivePrompt(null);
100388
100397
  setEvents([]);
100389
100398
  refuseAllConfirms();
100390
100399
  abortRef.current = null;
@@ -100429,7 +100438,7 @@ ${tools.map((t) => ` ${t.name}`).join("\n")}`);
100429
100438
  }),
100430
100439
  [sessions, applySession]
100431
100440
  );
100432
- return { turns, events, isRunning, turnTokens, notices, pending, mode, todos, stats, submit, retry, mentions, replayed, resume };
100441
+ return { turns, events, isRunning, livePrompt, turnTokens, notices, pending, mode, todos, stats, submit, retry, mentions, replayed, resume };
100433
100442
  }
100434
100443
  var import_react30, apiUrl;
100435
100444
  var init_useReplController = __esm({
@@ -100692,6 +100701,31 @@ var init_ResumePicker = __esm({
100692
100701
  }
100693
100702
  });
100694
100703
 
100704
+ // src/components/Transcript.tsx
100705
+ function Transcript({ scroll, onMeasure, children }) {
100706
+ const viewportRef = (0, import_react33.useRef)(null);
100707
+ const contentRef = (0, import_react33.useRef)(null);
100708
+ const last = (0, import_react33.useRef)({ viewport: -1, content: -1 });
100709
+ (0, import_react33.useLayoutEffect)(() => {
100710
+ if (!viewportRef.current || !contentRef.current) return;
100711
+ const viewport = measure_element_default(viewportRef.current).height;
100712
+ const content = measure_element_default(contentRef.current).height;
100713
+ if (viewport === last.current.viewport && content === last.current.content) return;
100714
+ last.current = { viewport, content };
100715
+ onMeasure(viewport, content);
100716
+ });
100717
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Box_default, { ref: viewportRef, flexDirection: "column", flexGrow: 1, flexShrink: 1, flexBasis: 0, overflow: "hidden", justifyContent: "flex-end", children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Box_default, { ref: contentRef, flexDirection: "column", flexShrink: 0, marginBottom: -scroll, children }) });
100718
+ }
100719
+ var import_react33, import_jsx_runtime12;
100720
+ var init_Transcript = __esm({
100721
+ async "src/components/Transcript.tsx"() {
100722
+ "use strict";
100723
+ import_react33 = __toESM(require_react(), 1);
100724
+ await init_build2();
100725
+ import_jsx_runtime12 = __toESM(require_jsx_runtime(), 1);
100726
+ }
100727
+ });
100728
+
100695
100729
  // src/App.tsx
100696
100730
  var App_exports = {};
100697
100731
  __export(App_exports, {
@@ -100699,39 +100733,58 @@ __export(App_exports, {
100699
100733
  });
100700
100734
  import os4 from "node:os";
100701
100735
  import path10 from "node:path";
100702
- function App2({ repoName: repoName2, onboardingMode: onboardingMode2, launchCount: launchCount2, yolo: yolo2, history, sessions, resumeLatest: resumeLatest2, git: gitRunner, interactivePicker = true }) {
100703
- const promptHistory = (0, import_react33.useMemo)(
100736
+ function App2({ repoName: repoName2, onboardingMode: onboardingMode2, launchCount: launchCount2, yolo: yolo2, history, sessions, resumeLatest: resumeLatest2, git: gitRunner, interactivePicker = true, fullscreen: fullscreen2 = false }) {
100737
+ const promptHistory = (0, import_react34.useMemo)(
100704
100738
  () => history ?? new PromptHistory(createFileHistoryIO(path10.join(os4.homedir(), ".spacecode", "history"))),
100705
100739
  [history]
100706
100740
  );
100707
- const sessionStore = (0, import_react33.useMemo)(() => sessions ?? new SessionStore(path10.join(os4.homedir(), ".spacecode", "sessions")), [sessions]);
100708
- const runGit = (0, import_react33.useMemo)(() => gitRunner ?? createNodeGitRunner(process.cwd()), [gitRunner]);
100709
- const startedAtRef = (0, import_react33.useRef)(Date.now());
100710
- const [viewingRaw, setViewing] = (0, import_react33.useState)(false);
100711
- const escViewRef = (0, import_react33.useRef)(false);
100712
- const escSwallowRef = (0, import_react33.useRef)(false);
100713
- const swallowEsc = (0, import_react33.useCallback)(() => {
100741
+ const sessionStore = (0, import_react34.useMemo)(() => sessions ?? new SessionStore(path10.join(os4.homedir(), ".spacecode", "sessions")), [sessions]);
100742
+ const runGit = (0, import_react34.useMemo)(() => gitRunner ?? createNodeGitRunner(process.cwd()), [gitRunner]);
100743
+ const startedAtRef = (0, import_react34.useRef)(Date.now());
100744
+ const [viewingRaw, setViewing] = (0, import_react34.useState)(false);
100745
+ const escViewRef = (0, import_react34.useRef)(false);
100746
+ const escSwallowRef = (0, import_react34.useRef)(false);
100747
+ const swallowEsc = (0, import_react34.useCallback)(() => {
100714
100748
  escSwallowRef.current = true;
100715
100749
  setTimeout(() => {
100716
100750
  escSwallowRef.current = false;
100717
100751
  }, 0);
100718
100752
  }, []);
100719
- const isEscOwned = (0, import_react33.useCallback)(() => escViewRef.current || escSwallowRef.current, []);
100720
- const openViewer = (0, import_react33.useCallback)(() => setViewing(true), []);
100753
+ const isEscOwned = (0, import_react34.useCallback)(() => escViewRef.current || escSwallowRef.current, []);
100754
+ const openViewer = (0, import_react34.useCallback)(() => setViewing(true), []);
100721
100755
  const { isRawModeSupported } = use_stdin_default();
100722
- const [resumeFound, setResumeFound] = (0, import_react33.useState)(null);
100723
- const openResume = (0, import_react33.useCallback)((found) => setResumeFound(found), []);
100724
- const { turns, events, isRunning, notices, pending, mode, todos, stats, submit, retry, mentions, replayed, resume } = useReplController({ repoName: repoName2, yolo: yolo2, sessions: sessionStore, resumeLatest: resumeLatest2, onViewTurns: openViewer, onViewResume: isRawModeSupported && interactivePicker ? openResume : void 0, isEscOwned });
100756
+ const [resumeFound, setResumeFound] = (0, import_react34.useState)(null);
100757
+ const openResume = (0, import_react34.useCallback)((found) => setResumeFound(found), []);
100758
+ const { turns, events, isRunning, livePrompt, notices, pending, mode, todos, stats, submit, retry, mentions, replayed, resume } = useReplController({ repoName: repoName2, yolo: yolo2, sessions: sessionStore, resumeLatest: resumeLatest2, onViewTurns: openViewer, onViewResume: isRawModeSupported && interactivePicker ? openResume : void 0, isEscOwned });
100725
100759
  const { columns, rows } = useTerminalSize();
100726
100760
  const viewing = viewingRaw && !pending;
100727
100761
  const picking = resumeFound !== null && !pending;
100728
- const liveSteps = (0, import_react33.useMemo)(() => stepsOfEvents(events), [events]);
100729
- const [focusId, setFocusId] = (0, import_react33.useState)(null);
100730
- const [openId, setOpenId] = (0, import_react33.useState)(null);
100762
+ const [scroll, setScroll] = (0, import_react34.useState)(0);
100763
+ const measured = (0, import_react34.useRef)({ viewport: 0, content: 0 });
100764
+ const onMeasure = (0, import_react34.useCallback)((viewport, content) => {
100765
+ if (viewport <= 0) return;
100766
+ const prev = measured.current;
100767
+ measured.current = { viewport, content };
100768
+ setScroll((s) => s === 0 ? 0 : Math.min(Math.max(0, content - viewport), s + Math.max(0, content - prev.content)));
100769
+ }, []);
100770
+ const pageBy = (0, import_react34.useCallback)((dir) => {
100771
+ const { viewport, content } = measured.current;
100772
+ setScroll((s) => Math.min(Math.max(0, content - viewport), Math.max(0, s + dir * Math.max(1, viewport - 2))));
100773
+ }, []);
100774
+ use_input_default((_input, key) => {
100775
+ if (key.pageUp) pageBy(1);
100776
+ else if (key.pageDown) pageBy(-1);
100777
+ }, { isActive: fullscreen2 && Boolean(isRawModeSupported) && !viewing && !picking });
100778
+ (0, import_react34.useEffect)(() => {
100779
+ if (pending || isRunning) setScroll(0);
100780
+ }, [pending, isRunning]);
100781
+ const liveSteps = (0, import_react34.useMemo)(() => stepsOfEvents(events), [events]);
100782
+ const [focusId, setFocusId] = (0, import_react34.useState)(null);
100783
+ const [openId, setOpenId] = (0, import_react34.useState)(null);
100731
100784
  const focusIdx = focusId === null ? -1 : liveSteps.findIndex((r) => r.id === focusId);
100732
100785
  const focusing = focusIdx >= 0 && !viewing && !picking && !pending;
100733
100786
  escViewRef.current = focusing || viewing || picking;
100734
- const enterFocus = (0, import_react33.useCallback)(() => {
100787
+ const enterFocus = (0, import_react34.useCallback)(() => {
100735
100788
  if (liveSteps.length > 0) setFocusId(liveSteps[liveSteps.length - 1].id);
100736
100789
  }, [liveSteps]);
100737
100790
  use_input_default((input, key) => {
@@ -100753,11 +100806,11 @@ function App2({ repoName: repoName2, onboardingMode: onboardingMode2, launchCoun
100753
100806
  if (key.ctrl && input === "o") setViewing(true);
100754
100807
  }, { isActive: Boolean(isRawModeSupported) && !viewing && !picking && !pending });
100755
100808
  const waitingStep = pending ? findBlockedStep(liveSteps, pending.req) : void 0;
100756
- const promptNode = pending ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PermissionPrompt, { req: pending.req, onDecide: pending.resolve }, pending.id) : null;
100757
- const viewerTurns = (0, import_react33.useMemo)(() => [...replayed, ...turns], [replayed, turns]);
100758
- const turnSteps = (0, import_react33.useMemo)(() => viewing ? stepsOfTurns(viewerTurns) : /* @__PURE__ */ new Map(), [viewing, viewerTurns]);
100759
- const [gitState, setGitState] = (0, import_react33.useState)(null);
100760
- (0, import_react33.useEffect)(() => {
100809
+ const promptNode = pending ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PermissionPrompt, { req: pending.req, onDecide: pending.resolve }, pending.id) : null;
100810
+ const viewerTurns = (0, import_react34.useMemo)(() => [...replayed, ...turns], [replayed, turns]);
100811
+ const turnSteps = (0, import_react34.useMemo)(() => viewing ? stepsOfTurns(viewerTurns) : /* @__PURE__ */ new Map(), [viewing, viewerTurns]);
100812
+ const [gitState, setGitState] = (0, import_react34.useState)(null);
100813
+ (0, import_react34.useEffect)(() => {
100761
100814
  let live = true;
100762
100815
  void readGitState(runGit).then((g2) => {
100763
100816
  if (live) setGitState(g2);
@@ -100767,20 +100820,57 @@ function App2({ repoName: repoName2, onboardingMode: onboardingMode2, launchCoun
100767
100820
  };
100768
100821
  }, [runGit, turns.length]);
100769
100822
  const footer = formatFooter({ mode, contextPct: stats.contextPct, costUsd: stats.costUsd, model: stats.model, columns });
100770
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Box_default, { flexDirection: "column", children: [
100771
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Header, { project: repoName2 ?? path10.basename(process.cwd()), git: gitState, turns: turns.length, elapsedMs: Date.now() - startedAtRef.current, columns }),
100772
- notices.map((n, i) => typeof n === "string" ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { ...paint("action"), children: n }, i) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ErrorBlock, { view: n.error }, i)),
100773
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Static, { items: [BANNER, ...turns], children: (turn) => typeof turn === "symbol" ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(WelcomeBanner, { repoName: repoName2, onboardingMode: onboardingMode2, launchCount: launchCount2 }, "banner") : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Box_default, { flexDirection: "column", children: [
100774
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Text, { ...paint("secondary"), children: [
100823
+ const turnNode = (turn) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TurnBlock, { turn }, turn.id);
100824
+ if (fullscreen2) {
100825
+ const hidden = viewing || picking;
100826
+ const unicode = activeGlyphs().rail === "\u2502";
100827
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Box_default, { flexDirection: "column", height: Math.max(rows - 1, 5), children: [
100828
+ viewing && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TurnViewer, { turns: viewerTurns, steps: turnSteps, rows: rows - 2, columns, onClose: () => setViewing(false), onEscape: swallowEsc }),
100829
+ picking && resumeFound && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ResumePicker, { sessions: resumeFound.sessions, errors: resumeFound.errors, projectRoot: process.cwd(), now: /* @__PURE__ */ new Date(), rows: rows - 2, columns, preview: resume.preview, onResume: resume.load, onDelete: resume.remove, onClose: () => setResumeFound(null), onEscape: swallowEsc }),
100830
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Box_default, { flexDirection: "column", flexGrow: 1, display: hidden ? "none" : "flex", children: [
100831
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Box_default, { flexShrink: 0, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Header, { project: repoName2 ?? path10.basename(process.cwd()), git: gitState, turns: turns.length, elapsedMs: Date.now() - startedAtRef.current, columns }) }),
100832
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Transcript, { scroll, onMeasure, children: [
100833
+ notices.map((n, i) => typeof n === "string" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { ...paint("action"), children: n }, i) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ErrorBlock, { view: n.error }, i)),
100834
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(WelcomeBanner, { repoName: repoName2, onboardingMode: onboardingMode2, launchCount: launchCount2 }),
100835
+ turns.map(turnNode),
100836
+ livePrompt !== null && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Text, { ...paint("secondary"), children: [
100837
+ "> ",
100838
+ livePrompt
100839
+ ] }),
100840
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(EventRenderer, { deferErrors: true, events, liveMaxLines: Math.max(6, rows - 12), focusId: focusing ? focusId : null, openId: focusing ? openId : null, detailRows: Math.max(4, rows - 14), waitingId: waitingStep?.id ?? null, prompt: promptNode }),
100841
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TodoChecklist, { todos }),
100842
+ pending && !waitingStep && promptNode
100843
+ ] }),
100844
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Box_default, { flexDirection: "column", flexShrink: 0, children: [
100845
+ scroll > 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Text, { ...paint("needsYou"), children: [
100846
+ unicode ? "\u2193" : "v",
100847
+ " scrolled up ",
100848
+ scroll,
100849
+ " lines - PgDn for newer output"
100850
+ ] }),
100851
+ isRunning && !pending && stats.elapsedMs !== null && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { ...paint("secondary"), children: formatThinking(stats.elapsedMs, stats.approxTokens, unicode) }),
100852
+ focusing && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { ...paint("secondary"), children: unicode ? "step focus: \u2191\u2193 or tab move \xB7 enter open/close \xB7 esc back to the prompt" : "step focus: up/down or tab move - enter open/close - esc back to the prompt" }),
100853
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PromptEditor, { onEmptyEnter: isRunning ? void 0 : retry, promptGlyph: promptGlyph(mode, unicode), unicode, fullWidth: true, onSubmit: submit, disabled: isRunning, history: promptHistory, listFiles: mentions.list, onTab: enterFocus, locked: focusing || viewing || picking || Boolean(pending) }),
100854
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { ...footer.level === "critical" ? paint("delete") : footer.level === "warn" ? paint("needsYou") : paint("secondary"), children: footer.text }),
100855
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { ...paint("secondary"), children: formatHints({ running: isRunning, asking: Boolean(pending), columns }, activeGlyphs().sep) })
100856
+ ] })
100857
+ ] })
100858
+ ] });
100859
+ }
100860
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Box_default, { flexDirection: "column", children: [
100861
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Header, { project: repoName2 ?? path10.basename(process.cwd()), git: gitState, turns: turns.length, elapsedMs: Date.now() - startedAtRef.current, columns }),
100862
+ notices.map((n, i) => typeof n === "string" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { ...paint("action"), children: n }, i) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ErrorBlock, { view: n.error }, i)),
100863
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Static, { items: [BANNER, ...turns], children: (turn) => typeof turn === "symbol" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(WelcomeBanner, { repoName: repoName2, onboardingMode: onboardingMode2, launchCount: launchCount2 }, "banner") : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Box_default, { flexDirection: "column", children: [
100864
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Text, { ...paint("secondary"), children: [
100775
100865
  "> ",
100776
100866
  turn.prompt
100777
100867
  ] }),
100778
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(EventRenderer, { events: turn.events, promptSaved: turn.retained }),
100779
- turn.interrupted && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { ...paint("needsYou"), children: "Interrupted" }),
100780
- turn.summary && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { ...paint("secondary"), children: turn.summary })
100868
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(EventRenderer, { events: turn.events, promptSaved: turn.retained }),
100869
+ turn.interrupted && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { ...paint("needsYou"), children: "Interrupted" }),
100870
+ turn.summary && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { ...paint("secondary"), children: turn.summary })
100781
100871
  ] }, turn.id) }),
100782
- viewing && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TurnViewer, { turns: viewerTurns, steps: turnSteps, rows, columns, onClose: () => setViewing(false), onEscape: swallowEsc }),
100783
- picking && resumeFound && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
100872
+ viewing && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TurnViewer, { turns: viewerTurns, steps: turnSteps, rows, columns, onClose: () => setViewing(false), onEscape: swallowEsc }),
100873
+ picking && resumeFound && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
100784
100874
  ResumePicker,
100785
100875
  {
100786
100876
  sessions: resumeFound.sessions,
@@ -100796,23 +100886,27 @@ function App2({ repoName: repoName2, onboardingMode: onboardingMode2, launchCoun
100796
100886
  onEscape: swallowEsc
100797
100887
  }
100798
100888
  ),
100799
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Box_default, { flexDirection: "column", display: viewing || picking ? "none" : "flex", children: [
100800
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(EventRenderer, { deferErrors: true, events, liveMaxLines: Math.max(6, rows - 12), focusId: focusing ? focusId : null, openId: focusing ? openId : null, detailRows: Math.max(4, rows - 14), waitingId: waitingStep?.id ?? null, prompt: promptNode }),
100801
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TodoChecklist, { todos }),
100889
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Box_default, { flexDirection: "column", display: viewing || picking ? "none" : "flex", children: [
100890
+ livePrompt !== null && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Text, { ...paint("secondary"), children: [
100891
+ "> ",
100892
+ livePrompt
100893
+ ] }),
100894
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(EventRenderer, { deferErrors: true, events, liveMaxLines: Math.max(6, rows - 15), focusId: focusing ? focusId : null, openId: focusing ? openId : null, detailRows: Math.max(4, rows - 14), waitingId: waitingStep?.id ?? null, prompt: promptNode }),
100895
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TodoChecklist, { todos }),
100802
100896
  pending && !waitingStep && promptNode,
100803
- isRunning && !pending && stats.elapsedMs !== null && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { ...paint("secondary"), children: formatThinking(stats.elapsedMs, stats.approxTokens, activeGlyphs().rail === "\u2502") }),
100804
- focusing && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { ...paint("secondary"), children: activeGlyphs().rail === "\u2502" ? "step focus: \u2191\u2193 or tab move \xB7 enter open/close \xB7 esc back to the prompt" : "step focus: up/down or tab move - enter open/close - esc back to the prompt" }),
100805
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PromptEditor, { onEmptyEnter: isRunning ? void 0 : retry, promptGlyph: promptGlyph(mode, activeGlyphs().rail === "\u2502"), onSubmit: submit, disabled: isRunning, history: promptHistory, listFiles: mentions.list, onTab: enterFocus, locked: focusing || viewing || picking || Boolean(pending) }),
100806
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { ...footer.level === "critical" ? paint("delete") : footer.level === "warn" ? paint("needsYou") : paint("secondary"), children: footer.text }),
100807
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { ...paint("secondary"), children: formatHints({ running: isRunning, asking: Boolean(pending), columns }, activeGlyphs().sep) })
100897
+ isRunning && !pending && stats.elapsedMs !== null && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { ...paint("secondary"), children: formatThinking(stats.elapsedMs, stats.approxTokens, activeGlyphs().rail === "\u2502") }),
100898
+ focusing && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { ...paint("secondary"), children: activeGlyphs().rail === "\u2502" ? "step focus: \u2191\u2193 or tab move \xB7 enter open/close \xB7 esc back to the prompt" : "step focus: up/down or tab move - enter open/close - esc back to the prompt" }),
100899
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PromptEditor, { onEmptyEnter: isRunning ? void 0 : retry, promptGlyph: promptGlyph(mode, activeGlyphs().rail === "\u2502"), unicode: activeGlyphs().rail === "\u2502", onSubmit: submit, disabled: isRunning, history: promptHistory, listFiles: mentions.list, onTab: enterFocus, locked: focusing || viewing || picking || Boolean(pending) }),
100900
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { ...footer.level === "critical" ? paint("delete") : footer.level === "warn" ? paint("needsYou") : paint("secondary"), children: footer.text }),
100901
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { ...paint("secondary"), children: formatHints({ running: isRunning, asking: Boolean(pending), columns }, activeGlyphs().sep) })
100808
100902
  ] })
100809
100903
  ] });
100810
100904
  }
100811
- var import_react33, import_jsx_runtime12, BANNER;
100905
+ var import_react34, import_jsx_runtime13, BANNER, TurnBlock;
100812
100906
  var init_App2 = __esm({
100813
100907
  async "src/App.tsx"() {
100814
100908
  "use strict";
100815
- import_react33 = __toESM(require_react(), 1);
100909
+ import_react34 = __toESM(require_react(), 1);
100816
100910
  await init_build2();
100817
100911
  await init_WelcomeBanner();
100818
100912
  await init_Header();
@@ -100835,9 +100929,21 @@ var init_App2 = __esm({
100835
100929
  init_theme();
100836
100930
  await init_TurnViewer();
100837
100931
  await init_ResumePicker();
100932
+ await init_Transcript();
100838
100933
  init_step_view();
100839
- import_jsx_runtime12 = __toESM(require_jsx_runtime(), 1);
100934
+ import_jsx_runtime13 = __toESM(require_jsx_runtime(), 1);
100840
100935
  BANNER = /* @__PURE__ */ Symbol("welcome-banner");
100936
+ TurnBlock = import_react34.default.memo(function TurnBlock2({ turn }) {
100937
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Box_default, { flexDirection: "column", children: [
100938
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Text, { ...paint("secondary"), children: [
100939
+ "> ",
100940
+ turn.prompt
100941
+ ] }),
100942
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(EventRenderer, { events: turn.events, promptSaved: turn.retained }),
100943
+ turn.interrupted && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { ...paint("needsYou"), children: "Interrupted" }),
100944
+ turn.summary && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { ...paint("secondary"), children: turn.summary })
100945
+ ] });
100946
+ });
100841
100947
  }
100842
100948
  });
100843
100949
 
@@ -100845,6 +100951,12 @@ var init_App2 = __esm({
100845
100951
  init_color_policy();
100846
100952
  applyColorPolicy(process.env, Boolean(process.stdout.isTTY));
100847
100953
 
100954
+ // src/index.tsx
100955
+ import os5 from "node:os";
100956
+ import path11 from "node:path";
100957
+ import fs5 from "node:fs";
100958
+ import util2 from "node:util";
100959
+
100848
100960
  // src/render/terminal-env.ts
100849
100961
  function hideCiVariables(env3, stdoutIsTTY) {
100850
100962
  if (!stdoutIsTTY || env3.CI !== void 0) return () => {
@@ -100856,8 +100968,75 @@ function hideCiVariables(env3, stdoutIsTTY) {
100856
100968
  };
100857
100969
  }
100858
100970
 
100971
+ // src/fullscreen.ts
100972
+ import fs from "node:fs";
100973
+ import util from "node:util";
100974
+ var ENTER = "\x1B[?1049h\x1B[2J\x1B[H\x1B[?25l";
100975
+ var LEAVE = "\x1B[?25h\x1B[?1049l";
100976
+ function shouldUseFullscreen(env3, stdout, stdinIsTTY) {
100977
+ if (!stdout.isTTY || !stdinIsTTY) return false;
100978
+ if (env3.SPACECODE_INLINE && env3.SPACECODE_INLINE !== "0") return false;
100979
+ return env3.TERM !== "dumb";
100980
+ }
100981
+ function enterFullscreen(out, proc, stderr = process.stderr) {
100982
+ let active2 = true;
100983
+ const cleanups = [];
100984
+ const leave = () => {
100985
+ if (!active2) return;
100986
+ active2 = false;
100987
+ for (const fn of cleanups) fn();
100988
+ out.write(LEAVE);
100989
+ };
100990
+ const fatal = (err) => {
100991
+ leave();
100992
+ stderr.write(`${util.inspect(err)}
100993
+ `);
100994
+ proc.exit(1);
100995
+ };
100996
+ out.write(ENTER);
100997
+ proc.on("exit", leave);
100998
+ for (const [sig, code] of [["SIGINT", 130], ["SIGTERM", 143], ["SIGHUP", 129]]) {
100999
+ proc.on(sig, () => {
101000
+ leave();
101001
+ proc.exit(code);
101002
+ });
101003
+ }
101004
+ proc.on("uncaughtException", fatal);
101005
+ proc.on("unhandledRejection", fatal);
101006
+ return { leave, onLeave: (fn) => {
101007
+ cleanups.push(fn);
101008
+ } };
101009
+ }
101010
+ function redirectConsole(file) {
101011
+ const original = { log: console.log, info: console.info, warn: console.warn, error: console.error, debug: console.debug };
101012
+ const write = (level) => (...args) => {
101013
+ try {
101014
+ fs.appendFileSync(file, `${(/* @__PURE__ */ new Date()).toISOString()} ${level} ${util.format(...args)}
101015
+ `, { mode: 384 });
101016
+ } catch (err) {
101017
+ process.stderr.write(`[spacecode] could not write ${file}: ${String(err)}
101018
+ `);
101019
+ }
101020
+ };
101021
+ console.log = write("log");
101022
+ console.info = write("info");
101023
+ console.warn = write("warn");
101024
+ console.error = write("error");
101025
+ console.debug = write("debug");
101026
+ return () => Object.assign(console, original);
101027
+ }
101028
+ function clearOnResize(stdout) {
101029
+ const clear = () => {
101030
+ stdout.write("\x1B[2J\x1B[H");
101031
+ };
101032
+ stdout.prependListener("resize", clear);
101033
+ return () => {
101034
+ stdout.off("resize", clear);
101035
+ };
101036
+ }
101037
+
100859
101038
  // src/index.tsx
100860
- var import_jsx_runtime13 = __toESM(require_jsx_runtime(), 1);
101039
+ var import_jsx_runtime14 = __toESM(require_jsx_runtime(), 1);
100861
101040
  var repoName = process.env.REPO_NAME || process.cwd().split("/").pop() || void 0;
100862
101041
  var validModes = ["guest", "new_project", "existing_repo"];
100863
101042
  var rawMode = process.env.ONBOARDING_MODE;
@@ -100874,7 +101053,34 @@ try {
100874
101053
  } finally {
100875
101054
  restoreCiVariables();
100876
101055
  }
100877
- render2(/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(App3, { repoName, onboardingMode, launchCount, yolo, resumeLatest, interactivePicker: Boolean(process.stdout.isTTY) }));
101056
+ var fullscreen = shouldUseFullscreen(process.env, process.stdout, Boolean(process.stdin.isTTY));
101057
+ var session;
101058
+ if (fullscreen) {
101059
+ const dir = path11.join(os5.homedir(), ".spacecode");
101060
+ fs5.mkdirSync(dir, { recursive: true });
101061
+ const restoreConsole = redirectConsole(path11.join(dir, "repl.log"));
101062
+ session = enterFullscreen(process.stdout, process);
101063
+ session.onLeave(restoreConsole);
101064
+ session.onLeave(clearOnResize(process.stdout));
101065
+ }
101066
+ var app = render2(
101067
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(App3, { repoName, onboardingMode, launchCount, yolo, resumeLatest, interactivePicker: Boolean(process.stdout.isTTY), fullscreen }),
101068
+ { patchConsole: !fullscreen }
101069
+ );
101070
+ if (session) {
101071
+ try {
101072
+ await app.waitUntilExit();
101073
+ session.leave();
101074
+ process.stdout.write("Session saved. Resume it with `spacecode --continue` or `/resume`.\n");
101075
+ } catch (err) {
101076
+ session.leave();
101077
+ process.stderr.write(`${util2.inspect(err)}
101078
+ `);
101079
+ process.exitCode = 1;
101080
+ } finally {
101081
+ session.leave();
101082
+ }
101083
+ }
100878
101084
  /*! Bundled license information:
100879
101085
 
100880
101086
  react/cjs/react.production.min.js: