@cydm/pie 1.0.41 → 1.0.42

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.
@@ -1,7 +1,7 @@
1
1
  import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
2
2
  import {
3
3
  Agent
4
- } from "./chunk-E3ELBCCX.js";
4
+ } from "./chunk-JVLAKTAS.js";
5
5
  import {
6
6
  FileSystemGateway,
7
7
  Type,
@@ -11,23 +11,70 @@ import {
11
11
  getPlatformConfig,
12
12
  hashText,
13
13
  streamSimple
14
- } from "./chunk-YCPKJCUB.js";
14
+ } from "./chunk-NGQ3PUOC.js";
15
15
  import {
16
16
  __commonJS,
17
17
  __toESM
18
- } from "./chunk-TG2EQLX2.js";
18
+ } from "./chunk-LZQXQOPJ.js";
19
19
 
20
- // ../../node_modules/shell-quote/quote.js
20
+ // ../../packages/shared-headless-capabilities/node_modules/shell-quote/quote.js
21
21
  var require_quote = __commonJS({
22
- "../../node_modules/shell-quote/quote.js"(exports, module) {
22
+ "../../packages/shared-headless-capabilities/node_modules/shell-quote/quote.js"(exports, module) {
23
23
  "use strict";
24
+ var OPS = (
25
+ /** @type {const} */
26
+ [
27
+ "||",
28
+ "&&",
29
+ ";;",
30
+ "|&",
31
+ "<(",
32
+ "<<<",
33
+ ">>",
34
+ ">&",
35
+ "<&",
36
+ "&",
37
+ ";",
38
+ "(",
39
+ ")",
40
+ "|",
41
+ "<",
42
+ ">"
43
+ ]
44
+ );
45
+ var LINE_TERMINATORS = /[\n\r\u2028\u2029]/;
46
+ var GLOB_SHELL_SPECIAL = /[\s#!"$&'():;<=>@\\^`|]/g;
24
47
  module.exports = function quote(xs) {
25
48
  return xs.map(function(s) {
26
49
  if (s === "") {
27
- return "''";
50
+ return (
51
+ /** @type {const} */
52
+ "''"
53
+ );
28
54
  }
29
55
  if (s && typeof s === "object") {
30
- return s.op.replace(/(.)/g, "\\$1");
56
+ if ("op" in s && s.op === "glob") {
57
+ if (typeof s.pattern !== "string") {
58
+ throw new TypeError("glob token requires a string `pattern`");
59
+ }
60
+ if (LINE_TERMINATORS.test(s.pattern)) {
61
+ throw new TypeError("glob `pattern` must not contain line terminators");
62
+ }
63
+ return s.pattern.replace(GLOB_SHELL_SPECIAL, "\\$&");
64
+ }
65
+ if ("op" in s && typeof s.op === "string") {
66
+ if (OPS.indexOf(s.op) < 0) {
67
+ throw new TypeError("invalid `op` value: " + JSON.stringify(s.op));
68
+ }
69
+ return s.op.replace(/[\s\S]/g, "\\$&");
70
+ }
71
+ if ("comment" in s && typeof s.comment === "string") {
72
+ if (LINE_TERMINATORS.test(s.comment)) {
73
+ throw new TypeError("`comment` must not contain line terminators");
74
+ }
75
+ return "#" + s.comment;
76
+ }
77
+ throw new TypeError("unrecognized object token shape");
31
78
  }
32
79
  if (/["\s\\]/.test(s) && !/'/.test(s)) {
33
80
  return "'" + s.replace(/(['])/g, "\\$1") + "'";
@@ -35,38 +82,67 @@ var require_quote = __commonJS({
35
82
  if (/["'\s]/.test(s)) {
36
83
  return '"' + s.replace(/(["\\$`!])/g, "\\$1") + '"';
37
84
  }
38
- return String(s).replace(/([A-Za-z]:)?([#!"$&'()*,:;<=>?@[\\\]^`{|}])/g, "$1\\$2");
85
+ return String(s).replace(/([A-Za-z]:)?([#!"$&'()*,:;<=>?@[\\\]^`{|}~])/g, "$1\\$2");
39
86
  }).join(" ");
40
87
  };
41
88
  }
42
89
  });
43
90
 
44
- // ../../node_modules/shell-quote/parse.js
91
+ // ../../packages/shared-headless-capabilities/node_modules/shell-quote/parse.js
45
92
  var require_parse = __commonJS({
46
- "../../node_modules/shell-quote/parse.js"(exports, module) {
93
+ "../../packages/shared-headless-capabilities/node_modules/shell-quote/parse.js"(exports, module) {
47
94
  "use strict";
48
- var CONTROL = "(?:" + [
49
- "\\|\\|",
50
- "\\&\\&",
51
- ";;",
52
- "\\|\\&",
53
- "\\<\\(",
54
- "\\<\\<\\<",
55
- ">>",
56
- ">\\&",
57
- "<\\&",
58
- "[&;()|<>]"
59
- ].join("|") + ")";
95
+ var CONTROL = (
96
+ /** @type {const} */
97
+ "(?:" + /** @type {const} */
98
+ [
99
+ "\\|\\|",
100
+ "\\&\\&",
101
+ ";;",
102
+ "\\|\\&",
103
+ "\\<\\(",
104
+ "\\<\\<\\<",
105
+ ">>",
106
+ ">\\&",
107
+ "<\\&",
108
+ "[&;()|<>]"
109
+ ].join(
110
+ /** @type {const} */
111
+ "|"
112
+ ) + /** @type {const} */
113
+ ")"
114
+ );
60
115
  var controlRE = new RegExp("^" + CONTROL + "$");
61
- var META = "|&;()<> \\t";
62
- var SINGLE_QUOTE = '"((\\\\"|[^"])*?)"';
63
- var DOUBLE_QUOTE = "'((\\\\'|[^'])*?)'";
116
+ var META = (
117
+ /** @type {const} */
118
+ "|&;()<> \\t"
119
+ );
120
+ var SINGLE_QUOTE = (
121
+ /** @type {const} */
122
+ "'([^']*?)'"
123
+ );
124
+ var DOUBLE_QUOTE = (
125
+ /** @type {const} */
126
+ '"((\\\\"|[^"])*?)"'
127
+ );
64
128
  var hash = /^#$/;
65
- var SQ = "'";
66
- var DQ = '"';
67
- var DS = "$";
129
+ var SQ = (
130
+ /** @type {const} */
131
+ "'"
132
+ );
133
+ var DQ = (
134
+ /** @type {const} */
135
+ '"'
136
+ );
137
+ var DS = (
138
+ /** @type {const} */
139
+ "$"
140
+ );
68
141
  var TOKEN = "";
69
- var mult = 4294967296;
142
+ var mult = (
143
+ /** @type {const} */
144
+ 4294967296
145
+ );
70
146
  for (i = 0; i < 4; i++) {
71
147
  TOKEN += (mult * Math.random()).toString(16);
72
148
  }
@@ -77,7 +153,7 @@ var require_parse = __commonJS({
77
153
  var matches = [];
78
154
  var matchObj;
79
155
  while (matchObj = r.exec(s)) {
80
- matches.push(matchObj);
156
+ matches[matches.length] = matchObj;
81
157
  if (r.lastIndex === matchObj.index) {
82
158
  r.lastIndex += 1;
83
159
  }
@@ -102,11 +178,12 @@ var require_parse = __commonJS({
102
178
  opts = {};
103
179
  }
104
180
  var BS = opts.escape || "\\";
181
+ var ifs = opts.splitUnquoted === true ? " \n" : typeof opts.splitUnquoted === "string" ? opts.splitUnquoted : "";
105
182
  var BAREWORD = "(\\" + BS + `['"` + META + `]|[^\\s'"` + META + "])+";
106
183
  var chunker = new RegExp([
107
184
  "(" + CONTROL + ")",
108
185
  // control chars
109
- "(" + BAREWORD + "|" + SINGLE_QUOTE + "|" + DOUBLE_QUOTE + ")+"
186
+ "(" + BAREWORD + "|" + DOUBLE_QUOTE + "|" + SINGLE_QUOTE + ")+"
110
187
  ].join("|"), "g");
111
188
  var matches = matchAll(string, chunker);
112
189
  if (matches.length === 0) {
@@ -122,11 +199,17 @@ var require_parse = __commonJS({
122
199
  return void 0;
123
200
  }
124
201
  if (controlRE.test(s)) {
125
- return { op: s };
202
+ return (
203
+ /** @type {ControlOperator} */
204
+ { op: s }
205
+ );
126
206
  }
127
207
  var quote = false;
128
208
  var esc = false;
129
209
  var out = "";
210
+ var words = [];
211
+ var sawQuote = false;
212
+ var pendingNw = null;
130
213
  var isGlob = false;
131
214
  var i2;
132
215
  function parseEnvVar() {
@@ -139,10 +222,20 @@ var require_parse = __commonJS({
139
222
  if (s.charAt(i2) === "}") {
140
223
  throw new Error("Bad substitution: " + s.slice(i2 - 2, i2 + 1));
141
224
  }
142
- varend = s.indexOf("}", i2);
143
- if (varend < 0) {
225
+ var depth = 1;
226
+ varend = i2;
227
+ while (depth > 0 && varend < s.length) {
228
+ if (s.charAt(varend) === "{" && s.charAt(varend - 1) === "$") {
229
+ depth += 1;
230
+ } else if (s.charAt(varend) === "}") {
231
+ depth -= 1;
232
+ }
233
+ varend += 1;
234
+ }
235
+ if (depth !== 0) {
144
236
  throw new Error("Bad substitution: " + s.slice(i2));
145
237
  }
238
+ varend -= 1;
146
239
  varname = s.slice(i2, varend);
147
240
  i2 = varend;
148
241
  } else if (/[*@#?$!_-]/.test(char)) {
@@ -156,13 +249,40 @@ var require_parse = __commonJS({
156
249
  i2 = s.length;
157
250
  } else {
158
251
  varname = slicedFromI.slice(0, varend.index);
159
- i2 += varend.index - 1;
252
+ i2 += /** @type {number} */
253
+ varend.index - 1;
254
+ }
255
+ }
256
+ return getVar(
257
+ /** @type {NonNullable<typeof env>} */
258
+ env,
259
+ "",
260
+ varname
261
+ );
262
+ }
263
+ function flushRun() {
264
+ if (pendingNw === null) {
265
+ return;
266
+ }
267
+ if (pendingNw === 0) {
268
+ if (out !== "") {
269
+ words[words.length] = out;
270
+ out = "";
271
+ }
272
+ } else {
273
+ words[words.length] = out;
274
+ out = "";
275
+ for (var fe = 1; fe < pendingNw; fe += 1) {
276
+ words[words.length] = "";
160
277
  }
161
278
  }
162
- return getVar(env, "", varname);
279
+ pendingNw = null;
163
280
  }
164
281
  for (i2 = 0; i2 < s.length; i2++) {
165
282
  var c = s.charAt(i2);
283
+ if (ifs && c !== DS) {
284
+ flushRun();
285
+ }
166
286
  isGlob = isGlob || !quote && (c === "*" || c === "?");
167
287
  if (esc) {
168
288
  out += c;
@@ -189,58 +309,113 @@ var require_parse = __commonJS({
189
309
  }
190
310
  } else if (c === DQ || c === SQ) {
191
311
  quote = c;
312
+ sawQuote = true;
192
313
  } else if (controlRE.test(c)) {
193
- return { op: s };
314
+ return (
315
+ /** @type {ControlOperator} */
316
+ { op: s }
317
+ );
194
318
  } else if (hash.test(c)) {
195
319
  commented = true;
196
320
  var commentObj = { comment: string.slice(match2.index + i2 + 1) };
197
321
  if (out.length) {
198
- return [out, commentObj];
322
+ return (
323
+ /** @type {const} */
324
+ [out, commentObj]
325
+ );
199
326
  }
200
- return [commentObj];
327
+ return (
328
+ /** @type {const} */
329
+ [commentObj]
330
+ );
201
331
  } else if (c === BS) {
202
332
  esc = true;
203
333
  } else if (c === DS) {
204
- out += parseEnvVar();
334
+ var value = parseEnvVar();
335
+ if (!ifs) {
336
+ out += value;
337
+ } else {
338
+ for (var vi = 0; vi < value.length; vi += 1) {
339
+ var vc = value.charAt(vi);
340
+ if (ifs.indexOf(vc) < 0) {
341
+ flushRun();
342
+ out += vc;
343
+ } else if (pendingNw === null) {
344
+ pendingNw = vc === " " || vc === " " || vc === "\n" ? 0 : 1;
345
+ } else if (vc !== " " && vc !== " " && vc !== "\n") {
346
+ pendingNw += 1;
347
+ }
348
+ }
349
+ }
205
350
  } else {
206
351
  out += c;
207
352
  }
208
353
  }
209
354
  if (isGlob) {
210
- return { op: "glob", pattern: out };
355
+ return (
356
+ /** @type {GlobPattern} */
357
+ { op: "glob", pattern: out }
358
+ );
359
+ }
360
+ if (ifs) {
361
+ if (pendingNw !== null && pendingNw > 0) {
362
+ words[words.length] = out;
363
+ out = "";
364
+ for (var te = 1; te < pendingNw; te += 1) {
365
+ words[words.length] = "";
366
+ }
367
+ }
368
+ if (out !== "" || sawQuote && words.length === 0) {
369
+ words[words.length] = out;
370
+ }
371
+ return words;
211
372
  }
212
373
  return out;
213
- }).reduce(function(prev, arg) {
214
- return typeof arg === "undefined" ? prev : prev.concat(arg);
215
- }, []);
374
+ }).reduce(
375
+ function(prev, arg) {
376
+ if (typeof arg === "undefined") {
377
+ return prev;
378
+ }
379
+ [].concat(arg).forEach(function(entry) {
380
+ prev[prev.length] = entry;
381
+ });
382
+ return prev;
383
+ },
384
+ /** @type {ParseEntry[]} */
385
+ []
386
+ );
216
387
  }
217
388
  module.exports = function parse2(s, env, opts) {
218
389
  var mapped = parseInternal(s, env, opts);
219
390
  if (typeof env !== "function") {
220
391
  return mapped;
221
392
  }
222
- return mapped.reduce(function(acc, s2) {
223
- if (typeof s2 === "object") {
224
- return acc.concat(s2);
225
- }
226
- var xs = s2.split(RegExp("(" + TOKEN + ".*?" + TOKEN + ")", "g"));
227
- if (xs.length === 1) {
228
- return acc.concat(xs[0]);
229
- }
230
- return acc.concat(xs.filter(Boolean).map(function(x) {
231
- if (startsWithToken.test(x)) {
232
- return JSON.parse(x.split(TOKEN)[1]);
393
+ return mapped.reduce(
394
+ function(acc, s2) {
395
+ if (typeof s2 === "object") {
396
+ acc[acc.length] = s2;
397
+ return acc;
233
398
  }
234
- return x;
235
- }));
236
- }, []);
399
+ var xs = s2.split(RegExp("(" + TOKEN + ".*?" + TOKEN + ")", "g"));
400
+ if (xs.length === 1) {
401
+ acc[acc.length] = xs[0];
402
+ return acc;
403
+ }
404
+ xs.filter(Boolean).forEach(function(x) {
405
+ acc[acc.length] = startsWithToken.test(x) ? JSON.parse(x.split(TOKEN)[1]) : x;
406
+ });
407
+ return acc;
408
+ },
409
+ /** @type {ParseEntry[]} */
410
+ []
411
+ );
237
412
  };
238
413
  }
239
414
  });
240
415
 
241
- // ../../node_modules/shell-quote/index.js
416
+ // ../../packages/shared-headless-capabilities/node_modules/shell-quote/index.js
242
417
  var require_shell_quote = __commonJS({
243
- "../../node_modules/shell-quote/index.js"(exports) {
418
+ "../../packages/shared-headless-capabilities/node_modules/shell-quote/index.js"(exports) {
244
419
  "use strict";
245
420
  exports.quote = require_quote();
246
421
  exports.parse = require_parse();
@@ -3411,6 +3586,68 @@ var SessionManager = class {
3411
3586
  this.activeSession.isDirty = true;
3412
3587
  return entry;
3413
3588
  }
3589
+ /**
3590
+ * Append an extension-owned custom entry to the active path. Custom
3591
+ * entries persist with the session tree (they follow fork branches) but
3592
+ * never enter the LLM message context.
3593
+ */
3594
+ appendCustomEntry(customType, data) {
3595
+ if (!this.activeSession) {
3596
+ throw new Error("No active session");
3597
+ }
3598
+ if (!customType || typeof customType !== "string") {
3599
+ throw new Error("appendCustomEntry requires a non-empty customType");
3600
+ }
3601
+ const entry = {
3602
+ id: generateEntryId(),
3603
+ parentId: this.activeSession.activeEntryId,
3604
+ type: "custom",
3605
+ timestamp: Date.now(),
3606
+ customType,
3607
+ data
3608
+ };
3609
+ this.activeSession.entries.push(entry);
3610
+ this.activeSession.activeEntryId = entry.id;
3611
+ this.activeSession.isDirty = true;
3612
+ return entry;
3613
+ }
3614
+ /** Get the custom entries of one kind on the current active path, oldest first. */
3615
+ getCustomEntries(customType) {
3616
+ if (!this.activeSession) return [];
3617
+ return this.getPathToEntry(this.activeSession.activeEntryId ?? "").filter((entry) => entry.type === "custom" && entry.customType === customType);
3618
+ }
3619
+ /** Set or clear a bookmark label on an entry. Labels persist with the session. */
3620
+ setLabel(entryId, label) {
3621
+ if (!this.activeSession) {
3622
+ throw new Error("No active session");
3623
+ }
3624
+ const entry = this.activeSession.entries.find((candidate) => candidate.id === entryId);
3625
+ if (!entry) {
3626
+ throw new Error(`Entry not found: ${entryId}`);
3627
+ }
3628
+ if (label === void 0 || label === "") {
3629
+ delete entry.label;
3630
+ } else {
3631
+ entry.label = label;
3632
+ }
3633
+ this.activeSession.isDirty = true;
3634
+ }
3635
+ getLabel(entryId) {
3636
+ if (!this.activeSession) return void 0;
3637
+ return this.activeSession.entries.find((candidate) => candidate.id === entryId)?.label;
3638
+ }
3639
+ /** Set a manual display name for the active session (never auto-overwritten). */
3640
+ setSessionName(name) {
3641
+ if (!this.activeSession) {
3642
+ throw new Error("No active session");
3643
+ }
3644
+ this.activeSession.metadata.name = name;
3645
+ this.activeSession.metadata.nameSource = "manual";
3646
+ this.activeSession.isDirty = true;
3647
+ }
3648
+ getSessionName() {
3649
+ return this.activeSession?.metadata.nameSource === "manual" ? this.activeSession?.metadata.name : void 0;
3650
+ }
3414
3651
  /**
3415
3652
  * Update messages (legacy compatibility - rebuilds tree)
3416
3653
  * @deprecated Use addMessage() instead
@@ -6369,6 +6606,97 @@ function buildPathResolutionDescription(sandboxRoot, options) {
6369
6606
  return `Available roots: ${rootSummaries.join("; ")}. ${defaultSentence} ${allowlistSentence}`.trim();
6370
6607
  }
6371
6608
 
6609
+ // ../../packages/shared-headless-capabilities/src/builtin/fs/utf8.ts
6610
+ function encodeUtf8(text) {
6611
+ if (typeof TextEncoder !== "undefined") {
6612
+ return new TextEncoder().encode(text);
6613
+ }
6614
+ const out = [];
6615
+ for (let i = 0; i < text.length; i += 1) {
6616
+ let codePoint = text.charCodeAt(i);
6617
+ if (codePoint >= 55296 && codePoint <= 56319) {
6618
+ const low = i + 1 < text.length ? text.charCodeAt(i + 1) : 0;
6619
+ if (low >= 56320 && low <= 57343) {
6620
+ codePoint = 65536 + (codePoint - 55296 << 10) + (low - 56320);
6621
+ i += 1;
6622
+ } else {
6623
+ codePoint = 65533;
6624
+ }
6625
+ } else if (codePoint >= 56320 && codePoint <= 57343) {
6626
+ codePoint = 65533;
6627
+ }
6628
+ if (codePoint < 128) {
6629
+ out.push(codePoint);
6630
+ } else if (codePoint < 2048) {
6631
+ out.push(192 | codePoint >> 6, 128 | codePoint & 63);
6632
+ } else if (codePoint < 65536) {
6633
+ out.push(224 | codePoint >> 12, 128 | codePoint >> 6 & 63, 128 | codePoint & 63);
6634
+ } else {
6635
+ out.push(
6636
+ 240 | codePoint >> 18,
6637
+ 128 | codePoint >> 12 & 63,
6638
+ 128 | codePoint >> 6 & 63,
6639
+ 128 | codePoint & 63
6640
+ );
6641
+ }
6642
+ }
6643
+ return new Uint8Array(out);
6644
+ }
6645
+ function utf8ByteLength2(text) {
6646
+ return encodeUtf8(text).length;
6647
+ }
6648
+ function probeUtf8Sequence(bytes, offset) {
6649
+ const lead = bytes[offset] ?? 0;
6650
+ if (lead < 128) return { status: "complete", codePoint: lead, width: 1 };
6651
+ if (lead < 194 || lead > 244) return { status: "invalid", width: 1 };
6652
+ const width = lead < 224 ? 2 : lead < 240 ? 3 : 4;
6653
+ let minFirst = 128;
6654
+ let maxFirst = 191;
6655
+ if (lead === 224) minFirst = 160;
6656
+ else if (lead === 237) maxFirst = 159;
6657
+ else if (lead === 240) minFirst = 144;
6658
+ else if (lead === 244) maxFirst = 143;
6659
+ let codePoint = lead & (width === 2 ? 31 : width === 3 ? 15 : 7);
6660
+ for (let k = 1; k < width; k += 1) {
6661
+ const byte = bytes[offset + k];
6662
+ if (byte === void 0) return { status: "incomplete" };
6663
+ const min = k === 1 ? minFirst : 128;
6664
+ const max = k === 1 ? maxFirst : 191;
6665
+ if (byte < min || byte > max) return { status: "invalid", width: k };
6666
+ codePoint = codePoint << 6 | byte & 63;
6667
+ }
6668
+ return { status: "complete", codePoint, width };
6669
+ }
6670
+ function createLenientStreamingDecoder() {
6671
+ let pending = [];
6672
+ return {
6673
+ decode(bytes, options) {
6674
+ const chunk = bytes ?? new Uint8Array(0);
6675
+ const combined = pending.concat(Array.from(chunk));
6676
+ const flush = options?.stream !== true;
6677
+ let out = "";
6678
+ let i = 0;
6679
+ while (i < combined.length) {
6680
+ const probe = probeUtf8Sequence(combined, i);
6681
+ if (probe.status === "incomplete") {
6682
+ if (flush) {
6683
+ out += String.fromCodePoint(65533);
6684
+ i = combined.length;
6685
+ } else {
6686
+ pending = combined.slice(i);
6687
+ return out;
6688
+ }
6689
+ continue;
6690
+ }
6691
+ out += String.fromCodePoint(probe.status === "complete" ? probe.codePoint : 65533);
6692
+ i += probe.width;
6693
+ }
6694
+ pending = [];
6695
+ return out;
6696
+ }
6697
+ };
6698
+ }
6699
+
6372
6700
  // ../../packages/shared-headless-capabilities/src/builtin/fs/truncate.ts
6373
6701
  var DEFAULT_MAX_LINES = 2e3;
6374
6702
  var DEFAULT_MAX_BYTES = 50 * 1024;
@@ -6385,7 +6713,7 @@ function formatSize(bytes) {
6385
6713
  function truncateHead(content, options = {}) {
6386
6714
  const maxLines = options.maxLines ?? DEFAULT_MAX_LINES;
6387
6715
  const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;
6388
- const totalBytes = Buffer.byteLength(content, "utf-8");
6716
+ const totalBytes = utf8ByteLength2(content);
6389
6717
  const lines = content.split("\n");
6390
6718
  const totalLines = lines.length;
6391
6719
  if (totalLines <= maxLines && totalBytes <= maxBytes) {
@@ -6403,7 +6731,7 @@ function truncateHead(content, options = {}) {
6403
6731
  maxBytes
6404
6732
  };
6405
6733
  }
6406
- const firstLineBytes = Buffer.byteLength(lines[0], "utf-8");
6734
+ const firstLineBytes = utf8ByteLength2(lines[0]);
6407
6735
  if (firstLineBytes > maxBytes) {
6408
6736
  return {
6409
6737
  content: "",
@@ -6424,7 +6752,7 @@ function truncateHead(content, options = {}) {
6424
6752
  let truncatedBy = "lines";
6425
6753
  for (let i = 0; i < lines.length && i < maxLines; i++) {
6426
6754
  const line = lines[i];
6427
- const lineBytes = Buffer.byteLength(line, "utf-8") + (i > 0 ? 1 : 0);
6755
+ const lineBytes = utf8ByteLength2(line) + (i > 0 ? 1 : 0);
6428
6756
  if (outputBytesCount + lineBytes > maxBytes) {
6429
6757
  truncatedBy = "bytes";
6430
6758
  break;
@@ -6436,7 +6764,7 @@ function truncateHead(content, options = {}) {
6436
6764
  truncatedBy = "lines";
6437
6765
  }
6438
6766
  const outputContent = outputLinesArr.join("\n");
6439
- const finalOutputBytes = Buffer.byteLength(outputContent, "utf-8");
6767
+ const finalOutputBytes = utf8ByteLength2(outputContent);
6440
6768
  return {
6441
6769
  content: outputContent,
6442
6770
  truncated: true,
@@ -7007,39 +7335,92 @@ function detectTextOnlyBinary(input, filePath, prefixMayBeTruncated) {
7007
7335
  return detectBinaryKind(filePath) ?? { kind: "document", mimeType: "application/octet-stream" };
7008
7336
  }
7009
7337
  async function readImageInfo(path4, fs2) {
7010
- if (typeof Buffer === "undefined") {
7011
- return void 0;
7012
- }
7013
7338
  try {
7014
- const base64 = await fs2.readFile(path4, "base64");
7015
- const bytes = Buffer.from(base64, "base64");
7016
- if (bytes.length >= 8 && bytes.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))) {
7339
+ let base64 = "";
7340
+ const size = (await fs2.stat(path4).catch(() => void 0))?.size ?? 0;
7341
+ if (typeof fs2.readFile === "function") {
7342
+ base64 = await fs2.readFile(path4, "base64").catch(() => "");
7343
+ }
7344
+ if (!base64 && size > 0 && typeof fs2.readFileSync === "function") {
7345
+ base64 = fs2.readFileSync(path4, "base64");
7346
+ }
7347
+ if (!base64) {
7348
+ console.error(`[pie] readImageInfo got empty base64 for ${path4}`);
7349
+ return void 0;
7350
+ }
7351
+ const bytes = decodeBase64ToBytes(base64);
7352
+ if (bytes.length === 0) {
7353
+ console.error(`[pie] readImageInfo decoded 0 bytes for ${path4} (base64 length ${base64.length})`);
7354
+ return void 0;
7355
+ }
7356
+ const pngMagic = [137, 80, 78, 71, 13, 10, 26, 10];
7357
+ if (bytes.length >= 8 && pngMagic.every((byte, index) => bytes[index] === byte)) {
7017
7358
  return { mimeType: "image/png", base64, ...parsePngDimensions(bytes) };
7018
7359
  }
7019
7360
  if (bytes.length >= 3 && bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255) {
7020
7361
  return { mimeType: "image/jpeg", base64, ...parseJpegDimensions(bytes) };
7021
7362
  }
7022
7363
  if (bytes.length >= 6) {
7023
- const gifHeader = bytes.subarray(0, 6).toString("ascii");
7364
+ const gifHeader = asciiAt(bytes, 0, 6);
7024
7365
  if (gifHeader === "GIF87a" || gifHeader === "GIF89a") {
7025
7366
  return { mimeType: "image/gif", base64, ...parseGifDimensions(bytes) };
7026
7367
  }
7027
7368
  }
7028
- if (bytes.length >= 12 && bytes.subarray(0, 4).toString("ascii") === "RIFF" && bytes.subarray(8, 12).toString("ascii") === "WEBP") {
7369
+ if (bytes.length >= 12 && asciiAt(bytes, 0, 4) === "RIFF" && asciiAt(bytes, 8, 12 - 8) === "WEBP") {
7029
7370
  return { mimeType: "image/webp", base64, ...parseWebpDimensions(bytes) };
7030
7371
  }
7031
- } catch {
7372
+ } catch (error) {
7373
+ console.error(`[pie] readImageInfo failed for ${path4}: ${error instanceof Error ? error.message : String(error)}`);
7032
7374
  return void 0;
7033
7375
  }
7034
7376
  return void 0;
7035
7377
  }
7378
+ function decodeBase64ToBytes(base64) {
7379
+ if (typeof Buffer !== "undefined") {
7380
+ return Buffer.from(base64, "base64");
7381
+ }
7382
+ const clean = base64.replace(/[^A-Za-z0-9+/=]/g, "");
7383
+ if (clean.length % 4 !== 0) {
7384
+ return new Uint8Array(0);
7385
+ }
7386
+ const lookup = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
7387
+ const bytes = new Uint8Array(clean.length / 4 * 3);
7388
+ let at = 0;
7389
+ for (let i = 0; i < clean.length; i += 4) {
7390
+ const padding = clean[i + 2] === "=" ? clean[i + 3] === "=" ? 2 : 1 : 0;
7391
+ const n = lookup.indexOf(clean[i]) << 18 | lookup.indexOf(clean[i + 1]) << 12 | (padding < 2 ? lookup.indexOf(clean[i + 2]) << 6 : 0) | (padding < 1 ? lookup.indexOf(clean[i + 3]) : 0);
7392
+ bytes[at++] = n >> 16 & 255;
7393
+ if (padding < 2) bytes[at++] = n >> 8 & 255;
7394
+ if (padding < 1) bytes[at++] = n & 255;
7395
+ }
7396
+ return bytes.subarray(0, at);
7397
+ }
7398
+ function readUIntBE(bytes, offset, length) {
7399
+ let value = 0;
7400
+ for (let i = 0; i < length; i += 1) {
7401
+ value = value * 256 + bytes[offset + i];
7402
+ }
7403
+ return value;
7404
+ }
7405
+ function readUIntLE(bytes, offset, length) {
7406
+ let value = 0;
7407
+ for (let i = length - 1; i >= 0; i -= 1) {
7408
+ value = value * 256 + bytes[offset + i];
7409
+ }
7410
+ return value;
7411
+ }
7412
+ function asciiAt(bytes, offset, length) {
7413
+ let text = "";
7414
+ for (let i = 0; i < length; i += 1) text += String.fromCharCode(bytes[offset + i]);
7415
+ return text;
7416
+ }
7036
7417
  function parsePngDimensions(bytes) {
7037
7418
  if (bytes.length < 24) {
7038
7419
  return {};
7039
7420
  }
7040
7421
  return {
7041
- width: bytes.readUInt32BE(16),
7042
- height: bytes.readUInt32BE(20)
7422
+ width: readUIntBE(bytes, 16, 4),
7423
+ height: readUIntBE(bytes, 20, 4)
7043
7424
  };
7044
7425
  }
7045
7426
  function parseGifDimensions(bytes) {
@@ -7047,8 +7428,8 @@ function parseGifDimensions(bytes) {
7047
7428
  return {};
7048
7429
  }
7049
7430
  return {
7050
- width: bytes.readUInt16LE(6),
7051
- height: bytes.readUInt16LE(8)
7431
+ width: readUIntLE(bytes, 6, 2),
7432
+ height: readUIntLE(bytes, 8, 2)
7052
7433
  };
7053
7434
  }
7054
7435
  function parseJpegDimensions(bytes) {
@@ -7066,15 +7447,15 @@ function parseJpegDimensions(bytes) {
7066
7447
  if (offset + 2 > bytes.length) {
7067
7448
  break;
7068
7449
  }
7069
- const segmentLength = bytes.readUInt16BE(offset);
7450
+ const segmentLength = readUIntBE(bytes, offset, 2);
7070
7451
  if (segmentLength < 2 || offset + segmentLength > bytes.length) {
7071
7452
  break;
7072
7453
  }
7073
7454
  const isStartOfFrame = marker >= 192 && marker <= 195 || marker >= 197 && marker <= 199 || marker >= 201 && marker <= 203 || marker >= 205 && marker <= 207;
7074
7455
  if (isStartOfFrame && segmentLength >= 7) {
7075
7456
  return {
7076
- height: bytes.readUInt16BE(offset + 3),
7077
- width: bytes.readUInt16BE(offset + 5)
7457
+ height: readUIntBE(bytes, offset + 3, 2),
7458
+ width: readUIntBE(bytes, offset + 5, 2)
7078
7459
  };
7079
7460
  }
7080
7461
  offset += segmentLength;
@@ -7085,21 +7466,21 @@ function parseWebpDimensions(bytes) {
7085
7466
  if (bytes.length < 30) {
7086
7467
  return {};
7087
7468
  }
7088
- const chunkType = bytes.subarray(12, 16).toString("ascii");
7469
+ const chunkType = asciiAt(bytes, 12, 4);
7089
7470
  if (chunkType === "VP8X" && bytes.length >= 30) {
7090
7471
  return {
7091
- width: 1 + bytes.readUIntLE(24, 3),
7092
- height: 1 + bytes.readUIntLE(27, 3)
7472
+ width: 1 + readUIntLE(bytes, 24, 3),
7473
+ height: 1 + readUIntLE(bytes, 27, 3)
7093
7474
  };
7094
7475
  }
7095
7476
  if (chunkType === "VP8 " && bytes.length >= 30) {
7096
7477
  return {
7097
- width: bytes.readUInt16LE(26) & 16383,
7098
- height: bytes.readUInt16LE(28) & 16383
7478
+ width: readUIntLE(bytes, 26, 2) & 16383,
7479
+ height: readUIntLE(bytes, 28, 2) & 16383
7099
7480
  };
7100
7481
  }
7101
7482
  if (chunkType === "VP8L" && bytes.length >= 25) {
7102
- const bits = bytes.readUInt32LE(21);
7483
+ const bits = readUIntLE(bytes, 21, 4);
7103
7484
  return {
7104
7485
  width: (bits & 16383) + 1,
7105
7486
  height: (bits >> 14 & 16383) + 1
@@ -10081,7 +10462,7 @@ function appendMergedContentMatches(input) {
10081
10462
  const lineNumber = lineIndex + 1;
10082
10463
  const formatted = matches.has(lineIndex) ? `${input.relativePath}:${lineNumber}: ${text}` : `${input.relativePath}-${lineNumber}- ${text}`;
10083
10464
  input.outputLines.push(formatted);
10084
- outputBytes += Buffer.byteLength(formatted, "utf8") + (input.outputLines.length > 1 ? 1 : 0);
10465
+ outputBytes += utf8ByteLength2(formatted) + (input.outputLines.length > 1 ? 1 : 0);
10085
10466
  if (outputBytes > DEFAULT_MAX_BYTES) return { outputBytes, linesTruncated, outputBudgetReached: true };
10086
10467
  }
10087
10468
  }
@@ -12222,6 +12603,112 @@ function extractOpenAIResponsesContent(response, originalQuery) {
12222
12603
  const text = textChunks.join("\n").trim();
12223
12604
  return { text, sources: uniqueSources(sources), results: text ? [makeTextSegment(text)] : [], actualQueries: [originalQuery] };
12224
12605
  }
12606
+ var MAX_PLAIN_PAYLOAD_CHARS = 2 * 1024 * 1024;
12607
+ async function readOpenAIResponsesSearchStream(response, originalQuery) {
12608
+ if (!response.body) {
12609
+ const statusDetail = await response.text().then((text) => text.slice(0, 200)).catch(() => "");
12610
+ throw new Error(`Responses web_search returned no SSE body (HTTP ${response.status}${statusDetail ? `: ${statusDetail}` : ""}).`);
12611
+ }
12612
+ const reader = response.body.getReader();
12613
+ const decoder = typeof TextDecoder !== "undefined" ? new TextDecoder() : createLenientStreamingDecoder();
12614
+ const outputItems = [];
12615
+ let completedOutput = [];
12616
+ let textDeltas = "";
12617
+ let buffer = "";
12618
+ let dataLines = [];
12619
+ let plainText = "";
12620
+ let completed = false;
12621
+ let searched = false;
12622
+ const handleEvent = (data) => {
12623
+ if (!data || data === "[DONE]") return;
12624
+ const event = JSON.parse(data);
12625
+ if (!isRecord4(event)) return;
12626
+ const type = event.type;
12627
+ if (type === "response.web_search_call.completed") searched = true;
12628
+ if (type === "response.output_item.done" && isRecord4(event.item)) {
12629
+ if (event.item.type === "web_search_call" && event.item.status === "completed") searched = true;
12630
+ if (event.item.type === "message") outputItems.push(event.item);
12631
+ }
12632
+ if (type === "response.output_text.delta" && typeof event.delta === "string") textDeltas += event.delta;
12633
+ if (type === "response.completed") {
12634
+ completed = true;
12635
+ const result = isRecord4(event.response) ? event.response : {};
12636
+ completedOutput = Array.isArray(result.output) ? result.output : [];
12637
+ const toolUsage = isRecord4(result.tool_usage) ? result.tool_usage : {};
12638
+ const webSearch = isRecord4(toolUsage.web_search) ? toolUsage.web_search : {};
12639
+ if (typeof webSearch.num_requests === "number" && webSearch.num_requests > 0) searched = true;
12640
+ }
12641
+ if (type === "response.failed" || type === "response.incomplete" || type === "error") {
12642
+ const result = isRecord4(event.response) ? event.response : {};
12643
+ const error = isRecord4(event.error) ? event.error : isRecord4(result.error) ? result.error : {};
12644
+ throw new Error(`Responses web_search ${type}: ${String(error.message || error.code || "upstream error")}`);
12645
+ }
12646
+ };
12647
+ const handleLine = (rawLine) => {
12648
+ const line = rawLine.endsWith("\r") ? rawLine.slice(0, -1) : rawLine;
12649
+ if (line === "") {
12650
+ const data = dataLines.join("\n");
12651
+ dataLines = [];
12652
+ handleEvent(data);
12653
+ } else if (line.startsWith("data:")) {
12654
+ dataLines.push(line.slice(5).trimStart());
12655
+ } else {
12656
+ plainText += line;
12657
+ if (plainText.length > MAX_PLAIN_PAYLOAD_CHARS) {
12658
+ throw new Error(`Responses web_search plain-text payload exceeded ${MAX_PLAIN_PAYLOAD_CHARS} characters.`);
12659
+ }
12660
+ }
12661
+ };
12662
+ let streamDrained = false;
12663
+ try {
12664
+ while (true) {
12665
+ const { done, value } = await reader.read();
12666
+ if (done) streamDrained = true;
12667
+ buffer += decoder.decode(value, { stream: !done });
12668
+ if (buffer.length > MAX_PLAIN_PAYLOAD_CHARS) {
12669
+ throw new Error(`Responses web_search line exceeded ${MAX_PLAIN_PAYLOAD_CHARS} characters.`);
12670
+ }
12671
+ let newline;
12672
+ while ((newline = buffer.indexOf("\n")) !== -1) {
12673
+ handleLine(buffer.slice(0, newline));
12674
+ buffer = buffer.slice(newline + 1);
12675
+ }
12676
+ if (completed || done) break;
12677
+ }
12678
+ if (!completed) {
12679
+ if (buffer) handleLine(buffer);
12680
+ if (dataLines.length) handleEvent(dataLines.join("\n"));
12681
+ }
12682
+ } finally {
12683
+ if (!streamDrained) await reader.cancel().catch(() => void 0);
12684
+ reader.releaseLock();
12685
+ }
12686
+ if (!completed && plainText.trim().startsWith("{")) {
12687
+ try {
12688
+ const document = JSON.parse(plainText);
12689
+ if (isRecord4(document) && Array.isArray(document.output)) {
12690
+ completed = true;
12691
+ completedOutput = document.output;
12692
+ const toolUsage = isRecord4(document.tool_usage) ? document.tool_usage : {};
12693
+ const webSearch = isRecord4(toolUsage.web_search) ? toolUsage.web_search : {};
12694
+ if (typeof webSearch.num_requests === "number" && webSearch.num_requests > 0) searched = true;
12695
+ for (const item of completedOutput) {
12696
+ if (isRecord4(item) && item.type === "web_search_call" && item.status === "completed") searched = true;
12697
+ if (isRecord4(item) && item.type === "message" && Array.isArray(item.content)) {
12698
+ for (const block of item.content) {
12699
+ if (isRecord4(block) && Array.isArray(block.annotations) && block.annotations.length > 0) searched = true;
12700
+ }
12701
+ }
12702
+ }
12703
+ }
12704
+ } catch {
12705
+ }
12706
+ }
12707
+ if (!completed) throw new Error("Responses web_search stream ended before response.completed.");
12708
+ if (!searched) throw new Error("Responses web_search completed without a search call.");
12709
+ const output = outputItems.length ? outputItems : completedOutput;
12710
+ return extractOpenAIResponsesContent({ output, output_text: output.length ? void 0 : textDeltas }, originalQuery);
12711
+ }
12225
12712
  function extractChatCompletionsContent(response, originalQuery) {
12226
12713
  const body = isRecord4(response) ? response : {};
12227
12714
  const sources = [];
@@ -12263,6 +12750,9 @@ async function runOpenAIResponsesSearch(params) {
12263
12750
  },
12264
12751
  body: JSON.stringify({
12265
12752
  model: params.model.id,
12753
+ store: false,
12754
+ stream: true,
12755
+ tool_choice: { type: "web_search" },
12266
12756
  input: [{
12267
12757
  role: "user",
12268
12758
  content: [{
@@ -12279,7 +12769,7 @@ Perform a web search for this query and summarize the useful results with source
12279
12769
  const errorBody = await response.text().catch(() => "");
12280
12770
  throw new Error(`Responses API error ${response.status}: ${errorBody}`);
12281
12771
  }
12282
- return extractOpenAIResponsesContent(await response.json(), params.input.query);
12772
+ return readOpenAIResponsesSearchStream(response, params.input.query);
12283
12773
  }
12284
12774
  async function runAnthropicNativeSearch(params) {
12285
12775
  const baseUrl = (params.model.baseUrl || "").replace(/\/+$/, "");
@@ -12580,8 +13070,9 @@ function createSharedWebSearchTool(deps) {
12580
13070
  }
12581
13071
  const qualityWarnings = evaluateSearchQuality(search);
12582
13072
  const durationSeconds = (Date.now() - start) / 1e3;
12583
- if (qualityWarnings.length > 0) {
12584
- lastFailureReason = `Provider returned low-quality web_search results: ${qualityWarnings.join(", ")}`;
13073
+ const hardQualityFailures = qualityWarnings.filter((warning) => warning !== "only_homepage_or_search_page_sources");
13074
+ if (hardQualityFailures.length > 0) {
13075
+ lastFailureReason = `Provider returned low-quality web_search results: ${hardQualityFailures.join(", ")}`;
12585
13076
  lastFailureCategory = "low_quality_result";
12586
13077
  attempts.push(makeAttempt({
12587
13078
  model: searchModel,
@@ -12591,7 +13082,7 @@ function createSharedWebSearchTool(deps) {
12591
13082
  fallbackReason: lastFailureReason,
12592
13083
  sourceCount: search.sources.length,
12593
13084
  durationSeconds,
12594
- qualityWarnings
13085
+ qualityWarnings: hardQualityFailures
12595
13086
  }));
12596
13087
  continue;
12597
13088
  }
@@ -12625,6 +13116,7 @@ function createSharedWebSearchTool(deps) {
12625
13116
  sources: search.sources,
12626
13117
  actualQueries: search.actualQueries,
12627
13118
  results: search.results,
13119
+ qualityWarnings,
12628
13120
  attempts
12629
13121
  },
12630
13122
  isError: false