open-agents-ai 0.103.83 → 0.103.86
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 +200 -59
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4713,6 +4713,24 @@ Process error: ${err.message}`;
|
|
|
4713
4713
|
entry.finishedAt = Date.now();
|
|
4714
4714
|
return true;
|
|
4715
4715
|
}
|
|
4716
|
+
/** Kill ALL running tasks immediately (for /stop and /quit authority) */
|
|
4717
|
+
stopAll() {
|
|
4718
|
+
let killed = 0;
|
|
4719
|
+
for (const [, entry] of this.tasks) {
|
|
4720
|
+
if (entry.status !== "running")
|
|
4721
|
+
continue;
|
|
4722
|
+
if (entry.child) {
|
|
4723
|
+
try {
|
|
4724
|
+
entry.child.kill("SIGKILL");
|
|
4725
|
+
} catch {
|
|
4726
|
+
}
|
|
4727
|
+
}
|
|
4728
|
+
entry.status = "stopped";
|
|
4729
|
+
entry.finishedAt = Date.now();
|
|
4730
|
+
killed++;
|
|
4731
|
+
}
|
|
4732
|
+
return killed;
|
|
4733
|
+
}
|
|
4716
4734
|
list() {
|
|
4717
4735
|
return Array.from(this.tasks.values()).map(toInfo);
|
|
4718
4736
|
}
|
|
@@ -12442,8 +12460,8 @@ async function handleCmd(cmd) {
|
|
|
12442
12460
|
// succeeds in <1s. Racing them eliminates the wait.
|
|
12443
12461
|
dlog('remote_infer: invoking ' + riCapName + ' on peer ' + riTargetPeer.slice(0, 20) + ' (libp2p' + (_natsConn ? ' + NATS parallel' : '') + ')');
|
|
12444
12462
|
try {
|
|
12445
|
-
var RI_TIMEOUT =
|
|
12446
|
-
var riInvokeP = nexus.invokeCapability(riTargetPeer, riCapName, riData, { stream: false, maxDurationMs:
|
|
12463
|
+
var RI_TIMEOUT = 60000; // 60s outer timeout \u2014 fail fast for interactive use
|
|
12464
|
+
var riInvokeP = nexus.invokeCapability(riTargetPeer, riCapName, riData, { stream: false, maxDurationMs: 45000 });
|
|
12447
12465
|
var riTimeoutP = new Promise(function(_, reject) { setTimeout(function() { reject(new Error('remote_infer timed out after ' + (RI_TIMEOUT / 1000) + 's')); }, RI_TIMEOUT); });
|
|
12448
12466
|
|
|
12449
12467
|
// Build race candidates \u2014 libp2p + timeout always present
|
|
@@ -12454,7 +12472,7 @@ async function handleCmd(cmd) {
|
|
|
12454
12472
|
var _riNatsRaceP = (async function() {
|
|
12455
12473
|
var _rSubject = 'nexus.invoke.' + riTargetPeer;
|
|
12456
12474
|
var _rPayload = JSON.stringify({ capability: riCapName, input: riData, from: nexus.peerId || '' });
|
|
12457
|
-
var _rResp = await _natsConn.request(_rSubject, _natsCodec.encode(_rPayload), { timeout:
|
|
12475
|
+
var _rResp = await _natsConn.request(_rSubject, _natsCodec.encode(_rPayload), { timeout: 45000 });
|
|
12458
12476
|
var _rResult = JSON.parse(_natsCodec.decode(_rResp.data));
|
|
12459
12477
|
if (_rResult && _rResult.error) throw new Error('NATS: ' + _rResult.error);
|
|
12460
12478
|
dlog('remote_infer: NATS won the race');
|
|
@@ -12493,8 +12511,8 @@ async function handleCmd(cmd) {
|
|
|
12493
12511
|
var rPid = riCandidates[ri];
|
|
12494
12512
|
dlog('remote_infer: trying peer ' + rPid.slice(0, 20) + '...');
|
|
12495
12513
|
try {
|
|
12496
|
-
var PEER_INVOKE_TIMEOUT =
|
|
12497
|
-
var specInvoke = nexus.invokeCapability(rPid, riCapName, riData, { stream: false, maxDurationMs:
|
|
12514
|
+
var PEER_INVOKE_TIMEOUT = 30000; // 30s per peer in discovery \u2014 fail fast, try next
|
|
12515
|
+
var specInvoke = nexus.invokeCapability(rPid, riCapName, riData, { stream: false, maxDurationMs: 25000 });
|
|
12498
12516
|
var specTimeout = new Promise(function(_, reject) {
|
|
12499
12517
|
setTimeout(function() { reject(new Error('peer invoke timeout')); }, PEER_INVOKE_TIMEOUT);
|
|
12500
12518
|
});
|
|
@@ -12523,7 +12541,7 @@ async function handleCmd(cmd) {
|
|
|
12523
12541
|
try {
|
|
12524
12542
|
var _dpSubject = 'nexus.invoke.' + _dpPid;
|
|
12525
12543
|
var _dpPayload = JSON.stringify({ capability: riCapName, input: riData, from: nexus.peerId || '' });
|
|
12526
|
-
var _dpResp = await _natsConn.request(_dpSubject, _natsCodec.encode(_dpPayload), { timeout:
|
|
12544
|
+
var _dpResp = await _natsConn.request(_dpSubject, _natsCodec.encode(_dpPayload), { timeout: 30000 });
|
|
12527
12545
|
var _dpResult = JSON.parse(_natsCodec.decode(_dpResp.data));
|
|
12528
12546
|
if (_dpResult && !_dpResult.error) {
|
|
12529
12547
|
riResult = _dpResult;
|
|
@@ -18848,6 +18866,13 @@ ${this.options.dynamicContext}`,
|
|
|
18848
18866
|
injectUserMessage(content) {
|
|
18849
18867
|
this.pendingUserMessages.push(content);
|
|
18850
18868
|
}
|
|
18869
|
+
/** Retract the last pending user message (Esc cancel).
|
|
18870
|
+
* Returns the retracted text, or null if queue is empty or already consumed. */
|
|
18871
|
+
retractLastPendingMessage() {
|
|
18872
|
+
if (this.pendingUserMessages.length === 0)
|
|
18873
|
+
return null;
|
|
18874
|
+
return this.pendingUserMessages.pop();
|
|
18875
|
+
}
|
|
18851
18876
|
/** Abort the current task run — cancels in-flight requests and kills child processes */
|
|
18852
18877
|
abort() {
|
|
18853
18878
|
this.aborted = true;
|
|
@@ -19126,6 +19151,10 @@ If you're stuck, try a completely different approach. Do NOT repeat what failed
|
|
|
19126
19151
|
try {
|
|
19127
19152
|
response = this.options.streamEnabled && this.hasStreamingSupport() ? await this.streamingRequest(chatRequest, turn) : await this.backend.chatCompletion(chatRequest);
|
|
19128
19153
|
} catch (reqErr) {
|
|
19154
|
+
if (reqErr instanceof Error && reqErr.fatal) {
|
|
19155
|
+
this.emit({ type: "error", content: `Backend error: ${reqErr.message}`, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
19156
|
+
break;
|
|
19157
|
+
}
|
|
19129
19158
|
const recovered = await this.retryOnTransient(reqErr, chatRequest, turn);
|
|
19130
19159
|
if (!recovered) {
|
|
19131
19160
|
const errMsg = reqErr instanceof Error ? reqErr.message : String(reqErr);
|
|
@@ -20886,6 +20915,8 @@ ${transcript}`
|
|
|
20886
20915
|
// -------------------------------------------------------------------------
|
|
20887
20916
|
/** Detect whether an error is transient (worth retrying) */
|
|
20888
20917
|
isTransientError(err) {
|
|
20918
|
+
if (err instanceof Error && err.fatal)
|
|
20919
|
+
return false;
|
|
20889
20920
|
const msg = err instanceof Error ? err.message : String(err);
|
|
20890
20921
|
if (/Backend HTTP (502|503|504)/i.test(msg))
|
|
20891
20922
|
return true;
|
|
@@ -20895,6 +20926,10 @@ ${transcript}`
|
|
|
20895
20926
|
return true;
|
|
20896
20927
|
if (/model is loading|server busy|overloaded/i.test(msg))
|
|
20897
20928
|
return true;
|
|
20929
|
+
if (/multiaddrs failed|all multiaddrs failed|dial to peer failed|stream was reset|Cannot reach peer/i.test(msg))
|
|
20930
|
+
return true;
|
|
20931
|
+
if (/NATS.*timeout|relay.*timeout|invoke.*timeout/i.test(msg))
|
|
20932
|
+
return true;
|
|
20898
20933
|
return false;
|
|
20899
20934
|
}
|
|
20900
20935
|
/**
|
|
@@ -21222,6 +21257,15 @@ var init_nexusBackend = __esm({
|
|
|
21222
21257
|
this.authKey = authKey || "";
|
|
21223
21258
|
this.thinking = thinking ?? true;
|
|
21224
21259
|
}
|
|
21260
|
+
/** Reset the consecutive failure counter (called on endpoint switch / reconnect) */
|
|
21261
|
+
resetFailures() {
|
|
21262
|
+
this.consecutiveFailures = 0;
|
|
21263
|
+
}
|
|
21264
|
+
/** Update target peer (allows switching peers without recreating the backend) */
|
|
21265
|
+
setTargetPeer(peerId) {
|
|
21266
|
+
this.targetPeer = peerId;
|
|
21267
|
+
this.consecutiveFailures = 0;
|
|
21268
|
+
}
|
|
21225
21269
|
async chatCompletion(request) {
|
|
21226
21270
|
if (this.consecutiveFailures >= _NexusAgenticBackend.MAX_CONSECUTIVE_FAILURES) {
|
|
21227
21271
|
const err = new Error(`Remote peer unreachable after ${this.consecutiveFailures} attempts. Use /endpoint to switch to a local model or reconnect.`);
|
|
@@ -21258,7 +21302,10 @@ var init_nexusBackend = __esm({
|
|
|
21258
21302
|
}
|
|
21259
21303
|
if (parsed.success === false) {
|
|
21260
21304
|
this.consecutiveFailures++;
|
|
21261
|
-
|
|
21305
|
+
const output = String(parsed.output || rawResult);
|
|
21306
|
+
const isDialErr = /multiaddrs failed|Cannot reach peer|dial to peer|timeout|ECONNREFUSED/i.test(output);
|
|
21307
|
+
const hint = isDialErr ? ` (${this.consecutiveFailures}/${_NexusAgenticBackend.MAX_CONSECUTIVE_FAILURES} failures \u2014 will stop after ${_NexusAgenticBackend.MAX_CONSECUTIVE_FAILURES})` : "";
|
|
21308
|
+
throw new Error(`Remote inference failed: ${output}${hint}`);
|
|
21262
21309
|
}
|
|
21263
21310
|
this.consecutiveFailures = 0;
|
|
21264
21311
|
const invokeResult = parsed.result;
|
|
@@ -33531,9 +33578,9 @@ function tuiSelect(opts) {
|
|
|
33531
33578
|
const first = findSelectable(0, 1);
|
|
33532
33579
|
cursor = first >= 0 ? first : 0;
|
|
33533
33580
|
}
|
|
33534
|
-
const
|
|
33535
|
-
const
|
|
33536
|
-
const maxVisible = opts.maxVisible ?? Math.max(3,
|
|
33581
|
+
const selectChrome = 3;
|
|
33582
|
+
const contentArea = opts.availableRows ?? (process.stdout.rows ?? 24);
|
|
33583
|
+
const maxVisible = opts.maxVisible ?? Math.max(3, contentArea - selectChrome);
|
|
33537
33584
|
let scrollOffset = 0;
|
|
33538
33585
|
let lastRenderedLines = 0;
|
|
33539
33586
|
return new Promise((resolve31) => {
|
|
@@ -35178,7 +35225,8 @@ async function showConfigEditor(ctx) {
|
|
|
35178
35225
|
rl: ctx.rl,
|
|
35179
35226
|
skipKeys,
|
|
35180
35227
|
renderRow: renderConfigRow,
|
|
35181
|
-
onAction
|
|
35228
|
+
onAction,
|
|
35229
|
+
availableRows: ctx.availableContentRows?.()
|
|
35182
35230
|
});
|
|
35183
35231
|
if (result.confirmed && result.key) {
|
|
35184
35232
|
const entry = entries.find((e) => e.key === result.key);
|
|
@@ -35251,7 +35299,8 @@ async function handleExposeConfig(ctx) {
|
|
|
35251
35299
|
items,
|
|
35252
35300
|
title: "Expose Configuration",
|
|
35253
35301
|
rl: ctx.rl,
|
|
35254
|
-
skipKeys
|
|
35302
|
+
skipKeys,
|
|
35303
|
+
availableRows: ctx.availableContentRows?.()
|
|
35255
35304
|
});
|
|
35256
35305
|
if (!result.confirmed || !result.key) {
|
|
35257
35306
|
renderInfo("Expose config cancelled.");
|
|
@@ -35360,7 +35409,8 @@ async function showModelPicker(ctx, local = false) {
|
|
|
35360
35409
|
title: "Select Model",
|
|
35361
35410
|
rl: ctx.rl,
|
|
35362
35411
|
// Skip header rows
|
|
35363
|
-
skipKeys: ["__header_recent__", "__header_available__"]
|
|
35412
|
+
skipKeys: ["__header_recent__", "__header_available__"],
|
|
35413
|
+
availableRows: ctx.availableContentRows?.()
|
|
35364
35414
|
});
|
|
35365
35415
|
if (!result.confirmed || !result.key) {
|
|
35366
35416
|
renderInfo("Model selection cancelled.");
|
|
@@ -35390,6 +35440,7 @@ async function handleEndpoint(arg, ctx, local = false) {
|
|
|
35390
35440
|
activeKey: ctx.config.backendUrl,
|
|
35391
35441
|
title: "Select Endpoint",
|
|
35392
35442
|
rl: ctx.rl,
|
|
35443
|
+
availableRows: ctx.availableContentRows?.(),
|
|
35393
35444
|
onDelete: (item, done) => {
|
|
35394
35445
|
deleteUsageRecord("endpoint", item.key, ctx.repoRoot);
|
|
35395
35446
|
done(true);
|
|
@@ -45592,8 +45643,11 @@ var init_status_bar = __esm({
|
|
|
45592
45643
|
active = false;
|
|
45593
45644
|
scrollRegionTop = 1;
|
|
45594
45645
|
stdinHooked = false;
|
|
45595
|
-
/** Track previous terminal
|
|
45646
|
+
/** Track previous terminal dimensions to clear ghost separators on resize */
|
|
45596
45647
|
_prevTermRows = 0;
|
|
45648
|
+
_prevTermCols = 0;
|
|
45649
|
+
/** Debounce timer for resize events — prevents separator stacking during drag */
|
|
45650
|
+
_resizeTimer = null;
|
|
45597
45651
|
/**
|
|
45598
45652
|
* Depth-counted content write guard. Incremented by beginContentWrite(),
|
|
45599
45653
|
* decremented by endContentWrite(). Footer is only redrawn and cursor
|
|
@@ -46040,6 +46094,7 @@ var init_status_bar = __esm({
|
|
|
46040
46094
|
this.scrollRegionTop = scrollRegionTop ?? 1;
|
|
46041
46095
|
this.active = true;
|
|
46042
46096
|
this._prevTermRows = process.stdout.rows ?? 24;
|
|
46097
|
+
this._prevTermCols = process.stdout.columns ?? 80;
|
|
46043
46098
|
this.applyScrollRegion();
|
|
46044
46099
|
this.renderFooterAndPositionInput();
|
|
46045
46100
|
this.hookStdin();
|
|
@@ -46077,24 +46132,56 @@ var init_status_bar = __esm({
|
|
|
46077
46132
|
get reservedRows() {
|
|
46078
46133
|
return this._currentFooterHeight;
|
|
46079
46134
|
}
|
|
46080
|
-
/**
|
|
46135
|
+
/**
|
|
46136
|
+
* Usable content area height — the rows available for scroll content,
|
|
46137
|
+
* model lists, dashboards, etc. Accounts for:
|
|
46138
|
+
* - Header/carousel rows (scrollRegionTop)
|
|
46139
|
+
* - Footer rows (buffer + top separator + input lines + bottom separator + metrics)
|
|
46140
|
+
*
|
|
46141
|
+
* This is the accurate "how many rows can I draw in?" value that all
|
|
46142
|
+
* overlay UIs (tuiSelect, /expose dashboard, etc.) should use.
|
|
46143
|
+
*/
|
|
46144
|
+
get availableContentRows() {
|
|
46145
|
+
const rows = process.stdout.rows ?? 24;
|
|
46146
|
+
const usable = rows - (this.scrollRegionTop - 1) - this._currentFooterHeight;
|
|
46147
|
+
return Math.max(3, usable);
|
|
46148
|
+
}
|
|
46149
|
+
/** Handle terminal resize — debounced to prevent separator stacking during drag */
|
|
46081
46150
|
handleResize() {
|
|
46082
46151
|
if (!this.active)
|
|
46083
46152
|
return;
|
|
46153
|
+
if (this._resizeTimer)
|
|
46154
|
+
clearTimeout(this._resizeTimer);
|
|
46155
|
+
this._resizeTimer = setTimeout(() => {
|
|
46156
|
+
this._resizeTimer = null;
|
|
46157
|
+
this._handleResizeImmediate();
|
|
46158
|
+
}, 50);
|
|
46159
|
+
}
|
|
46160
|
+
/** Actual resize handler — called after debounce settles */
|
|
46161
|
+
_handleResizeImmediate() {
|
|
46162
|
+
if (!this.active)
|
|
46163
|
+
return;
|
|
46164
|
+
const prevRows = this._prevTermRows;
|
|
46165
|
+
const prevCols = this._prevTermCols;
|
|
46084
46166
|
this.updateFooterHeight();
|
|
46085
46167
|
const rows = process.stdout.rows ?? 24;
|
|
46086
|
-
const
|
|
46168
|
+
const cols = process.stdout.columns ?? 80;
|
|
46087
46169
|
this._prevTermRows = rows;
|
|
46170
|
+
this._prevTermCols = cols;
|
|
46088
46171
|
const pos = this.rowPositions(rows);
|
|
46089
46172
|
const w = getTermWidth();
|
|
46090
46173
|
const sep = c2.dim("\u2500".repeat(w));
|
|
46091
|
-
let
|
|
46092
|
-
if (prevRows > 0 && rows
|
|
46093
|
-
|
|
46174
|
+
let clearBuf = "";
|
|
46175
|
+
if (prevRows > 0 && (rows !== prevRows || cols !== prevCols)) {
|
|
46176
|
+
const wrapFactor = cols > 0 ? Math.ceil(prevCols / cols) : 1;
|
|
46177
|
+
const extraWrappedRows = Math.max(0, (wrapFactor - 1) * 3);
|
|
46178
|
+
const safetyMargin = extraWrappedRows + 2;
|
|
46179
|
+
const clearFrom = Math.max(1, pos.bufferRow - safetyMargin);
|
|
46180
|
+
clearBuf = "\x1B[1;" + rows + `r\x1B[${clearFrom};1H\x1B[J`;
|
|
46094
46181
|
}
|
|
46095
46182
|
if (this.writeDepth > 0) {
|
|
46096
46183
|
const inputWrap = this.wrapInput(w);
|
|
46097
|
-
let buf =
|
|
46184
|
+
let buf = clearBuf + `\x1B[${this.scrollRegionTop};${pos.scrollEnd}r\x1B[?25l\x1B[?7l\x1B[${pos.bufferRow};1H\x1B[2K${this.buildBufferContent(w)}\x1B[${pos.topSepRow};1H\x1B[2K${sep}`;
|
|
46098
46185
|
for (let i = 0; i < inputWrap.lines.length; i++) {
|
|
46099
46186
|
const row = pos.inputStartRow + i;
|
|
46100
46187
|
const prefix = i === 0 ? this.promptText : " ".repeat(this.promptWidth);
|
|
@@ -46103,8 +46190,8 @@ var init_status_bar = __esm({
|
|
|
46103
46190
|
buf += `\x1B[${pos.bottomSepRow};1H\x1B[2K${sep}\x1B[${pos.metricsRow};1H\x1B[2K${this.buildMetricsLine()}\x1B[?7h\x1B[${pos.scrollEnd};1H`;
|
|
46104
46191
|
process.stdout.write(buf);
|
|
46105
46192
|
} else {
|
|
46106
|
-
if (
|
|
46107
|
-
process.stdout.write(
|
|
46193
|
+
if (clearBuf)
|
|
46194
|
+
process.stdout.write(clearBuf);
|
|
46108
46195
|
this.applyScrollRegion();
|
|
46109
46196
|
this.renderFooterAndPositionInput();
|
|
46110
46197
|
}
|
|
@@ -47956,8 +48043,9 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
47956
48043
|
let currentTaskType;
|
|
47957
48044
|
let sessionFilesTouched = [];
|
|
47958
48045
|
let sessionToolCallCount = 0;
|
|
48046
|
+
let lastSteeringInput = "";
|
|
48047
|
+
let lastSteeringRetracted = false;
|
|
47959
48048
|
let restoredSessionContext = null;
|
|
47960
|
-
let pendingSessionRestore = false;
|
|
47961
48049
|
let sessionSudoPassword = null;
|
|
47962
48050
|
let sudoPromptPending = false;
|
|
47963
48051
|
const idlePrompt = `${c2.bold(c2.white("\u276F "))}`;
|
|
@@ -48268,6 +48356,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
48268
48356
|
items,
|
|
48269
48357
|
title: "Select one or more (Space to toggle, Enter to confirm)",
|
|
48270
48358
|
rl,
|
|
48359
|
+
availableRows: statusBar.isActive ? statusBar.availableContentRows : void 0,
|
|
48271
48360
|
renderRow: (item, focused, _isActive) => {
|
|
48272
48361
|
const isSelected = selected.has(item.key);
|
|
48273
48362
|
const marker = isSelected ? c2.green("\u2611") : focused ? c2.cyan("\u2610") : c2.dim("\u2610");
|
|
@@ -48299,7 +48388,8 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
48299
48388
|
const result = await tuiSelect({
|
|
48300
48389
|
items,
|
|
48301
48390
|
title: "Select one option",
|
|
48302
|
-
rl
|
|
48391
|
+
rl,
|
|
48392
|
+
availableRows: statusBar.isActive ? statusBar.availableContentRows : void 0
|
|
48303
48393
|
});
|
|
48304
48394
|
if (statusBar?.isActive)
|
|
48305
48395
|
statusBar.endContentWrite();
|
|
@@ -49217,7 +49307,8 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
49217
49307
|
if (!activeTask)
|
|
49218
49308
|
return false;
|
|
49219
49309
|
activeTask.runner.abort();
|
|
49220
|
-
|
|
49310
|
+
const bgKilled = taskManager.stopAll();
|
|
49311
|
+
writeContent(() => renderInfo(`Task aborted.${bgKilled > 0 ? ` ${bgKilled} background task(s) killed.` : ""}`));
|
|
49221
49312
|
return true;
|
|
49222
49313
|
},
|
|
49223
49314
|
pauseTask() {
|
|
@@ -49256,6 +49347,9 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
49256
49347
|
}, 100);
|
|
49257
49348
|
return true;
|
|
49258
49349
|
},
|
|
49350
|
+
availableContentRows() {
|
|
49351
|
+
return statusBar.isActive ? statusBar.availableContentRows : Math.max(3, (process.stdout.rows ?? 24) - 6);
|
|
49352
|
+
},
|
|
49259
49353
|
destroyProject() {
|
|
49260
49354
|
const oaPath = join50(repoRoot, OA_DIR);
|
|
49261
49355
|
if (existsSync40(oaPath)) {
|
|
@@ -49309,28 +49403,41 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
49309
49403
|
const lastTime = lastEntry.savedAt ? new Date(lastEntry.savedAt) : null;
|
|
49310
49404
|
const timeAgo = lastTime ? formatTimeAgo(lastTime) : "unknown";
|
|
49311
49405
|
const lastTask = lastEntry.task?.slice(0, 80) || "unknown";
|
|
49312
|
-
setTimeout(() => {
|
|
49406
|
+
setTimeout(async () => {
|
|
49313
49407
|
writeContent(() => {
|
|
49314
49408
|
renderInfo(`Previous session found (${savedCtx.entries.length} entries, last active ${timeAgo})`);
|
|
49315
49409
|
renderInfo(`Last task: ${lastTask}${lastEntry.task && lastEntry.task.length > 80 ? "..." : ""}`);
|
|
49316
|
-
renderInfo(`Restore previous context? (y/n) [auto-restores in 15s]`);
|
|
49317
49410
|
});
|
|
49318
|
-
|
|
49319
|
-
|
|
49320
|
-
setTimeout(() => {
|
|
49321
|
-
if (pendingSessionRestore) {
|
|
49322
|
-
pendingSessionRestore = false;
|
|
49323
|
-
const prompt = buildContextRestorePrompt(repoRoot);
|
|
49324
|
-
if (prompt) {
|
|
49325
|
-
restoredSessionContext = prompt;
|
|
49326
|
-
const info = loadSessionContext(repoRoot);
|
|
49327
|
-
writeContent(() => renderInfo(`Context auto-restored from ${info?.entries.length ?? 0} session(s).`));
|
|
49328
|
-
} else {
|
|
49329
|
-
writeContent(() => renderInfo("No context to restore. Starting fresh."));
|
|
49330
|
-
}
|
|
49331
|
-
showPrompt();
|
|
49332
|
-
}
|
|
49411
|
+
let autoRestoreTimer = setTimeout(() => {
|
|
49412
|
+
autoRestoreTimer = null;
|
|
49333
49413
|
}, 15e3);
|
|
49414
|
+
const result = await tuiSelect({
|
|
49415
|
+
items: [
|
|
49416
|
+
{ key: "restore", label: "Restore previous context" },
|
|
49417
|
+
{ key: "fresh", label: "Start fresh" }
|
|
49418
|
+
],
|
|
49419
|
+
activeKey: "restore",
|
|
49420
|
+
title: "Restore previous session context?",
|
|
49421
|
+
rl,
|
|
49422
|
+
availableRows: statusBar.isActive ? statusBar.availableContentRows : void 0
|
|
49423
|
+
});
|
|
49424
|
+
if (autoRestoreTimer)
|
|
49425
|
+
clearTimeout(autoRestoreTimer);
|
|
49426
|
+
if (result.confirmed && result.key === "restore" || !result.confirmed && !autoRestoreTimer) {
|
|
49427
|
+
const prompt = buildContextRestorePrompt(repoRoot);
|
|
49428
|
+
if (prompt) {
|
|
49429
|
+
restoredSessionContext = prompt;
|
|
49430
|
+
const info = loadSessionContext(repoRoot);
|
|
49431
|
+
writeContent(() => renderInfo(`Context restored from ${info?.entries.length ?? 0} session(s).`));
|
|
49432
|
+
} else {
|
|
49433
|
+
writeContent(() => renderInfo("No context to restore. Starting fresh."));
|
|
49434
|
+
}
|
|
49435
|
+
} else if (result.confirmed && result.key === "fresh") {
|
|
49436
|
+
writeContent(() => renderInfo("Starting fresh."));
|
|
49437
|
+
} else {
|
|
49438
|
+
writeContent(() => renderInfo("Starting fresh."));
|
|
49439
|
+
}
|
|
49440
|
+
showPrompt();
|
|
49334
49441
|
}, 150);
|
|
49335
49442
|
}
|
|
49336
49443
|
}
|
|
@@ -49453,22 +49560,6 @@ ${result.content.slice(0, 2e3)}${result.content.length > 2e3 ? "\n[truncated]" :
|
|
|
49453
49560
|
rl.on("line", (line) => {
|
|
49454
49561
|
persistHistoryLine(line);
|
|
49455
49562
|
const input = line.trim();
|
|
49456
|
-
if (pendingSessionRestore) {
|
|
49457
|
-
pendingSessionRestore = false;
|
|
49458
|
-
const answer = input.toLowerCase();
|
|
49459
|
-
if (answer === "y" || answer === "yes") {
|
|
49460
|
-
const prompt = buildContextRestorePrompt(repoRoot);
|
|
49461
|
-
if (prompt) {
|
|
49462
|
-
restoredSessionContext = prompt;
|
|
49463
|
-
const info = loadSessionContext(repoRoot);
|
|
49464
|
-
writeContent(() => renderInfo(`Context restored from ${info?.entries.length ?? 0} session(s). Will be injected into your next task.`));
|
|
49465
|
-
}
|
|
49466
|
-
} else {
|
|
49467
|
-
writeContent(() => renderInfo("Starting fresh."));
|
|
49468
|
-
}
|
|
49469
|
-
showPrompt();
|
|
49470
|
-
return;
|
|
49471
|
-
}
|
|
49472
49563
|
if (!input) {
|
|
49473
49564
|
if (pasteBuffer.length > 0) {
|
|
49474
49565
|
flushPasteBuffer();
|
|
@@ -49523,6 +49614,7 @@ ${result.content.slice(0, 2e3)}${result.content.length > 2e3 ? "\n[truncated]" :
|
|
|
49523
49614
|
if (activeTask) {
|
|
49524
49615
|
activeTask.runner.abort();
|
|
49525
49616
|
}
|
|
49617
|
+
taskManager.stopAll();
|
|
49526
49618
|
if (blessEngine?.isActive)
|
|
49527
49619
|
blessEngine.stop();
|
|
49528
49620
|
if (telegramBridge?.isActive)
|
|
@@ -49592,6 +49684,10 @@ Execute this skill now. Follow the behavioral guidance above.`;
|
|
|
49592
49684
|
const isImage = isImagePath(cleanPath) && existsSync40(resolve28(repoRoot, cleanPath));
|
|
49593
49685
|
const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync40(resolve28(repoRoot, cleanPath));
|
|
49594
49686
|
if (activeTask) {
|
|
49687
|
+
if (activeTask.runner.isPaused) {
|
|
49688
|
+
activeTask.runner.resume();
|
|
49689
|
+
statusBar.setProcessing(true);
|
|
49690
|
+
}
|
|
49595
49691
|
if (isImage) {
|
|
49596
49692
|
try {
|
|
49597
49693
|
const imgPath = resolve28(repoRoot, cleanPath);
|
|
@@ -49619,8 +49715,16 @@ ${result.text}`;
|
|
|
49619
49715
|
writeContent(() => renderUserInterrupt(`[Media: ${cleanPath}]`));
|
|
49620
49716
|
}
|
|
49621
49717
|
} else {
|
|
49718
|
+
const isReplacement = lastSteeringRetracted;
|
|
49719
|
+
lastSteeringInput = input;
|
|
49720
|
+
lastSteeringRetracted = false;
|
|
49622
49721
|
const lineCount = input.split("\n").length;
|
|
49623
|
-
if (
|
|
49722
|
+
if (isReplacement) {
|
|
49723
|
+
const displayText2 = lineCount > 1 ? `[pasted ${lineCount} lines]` : input;
|
|
49724
|
+
writeContent(() => process.stdout.write(`
|
|
49725
|
+
${c2.green("\u21BB")} ${c2.bold("Context replaced:")} ${displayText2}
|
|
49726
|
+
`));
|
|
49727
|
+
} else if (lineCount > 1) {
|
|
49624
49728
|
writeContent(() => renderUserInterrupt(`[pasted ${lineCount} lines]`));
|
|
49625
49729
|
} else {
|
|
49626
49730
|
writeContent(() => renderUserInterrupt(input));
|
|
@@ -49991,6 +50095,7 @@ ${c2.dim("(paste cancelled)")}
|
|
|
49991
50095
|
}
|
|
49992
50096
|
if (activeTask) {
|
|
49993
50097
|
activeTask.runner.abort();
|
|
50098
|
+
taskManager.stopAll();
|
|
49994
50099
|
writeContent(() => renderTaskAborted());
|
|
49995
50100
|
} else {
|
|
49996
50101
|
writeContent(() => process.stdout.write(`
|
|
@@ -49999,6 +50104,42 @@ ${c2.dim("(Use /quit to exit)")}
|
|
|
49999
50104
|
}
|
|
50000
50105
|
showPrompt();
|
|
50001
50106
|
});
|
|
50107
|
+
if (process.stdin.isTTY) {
|
|
50108
|
+
readline2.emitKeypressEvents(process.stdin, rl);
|
|
50109
|
+
process.stdin.on("keypress", (_str, key) => {
|
|
50110
|
+
if (!key)
|
|
50111
|
+
return;
|
|
50112
|
+
if (key.name === "escape" && activeTask) {
|
|
50113
|
+
if (!activeTask.runner.isPaused) {
|
|
50114
|
+
activeTask.runner.pause();
|
|
50115
|
+
statusBar.setProcessing(false);
|
|
50116
|
+
}
|
|
50117
|
+
const retracted = activeTask.runner.retractLastPendingMessage();
|
|
50118
|
+
if (retracted) {
|
|
50119
|
+
lastSteeringInput = retracted;
|
|
50120
|
+
lastSteeringRetracted = true;
|
|
50121
|
+
writeContent(() => process.stdout.write(` ${c2.yellow("\u23F8")} ${c2.dim("\x1B[9m" + retracted.slice(0, 120) + "\x1B[29m")} ${c2.dim("\u2190 retracted, edit below and press Enter")}
|
|
50122
|
+
`));
|
|
50123
|
+
rl.line = retracted;
|
|
50124
|
+
rl.cursor = retracted.length;
|
|
50125
|
+
if (statusBar.isActive)
|
|
50126
|
+
statusBar.renderFooterPreserveCursor?.();
|
|
50127
|
+
} else if (lastSteeringInput) {
|
|
50128
|
+
lastSteeringRetracted = true;
|
|
50129
|
+
writeContent(() => process.stdout.write(` ${c2.yellow("\u23F8")} ${c2.dim("\x1B[9m" + lastSteeringInput.slice(0, 120) + "\x1B[29m")} ${c2.dim("\u2190 already sent, re-type below to override")}
|
|
50130
|
+
`));
|
|
50131
|
+
rl.line = lastSteeringInput;
|
|
50132
|
+
rl.cursor = lastSteeringInput.length;
|
|
50133
|
+
if (statusBar.isActive)
|
|
50134
|
+
statusBar.renderFooterPreserveCursor?.();
|
|
50135
|
+
} else {
|
|
50136
|
+
writeContent(() => process.stdout.write(` ${c2.yellow("\u23F8")} ${c2.dim("Paused. /resume to continue, /stop to kill.")}
|
|
50137
|
+
`));
|
|
50138
|
+
}
|
|
50139
|
+
showPrompt();
|
|
50140
|
+
}
|
|
50141
|
+
});
|
|
50142
|
+
}
|
|
50002
50143
|
}
|
|
50003
50144
|
async function runWithTUI(task, config, repoPath) {
|
|
50004
50145
|
const repoRoot = resolve28(repoPath ?? cwd());
|
package/package.json
CHANGED