reasonix 0.36.0 → 0.36.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -0
- package/README.zh-CN.md +17 -0
- package/dist/cli/{chat-RGMYAOY2.js → chat-7AF5SPAJ.js} +2 -2
- package/dist/cli/{chunk-EN4LAZW5.js → chunk-3OBWN2NH.js} +348 -317
- package/dist/cli/chunk-3OBWN2NH.js.map +1 -0
- package/dist/cli/{code-KJB3WDU6.js → code-SWI4EBME.js} +2 -2
- package/dist/cli/index.js +3 -3
- package/package.json +1 -1
- package/dist/cli/chunk-EN4LAZW5.js.map +0 -1
- /package/dist/cli/{chat-RGMYAOY2.js.map → chat-7AF5SPAJ.js.map} +0 -0
- /package/dist/cli/{code-KJB3WDU6.js.map → code-SWI4EBME.js.map} +0 -0
|
@@ -6894,6 +6894,10 @@ function handleToolStart(ev, ctx) {
|
|
|
6894
6894
|
}
|
|
6895
6895
|
}
|
|
6896
6896
|
function handleErrorEvent(ev, ctx) {
|
|
6897
|
+
ctx.setOngoingTool(null);
|
|
6898
|
+
ctx.setToolProgress(null);
|
|
6899
|
+
ctx.toolStartedAtRef.current = null;
|
|
6900
|
+
ctx.translator.toolAbort(ev.error ?? ev.content);
|
|
6897
6901
|
ctx.log.pushError("tool error", ev.error ?? ev.content);
|
|
6898
6902
|
}
|
|
6899
6903
|
function handleWarningEvent(ev, ctx) {
|
|
@@ -6935,272 +6939,6 @@ function handleToolEvent(ev, ctx) {
|
|
|
6935
6939
|
}
|
|
6936
6940
|
}
|
|
6937
6941
|
|
|
6938
|
-
// src/cli/ui/hooks/useAgentSession.ts
|
|
6939
|
-
import { useMemo as useMemo6 } from "react";
|
|
6940
|
-
function useAgentSession({
|
|
6941
|
-
sessionId,
|
|
6942
|
-
model: model2,
|
|
6943
|
-
workspace,
|
|
6944
|
-
branch
|
|
6945
|
-
}) {
|
|
6946
|
-
return useMemo6(
|
|
6947
|
-
() => ({
|
|
6948
|
-
id: sessionId ?? "default",
|
|
6949
|
-
branch: branch ?? "main",
|
|
6950
|
-
workspace,
|
|
6951
|
-
model: model2
|
|
6952
|
-
}),
|
|
6953
|
-
[sessionId, branch, workspace, model2]
|
|
6954
|
-
);
|
|
6955
|
-
}
|
|
6956
|
-
|
|
6957
|
-
// src/cli/ui/hooks/useChatScroll.ts
|
|
6958
|
-
import { useCallback as useCallback2, useEffect as useEffect4, useRef as useRef2, useState as useState14 } from "react";
|
|
6959
|
-
var SCROLL_PAGE_ROWS = 3;
|
|
6960
|
-
var COALESCE_MS = 16;
|
|
6961
|
-
function useChatScroll() {
|
|
6962
|
-
const [scrollRows, setScrollRows] = useState14(0);
|
|
6963
|
-
const [pinned, setPinned] = useState14(true);
|
|
6964
|
-
const [maxScroll, setMaxScrollState] = useState14(0);
|
|
6965
|
-
const maxScrollRef = useRef2(0);
|
|
6966
|
-
const pendingDelta = useRef2(0);
|
|
6967
|
-
const flushTimer = useRef2(null);
|
|
6968
|
-
const flush = useCallback2(() => {
|
|
6969
|
-
flushTimer.current = null;
|
|
6970
|
-
const d = pendingDelta.current;
|
|
6971
|
-
pendingDelta.current = 0;
|
|
6972
|
-
if (d === 0) return;
|
|
6973
|
-
if (d < 0) setPinned(false);
|
|
6974
|
-
setScrollRows((o) => {
|
|
6975
|
-
const next = Math.max(0, Math.min(maxScrollRef.current, o + d));
|
|
6976
|
-
if (next >= maxScrollRef.current) setPinned(true);
|
|
6977
|
-
return next;
|
|
6978
|
-
});
|
|
6979
|
-
}, []);
|
|
6980
|
-
const schedule = useCallback2(
|
|
6981
|
-
(delta) => {
|
|
6982
|
-
pendingDelta.current += delta;
|
|
6983
|
-
if (flushTimer.current !== null) return;
|
|
6984
|
-
flushTimer.current = setTimeout(flush, COALESCE_MS);
|
|
6985
|
-
},
|
|
6986
|
-
[flush]
|
|
6987
|
-
);
|
|
6988
|
-
useEffect4(() => {
|
|
6989
|
-
return () => {
|
|
6990
|
-
if (flushTimer.current !== null) {
|
|
6991
|
-
clearTimeout(flushTimer.current);
|
|
6992
|
-
flushTimer.current = null;
|
|
6993
|
-
}
|
|
6994
|
-
};
|
|
6995
|
-
}, []);
|
|
6996
|
-
useEffect4(() => {
|
|
6997
|
-
if (pinned) setScrollRows(maxScroll);
|
|
6998
|
-
}, [pinned, maxScroll]);
|
|
6999
|
-
useEffect4(() => {
|
|
7000
|
-
if (scrollRows > maxScroll) setScrollRows(maxScroll);
|
|
7001
|
-
}, [scrollRows, maxScroll]);
|
|
7002
|
-
const scrollUp = useCallback2(() => schedule(-SCROLL_PAGE_ROWS), [schedule]);
|
|
7003
|
-
const scrollDown = useCallback2(() => schedule(SCROLL_PAGE_ROWS), [schedule]);
|
|
7004
|
-
const jumpToBottom = useCallback2(() => {
|
|
7005
|
-
pendingDelta.current = 0;
|
|
7006
|
-
if (flushTimer.current !== null) {
|
|
7007
|
-
clearTimeout(flushTimer.current);
|
|
7008
|
-
flushTimer.current = null;
|
|
7009
|
-
}
|
|
7010
|
-
setPinned(true);
|
|
7011
|
-
}, []);
|
|
7012
|
-
const setMaxScroll = useCallback2((rows) => {
|
|
7013
|
-
maxScrollRef.current = rows;
|
|
7014
|
-
setMaxScrollState(rows);
|
|
7015
|
-
}, []);
|
|
7016
|
-
return { scrollRows, pinned, scrollUp, scrollDown, jumpToBottom, setMaxScroll };
|
|
7017
|
-
}
|
|
7018
|
-
|
|
7019
|
-
// src/cli/ui/hooks/useCodeMode.ts
|
|
7020
|
-
import { useCallback as useCallback3 } from "react";
|
|
7021
|
-
function useCodeMode(opts) {
|
|
7022
|
-
const { codeMode, pendingEdits, currentRootDir, session, syncPendingCount, recordEdit } = opts;
|
|
7023
|
-
const codeApply = useCallback3(
|
|
7024
|
-
(indices) => {
|
|
7025
|
-
if (!codeMode) return "not in code mode";
|
|
7026
|
-
const blocks = pendingEdits.current;
|
|
7027
|
-
if (blocks.length === 0) {
|
|
7028
|
-
return "nothing pending \u2014 the model hasn't proposed edits since the last /apply or /discard.";
|
|
7029
|
-
}
|
|
7030
|
-
const useSubset = indices !== void 0 && indices.length > 0;
|
|
7031
|
-
const { selected, remaining } = useSubset ? partitionEdits(blocks, indices) : { selected: blocks, remaining: [] };
|
|
7032
|
-
if (selected.length === 0) {
|
|
7033
|
-
return "\u25B8 no edits matched those indices \u2014 nothing applied. Use /apply with no args to commit them all.";
|
|
7034
|
-
}
|
|
7035
|
-
const snaps = snapshotBeforeEdits(selected, currentRootDir);
|
|
7036
|
-
const results = applyEditBlocks(selected, currentRootDir);
|
|
7037
|
-
const anyApplied = results.some((r) => r.status === "applied" || r.status === "created");
|
|
7038
|
-
if (anyApplied) recordEdit("review-apply", selected, results, snaps);
|
|
7039
|
-
pendingEdits.current = remaining;
|
|
7040
|
-
if (remaining.length === 0) clearPendingEdits(session ?? null);
|
|
7041
|
-
else savePendingEdits(session ?? null, remaining);
|
|
7042
|
-
syncPendingCount();
|
|
7043
|
-
const tail = remaining.length > 0 ? `
|
|
7044
|
-
\u25B8 ${remaining.length} edit block(s) still pending \u2014 /apply or /discard to clear them.` : "";
|
|
7045
|
-
return formatEditResults(results) + tail;
|
|
7046
|
-
},
|
|
7047
|
-
[codeMode, currentRootDir, session, syncPendingCount, recordEdit, pendingEdits]
|
|
7048
|
-
);
|
|
7049
|
-
const codeDiscard = useCallback3(
|
|
7050
|
-
(indices) => {
|
|
7051
|
-
const blocks = pendingEdits.current;
|
|
7052
|
-
if (blocks.length === 0) return "nothing pending to discard.";
|
|
7053
|
-
const useSubset = indices !== void 0 && indices.length > 0;
|
|
7054
|
-
const { selected, remaining } = useSubset ? partitionEdits(blocks, indices) : { selected: blocks, remaining: [] };
|
|
7055
|
-
if (selected.length === 0) {
|
|
7056
|
-
return "\u25B8 no edits matched those indices \u2014 nothing discarded.";
|
|
7057
|
-
}
|
|
7058
|
-
pendingEdits.current = remaining;
|
|
7059
|
-
if (remaining.length === 0) clearPendingEdits(session ?? null);
|
|
7060
|
-
else savePendingEdits(session ?? null, remaining);
|
|
7061
|
-
syncPendingCount();
|
|
7062
|
-
const tail = remaining.length > 0 ? ` (${remaining.length} block(s) still pending)` : ". Nothing was written to disk.";
|
|
7063
|
-
return `\u25B8 discarded ${selected.length} pending edit block(s)${tail}`;
|
|
7064
|
-
},
|
|
7065
|
-
[session, syncPendingCount, pendingEdits]
|
|
7066
|
-
);
|
|
7067
|
-
return { codeApply, codeDiscard };
|
|
7068
|
-
}
|
|
7069
|
-
|
|
7070
|
-
// src/cli/ui/hooks/useInputRecall.ts
|
|
7071
|
-
import { useCallback as useCallback4, useRef as useRef3 } from "react";
|
|
7072
|
-
function useInputRecall(setInput) {
|
|
7073
|
-
const promptHistory = useRef3([]);
|
|
7074
|
-
const historyCursor = useRef3(-1);
|
|
7075
|
-
const recallPrev = useCallback4(() => {
|
|
7076
|
-
const hist = promptHistory.current;
|
|
7077
|
-
if (hist.length === 0) return;
|
|
7078
|
-
const nextCursor = Math.min(historyCursor.current + 1, hist.length - 1);
|
|
7079
|
-
historyCursor.current = nextCursor;
|
|
7080
|
-
setInput(hist[hist.length - 1 - nextCursor] ?? "");
|
|
7081
|
-
}, [setInput]);
|
|
7082
|
-
const recallNext = useCallback4(() => {
|
|
7083
|
-
if (historyCursor.current < 0) return;
|
|
7084
|
-
const hist = promptHistory.current;
|
|
7085
|
-
const nextCursor = historyCursor.current - 1;
|
|
7086
|
-
historyCursor.current = nextCursor;
|
|
7087
|
-
setInput(nextCursor < 0 ? "" : hist[hist.length - 1 - nextCursor] ?? "");
|
|
7088
|
-
}, [setInput]);
|
|
7089
|
-
const pushHistory = useCallback4((text) => {
|
|
7090
|
-
promptHistory.current.push(text);
|
|
7091
|
-
}, []);
|
|
7092
|
-
const resetCursor = useCallback4(() => {
|
|
7093
|
-
historyCursor.current = -1;
|
|
7094
|
-
}, []);
|
|
7095
|
-
return { recallPrev, recallNext, pushHistory, resetCursor };
|
|
7096
|
-
}
|
|
7097
|
-
|
|
7098
|
-
// src/cli/ui/hooks/useLoopMode.ts
|
|
7099
|
-
import { useCallback as useCallback5, useEffect as useEffect5, useRef as useRef4, useState as useState15 } from "react";
|
|
7100
|
-
function useLoopMode(opts) {
|
|
7101
|
-
const { log, busyRef, handleSubmitRef } = opts;
|
|
7102
|
-
const [activeLoop, setActiveLoop] = useState15(null);
|
|
7103
|
-
const activeLoopRef = useRef4(null);
|
|
7104
|
-
const loopTimerRef = useRef4(null);
|
|
7105
|
-
const loopFiringRef = useRef4(false);
|
|
7106
|
-
useEffect5(() => {
|
|
7107
|
-
activeLoopRef.current = activeLoop;
|
|
7108
|
-
}, [activeLoop]);
|
|
7109
|
-
const stopLoop = useCallback5(() => {
|
|
7110
|
-
if (loopTimerRef.current) {
|
|
7111
|
-
clearTimeout(loopTimerRef.current);
|
|
7112
|
-
loopTimerRef.current = null;
|
|
7113
|
-
}
|
|
7114
|
-
const cur = activeLoopRef.current;
|
|
7115
|
-
if (!cur) return;
|
|
7116
|
-
setActiveLoop(null);
|
|
7117
|
-
log.pushInfo(`\u25B8 loop stopped (after ${cur.iter} iter${cur.iter === 1 ? "" : "s"}).`);
|
|
7118
|
-
}, [log]);
|
|
7119
|
-
const startLoop = useCallback5((intervalMs, prompt) => {
|
|
7120
|
-
if (loopTimerRef.current) {
|
|
7121
|
-
clearTimeout(loopTimerRef.current);
|
|
7122
|
-
loopTimerRef.current = null;
|
|
7123
|
-
}
|
|
7124
|
-
setActiveLoop({
|
|
7125
|
-
prompt,
|
|
7126
|
-
intervalMs,
|
|
7127
|
-
nextFireAt: Date.now() + intervalMs,
|
|
7128
|
-
iter: 0
|
|
7129
|
-
});
|
|
7130
|
-
}, []);
|
|
7131
|
-
const getLoopStatus = useCallback5(() => {
|
|
7132
|
-
const cur = activeLoopRef.current;
|
|
7133
|
-
if (!cur) return null;
|
|
7134
|
-
return {
|
|
7135
|
-
prompt: cur.prompt,
|
|
7136
|
-
intervalMs: cur.intervalMs,
|
|
7137
|
-
iter: cur.iter,
|
|
7138
|
-
nextFireMs: Math.max(0, cur.nextFireAt - Date.now())
|
|
7139
|
-
};
|
|
7140
|
-
}, []);
|
|
7141
|
-
const isLoopActive = useCallback5(() => activeLoopRef.current !== null, []);
|
|
7142
|
-
const isLoopFiring = useCallback5(() => loopFiringRef.current, []);
|
|
7143
|
-
const clearFiringFlag = useCallback5(() => {
|
|
7144
|
-
loopFiringRef.current = false;
|
|
7145
|
-
}, []);
|
|
7146
|
-
useEffect5(() => {
|
|
7147
|
-
if (!activeLoop) return;
|
|
7148
|
-
const delay = Math.max(0, activeLoop.nextFireAt - Date.now());
|
|
7149
|
-
const timer = setTimeout(async () => {
|
|
7150
|
-
loopTimerRef.current = null;
|
|
7151
|
-
if (busyRef.current) {
|
|
7152
|
-
setActiveLoop((cur2) => cur2 ? { ...cur2, nextFireAt: Date.now() + 1e3 } : cur2);
|
|
7153
|
-
return;
|
|
7154
|
-
}
|
|
7155
|
-
const cur = activeLoopRef.current;
|
|
7156
|
-
if (!cur) return;
|
|
7157
|
-
const nextIter = cur.iter + 1;
|
|
7158
|
-
setActiveLoop(
|
|
7159
|
-
(c) => c ? { ...c, iter: nextIter, nextFireAt: Date.now() + cur.intervalMs } : c
|
|
7160
|
-
);
|
|
7161
|
-
log.pushInfo(`\u25B8 /loop iter ${nextIter} \u2192 ${cur.prompt}`);
|
|
7162
|
-
loopFiringRef.current = true;
|
|
7163
|
-
try {
|
|
7164
|
-
await handleSubmitRef.current?.(cur.prompt);
|
|
7165
|
-
} catch {
|
|
7166
|
-
stopLoop();
|
|
7167
|
-
} finally {
|
|
7168
|
-
loopFiringRef.current = false;
|
|
7169
|
-
}
|
|
7170
|
-
}, delay);
|
|
7171
|
-
loopTimerRef.current = timer;
|
|
7172
|
-
return () => clearTimeout(timer);
|
|
7173
|
-
}, [activeLoop, stopLoop, log, busyRef, handleSubmitRef]);
|
|
7174
|
-
return {
|
|
7175
|
-
startLoop,
|
|
7176
|
-
stopLoop,
|
|
7177
|
-
getLoopStatus,
|
|
7178
|
-
isLoopActive,
|
|
7179
|
-
isLoopFiring,
|
|
7180
|
-
clearFiringFlag,
|
|
7181
|
-
activeLoop
|
|
7182
|
-
};
|
|
7183
|
-
}
|
|
7184
|
-
|
|
7185
|
-
// src/cli/ui/hooks/useQuit.ts
|
|
7186
|
-
import { useCallback as useCallback6, useEffect as useEffect6 } from "react";
|
|
7187
|
-
function useQuit(transcriptRef) {
|
|
7188
|
-
const quitProcess = useCallback6(() => {
|
|
7189
|
-
transcriptRef.current?.end();
|
|
7190
|
-
process.exit(0);
|
|
7191
|
-
}, [transcriptRef]);
|
|
7192
|
-
useEffect6(() => {
|
|
7193
|
-
process.on("SIGINT", quitProcess);
|
|
7194
|
-
return () => {
|
|
7195
|
-
process.off("SIGINT", quitProcess);
|
|
7196
|
-
};
|
|
7197
|
-
}, [quitProcess]);
|
|
7198
|
-
return quitProcess;
|
|
7199
|
-
}
|
|
7200
|
-
|
|
7201
|
-
// src/cli/ui/hooks/useScrollback.ts
|
|
7202
|
-
import { useMemo as useMemo7 } from "react";
|
|
7203
|
-
|
|
7204
6942
|
// src/cli/ui/state/provider.tsx
|
|
7205
6943
|
import React29 from "react";
|
|
7206
6944
|
|
|
@@ -7536,62 +7274,337 @@ function initialState(session, cards = []) {
|
|
|
7536
7274
|
};
|
|
7537
7275
|
}
|
|
7538
7276
|
|
|
7539
|
-
// src/cli/ui/state/store.ts
|
|
7540
|
-
function createStore(session, initialCards) {
|
|
7541
|
-
let state = initialState(session, initialCards);
|
|
7542
|
-
const stateListeners = /* @__PURE__ */ new Set();
|
|
7543
|
-
const eventListeners = /* @__PURE__ */ new Set();
|
|
7544
|
-
return {
|
|
7545
|
-
getState() {
|
|
7546
|
-
return state;
|
|
7547
|
-
},
|
|
7548
|
-
dispatch(event) {
|
|
7549
|
-
state = reduce(state, event);
|
|
7550
|
-
for (const listener of stateListeners) listener();
|
|
7551
|
-
for (const listener of eventListeners) listener(event);
|
|
7277
|
+
// src/cli/ui/state/store.ts
|
|
7278
|
+
function createStore(session, initialCards) {
|
|
7279
|
+
let state = initialState(session, initialCards);
|
|
7280
|
+
const stateListeners = /* @__PURE__ */ new Set();
|
|
7281
|
+
const eventListeners = /* @__PURE__ */ new Set();
|
|
7282
|
+
return {
|
|
7283
|
+
getState() {
|
|
7284
|
+
return state;
|
|
7285
|
+
},
|
|
7286
|
+
dispatch(event) {
|
|
7287
|
+
state = reduce(state, event);
|
|
7288
|
+
for (const listener of stateListeners) listener();
|
|
7289
|
+
for (const listener of eventListeners) listener(event);
|
|
7290
|
+
},
|
|
7291
|
+
subscribe(listener) {
|
|
7292
|
+
stateListeners.add(listener);
|
|
7293
|
+
return () => {
|
|
7294
|
+
stateListeners.delete(listener);
|
|
7295
|
+
};
|
|
7296
|
+
},
|
|
7297
|
+
onEvent(listener) {
|
|
7298
|
+
eventListeners.add(listener);
|
|
7299
|
+
return () => {
|
|
7300
|
+
eventListeners.delete(listener);
|
|
7301
|
+
};
|
|
7302
|
+
}
|
|
7303
|
+
};
|
|
7304
|
+
}
|
|
7305
|
+
|
|
7306
|
+
// src/cli/ui/state/provider.tsx
|
|
7307
|
+
var StoreCtx = React29.createContext(null);
|
|
7308
|
+
function AgentStoreProvider({
|
|
7309
|
+
session,
|
|
7310
|
+
initialCards,
|
|
7311
|
+
children
|
|
7312
|
+
}) {
|
|
7313
|
+
const initialCardsRef = React29.useRef(initialCards);
|
|
7314
|
+
const store = React29.useMemo(() => createStore(session, initialCardsRef.current), [session]);
|
|
7315
|
+
return /* @__PURE__ */ React29.createElement(StoreCtx.Provider, { value: store }, children);
|
|
7316
|
+
}
|
|
7317
|
+
function useAgentStore() {
|
|
7318
|
+
const store = React29.useContext(StoreCtx);
|
|
7319
|
+
if (!store) throw new Error("useAgentStore must be used inside AgentStoreProvider");
|
|
7320
|
+
return store;
|
|
7321
|
+
}
|
|
7322
|
+
function useAgentState(selector) {
|
|
7323
|
+
const store = useAgentStore();
|
|
7324
|
+
const subscribe = React29.useCallback((cb) => store.subscribe(cb), [store]);
|
|
7325
|
+
const getSnapshot = React29.useCallback(() => selector(store.getState()), [store, selector]);
|
|
7326
|
+
return React29.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
7327
|
+
}
|
|
7328
|
+
function useDispatch() {
|
|
7329
|
+
return useAgentStore().dispatch;
|
|
7330
|
+
}
|
|
7331
|
+
|
|
7332
|
+
// src/cli/ui/hooks/useActivityPhase.ts
|
|
7333
|
+
function deriveActivityLabel(cards) {
|
|
7334
|
+
if (cards.some((c) => c.kind === "reasoning" && c.streaming)) return "thinking\u2026";
|
|
7335
|
+
const last = cards[cards.length - 1];
|
|
7336
|
+
if (!last || last.kind === "user") return "waiting for model\u2026";
|
|
7337
|
+
return "processing\u2026";
|
|
7338
|
+
}
|
|
7339
|
+
function useActivityLabel() {
|
|
7340
|
+
return useAgentState((s) => deriveActivityLabel(s.cards));
|
|
7341
|
+
}
|
|
7342
|
+
|
|
7343
|
+
// src/cli/ui/hooks/useAgentSession.ts
|
|
7344
|
+
import { useMemo as useMemo6 } from "react";
|
|
7345
|
+
function useAgentSession({
|
|
7346
|
+
sessionId,
|
|
7347
|
+
model: model2,
|
|
7348
|
+
workspace,
|
|
7349
|
+
branch
|
|
7350
|
+
}) {
|
|
7351
|
+
return useMemo6(
|
|
7352
|
+
() => ({
|
|
7353
|
+
id: sessionId ?? "default",
|
|
7354
|
+
branch: branch ?? "main",
|
|
7355
|
+
workspace,
|
|
7356
|
+
model: model2
|
|
7357
|
+
}),
|
|
7358
|
+
[sessionId, branch, workspace, model2]
|
|
7359
|
+
);
|
|
7360
|
+
}
|
|
7361
|
+
|
|
7362
|
+
// src/cli/ui/hooks/useChatScroll.ts
|
|
7363
|
+
import { useCallback as useCallback2, useEffect as useEffect4, useRef as useRef2, useState as useState14 } from "react";
|
|
7364
|
+
var SCROLL_PAGE_ROWS = 3;
|
|
7365
|
+
var COALESCE_MS = 16;
|
|
7366
|
+
function useChatScroll() {
|
|
7367
|
+
const [scrollRows, setScrollRows] = useState14(0);
|
|
7368
|
+
const [pinned, setPinned] = useState14(true);
|
|
7369
|
+
const [maxScroll, setMaxScrollState] = useState14(0);
|
|
7370
|
+
const maxScrollRef = useRef2(0);
|
|
7371
|
+
const pendingDelta = useRef2(0);
|
|
7372
|
+
const flushTimer = useRef2(null);
|
|
7373
|
+
const flush = useCallback2(() => {
|
|
7374
|
+
flushTimer.current = null;
|
|
7375
|
+
const d = pendingDelta.current;
|
|
7376
|
+
pendingDelta.current = 0;
|
|
7377
|
+
if (d === 0) return;
|
|
7378
|
+
if (d < 0) setPinned(false);
|
|
7379
|
+
setScrollRows((o) => {
|
|
7380
|
+
const next = Math.max(0, Math.min(maxScrollRef.current, o + d));
|
|
7381
|
+
if (next >= maxScrollRef.current) setPinned(true);
|
|
7382
|
+
return next;
|
|
7383
|
+
});
|
|
7384
|
+
}, []);
|
|
7385
|
+
const schedule = useCallback2(
|
|
7386
|
+
(delta) => {
|
|
7387
|
+
pendingDelta.current += delta;
|
|
7388
|
+
if (flushTimer.current !== null) return;
|
|
7389
|
+
flushTimer.current = setTimeout(flush, COALESCE_MS);
|
|
7390
|
+
},
|
|
7391
|
+
[flush]
|
|
7392
|
+
);
|
|
7393
|
+
useEffect4(() => {
|
|
7394
|
+
return () => {
|
|
7395
|
+
if (flushTimer.current !== null) {
|
|
7396
|
+
clearTimeout(flushTimer.current);
|
|
7397
|
+
flushTimer.current = null;
|
|
7398
|
+
}
|
|
7399
|
+
};
|
|
7400
|
+
}, []);
|
|
7401
|
+
useEffect4(() => {
|
|
7402
|
+
if (pinned) setScrollRows(maxScroll);
|
|
7403
|
+
}, [pinned, maxScroll]);
|
|
7404
|
+
useEffect4(() => {
|
|
7405
|
+
if (scrollRows > maxScroll) setScrollRows(maxScroll);
|
|
7406
|
+
}, [scrollRows, maxScroll]);
|
|
7407
|
+
const scrollUp = useCallback2(() => schedule(-SCROLL_PAGE_ROWS), [schedule]);
|
|
7408
|
+
const scrollDown = useCallback2(() => schedule(SCROLL_PAGE_ROWS), [schedule]);
|
|
7409
|
+
const jumpToBottom = useCallback2(() => {
|
|
7410
|
+
pendingDelta.current = 0;
|
|
7411
|
+
if (flushTimer.current !== null) {
|
|
7412
|
+
clearTimeout(flushTimer.current);
|
|
7413
|
+
flushTimer.current = null;
|
|
7414
|
+
}
|
|
7415
|
+
setPinned(true);
|
|
7416
|
+
}, []);
|
|
7417
|
+
const setMaxScroll = useCallback2((rows) => {
|
|
7418
|
+
maxScrollRef.current = rows;
|
|
7419
|
+
setMaxScrollState(rows);
|
|
7420
|
+
}, []);
|
|
7421
|
+
return { scrollRows, pinned, scrollUp, scrollDown, jumpToBottom, setMaxScroll };
|
|
7422
|
+
}
|
|
7423
|
+
|
|
7424
|
+
// src/cli/ui/hooks/useCodeMode.ts
|
|
7425
|
+
import { useCallback as useCallback3 } from "react";
|
|
7426
|
+
function useCodeMode(opts) {
|
|
7427
|
+
const { codeMode, pendingEdits, currentRootDir, session, syncPendingCount, recordEdit } = opts;
|
|
7428
|
+
const codeApply = useCallback3(
|
|
7429
|
+
(indices) => {
|
|
7430
|
+
if (!codeMode) return "not in code mode";
|
|
7431
|
+
const blocks = pendingEdits.current;
|
|
7432
|
+
if (blocks.length === 0) {
|
|
7433
|
+
return "nothing pending \u2014 the model hasn't proposed edits since the last /apply or /discard.";
|
|
7434
|
+
}
|
|
7435
|
+
const useSubset = indices !== void 0 && indices.length > 0;
|
|
7436
|
+
const { selected, remaining } = useSubset ? partitionEdits(blocks, indices) : { selected: blocks, remaining: [] };
|
|
7437
|
+
if (selected.length === 0) {
|
|
7438
|
+
return "\u25B8 no edits matched those indices \u2014 nothing applied. Use /apply with no args to commit them all.";
|
|
7439
|
+
}
|
|
7440
|
+
const snaps = snapshotBeforeEdits(selected, currentRootDir);
|
|
7441
|
+
const results = applyEditBlocks(selected, currentRootDir);
|
|
7442
|
+
const anyApplied = results.some((r) => r.status === "applied" || r.status === "created");
|
|
7443
|
+
if (anyApplied) recordEdit("review-apply", selected, results, snaps);
|
|
7444
|
+
pendingEdits.current = remaining;
|
|
7445
|
+
if (remaining.length === 0) clearPendingEdits(session ?? null);
|
|
7446
|
+
else savePendingEdits(session ?? null, remaining);
|
|
7447
|
+
syncPendingCount();
|
|
7448
|
+
const tail = remaining.length > 0 ? `
|
|
7449
|
+
\u25B8 ${remaining.length} edit block(s) still pending \u2014 /apply or /discard to clear them.` : "";
|
|
7450
|
+
return formatEditResults(results) + tail;
|
|
7552
7451
|
},
|
|
7553
|
-
|
|
7554
|
-
|
|
7555
|
-
|
|
7556
|
-
|
|
7557
|
-
|
|
7452
|
+
[codeMode, currentRootDir, session, syncPendingCount, recordEdit, pendingEdits]
|
|
7453
|
+
);
|
|
7454
|
+
const codeDiscard = useCallback3(
|
|
7455
|
+
(indices) => {
|
|
7456
|
+
const blocks = pendingEdits.current;
|
|
7457
|
+
if (blocks.length === 0) return "nothing pending to discard.";
|
|
7458
|
+
const useSubset = indices !== void 0 && indices.length > 0;
|
|
7459
|
+
const { selected, remaining } = useSubset ? partitionEdits(blocks, indices) : { selected: blocks, remaining: [] };
|
|
7460
|
+
if (selected.length === 0) {
|
|
7461
|
+
return "\u25B8 no edits matched those indices \u2014 nothing discarded.";
|
|
7462
|
+
}
|
|
7463
|
+
pendingEdits.current = remaining;
|
|
7464
|
+
if (remaining.length === 0) clearPendingEdits(session ?? null);
|
|
7465
|
+
else savePendingEdits(session ?? null, remaining);
|
|
7466
|
+
syncPendingCount();
|
|
7467
|
+
const tail = remaining.length > 0 ? ` (${remaining.length} block(s) still pending)` : ". Nothing was written to disk.";
|
|
7468
|
+
return `\u25B8 discarded ${selected.length} pending edit block(s)${tail}`;
|
|
7558
7469
|
},
|
|
7559
|
-
|
|
7560
|
-
|
|
7561
|
-
|
|
7562
|
-
eventListeners.delete(listener);
|
|
7563
|
-
};
|
|
7564
|
-
}
|
|
7565
|
-
};
|
|
7470
|
+
[session, syncPendingCount, pendingEdits]
|
|
7471
|
+
);
|
|
7472
|
+
return { codeApply, codeDiscard };
|
|
7566
7473
|
}
|
|
7567
7474
|
|
|
7568
|
-
// src/cli/ui/
|
|
7569
|
-
|
|
7570
|
-
function
|
|
7571
|
-
|
|
7572
|
-
|
|
7573
|
-
|
|
7574
|
-
|
|
7575
|
-
|
|
7576
|
-
|
|
7577
|
-
|
|
7578
|
-
|
|
7579
|
-
|
|
7580
|
-
const
|
|
7581
|
-
|
|
7582
|
-
|
|
7475
|
+
// src/cli/ui/hooks/useInputRecall.ts
|
|
7476
|
+
import { useCallback as useCallback4, useRef as useRef3 } from "react";
|
|
7477
|
+
function useInputRecall(setInput) {
|
|
7478
|
+
const promptHistory = useRef3([]);
|
|
7479
|
+
const historyCursor = useRef3(-1);
|
|
7480
|
+
const recallPrev = useCallback4(() => {
|
|
7481
|
+
const hist = promptHistory.current;
|
|
7482
|
+
if (hist.length === 0) return;
|
|
7483
|
+
const nextCursor = Math.min(historyCursor.current + 1, hist.length - 1);
|
|
7484
|
+
historyCursor.current = nextCursor;
|
|
7485
|
+
setInput(hist[hist.length - 1 - nextCursor] ?? "");
|
|
7486
|
+
}, [setInput]);
|
|
7487
|
+
const recallNext = useCallback4(() => {
|
|
7488
|
+
if (historyCursor.current < 0) return;
|
|
7489
|
+
const hist = promptHistory.current;
|
|
7490
|
+
const nextCursor = historyCursor.current - 1;
|
|
7491
|
+
historyCursor.current = nextCursor;
|
|
7492
|
+
setInput(nextCursor < 0 ? "" : hist[hist.length - 1 - nextCursor] ?? "");
|
|
7493
|
+
}, [setInput]);
|
|
7494
|
+
const pushHistory = useCallback4((text) => {
|
|
7495
|
+
promptHistory.current.push(text);
|
|
7496
|
+
}, []);
|
|
7497
|
+
const resetCursor = useCallback4(() => {
|
|
7498
|
+
historyCursor.current = -1;
|
|
7499
|
+
}, []);
|
|
7500
|
+
return { recallPrev, recallNext, pushHistory, resetCursor };
|
|
7583
7501
|
}
|
|
7584
|
-
|
|
7585
|
-
|
|
7586
|
-
|
|
7587
|
-
|
|
7588
|
-
|
|
7502
|
+
|
|
7503
|
+
// src/cli/ui/hooks/useLoopMode.ts
|
|
7504
|
+
import { useCallback as useCallback5, useEffect as useEffect5, useRef as useRef4, useState as useState15 } from "react";
|
|
7505
|
+
function useLoopMode(opts) {
|
|
7506
|
+
const { log, busyRef, handleSubmitRef } = opts;
|
|
7507
|
+
const [activeLoop, setActiveLoop] = useState15(null);
|
|
7508
|
+
const activeLoopRef = useRef4(null);
|
|
7509
|
+
const loopTimerRef = useRef4(null);
|
|
7510
|
+
const loopFiringRef = useRef4(false);
|
|
7511
|
+
useEffect5(() => {
|
|
7512
|
+
activeLoopRef.current = activeLoop;
|
|
7513
|
+
}, [activeLoop]);
|
|
7514
|
+
const stopLoop = useCallback5(() => {
|
|
7515
|
+
if (loopTimerRef.current) {
|
|
7516
|
+
clearTimeout(loopTimerRef.current);
|
|
7517
|
+
loopTimerRef.current = null;
|
|
7518
|
+
}
|
|
7519
|
+
const cur = activeLoopRef.current;
|
|
7520
|
+
if (!cur) return;
|
|
7521
|
+
setActiveLoop(null);
|
|
7522
|
+
log.pushInfo(`\u25B8 loop stopped (after ${cur.iter} iter${cur.iter === 1 ? "" : "s"}).`);
|
|
7523
|
+
}, [log]);
|
|
7524
|
+
const startLoop = useCallback5((intervalMs, prompt) => {
|
|
7525
|
+
if (loopTimerRef.current) {
|
|
7526
|
+
clearTimeout(loopTimerRef.current);
|
|
7527
|
+
loopTimerRef.current = null;
|
|
7528
|
+
}
|
|
7529
|
+
setActiveLoop({
|
|
7530
|
+
prompt,
|
|
7531
|
+
intervalMs,
|
|
7532
|
+
nextFireAt: Date.now() + intervalMs,
|
|
7533
|
+
iter: 0
|
|
7534
|
+
});
|
|
7535
|
+
}, []);
|
|
7536
|
+
const getLoopStatus = useCallback5(() => {
|
|
7537
|
+
const cur = activeLoopRef.current;
|
|
7538
|
+
if (!cur) return null;
|
|
7539
|
+
return {
|
|
7540
|
+
prompt: cur.prompt,
|
|
7541
|
+
intervalMs: cur.intervalMs,
|
|
7542
|
+
iter: cur.iter,
|
|
7543
|
+
nextFireMs: Math.max(0, cur.nextFireAt - Date.now())
|
|
7544
|
+
};
|
|
7545
|
+
}, []);
|
|
7546
|
+
const isLoopActive = useCallback5(() => activeLoopRef.current !== null, []);
|
|
7547
|
+
const isLoopFiring = useCallback5(() => loopFiringRef.current, []);
|
|
7548
|
+
const clearFiringFlag = useCallback5(() => {
|
|
7549
|
+
loopFiringRef.current = false;
|
|
7550
|
+
}, []);
|
|
7551
|
+
useEffect5(() => {
|
|
7552
|
+
if (!activeLoop) return;
|
|
7553
|
+
const delay = Math.max(0, activeLoop.nextFireAt - Date.now());
|
|
7554
|
+
const timer = setTimeout(async () => {
|
|
7555
|
+
loopTimerRef.current = null;
|
|
7556
|
+
if (busyRef.current) {
|
|
7557
|
+
setActiveLoop((cur2) => cur2 ? { ...cur2, nextFireAt: Date.now() + 1e3 } : cur2);
|
|
7558
|
+
return;
|
|
7559
|
+
}
|
|
7560
|
+
const cur = activeLoopRef.current;
|
|
7561
|
+
if (!cur) return;
|
|
7562
|
+
const nextIter = cur.iter + 1;
|
|
7563
|
+
setActiveLoop(
|
|
7564
|
+
(c) => c ? { ...c, iter: nextIter, nextFireAt: Date.now() + cur.intervalMs } : c
|
|
7565
|
+
);
|
|
7566
|
+
log.pushInfo(`\u25B8 /loop iter ${nextIter} \u2192 ${cur.prompt}`);
|
|
7567
|
+
loopFiringRef.current = true;
|
|
7568
|
+
try {
|
|
7569
|
+
await handleSubmitRef.current?.(cur.prompt);
|
|
7570
|
+
} catch {
|
|
7571
|
+
stopLoop();
|
|
7572
|
+
} finally {
|
|
7573
|
+
loopFiringRef.current = false;
|
|
7574
|
+
}
|
|
7575
|
+
}, delay);
|
|
7576
|
+
loopTimerRef.current = timer;
|
|
7577
|
+
return () => clearTimeout(timer);
|
|
7578
|
+
}, [activeLoop, stopLoop, log, busyRef, handleSubmitRef]);
|
|
7579
|
+
return {
|
|
7580
|
+
startLoop,
|
|
7581
|
+
stopLoop,
|
|
7582
|
+
getLoopStatus,
|
|
7583
|
+
isLoopActive,
|
|
7584
|
+
isLoopFiring,
|
|
7585
|
+
clearFiringFlag,
|
|
7586
|
+
activeLoop
|
|
7587
|
+
};
|
|
7589
7588
|
}
|
|
7590
|
-
|
|
7591
|
-
|
|
7589
|
+
|
|
7590
|
+
// src/cli/ui/hooks/useQuit.ts
|
|
7591
|
+
import { useCallback as useCallback6, useEffect as useEffect6 } from "react";
|
|
7592
|
+
function useQuit(transcriptRef) {
|
|
7593
|
+
const quitProcess = useCallback6(() => {
|
|
7594
|
+
transcriptRef.current?.end();
|
|
7595
|
+
process.exit(0);
|
|
7596
|
+
}, [transcriptRef]);
|
|
7597
|
+
useEffect6(() => {
|
|
7598
|
+
process.on("SIGINT", quitProcess);
|
|
7599
|
+
return () => {
|
|
7600
|
+
process.off("SIGINT", quitProcess);
|
|
7601
|
+
};
|
|
7602
|
+
}, [quitProcess]);
|
|
7603
|
+
return quitProcess;
|
|
7592
7604
|
}
|
|
7593
7605
|
|
|
7594
7606
|
// src/cli/ui/hooks/useScrollback.ts
|
|
7607
|
+
import { useMemo as useMemo7 } from "react";
|
|
7595
7608
|
var seq = 0;
|
|
7596
7609
|
function nextId2(prefix) {
|
|
7597
7610
|
seq += 1;
|
|
@@ -11921,6 +11934,16 @@ var TurnTranslator = class {
|
|
|
11921
11934
|
this.toolCardId = null;
|
|
11922
11935
|
}
|
|
11923
11936
|
}
|
|
11937
|
+
toolAbort(output) {
|
|
11938
|
+
if (this.toolCardId) {
|
|
11939
|
+
this.log.endTool(this.toolCardId, {
|
|
11940
|
+
output,
|
|
11941
|
+
elapsedMs: Date.now() - this.toolStartedAt,
|
|
11942
|
+
aborted: true
|
|
11943
|
+
});
|
|
11944
|
+
this.toolCardId = null;
|
|
11945
|
+
}
|
|
11946
|
+
}
|
|
11924
11947
|
toolRetry(attempt, max) {
|
|
11925
11948
|
if (this.toolCardId) this.log.retryTool(this.toolCardId, attempt, max);
|
|
11926
11949
|
}
|
|
@@ -12859,6 +12882,7 @@ function AppInner({
|
|
|
12859
12882
|
(s) => s.cards.some((c) => c.kind === "user" || c.kind === "streaming")
|
|
12860
12883
|
);
|
|
12861
12884
|
const isStreaming = useAgentState((s) => s.cards.some((c) => c.kind === "streaming" && !c.done));
|
|
12885
|
+
const activityLabel = useActivityLabel();
|
|
12862
12886
|
const chatScroll = useChatScroll();
|
|
12863
12887
|
const [input, setInput] = useState20("");
|
|
12864
12888
|
const [busy, setBusy] = useState20(false);
|
|
@@ -13906,7 +13930,7 @@ function AppInner({
|
|
|
13906
13930
|
}
|
|
13907
13931
|
if (text.startsWith("/") && !text.includes(" ")) {
|
|
13908
13932
|
const typed = text.slice(1).toLowerCase();
|
|
13909
|
-
const matches = suggestSlashCommands(typed, !!codeMode);
|
|
13933
|
+
const matches = suggestSlashCommands(typed, !!codeMode, slashUsage);
|
|
13910
13934
|
const exact = matches.find((m) => m.cmd === typed);
|
|
13911
13935
|
if (!exact && matches.length > 0) {
|
|
13912
13936
|
const chosen = matches[slashSelected] ?? matches[0];
|
|
@@ -14346,7 +14370,13 @@ function AppInner({
|
|
|
14346
14370
|
codeModeOn: !!codeMode
|
|
14347
14371
|
});
|
|
14348
14372
|
} else if (ev.role === "error") {
|
|
14349
|
-
handleErrorEvent(ev, {
|
|
14373
|
+
handleErrorEvent(ev, {
|
|
14374
|
+
log,
|
|
14375
|
+
setOngoingTool,
|
|
14376
|
+
setToolProgress,
|
|
14377
|
+
toolStartedAtRef,
|
|
14378
|
+
translator
|
|
14379
|
+
});
|
|
14350
14380
|
} else if (ev.role === "warning") {
|
|
14351
14381
|
handleWarningEvent(ev, { log, setTurnOnPro });
|
|
14352
14382
|
}
|
|
@@ -14400,6 +14430,7 @@ function AppInner({
|
|
|
14400
14430
|
planMode,
|
|
14401
14431
|
session,
|
|
14402
14432
|
slashSelected,
|
|
14433
|
+
slashUsage,
|
|
14403
14434
|
atState,
|
|
14404
14435
|
atSelected,
|
|
14405
14436
|
pickAtMention,
|
|
@@ -14859,7 +14890,7 @@ function AppInner({
|
|
|
14859
14890
|
dashboardUrl,
|
|
14860
14891
|
languageVersion
|
|
14861
14892
|
}
|
|
14862
|
-
) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !pendingReviseEditor && !pendingSessionsPicker && !pendingCheckpointPicker && !pendingMcpHub && !stagedInput && !pendingEditReview && ongoingTool ? /* @__PURE__ */ React60.createElement(OngoingToolRow, { tool: ongoingTool, progress: toolProgress }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !pendingReviseEditor && !pendingSessionsPicker && !pendingCheckpointPicker && !pendingMcpHub && !stagedInput && !pendingEditReview && subagentActivities.length > 0 ? /* @__PURE__ */ React60.createElement(SubagentLiveStack, { activities: subagentActivities, max: 3 }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !pendingReviseEditor && !pendingSessionsPicker && !pendingCheckpointPicker && !pendingMcpHub && !stagedInput && !pendingEditReview && !ongoingTool && statusLine ? /* @__PURE__ */ React60.createElement(ThinkingRow, { text: statusLine }) : null, !PLAIN_UI && undoBanner && !pendingShell && !pendingPlan && !pendingReviseEditor && !pendingSessionsPicker && !pendingCheckpointPicker && !pendingMcpHub && !stagedInput && !pendingEditReview && !pendingChoice && !stagedChoiceCustom && !pendingRevision && !stagedCheckpointRevise && !pendingCheckpoint ? /* @__PURE__ */ React60.createElement(UndoBanner, { banner: undoBanner }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !pendingReviseEditor && !pendingSessionsPicker && !pendingCheckpointPicker && !pendingMcpHub && !stagedInput && !pendingEditReview && busy && !isStreaming && !ongoingTool && !statusLine ? /* @__PURE__ */ React60.createElement(ThinkingRow, { text:
|
|
14893
|
+
) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !pendingReviseEditor && !pendingSessionsPicker && !pendingCheckpointPicker && !pendingMcpHub && !stagedInput && !pendingEditReview && ongoingTool ? /* @__PURE__ */ React60.createElement(OngoingToolRow, { tool: ongoingTool, progress: toolProgress }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !pendingReviseEditor && !pendingSessionsPicker && !pendingCheckpointPicker && !pendingMcpHub && !stagedInput && !pendingEditReview && subagentActivities.length > 0 ? /* @__PURE__ */ React60.createElement(SubagentLiveStack, { activities: subagentActivities, max: 3 }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !pendingReviseEditor && !pendingSessionsPicker && !pendingCheckpointPicker && !pendingMcpHub && !stagedInput && !pendingEditReview && !ongoingTool && statusLine ? /* @__PURE__ */ React60.createElement(ThinkingRow, { text: statusLine }) : null, !PLAIN_UI && undoBanner && !pendingShell && !pendingPlan && !pendingReviseEditor && !pendingSessionsPicker && !pendingCheckpointPicker && !pendingMcpHub && !stagedInput && !pendingEditReview && !pendingChoice && !stagedChoiceCustom && !pendingRevision && !stagedCheckpointRevise && !pendingCheckpoint ? /* @__PURE__ */ React60.createElement(UndoBanner, { banner: undoBanner }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !pendingReviseEditor && !pendingSessionsPicker && !pendingCheckpointPicker && !pendingMcpHub && !stagedInput && !pendingEditReview && busy && !isStreaming && !ongoingTool && !statusLine ? /* @__PURE__ */ React60.createElement(ThinkingRow, { text: activityLabel }) : null, !PLAIN_UI && !pendingShell && !pendingPlan && !pendingReviseEditor && !pendingSessionsPicker && !pendingCheckpointPicker && !pendingMcpHub && !stagedInput && !pendingEditReview ? /* @__PURE__ */ React60.createElement(PlanLiveRow, null) : null, /* @__PURE__ */ React60.createElement(ToastRail, null)), stagedInput ? /* @__PURE__ */ React60.createElement(
|
|
14863
14894
|
PlanRefineInput,
|
|
14864
14895
|
{
|
|
14865
14896
|
mode: stagedInput.mode,
|
|
@@ -15600,4 +15631,4 @@ async function chatCommand(opts) {
|
|
|
15600
15631
|
export {
|
|
15601
15632
|
chatCommand
|
|
15602
15633
|
};
|
|
15603
|
-
//# sourceMappingURL=chunk-
|
|
15634
|
+
//# sourceMappingURL=chunk-3OBWN2NH.js.map
|