spacecode 2.0.2 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/repl.mjs +1715 -582
- package/package.json +1 -1
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
|
|
1399
|
+
function useState10(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
|
|
1407
|
+
function useRef4(initialValue) {
|
|
1408
1408
|
var dispatcher = resolveDispatcher();
|
|
1409
1409
|
return dispatcher.useRef(initialValue);
|
|
1410
1410
|
}
|
|
1411
|
-
function
|
|
1411
|
+
function useEffect9(create2, deps) {
|
|
1412
1412
|
var dispatcher = resolveDispatcher();
|
|
1413
1413
|
return dispatcher.useEffect(create2, deps);
|
|
1414
1414
|
}
|
|
@@ -1420,11 +1420,11 @@ var require_react_development = __commonJS({
|
|
|
1420
1420
|
var dispatcher = resolveDispatcher();
|
|
1421
1421
|
return dispatcher.useLayoutEffect(create2, deps);
|
|
1422
1422
|
}
|
|
1423
|
-
function
|
|
1423
|
+
function useCallback4(callback, deps) {
|
|
1424
1424
|
var dispatcher = resolveDispatcher();
|
|
1425
1425
|
return dispatcher.useCallback(callback, deps);
|
|
1426
1426
|
}
|
|
1427
|
-
function
|
|
1427
|
+
function useMemo8(create2, deps) {
|
|
1428
1428
|
var dispatcher = resolveDispatcher();
|
|
1429
1429
|
return dispatcher.useMemo(create2, deps);
|
|
1430
1430
|
}
|
|
@@ -2187,19 +2187,19 @@ var require_react_development = __commonJS({
|
|
|
2187
2187
|
exports.memo = memo;
|
|
2188
2188
|
exports.startTransition = startTransition;
|
|
2189
2189
|
exports.unstable_act = act;
|
|
2190
|
-
exports.useCallback =
|
|
2190
|
+
exports.useCallback = useCallback4;
|
|
2191
2191
|
exports.useContext = useContext7;
|
|
2192
2192
|
exports.useDebugValue = useDebugValue;
|
|
2193
2193
|
exports.useDeferredValue = useDeferredValue;
|
|
2194
|
-
exports.useEffect =
|
|
2194
|
+
exports.useEffect = useEffect9;
|
|
2195
2195
|
exports.useId = useId;
|
|
2196
2196
|
exports.useImperativeHandle = useImperativeHandle;
|
|
2197
2197
|
exports.useInsertionEffect = useInsertionEffect;
|
|
2198
2198
|
exports.useLayoutEffect = useLayoutEffect2;
|
|
2199
|
-
exports.useMemo =
|
|
2199
|
+
exports.useMemo = useMemo8;
|
|
2200
2200
|
exports.useReducer = useReducer;
|
|
2201
|
-
exports.useRef =
|
|
2202
|
-
exports.useState =
|
|
2201
|
+
exports.useRef = useRef4;
|
|
2202
|
+
exports.useState = useState10;
|
|
2203
2203
|
exports.useSyncExternalStore = useSyncExternalStore;
|
|
2204
2204
|
exports.useTransition = useTransition;
|
|
2205
2205
|
exports.version = ReactVersion;
|
|
@@ -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
|
|
2258
|
+
var React19 = 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 =
|
|
2284
|
+
var ReactSharedInternals = React19.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
|
|
2285
2285
|
function error(format) {
|
|
2286
2286
|
{
|
|
2287
2287
|
{
|
|
@@ -3131,11 +3131,11 @@ var require_react_jsx_runtime_development = __commonJS({
|
|
|
3131
3131
|
return jsxWithValidation(type, props, key, false);
|
|
3132
3132
|
}
|
|
3133
3133
|
}
|
|
3134
|
-
var
|
|
3135
|
-
var
|
|
3134
|
+
var jsx12 = jsxWithValidationDynamic;
|
|
3135
|
+
var jsxs12 = jsxWithValidationStatic;
|
|
3136
3136
|
exports.Fragment = REACT_FRAGMENT_TYPE;
|
|
3137
|
-
exports.jsx =
|
|
3138
|
-
exports.jsxs =
|
|
3137
|
+
exports.jsx = jsx12;
|
|
3138
|
+
exports.jsxs = jsxs12;
|
|
3139
3139
|
})();
|
|
3140
3140
|
}
|
|
3141
3141
|
}
|
|
@@ -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
|
|
10826
|
+
var React19 = require_react();
|
|
10827
10827
|
var Scheduler = require_scheduler();
|
|
10828
|
-
var ReactSharedInternals =
|
|
10828
|
+
var ReactSharedInternals = React19.__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,
|
|
25706
|
-
var key =
|
|
25705
|
+
var copyWithDeleteImpl = function(obj, path11, index2) {
|
|
25706
|
+
var key = path11[index2];
|
|
25707
25707
|
var updated = isArray(obj) ? obj.slice() : assign({}, obj);
|
|
25708
|
-
if (index2 + 1 ===
|
|
25708
|
+
if (index2 + 1 === path11.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],
|
|
25716
|
+
updated[key] = copyWithDeleteImpl(obj[key], path11, index2 + 1);
|
|
25717
25717
|
return updated;
|
|
25718
25718
|
};
|
|
25719
|
-
var copyWithDelete = function(obj,
|
|
25720
|
-
return copyWithDeleteImpl(obj,
|
|
25719
|
+
var copyWithDelete = function(obj, path11) {
|
|
25720
|
+
return copyWithDeleteImpl(obj, path11, 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,
|
|
25759
|
-
if (index2 >=
|
|
25758
|
+
var copyWithSetImpl = function(obj, path11, index2, value) {
|
|
25759
|
+
if (index2 >= path11.length) {
|
|
25760
25760
|
return value;
|
|
25761
25761
|
}
|
|
25762
|
-
var key =
|
|
25762
|
+
var key = path11[index2];
|
|
25763
25763
|
var updated = isArray(obj) ? obj.slice() : assign({}, obj);
|
|
25764
|
-
updated[key] = copyWithSetImpl(obj[key],
|
|
25764
|
+
updated[key] = copyWithSetImpl(obj[key], path11, index2 + 1, value);
|
|
25765
25765
|
return updated;
|
|
25766
25766
|
};
|
|
25767
|
-
var copyWithSet = function(obj,
|
|
25768
|
-
return copyWithSetImpl(obj,
|
|
25767
|
+
var copyWithSet = function(obj, path11, value) {
|
|
25768
|
+
return copyWithSetImpl(obj, path11, 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,
|
|
25778
|
+
overrideHookState = function(fiber, id, path11, value) {
|
|
25779
25779
|
var hook = findHook(fiber, id);
|
|
25780
25780
|
if (hook !== null) {
|
|
25781
|
-
var newState = copyWithSet(hook.memoizedState,
|
|
25781
|
+
var newState = copyWithSet(hook.memoizedState, path11, 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,
|
|
25791
|
+
overrideHookStateDeletePath = function(fiber, id, path11) {
|
|
25792
25792
|
var hook = findHook(fiber, id);
|
|
25793
25793
|
if (hook !== null) {
|
|
25794
|
-
var newState = copyWithDelete(hook.memoizedState,
|
|
25794
|
+
var newState = copyWithDelete(hook.memoizedState, path11);
|
|
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,
|
|
25818
|
-
fiber.pendingProps = copyWithSet(fiber.memoizedProps,
|
|
25817
|
+
overrideProps = function(fiber, path11, value) {
|
|
25818
|
+
fiber.pendingProps = copyWithSet(fiber.memoizedProps, path11, 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,
|
|
25828
|
-
fiber.pendingProps = copyWithDelete(fiber.memoizedProps,
|
|
25827
|
+
overridePropsDeletePath = function(fiber, path11) {
|
|
25828
|
+
fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path11);
|
|
25829
25829
|
if (fiber.alternate) {
|
|
25830
25830
|
fiber.alternate.pendingProps = fiber.pendingProps;
|
|
25831
25831
|
}
|
|
@@ -28903,24 +28903,24 @@ var require_sender = __commonJS({
|
|
|
28903
28903
|
* @public
|
|
28904
28904
|
*/
|
|
28905
28905
|
ping(data, mask, cb) {
|
|
28906
|
-
let
|
|
28906
|
+
let byteLength2;
|
|
28907
28907
|
let readOnly;
|
|
28908
28908
|
if (typeof data === "string") {
|
|
28909
|
-
|
|
28909
|
+
byteLength2 = Buffer.byteLength(data);
|
|
28910
28910
|
readOnly = false;
|
|
28911
28911
|
} else if (isBlob(data)) {
|
|
28912
|
-
|
|
28912
|
+
byteLength2 = data.size;
|
|
28913
28913
|
readOnly = false;
|
|
28914
28914
|
} else {
|
|
28915
28915
|
data = toBuffer(data);
|
|
28916
|
-
|
|
28916
|
+
byteLength2 = data.length;
|
|
28917
28917
|
readOnly = toBuffer.readOnly;
|
|
28918
28918
|
}
|
|
28919
|
-
if (
|
|
28919
|
+
if (byteLength2 > 125) {
|
|
28920
28920
|
throw new RangeError("The data size must not be greater than 125 bytes");
|
|
28921
28921
|
}
|
|
28922
28922
|
const options = {
|
|
28923
|
-
[kByteLength]:
|
|
28923
|
+
[kByteLength]: byteLength2,
|
|
28924
28924
|
fin: true,
|
|
28925
28925
|
generateMask: this._generateMask,
|
|
28926
28926
|
mask,
|
|
@@ -28950,24 +28950,24 @@ var require_sender = __commonJS({
|
|
|
28950
28950
|
* @public
|
|
28951
28951
|
*/
|
|
28952
28952
|
pong(data, mask, cb) {
|
|
28953
|
-
let
|
|
28953
|
+
let byteLength2;
|
|
28954
28954
|
let readOnly;
|
|
28955
28955
|
if (typeof data === "string") {
|
|
28956
|
-
|
|
28956
|
+
byteLength2 = Buffer.byteLength(data);
|
|
28957
28957
|
readOnly = false;
|
|
28958
28958
|
} else if (isBlob(data)) {
|
|
28959
|
-
|
|
28959
|
+
byteLength2 = data.size;
|
|
28960
28960
|
readOnly = false;
|
|
28961
28961
|
} else {
|
|
28962
28962
|
data = toBuffer(data);
|
|
28963
|
-
|
|
28963
|
+
byteLength2 = data.length;
|
|
28964
28964
|
readOnly = toBuffer.readOnly;
|
|
28965
28965
|
}
|
|
28966
|
-
if (
|
|
28966
|
+
if (byteLength2 > 125) {
|
|
28967
28967
|
throw new RangeError("The data size must not be greater than 125 bytes");
|
|
28968
28968
|
}
|
|
28969
28969
|
const options = {
|
|
28970
|
-
[kByteLength]:
|
|
28970
|
+
[kByteLength]: byteLength2,
|
|
28971
28971
|
fin: true,
|
|
28972
28972
|
generateMask: this._generateMask,
|
|
28973
28973
|
mask,
|
|
@@ -29008,23 +29008,23 @@ var require_sender = __commonJS({
|
|
|
29008
29008
|
const perMessageDeflate = this._extensions[PerMessageDeflate2.extensionName];
|
|
29009
29009
|
let opcode = options.binary ? 2 : 1;
|
|
29010
29010
|
let rsv1 = options.compress;
|
|
29011
|
-
let
|
|
29011
|
+
let byteLength2;
|
|
29012
29012
|
let readOnly;
|
|
29013
29013
|
if (typeof data === "string") {
|
|
29014
|
-
|
|
29014
|
+
byteLength2 = Buffer.byteLength(data);
|
|
29015
29015
|
readOnly = false;
|
|
29016
29016
|
} else if (isBlob(data)) {
|
|
29017
|
-
|
|
29017
|
+
byteLength2 = data.size;
|
|
29018
29018
|
readOnly = false;
|
|
29019
29019
|
} else {
|
|
29020
29020
|
data = toBuffer(data);
|
|
29021
|
-
|
|
29021
|
+
byteLength2 = data.length;
|
|
29022
29022
|
readOnly = toBuffer.readOnly;
|
|
29023
29023
|
}
|
|
29024
29024
|
if (this._firstFragment) {
|
|
29025
29025
|
this._firstFragment = false;
|
|
29026
29026
|
if (rsv1 && perMessageDeflate && perMessageDeflate.params[perMessageDeflate._isServer ? "server_no_context_takeover" : "client_no_context_takeover"]) {
|
|
29027
|
-
rsv1 =
|
|
29027
|
+
rsv1 = byteLength2 >= perMessageDeflate._threshold;
|
|
29028
29028
|
}
|
|
29029
29029
|
this._compress = rsv1;
|
|
29030
29030
|
} else {
|
|
@@ -29033,7 +29033,7 @@ var require_sender = __commonJS({
|
|
|
29033
29033
|
}
|
|
29034
29034
|
if (options.fin) this._firstFragment = true;
|
|
29035
29035
|
const opts = {
|
|
29036
|
-
[kByteLength]:
|
|
29036
|
+
[kByteLength]: byteLength2,
|
|
29037
29037
|
fin: options.fin,
|
|
29038
29038
|
generateMask: this._generateMask,
|
|
29039
29039
|
mask: options.mask,
|
|
@@ -30543,7 +30543,7 @@ var require_stream = __commonJS({
|
|
|
30543
30543
|
};
|
|
30544
30544
|
duplex._final = function(callback) {
|
|
30545
30545
|
if (ws.readyState === ws.CONNECTING) {
|
|
30546
|
-
ws.once("open", function
|
|
30546
|
+
ws.once("open", function open3() {
|
|
30547
30547
|
duplex._final(callback);
|
|
30548
30548
|
});
|
|
30549
30549
|
return;
|
|
@@ -30564,7 +30564,7 @@ var require_stream = __commonJS({
|
|
|
30564
30564
|
};
|
|
30565
30565
|
duplex._write = function(chunk, encoding, callback) {
|
|
30566
30566
|
if (ws.readyState === ws.CONNECTING) {
|
|
30567
|
-
ws.once("open", function
|
|
30567
|
+
ws.once("open", function open3() {
|
|
30568
30568
|
duplex._write(chunk, encoding, callback);
|
|
30569
30569
|
});
|
|
30570
30570
|
return;
|
|
@@ -31950,18 +31950,18 @@ var init_source = __esm({
|
|
|
31950
31950
|
}
|
|
31951
31951
|
}
|
|
31952
31952
|
});
|
|
31953
|
-
createStyler = (
|
|
31953
|
+
createStyler = (open3, close, parent) => {
|
|
31954
31954
|
let openAll;
|
|
31955
31955
|
let closeAll;
|
|
31956
31956
|
if (parent === void 0) {
|
|
31957
|
-
openAll =
|
|
31957
|
+
openAll = open3;
|
|
31958
31958
|
closeAll = close;
|
|
31959
31959
|
} else {
|
|
31960
|
-
openAll = parent.openAll +
|
|
31960
|
+
openAll = parent.openAll + open3;
|
|
31961
31961
|
closeAll = close + parent.closeAll;
|
|
31962
31962
|
}
|
|
31963
31963
|
return {
|
|
31964
|
-
open:
|
|
31964
|
+
open: open3,
|
|
31965
31965
|
close,
|
|
31966
31966
|
openAll,
|
|
31967
31967
|
closeAll,
|
|
@@ -33530,8 +33530,8 @@ var init_ErrorOverview = __esm({
|
|
|
33530
33530
|
init_dist3();
|
|
33531
33531
|
init_Box();
|
|
33532
33532
|
init_Text();
|
|
33533
|
-
cleanupPath = (
|
|
33534
|
-
return
|
|
33533
|
+
cleanupPath = (path11) => {
|
|
33534
|
+
return path11?.replace(`file://${cwd()}/`, "");
|
|
33535
33535
|
};
|
|
33536
33536
|
stackUtils = new import_stack_utils.default({
|
|
33537
33537
|
cwd: cwd(),
|
|
@@ -34606,6 +34606,47 @@ var init_build2 = __esm({
|
|
|
34606
34606
|
}
|
|
34607
34607
|
});
|
|
34608
34608
|
|
|
34609
|
+
// src/render/theme.ts
|
|
34610
|
+
function roleProps(role, theme) {
|
|
34611
|
+
switch (theme) {
|
|
34612
|
+
case "plain":
|
|
34613
|
+
return {};
|
|
34614
|
+
case "high-contrast":
|
|
34615
|
+
return role === "secondary" ? {} : { color: ROLE_COLORS[role], bold: true };
|
|
34616
|
+
case "auto":
|
|
34617
|
+
return { color: ROLE_COLORS[role] };
|
|
34618
|
+
}
|
|
34619
|
+
}
|
|
34620
|
+
function resolveThemeName(env3, warn = (m2) => console.warn(m2)) {
|
|
34621
|
+
const raw = env3.SPACECODE_THEME;
|
|
34622
|
+
if (raw === void 0 || raw === "") return "auto";
|
|
34623
|
+
if (THEME_NAMES.includes(raw)) return raw;
|
|
34624
|
+
warn(`[theme] unknown SPACECODE_THEME "${raw}"; using "auto". Accepted values: ${THEME_NAMES.join(", ")}.`);
|
|
34625
|
+
return "auto";
|
|
34626
|
+
}
|
|
34627
|
+
function activeTheme() {
|
|
34628
|
+
active ??= resolveThemeName(process.env);
|
|
34629
|
+
return active;
|
|
34630
|
+
}
|
|
34631
|
+
function paint(role) {
|
|
34632
|
+
return roleProps(role, activeTheme());
|
|
34633
|
+
}
|
|
34634
|
+
var THEME_NAMES, ROLE_COLORS, active;
|
|
34635
|
+
var init_theme = __esm({
|
|
34636
|
+
"src/render/theme.ts"() {
|
|
34637
|
+
"use strict";
|
|
34638
|
+
THEME_NAMES = ["auto", "plain", "high-contrast"];
|
|
34639
|
+
ROLE_COLORS = {
|
|
34640
|
+
agent: "magenta",
|
|
34641
|
+
add: "green",
|
|
34642
|
+
delete: "red",
|
|
34643
|
+
needsYou: "yellow",
|
|
34644
|
+
action: "blue",
|
|
34645
|
+
secondary: "gray"
|
|
34646
|
+
};
|
|
34647
|
+
}
|
|
34648
|
+
});
|
|
34649
|
+
|
|
34609
34650
|
// src/components/WelcomeBanner.tsx
|
|
34610
34651
|
function getSubtitle(mode, launchCount2) {
|
|
34611
34652
|
switch (mode) {
|
|
@@ -34622,26 +34663,238 @@ function getSubtitle(mode, launchCount2) {
|
|
|
34622
34663
|
return "Ready to code. What's next?";
|
|
34623
34664
|
}
|
|
34624
34665
|
}
|
|
34625
|
-
function WelcomeBanner({
|
|
34626
|
-
|
|
34627
|
-
|
|
34628
|
-
|
|
34629
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: "cyan", bold: true, children: "SpaceCode Agent" }),
|
|
34630
|
-
repoName2 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { children: [
|
|
34631
|
-
"Project: ",
|
|
34632
|
-
repoName2
|
|
34633
|
-
] }),
|
|
34634
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: "gray", children: subtitle }),
|
|
34635
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: "cyan", children: BORDER })
|
|
34666
|
+
function WelcomeBanner({ onboardingMode: onboardingMode2, launchCount: launchCount2 }) {
|
|
34667
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Text, { ...paint("secondary"), children: [
|
|
34668
|
+
getSubtitle(onboardingMode2, launchCount2),
|
|
34669
|
+
" /help for commands, @ to attach a file."
|
|
34636
34670
|
] });
|
|
34637
34671
|
}
|
|
34638
|
-
var import_jsx_runtime
|
|
34672
|
+
var import_jsx_runtime;
|
|
34639
34673
|
var init_WelcomeBanner = __esm({
|
|
34640
34674
|
async "src/components/WelcomeBanner.tsx"() {
|
|
34641
34675
|
"use strict";
|
|
34642
34676
|
await init_build2();
|
|
34677
|
+
init_theme();
|
|
34643
34678
|
import_jsx_runtime = __toESM(require_jsx_runtime(), 1);
|
|
34644
|
-
|
|
34679
|
+
}
|
|
34680
|
+
});
|
|
34681
|
+
|
|
34682
|
+
// src/render/hints.ts
|
|
34683
|
+
function formatHints({ running, asking, columns }, sep2 = "\xB7") {
|
|
34684
|
+
columns = Math.min(columns, MAX_STATIC_LINE);
|
|
34685
|
+
const parts = asking ? ["1 2 3 answer", "esc refuse"] : running ? ["esc interrupt", "tab step", "shift+tab mode", "ctrl+o turns"] : ["enter send", "shift+tab mode", "/ commands", "@ file", "! shell", "ctrl+o turns"];
|
|
34686
|
+
const kept = [...parts];
|
|
34687
|
+
while (kept.length > 1 && kept.join(` ${sep2} `).length > columns) kept.pop();
|
|
34688
|
+
return kept.join(` ${sep2} `);
|
|
34689
|
+
}
|
|
34690
|
+
var MAX_STATIC_LINE;
|
|
34691
|
+
var init_hints = __esm({
|
|
34692
|
+
"src/render/hints.ts"() {
|
|
34693
|
+
"use strict";
|
|
34694
|
+
MAX_STATIC_LINE = 58;
|
|
34695
|
+
}
|
|
34696
|
+
});
|
|
34697
|
+
|
|
34698
|
+
// src/render/header.ts
|
|
34699
|
+
function formatDuration(ms) {
|
|
34700
|
+
const min = Math.floor(ms / 6e4);
|
|
34701
|
+
return min < 1 ? "<1 min" : min < 60 ? `${min} min` : `${Math.floor(min / 60)}h ${min % 60}m`;
|
|
34702
|
+
}
|
|
34703
|
+
function formatHeader({ project, git, otherSessions, turns, elapsedMs, columns: terminalColumns }, sep2 = "\xB7") {
|
|
34704
|
+
const columns = Math.min(terminalColumns, MAX_STATIC_LINE);
|
|
34705
|
+
const optional = [];
|
|
34706
|
+
const branch = [];
|
|
34707
|
+
if (git?.kind === "ok") {
|
|
34708
|
+
branch.push({ text: git.branch });
|
|
34709
|
+
if (git.dirty > 0) branch.push({ text: `${sep2 === "\xB7" ? "\xB1" : "+-"}${git.dirty}`, role: "needsYou" });
|
|
34710
|
+
} else if (git?.kind === "unknown") {
|
|
34711
|
+
branch.push({ text: "git ?", role: "needsYou" });
|
|
34712
|
+
}
|
|
34713
|
+
if (otherSessions !== void 0 && otherSessions > 0) optional.push({ text: `+${otherSessions} other session${otherSessions === 1 ? "" : "s"}`, role: "secondary" });
|
|
34714
|
+
optional.push({ text: `${turns} turn${turns === 1 ? "" : "s"}`, role: "secondary" });
|
|
34715
|
+
optional.push({ text: formatDuration(elapsedMs), role: "secondary" });
|
|
34716
|
+
const base = [{ text: "spacecode", bold: true }, { text: project }];
|
|
34717
|
+
const all = [...base, ...branch, ...optional];
|
|
34718
|
+
const width = (segs) => segs.reduce((n, s, i) => n + s.text.length + (i > 0 ? sep2.length + 2 : 0), 0);
|
|
34719
|
+
const kept = [...all];
|
|
34720
|
+
while (kept.length > base.length && width(kept) > columns) kept.pop();
|
|
34721
|
+
return kept;
|
|
34722
|
+
}
|
|
34723
|
+
var init_header = __esm({
|
|
34724
|
+
"src/render/header.ts"() {
|
|
34725
|
+
"use strict";
|
|
34726
|
+
init_hints();
|
|
34727
|
+
}
|
|
34728
|
+
});
|
|
34729
|
+
|
|
34730
|
+
// src/render/rail.ts
|
|
34731
|
+
function unicodeAvailable(env3, stdoutIsTTY) {
|
|
34732
|
+
if (!stdoutIsTTY) return false;
|
|
34733
|
+
const locale = env3.LC_ALL || env3.LC_CTYPE || env3.LANG || "";
|
|
34734
|
+
return /utf-?8/i.test(locale);
|
|
34735
|
+
}
|
|
34736
|
+
function railGlyphs(unicode) {
|
|
34737
|
+
return unicode ? UNICODE : ASCII;
|
|
34738
|
+
}
|
|
34739
|
+
function truncatePath(target, max, ellipsis = "\u2026") {
|
|
34740
|
+
if (max <= 0) return "";
|
|
34741
|
+
const e = ellipsis.length;
|
|
34742
|
+
if (target.length <= max) return target;
|
|
34743
|
+
const parts = target.split("/");
|
|
34744
|
+
const file = parts[parts.length - 1];
|
|
34745
|
+
if (parts.length > 1 && file.length + e + 1 <= max) {
|
|
34746
|
+
let tail = file;
|
|
34747
|
+
for (let i = parts.length - 2; i >= 0; i--) {
|
|
34748
|
+
const next = `${parts[i]}/${tail}`;
|
|
34749
|
+
if (next.length + e + 1 > max) break;
|
|
34750
|
+
tail = next;
|
|
34751
|
+
}
|
|
34752
|
+
return `${ellipsis}/${tail}`;
|
|
34753
|
+
}
|
|
34754
|
+
return max <= e ? ellipsis.slice(0, max) : `${target.slice(0, max - e)}${ellipsis}`;
|
|
34755
|
+
}
|
|
34756
|
+
function fitStepLine({ verb, target, meta, columns, indent = 4, ellipsis = "\u2026", sep: sep2 = "\xB7" }) {
|
|
34757
|
+
const room = Math.max(10, columns - indent);
|
|
34758
|
+
const metaText = meta ? ` ${sep2} ${meta}` : "";
|
|
34759
|
+
const fixed = verb.length + 1;
|
|
34760
|
+
if (fixed + target.length + metaText.length <= room) return { verb, target, meta };
|
|
34761
|
+
const targetRoom = room - fixed - metaText.length;
|
|
34762
|
+
const fileName = target.split("/").pop() ?? target;
|
|
34763
|
+
if (meta && targetRoom >= Math.min(fileName.length, 12) + 2) {
|
|
34764
|
+
return { verb, target: truncatePath(target, targetRoom, ellipsis), meta };
|
|
34765
|
+
}
|
|
34766
|
+
return { verb, target: truncatePath(target, Math.max(1, room - fixed), ellipsis) };
|
|
34767
|
+
}
|
|
34768
|
+
function plainOutput() {
|
|
34769
|
+
return unicodeOverride === void 0 && !process.stdout.isTTY;
|
|
34770
|
+
}
|
|
34771
|
+
function activeGlyphs() {
|
|
34772
|
+
return railGlyphs(unicodeOverride ?? unicodeAvailable(process.env, Boolean(process.stdout.isTTY)));
|
|
34773
|
+
}
|
|
34774
|
+
var UNICODE, ASCII, unicodeOverride;
|
|
34775
|
+
var init_rail = __esm({
|
|
34776
|
+
"src/render/rail.ts"() {
|
|
34777
|
+
"use strict";
|
|
34778
|
+
UNICODE = { rail: "\u2502", result: "\u23BF", ellipsis: "\u2026", sep: "\xB7", marker: { running: "\u25D0", waiting: "\u25C7", ok: "\u25CF", failed: "\u2717" } };
|
|
34779
|
+
ASCII = { rail: "|", result: ">", ellipsis: "...", sep: "-", marker: { running: "o", waiting: "?", ok: "*", failed: "x" } };
|
|
34780
|
+
}
|
|
34781
|
+
});
|
|
34782
|
+
|
|
34783
|
+
// src/components/Header.tsx
|
|
34784
|
+
function Header(props) {
|
|
34785
|
+
const sep2 = activeGlyphs().sep;
|
|
34786
|
+
const segments2 = formatHeader(props, sep2);
|
|
34787
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Box_default, { children: segments2.map((seg, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_react22.default.Fragment, { children: [
|
|
34788
|
+
i > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { ...paint("secondary"), children: ` ${sep2} ` }),
|
|
34789
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Text, { bold: seg.bold, ...seg.role ? paint(seg.role) : {}, children: seg.text })
|
|
34790
|
+
] }, i)) });
|
|
34791
|
+
}
|
|
34792
|
+
var import_react22, import_jsx_runtime2;
|
|
34793
|
+
var init_Header = __esm({
|
|
34794
|
+
async "src/components/Header.tsx"() {
|
|
34795
|
+
"use strict";
|
|
34796
|
+
import_react22 = __toESM(require_react(), 1);
|
|
34797
|
+
await init_build2();
|
|
34798
|
+
init_header();
|
|
34799
|
+
init_rail();
|
|
34800
|
+
init_theme();
|
|
34801
|
+
import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
|
|
34802
|
+
}
|
|
34803
|
+
});
|
|
34804
|
+
|
|
34805
|
+
// src/components/ErrorBlock.tsx
|
|
34806
|
+
function ErrorBlock({ view }) {
|
|
34807
|
+
const glyphs = activeGlyphs();
|
|
34808
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box_default, { flexDirection: "column", children: [
|
|
34809
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { ...paint("delete"), bold: true, children: `${glyphs.marker.failed} ${view.title}` }),
|
|
34810
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { children: ` ${view.cause}` }),
|
|
34811
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { ...paint("secondary"), children: ` ${view.action}` })
|
|
34812
|
+
] });
|
|
34813
|
+
}
|
|
34814
|
+
var import_jsx_runtime3;
|
|
34815
|
+
var init_ErrorBlock = __esm({
|
|
34816
|
+
async "src/components/ErrorBlock.tsx"() {
|
|
34817
|
+
"use strict";
|
|
34818
|
+
await init_build2();
|
|
34819
|
+
init_rail();
|
|
34820
|
+
init_theme();
|
|
34821
|
+
import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1);
|
|
34822
|
+
}
|
|
34823
|
+
});
|
|
34824
|
+
|
|
34825
|
+
// src/render/git-status.ts
|
|
34826
|
+
function parseGitStatus(output) {
|
|
34827
|
+
const lines2 = output.split("\n").filter((l) => l !== "");
|
|
34828
|
+
const head = lines2.find((l) => l.startsWith("## "));
|
|
34829
|
+
const dirty = lines2.filter((l) => !l.startsWith("## ")).length;
|
|
34830
|
+
if (!head) throw new Error("git status output has no branch line");
|
|
34831
|
+
const rest = head.slice(3);
|
|
34832
|
+
let branch;
|
|
34833
|
+
if (rest.startsWith("No commits yet on ")) branch = rest.slice("No commits yet on ".length);
|
|
34834
|
+
else if (rest.startsWith("HEAD (no branch)")) branch = "detached HEAD";
|
|
34835
|
+
else if (rest.startsWith("Initial commit on ")) branch = rest.slice("Initial commit on ".length);
|
|
34836
|
+
else branch = rest.split("...")[0].split(" ")[0];
|
|
34837
|
+
return { branch, dirty };
|
|
34838
|
+
}
|
|
34839
|
+
async function readGitState(run) {
|
|
34840
|
+
try {
|
|
34841
|
+
const { branch, dirty } = parseGitStatus(await run(["status", "--porcelain=v1", "-b"]));
|
|
34842
|
+
return { kind: "ok", branch, dirty };
|
|
34843
|
+
} catch (err) {
|
|
34844
|
+
const text = `${err instanceof Error ? err.message : String(err)} ${err?.stderr ?? ""}`;
|
|
34845
|
+
return /not a git repository/i.test(text) ? { kind: "none" } : { kind: "unknown" };
|
|
34846
|
+
}
|
|
34847
|
+
}
|
|
34848
|
+
var init_git_status = __esm({
|
|
34849
|
+
"src/render/git-status.ts"() {
|
|
34850
|
+
"use strict";
|
|
34851
|
+
}
|
|
34852
|
+
});
|
|
34853
|
+
|
|
34854
|
+
// src/render/node-git.ts
|
|
34855
|
+
import { execFile } from "node:child_process";
|
|
34856
|
+
function createNodeGitRunner(cwd2, timeoutMs = 1e3) {
|
|
34857
|
+
return (args) => new Promise((resolve2, reject) => {
|
|
34858
|
+
execFile("git", args, { cwd: cwd2, timeout: timeoutMs, maxBuffer: 1024 * 1024, env: { ...process.env, LC_ALL: "C", GIT_OPTIONAL_LOCKS: "0" } }, (err, stdout, stderr) => {
|
|
34859
|
+
if (err) reject(Object.assign(err, { stderr }));
|
|
34860
|
+
else resolve2(stdout);
|
|
34861
|
+
});
|
|
34862
|
+
});
|
|
34863
|
+
}
|
|
34864
|
+
var init_node_git = __esm({
|
|
34865
|
+
"src/render/node-git.ts"() {
|
|
34866
|
+
"use strict";
|
|
34867
|
+
}
|
|
34868
|
+
});
|
|
34869
|
+
|
|
34870
|
+
// src/render/mode-line.ts
|
|
34871
|
+
function modeGlyph(mode, unicode = true) {
|
|
34872
|
+
return unicode ? GLYPHS[mode].unicode : GLYPHS[mode].ascii;
|
|
34873
|
+
}
|
|
34874
|
+
function promptGlyph(mode, unicode = true) {
|
|
34875
|
+
return mode === "plan" || mode === "yolo" ? modeGlyph(mode, unicode) : ">";
|
|
34876
|
+
}
|
|
34877
|
+
function modeLine(mode, unicode = true) {
|
|
34878
|
+
const label = unicode ? LABELS[mode] : LABELS[mode].replace(" \xB7 ", " - ");
|
|
34879
|
+
const role = mode === "accept-edits" ? "add" : mode === "plan" ? "action" : mode === "yolo" ? "delete" : void 0;
|
|
34880
|
+
return { text: `${modeGlyph(mode, unicode)} ${label}`, role };
|
|
34881
|
+
}
|
|
34882
|
+
var GLYPHS, LABELS;
|
|
34883
|
+
var init_mode_line = __esm({
|
|
34884
|
+
"src/render/mode-line.ts"() {
|
|
34885
|
+
"use strict";
|
|
34886
|
+
GLYPHS = {
|
|
34887
|
+
default: { unicode: "\u25C7", ascii: "-" },
|
|
34888
|
+
"accept-edits": { unicode: "\u25C8", ascii: "+" },
|
|
34889
|
+
plan: { unicode: "\u25A2", ascii: "#" },
|
|
34890
|
+
yolo: { unicode: "!", ascii: "!" }
|
|
34891
|
+
};
|
|
34892
|
+
LABELS = {
|
|
34893
|
+
default: "default",
|
|
34894
|
+
"accept-edits": "accept edits",
|
|
34895
|
+
plan: "plan \xB7 read-only",
|
|
34896
|
+
yolo: "yolo"
|
|
34897
|
+
};
|
|
34645
34898
|
}
|
|
34646
34899
|
});
|
|
34647
34900
|
|
|
@@ -34764,13 +35017,13 @@ function processEvents(events) {
|
|
|
34764
35017
|
return { renderOrder, statusMessage };
|
|
34765
35018
|
}
|
|
34766
35019
|
function useEventAccumulator(events) {
|
|
34767
|
-
return (0,
|
|
35020
|
+
return (0, import_react23.useMemo)(() => processEvents(events), [events]);
|
|
34768
35021
|
}
|
|
34769
|
-
var
|
|
35022
|
+
var import_react23, MAX_OUTPUT_LINES, MAX_RESULT_OUTPUT;
|
|
34770
35023
|
var init_useEventAccumulator = __esm({
|
|
34771
35024
|
"src/components/useEventAccumulator.ts"() {
|
|
34772
35025
|
"use strict";
|
|
34773
|
-
|
|
35026
|
+
import_react23 = __toESM(require_react(), 1);
|
|
34774
35027
|
MAX_OUTPUT_LINES = 3;
|
|
34775
35028
|
MAX_RESULT_OUTPUT = 500;
|
|
34776
35029
|
}
|
|
@@ -38638,7 +38891,7 @@ var require_core = __commonJS({
|
|
|
38638
38891
|
}
|
|
38639
38892
|
return highlighted[0].event === "start" ? original : highlighted;
|
|
38640
38893
|
}
|
|
38641
|
-
function
|
|
38894
|
+
function open3(node) {
|
|
38642
38895
|
function attributeString(attr) {
|
|
38643
38896
|
return " " + attr.nodeName + '="' + escapeHTML(attr.value) + '"';
|
|
38644
38897
|
}
|
|
@@ -38648,7 +38901,7 @@ var require_core = __commonJS({
|
|
|
38648
38901
|
result += "</" + tag(node) + ">";
|
|
38649
38902
|
}
|
|
38650
38903
|
function render3(event) {
|
|
38651
|
-
(event.event === "start" ?
|
|
38904
|
+
(event.event === "start" ? open3 : close)(event.node);
|
|
38652
38905
|
}
|
|
38653
38906
|
while (original.length || highlighted.length) {
|
|
38654
38907
|
let stream = selectStream();
|
|
@@ -38660,7 +38913,7 @@ var require_core = __commonJS({
|
|
|
38660
38913
|
render3(stream.splice(0, 1)[0]);
|
|
38661
38914
|
stream = selectStream();
|
|
38662
38915
|
} while (stream === original && stream.length && stream[0].offset === processed);
|
|
38663
|
-
nodeStack.reverse().forEach(
|
|
38916
|
+
nodeStack.reverse().forEach(open3);
|
|
38664
38917
|
} else {
|
|
38665
38918
|
if (stream[0].event === "start") {
|
|
38666
38919
|
nodeStack.push(stream[0].node);
|
|
@@ -61906,11 +62159,11 @@ var require_perl = __commonJS({
|
|
|
61906
62159
|
/#/
|
|
61907
62160
|
// valid but infrequent and weird
|
|
61908
62161
|
];
|
|
61909
|
-
const PAIRED_DOUBLE_RE = (prefix,
|
|
61910
|
-
const middle = close === "\\1" ? close : concat(close,
|
|
62162
|
+
const PAIRED_DOUBLE_RE = (prefix, open3, close = "\\1") => {
|
|
62163
|
+
const middle = close === "\\1" ? close : concat(close, open3);
|
|
61911
62164
|
return concat(
|
|
61912
62165
|
concat("(?:", prefix, ")"),
|
|
61913
|
-
|
|
62166
|
+
open3,
|
|
61914
62167
|
/(?:\\.|[^\\\/])*?/,
|
|
61915
62168
|
middle,
|
|
61916
62169
|
/(?:\\.|[^\\\/])*?/,
|
|
@@ -61918,10 +62171,10 @@ var require_perl = __commonJS({
|
|
|
61918
62171
|
REGEX_MODIFIERS
|
|
61919
62172
|
);
|
|
61920
62173
|
};
|
|
61921
|
-
const PAIRED_RE = (prefix,
|
|
62174
|
+
const PAIRED_RE = (prefix, open3, close) => {
|
|
61922
62175
|
return concat(
|
|
61923
62176
|
concat("(?:", prefix, ")"),
|
|
61924
|
-
|
|
62177
|
+
open3,
|
|
61925
62178
|
/(?:\\.|[^\\\/])*?/,
|
|
61926
62179
|
close,
|
|
61927
62180
|
REGEX_MODIFIERS
|
|
@@ -80629,15 +80882,15 @@ var require_route = __commonJS({
|
|
|
80629
80882
|
};
|
|
80630
80883
|
}
|
|
80631
80884
|
function wrapConversion(toModel, graph) {
|
|
80632
|
-
const
|
|
80885
|
+
const path11 = [graph[toModel].parent, toModel];
|
|
80633
80886
|
let fn = conversions[graph[toModel].parent][toModel];
|
|
80634
80887
|
let cur = graph[toModel].parent;
|
|
80635
80888
|
while (graph[cur].parent) {
|
|
80636
|
-
|
|
80889
|
+
path11.unshift(graph[cur].parent);
|
|
80637
80890
|
fn = link2(conversions[graph[cur].parent][cur], fn);
|
|
80638
80891
|
cur = graph[cur].parent;
|
|
80639
80892
|
}
|
|
80640
|
-
fn.conversion =
|
|
80893
|
+
fn.conversion = path11;
|
|
80641
80894
|
return fn;
|
|
80642
80895
|
}
|
|
80643
80896
|
module.exports = function(fromModel) {
|
|
@@ -81226,18 +81479,18 @@ var require_source = __commonJS({
|
|
|
81226
81479
|
}
|
|
81227
81480
|
}
|
|
81228
81481
|
});
|
|
81229
|
-
var createStyler2 = (
|
|
81482
|
+
var createStyler2 = (open3, close, parent) => {
|
|
81230
81483
|
let openAll;
|
|
81231
81484
|
let closeAll;
|
|
81232
81485
|
if (parent === void 0) {
|
|
81233
|
-
openAll =
|
|
81486
|
+
openAll = open3;
|
|
81234
81487
|
closeAll = close;
|
|
81235
81488
|
} else {
|
|
81236
|
-
openAll = parent.openAll +
|
|
81489
|
+
openAll = parent.openAll + open3;
|
|
81237
81490
|
closeAll = close + parent.closeAll;
|
|
81238
81491
|
}
|
|
81239
81492
|
return {
|
|
81240
|
-
open:
|
|
81493
|
+
open: open3,
|
|
81241
81494
|
close,
|
|
81242
81495
|
openAll,
|
|
81243
81496
|
closeAll,
|
|
@@ -94055,8 +94308,8 @@ var init_markdown = __esm({
|
|
|
94055
94308
|
// src/useTerminalSize.ts
|
|
94056
94309
|
function useTerminalSize(fallback = { columns: 80, rows: 24 }) {
|
|
94057
94310
|
const { stdout } = use_stdout_default();
|
|
94058
|
-
const [size, setSize] = (0,
|
|
94059
|
-
(0,
|
|
94311
|
+
const [size, setSize] = (0, import_react24.useState)({ columns: stdout?.columns || fallback.columns, rows: stdout?.rows || fallback.rows });
|
|
94312
|
+
(0, import_react24.useEffect)(() => {
|
|
94060
94313
|
if (!stdout) return;
|
|
94061
94314
|
const update = () => setSize({ columns: stdout.columns || fallback.columns, rows: stdout.rows || fallback.rows });
|
|
94062
94315
|
update();
|
|
@@ -94067,11 +94320,11 @@ function useTerminalSize(fallback = { columns: 80, rows: 24 }) {
|
|
|
94067
94320
|
}, [stdout, fallback.columns, fallback.rows]);
|
|
94068
94321
|
return size;
|
|
94069
94322
|
}
|
|
94070
|
-
var
|
|
94323
|
+
var import_react24;
|
|
94071
94324
|
var init_useTerminalSize = __esm({
|
|
94072
94325
|
async "src/useTerminalSize.ts"() {
|
|
94073
94326
|
"use strict";
|
|
94074
|
-
|
|
94327
|
+
import_react24 = __toESM(require_react(), 1);
|
|
94075
94328
|
await init_build2();
|
|
94076
94329
|
}
|
|
94077
94330
|
});
|
|
@@ -94085,22 +94338,22 @@ function tailLines(text, maxLines) {
|
|
|
94085
94338
|
}
|
|
94086
94339
|
function MarkdownBlock({ content, maxLines }) {
|
|
94087
94340
|
const { columns } = useTerminalSize();
|
|
94088
|
-
const rendered = (0,
|
|
94341
|
+
const rendered = (0, import_react25.useMemo)(() => {
|
|
94089
94342
|
const out = renderMarkdown(content, { columns });
|
|
94090
94343
|
return (maxLines && maxLines >= 2 ? tailLines(out, maxLines) : out) || null;
|
|
94091
94344
|
}, [content, columns, maxLines]);
|
|
94092
94345
|
if (rendered === null) return null;
|
|
94093
|
-
return /* @__PURE__ */ (0,
|
|
94346
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Text, { children: rendered });
|
|
94094
94347
|
}
|
|
94095
|
-
var
|
|
94348
|
+
var import_react25, import_jsx_runtime4;
|
|
94096
94349
|
var init_MarkdownBlock = __esm({
|
|
94097
94350
|
async "src/components/MarkdownBlock.tsx"() {
|
|
94098
94351
|
"use strict";
|
|
94099
|
-
|
|
94352
|
+
import_react25 = __toESM(require_react(), 1);
|
|
94100
94353
|
await init_build2();
|
|
94101
94354
|
init_markdown();
|
|
94102
94355
|
await init_useTerminalSize();
|
|
94103
|
-
|
|
94356
|
+
import_jsx_runtime4 = __toESM(require_jsx_runtime(), 1);
|
|
94104
94357
|
}
|
|
94105
94358
|
});
|
|
94106
94359
|
|
|
@@ -95751,9 +96004,9 @@ var require_cli_spinners = __commonJS({
|
|
|
95751
96004
|
|
|
95752
96005
|
// ../../node_modules/ink-spinner/build/index.js
|
|
95753
96006
|
function Spinner({ type = "dots" }) {
|
|
95754
|
-
const [frame, setFrame] = (0,
|
|
96007
|
+
const [frame, setFrame] = (0, import_react26.useState)(0);
|
|
95755
96008
|
const spinner = import_cli_spinners.default[type];
|
|
95756
|
-
(0,
|
|
96009
|
+
(0, import_react26.useEffect)(() => {
|
|
95757
96010
|
const timer = setInterval(() => {
|
|
95758
96011
|
setFrame((previousFrame) => {
|
|
95759
96012
|
const isLastFrame = previousFrame === spinner.frames.length - 1;
|
|
@@ -95764,12 +96017,12 @@ function Spinner({ type = "dots" }) {
|
|
|
95764
96017
|
clearInterval(timer);
|
|
95765
96018
|
};
|
|
95766
96019
|
}, [spinner]);
|
|
95767
|
-
return
|
|
96020
|
+
return import_react26.default.createElement(Text, null, spinner.frames[frame]);
|
|
95768
96021
|
}
|
|
95769
|
-
var
|
|
96022
|
+
var import_react26, import_cli_spinners, build_default;
|
|
95770
96023
|
var init_build3 = __esm({
|
|
95771
96024
|
async "../../node_modules/ink-spinner/build/index.js"() {
|
|
95772
|
-
|
|
96025
|
+
import_react26 = __toESM(require_react(), 1);
|
|
95773
96026
|
await init_build2();
|
|
95774
96027
|
import_cli_spinners = __toESM(require_cli_spinners(), 1);
|
|
95775
96028
|
build_default = Spinner;
|
|
@@ -95777,48 +96030,238 @@ var init_build3 = __esm({
|
|
|
95777
96030
|
});
|
|
95778
96031
|
|
|
95779
96032
|
// src/render/tool-header.ts
|
|
95780
|
-
function
|
|
96033
|
+
function stepParts(tool, input) {
|
|
95781
96034
|
if (tool === "todo_write") {
|
|
95782
96035
|
const n = Array.isArray(input.todos) ? input.todos.length : 0;
|
|
95783
|
-
return
|
|
95784
|
-
}
|
|
95785
|
-
const LABELS = {
|
|
95786
|
-
read_file: { label: "Read", field: "path" },
|
|
95787
|
-
write_file: { label: "Write", field: "path" },
|
|
95788
|
-
edit_file: { label: "Update", field: "path" },
|
|
95789
|
-
list_directory: { label: "List", field: "path" },
|
|
95790
|
-
search: { label: "Search", field: "query" },
|
|
95791
|
-
bash: { label: "Bash", field: "command" }
|
|
95792
|
-
};
|
|
95793
|
-
const mapping = LABELS[tool];
|
|
95794
|
-
if (mapping) {
|
|
95795
|
-
const rawValue = input[mapping.field];
|
|
95796
|
-
let value2 = "";
|
|
95797
|
-
if (typeof rawValue === "string") {
|
|
95798
|
-
if (tool === "bash") {
|
|
95799
|
-
const firstLine = rawValue.split("\n")[0];
|
|
95800
|
-
value2 = firstLine.length > 60 ? firstLine.slice(0, 60) + "\u2026" : firstLine;
|
|
95801
|
-
} else {
|
|
95802
|
-
value2 = rawValue;
|
|
95803
|
-
}
|
|
95804
|
-
}
|
|
95805
|
-
return `${mapping.label}(${value2})`;
|
|
95806
|
-
}
|
|
95807
|
-
let value = "";
|
|
95808
|
-
for (const [, v2] of Object.entries(input)) {
|
|
95809
|
-
if (typeof v2 === "string") {
|
|
95810
|
-
value = v2;
|
|
95811
|
-
break;
|
|
95812
|
-
}
|
|
96036
|
+
return { verb: "Todos", target: `${n} item${n === 1 ? "" : "s"}` };
|
|
95813
96037
|
}
|
|
95814
|
-
|
|
95815
|
-
|
|
95816
|
-
|
|
95817
|
-
|
|
96038
|
+
const field = { read_file: "path", write_file: "path", edit_file: "path", list_directory: "path", search: "query", bash: "command" }[tool];
|
|
96039
|
+
const raw = field ? input[field] : Object.values(input).find((v2) => typeof v2 === "string");
|
|
96040
|
+
let target = typeof raw === "string" ? raw : "";
|
|
96041
|
+
if (tool === "bash") target = target.split("\n")[0];
|
|
96042
|
+
return { verb: STEP_VERBS[tool] ?? tool, target };
|
|
95818
96043
|
}
|
|
96044
|
+
var STEP_VERBS;
|
|
95819
96045
|
var init_tool_header = __esm({
|
|
95820
96046
|
"src/render/tool-header.ts"() {
|
|
95821
96047
|
"use strict";
|
|
96048
|
+
STEP_VERBS = {
|
|
96049
|
+
read_file: "Read",
|
|
96050
|
+
write_file: "Write",
|
|
96051
|
+
edit_file: "Edit",
|
|
96052
|
+
list_directory: "List",
|
|
96053
|
+
search: "Search",
|
|
96054
|
+
bash: "Run",
|
|
96055
|
+
todo_write: "Todos"
|
|
96056
|
+
};
|
|
96057
|
+
}
|
|
96058
|
+
});
|
|
96059
|
+
|
|
96060
|
+
// src/editor/credential-filter.ts
|
|
96061
|
+
function containsCredential(entry) {
|
|
96062
|
+
return PATTERNS.some((re3) => re3.test(entry));
|
|
96063
|
+
}
|
|
96064
|
+
var PATTERNS;
|
|
96065
|
+
var init_credential_filter = __esm({
|
|
96066
|
+
"src/editor/credential-filter.ts"() {
|
|
96067
|
+
"use strict";
|
|
96068
|
+
PATTERNS = [
|
|
96069
|
+
/\bsk[_-][A-Za-z0-9_-]{16,}/,
|
|
96070
|
+
/\bgh[pos]_[A-Za-z0-9]{20,}/,
|
|
96071
|
+
/\bgithub_pat_[A-Za-z0-9_]{20,}/,
|
|
96072
|
+
/\bAKIA[0-9A-Z]{16}\b/,
|
|
96073
|
+
/\bBearer\s+[A-Za-z0-9._~+/=-]{20,}/,
|
|
96074
|
+
/-----BEGIN [A-Z ]*PRIVATE KEY-----/,
|
|
96075
|
+
/\bxox[abp]-[A-Za-z0-9-]{10,}/,
|
|
96076
|
+
/\bnpm_[A-Za-z0-9]{30,}/,
|
|
96077
|
+
/\b[A-Za-z0-9_]*(?:KEY|TOKEN|SECRET|PASSWORD)[A-Za-z0-9_]*=\S{8,}/i
|
|
96078
|
+
];
|
|
96079
|
+
}
|
|
96080
|
+
});
|
|
96081
|
+
|
|
96082
|
+
// src/session/session-store.ts
|
|
96083
|
+
import { chmod, mkdir, open, readdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
96084
|
+
import { randomBytes } from "node:crypto";
|
|
96085
|
+
import path from "node:path";
|
|
96086
|
+
function redactCredentials(value) {
|
|
96087
|
+
if (typeof value === "string") return containsCredential(value) ? REDACTED : value;
|
|
96088
|
+
if (Array.isArray(value)) return value.map(redactCredentials);
|
|
96089
|
+
if (value && typeof value === "object") {
|
|
96090
|
+
return Object.fromEntries(Object.entries(value).map(([k2, v2]) => [k2, redactCredentials(v2)]));
|
|
96091
|
+
}
|
|
96092
|
+
return value;
|
|
96093
|
+
}
|
|
96094
|
+
function parseSession(file, text) {
|
|
96095
|
+
const lines2 = text.split("\n").filter((l) => l.length > 0);
|
|
96096
|
+
if (lines2.length === 0) throw new SessionError(file, "Session file is empty");
|
|
96097
|
+
let parsed;
|
|
96098
|
+
try {
|
|
96099
|
+
parsed = lines2.map((l) => JSON.parse(l));
|
|
96100
|
+
} catch (err) {
|
|
96101
|
+
throw new SessionError(file, `Corrupt session file: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
96102
|
+
}
|
|
96103
|
+
const meta = parsed[0];
|
|
96104
|
+
if (meta.v !== 1 || typeof meta.id !== "string" || typeof meta.projectRoot !== "string" || typeof meta.updatedAt !== "string") {
|
|
96105
|
+
throw new SessionError(file, "Unrecognized session header (expected v1 with id, projectRoot, updatedAt)");
|
|
96106
|
+
}
|
|
96107
|
+
const warnings = [];
|
|
96108
|
+
if (meta.todos !== void 0 && !(Array.isArray(meta.todos) && meta.todos.every((t) => t && typeof t.content === "string" && ["pending", "in_progress", "completed"].includes(t.status)))) {
|
|
96109
|
+
delete meta.todos;
|
|
96110
|
+
warnings.push(`The saved checklist in ${file} was not understood (saved by a different version?) and was left out.`);
|
|
96111
|
+
}
|
|
96112
|
+
const messages = parsed.slice(1);
|
|
96113
|
+
if (!messages.every((m2) => m2 && (m2.role === "user" || m2.role === "assistant"))) {
|
|
96114
|
+
throw new SessionError(file, "Corrupt session file: a message has no valid role");
|
|
96115
|
+
}
|
|
96116
|
+
return warnings.length > 0 ? { meta, messages, warnings } : { meta, messages };
|
|
96117
|
+
}
|
|
96118
|
+
function formatAge(fromIso, now) {
|
|
96119
|
+
const secs = Math.max(0, Math.floor((now.getTime() - new Date(fromIso).getTime()) / 1e3));
|
|
96120
|
+
if (secs < 60) return `${secs}s ago`;
|
|
96121
|
+
if (secs < 3600) return `${Math.floor(secs / 60)}m ago`;
|
|
96122
|
+
if (secs < 86400) return `${Math.floor(secs / 3600)}h ago`;
|
|
96123
|
+
return `${Math.floor(secs / 86400)}d ago`;
|
|
96124
|
+
}
|
|
96125
|
+
function titleFromMessages(messages) {
|
|
96126
|
+
const first = messages.find((m2) => m2.role === "user");
|
|
96127
|
+
const text = !first ? "" : typeof first.content === "string" ? first.content : first.content.map((b2) => b2.text ?? "").join(" ");
|
|
96128
|
+
const oneLine = text.replace(/\s+/g, " ").trim();
|
|
96129
|
+
return oneLine.length > 60 ? `${oneLine.slice(0, 59)}\u2026` : oneLine || "(untitled)";
|
|
96130
|
+
}
|
|
96131
|
+
function countTurns(messages) {
|
|
96132
|
+
return messages.filter((m2) => m2.role === "user" && (typeof m2.content === "string" || m2.content.some((b2) => b2.type === "text"))).length;
|
|
96133
|
+
}
|
|
96134
|
+
var MAX_SESSION_BYTES, PREVIEW_TAIL_BYTES, REDACTED, SessionError, ID, SessionStore;
|
|
96135
|
+
var init_session_store = __esm({
|
|
96136
|
+
"src/session/session-store.ts"() {
|
|
96137
|
+
"use strict";
|
|
96138
|
+
init_credential_filter();
|
|
96139
|
+
MAX_SESSION_BYTES = 5 * 1024 * 1024;
|
|
96140
|
+
PREVIEW_TAIL_BYTES = 256 * 1024;
|
|
96141
|
+
REDACTED = "[redacted: credential-shaped content]";
|
|
96142
|
+
SessionError = class extends Error {
|
|
96143
|
+
constructor(file, message, options) {
|
|
96144
|
+
super(`${message} (${file})`, options);
|
|
96145
|
+
this.file = file;
|
|
96146
|
+
this.name = "SessionError";
|
|
96147
|
+
}
|
|
96148
|
+
};
|
|
96149
|
+
ID = /^[A-Za-z0-9_-]{8,64}$/;
|
|
96150
|
+
SessionStore = class {
|
|
96151
|
+
constructor(dir, now = () => /* @__PURE__ */ new Date()) {
|
|
96152
|
+
this.dir = dir;
|
|
96153
|
+
this.now = now;
|
|
96154
|
+
}
|
|
96155
|
+
newId() {
|
|
96156
|
+
return `${this.now().toISOString().replace(/[-:.TZ]/g, "").slice(0, 14)}-${randomBytes(4).toString("hex")}`;
|
|
96157
|
+
}
|
|
96158
|
+
fileFor(id) {
|
|
96159
|
+
if (!ID.test(id)) throw new SessionError(this.dir, `Invalid session id ${JSON.stringify(id)}`);
|
|
96160
|
+
return path.join(this.dir, `${id}.jsonl`);
|
|
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";
|
|
96166
|
+
const bytes = Buffer.byteLength(body);
|
|
96167
|
+
if (bytes > MAX_SESSION_BYTES) {
|
|
96168
|
+
throw new SessionError(file, `Session is ${bytes} bytes, over the ${MAX_SESSION_BYTES}-byte cap; use /compact or /clear`);
|
|
96169
|
+
}
|
|
96170
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
96171
|
+
try {
|
|
96172
|
+
await mkdir(this.dir, { recursive: true, mode: 448 });
|
|
96173
|
+
await chmod(this.dir, 448);
|
|
96174
|
+
await writeFile(tmp, body, { mode: 384 });
|
|
96175
|
+
await chmod(tmp, 384);
|
|
96176
|
+
await rename(tmp, file);
|
|
96177
|
+
} catch (err) {
|
|
96178
|
+
throw new SessionError(file, `Could not save session: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
96179
|
+
}
|
|
96180
|
+
}
|
|
96181
|
+
async load(id) {
|
|
96182
|
+
const file = this.fileFor(id);
|
|
96183
|
+
let text;
|
|
96184
|
+
try {
|
|
96185
|
+
const { size } = await stat(file);
|
|
96186
|
+
if (size > MAX_SESSION_BYTES) {
|
|
96187
|
+
throw new SessionError(file, `Session is ${size} bytes, over the ${MAX_SESSION_BYTES}-byte cap; not loaded`);
|
|
96188
|
+
}
|
|
96189
|
+
text = await readFile(file, "utf8");
|
|
96190
|
+
} catch (err) {
|
|
96191
|
+
if (err instanceof SessionError) throw err;
|
|
96192
|
+
throw new SessionError(file, `Could not read session: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
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;
|
|
96197
|
+
}
|
|
96198
|
+
/** Newest first. Unreadable files are reported, not skipped silently. */
|
|
96199
|
+
async list() {
|
|
96200
|
+
let names;
|
|
96201
|
+
try {
|
|
96202
|
+
names = await readdir(this.dir);
|
|
96203
|
+
} catch (err) {
|
|
96204
|
+
if (err.code === "ENOENT") return { sessions: [], errors: [] };
|
|
96205
|
+
throw new SessionError(this.dir, `Could not list sessions: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
96206
|
+
}
|
|
96207
|
+
const sessions = [];
|
|
96208
|
+
const errors = [];
|
|
96209
|
+
for (const name of names.filter((n) => n.endsWith(".jsonl"))) {
|
|
96210
|
+
try {
|
|
96211
|
+
sessions.push((await this.load(name.slice(0, -".jsonl".length))).meta);
|
|
96212
|
+
} catch (err) {
|
|
96213
|
+
errors.push(err instanceof SessionError ? err : new SessionError(path.join(this.dir, name), String(err), { cause: err }));
|
|
96214
|
+
}
|
|
96215
|
+
}
|
|
96216
|
+
sessions.sort((a, b2) => b2.updatedAt.localeCompare(a.updatedAt));
|
|
96217
|
+
return { sessions, errors };
|
|
96218
|
+
}
|
|
96219
|
+
/**
|
|
96220
|
+
* The last assistant text of a session (first 120 chars, credential-redacted), read from the end of the file so a
|
|
96221
|
+
* large session is not loaded whole. null when none is found in the tail.
|
|
96222
|
+
*/
|
|
96223
|
+
async preview(id) {
|
|
96224
|
+
const file = this.fileFor(id);
|
|
96225
|
+
try {
|
|
96226
|
+
const { size } = await stat(file);
|
|
96227
|
+
const length = Math.min(size, PREVIEW_TAIL_BYTES);
|
|
96228
|
+
const handle = await open(file, "r");
|
|
96229
|
+
let tail;
|
|
96230
|
+
try {
|
|
96231
|
+
const buf = Buffer.alloc(length);
|
|
96232
|
+
await handle.read(buf, 0, length, size - length);
|
|
96233
|
+
tail = buf.toString("utf8");
|
|
96234
|
+
} finally {
|
|
96235
|
+
await handle.close();
|
|
96236
|
+
}
|
|
96237
|
+
const lines2 = tail.split("\n").filter((l) => l.length > 0);
|
|
96238
|
+
if (length < size) lines2.shift();
|
|
96239
|
+
for (let i = lines2.length - 1; i >= 0; i--) {
|
|
96240
|
+
let msg;
|
|
96241
|
+
try {
|
|
96242
|
+
msg = JSON.parse(lines2[i]);
|
|
96243
|
+
} catch {
|
|
96244
|
+
continue;
|
|
96245
|
+
}
|
|
96246
|
+
if (msg.role !== "assistant") continue;
|
|
96247
|
+
const text = typeof msg.content === "string" ? msg.content : msg.content.map((b2) => b2.text ?? "").join(" ");
|
|
96248
|
+
const oneLine = redactCredentials(text.replace(/\s+/g, " ").trim());
|
|
96249
|
+
if (oneLine) return oneLine.length > 120 ? `${oneLine.slice(0, 119)}\u2026` : oneLine;
|
|
96250
|
+
}
|
|
96251
|
+
return null;
|
|
96252
|
+
} catch (err) {
|
|
96253
|
+
throw new SessionError(file, `Could not read session preview: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
96254
|
+
}
|
|
96255
|
+
}
|
|
96256
|
+
async delete(id) {
|
|
96257
|
+
const file = this.fileFor(id);
|
|
96258
|
+
try {
|
|
96259
|
+
await rm(file);
|
|
96260
|
+
} catch (err) {
|
|
96261
|
+
throw new SessionError(file, `Could not delete session: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
96262
|
+
}
|
|
96263
|
+
}
|
|
96264
|
+
};
|
|
95822
96265
|
}
|
|
95823
96266
|
});
|
|
95824
96267
|
|
|
@@ -95865,6 +96308,287 @@ var init_diff_rows = __esm({
|
|
|
95865
96308
|
}
|
|
95866
96309
|
});
|
|
95867
96310
|
|
|
96311
|
+
// src/render/step-record.ts
|
|
96312
|
+
function cutToBytes(text, max) {
|
|
96313
|
+
let out = text;
|
|
96314
|
+
while (byteLength(out) > max) out = out.slice(0, Math.max(0, Math.floor(out.length * (max / byteLength(out)) * 0.98) - 1));
|
|
96315
|
+
const last = out.charCodeAt(out.length - 1);
|
|
96316
|
+
if (last >= 55296 && last <= 56319) out = out.slice(0, -1);
|
|
96317
|
+
return out;
|
|
96318
|
+
}
|
|
96319
|
+
function redactLines(raw) {
|
|
96320
|
+
let inKey = false;
|
|
96321
|
+
return raw.split("\n").map((line) => {
|
|
96322
|
+
if (inKey) {
|
|
96323
|
+
if (PEM_END.test(line)) inKey = false;
|
|
96324
|
+
return REDACTED;
|
|
96325
|
+
}
|
|
96326
|
+
if (PEM_BEGIN.test(line)) {
|
|
96327
|
+
inKey = !PEM_END.test(line);
|
|
96328
|
+
return REDACTED;
|
|
96329
|
+
}
|
|
96330
|
+
return containsCredential(line) ? REDACTED : line;
|
|
96331
|
+
});
|
|
96332
|
+
}
|
|
96333
|
+
function capDetail(raw) {
|
|
96334
|
+
const lines2 = redactLines(raw);
|
|
96335
|
+
const kept = lines2.slice(0, MAX_DETAIL_LINES);
|
|
96336
|
+
let text = kept.join("\n");
|
|
96337
|
+
const notes = [];
|
|
96338
|
+
if (lines2.length > kept.length) notes.push(`${lines2.length - kept.length} more line${lines2.length - kept.length === 1 ? "" : "s"} not kept`);
|
|
96339
|
+
if (byteLength(text) > MAX_DETAIL_BYTES) {
|
|
96340
|
+
text = cutToBytes(text, MAX_DETAIL_BYTES);
|
|
96341
|
+
notes.push(`truncated to ${MAX_DETAIL_BYTES / 1024} KB`);
|
|
96342
|
+
}
|
|
96343
|
+
return notes.length > 0 ? `${text}
|
|
96344
|
+
\u2026 ${notes.join("; ")}` : text;
|
|
96345
|
+
}
|
|
96346
|
+
function detailOf(state) {
|
|
96347
|
+
const { tool, input, result, outputLines } = state;
|
|
96348
|
+
if (tool === "edit_file" && typeof input.old_string === "string" && typeof input.new_string === "string") {
|
|
96349
|
+
const { rows, hidden } = diffRows(input.old_string, input.new_string, MAX_DETAIL_LINES);
|
|
96350
|
+
const body = rows.map((r) => `${String(r.n).padStart(4)} ${r.kind === "add" ? "+" : "-"} ${r.text}`).join("\n");
|
|
96351
|
+
return hidden > 0 ? `${body}
|
|
96352
|
+
\u2026 ${hidden} more line${hidden === 1 ? "" : "s"} not kept` : body;
|
|
96353
|
+
}
|
|
96354
|
+
if (tool === "write_file" && typeof input.content === "string") return input.content;
|
|
96355
|
+
if (result) return result.output;
|
|
96356
|
+
return outputLines.length > 0 ? outputLines.join("\n") : null;
|
|
96357
|
+
}
|
|
96358
|
+
function metaOf(state) {
|
|
96359
|
+
const { result } = state;
|
|
96360
|
+
const parts = [];
|
|
96361
|
+
if (state.status === "error") parts.push("failed");
|
|
96362
|
+
if (result?.duration_ms != null) parts.push(`${(result.duration_ms / 1e3).toFixed(1)}s`);
|
|
96363
|
+
return parts.join(" \xB7 ");
|
|
96364
|
+
}
|
|
96365
|
+
function toStepRecord(state) {
|
|
96366
|
+
const { verb, target } = stepParts(state.tool, state.input);
|
|
96367
|
+
const raw = detailOf(state);
|
|
96368
|
+
return {
|
|
96369
|
+
id: state.id,
|
|
96370
|
+
tool: state.tool,
|
|
96371
|
+
verb,
|
|
96372
|
+
target,
|
|
96373
|
+
state: state.status === "running" ? "running" : state.status === "error" ? "failed" : "ok",
|
|
96374
|
+
meta: metaOf(state),
|
|
96375
|
+
durationMs: state.result?.duration_ms,
|
|
96376
|
+
detail: raw === null ? null : capDetail(raw)
|
|
96377
|
+
};
|
|
96378
|
+
}
|
|
96379
|
+
var MAX_DETAIL_LINES, MAX_DETAIL_BYTES, MAX_SESSION_BYTES2, NOT_KEPT, encoder, byteLength, PEM_BEGIN, PEM_END, StepStore;
|
|
96380
|
+
var init_step_record = __esm({
|
|
96381
|
+
"src/render/step-record.ts"() {
|
|
96382
|
+
"use strict";
|
|
96383
|
+
init_session_store();
|
|
96384
|
+
init_credential_filter();
|
|
96385
|
+
init_diff_rows();
|
|
96386
|
+
init_tool_header();
|
|
96387
|
+
MAX_DETAIL_LINES = 200;
|
|
96388
|
+
MAX_DETAIL_BYTES = 20 * 1024;
|
|
96389
|
+
MAX_SESSION_BYTES2 = 5 * 1024 * 1024;
|
|
96390
|
+
NOT_KEPT = "output not kept";
|
|
96391
|
+
encoder = new TextEncoder();
|
|
96392
|
+
byteLength = (s) => encoder.encode(s).length;
|
|
96393
|
+
PEM_BEGIN = /-----BEGIN [A-Z ]*PRIVATE KEY-----/;
|
|
96394
|
+
PEM_END = /-----END [A-Z ]*PRIVATE KEY-----/;
|
|
96395
|
+
StepStore = class {
|
|
96396
|
+
constructor(maxBytes = MAX_SESSION_BYTES2) {
|
|
96397
|
+
this.maxBytes = maxBytes;
|
|
96398
|
+
}
|
|
96399
|
+
records = [];
|
|
96400
|
+
bytes = 0;
|
|
96401
|
+
/** Insert or replace by id (a running step is updated as it finishes). */
|
|
96402
|
+
upsert(record) {
|
|
96403
|
+
const at = this.records.findIndex((r) => r.id === record.id);
|
|
96404
|
+
if (at >= 0) {
|
|
96405
|
+
this.bytes -= byteLength(this.records[at].detail ?? "");
|
|
96406
|
+
this.records[at] = record;
|
|
96407
|
+
} else {
|
|
96408
|
+
this.records.push(record);
|
|
96409
|
+
}
|
|
96410
|
+
this.bytes += byteLength(record.detail ?? "");
|
|
96411
|
+
for (let i = 0; i < this.records.length && this.bytes > this.maxBytes; i++) {
|
|
96412
|
+
const old = this.records[i];
|
|
96413
|
+
if (old.id === record.id || old.detail === null) continue;
|
|
96414
|
+
this.bytes -= byteLength(old.detail);
|
|
96415
|
+
this.records[i] = { ...old, detail: null };
|
|
96416
|
+
}
|
|
96417
|
+
}
|
|
96418
|
+
get(id) {
|
|
96419
|
+
return this.records.find((r) => r.id === id);
|
|
96420
|
+
}
|
|
96421
|
+
all() {
|
|
96422
|
+
return this.records;
|
|
96423
|
+
}
|
|
96424
|
+
get detailBytes() {
|
|
96425
|
+
return this.bytes;
|
|
96426
|
+
}
|
|
96427
|
+
};
|
|
96428
|
+
}
|
|
96429
|
+
});
|
|
96430
|
+
|
|
96431
|
+
// src/render/describe-error.ts
|
|
96432
|
+
function sanitizeCause(raw) {
|
|
96433
|
+
const lines2 = raw.split("\n").map((l) => l.trim()).filter(Boolean).filter((l) => !/^\s*at\s+\S+\s+\(.*:\d+:\d+\)\s*$|^\s*at\s+\S+:\d+:\d+\s*$/.test(l)).slice(0, MAX_CAUSE_LINES);
|
|
96434
|
+
const safe = lines2.map((l) => containsCredential(l) ? "[redacted: credential-shaped content]" : l).join(" ");
|
|
96435
|
+
return safe.length > MAX_CAUSE_CHARS ? `${safe.slice(0, MAX_CAUSE_CHARS - 1)}\u2026` : safe || "No details were reported.";
|
|
96436
|
+
}
|
|
96437
|
+
function classifyError(message) {
|
|
96438
|
+
const api = /^API error (\d{3})\b/.exec(message);
|
|
96439
|
+
if (api) {
|
|
96440
|
+
const status = Number(api[1]);
|
|
96441
|
+
if (status === 401 || status === 403) return { kind: "auth", status };
|
|
96442
|
+
if (status === 402) return { kind: "payment", status };
|
|
96443
|
+
if (status === 429) return { kind: "rate-limit", status };
|
|
96444
|
+
if (status >= 500) return { kind: "gateway", status };
|
|
96445
|
+
return { kind: "unknown", status };
|
|
96446
|
+
}
|
|
96447
|
+
if (/^No API key found/.test(message)) return { kind: "missing-key" };
|
|
96448
|
+
if (/^Not approved\b/.test(message)) return { kind: "policy" };
|
|
96449
|
+
if (NETWORK.test(message)) return { kind: "network" };
|
|
96450
|
+
return { kind: "unknown" };
|
|
96451
|
+
}
|
|
96452
|
+
function bodyMessage(cause) {
|
|
96453
|
+
const json = cause.slice(cause.indexOf(":") + 1).trim();
|
|
96454
|
+
try {
|
|
96455
|
+
const parsed = JSON.parse(json);
|
|
96456
|
+
const m2 = parsed.error?.message ?? parsed.message;
|
|
96457
|
+
return typeof m2 === "string" && m2.trim() ? m2.trim() : null;
|
|
96458
|
+
} catch {
|
|
96459
|
+
return null;
|
|
96460
|
+
}
|
|
96461
|
+
}
|
|
96462
|
+
function defaultHost() {
|
|
96463
|
+
try {
|
|
96464
|
+
return new URL(process.env.API_PROXY_URL || "https://api.spacecode.app").host;
|
|
96465
|
+
} catch {
|
|
96466
|
+
return "the gateway";
|
|
96467
|
+
}
|
|
96468
|
+
}
|
|
96469
|
+
function describeError(kind, cause, ctx = {}) {
|
|
96470
|
+
const retained = ctx.retained === true;
|
|
96471
|
+
const shown = sanitizeCause(cause);
|
|
96472
|
+
const status = ctx.status;
|
|
96473
|
+
switch (kind) {
|
|
96474
|
+
case "gateway":
|
|
96475
|
+
return {
|
|
96476
|
+
title: `Gateway didn't answer${status ? ` (${status})` : ""}`,
|
|
96477
|
+
cause: `${ctx.host ?? defaultHost()} is unavailable.${retained ? " Your prompt is saved." : ""}`,
|
|
96478
|
+
action: retained ? "Press enter to retry, or run /status to check the gateway." : "Run /status to check the gateway, then send your prompt again."
|
|
96479
|
+
};
|
|
96480
|
+
case "rate-limit":
|
|
96481
|
+
return {
|
|
96482
|
+
title: `Rate limited${status ? ` (${status})` : ""}`,
|
|
96483
|
+
cause: `The gateway is getting too many requests; it already retried a few times.${retained ? " Your prompt is saved." : ""}`,
|
|
96484
|
+
action: retained ? "Wait a moment, then press enter to retry." : "Wait a moment, then send your prompt again."
|
|
96485
|
+
};
|
|
96486
|
+
case "auth":
|
|
96487
|
+
return {
|
|
96488
|
+
title: `Sign-in rejected${status ? ` (${status})` : ""}`,
|
|
96489
|
+
cause: "The gateway did not accept your key.",
|
|
96490
|
+
action: retained ? "Run `spacecode login` in another terminal, then press enter to retry." : "Run `spacecode login`, then send your prompt again."
|
|
96491
|
+
};
|
|
96492
|
+
case "missing-key":
|
|
96493
|
+
return {
|
|
96494
|
+
title: "No API key",
|
|
96495
|
+
cause: "The REPL needs a key to call the gateway.",
|
|
96496
|
+
action: retained ? "Run `spacecode login` in another terminal or set SPACECODE_API_KEY, then press enter to retry." : "Run `spacecode login` or set SPACECODE_API_KEY, then send your prompt again."
|
|
96497
|
+
};
|
|
96498
|
+
case "payment":
|
|
96499
|
+
return {
|
|
96500
|
+
title: `Payment required${status ? ` (${status})` : ""}`,
|
|
96501
|
+
cause: sanitizeCause(bodyMessage(cause) ?? "Your plan does not include this."),
|
|
96502
|
+
action: `Open ${BILLING_URL} to choose a plan.`
|
|
96503
|
+
};
|
|
96504
|
+
case "network":
|
|
96505
|
+
return {
|
|
96506
|
+
title: "Can't reach the gateway",
|
|
96507
|
+
cause: `${shown}${retained ? " Your prompt is saved." : ""}`,
|
|
96508
|
+
action: retained ? "Check your connection, then press enter to retry." : "Check your connection, then send your prompt again."
|
|
96509
|
+
};
|
|
96510
|
+
case "session-save":
|
|
96511
|
+
return {
|
|
96512
|
+
title: "Session not saved",
|
|
96513
|
+
cause: shown,
|
|
96514
|
+
action: "Your conversation continues. Free some space or run /compact; the next turn tries to save again."
|
|
96515
|
+
};
|
|
96516
|
+
case "policy":
|
|
96517
|
+
return {
|
|
96518
|
+
title: "Not approved",
|
|
96519
|
+
cause: shown.replace(/^Not approved\s*\(([^)]*)\):\s*(.*)$/, "$2 ($1)").replace(/^Not approved\s*/, ""),
|
|
96520
|
+
action: "Press shift+tab to change the permission mode, or ask the agent to take another approach."
|
|
96521
|
+
};
|
|
96522
|
+
case "unknown":
|
|
96523
|
+
return { title: "Something went wrong", cause: shown, action: "Run /status for the session state, or send your prompt again." };
|
|
96524
|
+
}
|
|
96525
|
+
}
|
|
96526
|
+
function describeEventError(message, ctx = {}) {
|
|
96527
|
+
const { kind, status } = classifyError(message);
|
|
96528
|
+
return describeError(kind, message, { ...ctx, status: ctx.status ?? status });
|
|
96529
|
+
}
|
|
96530
|
+
function isRetryable(message) {
|
|
96531
|
+
const { kind } = classifyError(message);
|
|
96532
|
+
return kind === "gateway" || kind === "rate-limit" || kind === "network" || kind === "missing-key" || kind === "auth";
|
|
96533
|
+
}
|
|
96534
|
+
var BILLING_URL, MAX_CAUSE_LINES, MAX_CAUSE_CHARS, NETWORK;
|
|
96535
|
+
var init_describe_error = __esm({
|
|
96536
|
+
"src/render/describe-error.ts"() {
|
|
96537
|
+
"use strict";
|
|
96538
|
+
init_credential_filter();
|
|
96539
|
+
BILLING_URL = "https://spacecode.g-a-l-a-c-t-i-c.com";
|
|
96540
|
+
MAX_CAUSE_LINES = 3;
|
|
96541
|
+
MAX_CAUSE_CHARS = 300;
|
|
96542
|
+
NETWORK = /fetch failed|ENOTFOUND|ECONNREFUSED|ECONNRESET|ETIMEDOUT|EAI_AGAIN|network (error|request failed|is unreachable)|socket hang up/i;
|
|
96543
|
+
}
|
|
96544
|
+
});
|
|
96545
|
+
|
|
96546
|
+
// src/render/step-view.ts
|
|
96547
|
+
function stepsOfEvents(events) {
|
|
96548
|
+
return processEvents(events).renderOrder.flatMap((item) => item.type === "tool" ? [toStepRecord(item.state)] : []);
|
|
96549
|
+
}
|
|
96550
|
+
function stepsOfTurns(turns, maxBytes) {
|
|
96551
|
+
const store = new StepStore(maxBytes);
|
|
96552
|
+
for (const turn of turns) for (const record of stepsOfEvents(turn.events)) store.upsert({ ...record, id: `${turn.id}:${record.id}` });
|
|
96553
|
+
const byTurn = /* @__PURE__ */ new Map();
|
|
96554
|
+
for (const record of store.all()) {
|
|
96555
|
+
const turnId = Number(record.id.slice(0, record.id.indexOf(":")));
|
|
96556
|
+
const list2 = byTurn.get(turnId) ?? [];
|
|
96557
|
+
list2.push({ ...record, id: record.id.slice(record.id.indexOf(":") + 1) });
|
|
96558
|
+
byTurn.set(turnId, list2);
|
|
96559
|
+
}
|
|
96560
|
+
return byTurn;
|
|
96561
|
+
}
|
|
96562
|
+
function detailWindow(detail, maxLines, width, offset = 0) {
|
|
96563
|
+
if (detail === null) return { lines: [NOT_KEPT], above: 0, below: 0 };
|
|
96564
|
+
const rows = [];
|
|
96565
|
+
for (const line of detail.split("\n")) {
|
|
96566
|
+
if (line.length <= width) rows.push(line);
|
|
96567
|
+
else for (let i = 0; i < line.length; i += width) rows.push(line.slice(i, i + width));
|
|
96568
|
+
}
|
|
96569
|
+
const room = Math.max(1, maxLines);
|
|
96570
|
+
const start = Math.min(Math.max(0, offset), Math.max(0, rows.length - room));
|
|
96571
|
+
return { lines: rows.slice(start, start + room), above: start, below: Math.max(0, rows.length - start - room) };
|
|
96572
|
+
}
|
|
96573
|
+
function findBlockedStep(steps, req) {
|
|
96574
|
+
const tools = TOOLS_FOR_KIND[req.kind];
|
|
96575
|
+
if (!tools) return void 0;
|
|
96576
|
+
const subject = req.kind === "exec" ? req.subject.split("\n")[0] : req.subject;
|
|
96577
|
+
return steps.find((r) => {
|
|
96578
|
+
if (r.state !== "running" || !tools.includes(r.tool)) return false;
|
|
96579
|
+
return r.target === subject;
|
|
96580
|
+
});
|
|
96581
|
+
}
|
|
96582
|
+
var TOOLS_FOR_KIND;
|
|
96583
|
+
var init_step_view = __esm({
|
|
96584
|
+
"src/render/step-view.ts"() {
|
|
96585
|
+
"use strict";
|
|
96586
|
+
init_useEventAccumulator();
|
|
96587
|
+
init_step_record();
|
|
96588
|
+
TOOLS_FOR_KIND = { exec: ["bash"], edit_file: ["edit_file"], write_file: ["write_file"] };
|
|
96589
|
+
}
|
|
96590
|
+
});
|
|
96591
|
+
|
|
95868
96592
|
// src/render/highlight.ts
|
|
95869
96593
|
function languageFor(filePath) {
|
|
95870
96594
|
if (!filePath) return null;
|
|
@@ -95916,111 +96640,156 @@ var init_highlight = __esm({
|
|
|
95916
96640
|
});
|
|
95917
96641
|
|
|
95918
96642
|
// src/components/ToolCallBlock.tsx
|
|
95919
|
-
function
|
|
96643
|
+
function formatDuration2(ms) {
|
|
95920
96644
|
return (ms / 1e3).toFixed(1) + "s";
|
|
95921
96645
|
}
|
|
95922
|
-
function summarize(output) {
|
|
96646
|
+
function summarize(output, ellipsis = "\u2026") {
|
|
95923
96647
|
const lines2 = output.split("\n").filter((l) => l.trim().length > 0);
|
|
95924
96648
|
if (lines2.length === 0) return "(no output)";
|
|
95925
|
-
const first = lines2[0].length > MAX_SUMMARY_CHARS ? lines2[0].slice(0, MAX_SUMMARY_CHARS) +
|
|
96649
|
+
const first = lines2[0].length > MAX_SUMMARY_CHARS ? lines2[0].slice(0, MAX_SUMMARY_CHARS) + ellipsis : lines2[0];
|
|
95926
96650
|
return lines2.length > 1 ? `${first} (+${lines2.length - 1} lines)` : first;
|
|
95927
96651
|
}
|
|
95928
96652
|
function DiffBlock({ oldStr, newStr, filePath }) {
|
|
95929
96653
|
const { rows, hidden } = diffRows(oldStr, newStr);
|
|
95930
|
-
|
|
96654
|
+
const ellipsis = activeGlyphs().ellipsis;
|
|
96655
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { flexDirection: "column", children: [
|
|
95931
96656
|
rows.map((row, i) => {
|
|
95932
96657
|
const isAdd = row.kind === "add";
|
|
95933
|
-
const
|
|
95934
|
-
return /* @__PURE__ */ (0,
|
|
95935
|
-
/* @__PURE__ */ (0,
|
|
96658
|
+
const role = isAdd ? "add" : "delete";
|
|
96659
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { children: [
|
|
96660
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { ...paint(role), children: [
|
|
95936
96661
|
" ",
|
|
95937
96662
|
String(row.n).padStart(4),
|
|
95938
96663
|
" ",
|
|
95939
96664
|
isAdd ? "+" : "-",
|
|
95940
96665
|
" "
|
|
95941
96666
|
] }),
|
|
95942
|
-
isAdd ? highlightLine(row.text, filePath) : /* @__PURE__ */ (0,
|
|
96667
|
+
isAdd ? highlightLine(row.text, filePath) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { ...paint(role), children: row.text })
|
|
95943
96668
|
] }, i);
|
|
95944
96669
|
}),
|
|
95945
|
-
hidden > 0 && /* @__PURE__ */ (0,
|
|
95946
|
-
|
|
96670
|
+
hidden > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { ...paint("secondary"), children: [
|
|
96671
|
+
` ${ellipsis} +`,
|
|
95947
96672
|
hidden,
|
|
95948
96673
|
" lines"
|
|
95949
96674
|
] })
|
|
95950
96675
|
] });
|
|
95951
96676
|
}
|
|
95952
|
-
function ToolCallBlock({ state }) {
|
|
96677
|
+
function ToolCallBlock({ state, focused = false, open: open3 = false, detailRows = 12, waiting = false }) {
|
|
95953
96678
|
const { tool, input, status, outputLines, result } = state;
|
|
95954
|
-
const
|
|
96679
|
+
const { columns } = useTerminalSize();
|
|
96680
|
+
const glyphs = activeGlyphs();
|
|
96681
|
+
const plain = plainOutput();
|
|
96682
|
+
const unicode = glyphs.rail === "\u2502";
|
|
96683
|
+
const ellipsis = glyphs.ellipsis;
|
|
96684
|
+
const parts = stepParts(tool, input);
|
|
96685
|
+
const twist = open3 ? unicode ? "\u25BE" : "v" : unicode ? "\u25B8" : ">";
|
|
96686
|
+
if (status === "running" && waiting) {
|
|
96687
|
+
const line2 = fitStepLine({ ...parts, meta: "waiting for you", columns, indent: plain ? 0 : 4, ellipsis, sep: glyphs.sep });
|
|
96688
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { children: [
|
|
96689
|
+
!plain && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { ...paint("needsYou"), children: [
|
|
96690
|
+
glyphs.marker.waiting,
|
|
96691
|
+
" "
|
|
96692
|
+
] }),
|
|
96693
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { children: [
|
|
96694
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { ...paint("action"), children: line2.verb }),
|
|
96695
|
+
" ",
|
|
96696
|
+
line2.target
|
|
96697
|
+
] }),
|
|
96698
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { ...paint("needsYou"), children: ` ${glyphs.sep} waiting for you` })
|
|
96699
|
+
] });
|
|
96700
|
+
}
|
|
95955
96701
|
if (status === "running") {
|
|
95956
|
-
return /* @__PURE__ */ (0,
|
|
95957
|
-
/* @__PURE__ */ (0,
|
|
95958
|
-
/* @__PURE__ */ (0,
|
|
95959
|
-
/* @__PURE__ */ (0,
|
|
96702
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { flexDirection: "column", children: [
|
|
96703
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { children: [
|
|
96704
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { ...paint("action"), children: [
|
|
96705
|
+
plain ? null : unicode ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(build_default, { type: "dots" }) : glyphs.marker.running,
|
|
96706
|
+
focused ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { bold: true, children: twist }) : plain ? "" : " ",
|
|
96707
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { bold: true, inverse: focused, children: parts.verb }),
|
|
95960
96708
|
" ",
|
|
95961
|
-
|
|
96709
|
+
fitStepLine({ ...parts, meta: "running", columns, indent: plain ? 0 : 4, ellipsis, sep: glyphs.sep }).target
|
|
95962
96710
|
] }),
|
|
95963
|
-
/* @__PURE__ */ (0,
|
|
96711
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { ...paint("secondary"), children: ` ${glyphs.sep} running` })
|
|
95964
96712
|
] }),
|
|
95965
|
-
|
|
96713
|
+
open3 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(StepDetail, { state, rows: detailRows, columns }),
|
|
96714
|
+
!open3 && outputLines.map((line2, i) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { ...paint("secondary"), children: [
|
|
95966
96715
|
" ",
|
|
95967
|
-
|
|
96716
|
+
glyphs.rail,
|
|
95968
96717
|
" ",
|
|
95969
|
-
|
|
96718
|
+
line2.length > MAX_RUNNING_LINE_CHARS ? `${line2.slice(0, MAX_RUNNING_LINE_CHARS)}${ellipsis} (+${line2.length - MAX_RUNNING_LINE_CHARS} chars)` : line2
|
|
95970
96719
|
] }, i))
|
|
95971
96720
|
] });
|
|
95972
96721
|
}
|
|
95973
96722
|
const isError = status === "error";
|
|
95974
|
-
const
|
|
96723
|
+
const metaText = [isError ? "failed" : "", result?.duration_ms != null ? formatDuration2(result.duration_ms) : ""].filter(Boolean).join(` ${glyphs.sep} `);
|
|
96724
|
+
const line = fitStepLine({ ...parts, meta: metaText || void 0, columns, indent: plain ? 0 : 4, ellipsis, sep: glyphs.sep });
|
|
95975
96725
|
const output = result?.output ?? "";
|
|
95976
96726
|
let body = null;
|
|
95977
96727
|
if (isError && output) {
|
|
95978
96728
|
const lines2 = output.split("\n");
|
|
96729
|
+
const policyRefusal = /^Not approved\b/.test(output);
|
|
95979
96730
|
const shown = lines2.slice(0, MAX_ERROR_LINES);
|
|
95980
96731
|
const more = lines2.length - shown.length;
|
|
95981
|
-
body = /* @__PURE__ */ (0,
|
|
95982
|
-
shown.map((l, i) => /* @__PURE__ */ (0,
|
|
95983
|
-
|
|
96732
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { flexDirection: "column", children: [
|
|
96733
|
+
shown.map((l, i) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { ...paint("delete"), children: [
|
|
96734
|
+
` ${glyphs.result} `,
|
|
95984
96735
|
l
|
|
95985
96736
|
] }, i)),
|
|
95986
|
-
more > 0 && /* @__PURE__ */ (0,
|
|
95987
|
-
|
|
96737
|
+
more > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { ...paint("secondary"), children: [
|
|
96738
|
+
` ${ellipsis} `,
|
|
95988
96739
|
more,
|
|
95989
96740
|
" more"
|
|
95990
|
-
] })
|
|
96741
|
+
] }),
|
|
96742
|
+
policyRefusal && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { ...paint("secondary"), children: ` ${glyphs.result} ${describeError("policy", output).action}` })
|
|
95991
96743
|
] });
|
|
95992
96744
|
} else if (tool === "edit_file" && typeof input.old_string === "string" && typeof input.new_string === "string") {
|
|
95993
|
-
body = /* @__PURE__ */ (0,
|
|
96745
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(DiffBlock, { oldStr: input.old_string, newStr: input.new_string, filePath: typeof input.path === "string" ? input.path : void 0 });
|
|
95994
96746
|
} else if (tool === "write_file" && typeof input.content === "string") {
|
|
95995
|
-
body = /* @__PURE__ */ (0,
|
|
96747
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(DiffBlock, { oldStr: "", newStr: input.content, filePath: typeof input.path === "string" ? input.path : void 0 });
|
|
95996
96748
|
} else if (output) {
|
|
95997
|
-
body = /* @__PURE__ */ (0,
|
|
95998
|
-
|
|
95999
|
-
summarize(output)
|
|
96749
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { ...paint("secondary"), children: [
|
|
96750
|
+
` ${glyphs.result} `,
|
|
96751
|
+
summarize(output, ellipsis)
|
|
96000
96752
|
] });
|
|
96001
96753
|
}
|
|
96002
|
-
return /* @__PURE__ */ (0,
|
|
96003
|
-
/* @__PURE__ */ (0,
|
|
96004
|
-
/* @__PURE__ */ (0,
|
|
96005
|
-
/* @__PURE__ */ (0,
|
|
96754
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { flexDirection: "column", children: [
|
|
96755
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { children: [
|
|
96756
|
+
!plain && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { ...paint(isError ? "delete" : "add"), children: isError ? glyphs.marker.failed : glyphs.marker.ok }),
|
|
96757
|
+
!plain && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { bold: focused, children: focused ? twist : " " }),
|
|
96758
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { inverse: focused, children: [
|
|
96759
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { ...paint("action"), children: line.verb }),
|
|
96006
96760
|
" ",
|
|
96007
|
-
|
|
96761
|
+
line.target
|
|
96008
96762
|
] }),
|
|
96009
|
-
|
|
96763
|
+
line.meta && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { ...paint("secondary"), children: ` ${glyphs.sep} ${line.meta}` })
|
|
96010
96764
|
] }),
|
|
96011
|
-
body
|
|
96765
|
+
open3 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(StepDetail, { state, rows: detailRows, columns }) : body
|
|
96012
96766
|
] });
|
|
96013
96767
|
}
|
|
96014
|
-
|
|
96768
|
+
function StepDetail({ state, rows, columns }) {
|
|
96769
|
+
const record = toStepRecord(state);
|
|
96770
|
+
const detail = record.detail ?? (state.status === "running" ? "no output yet" : null);
|
|
96771
|
+
const win = detailWindow(detail, rows, Math.max(20, columns - 8));
|
|
96772
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { flexDirection: "column", marginLeft: 3, children: [
|
|
96773
|
+
win.lines.map((l, i) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { ...paint("secondary"), children: l }, i)),
|
|
96774
|
+
win.below > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { ...paint("secondary"), children: `${activeGlyphs().ellipsis} ${win.below} more line${win.below === 1 ? "" : "s"}` })
|
|
96775
|
+
] });
|
|
96776
|
+
}
|
|
96777
|
+
var import_jsx_runtime5, MAX_ERROR_LINES, MAX_RUNNING_LINE_CHARS, MAX_SUMMARY_CHARS;
|
|
96015
96778
|
var init_ToolCallBlock = __esm({
|
|
96016
96779
|
async "src/components/ToolCallBlock.tsx"() {
|
|
96017
96780
|
"use strict";
|
|
96018
96781
|
await init_build2();
|
|
96019
96782
|
await init_build3();
|
|
96020
96783
|
init_tool_header();
|
|
96784
|
+
init_rail();
|
|
96785
|
+
await init_useTerminalSize();
|
|
96786
|
+
init_step_record();
|
|
96787
|
+
init_describe_error();
|
|
96788
|
+
init_step_view();
|
|
96021
96789
|
init_diff_rows();
|
|
96022
96790
|
init_highlight();
|
|
96023
|
-
|
|
96791
|
+
init_theme();
|
|
96792
|
+
import_jsx_runtime5 = __toESM(require_jsx_runtime(), 1);
|
|
96024
96793
|
MAX_ERROR_LINES = 8;
|
|
96025
96794
|
MAX_RUNNING_LINE_CHARS = 200;
|
|
96026
96795
|
MAX_SUMMARY_CHARS = 100;
|
|
@@ -96028,54 +96797,114 @@ var init_ToolCallBlock = __esm({
|
|
|
96028
96797
|
});
|
|
96029
96798
|
|
|
96030
96799
|
// src/components/EventRenderer.tsx
|
|
96031
|
-
function EventRenderer({ events, liveMaxLines }) {
|
|
96800
|
+
function EventRenderer({ events, liveMaxLines, focusId = null, openId = null, detailRows, waitingId = null, prompt, promptSaved = false, deferErrors = false }) {
|
|
96032
96801
|
const { renderOrder, statusMessage } = useEventAccumulator(events);
|
|
96033
|
-
|
|
96034
|
-
|
|
96802
|
+
const glyphs = activeGlyphs();
|
|
96803
|
+
const railStyle = { topLeft: "", top: "", topRight: "", right: "", bottomRight: "", bottom: "", bottomLeft: "", left: glyphs.rail };
|
|
96804
|
+
const groups = [];
|
|
96805
|
+
for (const item of renderOrder) {
|
|
96806
|
+
const last = groups[groups.length - 1];
|
|
96807
|
+
if (item.type === "tool" && Array.isArray(last)) last.push(item);
|
|
96808
|
+
else groups.push(item.type === "tool" ? [item] : item);
|
|
96809
|
+
}
|
|
96810
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Box_default, { flexDirection: "column", children: [
|
|
96811
|
+
groups.map((group) => {
|
|
96812
|
+
if (Array.isArray(group) && plainOutput()) {
|
|
96813
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Box_default, { flexDirection: "column", children: group.map((item2) => item2.type === "tool" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react27.default.Fragment, { children: [
|
|
96814
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToolCallBlock, { state: item2.state, focused: item2.id === focusId, open: item2.id === openId, detailRows, waiting: item2.id === waitingId }),
|
|
96815
|
+
item2.id === waitingId && prompt
|
|
96816
|
+
] }, item2.id)) }, group[0].id);
|
|
96817
|
+
}
|
|
96818
|
+
if (Array.isArray(group)) {
|
|
96819
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
96820
|
+
Box_default,
|
|
96821
|
+
{
|
|
96822
|
+
flexDirection: "column",
|
|
96823
|
+
borderStyle: railStyle,
|
|
96824
|
+
borderTop: false,
|
|
96825
|
+
borderBottom: false,
|
|
96826
|
+
borderRight: false,
|
|
96827
|
+
borderColor: paint("secondary").color,
|
|
96828
|
+
paddingLeft: 1,
|
|
96829
|
+
children: group.map((item2) => item2.type === "tool" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_react27.default.Fragment, { children: [
|
|
96830
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ToolCallBlock, { state: item2.state, focused: item2.id === focusId, open: item2.id === openId, detailRows, waiting: item2.id === waitingId }),
|
|
96831
|
+
item2.id === waitingId && prompt
|
|
96832
|
+
] }, item2.id))
|
|
96833
|
+
},
|
|
96834
|
+
group[0].id
|
|
96835
|
+
);
|
|
96836
|
+
}
|
|
96837
|
+
const item = group;
|
|
96035
96838
|
switch (item.type) {
|
|
96036
96839
|
case "text":
|
|
96037
|
-
return /* @__PURE__ */ (0,
|
|
96840
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MarkdownBlock, { content: item.content, maxLines: liveMaxLines }) }, item.id);
|
|
96038
96841
|
case "tool":
|
|
96039
|
-
return
|
|
96842
|
+
return null;
|
|
96843
|
+
// grouped onto the rail above
|
|
96040
96844
|
case "error":
|
|
96041
|
-
|
|
96042
|
-
|
|
96043
|
-
item.message
|
|
96044
|
-
] }) }, item.id);
|
|
96845
|
+
if (deferErrors) return null;
|
|
96846
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ErrorBlock, { view: describeEventError(item.message, { retained: promptSaved }) }) }, item.id);
|
|
96045
96847
|
default: {
|
|
96046
96848
|
const _exhaustive = item;
|
|
96047
96849
|
return _exhaustive;
|
|
96048
96850
|
}
|
|
96049
96851
|
}
|
|
96050
96852
|
}),
|
|
96051
|
-
statusMessage && /* @__PURE__ */ (0,
|
|
96052
|
-
"\u2022 "
|
|
96853
|
+
statusMessage && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Text, { ...paint("needsYou"), children: [
|
|
96854
|
+
`${glyphs.rail === "\u2502" ? "\u2022" : "*"} `,
|
|
96053
96855
|
statusMessage
|
|
96054
96856
|
] })
|
|
96055
96857
|
] });
|
|
96056
96858
|
}
|
|
96057
|
-
var
|
|
96859
|
+
var import_react27, import_jsx_runtime6;
|
|
96058
96860
|
var init_EventRenderer = __esm({
|
|
96059
96861
|
async "src/components/EventRenderer.tsx"() {
|
|
96060
96862
|
"use strict";
|
|
96863
|
+
import_react27 = __toESM(require_react(), 1);
|
|
96061
96864
|
await init_build2();
|
|
96062
96865
|
init_useEventAccumulator();
|
|
96063
96866
|
await init_MarkdownBlock();
|
|
96064
96867
|
await init_ToolCallBlock();
|
|
96065
|
-
|
|
96868
|
+
init_theme();
|
|
96869
|
+
init_rail();
|
|
96870
|
+
await init_ErrorBlock();
|
|
96871
|
+
init_describe_error();
|
|
96872
|
+
import_jsx_runtime6 = __toESM(require_jsx_runtime(), 1);
|
|
96873
|
+
}
|
|
96874
|
+
});
|
|
96875
|
+
|
|
96876
|
+
// src/render/describe-approval.ts
|
|
96877
|
+
function describeApproval(req) {
|
|
96878
|
+
const reason = req.reason.trim();
|
|
96879
|
+
const sentence = reason === "" ? "" : `${reason[0].toUpperCase()}${reason.slice(1)}${/[.!?]$/.test(reason) ? "" : "."}`;
|
|
96880
|
+
switch (req.kind) {
|
|
96881
|
+
case "exec":
|
|
96882
|
+
return sentence !== "" ? `Runs a shell command. ${sentence}` : "Runs a shell command.";
|
|
96883
|
+
case "edit_file":
|
|
96884
|
+
return sentence !== "" ? `Edits a file in your project. ${sentence}` : "Edits a file in your project.";
|
|
96885
|
+
case "write_file":
|
|
96886
|
+
return sentence !== "" ? `Writes a file in your project. ${sentence}` : "Writes a file in your project.";
|
|
96887
|
+
default:
|
|
96888
|
+
return sentence !== "" ? sentence : "Needs your approval.";
|
|
96889
|
+
}
|
|
96890
|
+
}
|
|
96891
|
+
var init_describe_approval = __esm({
|
|
96892
|
+
"src/render/describe-approval.ts"() {
|
|
96893
|
+
"use strict";
|
|
96066
96894
|
}
|
|
96067
96895
|
});
|
|
96068
96896
|
|
|
96069
96897
|
// src/components/PermissionPrompt.tsx
|
|
96070
96898
|
function permissionOptions(req) {
|
|
96071
|
-
const second = req.kind === "exec" ? `Yes, and don't ask again for this exact command` : "Yes, and allow all edits this session";
|
|
96899
|
+
const second = req.kind === "exec" ? `Yes, and don't ask again for this exact command this session` : "Yes, and allow all edits this session";
|
|
96072
96900
|
return ["Yes", second, "No, tell the agent what to do instead"];
|
|
96073
96901
|
}
|
|
96074
96902
|
function PermissionPrompt({ req, onDecide }) {
|
|
96075
|
-
const [selected, setSelected] = (0,
|
|
96076
|
-
const [typing, setTyping] = (0,
|
|
96077
|
-
const [feedback, setFeedback] = (0,
|
|
96903
|
+
const [selected, setSelected] = (0, import_react28.useState)(0);
|
|
96904
|
+
const [typing, setTyping] = (0, import_react28.useState)(false);
|
|
96905
|
+
const [feedback, setFeedback] = (0, import_react28.useState)("");
|
|
96078
96906
|
const options = permissionOptions(req);
|
|
96907
|
+
const unicode = activeGlyphs().rail === "\u2502";
|
|
96079
96908
|
const { isRawModeSupported } = use_stdin_default();
|
|
96080
96909
|
const choose = (index) => {
|
|
96081
96910
|
if (index === 0) onDecide({ approved: true });
|
|
@@ -96107,39 +96936,42 @@ function PermissionPrompt({ req, onDecide }) {
|
|
|
96107
96936
|
}
|
|
96108
96937
|
}, { isActive: Boolean(isRawModeSupported) });
|
|
96109
96938
|
const title = req.kind === "exec" ? "Run command?" : req.kind === "edit_file" ? "Edit file?" : "Write file?";
|
|
96110
|
-
return /* @__PURE__ */ (0,
|
|
96111
|
-
/* @__PURE__ */ (0,
|
|
96112
|
-
/* @__PURE__ */ (0,
|
|
96113
|
-
req.preview && /* @__PURE__ */ (0,
|
|
96114
|
-
/* @__PURE__ */ (0,
|
|
96115
|
-
req
|
|
96939
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Box_default, { flexDirection: "column", borderStyle: unicode ? "round" : "classic", borderColor: paint("needsYou").color, paddingX: 1, children: [
|
|
96940
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { bold: true, ...paint("needsYou"), children: title }),
|
|
96941
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { children: req.subject }),
|
|
96942
|
+
req.preview && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DiffBlock, { oldStr: req.preview.oldText, newStr: req.preview.newText, filePath: req.subject }),
|
|
96943
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { ...paint("secondary"), children: [
|
|
96944
|
+
describeApproval(req),
|
|
96116
96945
|
" (",
|
|
96117
96946
|
req.rule,
|
|
96118
96947
|
")"
|
|
96119
96948
|
] }),
|
|
96120
|
-
options.map((label, i) => /* @__PURE__ */ (0,
|
|
96121
|
-
i === selected ? "\u276F " : " ",
|
|
96949
|
+
options.map((label, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { ...i === selected ? paint("action") : {}, children: [
|
|
96950
|
+
i === selected ? unicode ? "\u276F " : "> " : " ",
|
|
96122
96951
|
i + 1,
|
|
96123
96952
|
". ",
|
|
96124
96953
|
label
|
|
96125
96954
|
] }, label)),
|
|
96126
|
-
typing ? /* @__PURE__ */ (0,
|
|
96955
|
+
typing ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { children: [
|
|
96127
96956
|
"Tell the agent what to do instead: ",
|
|
96128
96957
|
feedback,
|
|
96129
|
-
/* @__PURE__ */ (0,
|
|
96958
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { inverse: true, children: " " }),
|
|
96130
96959
|
" ",
|
|
96131
|
-
/* @__PURE__ */ (0,
|
|
96132
|
-
] }) : /* @__PURE__ */ (0,
|
|
96960
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { ...paint("secondary"), children: "(Enter to send, Esc to go back)" })
|
|
96961
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { ...paint("secondary"), children: unicode ? "\u2191/\u2193 Enter or 1-3 to choose \xB7 Esc to refuse" : "up/down Enter or 1-3 to choose - Esc to refuse" })
|
|
96133
96962
|
] });
|
|
96134
96963
|
}
|
|
96135
|
-
var
|
|
96964
|
+
var import_react28, import_jsx_runtime7;
|
|
96136
96965
|
var init_PermissionPrompt = __esm({
|
|
96137
96966
|
async "src/components/PermissionPrompt.tsx"() {
|
|
96138
96967
|
"use strict";
|
|
96139
|
-
|
|
96968
|
+
import_react28 = __toESM(require_react(), 1);
|
|
96140
96969
|
await init_build2();
|
|
96141
96970
|
await init_ToolCallBlock();
|
|
96142
|
-
|
|
96971
|
+
init_describe_approval();
|
|
96972
|
+
init_rail();
|
|
96973
|
+
init_theme();
|
|
96974
|
+
import_jsx_runtime7 = __toESM(require_jsx_runtime(), 1);
|
|
96143
96975
|
}
|
|
96144
96976
|
});
|
|
96145
96977
|
|
|
@@ -96147,10 +96979,10 @@ var init_PermissionPrompt = __esm({
|
|
|
96147
96979
|
function TodoChecklist({ todos }) {
|
|
96148
96980
|
if (todos.length === 0) return null;
|
|
96149
96981
|
const done = todos.filter((t) => t.status === "completed").length;
|
|
96150
|
-
return /* @__PURE__ */ (0,
|
|
96151
|
-
/* @__PURE__ */ (0,
|
|
96982
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box_default, { flexDirection: "column", marginTop: 1, children: [
|
|
96983
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Text, { bold: true, children: [
|
|
96152
96984
|
"Tasks ",
|
|
96153
|
-
/* @__PURE__ */ (0,
|
|
96985
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Text, { ...paint("secondary"), children: [
|
|
96154
96986
|
"(",
|
|
96155
96987
|
done,
|
|
96156
96988
|
"/",
|
|
@@ -96158,11 +96990,10 @@ function TodoChecklist({ todos }) {
|
|
|
96158
96990
|
")"
|
|
96159
96991
|
] })
|
|
96160
96992
|
] }),
|
|
96161
|
-
todos.map((t, i) => /* @__PURE__ */ (0,
|
|
96993
|
+
todos.map((t, i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
96162
96994
|
Text,
|
|
96163
96995
|
{
|
|
96164
|
-
|
|
96165
|
-
dimColor: t.status === "completed",
|
|
96996
|
+
...t.status === "in_progress" ? paint("action") : t.status === "completed" ? paint("secondary") : {},
|
|
96166
96997
|
bold: t.status === "in_progress",
|
|
96167
96998
|
strikethrough: t.status === "completed",
|
|
96168
96999
|
children: [
|
|
@@ -96176,35 +97007,17 @@ function TodoChecklist({ todos }) {
|
|
|
96176
97007
|
))
|
|
96177
97008
|
] });
|
|
96178
97009
|
}
|
|
96179
|
-
var
|
|
97010
|
+
var import_jsx_runtime8, TODO_MARKS;
|
|
96180
97011
|
var init_TodoChecklist = __esm({
|
|
96181
97012
|
async "src/components/TodoChecklist.tsx"() {
|
|
96182
97013
|
"use strict";
|
|
96183
97014
|
await init_build2();
|
|
96184
|
-
|
|
97015
|
+
init_theme();
|
|
97016
|
+
import_jsx_runtime8 = __toESM(require_jsx_runtime(), 1);
|
|
96185
97017
|
TODO_MARKS = { pending: "\u2610", in_progress: "\u25D0", completed: "\u2611" };
|
|
96186
97018
|
}
|
|
96187
97019
|
});
|
|
96188
97020
|
|
|
96189
|
-
// src/render/mode-line.ts
|
|
96190
|
-
function modeLine(mode) {
|
|
96191
|
-
switch (mode) {
|
|
96192
|
-
case "default":
|
|
96193
|
-
return { text: "? default mode (shift+tab to cycle)" };
|
|
96194
|
-
case "accept-edits":
|
|
96195
|
-
return { text: "\u23F5\u23F5 accept edits on (shift+tab to cycle)", color: "green" };
|
|
96196
|
-
case "plan":
|
|
96197
|
-
return { text: "\u23F8 plan mode, read-only (shift+tab to cycle)", color: "blue" };
|
|
96198
|
-
case "yolo":
|
|
96199
|
-
return { text: "\u26A0 yolo, no prompts (shift+tab to cycle)", color: "red" };
|
|
96200
|
-
}
|
|
96201
|
-
}
|
|
96202
|
-
var init_mode_line = __esm({
|
|
96203
|
-
"src/render/mode-line.ts"() {
|
|
96204
|
-
"use strict";
|
|
96205
|
-
}
|
|
96206
|
-
});
|
|
96207
|
-
|
|
96208
97021
|
// src/render/footer.ts
|
|
96209
97022
|
function estimateCostUsd(inputTokens, outputTokens) {
|
|
96210
97023
|
return (inputTokens * ESTIMATED_USD_PER_MTOK.input + outputTokens * ESTIMATED_USD_PER_MTOK.output) / 1e6;
|
|
@@ -96222,31 +97035,45 @@ function contextPercent(usedTokens, maxTokens) {
|
|
|
96222
97035
|
function contextLevel(pct) {
|
|
96223
97036
|
return pct >= CONTEXT_CRITICAL_PCT ? "critical" : pct >= CONTEXT_WARN_PCT ? "warn" : "ok";
|
|
96224
97037
|
}
|
|
97038
|
+
function contextBar(pct, unicode = true) {
|
|
97039
|
+
const filled = Math.max(0, Math.min(BAR_CELLS, Math.round(pct / 100 * BAR_CELLS)));
|
|
97040
|
+
return unicode ? "\u25B0".repeat(filled) + "\u25B1".repeat(BAR_CELLS - filled) : `[${"#".repeat(filled)}${"-".repeat(BAR_CELLS - filled)}]`;
|
|
97041
|
+
}
|
|
97042
|
+
function formatModel(model) {
|
|
97043
|
+
return model === void 0 ? MODEL_PLACEHOLDER : `${model} (selected)`;
|
|
97044
|
+
}
|
|
96225
97045
|
function formatFooter({ mode, contextPct, costUsd, model, columns }) {
|
|
96226
97046
|
const level = contextLevel(contextPct);
|
|
96227
|
-
const
|
|
96228
|
-
const
|
|
97047
|
+
const unicode = activeGlyphs().rail === "\u2502";
|
|
97048
|
+
const mark = level === "critical" ? " !!" : level === "warn" ? " !" : "";
|
|
97049
|
+
const ctx = columns >= BAR_MIN_COLUMNS ? `ctx ${contextBar(contextPct, unicode)} ${contextPct}%${mark}` : `ctx ${contextPct}%${mark}`;
|
|
97050
|
+
const fields = [modeLine(mode, unicode).text, ctx, formatCost(costUsd), formatModel(model)];
|
|
96229
97051
|
while (fields.length > 1 && fields.join(" ").length > columns) fields.pop();
|
|
96230
97052
|
return { text: fields.join(" "), level };
|
|
96231
97053
|
}
|
|
96232
|
-
function formatTurnSummary({ toolCount, elapsedMs, inputTokens, outputTokens, interrupted, failed }) {
|
|
97054
|
+
function formatTurnSummary({ toolCount, elapsedMs, inputTokens, outputTokens, interrupted, failed }, unicode = true) {
|
|
96233
97055
|
const tools = `${toolCount} tool${toolCount === 1 ? "" : "s"}`;
|
|
96234
97056
|
const secs = (elapsedMs / 1e3).toFixed(1);
|
|
96235
|
-
const
|
|
96236
|
-
|
|
97057
|
+
const [ok, bad, bar, arrow] = unicode ? ["\u2713", "\u2717", "\u2502", "\u2192"] : ["+", "x", "|", "->"];
|
|
97058
|
+
const head = interrupted ? `${bad} Interrupted (${tools}, ${secs}s)` : failed ? `${bad} Failed (${tools}, ${secs}s)` : `${ok} Done (${tools}, ${secs}s)`;
|
|
97059
|
+
return `${head} ${bar} ${formatTokens(inputTokens)} ${arrow} ${formatTokens(outputTokens)} ${bar} ${formatCost(estimateCostUsd(inputTokens, outputTokens))}`;
|
|
96237
97060
|
}
|
|
96238
|
-
function formatThinking(elapsedMs, approxTokens) {
|
|
96239
|
-
|
|
97061
|
+
function formatThinking(elapsedMs, approxTokens, unicode = true) {
|
|
97062
|
+
const [mark, dots, sep2] = unicode ? ["\u273B", "\u2026", "\xB7"] : ["*", "...", "-"];
|
|
97063
|
+
return `${mark} Thinking${dots} (${Math.floor(elapsedMs / 1e3)}s ${sep2} ~${formatTokens(approxTokens)} tokens ${sep2} esc to interrupt)`;
|
|
96240
97064
|
}
|
|
96241
|
-
var ESTIMATED_USD_PER_MTOK, MODEL_PLACEHOLDER, CONTEXT_WARN_PCT, CONTEXT_CRITICAL_PCT;
|
|
97065
|
+
var ESTIMATED_USD_PER_MTOK, MODEL_PLACEHOLDER, CONTEXT_WARN_PCT, CONTEXT_CRITICAL_PCT, BAR_CELLS, BAR_MIN_COLUMNS;
|
|
96242
97066
|
var init_footer = __esm({
|
|
96243
97067
|
"src/render/footer.ts"() {
|
|
96244
97068
|
"use strict";
|
|
96245
97069
|
init_mode_line();
|
|
97070
|
+
init_rail();
|
|
96246
97071
|
ESTIMATED_USD_PER_MTOK = { input: 0.5, output: 1.5 };
|
|
96247
97072
|
MODEL_PLACEHOLDER = "gateway default";
|
|
96248
97073
|
CONTEXT_WARN_PCT = 80;
|
|
96249
97074
|
CONTEXT_CRITICAL_PCT = 95;
|
|
97075
|
+
BAR_CELLS = 8;
|
|
97076
|
+
BAR_MIN_COLUMNS = 60;
|
|
96250
97077
|
}
|
|
96251
97078
|
});
|
|
96252
97079
|
|
|
@@ -96449,17 +97276,17 @@ function isSubsequence(needle, hay) {
|
|
|
96449
97276
|
for (let j2 = 0; j2 < hay.length && i < needle.length; j2++) if (hay[j2] === needle[i]) i++;
|
|
96450
97277
|
return i === needle.length;
|
|
96451
97278
|
}
|
|
96452
|
-
function tier(
|
|
96453
|
-
const base =
|
|
97279
|
+
function tier(path11, q2) {
|
|
97280
|
+
const base = path11.slice(path11.lastIndexOf("/") + 1);
|
|
96454
97281
|
if (base.startsWith(q2)) return 0;
|
|
96455
97282
|
if (base.includes(q2)) return 1;
|
|
96456
|
-
if (
|
|
97283
|
+
if (path11.includes(q2)) return 2;
|
|
96457
97284
|
return 3;
|
|
96458
97285
|
}
|
|
96459
97286
|
function rankPaths(paths, query, limit = 8) {
|
|
96460
97287
|
if (query === "") return paths.slice(0, limit);
|
|
96461
97288
|
const q2 = query.toLowerCase();
|
|
96462
|
-
return paths.map((
|
|
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);
|
|
96463
97290
|
}
|
|
96464
97291
|
var init_mention_rank = __esm({
|
|
96465
97292
|
"src/editor/mention-rank.ts"() {
|
|
@@ -96476,9 +97303,9 @@ function activeMention(text, cursor) {
|
|
|
96476
97303
|
const explicit = token[1] === "!";
|
|
96477
97304
|
return { start, query: token.slice(explicit ? 2 : 1), explicit };
|
|
96478
97305
|
}
|
|
96479
|
-
function insertMention(text, cursor, mention,
|
|
96480
|
-
if (/\s/.test(
|
|
96481
|
-
const inserted = `@${mention.explicit ? "!" : ""}${
|
|
97306
|
+
function insertMention(text, cursor, mention, path11) {
|
|
97307
|
+
if (/\s/.test(path11)) return { text, cursor };
|
|
97308
|
+
const inserted = `@${mention.explicit ? "!" : ""}${path11}`;
|
|
96482
97309
|
const head = text.slice(0, mention.start) + inserted;
|
|
96483
97310
|
const next = text[cursor];
|
|
96484
97311
|
if (next !== void 0 && /\s/.test(next)) return { text: head + text.slice(cursor), cursor: head.length + 1 };
|
|
@@ -96524,7 +97351,16 @@ function isKnownSlashCommand(name) {
|
|
|
96524
97351
|
function formatHelp() {
|
|
96525
97352
|
const width = Math.max(...SLASH_COMMANDS.map((c) => c.name.length));
|
|
96526
97353
|
const lines2 = SLASH_COMMANDS.map((c) => ` /${c.name.padEnd(width)} ${c.description}`);
|
|
96527
|
-
return [
|
|
97354
|
+
return [
|
|
97355
|
+
"Commands:",
|
|
97356
|
+
...lines2,
|
|
97357
|
+
"",
|
|
97358
|
+
" tab (no menu open) focus a step of the running turn: \u2191\u2193 move, enter opens its output, esc leaves; ctrl+o or /turns browses finished turns",
|
|
97359
|
+
" @path attach a file to your message (@!path overrides the secret/.gitignore filters)",
|
|
97360
|
+
" ! on an empty prompt: shell mode, runs a command on this machine (not sent to the model)",
|
|
97361
|
+
"",
|
|
97362
|
+
"Press Esc while the agent is running to cancel the turn."
|
|
97363
|
+
].join("\n");
|
|
96528
97364
|
}
|
|
96529
97365
|
var SLASH_COMMANDS;
|
|
96530
97366
|
var init_slash_commands = __esm({
|
|
@@ -96539,6 +97375,7 @@ var init_slash_commands = __esm({
|
|
|
96539
97375
|
{ name: "status", description: "Show project, session, mode, context and cost" },
|
|
96540
97376
|
{ name: "compact", description: "Summarize the conversation to free up context" },
|
|
96541
97377
|
{ name: "model", description: "List gateway models; /model <n|id> switches for this session" },
|
|
97378
|
+
{ name: "turns", description: "Browse earlier turns and open their steps (shortcut: ctrl+o)" },
|
|
96542
97379
|
{ name: "tools", description: "List the tools available to the agent" },
|
|
96543
97380
|
{ name: "exit", description: "Quit the REPL (alias: /quit)" },
|
|
96544
97381
|
{ name: "quit", description: "Quit the REPL" }
|
|
@@ -96555,41 +97392,41 @@ function validateSubmission(text) {
|
|
|
96555
97392
|
function withCursor(row, col) {
|
|
96556
97393
|
return `${row.slice(0, col)}\x1B[7m${row[col] ?? " "}\x1B[27m${row.slice(col + 1)}`;
|
|
96557
97394
|
}
|
|
96558
|
-
function PromptEditor({ onSubmit, disabled, history, listFiles: listFiles2 }) {
|
|
97395
|
+
function PromptEditor({ onSubmit, disabled, history, listFiles: listFiles2, onTab, locked = false, promptGlyph: promptGlyph2 = ">", onEmptyEnter }) {
|
|
96559
97396
|
const { exit } = use_app_default();
|
|
96560
97397
|
const { isRawModeSupported } = use_stdin_default();
|
|
96561
|
-
const [buf, setBuf] = (0,
|
|
96562
|
-
const [hint, setHint] = (0,
|
|
96563
|
-
const bufRef = (0,
|
|
96564
|
-
const queue = (0,
|
|
96565
|
-
const [files, setFiles] = (0,
|
|
96566
|
-
const filesRef = (0,
|
|
96567
|
-
const loadingFiles = (0,
|
|
96568
|
-
const [sel, setSel] = (0,
|
|
96569
|
-
const selRef = (0,
|
|
96570
|
-
const [shell, setShellState] = (0,
|
|
96571
|
-
const shellRef = (0,
|
|
97398
|
+
const [buf, setBuf] = (0, import_react29.useState)(() => createBuffer());
|
|
97399
|
+
const [hint, setHint] = (0, import_react29.useState)(null);
|
|
97400
|
+
const bufRef = (0, import_react29.useRef)(buf);
|
|
97401
|
+
const queue = (0, import_react29.useRef)([]);
|
|
97402
|
+
const [files, setFiles] = (0, import_react29.useState)(null);
|
|
97403
|
+
const filesRef = (0, import_react29.useRef)(null);
|
|
97404
|
+
const loadingFiles = (0, import_react29.useRef)(false);
|
|
97405
|
+
const [sel, setSel] = (0, import_react29.useState)(0);
|
|
97406
|
+
const selRef = (0, import_react29.useRef)(0);
|
|
97407
|
+
const [shell, setShellState] = (0, import_react29.useState)(false);
|
|
97408
|
+
const shellRef = (0, import_react29.useRef)(false);
|
|
96572
97409
|
const setShell = (on) => {
|
|
96573
97410
|
shellRef.current = on;
|
|
96574
97411
|
setShellState(on);
|
|
96575
97412
|
};
|
|
96576
97413
|
bufRef.current = buf;
|
|
96577
|
-
const fail = (0,
|
|
97414
|
+
const fail = (0, import_react29.useCallback)((what, err) => {
|
|
96578
97415
|
setHint(`${what}: ${err instanceof Error ? err.message : String(err)}`);
|
|
96579
97416
|
}, []);
|
|
96580
|
-
(0,
|
|
97417
|
+
(0, import_react29.useEffect)(() => {
|
|
96581
97418
|
history?.load().catch((err) => fail("Could not load prompt history", err));
|
|
96582
97419
|
}, [history, fail]);
|
|
96583
|
-
const dispatch = (0,
|
|
97420
|
+
const dispatch = (0, import_react29.useCallback)((text) => {
|
|
96584
97421
|
const result = onSubmit(text);
|
|
96585
97422
|
if (result instanceof Promise) result.catch((err) => fail("Submit failed", err));
|
|
96586
97423
|
}, [onSubmit, fail]);
|
|
96587
|
-
(0,
|
|
97424
|
+
(0, import_react29.useEffect)(() => {
|
|
96588
97425
|
if (!disabled && queue.current.length > 0) dispatch(queue.current.shift());
|
|
96589
97426
|
}, [disabled, dispatch]);
|
|
96590
97427
|
const mention = shell ? null : activeMention(buf.text, buf.cursor);
|
|
96591
97428
|
const mentionOpen = mention !== null;
|
|
96592
|
-
(0,
|
|
97429
|
+
(0, import_react29.useEffect)(() => {
|
|
96593
97430
|
if (!mentionOpen || !listFiles2 || filesRef.current !== null || loadingFiles.current) return;
|
|
96594
97431
|
loadingFiles.current = true;
|
|
96595
97432
|
listFiles2().then((f) => {
|
|
@@ -96659,6 +97496,7 @@ function PromptEditor({ onSubmit, disabled, history, listFiles: listFiles2 }) {
|
|
|
96659
97496
|
case "tab": {
|
|
96660
97497
|
const completed = completeSlash(cur.text, slashMatches(cur.text, SLASH_COMMANDS));
|
|
96661
97498
|
if (completed) update(createBuffer(completed));
|
|
97499
|
+
else onTab?.();
|
|
96662
97500
|
return;
|
|
96663
97501
|
}
|
|
96664
97502
|
case "historyPrev":
|
|
@@ -96685,6 +97523,7 @@ function PromptEditor({ onSubmit, disabled, history, listFiles: listFiles2 }) {
|
|
|
96685
97523
|
const typed = cur.text.trim();
|
|
96686
97524
|
if (typed === "") {
|
|
96687
97525
|
if (inShell) setHint("Type a command after ! (Backspace on an empty prompt leaves shell mode)");
|
|
97526
|
+
else onEmptyEnter?.();
|
|
96688
97527
|
return;
|
|
96689
97528
|
}
|
|
96690
97529
|
const text = inShell ? `!${typed}` : typed;
|
|
@@ -96702,9 +97541,9 @@ function PromptEditor({ onSubmit, disabled, history, listFiles: listFiles2 }) {
|
|
|
96702
97541
|
else dispatch(text);
|
|
96703
97542
|
}
|
|
96704
97543
|
}
|
|
96705
|
-
}, { isActive: Boolean(isRawModeSupported) });
|
|
97544
|
+
}, { isActive: Boolean(isRawModeSupported) && !locked });
|
|
96706
97545
|
if (!isRawModeSupported) {
|
|
96707
|
-
return /* @__PURE__ */ (0,
|
|
97546
|
+
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.' });
|
|
96708
97547
|
}
|
|
96709
97548
|
if (disabled && buf.text === "") return null;
|
|
96710
97549
|
const rows = lines(buf);
|
|
@@ -96712,26 +97551,26 @@ function PromptEditor({ onSubmit, disabled, history, listFiles: listFiles2 }) {
|
|
|
96712
97551
|
const matches = shell ? [] : slashMatches(buf.text, SLASH_COMMANDS);
|
|
96713
97552
|
const picks = mention && files ? rankPaths(files, mention.query, PICKER_ROWS) : [];
|
|
96714
97553
|
const pickAt = Math.min(sel, Math.max(picks.length - 1, 0));
|
|
96715
|
-
return /* @__PURE__ */ (0,
|
|
96716
|
-
rows.map((row, i) => /* @__PURE__ */ (0,
|
|
96717
|
-
/* @__PURE__ */ (0,
|
|
96718
|
-
/* @__PURE__ */ (0,
|
|
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: [
|
|
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 })
|
|
96719
97558
|
] }, i)),
|
|
96720
|
-
matches.length > 0 && /* @__PURE__ */ (0,
|
|
97559
|
+
matches.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { ...paint("secondary"), children: [
|
|
96721
97560
|
matches.map((c) => `/${c.name} \u2014 ${c.description}`).join(" "),
|
|
96722
97561
|
" (Tab to complete)"
|
|
96723
97562
|
] }),
|
|
96724
|
-
shell && buf.text === "" && !disabled && /* @__PURE__ */ (0,
|
|
96725
|
-
picks.map((p, i) => /* @__PURE__ */ (0,
|
|
96726
|
-
picks.length > 0 && /* @__PURE__ */ (0,
|
|
96727
|
-
hint && /* @__PURE__ */ (0,
|
|
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)" }),
|
|
97566
|
+
hint && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { ...paint("delete"), children: hint })
|
|
96728
97567
|
] });
|
|
96729
97568
|
}
|
|
96730
|
-
var
|
|
97569
|
+
var import_react29, import_jsx_runtime9, PICKER_ROWS;
|
|
96731
97570
|
var init_PromptEditor = __esm({
|
|
96732
97571
|
async "src/components/PromptEditor.tsx"() {
|
|
96733
97572
|
"use strict";
|
|
96734
|
-
|
|
97573
|
+
import_react29 = __toESM(require_react(), 1);
|
|
96735
97574
|
await init_build2();
|
|
96736
97575
|
init_edit_buffer();
|
|
96737
97576
|
init_editor_keys();
|
|
@@ -96739,33 +97578,12 @@ var init_PromptEditor = __esm({
|
|
|
96739
97578
|
init_mention_token();
|
|
96740
97579
|
init_slash_menu();
|
|
96741
97580
|
init_slash_commands();
|
|
96742
|
-
|
|
97581
|
+
init_theme();
|
|
97582
|
+
import_jsx_runtime9 = __toESM(require_jsx_runtime(), 1);
|
|
96743
97583
|
PICKER_ROWS = 6;
|
|
96744
97584
|
}
|
|
96745
97585
|
});
|
|
96746
97586
|
|
|
96747
|
-
// src/editor/credential-filter.ts
|
|
96748
|
-
function containsCredential(entry) {
|
|
96749
|
-
return PATTERNS.some((re3) => re3.test(entry));
|
|
96750
|
-
}
|
|
96751
|
-
var PATTERNS;
|
|
96752
|
-
var init_credential_filter = __esm({
|
|
96753
|
-
"src/editor/credential-filter.ts"() {
|
|
96754
|
-
"use strict";
|
|
96755
|
-
PATTERNS = [
|
|
96756
|
-
/\bsk[_-][A-Za-z0-9_-]{16,}/,
|
|
96757
|
-
/\bgh[pos]_[A-Za-z0-9]{20,}/,
|
|
96758
|
-
/\bgithub_pat_[A-Za-z0-9_]{20,}/,
|
|
96759
|
-
/\bAKIA[0-9A-Z]{16}\b/,
|
|
96760
|
-
/\bBearer\s+[A-Za-z0-9._~+/=-]{20,}/,
|
|
96761
|
-
/-----BEGIN [A-Z ]*PRIVATE KEY-----/,
|
|
96762
|
-
/\bxox[abp]-[A-Za-z0-9-]{10,}/,
|
|
96763
|
-
/\bnpm_[A-Za-z0-9]{30,}/,
|
|
96764
|
-
/\b[A-Za-z0-9_]*(?:KEY|TOKEN|SECRET|PASSWORD)[A-Za-z0-9_]*=\S{8,}/i
|
|
96765
|
-
];
|
|
96766
|
-
}
|
|
96767
|
-
});
|
|
96768
|
-
|
|
96769
97587
|
// src/editor/history-store.ts
|
|
96770
97588
|
var PromptHistory;
|
|
96771
97589
|
var init_history_store = __esm({
|
|
@@ -96847,24 +97665,24 @@ var init_history_store = __esm({
|
|
|
96847
97665
|
});
|
|
96848
97666
|
|
|
96849
97667
|
// src/editor/history-file-io.ts
|
|
96850
|
-
import { chmod, mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
96851
|
-
import
|
|
97668
|
+
import { chmod as chmod2, mkdir as mkdir2, readFile as readFile2, rename as rename2, writeFile as writeFile2 } from "node:fs/promises";
|
|
97669
|
+
import path2 from "node:path";
|
|
96852
97670
|
function createFileHistoryIO(file) {
|
|
96853
97671
|
return {
|
|
96854
97672
|
async read() {
|
|
96855
97673
|
try {
|
|
96856
|
-
return await
|
|
97674
|
+
return await readFile2(file, "utf8");
|
|
96857
97675
|
} catch (err) {
|
|
96858
97676
|
if (err.code === "ENOENT") return null;
|
|
96859
97677
|
throw err;
|
|
96860
97678
|
}
|
|
96861
97679
|
},
|
|
96862
97680
|
async write(content) {
|
|
96863
|
-
await
|
|
97681
|
+
await mkdir2(path2.dirname(file), { recursive: true, mode: 448 });
|
|
96864
97682
|
const tmp = `${file}.${process.pid}.tmp`;
|
|
96865
|
-
await
|
|
96866
|
-
await
|
|
96867
|
-
await
|
|
97683
|
+
await writeFile2(tmp, content, { mode: 384 });
|
|
97684
|
+
await chmod2(tmp, 384);
|
|
97685
|
+
await rename2(tmp, file);
|
|
96868
97686
|
}
|
|
96869
97687
|
};
|
|
96870
97688
|
}
|
|
@@ -97310,6 +98128,7 @@ async function runAgentLoop(prompt, config, executor, emit, signal, existingMess
|
|
|
97310
98128
|
}
|
|
97311
98129
|
lastToolCount = toolUseBlocks.length;
|
|
97312
98130
|
if (data.stop_reason !== "tool_use") {
|
|
98131
|
+
if (data.content.length > 0) messages.push({ role: "assistant", content: data.content });
|
|
97313
98132
|
emitDone(emit, {
|
|
97314
98133
|
type: "done",
|
|
97315
98134
|
success: true,
|
|
@@ -97539,9 +98358,9 @@ function createFileTools(store) {
|
|
|
97539
98358
|
readCache.clear();
|
|
97540
98359
|
listCache.clear();
|
|
97541
98360
|
}
|
|
97542
|
-
function invalidatePath(
|
|
97543
|
-
readCache.delete(
|
|
97544
|
-
const parent =
|
|
98361
|
+
function invalidatePath(path11) {
|
|
98362
|
+
readCache.delete(path11);
|
|
98363
|
+
const parent = path11.includes("/") ? path11.slice(0, path11.lastIndexOf("/") + 1) : "";
|
|
97545
98364
|
listCache.delete(parent);
|
|
97546
98365
|
listCache.delete("");
|
|
97547
98366
|
listCache.delete(".");
|
|
@@ -97549,36 +98368,36 @@ function createFileTools(store) {
|
|
|
97549
98368
|
}
|
|
97550
98369
|
const handlers = {
|
|
97551
98370
|
read_file: async (input) => {
|
|
97552
|
-
const
|
|
97553
|
-
const cached = readCache.get(
|
|
98371
|
+
const path11 = input.path;
|
|
98372
|
+
const cached = readCache.get(path11);
|
|
97554
98373
|
if (cached !== void 0) {
|
|
97555
98374
|
return { output: cached };
|
|
97556
98375
|
}
|
|
97557
|
-
const content = await store.readFile(
|
|
98376
|
+
const content = await store.readFile(path11);
|
|
97558
98377
|
if (content === null) {
|
|
97559
|
-
return { output: `File not found: ${
|
|
98378
|
+
return { output: `File not found: ${path11}`, is_error: true };
|
|
97560
98379
|
}
|
|
97561
|
-
readCache.set(
|
|
98380
|
+
readCache.set(path11, content);
|
|
97562
98381
|
return { output: content };
|
|
97563
98382
|
},
|
|
97564
98383
|
write_file: async (input) => {
|
|
97565
|
-
const
|
|
98384
|
+
const path11 = input.path;
|
|
97566
98385
|
const content = input.content;
|
|
97567
|
-
await store.writeFile(
|
|
97568
|
-
invalidatePath(
|
|
97569
|
-
readCache.set(
|
|
97570
|
-
return { output: `Written: ${
|
|
98386
|
+
await store.writeFile(path11, content);
|
|
98387
|
+
invalidatePath(path11);
|
|
98388
|
+
readCache.set(path11, content);
|
|
98389
|
+
return { output: `Written: ${path11}` };
|
|
97571
98390
|
},
|
|
97572
98391
|
edit_file: async (input) => {
|
|
97573
|
-
const
|
|
98392
|
+
const path11 = input.path;
|
|
97574
98393
|
const oldStr = input.old_string;
|
|
97575
98394
|
const newStr = input.new_string;
|
|
97576
|
-
let content = readCache.get(
|
|
98395
|
+
let content = readCache.get(path11);
|
|
97577
98396
|
if (content === void 0) {
|
|
97578
|
-
const stored = await store.readFile(
|
|
98397
|
+
const stored = await store.readFile(path11);
|
|
97579
98398
|
if (stored === null) {
|
|
97580
98399
|
return {
|
|
97581
|
-
output: `File not found: ${
|
|
98400
|
+
output: `File not found: ${path11}. Did you read the file first?`,
|
|
97582
98401
|
is_error: true
|
|
97583
98402
|
};
|
|
97584
98403
|
}
|
|
@@ -97588,41 +98407,41 @@ function createFileTools(store) {
|
|
|
97588
98407
|
if (lineNumbers.length === 0) {
|
|
97589
98408
|
const lineCount = content.split("\n").length;
|
|
97590
98409
|
return {
|
|
97591
|
-
output: `old_string not found in ${
|
|
98410
|
+
output: `old_string not found in ${path11}. The file has ${lineCount} lines. Did you read the file first?`,
|
|
97592
98411
|
is_error: true
|
|
97593
98412
|
};
|
|
97594
98413
|
}
|
|
97595
98414
|
if (lineNumbers.length > 1) {
|
|
97596
98415
|
const locations = lineNumbers.map((ln) => ` - line ${ln}`).join("\n");
|
|
97597
98416
|
return {
|
|
97598
|
-
output: `old_string matches ${lineNumbers.length} locations in ${
|
|
98417
|
+
output: `old_string matches ${lineNumbers.length} locations in ${path11}:
|
|
97599
98418
|
${locations}
|
|
97600
98419
|
Include more surrounding context to make old_string unique.`,
|
|
97601
98420
|
is_error: true
|
|
97602
98421
|
};
|
|
97603
98422
|
}
|
|
97604
|
-
const result = await store.editFile(
|
|
98423
|
+
const result = await store.editFile(path11, oldStr, newStr);
|
|
97605
98424
|
if (!result.success) {
|
|
97606
98425
|
return { output: result.error, is_error: true };
|
|
97607
98426
|
}
|
|
97608
|
-
invalidatePath(
|
|
97609
|
-
const updated = await store.readFile(
|
|
97610
|
-
if (updated !== null) readCache.set(
|
|
97611
|
-
return { output: `Edited: ${
|
|
98427
|
+
invalidatePath(path11);
|
|
98428
|
+
const updated = await store.readFile(path11);
|
|
98429
|
+
if (updated !== null) readCache.set(path11, updated);
|
|
98430
|
+
return { output: `Edited: ${path11}` };
|
|
97612
98431
|
},
|
|
97613
98432
|
list_directory: async (input) => {
|
|
97614
|
-
const
|
|
97615
|
-
const cached = listCache.get(
|
|
98433
|
+
const path11 = input.path;
|
|
98434
|
+
const cached = listCache.get(path11);
|
|
97616
98435
|
if (cached !== void 0) {
|
|
97617
98436
|
if (cached.length === 0) {
|
|
97618
|
-
return { output: `Empty or not found: ${
|
|
98437
|
+
return { output: `Empty or not found: ${path11}` };
|
|
97619
98438
|
}
|
|
97620
98439
|
return { output: cached.join("\n") };
|
|
97621
98440
|
}
|
|
97622
|
-
const entries = await store.listDirectory(
|
|
97623
|
-
listCache.set(
|
|
98441
|
+
const entries = await store.listDirectory(path11);
|
|
98442
|
+
listCache.set(path11, entries);
|
|
97624
98443
|
if (entries.length === 0) {
|
|
97625
|
-
return { output: `Empty or not found: ${
|
|
98444
|
+
return { output: `Empty or not found: ${path11}` };
|
|
97626
98445
|
}
|
|
97627
98446
|
return { output: entries.join("\n") };
|
|
97628
98447
|
}
|
|
@@ -97858,8 +98677,8 @@ function parseTodos(input) {
|
|
|
97858
98677
|
if (typeof e.status !== "string" || !STATUSES.includes(e.status)) throw new Error(`Item ${i + 1}: "status" must be one of ${STATUSES.join(", ")}`);
|
|
97859
98678
|
return { content: e.content.trim(), status: e.status };
|
|
97860
98679
|
});
|
|
97861
|
-
const
|
|
97862
|
-
if (
|
|
98680
|
+
const active2 = items.filter((t) => t.status === "in_progress").length;
|
|
98681
|
+
if (active2 > 1) throw new Error(`Only one item may be "in_progress" at a time (found ${active2})`);
|
|
97863
98682
|
return items;
|
|
97864
98683
|
}
|
|
97865
98684
|
function createTodoTool(onUpdate) {
|
|
@@ -97958,9 +98777,9 @@ var init_host = __esm({
|
|
|
97958
98777
|
});
|
|
97959
98778
|
|
|
97960
98779
|
// ../agent/src/host/local-host.ts
|
|
97961
|
-
import { execFile } from "node:child_process";
|
|
98780
|
+
import { execFile as execFile2 } from "node:child_process";
|
|
97962
98781
|
import { promises as fs2 } from "node:fs";
|
|
97963
|
-
import * as
|
|
98782
|
+
import * as path3 from "node:path";
|
|
97964
98783
|
var LocalHost;
|
|
97965
98784
|
var init_local_host = __esm({
|
|
97966
98785
|
"../agent/src/host/local-host.ts"() {
|
|
@@ -97970,7 +98789,7 @@ var init_local_host = __esm({
|
|
|
97970
98789
|
files;
|
|
97971
98790
|
root;
|
|
97972
98791
|
constructor(rootDir) {
|
|
97973
|
-
this.root =
|
|
98792
|
+
this.root = path3.resolve(rootDir);
|
|
97974
98793
|
this.files = {
|
|
97975
98794
|
readFile: (p) => this.readFile(p),
|
|
97976
98795
|
writeFile: (p, c) => this.writeFile(p, c),
|
|
@@ -97979,12 +98798,12 @@ var init_local_host = __esm({
|
|
|
97979
98798
|
};
|
|
97980
98799
|
}
|
|
97981
98800
|
static inside(root, abs) {
|
|
97982
|
-
const rel =
|
|
97983
|
-
return !(rel === ".." || rel.startsWith(".." +
|
|
98801
|
+
const rel = path3.relative(root, abs);
|
|
98802
|
+
return !(rel === ".." || rel.startsWith(".." + path3.sep) || path3.isAbsolute(rel));
|
|
97984
98803
|
}
|
|
97985
98804
|
/** Lexical confinement plus a symlink-aware check of the deepest existing ancestor. */
|
|
97986
98805
|
async resolve(p) {
|
|
97987
|
-
const abs =
|
|
98806
|
+
const abs = path3.resolve(this.root, p);
|
|
97988
98807
|
if (!_LocalHost.inside(this.root, abs)) throw new Error(`Path escapes workspace root: ${p}`);
|
|
97989
98808
|
const realRoot = await fs2.realpath(this.root);
|
|
97990
98809
|
let probe = abs;
|
|
@@ -98002,7 +98821,7 @@ var init_local_host = __esm({
|
|
|
98002
98821
|
throw e;
|
|
98003
98822
|
});
|
|
98004
98823
|
if (st?.isSymbolicLink()) throw new Error(`Path is a dangling symlink: ${p}`);
|
|
98005
|
-
const parent =
|
|
98824
|
+
const parent = path3.dirname(probe);
|
|
98006
98825
|
if (parent === probe) break;
|
|
98007
98826
|
probe = parent;
|
|
98008
98827
|
}
|
|
@@ -98019,7 +98838,7 @@ var init_local_host = __esm({
|
|
|
98019
98838
|
}
|
|
98020
98839
|
async writeFile(p, content) {
|
|
98021
98840
|
const abs = await this.resolve(p);
|
|
98022
|
-
await fs2.mkdir(
|
|
98841
|
+
await fs2.mkdir(path3.dirname(abs), { recursive: true });
|
|
98023
98842
|
await fs2.writeFile(abs, content, "utf8");
|
|
98024
98843
|
}
|
|
98025
98844
|
async editFile(p, oldStr, newStr) {
|
|
@@ -98049,7 +98868,7 @@ var init_local_host = __esm({
|
|
|
98049
98868
|
*/
|
|
98050
98869
|
exec(command, onOutput) {
|
|
98051
98870
|
return new Promise((resolve2, reject) => {
|
|
98052
|
-
const child =
|
|
98871
|
+
const child = execFile2(
|
|
98053
98872
|
"/bin/sh",
|
|
98054
98873
|
["-c", command],
|
|
98055
98874
|
{ cwd: this.root, maxBuffer: 10 * 1024 * 1024 },
|
|
@@ -98311,7 +99130,7 @@ var init_policy = __esm({
|
|
|
98311
99130
|
|
|
98312
99131
|
// ../agent/src/host/audit-log.ts
|
|
98313
99132
|
import { promises as fs3 } from "node:fs";
|
|
98314
|
-
import * as
|
|
99133
|
+
import * as path4 from "node:path";
|
|
98315
99134
|
function truncate(e) {
|
|
98316
99135
|
return e.subject.length > MAX_SUBJECT ? { ...e, subject: e.subject.slice(0, MAX_SUBJECT) + "...[truncated]" } : e;
|
|
98317
99136
|
}
|
|
@@ -98325,7 +99144,7 @@ var init_audit_log = __esm({
|
|
|
98325
99144
|
this.file = file;
|
|
98326
99145
|
}
|
|
98327
99146
|
async record(entry) {
|
|
98328
|
-
await fs3.mkdir(
|
|
99147
|
+
await fs3.mkdir(path4.dirname(this.file), { recursive: true });
|
|
98329
99148
|
await fs3.appendFile(this.file, JSON.stringify(truncate(entry)) + "\n", { mode: 384 });
|
|
98330
99149
|
}
|
|
98331
99150
|
};
|
|
@@ -98570,136 +99389,39 @@ var init_src2 = __esm({
|
|
|
98570
99389
|
}
|
|
98571
99390
|
});
|
|
98572
99391
|
|
|
98573
|
-
// src/session/
|
|
98574
|
-
|
|
98575
|
-
|
|
98576
|
-
|
|
98577
|
-
|
|
98578
|
-
|
|
98579
|
-
|
|
98580
|
-
|
|
98581
|
-
|
|
98582
|
-
|
|
98583
|
-
|
|
98584
|
-
}
|
|
98585
|
-
|
|
98586
|
-
const lines2 = text.split("\n").filter((l) => l.length > 0);
|
|
98587
|
-
if (lines2.length === 0) throw new SessionError(file, "Session file is empty");
|
|
98588
|
-
let parsed;
|
|
98589
|
-
try {
|
|
98590
|
-
parsed = lines2.map((l) => JSON.parse(l));
|
|
98591
|
-
} catch (err) {
|
|
98592
|
-
throw new SessionError(file, `Corrupt session file: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
98593
|
-
}
|
|
98594
|
-
const meta = parsed[0];
|
|
98595
|
-
if (meta.v !== 1 || typeof meta.id !== "string" || typeof meta.projectRoot !== "string" || typeof meta.updatedAt !== "string") {
|
|
98596
|
-
throw new SessionError(file, "Unrecognized session header (expected v1 with id, projectRoot, updatedAt)");
|
|
98597
|
-
}
|
|
98598
|
-
const messages = parsed.slice(1);
|
|
98599
|
-
if (!messages.every((m2) => m2 && (m2.role === "user" || m2.role === "assistant"))) {
|
|
98600
|
-
throw new SessionError(file, "Corrupt session file: a message has no valid role");
|
|
98601
|
-
}
|
|
98602
|
-
return { meta, messages };
|
|
98603
|
-
}
|
|
98604
|
-
function formatAge(fromIso, now) {
|
|
98605
|
-
const secs = Math.max(0, Math.floor((now.getTime() - new Date(fromIso).getTime()) / 1e3));
|
|
98606
|
-
if (secs < 60) return `${secs}s ago`;
|
|
98607
|
-
if (secs < 3600) return `${Math.floor(secs / 60)}m ago`;
|
|
98608
|
-
if (secs < 86400) return `${Math.floor(secs / 3600)}h ago`;
|
|
98609
|
-
return `${Math.floor(secs / 86400)}d ago`;
|
|
98610
|
-
}
|
|
98611
|
-
function titleFromMessages(messages) {
|
|
98612
|
-
const first = messages.find((m2) => m2.role === "user");
|
|
98613
|
-
const text = !first ? "" : typeof first.content === "string" ? first.content : first.content.map((b2) => b2.text ?? "").join(" ");
|
|
98614
|
-
const oneLine = text.replace(/\s+/g, " ").trim();
|
|
98615
|
-
return oneLine.length > 60 ? `${oneLine.slice(0, 59)}\u2026` : oneLine || "(untitled)";
|
|
98616
|
-
}
|
|
98617
|
-
var MAX_SESSION_BYTES, REDACTED, SessionError, ID, SessionStore;
|
|
98618
|
-
var init_session_store = __esm({
|
|
98619
|
-
"src/session/session-store.ts"() {
|
|
98620
|
-
"use strict";
|
|
98621
|
-
init_credential_filter();
|
|
98622
|
-
MAX_SESSION_BYTES = 5 * 1024 * 1024;
|
|
98623
|
-
REDACTED = "[redacted: credential-shaped content]";
|
|
98624
|
-
SessionError = class extends Error {
|
|
98625
|
-
constructor(file, message, options) {
|
|
98626
|
-
super(`${message} (${file})`, options);
|
|
98627
|
-
this.file = file;
|
|
98628
|
-
this.name = "SessionError";
|
|
98629
|
-
}
|
|
98630
|
-
};
|
|
98631
|
-
ID = /^[A-Za-z0-9_-]{8,64}$/;
|
|
98632
|
-
SessionStore = class {
|
|
98633
|
-
constructor(dir, now = () => /* @__PURE__ */ new Date()) {
|
|
98634
|
-
this.dir = dir;
|
|
98635
|
-
this.now = now;
|
|
98636
|
-
}
|
|
98637
|
-
newId() {
|
|
98638
|
-
return `${this.now().toISOString().replace(/[-:.TZ]/g, "").slice(0, 14)}-${randomBytes(4).toString("hex")}`;
|
|
98639
|
-
}
|
|
98640
|
-
fileFor(id) {
|
|
98641
|
-
if (!ID.test(id)) throw new SessionError(this.dir, `Invalid session id ${JSON.stringify(id)}`);
|
|
98642
|
-
return path4.join(this.dir, `${id}.jsonl`);
|
|
98643
|
-
}
|
|
98644
|
-
async save(session) {
|
|
98645
|
-
const file = this.fileFor(session.meta.id);
|
|
98646
|
-
const meta = { ...session.meta, updatedAt: this.now().toISOString() };
|
|
98647
|
-
const body = [meta, ...session.messages].map((entry) => JSON.stringify(redactCredentials(entry))).join("\n") + "\n";
|
|
98648
|
-
const bytes = Buffer.byteLength(body);
|
|
98649
|
-
if (bytes > MAX_SESSION_BYTES) {
|
|
98650
|
-
throw new SessionError(file, `Session is ${bytes} bytes, over the ${MAX_SESSION_BYTES}-byte cap; use /compact or /clear`);
|
|
98651
|
-
}
|
|
98652
|
-
const tmp = `${file}.${process.pid}.tmp`;
|
|
98653
|
-
try {
|
|
98654
|
-
await mkdir2(this.dir, { recursive: true, mode: 448 });
|
|
98655
|
-
await chmod2(this.dir, 448);
|
|
98656
|
-
await writeFile2(tmp, body, { mode: 384 });
|
|
98657
|
-
await chmod2(tmp, 384);
|
|
98658
|
-
await rename2(tmp, file);
|
|
98659
|
-
} catch (err) {
|
|
98660
|
-
throw new SessionError(file, `Could not save session: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
98661
|
-
}
|
|
99392
|
+
// src/session/replay.ts
|
|
99393
|
+
function replayTurns(messages) {
|
|
99394
|
+
const turns = [];
|
|
99395
|
+
let current = null;
|
|
99396
|
+
let seq = 0;
|
|
99397
|
+
const push = (event) => current?.events.push({ ...event, seq: ++seq });
|
|
99398
|
+
for (const message of messages) {
|
|
99399
|
+
const blocks = typeof message.content === "string" ? [{ type: "text", text: message.content }] : message.content;
|
|
99400
|
+
if (message.role === "user") {
|
|
99401
|
+
const text = blocks.filter((b2) => b2.type === "text").map((b2) => b2.text ?? "").join("\n");
|
|
99402
|
+
if (text !== "" || !current) {
|
|
99403
|
+
current = { id: -(turns.length + 1), prompt: text || "(no prompt text)", events: [], interrupted: false };
|
|
99404
|
+
turns.push(current);
|
|
98662
99405
|
}
|
|
98663
|
-
|
|
98664
|
-
|
|
98665
|
-
|
|
98666
|
-
try {
|
|
98667
|
-
text = await readFile2(file, "utf8");
|
|
98668
|
-
} catch (err) {
|
|
98669
|
-
throw new SessionError(file, `Could not read session: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
99406
|
+
for (const b2 of blocks) {
|
|
99407
|
+
if (b2.type === "tool_result" && b2.tool_use_id) {
|
|
99408
|
+
push({ type: "tool_result", id: b2.tool_use_id, output: contentText(b2.content), is_error: b2.is_error ?? false });
|
|
98670
99409
|
}
|
|
98671
|
-
return parseSession(file, text);
|
|
98672
99410
|
}
|
|
98673
|
-
|
|
98674
|
-
|
|
98675
|
-
|
|
98676
|
-
|
|
98677
|
-
names = await readdir(this.dir);
|
|
98678
|
-
} catch (err) {
|
|
98679
|
-
if (err.code === "ENOENT") return { sessions: [], errors: [] };
|
|
98680
|
-
throw new SessionError(this.dir, `Could not list sessions: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
98681
|
-
}
|
|
98682
|
-
const sessions = [];
|
|
98683
|
-
const errors = [];
|
|
98684
|
-
for (const name of names.filter((n) => n.endsWith(".jsonl"))) {
|
|
98685
|
-
try {
|
|
98686
|
-
sessions.push((await this.load(name.slice(0, -".jsonl".length))).meta);
|
|
98687
|
-
} catch (err) {
|
|
98688
|
-
errors.push(err instanceof SessionError ? err : new SessionError(path4.join(this.dir, name), String(err), { cause: err }));
|
|
98689
|
-
}
|
|
98690
|
-
}
|
|
98691
|
-
sessions.sort((a, b2) => b2.updatedAt.localeCompare(a.updatedAt));
|
|
98692
|
-
return { sessions, errors };
|
|
99411
|
+
} else if (current) {
|
|
99412
|
+
for (const b2 of blocks) {
|
|
99413
|
+
if (b2.type === "text" && b2.text) push({ type: "text", content: b2.text });
|
|
99414
|
+
else if (b2.type === "tool_use" && b2.id && b2.name) push({ type: "tool_call", id: b2.id, tool: b2.name, input: b2.input ?? {} });
|
|
98693
99415
|
}
|
|
98694
|
-
|
|
98695
|
-
|
|
98696
|
-
|
|
98697
|
-
|
|
98698
|
-
|
|
98699
|
-
|
|
98700
|
-
|
|
98701
|
-
|
|
98702
|
-
|
|
99416
|
+
}
|
|
99417
|
+
}
|
|
99418
|
+
return turns;
|
|
99419
|
+
}
|
|
99420
|
+
var contentText;
|
|
99421
|
+
var init_replay = __esm({
|
|
99422
|
+
"src/session/replay.ts"() {
|
|
99423
|
+
"use strict";
|
|
99424
|
+
contentText = (content) => typeof content === "string" ? content : Array.isArray(content) ? content.map((b2) => b2 && typeof b2 === "object" && "text" in b2 ? String(b2.text ?? "") : "").join("") : "";
|
|
98703
99425
|
}
|
|
98704
99426
|
});
|
|
98705
99427
|
|
|
@@ -99090,7 +99812,7 @@ var init_mention_resolver = __esm({
|
|
|
99090
99812
|
});
|
|
99091
99813
|
|
|
99092
99814
|
// src/editor/node-mention-fs.ts
|
|
99093
|
-
import { open, realpath, stat } from "node:fs/promises";
|
|
99815
|
+
import { open as open2, realpath, stat as stat2 } from "node:fs/promises";
|
|
99094
99816
|
import path6 from "node:path";
|
|
99095
99817
|
function isInside(root, target) {
|
|
99096
99818
|
return target === root || target.startsWith(root.endsWith(path6.sep) ? root : root + path6.sep);
|
|
@@ -99113,13 +99835,13 @@ function createNodeMentionFS(cwd2) {
|
|
|
99113
99835
|
const real = await confined(abs);
|
|
99114
99836
|
if (real === null) return null;
|
|
99115
99837
|
if (real === "") return { size: 0, isFile: false };
|
|
99116
|
-
const st = await
|
|
99838
|
+
const st = await stat2(real);
|
|
99117
99839
|
return { size: st.size, isFile: st.isFile() };
|
|
99118
99840
|
},
|
|
99119
99841
|
async readFile(abs, maxBytes) {
|
|
99120
99842
|
const real = await confined(abs);
|
|
99121
99843
|
if (!real) throw new Error(`refusing to read outside cwd: ${abs}`);
|
|
99122
|
-
const fh = await
|
|
99844
|
+
const fh = await open2(real, "r");
|
|
99123
99845
|
try {
|
|
99124
99846
|
const buf = Buffer.alloc(maxBytes);
|
|
99125
99847
|
const { bytesRead } = await fh.read(buf, 0, maxBytes, 0);
|
|
@@ -99226,109 +99948,143 @@ var init_api_key = __esm({
|
|
|
99226
99948
|
// src/useReplController.ts
|
|
99227
99949
|
import { readFile as readFile4 } from "node:fs/promises";
|
|
99228
99950
|
import { homedir as homedir2 } from "node:os";
|
|
99229
|
-
function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mentionsOpt, sessions, resumeLatest: resumeLatest2 }) {
|
|
99951
|
+
function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mentionsOpt, sessions, resumeLatest: resumeLatest2, onViewTurns, onViewResume, isEscOwned }) {
|
|
99230
99952
|
const { exit } = use_app_default();
|
|
99231
|
-
const mentions = (0,
|
|
99232
|
-
const [events, setEvents] = (0,
|
|
99233
|
-
const [turns, setTurns] = (0,
|
|
99234
|
-
const turnIdRef = (0,
|
|
99235
|
-
const [isRunning, setIsRunning] = (0,
|
|
99236
|
-
const [history, setHistory] = (0,
|
|
99237
|
-
const [turnTokens, setTurnTokens] = (0,
|
|
99238
|
-
const [sessionTokens, setSessionTokens] = (0,
|
|
99239
|
-
const [turnStartedAt, setTurnStartedAt] = (0,
|
|
99240
|
-
const [now, setNow] = (0,
|
|
99241
|
-
(0,
|
|
99953
|
+
const mentions = (0, import_react30.useMemo)(() => mentionsOpt ?? createNodeMentions(process.cwd()), [mentionsOpt]);
|
|
99954
|
+
const [events, setEvents] = (0, import_react30.useState)([]);
|
|
99955
|
+
const [turns, setTurns] = (0, import_react30.useState)([]);
|
|
99956
|
+
const turnIdRef = (0, import_react30.useRef)(0);
|
|
99957
|
+
const [isRunning, setIsRunning] = (0, import_react30.useState)(false);
|
|
99958
|
+
const [history, setHistory] = (0, import_react30.useState)([]);
|
|
99959
|
+
const [turnTokens, setTurnTokens] = (0, import_react30.useState)(null);
|
|
99960
|
+
const [sessionTokens, setSessionTokens] = (0, import_react30.useState)({ input: 0, output: 0 });
|
|
99961
|
+
const [turnStartedAt, setTurnStartedAt] = (0, import_react30.useState)(null);
|
|
99962
|
+
const [now, setNow] = (0, import_react30.useState)(() => Date.now());
|
|
99963
|
+
(0, import_react30.useEffect)(() => {
|
|
99242
99964
|
if (turnStartedAt === null) return;
|
|
99243
99965
|
setNow(Date.now());
|
|
99244
99966
|
const timer = setInterval(() => setNow(Date.now()), 1e3);
|
|
99245
99967
|
return () => clearInterval(timer);
|
|
99246
99968
|
}, [turnStartedAt]);
|
|
99247
|
-
const projectRoot = (0,
|
|
99248
|
-
const sessionIdRef = (0,
|
|
99249
|
-
const sessionCreatedAtRef = (0,
|
|
99250
|
-
const sessionTokensRef = (0,
|
|
99251
|
-
const resumeListRef = (0,
|
|
99252
|
-
const [model, setModel] = (0,
|
|
99253
|
-
const [todos,
|
|
99254
|
-
const
|
|
99255
|
-
const
|
|
99256
|
-
|
|
99257
|
-
|
|
99258
|
-
|
|
99259
|
-
(0,
|
|
99969
|
+
const projectRoot = (0, import_react30.useMemo)(() => process.cwd(), []);
|
|
99970
|
+
const sessionIdRef = (0, import_react30.useRef)(null);
|
|
99971
|
+
const sessionCreatedAtRef = (0, import_react30.useRef)(null);
|
|
99972
|
+
const sessionTokensRef = (0, import_react30.useRef)({ input: 0, output: 0 });
|
|
99973
|
+
const resumeListRef = (0, import_react30.useRef)([]);
|
|
99974
|
+
const [model, setModel] = (0, import_react30.useState)(null);
|
|
99975
|
+
const [todos, setTodosState] = (0, import_react30.useState)([]);
|
|
99976
|
+
const todosRef = (0, import_react30.useRef)([]);
|
|
99977
|
+
const setTodos = (0, import_react30.useCallback)((t) => {
|
|
99978
|
+
todosRef.current = t;
|
|
99979
|
+
setTodosState(t);
|
|
99980
|
+
}, []);
|
|
99981
|
+
const [replayed, setReplayed] = (0, import_react30.useState)([]);
|
|
99982
|
+
const [notices, setNotices] = (0, import_react30.useState)([]);
|
|
99983
|
+
const retryRef = (0, import_react30.useRef)(null);
|
|
99984
|
+
const [pending, setPending] = (0, import_react30.useState)(null);
|
|
99985
|
+
const abortRef = (0, import_react30.useRef)(null);
|
|
99986
|
+
const pendingRef = (0, import_react30.useRef)(null);
|
|
99987
|
+
const toolsetRef = (0, import_react30.useRef)(null);
|
|
99988
|
+
(0, import_react30.useEffect)(() => {
|
|
99260
99989
|
sessionTokensRef.current = sessionTokens;
|
|
99261
99990
|
}, [sessionTokens]);
|
|
99262
|
-
const [permissions] = (0,
|
|
99263
|
-
const [mode, setMode] = (0,
|
|
99264
|
-
(0,
|
|
99265
|
-
const answeredThisKeypressRef = (0,
|
|
99266
|
-
const
|
|
99267
|
-
|
|
99268
|
-
|
|
99991
|
+
const [permissions] = (0, import_react30.useState)(() => new PermissionState(yolo2 ? "yolo" : "default"));
|
|
99992
|
+
const [mode, setMode] = (0, import_react30.useState)(permissions.mode);
|
|
99993
|
+
(0, import_react30.useEffect)(() => permissions.onChange(setMode), [permissions]);
|
|
99994
|
+
const answeredThisKeypressRef = (0, import_react30.useRef)(false);
|
|
99995
|
+
const confirmQueueRef = (0, import_react30.useRef)([]);
|
|
99996
|
+
const confirmIdRef = (0, import_react30.useRef)(0);
|
|
99997
|
+
const showNextConfirm = (0, import_react30.useCallback)(() => {
|
|
99998
|
+
const head = confirmQueueRef.current[0] ?? null;
|
|
99999
|
+
pendingRef.current = head;
|
|
100000
|
+
setPending(head);
|
|
99269
100001
|
}, []);
|
|
99270
|
-
const
|
|
99271
|
-
|
|
100002
|
+
const enqueueConfirm = (0, import_react30.useCallback)((p) => {
|
|
100003
|
+
confirmQueueRef.current.push(p);
|
|
100004
|
+
if (confirmQueueRef.current.length === 1) showNextConfirm();
|
|
100005
|
+
}, [showNextConfirm]);
|
|
100006
|
+
const dequeueConfirm = (0, import_react30.useCallback)((p) => {
|
|
100007
|
+
confirmQueueRef.current = confirmQueueRef.current.filter((q2) => q2 !== p);
|
|
100008
|
+
showNextConfirm();
|
|
100009
|
+
}, [showNextConfirm]);
|
|
100010
|
+
const refuseAllConfirms = (0, import_react30.useCallback)(() => {
|
|
100011
|
+
const all = confirmQueueRef.current;
|
|
100012
|
+
confirmQueueRef.current = [];
|
|
100013
|
+
for (const p of all) p.resolve(false);
|
|
100014
|
+
pendingRef.current = null;
|
|
100015
|
+
setPending(null);
|
|
99272
100016
|
}, []);
|
|
99273
|
-
const
|
|
100017
|
+
const commitTurn = (0, import_react30.useCallback)((prompt, turnEvents, interrupted, summary, retained) => {
|
|
100018
|
+
setTurns((prev) => [...prev, { id: turnIdRef.current++, prompt, events: turnEvents, interrupted, summary, retained }]);
|
|
100019
|
+
}, []);
|
|
100020
|
+
const notice = (0, import_react30.useCallback)((message) => {
|
|
99274
100021
|
setNotices((prev) => [...prev, message]);
|
|
99275
100022
|
}, []);
|
|
100023
|
+
const noticeError = (0, import_react30.useCallback)((view) => {
|
|
100024
|
+
setNotices((prev) => [...prev, { error: view }]);
|
|
100025
|
+
}, []);
|
|
99276
100026
|
const { isRawModeSupported } = use_stdin_default();
|
|
99277
100027
|
use_input_default((_input, key) => {
|
|
99278
100028
|
if (key.shift && key.tab) {
|
|
99279
100029
|
permissions.cycle();
|
|
99280
100030
|
return;
|
|
99281
100031
|
}
|
|
99282
|
-
if (pendingRef.current || answeredThisKeypressRef.current) return;
|
|
100032
|
+
if (pendingRef.current || answeredThisKeypressRef.current || isEscOwned?.()) return;
|
|
99283
100033
|
if (key.escape && abortRef.current) abortRef.current.abort();
|
|
99284
100034
|
}, { isActive: Boolean(isRawModeSupported) });
|
|
99285
|
-
const createToolset = (0,
|
|
100035
|
+
const createToolset = (0, import_react30.useCallback)(
|
|
99286
100036
|
() => createLocalToolset({
|
|
99287
100037
|
cwd: process.cwd(),
|
|
99288
100038
|
permissions,
|
|
99289
100039
|
onTodos: setTodos,
|
|
99290
|
-
confirm: (req) => new Promise(
|
|
99291
|
-
|
|
100040
|
+
confirm: (req) => new Promise((resolve2) => {
|
|
100041
|
+
const item = {
|
|
100042
|
+
id: confirmIdRef.current++,
|
|
99292
100043
|
req,
|
|
99293
100044
|
resolve: (decision) => {
|
|
99294
100045
|
answeredThisKeypressRef.current = true;
|
|
99295
100046
|
setTimeout(() => {
|
|
99296
100047
|
answeredThisKeypressRef.current = false;
|
|
99297
100048
|
}, 0);
|
|
99298
|
-
|
|
100049
|
+
dequeueConfirm(item);
|
|
99299
100050
|
resolve2(decision);
|
|
99300
100051
|
}
|
|
99301
|
-
}
|
|
99302
|
-
|
|
100052
|
+
};
|
|
100053
|
+
enqueueConfirm(item);
|
|
100054
|
+
})
|
|
99303
100055
|
}),
|
|
99304
|
-
[permissions,
|
|
100056
|
+
[permissions, enqueueConfirm, dequeueConfirm]
|
|
99305
100057
|
);
|
|
99306
|
-
const persist = (0,
|
|
100058
|
+
const persist = (0, import_react30.useCallback)(
|
|
99307
100059
|
async (messages, tokens) => {
|
|
99308
100060
|
if (!sessions) return;
|
|
99309
100061
|
try {
|
|
99310
100062
|
const id = sessionIdRef.current ??= sessions.newId();
|
|
99311
100063
|
const createdAt = sessionCreatedAtRef.current ??= (/* @__PURE__ */ new Date()).toISOString();
|
|
99312
|
-
await sessions.save({ meta: { v: 1, id, projectRoot, createdAt, updatedAt: createdAt, tokens, title: titleFromMessages(messages) }, messages });
|
|
100064
|
+
await sessions.save({ meta: { v: 1, id, projectRoot, createdAt, updatedAt: createdAt, tokens, title: titleFromMessages(messages), turns: countTurns(messages), todos: todosRef.current }, messages });
|
|
99313
100065
|
} catch (err) {
|
|
99314
|
-
|
|
100066
|
+
noticeError(describeError("session-save", err instanceof Error ? err.message : String(err)));
|
|
99315
100067
|
}
|
|
99316
100068
|
},
|
|
99317
|
-
[sessions, projectRoot,
|
|
100069
|
+
[sessions, projectRoot, noticeError]
|
|
99318
100070
|
);
|
|
99319
|
-
const applySession = (0,
|
|
100071
|
+
const applySession = (0, import_react30.useCallback)(
|
|
99320
100072
|
(loaded) => {
|
|
100073
|
+
retryRef.current = null;
|
|
100074
|
+
for (const w2 of loaded.warnings ?? []) notice(w2);
|
|
99321
100075
|
sessionIdRef.current = loaded.meta.id;
|
|
99322
100076
|
sessionCreatedAtRef.current = loaded.meta.createdAt;
|
|
99323
100077
|
setHistory(loaded.messages);
|
|
99324
100078
|
setSessionTokens(loaded.meta.tokens);
|
|
99325
100079
|
setTurns([]);
|
|
99326
100080
|
setEvents([]);
|
|
99327
|
-
|
|
100081
|
+
setReplayed(replayTurns(loaded.messages));
|
|
100082
|
+
setTodos(loaded.meta.todos ?? []);
|
|
100083
|
+
notice(`Resumed "${loaded.meta.title}" (${loaded.messages.length} messages, saved ${formatAge(loaded.meta.updatedAt, /* @__PURE__ */ new Date())}). Earlier turns are in /turns (ctrl+o).`);
|
|
99328
100084
|
},
|
|
99329
|
-
[notice]
|
|
100085
|
+
[notice, setTodos]
|
|
99330
100086
|
);
|
|
99331
|
-
(0,
|
|
100087
|
+
(0, import_react30.useEffect)(() => {
|
|
99332
100088
|
if (!resumeLatest2) return;
|
|
99333
100089
|
if (!sessions) {
|
|
99334
100090
|
notice("Cannot continue: session storage is not available.");
|
|
@@ -99349,7 +100105,7 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
99349
100105
|
}
|
|
99350
100106
|
})();
|
|
99351
100107
|
}, [resumeLatest2, sessions, projectRoot, notice, applySession]);
|
|
99352
|
-
const submit = (0,
|
|
100108
|
+
const submit = (0, import_react30.useCallback)(async (prompt) => {
|
|
99353
100109
|
const shellCommand = shellCommandOf(prompt);
|
|
99354
100110
|
if (shellCommand !== null) {
|
|
99355
100111
|
if (shellCommand === "") {
|
|
@@ -99379,8 +100135,7 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
99379
100135
|
} finally {
|
|
99380
100136
|
commitTurn(prompt, shellEvents, false);
|
|
99381
100137
|
setEvents([]);
|
|
99382
|
-
|
|
99383
|
-
setPendingConfirm(null);
|
|
100138
|
+
refuseAllConfirms();
|
|
99384
100139
|
setIsRunning(false);
|
|
99385
100140
|
}
|
|
99386
100141
|
return;
|
|
@@ -99400,6 +100155,8 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
99400
100155
|
setSessionTokens({ input: 0, output: 0 });
|
|
99401
100156
|
setTurnTokens(null);
|
|
99402
100157
|
setTodos([]);
|
|
100158
|
+
setReplayed([]);
|
|
100159
|
+
retryRef.current = null;
|
|
99403
100160
|
sessionIdRef.current = null;
|
|
99404
100161
|
sessionCreatedAtRef.current = null;
|
|
99405
100162
|
return;
|
|
@@ -99437,6 +100194,10 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
99437
100194
|
if (parsed.kind === "list") {
|
|
99438
100195
|
const { sessions: all, errors } = await sessions.list();
|
|
99439
100196
|
resumeListRef.current = all;
|
|
100197
|
+
if (onViewResume) {
|
|
100198
|
+
onViewResume({ sessions: all, errors: errors.map((e) => e.message) });
|
|
100199
|
+
return;
|
|
100200
|
+
}
|
|
99440
100201
|
for (const e of errors) notice(e.message);
|
|
99441
100202
|
notice(formatSessionList(all, projectRoot, /* @__PURE__ */ new Date()));
|
|
99442
100203
|
return;
|
|
@@ -99517,6 +100278,10 @@ function useReplController({ repoName: repoName2, yolo: yolo2, mentions: mention
|
|
|
99517
100278
|
}
|
|
99518
100279
|
return;
|
|
99519
100280
|
}
|
|
100281
|
+
case "turns":
|
|
100282
|
+
if (onViewTurns) onViewTurns();
|
|
100283
|
+
else notice("The turn viewer is not available here.");
|
|
100284
|
+
return;
|
|
99520
100285
|
case "tools": {
|
|
99521
100286
|
const tools = toolsetRef.current?.tools ?? createLocalToolset({ cwd: process.cwd(), permissions, onTodos: setTodos }).tools;
|
|
99522
100287
|
notice(`Tools:
|
|
@@ -99529,6 +100294,7 @@ ${tools.map((t) => ` ${t.name}`).join("\n")}`);
|
|
|
99529
100294
|
return;
|
|
99530
100295
|
}
|
|
99531
100296
|
let apiKey;
|
|
100297
|
+
retryRef.current = null;
|
|
99532
100298
|
try {
|
|
99533
100299
|
apiKey = await resolveApiKey({
|
|
99534
100300
|
env: process.env,
|
|
@@ -99544,11 +100310,12 @@ ${tools.map((t) => ` ${t.name}`).join("\n")}`);
|
|
|
99544
100310
|
return;
|
|
99545
100311
|
}
|
|
99546
100312
|
if (!apiKey) {
|
|
100313
|
+
retryRef.current = prompt;
|
|
99547
100314
|
commitTurn(prompt, [{
|
|
99548
100315
|
type: "error",
|
|
99549
100316
|
seq: 1,
|
|
99550
100317
|
message: MISSING_KEY_MESSAGE
|
|
99551
|
-
}], false);
|
|
100318
|
+
}], false, void 0, true);
|
|
99552
100319
|
return;
|
|
99553
100320
|
}
|
|
99554
100321
|
setIsRunning(true);
|
|
@@ -99562,6 +100329,7 @@ ${tools.map((t) => ` ${t.name}`).join("\n")}`);
|
|
|
99562
100329
|
setTurnStartedAt(startedAt);
|
|
99563
100330
|
let usage = { input: 0, output: 0 };
|
|
99564
100331
|
let failed = false;
|
|
100332
|
+
let keepForRetry = false;
|
|
99565
100333
|
try {
|
|
99566
100334
|
const toolset = createToolset();
|
|
99567
100335
|
toolsetRef.current = toolset;
|
|
@@ -99585,13 +100353,17 @@ ${tools.map((t) => ` ${t.name}`).join("\n")}`);
|
|
|
99585
100353
|
const attached = await mentions.attach(prompt);
|
|
99586
100354
|
if (attached.notices.length > 0) setNotices(attached.notices);
|
|
99587
100355
|
const result = await runAgentLoop(attached.prompt, config, toolset.executor, emit, controller.signal, history);
|
|
99588
|
-
|
|
100356
|
+
const failure = [...turnEvents].reverse().find((e) => e.type === "error");
|
|
100357
|
+
const noProgress = result.messages.length === history.length + 1;
|
|
100358
|
+
keepForRetry = !controller.signal.aborted && failure !== void 0 && isRetryable(failure.message) && noProgress;
|
|
100359
|
+
const savedMessages = keepForRetry ? history : result.messages;
|
|
100360
|
+
setHistory(savedMessages);
|
|
99589
100361
|
usage = { input: result.totalInputTokens, output: result.totalOutputTokens };
|
|
99590
100362
|
failed = !result.success;
|
|
99591
100363
|
setTurnTokens(usage);
|
|
99592
100364
|
const totals = { input: sessionTokensRef.current.input + usage.input, output: sessionTokensRef.current.output + usage.output };
|
|
99593
100365
|
setSessionTokens(totals);
|
|
99594
|
-
await persist(
|
|
100366
|
+
if (savedMessages.length > 0) await persist(savedMessages, totals);
|
|
99595
100367
|
} catch (err) {
|
|
99596
100368
|
failed = true;
|
|
99597
100369
|
console.error("[agent-ui] Agent loop failed:", err);
|
|
@@ -99603,21 +100375,23 @@ ${tools.map((t) => ` ${t.name}`).join("\n")}`);
|
|
|
99603
100375
|
} finally {
|
|
99604
100376
|
const toolCount = turnEvents.filter((e) => e.type === "tool_call").length;
|
|
99605
100377
|
const committedEvents = turnEvents.filter((e) => e.type !== "status");
|
|
100378
|
+
const retained = keepForRetry;
|
|
100379
|
+
retryRef.current = retained ? prompt : null;
|
|
99606
100380
|
commitTurn(
|
|
99607
100381
|
prompt,
|
|
99608
100382
|
committedEvents,
|
|
99609
100383
|
controller.signal.aborted,
|
|
99610
|
-
formatTurnSummary({ toolCount, elapsedMs: Date.now() - startedAt, inputTokens: usage.input, outputTokens: usage.output, interrupted: controller.signal.aborted, failed })
|
|
100384
|
+
formatTurnSummary({ toolCount, elapsedMs: Date.now() - startedAt, inputTokens: usage.input, outputTokens: usage.output, interrupted: controller.signal.aborted, failed }, activeGlyphs().rail === "\u2502"),
|
|
100385
|
+
retained
|
|
99611
100386
|
);
|
|
99612
100387
|
setTurnStartedAt(null);
|
|
99613
100388
|
setEvents([]);
|
|
99614
|
-
|
|
99615
|
-
setPendingConfirm(null);
|
|
100389
|
+
refuseAllConfirms();
|
|
99616
100390
|
abortRef.current = null;
|
|
99617
100391
|
setIsRunning(false);
|
|
99618
100392
|
}
|
|
99619
|
-
}, [repoName2, history, exit, permissions, notice,
|
|
99620
|
-
const approxTokens = (0,
|
|
100393
|
+
}, [repoName2, history, exit, permissions, notice, refuseAllConfirms, commitTurn, mentions, createToolset, sessions, projectRoot, persist, applySession, model, onViewTurns, onViewResume, setTodos]);
|
|
100394
|
+
const approxTokens = (0, import_react30.useMemo)(
|
|
99621
100395
|
() => events.reduce((n, e) => n + (e.type === "text" ? estimateTokens(e.content) : e.type === "text_delta" ? estimateTokens(e.text) : 0), 0),
|
|
99622
100396
|
[events]
|
|
99623
100397
|
);
|
|
@@ -99628,17 +100402,47 @@ ${tools.map((t) => ` ${t.name}`).join("\n")}`);
|
|
|
99628
100402
|
approxTokens,
|
|
99629
100403
|
...model ? { model } : {}
|
|
99630
100404
|
};
|
|
99631
|
-
|
|
100405
|
+
const retry = (0, import_react30.useCallback)(() => {
|
|
100406
|
+
const kept = retryRef.current;
|
|
100407
|
+
if (kept !== null) void submit(kept);
|
|
100408
|
+
}, [submit]);
|
|
100409
|
+
const resume = (0, import_react30.useMemo)(
|
|
100410
|
+
() => ({
|
|
100411
|
+
available: Boolean(sessions),
|
|
100412
|
+
load: async (meta) => {
|
|
100413
|
+
if (!sessions) throw new Error("Session storage is not available.");
|
|
100414
|
+
applySession(await sessions.load(meta.id));
|
|
100415
|
+
},
|
|
100416
|
+
remove: async (meta) => {
|
|
100417
|
+
if (!sessions) throw new Error("Session storage is not available.");
|
|
100418
|
+
await sessions.delete(meta.id);
|
|
100419
|
+
resumeListRef.current = resumeListRef.current.filter((m2) => m2.id !== meta.id);
|
|
100420
|
+
if (sessionIdRef.current === meta.id) {
|
|
100421
|
+
sessionIdRef.current = null;
|
|
100422
|
+
sessionCreatedAtRef.current = null;
|
|
100423
|
+
}
|
|
100424
|
+
},
|
|
100425
|
+
preview: async (meta) => {
|
|
100426
|
+
if (!sessions) return null;
|
|
100427
|
+
return sessions.preview(meta.id);
|
|
100428
|
+
}
|
|
100429
|
+
}),
|
|
100430
|
+
[sessions, applySession]
|
|
100431
|
+
);
|
|
100432
|
+
return { turns, events, isRunning, turnTokens, notices, pending, mode, todos, stats, submit, retry, mentions, replayed, resume };
|
|
99632
100433
|
}
|
|
99633
|
-
var
|
|
100434
|
+
var import_react30, apiUrl;
|
|
99634
100435
|
var init_useReplController = __esm({
|
|
99635
100436
|
async "src/useReplController.ts"() {
|
|
99636
100437
|
"use strict";
|
|
99637
|
-
|
|
100438
|
+
import_react30 = __toESM(require_react(), 1);
|
|
99638
100439
|
await init_build2();
|
|
99639
100440
|
init_src2();
|
|
99640
100441
|
init_footer();
|
|
99641
100442
|
init_session_store();
|
|
100443
|
+
init_replay();
|
|
100444
|
+
init_rail();
|
|
100445
|
+
init_describe_error();
|
|
99642
100446
|
init_compact();
|
|
99643
100447
|
init_models();
|
|
99644
100448
|
init_session_commands();
|
|
@@ -99651,48 +100455,373 @@ var init_useReplController = __esm({
|
|
|
99651
100455
|
}
|
|
99652
100456
|
});
|
|
99653
100457
|
|
|
100458
|
+
// src/components/TurnViewer.tsx
|
|
100459
|
+
function TurnViewer({ turns, steps, rows, columns, onClose, onEscape }) {
|
|
100460
|
+
const { isRawModeSupported } = use_stdin_default();
|
|
100461
|
+
const glyphs = activeGlyphs();
|
|
100462
|
+
const [turnIdx, setTurnIdx] = (0, import_react31.useState)(null);
|
|
100463
|
+
const [cursorRaw, setCursor] = (0, import_react31.useState)(turns.length - 1);
|
|
100464
|
+
const cursor = clamp(cursorRaw, 0, Math.max(0, turns.length - 1));
|
|
100465
|
+
const [stepCursor, setStepCursor] = (0, import_react31.useState)(0);
|
|
100466
|
+
const [openId, setOpenId] = (0, import_react31.useState)(null);
|
|
100467
|
+
const [scroll, setScroll] = (0, import_react31.useState)(0);
|
|
100468
|
+
const turn = turnIdx === null ? null : turns[turnIdx] ?? null;
|
|
100469
|
+
const turnSteps = turn ? steps.get(turn.id) ?? [] : [];
|
|
100470
|
+
const detailRows = Math.max(3, rows - 6 - turnSteps.length);
|
|
100471
|
+
use_input_default((_input, key) => {
|
|
100472
|
+
if (key.escape) onEscape?.();
|
|
100473
|
+
if (turn === null) {
|
|
100474
|
+
if (key.escape) onClose();
|
|
100475
|
+
else if (key.upArrow) setCursor((c) => clamp(clamp(c, 0, turns.length - 1) - 1, 0, turns.length - 1));
|
|
100476
|
+
else if (key.downArrow) setCursor((c) => clamp(clamp(c, 0, turns.length - 1) + 1, 0, turns.length - 1));
|
|
100477
|
+
else if (key.return && turns.length > 0) {
|
|
100478
|
+
setTurnIdx(cursor);
|
|
100479
|
+
setStepCursor(0);
|
|
100480
|
+
setOpenId(null);
|
|
100481
|
+
setScroll(0);
|
|
100482
|
+
}
|
|
100483
|
+
return;
|
|
100484
|
+
}
|
|
100485
|
+
if (key.escape) {
|
|
100486
|
+
if (openId !== null) {
|
|
100487
|
+
setOpenId(null);
|
|
100488
|
+
setScroll(0);
|
|
100489
|
+
} else setTurnIdx(null);
|
|
100490
|
+
} else if (key.upArrow) {
|
|
100491
|
+
setStepCursor((c) => clamp(c - 1, 0, turnSteps.length - 1));
|
|
100492
|
+
setOpenId(null);
|
|
100493
|
+
setScroll(0);
|
|
100494
|
+
} else if (key.downArrow) {
|
|
100495
|
+
setStepCursor((c) => clamp(c + 1, 0, turnSteps.length - 1));
|
|
100496
|
+
setOpenId(null);
|
|
100497
|
+
setScroll(0);
|
|
100498
|
+
} else if (key.return && turnSteps.length > 0) {
|
|
100499
|
+
const id = turnSteps[stepCursor].id;
|
|
100500
|
+
setOpenId((cur) => cur === id ? null : id);
|
|
100501
|
+
setScroll(0);
|
|
100502
|
+
} else if (key.pageDown) setScroll((s) => s + detailRows);
|
|
100503
|
+
else if (key.pageUp) setScroll((s) => Math.max(0, s - detailRows));
|
|
100504
|
+
}, { isActive: Boolean(isRawModeSupported) });
|
|
100505
|
+
const listRows = Math.max(3, rows - 4);
|
|
100506
|
+
const listStart = clamp(cursor - listRows + 1, 0, Math.max(0, turns.length - listRows));
|
|
100507
|
+
if (turn === null) {
|
|
100508
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "column", children: [
|
|
100509
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { bold: true, children: [
|
|
100510
|
+
"Earlier turns ",
|
|
100511
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { ...paint("secondary"), children: "(\u2191\u2193 choose \xB7 enter open \xB7 esc close)" })
|
|
100512
|
+
] }),
|
|
100513
|
+
turns.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { ...paint("secondary"), children: "No finished turns yet." }),
|
|
100514
|
+
turns.slice(listStart, listStart + listRows).map((t, k2) => {
|
|
100515
|
+
const idx = listStart + k2;
|
|
100516
|
+
const n = steps.get(t.id)?.length ?? 0;
|
|
100517
|
+
const prompt = t.prompt.split("\n")[0].slice(0, Math.max(10, columns - 24));
|
|
100518
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { inverse: idx === cursor, children: [
|
|
100519
|
+
idx === cursor ? "> " : " ",
|
|
100520
|
+
idx + 1,
|
|
100521
|
+
". ",
|
|
100522
|
+
prompt,
|
|
100523
|
+
" ",
|
|
100524
|
+
glyphs.sep,
|
|
100525
|
+
" ",
|
|
100526
|
+
n,
|
|
100527
|
+
" step",
|
|
100528
|
+
n === 1 ? "" : "s"
|
|
100529
|
+
] }, t.id);
|
|
100530
|
+
})
|
|
100531
|
+
] });
|
|
100532
|
+
}
|
|
100533
|
+
const open3 = turnSteps.find((r) => r.id === openId);
|
|
100534
|
+
const win = open3 ? detailWindow(open3.detail, detailRows, Math.max(20, columns - 8), scroll) : null;
|
|
100535
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "column", children: [
|
|
100536
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { bold: true, children: `${turnIdx + 1}. ${turn.prompt.split("\n")[0].slice(0, Math.max(10, columns - 8))}` }),
|
|
100537
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { ...paint("secondary"), children: turnSteps.length === 0 ? "No steps in this turn. (esc back)" : "\u2191\u2193 choose \xB7 enter open/close \xB7 pgup/pgdn scroll \xB7 esc back" }),
|
|
100538
|
+
turnSteps.map((r, i) => {
|
|
100539
|
+
const line = fitStepLine({ verb: r.verb, target: r.target, meta: r.meta || void 0, columns, indent: 6, ellipsis: glyphs.ellipsis, sep: glyphs.sep });
|
|
100540
|
+
const marker = glyphs.marker[r.state];
|
|
100541
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "column", children: [
|
|
100542
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { inverse: i === stepCursor, children: [
|
|
100543
|
+
i === stepCursor ? "> " : " ",
|
|
100544
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { ...paint(r.state === "failed" ? "delete" : "add"), children: marker }),
|
|
100545
|
+
" ",
|
|
100546
|
+
line.verb,
|
|
100547
|
+
" ",
|
|
100548
|
+
line.target,
|
|
100549
|
+
line.meta ? ` ${glyphs.sep} ${line.meta}` : ""
|
|
100550
|
+
] }),
|
|
100551
|
+
r.id === openId && win && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "column", marginLeft: 4, children: [
|
|
100552
|
+
win.above > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { ...paint("secondary"), children: `${glyphs.ellipsis} ${win.above} line${win.above === 1 ? "" : "s"} above` }),
|
|
100553
|
+
win.lines.map((l, k2) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { ...paint("secondary"), children: l }, k2)),
|
|
100554
|
+
win.below > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { ...paint("secondary"), children: `${glyphs.ellipsis} ${win.below} more line${win.below === 1 ? "" : "s"}` })
|
|
100555
|
+
] })
|
|
100556
|
+
] }, r.id);
|
|
100557
|
+
})
|
|
100558
|
+
] });
|
|
100559
|
+
}
|
|
100560
|
+
var import_react31, import_jsx_runtime10, clamp;
|
|
100561
|
+
var init_TurnViewer = __esm({
|
|
100562
|
+
async "src/components/TurnViewer.tsx"() {
|
|
100563
|
+
"use strict";
|
|
100564
|
+
import_react31 = __toESM(require_react(), 1);
|
|
100565
|
+
await init_build2();
|
|
100566
|
+
init_step_view();
|
|
100567
|
+
init_rail();
|
|
100568
|
+
init_theme();
|
|
100569
|
+
import_jsx_runtime10 = __toESM(require_jsx_runtime(), 1);
|
|
100570
|
+
clamp = (n, lo, hi) => Math.max(lo, Math.min(hi, n));
|
|
100571
|
+
}
|
|
100572
|
+
});
|
|
100573
|
+
|
|
100574
|
+
// src/render/resume-rows.ts
|
|
100575
|
+
import path9 from "node:path";
|
|
100576
|
+
function orderSessions(sessions, projectRoot) {
|
|
100577
|
+
return [...sessions.filter((s) => s.projectRoot === projectRoot), ...sessions.filter((s) => s.projectRoot !== projectRoot)];
|
|
100578
|
+
}
|
|
100579
|
+
function formatResumeRow(meta, now, columns, sep2 = "\xB7", ellipsis = "\u2026") {
|
|
100580
|
+
const project = path9.basename(meta.projectRoot) || meta.projectRoot;
|
|
100581
|
+
const tail = [meta.turns !== void 0 ? `${meta.turns} turn${meta.turns === 1 ? "" : "s"}` : null, formatCost(estimateCostUsd(meta.tokens.input, meta.tokens.output))].filter(Boolean).join(` ${sep2} `);
|
|
100582
|
+
const head = `${formatAge(meta.updatedAt, now)} ${sep2} ${project} ${sep2} `;
|
|
100583
|
+
const fixed = head.length + 2 + ` ${sep2} ${tail}`.length;
|
|
100584
|
+
const room = Math.max(8, columns - fixed);
|
|
100585
|
+
const title = meta.title.length > room ? `${meta.title.slice(0, Math.max(1, room - ellipsis.length))}${ellipsis}` : meta.title;
|
|
100586
|
+
return `${head}"${title}" ${sep2} ${tail}`;
|
|
100587
|
+
}
|
|
100588
|
+
var init_resume_rows = __esm({
|
|
100589
|
+
"src/render/resume-rows.ts"() {
|
|
100590
|
+
"use strict";
|
|
100591
|
+
init_footer();
|
|
100592
|
+
init_session_store();
|
|
100593
|
+
}
|
|
100594
|
+
});
|
|
100595
|
+
|
|
100596
|
+
// src/components/ResumePicker.tsx
|
|
100597
|
+
function ResumePicker({ sessions, errors, projectRoot, now, rows, columns, preview, onResume, onDelete, onClose, onEscape }) {
|
|
100598
|
+
const { isRawModeSupported } = use_stdin_default();
|
|
100599
|
+
const glyphs = activeGlyphs();
|
|
100600
|
+
const [items, setItems] = (0, import_react32.useState)(() => orderSessions(sessions, projectRoot));
|
|
100601
|
+
const [cursor, setCursor] = (0, import_react32.useState)(0);
|
|
100602
|
+
const [stage, setStage] = (0, import_react32.useState)("browse");
|
|
100603
|
+
const [message, setMessage] = (0, import_react32.useState)(null);
|
|
100604
|
+
const [previews, setPreviews] = (0, import_react32.useState)({});
|
|
100605
|
+
const at = clamp2(cursor, 0, Math.max(0, items.length - 1));
|
|
100606
|
+
const current = items[at];
|
|
100607
|
+
(0, import_react32.useEffect)(() => {
|
|
100608
|
+
if (!current || current.id in previews) return;
|
|
100609
|
+
let live = true;
|
|
100610
|
+
preview(current).then((p) => live && setPreviews((m2) => ({ ...m2, [current.id]: p }))).catch((err) => live && setPreviews((m2) => ({ ...m2, [current.id]: err instanceof Error ? err : new Error(String(err)) })));
|
|
100611
|
+
return () => {
|
|
100612
|
+
live = false;
|
|
100613
|
+
};
|
|
100614
|
+
}, [current, preview, previews]);
|
|
100615
|
+
use_input_default((input, key) => {
|
|
100616
|
+
if (key.escape) {
|
|
100617
|
+
onEscape?.();
|
|
100618
|
+
if (stage !== "browse") {
|
|
100619
|
+
setStage("browse");
|
|
100620
|
+
setMessage(null);
|
|
100621
|
+
} else onClose();
|
|
100622
|
+
return;
|
|
100623
|
+
}
|
|
100624
|
+
if (stage === "confirm-delete") {
|
|
100625
|
+
if (input === "y" && current) {
|
|
100626
|
+
onDelete(current).then(() => {
|
|
100627
|
+
setItems((list2) => list2.filter((m2) => m2.id !== current.id));
|
|
100628
|
+
setMessage(`Deleted "${current.title}".`);
|
|
100629
|
+
}).catch((err) => setMessage(`Could not delete: ${err instanceof Error ? err.message : String(err)}`));
|
|
100630
|
+
setStage("browse");
|
|
100631
|
+
} else if (input === "n") {
|
|
100632
|
+
setStage("browse");
|
|
100633
|
+
setMessage(null);
|
|
100634
|
+
}
|
|
100635
|
+
return;
|
|
100636
|
+
}
|
|
100637
|
+
if (key.upArrow) {
|
|
100638
|
+
setCursor((c) => clamp2(c - 1, 0, items.length - 1));
|
|
100639
|
+
setStage("browse");
|
|
100640
|
+
setMessage(null);
|
|
100641
|
+
} else if (key.downArrow) {
|
|
100642
|
+
setCursor((c) => clamp2(c + 1, 0, items.length - 1));
|
|
100643
|
+
setStage("browse");
|
|
100644
|
+
setMessage(null);
|
|
100645
|
+
} else if (input === "d" && current) {
|
|
100646
|
+
setStage("confirm-delete");
|
|
100647
|
+
setMessage(`Delete "${current.title}"? y/n`);
|
|
100648
|
+
} else if (key.return && current) {
|
|
100649
|
+
if (current.projectRoot !== projectRoot && stage !== "confirm-foreign") {
|
|
100650
|
+
setStage("confirm-foreign");
|
|
100651
|
+
setMessage(`That session belongs to ${current.projectRoot}, not ${projectRoot}. Enter again to load it anyway, Esc to go back.`);
|
|
100652
|
+
return;
|
|
100653
|
+
}
|
|
100654
|
+
onResume(current).then(onClose).catch((err) => setMessage(`Could not resume: ${err instanceof Error ? err.message : String(err)}`));
|
|
100655
|
+
}
|
|
100656
|
+
}, { isActive: Boolean(isRawModeSupported) });
|
|
100657
|
+
const listRows = Math.max(3, rows - 8);
|
|
100658
|
+
const start = clamp2(at - listRows + 1, 0, Math.max(0, items.length - listRows));
|
|
100659
|
+
const shown = (0, import_react32.useMemo)(() => items.slice(start, start + listRows), [items, start, listRows]);
|
|
100660
|
+
const pv = current ? previews[current.id] : void 0;
|
|
100661
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Box_default, { flexDirection: "column", children: [
|
|
100662
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { bold: true, children: [
|
|
100663
|
+
"Resume a session ",
|
|
100664
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { ...paint("secondary"), children: `(up/down choose ${glyphs.sep} enter resume ${glyphs.sep} d delete ${glyphs.sep} esc back)` })
|
|
100665
|
+
] }),
|
|
100666
|
+
errors.map((e, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { ...paint("needsYou"), children: e }, i)),
|
|
100667
|
+
items.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { ...paint("secondary"), children: "No saved sessions yet." }),
|
|
100668
|
+
shown.map((m2, k2) => {
|
|
100669
|
+
const selected = start + k2 === at;
|
|
100670
|
+
const foreign = m2.projectRoot !== projectRoot;
|
|
100671
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { inverse: selected, ...foreign && !selected ? paint("secondary") : {}, children: [
|
|
100672
|
+
selected ? "> " : " ",
|
|
100673
|
+
formatResumeRow(m2, now, columns - 4, glyphs.sep, glyphs.ellipsis),
|
|
100674
|
+
foreign ? ` [${m2.projectRoot}]` : ""
|
|
100675
|
+
] }, m2.id);
|
|
100676
|
+
}),
|
|
100677
|
+
current && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { ...paint("secondary"), children: pv === void 0 ? "Last message: ..." : pv instanceof Error ? `Preview unavailable: ${pv.message}` : pv === null ? "No assistant reply saved in this session." : `Last message: "${pv}"` }),
|
|
100678
|
+
message && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { ...paint("needsYou"), children: message })
|
|
100679
|
+
] });
|
|
100680
|
+
}
|
|
100681
|
+
var import_react32, import_jsx_runtime11, clamp2;
|
|
100682
|
+
var init_ResumePicker = __esm({
|
|
100683
|
+
async "src/components/ResumePicker.tsx"() {
|
|
100684
|
+
"use strict";
|
|
100685
|
+
import_react32 = __toESM(require_react(), 1);
|
|
100686
|
+
await init_build2();
|
|
100687
|
+
init_resume_rows();
|
|
100688
|
+
init_rail();
|
|
100689
|
+
init_theme();
|
|
100690
|
+
import_jsx_runtime11 = __toESM(require_jsx_runtime(), 1);
|
|
100691
|
+
clamp2 = (n, lo, hi) => Math.max(lo, Math.min(hi, n));
|
|
100692
|
+
}
|
|
100693
|
+
});
|
|
100694
|
+
|
|
99654
100695
|
// src/App.tsx
|
|
99655
100696
|
var App_exports = {};
|
|
99656
100697
|
__export(App_exports, {
|
|
99657
100698
|
App: () => App2
|
|
99658
100699
|
});
|
|
99659
100700
|
import os4 from "node:os";
|
|
99660
|
-
import
|
|
99661
|
-
function App2({ repoName: repoName2, onboardingMode: onboardingMode2, launchCount: launchCount2, yolo: yolo2, history, sessions, resumeLatest: resumeLatest2 }) {
|
|
99662
|
-
const promptHistory = (0,
|
|
99663
|
-
() => history ?? new PromptHistory(createFileHistoryIO(
|
|
100701
|
+
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)(
|
|
100704
|
+
() => history ?? new PromptHistory(createFileHistoryIO(path10.join(os4.homedir(), ".spacecode", "history"))),
|
|
99664
100705
|
[history]
|
|
99665
100706
|
);
|
|
99666
|
-
const sessionStore = (0,
|
|
99667
|
-
const
|
|
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)(() => {
|
|
100714
|
+
escSwallowRef.current = true;
|
|
100715
|
+
setTimeout(() => {
|
|
100716
|
+
escSwallowRef.current = false;
|
|
100717
|
+
}, 0);
|
|
100718
|
+
}, []);
|
|
100719
|
+
const isEscOwned = (0, import_react33.useCallback)(() => escViewRef.current || escSwallowRef.current, []);
|
|
100720
|
+
const openViewer = (0, import_react33.useCallback)(() => setViewing(true), []);
|
|
100721
|
+
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 });
|
|
99668
100725
|
const { columns, rows } = useTerminalSize();
|
|
100726
|
+
const viewing = viewingRaw && !pending;
|
|
100727
|
+
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);
|
|
100731
|
+
const focusIdx = focusId === null ? -1 : liveSteps.findIndex((r) => r.id === focusId);
|
|
100732
|
+
const focusing = focusIdx >= 0 && !viewing && !picking && !pending;
|
|
100733
|
+
escViewRef.current = focusing || viewing || picking;
|
|
100734
|
+
const enterFocus = (0, import_react33.useCallback)(() => {
|
|
100735
|
+
if (liveSteps.length > 0) setFocusId(liveSteps[liveSteps.length - 1].id);
|
|
100736
|
+
}, [liveSteps]);
|
|
100737
|
+
use_input_default((input, key) => {
|
|
100738
|
+
if (key.escape) {
|
|
100739
|
+
swallowEsc();
|
|
100740
|
+
setFocusId(null);
|
|
100741
|
+
setOpenId(null);
|
|
100742
|
+
} else if (key.tab && !key.shift || key.downArrow) {
|
|
100743
|
+
setFocusId(liveSteps[(focusIdx + 1) % liveSteps.length].id);
|
|
100744
|
+
setOpenId(null);
|
|
100745
|
+
} else if (key.upArrow) {
|
|
100746
|
+
setFocusId(liveSteps[(focusIdx + liveSteps.length - 1) % liveSteps.length].id);
|
|
100747
|
+
setOpenId(null);
|
|
100748
|
+
} else if (key.return || input === " ") {
|
|
100749
|
+
setOpenId((cur) => cur === focusId ? null : focusId);
|
|
100750
|
+
}
|
|
100751
|
+
}, { isActive: Boolean(isRawModeSupported) && focusing });
|
|
100752
|
+
use_input_default((input, key) => {
|
|
100753
|
+
if (key.ctrl && input === "o") setViewing(true);
|
|
100754
|
+
}, { isActive: Boolean(isRawModeSupported) && !viewing && !picking && !pending });
|
|
100755
|
+
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)(() => {
|
|
100761
|
+
let live = true;
|
|
100762
|
+
void readGitState(runGit).then((g2) => {
|
|
100763
|
+
if (live) setGitState(g2);
|
|
100764
|
+
});
|
|
100765
|
+
return () => {
|
|
100766
|
+
live = false;
|
|
100767
|
+
};
|
|
100768
|
+
}, [runGit, turns.length]);
|
|
99669
100769
|
const footer = formatFooter({ mode, contextPct: stats.contextPct, costUsd: stats.costUsd, model: stats.model, columns });
|
|
99670
|
-
return /* @__PURE__ */ (0,
|
|
99671
|
-
|
|
99672
|
-
|
|
99673
|
-
|
|
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: [
|
|
99674
100775
|
"> ",
|
|
99675
100776
|
turn.prompt
|
|
99676
100777
|
] }),
|
|
99677
|
-
/* @__PURE__ */ (0,
|
|
99678
|
-
turn.interrupted && /* @__PURE__ */ (0,
|
|
99679
|
-
turn.summary && /* @__PURE__ */ (0,
|
|
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 })
|
|
99680
100781
|
] }, turn.id) }),
|
|
99681
|
-
/* @__PURE__ */ (0,
|
|
99682
|
-
/* @__PURE__ */ (0,
|
|
99683
|
-
|
|
99684
|
-
|
|
99685
|
-
|
|
99686
|
-
|
|
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)(
|
|
100784
|
+
ResumePicker,
|
|
100785
|
+
{
|
|
100786
|
+
sessions: resumeFound.sessions,
|
|
100787
|
+
errors: resumeFound.errors,
|
|
100788
|
+
projectRoot: process.cwd(),
|
|
100789
|
+
now: /* @__PURE__ */ new Date(),
|
|
100790
|
+
rows,
|
|
100791
|
+
columns,
|
|
100792
|
+
preview: resume.preview,
|
|
100793
|
+
onResume: resume.load,
|
|
100794
|
+
onDelete: resume.remove,
|
|
100795
|
+
onClose: () => setResumeFound(null),
|
|
100796
|
+
onEscape: swallowEsc
|
|
100797
|
+
}
|
|
100798
|
+
),
|
|
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 }),
|
|
100802
|
+
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) })
|
|
100808
|
+
] })
|
|
99687
100809
|
] });
|
|
99688
100810
|
}
|
|
99689
|
-
var
|
|
100811
|
+
var import_react33, import_jsx_runtime12, BANNER;
|
|
99690
100812
|
var init_App2 = __esm({
|
|
99691
100813
|
async "src/App.tsx"() {
|
|
99692
100814
|
"use strict";
|
|
99693
|
-
|
|
100815
|
+
import_react33 = __toESM(require_react(), 1);
|
|
99694
100816
|
await init_build2();
|
|
99695
100817
|
await init_WelcomeBanner();
|
|
100818
|
+
await init_Header();
|
|
100819
|
+
await init_ErrorBlock();
|
|
100820
|
+
init_git_status();
|
|
100821
|
+
init_node_git();
|
|
100822
|
+
init_hints();
|
|
100823
|
+
init_mode_line();
|
|
100824
|
+
init_rail();
|
|
99696
100825
|
await init_EventRenderer();
|
|
99697
100826
|
await init_PermissionPrompt();
|
|
99698
100827
|
await init_TodoChecklist();
|
|
@@ -99703,7 +100832,11 @@ var init_App2 = __esm({
|
|
|
99703
100832
|
await init_useReplController();
|
|
99704
100833
|
await init_useTerminalSize();
|
|
99705
100834
|
init_session_store();
|
|
99706
|
-
|
|
100835
|
+
init_theme();
|
|
100836
|
+
await init_TurnViewer();
|
|
100837
|
+
await init_ResumePicker();
|
|
100838
|
+
init_step_view();
|
|
100839
|
+
import_jsx_runtime12 = __toESM(require_jsx_runtime(), 1);
|
|
99707
100840
|
BANNER = /* @__PURE__ */ Symbol("welcome-banner");
|
|
99708
100841
|
}
|
|
99709
100842
|
});
|
|
@@ -99724,7 +100857,7 @@ function hideCiVariables(env3, stdoutIsTTY) {
|
|
|
99724
100857
|
}
|
|
99725
100858
|
|
|
99726
100859
|
// src/index.tsx
|
|
99727
|
-
var
|
|
100860
|
+
var import_jsx_runtime13 = __toESM(require_jsx_runtime(), 1);
|
|
99728
100861
|
var repoName = process.env.REPO_NAME || process.cwd().split("/").pop() || void 0;
|
|
99729
100862
|
var validModes = ["guest", "new_project", "existing_repo"];
|
|
99730
100863
|
var rawMode = process.env.ONBOARDING_MODE;
|
|
@@ -99741,7 +100874,7 @@ try {
|
|
|
99741
100874
|
} finally {
|
|
99742
100875
|
restoreCiVariables();
|
|
99743
100876
|
}
|
|
99744
|
-
render2(/* @__PURE__ */ (0,
|
|
100877
|
+
render2(/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(App3, { repoName, onboardingMode, launchCount, yolo, resumeLatest, interactivePicker: Boolean(process.stdout.isTTY) }));
|
|
99745
100878
|
/*! Bundled license information:
|
|
99746
100879
|
|
|
99747
100880
|
react/cjs/react.production.min.js:
|