spacecode 2.1.1 → 2.2.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/repl.mjs CHANGED
@@ -1396,7 +1396,7 @@ var require_react_development = __commonJS({
1396
1396
  }
1397
1397
  return dispatcher.useContext(Context);
1398
1398
  }
1399
- function useState10(initialState) {
1399
+ function useState9(initialState) {
1400
1400
  var dispatcher = resolveDispatcher();
1401
1401
  return dispatcher.useState(initialState);
1402
1402
  }
@@ -1404,11 +1404,11 @@ 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 useRef6(initialValue) {
1408
1408
  var dispatcher = resolveDispatcher();
1409
1409
  return dispatcher.useRef(initialValue);
1410
1410
  }
1411
- function useEffect9(create2, deps) {
1411
+ function useEffect8(create2, deps) {
1412
1412
  var dispatcher = resolveDispatcher();
1413
1413
  return dispatcher.useEffect(create2, deps);
1414
1414
  }
@@ -1416,11 +1416,11 @@ 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
  }
1423
- function useCallback4(callback, deps) {
1423
+ function useCallback5(callback, deps) {
1424
1424
  var dispatcher = resolveDispatcher();
1425
1425
  return dispatcher.useCallback(callback, deps);
1426
1426
  }
@@ -1450,7 +1450,7 @@ var require_react_development = __commonJS({
1450
1450
  var dispatcher = resolveDispatcher();
1451
1451
  return dispatcher.useId();
1452
1452
  }
1453
- function useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot) {
1453
+ function useSyncExternalStore2(subscribe, getSnapshot, getServerSnapshot) {
1454
1454
  var dispatcher = resolveDispatcher();
1455
1455
  return dispatcher.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
1456
1456
  }
@@ -2187,20 +2187,20 @@ var require_react_development = __commonJS({
2187
2187
  exports.memo = memo;
2188
2188
  exports.startTransition = startTransition;
2189
2189
  exports.unstable_act = act;
2190
- exports.useCallback = useCallback4;
2190
+ exports.useCallback = useCallback5;
2191
2191
  exports.useContext = useContext7;
2192
2192
  exports.useDebugValue = useDebugValue;
2193
2193
  exports.useDeferredValue = useDeferredValue;
2194
- exports.useEffect = useEffect9;
2194
+ exports.useEffect = useEffect8;
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;
2202
- exports.useState = useState10;
2203
- exports.useSyncExternalStore = useSyncExternalStore;
2201
+ exports.useRef = useRef6;
2202
+ exports.useState = useState9;
2203
+ exports.useSyncExternalStore = useSyncExternalStore2;
2204
2204
  exports.useTransition = useTransition;
2205
2205
  exports.version = ReactVersion;
2206
2206
  if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== "undefined" && typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop === "function") {
@@ -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
  {
@@ -16072,11 +16072,11 @@ var require_react_reconciler_development = __commonJS({
16072
16072
  currentlyRenderingFiber$1.updateQueue = componentUpdateQueue;
16073
16073
  componentUpdateQueue.stores = [check];
16074
16074
  } else {
16075
- var stores = componentUpdateQueue.stores;
16076
- if (stores === null) {
16075
+ var stores2 = componentUpdateQueue.stores;
16076
+ if (stores2 === null) {
16077
16077
  componentUpdateQueue.stores = [check];
16078
16078
  } else {
16079
- stores.push(check);
16079
+ stores2.push(check);
16080
16080
  }
16081
16081
  }
16082
16082
  }
@@ -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(),
@@ -34899,7 +34899,18 @@ var init_mode_line = __esm({
34899
34899
  });
34900
34900
 
34901
34901
  // src/components/useEventAccumulator.ts
34902
- function processEvents(events) {
34902
+ function dropDiscardedEvents(events) {
34903
+ const ranges = [];
34904
+ for (const e of events) {
34905
+ if (e.type === "status" && e.discardFromSeq !== void 0) ranges.push({ from: e.discardFromSeq, to: e.seq });
34906
+ }
34907
+ if (ranges.length === 0) return events;
34908
+ return events.filter(
34909
+ (e) => !((e.type === "text" || e.type === "text_delta") && ranges.some((r) => e.seq >= r.from && e.seq < r.to))
34910
+ );
34911
+ }
34912
+ function processEvents(rawEvents) {
34913
+ const events = dropDiscardedEvents(rawEvents);
34903
34914
  const renderOrder = [];
34904
34915
  const toolMap = /* @__PURE__ */ new Map();
34905
34916
  let statusMessage = null;
@@ -36759,7 +36770,7 @@ var require_has_flag = __commonJS({
36759
36770
  var require_supports_colors = __commonJS({
36760
36771
  "../../node_modules/@colors/colors/lib/system/supports-colors.js"(exports, module) {
36761
36772
  "use strict";
36762
- var os5 = __require("os");
36773
+ var os6 = __require("os");
36763
36774
  var hasFlag2 = require_has_flag();
36764
36775
  var env3 = process.env;
36765
36776
  var forceColor = void 0;
@@ -36797,7 +36808,7 @@ var require_supports_colors = __commonJS({
36797
36808
  }
36798
36809
  var min = forceColor ? 1 : 0;
36799
36810
  if (process.platform === "win32") {
36800
- var osRelease = os5.release().split(".");
36811
+ var osRelease = os6.release().split(".");
36801
36812
  if (Number(process.versions.node.split(".")[0]) >= 8 && Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
36802
36813
  return Number(osRelease[2]) >= 14931 ? 3 : 2;
36803
36814
  }
@@ -37189,7 +37200,7 @@ var require_colors = __commonJS({
37189
37200
  var colors = {};
37190
37201
  module["exports"] = colors;
37191
37202
  colors.themes = {};
37192
- var util = __require("util");
37203
+ var util3 = __require("util");
37193
37204
  var ansiStyles3 = colors.styles = require_styles();
37194
37205
  var defineProps = Object.defineProperties;
37195
37206
  var newLineRegex = new RegExp(/[\r\n]+/g);
@@ -37252,7 +37263,7 @@ var require_colors = __commonJS({
37252
37263
  if (arg != null && arg.constructor === String) {
37253
37264
  return arg;
37254
37265
  } else {
37255
- return util.inspect(arg);
37266
+ return util3.inspect(arg);
37256
37267
  }
37257
37268
  }).join(" ");
37258
37269
  if (!colors.enabled || !str) {
@@ -80882,15 +80893,15 @@ var require_route = __commonJS({
80882
80893
  };
80883
80894
  }
80884
80895
  function wrapConversion(toModel, graph) {
80885
- const path11 = [graph[toModel].parent, toModel];
80896
+ const path12 = [graph[toModel].parent, toModel];
80886
80897
  let fn = conversions[graph[toModel].parent][toModel];
80887
80898
  let cur = graph[toModel].parent;
80888
80899
  while (graph[cur].parent) {
80889
- path11.unshift(graph[cur].parent);
80900
+ path12.unshift(graph[cur].parent);
80890
80901
  fn = link2(conversions[graph[cur].parent][cur], fn);
80891
80902
  cur = graph[cur].parent;
80892
80903
  }
80893
- fn.conversion = path11;
80904
+ fn.conversion = path12;
80894
80905
  return fn;
80895
80906
  }
80896
80907
  module.exports = function(fromModel) {
@@ -81130,7 +81141,7 @@ var require_has_flag2 = __commonJS({
81130
81141
  var require_supports_color = __commonJS({
81131
81142
  "../../node_modules/supports-color/index.js"(exports, module) {
81132
81143
  "use strict";
81133
- var os5 = __require("os");
81144
+ var os6 = __require("os");
81134
81145
  var tty2 = __require("tty");
81135
81146
  var hasFlag2 = require_has_flag2();
81136
81147
  var { env: env3 } = process;
@@ -81178,7 +81189,7 @@ var require_supports_color = __commonJS({
81178
81189
  return min;
81179
81190
  }
81180
81191
  if (process.platform === "win32") {
81181
- const osRelease = os5.release().split(".");
81192
+ const osRelease = os6.release().split(".");
81182
81193
  if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
81183
81194
  return Number(osRelease[2]) >= 14931 ? 3 : 2;
81184
81195
  }
@@ -94306,26 +94317,57 @@ var init_markdown = __esm({
94306
94317
  });
94307
94318
 
94308
94319
  // src/useTerminalSize.ts
94320
+ function readSize(stdout, fallback) {
94321
+ return { columns: stdout?.columns || fallback.columns, rows: stdout?.rows || fallback.rows };
94322
+ }
94323
+ function storeFor(stdout, fallback) {
94324
+ let store = stores.get(stdout);
94325
+ if (!store) {
94326
+ const created = {
94327
+ size: readSize(stdout, fallback),
94328
+ listeners: /* @__PURE__ */ new Set(),
94329
+ onResize: () => {
94330
+ const next = readSize(stdout, fallback);
94331
+ if (next.columns === created.size.columns && next.rows === created.size.rows) return;
94332
+ created.size = next;
94333
+ for (const l of created.listeners) l();
94334
+ }
94335
+ };
94336
+ store = created;
94337
+ stores.set(stdout, store);
94338
+ }
94339
+ return store;
94340
+ }
94309
94341
  function useTerminalSize(fallback = { columns: 80, rows: 24 }) {
94310
94342
  const { stdout } = use_stdout_default();
94311
- const [size, setSize] = (0, import_react24.useState)({ columns: stdout?.columns || fallback.columns, rows: stdout?.rows || fallback.rows });
94312
- (0, import_react24.useEffect)(() => {
94313
- if (!stdout) return;
94314
- const update = () => setSize({ columns: stdout.columns || fallback.columns, rows: stdout.rows || fallback.rows });
94315
- update();
94316
- stdout.on("resize", update);
94317
- return () => {
94318
- stdout.off("resize", update);
94319
- };
94320
- }, [stdout, fallback.columns, fallback.rows]);
94321
- return size;
94343
+ const fallbackRef = (0, import_react24.useRef)(fallback);
94344
+ fallbackRef.current = fallback;
94345
+ const fixed = (0, import_react24.useRef)(readSize(void 0, fallback));
94346
+ const subscribe = (0, import_react24.useCallback)(
94347
+ (listener) => {
94348
+ if (!stdout) return () => {
94349
+ };
94350
+ const store = storeFor(stdout, fallbackRef.current);
94351
+ store.onResize();
94352
+ if (store.listeners.size === 0) stdout.on("resize", store.onResize);
94353
+ store.listeners.add(listener);
94354
+ return () => {
94355
+ store.listeners.delete(listener);
94356
+ if (store.listeners.size === 0) stdout.off("resize", store.onResize);
94357
+ };
94358
+ },
94359
+ [stdout]
94360
+ );
94361
+ const getSnapshot = (0, import_react24.useCallback)(() => stdout ? storeFor(stdout, fallbackRef.current).size : fixed.current, [stdout]);
94362
+ return (0, import_react24.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
94322
94363
  }
94323
- var import_react24;
94364
+ var import_react24, stores;
94324
94365
  var init_useTerminalSize = __esm({
94325
94366
  async "src/useTerminalSize.ts"() {
94326
94367
  "use strict";
94327
94368
  import_react24 = __toESM(require_react(), 1);
94328
94369
  await init_build2();
94370
+ stores = /* @__PURE__ */ new WeakMap();
94329
94371
  }
94330
94372
  });
94331
94373
 
@@ -96159,10 +96201,10 @@ var init_session_store = __esm({
96159
96201
  if (!ID.test(id)) throw new SessionError(this.dir, `Invalid session id ${JSON.stringify(id)}`);
96160
96202
  return path.join(this.dir, `${id}.jsonl`);
96161
96203
  }
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";
96204
+ async save(session2) {
96205
+ const file = this.fileFor(session2.meta.id);
96206
+ const meta = { ...session2.meta, updatedAt: this.now().toISOString() };
96207
+ const body = [meta, ...session2.messages].map((entry) => JSON.stringify(redactCredentials(entry))).join("\n") + "\n";
96166
96208
  const bytes = Buffer.byteLength(body);
96167
96209
  if (bytes > MAX_SESSION_BYTES) {
96168
96210
  throw new SessionError(file, `Session is ${bytes} bytes, over the ${MAX_SESSION_BYTES}-byte cap; use /compact or /clear`);
@@ -96191,9 +96233,9 @@ var init_session_store = __esm({
96191
96233
  if (err instanceof SessionError) throw err;
96192
96234
  throw new SessionError(file, `Could not read session: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
96193
96235
  }
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;
96236
+ const session2 = parseSession(file, text);
96237
+ if (session2.meta.id !== id) throw new SessionError(file, `Session header id "${session2.meta.id}" does not match the file name`);
96238
+ return session2;
96197
96239
  }
96198
96240
  /** Newest first. Unreadable files are reported, not skipped silently. */
96199
96241
  async list() {
@@ -97276,17 +97318,17 @@ function isSubsequence(needle, hay) {
97276
97318
  for (let j2 = 0; j2 < hay.length && i < needle.length; j2++) if (hay[j2] === needle[i]) i++;
97277
97319
  return i === needle.length;
97278
97320
  }
97279
- function tier(path11, q2) {
97280
- const base = path11.slice(path11.lastIndexOf("/") + 1);
97321
+ function tier(path12, q2) {
97322
+ const base = path12.slice(path12.lastIndexOf("/") + 1);
97281
97323
  if (base.startsWith(q2)) return 0;
97282
97324
  if (base.includes(q2)) return 1;
97283
- if (path11.includes(q2)) return 2;
97325
+ if (path12.includes(q2)) return 2;
97284
97326
  return 3;
97285
97327
  }
97286
97328
  function rankPaths(paths, query, limit = 8) {
97287
97329
  if (query === "") return paths.slice(0, limit);
97288
97330
  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);
97331
+ 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
97332
  }
97291
97333
  var init_mention_rank = __esm({
97292
97334
  "src/editor/mention-rank.ts"() {
@@ -97303,9 +97345,9 @@ function activeMention(text, cursor) {
97303
97345
  const explicit = token[1] === "!";
97304
97346
  return { start, query: token.slice(explicit ? 2 : 1), explicit };
97305
97347
  }
97306
- function insertMention(text, cursor, mention, path11) {
97307
- if (/\s/.test(path11)) return { text, cursor };
97308
- const inserted = `@${mention.explicit ? "!" : ""}${path11}`;
97348
+ function insertMention(text, cursor, mention, path12) {
97349
+ if (/\s/.test(path12)) return { text, cursor };
97350
+ const inserted = `@${mention.explicit ? "!" : ""}${path12}`;
97309
97351
  const head = text.slice(0, mention.start) + inserted;
97310
97352
  const next = text[cursor];
97311
97353
  if (next !== void 0 && /\s/.test(next)) return { text: head + text.slice(cursor), cursor: head.length + 1 };
@@ -97392,7 +97434,7 @@ function validateSubmission(text) {
97392
97434
  function withCursor(row, col) {
97393
97435
  return `${row.slice(0, col)}\x1B[7m${row[col] ?? " "}\x1B[27m${row.slice(col + 1)}`;
97394
97436
  }
97395
- function PromptEditor({ onSubmit, disabled, history, listFiles: listFiles2, onTab, locked = false, promptGlyph: promptGlyph2 = ">", onEmptyEnter, unicode = true }) {
97437
+ function PromptEditor({ onSubmit, disabled, history, listFiles: listFiles2, onTab, locked = false, promptGlyph: promptGlyph2 = ">", onEmptyEnter, unicode = true, fullWidth = false }) {
97396
97438
  const { exit } = use_app_default();
97397
97439
  const { columns } = useTerminalSize();
97398
97440
  const { isRawModeSupported } = use_stdin_default();
@@ -97552,7 +97594,7 @@ function PromptEditor({ onSubmit, disabled, history, listFiles: listFiles2, onTa
97552
97594
  const picks = mention && files ? rankPaths(files, mention.query, PICKER_ROWS) : [];
97553
97595
  const pickAt = Math.min(sel, Math.max(picks.length - 1, 0));
97554
97596
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { flexDirection: "column", 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: Math.min(columns, MAX_STATIC_LINE), children: rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { children: [
97597
+ /* @__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
97598
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { ...paint(shell ? "action" : "agent"), bold: true, dimColor: disabled, children: i === 0 ? shell ? "! " : `${promptGlyph2} ` : " " }),
97557
97599
  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
97600
  ] }, i)) }),
@@ -97744,6 +97786,8 @@ async function parseStreamResponse(body, emit, signal) {
97744
97786
  let currentText = "";
97745
97787
  let currentThinking = "";
97746
97788
  let currentToolInput = "";
97789
+ let sawMessageStop = false;
97790
+ let thinkingStatusShown = false;
97747
97791
  try {
97748
97792
  while (true) {
97749
97793
  if (signal?.aborted) break;
@@ -97778,6 +97822,7 @@ async function parseStreamResponse(body, emit, signal) {
97778
97822
  if (block?.type === "thinking") {
97779
97823
  currentBlockType = "thinking";
97780
97824
  currentThinking = "";
97825
+ thinkingStatusShown = false;
97781
97826
  } else if (block?.type === "text") {
97782
97827
  currentBlockType = "text";
97783
97828
  currentText = "";
@@ -97797,6 +97842,10 @@ async function parseStreamResponse(body, emit, signal) {
97797
97842
  const delta = event.delta;
97798
97843
  if (delta?.type === "thinking_delta" && delta.thinking) {
97799
97844
  currentThinking += delta.thinking;
97845
+ if (!thinkingStatusShown) {
97846
+ thinkingStatusShown = true;
97847
+ emitStatus(emit, { type: "status", phase: "thinking" });
97848
+ }
97800
97849
  } else if (delta?.type === "text_delta" && delta.text) {
97801
97850
  currentText += delta.text;
97802
97851
  emitTextDelta(emit, { type: "text_delta", text: delta.text });
@@ -97820,7 +97869,10 @@ async function parseStreamResponse(body, emit, signal) {
97820
97869
  try {
97821
97870
  toolBlock.input = JSON.parse(currentToolInput);
97822
97871
  } catch {
97823
- toolBlock.input = {};
97872
+ throw new StreamIncompleteError(
97873
+ "invalid_tool_json",
97874
+ `Tool call "${toolBlock.name}" arrived with invalid JSON arguments`
97875
+ );
97824
97876
  }
97825
97877
  }
97826
97878
  currentToolInput = "";
@@ -97839,6 +97891,7 @@ async function parseStreamResponse(body, emit, signal) {
97839
97891
  break;
97840
97892
  }
97841
97893
  case "message_stop": {
97894
+ sawMessageStop = true;
97842
97895
  break;
97843
97896
  }
97844
97897
  case "error": {
@@ -97850,6 +97903,14 @@ async function parseStreamResponse(body, emit, signal) {
97850
97903
  } finally {
97851
97904
  reader.releaseLock();
97852
97905
  }
97906
+ if (!signal?.aborted) {
97907
+ if (currentBlockType === "tool_use") {
97908
+ throw new StreamIncompleteError("incomplete_tool_block", "Stream ended inside a tool call");
97909
+ }
97910
+ if (!sawMessageStop) {
97911
+ throw new StreamIncompleteError("missing_message_stop", "Stream ended without message_stop");
97912
+ }
97913
+ }
97853
97914
  return {
97854
97915
  content,
97855
97916
  stop_reason: stopReason,
@@ -97861,11 +97922,18 @@ async function parseStreamResponse(body, emit, signal) {
97861
97922
  }
97862
97923
  };
97863
97924
  }
97864
- var seqCounter;
97925
+ var seqCounter, StreamIncompleteError;
97865
97926
  var init_stream = __esm({
97866
97927
  "../agent/src/stream.ts"() {
97867
97928
  "use strict";
97868
97929
  seqCounter = 0;
97930
+ StreamIncompleteError = class extends Error {
97931
+ constructor(reason, message) {
97932
+ super(message);
97933
+ this.reason = reason;
97934
+ this.name = "StreamIncompleteError";
97935
+ }
97936
+ };
97869
97937
  }
97870
97938
  });
97871
97939
 
@@ -97966,7 +98034,30 @@ var init_retry = __esm({
97966
98034
  "use strict";
97967
98035
  MAX_RETRIES = 3;
97968
98036
  INITIAL_RETRY_DELAY_MS = 1e3;
97969
- RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([429, 529]);
98037
+ RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([429, 502, 503, 504, 529]);
98038
+ }
98039
+ });
98040
+
98041
+ // ../agent/src/request-headers.ts
98042
+ function buildRequestHeaders(i) {
98043
+ const headers = {
98044
+ "Content-Type": "application/json",
98045
+ "x-api-key": i.apiKey,
98046
+ "anthropic-version": "2023-06-01",
98047
+ "x-spacecode-session": i.sessionId,
98048
+ "x-spacecode-run": i.runId
98049
+ };
98050
+ if (i.isToolFollowUp && i.lastTier) headers["x-spacecode-tier"] = i.lastTier;
98051
+ return headers;
98052
+ }
98053
+ function isToolFollowUp(messages) {
98054
+ const last = messages[messages.length - 1];
98055
+ if (!last || last.role !== "user" || !Array.isArray(last.content)) return false;
98056
+ return last.content.length > 0 && last.content.every((b2) => b2?.type === "tool_result");
98057
+ }
98058
+ var init_request_headers = __esm({
98059
+ "../agent/src/request-headers.ts"() {
98060
+ "use strict";
97970
98061
  }
97971
98062
  });
97972
98063
 
@@ -98003,6 +98094,9 @@ async function runAgentLoop(prompt, config, executor, emit, signal, existingMess
98003
98094
  let truncationCount = 0;
98004
98095
  let toolExecutionMs = 0;
98005
98096
  let toolCount = 0;
98097
+ const runId = crypto.randomUUID();
98098
+ const sessionId = config.sessionId ?? runId;
98099
+ let lastTier;
98006
98100
  resetSeq();
98007
98101
  while (turns < maxTurns) {
98008
98102
  if (signal?.aborted) {
@@ -98051,74 +98145,103 @@ async function runAgentLoop(prompt, config, executor, emit, signal, existingMess
98051
98145
  }
98052
98146
  let response;
98053
98147
  let retryCount = 0;
98148
+ let data;
98054
98149
  while (true) {
98055
- try {
98056
- response = await fetch(url, {
98057
- method: "POST",
98058
- headers: {
98059
- "Content-Type": "application/json",
98060
- "x-api-key": config.apiKey,
98061
- "anthropic-version": "2023-06-01"
98062
- },
98063
- body: JSON.stringify(body),
98064
- signal
98065
- });
98066
- } catch (err) {
98067
- const message = err instanceof Error ? err.message : "Unknown fetch error";
98150
+ while (true) {
98151
+ try {
98152
+ response = await fetch(url, {
98153
+ method: "POST",
98154
+ headers: buildRequestHeaders({
98155
+ apiKey: config.apiKey,
98156
+ sessionId,
98157
+ runId,
98158
+ lastTier,
98159
+ isToolFollowUp: isToolFollowUp(messages)
98160
+ }),
98161
+ body: JSON.stringify(body),
98162
+ signal
98163
+ });
98164
+ } catch (err) {
98165
+ const message = err instanceof Error ? err.message : "Unknown fetch error";
98166
+ emitError(emit, { type: "error", message });
98167
+ return { success: false, text: lastText, totalInputTokens, totalOutputTokens, cacheCreationTokens, cacheReadTokens, turns, messages, retryCount: totalRetryCount, truncationCount, toolExecutionMs, toolCount };
98168
+ }
98169
+ if (isRetryableStatus(response.status) && retryCount < MAX_RETRIES) {
98170
+ retryCount++;
98171
+ totalRetryCount++;
98172
+ const delayMs = computeRetryDelayMs(response.headers.get("retry-after"), retryCount);
98173
+ emitStatus(emit, {
98174
+ type: "status",
98175
+ phase: "retrying",
98176
+ message: `API returned ${response.status}, retrying in ${Math.round(delayMs / 1e3)}s (attempt ${retryCount}/${MAX_RETRIES})`
98177
+ });
98178
+ try {
98179
+ await sleep(delayMs, signal);
98180
+ } catch {
98181
+ emitError(emit, { type: "error", message: "Aborted" });
98182
+ return { success: false, text: lastText, totalInputTokens, totalOutputTokens, cacheCreationTokens, cacheReadTokens, turns, messages, retryCount: totalRetryCount, truncationCount, toolExecutionMs, toolCount };
98183
+ }
98184
+ continue;
98185
+ }
98186
+ break;
98187
+ }
98188
+ if (!response.ok) {
98189
+ let errorBody;
98190
+ try {
98191
+ errorBody = await response.text();
98192
+ } catch {
98193
+ errorBody = response.statusText;
98194
+ }
98195
+ const message = `API error ${response.status}: ${errorBody}`;
98068
98196
  emitError(emit, { type: "error", message });
98069
98197
  return { success: false, text: lastText, totalInputTokens, totalOutputTokens, cacheCreationTokens, cacheReadTokens, turns, messages, retryCount: totalRetryCount, truncationCount, toolExecutionMs, toolCount };
98070
98198
  }
98071
- if (isRetryableStatus(response.status) && retryCount < MAX_RETRIES) {
98072
- retryCount++;
98073
- const delayMs = computeRetryDelayMs(response.headers.get("retry-after"), retryCount);
98074
- emitStatus(emit, {
98075
- type: "status",
98076
- phase: "retrying",
98077
- message: `API returned ${response.status}, retrying in ${Math.round(delayMs / 1e3)}s (attempt ${retryCount}/${MAX_RETRIES})`
98078
- });
98199
+ lastTier = response.headers.get("x-spacecode-tier") ?? lastTier;
98200
+ if (!response.body) {
98079
98201
  try {
98080
- await sleep(delayMs, signal);
98202
+ data = await response.json();
98081
98203
  } catch {
98082
- emitError(emit, { type: "error", message: "Aborted" });
98204
+ emitError(emit, { type: "error", message: "Failed to parse API response" });
98083
98205
  return { success: false, text: lastText, totalInputTokens, totalOutputTokens, cacheCreationTokens, cacheReadTokens, turns, messages, retryCount: totalRetryCount, truncationCount, toolExecutionMs, toolCount };
98084
98206
  }
98085
- continue;
98086
- }
98087
- break;
98088
- }
98089
- totalRetryCount += retryCount;
98090
- if (!response.ok) {
98091
- let errorBody;
98092
- try {
98093
- errorBody = await response.text();
98094
- } catch {
98095
- errorBody = response.statusText;
98207
+ for (const block of data.content) {
98208
+ if (block.type === "text" && block.text !== void 0) {
98209
+ emitText(emit, { type: "text", content: block.text });
98210
+ }
98211
+ }
98212
+ break;
98096
98213
  }
98097
- const message = `API error ${response.status}: ${errorBody}`;
98098
- emitError(emit, { type: "error", message });
98099
- return { success: false, text: lastText, totalInputTokens, totalOutputTokens, cacheCreationTokens, cacheReadTokens, turns, messages, retryCount: totalRetryCount, truncationCount, toolExecutionMs, toolCount };
98100
- }
98101
- let data;
98102
- if (response.body) {
98214
+ let attemptFirstSeq;
98215
+ const attemptEmit = (event) => {
98216
+ if (attemptFirstSeq === void 0) attemptFirstSeq = event.seq;
98217
+ emit(event);
98218
+ };
98103
98219
  try {
98104
- data = await parseStreamResponse(response.body, emit, signal);
98220
+ data = await parseStreamResponse(response.body, attemptEmit, signal);
98221
+ break;
98105
98222
  } catch (err) {
98223
+ if (err instanceof StreamIncompleteError && retryCount < MAX_RETRIES) {
98224
+ retryCount++;
98225
+ totalRetryCount++;
98226
+ const delayMs = computeRetryDelayMs(null, retryCount);
98227
+ emitStatus(emit, {
98228
+ type: "status",
98229
+ phase: "retrying",
98230
+ message: `Stream ended early (${err.reason}), retrying (attempt ${retryCount}/${MAX_RETRIES})`,
98231
+ ...attemptFirstSeq !== void 0 ? { discardFromSeq: attemptFirstSeq } : {}
98232
+ });
98233
+ try {
98234
+ await sleep(delayMs, signal);
98235
+ } catch {
98236
+ emitError(emit, { type: "error", message: "Aborted" });
98237
+ return { success: false, text: lastText, totalInputTokens, totalOutputTokens, cacheCreationTokens, cacheReadTokens, turns, messages, retryCount: totalRetryCount, truncationCount, toolExecutionMs, toolCount };
98238
+ }
98239
+ continue;
98240
+ }
98106
98241
  const message = err instanceof Error ? err.message : "Stream parse error";
98107
98242
  emitError(emit, { type: "error", message });
98108
98243
  return { success: false, text: lastText, totalInputTokens, totalOutputTokens, cacheCreationTokens, cacheReadTokens, turns, messages, retryCount: totalRetryCount, truncationCount, toolExecutionMs, toolCount };
98109
98244
  }
98110
- } else {
98111
- try {
98112
- data = await response.json();
98113
- } catch {
98114
- emitError(emit, { type: "error", message: "Failed to parse API response" });
98115
- return { success: false, text: lastText, totalInputTokens, totalOutputTokens, cacheCreationTokens, cacheReadTokens, turns, messages, retryCount: totalRetryCount, truncationCount, toolExecutionMs, toolCount };
98116
- }
98117
- for (const block of data.content) {
98118
- if (block.type === "text" && block.text !== void 0) {
98119
- emitText(emit, { type: "text", content: block.text });
98120
- }
98121
- }
98122
98245
  }
98123
98246
  totalInputTokens += data.usage.input_tokens;
98124
98247
  totalOutputTokens += data.usage.output_tokens;
@@ -98211,6 +98334,7 @@ var init_loop = __esm({
98211
98334
  init_stream();
98212
98335
  init_context_window();
98213
98336
  init_retry();
98337
+ init_request_headers();
98214
98338
  init_context_window();
98215
98339
  DEFAULT_MODEL = "claude-sonnet-4-6";
98216
98340
  DEFAULT_MAX_TURNS = 100;
@@ -98364,9 +98488,9 @@ function createFileTools(store) {
98364
98488
  readCache.clear();
98365
98489
  listCache.clear();
98366
98490
  }
98367
- function invalidatePath(path11) {
98368
- readCache.delete(path11);
98369
- const parent = path11.includes("/") ? path11.slice(0, path11.lastIndexOf("/") + 1) : "";
98491
+ function invalidatePath(path12) {
98492
+ readCache.delete(path12);
98493
+ const parent = path12.includes("/") ? path12.slice(0, path12.lastIndexOf("/") + 1) : "";
98370
98494
  listCache.delete(parent);
98371
98495
  listCache.delete("");
98372
98496
  listCache.delete(".");
@@ -98374,36 +98498,36 @@ function createFileTools(store) {
98374
98498
  }
98375
98499
  const handlers = {
98376
98500
  read_file: async (input) => {
98377
- const path11 = input.path;
98378
- const cached = readCache.get(path11);
98501
+ const path12 = input.path;
98502
+ const cached = readCache.get(path12);
98379
98503
  if (cached !== void 0) {
98380
98504
  return { output: cached };
98381
98505
  }
98382
- const content = await store.readFile(path11);
98506
+ const content = await store.readFile(path12);
98383
98507
  if (content === null) {
98384
- return { output: `File not found: ${path11}`, is_error: true };
98508
+ return { output: `File not found: ${path12}`, is_error: true };
98385
98509
  }
98386
- readCache.set(path11, content);
98510
+ readCache.set(path12, content);
98387
98511
  return { output: content };
98388
98512
  },
98389
98513
  write_file: async (input) => {
98390
- const path11 = input.path;
98514
+ const path12 = input.path;
98391
98515
  const content = input.content;
98392
- await store.writeFile(path11, content);
98393
- invalidatePath(path11);
98394
- readCache.set(path11, content);
98395
- return { output: `Written: ${path11}` };
98516
+ await store.writeFile(path12, content);
98517
+ invalidatePath(path12);
98518
+ readCache.set(path12, content);
98519
+ return { output: `Written: ${path12}` };
98396
98520
  },
98397
98521
  edit_file: async (input) => {
98398
- const path11 = input.path;
98522
+ const path12 = input.path;
98399
98523
  const oldStr = input.old_string;
98400
98524
  const newStr = input.new_string;
98401
- let content = readCache.get(path11);
98525
+ let content = readCache.get(path12);
98402
98526
  if (content === void 0) {
98403
- const stored = await store.readFile(path11);
98527
+ const stored = await store.readFile(path12);
98404
98528
  if (stored === null) {
98405
98529
  return {
98406
- output: `File not found: ${path11}. Did you read the file first?`,
98530
+ output: `File not found: ${path12}. Did you read the file first?`,
98407
98531
  is_error: true
98408
98532
  };
98409
98533
  }
@@ -98413,41 +98537,41 @@ function createFileTools(store) {
98413
98537
  if (lineNumbers.length === 0) {
98414
98538
  const lineCount = content.split("\n").length;
98415
98539
  return {
98416
- output: `old_string not found in ${path11}. The file has ${lineCount} lines. Did you read the file first?`,
98540
+ output: `old_string not found in ${path12}. The file has ${lineCount} lines. Did you read the file first?`,
98417
98541
  is_error: true
98418
98542
  };
98419
98543
  }
98420
98544
  if (lineNumbers.length > 1) {
98421
98545
  const locations = lineNumbers.map((ln) => ` - line ${ln}`).join("\n");
98422
98546
  return {
98423
- output: `old_string matches ${lineNumbers.length} locations in ${path11}:
98547
+ output: `old_string matches ${lineNumbers.length} locations in ${path12}:
98424
98548
  ${locations}
98425
98549
  Include more surrounding context to make old_string unique.`,
98426
98550
  is_error: true
98427
98551
  };
98428
98552
  }
98429
- const result = await store.editFile(path11, oldStr, newStr);
98553
+ const result = await store.editFile(path12, oldStr, newStr);
98430
98554
  if (!result.success) {
98431
98555
  return { output: result.error, is_error: true };
98432
98556
  }
98433
- invalidatePath(path11);
98434
- const updated = await store.readFile(path11);
98435
- if (updated !== null) readCache.set(path11, updated);
98436
- return { output: `Edited: ${path11}` };
98557
+ invalidatePath(path12);
98558
+ const updated = await store.readFile(path12);
98559
+ if (updated !== null) readCache.set(path12, updated);
98560
+ return { output: `Edited: ${path12}` };
98437
98561
  },
98438
98562
  list_directory: async (input) => {
98439
- const path11 = input.path;
98440
- const cached = listCache.get(path11);
98563
+ const path12 = input.path;
98564
+ const cached = listCache.get(path12);
98441
98565
  if (cached !== void 0) {
98442
98566
  if (cached.length === 0) {
98443
- return { output: `Empty or not found: ${path11}` };
98567
+ return { output: `Empty or not found: ${path12}` };
98444
98568
  }
98445
98569
  return { output: cached.join("\n") };
98446
98570
  }
98447
- const entries = await store.listDirectory(path11);
98448
- listCache.set(path11, entries);
98571
+ const entries = await store.listDirectory(path12);
98572
+ listCache.set(path12, entries);
98449
98573
  if (entries.length === 0) {
98450
- return { output: `Empty or not found: ${path11}` };
98574
+ return { output: `Empty or not found: ${path12}` };
98451
98575
  }
98452
98576
  return { output: entries.join("\n") };
98453
98577
  }
@@ -98784,7 +98908,7 @@ var init_host = __esm({
98784
98908
 
98785
98909
  // ../agent/src/host/local-host.ts
98786
98910
  import { execFile as execFile2 } from "node:child_process";
98787
- import { promises as fs2 } from "node:fs";
98911
+ import { promises as fs3 } from "node:fs";
98788
98912
  import * as path3 from "node:path";
98789
98913
  var LocalHost;
98790
98914
  var init_local_host = __esm({
@@ -98811,18 +98935,18 @@ var init_local_host = __esm({
98811
98935
  async resolve(p) {
98812
98936
  const abs = path3.resolve(this.root, p);
98813
98937
  if (!_LocalHost.inside(this.root, abs)) throw new Error(`Path escapes workspace root: ${p}`);
98814
- const realRoot = await fs2.realpath(this.root);
98938
+ const realRoot = await fs3.realpath(this.root);
98815
98939
  let probe = abs;
98816
98940
  for (; ; ) {
98817
98941
  try {
98818
- const real = await fs2.realpath(probe);
98942
+ const real = await fs3.realpath(probe);
98819
98943
  if (!_LocalHost.inside(realRoot, real)) {
98820
98944
  throw new Error(`Path escapes workspace root via symlink: ${p}`);
98821
98945
  }
98822
98946
  break;
98823
98947
  } catch (err) {
98824
98948
  if (err.code !== "ENOENT") throw err;
98825
- const st = await fs2.lstat(probe).catch((e) => {
98949
+ const st = await fs3.lstat(probe).catch((e) => {
98826
98950
  if (e.code === "ENOENT") return null;
98827
98951
  throw e;
98828
98952
  });
@@ -98836,7 +98960,7 @@ var init_local_host = __esm({
98836
98960
  }
98837
98961
  async readFile(p) {
98838
98962
  try {
98839
- return await fs2.readFile(await this.resolve(p), "utf8");
98963
+ return await fs3.readFile(await this.resolve(p), "utf8");
98840
98964
  } catch (err) {
98841
98965
  if (err.code === "ENOENT") return null;
98842
98966
  throw err;
@@ -98844,8 +98968,8 @@ var init_local_host = __esm({
98844
98968
  }
98845
98969
  async writeFile(p, content) {
98846
98970
  const abs = await this.resolve(p);
98847
- await fs2.mkdir(path3.dirname(abs), { recursive: true });
98848
- await fs2.writeFile(abs, content, "utf8");
98971
+ await fs3.mkdir(path3.dirname(abs), { recursive: true });
98972
+ await fs3.writeFile(abs, content, "utf8");
98849
98973
  }
98850
98974
  async editFile(p, oldStr, newStr) {
98851
98975
  const content = await this.readFile(p);
@@ -98860,7 +98984,7 @@ var init_local_host = __esm({
98860
98984
  }
98861
98985
  async listDirectory(p) {
98862
98986
  try {
98863
- const entries = await fs2.readdir(await this.resolve(p), { withFileTypes: true });
98987
+ const entries = await fs3.readdir(await this.resolve(p), { withFileTypes: true });
98864
98988
  return entries.map((e) => e.isDirectory() ? `${e.name}/` : e.name);
98865
98989
  } catch (err) {
98866
98990
  if (err.code === "ENOENT") return [];
@@ -99135,7 +99259,7 @@ var init_policy = __esm({
99135
99259
  });
99136
99260
 
99137
99261
  // ../agent/src/host/audit-log.ts
99138
- import { promises as fs3 } from "node:fs";
99262
+ import { promises as fs4 } from "node:fs";
99139
99263
  import * as path4 from "node:path";
99140
99264
  function truncate(e) {
99141
99265
  return e.subject.length > MAX_SUBJECT ? { ...e, subject: e.subject.slice(0, MAX_SUBJECT) + "...[truncated]" } : e;
@@ -99150,8 +99274,8 @@ var init_audit_log = __esm({
99150
99274
  this.file = file;
99151
99275
  }
99152
99276
  async record(entry) {
99153
- await fs3.mkdir(path4.dirname(this.file), { recursive: true });
99154
- await fs3.appendFile(this.file, JSON.stringify(truncate(entry)) + "\n", { mode: 384 });
99277
+ await fs4.mkdir(path4.dirname(this.file), { recursive: true });
99278
+ await fs4.appendFile(this.file, JSON.stringify(truncate(entry)) + "\n", { mode: 384 });
99155
99279
  }
99156
99280
  };
99157
99281
  }
@@ -99891,10 +100015,10 @@ async function readGitignore(cwd2) {
99891
100015
  }
99892
100016
  }
99893
100017
  function createNodeMentions(cwd2) {
99894
- const fs4 = createNodeMentionFS(cwd2);
100018
+ const fs6 = createNodeMentionFS(cwd2);
99895
100019
  return {
99896
100020
  async attach(text) {
99897
- const result = await resolveMentions(text, { cwd: cwd2, fs: fs4, ignored: await readGitignore(cwd2) });
100021
+ const result = await resolveMentions(text, { cwd: cwd2, fs: fs6, ignored: await readGitignore(cwd2) });
99898
100022
  return formatMentionPrompt(text, result);
99899
100023
  },
99900
100024
  async list() {
@@ -100351,7 +100475,10 @@ ${tools.map((t) => ` ${t.name}`).join("\n")}`);
100351
100475
  hasGitHubTools: toolset.hasGitHubTools
100352
100476
  }),
100353
100477
  tools: toolset.tools,
100354
- maxTurns: 100
100478
+ maxTurns: 100,
100479
+ // One conversation key for the whole saved session (also after --continue), so the gateway can keep a
100480
+ // conversation on one model. The id is only reserved here; nothing is saved until a turn commits.
100481
+ ...sessions ? { sessionId: sessionIdRef.current ??= sessions.newId() } : {}
100355
100482
  };
100356
100483
  const emit = (event) => {
100357
100484
  if (event.type === "error" && controller.signal.aborted) return;
@@ -100401,7 +100528,7 @@ ${tools.map((t) => ` ${t.name}`).join("\n")}`);
100401
100528
  }
100402
100529
  }, [repoName2, history, exit, permissions, notice, refuseAllConfirms, commitTurn, mentions, createToolset, sessions, projectRoot, persist, applySession, model, onViewTurns, onViewResume, setTodos]);
100403
100530
  const approxTokens = (0, import_react30.useMemo)(
100404
- () => events.reduce((n, e) => n + (e.type === "text" ? estimateTokens(e.content) : e.type === "text_delta" ? estimateTokens(e.text) : 0), 0),
100531
+ () => dropDiscardedEvents(events).reduce((n, e) => n + (e.type === "text" ? estimateTokens(e.content) : e.type === "text_delta" ? estimateTokens(e.text) : 0), 0),
100405
100532
  [events]
100406
100533
  );
100407
100534
  const stats = {
@@ -100460,6 +100587,7 @@ var init_useReplController = __esm({
100460
100587
  init_node_mentions();
100461
100588
  init_api_key();
100462
100589
  init_slash_commands();
100590
+ init_useEventAccumulator();
100463
100591
  apiUrl = () => process.env.API_PROXY_URL || "https://api.spacecode.app";
100464
100592
  }
100465
100593
  });
@@ -100701,6 +100829,31 @@ var init_ResumePicker = __esm({
100701
100829
  }
100702
100830
  });
100703
100831
 
100832
+ // src/components/Transcript.tsx
100833
+ function Transcript({ scroll, onMeasure, children }) {
100834
+ const viewportRef = (0, import_react33.useRef)(null);
100835
+ const contentRef = (0, import_react33.useRef)(null);
100836
+ const last = (0, import_react33.useRef)({ viewport: -1, content: -1 });
100837
+ (0, import_react33.useLayoutEffect)(() => {
100838
+ if (!viewportRef.current || !contentRef.current) return;
100839
+ const viewport = measure_element_default(viewportRef.current).height;
100840
+ const content = measure_element_default(contentRef.current).height;
100841
+ if (viewport === last.current.viewport && content === last.current.content) return;
100842
+ last.current = { viewport, content };
100843
+ onMeasure(viewport, content);
100844
+ });
100845
+ 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 }) });
100846
+ }
100847
+ var import_react33, import_jsx_runtime12;
100848
+ var init_Transcript = __esm({
100849
+ async "src/components/Transcript.tsx"() {
100850
+ "use strict";
100851
+ import_react33 = __toESM(require_react(), 1);
100852
+ await init_build2();
100853
+ import_jsx_runtime12 = __toESM(require_jsx_runtime(), 1);
100854
+ }
100855
+ });
100856
+
100704
100857
  // src/App.tsx
100705
100858
  var App_exports = {};
100706
100859
  __export(App_exports, {
@@ -100708,39 +100861,58 @@ __export(App_exports, {
100708
100861
  });
100709
100862
  import os4 from "node:os";
100710
100863
  import path10 from "node:path";
100711
- function App2({ repoName: repoName2, onboardingMode: onboardingMode2, launchCount: launchCount2, yolo: yolo2, history, sessions, resumeLatest: resumeLatest2, git: gitRunner, interactivePicker = true }) {
100712
- const promptHistory = (0, import_react33.useMemo)(
100864
+ function App2({ repoName: repoName2, onboardingMode: onboardingMode2, launchCount: launchCount2, yolo: yolo2, history, sessions, resumeLatest: resumeLatest2, git: gitRunner, interactivePicker = true, fullscreen: fullscreen2 = false }) {
100865
+ const promptHistory = (0, import_react34.useMemo)(
100713
100866
  () => history ?? new PromptHistory(createFileHistoryIO(path10.join(os4.homedir(), ".spacecode", "history"))),
100714
100867
  [history]
100715
100868
  );
100716
- const sessionStore = (0, import_react33.useMemo)(() => sessions ?? new SessionStore(path10.join(os4.homedir(), ".spacecode", "sessions")), [sessions]);
100717
- const runGit = (0, import_react33.useMemo)(() => gitRunner ?? createNodeGitRunner(process.cwd()), [gitRunner]);
100718
- const startedAtRef = (0, import_react33.useRef)(Date.now());
100719
- const [viewingRaw, setViewing] = (0, import_react33.useState)(false);
100720
- const escViewRef = (0, import_react33.useRef)(false);
100721
- const escSwallowRef = (0, import_react33.useRef)(false);
100722
- const swallowEsc = (0, import_react33.useCallback)(() => {
100869
+ const sessionStore = (0, import_react34.useMemo)(() => sessions ?? new SessionStore(path10.join(os4.homedir(), ".spacecode", "sessions")), [sessions]);
100870
+ const runGit = (0, import_react34.useMemo)(() => gitRunner ?? createNodeGitRunner(process.cwd()), [gitRunner]);
100871
+ const startedAtRef = (0, import_react34.useRef)(Date.now());
100872
+ const [viewingRaw, setViewing] = (0, import_react34.useState)(false);
100873
+ const escViewRef = (0, import_react34.useRef)(false);
100874
+ const escSwallowRef = (0, import_react34.useRef)(false);
100875
+ const swallowEsc = (0, import_react34.useCallback)(() => {
100723
100876
  escSwallowRef.current = true;
100724
100877
  setTimeout(() => {
100725
100878
  escSwallowRef.current = false;
100726
100879
  }, 0);
100727
100880
  }, []);
100728
- const isEscOwned = (0, import_react33.useCallback)(() => escViewRef.current || escSwallowRef.current, []);
100729
- const openViewer = (0, import_react33.useCallback)(() => setViewing(true), []);
100881
+ const isEscOwned = (0, import_react34.useCallback)(() => escViewRef.current || escSwallowRef.current, []);
100882
+ const openViewer = (0, import_react34.useCallback)(() => setViewing(true), []);
100730
100883
  const { isRawModeSupported } = use_stdin_default();
100731
- const [resumeFound, setResumeFound] = (0, import_react33.useState)(null);
100732
- const openResume = (0, import_react33.useCallback)((found) => setResumeFound(found), []);
100884
+ const [resumeFound, setResumeFound] = (0, import_react34.useState)(null);
100885
+ const openResume = (0, import_react34.useCallback)((found) => setResumeFound(found), []);
100733
100886
  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 });
100734
100887
  const { columns, rows } = useTerminalSize();
100735
100888
  const viewing = viewingRaw && !pending;
100736
100889
  const picking = resumeFound !== null && !pending;
100737
- const liveSteps = (0, import_react33.useMemo)(() => stepsOfEvents(events), [events]);
100738
- const [focusId, setFocusId] = (0, import_react33.useState)(null);
100739
- const [openId, setOpenId] = (0, import_react33.useState)(null);
100890
+ const [scroll, setScroll] = (0, import_react34.useState)(0);
100891
+ const measured = (0, import_react34.useRef)({ viewport: 0, content: 0 });
100892
+ const onMeasure = (0, import_react34.useCallback)((viewport, content) => {
100893
+ if (viewport <= 0) return;
100894
+ const prev = measured.current;
100895
+ measured.current = { viewport, content };
100896
+ setScroll((s) => s === 0 ? 0 : Math.min(Math.max(0, content - viewport), s + Math.max(0, content - prev.content)));
100897
+ }, []);
100898
+ const pageBy = (0, import_react34.useCallback)((dir) => {
100899
+ const { viewport, content } = measured.current;
100900
+ setScroll((s) => Math.min(Math.max(0, content - viewport), Math.max(0, s + dir * Math.max(1, viewport - 2))));
100901
+ }, []);
100902
+ use_input_default((_input, key) => {
100903
+ if (key.pageUp) pageBy(1);
100904
+ else if (key.pageDown) pageBy(-1);
100905
+ }, { isActive: fullscreen2 && Boolean(isRawModeSupported) && !viewing && !picking });
100906
+ (0, import_react34.useEffect)(() => {
100907
+ if (pending || isRunning) setScroll(0);
100908
+ }, [pending, isRunning]);
100909
+ const liveSteps = (0, import_react34.useMemo)(() => stepsOfEvents(events), [events]);
100910
+ const [focusId, setFocusId] = (0, import_react34.useState)(null);
100911
+ const [openId, setOpenId] = (0, import_react34.useState)(null);
100740
100912
  const focusIdx = focusId === null ? -1 : liveSteps.findIndex((r) => r.id === focusId);
100741
100913
  const focusing = focusIdx >= 0 && !viewing && !picking && !pending;
100742
100914
  escViewRef.current = focusing || viewing || picking;
100743
- const enterFocus = (0, import_react33.useCallback)(() => {
100915
+ const enterFocus = (0, import_react34.useCallback)(() => {
100744
100916
  if (liveSteps.length > 0) setFocusId(liveSteps[liveSteps.length - 1].id);
100745
100917
  }, [liveSteps]);
100746
100918
  use_input_default((input, key) => {
@@ -100762,11 +100934,11 @@ function App2({ repoName: repoName2, onboardingMode: onboardingMode2, launchCoun
100762
100934
  if (key.ctrl && input === "o") setViewing(true);
100763
100935
  }, { isActive: Boolean(isRawModeSupported) && !viewing && !picking && !pending });
100764
100936
  const waitingStep = pending ? findBlockedStep(liveSteps, pending.req) : void 0;
100765
- const promptNode = pending ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(PermissionPrompt, { req: pending.req, onDecide: pending.resolve }, pending.id) : null;
100766
- const viewerTurns = (0, import_react33.useMemo)(() => [...replayed, ...turns], [replayed, turns]);
100767
- const turnSteps = (0, import_react33.useMemo)(() => viewing ? stepsOfTurns(viewerTurns) : /* @__PURE__ */ new Map(), [viewing, viewerTurns]);
100768
- const [gitState, setGitState] = (0, import_react33.useState)(null);
100769
- (0, import_react33.useEffect)(() => {
100937
+ const promptNode = pending ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PermissionPrompt, { req: pending.req, onDecide: pending.resolve }, pending.id) : null;
100938
+ const viewerTurns = (0, import_react34.useMemo)(() => [...replayed, ...turns], [replayed, turns]);
100939
+ const turnSteps = (0, import_react34.useMemo)(() => viewing ? stepsOfTurns(viewerTurns) : /* @__PURE__ */ new Map(), [viewing, viewerTurns]);
100940
+ const [gitState, setGitState] = (0, import_react34.useState)(null);
100941
+ (0, import_react34.useEffect)(() => {
100770
100942
  let live = true;
100771
100943
  void readGitState(runGit).then((g2) => {
100772
100944
  if (live) setGitState(g2);
@@ -100776,20 +100948,57 @@ function App2({ repoName: repoName2, onboardingMode: onboardingMode2, launchCoun
100776
100948
  };
100777
100949
  }, [runGit, turns.length]);
100778
100950
  const footer = formatFooter({ mode, contextPct: stats.contextPct, costUsd: stats.costUsd, model: stats.model, columns });
100779
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Box_default, { flexDirection: "column", children: [
100780
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Header, { project: repoName2 ?? path10.basename(process.cwd()), git: gitState, turns: turns.length, elapsedMs: Date.now() - startedAtRef.current, columns }),
100781
- 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)),
100782
- /* @__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: [
100783
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Text, { ...paint("secondary"), children: [
100951
+ const turnNode = (turn) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TurnBlock, { turn }, turn.id);
100952
+ if (fullscreen2) {
100953
+ const hidden = viewing || picking;
100954
+ const unicode = activeGlyphs().rail === "\u2502";
100955
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Box_default, { flexDirection: "column", height: Math.max(rows - 1, 5), children: [
100956
+ viewing && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TurnViewer, { turns: viewerTurns, steps: turnSteps, rows: rows - 2, columns, onClose: () => setViewing(false), onEscape: swallowEsc }),
100957
+ 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 }),
100958
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Box_default, { flexDirection: "column", flexGrow: 1, display: hidden ? "none" : "flex", children: [
100959
+ /* @__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 }) }),
100960
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Transcript, { scroll, onMeasure, children: [
100961
+ 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)),
100962
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(WelcomeBanner, { repoName: repoName2, onboardingMode: onboardingMode2, launchCount: launchCount2 }),
100963
+ turns.map(turnNode),
100964
+ livePrompt !== null && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Text, { ...paint("secondary"), children: [
100965
+ "> ",
100966
+ livePrompt
100967
+ ] }),
100968
+ /* @__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 }),
100969
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TodoChecklist, { todos }),
100970
+ pending && !waitingStep && promptNode
100971
+ ] }),
100972
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Box_default, { flexDirection: "column", flexShrink: 0, children: [
100973
+ scroll > 0 && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Text, { ...paint("needsYou"), children: [
100974
+ unicode ? "\u2193" : "v",
100975
+ " scrolled up ",
100976
+ scroll,
100977
+ " lines - PgDn for newer output"
100978
+ ] }),
100979
+ isRunning && !pending && stats.elapsedMs !== null && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { ...paint("secondary"), children: formatThinking(stats.elapsedMs, stats.approxTokens, unicode) }),
100980
+ 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" }),
100981
+ /* @__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) }),
100982
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { ...footer.level === "critical" ? paint("delete") : footer.level === "warn" ? paint("needsYou") : paint("secondary"), children: footer.text }),
100983
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { ...paint("secondary"), children: formatHints({ running: isRunning, asking: Boolean(pending), columns }, activeGlyphs().sep) })
100984
+ ] })
100985
+ ] })
100986
+ ] });
100987
+ }
100988
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Box_default, { flexDirection: "column", children: [
100989
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Header, { project: repoName2 ?? path10.basename(process.cwd()), git: gitState, turns: turns.length, elapsedMs: Date.now() - startedAtRef.current, columns }),
100990
+ 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)),
100991
+ /* @__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: [
100992
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Text, { ...paint("secondary"), children: [
100784
100993
  "> ",
100785
100994
  turn.prompt
100786
100995
  ] }),
100787
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(EventRenderer, { events: turn.events, promptSaved: turn.retained }),
100788
- turn.interrupted && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { ...paint("needsYou"), children: "Interrupted" }),
100789
- turn.summary && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { ...paint("secondary"), children: turn.summary })
100996
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(EventRenderer, { events: turn.events, promptSaved: turn.retained }),
100997
+ turn.interrupted && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { ...paint("needsYou"), children: "Interrupted" }),
100998
+ turn.summary && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { ...paint("secondary"), children: turn.summary })
100790
100999
  ] }, turn.id) }),
100791
- viewing && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TurnViewer, { turns: viewerTurns, steps: turnSteps, rows, columns, onClose: () => setViewing(false), onEscape: swallowEsc }),
100792
- picking && resumeFound && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
101000
+ viewing && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TurnViewer, { turns: viewerTurns, steps: turnSteps, rows, columns, onClose: () => setViewing(false), onEscape: swallowEsc }),
101001
+ picking && resumeFound && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
100793
101002
  ResumePicker,
100794
101003
  {
100795
101004
  sessions: resumeFound.sessions,
@@ -100805,27 +101014,27 @@ function App2({ repoName: repoName2, onboardingMode: onboardingMode2, launchCoun
100805
101014
  onEscape: swallowEsc
100806
101015
  }
100807
101016
  ),
100808
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Box_default, { flexDirection: "column", display: viewing || picking ? "none" : "flex", children: [
100809
- livePrompt !== null && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Text, { ...paint("secondary"), children: [
101017
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Box_default, { flexDirection: "column", display: viewing || picking ? "none" : "flex", children: [
101018
+ livePrompt !== null && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Text, { ...paint("secondary"), children: [
100810
101019
  "> ",
100811
101020
  livePrompt
100812
101021
  ] }),
100813
- /* @__PURE__ */ (0, import_jsx_runtime12.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 }),
100814
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(TodoChecklist, { todos }),
101022
+ /* @__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 }),
101023
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(TodoChecklist, { todos }),
100815
101024
  pending && !waitingStep && promptNode,
100816
- isRunning && !pending && stats.elapsedMs !== null && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { ...paint("secondary"), children: formatThinking(stats.elapsedMs, stats.approxTokens, activeGlyphs().rail === "\u2502") }),
100817
- 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" }),
100818
- /* @__PURE__ */ (0, import_jsx_runtime12.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) }),
100819
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { ...footer.level === "critical" ? paint("delete") : footer.level === "warn" ? paint("needsYou") : paint("secondary"), children: footer.text }),
100820
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { ...paint("secondary"), children: formatHints({ running: isRunning, asking: Boolean(pending), columns }, activeGlyphs().sep) })
101025
+ isRunning && !pending && stats.elapsedMs !== null && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { ...paint("secondary"), children: formatThinking(stats.elapsedMs, stats.approxTokens, activeGlyphs().rail === "\u2502") }),
101026
+ 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" }),
101027
+ /* @__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) }),
101028
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { ...footer.level === "critical" ? paint("delete") : footer.level === "warn" ? paint("needsYou") : paint("secondary"), children: footer.text }),
101029
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { ...paint("secondary"), children: formatHints({ running: isRunning, asking: Boolean(pending), columns }, activeGlyphs().sep) })
100821
101030
  ] })
100822
101031
  ] });
100823
101032
  }
100824
- var import_react33, import_jsx_runtime12, BANNER;
101033
+ var import_react34, import_jsx_runtime13, BANNER, TurnBlock;
100825
101034
  var init_App2 = __esm({
100826
101035
  async "src/App.tsx"() {
100827
101036
  "use strict";
100828
- import_react33 = __toESM(require_react(), 1);
101037
+ import_react34 = __toESM(require_react(), 1);
100829
101038
  await init_build2();
100830
101039
  await init_WelcomeBanner();
100831
101040
  await init_Header();
@@ -100848,9 +101057,21 @@ var init_App2 = __esm({
100848
101057
  init_theme();
100849
101058
  await init_TurnViewer();
100850
101059
  await init_ResumePicker();
101060
+ await init_Transcript();
100851
101061
  init_step_view();
100852
- import_jsx_runtime12 = __toESM(require_jsx_runtime(), 1);
101062
+ import_jsx_runtime13 = __toESM(require_jsx_runtime(), 1);
100853
101063
  BANNER = /* @__PURE__ */ Symbol("welcome-banner");
101064
+ TurnBlock = import_react34.default.memo(function TurnBlock2({ turn }) {
101065
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Box_default, { flexDirection: "column", children: [
101066
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Text, { ...paint("secondary"), children: [
101067
+ "> ",
101068
+ turn.prompt
101069
+ ] }),
101070
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(EventRenderer, { events: turn.events, promptSaved: turn.retained }),
101071
+ turn.interrupted && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { ...paint("needsYou"), children: "Interrupted" }),
101072
+ turn.summary && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { ...paint("secondary"), children: turn.summary })
101073
+ ] });
101074
+ });
100854
101075
  }
100855
101076
  });
100856
101077
 
@@ -100858,6 +101079,12 @@ var init_App2 = __esm({
100858
101079
  init_color_policy();
100859
101080
  applyColorPolicy(process.env, Boolean(process.stdout.isTTY));
100860
101081
 
101082
+ // src/index.tsx
101083
+ import os5 from "node:os";
101084
+ import path11 from "node:path";
101085
+ import fs5 from "node:fs";
101086
+ import util2 from "node:util";
101087
+
100861
101088
  // src/render/terminal-env.ts
100862
101089
  function hideCiVariables(env3, stdoutIsTTY) {
100863
101090
  if (!stdoutIsTTY || env3.CI !== void 0) return () => {
@@ -100869,8 +101096,75 @@ function hideCiVariables(env3, stdoutIsTTY) {
100869
101096
  };
100870
101097
  }
100871
101098
 
101099
+ // src/fullscreen.ts
101100
+ import fs from "node:fs";
101101
+ import util from "node:util";
101102
+ var ENTER = "\x1B[?1049h\x1B[2J\x1B[H\x1B[?25l";
101103
+ var LEAVE = "\x1B[?25h\x1B[?1049l";
101104
+ function shouldUseFullscreen(env3, stdout, stdinIsTTY) {
101105
+ if (!stdout.isTTY || !stdinIsTTY) return false;
101106
+ if (env3.SPACECODE_INLINE && env3.SPACECODE_INLINE !== "0") return false;
101107
+ return env3.TERM !== "dumb";
101108
+ }
101109
+ function enterFullscreen(out, proc, stderr = process.stderr) {
101110
+ let active2 = true;
101111
+ const cleanups = [];
101112
+ const leave = () => {
101113
+ if (!active2) return;
101114
+ active2 = false;
101115
+ for (const fn of cleanups) fn();
101116
+ out.write(LEAVE);
101117
+ };
101118
+ const fatal = (err) => {
101119
+ leave();
101120
+ stderr.write(`${util.inspect(err)}
101121
+ `);
101122
+ proc.exit(1);
101123
+ };
101124
+ out.write(ENTER);
101125
+ proc.on("exit", leave);
101126
+ for (const [sig, code] of [["SIGINT", 130], ["SIGTERM", 143], ["SIGHUP", 129]]) {
101127
+ proc.on(sig, () => {
101128
+ leave();
101129
+ proc.exit(code);
101130
+ });
101131
+ }
101132
+ proc.on("uncaughtException", fatal);
101133
+ proc.on("unhandledRejection", fatal);
101134
+ return { leave, onLeave: (fn) => {
101135
+ cleanups.push(fn);
101136
+ } };
101137
+ }
101138
+ function redirectConsole(file) {
101139
+ const original = { log: console.log, info: console.info, warn: console.warn, error: console.error, debug: console.debug };
101140
+ const write = (level) => (...args) => {
101141
+ try {
101142
+ fs.appendFileSync(file, `${(/* @__PURE__ */ new Date()).toISOString()} ${level} ${util.format(...args)}
101143
+ `, { mode: 384 });
101144
+ } catch (err) {
101145
+ process.stderr.write(`[spacecode] could not write ${file}: ${String(err)}
101146
+ `);
101147
+ }
101148
+ };
101149
+ console.log = write("log");
101150
+ console.info = write("info");
101151
+ console.warn = write("warn");
101152
+ console.error = write("error");
101153
+ console.debug = write("debug");
101154
+ return () => Object.assign(console, original);
101155
+ }
101156
+ function clearOnResize(stdout) {
101157
+ const clear = () => {
101158
+ stdout.write("\x1B[2J\x1B[H");
101159
+ };
101160
+ stdout.prependListener("resize", clear);
101161
+ return () => {
101162
+ stdout.off("resize", clear);
101163
+ };
101164
+ }
101165
+
100872
101166
  // src/index.tsx
100873
- var import_jsx_runtime13 = __toESM(require_jsx_runtime(), 1);
101167
+ var import_jsx_runtime14 = __toESM(require_jsx_runtime(), 1);
100874
101168
  var repoName = process.env.REPO_NAME || process.cwd().split("/").pop() || void 0;
100875
101169
  var validModes = ["guest", "new_project", "existing_repo"];
100876
101170
  var rawMode = process.env.ONBOARDING_MODE;
@@ -100887,7 +101181,34 @@ try {
100887
101181
  } finally {
100888
101182
  restoreCiVariables();
100889
101183
  }
100890
- render2(/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(App3, { repoName, onboardingMode, launchCount, yolo, resumeLatest, interactivePicker: Boolean(process.stdout.isTTY) }));
101184
+ var fullscreen = shouldUseFullscreen(process.env, process.stdout, Boolean(process.stdin.isTTY));
101185
+ var session;
101186
+ if (fullscreen) {
101187
+ const dir = path11.join(os5.homedir(), ".spacecode");
101188
+ fs5.mkdirSync(dir, { recursive: true });
101189
+ const restoreConsole = redirectConsole(path11.join(dir, "repl.log"));
101190
+ session = enterFullscreen(process.stdout, process);
101191
+ session.onLeave(restoreConsole);
101192
+ session.onLeave(clearOnResize(process.stdout));
101193
+ }
101194
+ var app = render2(
101195
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(App3, { repoName, onboardingMode, launchCount, yolo, resumeLatest, interactivePicker: Boolean(process.stdout.isTTY), fullscreen }),
101196
+ { patchConsole: !fullscreen }
101197
+ );
101198
+ if (session) {
101199
+ try {
101200
+ await app.waitUntilExit();
101201
+ session.leave();
101202
+ process.stdout.write("Session saved. Resume it with `spacecode --continue` or `/resume`.\n");
101203
+ } catch (err) {
101204
+ session.leave();
101205
+ process.stderr.write(`${util2.inspect(err)}
101206
+ `);
101207
+ process.exitCode = 1;
101208
+ } finally {
101209
+ session.leave();
101210
+ }
101211
+ }
100891
101212
  /*! Bundled license information:
100892
101213
 
100893
101214
  react/cjs/react.production.min.js: