laohuang 0.8.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +1050 -403
- package/dist/bin.js.map +4 -4
- package/package.json +3 -1
package/dist/bin.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/main.ts
|
|
4
|
-
import { existsSync as
|
|
5
|
-
import { dirname as dirname4, join as
|
|
4
|
+
import { existsSync as existsSync8, readFileSync as readFileSync6 } from "node:fs";
|
|
5
|
+
import { dirname as dirname4, join as join7 } from "node:path";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
|
|
8
8
|
// ../../packages/core/agent-runtime/dist/agent.js
|
|
@@ -62,8 +62,8 @@ var CancelToken = class {
|
|
|
62
62
|
continue;
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
|
-
for (const
|
|
66
|
-
|
|
65
|
+
for (const resolve3 of this.#waiters) {
|
|
66
|
+
resolve3();
|
|
67
67
|
}
|
|
68
68
|
this.#waiters.clear();
|
|
69
69
|
return true;
|
|
@@ -76,20 +76,20 @@ var CancelToken = class {
|
|
|
76
76
|
if (this.#cancelled) {
|
|
77
77
|
return Promise.resolve(true);
|
|
78
78
|
}
|
|
79
|
-
return new Promise((
|
|
79
|
+
return new Promise((resolve3) => {
|
|
80
80
|
let timer;
|
|
81
81
|
const onCancel = () => {
|
|
82
82
|
if (timer !== void 0) {
|
|
83
83
|
clearTimeout(timer);
|
|
84
84
|
}
|
|
85
85
|
this.#waiters.delete(onCancel);
|
|
86
|
-
|
|
86
|
+
resolve3(true);
|
|
87
87
|
};
|
|
88
88
|
this.#waiters.add(onCancel);
|
|
89
89
|
if (timeoutMs !== void 0) {
|
|
90
90
|
timer = setTimeout(() => {
|
|
91
91
|
this.#waiters.delete(onCancel);
|
|
92
|
-
|
|
92
|
+
resolve3(false);
|
|
93
93
|
}, timeoutMs);
|
|
94
94
|
}
|
|
95
95
|
});
|
|
@@ -149,6 +149,7 @@ var EventKind = {
|
|
|
149
149
|
AgentRepeatWarning: "agent.repeat_warning",
|
|
150
150
|
ToolStarted: "tool.started",
|
|
151
151
|
ToolOutputDelta: "tool.output_delta",
|
|
152
|
+
ToolOutputSnapshot: "tool.output_snapshot",
|
|
152
153
|
ToolFinished: "tool.finished",
|
|
153
154
|
SessionReady: "session.ready",
|
|
154
155
|
SessionStopped: "session.stopped",
|
|
@@ -222,7 +223,7 @@ var EventSpec = class {
|
|
|
222
223
|
this.payload_types = options.payload_types ?? {};
|
|
223
224
|
this.require_task_id = options.require_task_id ?? false;
|
|
224
225
|
this.require_correlation_id = options.require_correlation_id ?? false;
|
|
225
|
-
this.max_payload_chars = options.max_payload_chars
|
|
226
|
+
this.max_payload_chars = options.max_payload_chars === void 0 ? DEFAULT_MAX_PAYLOAD_CHARS : options.max_payload_chars;
|
|
226
227
|
this.validator = options.validator ?? null;
|
|
227
228
|
}
|
|
228
229
|
validate(event) {
|
|
@@ -254,7 +255,7 @@ var EventSpec = class {
|
|
|
254
255
|
} catch (error) {
|
|
255
256
|
throw new EventValidationError(`event ${event.kind} payload must be JSON-compatible`, { cause: error });
|
|
256
257
|
}
|
|
257
|
-
if (payloadSize > this.max_payload_chars) {
|
|
258
|
+
if (this.max_payload_chars !== null && payloadSize > this.max_payload_chars) {
|
|
258
259
|
throw new EventValidationError(`event ${event.kind} payload exceeds ${this.max_payload_chars} characters`);
|
|
259
260
|
}
|
|
260
261
|
if (this.validator !== null && this.validator(event) === false) {
|
|
@@ -414,7 +415,16 @@ var EVENT_SPECS = new Map([
|
|
|
414
415
|
payload_types: { stream: "string", text: "string" },
|
|
415
416
|
require_task_id: true,
|
|
416
417
|
require_correlation_id: true,
|
|
417
|
-
max_payload_chars:
|
|
418
|
+
max_payload_chars: null
|
|
419
|
+
}),
|
|
420
|
+
spec(EventKind.ToolOutputSnapshot, {
|
|
421
|
+
sources: [EventSource.Tool],
|
|
422
|
+
required_payload: ["stream", "text"],
|
|
423
|
+
payload_types: { stream: "string", text: "string", stream_sequence: "integer" },
|
|
424
|
+
require_task_id: true,
|
|
425
|
+
require_correlation_id: true,
|
|
426
|
+
// Producers own output budgets; JSON escaping must not reject valid previews.
|
|
427
|
+
max_payload_chars: null
|
|
418
428
|
}),
|
|
419
429
|
spec(EventKind.ToolFinished, {
|
|
420
430
|
sources: [EventSource.Tool],
|
|
@@ -422,7 +432,7 @@ var EVENT_SPECS = new Map([
|
|
|
422
432
|
payload_types: { status: "string" },
|
|
423
433
|
require_task_id: true,
|
|
424
434
|
require_correlation_id: true,
|
|
425
|
-
max_payload_chars:
|
|
435
|
+
max_payload_chars: null
|
|
426
436
|
}),
|
|
427
437
|
spec(EventKind.RoutingDecided, {
|
|
428
438
|
sources: [EventSource.Router],
|
|
@@ -528,6 +538,12 @@ function projectValue(value) {
|
|
|
528
538
|
}
|
|
529
539
|
return value;
|
|
530
540
|
}
|
|
541
|
+
function omitPartialOutputLine(value) {
|
|
542
|
+
if (value === "")
|
|
543
|
+
return value;
|
|
544
|
+
const newline = value.indexOf("\n");
|
|
545
|
+
return `[partial line omitted]${newline >= 0 ? value.slice(newline) : ""}`;
|
|
546
|
+
}
|
|
531
547
|
var EventProjector = class _EventProjector {
|
|
532
548
|
static AUDIENCES = /* @__PURE__ */ new Set([
|
|
533
549
|
"terminal",
|
|
@@ -538,6 +554,16 @@ var EventProjector = class _EventProjector {
|
|
|
538
554
|
if (!_EventProjector.AUDIENCES.has(audience)) {
|
|
539
555
|
throw new Error(`unknown event audience: ${audience}`);
|
|
540
556
|
}
|
|
557
|
+
const payload = { ...event.payload };
|
|
558
|
+
if (event.kind === EventKind.ToolOutputSnapshot && payload["start_mid_line"] === true && typeof payload["text"] === "string") {
|
|
559
|
+
payload["text"] = omitPartialOutputLine(payload["text"]);
|
|
560
|
+
} else if (event.kind === EventKind.ToolFinished) {
|
|
561
|
+
for (const stream of ["stdout", "stderr"]) {
|
|
562
|
+
if (payload[`${stream}_start_mid_line`] === true && typeof payload[stream] === "string") {
|
|
563
|
+
payload[stream] = omitPartialOutputLine(payload[stream]);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
541
567
|
return {
|
|
542
568
|
event_id: event.event_id,
|
|
543
569
|
kind: event.kind,
|
|
@@ -546,7 +572,7 @@ var EventProjector = class _EventProjector {
|
|
|
546
572
|
task_id: event.task_id,
|
|
547
573
|
correlation_id: event.correlation_id,
|
|
548
574
|
sequence: event.sequence,
|
|
549
|
-
payload: projectValue(
|
|
575
|
+
payload: projectValue(payload)
|
|
550
576
|
};
|
|
551
577
|
}
|
|
552
578
|
};
|
|
@@ -554,7 +580,8 @@ var COALESCIBLE_EVENTS = /* @__PURE__ */ new Set([
|
|
|
554
580
|
EventKind.ModelTextDelta,
|
|
555
581
|
EventKind.ModelReasoningDelta,
|
|
556
582
|
EventKind.ModelToolCallDelta,
|
|
557
|
-
EventKind.ToolOutputDelta
|
|
583
|
+
EventKind.ToolOutputDelta,
|
|
584
|
+
EventKind.ToolOutputSnapshot
|
|
558
585
|
]);
|
|
559
586
|
var MAX_COALESCED_TEXT_CHARS = 65536;
|
|
560
587
|
var MAILBOX_CRITICAL_HEADROOM = 64;
|
|
@@ -582,7 +609,7 @@ var SubscriberMailbox = class _SubscriberMailbox {
|
|
|
582
609
|
this.workerDone = this.run();
|
|
583
610
|
}
|
|
584
611
|
static merge(left, right) {
|
|
585
|
-
if (left.kind !== right.kind || left.task_id !== right.task_id || left.correlation_id !== right.correlation_id || !COALESCIBLE_EVENTS.has(left.kind)) {
|
|
612
|
+
if (left.kind !== right.kind || left.task_id !== right.task_id || left.correlation_id !== right.correlation_id || left.kind === EventKind.ToolOutputSnapshot || !COALESCIBLE_EVENTS.has(left.kind)) {
|
|
586
613
|
return null;
|
|
587
614
|
}
|
|
588
615
|
const leftText = left.payload["text"];
|
|
@@ -606,15 +633,23 @@ var SubscriberMailbox = class _SubscriberMailbox {
|
|
|
606
633
|
if (this.closed) {
|
|
607
634
|
return false;
|
|
608
635
|
}
|
|
636
|
+
if (event.kind === EventKind.ToolOutputSnapshot) {
|
|
637
|
+
const previous = this.items.findIndex((item) => item.kind === event.kind && item.task_id === event.task_id && item.correlation_id === event.correlation_id && item.payload.stream === event.payload.stream);
|
|
638
|
+
if (previous >= 0) {
|
|
639
|
+
const old = this.items.splice(previous, 1)[0];
|
|
640
|
+
this.unfinished--;
|
|
641
|
+
this.pendingGap += gapOf(old.payload);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
609
644
|
if (this.items.length > 0) {
|
|
610
645
|
const last = this.items[this.items.length - 1];
|
|
611
646
|
const merged = _SubscriberMailbox.merge(last, event);
|
|
612
|
-
if (merged !== null && this.items.length >= this.maxItems - MAILBOX_CRITICAL_HEADROOM) {
|
|
647
|
+
if (merged !== null && event.kind !== EventKind.ToolOutputSnapshot && this.items.length >= this.maxItems - MAILBOX_CRITICAL_HEADROOM) {
|
|
613
648
|
this.items[this.items.length - 1] = this.withGapMarker(merged);
|
|
614
649
|
return true;
|
|
615
650
|
}
|
|
616
651
|
}
|
|
617
|
-
if (COALESCIBLE_EVENTS.has(event.kind) && this.items.length >= this.maxItems - MAILBOX_CRITICAL_HEADROOM) {
|
|
652
|
+
if (COALESCIBLE_EVENTS.has(event.kind) && event.kind !== EventKind.ToolOutputSnapshot && this.items.length >= this.maxItems - MAILBOX_CRITICAL_HEADROOM) {
|
|
618
653
|
this.recordDrop();
|
|
619
654
|
return false;
|
|
620
655
|
}
|
|
@@ -650,8 +685,8 @@ var SubscriberMailbox = class _SubscriberMailbox {
|
|
|
650
685
|
const deadline = timeoutMs === void 0 ? void 0 : Date.now() + timeoutMs;
|
|
651
686
|
while (this.unfinished > 0) {
|
|
652
687
|
if (deadline === void 0) {
|
|
653
|
-
await new Promise((
|
|
654
|
-
this.flushWaiters.push(
|
|
688
|
+
await new Promise((resolve3) => {
|
|
689
|
+
this.flushWaiters.push(resolve3);
|
|
655
690
|
});
|
|
656
691
|
continue;
|
|
657
692
|
}
|
|
@@ -659,12 +694,12 @@ var SubscriberMailbox = class _SubscriberMailbox {
|
|
|
659
694
|
if (remaining <= 0) {
|
|
660
695
|
return false;
|
|
661
696
|
}
|
|
662
|
-
const waiter = new Promise((
|
|
663
|
-
this.flushWaiters.push(
|
|
697
|
+
const waiter = new Promise((resolve3) => {
|
|
698
|
+
this.flushWaiters.push(resolve3);
|
|
664
699
|
});
|
|
665
700
|
let timer;
|
|
666
|
-
const timeout = new Promise((
|
|
667
|
-
timer = setTimeout(
|
|
701
|
+
const timeout = new Promise((resolve3) => {
|
|
702
|
+
timer = setTimeout(resolve3, remaining);
|
|
668
703
|
});
|
|
669
704
|
await Promise.race([waiter, timeout]);
|
|
670
705
|
clearTimeout(timer);
|
|
@@ -693,22 +728,22 @@ var SubscriberMailbox = class _SubscriberMailbox {
|
|
|
693
728
|
wake() {
|
|
694
729
|
const waiters = this.wakeWaiters;
|
|
695
730
|
this.wakeWaiters = [];
|
|
696
|
-
for (const
|
|
697
|
-
|
|
731
|
+
for (const resolve3 of waiters) {
|
|
732
|
+
resolve3();
|
|
698
733
|
}
|
|
699
734
|
}
|
|
700
735
|
notifyFlushWaiters() {
|
|
701
736
|
const waiters = this.flushWaiters;
|
|
702
737
|
this.flushWaiters = [];
|
|
703
|
-
for (const
|
|
704
|
-
|
|
738
|
+
for (const resolve3 of waiters) {
|
|
739
|
+
resolve3();
|
|
705
740
|
}
|
|
706
741
|
}
|
|
707
742
|
async run() {
|
|
708
743
|
for (; ; ) {
|
|
709
744
|
while (this.items.length === 0 && !this.closed) {
|
|
710
|
-
await new Promise((
|
|
711
|
-
this.wakeWaiters.push(
|
|
745
|
+
await new Promise((resolve3) => {
|
|
746
|
+
this.wakeWaiters.push(resolve3);
|
|
712
747
|
});
|
|
713
748
|
}
|
|
714
749
|
if (this.items.length === 0 && this.closed) {
|
|
@@ -780,6 +815,11 @@ var EventBus = class {
|
|
|
780
815
|
}
|
|
781
816
|
this.sequence += 1;
|
|
782
817
|
const published = { ...event, sequence: this.sequence };
|
|
818
|
+
if (event.kind === EventKind.ToolOutputSnapshot) {
|
|
819
|
+
const previous = this.buffer.findIndex((item) => item.kind === event.kind && item.task_id === event.task_id && item.correlation_id === event.correlation_id && item.payload.stream === event.payload.stream);
|
|
820
|
+
if (previous >= 0)
|
|
821
|
+
this.buffer.splice(previous, 1);
|
|
822
|
+
}
|
|
783
823
|
if (this.buffer.length >= this.maxBufferedEvents) {
|
|
784
824
|
this.buffer.shift();
|
|
785
825
|
}
|
|
@@ -851,8 +891,8 @@ var EventBus = class {
|
|
|
851
891
|
if (this.closed) {
|
|
852
892
|
return Promise.reject(new EventBusClosedError());
|
|
853
893
|
}
|
|
854
|
-
return new Promise((
|
|
855
|
-
const waiter = { resolve:
|
|
894
|
+
return new Promise((resolve3, reject) => {
|
|
895
|
+
const waiter = { resolve: resolve3, reject };
|
|
856
896
|
if (timeoutMs !== void 0) {
|
|
857
897
|
waiter.timer = setTimeout(() => {
|
|
858
898
|
const index = this.bufferWaiters.indexOf(waiter);
|
|
@@ -1190,7 +1230,7 @@ async function defaultSleep(delayMs, cancelToken) {
|
|
|
1190
1230
|
throw new ModelStreamCancelled(cancelToken?.reason || "cancelled");
|
|
1191
1231
|
}
|
|
1192
1232
|
if (cancelToken === null) {
|
|
1193
|
-
await new Promise((
|
|
1233
|
+
await new Promise((resolve3) => setTimeout(resolve3, delayMs));
|
|
1194
1234
|
}
|
|
1195
1235
|
}
|
|
1196
1236
|
function errorMessage(error) {
|
|
@@ -1229,20 +1269,20 @@ ${body}`;
|
|
|
1229
1269
|
].join("\n");
|
|
1230
1270
|
}
|
|
1231
1271
|
function runtimeFactLines(options) {
|
|
1232
|
-
const
|
|
1272
|
+
const lines2 = [];
|
|
1233
1273
|
if (hasText(options.cliName)) {
|
|
1234
|
-
|
|
1274
|
+
lines2.push(`- CLI: ${options.cliName}`);
|
|
1235
1275
|
}
|
|
1236
1276
|
if (hasText(options.cliVersion)) {
|
|
1237
|
-
|
|
1277
|
+
lines2.push(`- CLI version: ${options.cliVersion}`);
|
|
1238
1278
|
}
|
|
1239
1279
|
if (hasText(options.provider) && hasText(options.model)) {
|
|
1240
|
-
|
|
1280
|
+
lines2.push(`- Provider/model: ${options.provider}/${options.model}`);
|
|
1241
1281
|
}
|
|
1242
1282
|
if (hasText(options.promptCwd)) {
|
|
1243
|
-
|
|
1283
|
+
lines2.push(`- Current working directory: ${options.promptCwd}`);
|
|
1244
1284
|
}
|
|
1245
|
-
return
|
|
1285
|
+
return lines2;
|
|
1246
1286
|
}
|
|
1247
1287
|
function hasText(value) {
|
|
1248
1288
|
return value !== null && value !== void 0 && value.length > 0;
|
|
@@ -1701,14 +1741,6 @@ function optionalPositiveInteger(args, key) {
|
|
|
1701
1741
|
}
|
|
1702
1742
|
return value;
|
|
1703
1743
|
}
|
|
1704
|
-
function truncateText(text, maxOutputChars) {
|
|
1705
|
-
if (text.length <= maxOutputChars) {
|
|
1706
|
-
return text;
|
|
1707
|
-
}
|
|
1708
|
-
const omitted = text.length - maxOutputChars;
|
|
1709
|
-
return `${text.slice(0, maxOutputChars)}
|
|
1710
|
-
...[truncated ${omitted} chars]`;
|
|
1711
|
-
}
|
|
1712
1744
|
function errorMessage3(error) {
|
|
1713
1745
|
return error instanceof Error ? error.message : String(error);
|
|
1714
1746
|
}
|
|
@@ -2480,12 +2512,11 @@ function makeToolContext(context, toolCallId, cancelToken) {
|
|
|
2480
2512
|
cancellationReason: cancelToken?.reason || "cancelled",
|
|
2481
2513
|
publish: (kind, payload) => {
|
|
2482
2514
|
if (typeof context?.publish === "function") {
|
|
2483
|
-
context.publish(kind, {
|
|
2515
|
+
return context.publish(kind, {
|
|
2484
2516
|
source: EventSource.Tool,
|
|
2485
2517
|
correlation_id: toolCallId,
|
|
2486
2518
|
payload
|
|
2487
2519
|
});
|
|
2488
|
-
return;
|
|
2489
2520
|
}
|
|
2490
2521
|
const bus = context?.eventBus ?? null;
|
|
2491
2522
|
if (bus !== null) {
|
|
@@ -2534,14 +2565,14 @@ var ConversationHistory = class _ConversationHistory {
|
|
|
2534
2565
|
}
|
|
2535
2566
|
static fromReplay(replay, journal) {
|
|
2536
2567
|
const history = new _ConversationHistory(replay.items.filter((item) => item.kind === "entry"), journal);
|
|
2537
|
-
for (const
|
|
2568
|
+
for (const open2 of replay.openToolCalls) {
|
|
2538
2569
|
const entry = history.appendToolResults({
|
|
2539
2570
|
requestId: "recovered",
|
|
2540
2571
|
recovered: true,
|
|
2541
2572
|
messages: [{
|
|
2542
2573
|
role: "tool-result",
|
|
2543
|
-
toolCallId:
|
|
2544
|
-
toolName:
|
|
2574
|
+
toolCallId: open2.toolCallId,
|
|
2575
|
+
toolName: open2.toolName,
|
|
2545
2576
|
content: JSON.stringify({
|
|
2546
2577
|
ok: false,
|
|
2547
2578
|
status: "interrupted",
|
|
@@ -2554,7 +2585,7 @@ var ConversationHistory = class _ConversationHistory {
|
|
|
2554
2585
|
recordType: "error",
|
|
2555
2586
|
payload: {
|
|
2556
2587
|
type: "interrupted_tool_call",
|
|
2557
|
-
toolCallId:
|
|
2588
|
+
toolCallId: open2.toolCallId,
|
|
2558
2589
|
repairedEntryId: entry?.id ?? null
|
|
2559
2590
|
}
|
|
2560
2591
|
});
|
|
@@ -2901,26 +2932,26 @@ function selectCompactionPlan(input) {
|
|
|
2901
2932
|
};
|
|
2902
2933
|
}
|
|
2903
2934
|
function serializeConversation(entries) {
|
|
2904
|
-
const
|
|
2935
|
+
const lines2 = ["<conversation>"];
|
|
2905
2936
|
for (const entry of entries) {
|
|
2906
|
-
|
|
2937
|
+
lines2.push(`<entry id="${entry.id}" seq="${entry.seq}" type="${entry.entryType}">`);
|
|
2907
2938
|
if (entry.entryType === "assistant_message") {
|
|
2908
2939
|
for (const block of entry.payload.message.content) {
|
|
2909
2940
|
if (block.type === "tool-call") {
|
|
2910
|
-
|
|
2941
|
+
lines2.push(`[assistant tool-call ${block.call.id} ${block.call.name}] ${JSON.stringify(block.call.arguments)}`);
|
|
2911
2942
|
} else {
|
|
2912
|
-
|
|
2943
|
+
lines2.push(`[assistant ${block.type}] ${block.text}`);
|
|
2913
2944
|
}
|
|
2914
2945
|
}
|
|
2915
2946
|
} else if (entry.entryType === "tool_result") {
|
|
2916
|
-
|
|
2947
|
+
lines2.push(`[tool-result ${entry.payload.message.toolCallId} ${entry.payload.message.toolName}] ${entry.payload.message.content}`);
|
|
2917
2948
|
} else if (entry.entryType === "user_message" || entry.entryType === "reminder" || entry.entryType === "project_instructions") {
|
|
2918
|
-
|
|
2949
|
+
lines2.push(`[${entry.payload.message.role}] ${entry.payload.message.content}`);
|
|
2919
2950
|
}
|
|
2920
|
-
|
|
2951
|
+
lines2.push("</entry>");
|
|
2921
2952
|
}
|
|
2922
|
-
|
|
2923
|
-
return
|
|
2953
|
+
lines2.push("</conversation>");
|
|
2954
|
+
return lines2.join("\n");
|
|
2924
2955
|
}
|
|
2925
2956
|
function semanticUnits(entries) {
|
|
2926
2957
|
const units = [];
|
|
@@ -3673,8 +3704,8 @@ var SessionManager = class {
|
|
|
3673
3704
|
const visit = (directory) => {
|
|
3674
3705
|
for (const entry of readdirSync(directory)) {
|
|
3675
3706
|
const absolute = join2(directory, entry);
|
|
3676
|
-
const
|
|
3677
|
-
if (
|
|
3707
|
+
const stat2 = statSync2(absolute);
|
|
3708
|
+
if (stat2.isDirectory()) {
|
|
3678
3709
|
visit(absolute);
|
|
3679
3710
|
} else if (absolute.endsWith(".jsonl")) {
|
|
3680
3711
|
paths.push(absolute);
|
|
@@ -4679,31 +4710,106 @@ function errorMessage6(error) {
|
|
|
4679
4710
|
|
|
4680
4711
|
// ../../packages/storage/local-config/dist/config.js
|
|
4681
4712
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
4682
|
-
import { chmodSync, existsSync as
|
|
4683
|
-
import { homedir } from "node:os";
|
|
4713
|
+
import { chmodSync, existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync3, renameSync, writeFileSync } from "node:fs";
|
|
4684
4714
|
import { basename as basename2, dirname, join as join3 } from "node:path";
|
|
4715
|
+
|
|
4716
|
+
// ../../packages/fs/local-paths/dist/index.js
|
|
4717
|
+
import { execFileSync } from "node:child_process";
|
|
4718
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
4719
|
+
import { homedir } from "node:os";
|
|
4720
|
+
import { posix, win32 } from "node:path";
|
|
4721
|
+
function envValue(env, name) {
|
|
4722
|
+
const key = Object.keys(env).find((key2) => key2.toLowerCase() === name.toLowerCase());
|
|
4723
|
+
return key === void 0 ? void 0 : env[key];
|
|
4724
|
+
}
|
|
4725
|
+
function convertVirtualPath(input, options) {
|
|
4726
|
+
if (options.convertShellPath)
|
|
4727
|
+
return options.convertShellPath(input);
|
|
4728
|
+
const candidates = [];
|
|
4729
|
+
const env = options.env ?? process.env;
|
|
4730
|
+
if (options.shellPath) {
|
|
4731
|
+
const directory = win32.dirname(options.shellPath());
|
|
4732
|
+
candidates.push(win32.join(directory, "cygpath.exe"), win32.resolve(directory, "../usr/bin/cygpath.exe"));
|
|
4733
|
+
} else {
|
|
4734
|
+
for (const name of ["ProgramFiles", "ProgramFiles(x86)"]) {
|
|
4735
|
+
const root = envValue(env, name);
|
|
4736
|
+
if (root && win32.isAbsolute(root))
|
|
4737
|
+
candidates.push(win32.join(root, "Git", "usr", "bin", "cygpath.exe"));
|
|
4738
|
+
}
|
|
4739
|
+
for (const entry of (envValue(env, "PATH") ?? "").split(";")) {
|
|
4740
|
+
const directory = entry.replace(/^"(.*)"$/, "$1");
|
|
4741
|
+
if (win32.isAbsolute(directory)) {
|
|
4742
|
+
candidates.push(win32.join(directory, "cygpath.exe"), win32.resolve(directory, "../usr/bin/cygpath.exe"));
|
|
4743
|
+
}
|
|
4744
|
+
}
|
|
4745
|
+
}
|
|
4746
|
+
const executable = candidates.find((candidate) => existsSync4(candidate));
|
|
4747
|
+
if (!executable)
|
|
4748
|
+
throw new Error(`Cannot map Git Bash path '${input}': cygpath.exe was not found. Use a Windows absolute path.`);
|
|
4749
|
+
return execFileSync(executable, ["-w", "--", input], {
|
|
4750
|
+
encoding: "utf8",
|
|
4751
|
+
windowsHide: true,
|
|
4752
|
+
timeout: 5e3
|
|
4753
|
+
}).replace(/\r?\n$/, "");
|
|
4754
|
+
}
|
|
4755
|
+
function getHomeDirectory(options = {}) {
|
|
4756
|
+
const windows = (options.platform ?? process.platform) === "win32";
|
|
4757
|
+
const env = options.env ?? process.env;
|
|
4758
|
+
const home = windows ? envValue(env, "USERPROFILE") || envValue(env, "HOME") || homedir() : env.HOME || homedir();
|
|
4759
|
+
return normalizeLocalPath(home, options, false);
|
|
4760
|
+
}
|
|
4761
|
+
function normalizeLocalPath(input, options = {}, expandHome = true) {
|
|
4762
|
+
if (input.includes("\0"))
|
|
4763
|
+
throw new Error("Paths cannot contain a NUL character");
|
|
4764
|
+
const windows = (options.platform ?? process.platform) === "win32";
|
|
4765
|
+
const paths = windows ? win32 : posix;
|
|
4766
|
+
if (expandHome && (input === "~" || input.startsWith("~/") || windows && input.startsWith("~\\"))) {
|
|
4767
|
+
return paths.join(getHomeDirectory(options), input.slice(2));
|
|
4768
|
+
}
|
|
4769
|
+
if (!windows)
|
|
4770
|
+
return input;
|
|
4771
|
+
if (input.startsWith("/") && !input.startsWith("//") && !input.includes("\\")) {
|
|
4772
|
+
const drive = /^\/(?:mnt\/|cygdrive\/)?([a-z])(?:\/(.*))?$/i.exec(input);
|
|
4773
|
+
if (drive)
|
|
4774
|
+
return `${drive[1].toUpperCase()}:\\${(drive[2] ?? "").replaceAll("/", "\\")}`;
|
|
4775
|
+
const converted = convertVirtualPath(input, options);
|
|
4776
|
+
if (!/^(?:[a-z]:[\\/]|\\\\)/i.test(converted)) {
|
|
4777
|
+
throw new Error(`Git Bash path did not resolve to a Windows absolute path: ${input}`);
|
|
4778
|
+
}
|
|
4779
|
+
return converted;
|
|
4780
|
+
}
|
|
4781
|
+
return input;
|
|
4782
|
+
}
|
|
4783
|
+
function resolveLocalPath(input, base = process.cwd(), options = {}) {
|
|
4784
|
+
const paths = (options.platform ?? process.platform) === "win32" ? win32 : posix;
|
|
4785
|
+
return paths.resolve(normalizeLocalPath(base, options), normalizeLocalPath(input, options));
|
|
4786
|
+
}
|
|
4787
|
+
function displayLocalPath(input, home, platform = process.platform) {
|
|
4788
|
+
if (!input || !home)
|
|
4789
|
+
return input;
|
|
4790
|
+
const paths = platform === "win32" ? win32 : posix;
|
|
4791
|
+
if (!paths.isAbsolute(input) || !paths.isAbsolute(home))
|
|
4792
|
+
return input;
|
|
4793
|
+
const relative = paths.relative(home, input);
|
|
4794
|
+
if (relative === "")
|
|
4795
|
+
return "~";
|
|
4796
|
+
return relative !== ".." && !relative.startsWith(`..${paths.sep}`) && !paths.isAbsolute(relative) ? `~/${relative.split(paths.sep).join("/")}` : input;
|
|
4797
|
+
}
|
|
4798
|
+
|
|
4799
|
+
// ../../packages/storage/local-config/dist/config.js
|
|
4685
4800
|
function isPlainObject(value) {
|
|
4686
4801
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4687
4802
|
}
|
|
4688
4803
|
function errorMessage7(error) {
|
|
4689
4804
|
return error instanceof Error ? error.message : String(error);
|
|
4690
4805
|
}
|
|
4691
|
-
function expandUser(input) {
|
|
4692
|
-
if (input === "~") {
|
|
4693
|
-
return homedir();
|
|
4694
|
-
}
|
|
4695
|
-
if (input.startsWith("~/")) {
|
|
4696
|
-
return join3(homedir(), input.slice(2));
|
|
4697
|
-
}
|
|
4698
|
-
return input;
|
|
4699
|
-
}
|
|
4700
4806
|
function defaultConfigPath(environ = process.env) {
|
|
4701
4807
|
const explicit = environ["LAOHUANG_CONFIG"];
|
|
4702
4808
|
if (explicit) {
|
|
4703
|
-
return
|
|
4809
|
+
return normalizeLocalPath(explicit, { env: environ });
|
|
4704
4810
|
}
|
|
4705
4811
|
const configHome = environ["XDG_CONFIG_HOME"];
|
|
4706
|
-
const root = configHome ?
|
|
4812
|
+
const root = configHome ? normalizeLocalPath(configHome, { env: environ }) : join3(getHomeDirectory({ env: environ }), ".config");
|
|
4707
4813
|
return join3(root, "laohuang", "config.json");
|
|
4708
4814
|
}
|
|
4709
4815
|
var ConfigManager = class {
|
|
@@ -4734,6 +4840,9 @@ var ConfigManager = class {
|
|
|
4734
4840
|
resolve(options = {}) {
|
|
4735
4841
|
return this.resolveSettings(options);
|
|
4736
4842
|
}
|
|
4843
|
+
getShellPath() {
|
|
4844
|
+
return this.readDocument({ optional: true })["shell_path"];
|
|
4845
|
+
}
|
|
4737
4846
|
resolveSettings(options = {}) {
|
|
4738
4847
|
const document = this.readDocument();
|
|
4739
4848
|
const environment = options.environ ?? process.env;
|
|
@@ -4778,7 +4887,7 @@ var ConfigManager = class {
|
|
|
4778
4887
|
});
|
|
4779
4888
|
}
|
|
4780
4889
|
readDocument(options = {}) {
|
|
4781
|
-
if (!
|
|
4890
|
+
if (!existsSync5(this.path)) {
|
|
4782
4891
|
if (options.optional) {
|
|
4783
4892
|
return {};
|
|
4784
4893
|
}
|
|
@@ -4807,6 +4916,10 @@ var ConfigManager = class {
|
|
|
4807
4916
|
}
|
|
4808
4917
|
};
|
|
4809
4918
|
function validateDocument(document) {
|
|
4919
|
+
const shellPath = document["shell_path"];
|
|
4920
|
+
if (shellPath !== void 0 && (typeof shellPath !== "string" || !shellPath.trim())) {
|
|
4921
|
+
throw new Error("Configuration shell_path must be a non-empty string");
|
|
4922
|
+
}
|
|
4810
4923
|
const version = document["version"] ?? 1;
|
|
4811
4924
|
if (version !== 1) {
|
|
4812
4925
|
throw new Error(`Unsupported configuration version: ${String(version)}`);
|
|
@@ -4843,7 +4956,7 @@ function validateDocument(document) {
|
|
|
4843
4956
|
|
|
4844
4957
|
// ../../packages/storage/local-config/dist/credentials.js
|
|
4845
4958
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
4846
|
-
import { chmodSync as chmodSync2, existsSync as
|
|
4959
|
+
import { chmodSync as chmodSync2, existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
4847
4960
|
import { basename as basename3, dirname as dirname2, join as join4 } from "node:path";
|
|
4848
4961
|
function isPlainObject2(value) {
|
|
4849
4962
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -4968,7 +5081,7 @@ var CredentialStore = class {
|
|
|
4968
5081
|
await operation;
|
|
4969
5082
|
}
|
|
4970
5083
|
readDocument() {
|
|
4971
|
-
if (!
|
|
5084
|
+
if (!existsSync6(this.path)) {
|
|
4972
5085
|
return { version: 2, providers: {} };
|
|
4973
5086
|
}
|
|
4974
5087
|
let document;
|
|
@@ -4999,7 +5112,7 @@ var CredentialStore = class {
|
|
|
4999
5112
|
}
|
|
5000
5113
|
writeDocument(document) {
|
|
5001
5114
|
const parent = dirname2(this.path);
|
|
5002
|
-
const parentExisted =
|
|
5115
|
+
const parentExisted = existsSync6(parent);
|
|
5003
5116
|
mkdirSync3(parent, { recursive: true, mode: 448 });
|
|
5004
5117
|
if (!parentExisted) {
|
|
5005
5118
|
chmodSync2(parent, 448);
|
|
@@ -5024,7 +5137,7 @@ function normalizeStoredCredential(credential) {
|
|
|
5024
5137
|
|
|
5025
5138
|
// ../../packages/storage/local-config/dist/model-catalog-store.js
|
|
5026
5139
|
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
5027
|
-
import { chmodSync as chmodSync3, existsSync as
|
|
5140
|
+
import { chmodSync as chmodSync3, existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync5, renameSync as renameSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
5028
5141
|
import { basename as basename4, dirname as dirname3, join as join5 } from "node:path";
|
|
5029
5142
|
function isPlainObject3(value) {
|
|
5030
5143
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -5056,7 +5169,7 @@ var ModelCatalogStore = class {
|
|
|
5056
5169
|
}
|
|
5057
5170
|
}
|
|
5058
5171
|
readDocument() {
|
|
5059
|
-
if (!
|
|
5172
|
+
if (!existsSync7(this.path)) {
|
|
5060
5173
|
return { version: 1, providers: {} };
|
|
5061
5174
|
}
|
|
5062
5175
|
let document;
|
|
@@ -5083,7 +5196,7 @@ var ModelCatalogStore = class {
|
|
|
5083
5196
|
}
|
|
5084
5197
|
writeDocument(document) {
|
|
5085
5198
|
const parent = dirname3(this.path);
|
|
5086
|
-
const parentExisted =
|
|
5199
|
+
const parentExisted = existsSync7(parent);
|
|
5087
5200
|
mkdirSync4(parent, { recursive: true, mode: 448 });
|
|
5088
5201
|
if (!parentExisted) {
|
|
5089
5202
|
chmodSync3(parent, 448);
|
|
@@ -6609,20 +6722,20 @@ var AgentSession = class {
|
|
|
6609
6722
|
if (timeoutMs !== void 0 && timeoutMs <= 0) {
|
|
6610
6723
|
return Promise.resolve(false);
|
|
6611
6724
|
}
|
|
6612
|
-
return new Promise((
|
|
6725
|
+
return new Promise((resolve3) => {
|
|
6613
6726
|
let timer;
|
|
6614
6727
|
const onIdle = () => {
|
|
6615
6728
|
if (timer !== void 0) {
|
|
6616
6729
|
clearTimeout(timer);
|
|
6617
6730
|
}
|
|
6618
6731
|
this.#idleWaiters.delete(onIdle);
|
|
6619
|
-
|
|
6732
|
+
resolve3(true);
|
|
6620
6733
|
};
|
|
6621
6734
|
this.#idleWaiters.add(onIdle);
|
|
6622
6735
|
if (timeoutMs !== void 0) {
|
|
6623
6736
|
timer = setTimeout(() => {
|
|
6624
6737
|
this.#idleWaiters.delete(onIdle);
|
|
6625
|
-
|
|
6738
|
+
resolve3(false);
|
|
6626
6739
|
}, timeoutMs);
|
|
6627
6740
|
timer.unref();
|
|
6628
6741
|
}
|
|
@@ -6936,8 +7049,8 @@ var AgentSession = class {
|
|
|
6936
7049
|
if (value) {
|
|
6937
7050
|
const waiters = [...this.#idleWaiters];
|
|
6938
7051
|
this.#idleWaiters.clear();
|
|
6939
|
-
for (const
|
|
6940
|
-
|
|
7052
|
+
for (const resolve3 of waiters) {
|
|
7053
|
+
resolve3();
|
|
6941
7054
|
}
|
|
6942
7055
|
}
|
|
6943
7056
|
}
|
|
@@ -7070,8 +7183,89 @@ function unavailableActionNotice(action) {
|
|
|
7070
7183
|
return "Cancellation is unavailable for this runtime.";
|
|
7071
7184
|
}
|
|
7072
7185
|
|
|
7186
|
+
// ../../packages/terminal/tui/dist/tui/native-console.js
|
|
7187
|
+
import { createRequire } from "node:module";
|
|
7188
|
+
var require2 = createRequire(import.meta.url);
|
|
7189
|
+
var native;
|
|
7190
|
+
var activeConsoles = [];
|
|
7191
|
+
function getWindowsConsole() {
|
|
7192
|
+
if (process.platform !== "win32")
|
|
7193
|
+
return null;
|
|
7194
|
+
if (native !== void 0)
|
|
7195
|
+
return native;
|
|
7196
|
+
const koffi = require2("koffi");
|
|
7197
|
+
const kernel = koffi.load("kernel32.dll");
|
|
7198
|
+
const user = koffi.load("user32.dll");
|
|
7199
|
+
const getHandle = kernel.func("__stdcall", "GetStdHandle", "void *", ["uint32_t"]);
|
|
7200
|
+
const getMode = kernel.func("__stdcall", "GetConsoleMode", "int", ["void *", "void *"]);
|
|
7201
|
+
const setMode = kernel.func("__stdcall", "SetConsoleMode", "int", ["void *", "uint32_t"]);
|
|
7202
|
+
const getKey = user.func("__stdcall", "GetAsyncKeyState", "int16_t", ["int"]);
|
|
7203
|
+
const getError = kernel.func("__stdcall", "GetLastError", "uint32_t", []);
|
|
7204
|
+
const handle = getHandle(4294967286);
|
|
7205
|
+
const buffer = Buffer.alloc(4);
|
|
7206
|
+
if (!getMode(handle, buffer))
|
|
7207
|
+
return native = null;
|
|
7208
|
+
native = {
|
|
7209
|
+
getMode: () => {
|
|
7210
|
+
if (!getMode(handle, buffer))
|
|
7211
|
+
throw new Error(`GetConsoleMode failed (${getError()})`);
|
|
7212
|
+
return buffer.readUInt32LE();
|
|
7213
|
+
},
|
|
7214
|
+
setMode: (mode) => {
|
|
7215
|
+
if (!setMode(handle, mode))
|
|
7216
|
+
throw new Error(`SetConsoleMode failed (${getError()})`);
|
|
7217
|
+
},
|
|
7218
|
+
shiftPressed: () => (getKey(16) & 32768) !== 0
|
|
7219
|
+
};
|
|
7220
|
+
return native;
|
|
7221
|
+
}
|
|
7222
|
+
function isLocalWindowsConsole() {
|
|
7223
|
+
return process.platform === "win32" && activeConsoles.length > 0 && !process.env.SSH_CONNECTION && !process.env.SSH_CLIENT && !process.env.SSH_TTY;
|
|
7224
|
+
}
|
|
7225
|
+
function isNativeShiftPressed() {
|
|
7226
|
+
return isLocalWindowsConsole() && (activeConsoles.at(-1)?.shiftPressed() ?? false);
|
|
7227
|
+
}
|
|
7228
|
+
function enterTerminalRawMode(input, console2 = input === process.stdin ? getWindowsConsole() : null) {
|
|
7229
|
+
if (!input.setRawMode)
|
|
7230
|
+
return () => {
|
|
7231
|
+
};
|
|
7232
|
+
const wasRaw = input.isRaw ?? false;
|
|
7233
|
+
const originalMode = console2?.getMode();
|
|
7234
|
+
let active = true;
|
|
7235
|
+
let registered = false;
|
|
7236
|
+
const restore = () => {
|
|
7237
|
+
if (!active)
|
|
7238
|
+
return;
|
|
7239
|
+
active = false;
|
|
7240
|
+
if (registered && console2)
|
|
7241
|
+
activeConsoles.splice(activeConsoles.lastIndexOf(console2), 1);
|
|
7242
|
+
try {
|
|
7243
|
+
input.setRawMode?.(wasRaw);
|
|
7244
|
+
} finally {
|
|
7245
|
+
if (originalMode !== void 0)
|
|
7246
|
+
console2?.setMode(originalMode);
|
|
7247
|
+
}
|
|
7248
|
+
};
|
|
7249
|
+
try {
|
|
7250
|
+
input.setRawMode(true);
|
|
7251
|
+
if (console2) {
|
|
7252
|
+
console2.setMode(console2.getMode() | 512);
|
|
7253
|
+
activeConsoles.push(console2);
|
|
7254
|
+
registered = true;
|
|
7255
|
+
}
|
|
7256
|
+
return restore;
|
|
7257
|
+
} catch (error) {
|
|
7258
|
+
try {
|
|
7259
|
+
restore();
|
|
7260
|
+
} catch (restoreError) {
|
|
7261
|
+
throw new AggregateError([error, restoreError], "Terminal setup and mode restoration failed");
|
|
7262
|
+
}
|
|
7263
|
+
throw error;
|
|
7264
|
+
}
|
|
7265
|
+
}
|
|
7266
|
+
|
|
7073
7267
|
// ../../packages/terminal/tui/dist/tui/screen.js
|
|
7074
|
-
var
|
|
7268
|
+
var MainScreenRenderer = class _MainScreenRenderer {
|
|
7075
7269
|
#terminal;
|
|
7076
7270
|
#previousLines = [];
|
|
7077
7271
|
#previousWidth = 0;
|
|
@@ -7084,7 +7278,7 @@ var PiMainScreenRenderer = class _PiMainScreenRenderer {
|
|
|
7084
7278
|
#closed = false;
|
|
7085
7279
|
constructor(terminal, env = process.env) {
|
|
7086
7280
|
this.#terminal = terminal;
|
|
7087
|
-
this.#clearOnShrink = env.
|
|
7281
|
+
this.#clearOnShrink = env.LAOHUANG_CLEAR_ON_SHRINK === "1";
|
|
7088
7282
|
}
|
|
7089
7283
|
render(frame) {
|
|
7090
7284
|
if (this.#closed) {
|
|
@@ -7094,7 +7288,7 @@ var PiMainScreenRenderer = class _PiMainScreenRenderer {
|
|
|
7094
7288
|
const width = Math.max(1, size.columns);
|
|
7095
7289
|
const height = Math.max(1, size.rows);
|
|
7096
7290
|
const newLines = frame.lines;
|
|
7097
|
-
|
|
7291
|
+
_MainScreenRenderer.#validateLines(newLines, width);
|
|
7098
7292
|
const widthChanged = this.#previousWidth !== 0 && this.#previousWidth !== width;
|
|
7099
7293
|
const heightChanged = this.#previousHeight !== 0 && this.#previousHeight !== height;
|
|
7100
7294
|
const previousBufferLength = this.#previousHeight > 0 ? this.#previousViewportTop + this.#previousHeight : height;
|
|
@@ -7144,7 +7338,7 @@ var PiMainScreenRenderer = class _PiMainScreenRenderer {
|
|
|
7144
7338
|
fullRender(true);
|
|
7145
7339
|
return;
|
|
7146
7340
|
}
|
|
7147
|
-
const span2 =
|
|
7341
|
+
const span2 = _MainScreenRenderer.#changedSpan(this.#previousLines, newLines);
|
|
7148
7342
|
if (span2 === null) {
|
|
7149
7343
|
const buffer2 = this.#positionHardwareCursor(frame, width, newLines.length);
|
|
7150
7344
|
this.#previousViewportTop = prevViewportTop;
|
|
@@ -7310,13 +7504,13 @@ var PiMainScreenRenderer = class _PiMainScreenRenderer {
|
|
|
7310
7504
|
this.#hardwareCursorRow = targetRow;
|
|
7311
7505
|
return buffer;
|
|
7312
7506
|
}
|
|
7313
|
-
#commitState(
|
|
7314
|
-
this.#previousLines = [...
|
|
7507
|
+
#commitState(lines2, width, height) {
|
|
7508
|
+
this.#previousLines = [...lines2];
|
|
7315
7509
|
this.#previousWidth = width;
|
|
7316
7510
|
this.#previousHeight = height;
|
|
7317
7511
|
}
|
|
7318
|
-
static #validateLines(
|
|
7319
|
-
|
|
7512
|
+
static #validateLines(lines2, width) {
|
|
7513
|
+
lines2.forEach((line2, index) => {
|
|
7320
7514
|
if (/[\r\n]/u.test(line2)) {
|
|
7321
7515
|
throw new Error(`rendered line ${index} contains a physical newline`);
|
|
7322
7516
|
}
|
|
@@ -7515,7 +7709,7 @@ function lineText(value) {
|
|
|
7515
7709
|
}
|
|
7516
7710
|
function wrapStyledSpans(spans, width) {
|
|
7517
7711
|
const targetWidth = Math.max(1, width);
|
|
7518
|
-
const
|
|
7712
|
+
const lines2 = [];
|
|
7519
7713
|
let current = [];
|
|
7520
7714
|
let currentWidth = 0;
|
|
7521
7715
|
let skipLineFeed = false;
|
|
@@ -7528,7 +7722,7 @@ function wrapStyledSpans(spans, width) {
|
|
|
7528
7722
|
current.push(span(text, style));
|
|
7529
7723
|
};
|
|
7530
7724
|
const finish = () => {
|
|
7531
|
-
|
|
7725
|
+
lines2.push(line(...current));
|
|
7532
7726
|
current = [];
|
|
7533
7727
|
currentWidth = 0;
|
|
7534
7728
|
};
|
|
@@ -7560,7 +7754,7 @@ function wrapStyledSpans(spans, width) {
|
|
|
7560
7754
|
}
|
|
7561
7755
|
}
|
|
7562
7756
|
finish();
|
|
7563
|
-
return
|
|
7757
|
+
return lines2;
|
|
7564
7758
|
}
|
|
7565
7759
|
function truncateStyledLine(value, width, ellipsis = "\u2026") {
|
|
7566
7760
|
if (width <= 0) {
|
|
@@ -7649,6 +7843,7 @@ var InputActionKind = {
|
|
|
7649
7843
|
CursorLeft: "cursor_left",
|
|
7650
7844
|
CursorRight: "cursor_right",
|
|
7651
7845
|
Backspace: "backspace",
|
|
7846
|
+
DeleteToLineStart: "delete_to_line_start",
|
|
7652
7847
|
Key: "key",
|
|
7653
7848
|
Dismiss: "dismiss",
|
|
7654
7849
|
Cancel: "cancel",
|
|
@@ -7697,6 +7892,8 @@ function toTuiInputEvent(input) {
|
|
|
7697
7892
|
return { type: "key", key: makeKeyInput("right") };
|
|
7698
7893
|
case InputActionKind.Backspace:
|
|
7699
7894
|
return { type: "key", key: makeKeyInput("backspace") };
|
|
7895
|
+
case InputActionKind.DeleteToLineStart:
|
|
7896
|
+
return { type: "key", key: makeKeyInput("ctrl_u", { ctrl: true }) };
|
|
7700
7897
|
case InputActionKind.Dismiss:
|
|
7701
7898
|
return { type: "key", key: makeKeyInput("escape") };
|
|
7702
7899
|
case InputActionKind.Cancel:
|
|
@@ -7829,13 +8026,15 @@ var ABANDONED_NEGOTIATION_TAIL_RE = /^\x1b\[\?[\d;]*([A-Za-z])$/;
|
|
|
7829
8026
|
var TerminalInputFilter = class {
|
|
7830
8027
|
pendingNegotiationPrefix = "";
|
|
7831
8028
|
isAppleTerminal;
|
|
8029
|
+
isWindowsConsole;
|
|
7832
8030
|
shiftPressed;
|
|
7833
8031
|
enableModifyOtherKeys;
|
|
7834
8032
|
disableModifyOtherKeys;
|
|
7835
8033
|
kittyProtocolActive = false;
|
|
7836
8034
|
constructor(options = {}) {
|
|
7837
8035
|
this.isAppleTerminal = options.isAppleTerminal ?? isAppleTerminalSession;
|
|
7838
|
-
this.
|
|
8036
|
+
this.isWindowsConsole = options.isWindowsConsole ?? isLocalWindowsConsole;
|
|
8037
|
+
this.shiftPressed = options.shiftPressed ?? isNativeShiftPressed;
|
|
7839
8038
|
this.enableModifyOtherKeys = options.enableModifyOtherKeys ?? (() => {
|
|
7840
8039
|
});
|
|
7841
8040
|
this.disableModifyOtherKeys = options.disableModifyOtherKeys ?? (() => {
|
|
@@ -7914,7 +8113,7 @@ var TerminalInputFilter = class {
|
|
|
7914
8113
|
return match[1];
|
|
7915
8114
|
}
|
|
7916
8115
|
normalizePlatformInput(sequence) {
|
|
7917
|
-
if (sequence === "\r" && this.isAppleTerminal() && this.shiftPressed()) {
|
|
8116
|
+
if (sequence === "\r" && (this.isAppleTerminal() || this.isWindowsConsole()) && this.shiftPressed()) {
|
|
7918
8117
|
return APPLE_TERMINAL_SHIFT_ENTER_SEQUENCE;
|
|
7919
8118
|
}
|
|
7920
8119
|
return sequence;
|
|
@@ -7937,6 +8136,7 @@ var CONTROL_ACTIONS = /* @__PURE__ */ new Map([
|
|
|
7937
8136
|
[4, InputActionKind.Eof],
|
|
7938
8137
|
[9, InputActionKind.Complete],
|
|
7939
8138
|
[8, InputActionKind.Backspace],
|
|
8139
|
+
[21, InputActionKind.DeleteToLineStart],
|
|
7940
8140
|
[127, InputActionKind.Backspace]
|
|
7941
8141
|
]);
|
|
7942
8142
|
var CONTROL_KEYS = /* @__PURE__ */ new Map([
|
|
@@ -8367,10 +8567,13 @@ function decodeSpecialEscapeAction(sequence) {
|
|
|
8367
8567
|
return kind !== void 0 ? inputAction(kind) : null;
|
|
8368
8568
|
}
|
|
8369
8569
|
function decodeModifiedControlKey(sequence) {
|
|
8370
|
-
const kitty = /^\x1b\[(13|57414|9)
|
|
8570
|
+
const kitty = /^\x1b\[(13|57414|9|117)(?::\d*)?(?::\d+)?;(\d+)(?::(\d+))?u$/.exec(sequence);
|
|
8371
8571
|
if (kitty !== null) {
|
|
8372
8572
|
const code = kitty[1];
|
|
8373
8573
|
const modifier2 = Number.parseInt(kitty[2], 10) - 1;
|
|
8574
|
+
if (code === "117" && matchesKittyModifiers(modifier2, 4) && (isKittyPressEvent(kitty[3]) || kitty[3] === "2")) {
|
|
8575
|
+
return inputAction(InputActionKind.DeleteToLineStart);
|
|
8576
|
+
}
|
|
8374
8577
|
if (!isKittyPressEvent(kitty[3])) {
|
|
8375
8578
|
return null;
|
|
8376
8579
|
}
|
|
@@ -8388,6 +8591,9 @@ function decodeModifiedControlKey(sequence) {
|
|
|
8388
8591
|
}
|
|
8389
8592
|
const modifier = Number.parseInt(modifyOtherKeys[1], 10) - 1;
|
|
8390
8593
|
const codepoint = Number.parseInt(modifyOtherKeys[2], 10);
|
|
8594
|
+
if (codepoint === 117 && modifier === 4) {
|
|
8595
|
+
return inputAction(InputActionKind.DeleteToLineStart);
|
|
8596
|
+
}
|
|
8391
8597
|
if (codepoint === 13 && modifier === 2) {
|
|
8392
8598
|
return inputAction(InputActionKind.Key, "", makeKeyInput("enter", { alt: true }));
|
|
8393
8599
|
}
|
|
@@ -8506,13 +8712,13 @@ var EditorState = class _EditorState {
|
|
|
8506
8712
|
const projection = this.#renderProjection(width, prompt, options.mask ?? false);
|
|
8507
8713
|
const promptStyle = options.styles?.prompt ?? ((text) => text);
|
|
8508
8714
|
const textStyle = options.styles?.text ?? ((text) => text);
|
|
8509
|
-
const
|
|
8715
|
+
const lines2 = projection.rows.map((row, index) => {
|
|
8510
8716
|
const promptText = index === 0 ? projection.prompt : " ".repeat(projection.promptWidth);
|
|
8511
8717
|
const renderedPrompt = index === 0 ? promptStyle(promptText) : promptText;
|
|
8512
8718
|
return renderedPrompt + textStyle(row);
|
|
8513
8719
|
});
|
|
8514
8720
|
return {
|
|
8515
|
-
lines,
|
|
8721
|
+
lines: lines2,
|
|
8516
8722
|
cursorRow: projection.cursorRow,
|
|
8517
8723
|
cursorColumn: projection.cursorColumn
|
|
8518
8724
|
};
|
|
@@ -8609,6 +8815,8 @@ var EditorState = class _EditorState {
|
|
|
8609
8815
|
this.clearCompletions();
|
|
8610
8816
|
this.text = this.text.slice(0, this.cursor - 1) + this.text.slice(this.cursor);
|
|
8611
8817
|
this.cursor -= 1;
|
|
8818
|
+
} else if (action.kind === InputActionKind.DeleteToLineStart) {
|
|
8819
|
+
this.deleteToLineStart();
|
|
8612
8820
|
} else if (action.kind === InputActionKind.CursorLeft) {
|
|
8613
8821
|
this.clearCompletions();
|
|
8614
8822
|
this.cursor = Math.max(0, this.cursor - 1);
|
|
@@ -8631,6 +8839,22 @@ var EditorState = class _EditorState {
|
|
|
8631
8839
|
this.cursor += text.length;
|
|
8632
8840
|
this.historyIndex = null;
|
|
8633
8841
|
}
|
|
8842
|
+
deleteToLineStart() {
|
|
8843
|
+
if (this.cursor === 0) {
|
|
8844
|
+
return;
|
|
8845
|
+
}
|
|
8846
|
+
const previousNewline = this.text.lastIndexOf("\n", this.cursor - 1);
|
|
8847
|
+
const lineStart = previousNewline + 1;
|
|
8848
|
+
this.clearCompletions();
|
|
8849
|
+
if (lineStart === this.cursor) {
|
|
8850
|
+
this.text = this.text.slice(0, previousNewline) + this.text.slice(this.cursor);
|
|
8851
|
+
this.cursor = previousNewline;
|
|
8852
|
+
} else {
|
|
8853
|
+
this.text = this.text.slice(0, lineStart) + this.text.slice(this.cursor);
|
|
8854
|
+
this.cursor = lineStart;
|
|
8855
|
+
}
|
|
8856
|
+
this.historyIndex = null;
|
|
8857
|
+
}
|
|
8634
8858
|
acceptCompletion() {
|
|
8635
8859
|
if (this.selectedCompletion === null) {
|
|
8636
8860
|
return;
|
|
@@ -8728,6 +8952,7 @@ var DEFAULT_KEYBINDINGS = [
|
|
|
8728
8952
|
{ context: "terminal", key: "ctrl+o", action: "toggle_tool_output" },
|
|
8729
8953
|
{ context: "terminal", key: "ctrl+l", action: "select_model" },
|
|
8730
8954
|
{ context: "terminal", key: "ctrl+t", action: "toggle_thinking" },
|
|
8955
|
+
{ context: "editor", key: "ctrl+u", action: "delete_to_line_start" },
|
|
8731
8956
|
{ context: "editor", key: "ctrl+s", action: "steer_now" },
|
|
8732
8957
|
{ context: "editor", key: "alt+enter", action: "submit_follow_up" },
|
|
8733
8958
|
{ context: "editor", key: "escape", action: "dismiss" },
|
|
@@ -8762,6 +8987,9 @@ function controlKeyId(character) {
|
|
|
8762
8987
|
if (character === "l") {
|
|
8763
8988
|
return "ctrl_l";
|
|
8764
8989
|
}
|
|
8990
|
+
if (character === "u") {
|
|
8991
|
+
return "ctrl_u";
|
|
8992
|
+
}
|
|
8765
8993
|
return "character";
|
|
8766
8994
|
}
|
|
8767
8995
|
function parseKey(value) {
|
|
@@ -9035,6 +9263,14 @@ var UIEventReducer = class _UIEventReducer {
|
|
|
9035
9263
|
}
|
|
9036
9264
|
return createUpdate(kind, { text, correlationId, stream });
|
|
9037
9265
|
}
|
|
9266
|
+
if (kind === "tool.output_snapshot") {
|
|
9267
|
+
const stream = String(payload.stream ?? "stdout");
|
|
9268
|
+
const text = String(payload.text ?? "");
|
|
9269
|
+
const tool = this.state.activeTools.get(correlationId);
|
|
9270
|
+
if (tool !== void 0 && (stream === "stdout" || stream === "stderr"))
|
|
9271
|
+
tool[stream] = text;
|
|
9272
|
+
return createUpdate(kind, { text, correlationId, stream, payload });
|
|
9273
|
+
}
|
|
9038
9274
|
if (kind === "tool.finished") {
|
|
9039
9275
|
const tool = this.state.activeTools.get(correlationId);
|
|
9040
9276
|
this.state.activeTools.delete(correlationId);
|
|
@@ -9094,11 +9330,13 @@ var LIFECYCLE_EVENTS = /* @__PURE__ */ new Set([
|
|
|
9094
9330
|
var HIGH_FREQUENCY_EVENTS = /* @__PURE__ */ new Set([
|
|
9095
9331
|
"model.reasoning_delta",
|
|
9096
9332
|
"model.tool_call_delta",
|
|
9097
|
-
"tool.output_delta"
|
|
9333
|
+
"tool.output_delta",
|
|
9334
|
+
"tool.output_snapshot"
|
|
9098
9335
|
]);
|
|
9099
9336
|
var TOOL_EVENTS = /* @__PURE__ */ new Set([
|
|
9100
9337
|
"tool.started",
|
|
9101
9338
|
"tool.output_delta",
|
|
9339
|
+
"tool.output_snapshot",
|
|
9102
9340
|
"tool.finished"
|
|
9103
9341
|
]);
|
|
9104
9342
|
var SENSITIVE_FIELDS2 = /* @__PURE__ */ new Set([
|
|
@@ -9129,6 +9367,26 @@ function asPayload(value) {
|
|
|
9129
9367
|
function redactToolText(value) {
|
|
9130
9368
|
return SENSITIVE_TEXT_PATTERNS2.reduce((text, pattern) => text.replace(pattern, "$1[REDACTED]"), value);
|
|
9131
9369
|
}
|
|
9370
|
+
function redactToolSnapshot(value, startMidLine = false) {
|
|
9371
|
+
const text = startMidLine ? omitPartialOutputLine(value) : value;
|
|
9372
|
+
return redactToolText(text);
|
|
9373
|
+
}
|
|
9374
|
+
function toolOutputNote(payload) {
|
|
9375
|
+
const notes = [];
|
|
9376
|
+
if (payload.truncated === true)
|
|
9377
|
+
notes.push("Output preview truncated.");
|
|
9378
|
+
if (isRecord3(payload.output_files)) {
|
|
9379
|
+
const label = payload.output_file_complete === true ? "Full output" : "Partial output";
|
|
9380
|
+
notes.push(`${label}: ${Object.values(payload.output_files).filter((value) => typeof value === "string").join(", ")}`);
|
|
9381
|
+
}
|
|
9382
|
+
if (payload.output_file_error)
|
|
9383
|
+
notes.push(String(payload.output_file_error));
|
|
9384
|
+
if (payload.output_complete === false)
|
|
9385
|
+
notes.push("Output collection incomplete.");
|
|
9386
|
+
if (payload.error)
|
|
9387
|
+
notes.push(String(payload.error));
|
|
9388
|
+
return redactToolText(notes.join("\n"));
|
|
9389
|
+
}
|
|
9132
9390
|
function redactToolValue(value) {
|
|
9133
9391
|
if (typeof value === "string")
|
|
9134
9392
|
return redactToolText(value);
|
|
@@ -9199,8 +9457,15 @@ var DisplayPolicy = class {
|
|
|
9199
9457
|
const text = kind === "tool.output_delta" ? this.#toolOutputRedactor.redact(correlationId, stream || "stdout", String(rawPayload.text ?? rawPayload.chunk ?? "")) : String(payload.text ?? payload.chunk ?? "");
|
|
9200
9458
|
if (kind === "tool.output_delta") {
|
|
9201
9459
|
payload = { ...payload, text };
|
|
9460
|
+
} else if (kind === "tool.output_snapshot") {
|
|
9461
|
+
payload = { ...payload, text: redactToolSnapshot(String(rawPayload.text ?? ""), rawPayload.start_mid_line === true) };
|
|
9202
9462
|
} else if (kind === "tool.finished") {
|
|
9203
9463
|
this.#toolOutputRedactor.clear(correlationId);
|
|
9464
|
+
for (const name of ["stdout", "stderr"]) {
|
|
9465
|
+
if (typeof rawPayload[name] === "string") {
|
|
9466
|
+
payload[name] = redactToolSnapshot(rawPayload[name], rawPayload[`${name}_start_mid_line`] === true);
|
|
9467
|
+
}
|
|
9468
|
+
}
|
|
9204
9469
|
}
|
|
9205
9470
|
const projected = [];
|
|
9206
9471
|
const dropped = droppedCount(payload);
|
|
@@ -9216,11 +9481,11 @@ var DisplayPolicy = class {
|
|
|
9216
9481
|
if (kind === "model.reasoning_delta" && !this.showReasoning) {
|
|
9217
9482
|
return projected;
|
|
9218
9483
|
}
|
|
9219
|
-
if (this.foldToolOutput && kind === "tool.output_delta" && (stream || "stdout") === "stdout") {
|
|
9484
|
+
if (this.foldToolOutput && (kind === "tool.output_delta" || kind === "tool.output_snapshot") && (stream || "stdout") === "stdout") {
|
|
9220
9485
|
return projected;
|
|
9221
9486
|
}
|
|
9222
9487
|
if (LIFECYCLE_EVENTS.has(kind) || kind.length > 0) {
|
|
9223
|
-
projected.push({ kind, correlationId, stream, text, payload });
|
|
9488
|
+
projected.push({ kind, correlationId, stream, text: String(payload.text ?? text), payload });
|
|
9224
9489
|
}
|
|
9225
9490
|
return projected;
|
|
9226
9491
|
}
|
|
@@ -9412,11 +9677,27 @@ var TranscriptStore = class {
|
|
|
9412
9677
|
}
|
|
9413
9678
|
return;
|
|
9414
9679
|
}
|
|
9680
|
+
if (kind === "tool.output_snapshot") {
|
|
9681
|
+
const item = this.#byCorrelation.get(`tool:${correlationId}`);
|
|
9682
|
+
if (item?.kind === "tool" && item.mutable && (update.stream === "stdout" || update.stream === "stderr")) {
|
|
9683
|
+
item[update.stream] = redactToolSnapshot(update.text, update.payload.start_mid_line === true);
|
|
9684
|
+
if (update.payload.truncated === true)
|
|
9685
|
+
item.outputNote = "Output preview truncated.";
|
|
9686
|
+
touchBlock(item);
|
|
9687
|
+
}
|
|
9688
|
+
return;
|
|
9689
|
+
}
|
|
9415
9690
|
if (kind === "tool.finished") {
|
|
9416
9691
|
const item = this.#getOrCreateTool(correlationId);
|
|
9417
9692
|
item.status = String(update.payload.status ?? "completed");
|
|
9418
9693
|
item.exitCode = typeof update.payload.exit_code === "number" ? Math.trunc(update.payload.exit_code) : null;
|
|
9419
9694
|
item.durationMs = typeof update.payload.duration_ms === "number" ? Math.trunc(update.payload.duration_ms) : null;
|
|
9695
|
+
for (const stream of ["stdout", "stderr"]) {
|
|
9696
|
+
const text = update.payload[stream];
|
|
9697
|
+
if (typeof text === "string")
|
|
9698
|
+
item[stream] = redactToolSnapshot(text, update.payload[`${stream}_start_mid_line`] === true);
|
|
9699
|
+
}
|
|
9700
|
+
item.outputNote = toolOutputNote(update.payload);
|
|
9420
9701
|
item.mutable = false;
|
|
9421
9702
|
touchBlock(item);
|
|
9422
9703
|
this.#toolOutputRedactor.clear(correlationId);
|
|
@@ -9581,13 +9862,13 @@ var Composer = class {
|
|
|
9581
9862
|
mask: this.#mask
|
|
9582
9863
|
});
|
|
9583
9864
|
const borderStyle = { foreground: "dim" };
|
|
9584
|
-
const
|
|
9865
|
+
const lines2 = [
|
|
9585
9866
|
line(span("\u256D", borderStyle), span("\u2500".repeat(innerWidth), borderStyle), span("\u256E", borderStyle)),
|
|
9586
9867
|
...rendered.lines.map((value) => line(span("\u2502", borderStyle), ...padStyledLine(truncateStyledLine(value, innerWidth, ""), innerWidth).spans, span("\u2502", borderStyle))),
|
|
9587
9868
|
line(span("\u2570", borderStyle), span("\u2500".repeat(innerWidth), borderStyle), span("\u256F", borderStyle))
|
|
9588
9869
|
];
|
|
9589
9870
|
return {
|
|
9590
|
-
lines,
|
|
9871
|
+
lines: lines2,
|
|
9591
9872
|
cursor: {
|
|
9592
9873
|
row: rendered.cursorRow + 1,
|
|
9593
9874
|
column: rendered.cursorColumn + 1
|
|
@@ -9702,22 +9983,22 @@ function renderMarkdownStyledLines(text, width) {
|
|
|
9702
9983
|
return [];
|
|
9703
9984
|
}
|
|
9704
9985
|
const layoutWidth = Math.max(12, width);
|
|
9705
|
-
const
|
|
9986
|
+
const lines2 = [];
|
|
9706
9987
|
let previous = null;
|
|
9707
9988
|
for (const block of renderBlocks(clean, layoutWidth)) {
|
|
9708
9989
|
const leadingBlank = previous === null ? block.kind === "list" || block.kind === "table" || block.kind === "quote" : previous !== "hr";
|
|
9709
9990
|
if (leadingBlank) {
|
|
9710
|
-
|
|
9991
|
+
lines2.push(line());
|
|
9711
9992
|
}
|
|
9712
9993
|
for (const line2 of block.lines) {
|
|
9713
|
-
|
|
9994
|
+
lines2.push(truncateMarkdownLine(serializeLine(line2), width));
|
|
9714
9995
|
}
|
|
9715
9996
|
if (block.kind === "hr") {
|
|
9716
|
-
|
|
9997
|
+
lines2.push(line());
|
|
9717
9998
|
}
|
|
9718
9999
|
previous = block.kind;
|
|
9719
10000
|
}
|
|
9720
|
-
return
|
|
10001
|
+
return lines2;
|
|
9721
10002
|
}
|
|
9722
10003
|
function styleKey(style) {
|
|
9723
10004
|
return [
|
|
@@ -9729,7 +10010,7 @@ function styleKey(style) {
|
|
|
9729
10010
|
].join("|");
|
|
9730
10011
|
}
|
|
9731
10012
|
function renderBlocks(text, layoutWidth) {
|
|
9732
|
-
const
|
|
10013
|
+
const lines2 = text.replace(/\r\n/g, "\n").split("\n");
|
|
9733
10014
|
const blocks = [];
|
|
9734
10015
|
let paragraph = [];
|
|
9735
10016
|
let index = 0;
|
|
@@ -9743,8 +10024,8 @@ function renderBlocks(text, layoutWidth) {
|
|
|
9743
10024
|
});
|
|
9744
10025
|
}
|
|
9745
10026
|
};
|
|
9746
|
-
while (index <
|
|
9747
|
-
const line2 =
|
|
10027
|
+
while (index < lines2.length) {
|
|
10028
|
+
const line2 = lines2[index];
|
|
9748
10029
|
const trimmed = line2.trim();
|
|
9749
10030
|
if (trimmed.startsWith("```") || trimmed.startsWith("~~~")) {
|
|
9750
10031
|
flushParagraph();
|
|
@@ -9754,8 +10035,8 @@ function renderBlocks(text, layoutWidth) {
|
|
|
9754
10035
|
foreground: "code"
|
|
9755
10036
|
};
|
|
9756
10037
|
const codeLines = [];
|
|
9757
|
-
while (index <
|
|
9758
|
-
const body =
|
|
10038
|
+
while (index < lines2.length) {
|
|
10039
|
+
const body = lines2[index];
|
|
9759
10040
|
if (body.trim().startsWith(fence)) {
|
|
9760
10041
|
index += 1;
|
|
9761
10042
|
break;
|
|
@@ -9771,15 +10052,15 @@ function renderBlocks(text, layoutWidth) {
|
|
|
9771
10052
|
index += 1;
|
|
9772
10053
|
continue;
|
|
9773
10054
|
}
|
|
9774
|
-
if (trimmed.includes("|") && index + 1 <
|
|
10055
|
+
if (trimmed.includes("|") && index + 1 < lines2.length) {
|
|
9775
10056
|
const header = splitTableRow(trimmed);
|
|
9776
|
-
const delimiter = splitTableRow(
|
|
10057
|
+
const delimiter = splitTableRow(lines2[index + 1].trim());
|
|
9777
10058
|
if (header !== null && delimiter !== null && delimiter.length === header.length && delimiter.every((cell) => /^:?-+:?$/.test(cell))) {
|
|
9778
10059
|
flushParagraph();
|
|
9779
10060
|
index += 2;
|
|
9780
10061
|
const rows = [];
|
|
9781
|
-
while (index <
|
|
9782
|
-
const rowLine =
|
|
10062
|
+
while (index < lines2.length) {
|
|
10063
|
+
const rowLine = lines2[index].trim();
|
|
9783
10064
|
if (!rowLine) {
|
|
9784
10065
|
break;
|
|
9785
10066
|
}
|
|
@@ -9826,8 +10107,8 @@ function renderBlocks(text, layoutWidth) {
|
|
|
9826
10107
|
if (trimmed.startsWith(">")) {
|
|
9827
10108
|
flushParagraph();
|
|
9828
10109
|
const content = [];
|
|
9829
|
-
while (index <
|
|
9830
|
-
const match = /^>\s?(.*)$/.exec(
|
|
10110
|
+
while (index < lines2.length) {
|
|
10111
|
+
const match = /^>\s?(.*)$/.exec(lines2[index].trim());
|
|
9831
10112
|
if (!match) {
|
|
9832
10113
|
break;
|
|
9833
10114
|
}
|
|
@@ -9846,8 +10127,8 @@ function renderBlocks(text, layoutWidth) {
|
|
|
9846
10127
|
if (/^[-*+]\s+/.test(trimmed)) {
|
|
9847
10128
|
flushParagraph();
|
|
9848
10129
|
const items = [];
|
|
9849
|
-
while (index <
|
|
9850
|
-
const match = /^[-*+]\s+(.*)$/.exec(
|
|
10130
|
+
while (index < lines2.length) {
|
|
10131
|
+
const match = /^[-*+]\s+(.*)$/.exec(lines2[index].trim());
|
|
9851
10132
|
if (!match) {
|
|
9852
10133
|
break;
|
|
9853
10134
|
}
|
|
@@ -9866,8 +10147,8 @@ function renderBlocks(text, layoutWidth) {
|
|
|
9866
10147
|
const start = parseInt(numbered[1], 10);
|
|
9867
10148
|
const items = [parseInline(numbered[2], {})];
|
|
9868
10149
|
index += 1;
|
|
9869
|
-
while (index <
|
|
9870
|
-
const match = /^(\d+)[.)]\s+(.*)$/.exec(
|
|
10150
|
+
while (index < lines2.length) {
|
|
10151
|
+
const match = /^(\d+)[.)]\s+(.*)$/.exec(lines2[index].trim());
|
|
9871
10152
|
if (!match) {
|
|
9872
10153
|
break;
|
|
9873
10154
|
}
|
|
@@ -9889,16 +10170,16 @@ function renderBlocks(text, layoutWidth) {
|
|
|
9889
10170
|
}
|
|
9890
10171
|
function renderListItems(items, prefixFor, layoutWidth) {
|
|
9891
10172
|
const marker = { foreground: "accent" };
|
|
9892
|
-
const
|
|
10173
|
+
const lines2 = [];
|
|
9893
10174
|
for (let index = 0; index < items.length; index += 1) {
|
|
9894
10175
|
const prefix = prefixFor(index);
|
|
9895
10176
|
const wrapped = wrapSegments(items[index], Math.max(1, layoutWidth - prefix.length));
|
|
9896
10177
|
if (wrapped.length === 0) {
|
|
9897
|
-
|
|
10178
|
+
lines2.push([{ style: marker, text: prefix }]);
|
|
9898
10179
|
continue;
|
|
9899
10180
|
}
|
|
9900
10181
|
for (let row = 0; row < wrapped.length; row += 1) {
|
|
9901
|
-
|
|
10182
|
+
lines2.push([
|
|
9902
10183
|
{
|
|
9903
10184
|
style: marker,
|
|
9904
10185
|
text: row === 0 ? prefix : " ".repeat(prefix.length)
|
|
@@ -9907,7 +10188,7 @@ function renderListItems(items, prefixFor, layoutWidth) {
|
|
|
9907
10188
|
]);
|
|
9908
10189
|
}
|
|
9909
10190
|
}
|
|
9910
|
-
return
|
|
10191
|
+
return lines2;
|
|
9911
10192
|
}
|
|
9912
10193
|
function splitTableRow(line2) {
|
|
9913
10194
|
if (!line2.includes("|")) {
|
|
@@ -9955,15 +10236,15 @@ function renderTable(header, rows, layoutWidth) {
|
|
|
9955
10236
|
widths[widest] = widths[widest] - 1;
|
|
9956
10237
|
}
|
|
9957
10238
|
const inner = widths.reduce((total, w) => total + w, 0) + 2 * (columnCount - 1);
|
|
9958
|
-
const
|
|
9959
|
-
|
|
9960
|
-
|
|
9961
|
-
|
|
10239
|
+
const lines2 = [];
|
|
10240
|
+
lines2.push([{ style: borderStyle, text: " ".repeat(inner + 2) }]);
|
|
10241
|
+
lines2.push(...renderTableRows(headerCells, widths, borderStyle, headerStyle));
|
|
10242
|
+
lines2.push([{ style: borderStyle, text: ` ${"\u2500".repeat(inner)} ` }]);
|
|
9962
10243
|
for (const row of bodyCells) {
|
|
9963
|
-
|
|
10244
|
+
lines2.push(...renderTableRows(row, widths, borderStyle, {}));
|
|
9964
10245
|
}
|
|
9965
|
-
|
|
9966
|
-
return
|
|
10246
|
+
lines2.push([{ style: borderStyle, text: " ".repeat(inner + 2) }]);
|
|
10247
|
+
return lines2;
|
|
9967
10248
|
}
|
|
9968
10249
|
function renderTableRows(cells, widths, borderStyle, padStyle) {
|
|
9969
10250
|
const wrappedCells = cells.map((cell, i) => {
|
|
@@ -9971,7 +10252,7 @@ function renderTableRows(cells, widths, borderStyle, padStyle) {
|
|
|
9971
10252
|
return wrapped.length > 0 ? wrapped : [[]];
|
|
9972
10253
|
});
|
|
9973
10254
|
const height = Math.max(...wrappedCells.map((cell) => cell.length));
|
|
9974
|
-
const
|
|
10255
|
+
const lines2 = [];
|
|
9975
10256
|
for (let row = 0; row < height; row += 1) {
|
|
9976
10257
|
const line2 = [{ style: borderStyle, text: " " }];
|
|
9977
10258
|
for (let i = 0; i < cells.length; i += 1) {
|
|
@@ -9989,9 +10270,9 @@ function renderTableRows(cells, widths, borderStyle, padStyle) {
|
|
|
9989
10270
|
}
|
|
9990
10271
|
}
|
|
9991
10272
|
line2.push({ style: borderStyle, text: " " });
|
|
9992
|
-
|
|
10273
|
+
lines2.push(mergeSegments(line2));
|
|
9993
10274
|
}
|
|
9994
|
-
return
|
|
10275
|
+
return lines2;
|
|
9995
10276
|
}
|
|
9996
10277
|
var INLINE_PATTERNS = [
|
|
9997
10278
|
{
|
|
@@ -10146,12 +10427,12 @@ function wrapSegments(segments, width) {
|
|
|
10146
10427
|
if (current.length > 0) {
|
|
10147
10428
|
words.push(current);
|
|
10148
10429
|
}
|
|
10149
|
-
const
|
|
10430
|
+
const lines2 = [];
|
|
10150
10431
|
let line2 = [];
|
|
10151
10432
|
let lineWidth = 0;
|
|
10152
10433
|
let pendingSpace = null;
|
|
10153
10434
|
const flushLine = () => {
|
|
10154
|
-
|
|
10435
|
+
lines2.push(line2);
|
|
10155
10436
|
line2 = [];
|
|
10156
10437
|
lineWidth = 0;
|
|
10157
10438
|
pendingSpace = null;
|
|
@@ -10192,7 +10473,7 @@ function wrapSegments(segments, width) {
|
|
|
10192
10473
|
if (line2.length > 0) {
|
|
10193
10474
|
flushLine();
|
|
10194
10475
|
}
|
|
10195
|
-
return
|
|
10476
|
+
return lines2.map((physical) => regroup(physical));
|
|
10196
10477
|
}
|
|
10197
10478
|
function regroup(clusters) {
|
|
10198
10479
|
const segments = [];
|
|
@@ -10274,11 +10555,11 @@ var Text = class {
|
|
|
10274
10555
|
this.#cache = null;
|
|
10275
10556
|
}
|
|
10276
10557
|
};
|
|
10277
|
-
function applyTextPadding(
|
|
10558
|
+
function applyTextPadding(lines2, width, options) {
|
|
10278
10559
|
const targetWidth = Math.max(0, width);
|
|
10279
10560
|
const blank = () => line(span(" ".repeat(targetWidth), backgroundStyle(options.background)));
|
|
10280
10561
|
const horizontalPadding = span(" ".repeat(options.paddingX), backgroundStyle(options.background));
|
|
10281
|
-
const contentLines =
|
|
10562
|
+
const contentLines = lines2.map((value) => {
|
|
10282
10563
|
const contentSpans = options.background === void 0 ? value.spans : value.spans.map((item) => span(item.text, {
|
|
10283
10564
|
...item.style,
|
|
10284
10565
|
background: item.style?.background ?? options.background
|
|
@@ -10362,7 +10643,7 @@ var Box = class {
|
|
|
10362
10643
|
const width = Math.max(0, context.width);
|
|
10363
10644
|
const child = this.#child.render({ ...context, width: Math.max(1, width - this.#paddingX * 2) });
|
|
10364
10645
|
const blank = () => line(span(" ".repeat(width), backgroundStyle2(this.#background)));
|
|
10365
|
-
const
|
|
10646
|
+
const lines2 = child.lines.map((value) => this.#renderLine(value, width));
|
|
10366
10647
|
const cursor = child.cursor === void 0 ? void 0 : {
|
|
10367
10648
|
row: child.cursor.row + this.#paddingY,
|
|
10368
10649
|
column: child.cursor.column + this.#paddingX
|
|
@@ -10370,7 +10651,7 @@ var Box = class {
|
|
|
10370
10651
|
return {
|
|
10371
10652
|
lines: [
|
|
10372
10653
|
...Array.from({ length: this.#paddingY }, blank),
|
|
10373
|
-
...
|
|
10654
|
+
...lines2,
|
|
10374
10655
|
...Array.from({ length: this.#paddingY }, blank)
|
|
10375
10656
|
],
|
|
10376
10657
|
...cursor === void 0 ? {} : { cursor }
|
|
@@ -10420,11 +10701,11 @@ var ToolMessage = class {
|
|
|
10420
10701
|
options.exitCode === null ? "" : `exit ${options.exitCode}`,
|
|
10421
10702
|
options.durationMs === null ? "" : `${options.durationMs}ms`
|
|
10422
10703
|
].filter(Boolean).join(" \xB7 ");
|
|
10423
|
-
const output = options.expanded ? [stderr
|
|
10704
|
+
const output = options.expanded ? [stderr, stdout].filter(Boolean).map((text) => text.length > 1200 ? `\u2026${text.slice(-1200)}` : text) : [];
|
|
10424
10705
|
this.#content = new Box({
|
|
10425
10706
|
child: new Text({
|
|
10426
10707
|
spans: [...title, { text: `
|
|
10427
|
-
${[metadata, ...output].join("\n")}` }]
|
|
10708
|
+
${[metadata, ...output, options.outputNote && redactToolText(options.outputNote)].filter(Boolean).join("\n")}` }]
|
|
10428
10709
|
})
|
|
10429
10710
|
});
|
|
10430
10711
|
}
|
|
@@ -10447,12 +10728,12 @@ var UserMessage = class {
|
|
|
10447
10728
|
}
|
|
10448
10729
|
render(context) {
|
|
10449
10730
|
const width = Math.max(3, context.width);
|
|
10450
|
-
const
|
|
10731
|
+
const lines2 = wrapStyledSpans([
|
|
10451
10732
|
span("\u2728 ", { foreground: "accent" }),
|
|
10452
10733
|
span(this.#text)
|
|
10453
10734
|
], width);
|
|
10454
10735
|
return {
|
|
10455
|
-
lines:
|
|
10736
|
+
lines: lines2.map((value) => padStyledLine(value, width))
|
|
10456
10737
|
};
|
|
10457
10738
|
}
|
|
10458
10739
|
invalidate() {
|
|
@@ -10474,7 +10755,7 @@ var WelcomeMessage = class {
|
|
|
10474
10755
|
}
|
|
10475
10756
|
const innerWidth = width - 2;
|
|
10476
10757
|
const borderStyle = { foreground: "accent" };
|
|
10477
|
-
const
|
|
10758
|
+
const lines2 = [
|
|
10478
10759
|
line(span("\u256D", borderStyle), span("\u2500".repeat(innerWidth), borderStyle), span("\u256E", borderStyle)),
|
|
10479
10760
|
frameRow(innerWidth, borderStyle, [
|
|
10480
10761
|
span("H", { foreground: "accent", bold: true }),
|
|
@@ -10484,17 +10765,17 @@ var WelcomeMessage = class {
|
|
|
10484
10765
|
];
|
|
10485
10766
|
const [subtitle, ...meta] = this.#details;
|
|
10486
10767
|
if (subtitle !== void 0) {
|
|
10487
|
-
|
|
10768
|
+
lines2.push(frameRow(innerWidth, borderStyle, [
|
|
10488
10769
|
span(" "),
|
|
10489
10770
|
span(subtitle, { foreground: "dim" })
|
|
10490
10771
|
]));
|
|
10491
10772
|
}
|
|
10492
|
-
|
|
10773
|
+
lines2.push(frameRow(innerWidth, borderStyle, [span("")]));
|
|
10493
10774
|
for (const detail of meta) {
|
|
10494
|
-
|
|
10775
|
+
lines2.push(frameRow(innerWidth, borderStyle, metaSpans(detail)));
|
|
10495
10776
|
}
|
|
10496
|
-
|
|
10497
|
-
return { lines };
|
|
10777
|
+
lines2.push(line(span("\u2570", borderStyle), span("\u2500".repeat(innerWidth), borderStyle), span("\u256F", borderStyle)));
|
|
10778
|
+
return { lines: lines2 };
|
|
10498
10779
|
}
|
|
10499
10780
|
invalidate() {
|
|
10500
10781
|
}
|
|
@@ -10627,23 +10908,23 @@ var Transcript = class {
|
|
|
10627
10908
|
}
|
|
10628
10909
|
renderWithMetadata(context) {
|
|
10629
10910
|
const usableWidth = Math.max(12, context.width);
|
|
10630
|
-
const
|
|
10911
|
+
const lines2 = [];
|
|
10631
10912
|
let activeStart = null;
|
|
10632
10913
|
const seenKeys = /* @__PURE__ */ new Set();
|
|
10633
10914
|
for (const block of this.#blocks) {
|
|
10634
|
-
if (
|
|
10635
|
-
|
|
10915
|
+
if (lines2.length > 0) {
|
|
10916
|
+
lines2.push(plainLine(""));
|
|
10636
10917
|
}
|
|
10637
10918
|
if (block.mutable && activeStart === null)
|
|
10638
|
-
activeStart =
|
|
10919
|
+
activeStart = lines2.length;
|
|
10639
10920
|
seenKeys.add(cacheKey(block));
|
|
10640
|
-
|
|
10921
|
+
lines2.push(...this.#renderBlockCached(block, { ...context, width: usableWidth }));
|
|
10641
10922
|
}
|
|
10642
10923
|
for (const key of this.#cache.keys()) {
|
|
10643
10924
|
if (!seenKeys.has(key))
|
|
10644
10925
|
this.#cache.delete(key);
|
|
10645
10926
|
}
|
|
10646
|
-
return { lines, activeStart };
|
|
10927
|
+
return { lines: lines2, activeStart };
|
|
10647
10928
|
}
|
|
10648
10929
|
invalidate() {
|
|
10649
10930
|
this.#cache.clear();
|
|
@@ -10656,23 +10937,23 @@ var Transcript = class {
|
|
|
10656
10937
|
return cached.lines;
|
|
10657
10938
|
}
|
|
10658
10939
|
if (cached !== void 0 && cached.signature === signature) {
|
|
10659
|
-
const
|
|
10940
|
+
const lines3 = cached.component.render(context).lines;
|
|
10660
10941
|
this.#cache.set(key, {
|
|
10661
10942
|
...cached,
|
|
10662
10943
|
width: context.width,
|
|
10663
|
-
lines:
|
|
10944
|
+
lines: lines3
|
|
10664
10945
|
});
|
|
10665
|
-
return
|
|
10946
|
+
return lines3;
|
|
10666
10947
|
}
|
|
10667
10948
|
const component = this.#createBlockComponent(block);
|
|
10668
|
-
const
|
|
10949
|
+
const lines2 = component.render(context).lines;
|
|
10669
10950
|
this.#cache.set(key, {
|
|
10670
10951
|
component,
|
|
10671
10952
|
width: context.width,
|
|
10672
10953
|
signature,
|
|
10673
|
-
lines
|
|
10954
|
+
lines: lines2
|
|
10674
10955
|
});
|
|
10675
|
-
return
|
|
10956
|
+
return lines2;
|
|
10676
10957
|
}
|
|
10677
10958
|
#createBlockComponent(block) {
|
|
10678
10959
|
switch (block.kind) {
|
|
@@ -10744,7 +11025,7 @@ var TerminalTheme = class {
|
|
|
10744
11025
|
return `\x1B[${channel};2;${r};${g};${b}m`;
|
|
10745
11026
|
}
|
|
10746
11027
|
};
|
|
10747
|
-
var
|
|
11028
|
+
var DEFAULT_DARK_THEME = new TerminalTheme("dark", {
|
|
10748
11029
|
accent: "#8abeb7",
|
|
10749
11030
|
border: "#5f87ff",
|
|
10750
11031
|
border_muted: "#505050",
|
|
@@ -10765,7 +11046,7 @@ var PI_DARK = new TerminalTheme("dark", {
|
|
|
10765
11046
|
thinking: "#808080",
|
|
10766
11047
|
bash: "#b5bd68"
|
|
10767
11048
|
});
|
|
10768
|
-
var
|
|
11049
|
+
var DEFAULT_LIGHT_THEME = new TerminalTheme("light", {
|
|
10769
11050
|
accent: "#5a8080",
|
|
10770
11051
|
border: "#547da7",
|
|
10771
11052
|
border_muted: "#b0b0b0",
|
|
@@ -10789,10 +11070,10 @@ var PI_LIGHT = new TerminalTheme("light", {
|
|
|
10789
11070
|
function resolveTerminalTheme(name, env = process.env) {
|
|
10790
11071
|
const requested = (name ?? "auto").trim().toLowerCase() || "auto";
|
|
10791
11072
|
if (requested === "light") {
|
|
10792
|
-
return
|
|
11073
|
+
return DEFAULT_LIGHT_THEME;
|
|
10793
11074
|
}
|
|
10794
11075
|
if (requested === "dark") {
|
|
10795
|
-
return
|
|
11076
|
+
return DEFAULT_DARK_THEME;
|
|
10796
11077
|
}
|
|
10797
11078
|
if (requested !== "auto") {
|
|
10798
11079
|
throw new Error("terminal theme must be 'auto', 'dark', or 'light'");
|
|
@@ -10800,9 +11081,9 @@ function resolveTerminalTheme(name, env = process.env) {
|
|
|
10800
11081
|
const colorfgbg = env.COLORFGBG ?? "";
|
|
10801
11082
|
const background = colorfgbg ? colorfgbg.split(";").pop() : "";
|
|
10802
11083
|
if (/^\s*[+-]?\d+\s*$/.test(background)) {
|
|
10803
|
-
return parseInt(background, 10) >= 7 ?
|
|
11084
|
+
return parseInt(background, 10) >= 7 ? DEFAULT_LIGHT_THEME : DEFAULT_DARK_THEME;
|
|
10804
11085
|
}
|
|
10805
|
-
return
|
|
11086
|
+
return DEFAULT_DARK_THEME;
|
|
10806
11087
|
}
|
|
10807
11088
|
|
|
10808
11089
|
// ../../packages/terminal/tui/dist/tui/frame-builder.js
|
|
@@ -10829,9 +11110,9 @@ var FrameBuilder = class {
|
|
|
10829
11110
|
const terminalWidth = Math.max(1, options.width);
|
|
10830
11111
|
const width = Math.max(1, terminalWidth - 1);
|
|
10831
11112
|
const mainScreen = options.compiledMainScreen ?? this.#fallbackMainScreen(options, width);
|
|
10832
|
-
const
|
|
11113
|
+
const lines2 = mainScreen.lines.map((value) => visibleWidth(value) <= width ? value : truncateToWidth(value, width));
|
|
10833
11114
|
const cursor = {
|
|
10834
|
-
row: Math.max(0, Math.min(mainScreen.cursor.row, Math.max(0,
|
|
11115
|
+
row: Math.max(0, Math.min(mainScreen.cursor.row, Math.max(0, lines2.length - 1))),
|
|
10835
11116
|
col: Math.max(0, Math.min(mainScreen.cursor.column, width - 1))
|
|
10836
11117
|
};
|
|
10837
11118
|
return {
|
|
@@ -10840,8 +11121,8 @@ var FrameBuilder = class {
|
|
|
10840
11121
|
statusBar: this.statusBar(width),
|
|
10841
11122
|
cursor,
|
|
10842
11123
|
screen: {
|
|
10843
|
-
lines,
|
|
10844
|
-
activeStart: Math.max(0, Math.min(mainScreen.activeStart,
|
|
11124
|
+
lines: lines2,
|
|
11125
|
+
activeStart: Math.max(0, Math.min(mainScreen.activeStart, lines2.length)),
|
|
10845
11126
|
cursorRow: cursor.row,
|
|
10846
11127
|
cursorCol: cursor.col
|
|
10847
11128
|
}
|
|
@@ -10866,9 +11147,9 @@ var FrameBuilder = class {
|
|
|
10866
11147
|
}).render({ width, theme: this.#theme });
|
|
10867
11148
|
const status = this.#status().render({ width, theme: this.#theme });
|
|
10868
11149
|
const cursor = composer.cursor ?? { row: Math.max(0, composer.lines.length - 1), column: 0 };
|
|
10869
|
-
const
|
|
11150
|
+
const lines2 = [...transcriptLines, ...composer.lines, ...completion.lines, ...status.lines];
|
|
10870
11151
|
return {
|
|
10871
|
-
lines: compileStyledLines(
|
|
11152
|
+
lines: compileStyledLines(lines2, width, this.#theme),
|
|
10872
11153
|
cursor: {
|
|
10873
11154
|
row: transcriptLines.length + cursor.row,
|
|
10874
11155
|
column: cursor.column
|
|
@@ -10972,8 +11253,8 @@ var SearchInput = class {
|
|
|
10972
11253
|
const width = Math.max(1, context.width);
|
|
10973
11254
|
const contentWidth = Math.max(1, width - displayWidth4(PROMPT));
|
|
10974
11255
|
const displayText = this.#secret ? "\u2022".repeat(this.#editor.text.length) : this.#editor.text;
|
|
10975
|
-
const
|
|
10976
|
-
const structuredLines =
|
|
11256
|
+
const lines2 = renderLines(displayText || this.#placeholder, contentWidth, displayText.length === 0 && this.#placeholder.length > 0);
|
|
11257
|
+
const structuredLines = lines2.map((value, index) => truncateStyledLine(line(span(index === 0 ? PROMPT : " ".repeat(displayWidth4(PROMPT)), index === 0 ? { foreground: "accent" } : void 0), span(value, displayText.length === 0 && this.#placeholder.length > 0 ? { foreground: "muted" } : void 0)), width, ""));
|
|
10977
11258
|
const cursor = this.focused ? cursorMetadata(displayText.slice(0, this.#editor.cursor), contentWidth) : void 0;
|
|
10978
11259
|
return cursor === void 0 ? { lines: structuredLines } : {
|
|
10979
11260
|
lines: structuredLines,
|
|
@@ -11041,15 +11322,15 @@ function renderLines(value, width, placeholder) {
|
|
|
11041
11322
|
if (placeholder) {
|
|
11042
11323
|
return [value];
|
|
11043
11324
|
}
|
|
11044
|
-
const
|
|
11325
|
+
const lines2 = [];
|
|
11045
11326
|
for (const source of value.split("\n")) {
|
|
11046
|
-
|
|
11327
|
+
lines2.push(...wrapStyledSpans([span(source)], width).map((item) => item.spans.map((part) => part.text).join("")));
|
|
11047
11328
|
}
|
|
11048
11329
|
const last = value.split("\n").at(-1) ?? "";
|
|
11049
11330
|
if (value && !value.endsWith("\n") && displayWidth4(last) % width === 0) {
|
|
11050
|
-
|
|
11331
|
+
lines2.push("");
|
|
11051
11332
|
}
|
|
11052
|
-
return
|
|
11333
|
+
return lines2;
|
|
11053
11334
|
}
|
|
11054
11335
|
function cursorMetadata(before, width) {
|
|
11055
11336
|
const segments = before.split("\n");
|
|
@@ -11133,11 +11414,11 @@ var SelectList = class {
|
|
|
11133
11414
|
const start = Math.max(0, Math.min(this.#selectedIndex - Math.floor(this.#maxVisible / 2), this.#filteredItems.length - this.#maxVisible));
|
|
11134
11415
|
const end = Math.min(start + this.#maxVisible, this.#filteredItems.length);
|
|
11135
11416
|
const primaryColumnWidth = this.#primaryColumnWidth();
|
|
11136
|
-
const
|
|
11417
|
+
const lines2 = this.#filteredItems.slice(start, end).map((item, index) => this.#renderItem(item, start + index === this.#selectedIndex, context.width, primaryColumnWidth));
|
|
11137
11418
|
if (start > 0 || end < this.#filteredItems.length) {
|
|
11138
|
-
|
|
11419
|
+
lines2.push(truncateStyledLine(line(span(` (${this.#selectedIndex + 1}/${this.#filteredItems.length})`, { foreground: "muted" })), context.width, ""));
|
|
11139
11420
|
}
|
|
11140
|
-
return { lines };
|
|
11421
|
+
return { lines: lines2 };
|
|
11141
11422
|
}
|
|
11142
11423
|
handleInput(event) {
|
|
11143
11424
|
if (!this.focused || event.type !== "key") {
|
|
@@ -11171,14 +11452,14 @@ var SelectList = class {
|
|
|
11171
11452
|
const description = item.description === void 0 ? void 0 : normalizeDescription(item.description);
|
|
11172
11453
|
if (description && width > 40) {
|
|
11173
11454
|
const effectivePrimaryWidth = Math.max(1, Math.min(primaryColumnWidth, width - prefixWidth - 4));
|
|
11174
|
-
const label =
|
|
11455
|
+
const label = truncateText(displayValue(item), Math.max(1, effectivePrimaryWidth - PRIMARY_COLUMN_GAP));
|
|
11175
11456
|
const spacing = " ".repeat(Math.max(1, effectivePrimaryWidth - displayWidth5(label)));
|
|
11176
11457
|
const remainingWidth = width - prefixWidth - displayWidth5(label) - displayWidth5(spacing) - 2;
|
|
11177
11458
|
if (remainingWidth > MIN_DESCRIPTION_WIDTH) {
|
|
11178
|
-
return truncateStyledLine(line(prefix, span(label, selected ? { foreground: "accent" } : void 0), span(spacing), span(
|
|
11459
|
+
return truncateStyledLine(line(prefix, span(label, selected ? { foreground: "accent" } : void 0), span(spacing), span(truncateText(description, remainingWidth), { foreground: "muted" })), width, "");
|
|
11179
11460
|
}
|
|
11180
11461
|
}
|
|
11181
|
-
return truncateStyledLine(line(prefix, span(
|
|
11462
|
+
return truncateStyledLine(line(prefix, span(truncateText(displayValue(item), Math.max(1, width - prefixWidth - 2)), selected ? { foreground: "accent" } : void 0)), width, "");
|
|
11182
11463
|
}
|
|
11183
11464
|
#primaryColumnWidth() {
|
|
11184
11465
|
const widest = this.#filteredItems.reduce((value, item) => Math.max(value, displayWidth5(displayValue(item)) + PRIMARY_COLUMN_GAP), 0);
|
|
@@ -11191,7 +11472,7 @@ function displayValue(item) {
|
|
|
11191
11472
|
function normalizeDescription(value) {
|
|
11192
11473
|
return value.replace(/[\r\n]+/gu, " ").trim();
|
|
11193
11474
|
}
|
|
11194
|
-
function
|
|
11475
|
+
function truncateText(value, width) {
|
|
11195
11476
|
return lineText(truncateStyledLine(line(span(value)), width, ""));
|
|
11196
11477
|
}
|
|
11197
11478
|
function displayWidth5(value) {
|
|
@@ -11214,13 +11495,13 @@ var VStack = class {
|
|
|
11214
11495
|
}
|
|
11215
11496
|
}
|
|
11216
11497
|
render(context) {
|
|
11217
|
-
const
|
|
11498
|
+
const lines2 = [];
|
|
11218
11499
|
let cursor;
|
|
11219
11500
|
let rowOffset = 0;
|
|
11220
11501
|
for (const [index, child] of this.#children.entries()) {
|
|
11221
11502
|
if (index > 0) {
|
|
11222
11503
|
const gaps = Array.from({ length: this.#gap }, () => plainLine(""));
|
|
11223
|
-
|
|
11504
|
+
lines2.push(...gaps);
|
|
11224
11505
|
rowOffset += gaps.length;
|
|
11225
11506
|
}
|
|
11226
11507
|
const rendered = child.render(context);
|
|
@@ -11230,11 +11511,11 @@ var VStack = class {
|
|
|
11230
11511
|
column: rendered.cursor.column
|
|
11231
11512
|
};
|
|
11232
11513
|
}
|
|
11233
|
-
|
|
11514
|
+
lines2.push(...rendered.lines);
|
|
11234
11515
|
rowOffset += rendered.lines.length;
|
|
11235
11516
|
}
|
|
11236
11517
|
return {
|
|
11237
|
-
lines,
|
|
11518
|
+
lines: lines2,
|
|
11238
11519
|
...cursor === void 0 ? {} : { cursor }
|
|
11239
11520
|
};
|
|
11240
11521
|
}
|
|
@@ -11480,19 +11761,19 @@ var ViewHost = class {
|
|
|
11480
11761
|
this.#overlays = overlays;
|
|
11481
11762
|
}
|
|
11482
11763
|
openSelection(request) {
|
|
11483
|
-
return new Promise((
|
|
11764
|
+
return new Promise((resolve3) => {
|
|
11484
11765
|
const component = this.#selectionComponent(request);
|
|
11485
|
-
this.#open({ id: request.id, component, resolve:
|
|
11766
|
+
this.#open({ id: request.id, component, resolve: resolve3 }, "selector");
|
|
11486
11767
|
});
|
|
11487
11768
|
}
|
|
11488
11769
|
openPrompt(request) {
|
|
11489
|
-
return new Promise((
|
|
11770
|
+
return new Promise((resolve3) => {
|
|
11490
11771
|
const component = new AuthDialog({
|
|
11491
11772
|
request,
|
|
11492
11773
|
onSubmit: (value) => this.#close(request.id, value),
|
|
11493
11774
|
onCancel: () => this.#close(request.id, null)
|
|
11494
11775
|
});
|
|
11495
|
-
this.#open({ id: request.id, component, resolve:
|
|
11776
|
+
this.#open({ id: request.id, component, resolve: resolve3 }, "modal");
|
|
11496
11777
|
});
|
|
11497
11778
|
}
|
|
11498
11779
|
handleInput(event) {
|
|
@@ -11852,7 +12133,7 @@ var InteractiveTerminalLoop = class {
|
|
|
11852
12133
|
this.#disableModifyOtherKeys();
|
|
11853
12134
|
}
|
|
11854
12135
|
});
|
|
11855
|
-
this.#renderer = new
|
|
12136
|
+
this.#renderer = new MainScreenRenderer(driver);
|
|
11856
12137
|
}
|
|
11857
12138
|
get editor() {
|
|
11858
12139
|
return this.#editor;
|
|
@@ -11876,6 +12157,12 @@ var InteractiveTerminalLoop = class {
|
|
|
11876
12157
|
if (!this.#ui.shouldQueueDisplayEvent(event)) {
|
|
11877
12158
|
return;
|
|
11878
12159
|
}
|
|
12160
|
+
if (isRecord5(event) && event.kind === "tool.output_snapshot" && isRecord5(event.payload)) {
|
|
12161
|
+
const stream = event.payload.stream;
|
|
12162
|
+
const previous = this.#work.findIndex((item) => item.type === "event" && isRecord5(item.event) && item.event.kind === event.kind && item.event.correlation_id === event.correlation_id && isRecord5(item.event.payload) && item.event.payload.stream === stream);
|
|
12163
|
+
if (previous >= 0)
|
|
12164
|
+
this.#work.splice(previous, 1);
|
|
12165
|
+
}
|
|
11879
12166
|
if (this.#work.length >= _a.WORK_QUEUE_LIMIT - 128 && this.#ui.isHighFrequencyDisplayEvent(event)) {
|
|
11880
12167
|
this.#ui.recordDisplayDrop(event);
|
|
11881
12168
|
return;
|
|
@@ -11967,8 +12254,8 @@ var InteractiveTerminalLoop = class {
|
|
|
11967
12254
|
this.#wakeupEnabled = true;
|
|
11968
12255
|
try {
|
|
11969
12256
|
if (!this.#exitRequested) {
|
|
11970
|
-
await new Promise((
|
|
11971
|
-
this.#exitResolve =
|
|
12257
|
+
await new Promise((resolve3) => {
|
|
12258
|
+
this.#exitResolve = resolve3;
|
|
11972
12259
|
});
|
|
11973
12260
|
}
|
|
11974
12261
|
} finally {
|
|
@@ -12153,6 +12440,8 @@ var InteractiveTerminalLoop = class {
|
|
|
12153
12440
|
}
|
|
12154
12441
|
if (action === "editor_newline") {
|
|
12155
12442
|
this.#applyEditorAction(inputAction(InputActionKind.Newline));
|
|
12443
|
+
} else if (action === "delete_to_line_start") {
|
|
12444
|
+
this.#applyEditorAction(inputAction(InputActionKind.DeleteToLineStart));
|
|
12156
12445
|
} else if (action === "steer_now") {
|
|
12157
12446
|
this.#applySteerSubmit();
|
|
12158
12447
|
} else if (action === "submit_follow_up") {
|
|
@@ -12294,18 +12583,18 @@ var InteractiveTerminalLoop = class {
|
|
|
12294
12583
|
if (this.#closed || !this.#running) {
|
|
12295
12584
|
return Promise.resolve(null);
|
|
12296
12585
|
}
|
|
12297
|
-
return new Promise((
|
|
12586
|
+
return new Promise((resolve3) => {
|
|
12298
12587
|
if (type === "open_selection") {
|
|
12299
12588
|
this.#work.push({
|
|
12300
12589
|
type,
|
|
12301
12590
|
request,
|
|
12302
|
-
resolve:
|
|
12591
|
+
resolve: resolve3
|
|
12303
12592
|
});
|
|
12304
12593
|
} else {
|
|
12305
12594
|
this.#work.push({
|
|
12306
12595
|
type,
|
|
12307
12596
|
request,
|
|
12308
|
-
resolve:
|
|
12597
|
+
resolve: resolve3
|
|
12309
12598
|
});
|
|
12310
12599
|
}
|
|
12311
12600
|
this.#scheduleWakeup();
|
|
@@ -12642,11 +12931,11 @@ var TerminalUI = class {
|
|
|
12642
12931
|
effort: this.effort
|
|
12643
12932
|
})
|
|
12644
12933
|
}).renderWithMetadata({ width: contentWidth, theme: this.theme });
|
|
12645
|
-
const
|
|
12934
|
+
const lines2 = compileStyledLines(rendered.lines.map((line2) => truncateStyledLine(line2, contentWidth, "")), contentWidth, this.theme);
|
|
12646
12935
|
return this.#frameBuilder.build({
|
|
12647
12936
|
...options,
|
|
12648
12937
|
compiledMainScreen: {
|
|
12649
|
-
lines,
|
|
12938
|
+
lines: lines2,
|
|
12650
12939
|
cursor: rendered.cursor ?? { row: 0, column: 0 },
|
|
12651
12940
|
activeStart: rendered.activeStart
|
|
12652
12941
|
}
|
|
@@ -12841,7 +13130,17 @@ var PlainEventSink = class {
|
|
|
12841
13130
|
if (text) {
|
|
12842
13131
|
this.outputFn(`[${correlationId || "unknown"}:${stream}] ${text}`);
|
|
12843
13132
|
}
|
|
13133
|
+
} else if (kind === "tool.output_snapshot") {
|
|
13134
|
+
return;
|
|
12844
13135
|
} else if (kind === "tool.finished") {
|
|
13136
|
+
for (const stream of ["stdout", "stderr"]) {
|
|
13137
|
+
if (typeof payload[stream] === "string" && payload[stream] !== "") {
|
|
13138
|
+
this.outputFn(`[${correlationId || "unknown"}:${stream}] ${payload[stream]}`);
|
|
13139
|
+
}
|
|
13140
|
+
}
|
|
13141
|
+
const note = toolOutputNote(payload);
|
|
13142
|
+
if (note)
|
|
13143
|
+
this.outputFn(note);
|
|
12845
13144
|
const status = String(payload.status ?? "completed");
|
|
12846
13145
|
this.outputFn(`[tool:${correlationId || "unknown"}] ${status}`);
|
|
12847
13146
|
} else if (kind === "task.failed") {
|
|
@@ -12866,7 +13165,7 @@ function escapeDebugCapture(data) {
|
|
|
12866
13165
|
return escaped;
|
|
12867
13166
|
}
|
|
12868
13167
|
var StdTerminalDriver = class {
|
|
12869
|
-
#
|
|
13168
|
+
#restoreRawMode = null;
|
|
12870
13169
|
/**
|
|
12871
13170
|
* Debug capture target from LAOHUANG_DEBUG_LOG: when set, every write is
|
|
12872
13171
|
* teed to this file with escape sequences made visible (for diagnosing
|
|
@@ -12884,8 +13183,7 @@ var StdTerminalDriver = class {
|
|
|
12884
13183
|
if (!process.stdin.isTTY) {
|
|
12885
13184
|
return;
|
|
12886
13185
|
}
|
|
12887
|
-
process.stdin
|
|
12888
|
-
this.#rawModeActive = true;
|
|
13186
|
+
this.#restoreRawMode ??= enterTerminalRawMode(process.stdin);
|
|
12889
13187
|
}
|
|
12890
13188
|
write(data) {
|
|
12891
13189
|
if (this.#debugLogPath !== null) {
|
|
@@ -12911,10 +13209,9 @@ var StdTerminalDriver = class {
|
|
|
12911
13209
|
};
|
|
12912
13210
|
}
|
|
12913
13211
|
restore() {
|
|
12914
|
-
|
|
12915
|
-
|
|
12916
|
-
|
|
12917
|
-
}
|
|
13212
|
+
const restore = this.#restoreRawMode;
|
|
13213
|
+
this.#restoreRawMode = null;
|
|
13214
|
+
restore?.();
|
|
12918
13215
|
}
|
|
12919
13216
|
};
|
|
12920
13217
|
|
|
@@ -12922,21 +13219,23 @@ var StdTerminalDriver = class {
|
|
|
12922
13219
|
import { promises as fs } from "node:fs";
|
|
12923
13220
|
import { realpathSync as realpathSync3 } from "node:fs";
|
|
12924
13221
|
import path3 from "node:path";
|
|
13222
|
+
var READ_MAX_BYTES = 50 * 1024;
|
|
13223
|
+
var READ_MAX_LINES = 2e3;
|
|
13224
|
+
var READ_MAX_LINE_CHARACTERS = 2e3;
|
|
12925
13225
|
var DEFAULT_IO = {
|
|
12926
13226
|
readFile: (target) => fs.readFile(target, "utf8"),
|
|
12927
13227
|
writeFile: (target, content) => fs.writeFile(target, content, "utf8")
|
|
12928
13228
|
};
|
|
12929
13229
|
var mutationLocks = /* @__PURE__ */ new Map();
|
|
12930
13230
|
function createFileToolDefinitions(options) {
|
|
12931
|
-
const root = resolveNonStrictSync(
|
|
13231
|
+
const root = resolveNonStrictSync(resolveLocalPath(options.projectRoot, process.cwd(), options.pathOptions));
|
|
12932
13232
|
const io = options.fileIo ?? DEFAULT_IO;
|
|
12933
|
-
const
|
|
12934
|
-
const resolvePath2 = (rawPath) => resolveNonStrict(path3.resolve(root, rawPath));
|
|
13233
|
+
const resolvePath = (rawPath) => resolveNonStrict(resolveLocalPath(rawPath, root, options.pathOptions));
|
|
12935
13234
|
return [
|
|
12936
13235
|
{
|
|
12937
13236
|
spec: {
|
|
12938
13237
|
name: "read",
|
|
12939
|
-
description: "Read a UTF-8 text file.",
|
|
13238
|
+
description: "Read a UTF-8 text file, up to 50 KiB of content, 2000 lines, and 2000 Unicode characters per line. has_more reports omitted content; next_offset resumes at the next unread line, or is null at EOF. truncated_line_numbers identifies shortened lines; use Bash to inspect their omitted content.",
|
|
12940
13239
|
parameters: {
|
|
12941
13240
|
type: "object",
|
|
12942
13241
|
properties: {
|
|
@@ -12951,8 +13250,9 @@ function createFileToolDefinitions(options) {
|
|
|
12951
13250
|
},
|
|
12952
13251
|
limit: {
|
|
12953
13252
|
type: "integer",
|
|
12954
|
-
description: "Maximum number of lines to return.",
|
|
12955
|
-
minimum: 1
|
|
13253
|
+
description: "Maximum number of lines to return (default and maximum: 2000).",
|
|
13254
|
+
minimum: 1,
|
|
13255
|
+
maximum: READ_MAX_LINES
|
|
12956
13256
|
}
|
|
12957
13257
|
},
|
|
12958
13258
|
required: ["path"],
|
|
@@ -12965,26 +13265,57 @@ function createFileToolDefinitions(options) {
|
|
|
12965
13265
|
]
|
|
12966
13266
|
},
|
|
12967
13267
|
execute: async (args, execution) => {
|
|
12968
|
-
const target = await
|
|
13268
|
+
const target = await resolvePath(stringArgument(args, "path"));
|
|
12969
13269
|
const offset = optionalPositiveInteger(args, "offset") ?? 1;
|
|
12970
|
-
const limit = optionalPositiveInteger(args, "limit");
|
|
13270
|
+
const limit = optionalPositiveInteger(args, "limit") ?? READ_MAX_LINES;
|
|
13271
|
+
if (limit > READ_MAX_LINES) {
|
|
13272
|
+
throw new Error(`limit must be less than or equal to ${READ_MAX_LINES}`);
|
|
13273
|
+
}
|
|
12971
13274
|
const content = await io.readFile(target);
|
|
12972
13275
|
if (execution.isCancelled()) {
|
|
12973
13276
|
return cancelledResult(execution);
|
|
12974
13277
|
}
|
|
12975
|
-
const
|
|
12976
|
-
const totalLines =
|
|
13278
|
+
const lines2 = content === "" ? [] : content.split(/(?<=\n)/);
|
|
13279
|
+
const totalLines = lines2.length;
|
|
12977
13280
|
if (offset > Math.max(totalLines, 1)) {
|
|
12978
13281
|
throw new Error(`offset ${offset} is out of range; the file has ${totalLines} lines`);
|
|
12979
13282
|
}
|
|
12980
|
-
const window =
|
|
13283
|
+
const window = [];
|
|
13284
|
+
const truncatedLineNumbers = [];
|
|
13285
|
+
let bytes = 0;
|
|
13286
|
+
for (const line2 of lines2.slice(offset - 1, offset - 1 + limit)) {
|
|
13287
|
+
const ending = line2.endsWith("\r\n") ? "\r\n" : line2.endsWith("\n") ? "\n" : "";
|
|
13288
|
+
const body = line2.slice(0, line2.length - ending.length);
|
|
13289
|
+
let end = 0;
|
|
13290
|
+
let characters = 0;
|
|
13291
|
+
for (const character of body) {
|
|
13292
|
+
if (characters === READ_MAX_LINE_CHARACTERS)
|
|
13293
|
+
break;
|
|
13294
|
+
end += character.length;
|
|
13295
|
+
characters += 1;
|
|
13296
|
+
}
|
|
13297
|
+
const rendered = body.slice(0, end) + ending;
|
|
13298
|
+
const lineBytes = Buffer.byteLength(rendered, "utf8");
|
|
13299
|
+
if (bytes + lineBytes > READ_MAX_BYTES)
|
|
13300
|
+
break;
|
|
13301
|
+
if (end < body.length)
|
|
13302
|
+
truncatedLineNumbers.push(offset + window.length);
|
|
13303
|
+
window.push(rendered);
|
|
13304
|
+
bytes += lineBytes;
|
|
13305
|
+
}
|
|
13306
|
+
const nextOffset = offset - 1 + window.length < totalLines ? offset + window.length : null;
|
|
12981
13307
|
return withTouchedPath({
|
|
12982
13308
|
ok: true,
|
|
12983
|
-
content:
|
|
13309
|
+
content: window.join(""),
|
|
12984
13310
|
offset,
|
|
12985
|
-
limit
|
|
13311
|
+
limit,
|
|
12986
13312
|
total_lines: totalLines,
|
|
12987
|
-
has_more:
|
|
13313
|
+
has_more: nextOffset !== null || truncatedLineNumbers.length > 0,
|
|
13314
|
+
next_offset: nextOffset,
|
|
13315
|
+
truncated_line_numbers: truncatedLineNumbers,
|
|
13316
|
+
...truncatedLineNumbers.length > 0 ? {
|
|
13317
|
+
note: "Listed lines were truncated to 2000 Unicode characters. Use Bash to inspect their omitted content; next_offset only continues to later lines."
|
|
13318
|
+
} : {}
|
|
12988
13319
|
}, target);
|
|
12989
13320
|
}
|
|
12990
13321
|
},
|
|
@@ -13012,7 +13343,7 @@ function createFileToolDefinitions(options) {
|
|
|
13012
13343
|
executionMode: "sequential",
|
|
13013
13344
|
execute: async (args, execution) => {
|
|
13014
13345
|
const rawPath = stringArgument(args, "path");
|
|
13015
|
-
const target = await
|
|
13346
|
+
const target = await resolvePath(rawPath);
|
|
13016
13347
|
return await withFileMutationLock(target, async () => {
|
|
13017
13348
|
if (execution.isCancelled()) {
|
|
13018
13349
|
return cancelledResult(execution);
|
|
@@ -13062,13 +13393,13 @@ function createFileToolDefinitions(options) {
|
|
|
13062
13393
|
]
|
|
13063
13394
|
},
|
|
13064
13395
|
executionMode: "sequential",
|
|
13065
|
-
execute: async (args, execution) => executeEdit(args, execution,
|
|
13396
|
+
execute: async (args, execution) => executeEdit(args, execution, resolvePath, io)
|
|
13066
13397
|
}
|
|
13067
13398
|
];
|
|
13068
13399
|
}
|
|
13069
|
-
async function executeEdit(args, execution,
|
|
13400
|
+
async function executeEdit(args, execution, resolvePath, io) {
|
|
13070
13401
|
const rawPath = stringArgument(args, "path");
|
|
13071
|
-
const target = await
|
|
13402
|
+
const target = await resolvePath(rawPath);
|
|
13072
13403
|
const edits = editsArgument(args);
|
|
13073
13404
|
return await withFileMutationLock(target, async () => {
|
|
13074
13405
|
if (execution.isCancelled()) {
|
|
@@ -13109,17 +13440,17 @@ async function executeEdit(args, execution, resolvePath2, io) {
|
|
|
13109
13440
|
async function withFileMutationLock(key, fn) {
|
|
13110
13441
|
const previous = mutationLocks.get(key) ?? Promise.resolve();
|
|
13111
13442
|
let release;
|
|
13112
|
-
const current = new Promise((
|
|
13113
|
-
release =
|
|
13443
|
+
const current = new Promise((resolve3) => {
|
|
13444
|
+
release = resolve3;
|
|
13114
13445
|
});
|
|
13115
|
-
const
|
|
13116
|
-
mutationLocks.set(key,
|
|
13446
|
+
const tail2 = previous.then(() => current);
|
|
13447
|
+
mutationLocks.set(key, tail2);
|
|
13117
13448
|
await previous;
|
|
13118
13449
|
try {
|
|
13119
13450
|
return await fn();
|
|
13120
13451
|
} finally {
|
|
13121
13452
|
release();
|
|
13122
|
-
if (mutationLocks.get(key) ===
|
|
13453
|
+
if (mutationLocks.get(key) === tail2) {
|
|
13123
13454
|
mutationLocks.delete(key);
|
|
13124
13455
|
}
|
|
13125
13456
|
}
|
|
@@ -13198,14 +13529,232 @@ import { promises as fs2 } from "node:fs";
|
|
|
13198
13529
|
import { realpathSync as realpathSync4 } from "node:fs";
|
|
13199
13530
|
import path4 from "node:path";
|
|
13200
13531
|
|
|
13532
|
+
// ../../packages/shell/bash-local/dist/bash-path.js
|
|
13533
|
+
import { accessSync, constants, statSync as statSync3 } from "node:fs";
|
|
13534
|
+
import { homedir as homedir2 } from "node:os";
|
|
13535
|
+
import { posix as posix2, win32 as win322 } from "node:path";
|
|
13536
|
+
function resolveBashPath(options = {}) {
|
|
13537
|
+
const windows = (options.platform ?? process.platform) === "win32";
|
|
13538
|
+
const paths = windows ? win322 : posix2;
|
|
13539
|
+
const env = options.env ?? process.env;
|
|
13540
|
+
const isExecutable = options.isExecutable ?? ((pathname) => {
|
|
13541
|
+
try {
|
|
13542
|
+
if (!statSync3(pathname).isFile())
|
|
13543
|
+
return false;
|
|
13544
|
+
accessSync(pathname, windows ? constants.F_OK : constants.X_OK);
|
|
13545
|
+
return true;
|
|
13546
|
+
} catch {
|
|
13547
|
+
return false;
|
|
13548
|
+
}
|
|
13549
|
+
});
|
|
13550
|
+
const environment = (name) => {
|
|
13551
|
+
const key = windows ? Object.keys(env).find((entry) => entry.toLowerCase() === name.toLowerCase()) : name;
|
|
13552
|
+
return key === void 0 ? void 0 : env[key];
|
|
13553
|
+
};
|
|
13554
|
+
const isLegacyWsl = (pathname) => windows && /[\\/]windows[\\/](?:system32|sysnative)[\\/]bash\.exe$/i.test(pathname);
|
|
13555
|
+
if (options.shellPath !== void 0) {
|
|
13556
|
+
let explicit = options.shellPath;
|
|
13557
|
+
if (explicit === "~" || explicit.startsWith("~/") || windows && explicit.startsWith("~\\")) {
|
|
13558
|
+
explicit = paths.join(options.homeDirectory ?? homedir2(), explicit.slice(2));
|
|
13559
|
+
}
|
|
13560
|
+
if (!paths.isAbsolute(explicit)) {
|
|
13561
|
+
throw new Error("shell_path must be an absolute Bash path (or start with ~/).");
|
|
13562
|
+
}
|
|
13563
|
+
if (isLegacyWsl(explicit)) {
|
|
13564
|
+
throw new Error("shell_path points to a legacy WSL launcher; select Git for Windows bash.exe instead.");
|
|
13565
|
+
}
|
|
13566
|
+
if (!isExecutable(explicit)) {
|
|
13567
|
+
throw new Error(`Configured Bash is missing or not executable: ${explicit}`);
|
|
13568
|
+
}
|
|
13569
|
+
return explicit;
|
|
13570
|
+
}
|
|
13571
|
+
const candidates = [];
|
|
13572
|
+
if (windows) {
|
|
13573
|
+
for (const name of ["ProgramFiles", "ProgramFiles(x86)"]) {
|
|
13574
|
+
const directory = environment(name);
|
|
13575
|
+
if (directory && paths.isAbsolute(directory)) {
|
|
13576
|
+
candidates.push(paths.join(directory, "Git", "bin", "bash.exe"));
|
|
13577
|
+
}
|
|
13578
|
+
}
|
|
13579
|
+
} else {
|
|
13580
|
+
candidates.push("/bin/bash");
|
|
13581
|
+
}
|
|
13582
|
+
for (const entry of (environment("PATH") ?? "").split(paths.delimiter)) {
|
|
13583
|
+
const directory = windows && entry.startsWith('"') && entry.endsWith('"') ? entry.slice(1, -1) : entry;
|
|
13584
|
+
if (paths.isAbsolute(directory)) {
|
|
13585
|
+
candidates.push(paths.join(directory, windows ? "bash.exe" : "bash"));
|
|
13586
|
+
}
|
|
13587
|
+
}
|
|
13588
|
+
for (const candidate of new Set(candidates)) {
|
|
13589
|
+
if (!isLegacyWsl(candidate) && isExecutable(candidate))
|
|
13590
|
+
return candidate;
|
|
13591
|
+
}
|
|
13592
|
+
throw new Error(windows ? "Bash not found. Install Git for Windows, add its bin directory to PATH, or set shell_path in config.json." : "Bash not found. Install Bash, add its directory to PATH, or set shell_path in config.json.");
|
|
13593
|
+
}
|
|
13594
|
+
|
|
13595
|
+
// ../../packages/shell/bash-local/dist/bash-output.js
|
|
13596
|
+
import { mkdir, mkdtemp, open, readdir, rm, stat, writeFile } from "node:fs/promises";
|
|
13597
|
+
import { homedir as homedir3 } from "node:os";
|
|
13598
|
+
import { join as join6, resolve as resolve2 } from "node:path";
|
|
13599
|
+
var BASH_OUTPUT_MAX_BYTES = 50 * 1024;
|
|
13600
|
+
var BASH_OUTPUT_MAX_LINES = 2e3;
|
|
13601
|
+
var OUTPUT_RETENTION_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
13602
|
+
var OUTPUT_FILE_MAX_BYTES = 64 * 1024 * 1024;
|
|
13603
|
+
function lines(text) {
|
|
13604
|
+
return text === "" ? 0 : text.split("\n").length;
|
|
13605
|
+
}
|
|
13606
|
+
function tail(value, maxBytes, maxLines) {
|
|
13607
|
+
if (maxBytes <= 0 || maxLines <= 0)
|
|
13608
|
+
return { text: "", startMidLine: value.text !== "" || value.startMidLine };
|
|
13609
|
+
const bytes = Buffer.from(value.text);
|
|
13610
|
+
let start = Math.max(0, bytes.length - maxBytes);
|
|
13611
|
+
while (start < bytes.length && (bytes[start] & 192) === 128)
|
|
13612
|
+
start++;
|
|
13613
|
+
let text = bytes.subarray(start).toString("utf8");
|
|
13614
|
+
let startMidLine = start > 0 ? bytes[start - 1] !== 10 : value.startMidLine;
|
|
13615
|
+
const parts = text.split("\n");
|
|
13616
|
+
if (parts.length > maxLines) {
|
|
13617
|
+
text = parts.slice(-maxLines).join("\n");
|
|
13618
|
+
startMidLine = false;
|
|
13619
|
+
}
|
|
13620
|
+
return { text, startMidLine };
|
|
13621
|
+
}
|
|
13622
|
+
var BashOutput = class {
|
|
13623
|
+
maxBytes;
|
|
13624
|
+
maxLines;
|
|
13625
|
+
#directory;
|
|
13626
|
+
#fileLimit;
|
|
13627
|
+
#tails = {
|
|
13628
|
+
stdout: { text: "", startMidLine: false },
|
|
13629
|
+
stderr: { text: "", startMidLine: false }
|
|
13630
|
+
};
|
|
13631
|
+
#totals = { stdout: 0, stderr: 0 };
|
|
13632
|
+
#handles = {};
|
|
13633
|
+
#pending = Promise.resolve();
|
|
13634
|
+
#archiveDirectory = null;
|
|
13635
|
+
#fileBytes = 0;
|
|
13636
|
+
#spillAttempted = false;
|
|
13637
|
+
files = null;
|
|
13638
|
+
fileError = null;
|
|
13639
|
+
revision = 0;
|
|
13640
|
+
constructor(options = {}) {
|
|
13641
|
+
this.maxBytes = options.maxOutputBytes ?? BASH_OUTPUT_MAX_BYTES;
|
|
13642
|
+
this.maxLines = options.maxOutputLines ?? BASH_OUTPUT_MAX_LINES;
|
|
13643
|
+
this.#fileLimit = options.maxOutputFileBytes ?? OUTPUT_FILE_MAX_BYTES;
|
|
13644
|
+
for (const limit of [this.maxBytes, this.maxLines, this.#fileLimit]) {
|
|
13645
|
+
if (!Number.isSafeInteger(limit) || limit < 1)
|
|
13646
|
+
throw new RangeError("Bash output limits must be positive integers");
|
|
13647
|
+
}
|
|
13648
|
+
this.#directory = resolve2(options.outputDirectory ?? join6(homedir3(), ".laohuang", "tool-output"));
|
|
13649
|
+
}
|
|
13650
|
+
append(stream, text) {
|
|
13651
|
+
const next = this.#pending.then(() => this.#append(stream, text));
|
|
13652
|
+
this.#pending = next.catch(() => {
|
|
13653
|
+
});
|
|
13654
|
+
return next;
|
|
13655
|
+
}
|
|
13656
|
+
async #append(stream, text) {
|
|
13657
|
+
if (!text)
|
|
13658
|
+
return;
|
|
13659
|
+
const combined = { ...this.#tails[stream], text: this.#tails[stream].text + text };
|
|
13660
|
+
const other = stream === "stdout" ? "stderr" : "stdout";
|
|
13661
|
+
if (!this.#spillAttempted && (Buffer.byteLength(combined.text) + Buffer.byteLength(this.#tails[other].text) > this.maxBytes || lines(combined.text) + lines(this.#tails[other].text) > this.maxLines)) {
|
|
13662
|
+
this.#spillAttempted = true;
|
|
13663
|
+
await this.#startArchive();
|
|
13664
|
+
for (const name of ["stdout", "stderr"])
|
|
13665
|
+
await this.#write(name, this.#tails[name].text);
|
|
13666
|
+
}
|
|
13667
|
+
await this.#write(stream, text);
|
|
13668
|
+
this.#totals[stream] += Buffer.byteLength(text);
|
|
13669
|
+
this.#tails[stream] = tail(combined, this.maxBytes, this.maxLines);
|
|
13670
|
+
this.revision++;
|
|
13671
|
+
}
|
|
13672
|
+
snapshot() {
|
|
13673
|
+
const reserved = tail(this.#tails.stderr, Math.floor(this.maxBytes / 2), Math.floor(this.maxLines / 2));
|
|
13674
|
+
const stdout = tail(this.#tails.stdout, this.maxBytes - Buffer.byteLength(reserved.text), this.maxLines - lines(reserved.text));
|
|
13675
|
+
const stderr = tail(this.#tails.stderr, this.maxBytes - Buffer.byteLength(stdout.text), this.maxLines - lines(stdout.text));
|
|
13676
|
+
return {
|
|
13677
|
+
stdout: { ...stdout, truncated: Buffer.byteLength(stdout.text) < this.#totals.stdout },
|
|
13678
|
+
stderr: { ...stderr, truncated: Buffer.byteLength(stderr.text) < this.#totals.stderr }
|
|
13679
|
+
};
|
|
13680
|
+
}
|
|
13681
|
+
async #startArchive() {
|
|
13682
|
+
try {
|
|
13683
|
+
await mkdir(this.#directory, { recursive: true, mode: 448 });
|
|
13684
|
+
await this.#removeExpired();
|
|
13685
|
+
this.#archiveDirectory = await mkdtemp(join6(this.#directory, "bash-"));
|
|
13686
|
+
const files = {
|
|
13687
|
+
stdout: join6(this.#archiveDirectory, "stdout.log"),
|
|
13688
|
+
stderr: join6(this.#archiveDirectory, "stderr.log")
|
|
13689
|
+
};
|
|
13690
|
+
for (const stream of ["stdout", "stderr"])
|
|
13691
|
+
this.#handles[stream] = await open(files[stream], "wx", 384);
|
|
13692
|
+
this.files = files;
|
|
13693
|
+
} catch (error) {
|
|
13694
|
+
this.fileError = `Cannot save Bash output: ${String(error)}`;
|
|
13695
|
+
}
|
|
13696
|
+
}
|
|
13697
|
+
async #write(stream, text) {
|
|
13698
|
+
const handle = this.#handles[stream];
|
|
13699
|
+
if (!handle || this.fileError !== null || text === "")
|
|
13700
|
+
return;
|
|
13701
|
+
try {
|
|
13702
|
+
const bytes = Buffer.from(text);
|
|
13703
|
+
const available = Math.max(0, this.#fileLimit - this.#fileBytes);
|
|
13704
|
+
let end = Math.min(bytes.length, available);
|
|
13705
|
+
while (end > 0 && end < bytes.length && (bytes[end] & 192) === 128)
|
|
13706
|
+
end--;
|
|
13707
|
+
if (end > 0)
|
|
13708
|
+
await handle.writeFile(bytes.subarray(0, end));
|
|
13709
|
+
this.#fileBytes += end;
|
|
13710
|
+
if (end < bytes.length)
|
|
13711
|
+
this.fileError = `Bash output file limit reached (${this.#fileLimit} bytes); files contain partial output`;
|
|
13712
|
+
} catch (error) {
|
|
13713
|
+
this.fileError = `Cannot save Bash output: ${String(error)}`;
|
|
13714
|
+
}
|
|
13715
|
+
}
|
|
13716
|
+
async close() {
|
|
13717
|
+
await this.#pending;
|
|
13718
|
+
for (const handle of Object.values(this.#handles)) {
|
|
13719
|
+
try {
|
|
13720
|
+
await handle.close();
|
|
13721
|
+
} catch (error) {
|
|
13722
|
+
this.fileError ??= `Cannot close Bash output: ${String(error)}`;
|
|
13723
|
+
}
|
|
13724
|
+
}
|
|
13725
|
+
if (this.#archiveDirectory !== null) {
|
|
13726
|
+
try {
|
|
13727
|
+
await writeFile(join6(this.#archiveDirectory, "completed"), "", { mode: 384 });
|
|
13728
|
+
} catch {
|
|
13729
|
+
}
|
|
13730
|
+
}
|
|
13731
|
+
}
|
|
13732
|
+
async #removeExpired() {
|
|
13733
|
+
for (const entry of await readdir(this.#directory, { withFileTypes: true })) {
|
|
13734
|
+
if (!entry.isDirectory() || !entry.name.startsWith("bash-"))
|
|
13735
|
+
continue;
|
|
13736
|
+
const directory = join6(this.#directory, entry.name);
|
|
13737
|
+
try {
|
|
13738
|
+
if (Date.now() - (await stat(join6(directory, "completed"))).mtimeMs > OUTPUT_RETENTION_MS) {
|
|
13739
|
+
await rm(directory, { recursive: true, force: true });
|
|
13740
|
+
}
|
|
13741
|
+
} catch {
|
|
13742
|
+
}
|
|
13743
|
+
}
|
|
13744
|
+
}
|
|
13745
|
+
};
|
|
13746
|
+
|
|
13201
13747
|
// ../../packages/shell/bash-local/dist/bash-runner.js
|
|
13202
|
-
import { spawn } from "node:child_process";
|
|
13748
|
+
import { execFile, spawn } from "node:child_process";
|
|
13203
13749
|
import { constants as osConstants } from "node:os";
|
|
13750
|
+
import { win32 as win323 } from "node:path";
|
|
13204
13751
|
import { StringDecoder } from "node:string_decoder";
|
|
13205
|
-
var FLUSH_INTERVAL_MS =
|
|
13206
|
-
var FLUSH_CHARS = 4096;
|
|
13752
|
+
var FLUSH_INTERVAL_MS = 100;
|
|
13207
13753
|
var TERMINATION_GRACE_MS = 2e3;
|
|
13208
13754
|
var WATCHDOG_INTERVAL_MS = 10;
|
|
13755
|
+
var POST_EXIT_IDLE_MS = 100;
|
|
13756
|
+
var TERMINATION_EXIT_GRACE_MS = 1e3;
|
|
13757
|
+
var TASKKILL_TIMEOUT_MS = 5e3;
|
|
13209
13758
|
var MODEL_API_KEY_ENV_NAMES = [
|
|
13210
13759
|
"OPENAI_API_KEY",
|
|
13211
13760
|
"DEEPSEEK_API_KEY",
|
|
@@ -13246,11 +13795,10 @@ var ToolExecutionContext = class {
|
|
|
13246
13795
|
if (sink == null)
|
|
13247
13796
|
return;
|
|
13248
13797
|
if (typeof sink === "function") {
|
|
13249
|
-
sink(kind, payload);
|
|
13250
|
-
return;
|
|
13798
|
+
return sink(kind, payload);
|
|
13251
13799
|
}
|
|
13252
13800
|
if (typeof sink.publish === "function") {
|
|
13253
|
-
sink.publish(kind, {
|
|
13801
|
+
return sink.publish(kind, {
|
|
13254
13802
|
source: "tool",
|
|
13255
13803
|
session_id: this.sessionId ?? "local",
|
|
13256
13804
|
task_id: this.taskId,
|
|
@@ -13268,6 +13816,12 @@ var BashResult = class {
|
|
|
13268
13816
|
error;
|
|
13269
13817
|
durationMs;
|
|
13270
13818
|
truncated;
|
|
13819
|
+
outputComplete;
|
|
13820
|
+
outputFiles;
|
|
13821
|
+
outputFileComplete;
|
|
13822
|
+
outputFileError;
|
|
13823
|
+
stdoutStartMidLine;
|
|
13824
|
+
stderrStartMidLine;
|
|
13271
13825
|
constructor(init) {
|
|
13272
13826
|
this.status = init.status;
|
|
13273
13827
|
this.stdout = init.stdout ?? "";
|
|
@@ -13276,6 +13830,12 @@ var BashResult = class {
|
|
|
13276
13830
|
this.error = init.error ?? null;
|
|
13277
13831
|
this.durationMs = init.durationMs ?? 0;
|
|
13278
13832
|
this.truncated = init.truncated ?? false;
|
|
13833
|
+
this.outputComplete = init.outputComplete ?? true;
|
|
13834
|
+
this.outputFiles = init.outputFiles ?? null;
|
|
13835
|
+
this.outputFileComplete = init.outputFileComplete ?? false;
|
|
13836
|
+
this.outputFileError = init.outputFileError ?? null;
|
|
13837
|
+
this.stdoutStartMidLine = init.stdoutStartMidLine ?? false;
|
|
13838
|
+
this.stderrStartMidLine = init.stderrStartMidLine ?? false;
|
|
13279
13839
|
}
|
|
13280
13840
|
get ok() {
|
|
13281
13841
|
return this.status === "completed" && this.exitCode === 0;
|
|
@@ -13288,66 +13848,21 @@ var BashResult = class {
|
|
|
13288
13848
|
stdout: this.stdout,
|
|
13289
13849
|
stderr: this.stderr,
|
|
13290
13850
|
duration_ms: this.durationMs,
|
|
13291
|
-
truncated: this.truncated
|
|
13851
|
+
truncated: this.truncated,
|
|
13852
|
+
output_complete: this.outputComplete,
|
|
13853
|
+
output_files: this.outputFiles,
|
|
13854
|
+
output_file_complete: this.outputFileComplete,
|
|
13855
|
+
stdout_start_mid_line: this.stdoutStartMidLine,
|
|
13856
|
+
stderr_start_mid_line: this.stderrStartMidLine
|
|
13292
13857
|
};
|
|
13858
|
+
if (this.outputFileError)
|
|
13859
|
+
result["output_file_error"] = this.outputFileError;
|
|
13293
13860
|
if (this.error) {
|
|
13294
13861
|
result["error"] = this.error;
|
|
13295
13862
|
}
|
|
13296
13863
|
return result;
|
|
13297
13864
|
}
|
|
13298
13865
|
};
|
|
13299
|
-
var BoundedOutput = class {
|
|
13300
|
-
limit;
|
|
13301
|
-
headLimit;
|
|
13302
|
-
tailLimit;
|
|
13303
|
-
totalChars = 0;
|
|
13304
|
-
whole = "";
|
|
13305
|
-
head = "";
|
|
13306
|
-
tail = "";
|
|
13307
|
-
isTruncated = false;
|
|
13308
|
-
constructor(limit) {
|
|
13309
|
-
this.limit = Math.max(0, Math.trunc(limit));
|
|
13310
|
-
this.headLimit = Math.trunc(this.limit * 0.4);
|
|
13311
|
-
this.tailLimit = this.limit - this.headLimit;
|
|
13312
|
-
}
|
|
13313
|
-
append(text) {
|
|
13314
|
-
if (!text)
|
|
13315
|
-
return;
|
|
13316
|
-
this.totalChars += text.length;
|
|
13317
|
-
if (this.limit === 0) {
|
|
13318
|
-
this.isTruncated = true;
|
|
13319
|
-
return;
|
|
13320
|
-
}
|
|
13321
|
-
if (!this.isTruncated && this.whole.length + text.length <= this.limit) {
|
|
13322
|
-
this.whole += text;
|
|
13323
|
-
return;
|
|
13324
|
-
}
|
|
13325
|
-
if (!this.isTruncated) {
|
|
13326
|
-
const combined = this.whole + text;
|
|
13327
|
-
this.head = combined.slice(0, this.headLimit);
|
|
13328
|
-
this.tail = this.tailLimit > 0 ? combined.slice(-this.tailLimit) : "";
|
|
13329
|
-
this.whole = "";
|
|
13330
|
-
this.isTruncated = true;
|
|
13331
|
-
return;
|
|
13332
|
-
}
|
|
13333
|
-
if (this.tailLimit > 0) {
|
|
13334
|
-
this.tail = (this.tail + text).slice(-this.tailLimit);
|
|
13335
|
-
}
|
|
13336
|
-
}
|
|
13337
|
-
render() {
|
|
13338
|
-
if (!this.isTruncated)
|
|
13339
|
-
return this.whole;
|
|
13340
|
-
const retained = this.head.length + this.tail.length;
|
|
13341
|
-
const omitted = Math.max(0, this.totalChars - retained);
|
|
13342
|
-
const marker = `
|
|
13343
|
-
...[truncated ${omitted} chars]...
|
|
13344
|
-
`;
|
|
13345
|
-
return this.head + marker + this.tail;
|
|
13346
|
-
}
|
|
13347
|
-
get truncated() {
|
|
13348
|
-
return this.isTruncated;
|
|
13349
|
-
}
|
|
13350
|
-
};
|
|
13351
13866
|
var TerminalSanitizer = class {
|
|
13352
13867
|
state = "normal";
|
|
13353
13868
|
feed(text) {
|
|
@@ -13402,15 +13917,31 @@ var TerminalSanitizer = class {
|
|
|
13402
13917
|
}
|
|
13403
13918
|
};
|
|
13404
13919
|
function sleep(ms) {
|
|
13405
|
-
return new Promise((
|
|
13920
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
13406
13921
|
}
|
|
13407
13922
|
function errnoCode(error) {
|
|
13408
13923
|
return error?.code;
|
|
13409
13924
|
}
|
|
13410
|
-
async function
|
|
13925
|
+
async function terminateProcessTree(child, graceMs = TERMINATION_GRACE_MS) {
|
|
13411
13926
|
const pid = child.pid;
|
|
13412
13927
|
if (pid === void 0)
|
|
13413
13928
|
return;
|
|
13929
|
+
if (process.platform === "win32") {
|
|
13930
|
+
const taskkill = win323.join(process.env.SystemRoot ?? "C:\\Windows", "System32", "taskkill.exe");
|
|
13931
|
+
await new Promise((resolve3, reject) => {
|
|
13932
|
+
execFile(taskkill, ["/F", "/T", "/PID", String(pid)], {
|
|
13933
|
+
windowsHide: true,
|
|
13934
|
+
timeout: TASKKILL_TIMEOUT_MS,
|
|
13935
|
+
killSignal: "SIGKILL"
|
|
13936
|
+
}, (error) => {
|
|
13937
|
+
if (error)
|
|
13938
|
+
reject(new Error(`taskkill failed: ${error.message}`));
|
|
13939
|
+
else
|
|
13940
|
+
resolve3();
|
|
13941
|
+
});
|
|
13942
|
+
});
|
|
13943
|
+
return;
|
|
13944
|
+
}
|
|
13414
13945
|
try {
|
|
13415
13946
|
process.kill(-pid, "SIGTERM");
|
|
13416
13947
|
} catch (error) {
|
|
@@ -13463,25 +13994,55 @@ function toExitCode(code, signal) {
|
|
|
13463
13994
|
async function runBash(command, options) {
|
|
13464
13995
|
const invokedAt = performance.now();
|
|
13465
13996
|
const execution = options.context ?? new ToolExecutionContext();
|
|
13997
|
+
const output = new BashOutput(options);
|
|
13998
|
+
let publicationError = null;
|
|
13999
|
+
const publish = async (kind, payload) => {
|
|
14000
|
+
try {
|
|
14001
|
+
await execution.publish(kind, payload);
|
|
14002
|
+
} catch (error) {
|
|
14003
|
+
publicationError ??= `Bash event publication failed: ${String(error)}`;
|
|
14004
|
+
}
|
|
14005
|
+
};
|
|
14006
|
+
const finish = async (result2) => {
|
|
14007
|
+
await publish("tool.finished", result2.asDict());
|
|
14008
|
+
if (publicationError !== null) {
|
|
14009
|
+
result2.status = "failed";
|
|
14010
|
+
if (!result2.error?.includes(publicationError)) {
|
|
14011
|
+
result2.error = [result2.error, publicationError].filter(Boolean).join("; ");
|
|
14012
|
+
}
|
|
14013
|
+
}
|
|
14014
|
+
return result2;
|
|
14015
|
+
};
|
|
13466
14016
|
if (execution.isCancelled()) {
|
|
13467
14017
|
const result2 = new BashResult({
|
|
13468
14018
|
status: "cancelled",
|
|
13469
14019
|
error: execution.cancellationReason,
|
|
13470
14020
|
durationMs: Math.trunc(performance.now() - invokedAt)
|
|
13471
14021
|
});
|
|
13472
|
-
|
|
13473
|
-
return result2;
|
|
14022
|
+
return await finish(result2);
|
|
13474
14023
|
}
|
|
13475
14024
|
const environment = cleanEnvironment(options.env ?? process.env);
|
|
13476
|
-
|
|
13477
|
-
|
|
13478
|
-
env: environment
|
|
13479
|
-
|
|
13480
|
-
|
|
13481
|
-
|
|
13482
|
-
|
|
13483
|
-
|
|
13484
|
-
|
|
14025
|
+
let child;
|
|
14026
|
+
try {
|
|
14027
|
+
const shellPath = resolveBashPath({ shellPath: options.shellPath, env: environment });
|
|
14028
|
+
child = spawn(shellPath, ["-lc", command], {
|
|
14029
|
+
cwd: options.cwd,
|
|
14030
|
+
env: environment,
|
|
14031
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
14032
|
+
detached: process.platform !== "win32",
|
|
14033
|
+
windowsHide: true
|
|
14034
|
+
});
|
|
14035
|
+
} catch (error) {
|
|
14036
|
+
const result2 = new BashResult({
|
|
14037
|
+
status: "spawn_failed",
|
|
14038
|
+
error: String(error),
|
|
14039
|
+
durationMs: Math.trunc(performance.now() - invokedAt)
|
|
14040
|
+
});
|
|
14041
|
+
return await finish(result2);
|
|
14042
|
+
}
|
|
14043
|
+
const spawnError = await new Promise((resolve3) => {
|
|
14044
|
+
child.once("spawn", () => resolve3(null));
|
|
14045
|
+
child.once("error", (error) => resolve3(error));
|
|
13485
14046
|
});
|
|
13486
14047
|
if (spawnError) {
|
|
13487
14048
|
const result2 = new BashResult({
|
|
@@ -13489,76 +14050,130 @@ async function runBash(command, options) {
|
|
|
13489
14050
|
error: String(spawnError),
|
|
13490
14051
|
durationMs: Math.trunc(performance.now() - invokedAt)
|
|
13491
14052
|
});
|
|
13492
|
-
|
|
13493
|
-
return result2;
|
|
14053
|
+
return await finish(result2);
|
|
13494
14054
|
}
|
|
13495
14055
|
child.on("error", () => {
|
|
13496
14056
|
});
|
|
13497
|
-
|
|
13498
|
-
|
|
13499
|
-
|
|
13500
|
-
|
|
13501
|
-
|
|
13502
|
-
|
|
13503
|
-
|
|
14057
|
+
const started = publish("tool.started", { name: "bash", arguments: { command } });
|
|
14058
|
+
let publishing = null;
|
|
14059
|
+
let publishedRevision = 0;
|
|
14060
|
+
let exited = false;
|
|
14061
|
+
let lastOutputAt = performance.now();
|
|
14062
|
+
let outputIncomplete = false;
|
|
14063
|
+
const ingesting = { stdout: false, stderr: false };
|
|
14064
|
+
const closeOutput = (force = false) => {
|
|
14065
|
+
for (const stream of ["stdout", "stderr"]) {
|
|
14066
|
+
const pipe = child[stream];
|
|
14067
|
+
if (!force && (ingesting[stream] || (pipe?.readableLength ?? 0) > 0))
|
|
14068
|
+
continue;
|
|
14069
|
+
if (pipe && !pipe.readableEnded && !pipe.destroyed) {
|
|
14070
|
+
outputIncomplete = true;
|
|
14071
|
+
pipe.destroy();
|
|
14072
|
+
}
|
|
14073
|
+
}
|
|
13504
14074
|
};
|
|
13505
|
-
const
|
|
13506
|
-
|
|
13507
|
-
const flush = (stream) => {
|
|
13508
|
-
const text = pending[stream];
|
|
13509
|
-
if (!text)
|
|
14075
|
+
const flush = () => {
|
|
14076
|
+
if (publishing !== null || publicationError !== null || publishedRevision === output.revision)
|
|
13510
14077
|
return;
|
|
13511
|
-
|
|
13512
|
-
|
|
13513
|
-
|
|
13514
|
-
|
|
13515
|
-
|
|
13516
|
-
stream,
|
|
13517
|
-
|
|
13518
|
-
|
|
14078
|
+
const snapshot2 = output.snapshot();
|
|
14079
|
+
publishedRevision = output.revision;
|
|
14080
|
+
const revision = publishedRevision;
|
|
14081
|
+
publishing = (async () => {
|
|
14082
|
+
await started;
|
|
14083
|
+
for (const stream of ["stdout", "stderr"]) {
|
|
14084
|
+
if (publicationError !== null)
|
|
14085
|
+
break;
|
|
14086
|
+
await publish("tool.output_snapshot", {
|
|
14087
|
+
name: "bash",
|
|
14088
|
+
stream,
|
|
14089
|
+
text: snapshot2[stream].text,
|
|
14090
|
+
stream_sequence: revision,
|
|
14091
|
+
truncated: snapshot2[stream].truncated,
|
|
14092
|
+
start_mid_line: snapshot2[stream].startMidLine
|
|
14093
|
+
});
|
|
14094
|
+
}
|
|
14095
|
+
})().finally(() => {
|
|
14096
|
+
publishing = null;
|
|
13519
14097
|
});
|
|
13520
14098
|
};
|
|
13521
14099
|
const readPipe = async (stream, pipe) => {
|
|
13522
14100
|
const decoder = new StringDecoder("utf8");
|
|
13523
14101
|
const sanitizer = new TerminalSanitizer();
|
|
13524
|
-
const ingest = (text) => {
|
|
13525
|
-
if (!text)
|
|
13526
|
-
return;
|
|
13527
|
-
pending[stream] += text;
|
|
13528
|
-
if (pending[stream].length >= FLUSH_CHARS)
|
|
13529
|
-
flush(stream);
|
|
13530
|
-
};
|
|
13531
14102
|
try {
|
|
13532
14103
|
for await (const chunk of pipe) {
|
|
13533
|
-
|
|
14104
|
+
lastOutputAt = performance.now();
|
|
14105
|
+
ingesting[stream] = true;
|
|
14106
|
+
try {
|
|
14107
|
+
await output.append(stream, sanitizer.feed(decoder.write(chunk)));
|
|
14108
|
+
} finally {
|
|
14109
|
+
ingesting[stream] = false;
|
|
14110
|
+
lastOutputAt = performance.now();
|
|
14111
|
+
}
|
|
13534
14112
|
}
|
|
13535
|
-
ingest(sanitizer.feed(decoder.end()));
|
|
13536
14113
|
} catch {
|
|
14114
|
+
outputIncomplete = true;
|
|
14115
|
+
} finally {
|
|
14116
|
+
await output.append(stream, sanitizer.feed(decoder.end()));
|
|
13537
14117
|
}
|
|
13538
14118
|
};
|
|
13539
14119
|
const stdoutDone = readPipe("stdout", child.stdout);
|
|
13540
14120
|
const stderrDone = readPipe("stderr", child.stderr);
|
|
13541
|
-
|
|
13542
|
-
|
|
14121
|
+
let resolveExit;
|
|
14122
|
+
const exitInfo = new Promise((resolve3) => {
|
|
14123
|
+
resolveExit = resolve3;
|
|
13543
14124
|
});
|
|
14125
|
+
const onExit = (code2, signal2) => {
|
|
14126
|
+
exited = true;
|
|
14127
|
+
lastOutputAt = performance.now();
|
|
14128
|
+
resolveExit({ code: code2, signal: signal2 });
|
|
14129
|
+
};
|
|
14130
|
+
child.once("exit", onExit);
|
|
13544
14131
|
let terminalStatus = null;
|
|
13545
14132
|
const startedAt = performance.now();
|
|
13546
14133
|
let lastFlush = startedAt;
|
|
13547
14134
|
const timeoutMs = options.timeout * 1e3;
|
|
14135
|
+
let termination = null;
|
|
14136
|
+
let terminationCompletedAt = null;
|
|
14137
|
+
let cleanupError = null;
|
|
14138
|
+
const terminate = () => {
|
|
14139
|
+
if (termination !== null)
|
|
14140
|
+
return;
|
|
14141
|
+
termination = terminateProcessTree(child).catch((error) => {
|
|
14142
|
+
cleanupError = error instanceof Error ? error.message : String(error);
|
|
14143
|
+
try {
|
|
14144
|
+
child.kill("SIGKILL");
|
|
14145
|
+
} catch {
|
|
14146
|
+
}
|
|
14147
|
+
}).finally(() => {
|
|
14148
|
+
terminationCompletedAt = performance.now();
|
|
14149
|
+
});
|
|
14150
|
+
};
|
|
13548
14151
|
const watchdog = setInterval(() => {
|
|
13549
14152
|
const now = performance.now();
|
|
13550
14153
|
if (terminalStatus === null) {
|
|
13551
|
-
if (
|
|
14154
|
+
if (publicationError !== null) {
|
|
14155
|
+
terminalStatus = "failed";
|
|
14156
|
+
terminate();
|
|
14157
|
+
} else if (execution.isCancelled()) {
|
|
13552
14158
|
terminalStatus = "cancelled";
|
|
13553
|
-
|
|
14159
|
+
terminate();
|
|
13554
14160
|
} else if (options.timeout >= 0 && now - startedAt >= timeoutMs) {
|
|
13555
14161
|
terminalStatus = "timed_out";
|
|
13556
|
-
|
|
14162
|
+
terminate();
|
|
14163
|
+
}
|
|
14164
|
+
}
|
|
14165
|
+
if (exited && now - lastOutputAt >= POST_EXIT_IDLE_MS)
|
|
14166
|
+
closeOutput();
|
|
14167
|
+
if (terminationCompletedAt !== null && now - terminationCompletedAt >= TERMINATION_EXIT_GRACE_MS) {
|
|
14168
|
+
closeOutput(true);
|
|
14169
|
+
if (!exited) {
|
|
14170
|
+
cleanupError ??= "Bash did not exit after process termination";
|
|
14171
|
+
child.unref();
|
|
14172
|
+
resolveExit({ code: null, signal: null });
|
|
13557
14173
|
}
|
|
13558
14174
|
}
|
|
13559
14175
|
if (now - lastFlush >= FLUSH_INTERVAL_MS) {
|
|
13560
|
-
flush(
|
|
13561
|
-
flush("stderr");
|
|
14176
|
+
flush();
|
|
13562
14177
|
lastFlush = now;
|
|
13563
14178
|
}
|
|
13564
14179
|
}, WATCHDOG_INTERVAL_MS);
|
|
@@ -13567,18 +14182,21 @@ async function runBash(command, options) {
|
|
|
13567
14182
|
await Promise.all([stdoutDone, stderrDone, exitInfo]);
|
|
13568
14183
|
} finally {
|
|
13569
14184
|
clearInterval(watchdog);
|
|
13570
|
-
|
|
13571
|
-
|
|
13572
|
-
|
|
13573
|
-
}
|
|
13574
|
-
|
|
13575
|
-
|
|
14185
|
+
child.removeListener("exit", onExit);
|
|
14186
|
+
await termination;
|
|
14187
|
+
await output.close();
|
|
14188
|
+
}
|
|
14189
|
+
await started;
|
|
14190
|
+
await publishing;
|
|
14191
|
+
flush();
|
|
14192
|
+
await publishing;
|
|
13576
14193
|
const { code, signal } = await exitInfo;
|
|
13577
14194
|
const exitCode = toExitCode(code, signal);
|
|
13578
|
-
const
|
|
13579
|
-
const
|
|
14195
|
+
const snapshot = output.snapshot();
|
|
14196
|
+
const stdout = snapshot.stdout.text;
|
|
14197
|
+
const stderr = snapshot.stderr.text;
|
|
13580
14198
|
const durationMs = Math.trunc(performance.now() - invokedAt);
|
|
13581
|
-
const truncated =
|
|
14199
|
+
const truncated = snapshot.stdout.truncated || snapshot.stderr.truncated;
|
|
13582
14200
|
let result;
|
|
13583
14201
|
if (terminalStatus === "cancelled") {
|
|
13584
14202
|
result = new BashResult({
|
|
@@ -13620,20 +14238,35 @@ async function runBash(command, options) {
|
|
|
13620
14238
|
truncated
|
|
13621
14239
|
});
|
|
13622
14240
|
}
|
|
13623
|
-
|
|
13624
|
-
|
|
14241
|
+
if (cleanupError !== null) {
|
|
14242
|
+
result.error = `${result.error ?? "Bash execution failed"}; Process cleanup failed: ${cleanupError}`;
|
|
14243
|
+
}
|
|
14244
|
+
result.outputComplete = !outputIncomplete;
|
|
14245
|
+
result.outputFiles = output.files;
|
|
14246
|
+
result.outputFileComplete = output.files !== null && output.fileError === null && !outputIncomplete;
|
|
14247
|
+
result.outputFileError = output.fileError;
|
|
14248
|
+
result.stdoutStartMidLine = snapshot.stdout.startMidLine;
|
|
14249
|
+
result.stderrStartMidLine = snapshot.stderr.startMidLine;
|
|
14250
|
+
if (publicationError !== null) {
|
|
14251
|
+
result.status = "failed";
|
|
14252
|
+
result.error = publicationError + (cleanupError === null ? "" : `; Process cleanup failed: ${cleanupError}`);
|
|
14253
|
+
}
|
|
14254
|
+
return await finish(result);
|
|
13625
14255
|
}
|
|
13626
14256
|
|
|
13627
14257
|
// ../../packages/shell/tool-bash/dist/tool-bash.js
|
|
13628
14258
|
function createBashToolDefinition(options) {
|
|
13629
|
-
const
|
|
14259
|
+
const pathOptions = {
|
|
14260
|
+
env: options.env ?? process.env,
|
|
14261
|
+
shellPath: () => resolveBashPath({ shellPath: options.shellPath, env: options.env })
|
|
14262
|
+
};
|
|
14263
|
+
const root = resolveNonStrictSync2(resolveLocalPath(options.projectRoot, process.cwd(), pathOptions));
|
|
13630
14264
|
const bashTimeoutSeconds = options.bashTimeoutSeconds ?? 120;
|
|
13631
|
-
const maxOutputChars = options.maxOutputChars ?? 2e4;
|
|
13632
14265
|
const runBash2 = options.runBash ?? defaultRunBash;
|
|
13633
14266
|
return {
|
|
13634
14267
|
spec: {
|
|
13635
14268
|
name: "bash",
|
|
13636
|
-
description: "Run a Bash command.",
|
|
14269
|
+
description: "Run a Bash command. Returns stdout and stderr, limited together to the latest 2000 lines or 50KiB by default. When truncated, output_files contains saved output paths; check output_file_complete before assuming the files are complete.",
|
|
13637
14270
|
parameters: {
|
|
13638
14271
|
type: "object",
|
|
13639
14272
|
properties: {
|
|
@@ -13659,39 +14292,52 @@ function createBashToolDefinition(options) {
|
|
|
13659
14292
|
"Supply a concise description of what the command does.",
|
|
13660
14293
|
"Use workdir instead of cd.",
|
|
13661
14294
|
"Each call runs in an independent shell; state does not persist between calls.",
|
|
13662
|
-
"On a non-zero exit, inspect the output before retrying."
|
|
14295
|
+
"On a non-zero exit, inspect the output before retrying.",
|
|
14296
|
+
"When output is truncated, use read or a targeted Bash search on output_files instead of repeating the command. Saved output expires after 7 days; files are capped at 64MiB per call."
|
|
13663
14297
|
]
|
|
13664
14298
|
},
|
|
13665
14299
|
execute: async (args, execution) => {
|
|
13666
14300
|
const command = stringArgument(args, "command");
|
|
13667
14301
|
stringArgument(args, "description");
|
|
13668
14302
|
const workdir = args["workdir"];
|
|
13669
|
-
const cwd = workdir === void 0 ? root : await
|
|
14303
|
+
const cwd = workdir === void 0 ? root : await resolveNonStrict2(resolveLocalPath(stringArgument(args, "workdir"), root, pathOptions));
|
|
13670
14304
|
const timeoutMs = optionalPositiveInteger(args, "timeoutMs");
|
|
13671
14305
|
return await runBash2(command, {
|
|
13672
14306
|
cwd,
|
|
14307
|
+
shellPath: options.shellPath,
|
|
13673
14308
|
timeoutSeconds: timeoutMs === void 0 ? bashTimeoutSeconds : timeoutMs / 1e3,
|
|
13674
|
-
|
|
14309
|
+
maxOutputBytes: options.maxOutputBytes,
|
|
14310
|
+
maxOutputLines: options.maxOutputLines,
|
|
14311
|
+
outputDirectory: options.outputDirectory,
|
|
14312
|
+
maxOutputFileBytes: options.maxOutputFileBytes,
|
|
13675
14313
|
context: execution,
|
|
13676
|
-
env: process.env
|
|
14314
|
+
env: options.env ?? process.env
|
|
13677
14315
|
});
|
|
13678
14316
|
}
|
|
13679
14317
|
};
|
|
13680
14318
|
}
|
|
13681
14319
|
async function defaultRunBash(command, options) {
|
|
13682
|
-
const
|
|
14320
|
+
const execution = options.context;
|
|
14321
|
+
const context = {
|
|
14322
|
+
isCancelled: () => execution.isCancelled(),
|
|
14323
|
+
get cancellationReason() {
|
|
14324
|
+
return execution.cancellationReason;
|
|
14325
|
+
},
|
|
14326
|
+
publish: (kind, payload) => execution.publish?.(kind, payload)
|
|
14327
|
+
};
|
|
13683
14328
|
const result = await runBash(command, {
|
|
13684
14329
|
cwd: options.cwd,
|
|
14330
|
+
shellPath: options.shellPath,
|
|
13685
14331
|
timeout: options.timeoutSeconds,
|
|
13686
|
-
|
|
14332
|
+
maxOutputBytes: options.maxOutputBytes,
|
|
14333
|
+
maxOutputLines: options.maxOutputLines,
|
|
14334
|
+
outputDirectory: options.outputDirectory,
|
|
14335
|
+
maxOutputFileBytes: options.maxOutputFileBytes,
|
|
13687
14336
|
context,
|
|
13688
14337
|
env: options.env
|
|
13689
14338
|
});
|
|
13690
14339
|
return result.asDict();
|
|
13691
14340
|
}
|
|
13692
|
-
async function resolvePath(root, rawPath) {
|
|
13693
|
-
return await resolveNonStrict2(path4.resolve(root, rawPath));
|
|
13694
|
-
}
|
|
13695
14341
|
async function resolveNonStrict2(pathname) {
|
|
13696
14342
|
const missing = [];
|
|
13697
14343
|
let current = pathname;
|
|
@@ -13963,23 +14609,13 @@ function sessionDisplayTitle(session) {
|
|
|
13963
14609
|
return lastUserText2 === "" ? "Untitled session" : lastUserText2;
|
|
13964
14610
|
}
|
|
13965
14611
|
function sessionDisplayDescription(session, options) {
|
|
13966
|
-
const displayPath =
|
|
14612
|
+
const displayPath = displayLocalPath(session.cwd ?? session.projectRoot ?? "", options.homeDirectory);
|
|
13967
14613
|
const updated = relativeTimeLabel(session.updatedAt, options.now);
|
|
13968
14614
|
return displayPath === "" ? updated : `${updated} ${displayPath}`;
|
|
13969
14615
|
}
|
|
13970
14616
|
function cleanSingleLine(value) {
|
|
13971
14617
|
return value?.replace(/\s+/g, " ").trim() ?? "";
|
|
13972
14618
|
}
|
|
13973
|
-
function displayPathFor(path5, homeDirectory) {
|
|
13974
|
-
if (path5 === "" || homeDirectory === null || homeDirectory === "") {
|
|
13975
|
-
return path5;
|
|
13976
|
-
}
|
|
13977
|
-
const home = homeDirectory.endsWith("/") ? homeDirectory.slice(0, -1) : homeDirectory;
|
|
13978
|
-
if (path5 === home) {
|
|
13979
|
-
return "~";
|
|
13980
|
-
}
|
|
13981
|
-
return path5.startsWith(`${home}/`) ? `~/${path5.slice(home.length + 1)}` : path5;
|
|
13982
|
-
}
|
|
13983
14619
|
function relativeTimeLabel(updatedAt, now) {
|
|
13984
14620
|
const updated = new Date(updatedAt);
|
|
13985
14621
|
const timestamp = updated.getTime();
|
|
@@ -15595,7 +16231,7 @@ function defaultSecretInputFn(prompt) {
|
|
|
15595
16231
|
}
|
|
15596
16232
|
const byte = Buffer.alloc(1);
|
|
15597
16233
|
let answer = "";
|
|
15598
|
-
process.stdin
|
|
16234
|
+
const restoreRawMode = enterTerminalRawMode(process.stdin);
|
|
15599
16235
|
try {
|
|
15600
16236
|
for (; ; ) {
|
|
15601
16237
|
const bytesRead = readSync2(0, byte, 0, 1, null);
|
|
@@ -15621,7 +16257,7 @@ function defaultSecretInputFn(prompt) {
|
|
|
15621
16257
|
answer += byte.toString("utf8", 0, 1);
|
|
15622
16258
|
}
|
|
15623
16259
|
} finally {
|
|
15624
|
-
|
|
16260
|
+
restoreRawMode();
|
|
15625
16261
|
}
|
|
15626
16262
|
process.stderr.write("\n");
|
|
15627
16263
|
return answer;
|
|
@@ -15790,8 +16426,8 @@ function startCoordinator(session, commandHandler, presenter, suggestCommand) {
|
|
|
15790
16426
|
const done = (async () => {
|
|
15791
16427
|
for (; ; ) {
|
|
15792
16428
|
if (queue.length === 0) {
|
|
15793
|
-
await new Promise((
|
|
15794
|
-
wake =
|
|
16429
|
+
await new Promise((resolve3) => {
|
|
16430
|
+
wake = resolve3;
|
|
15795
16431
|
});
|
|
15796
16432
|
wake = null;
|
|
15797
16433
|
}
|
|
@@ -15837,14 +16473,14 @@ function startCoordinator(session, commandHandler, presenter, suggestCommand) {
|
|
|
15837
16473
|
};
|
|
15838
16474
|
}
|
|
15839
16475
|
function delay(ms) {
|
|
15840
|
-
return new Promise((
|
|
15841
|
-
setTimeout(
|
|
16476
|
+
return new Promise((resolve3) => {
|
|
16477
|
+
setTimeout(resolve3, ms);
|
|
15842
16478
|
});
|
|
15843
16479
|
}
|
|
15844
16480
|
async function settlesWithin(promise, ms) {
|
|
15845
16481
|
let timer;
|
|
15846
|
-
const timeout = new Promise((
|
|
15847
|
-
timer = setTimeout(() =>
|
|
16482
|
+
const timeout = new Promise((resolve3) => {
|
|
16483
|
+
timer = setTimeout(() => resolve3(false), ms);
|
|
15848
16484
|
});
|
|
15849
16485
|
const settled = promise.then(
|
|
15850
16486
|
() => true,
|
|
@@ -16070,10 +16706,10 @@ async function main(argv, options = {}) {
|
|
|
16070
16706
|
const configPath = options.configPath ?? defaultConfigPath(environ);
|
|
16071
16707
|
const manager = new ConfigManager(configPath);
|
|
16072
16708
|
const credentials = new CredentialStore(
|
|
16073
|
-
options.credentialsPath ??
|
|
16709
|
+
options.credentialsPath ?? join7(dirname4(configPath), "credentials.json")
|
|
16074
16710
|
);
|
|
16075
16711
|
const modelCatalogStore = new ModelCatalogStore(
|
|
16076
|
-
options.modelsPath ??
|
|
16712
|
+
options.modelsPath ?? join7(dirname4(configPath), "models.json")
|
|
16077
16713
|
);
|
|
16078
16714
|
const modelPlatform = await createPiAiPlatform({
|
|
16079
16715
|
credentials,
|
|
@@ -16186,12 +16822,20 @@ async function main(argv, options = {}) {
|
|
|
16186
16822
|
outputFn(`Verified: ${provider.verified ? "yes" : "no"}`);
|
|
16187
16823
|
outputFn(`Configuration: ${configPath}`);
|
|
16188
16824
|
outputFn(`Node: ${process.version}`);
|
|
16189
|
-
|
|
16190
|
-
|
|
16825
|
+
let bashAvailable = true;
|
|
16826
|
+
try {
|
|
16827
|
+
outputFn(`Bash: ${resolveBashPath({ shellPath: manager.getShellPath(), env: environ })}`);
|
|
16828
|
+
} catch (error) {
|
|
16829
|
+
bashAvailable = false;
|
|
16830
|
+
outputFn(`Bash: ${errorMessage11(error)}`);
|
|
16831
|
+
}
|
|
16832
|
+
return provider !== void 0 && auth.configured && refreshOk && model !== void 0 && bashAvailable ? 0 : 1;
|
|
16191
16833
|
}
|
|
16192
16834
|
let config;
|
|
16835
|
+
let shellPath;
|
|
16193
16836
|
try {
|
|
16194
|
-
|
|
16837
|
+
shellPath = manager.getShellPath();
|
|
16838
|
+
if (existsSync8(configPath)) {
|
|
16195
16839
|
config = manager.resolve({
|
|
16196
16840
|
environ,
|
|
16197
16841
|
profile: args.profile,
|
|
@@ -16273,8 +16917,11 @@ async function main(argv, options = {}) {
|
|
|
16273
16917
|
terminalUi.state.model = config.model;
|
|
16274
16918
|
}
|
|
16275
16919
|
const toolRegistry = new ToolRegistry([
|
|
16276
|
-
...createFileToolDefinitions({ projectRoot
|
|
16277
|
-
|
|
16920
|
+
...createFileToolDefinitions({ projectRoot, pathOptions: {
|
|
16921
|
+
env: environ,
|
|
16922
|
+
shellPath: () => resolveBashPath({ shellPath, env: environ })
|
|
16923
|
+
} }),
|
|
16924
|
+
createBashToolDefinition({ projectRoot, shellPath, env: environ })
|
|
16278
16925
|
]);
|
|
16279
16926
|
const activeConversationHistory = {
|
|
16280
16927
|
appendUser: (input) => {
|
|
@@ -16503,7 +17150,7 @@ async function main(argv, options = {}) {
|
|
|
16503
17150
|
sessionController,
|
|
16504
17151
|
onComposerText: (text) => terminalUi?.setComposerText(text),
|
|
16505
17152
|
onSessionChanged: refreshSessionView,
|
|
16506
|
-
homeDirectory: environ
|
|
17153
|
+
homeDirectory: getHomeDirectory({ env: environ }),
|
|
16507
17154
|
onModelSelected: (selection) => {
|
|
16508
17155
|
semanticClassifier.configure({
|
|
16509
17156
|
provider: selection.config.provider,
|
|
@@ -16596,7 +17243,7 @@ async function main(argv, options = {}) {
|
|
|
16596
17243
|
return cleanShutdown ? 0 : 1;
|
|
16597
17244
|
}
|
|
16598
17245
|
function defaultSessionsRoot(environ) {
|
|
16599
|
-
return
|
|
17246
|
+
return join7(getHomeDirectory({ env: environ }), ".laohuang", "sessions");
|
|
16600
17247
|
}
|
|
16601
17248
|
function defaultContextPolicy() {
|
|
16602
17249
|
return {
|