@cydm/pie 2.7.11 → 2.7.12
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/builtin/extensions/ask-user/index.js +3 -3
- package/dist/builtin/extensions/plan-mode/index.js +37 -12
- package/dist/builtin/extensions/subagent/index.js +10 -4
- package/dist/builtin/extensions/todo/index.js +3 -3
- package/dist/chunks/{chunk-XVF6V6Q5.js → chunk-2NBUFVUQ.js} +48 -2
- package/dist/chunks/{chunk-XIRBNP2S.js → chunk-AFPRX5XI.js} +684 -263
- package/dist/chunks/{chunk-3VEIP2VY.js → chunk-EN47TIBG.js} +46 -21
- package/dist/chunks/{chunk-3NFKVBGY.js → chunk-YI3CSQGD.js} +156 -2
- package/dist/chunks/{src-2RCV3I3P.js → src-XDNJ3PHL.js} +2 -2
- package/dist/chunks/{test-stream-Y2S3H7DK.js → test-stream-LUUGOJMP.js} +1 -1
- package/dist/cli.js +1254 -490
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
|
+
CLI_RETRY_MAX_RETRIES,
|
|
4
5
|
VERSION,
|
|
6
|
+
classifyCliFailure,
|
|
5
7
|
cleanupBashOutputArtifacts,
|
|
6
8
|
createBashTool,
|
|
7
9
|
createCliHostCapabilities,
|
|
10
|
+
createCliRetryPolicy,
|
|
8
11
|
createCliWebResearchHealthStore,
|
|
9
12
|
createTraceTransportSink,
|
|
10
13
|
createTransportDiagnosticsStreamFn,
|
|
@@ -20,11 +23,13 @@ import {
|
|
|
20
23
|
getSessionsDir,
|
|
21
24
|
getSettingsPath,
|
|
22
25
|
getThemesDir,
|
|
26
|
+
isCliContextOverflowError,
|
|
27
|
+
isCliRetryableError,
|
|
23
28
|
logTransportLifecycle,
|
|
24
29
|
migrateConfigFromAgentDir,
|
|
25
30
|
setYoloGrantListener,
|
|
26
31
|
truncateHeadTail
|
|
27
|
-
} from "./chunks/chunk-
|
|
32
|
+
} from "./chunks/chunk-YI3CSQGD.js";
|
|
28
33
|
import {
|
|
29
34
|
resolveCliProjectRoot
|
|
30
35
|
} from "./chunks/chunk-WLFOBECN.js";
|
|
@@ -89,17 +94,15 @@ import {
|
|
|
89
94
|
shouldPreserveExecutionStateForUserText,
|
|
90
95
|
supersedeExecutionState,
|
|
91
96
|
verifyPreparedCompactionCommit
|
|
92
|
-
} from "./chunks/chunk-
|
|
93
|
-
import "./chunks/chunk-
|
|
97
|
+
} from "./chunks/chunk-AFPRX5XI.js";
|
|
98
|
+
import "./chunks/chunk-2NBUFVUQ.js";
|
|
94
99
|
import {
|
|
95
100
|
Deref,
|
|
96
|
-
EMPTY_ASSISTANT_CONTENT_ERROR,
|
|
97
101
|
Errors,
|
|
98
102
|
ExtendsUndefinedCheck,
|
|
99
103
|
HasTransform,
|
|
100
104
|
Hash,
|
|
101
105
|
MODEL_CLASS_FALLBACK_ORDER,
|
|
102
|
-
OPENAI_COMPAT_PROTOCOL_ERROR_CODE,
|
|
103
106
|
TransformDecode,
|
|
104
107
|
TransformDecodeCheckError,
|
|
105
108
|
TransformEncode,
|
|
@@ -115,7 +118,7 @@ import {
|
|
|
115
118
|
sortToolModelCandidatesByCapability,
|
|
116
119
|
streamSimple,
|
|
117
120
|
type_exports
|
|
118
|
-
} from "./chunks/chunk-
|
|
121
|
+
} from "./chunks/chunk-EN47TIBG.js";
|
|
119
122
|
import {
|
|
120
123
|
IsArray,
|
|
121
124
|
IsBigInt,
|
|
@@ -1937,7 +1940,7 @@ var require_core = __commonJS({
|
|
|
1937
1940
|
return match && match.index === 0;
|
|
1938
1941
|
}
|
|
1939
1942
|
var BACKREF_RE = /\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;
|
|
1940
|
-
function
|
|
1943
|
+
function join24(regexps, separator = "|") {
|
|
1941
1944
|
let numCaptures = 0;
|
|
1942
1945
|
return regexps.map((regex) => {
|
|
1943
1946
|
numCaptures += 1;
|
|
@@ -2241,7 +2244,7 @@ var require_core = __commonJS({
|
|
|
2241
2244
|
this.exec = () => null;
|
|
2242
2245
|
}
|
|
2243
2246
|
const terminators = this.regexes.map((el) => el[1]);
|
|
2244
|
-
this.matcherRe = langRe(
|
|
2247
|
+
this.matcherRe = langRe(join24(terminators), true);
|
|
2245
2248
|
this.lastIndex = 0;
|
|
2246
2249
|
}
|
|
2247
2250
|
/** @param {string} s */
|
|
@@ -58062,7 +58065,9 @@ var SYMBOL_KEYS = /* @__PURE__ */ new Set([
|
|
|
58062
58065
|
var MODIFIERS = {
|
|
58063
58066
|
shift: 1,
|
|
58064
58067
|
alt: 2,
|
|
58065
|
-
ctrl: 4
|
|
58068
|
+
ctrl: 4,
|
|
58069
|
+
/** Kitty keyboard protocol bit 8: Super (macOS Command / Windows/Linux Super). */
|
|
58070
|
+
super: 8
|
|
58066
58071
|
};
|
|
58067
58072
|
var LOCK_MASK = 64 + 128;
|
|
58068
58073
|
var CODEPOINTS = {
|
|
@@ -58256,7 +58261,8 @@ function parseKeyId(keyId) {
|
|
|
58256
58261
|
key,
|
|
58257
58262
|
ctrl: parts.includes("ctrl"),
|
|
58258
58263
|
shift: parts.includes("shift"),
|
|
58259
|
-
alt: parts.includes("alt")
|
|
58264
|
+
alt: parts.includes("alt"),
|
|
58265
|
+
super: parts.includes("super") || parts.includes("cmd") || parts.includes("meta")
|
|
58260
58266
|
};
|
|
58261
58267
|
}
|
|
58262
58268
|
function matchesKey(data, keyId) {
|
|
@@ -58267,6 +58273,7 @@ function matchesKey(data, keyId) {
|
|
|
58267
58273
|
if (shift) modifier |= MODIFIERS.shift;
|
|
58268
58274
|
if (alt) modifier |= MODIFIERS.alt;
|
|
58269
58275
|
if (ctrl) modifier |= MODIFIERS.ctrl;
|
|
58276
|
+
if (parsed.super) modifier |= MODIFIERS.super;
|
|
58270
58277
|
switch (key) {
|
|
58271
58278
|
case "escape":
|
|
58272
58279
|
case "esc":
|
|
@@ -63655,6 +63662,8 @@ import { EventEmitter } from "events";
|
|
|
63655
63662
|
var ESC = "\x1B";
|
|
63656
63663
|
var BRACKETED_PASTE_START = "\x1B[200~";
|
|
63657
63664
|
var BRACKETED_PASTE_END = "\x1B[201~";
|
|
63665
|
+
var OSC_5522_PREFIX = "\x1B]5522;";
|
|
63666
|
+
var OSC_5522_MAX_FRAME = 70 * 1024 * 1024;
|
|
63658
63667
|
function isCompleteSequence(data) {
|
|
63659
63668
|
if (!data.startsWith(ESC)) {
|
|
63660
63669
|
return "not-escape";
|
|
@@ -63741,11 +63750,19 @@ function isCompleteApcSequence(data) {
|
|
|
63741
63750
|
}
|
|
63742
63751
|
return "incomplete";
|
|
63743
63752
|
}
|
|
63744
|
-
function extractCompleteSequences(buffer) {
|
|
63753
|
+
function extractCompleteSequences(buffer, maxClipboardFrame = OSC_5522_MAX_FRAME) {
|
|
63745
63754
|
const sequences = [];
|
|
63746
63755
|
let pos = 0;
|
|
63747
63756
|
while (pos < buffer.length) {
|
|
63748
63757
|
const remaining = buffer.slice(pos);
|
|
63758
|
+
if (remaining.startsWith(`${ESC}]`)) {
|
|
63759
|
+
const end = /\x07|\x1b\\/.exec(remaining);
|
|
63760
|
+
if (!end) return { sequences, remainder: remaining };
|
|
63761
|
+
const length = end.index + end[0].length;
|
|
63762
|
+
if (!remaining.startsWith(OSC_5522_PREFIX) || length <= maxClipboardFrame) sequences.push(remaining.slice(0, length));
|
|
63763
|
+
pos += length;
|
|
63764
|
+
continue;
|
|
63765
|
+
}
|
|
63749
63766
|
if (remaining.startsWith(ESC)) {
|
|
63750
63767
|
let seqEnd = 1;
|
|
63751
63768
|
while (seqEnd <= remaining.length) {
|
|
@@ -63779,9 +63796,13 @@ var StdinBuffer = class extends EventEmitter {
|
|
|
63779
63796
|
timeoutMs;
|
|
63780
63797
|
pasteMode = false;
|
|
63781
63798
|
pasteBuffer = "";
|
|
63799
|
+
discardingClipboard = false;
|
|
63800
|
+
discardEsc = false;
|
|
63801
|
+
options;
|
|
63782
63802
|
constructor(options = {}) {
|
|
63783
63803
|
super();
|
|
63784
63804
|
this.timeoutMs = options.timeout ?? 10;
|
|
63805
|
+
this.options = options;
|
|
63785
63806
|
}
|
|
63786
63807
|
process(data) {
|
|
63787
63808
|
if (this.timeout) {
|
|
@@ -63803,6 +63824,21 @@ var StdinBuffer = class extends EventEmitter {
|
|
|
63803
63824
|
this.emit("data", "");
|
|
63804
63825
|
return;
|
|
63805
63826
|
}
|
|
63827
|
+
if (this.discardingClipboard) {
|
|
63828
|
+
const discarded = (this.discardEsc ? ESC : "") + str2;
|
|
63829
|
+
const end = /\x07|\x1b\\/.exec(discarded);
|
|
63830
|
+
if (!end) {
|
|
63831
|
+
this.discardEsc = discarded.endsWith(ESC);
|
|
63832
|
+
this.timeout = setTimeout(() => {
|
|
63833
|
+
this.discardingClipboard = false;
|
|
63834
|
+
this.discardEsc = false;
|
|
63835
|
+
}, this.options.clipboardFrameTimeout ?? 1e3);
|
|
63836
|
+
return;
|
|
63837
|
+
}
|
|
63838
|
+
this.discardingClipboard = false;
|
|
63839
|
+
this.discardEsc = false;
|
|
63840
|
+
str2 = discarded.slice(end.index + end[0].length);
|
|
63841
|
+
}
|
|
63806
63842
|
this.buffer += str2;
|
|
63807
63843
|
if (this.pasteMode) {
|
|
63808
63844
|
this.pasteBuffer += this.buffer;
|
|
@@ -63846,12 +63882,40 @@ var StdinBuffer = class extends EventEmitter {
|
|
|
63846
63882
|
}
|
|
63847
63883
|
return;
|
|
63848
63884
|
}
|
|
63849
|
-
const result = extractCompleteSequences(this.buffer);
|
|
63885
|
+
const result = extractCompleteSequences(this.buffer, this.options.clipboardMaxFrame);
|
|
63850
63886
|
this.buffer = result.remainder;
|
|
63851
63887
|
for (const sequence of result.sequences) {
|
|
63852
63888
|
this.emit("data", sequence);
|
|
63853
63889
|
}
|
|
63854
63890
|
if (this.buffer.length > 0) {
|
|
63891
|
+
const heldFor5522 = this.buffer.startsWith(OSC_5522_PREFIX) || this.buffer.length >= 2 && OSC_5522_PREFIX.startsWith(this.buffer) || this.buffer === ESC && this.options.clipboardResponsePending?.();
|
|
63892
|
+
if (heldFor5522 && this.buffer.length <= (this.options.clipboardMaxFrame ?? OSC_5522_MAX_FRAME)) {
|
|
63893
|
+
this.timeout = setTimeout(() => {
|
|
63894
|
+
const ambiguousEscape = this.buffer === ESC;
|
|
63895
|
+
this.discardEsc = this.buffer.endsWith(ESC);
|
|
63896
|
+
this.buffer = "";
|
|
63897
|
+
if (ambiguousEscape) {
|
|
63898
|
+
this.emit("data", ESC);
|
|
63899
|
+
return;
|
|
63900
|
+
}
|
|
63901
|
+
this.discardingClipboard = true;
|
|
63902
|
+
this.timeout = setTimeout(() => {
|
|
63903
|
+
this.discardingClipboard = false;
|
|
63904
|
+
this.discardEsc = false;
|
|
63905
|
+
}, this.options.clipboardFrameTimeout ?? 1e3);
|
|
63906
|
+
}, this.options.clipboardFrameTimeout ?? 1e3);
|
|
63907
|
+
return;
|
|
63908
|
+
}
|
|
63909
|
+
if (heldFor5522) {
|
|
63910
|
+
this.discardEsc = this.buffer.endsWith(ESC);
|
|
63911
|
+
this.buffer = "";
|
|
63912
|
+
this.discardingClipboard = true;
|
|
63913
|
+
this.timeout = setTimeout(() => {
|
|
63914
|
+
this.discardingClipboard = false;
|
|
63915
|
+
this.discardEsc = false;
|
|
63916
|
+
}, this.options.clipboardFrameTimeout ?? 1e3);
|
|
63917
|
+
return;
|
|
63918
|
+
}
|
|
63855
63919
|
this.timeout = setTimeout(() => {
|
|
63856
63920
|
const flushed = this.flush();
|
|
63857
63921
|
for (const sequence of flushed) {
|
|
@@ -63868,7 +63932,7 @@ var StdinBuffer = class extends EventEmitter {
|
|
|
63868
63932
|
if (this.buffer.length === 0) {
|
|
63869
63933
|
return [];
|
|
63870
63934
|
}
|
|
63871
|
-
const sequences = [this.buffer];
|
|
63935
|
+
const sequences = this.buffer.startsWith(OSC_5522_PREFIX) || this.buffer.length >= 2 && OSC_5522_PREFIX.startsWith(this.buffer) ? [] : [this.buffer];
|
|
63872
63936
|
this.buffer = "";
|
|
63873
63937
|
return sequences;
|
|
63874
63938
|
}
|
|
@@ -63880,6 +63944,8 @@ var StdinBuffer = class extends EventEmitter {
|
|
|
63880
63944
|
this.buffer = "";
|
|
63881
63945
|
this.pasteMode = false;
|
|
63882
63946
|
this.pasteBuffer = "";
|
|
63947
|
+
this.discardingClipboard = false;
|
|
63948
|
+
this.discardEsc = false;
|
|
63883
63949
|
}
|
|
63884
63950
|
getBuffer() {
|
|
63885
63951
|
return this.buffer;
|
|
@@ -63892,8 +63958,193 @@ var StdinBuffer = class extends EventEmitter {
|
|
|
63892
63958
|
// ../../packages/tui/src/terminal.ts
|
|
63893
63959
|
import * as fs11 from "node:fs";
|
|
63894
63960
|
import koffi from "koffi";
|
|
63961
|
+
|
|
63962
|
+
// ../../packages/tui/src/osc-5522.ts
|
|
63963
|
+
var OSC = "\x1B]";
|
|
63964
|
+
var ST = "\x1B\\";
|
|
63965
|
+
var READ_TIMEOUT_MS = 8e3;
|
|
63966
|
+
var SUPPORT_TIMEOUT_MS = 1200;
|
|
63967
|
+
var MAX_TOTAL_BYTES = 50 * 1024 * 1024;
|
|
63968
|
+
function parseOsc5522Packet(data) {
|
|
63969
|
+
const match = data.match(/^\x1b\]5522;([^;]*);?([^\x1b\x07]*)(?:\x1b\\|\x07)$/);
|
|
63970
|
+
if (!match) return void 0;
|
|
63971
|
+
return { metadata: match[1] ?? "", payload: match[2] ?? "" };
|
|
63972
|
+
}
|
|
63973
|
+
function isStrictBase64(value) {
|
|
63974
|
+
if (value.length % 4 !== 0) return false;
|
|
63975
|
+
if (!/^[A-Za-z0-9+/]+={0,2}$/.test(value)) return false;
|
|
63976
|
+
const padding = value.length - value.replace(/=+$/, "").length;
|
|
63977
|
+
if (padding > 2) return false;
|
|
63978
|
+
if (padding > 0 && value.slice(0, -padding).includes("=")) return false;
|
|
63979
|
+
return true;
|
|
63980
|
+
}
|
|
63981
|
+
function parseMetadata(metadata) {
|
|
63982
|
+
const fields = /* @__PURE__ */ new Map();
|
|
63983
|
+
for (const part of metadata.split(":")) {
|
|
63984
|
+
const eq = part.indexOf("=");
|
|
63985
|
+
if (eq === -1) {
|
|
63986
|
+
if (part) fields.set(part, "");
|
|
63987
|
+
} else {
|
|
63988
|
+
fields.set(part.slice(0, eq), part.slice(eq + 1));
|
|
63989
|
+
}
|
|
63990
|
+
}
|
|
63991
|
+
return fields;
|
|
63992
|
+
}
|
|
63993
|
+
var Osc5522Client = class {
|
|
63994
|
+
constructor(write = (data) => process.stdout.write(data)) {
|
|
63995
|
+
this.write = write;
|
|
63996
|
+
}
|
|
63997
|
+
write;
|
|
63998
|
+
session;
|
|
63999
|
+
supportMode = "unknown";
|
|
64000
|
+
pendingSupportResolve;
|
|
64001
|
+
get responsePending() {
|
|
64002
|
+
return this.session !== void 0 || this.pendingSupportResolve !== void 0;
|
|
64003
|
+
}
|
|
64004
|
+
/**
|
|
64005
|
+
* Feed one stdin sequence. Returns true when the packet was consumed as
|
|
64006
|
+
* part of this protocol, so the caller can drop it before normal routing.
|
|
64007
|
+
*/
|
|
64008
|
+
feed(data) {
|
|
64009
|
+
const support = data.match(/^\x1b\[\?5522;(\d+)\$y$/);
|
|
64010
|
+
if (support) {
|
|
64011
|
+
const ps = Number(support[1]);
|
|
64012
|
+
const supported = ps !== 0 && ps !== 4;
|
|
64013
|
+
this.supportMode = supported ? "supported" : "unsupported";
|
|
64014
|
+
this.pendingSupportResolve?.(supported);
|
|
64015
|
+
this.pendingSupportResolve = void 0;
|
|
64016
|
+
return true;
|
|
64017
|
+
}
|
|
64018
|
+
const packet = parseOsc5522Packet(data);
|
|
64019
|
+
if (!packet) return false;
|
|
64020
|
+
const fields = parseMetadata(packet.metadata);
|
|
64021
|
+
const type = fields.get("type") ?? "";
|
|
64022
|
+
if (!type.startsWith("read")) return false;
|
|
64023
|
+
const status = fields.get("status");
|
|
64024
|
+
const session = this.session;
|
|
64025
|
+
if (!session) return true;
|
|
64026
|
+
if (status === void 0) {
|
|
64027
|
+
this.finishFor(session, { ok: false, kind: "malformed", message: `OSC 5522 read packet without status: ${packet.metadata}` });
|
|
64028
|
+
return true;
|
|
64029
|
+
}
|
|
64030
|
+
if (status === "OK") {
|
|
64031
|
+
return true;
|
|
64032
|
+
}
|
|
64033
|
+
if (status === "DATA") {
|
|
64034
|
+
const mimeEncoded = fields.get("mime");
|
|
64035
|
+
if (mimeEncoded === void 0 || mimeEncoded === "") {
|
|
64036
|
+
this.finishFor(session, { ok: false, kind: "malformed", message: `DATA packet without mime field: ${packet.metadata}` });
|
|
64037
|
+
return true;
|
|
64038
|
+
}
|
|
64039
|
+
if (!isStrictBase64(mimeEncoded)) {
|
|
64040
|
+
this.finishFor(session, { ok: false, kind: "malformed", message: "Invalid base64 MIME in DATA packet" });
|
|
64041
|
+
return true;
|
|
64042
|
+
}
|
|
64043
|
+
const mimeType = Buffer.from(mimeEncoded, "base64").toString("utf8");
|
|
64044
|
+
if (session.mimeType !== void 0 && session.mimeType !== mimeType) {
|
|
64045
|
+
return true;
|
|
64046
|
+
}
|
|
64047
|
+
if (session.mimeType === void 0) {
|
|
64048
|
+
session.mimeType = mimeType;
|
|
64049
|
+
}
|
|
64050
|
+
if (!isStrictBase64(packet.payload)) {
|
|
64051
|
+
this.finishFor(session, { ok: false, kind: "malformed", message: "Invalid base64 payload in DATA packet" });
|
|
64052
|
+
return true;
|
|
64053
|
+
}
|
|
64054
|
+
const chunk = Buffer.from(packet.payload, "base64");
|
|
64055
|
+
session.totalBytes += chunk.length;
|
|
64056
|
+
if (session.totalBytes > MAX_TOTAL_BYTES) {
|
|
64057
|
+
this.finishFor(session, { ok: false, kind: "too-large", message: `Clipboard image exceeds the ${Math.floor(MAX_TOTAL_BYTES / (1024 * 1024))}MB limit.` });
|
|
64058
|
+
return true;
|
|
64059
|
+
}
|
|
64060
|
+
session.chunks.push(chunk);
|
|
64061
|
+
return true;
|
|
64062
|
+
}
|
|
64063
|
+
if (status === "DONE") {
|
|
64064
|
+
const mimeType = session.mimeType;
|
|
64065
|
+
if (!mimeType || session.chunks.length === 0) {
|
|
64066
|
+
this.finishFor(session, { ok: false, kind: "unavailable", message: "Clipboard read completed without data." });
|
|
64067
|
+
return true;
|
|
64068
|
+
}
|
|
64069
|
+
this.finishFor(session, { ok: true, mimeType, bytes: Buffer.concat(session.chunks) });
|
|
64070
|
+
return true;
|
|
64071
|
+
}
|
|
64072
|
+
const kind = status === "EPERM" ? "denied" : status === "EBUSY" ? "busy" : status === "ENOSYS" ? "unavailable" : "malformed";
|
|
64073
|
+
const message = status === "EPERM" ? "Terminal denied the clipboard read (permission)." : status === "EBUSY" ? "Clipboard is busy (another client is using it)." : status === "ENOSYS" ? "Requested clipboard type is not available." : `Unexpected OSC 5522 status: ${status}`;
|
|
64074
|
+
this.finishFor(session, { ok: false, kind, message });
|
|
64075
|
+
return true;
|
|
64076
|
+
}
|
|
64077
|
+
/**
|
|
64078
|
+
* Query DECRQM support (CSI ? 5522 $ p). Resolves false on timeout —
|
|
64079
|
+
* terminals that do not know the mode never reply.
|
|
64080
|
+
*/
|
|
64081
|
+
async querySupport(timeoutMs = SUPPORT_TIMEOUT_MS) {
|
|
64082
|
+
if (this.supportMode !== "unknown") return this.supportMode === "supported";
|
|
64083
|
+
return new Promise((resolve7) => {
|
|
64084
|
+
let settled = false;
|
|
64085
|
+
const settle = (supported) => {
|
|
64086
|
+
if (settled) return;
|
|
64087
|
+
settled = true;
|
|
64088
|
+
clearTimeout(timer);
|
|
64089
|
+
this.pendingSupportResolve = void 0;
|
|
64090
|
+
resolve7(supported);
|
|
64091
|
+
};
|
|
64092
|
+
const timer = setTimeout(() => settle(false), timeoutMs);
|
|
64093
|
+
this.pendingSupportResolve = settle;
|
|
64094
|
+
this.write(`\x1B[?5522$p`);
|
|
64095
|
+
});
|
|
64096
|
+
}
|
|
64097
|
+
/**
|
|
64098
|
+
* Read the clipboard's image data. The first offered representation of
|
|
64099
|
+
* the requested types is returned (png preferred over jpeg by request
|
|
64100
|
+
* order). Resolves unsupported when the terminal never replies to the
|
|
64101
|
+
* DECRQM probe.
|
|
64102
|
+
*/
|
|
64103
|
+
async readImage(timeoutMs = READ_TIMEOUT_MS, supportTimeoutMs = SUPPORT_TIMEOUT_MS) {
|
|
64104
|
+
if (this.session) {
|
|
64105
|
+
return { ok: false, kind: "busy", message: "Another OSC 5522 read is already in flight." };
|
|
64106
|
+
}
|
|
64107
|
+
const session = {
|
|
64108
|
+
resolve: void 0,
|
|
64109
|
+
timer: void 0,
|
|
64110
|
+
chunks: [],
|
|
64111
|
+
totalBytes: 0
|
|
64112
|
+
};
|
|
64113
|
+
const promise = new Promise((resolve7) => {
|
|
64114
|
+
session.resolve = resolve7;
|
|
64115
|
+
});
|
|
64116
|
+
session.timer = setTimeout(() => {
|
|
64117
|
+
this.finishFor(session, { ok: false, kind: "timeout", message: "Terminal did not respond to the clipboard read in time." });
|
|
64118
|
+
}, timeoutMs);
|
|
64119
|
+
this.session = session;
|
|
64120
|
+
const supported = await this.querySupport(supportTimeoutMs);
|
|
64121
|
+
if (!supported) {
|
|
64122
|
+
this.finishFor(session, { ok: false, kind: "unsupported", message: "Terminal does not support the OSC 5522 clipboard protocol." });
|
|
64123
|
+
return promise;
|
|
64124
|
+
}
|
|
64125
|
+
if (this.session !== session) return promise;
|
|
64126
|
+
const mimeList = Buffer.from("image/png image/jpeg").toString("base64");
|
|
64127
|
+
this.write(`${OSC}5522;type=read;${mimeList}${ST}`);
|
|
64128
|
+
return promise;
|
|
64129
|
+
}
|
|
64130
|
+
/** Finish only if `session` is still the live session (identity-bound). */
|
|
64131
|
+
finishFor(session, result) {
|
|
64132
|
+
if (this.session !== session) return;
|
|
64133
|
+
this.session = void 0;
|
|
64134
|
+
clearTimeout(session.timer);
|
|
64135
|
+
session.resolve(result);
|
|
64136
|
+
}
|
|
64137
|
+
};
|
|
64138
|
+
|
|
64139
|
+
// ../../packages/tui/src/terminal.ts
|
|
63895
64140
|
var ProcessTerminal = class {
|
|
63896
64141
|
wasRaw = false;
|
|
64142
|
+
/** Client for the Kitty OSC 5522 clipboard protocol (read side). */
|
|
64143
|
+
osc5522Client = new Osc5522Client();
|
|
64144
|
+
/** Access the OSC 5522 clipboard client (terminal-level clipboard reads). */
|
|
64145
|
+
get clipboard() {
|
|
64146
|
+
return this.osc5522Client;
|
|
64147
|
+
}
|
|
63897
64148
|
inputHandler;
|
|
63898
64149
|
resizeHandler;
|
|
63899
64150
|
_kittyProtocolActive = false;
|
|
@@ -63935,9 +64186,12 @@ var ProcessTerminal = class {
|
|
|
63935
64186
|
* to handle the case where the response arrives split across multiple events.
|
|
63936
64187
|
*/
|
|
63937
64188
|
setupStdinBuffer() {
|
|
63938
|
-
this.stdinBuffer = new StdinBuffer({ timeout: 10 });
|
|
64189
|
+
this.stdinBuffer = new StdinBuffer({ timeout: 10, clipboardResponsePending: () => this.osc5522Client.responsePending });
|
|
63939
64190
|
const kittyResponsePattern = /^\x1b\[\?(\d+)u$/;
|
|
63940
64191
|
this.stdinBuffer.on("data", (sequence) => {
|
|
64192
|
+
if (this.osc5522Client.feed(sequence)) {
|
|
64193
|
+
return;
|
|
64194
|
+
}
|
|
63941
64195
|
if (!this._kittyProtocolActive) {
|
|
63942
64196
|
const match = sequence.match(kittyResponsePattern);
|
|
63943
64197
|
if (match) {
|
|
@@ -64196,11 +64450,14 @@ var ExtensionRunner = class {
|
|
|
64196
64450
|
};
|
|
64197
64451
|
}
|
|
64198
64452
|
/**
|
|
64199
|
-
* Set the UI context for interactive mode.
|
|
64453
|
+
* Set the UI context for interactive mode. Does NOT change hasUI: the
|
|
64454
|
+
* constructor's hasUI argument (host-provided: true for interactive, false
|
|
64455
|
+
* for print/json-events no-op contexts) is the single source of truth.
|
|
64456
|
+
* Flipping it here used to make headless hosts report ctx.hasUI === true
|
|
64457
|
+
* while their ui.* methods silently no-op'd.
|
|
64200
64458
|
*/
|
|
64201
64459
|
setUIContext(uiContext) {
|
|
64202
64460
|
this.uiContext = uiContext;
|
|
64203
|
-
this.hasUI = true;
|
|
64204
64461
|
}
|
|
64205
64462
|
/**
|
|
64206
64463
|
* Wrap an unregister handle so this runner can revoke it during
|
|
@@ -64948,7 +65205,7 @@ var DEFAULT_APP_KEYBINDINGS = {
|
|
|
64948
65205
|
steer: "alt+enter",
|
|
64949
65206
|
followUp: [],
|
|
64950
65207
|
dequeue: ["alt+up", "ctrl+shift+up"],
|
|
64951
|
-
pasteImage: "ctrl+v",
|
|
65208
|
+
pasteImage: ["ctrl+v", "alt+v", "super+v"],
|
|
64952
65209
|
newSession: [],
|
|
64953
65210
|
tree: [],
|
|
64954
65211
|
fork: [],
|
|
@@ -65102,32 +65359,6 @@ function buildCliProjectContextSection(cwd) {
|
|
|
65102
65359
|
return buildProjectContextSection(collectAncestorAgentsFiles(cwd));
|
|
65103
65360
|
}
|
|
65104
65361
|
|
|
65105
|
-
// src/file-access-context.ts
|
|
65106
|
-
import * as path11 from "node:path";
|
|
65107
|
-
function uniqueNormalizedPaths(paths) {
|
|
65108
|
-
const seen = /* @__PURE__ */ new Set();
|
|
65109
|
-
const result = [];
|
|
65110
|
-
for (const entry of paths) {
|
|
65111
|
-
const trimmed = String(entry || "").trim();
|
|
65112
|
-
if (!trimmed) continue;
|
|
65113
|
-
const normalized = path11.normalize(trimmed);
|
|
65114
|
-
if (seen.has(normalized)) continue;
|
|
65115
|
-
seen.add(normalized);
|
|
65116
|
-
result.push(normalized);
|
|
65117
|
-
}
|
|
65118
|
-
return result;
|
|
65119
|
-
}
|
|
65120
|
-
function buildCliFileAccessOptions(params) {
|
|
65121
|
-
return {
|
|
65122
|
-
accessRoots: uniqueNormalizedPaths([
|
|
65123
|
-
resolveCliProjectRoot(params.cwd),
|
|
65124
|
-
params.configDir,
|
|
65125
|
-
...params.skills.map((skill) => skill.baseDir)
|
|
65126
|
-
]),
|
|
65127
|
-
allowlistedDirs: params.allowlistedDirs
|
|
65128
|
-
};
|
|
65129
|
-
}
|
|
65130
|
-
|
|
65131
65362
|
// src/runtime/computer-use-owner.ts
|
|
65132
65363
|
var COMPUTER_USE_OWNER_ENV = "PIE_COMPUTER_USE_OWNER_ID";
|
|
65133
65364
|
var COMPUTER_USE_EXECUTION_ENV = "PIE_COMPUTER_USE_EXECUTION_ID";
|
|
@@ -65147,7 +65378,7 @@ function computerUseOwnerEnv(ownerId, executionId) {
|
|
|
65147
65378
|
|
|
65148
65379
|
// src/theme/theme.ts
|
|
65149
65380
|
import * as fs13 from "node:fs";
|
|
65150
|
-
import * as
|
|
65381
|
+
import * as path11 from "node:path";
|
|
65151
65382
|
|
|
65152
65383
|
// ../../node_modules/@sinclair/typebox/build/esm/compiler/compiler.mjs
|
|
65153
65384
|
var TypeCheck = class {
|
|
@@ -66034,8 +66265,8 @@ var BUILTIN_THEMES;
|
|
|
66034
66265
|
function getBuiltinThemes() {
|
|
66035
66266
|
if (!BUILTIN_THEMES) {
|
|
66036
66267
|
const themesDir = getThemesDir();
|
|
66037
|
-
const darkPath =
|
|
66038
|
-
const lightPath =
|
|
66268
|
+
const darkPath = path11.join(themesDir, "dark.json");
|
|
66269
|
+
const lightPath = path11.join(themesDir, "light.json");
|
|
66039
66270
|
BUILTIN_THEMES = {
|
|
66040
66271
|
dark: JSON.parse(fs13.readFileSync(darkPath, "utf-8")),
|
|
66041
66272
|
light: JSON.parse(fs13.readFileSync(lightPath, "utf-8"))
|
|
@@ -66072,23 +66303,23 @@ function parseThemeJson(label, json) {
|
|
|
66072
66303
|
otherErrors.push(` - ${e.path}: ${e.message}`);
|
|
66073
66304
|
}
|
|
66074
66305
|
}
|
|
66075
|
-
let
|
|
66306
|
+
let errorMessage5 = `Invalid theme "${label}":
|
|
66076
66307
|
`;
|
|
66077
66308
|
if (missingColors.length > 0) {
|
|
66078
|
-
|
|
66079
|
-
|
|
66080
|
-
|
|
66309
|
+
errorMessage5 += "\nMissing required color tokens:\n";
|
|
66310
|
+
errorMessage5 += missingColors.map((c) => ` - ${c}`).join("\n");
|
|
66311
|
+
errorMessage5 += `
|
|
66081
66312
|
|
|
66082
66313
|
Please add these colors to your theme's "colors" object.`;
|
|
66083
|
-
|
|
66314
|
+
errorMessage5 += "\nSee the built-in themes (dark.json, light.json) for reference values.";
|
|
66084
66315
|
}
|
|
66085
66316
|
if (otherErrors.length > 0) {
|
|
66086
|
-
|
|
66317
|
+
errorMessage5 += `
|
|
66087
66318
|
|
|
66088
66319
|
Other errors:
|
|
66089
66320
|
${otherErrors.join("\n")}`;
|
|
66090
66321
|
}
|
|
66091
|
-
throw new Error(
|
|
66322
|
+
throw new Error(errorMessage5);
|
|
66092
66323
|
}
|
|
66093
66324
|
return json;
|
|
66094
66325
|
}
|
|
@@ -66115,7 +66346,7 @@ function loadThemeJson(name) {
|
|
|
66115
66346
|
throw new Error(`Theme "${name}" does not have a source path for export`);
|
|
66116
66347
|
}
|
|
66117
66348
|
const customThemesDir = getCustomThemesDir();
|
|
66118
|
-
const themePath =
|
|
66349
|
+
const themePath = path11.join(customThemesDir, `${name}.json`);
|
|
66119
66350
|
if (!fs13.existsSync(themePath)) {
|
|
66120
66351
|
throw new Error(`Theme not found: ${name}`);
|
|
66121
66352
|
}
|
|
@@ -66235,7 +66466,7 @@ function startThemeWatcher() {
|
|
|
66235
66466
|
return;
|
|
66236
66467
|
}
|
|
66237
66468
|
const customThemesDir = getCustomThemesDir();
|
|
66238
|
-
const themeFile =
|
|
66469
|
+
const themeFile = path11.join(customThemesDir, `${currentThemeName}.json`);
|
|
66239
66470
|
if (!fs13.existsSync(themeFile)) {
|
|
66240
66471
|
return;
|
|
66241
66472
|
}
|
|
@@ -66436,7 +66667,7 @@ function getSettingsListTheme() {
|
|
|
66436
66667
|
var import_yaml = __toESM(require_dist2(), 1);
|
|
66437
66668
|
import * as fs14 from "fs";
|
|
66438
66669
|
import * as os4 from "os";
|
|
66439
|
-
import * as
|
|
66670
|
+
import * as path12 from "path";
|
|
66440
66671
|
function parseSkillDescription(content) {
|
|
66441
66672
|
content = content.replace(/^\uFEFF/, "").replace(/\r\n/g, "\n");
|
|
66442
66673
|
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---(?:\n|$)/);
|
|
@@ -66460,8 +66691,8 @@ function parseSkillDescription(content) {
|
|
|
66460
66691
|
}
|
|
66461
66692
|
var USER_CONTROLLED_SOURCES = /* @__PURE__ */ new Set(["user-agents", "user"]);
|
|
66462
66693
|
function pathIsInside(child, parent) {
|
|
66463
|
-
const relative3 =
|
|
66464
|
-
return relative3 !== "" && !relative3.startsWith(`..${
|
|
66694
|
+
const relative3 = path12.relative(parent, child);
|
|
66695
|
+
return relative3 !== "" && !relative3.startsWith(`..${path12.sep}`) && relative3 !== ".." && !path12.isAbsolute(relative3);
|
|
66465
66696
|
}
|
|
66466
66697
|
function resolveSkillSymlink(fullPath, dir, source) {
|
|
66467
66698
|
let target;
|
|
@@ -66486,7 +66717,7 @@ function loadSkillsFromDir(dir, source) {
|
|
|
66486
66717
|
const entries = fs14.readdirSync(dir, { withFileTypes: true });
|
|
66487
66718
|
for (const entry of entries) {
|
|
66488
66719
|
if (entry.name.startsWith(".")) continue;
|
|
66489
|
-
const fullPath =
|
|
66720
|
+
const fullPath = path12.join(dir, entry.name);
|
|
66490
66721
|
let entryPath = fullPath;
|
|
66491
66722
|
let entryIsDirectory = entry.isDirectory();
|
|
66492
66723
|
let entryIsFile = entry.isFile();
|
|
@@ -66501,7 +66732,7 @@ function loadSkillsFromDir(dir, source) {
|
|
|
66501
66732
|
entryIsFile = resolved.isFile;
|
|
66502
66733
|
}
|
|
66503
66734
|
if (entryIsDirectory) {
|
|
66504
|
-
const skillMdPath =
|
|
66735
|
+
const skillMdPath = path12.join(entryPath, "SKILL.md");
|
|
66505
66736
|
if (fs14.existsSync(skillMdPath)) {
|
|
66506
66737
|
try {
|
|
66507
66738
|
const content = fs14.readFileSync(skillMdPath, "utf-8");
|
|
@@ -66533,7 +66764,7 @@ function loadSkillsFromDir(dir, source) {
|
|
|
66533
66764
|
content,
|
|
66534
66765
|
filePath: entryPath,
|
|
66535
66766
|
source,
|
|
66536
|
-
baseDir:
|
|
66767
|
+
baseDir: path12.dirname(entryPath)
|
|
66537
66768
|
});
|
|
66538
66769
|
} catch (e) {
|
|
66539
66770
|
diagnostics.push({
|
|
@@ -66547,18 +66778,18 @@ function loadSkillsFromDir(dir, source) {
|
|
|
66547
66778
|
return { skills, diagnostics };
|
|
66548
66779
|
}
|
|
66549
66780
|
function discoverAgentsSkillsDirs(cwd) {
|
|
66550
|
-
const resolvedCwd =
|
|
66781
|
+
const resolvedCwd = path12.resolve(cwd || process.cwd());
|
|
66551
66782
|
const projectRoot = resolveCliProjectRoot(resolvedCwd);
|
|
66552
66783
|
const projectAgentsDirs = [];
|
|
66553
66784
|
let current = projectRoot;
|
|
66554
66785
|
while (true) {
|
|
66555
|
-
projectAgentsDirs.push(
|
|
66786
|
+
projectAgentsDirs.push(path12.join(current, ".agents", "skills"));
|
|
66556
66787
|
if (current === resolvedCwd) break;
|
|
66557
|
-
const child =
|
|
66788
|
+
const child = path12.relative(current, resolvedCwd).split(path12.sep)[0];
|
|
66558
66789
|
if (!child) break;
|
|
66559
|
-
current =
|
|
66790
|
+
current = path12.join(current, child);
|
|
66560
66791
|
}
|
|
66561
|
-
return { userAgentsDir:
|
|
66792
|
+
return { userAgentsDir: path12.join(os4.homedir(), ".agents", "skills"), projectAgentsDirs };
|
|
66562
66793
|
}
|
|
66563
66794
|
function buildSkillDirs(options) {
|
|
66564
66795
|
const { userAgentsDir, projectAgentsDirs } = discoverAgentsSkillsDirs(options.cwd);
|
|
@@ -66732,7 +66963,7 @@ function validateSkillName(name) {
|
|
|
66732
66963
|
import * as path30 from "path";
|
|
66733
66964
|
|
|
66734
66965
|
// src/capabilities/read-file-understanding.ts
|
|
66735
|
-
import * as
|
|
66966
|
+
import * as path21 from "node:path";
|
|
66736
66967
|
import * as fs22 from "node:fs/promises";
|
|
66737
66968
|
|
|
66738
66969
|
// src/core/provider-capabilities.ts
|
|
@@ -66760,7 +66991,7 @@ function getProviderDisplayName(platform2) {
|
|
|
66760
66991
|
|
|
66761
66992
|
// src/files/adapters/kimi-adapter.ts
|
|
66762
66993
|
import * as fs15 from "node:fs";
|
|
66763
|
-
import * as
|
|
66994
|
+
import * as path13 from "node:path";
|
|
66764
66995
|
|
|
66765
66996
|
// src/files/errors.ts
|
|
66766
66997
|
var FileErrorMessages = {
|
|
@@ -66897,7 +67128,7 @@ var KimiFileAdapter = class {
|
|
|
66897
67128
|
// Upload
|
|
66898
67129
|
// ============================================================================
|
|
66899
67130
|
async upload(filePath, options = {}) {
|
|
66900
|
-
const fileName = options.sourceName ||
|
|
67131
|
+
const fileName = options.sourceName || path13.basename(filePath);
|
|
66901
67132
|
const mimeType = options.mimeType || this.guessMimeType(fileName);
|
|
66902
67133
|
const purpose = this.detectPurpose(filePath, options.purpose, mimeType);
|
|
66903
67134
|
const stats = fs15.statSync(filePath);
|
|
@@ -66959,7 +67190,7 @@ var KimiFileAdapter = class {
|
|
|
66959
67190
|
return "file-extract";
|
|
66960
67191
|
}
|
|
66961
67192
|
guessMimeType(filename) {
|
|
66962
|
-
const ext =
|
|
67193
|
+
const ext = path13.extname(filename).toLowerCase();
|
|
66963
67194
|
switch (ext) {
|
|
66964
67195
|
case ".jpg":
|
|
66965
67196
|
case ".jpeg":
|
|
@@ -67122,7 +67353,7 @@ var KimiFileAdapter = class {
|
|
|
67122
67353
|
|
|
67123
67354
|
// src/files/adapters/gemini-adapter.ts
|
|
67124
67355
|
import * as fs16 from "node:fs";
|
|
67125
|
-
import * as
|
|
67356
|
+
import * as path14 from "node:path";
|
|
67126
67357
|
import { Readable } from "node:stream";
|
|
67127
67358
|
var GeminiFileAdapter = class {
|
|
67128
67359
|
platform = "gemini";
|
|
@@ -67187,7 +67418,7 @@ var GeminiFileAdapter = class {
|
|
|
67187
67418
|
);
|
|
67188
67419
|
}
|
|
67189
67420
|
const mimeType = options.mimeType || this.guessMimeType(filePath);
|
|
67190
|
-
const displayName = options.sourceName ||
|
|
67421
|
+
const displayName = options.sourceName || path14.basename(filePath);
|
|
67191
67422
|
const startResponse = await fetch(
|
|
67192
67423
|
`${this.baseUrl}/upload/v1beta/files?key=${this.apiKey}`,
|
|
67193
67424
|
{
|
|
@@ -67423,7 +67654,7 @@ var GeminiFileAdapter = class {
|
|
|
67423
67654
|
|
|
67424
67655
|
// src/files/adapters/openai-compatible-files-adapter.ts
|
|
67425
67656
|
import * as fs17 from "node:fs";
|
|
67426
|
-
import * as
|
|
67657
|
+
import * as path15 from "node:path";
|
|
67427
67658
|
var OpenAICompatibleFilesAdapter = class {
|
|
67428
67659
|
constructor(apiKey, baseUrl, extraHeaders = {}) {
|
|
67429
67660
|
this.apiKey = apiKey;
|
|
@@ -67449,7 +67680,7 @@ var OpenAICompatibleFilesAdapter = class {
|
|
|
67449
67680
|
]
|
|
67450
67681
|
};
|
|
67451
67682
|
async upload(filePath, options = {}) {
|
|
67452
|
-
const fileName = options.sourceName ||
|
|
67683
|
+
const fileName = options.sourceName || path15.basename(filePath);
|
|
67453
67684
|
const mimeType = options.mimeType || guessMimeType(fileName);
|
|
67454
67685
|
const stats = fs17.statSync(filePath);
|
|
67455
67686
|
if (stats.size > this.capabilities.maxFileSize) {
|
|
@@ -67575,7 +67806,7 @@ function extractContentText(raw) {
|
|
|
67575
67806
|
return raw;
|
|
67576
67807
|
}
|
|
67577
67808
|
function guessMimeType(filename) {
|
|
67578
|
-
const ext =
|
|
67809
|
+
const ext = path15.extname(filename).toLowerCase();
|
|
67579
67810
|
switch (ext) {
|
|
67580
67811
|
case ".pdf":
|
|
67581
67812
|
return "application/pdf";
|
|
@@ -67592,12 +67823,12 @@ function guessMimeType(filename) {
|
|
|
67592
67823
|
|
|
67593
67824
|
// src/files/file-manager.ts
|
|
67594
67825
|
import * as fs21 from "node:fs";
|
|
67595
|
-
import * as
|
|
67826
|
+
import * as path20 from "node:path";
|
|
67596
67827
|
import * as crypto2 from "node:crypto";
|
|
67597
67828
|
|
|
67598
67829
|
// src/files/file-cache.ts
|
|
67599
67830
|
import * as fs18 from "node:fs";
|
|
67600
|
-
import * as
|
|
67831
|
+
import * as path17 from "node:path";
|
|
67601
67832
|
import * as crypto from "node:crypto";
|
|
67602
67833
|
|
|
67603
67834
|
// src/files/logger.ts
|
|
@@ -67692,7 +67923,7 @@ var DEFAULT_PIC_OPTIONS = {
|
|
|
67692
67923
|
};
|
|
67693
67924
|
|
|
67694
67925
|
// src/files/utils.ts
|
|
67695
|
-
import * as
|
|
67926
|
+
import * as path16 from "node:path";
|
|
67696
67927
|
import { homedir as homedir5 } from "node:os";
|
|
67697
67928
|
var WINDOWS_ABSOLUTE_PATH_RE = /^(?:[a-zA-Z]:[\\/]|[\\/]{2}[^\\/]+[\\/][^\\/]+)/;
|
|
67698
67929
|
function isWindowsAbsolutePath(filePath) {
|
|
@@ -67713,13 +67944,13 @@ function formatBytes(bytes) {
|
|
|
67713
67944
|
}
|
|
67714
67945
|
function resolvePath2(inputPath) {
|
|
67715
67946
|
if (inputPath.startsWith("~")) {
|
|
67716
|
-
return
|
|
67947
|
+
return path16.join(getHomeDirectory(), inputPath.slice(1));
|
|
67717
67948
|
}
|
|
67718
67949
|
if (isWindowsAbsolutePath(inputPath)) {
|
|
67719
67950
|
return inputPath;
|
|
67720
67951
|
}
|
|
67721
|
-
if (!
|
|
67722
|
-
return
|
|
67952
|
+
if (!path16.isAbsolute(inputPath)) {
|
|
67953
|
+
return path16.resolve(process.cwd(), inputPath);
|
|
67723
67954
|
}
|
|
67724
67955
|
return inputPath;
|
|
67725
67956
|
}
|
|
@@ -67747,8 +67978,8 @@ var FileCache = class _FileCache {
|
|
|
67747
67978
|
maxEntries;
|
|
67748
67979
|
constructor(baseDir, maxEntries = DEFAULT_MAX_CACHE_ENTRIES) {
|
|
67749
67980
|
this.baseDir = baseDir;
|
|
67750
|
-
this.dataDir =
|
|
67751
|
-
this.indexPath =
|
|
67981
|
+
this.dataDir = path17.join(baseDir, "data");
|
|
67982
|
+
this.indexPath = path17.join(baseDir, "index.json");
|
|
67752
67983
|
this.maxEntries = maxEntries;
|
|
67753
67984
|
this.index = this.loadIndex();
|
|
67754
67985
|
this.ensureDirectories();
|
|
@@ -67814,15 +68045,15 @@ var FileCache = class _FileCache {
|
|
|
67814
68045
|
// ============================================================================
|
|
67815
68046
|
getStoragePath(hash) {
|
|
67816
68047
|
const subdir = hash.slice(0, 2);
|
|
67817
|
-
const fullDir =
|
|
68048
|
+
const fullDir = path17.join(this.dataDir, subdir);
|
|
67818
68049
|
if (!fs18.existsSync(fullDir)) {
|
|
67819
68050
|
fs18.mkdirSync(fullDir, { recursive: true });
|
|
67820
68051
|
}
|
|
67821
|
-
return
|
|
68052
|
+
return path17.join(fullDir, hash);
|
|
67822
68053
|
}
|
|
67823
68054
|
getStorageRelativePath(hash) {
|
|
67824
68055
|
const subdir = hash.slice(0, 2);
|
|
67825
|
-
return
|
|
68056
|
+
return path17.join(subdir, hash);
|
|
67826
68057
|
}
|
|
67827
68058
|
async storeFile(sourcePath, name, mimeType) {
|
|
67828
68059
|
const hash = await this.computeHash(sourcePath);
|
|
@@ -67884,7 +68115,7 @@ var FileCache = class _FileCache {
|
|
|
67884
68115
|
getLocalPath(hash) {
|
|
67885
68116
|
const entry = this.index.files[hash];
|
|
67886
68117
|
if (!entry) return void 0;
|
|
67887
|
-
return
|
|
68118
|
+
return path17.join(this.dataDir, entry.localPath);
|
|
67888
68119
|
}
|
|
67889
68120
|
exists(hash) {
|
|
67890
68121
|
return hash in this.index.files;
|
|
@@ -67964,7 +68195,7 @@ var FileCache = class _FileCache {
|
|
|
67964
68195
|
this.index.pathHints[this.getPathHintKey(resolvedPath)] = {
|
|
67965
68196
|
path: resolvedPath,
|
|
67966
68197
|
hash,
|
|
67967
|
-
name: name || entry?.name ||
|
|
68198
|
+
name: name || entry?.name || path17.basename(resolvedPath),
|
|
67968
68199
|
size: stat2.size,
|
|
67969
68200
|
mtimeMs: normalizedMtimeMs,
|
|
67970
68201
|
lastSeenAt: Date.now(),
|
|
@@ -68012,7 +68243,7 @@ var FileCache = class _FileCache {
|
|
|
68012
68243
|
deleteEntry(hash, entry) {
|
|
68013
68244
|
entry = entry || this.index.files[hash];
|
|
68014
68245
|
if (!entry) return;
|
|
68015
|
-
const localPath =
|
|
68246
|
+
const localPath = path17.join(this.dataDir, entry.localPath);
|
|
68016
68247
|
if (fs18.existsSync(localPath)) {
|
|
68017
68248
|
fs18.unlinkSync(localPath);
|
|
68018
68249
|
}
|
|
@@ -68028,7 +68259,7 @@ var FileCache = class _FileCache {
|
|
|
68028
68259
|
}
|
|
68029
68260
|
clear() {
|
|
68030
68261
|
for (const entry of Object.values(this.index.files)) {
|
|
68031
|
-
const localPath =
|
|
68262
|
+
const localPath = path17.join(this.dataDir, entry.localPath);
|
|
68032
68263
|
if (fs18.existsSync(localPath)) {
|
|
68033
68264
|
fs18.unlinkSync(localPath);
|
|
68034
68265
|
}
|
|
@@ -68083,11 +68314,11 @@ var FileCache = class _FileCache {
|
|
|
68083
68314
|
};
|
|
68084
68315
|
}
|
|
68085
68316
|
static getMimeType(fileName) {
|
|
68086
|
-
const ext =
|
|
68317
|
+
const ext = path17.extname(fileName).toLowerCase();
|
|
68087
68318
|
return MIME_TYPES[ext] || "application/octet-stream";
|
|
68088
68319
|
}
|
|
68089
68320
|
static getFileTypeFromName(fileName) {
|
|
68090
|
-
const baseName =
|
|
68321
|
+
const baseName = path17.basename(fileName);
|
|
68091
68322
|
if (!baseName || baseName.startsWith(".")) {
|
|
68092
68323
|
return void 0;
|
|
68093
68324
|
}
|
|
@@ -68127,7 +68358,7 @@ var FileCache = class _FileCache {
|
|
|
68127
68358
|
|
|
68128
68359
|
// src/files/session-file-manager.ts
|
|
68129
68360
|
import * as fs19 from "node:fs";
|
|
68130
|
-
import * as
|
|
68361
|
+
import * as path18 from "node:path";
|
|
68131
68362
|
var INITIAL_REFRESH_BACKOFF_MS = 6e4;
|
|
68132
68363
|
var MAX_REFRESH_BACKOFF_MS = 60 * 60 * 1e3;
|
|
68133
68364
|
var SessionFileManager = class {
|
|
@@ -68141,7 +68372,7 @@ var SessionFileManager = class {
|
|
|
68141
68372
|
constructor(sessionId, sessionsDir, fileCache, authFingerprint) {
|
|
68142
68373
|
this.sessionId = sessionId;
|
|
68143
68374
|
this.sessionsDir = sessionsDir;
|
|
68144
|
-
this.statePath =
|
|
68375
|
+
this.statePath = path18.join(this.sessionsDir, `${sessionId}-files.json`);
|
|
68145
68376
|
this.fileCache = fileCache;
|
|
68146
68377
|
this.authFingerprint = authFingerprint;
|
|
68147
68378
|
this.state = this.loadState();
|
|
@@ -68487,7 +68718,7 @@ var SessionFileManager = class {
|
|
|
68487
68718
|
const files = fs19.readdirSync(sessionsDir);
|
|
68488
68719
|
for (const file of files) {
|
|
68489
68720
|
if (!file.endsWith(".json")) continue;
|
|
68490
|
-
const filePath =
|
|
68721
|
+
const filePath = path18.join(sessionsDir, file);
|
|
68491
68722
|
const stat2 = fs19.statSync(filePath);
|
|
68492
68723
|
if (now - stat2.mtime.getTime() > maxAge) {
|
|
68493
68724
|
fs19.unlinkSync(filePath);
|
|
@@ -68499,7 +68730,7 @@ var SessionFileManager = class {
|
|
|
68499
68730
|
|
|
68500
68731
|
// src/files/ffmpeg-processor.ts
|
|
68501
68732
|
import * as fs20 from "node:fs";
|
|
68502
|
-
import * as
|
|
68733
|
+
import * as path19 from "node:path";
|
|
68503
68734
|
import { spawn } from "node:child_process";
|
|
68504
68735
|
var FFmpegProcessor = class {
|
|
68505
68736
|
ffmpegPath = "ffmpeg";
|
|
@@ -68603,7 +68834,7 @@ var FFmpegProcessor = class {
|
|
|
68603
68834
|
}
|
|
68604
68835
|
async compressVideo(inputPath, outputDir, info, opts, onProgress) {
|
|
68605
68836
|
const outputName = `compressed_${Date.now()}.mp4`;
|
|
68606
|
-
const outputPath =
|
|
68837
|
+
const outputPath = path19.join(outputDir, outputName);
|
|
68607
68838
|
const adaptiveParams = this.calculateAdaptiveParams(info.duration, opts);
|
|
68608
68839
|
const args = [
|
|
68609
68840
|
"-i",
|
|
@@ -68665,9 +68896,9 @@ var FFmpegProcessor = class {
|
|
|
68665
68896
|
}
|
|
68666
68897
|
async extractKeyframes(inputPath, outputDir, info, opts, onProgress) {
|
|
68667
68898
|
const interval = Math.floor(info.duration / opts.keyframeCount);
|
|
68668
|
-
const framesDir =
|
|
68899
|
+
const framesDir = path19.join(outputDir, `keyframes_${Date.now()}`);
|
|
68669
68900
|
fs20.mkdirSync(framesDir, { recursive: true });
|
|
68670
|
-
const outputPattern =
|
|
68901
|
+
const outputPattern = path19.join(framesDir, "frame_%03d.jpg");
|
|
68671
68902
|
const args = [
|
|
68672
68903
|
"-i",
|
|
68673
68904
|
inputPath,
|
|
@@ -68685,7 +68916,7 @@ var FFmpegProcessor = class {
|
|
|
68685
68916
|
onProgress?.(percent);
|
|
68686
68917
|
}
|
|
68687
68918
|
});
|
|
68688
|
-
let frames = fs20.readdirSync(framesDir).filter((f) => f.endsWith(".jpg")).sort().map((f) =>
|
|
68919
|
+
let frames = fs20.readdirSync(framesDir).filter((f) => f.endsWith(".jpg")).sort().map((f) => path19.join(framesDir, f));
|
|
68689
68920
|
if (frames.length < opts.keyframeCount / 2) {
|
|
68690
68921
|
fs20.rmSync(framesDir, { recursive: true, force: true });
|
|
68691
68922
|
fs20.mkdirSync(framesDir, { recursive: true });
|
|
@@ -68704,7 +68935,7 @@ var FFmpegProcessor = class {
|
|
|
68704
68935
|
onProgress?.(percent);
|
|
68705
68936
|
}
|
|
68706
68937
|
});
|
|
68707
|
-
frames = fs20.readdirSync(framesDir).filter((f) => f.endsWith(".jpg")).sort().map((f) =>
|
|
68938
|
+
frames = fs20.readdirSync(framesDir).filter((f) => f.endsWith(".jpg")).sort().map((f) => path19.join(framesDir, f));
|
|
68708
68939
|
}
|
|
68709
68940
|
const totalOutputSize = frames.reduce(
|
|
68710
68941
|
(sum, f) => sum + fs20.statSync(f).size,
|
|
@@ -68728,7 +68959,7 @@ var FFmpegProcessor = class {
|
|
|
68728
68959
|
const opts = { ...DEFAULT_PIC_OPTIONS, ...options };
|
|
68729
68960
|
const ext = opts.format === "webp" ? ".webp" : ".jpg";
|
|
68730
68961
|
const outputName = `optimized_${Date.now()}${ext}`;
|
|
68731
|
-
const outputPath =
|
|
68962
|
+
const outputPath = path19.join(outputDir, outputName);
|
|
68732
68963
|
const args = [
|
|
68733
68964
|
"-i",
|
|
68734
68965
|
inputPath,
|
|
@@ -68903,8 +69134,8 @@ var DIRECTORY_LISTING_TTL_MS = 1500;
|
|
|
68903
69134
|
var FileManager = class {
|
|
68904
69135
|
constructor(options) {
|
|
68905
69136
|
this.options = options;
|
|
68906
|
-
const baseDir = options.baseDir ||
|
|
68907
|
-
const sessionsDir = options.sessionsDir ||
|
|
69137
|
+
const baseDir = options.baseDir || path20.join(process.env.HOME || ".", ".pie", "files");
|
|
69138
|
+
const sessionsDir = options.sessionsDir || path20.join(process.env.HOME || ".", ".pie", "sessions");
|
|
68908
69139
|
this.fileCache = new FileCache(baseDir);
|
|
68909
69140
|
this.authFingerprint = options.apiKey ? this.buildAuthFingerprint(options.apiKey) : void 0;
|
|
68910
69141
|
this.sessionManager = new SessionFileManager(
|
|
@@ -68915,7 +69146,7 @@ var FileManager = class {
|
|
|
68915
69146
|
);
|
|
68916
69147
|
this.ffmpeg = new FFmpegProcessor(options.ffmpegPath);
|
|
68917
69148
|
this.platform = normalizeFileManagerPlatform(options.platform);
|
|
68918
|
-
this.tempDir =
|
|
69149
|
+
this.tempDir = path20.join(baseDir, "temp");
|
|
68919
69150
|
this.ensureDirectories();
|
|
68920
69151
|
}
|
|
68921
69152
|
options;
|
|
@@ -68962,7 +69193,7 @@ var FileManager = class {
|
|
|
68962
69193
|
// ============================================================================
|
|
68963
69194
|
async stageLocal(filePath, options = {}) {
|
|
68964
69195
|
const resolvedPath = resolvePath2(filePath);
|
|
68965
|
-
const sourceName = options.sourceName ||
|
|
69196
|
+
const sourceName = options.sourceName || path20.basename(resolvedPath);
|
|
68966
69197
|
if (!fs21.existsSync(resolvedPath)) {
|
|
68967
69198
|
throw new FileManagerError(
|
|
68968
69199
|
"LOCAL_FILE_MISSING" /* LOCAL_FILE_MISSING */,
|
|
@@ -68992,7 +69223,7 @@ var FileManager = class {
|
|
|
68992
69223
|
}
|
|
68993
69224
|
async upload(filePath, options = {}) {
|
|
68994
69225
|
const resolvedPath = resolvePath2(filePath);
|
|
68995
|
-
const sourceName = options.sourceName ||
|
|
69226
|
+
const sourceName = options.sourceName || path20.basename(resolvedPath);
|
|
68996
69227
|
if (!fs21.existsSync(resolvedPath)) {
|
|
68997
69228
|
throw new FileManagerError(
|
|
68998
69229
|
"LOCAL_FILE_MISSING" /* LOCAL_FILE_MISSING */,
|
|
@@ -69082,7 +69313,7 @@ var FileManager = class {
|
|
|
69082
69313
|
}
|
|
69083
69314
|
const cachedResult = await this.tryReuseCachedSourceUpload(
|
|
69084
69315
|
resolvedPath,
|
|
69085
|
-
options.sourceName ||
|
|
69316
|
+
options.sourceName || path20.basename(resolvedPath),
|
|
69086
69317
|
options.platform || this.platform
|
|
69087
69318
|
);
|
|
69088
69319
|
if (cachedResult) {
|
|
@@ -69099,9 +69330,9 @@ var FileManager = class {
|
|
|
69099
69330
|
const result = await this.upload(optimizedPath, {
|
|
69100
69331
|
...options,
|
|
69101
69332
|
purpose: "image",
|
|
69102
|
-
sourceName:
|
|
69333
|
+
sourceName: path20.basename(resolvedPath)
|
|
69103
69334
|
});
|
|
69104
|
-
this.fileCache.rememberPathHint(resolvedPath, result.hash,
|
|
69335
|
+
this.fileCache.rememberPathHint(resolvedPath, result.hash, path20.basename(resolvedPath));
|
|
69105
69336
|
this.invalidateDirectoryListingCacheForPath(resolvedPath);
|
|
69106
69337
|
try {
|
|
69107
69338
|
fs21.unlinkSync(optimizedPath);
|
|
@@ -69122,7 +69353,7 @@ var FileManager = class {
|
|
|
69122
69353
|
}
|
|
69123
69354
|
const cachedResult = await this.tryReuseCachedSourceUpload(
|
|
69124
69355
|
resolvedPath,
|
|
69125
|
-
options.sourceName ||
|
|
69356
|
+
options.sourceName || path20.basename(resolvedPath),
|
|
69126
69357
|
options.platform || this.platform
|
|
69127
69358
|
);
|
|
69128
69359
|
if (cachedResult) {
|
|
@@ -69172,9 +69403,9 @@ var FileManager = class {
|
|
|
69172
69403
|
result = await this.upload(preprocessResult.output, {
|
|
69173
69404
|
...options,
|
|
69174
69405
|
purpose: "video",
|
|
69175
|
-
sourceName:
|
|
69406
|
+
sourceName: path20.basename(resolvedPath)
|
|
69176
69407
|
});
|
|
69177
|
-
this.fileCache.rememberPathHint(resolvedPath, result.hash,
|
|
69408
|
+
this.fileCache.rememberPathHint(resolvedPath, result.hash, path20.basename(resolvedPath));
|
|
69178
69409
|
this.invalidateDirectoryListingCacheForPath(resolvedPath);
|
|
69179
69410
|
} else {
|
|
69180
69411
|
throw new FileManagerError(
|
|
@@ -69466,7 +69697,7 @@ var FileManager = class {
|
|
|
69466
69697
|
* Detect purpose from file path based on extension
|
|
69467
69698
|
*/
|
|
69468
69699
|
detectPurpose(filePath) {
|
|
69469
|
-
const ext =
|
|
69700
|
+
const ext = path20.extname(filePath).toLowerCase();
|
|
69470
69701
|
switch (ext) {
|
|
69471
69702
|
case ".mp4":
|
|
69472
69703
|
case ".mov":
|
|
@@ -69648,7 +69879,7 @@ var FileManager = class {
|
|
|
69648
69879
|
if (!entry.name || entry.name.startsWith(".")) {
|
|
69649
69880
|
continue;
|
|
69650
69881
|
}
|
|
69651
|
-
const fullPath =
|
|
69882
|
+
const fullPath = path20.join(resolvedDir, entry.name);
|
|
69652
69883
|
if (entry.isDirectory()) {
|
|
69653
69884
|
listing.directories.push({ name: entry.name, path: fullPath });
|
|
69654
69885
|
continue;
|
|
@@ -69689,7 +69920,7 @@ var FileManager = class {
|
|
|
69689
69920
|
return listing;
|
|
69690
69921
|
}
|
|
69691
69922
|
invalidateDirectoryListingCacheForPath(filePath) {
|
|
69692
|
-
this.directoryListingCache.delete(
|
|
69923
|
+
this.directoryListingCache.delete(path20.dirname(resolvePath2(filePath)));
|
|
69693
69924
|
}
|
|
69694
69925
|
buildAuthFingerprint(apiKey) {
|
|
69695
69926
|
return crypto2.createHash("sha256").update(apiKey).digest("hex").slice(0, 16);
|
|
@@ -69738,8 +69969,8 @@ function createFileManagerForModel(params) {
|
|
|
69738
69969
|
sessionId: params.sessionId,
|
|
69739
69970
|
platform: platform2,
|
|
69740
69971
|
apiKey: params.apiKey,
|
|
69741
|
-
baseDir:
|
|
69742
|
-
sessionsDir:
|
|
69972
|
+
baseDir: path21.join(params.configDir, "files"),
|
|
69973
|
+
sessionsDir: path21.join(params.configDir, "sessions")
|
|
69743
69974
|
});
|
|
69744
69975
|
switch (getFileManagerAdapterKind(platform2)) {
|
|
69745
69976
|
case "kimi":
|
|
@@ -69779,7 +70010,7 @@ async function prepareInlineMediaContent(params) {
|
|
|
69779
70010
|
const limitBytes = limitMb * 1024 * 1024;
|
|
69780
70011
|
if (stat2.size > limitBytes) {
|
|
69781
70012
|
throw new Error(
|
|
69782
|
-
`${params.request.kind} understanding for ${params.model.provider}/${params.model.id} supports inline files up to ${limitMb}MB; ${
|
|
70013
|
+
`${params.request.kind} understanding for ${params.model.provider}/${params.model.id} supports inline files up to ${limitMb}MB; ${path21.basename(params.request.displayPath)} is ${(stat2.size / 1024 / 1024).toFixed(1)}MB. Configure a model with a file upload adapter, or compress/trim the file before reading it.`
|
|
69783
70014
|
);
|
|
69784
70015
|
}
|
|
69785
70016
|
const data = await fs22.readFile(params.request.absolutePath, "base64");
|
|
@@ -69818,7 +70049,7 @@ async function prepareFileContent(configDir, params) {
|
|
|
69818
70049
|
});
|
|
69819
70050
|
if (params.request.kind === "document") {
|
|
69820
70051
|
const upload2 = await manager.upload(params.request.absolutePath, {
|
|
69821
|
-
sourceName:
|
|
70052
|
+
sourceName: path21.basename(params.request.displayPath),
|
|
69822
70053
|
purpose: "file-extract"
|
|
69823
70054
|
});
|
|
69824
70055
|
await waitForReady({ manager, fileId: upload2.fileId, timeoutMs: 12e4, signal: params.request.signal });
|
|
@@ -69841,8 +70072,8 @@ async function prepareFileContent(configDir, params) {
|
|
|
69841
70072
|
}
|
|
69842
70073
|
};
|
|
69843
70074
|
}
|
|
69844
|
-
const upload = params.request.kind === "video" ? await manager.uploadVideo(params.request.absolutePath, { sourceName:
|
|
69845
|
-
sourceName:
|
|
70075
|
+
const upload = params.request.kind === "video" ? await manager.uploadVideo(params.request.absolutePath, { sourceName: path21.basename(params.request.displayPath), strategy: "compress" }) : await manager.upload(params.request.absolutePath, {
|
|
70076
|
+
sourceName: path21.basename(params.request.displayPath),
|
|
69846
70077
|
purpose: params.request.kind === "image" ? "image" : "file-extract"
|
|
69847
70078
|
});
|
|
69848
70079
|
if (params.request.kind !== "video") {
|
|
@@ -70012,6 +70243,53 @@ function createCliFileSystemTools(cwd, options) {
|
|
|
70012
70243
|
});
|
|
70013
70244
|
}
|
|
70014
70245
|
|
|
70246
|
+
// src/file-access-context.ts
|
|
70247
|
+
import * as path22 from "node:path";
|
|
70248
|
+
function uniqueNormalizedPaths(paths) {
|
|
70249
|
+
const seen = /* @__PURE__ */ new Set();
|
|
70250
|
+
const result = [];
|
|
70251
|
+
for (const entry of paths) {
|
|
70252
|
+
const trimmed = String(entry || "").trim();
|
|
70253
|
+
if (!trimmed) continue;
|
|
70254
|
+
const normalized = path22.normalize(trimmed);
|
|
70255
|
+
if (seen.has(normalized)) continue;
|
|
70256
|
+
seen.add(normalized);
|
|
70257
|
+
result.push(normalized);
|
|
70258
|
+
}
|
|
70259
|
+
return result;
|
|
70260
|
+
}
|
|
70261
|
+
function buildCliFileAccessOptions(params) {
|
|
70262
|
+
return {
|
|
70263
|
+
accessRoots: uniqueNormalizedPaths([
|
|
70264
|
+
resolveCliProjectRoot(params.cwd),
|
|
70265
|
+
params.configDir,
|
|
70266
|
+
...params.skills.map((skill) => skill.baseDir)
|
|
70267
|
+
]),
|
|
70268
|
+
allowlistedDirs: params.allowlistedDirs,
|
|
70269
|
+
descriptionAllowlistedDirs: params.descriptionAllowlistedDirs
|
|
70270
|
+
};
|
|
70271
|
+
}
|
|
70272
|
+
|
|
70273
|
+
// src/interactive-filesystem-tools.ts
|
|
70274
|
+
function buildInteractiveFilesystemToolOptions(host, allowlistedDirs) {
|
|
70275
|
+
return {
|
|
70276
|
+
...buildCliFileAccessOptions({
|
|
70277
|
+
cwd: host.cwd,
|
|
70278
|
+
configDir: host.configDir,
|
|
70279
|
+
skills: host.skills,
|
|
70280
|
+
allowlistedDirs,
|
|
70281
|
+
descriptionAllowlistedDirs: []
|
|
70282
|
+
}),
|
|
70283
|
+
configDir: host.configDir,
|
|
70284
|
+
fileObservationState: host.fileObservationState,
|
|
70285
|
+
getAgentModel: host.getAgentModel,
|
|
70286
|
+
getSessionId: () => host.getActiveSessionId() || void 0,
|
|
70287
|
+
resolveToolModel: host.resolveToolModel,
|
|
70288
|
+
resolveToolModelCandidates: host.resolveToolModelCandidates,
|
|
70289
|
+
getPolicyContext: host.getPlanPolicyContext
|
|
70290
|
+
};
|
|
70291
|
+
}
|
|
70292
|
+
|
|
70015
70293
|
// src/runtime/yolo-grant.ts
|
|
70016
70294
|
var YoloGrantTracker = class {
|
|
70017
70295
|
untilMs = 0;
|
|
@@ -77106,35 +77384,40 @@ var RuntimeModeBlockInjector = class {
|
|
|
77106
77384
|
// src/runtime/host-envelope-registry.ts
|
|
77107
77385
|
var sharedCliEnvelopeRegistry;
|
|
77108
77386
|
function cliHostEnvelopeRegistry() {
|
|
77109
|
-
|
|
77110
|
-
|
|
77387
|
+
return sharedCliEnvelopeRegistry ??= createCliHostEnvelopeRegistry();
|
|
77388
|
+
}
|
|
77389
|
+
function createCliHostEnvelopeRegistry() {
|
|
77390
|
+
const registry = createHostEnvelopeProjectorRegistry();
|
|
77111
77391
|
for (const { kind, version } of runtimeModeEnvelopeRegistry().listPins()) {
|
|
77112
|
-
|
|
77392
|
+
registry.register({
|
|
77113
77393
|
kind,
|
|
77114
77394
|
version,
|
|
77115
77395
|
project: (data) => runtimeModeEnvelopeRegistry().resolve(kind, version).project(data)
|
|
77116
77396
|
});
|
|
77117
77397
|
}
|
|
77118
|
-
return
|
|
77398
|
+
return registry;
|
|
77119
77399
|
}
|
|
77120
|
-
function registerExternalHostEnvelopeProjector(projector) {
|
|
77121
|
-
|
|
77400
|
+
function registerExternalHostEnvelopeProjector(projector, registry = cliHostEnvelopeRegistry()) {
|
|
77401
|
+
registry.register(projector);
|
|
77122
77402
|
return () => {
|
|
77123
77403
|
};
|
|
77124
77404
|
}
|
|
77125
77405
|
function resetCliHostEnvelopeRegistry() {
|
|
77126
77406
|
sharedCliEnvelopeRegistry = void 0;
|
|
77127
77407
|
}
|
|
77128
|
-
function cliHostEnvelopeKinds() {
|
|
77129
|
-
return
|
|
77408
|
+
function cliHostEnvelopeKinds(registry = cliHostEnvelopeRegistry()) {
|
|
77409
|
+
return registry.listPins().map(({ kind, version }) => `${kind}@${version}`).sort();
|
|
77410
|
+
}
|
|
77411
|
+
function projectCliHostEnvelopes(messages, onProjection, registry = cliHostEnvelopeRegistry()) {
|
|
77412
|
+
return projectHostEnvelopes(messages, registry, onProjection);
|
|
77130
77413
|
}
|
|
77131
|
-
function
|
|
77132
|
-
return
|
|
77414
|
+
function cliCompactionModelView(message) {
|
|
77415
|
+
return projectCliHostEnvelopes([message])[0];
|
|
77133
77416
|
}
|
|
77134
77417
|
function isIntakeHostContextError(value) {
|
|
77135
77418
|
return value.code !== void 0;
|
|
77136
77419
|
}
|
|
77137
|
-
function intakeHostContextBlock(value) {
|
|
77420
|
+
function intakeHostContextBlock(value, registry = cliHostEnvelopeRegistry()) {
|
|
77138
77421
|
if (!isHostContextBlock(value)) {
|
|
77139
77422
|
return {
|
|
77140
77423
|
ok: false,
|
|
@@ -77143,12 +77426,12 @@ function intakeHostContextBlock(value) {
|
|
|
77143
77426
|
};
|
|
77144
77427
|
}
|
|
77145
77428
|
const block = value;
|
|
77146
|
-
const projector =
|
|
77429
|
+
const projector = registry.resolve(block.kind, block.version);
|
|
77147
77430
|
if (!projector) {
|
|
77148
77431
|
return {
|
|
77149
77432
|
ok: false,
|
|
77150
77433
|
code: "host_context_unknown_projector",
|
|
77151
|
-
message: `no projector for ${block.kind}@${block.version}; this build supports: ${cliHostEnvelopeKinds().join(", ")}`
|
|
77434
|
+
message: `no projector for ${block.kind}@${block.version}; this build supports: ${cliHostEnvelopeKinds(registry).join(", ")}`
|
|
77152
77435
|
};
|
|
77153
77436
|
}
|
|
77154
77437
|
try {
|
|
@@ -77163,8 +77446,8 @@ function intakeHostContextBlock(value) {
|
|
|
77163
77446
|
}
|
|
77164
77447
|
return { ok: true, block };
|
|
77165
77448
|
}
|
|
77166
|
-
function intakeHostContextFailure(value) {
|
|
77167
|
-
const result = intakeHostContextBlock(value);
|
|
77449
|
+
function intakeHostContextFailure(value, registry = cliHostEnvelopeRegistry()) {
|
|
77450
|
+
const result = intakeHostContextBlock(value, registry);
|
|
77168
77451
|
return isIntakeHostContextError(result) ? { code: result.code, message: result.message } : void 0;
|
|
77169
77452
|
}
|
|
77170
77453
|
|
|
@@ -77196,13 +77479,14 @@ async function handleCompactCommand(host) {
|
|
|
77196
77479
|
const preparation = prepareSessionCompaction({
|
|
77197
77480
|
sessionManager: host.sessionManager,
|
|
77198
77481
|
messages: existingMessages,
|
|
77482
|
+
modelView: cliCompactionModelView,
|
|
77199
77483
|
budgetTokens: host.options.model?.contextWindow
|
|
77200
77484
|
});
|
|
77201
77485
|
if (preparation.entries.length === 0) {
|
|
77202
77486
|
host.showStatus("Need at least one real user message before compacting");
|
|
77203
77487
|
return;
|
|
77204
77488
|
}
|
|
77205
|
-
const tokensBefore =
|
|
77489
|
+
const tokensBefore = preparation.inputTokens;
|
|
77206
77490
|
const compactOptions = {
|
|
77207
77491
|
model: host.options.model,
|
|
77208
77492
|
apiKey: host.options.apiKey,
|
|
@@ -78420,6 +78704,7 @@ var FileStatusMonitor = class {
|
|
|
78420
78704
|
|
|
78421
78705
|
// src/files/mention/mention-handler.ts
|
|
78422
78706
|
import * as fs26 from "node:fs";
|
|
78707
|
+
import { randomUUID } from "node:crypto";
|
|
78423
78708
|
import * as path28 from "node:path";
|
|
78424
78709
|
var MentionHandler = class {
|
|
78425
78710
|
fileManager;
|
|
@@ -78513,75 +78798,11 @@ var MentionHandler = class {
|
|
|
78513
78798
|
this.onInsertMention(mention, queryToken);
|
|
78514
78799
|
this.onStatus?.(`Added ${option.name} (already uploaded to ${this.fileManager.getPlatformDisplayName()})`);
|
|
78515
78800
|
} else if (option.type === "upload" && option.path) {
|
|
78516
|
-
this.
|
|
78517
|
-
|
|
78518
|
-
|
|
78519
|
-
|
|
78520
|
-
|
|
78521
|
-
if (option.cacheStatus === "uploaded") {
|
|
78522
|
-
this.pushPendingStatus(
|
|
78523
|
-
pendingStatusKey,
|
|
78524
|
-
`Preparing ${option.name} (reusing upload from ${this.fileManager.getPlatformDisplayName()})...`
|
|
78525
|
-
);
|
|
78526
|
-
} else if (option.cacheStatus === "cached") {
|
|
78527
|
-
this.pushPendingStatus(
|
|
78528
|
-
pendingStatusKey,
|
|
78529
|
-
`Preparing ${option.name} (reusing local cache)...`
|
|
78530
|
-
);
|
|
78531
|
-
} else {
|
|
78532
|
-
this.pushPendingStatus(pendingStatusKey, `Preparing ${option.name}...`);
|
|
78533
|
-
}
|
|
78534
|
-
const mimeType = FileCache.getMimeType(option.path);
|
|
78535
|
-
const isMedia = mimeType.startsWith("image/") || mimeType.startsWith("video/");
|
|
78536
|
-
const shouldStageLocally = !isMedia || !this.fileManager.hasAdapter();
|
|
78537
|
-
if (isMedia && shouldStageLocally) {
|
|
78538
|
-
this.pushPendingStatus(pendingStatusKey, `Staging ${option.name} locally (no upload API for this provider)...`);
|
|
78539
|
-
}
|
|
78540
|
-
const onProgress = (progress, stage) => {
|
|
78541
|
-
this.pushPendingStatus(
|
|
78542
|
-
pendingStatusKey,
|
|
78543
|
-
this.formatUploadProgress(option.name, progress, stage)
|
|
78544
|
-
);
|
|
78545
|
-
};
|
|
78546
|
-
const result = shouldStageLocally ? await this.fileManager.stageLocal(option.path, { sourceName: option.name }) : mimeType.startsWith("video/") ? await this.fileManager.uploadVideo(option.path, {
|
|
78547
|
-
sourceName: option.name,
|
|
78548
|
-
onProgress
|
|
78549
|
-
}) : mimeType.startsWith("image/") ? await this.fileManager.uploadPic(option.path, {
|
|
78550
|
-
sourceName: option.name,
|
|
78551
|
-
onProgress
|
|
78552
|
-
}) : await this.fileManager.upload(option.path, {
|
|
78553
|
-
sourceName: option.name,
|
|
78554
|
-
onProgress
|
|
78555
|
-
});
|
|
78556
|
-
if (result.success) {
|
|
78557
|
-
const mention = this.formatMention(result.name, result.fileId);
|
|
78558
|
-
this.onInsertMention(mention, pendingMention);
|
|
78559
|
-
this.clearPendingStatus(pendingStatusKey);
|
|
78560
|
-
this.onStatus?.(shouldStageLocally ? `Added local file ${result.name}` : `Added ${result.name}`);
|
|
78561
|
-
} else {
|
|
78562
|
-
this.onInsertMention("", pendingMention);
|
|
78563
|
-
this.clearPendingStatus(pendingStatusKey);
|
|
78564
|
-
this.onError?.("File upload failed. Please try again.");
|
|
78565
|
-
}
|
|
78566
|
-
} catch (err) {
|
|
78567
|
-
this.onInsertMention("", pendingMention);
|
|
78568
|
-
this.clearPendingStatus(pendingStatusKey);
|
|
78569
|
-
const errorMessage4 = err instanceof Error ? err.message : String(err);
|
|
78570
|
-
if (errorMessage4.includes("PLATFORM_NOT_SUPPORTED")) {
|
|
78571
|
-
this.onError?.("The current AI model does not support file uploads.");
|
|
78572
|
-
} else if (errorMessage4.includes("ENOENT")) {
|
|
78573
|
-
this.onError?.("File does not exist or cannot be accessed.");
|
|
78574
|
-
} else if (errorMessage4.includes("EACCES") || errorMessage4.includes("PERMISSION")) {
|
|
78575
|
-
this.onError?.("Permission denied while accessing the file.");
|
|
78576
|
-
} else if (errorMessage4.includes("network") || errorMessage4.includes("ETIMEDOUT") || errorMessage4.includes("ECONNREFUSED")) {
|
|
78577
|
-
this.onError?.("Network error. Check the connection and try again.");
|
|
78578
|
-
} else {
|
|
78579
|
-
this.onError?.(`Upload failed: ${errorMessage4}`);
|
|
78580
|
-
}
|
|
78581
|
-
} finally {
|
|
78582
|
-
this.clearPendingStatus(pendingStatusKey);
|
|
78583
|
-
this.pendingUploadCount = Math.max(0, this.pendingUploadCount - 1);
|
|
78584
|
-
}
|
|
78801
|
+
await this.attachFileFromPath(option.path, {
|
|
78802
|
+
sourceName: option.name,
|
|
78803
|
+
queryToken,
|
|
78804
|
+
cacheStatus: option.cacheStatus
|
|
78805
|
+
});
|
|
78585
78806
|
} else {
|
|
78586
78807
|
this.onError?.("Invalid file option.");
|
|
78587
78808
|
}
|
|
@@ -78589,6 +78810,110 @@ var MentionHandler = class {
|
|
|
78589
78810
|
this.onHidePicker();
|
|
78590
78811
|
this.isPickerVisible = false;
|
|
78591
78812
|
}
|
|
78813
|
+
/**
|
|
78814
|
+
* Attach a local file from disk without going through the mention picker.
|
|
78815
|
+
*
|
|
78816
|
+
* Used by the clipboard image paste flow: the file goes through the exact
|
|
78817
|
+
* same pending-mention → stage/upload → final-mention lifecycle as a
|
|
78818
|
+
* picker-selected file, so submit-time queueing and attachment resolution
|
|
78819
|
+
* behave identically.
|
|
78820
|
+
*/
|
|
78821
|
+
async attachLocalFile(path34, displayName, pendingMention, isCurrent) {
|
|
78822
|
+
await this.attachFileFromPath(path34, { sourceName: displayName, queryToken: pendingMention, isCurrent });
|
|
78823
|
+
}
|
|
78824
|
+
/** Reserve a real queue-replaceable token before asynchronous clipboard IO. */
|
|
78825
|
+
beginPendingAttachment(name) {
|
|
78826
|
+
const token = `@[${name}](pending:clipboard-${randomUUID()})`;
|
|
78827
|
+
this.pendingUploadCount++;
|
|
78828
|
+
this.onInsertMention(`${token} `);
|
|
78829
|
+
let finished = false;
|
|
78830
|
+
return { token, finish: () => {
|
|
78831
|
+
if (finished) return;
|
|
78832
|
+
finished = true;
|
|
78833
|
+
this.onInsertMention("", token);
|
|
78834
|
+
this.pendingUploadCount = Math.max(0, this.pendingUploadCount - 1);
|
|
78835
|
+
} };
|
|
78836
|
+
}
|
|
78837
|
+
/**
|
|
78838
|
+
* Shared core of "attach a file from a local path": insert a pending
|
|
78839
|
+
* mention, stage or upload the file, then replace the pending mention with
|
|
78840
|
+
* the final one (or remove it on failure).
|
|
78841
|
+
*/
|
|
78842
|
+
async attachFileFromPath(path34, options) {
|
|
78843
|
+
const sourceName = options.sourceName ?? path34.split(/[\\/]/).pop() ?? path34;
|
|
78844
|
+
this.pendingUploadCount += 1;
|
|
78845
|
+
const pendingMention = options.queryToken?.includes("pending:clipboard-") ? options.queryToken : this.formatPendingMention(sourceName);
|
|
78846
|
+
this.onInsertMention(pendingMention, options.queryToken);
|
|
78847
|
+
const pendingStatusKey = `${path34}:${Date.now()}:${Math.random().toString(36).slice(2, 8)}`;
|
|
78848
|
+
try {
|
|
78849
|
+
if (options.cacheStatus === "uploaded") {
|
|
78850
|
+
this.pushPendingStatus(
|
|
78851
|
+
pendingStatusKey,
|
|
78852
|
+
`Preparing ${sourceName} (reusing upload from ${this.fileManager.getPlatformDisplayName()})...`
|
|
78853
|
+
);
|
|
78854
|
+
} else if (options.cacheStatus === "cached") {
|
|
78855
|
+
this.pushPendingStatus(
|
|
78856
|
+
pendingStatusKey,
|
|
78857
|
+
`Preparing ${sourceName} (reusing local cache)...`
|
|
78858
|
+
);
|
|
78859
|
+
} else {
|
|
78860
|
+
this.pushPendingStatus(pendingStatusKey, `Preparing ${sourceName}...`);
|
|
78861
|
+
}
|
|
78862
|
+
const mimeType = FileCache.getMimeType(path34);
|
|
78863
|
+
const isMedia = mimeType.startsWith("image/") || mimeType.startsWith("video/");
|
|
78864
|
+
const shouldStageLocally = !isMedia || !this.fileManager.hasAdapter();
|
|
78865
|
+
if (isMedia && shouldStageLocally) {
|
|
78866
|
+
this.pushPendingStatus(pendingStatusKey, `Staging ${sourceName} locally (no upload API for this provider)...`);
|
|
78867
|
+
}
|
|
78868
|
+
const onProgress = (progress, stage) => {
|
|
78869
|
+
if (options.isCurrent && !options.isCurrent()) return;
|
|
78870
|
+
this.pushPendingStatus(
|
|
78871
|
+
pendingStatusKey,
|
|
78872
|
+
this.formatUploadProgress(sourceName, progress, stage)
|
|
78873
|
+
);
|
|
78874
|
+
};
|
|
78875
|
+
const result = shouldStageLocally ? await this.fileManager.stageLocal(path34, { sourceName }) : mimeType.startsWith("video/") ? await this.fileManager.uploadVideo(path34, {
|
|
78876
|
+
sourceName,
|
|
78877
|
+
onProgress
|
|
78878
|
+
}) : mimeType.startsWith("image/") ? await this.fileManager.uploadPic(path34, {
|
|
78879
|
+
sourceName,
|
|
78880
|
+
onProgress
|
|
78881
|
+
}) : await this.fileManager.upload(path34, {
|
|
78882
|
+
sourceName,
|
|
78883
|
+
onProgress
|
|
78884
|
+
});
|
|
78885
|
+
if (options.isCurrent && !options.isCurrent()) return;
|
|
78886
|
+
if (result.success) {
|
|
78887
|
+
const mention = this.formatMention(result.name, result.fileId);
|
|
78888
|
+
this.onInsertMention(mention, pendingMention);
|
|
78889
|
+
this.clearPendingStatus(pendingStatusKey);
|
|
78890
|
+
this.onStatus?.(shouldStageLocally ? `Added local file ${result.name}` : `Added ${result.name}`);
|
|
78891
|
+
} else {
|
|
78892
|
+
this.onInsertMention("", pendingMention);
|
|
78893
|
+
this.clearPendingStatus(pendingStatusKey);
|
|
78894
|
+
this.onError?.("File upload failed. Please try again.");
|
|
78895
|
+
}
|
|
78896
|
+
} catch (err) {
|
|
78897
|
+
if (options.isCurrent && !options.isCurrent()) return;
|
|
78898
|
+
this.onInsertMention("", pendingMention);
|
|
78899
|
+
this.clearPendingStatus(pendingStatusKey);
|
|
78900
|
+
const errorMessage5 = err instanceof Error ? err.message : String(err);
|
|
78901
|
+
if (errorMessage5.includes("PLATFORM_NOT_SUPPORTED")) {
|
|
78902
|
+
this.onError?.("The current AI model does not support file uploads.");
|
|
78903
|
+
} else if (errorMessage5.includes("ENOENT")) {
|
|
78904
|
+
this.onError?.("File does not exist or cannot be accessed.");
|
|
78905
|
+
} else if (errorMessage5.includes("EACCES") || errorMessage5.includes("PERMISSION")) {
|
|
78906
|
+
this.onError?.("Permission denied while accessing the file.");
|
|
78907
|
+
} else if (errorMessage5.includes("network") || errorMessage5.includes("ETIMEDOUT") || errorMessage5.includes("ECONNREFUSED")) {
|
|
78908
|
+
this.onError?.("Network error. Check the connection and try again.");
|
|
78909
|
+
} else {
|
|
78910
|
+
this.onError?.(`Upload failed: ${errorMessage5}`);
|
|
78911
|
+
}
|
|
78912
|
+
} finally {
|
|
78913
|
+
this.clearPendingStatus(pendingStatusKey);
|
|
78914
|
+
this.pendingUploadCount = Math.max(0, this.pendingUploadCount - 1);
|
|
78915
|
+
}
|
|
78916
|
+
}
|
|
78592
78917
|
/**
|
|
78593
78918
|
* Parse mentions in text and convert to platform format
|
|
78594
78919
|
*/
|
|
@@ -79328,6 +79653,10 @@ function setupInteractiveKeybindings(host) {
|
|
|
79328
79653
|
host.handleInterrupt();
|
|
79329
79654
|
return { consume: true };
|
|
79330
79655
|
}
|
|
79656
|
+
if (!host.mentionPickerComponent && host.keybindings.matches(data, "pasteImage")) {
|
|
79657
|
+
host.handlePasteImage();
|
|
79658
|
+
return { consume: true };
|
|
79659
|
+
}
|
|
79331
79660
|
if (host.keybindings.matches(data, "expandTools")) {
|
|
79332
79661
|
host.toggleToolsExpansion();
|
|
79333
79662
|
return { consume: true };
|
|
@@ -79348,6 +79677,473 @@ function setupInteractiveKeybindings(host) {
|
|
|
79348
79677
|
});
|
|
79349
79678
|
}
|
|
79350
79679
|
|
|
79680
|
+
// src/clipboard/read-clipboard-image.ts
|
|
79681
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
79682
|
+
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
79683
|
+
import { existsSync as existsSync18, readFileSync as readFileSync17, statSync as statSync12, unlinkSync as unlinkSync8, writeFileSync as writeFileSync12 } from "node:fs";
|
|
79684
|
+
import { tmpdir } from "node:os";
|
|
79685
|
+
import { join as join20 } from "node:path";
|
|
79686
|
+
var MAX_IMAGE_BYTES = 50 * 1024 * 1024;
|
|
79687
|
+
var COMMAND_TIMEOUT_MS = 1e4;
|
|
79688
|
+
function isSpawnFailure(outcome) {
|
|
79689
|
+
return !outcome.ok;
|
|
79690
|
+
}
|
|
79691
|
+
function defaultSpawnFn(file, args, spawnImpl = spawn2, maxBytes = MAX_IMAGE_BYTES, timeoutMs = COMMAND_TIMEOUT_MS) {
|
|
79692
|
+
return new Promise((resolve7) => {
|
|
79693
|
+
let child;
|
|
79694
|
+
try {
|
|
79695
|
+
child = spawnImpl(file, args, {
|
|
79696
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
79697
|
+
windowsHide: true
|
|
79698
|
+
});
|
|
79699
|
+
} catch (err) {
|
|
79700
|
+
resolve7({ ok: false, error: "spawn-failed", message: err instanceof Error ? err.message : String(err) });
|
|
79701
|
+
return;
|
|
79702
|
+
}
|
|
79703
|
+
let settled = false;
|
|
79704
|
+
const stdoutChunks = [];
|
|
79705
|
+
let stderrText = "";
|
|
79706
|
+
let stdoutBytes = 0;
|
|
79707
|
+
const timer = setTimeout(() => {
|
|
79708
|
+
if (settled) return;
|
|
79709
|
+
settled = true;
|
|
79710
|
+
try {
|
|
79711
|
+
child.kill("SIGKILL");
|
|
79712
|
+
} catch {
|
|
79713
|
+
}
|
|
79714
|
+
resolve7({ ok: false, error: "timeout" });
|
|
79715
|
+
}, timeoutMs);
|
|
79716
|
+
child.on("error", (err) => {
|
|
79717
|
+
if (settled) return;
|
|
79718
|
+
settled = true;
|
|
79719
|
+
clearTimeout(timer);
|
|
79720
|
+
resolve7({ ok: false, error: err.code === "ENOENT" ? "not-found" : "spawn-failed", message: err.message });
|
|
79721
|
+
});
|
|
79722
|
+
child.stdout?.on("data", (chunk) => {
|
|
79723
|
+
if (settled) return;
|
|
79724
|
+
if (chunk.length > maxBytes - stdoutBytes) {
|
|
79725
|
+
settled = true;
|
|
79726
|
+
clearTimeout(timer);
|
|
79727
|
+
stdoutChunks.length = 0;
|
|
79728
|
+
resolve7({ ok: false, error: "too-large" });
|
|
79729
|
+
try {
|
|
79730
|
+
child.kill("SIGKILL");
|
|
79731
|
+
} catch {
|
|
79732
|
+
}
|
|
79733
|
+
return;
|
|
79734
|
+
}
|
|
79735
|
+
stdoutBytes += chunk.length;
|
|
79736
|
+
stdoutChunks.push(chunk);
|
|
79737
|
+
});
|
|
79738
|
+
child.stderr?.on("data", (chunk) => {
|
|
79739
|
+
if (!settled && stderrText.length < 4e3) stderrText += chunk.subarray(0, 4e3 - stderrText.length).toString("utf8");
|
|
79740
|
+
});
|
|
79741
|
+
child.on("close", (code) => {
|
|
79742
|
+
if (settled) return;
|
|
79743
|
+
settled = true;
|
|
79744
|
+
clearTimeout(timer);
|
|
79745
|
+
resolve7({ ok: true, result: { code: code ?? -1, stdout: Buffer.concat(stdoutChunks, stdoutBytes), stderr: stderrText } });
|
|
79746
|
+
});
|
|
79747
|
+
});
|
|
79748
|
+
}
|
|
79749
|
+
function defaultMkTempPath(ext) {
|
|
79750
|
+
return join20(tmpdir(), `pie-clipboard-${randomBytes2(6).toString("hex")}${ext}`);
|
|
79751
|
+
}
|
|
79752
|
+
async function readClipboardImage(deps = {}) {
|
|
79753
|
+
const platform2 = deps.platform ?? process.platform;
|
|
79754
|
+
const env = deps.env ?? process.env;
|
|
79755
|
+
const spawnImpl = deps.spawnImpl ?? defaultSpawnFn;
|
|
79756
|
+
const mkTempPath = deps.mkTempPath ?? defaultMkTempPath;
|
|
79757
|
+
switch (platform2) {
|
|
79758
|
+
case "darwin":
|
|
79759
|
+
return readMacClipboard(spawnImpl, mkTempPath);
|
|
79760
|
+
case "win32":
|
|
79761
|
+
return readWindowsClipboard(spawnImpl, mkTempPath);
|
|
79762
|
+
case "linux":
|
|
79763
|
+
case "freebsd":
|
|
79764
|
+
case "openbsd":
|
|
79765
|
+
case "netbsd":
|
|
79766
|
+
return readLinuxClipboard(spawnImpl, mkTempPath, env);
|
|
79767
|
+
default:
|
|
79768
|
+
return {
|
|
79769
|
+
ok: false,
|
|
79770
|
+
kind: "unsupported-platform",
|
|
79771
|
+
message: `Clipboard image paste is not supported on ${platform2}.`
|
|
79772
|
+
};
|
|
79773
|
+
}
|
|
79774
|
+
}
|
|
79775
|
+
function escapeAppleScriptString(value) {
|
|
79776
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
79777
|
+
}
|
|
79778
|
+
async function readMacClipboard(spawnImpl, mkTempPath) {
|
|
79779
|
+
const targetPath = mkTempPath(".png");
|
|
79780
|
+
const outcome = await spawnImpl("osascript", [
|
|
79781
|
+
"-e",
|
|
79782
|
+
"set pngData to (the clipboard as \xABclass PNGf\xBB)",
|
|
79783
|
+
"-e",
|
|
79784
|
+
`set fp to open for access POSIX file "${escapeAppleScriptString(targetPath)}" with write permission`,
|
|
79785
|
+
"-e",
|
|
79786
|
+
"write pngData to fp",
|
|
79787
|
+
"-e",
|
|
79788
|
+
"close access fp"
|
|
79789
|
+
]);
|
|
79790
|
+
if (isSpawnFailure(outcome)) {
|
|
79791
|
+
return spawnFailure(outcome, "osascript");
|
|
79792
|
+
}
|
|
79793
|
+
if (outcome.result.code !== 0) {
|
|
79794
|
+
const stderr = outcome.result.stderr.trim();
|
|
79795
|
+
if (/PNGf|Can't|can’t/i.test(stderr)) {
|
|
79796
|
+
return { ok: false, kind: "no-image", message: "Clipboard does not contain an image." };
|
|
79797
|
+
}
|
|
79798
|
+
return {
|
|
79799
|
+
ok: false,
|
|
79800
|
+
kind: "failed",
|
|
79801
|
+
message: `osascript failed: ${truncate(stderr) || `exit ${outcome.result.code}`}`
|
|
79802
|
+
};
|
|
79803
|
+
}
|
|
79804
|
+
return finalizeTempImage(targetPath, "image/png");
|
|
79805
|
+
}
|
|
79806
|
+
function escapePowerShellSingleQuoted(value) {
|
|
79807
|
+
return value.replace(/'/g, "''");
|
|
79808
|
+
}
|
|
79809
|
+
async function readWindowsClipboard(spawnImpl, mkTempPath) {
|
|
79810
|
+
const targetPath = mkTempPath(".png");
|
|
79811
|
+
const script = [
|
|
79812
|
+
"Add-Type -AssemblyName System.Windows.Forms",
|
|
79813
|
+
"Add-Type -AssemblyName System.Drawing",
|
|
79814
|
+
"$img = [System.Windows.Forms.Clipboard]::GetImage()",
|
|
79815
|
+
"if ($null -eq $img) { exit 2 }",
|
|
79816
|
+
`$img.Save('${escapePowerShellSingleQuoted(targetPath)}', [System.Drawing.Imaging.ImageFormat]::Png)`,
|
|
79817
|
+
"exit 0"
|
|
79818
|
+
].join("\n");
|
|
79819
|
+
const outcome = await spawnImpl("powershell", [
|
|
79820
|
+
"-NoProfile",
|
|
79821
|
+
"-NonInteractive",
|
|
79822
|
+
"-STA",
|
|
79823
|
+
"-Command",
|
|
79824
|
+
script
|
|
79825
|
+
]);
|
|
79826
|
+
if (isSpawnFailure(outcome)) {
|
|
79827
|
+
return spawnFailure(outcome, "powershell");
|
|
79828
|
+
}
|
|
79829
|
+
if (outcome.result.code === 2) {
|
|
79830
|
+
return { ok: false, kind: "no-image", message: "Clipboard does not contain an image." };
|
|
79831
|
+
}
|
|
79832
|
+
if (outcome.result.code !== 0) {
|
|
79833
|
+
return {
|
|
79834
|
+
ok: false,
|
|
79835
|
+
kind: "failed",
|
|
79836
|
+
message: `powershell failed: ${truncate(outcome.result.stderr.trim()) || `exit ${outcome.result.code}`}`
|
|
79837
|
+
};
|
|
79838
|
+
}
|
|
79839
|
+
return finalizeTempImage(targetPath, "image/png");
|
|
79840
|
+
}
|
|
79841
|
+
var PREFERRED_IMAGE_MIMES = ["image/png", "image/jpeg"];
|
|
79842
|
+
function extensionForMime(mimeType) {
|
|
79843
|
+
switch (mimeType) {
|
|
79844
|
+
case "image/png":
|
|
79845
|
+
return ".png";
|
|
79846
|
+
case "image/jpeg":
|
|
79847
|
+
return ".jpg";
|
|
79848
|
+
case "image/gif":
|
|
79849
|
+
return ".gif";
|
|
79850
|
+
case "image/webp":
|
|
79851
|
+
return ".webp";
|
|
79852
|
+
case "image/bmp":
|
|
79853
|
+
return ".bmp";
|
|
79854
|
+
default:
|
|
79855
|
+
return ".png";
|
|
79856
|
+
}
|
|
79857
|
+
}
|
|
79858
|
+
function pickImageMime(advertised) {
|
|
79859
|
+
for (const mime of PREFERRED_IMAGE_MIMES) {
|
|
79860
|
+
if (advertised.includes(mime)) return mime;
|
|
79861
|
+
}
|
|
79862
|
+
return advertised.find((mime) => mime.startsWith("image/"));
|
|
79863
|
+
}
|
|
79864
|
+
async function readLinuxClipboard(spawnImpl, mkTempPath, env) {
|
|
79865
|
+
if (env.WAYLAND_DISPLAY) {
|
|
79866
|
+
return readWaylandClipboard(spawnImpl, mkTempPath);
|
|
79867
|
+
}
|
|
79868
|
+
if (env.DISPLAY) {
|
|
79869
|
+
return readX11Clipboard(spawnImpl, mkTempPath);
|
|
79870
|
+
}
|
|
79871
|
+
return {
|
|
79872
|
+
ok: false,
|
|
79873
|
+
kind: "failed",
|
|
79874
|
+
message: "No graphical session detected (neither WAYLAND_DISPLAY nor DISPLAY is set)."
|
|
79875
|
+
};
|
|
79876
|
+
}
|
|
79877
|
+
async function readWaylandClipboard(spawnImpl, mkTempPath) {
|
|
79878
|
+
const listOutcome = await spawnImpl("wl-paste", ["--list-types"]);
|
|
79879
|
+
if (isSpawnFailure(listOutcome)) {
|
|
79880
|
+
return spawnFailure(listOutcome, "wl-paste");
|
|
79881
|
+
}
|
|
79882
|
+
if (listOutcome.result.code !== 0) {
|
|
79883
|
+
return { ok: false, kind: "no-image", message: "Clipboard does not contain an image." };
|
|
79884
|
+
}
|
|
79885
|
+
const advertised = listOutcome.result.stdout.toString("utf8").split("\n").map((line) => line.trim()).filter(Boolean);
|
|
79886
|
+
const mime = pickImageMime(advertised);
|
|
79887
|
+
if (!mime) {
|
|
79888
|
+
return { ok: false, kind: "no-image", message: "Clipboard does not contain an image." };
|
|
79889
|
+
}
|
|
79890
|
+
const dataOutcome = await spawnImpl("wl-paste", ["--type", mime]);
|
|
79891
|
+
if (isSpawnFailure(dataOutcome)) {
|
|
79892
|
+
return spawnFailure(dataOutcome, "wl-paste");
|
|
79893
|
+
}
|
|
79894
|
+
if (dataOutcome.result.code !== 0) {
|
|
79895
|
+
return {
|
|
79896
|
+
ok: false,
|
|
79897
|
+
kind: "failed",
|
|
79898
|
+
message: `wl-paste failed: ${truncate(dataOutcome.result.stderr.trim()) || `exit ${dataOutcome.result.code}`}`
|
|
79899
|
+
};
|
|
79900
|
+
}
|
|
79901
|
+
return writeImageBytes(dataOutcome.result.stdout, mime, mkTempPath);
|
|
79902
|
+
}
|
|
79903
|
+
async function readX11Clipboard(spawnImpl, mkTempPath) {
|
|
79904
|
+
const listOutcome = await spawnImpl("xclip", ["-selection", "clipboard", "-t", "TARGETS", "-o"]);
|
|
79905
|
+
if (isSpawnFailure(listOutcome)) {
|
|
79906
|
+
return spawnFailure(listOutcome, "xclip");
|
|
79907
|
+
}
|
|
79908
|
+
if (listOutcome.result.code !== 0) {
|
|
79909
|
+
return { ok: false, kind: "no-image", message: "Clipboard does not contain an image." };
|
|
79910
|
+
}
|
|
79911
|
+
const advertised = listOutcome.result.stdout.toString("utf8").split("\n").map((line) => line.trim()).filter(Boolean);
|
|
79912
|
+
const mime = pickImageMime(advertised);
|
|
79913
|
+
if (!mime) {
|
|
79914
|
+
return { ok: false, kind: "no-image", message: "Clipboard does not contain an image." };
|
|
79915
|
+
}
|
|
79916
|
+
const dataOutcome = await spawnImpl("xclip", ["-selection", "clipboard", "-t", mime, "-o"]);
|
|
79917
|
+
if (isSpawnFailure(dataOutcome)) {
|
|
79918
|
+
return spawnFailure(dataOutcome, "xclip");
|
|
79919
|
+
}
|
|
79920
|
+
if (dataOutcome.result.code !== 0) {
|
|
79921
|
+
return {
|
|
79922
|
+
ok: false,
|
|
79923
|
+
kind: "failed",
|
|
79924
|
+
message: `xclip failed: ${truncate(dataOutcome.result.stderr.trim()) || `exit ${dataOutcome.result.code}`}`
|
|
79925
|
+
};
|
|
79926
|
+
}
|
|
79927
|
+
return writeImageBytes(dataOutcome.result.stdout, mime, mkTempPath);
|
|
79928
|
+
}
|
|
79929
|
+
function writeImageBytes(bytes, declaredMime, mkTempPath) {
|
|
79930
|
+
if (bytes.length === 0) {
|
|
79931
|
+
return { ok: false, kind: "no-image", message: "Clipboard does not contain an image." };
|
|
79932
|
+
}
|
|
79933
|
+
if (bytes.length > MAX_IMAGE_BYTES) {
|
|
79934
|
+
return { ok: false, kind: "too-large", message: `Clipboard image is too large (${formatBytes2(bytes.length)}).` };
|
|
79935
|
+
}
|
|
79936
|
+
const mimeType = detectMimeFromMagic(bytes) ?? declaredMime;
|
|
79937
|
+
const targetPath = mkTempPath(extensionForMime(mimeType));
|
|
79938
|
+
try {
|
|
79939
|
+
writeFileSync12(targetPath, bytes);
|
|
79940
|
+
} catch (err) {
|
|
79941
|
+
return { ok: false, kind: "failed", message: `Failed to write temp image: ${errorMessage4(err)}` };
|
|
79942
|
+
}
|
|
79943
|
+
return {
|
|
79944
|
+
ok: true,
|
|
79945
|
+
path: targetPath,
|
|
79946
|
+
mimeType,
|
|
79947
|
+
cleanup: makeCleanup(targetPath)
|
|
79948
|
+
};
|
|
79949
|
+
}
|
|
79950
|
+
function finalizeTempImage(path34, mimeType) {
|
|
79951
|
+
let bytes;
|
|
79952
|
+
try {
|
|
79953
|
+
if (!existsSync18(path34)) {
|
|
79954
|
+
return { ok: false, kind: "no-image", message: "Clipboard does not contain an image." };
|
|
79955
|
+
}
|
|
79956
|
+
const size = statSync12(path34).size;
|
|
79957
|
+
if (size === 0) {
|
|
79958
|
+
makeCleanup(path34)();
|
|
79959
|
+
return { ok: false, kind: "no-image", message: "Clipboard does not contain an image." };
|
|
79960
|
+
}
|
|
79961
|
+
if (size > MAX_IMAGE_BYTES) {
|
|
79962
|
+
makeCleanup(path34)();
|
|
79963
|
+
return { ok: false, kind: "too-large", message: `Clipboard image is too large (${formatBytes2(size)}).` };
|
|
79964
|
+
}
|
|
79965
|
+
bytes = readFileSync17(path34);
|
|
79966
|
+
} catch (err) {
|
|
79967
|
+
return { ok: false, kind: "failed", message: `Failed to read clipboard image: ${errorMessage4(err)}` };
|
|
79968
|
+
}
|
|
79969
|
+
const detected = detectMimeFromMagic(bytes);
|
|
79970
|
+
if (!detected) {
|
|
79971
|
+
makeCleanup(path34)();
|
|
79972
|
+
return { ok: false, kind: "no-image", message: "Clipboard does not contain a supported image (PNG/JPEG)." };
|
|
79973
|
+
}
|
|
79974
|
+
return { ok: true, path: path34, mimeType: detected, cleanup: makeCleanup(path34) };
|
|
79975
|
+
}
|
|
79976
|
+
function detectMimeFromMagic(bytes) {
|
|
79977
|
+
if (bytes.length >= 8 && bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71) {
|
|
79978
|
+
return "image/png";
|
|
79979
|
+
}
|
|
79980
|
+
if (bytes.length >= 3 && bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255) {
|
|
79981
|
+
return "image/jpeg";
|
|
79982
|
+
}
|
|
79983
|
+
return void 0;
|
|
79984
|
+
}
|
|
79985
|
+
function makeCleanup(path34) {
|
|
79986
|
+
return () => {
|
|
79987
|
+
try {
|
|
79988
|
+
unlinkSync8(path34);
|
|
79989
|
+
} catch {
|
|
79990
|
+
}
|
|
79991
|
+
};
|
|
79992
|
+
}
|
|
79993
|
+
function spawnFailure(outcome, tool) {
|
|
79994
|
+
if (outcome.error === "too-large") {
|
|
79995
|
+
return { ok: false, kind: "too-large", message: "Clipboard image is too large." };
|
|
79996
|
+
}
|
|
79997
|
+
if (outcome.error === "not-found") {
|
|
79998
|
+
return {
|
|
79999
|
+
ok: false,
|
|
80000
|
+
kind: "missing-tool",
|
|
80001
|
+
message: `${tool} is not installed; it is required to read clipboard images on this platform.`
|
|
80002
|
+
};
|
|
80003
|
+
}
|
|
80004
|
+
if (outcome.error === "timeout") {
|
|
80005
|
+
return { ok: false, kind: "timeout", message: `Reading the clipboard with ${tool} timed out.` };
|
|
80006
|
+
}
|
|
80007
|
+
return { ok: false, kind: "failed", message: `Failed to run ${tool}: ${outcome.message ?? "unknown error"}` };
|
|
80008
|
+
}
|
|
80009
|
+
function truncate(text, max = 200) {
|
|
80010
|
+
const trimmed = text.trim();
|
|
80011
|
+
return trimmed.length > max ? `${trimmed.slice(0, max)}\u2026` : trimmed;
|
|
80012
|
+
}
|
|
80013
|
+
function errorMessage4(err) {
|
|
80014
|
+
return err instanceof Error ? err.message : String(err);
|
|
80015
|
+
}
|
|
80016
|
+
function formatBytes2(bytes) {
|
|
80017
|
+
if (bytes >= 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
80018
|
+
return `${Math.max(1, Math.round(bytes / 1024))}KB`;
|
|
80019
|
+
}
|
|
80020
|
+
|
|
80021
|
+
// src/input/image-paste.ts
|
|
80022
|
+
import { mkdtempSync, writeFileSync as writeFileSync13, rmSync as rmSync3 } from "node:fs";
|
|
80023
|
+
import { tmpdir as tmpdir2 } from "node:os";
|
|
80024
|
+
import { join as join21 } from "node:path";
|
|
80025
|
+
var pastingHosts = /* @__PURE__ */ new WeakSet();
|
|
80026
|
+
function formatPastedImageName(date, extension = ".png") {
|
|
80027
|
+
const pad = (value) => String(value).padStart(2, "0");
|
|
80028
|
+
const hh = pad(date.getHours());
|
|
80029
|
+
const mm = pad(date.getMinutes());
|
|
80030
|
+
const ss = pad(date.getSeconds());
|
|
80031
|
+
return `pasted-${hh}${mm}${ss}${extension}`;
|
|
80032
|
+
}
|
|
80033
|
+
function terminalResultToClipboardResult(result) {
|
|
80034
|
+
if (result.ok !== true) {
|
|
80035
|
+
const kindMap = {
|
|
80036
|
+
unsupported: "failed",
|
|
80037
|
+
timeout: "timeout",
|
|
80038
|
+
denied: "failed",
|
|
80039
|
+
busy: "failed",
|
|
80040
|
+
unavailable: "no-image",
|
|
80041
|
+
"too-large": "too-large",
|
|
80042
|
+
malformed: "failed"
|
|
80043
|
+
};
|
|
80044
|
+
return { ok: false, kind: kindMap[result.kind], message: result.message };
|
|
80045
|
+
}
|
|
80046
|
+
const ext = result.mimeType === "image/jpeg" ? ".jpg" : ".png";
|
|
80047
|
+
let dir;
|
|
80048
|
+
try {
|
|
80049
|
+
dir = mkdtempSync(join21(tmpdir2(), "pie-osc5522-"));
|
|
80050
|
+
const path34 = join21(dir, formatPastedImageName(/* @__PURE__ */ new Date(), ext));
|
|
80051
|
+
writeFileSync13(path34, result.bytes);
|
|
80052
|
+
return {
|
|
80053
|
+
ok: true,
|
|
80054
|
+
path: path34,
|
|
80055
|
+
mimeType: result.mimeType,
|
|
80056
|
+
cleanup: () => {
|
|
80057
|
+
try {
|
|
80058
|
+
rmSync3(dir, { recursive: true, force: true });
|
|
80059
|
+
} catch {
|
|
80060
|
+
}
|
|
80061
|
+
}
|
|
80062
|
+
};
|
|
80063
|
+
} catch (err) {
|
|
80064
|
+
if (dir) {
|
|
80065
|
+
try {
|
|
80066
|
+
rmSync3(dir, { recursive: true, force: true });
|
|
80067
|
+
} catch {
|
|
80068
|
+
}
|
|
80069
|
+
}
|
|
80070
|
+
return { ok: false, kind: "failed", message: `Failed to materialize clipboard image: ${err instanceof Error ? err.message : String(err)}` };
|
|
80071
|
+
}
|
|
80072
|
+
}
|
|
80073
|
+
async function handleImagePaste(host, options = {}) {
|
|
80074
|
+
if (pastingHosts.has(host)) {
|
|
80075
|
+
host.showStatus("Still reading the clipboard\u2026");
|
|
80076
|
+
return;
|
|
80077
|
+
}
|
|
80078
|
+
if (!host.mentionHandler) {
|
|
80079
|
+
host.showStatus("File attachments are not available yet (still initializing).");
|
|
80080
|
+
return;
|
|
80081
|
+
}
|
|
80082
|
+
pastingHosts.add(host);
|
|
80083
|
+
const handler = host.mentionHandler;
|
|
80084
|
+
const sessionId = host.sessionManager?.getActiveSessionId();
|
|
80085
|
+
const controller = host.agentSessionController;
|
|
80086
|
+
let invalidated = false;
|
|
80087
|
+
const unsubscribe = controller?.subscribe((event) => {
|
|
80088
|
+
if (event.type === "session_invalidated") invalidated = true;
|
|
80089
|
+
});
|
|
80090
|
+
const isCurrent = () => host.mentionHandler === handler && host.sessionManager?.getActiveSessionId() === sessionId && host.agentSessionController === controller && !invalidated;
|
|
80091
|
+
const displayName = formatPastedImageName(options.now?.() ?? /* @__PURE__ */ new Date());
|
|
80092
|
+
let pending;
|
|
80093
|
+
try {
|
|
80094
|
+
pending = handler.beginPendingAttachment(displayName);
|
|
80095
|
+
let result;
|
|
80096
|
+
const terminal = host.ui?.terminal;
|
|
80097
|
+
const readTerminal = options.readTerminalClipboardImage ?? (terminal?.clipboard ? () => terminal.clipboard.readImage() : void 0);
|
|
80098
|
+
if (readTerminal) {
|
|
80099
|
+
host.showStatus("Reading clipboard via terminal\u2026");
|
|
80100
|
+
const terminalResult = await readTerminal();
|
|
80101
|
+
if (terminalResult.ok === true) {
|
|
80102
|
+
result = terminalResultToClipboardResult(terminalResult);
|
|
80103
|
+
} else if (terminalResult.kind === "unsupported") {
|
|
80104
|
+
result = await (options.readClipboardImage ?? readClipboardImage)();
|
|
80105
|
+
} else {
|
|
80106
|
+
result = terminalResultToClipboardResult(terminalResult);
|
|
80107
|
+
}
|
|
80108
|
+
} else {
|
|
80109
|
+
result = await (options.readClipboardImage ?? readClipboardImage)();
|
|
80110
|
+
}
|
|
80111
|
+
if (result.ok === false) {
|
|
80112
|
+
switch (result.kind) {
|
|
80113
|
+
case "no-image":
|
|
80114
|
+
host.showStatus("Clipboard does not contain an image.");
|
|
80115
|
+
break;
|
|
80116
|
+
case "missing-tool":
|
|
80117
|
+
host.showWarning(result.message);
|
|
80118
|
+
break;
|
|
80119
|
+
case "too-large":
|
|
80120
|
+
host.showError(result.message);
|
|
80121
|
+
break;
|
|
80122
|
+
default:
|
|
80123
|
+
host.showError(result.message);
|
|
80124
|
+
break;
|
|
80125
|
+
}
|
|
80126
|
+
return;
|
|
80127
|
+
}
|
|
80128
|
+
try {
|
|
80129
|
+
if (!isCurrent()) return;
|
|
80130
|
+
await handler.attachLocalFile(result.path, displayName, pending.token, isCurrent);
|
|
80131
|
+
} finally {
|
|
80132
|
+
result.cleanup();
|
|
80133
|
+
}
|
|
80134
|
+
} catch (err) {
|
|
80135
|
+
host.showError(`Paste failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
80136
|
+
} finally {
|
|
80137
|
+
try {
|
|
80138
|
+
pending?.finish();
|
|
80139
|
+
if (isCurrent()) controller?.requestQueueDispatch?.();
|
|
80140
|
+
} finally {
|
|
80141
|
+
unsubscribe?.();
|
|
80142
|
+
pastingHosts.delete(host);
|
|
80143
|
+
}
|
|
80144
|
+
}
|
|
80145
|
+
}
|
|
80146
|
+
|
|
79351
80147
|
// src/runtime/interactive-queue-ui.ts
|
|
79352
80148
|
function updatePendingMessagesDisplay(host) {
|
|
79353
80149
|
host.pendingMessagesContainer.clear();
|
|
@@ -79359,11 +80155,11 @@ function updatePendingMessagesDisplay(host) {
|
|
|
79359
80155
|
const steerMessages = queuedInputs.filter((m2) => m2.mode === "steer");
|
|
79360
80156
|
const followUpMessages = queuedInputs.filter((m2) => m2.mode === "followUp");
|
|
79361
80157
|
for (const msg of steerMessages) {
|
|
79362
|
-
const text = theme.fg("dim", ` [steer] ${
|
|
80158
|
+
const text = theme.fg("dim", ` [steer] ${truncate2(msg.displayText, 50)}`);
|
|
79363
80159
|
host.pendingMessagesContainer.addChild(new Text(text, 1, 0));
|
|
79364
80160
|
}
|
|
79365
80161
|
for (const msg of followUpMessages) {
|
|
79366
|
-
const text = theme.fg("dim", ` [followUp] ${
|
|
80162
|
+
const text = theme.fg("dim", ` [followUp] ${truncate2(msg.displayText, 50)}`);
|
|
79367
80163
|
host.pendingMessagesContainer.addChild(new Text(text, 1, 0));
|
|
79368
80164
|
}
|
|
79369
80165
|
const dequeueHint = host.keybindings.getKeys("dequeue")[0] || "alt+up";
|
|
@@ -79472,7 +80268,7 @@ function handleSteer(host) {
|
|
|
79472
80268
|
void host.editor.onSubmit(text);
|
|
79473
80269
|
}
|
|
79474
80270
|
}
|
|
79475
|
-
function
|
|
80271
|
+
function truncate2(text, maxLength) {
|
|
79476
80272
|
if (text.length <= maxLength) return text;
|
|
79477
80273
|
return text.slice(0, maxLength) + "...";
|
|
79478
80274
|
}
|
|
@@ -79572,6 +80368,12 @@ var FooterComponent = class {
|
|
|
79572
80368
|
* derived from this at render time so long silent tool runs (e.g.
|
|
79573
80369
|
* subagents) still visibly tick — a moving elapsed says "alive". */
|
|
79574
80370
|
busySince = null;
|
|
80371
|
+
/** When the footer last started waiting for the user. Same derived-at-render
|
|
80372
|
+
* approach: the wait elapsed ticks only while a wait timer runs. */
|
|
80373
|
+
waitingSince = null;
|
|
80374
|
+
/** Animation timer for the waiting state (drives the wait elapsed ticker
|
|
80375
|
+
* in place of the stopped busy spinner). */
|
|
80376
|
+
waitingTimer = null;
|
|
79575
80377
|
/** Keyed ambient status slots for extensions (ctx.ui.setStatus). */
|
|
79576
80378
|
extensionStatuses = new ExtensionStatusSlots();
|
|
79577
80379
|
/** Set callback to request re-render when animation updates (pass true to force) */
|
|
@@ -79589,6 +80391,17 @@ var FooterComponent = class {
|
|
|
79589
80391
|
this.busySince = null;
|
|
79590
80392
|
this.stopSpinner();
|
|
79591
80393
|
}
|
|
80394
|
+
if (state.waitingForUser === true) {
|
|
80395
|
+
if (this.waitingSince === null) this.waitingSince = performance.now();
|
|
80396
|
+
this.startWaitingTimer();
|
|
80397
|
+
this.stopSpinner();
|
|
80398
|
+
} else if (state.waitingForUser === false) {
|
|
80399
|
+
this.waitingSince = null;
|
|
80400
|
+
this.stopWaitingTimer();
|
|
80401
|
+
if (this.state.status === "thinking" || this.state.status === "processing") {
|
|
80402
|
+
this.startSpinner();
|
|
80403
|
+
}
|
|
80404
|
+
}
|
|
79592
80405
|
}
|
|
79593
80406
|
setAutoCompactEnabled(enabled) {
|
|
79594
80407
|
this.autoCompactEnabled = enabled;
|
|
@@ -79597,6 +80410,7 @@ var FooterComponent = class {
|
|
|
79597
80410
|
}
|
|
79598
80411
|
dispose() {
|
|
79599
80412
|
this.stopSpinner();
|
|
80413
|
+
this.stopWaitingTimer();
|
|
79600
80414
|
}
|
|
79601
80415
|
/** Start spinner animation */
|
|
79602
80416
|
startSpinner() {
|
|
@@ -79614,6 +80428,20 @@ var FooterComponent = class {
|
|
|
79614
80428
|
this.spinnerTimer = null;
|
|
79615
80429
|
}
|
|
79616
80430
|
}
|
|
80431
|
+
/** Ticker for the waiting state: no spinner animation (nothing is
|
|
80432
|
+
* progressing), just a render tick so the wait elapsed updates. */
|
|
80433
|
+
startWaitingTimer() {
|
|
80434
|
+
if (this.waitingTimer) return;
|
|
80435
|
+
this.waitingTimer = setInterval(() => {
|
|
80436
|
+
this.onRequestRender?.();
|
|
80437
|
+
}, SPINNER_INTERVAL);
|
|
80438
|
+
}
|
|
80439
|
+
stopWaitingTimer() {
|
|
80440
|
+
if (this.waitingTimer) {
|
|
80441
|
+
clearInterval(this.waitingTimer);
|
|
80442
|
+
this.waitingTimer = null;
|
|
80443
|
+
}
|
|
80444
|
+
}
|
|
79617
80445
|
/** Get current spinner character */
|
|
79618
80446
|
getSpinner() {
|
|
79619
80447
|
if (this.state.status !== "thinking" && this.state.status !== "processing") {
|
|
@@ -79688,23 +80516,27 @@ var FooterComponent = class {
|
|
|
79688
80516
|
processing: "warning",
|
|
79689
80517
|
error: "error"
|
|
79690
80518
|
};
|
|
79691
|
-
const
|
|
79692
|
-
|
|
79693
|
-
|
|
79694
|
-
|
|
79695
|
-
|
|
79696
|
-
|
|
79697
|
-
|
|
79698
|
-
|
|
79699
|
-
|
|
79700
|
-
|
|
79701
|
-
|
|
79702
|
-
|
|
79703
|
-
|
|
79704
|
-
|
|
79705
|
-
|
|
79706
|
-
|
|
79707
|
-
|
|
80519
|
+
const isWaitingForUser2 = state.waitingForUser === true;
|
|
80520
|
+
const waitingElapsed = this.waitingSince !== null && isWaitingForUser2 ? ` \xB7 ${formatElapsed(performance.now() - this.waitingSince)}` : "";
|
|
80521
|
+
const statusWithSpinner = isWaitingForUser2 ? theme.fg("accent", `\u23F8 Waiting for you${waitingElapsed}`) : (() => {
|
|
80522
|
+
const spinner = this.getSpinner();
|
|
80523
|
+
let statusText;
|
|
80524
|
+
if (state.lifecycleEvent && state.status !== "ready") {
|
|
80525
|
+
statusText = state.lifecycleEvent;
|
|
80526
|
+
} else {
|
|
80527
|
+
const statusDisplayMap = {
|
|
80528
|
+
ready: "Ready",
|
|
80529
|
+
thinking: "Thinking",
|
|
80530
|
+
processing: "Processing",
|
|
80531
|
+
error: "Error"
|
|
80532
|
+
};
|
|
80533
|
+
statusText = statusDisplayMap[state.status] || state.status;
|
|
80534
|
+
}
|
|
80535
|
+
const isBusy = state.status === "thinking" || state.status === "processing";
|
|
80536
|
+
const busyElapsed = this.busySince !== null && isBusy ? ` \xB7 ${formatElapsed(performance.now() - this.busySince)}` : "";
|
|
80537
|
+
return theme.fg(statusColor[state.status], `${spinner ? `${spinner} ` : ""}${statusText}${busyElapsed}`);
|
|
80538
|
+
})();
|
|
80539
|
+
statsParts.push(statusWithSpinner);
|
|
79708
80540
|
let statsLeft = statsParts.join(" ");
|
|
79709
80541
|
statsLeft += this.extensionStatuses.format();
|
|
79710
80542
|
const modelName = state.modelName || "no-model";
|
|
@@ -79835,8 +80667,8 @@ function calculateCliContextUsage(params) {
|
|
|
79835
80667
|
};
|
|
79836
80668
|
}
|
|
79837
80669
|
function createCliAutoCompactDecision(params) {
|
|
79838
|
-
const
|
|
79839
|
-
if (
|
|
80670
|
+
const errorMessage5 = params.message?.role === "assistant" ? params.message.errorMessage : void 0;
|
|
80671
|
+
if (errorMessage5 && params.isContextOverflowError(errorMessage5)) {
|
|
79840
80672
|
return { reason: "overflow", willRetry: true };
|
|
79841
80673
|
}
|
|
79842
80674
|
if (!params.autoCompactEnabled || params.contextWindow <= 0) {
|
|
@@ -79890,7 +80722,7 @@ async function createCliAutoCompactionResult(params) {
|
|
|
79890
80722
|
systemPrompt: params.systemPrompt,
|
|
79891
80723
|
signal: params.context.signal
|
|
79892
80724
|
};
|
|
79893
|
-
const summary = await createCompactionSummary(projectCliHostEnvelopes(params.context.messages, params.onProjection), compactOptions);
|
|
80725
|
+
const summary = await createCompactionSummary(projectCliHostEnvelopes(params.context.messages, params.onProjection, params.envelopeRegistry), compactOptions);
|
|
79894
80726
|
if (params.context.signal?.aborted) {
|
|
79895
80727
|
return { aborted: true };
|
|
79896
80728
|
}
|
|
@@ -79898,7 +80730,7 @@ async function createCliAutoCompactionResult(params) {
|
|
|
79898
80730
|
summary,
|
|
79899
80731
|
retainedTail,
|
|
79900
80732
|
...retainedTail.kind === "from-entry" ? { firstKeptEntryId: retainedTail.entryId } : {},
|
|
79901
|
-
tokensBefore: calculateTotalTokens(params.context.messages)
|
|
80733
|
+
tokensBefore: params.context.preparation?.inputTokens ?? calculateTotalTokens(projectCliHostEnvelopes(params.context.messages, void 0, params.envelopeRegistry))
|
|
79902
80734
|
};
|
|
79903
80735
|
}
|
|
79904
80736
|
function stripStaleUsageBeforeCompaction(messages, latestCompactionTimestamp) {
|
|
@@ -79923,153 +80755,6 @@ function stripStaleUsageBeforeCompaction(messages, latestCompactionTimestamp) {
|
|
|
79923
80755
|
});
|
|
79924
80756
|
}
|
|
79925
80757
|
|
|
79926
|
-
// src/runtime/retry-policy.ts
|
|
79927
|
-
var TRANSIENT_NETWORK_ERROR_PATTERN = /sse stream aborted|sse stream closed before end|sse stream ended before response completed|responses stream ended without a terminal event|(?:read\s+)?ECONNRESET|ETIMEDOUT|EAI_AGAIN|ENOTFOUND|ECONNREFUSED|(?:read\s+|write\s+)?EPIPE|socket hang up|request timeout|websocket upgrade refused|websocket handshake|websocket connection failed|websocket transport failed|connection closed before opening|client network socket disconnected before secure TLS connection was established|connection.?error|connection.?refused|other side closed|fetch failed|upstream.?connect|reset before headers|terminated/i;
|
|
79928
|
-
var TLS_VALIDATION_ERROR_PATTERN = /certificate (?:has )?expired|certificate is not yet valid|unable to verify (?:the first certificate|certificate)|unable to get (?:local )?issuer certificate|self[-_ ]signed cert(?:ificate)?|CERT_HAS_EXPIRED|SELF_SIGNED_CERT|does not match certificate's altnames|ERR_TLS_CERT_ALTNAME_INVALID/i;
|
|
79929
|
-
var PROVIDER_TRANSIENT_ERROR_PATTERN = /overloaded|rate.?limit|too many requests|\b429\b|\b500\b|\b502\b|\b503\b|\b504\b|service.?unavailable|server error|internal error|retry delay|quota (?:has been |is )?exhausted/i;
|
|
79930
|
-
var USER_ABORT_PATTERN = /request was aborted|local abort signal|user abort|user_interrupt|interrupted by user|esc pressed|ctrl\+c/i;
|
|
79931
|
-
var AUTH_CONFIG_PATTERN = /missing api key|invalid api key|api key.*invalid|unauthorized|\b401\b|\b403\b|forbidden|authentication failed|no configured model|no models? are configured/i;
|
|
79932
|
-
var QUOTA_EXHAUSTED_PATTERN = /insufficient[_ ]quota|exceeded[_ ]current[_ ]quota|exceeded your current quota|billing[_ ]hard[_ ]limit|insufficient[_ ]balance|credit balance is too low|\barrearage\b|余额不足|\b(?:account|monthly|billing) quota (?:has been |is )?exhausted/i;
|
|
79933
|
-
var INVALID_FILE_REFERENCE_PATTERN = /not the owner of this file|owner of this file|invalid_authentication_error/i;
|
|
79934
|
-
var INVALID_REQUEST_PATTERN = /bad request|\b400\b|invalid request|invalid schema|schema validation|invalid parameter|unsupported parameter|malformed/i;
|
|
79935
|
-
var CLI_RETRY_MAX_RETRIES = 3;
|
|
79936
|
-
var CLI_RETRY_BASE_DELAY_MS = 2e3;
|
|
79937
|
-
var CLI_TRANSIENT_NETWORK_MAX_RETRIES = 10;
|
|
79938
|
-
var CLI_RETRY_TOTAL_MAX_RETRIES = 12;
|
|
79939
|
-
var CLI_RETRY_MAX_DELAY_MS = 6e4;
|
|
79940
|
-
function isCliContextOverflowError(errorMessage4) {
|
|
79941
|
-
return /context length exceeded|context_length_exceeded|maximum context length|maximum context size|too many tokens|input.*too long|prompt.*too long|context window|token limit exceeded|exceeds.{0,20}context/i.test(
|
|
79942
|
-
errorMessage4
|
|
79943
|
-
);
|
|
79944
|
-
}
|
|
79945
|
-
function createClassification(kind, message, overrides) {
|
|
79946
|
-
return {
|
|
79947
|
-
kind,
|
|
79948
|
-
message,
|
|
79949
|
-
retryable: false,
|
|
79950
|
-
compactable: false,
|
|
79951
|
-
userAbort: false,
|
|
79952
|
-
terminal: true,
|
|
79953
|
-
...overrides
|
|
79954
|
-
};
|
|
79955
|
-
}
|
|
79956
|
-
function classifyCliFailure(context) {
|
|
79957
|
-
const errorMessage4 = typeof context === "string" ? context : context.errorMessage;
|
|
79958
|
-
const structuredReplayClass = typeof context === "string" ? void 0 : context.message?.role === "assistant" ? context.message.replayClass : void 0;
|
|
79959
|
-
if (isCliContextOverflowError(errorMessage4)) {
|
|
79960
|
-
return createClassification("context_overflow", errorMessage4, {
|
|
79961
|
-
compactable: true,
|
|
79962
|
-
terminal: false
|
|
79963
|
-
});
|
|
79964
|
-
}
|
|
79965
|
-
if (USER_ABORT_PATTERN.test(errorMessage4)) {
|
|
79966
|
-
return createClassification("user_abort", errorMessage4, {
|
|
79967
|
-
userAbort: true,
|
|
79968
|
-
terminal: false
|
|
79969
|
-
});
|
|
79970
|
-
}
|
|
79971
|
-
if (INVALID_FILE_REFERENCE_PATTERN.test(errorMessage4)) {
|
|
79972
|
-
return createClassification("invalid_file_reference", errorMessage4);
|
|
79973
|
-
}
|
|
79974
|
-
if (AUTH_CONFIG_PATTERN.test(errorMessage4) || QUOTA_EXHAUSTED_PATTERN.test(errorMessage4)) {
|
|
79975
|
-
return createClassification("auth_config", errorMessage4);
|
|
79976
|
-
}
|
|
79977
|
-
if (TLS_VALIDATION_ERROR_PATTERN.test(errorMessage4)) {
|
|
79978
|
-
return createClassification("tls_config", errorMessage4, {
|
|
79979
|
-
retryable: true,
|
|
79980
|
-
terminal: false
|
|
79981
|
-
});
|
|
79982
|
-
}
|
|
79983
|
-
if (structuredReplayClass === "stream_lost" || structuredReplayClass === "stream_lost_partial" || TRANSIENT_NETWORK_ERROR_PATTERN.test(errorMessage4)) {
|
|
79984
|
-
return createClassification("transient_network", errorMessage4, {
|
|
79985
|
-
retryable: true,
|
|
79986
|
-
terminal: false
|
|
79987
|
-
});
|
|
79988
|
-
}
|
|
79989
|
-
if (errorMessage4.includes(EMPTY_ASSISTANT_CONTENT_ERROR)) {
|
|
79990
|
-
return createClassification("provider_transient", errorMessage4, {
|
|
79991
|
-
retryable: true,
|
|
79992
|
-
terminal: false
|
|
79993
|
-
});
|
|
79994
|
-
}
|
|
79995
|
-
if (errorMessage4.includes(OPENAI_COMPAT_PROTOCOL_ERROR_CODE)) {
|
|
79996
|
-
return createClassification("provider_transient", errorMessage4, {
|
|
79997
|
-
retryable: true,
|
|
79998
|
-
terminal: false
|
|
79999
|
-
});
|
|
80000
|
-
}
|
|
80001
|
-
if (PROVIDER_TRANSIENT_ERROR_PATTERN.test(errorMessage4)) {
|
|
80002
|
-
return createClassification("provider_transient", errorMessage4, {
|
|
80003
|
-
retryable: true,
|
|
80004
|
-
terminal: false
|
|
80005
|
-
});
|
|
80006
|
-
}
|
|
80007
|
-
if (INVALID_REQUEST_PATTERN.test(errorMessage4)) {
|
|
80008
|
-
return createClassification("invalid_request", errorMessage4);
|
|
80009
|
-
}
|
|
80010
|
-
return createClassification("unknown", errorMessage4);
|
|
80011
|
-
}
|
|
80012
|
-
function isCliRetryableError(errorMessage4) {
|
|
80013
|
-
return classifyCliFailure(errorMessage4).retryable;
|
|
80014
|
-
}
|
|
80015
|
-
function getCliRetryBaseDelayMs() {
|
|
80016
|
-
const override = process.env.PIE_TEST_CLI_RETRY_BASE_DELAY_MS;
|
|
80017
|
-
if (!override) {
|
|
80018
|
-
return CLI_RETRY_BASE_DELAY_MS;
|
|
80019
|
-
}
|
|
80020
|
-
const parsed = Number(override);
|
|
80021
|
-
return Number.isFinite(parsed) && parsed >= 0 ? parsed : CLI_RETRY_BASE_DELAY_MS;
|
|
80022
|
-
}
|
|
80023
|
-
function getCliTransientNetworkMaxRetries() {
|
|
80024
|
-
const override = process.env.PIE_RETRY_TRANSIENT_NETWORK_MAX_RETRIES;
|
|
80025
|
-
if (!override) {
|
|
80026
|
-
return CLI_TRANSIENT_NETWORK_MAX_RETRIES;
|
|
80027
|
-
}
|
|
80028
|
-
const parsed = Number(override);
|
|
80029
|
-
return Number.isFinite(parsed) && parsed >= 0 ? Math.floor(parsed) : CLI_TRANSIENT_NETWORK_MAX_RETRIES;
|
|
80030
|
-
}
|
|
80031
|
-
function getCliRetryMaxDelayMs() {
|
|
80032
|
-
const override = process.env.PIE_RETRY_MAX_DELAY_MS;
|
|
80033
|
-
if (!override) {
|
|
80034
|
-
return CLI_RETRY_MAX_DELAY_MS;
|
|
80035
|
-
}
|
|
80036
|
-
const parsed = Number(override);
|
|
80037
|
-
return Number.isFinite(parsed) && parsed >= 0 ? parsed : CLI_RETRY_MAX_DELAY_MS;
|
|
80038
|
-
}
|
|
80039
|
-
function getCliRetryTotalMaxRetries() {
|
|
80040
|
-
const override = process.env.PIE_RETRY_TOTAL_MAX_RETRIES;
|
|
80041
|
-
if (!override) {
|
|
80042
|
-
return CLI_RETRY_TOTAL_MAX_RETRIES;
|
|
80043
|
-
}
|
|
80044
|
-
const parsed = Number(override);
|
|
80045
|
-
return Number.isFinite(parsed) && parsed >= 0 ? Math.floor(parsed) : CLI_RETRY_TOTAL_MAX_RETRIES;
|
|
80046
|
-
}
|
|
80047
|
-
function createCliRetryPolicy(isRetryableErrorOverride) {
|
|
80048
|
-
return {
|
|
80049
|
-
isRetryableError: isRetryableErrorOverride ?? isCliRetryableError,
|
|
80050
|
-
maxRetries: CLI_RETRY_MAX_RETRIES,
|
|
80051
|
-
baseDelayMs: getCliRetryBaseDelayMs(),
|
|
80052
|
-
maxDelayMs: getCliRetryMaxDelayMs(),
|
|
80053
|
-
maxRetriesForFailure: (failure) => failure.kind === "transient_network" ? getCliTransientNetworkMaxRetries() : failure.replayExempt === true ? getCliTimeoutReplayMaxRetries() : CLI_RETRY_MAX_RETRIES,
|
|
80054
|
-
maxTotalRetries: getCliRetryTotalMaxRetries(),
|
|
80055
|
-
systemicReplayStallLimit: getCliSystemicReplayStallLimit()
|
|
80056
|
-
};
|
|
80057
|
-
}
|
|
80058
|
-
var CLI_TIMEOUT_REPLAY_MAX_RETRIES = 5;
|
|
80059
|
-
function getCliTimeoutReplayMaxRetries() {
|
|
80060
|
-
const override = process.env.PIE_TIMEOUT_REPLAY_MAX_RETRIES;
|
|
80061
|
-
if (!override) return CLI_TIMEOUT_REPLAY_MAX_RETRIES;
|
|
80062
|
-
const parsed = Number(override);
|
|
80063
|
-
return Number.isFinite(parsed) && parsed >= 0 ? Math.floor(parsed) : CLI_TIMEOUT_REPLAY_MAX_RETRIES;
|
|
80064
|
-
}
|
|
80065
|
-
var CLI_SYSTEMIC_REPLAY_STALL_LIMIT = 3;
|
|
80066
|
-
function getCliSystemicReplayStallLimit() {
|
|
80067
|
-
const override = process.env.PIE_SYSTEMIC_REPLAY_STALL_LIMIT;
|
|
80068
|
-
if (!override) return CLI_SYSTEMIC_REPLAY_STALL_LIMIT;
|
|
80069
|
-
const parsed = Number(override);
|
|
80070
|
-
return Number.isFinite(parsed) && parsed >= 1 ? Math.floor(parsed) : CLI_SYSTEMIC_REPLAY_STALL_LIMIT;
|
|
80071
|
-
}
|
|
80072
|
-
|
|
80073
80758
|
// src/runtime/interactive-context-ui.ts
|
|
80074
80759
|
function calculateContextUsage(host) {
|
|
80075
80760
|
const messages = host.agent?.state.messages ?? [];
|
|
@@ -80246,23 +80931,23 @@ function setupAutocomplete(host) {
|
|
|
80246
80931
|
};
|
|
80247
80932
|
host.editor.setAutocompleteProvider(provider);
|
|
80248
80933
|
}
|
|
80249
|
-
function isContextOverflowError(
|
|
80250
|
-
return isCliContextOverflowError(
|
|
80934
|
+
function isContextOverflowError(errorMessage5) {
|
|
80935
|
+
return isCliContextOverflowError(errorMessage5);
|
|
80251
80936
|
}
|
|
80252
80937
|
function shouldAutoCompact(host, contextTokens, contextWindow) {
|
|
80253
80938
|
if (!host.options.settingsManager.getAutoCompactEnabled()) return false;
|
|
80254
80939
|
const reserveTokens = host.options.settingsManager.getAutoCompactReserveTokens();
|
|
80255
80940
|
return shouldCliAutoCompactTokens({ tokens: contextTokens, contextWindow, reserveTokens });
|
|
80256
80941
|
}
|
|
80257
|
-
function isRetryableError(
|
|
80258
|
-
return isCliRetryableError(
|
|
80942
|
+
function isRetryableError(errorMessage5) {
|
|
80943
|
+
return isCliRetryableError(errorMessage5);
|
|
80259
80944
|
}
|
|
80260
|
-
function isInvalidFileReferenceError(
|
|
80945
|
+
function isInvalidFileReferenceError(errorMessage5) {
|
|
80261
80946
|
return /not the owner of this file|owner of this file|invalid_authentication_error/i.test(
|
|
80262
|
-
|
|
80947
|
+
errorMessage5
|
|
80263
80948
|
);
|
|
80264
80949
|
}
|
|
80265
|
-
function recoverFromInvalidFileReferenceError(host,
|
|
80950
|
+
function recoverFromInvalidFileReferenceError(host, errorMessage5) {
|
|
80266
80951
|
if (!host.fileManager || !host.agent) return;
|
|
80267
80952
|
const messages = host.agent.state.messages.slice();
|
|
80268
80953
|
const invalidFileIds = /* @__PURE__ */ new Set();
|
|
@@ -80280,7 +80965,7 @@ function recoverFromInvalidFileReferenceError(host, errorMessage4) {
|
|
|
80280
80965
|
}
|
|
80281
80966
|
if (invalidFileIds.size === 0) return;
|
|
80282
80967
|
for (const fileId of invalidFileIds) {
|
|
80283
|
-
host.fileManager.markFileReferenceError(fileId,
|
|
80968
|
+
host.fileManager.markFileReferenceError(fileId, errorMessage5);
|
|
80284
80969
|
}
|
|
80285
80970
|
let changed = false;
|
|
80286
80971
|
const sanitizedMessages = messages.map((message) => {
|
|
@@ -80574,9 +81259,9 @@ function clearStatusLine(host) {
|
|
|
80574
81259
|
}
|
|
80575
81260
|
if (removed) host.ui.requestRender();
|
|
80576
81261
|
}
|
|
80577
|
-
function showError(host,
|
|
81262
|
+
function showError(host, errorMessage5) {
|
|
80578
81263
|
host.chatContainer.addChild(new Spacer(1));
|
|
80579
|
-
host.chatContainer.addChild(new Text(theme.fg("error", `Error: ${
|
|
81264
|
+
host.chatContainer.addChild(new Text(theme.fg("error", `Error: ${errorMessage5}`), 1, 0));
|
|
80580
81265
|
host.ui.requestRender();
|
|
80581
81266
|
}
|
|
80582
81267
|
async function executeCommand(host, command) {
|
|
@@ -80772,22 +81457,42 @@ function scheduleContinuationTimeout(host) {
|
|
|
80772
81457
|
|
|
80773
81458
|
// src/runtime/interactive-controller-setup.ts
|
|
80774
81459
|
async function prepareAgentTurn(host, context) {
|
|
81460
|
+
let messages = context.messages;
|
|
81461
|
+
if (context.source === "interactive" && context.streamingBehavior && host.tryBuildAttachmentContentFromExtensions) {
|
|
81462
|
+
messages = await Promise.all(messages.map(async (message) => {
|
|
81463
|
+
if (message.role !== "user") return message;
|
|
81464
|
+
const blocks = typeof message.content === "string" ? [{ type: "text", text: message.content }] : message.content;
|
|
81465
|
+
if (blocks.some((block) => block.type !== "text" && block.type !== "hostContext")) return message;
|
|
81466
|
+
const content = [];
|
|
81467
|
+
for (const block of blocks) {
|
|
81468
|
+
if (block.type !== "text" || !/@\[[^\]]+\]\(file:/.test(block.text)) {
|
|
81469
|
+
content.push(block);
|
|
81470
|
+
continue;
|
|
81471
|
+
}
|
|
81472
|
+
const resolved = await host.tryBuildAttachmentContentFromExtensions(block.text);
|
|
81473
|
+
if (resolved.handled && resolved.content.length) content.push(...resolved.content);
|
|
81474
|
+
else content.push(block);
|
|
81475
|
+
if (resolved.warnings.length) host.showStatus(resolved.warnings.join(" | "));
|
|
81476
|
+
}
|
|
81477
|
+
return { ...message, content };
|
|
81478
|
+
}));
|
|
81479
|
+
}
|
|
80775
81480
|
if (!host.extensionRunner) {
|
|
80776
|
-
return void 0;
|
|
81481
|
+
return messages === context.messages ? void 0 : { messages };
|
|
80777
81482
|
}
|
|
80778
81483
|
const baseSystemPrompt = context.baseSystemPrompt ?? host.buildSystemPrompt();
|
|
80779
81484
|
const result = await host.extensionRunner.emitBeforeAgentStart({
|
|
80780
81485
|
type: "before_agent_start",
|
|
80781
|
-
messages
|
|
81486
|
+
messages,
|
|
80782
81487
|
baseSystemPrompt,
|
|
80783
81488
|
source: context.source
|
|
80784
81489
|
});
|
|
80785
81490
|
if (!result) {
|
|
80786
|
-
return { systemPrompt: baseSystemPrompt };
|
|
81491
|
+
return { systemPrompt: baseSystemPrompt, messages };
|
|
80787
81492
|
}
|
|
80788
81493
|
return {
|
|
80789
81494
|
systemPrompt: result.systemPrompt ?? baseSystemPrompt,
|
|
80790
|
-
messages: result.messages?.length ? [...
|
|
81495
|
+
messages: result.messages?.length ? [...messages, ...result.messages] : messages
|
|
80791
81496
|
};
|
|
80792
81497
|
}
|
|
80793
81498
|
function createInteractiveAgentSessionController(host) {
|
|
@@ -80807,6 +81512,7 @@ function createInteractiveAgentSessionController(host) {
|
|
|
80807
81512
|
let retryElapsedStartedAt = 0;
|
|
80808
81513
|
let executionWork;
|
|
80809
81514
|
let autoCompactBeforeStats = null;
|
|
81515
|
+
let lastShownCompactionError = null;
|
|
80810
81516
|
const attention = cliAttention(host);
|
|
80811
81517
|
const stopRetryElapsedTicker = () => {
|
|
80812
81518
|
if (retryElapsedTicker !== void 0) {
|
|
@@ -80860,9 +81566,10 @@ function createInteractiveAgentSessionController(host) {
|
|
|
80860
81566
|
getAutoContinueMessage: () => host.getTodoAutoContinueMessage(),
|
|
80861
81567
|
classifyFailure: (context) => classifyCliFailure(context),
|
|
80862
81568
|
retry: createCliRetryPolicy(
|
|
80863
|
-
(
|
|
81569
|
+
(errorMessage5) => !host._isContextOverflowError(errorMessage5) && isCliRetryableError(errorMessage5)
|
|
80864
81570
|
),
|
|
80865
81571
|
compaction: {
|
|
81572
|
+
modelView: cliCompactionModelView,
|
|
80866
81573
|
compact: async (context) => {
|
|
80867
81574
|
const beforeCompact = await host.extensionRunner?.emitSessionBeforeCompact({
|
|
80868
81575
|
type: "session:before_compact",
|
|
@@ -81013,7 +81720,10 @@ function createInteractiveAgentSessionController(host) {
|
|
|
81013
81720
|
if (state.mode === "todo" && state.lifecycle === "paused" && state.steps.length > 0) {
|
|
81014
81721
|
host.showStatus("Todo list preserved. Send 'continue' when you want to resume it.");
|
|
81015
81722
|
}
|
|
81016
|
-
|
|
81723
|
+
if (event.failure.message !== lastShownCompactionError) {
|
|
81724
|
+
host.showError(event.failure.message);
|
|
81725
|
+
}
|
|
81726
|
+
lastShownCompactionError = null;
|
|
81017
81727
|
host.setControllerBusy(false);
|
|
81018
81728
|
} else if (event.type === "turn_cancelled") {
|
|
81019
81729
|
const outcome = host.executionState.abort();
|
|
@@ -81057,14 +81767,17 @@ function createInteractiveAgentSessionController(host) {
|
|
|
81057
81767
|
willRetry: event.willRetry
|
|
81058
81768
|
});
|
|
81059
81769
|
} else if (event.type === "auto_compaction_end") {
|
|
81770
|
+
const stillRunning = host.agent.state.isStreaming;
|
|
81060
81771
|
host.isCompacting = false;
|
|
81061
|
-
host.isProcessing =
|
|
81772
|
+
host.isProcessing = stillRunning;
|
|
81773
|
+
if (stillRunning) host.setControllerBusy(true);
|
|
81062
81774
|
host.setSubmitLock(false);
|
|
81063
81775
|
if (event.errorMessage) {
|
|
81064
81776
|
const prefix = event.reason === "overflow" ? "Context overflow recovery failed" : "Auto-compaction failed";
|
|
81065
81777
|
host.showError(`${prefix}: ${event.errorMessage}`);
|
|
81066
|
-
|
|
81067
|
-
host.
|
|
81778
|
+
lastShownCompactionError = event.willRetry || stillRunning ? event.errorMessage : null;
|
|
81779
|
+
host.footer.setState({ status: stillRunning ? "processing" : "ready" });
|
|
81780
|
+
host.setControllerBusy(stillRunning);
|
|
81068
81781
|
autoCompactBeforeStats = null;
|
|
81069
81782
|
return;
|
|
81070
81783
|
}
|
|
@@ -81080,7 +81793,7 @@ function createInteractiveAgentSessionController(host) {
|
|
|
81080
81793
|
const contextWindow = host.options.model?.contextWindow ?? 0;
|
|
81081
81794
|
const contextPercent = contextWindow > 0 && contextUsage.tokens !== null ? contextUsage.tokens / contextWindow * 100 : 0;
|
|
81082
81795
|
host.footer.setState({
|
|
81083
|
-
status: "ready",
|
|
81796
|
+
status: stillRunning ? "processing" : "ready",
|
|
81084
81797
|
lifecycleEvent: "auto_compact",
|
|
81085
81798
|
inputTokens: contextUsage.input,
|
|
81086
81799
|
outputTokens: contextUsage.output,
|
|
@@ -81323,8 +82036,8 @@ async function handleDirectBash(host, command) {
|
|
|
81323
82036
|
outputContainer.addChild(new Spacer(1));
|
|
81324
82037
|
host.chatContainer.addChild(outputContainer);
|
|
81325
82038
|
host.ui.requestRender();
|
|
81326
|
-
const { spawn:
|
|
81327
|
-
const child =
|
|
82039
|
+
const { spawn: spawn3 } = await import("child_process");
|
|
82040
|
+
const child = spawn3(shellCommand.file, shellCommand.args, {
|
|
81328
82041
|
cwd: process.cwd(),
|
|
81329
82042
|
env: process.env
|
|
81330
82043
|
});
|
|
@@ -81363,15 +82076,14 @@ async function handleDirectBash(host, command) {
|
|
|
81363
82076
|
// src/extensions/interactive-extension-ui.ts
|
|
81364
82077
|
function createInteractiveExtensionUIContext(host) {
|
|
81365
82078
|
const interact = async (run) => {
|
|
81366
|
-
const
|
|
81367
|
-
const request = attention.request("input-required");
|
|
82079
|
+
const request = beginExtensionWaiting(host, "input-required");
|
|
81368
82080
|
let resolution = "cancelled";
|
|
81369
82081
|
try {
|
|
81370
82082
|
const value = await run();
|
|
81371
82083
|
resolution = interactionAttentionResolution({ value });
|
|
81372
82084
|
return value;
|
|
81373
82085
|
} finally {
|
|
81374
|
-
|
|
82086
|
+
endExtensionWaiting(host, request, resolution);
|
|
81375
82087
|
}
|
|
81376
82088
|
};
|
|
81377
82089
|
return {
|
|
@@ -81393,23 +82105,13 @@ function createInteractiveExtensionUIContext(host) {
|
|
|
81393
82105
|
}
|
|
81394
82106
|
function installInteractiveInteractionHandler(host) {
|
|
81395
82107
|
registerInteractionHandler(async (request) => {
|
|
81396
|
-
const attention = cliAttention(host);
|
|
81397
82108
|
let attentionRequest;
|
|
81398
82109
|
const beginWaitingForUser = () => {
|
|
81399
|
-
host.activeInteractionCount++;
|
|
81400
|
-
host.setWaitingForUser(true);
|
|
81401
|
-
host.footer.setState({ lifecycleEvent: "waiting_for_user_input" });
|
|
81402
82110
|
const reason = interactionAttentionReason(request);
|
|
81403
|
-
|
|
81404
|
-
host.safeRequestRender();
|
|
82111
|
+
attentionRequest = beginExtensionWaiting(host, reason, "id" in request ? request.id : void 0);
|
|
81405
82112
|
};
|
|
81406
|
-
const endWaitingForUser = () => {
|
|
81407
|
-
host
|
|
81408
|
-
if (host.activeInteractionCount === 0) {
|
|
81409
|
-
host.setWaitingForUser(false);
|
|
81410
|
-
}
|
|
81411
|
-
host.footer.setState({ lifecycleEvent: "\u25B6 resuming" });
|
|
81412
|
-
host.safeRequestRender();
|
|
82113
|
+
const endWaitingForUser = (resolution) => {
|
|
82114
|
+
endExtensionWaiting(host, attentionRequest, resolution);
|
|
81413
82115
|
};
|
|
81414
82116
|
const withTimeout2 = async (createPromise) => {
|
|
81415
82117
|
const controller = new AbortController();
|
|
@@ -81438,8 +82140,7 @@ function installInteractiveInteractionHandler(host) {
|
|
|
81438
82140
|
resolution = interactionAttentionResolution(result);
|
|
81439
82141
|
return result;
|
|
81440
82142
|
} finally {
|
|
81441
|
-
|
|
81442
|
-
endWaitingForUser();
|
|
82143
|
+
endWaitingForUser(resolution);
|
|
81443
82144
|
}
|
|
81444
82145
|
};
|
|
81445
82146
|
switch (request.type) {
|
|
@@ -81447,7 +82148,8 @@ function installInteractiveInteractionHandler(host) {
|
|
|
81447
82148
|
showExtensionNotification(
|
|
81448
82149
|
host,
|
|
81449
82150
|
request.message,
|
|
81450
|
-
request.level === "success" ? "info" : request.level
|
|
82151
|
+
request.level === "success" ? "info" : request.level,
|
|
82152
|
+
{ markdown: request.markdown === true }
|
|
81451
82153
|
);
|
|
81452
82154
|
return { type: "notify", acknowledged: true };
|
|
81453
82155
|
case "select_one": {
|
|
@@ -81536,6 +82238,30 @@ function installInteractiveInteractionHandler(host) {
|
|
|
81536
82238
|
}
|
|
81537
82239
|
});
|
|
81538
82240
|
}
|
|
82241
|
+
function beginExtensionWaiting(host, reason, id) {
|
|
82242
|
+
host.activeInteractionCount++;
|
|
82243
|
+
try {
|
|
82244
|
+
host.setWaitingForUser(true);
|
|
82245
|
+
host.footer.setState({ lifecycleEvent: "waiting_for_user_input", waitingForUser: true });
|
|
82246
|
+
const attention = reason ? cliAttention(host).request(reason, id) : void 0;
|
|
82247
|
+
host.safeRequestRender();
|
|
82248
|
+
return attention;
|
|
82249
|
+
} catch (error) {
|
|
82250
|
+
host.activeInteractionCount = Math.max(0, host.activeInteractionCount - 1);
|
|
82251
|
+
throw error;
|
|
82252
|
+
}
|
|
82253
|
+
}
|
|
82254
|
+
function endExtensionWaiting(host, attentionRequest, resolution) {
|
|
82255
|
+
host.activeInteractionCount = Math.max(0, host.activeInteractionCount - 1);
|
|
82256
|
+
if (host.activeInteractionCount === 0) {
|
|
82257
|
+
host.setWaitingForUser(false);
|
|
82258
|
+
host.footer.setState({ lifecycleEvent: "\u25B6 resuming", waitingForUser: false });
|
|
82259
|
+
} else {
|
|
82260
|
+
host.footer.setState({ lifecycleEvent: "waiting_for_user_input", waitingForUser: true });
|
|
82261
|
+
}
|
|
82262
|
+
if (attentionRequest) cliAttention(host).resolve(attentionRequest, resolution);
|
|
82263
|
+
host.safeRequestRender();
|
|
82264
|
+
}
|
|
81539
82265
|
function showExtensionNotification(host, message, type = "info", opts) {
|
|
81540
82266
|
const prefix = type === "error" ? "Error: " : type === "warning" ? "Warning: " : "";
|
|
81541
82267
|
host.chatContainer.addChild(new Spacer(1));
|
|
@@ -82313,24 +83039,21 @@ var InteractiveMode = class {
|
|
|
82313
83039
|
isYoloMode: () => this.yoloMode || this.yoloGrant.isActive(),
|
|
82314
83040
|
getEnv: () => computerUseOwnerEnv(this.sessionManager.getActiveSessionId() || COMPUTER_USE_STANDALONE_OWNER, String(process.pid))
|
|
82315
83041
|
});
|
|
82316
|
-
const fileSystemToolOptions = (allowlistedDirs) => ({
|
|
82317
|
-
|
|
82318
|
-
cwd: this.options.cwd,
|
|
82319
|
-
configDir: this.options.configDir,
|
|
82320
|
-
skills: this.skills,
|
|
82321
|
-
allowlistedDirs
|
|
82322
|
-
}),
|
|
83042
|
+
const fileSystemToolOptions = (allowlistedDirs) => buildInteractiveFilesystemToolOptions({
|
|
83043
|
+
cwd: this.options.cwd,
|
|
82323
83044
|
configDir: this.options.configDir,
|
|
82324
83045
|
fileObservationState: this.options.fileObservationState,
|
|
83046
|
+
skills: this.skills,
|
|
83047
|
+
getActiveSessionId: () => this.sessionManager.getActiveSessionId(),
|
|
82325
83048
|
getAgentModel: () => this.options.model,
|
|
82326
|
-
getSessionId: () => this.sessionManager.getActiveSessionId() || void 0,
|
|
82327
83049
|
resolveToolModel: (purpose) => this.options.modelRegistry.resolveToolModel(purpose, this.options.model),
|
|
82328
|
-
|
|
83050
|
+
resolveToolModelCandidates: this.options.modelRegistry.resolveToolModelCandidates ? (purpose) => this.options.modelRegistry.resolveToolModelCandidates(purpose, this.options.model) : void 0,
|
|
83051
|
+
getPlanPolicyContext: () => ({
|
|
82329
83052
|
mode: this.planModeEnabled ? "plan" : "normal",
|
|
82330
83053
|
yoloMode: this.yoloMode,
|
|
82331
83054
|
confirmationPolicy: "allow"
|
|
82332
83055
|
})
|
|
82333
|
-
});
|
|
83056
|
+
}, allowlistedDirs);
|
|
82334
83057
|
const normalFsTools = createCliFileSystemTools(this.options.cwd, fileSystemToolOptions([this.options.configDir]));
|
|
82335
83058
|
const currentFsTools = this.yoloMode ? createCliFileSystemTools(this.options.cwd, fileSystemToolOptions(["/"])) : normalFsTools;
|
|
82336
83059
|
return {
|
|
@@ -82460,7 +83183,7 @@ var InteractiveMode = class {
|
|
|
82460
83183
|
async init() {
|
|
82461
83184
|
const activeSession = this.sessionManager.getActiveSession();
|
|
82462
83185
|
this.thinkingLevel = resolveInitialThinkingLevel({ session: activeSession, settingsManager: this.options.settingsManager });
|
|
82463
|
-
const { Agent } = await import("./chunks/src-
|
|
83186
|
+
const { Agent } = await import("./chunks/src-XDNJ3PHL.js");
|
|
82464
83187
|
this.agent = new Agent({
|
|
82465
83188
|
initialState: {
|
|
82466
83189
|
systemPrompt: this.buildSystemPrompt(),
|
|
@@ -82637,20 +83360,20 @@ var InteractiveMode = class {
|
|
|
82637
83360
|
setupAgentSubscription() {
|
|
82638
83361
|
bindInteractiveRuntimeEvents(this.runtimeEventHost);
|
|
82639
83362
|
}
|
|
82640
|
-
_isContextOverflowError(
|
|
82641
|
-
return isContextOverflowError(
|
|
83363
|
+
_isContextOverflowError(errorMessage5) {
|
|
83364
|
+
return isContextOverflowError(errorMessage5);
|
|
82642
83365
|
}
|
|
82643
83366
|
_shouldAutoCompact(contextTokens, contextWindow) {
|
|
82644
83367
|
return shouldAutoCompact(this.contextUiHost, contextTokens, contextWindow);
|
|
82645
83368
|
}
|
|
82646
|
-
_isRetryableError(
|
|
82647
|
-
return isRetryableError(
|
|
83369
|
+
_isRetryableError(errorMessage5) {
|
|
83370
|
+
return isRetryableError(errorMessage5);
|
|
82648
83371
|
}
|
|
82649
|
-
_isInvalidFileReferenceError(
|
|
82650
|
-
return isInvalidFileReferenceError(
|
|
83372
|
+
_isInvalidFileReferenceError(errorMessage5) {
|
|
83373
|
+
return isInvalidFileReferenceError(errorMessage5);
|
|
82651
83374
|
}
|
|
82652
|
-
_recoverFromInvalidFileReferenceError(
|
|
82653
|
-
return recoverFromInvalidFileReferenceError(this.contextUiHost,
|
|
83375
|
+
_recoverFromInvalidFileReferenceError(errorMessage5) {
|
|
83376
|
+
return recoverFromInvalidFileReferenceError(this.contextUiHost, errorMessage5);
|
|
82654
83377
|
}
|
|
82655
83378
|
async handleCompactCommand() {
|
|
82656
83379
|
return handleCompactCommand(this.compactCommandHost);
|
|
@@ -82661,6 +83384,9 @@ var InteractiveMode = class {
|
|
|
82661
83384
|
setupKeybindings() {
|
|
82662
83385
|
return setupInteractiveKeybindings(this.keybindingsHost);
|
|
82663
83386
|
}
|
|
83387
|
+
handlePasteImage() {
|
|
83388
|
+
void handleImagePaste(this);
|
|
83389
|
+
}
|
|
82664
83390
|
async selectMentionOption(option) {
|
|
82665
83391
|
return selectMentionOption(this.filePipelineHost, option);
|
|
82666
83392
|
}
|
|
@@ -82836,8 +83562,8 @@ var InteractiveMode = class {
|
|
|
82836
83562
|
clearStatusLine() {
|
|
82837
83563
|
return clearStatusLine(this.uiHelperHost);
|
|
82838
83564
|
}
|
|
82839
|
-
showError(
|
|
82840
|
-
return showError(this.uiHelperHost,
|
|
83565
|
+
showError(errorMessage5) {
|
|
83566
|
+
return showError(this.uiHelperHost, errorMessage5);
|
|
82841
83567
|
}
|
|
82842
83568
|
async handleDirectBash(command) {
|
|
82843
83569
|
return handleDirectBash(this.directBashHost, command);
|
|
@@ -82888,8 +83614,8 @@ var InteractiveMode = class {
|
|
|
82888
83614
|
};
|
|
82889
83615
|
|
|
82890
83616
|
// src/app/runtime-composition.ts
|
|
82891
|
-
import { existsSync as
|
|
82892
|
-
import { randomUUID } from "crypto";
|
|
83617
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync13 } from "fs";
|
|
83618
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
82893
83619
|
import * as path31 from "path";
|
|
82894
83620
|
var CliMissingApiKeyError = class extends Error {
|
|
82895
83621
|
constructor(message) {
|
|
@@ -82916,7 +83642,7 @@ function getCliRuntimePaths() {
|
|
|
82916
83642
|
return { configDir, sessionsDir, skillsDir, builtinSkillsDir };
|
|
82917
83643
|
}
|
|
82918
83644
|
function ensureCliRuntimePaths(paths = getCliRuntimePaths()) {
|
|
82919
|
-
if (!
|
|
83645
|
+
if (!existsSync19(paths.skillsDir)) {
|
|
82920
83646
|
mkdirSync13(paths.skillsDir, { recursive: true });
|
|
82921
83647
|
}
|
|
82922
83648
|
return paths;
|
|
@@ -83019,7 +83745,7 @@ async function composeCliRuntime(params) {
|
|
|
83019
83745
|
await sessionManager.save();
|
|
83020
83746
|
}
|
|
83021
83747
|
const sessionId = sessionManager.getActiveSession()?.id;
|
|
83022
|
-
const computerUseExecutionId =
|
|
83748
|
+
const computerUseExecutionId = randomUUID2();
|
|
83023
83749
|
const fileObservationState = createFileObservationState();
|
|
83024
83750
|
if (sessionId) {
|
|
83025
83751
|
if (process.env.PIE_DEBUG && !fileLogger.isEnabled()) {
|
|
@@ -83053,6 +83779,11 @@ async function composeCliRuntime(params) {
|
|
|
83053
83779
|
});
|
|
83054
83780
|
const fileSystemToolOptions = {
|
|
83055
83781
|
...buildCliFileAccessOptions({ cwd, configDir: paths.configDir, skills, allowlistedDirs: [paths.configDir] }),
|
|
83782
|
+
// Must match interactive-mode's rebuild view byte-for-byte: the rebuilt
|
|
83783
|
+
// tool surface replaces this composition-time set on the first mode
|
|
83784
|
+
// toggle/skill reload, and any description drift there would invalidate
|
|
83785
|
+
// the prompt-cache prefix exactly like the /yolo scope flip did.
|
|
83786
|
+
descriptionAllowlistedDirs: [],
|
|
83056
83787
|
configDir: paths.configDir,
|
|
83057
83788
|
fileObservationState,
|
|
83058
83789
|
getAgentModel: getCurrentModel,
|
|
@@ -83180,6 +83911,7 @@ function createPrintModeRetryStatusReporter() {
|
|
|
83180
83911
|
// src/app/print-mode-compaction.ts
|
|
83181
83912
|
function createPrintModeCompactionHandler(params) {
|
|
83182
83913
|
return {
|
|
83914
|
+
modelView: cliCompactionModelView,
|
|
83183
83915
|
compact: async (context) => {
|
|
83184
83916
|
const beforeCompact = await params.runner.emitSessionBeforeCompact({
|
|
83185
83917
|
type: "session:before_compact",
|
|
@@ -83343,7 +84075,7 @@ async function runPrintMode(params) {
|
|
|
83343
84075
|
`);
|
|
83344
84076
|
console.log("Assistant: ");
|
|
83345
84077
|
}
|
|
83346
|
-
const { Agent: AgentClass } = await import("./chunks/src-
|
|
84078
|
+
const { Agent: AgentClass } = await import("./chunks/src-XDNJ3PHL.js");
|
|
83347
84079
|
let agent;
|
|
83348
84080
|
const printModeExtensions = await loadPrintModeExtensions({
|
|
83349
84081
|
cwd: runtime.cwd,
|
|
@@ -83512,21 +84244,21 @@ async function runPrintMode(params) {
|
|
|
83512
84244
|
console.log(assistantText);
|
|
83513
84245
|
}
|
|
83514
84246
|
} catch (err) {
|
|
83515
|
-
const
|
|
83516
|
-
sessionTrace.noteStalled(
|
|
84247
|
+
const errorMessage5 = err instanceof Error ? err.message : String(err);
|
|
84248
|
+
sessionTrace.noteStalled(errorMessage5, { mode: "print" });
|
|
83517
84249
|
process.exitCode = 1;
|
|
83518
84250
|
if (params.jsonOutput) {
|
|
83519
84251
|
console.log(
|
|
83520
84252
|
JSON.stringify({
|
|
83521
84253
|
ok: false,
|
|
83522
|
-
error:
|
|
84254
|
+
error: errorMessage5,
|
|
83523
84255
|
sessionId: runtime.sessionManager.getActiveSession()?.id,
|
|
83524
84256
|
provider: runtime.provider,
|
|
83525
84257
|
modelId: runtime.modelId
|
|
83526
84258
|
})
|
|
83527
84259
|
);
|
|
83528
84260
|
}
|
|
83529
|
-
console.error("Error:",
|
|
84261
|
+
console.error("Error:", errorMessage5);
|
|
83530
84262
|
}
|
|
83531
84263
|
try {
|
|
83532
84264
|
if (!params.rawOutput && !params.jsonOutput) console.log("");
|
|
@@ -83772,7 +84504,7 @@ async function loadJsonModeExtensions(params) {
|
|
|
83772
84504
|
getRuntimeTools: () => params.getAgent()?.state.tools ?? [],
|
|
83773
84505
|
resolveModelClass: (modelClass) => params.runtime.modelRegistry.resolveModelClass(modelClass),
|
|
83774
84506
|
resolveModelRef: (modelRef) => params.runtime.modelRegistry.resolveModelRef(modelRef),
|
|
83775
|
-
registerHostEnvelopeProjector: (projector) => registerExternalHostEnvelopeProjector(projector),
|
|
84507
|
+
registerHostEnvelopeProjector: (projector) => registerExternalHostEnvelopeProjector(projector, params.envelopeRegistry),
|
|
83776
84508
|
getMessages: () => params.getAgent()?.state.messages ?? [],
|
|
83777
84509
|
getSessionMetadata: () => ({ ...params.runtime.sessionManager.getActiveSession()?.metadata ?? {} }),
|
|
83778
84510
|
setSessionMetadata: (key, value) => {
|
|
@@ -83783,7 +84515,7 @@ async function loadJsonModeExtensions(params) {
|
|
|
83783
84515
|
},
|
|
83784
84516
|
yoloMode: false
|
|
83785
84517
|
};
|
|
83786
|
-
const { extensions } = await loadExtensions(
|
|
84518
|
+
const { extensions, errors } = await loadExtensions(
|
|
83787
84519
|
params.runtime.extensionPaths,
|
|
83788
84520
|
params.runtime.cwd,
|
|
83789
84521
|
uiContext,
|
|
@@ -83803,6 +84535,10 @@ async function loadJsonModeExtensions(params) {
|
|
|
83803
84535
|
false
|
|
83804
84536
|
);
|
|
83805
84537
|
runner.setUIContext(uiContext);
|
|
84538
|
+
if (errors.length) {
|
|
84539
|
+
await runner.dispose("shutdown");
|
|
84540
|
+
throw new Error(errors.map(({ path: path34, error }) => `${path34}: ${error}`).join("\n"));
|
|
84541
|
+
}
|
|
83806
84542
|
try {
|
|
83807
84543
|
await restoreExtensionProviderCredentials(params.runtime.modelRegistry);
|
|
83808
84544
|
const extensionTools = filterEnabledTools(convertExtensionTools(extensions), params.runtime.settingsManager);
|
|
@@ -83822,6 +84558,7 @@ async function runJsonEventsMode(params) {
|
|
|
83822
84558
|
const sessionId = params.explicitSessionId || params.runtime?.sessionManager.getActiveSession()?.id || `pie-json-${Date.now()}`;
|
|
83823
84559
|
let activeTurn = null;
|
|
83824
84560
|
let runtime = params.runtime;
|
|
84561
|
+
let envelopeRegistry = createCliHostEnvelopeRegistry();
|
|
83825
84562
|
let agent;
|
|
83826
84563
|
let controller;
|
|
83827
84564
|
let disposeAgentSubscription;
|
|
@@ -83838,6 +84575,7 @@ async function runJsonEventsMode(params) {
|
|
|
83838
84575
|
const completedSessionControlRequests = /* @__PURE__ */ new Map();
|
|
83839
84576
|
const completedSidechatRequests = /* @__PURE__ */ new Map();
|
|
83840
84577
|
const ensureRuntimeInFlight = /* @__PURE__ */ new Map();
|
|
84578
|
+
let compositionChain = Promise.resolve();
|
|
83841
84579
|
let runtimeClosing = false;
|
|
83842
84580
|
let activeSidechat = null;
|
|
83843
84581
|
let activeSidechatPromise = null;
|
|
@@ -83853,7 +84591,7 @@ async function runJsonEventsMode(params) {
|
|
|
83853
84591
|
// Capability broadcast: the envelope kinds THIS build can project at
|
|
83854
84592
|
// intake (embedded external kinds included), so embedders can probe
|
|
83855
84593
|
// before their first turn instead of learning mismatches from failures.
|
|
83856
|
-
capabilities: { hostContextKinds: cliHostEnvelopeKinds() }
|
|
84594
|
+
capabilities: { hostContextKinds: cliHostEnvelopeKinds(envelopeRegistry) }
|
|
83857
84595
|
});
|
|
83858
84596
|
function trackSidechatPromise(promise) {
|
|
83859
84597
|
activeSidechatPromise = promise;
|
|
@@ -83870,13 +84608,6 @@ async function runJsonEventsMode(params) {
|
|
|
83870
84608
|
function delay(ms) {
|
|
83871
84609
|
return new Promise((resolve7) => setTimeout(resolve7, Math.max(0, ms)));
|
|
83872
84610
|
}
|
|
83873
|
-
async function waitForActiveController(timeoutMs = 1e3) {
|
|
83874
|
-
const deadline = Date.now() + timeoutMs;
|
|
83875
|
-
while (!controller && activeTurn && !activeTurn.finalized && Date.now() < deadline) {
|
|
83876
|
-
await delay(5);
|
|
83877
|
-
}
|
|
83878
|
-
return controller;
|
|
83879
|
-
}
|
|
83880
84611
|
function touch() {
|
|
83881
84612
|
if (activeTurn) {
|
|
83882
84613
|
activeTurn.lastActivityAt = Date.now();
|
|
@@ -84214,7 +84945,7 @@ async function runJsonEventsMode(params) {
|
|
|
84214
84945
|
}
|
|
84215
84946
|
};
|
|
84216
84947
|
try {
|
|
84217
|
-
await ensureRuntime();
|
|
84948
|
+
await ensureRuntime(runtime?.cwd);
|
|
84218
84949
|
const hostContextFailure = validateIntakeHostContext(message);
|
|
84219
84950
|
if (hostContextFailure) {
|
|
84220
84951
|
writeSidechatFailure(message, hostContextFailure.message, hostContextFailure.code);
|
|
@@ -84232,22 +84963,26 @@ async function runJsonEventsMode(params) {
|
|
|
84232
84963
|
return;
|
|
84233
84964
|
}
|
|
84234
84965
|
const parent = agent;
|
|
84235
|
-
const
|
|
84966
|
+
const sideRegistry = envelopeRegistry;
|
|
84967
|
+
const sideTrace = trace;
|
|
84968
|
+
const sideApiKey = runtime.apiKey;
|
|
84969
|
+
const snapshot = structuredClone(parent.state.messages);
|
|
84970
|
+
const { Agent: AgentClass } = await import("./chunks/src-XDNJ3PHL.js");
|
|
84236
84971
|
const sideAgent = new AgentClass({
|
|
84237
84972
|
initialState: {
|
|
84238
84973
|
systemPrompt: parent.state.systemPrompt,
|
|
84239
84974
|
model: parent.state.model,
|
|
84240
84975
|
thinkingLevel: parent.state.thinkingLevel,
|
|
84241
84976
|
tools: [],
|
|
84242
|
-
messages:
|
|
84977
|
+
messages: snapshot
|
|
84243
84978
|
},
|
|
84244
|
-
apiKey:
|
|
84979
|
+
apiKey: sideApiKey,
|
|
84245
84980
|
// The sidechat snapshot clones the parent's stored history, including
|
|
84246
84981
|
// persisted hostContext facts; project them like the main agent does.
|
|
84247
|
-
transformContext: async (messages) => projectCliHostEnvelopes(messages, (outcome) =>
|
|
84982
|
+
transformContext: async (messages) => projectCliHostEnvelopes(messages, (outcome) => sideTrace?.noteRuntimeEvent(
|
|
84248
84983
|
outcome.degraded ? "host_envelope_degraded" : "host_envelope_projected",
|
|
84249
84984
|
outcome.audit
|
|
84250
|
-
)),
|
|
84985
|
+
), sideRegistry),
|
|
84251
84986
|
// Same body-free transport timeline as the main agent: a sidechat is
|
|
84252
84987
|
// an independent Responses request and previously had no record at all
|
|
84253
84988
|
// when it stalled. `streamSimple` matches the host default when the
|
|
@@ -84303,6 +85038,7 @@ async function runJsonEventsMode(params) {
|
|
|
84303
85038
|
const turn = activeTurn;
|
|
84304
85039
|
if (!turn || turn.finalized) return;
|
|
84305
85040
|
turn.finalized = true;
|
|
85041
|
+
turn.releaseReady();
|
|
84306
85042
|
const activeEntryId = activeHeadEntryId();
|
|
84307
85043
|
const base = {
|
|
84308
85044
|
sessionId: turn.sessionId,
|
|
@@ -84535,6 +85271,7 @@ async function runJsonEventsMode(params) {
|
|
|
84535
85271
|
agent.releaseTransport();
|
|
84536
85272
|
}
|
|
84537
85273
|
agent = void 0;
|
|
85274
|
+
envelopeRegistry = createCliHostEnvelopeRegistry();
|
|
84538
85275
|
try {
|
|
84539
85276
|
await runtime?.sessionManager.save();
|
|
84540
85277
|
} catch {
|
|
@@ -84561,7 +85298,9 @@ async function runJsonEventsMode(params) {
|
|
|
84561
85298
|
const effectiveCwd = requestedCwd ?? process.cwd();
|
|
84562
85299
|
const inFlight = ensureRuntimeInFlight.get(effectiveCwd);
|
|
84563
85300
|
if (inFlight) return inFlight;
|
|
84564
|
-
const composed = composeRuntime(effectiveCwd);
|
|
85301
|
+
const composed = compositionChain.then(() => composeRuntime(effectiveCwd));
|
|
85302
|
+
compositionChain = composed.catch(() => {
|
|
85303
|
+
});
|
|
84565
85304
|
ensureRuntimeInFlight.set(effectiveCwd, composed);
|
|
84566
85305
|
void composed.finally(() => ensureRuntimeInFlight.delete(effectiveCwd)).catch(() => {
|
|
84567
85306
|
});
|
|
@@ -84592,14 +85331,16 @@ async function runJsonEventsMode(params) {
|
|
|
84592
85331
|
if (runtime.initialModel.unconfigured || controller) {
|
|
84593
85332
|
return;
|
|
84594
85333
|
}
|
|
84595
|
-
const { Agent: AgentClass } = await import("./chunks/src-
|
|
85334
|
+
const { Agent: AgentClass } = await import("./chunks/src-XDNJ3PHL.js");
|
|
84596
85335
|
if (runtimeClosing) return;
|
|
84597
|
-
const
|
|
85336
|
+
const compositionRegistry = createCliHostEnvelopeRegistry();
|
|
85337
|
+
const jsonModeExtensions = await loadJsonModeExtensions({ runtime, envelopeRegistry: compositionRegistry, getAgent: () => agent });
|
|
84598
85338
|
if (runtimeClosing) {
|
|
84599
85339
|
await jsonModeExtensions.runner.dispose("shutdown");
|
|
84600
85340
|
return;
|
|
84601
85341
|
}
|
|
84602
85342
|
extensionRunner = jsonModeExtensions.runner;
|
|
85343
|
+
envelopeRegistry = compositionRegistry;
|
|
84603
85344
|
const tools = [...runtime.tools, ...jsonModeExtensions.extensionTools];
|
|
84604
85345
|
const restoredApiKey = runtime.modelRegistry.getApiKey(runtime.model);
|
|
84605
85346
|
if (restoredApiKey) runtime.apiKey = restoredApiKey;
|
|
@@ -84635,7 +85376,7 @@ async function runJsonEventsMode(params) {
|
|
|
84635
85376
|
transformContext: async (messages) => projectCliHostEnvelopes(messages, (outcome) => trace?.noteRuntimeEvent(
|
|
84636
85377
|
outcome.degraded ? "host_envelope_degraded" : "host_envelope_projected",
|
|
84637
85378
|
outcome.audit
|
|
84638
|
-
)),
|
|
85379
|
+
), compositionRegistry),
|
|
84639
85380
|
// Body-free transport timeline for the main (JSON-events) agent.
|
|
84640
85381
|
streamFn: createJsonEventsTransportStreamFn(params.streamFn)
|
|
84641
85382
|
});
|
|
@@ -84671,8 +85412,10 @@ async function runJsonEventsMode(params) {
|
|
|
84671
85412
|
reserveTokens: runtime.settingsManager.getAutoCompactReserveTokens()
|
|
84672
85413
|
})),
|
|
84673
85414
|
compaction: {
|
|
85415
|
+
modelView: (message) => projectCliHostEnvelopes([message], void 0, compositionRegistry)[0],
|
|
84674
85416
|
compact: async (context) => createCliAutoCompactionResult({
|
|
84675
85417
|
context,
|
|
85418
|
+
envelopeRegistry: compositionRegistry,
|
|
84676
85419
|
model: runtime.model,
|
|
84677
85420
|
apiKey: runtime.apiKey,
|
|
84678
85421
|
systemPrompt: agent?.state.systemPrompt ?? baseSystemPrompt,
|
|
@@ -84780,7 +85523,7 @@ async function runJsonEventsMode(params) {
|
|
|
84780
85523
|
return message.hostContext ? [message.hostContext, { type: "text", text: message.prompt }] : [{ type: "text", text: message.prompt }];
|
|
84781
85524
|
}
|
|
84782
85525
|
function validateIntakeHostContext(message) {
|
|
84783
|
-
return message.hostContext ? intakeHostContextFailure(message.hostContext) : void 0;
|
|
85526
|
+
return message.hostContext ? intakeHostContextFailure(message.hostContext, envelopeRegistry) : void 0;
|
|
84784
85527
|
}
|
|
84785
85528
|
async function runTurn(message) {
|
|
84786
85529
|
if (isSessionMismatch(message)) {
|
|
@@ -84793,21 +85536,19 @@ async function runJsonEventsMode(params) {
|
|
|
84793
85536
|
return;
|
|
84794
85537
|
}
|
|
84795
85538
|
if (activeTurn && !activeTurn.finalized) {
|
|
84796
|
-
const
|
|
84797
|
-
|
|
84798
|
-
|
|
84799
|
-
type: "turn.failed",
|
|
84800
|
-
sessionId,
|
|
84801
|
-
turnId: message.turnId,
|
|
84802
|
-
error: queuedHostContextFailure.message,
|
|
84803
|
-
...queuedHostContextFailure.code === "host_context_unknown_projector" ? { hostContextKinds: cliHostEnvelopeKinds() } : {}
|
|
84804
|
-
});
|
|
84805
|
-
return;
|
|
84806
|
-
}
|
|
84807
|
-
await queueActiveTurnInput(message);
|
|
85539
|
+
const owner = activeTurn;
|
|
85540
|
+
owner.queue = owner.queue.then(() => queueActiveTurnInput(message, owner));
|
|
85541
|
+
await owner.queue;
|
|
84808
85542
|
return;
|
|
84809
85543
|
}
|
|
85544
|
+
let releaseReady;
|
|
85545
|
+
const ready = new Promise((resolve7) => {
|
|
85546
|
+
releaseReady = resolve7;
|
|
85547
|
+
});
|
|
84810
85548
|
activeTurn = {
|
|
85549
|
+
ready,
|
|
85550
|
+
releaseReady,
|
|
85551
|
+
queue: Promise.resolve(),
|
|
84811
85552
|
sessionId,
|
|
84812
85553
|
turnId: message.turnId,
|
|
84813
85554
|
prompt: message.prompt,
|
|
@@ -84828,7 +85569,7 @@ async function runJsonEventsMode(params) {
|
|
|
84828
85569
|
finalize("failed", {
|
|
84829
85570
|
code: mockHostContextFailure.code,
|
|
84830
85571
|
message: mockHostContextFailure.message,
|
|
84831
|
-
...mockHostContextFailure.code === "host_context_unknown_projector" ? { hostContextKinds: cliHostEnvelopeKinds() } : {}
|
|
85572
|
+
...mockHostContextFailure.code === "host_context_unknown_projector" ? { hostContextKinds: cliHostEnvelopeKinds(envelopeRegistry) } : {}
|
|
84832
85573
|
});
|
|
84833
85574
|
if (activeTurn === turn) emitSettled(turn);
|
|
84834
85575
|
if (activeTurn === turn) activeTurn = null;
|
|
@@ -84868,12 +85609,21 @@ async function runJsonEventsMode(params) {
|
|
|
84868
85609
|
if (activeTurn === turn) activeTurn = null;
|
|
84869
85610
|
return;
|
|
84870
85611
|
}
|
|
85612
|
+
if (activeTurn !== turn || turn.finalized || turn.interrupted) {
|
|
85613
|
+
if (activeTurn === turn && !turn.finalized) finalize("cancelled", "user_interrupt");
|
|
85614
|
+
turn.releaseReady();
|
|
85615
|
+
if (activeTurn === turn) {
|
|
85616
|
+
emitSettled(turn);
|
|
85617
|
+
activeTurn = null;
|
|
85618
|
+
}
|
|
85619
|
+
return;
|
|
85620
|
+
}
|
|
84871
85621
|
const hostContextFailure = validateIntakeHostContext(message);
|
|
84872
85622
|
if (hostContextFailure) {
|
|
84873
85623
|
finalize("failed", {
|
|
84874
85624
|
code: hostContextFailure.code,
|
|
84875
85625
|
message: hostContextFailure.message,
|
|
84876
|
-
...hostContextFailure.code === "host_context_unknown_projector" ? { hostContextKinds: cliHostEnvelopeKinds() } : {}
|
|
85626
|
+
...hostContextFailure.code === "host_context_unknown_projector" ? { hostContextKinds: cliHostEnvelopeKinds(envelopeRegistry) } : {}
|
|
84877
85627
|
});
|
|
84878
85628
|
if (activeTurn === turn) emitSettled(turn);
|
|
84879
85629
|
if (activeTurn === turn) activeTurn = null;
|
|
@@ -84913,7 +85663,9 @@ async function runJsonEventsMode(params) {
|
|
|
84913
85663
|
try {
|
|
84914
85664
|
trace?.notePendingUserText(message.prompt);
|
|
84915
85665
|
trace?.noteDispatchStart({ mode: "json-events" });
|
|
84916
|
-
|
|
85666
|
+
const dispatched = controller.prompt(promptInputFor(message), { source: "json-events" });
|
|
85667
|
+
turn.releaseReady();
|
|
85668
|
+
await dispatched;
|
|
84917
85669
|
trace?.noteDispatchSettled({ mode: "json-events" });
|
|
84918
85670
|
trace?.noteWaitForIdleStart({ mode: "json-events" });
|
|
84919
85671
|
await controller.waitForSettled();
|
|
@@ -84951,7 +85703,7 @@ async function runJsonEventsMode(params) {
|
|
|
84951
85703
|
if (activeTurn === turn) activeTurn = null;
|
|
84952
85704
|
}
|
|
84953
85705
|
}
|
|
84954
|
-
async function queueActiveTurnInput(message) {
|
|
85706
|
+
async function queueActiveTurnInput(message, owner) {
|
|
84955
85707
|
if (!message.streamingBehavior) {
|
|
84956
85708
|
writeEvent({
|
|
84957
85709
|
type: "turn.failed",
|
|
@@ -84961,8 +85713,9 @@ async function runJsonEventsMode(params) {
|
|
|
84961
85713
|
});
|
|
84962
85714
|
return;
|
|
84963
85715
|
}
|
|
84964
|
-
|
|
84965
|
-
|
|
85716
|
+
await owner.ready;
|
|
85717
|
+
const activeController = controller;
|
|
85718
|
+
if (!activeController || activeTurn !== owner || owner.finalized || owner.interrupted || runtimeClosing) {
|
|
84966
85719
|
writeEvent({
|
|
84967
85720
|
type: "turn.failed",
|
|
84968
85721
|
sessionId,
|
|
@@ -84971,6 +85724,17 @@ async function runJsonEventsMode(params) {
|
|
|
84971
85724
|
});
|
|
84972
85725
|
return;
|
|
84973
85726
|
}
|
|
85727
|
+
const failure = validateIntakeHostContext(message);
|
|
85728
|
+
if (failure) {
|
|
85729
|
+
writeEvent({
|
|
85730
|
+
type: "turn.failed",
|
|
85731
|
+
sessionId,
|
|
85732
|
+
turnId: message.turnId,
|
|
85733
|
+
error: failure.message,
|
|
85734
|
+
hostContextKinds: cliHostEnvelopeKinds(envelopeRegistry)
|
|
85735
|
+
});
|
|
85736
|
+
return;
|
|
85737
|
+
}
|
|
84974
85738
|
try {
|
|
84975
85739
|
applyRuntimeSelection(message);
|
|
84976
85740
|
trace?.notePendingUserText(message.prompt);
|
|
@@ -84989,7 +85753,7 @@ async function runJsonEventsMode(params) {
|
|
|
84989
85753
|
sessionId,
|
|
84990
85754
|
turnId: message.turnId,
|
|
84991
85755
|
mode: message.streamingBehavior,
|
|
84992
|
-
activeTurnId:
|
|
85756
|
+
activeTurnId: owner.turnId
|
|
84993
85757
|
});
|
|
84994
85758
|
} catch (error) {
|
|
84995
85759
|
writeEvent({
|
|
@@ -85254,7 +86018,7 @@ async function runWithJsonEventsConsoleIsolation(fn) {
|
|
|
85254
86018
|
}
|
|
85255
86019
|
async function createCliTestStreamFnFromEnv() {
|
|
85256
86020
|
if (!process.env.PIE_TEST_MOCK_STREAM_SEQUENCE) return void 0;
|
|
85257
|
-
return (await import("./chunks/test-stream-
|
|
86021
|
+
return (await import("./chunks/test-stream-LUUGOJMP.js")).createTestStreamFnFromSequenceEnv();
|
|
85258
86022
|
}
|
|
85259
86023
|
function resolveJsonEventsDetailFlag() {
|
|
85260
86024
|
for (let index = 0; index < process.argv.length; index += 1) {
|