@desplega.ai/agent-swarm 1.135.2 → 1.136.0

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.
Files changed (97) hide show
  1. package/dist/{actions-3az2vwwn.js → actions-agcbc8nd.js} +6 -6
  2. package/dist/{app-vygnfvrh.js → app-g2s78xya.js} +3 -3
  3. package/dist/{assistant-2jr2frrm.js → assistant-yd3jkb9d.js} +8 -8
  4. package/dist/{boot-reembed-y7r9cxt0.js → boot-reembed-6spqw4q0.js} +3 -3
  5. package/dist/{boot-reembed-ncbg16rb.js → boot-reembed-b22s9w5x.js} +4 -4
  6. package/dist/{boot-scrub-logs-t82rwa0y.js → boot-scrub-logs-6h3cqkc0.js} +2 -2
  7. package/dist/{claude-adapter-vvx2aw3v.js → claude-adapter-ng5y8zd7.js} +4 -4
  8. package/dist/{cli-mfa2eaef.js → cli-35jknh9e.js} +5 -5
  9. package/dist/{cli-cv2vjg2y.js → cli-3y553gws.js} +1 -1
  10. package/dist/{cli-nhvym0d2.js → cli-4gzv54ss.js} +15 -6
  11. package/dist/{cli-4dakdn30.js → cli-4r4jkqep.js} +6 -6
  12. package/dist/{cli-83razmqg.js → cli-54ht104h.js} +3 -3
  13. package/dist/{cli-6290n4yz.js → cli-5bnz1t86.js} +1 -1
  14. package/dist/{cli-6bz2hzvw.js → cli-68vayryq.js} +2 -2
  15. package/dist/{cli-1z01xdqh.js → cli-6gwgzdgw.js} +2 -2
  16. package/dist/{cli-1dfatkzm.js → cli-84vrhesc.js} +1 -1
  17. package/dist/{cli-jfrh963q.js → cli-8v57p983.js} +10 -10
  18. package/dist/{cli-3f0tnh34.js → cli-ads0hfw2.js} +81 -23
  19. package/dist/{cli-fmha74ga.js → cli-bnq8h7ea.js} +3 -3
  20. package/dist/{cli-j3xnd5b4.js → cli-d5ygfv18.js} +7 -6
  21. package/dist/{cli-8f4h27gm.js → cli-edwrx42s.js} +1 -1
  22. package/dist/{cli-r5vwg1ma.js → cli-fpjmcbhz.js} +4 -4
  23. package/dist/{cli-w0ygcv43.js → cli-gpdtxzar.js} +6 -4
  24. package/dist/{cli-4rdjdddh.js → cli-hz5hp6wn.js} +1 -1
  25. package/dist/{cli-6mmwmy45.js → cli-j7qp8gtf.js} +1 -1
  26. package/dist/{cli-5a5nrq3g.js → cli-jjhnma34.js} +5 -5
  27. package/dist/{cli-ey09krp2.js → cli-m3z53bed.js} +1 -1
  28. package/dist/{cli-cf6vq6qa.js → cli-mgef08pc.js} +1 -1
  29. package/dist/{cli-0jhyxtdj.js → cli-qckgdqmr.js} +2 -2
  30. package/dist/{cli-a1zrc2g6.js → cli-qhfkxrpg.js} +108 -33
  31. package/dist/{cli-yw2z5kj9.js → cli-spf767vc.js} +1 -1
  32. package/dist/{cli-1857msnd.js → cli-tee8w7tq.js} +1 -1
  33. package/dist/{cli-qxn3g3yx.js → cli-tmn19cdz.js} +61 -6
  34. package/dist/{cli-7ccy0h4r.js → cli-y16cesaq.js} +2 -2
  35. package/dist/{cli-cm4z7w7w.js → cli-z6e8eqrm.js} +2 -2
  36. package/dist/cli.js +16 -16
  37. package/dist/{codex-adapter-6p290yq3.js → codex-adapter-kw11ps3j.js} +2 -2
  38. package/dist/{codex-session-runner-7b3dhpmx.js → codex-session-runner-sffb69v7.js} +2 -2
  39. package/dist/{commands-wxg1g4nq.js → commands-0xxp4tz8.js} +2 -2
  40. package/dist/{db-8fqeheve.js → db-0npp39zd.js} +6 -2
  41. package/dist/{handlers-gwtqp17c.js → handlers-5p7a1jx6.js} +15 -9
  42. package/dist/{hook-gd9fwfp0.js → hook-hpefr0a8.js} +2 -2
  43. package/dist/{hook-mrqygs7p.js → hook-jjpxn4se.js} +3 -3
  44. package/dist/{http-x4mc1mqg.js → http-wfp33653.js} +322 -61
  45. package/dist/{index-yd654kac.js → index-17h657rg.js} +12 -8
  46. package/dist/{index-pzgasj16.js → index-m2p7ctyh.js} +10 -10
  47. package/dist/{index-2mdqrd0n.js → index-racb4wfq.js} +9 -9
  48. package/dist/{index-4djjkp9z.js → index-zh66wm65.js} +8 -8
  49. package/dist/{keepalive-3tycspcy.js → keepalive-wxjd633a.js} +4 -4
  50. package/dist/{lead-js1h3z7d.js → lead-359ec2z0.js} +23 -23
  51. package/dist/{maintenance-y91ry8q4.js → maintenance-rr03qjtb.js} +4 -4
  52. package/dist/{mistral-conversations-hdmnkf6h.js → mistral-conversations-qdrnmrb8.js} +1 -1
  53. package/dist/{oauth-refresh-sweep-s33gtxrw.js → oauth-refresh-sweep-jwj22yb8.js} +3 -3
  54. package/dist/{onboard-vndj64mb.js → onboard-asnhchcv.js} +2 -2
  55. package/dist/{openai-completions-cwy2kkzg.js → openai-completions-yzftqrft.js} +33 -4
  56. package/dist/{otel-impl-d2p84k6e.js → otel-impl-54cra6mw.js} +18 -4
  57. package/dist/{pi-mono-adapter-1phspz2y.js → pi-mono-adapter-29g7axgj.js} +669 -335
  58. package/dist/{pricing-refresh-c2bwsyk5.js → pricing-refresh-mkyy7c2y.js} +4 -4
  59. package/dist/{rbac-roles-2pedz5e9.js → rbac-roles-ak56tr75.js} +2 -2
  60. package/dist/{rbac-roles-reef5y2d.js → rbac-roles-kb3afm95.js} +3 -3
  61. package/dist/{render-v2-zd5r5wgf.js → render-v2-434asg49.js} +3 -3
  62. package/dist/{seed-pricing-2kyk1vhg.js → seed-pricing-nbmd7ah8.js} +3 -3
  63. package/dist/{setup-5ys9pwyr.js → setup-wh4qmjs4.js} +2 -2
  64. package/dist/{worker-nb1f7k04.js → worker-j1d27tjv.js} +23 -23
  65. package/openapi.json +167 -2
  66. package/package.json +6 -6
  67. package/src/be/db-retention.ts +275 -0
  68. package/src/be/db.ts +82 -7
  69. package/src/be/swarm-config-guard.ts +30 -0
  70. package/src/heartbeat/heartbeat.ts +21 -0
  71. package/src/http/index.ts +33 -33
  72. package/src/http/route-def.ts +93 -4
  73. package/src/http/stats.ts +37 -1
  74. package/src/http/tasks.ts +93 -0
  75. package/src/http/utils.ts +94 -0
  76. package/src/otel-impl.ts +21 -3
  77. package/src/otel.ts +15 -4
  78. package/src/slack/blocks.ts +1 -0
  79. package/src/slack/handlers.ts +7 -0
  80. package/src/tasks/sibling-awareness.ts +1 -0
  81. package/src/tasks/sibling-block.ts +17 -4
  82. package/src/tests/artifact-sdk.test.ts +20 -15
  83. package/src/tests/db-retention.test.ts +344 -0
  84. package/src/tests/docs-index-footprint.test.js +4 -5
  85. package/src/tests/draft-task-dispatch-race.test.ts +189 -0
  86. package/src/tests/events-http.test.ts +70 -27
  87. package/src/tests/otel-abort-span.test.ts +156 -0
  88. package/src/tests/otel-span-kind.test.ts +59 -0
  89. package/src/tests/promote-draft-task-route.test.ts +175 -0
  90. package/src/tests/route-def-find-route.test.ts +90 -4
  91. package/src/tests/sibling-block.test.ts +29 -1
  92. package/src/tests/slack-assistant-comention-production.test.ts +7 -1
  93. package/src/tests/steering-enabled.test.ts +6 -0
  94. package/src/tests/swarm-config-reserved-keys.test.ts +27 -0
  95. package/src/types.ts +2 -1
  96. package/templates/skills/swarm-scripts/SKILL.md +4 -0
  97. package/templates/skills/swarm-scripts/content.md +4 -0
@@ -30,7 +30,7 @@ import {
30
30
  streamSimple,
31
31
  summarizeSession,
32
32
  validateToolArguments
33
- } from "./cli-a1zrc2g6.js";
33
+ } from "./cli-qhfkxrpg.js";
34
34
  import {
35
35
  checkToolLoop,
36
36
  clearToolHistory
@@ -64170,7 +64170,7 @@ var require_eventsource = __commonJS(function(exports, module) {
64170
64170
 
64171
64171
  // src/providers/pi-mono-adapter.ts
64172
64172
  import { existsSync as existsSync27, lstatSync, symlinkSync, unlinkSync as unlinkSync3 } from "node:fs";
64173
- import { join as join42 } from "node:path";
64173
+ import { join as join43 } from "node:path";
64174
64174
 
64175
64175
  // node_modules/@earendil-works/pi-coding-agent/dist/index.js
64176
64176
  var exports_dist3 = {};
@@ -64257,6 +64257,7 @@ __export(exports_dist3, {
64257
64257
  createWriteTool: () => createWriteTool2,
64258
64258
  createWriteToolDefinition: () => createWriteToolDefinition,
64259
64259
  defineTool: () => defineTool,
64260
+ detectSupportedImageMimeTypeFromFile: () => detectSupportedImageMimeTypeFromFile,
64260
64261
  discoverAndLoadExtensions: () => discoverAndLoadExtensions,
64261
64262
  estimateTokens: () => estimateTokens,
64262
64263
  findCutPoint: () => findCutPoint,
@@ -65330,6 +65331,7 @@ __export(exports_dist, {
65330
65331
  renderLatex: () => renderLatex,
65331
65332
  resetCapabilitiesCache: () => resetCapabilitiesCache,
65332
65333
  setCapabilities: () => setCapabilities,
65334
+ setCapabilityOverrides: () => setCapabilityOverrides,
65333
65335
  setCellDimensions: () => setCellDimensions,
65334
65336
  setKeybindings: () => setKeybindings,
65335
65337
  setKittyProtocolActive: () => setKittyProtocolActive,
@@ -66858,7 +66860,7 @@ function buildCompletionValue(path, options) {
66858
66860
  const closeQuote = '"';
66859
66861
  return `${openQuote}${path}${closeQuote}`;
66860
66862
  }
66861
- async function walkDirectoryWithFd(baseDir, fdPath, query, maxResults, signal) {
66863
+ async function walkDirectoryWithFd(baseDir, fdPath, query, maxResults, signal, maxDepth) {
66862
66864
  const args = [
66863
66865
  "--base-directory",
66864
66866
  baseDir,
@@ -66877,6 +66879,9 @@ async function walkDirectoryWithFd(baseDir, fdPath, query, maxResults, signal) {
66877
66879
  "--exclude",
66878
66880
  ".git/**"
66879
66881
  ];
66882
+ if (maxDepth !== undefined) {
66883
+ args.push("--max-depth", String(maxDepth));
66884
+ }
66880
66885
  if (toDisplayPath(query).includes("/")) {
66881
66886
  args.push("--full-path");
66882
66887
  }
@@ -67271,6 +67276,12 @@ class CombinedAutocompleteProvider {
67271
67276
  score += 10;
67272
67277
  return score;
67273
67278
  }
67279
+ async getBaseDirSuggestions(baseDir, query, signal) {
67280
+ if (!this.fdPath || signal.aborted) {
67281
+ return [];
67282
+ }
67283
+ return await walkDirectoryWithFd(baseDir, this.fdPath, query, 100, signal, 1);
67284
+ }
67274
67285
  async getFuzzyFileSuggestions(query, options) {
67275
67286
  if (!this.fdPath || options.signal.aborted) {
67276
67287
  return [];
@@ -67279,7 +67290,18 @@ class CombinedAutocompleteProvider {
67279
67290
  const scopedQuery = this.resolveScopedFuzzyQuery(query);
67280
67291
  const fdBaseDir = scopedQuery?.baseDir ?? this.basePath;
67281
67292
  const fdQuery = scopedQuery?.query ?? query;
67282
- const entries = await walkDirectoryWithFd(fdBaseDir, this.fdPath, fdQuery, 100, options.signal);
67293
+ const baseDirEntries = await this.getBaseDirSuggestions(fdBaseDir, fdQuery, options.signal);
67294
+ const recursiveEntries = await walkDirectoryWithFd(fdBaseDir, this.fdPath, fdQuery, 100, options.signal);
67295
+ const seenPaths = new Set(baseDirEntries.map((entry) => entry.path));
67296
+ const entries = [
67297
+ ...baseDirEntries,
67298
+ ...recursiveEntries.filter((entry) => {
67299
+ if (seenPaths.has(entry.path))
67300
+ return false;
67301
+ seenPaths.add(entry.path);
67302
+ return true;
67303
+ })
67304
+ ];
67283
67305
  if (options.signal.aborted) {
67284
67306
  return [];
67285
67307
  }
@@ -67287,7 +67309,20 @@ class CombinedAutocompleteProvider {
67287
67309
  ...entry,
67288
67310
  score: fdQuery ? this.scoreEntry(entry.path, fdQuery, entry.isDirectory) : 1
67289
67311
  })).filter((entry) => entry.score > 0);
67290
- scoredEntries.sort((a, b2) => b2.score - a.score);
67312
+ scoredEntries.sort((a, b2) => {
67313
+ const scoreDiff = b2.score - a.score;
67314
+ if (scoreDiff !== 0)
67315
+ return scoreDiff;
67316
+ const aDepth = toDisplayPath(a.path).split("/").filter(Boolean).length;
67317
+ const bDepth = toDisplayPath(b2.path).split("/").filter(Boolean).length;
67318
+ const depthDiff = aDepth - bDepth;
67319
+ if (depthDiff !== 0)
67320
+ return depthDiff;
67321
+ const lengthDiff = a.path.length - b2.path.length;
67322
+ if (lengthDiff !== 0)
67323
+ return lengthDiff;
67324
+ return a.path.localeCompare(b2.path);
67325
+ });
67291
67326
  const topEntries = scoredEntries.slice(0, 20);
67292
67327
  const suggestions = [];
67293
67328
  for (const { path: entryPath, isDirectory } of topEntries) {
@@ -69799,6 +69834,7 @@ import { homedir as homedir4 } from "node:os";
69799
69834
  import { isAbsolute as isAbsolute2 } from "node:path";
69800
69835
  import { pathToFileURL } from "node:url";
69801
69836
  var cachedCapabilities = null;
69837
+ var capabilityOverrides = {};
69802
69838
  var cellDimensions = { widthPx: 9, heightPx: 18 };
69803
69839
  function getCellDimensions() {
69804
69840
  return cellDimensions;
@@ -69818,7 +69854,7 @@ function probeTmuxHyperlinks() {
69818
69854
  return false;
69819
69855
  }
69820
69856
  }
69821
- function detectCapabilities(tmuxForwardsHyperlink = probeTmuxHyperlinks) {
69857
+ function detectCapabilitiesFromEnvironment(tmuxForwardsHyperlink) {
69822
69858
  const termProgram = process.env.TERM_PROGRAM?.toLowerCase() || "";
69823
69859
  const terminalEmulator = process.env.TERMINAL_EMULATOR?.toLowerCase() || "";
69824
69860
  const term = process.env.TERM?.toLowerCase() || "";
@@ -69863,15 +69899,42 @@ function detectCapabilities(tmuxForwardsHyperlink = probeTmuxHyperlinks) {
69863
69899
  }
69864
69900
  return { images: null, trueColor: hasTrueColorHint, hyperlinks: false };
69865
69901
  }
69902
+ function parseBooleanCapabilityOverride(value2) {
69903
+ return value2 === "1" ? true : value2 === "0" ? false : undefined;
69904
+ }
69905
+ function detectCapabilities(tmuxForwardsHyperlink = probeTmuxHyperlinks) {
69906
+ const hyperlinks = parseBooleanCapabilityOverride(process.env.PI_HYPERLINKS);
69907
+ const detected = detectCapabilitiesFromEnvironment(hyperlinks === undefined ? tmuxForwardsHyperlink : () => hyperlinks);
69908
+ const imageProtocol = process.env.PI_IMAGE_PROTOCOL?.toLowerCase();
69909
+ const images = imageProtocol === "kitty" || imageProtocol === "iterm2" ? imageProtocol : imageProtocol === "none" || imageProtocol === "0" ? null : undefined;
69910
+ const trueColor = parseBooleanCapabilityOverride(process.env.PI_TRUE_COLOR);
69911
+ return {
69912
+ ...detected,
69913
+ ...images !== undefined ? { images } : {},
69914
+ ...trueColor !== undefined ? { trueColor } : {},
69915
+ ...hyperlinks !== undefined ? { hyperlinks } : {}
69916
+ };
69917
+ }
69866
69918
  function getCapabilities() {
69867
69919
  if (!cachedCapabilities) {
69868
- cachedCapabilities = detectCapabilities();
69920
+ const hyperlinks = capabilityOverrides.hyperlinks;
69921
+ cachedCapabilities = {
69922
+ ...detectCapabilities(hyperlinks === undefined ? undefined : () => hyperlinks),
69923
+ ...capabilityOverrides
69924
+ };
69869
69925
  }
69870
69926
  return cachedCapabilities;
69871
69927
  }
69872
69928
  function resetCapabilitiesCache() {
69873
69929
  cachedCapabilities = null;
69874
69930
  }
69931
+ function setCapabilityOverrides(overrides) {
69932
+ if (capabilityOverrides.images === overrides.images && capabilityOverrides.trueColor === overrides.trueColor && capabilityOverrides.hyperlinks === overrides.hyperlinks) {
69933
+ return;
69934
+ }
69935
+ capabilityOverrides = { ...overrides };
69936
+ cachedCapabilities = null;
69937
+ }
69875
69938
  function setCapabilities(caps) {
69876
69939
  cachedCapabilities = caps;
69877
69940
  }
@@ -76893,6 +76956,7 @@ var MAX_CACHED_OFFSCREEN_KITTY_IMAGES = 16;
76893
76956
  var MAX_CACHED_OFFSCREEN_KITTY_TRANSMISSION_BYTES = 32 * 1024 * 1024;
76894
76957
  var MAX_CACHED_OFFSCREEN_KITTY_DECODED_BYTES = 64 * 1024 * 1024;
76895
76958
  var DOUBLE_CLICK_INTERVAL_MS = 500;
76959
+ var TERMINAL_WORD_SELECTION_JOINERS = new Set(["/", "-"]);
76896
76960
  var wordSegmenter4 = getWordSegmenter();
76897
76961
 
76898
76962
  class TuiAltScreen extends TuiBase {
@@ -76931,6 +76995,7 @@ class TuiAltScreen extends TuiBase {
76931
76995
  searchCurrentMatchStyle;
76932
76996
  openUrl;
76933
76997
  onRightClickPaste;
76998
+ copyOnSelect;
76934
76999
  copySelection;
76935
77000
  constructor(terminal, showHardwareCursor, logDirectory, options = {}) {
76936
77001
  super(terminal, showHardwareCursor, logDirectory);
@@ -76949,6 +77014,7 @@ class TuiAltScreen extends TuiBase {
76949
77014
  this.searchCurrentMatchStyle = options.searchCurrentMatchStyle ?? ((text) => `\x1B[1;7m${text}\x1B[22;27m`);
76950
77015
  this.openUrl = options.openUrl;
76951
77016
  this.onRightClickPaste = options.onRightClickPaste;
77017
+ this.copyOnSelect = options.copyOnSelect ?? true;
76952
77018
  this.copySelection = options.copySelection;
76953
77019
  this.addInputListener((data) => this.handleViewportInput(data));
76954
77020
  }
@@ -76958,6 +77024,21 @@ class TuiAltScreen extends TuiBase {
76958
77024
  get isFollowingOutput() {
76959
77025
  return this.getPrimaryScrollView().isFollowingEnd;
76960
77026
  }
77027
+ getCopyOnSelect() {
77028
+ return this.copyOnSelect;
77029
+ }
77030
+ setCopyOnSelect(enabled) {
77031
+ this.copyOnSelect = enabled;
77032
+ }
77033
+ hasActiveSelection() {
77034
+ return this.getActiveSelectionText() !== undefined;
77035
+ }
77036
+ async copyActiveSelectionToClipboard() {
77037
+ const text = this.getActiveSelectionText();
77038
+ if (!text)
77039
+ return false;
77040
+ return this.copyTextToClipboard(text);
77041
+ }
76961
77042
  setLayoutRoot(component) {
76962
77043
  if (this.layoutRoot === component)
76963
77044
  return;
@@ -77520,18 +77601,30 @@ class TuiAltScreen extends TuiBase {
77520
77601
  }
77521
77602
  getWordSelection(point) {
77522
77603
  const line = stripTerminalSequences(this.getSelectionSourceLine(point));
77604
+ const segments = [];
77523
77605
  let start = 0;
77524
77606
  for (const segment of wordSegmenter4.segment(line)) {
77525
77607
  const end = start + visibleWidth(segment.segment);
77526
- if (point.col >= start && point.col < end) {
77527
- return {
77528
- start: { ...point, col: start },
77529
- end: { ...point, col: end, boundary: true }
77530
- };
77531
- }
77608
+ const joiner = TERMINAL_WORD_SELECTION_JOINERS.has(segment.segment);
77609
+ segments.push({ start, end, selectable: segment.isWordLike === true || joiner, joiner });
77532
77610
  start = end;
77533
77611
  }
77534
- return;
77612
+ const clickedSegmentIndex = segments.findIndex((segment) => point.col >= segment.start && point.col < segment.end);
77613
+ if (clickedSegmentIndex < 0)
77614
+ return;
77615
+ const canJoin = (left, right) => left.selectable && right.selectable && (left.joiner || right.joiner);
77616
+ let selectionStart = segments[clickedSegmentIndex].start;
77617
+ let selectionEnd = segments[clickedSegmentIndex].end;
77618
+ for (let index = clickedSegmentIndex;index > 0 && canJoin(segments[index - 1], segments[index]); index--) {
77619
+ selectionStart = segments[index - 1].start;
77620
+ }
77621
+ for (let index = clickedSegmentIndex;index < segments.length - 1 && canJoin(segments[index], segments[index + 1]); index++) {
77622
+ selectionEnd = segments[index + 1].end;
77623
+ }
77624
+ return {
77625
+ start: { ...point, col: selectionStart },
77626
+ end: { ...point, col: selectionEnd, boundary: true }
77627
+ };
77535
77628
  }
77536
77629
  getLineSelection(point) {
77537
77630
  return {
@@ -77646,7 +77739,8 @@ class TuiAltScreen extends TuiBase {
77646
77739
  this.requestRender();
77647
77740
  return;
77648
77741
  }
77649
- this.copySelectionToClipboard();
77742
+ if (this.copyOnSelect)
77743
+ this.copySelectionToClipboard();
77650
77744
  this.requestRender();
77651
77745
  return;
77652
77746
  }
@@ -77699,7 +77793,7 @@ class TuiAltScreen extends TuiBase {
77699
77793
  }
77700
77794
  return { start: Math.max(minColumn, start), end: Math.min(maxColumn, end) };
77701
77795
  }
77702
- async copySelectionToClipboard() {
77796
+ getActiveSelectionText() {
77703
77797
  const selection = this.getSelectionBounds();
77704
77798
  if (!selection)
77705
77799
  return;
@@ -77720,15 +77814,23 @@ class TuiAltScreen extends TuiBase {
77720
77814
  }
77721
77815
  const text = lines.join(`
77722
77816
  `);
77723
- if (text.length === 0)
77724
- return;
77817
+ return text.length === 0 ? undefined : text;
77818
+ }
77819
+ async copySelectionToClipboard() {
77820
+ const text = this.getActiveSelectionText();
77821
+ if (!text)
77822
+ return false;
77823
+ return this.copyTextToClipboard(text);
77824
+ }
77825
+ async copyTextToClipboard(text) {
77725
77826
  if (this.copySelection) {
77726
77827
  const ok = await this.copySelection(text);
77727
77828
  this.flash(ok ? "Copied!" : "Copy failed");
77728
- return;
77829
+ return ok;
77729
77830
  }
77730
77831
  this.terminal.write(`\x1B]52;c;${Buffer.from(text).toString("base64")}\x07`);
77731
77832
  this.flash("Copied!");
77833
+ return true;
77732
77834
  }
77733
77835
  applySearchTextHighlight(text, current) {
77734
77836
  const style = current ? this.searchCurrentMatchStyle : this.searchMatchStyle;
@@ -77944,6 +78046,49 @@ class TuiAltScreen extends TuiBase {
77944
78046
  import * as fs2 from "node:fs";
77945
78047
  import * as path4 from "node:path";
77946
78048
  var KITTY_SEQUENCE_PREFIX = "\x1B_G";
78049
+ var MAX_RENDER_WRITE_CHARS = 1024 * 1024;
78050
+
78051
+ class BoundedTerminalWriter {
78052
+ buffer = "";
78053
+ writtenChars = 0;
78054
+ write;
78055
+ constructor(write) {
78056
+ this.write = write;
78057
+ }
78058
+ append(value2) {
78059
+ let offset = 0;
78060
+ while (offset < value2.length) {
78061
+ const capacity = MAX_RENDER_WRITE_CHARS - this.buffer.length;
78062
+ if (capacity === 0) {
78063
+ this.flush();
78064
+ continue;
78065
+ }
78066
+ let end = Math.min(value2.length, offset + capacity);
78067
+ if (end < value2.length && value2.charCodeAt(end - 1) >= 55296 && value2.charCodeAt(end - 1) <= 56319 && value2.charCodeAt(end) >= 56320 && value2.charCodeAt(end) <= 57343) {
78068
+ end--;
78069
+ }
78070
+ if (end === offset) {
78071
+ this.flush();
78072
+ continue;
78073
+ }
78074
+ this.buffer += value2.slice(offset, end);
78075
+ offset = end;
78076
+ if (this.buffer.length === MAX_RENDER_WRITE_CHARS) {
78077
+ this.flush();
78078
+ }
78079
+ }
78080
+ }
78081
+ flush() {
78082
+ if (!this.buffer)
78083
+ return;
78084
+ this.write(this.buffer);
78085
+ this.writtenChars += this.buffer.length;
78086
+ this.buffer = "";
78087
+ }
78088
+ get length() {
78089
+ return this.writtenChars + this.buffer.length;
78090
+ }
78091
+ }
77947
78092
  function parseKittyImageHeader(line) {
77948
78093
  const sequenceStart = line.indexOf(KITTY_SEQUENCE_PREFIX);
77949
78094
  if (sequenceStart === -1)
@@ -78115,33 +78260,34 @@ class TuiMainScreen extends TuiBase {
78115
78260
  newLines = this.applyLineResets(newLines);
78116
78261
  const fullRender = (clear) => {
78117
78262
  this.fullRedrawCount += 1;
78118
- let buffer2 = "\x1B[?2026h";
78263
+ const output2 = new BoundedTerminalWriter((data) => this.terminal.write(data));
78264
+ output2.append("\x1B[?2026h");
78119
78265
  if (clear) {
78120
- buffer2 += this.deleteKittyImages(this.previousKittyImageIds);
78121
- buffer2 += "\x1B[2J\x1B[H\x1B[3J";
78266
+ output2.append(this.deleteKittyImages(this.previousKittyImageIds));
78267
+ output2.append("\x1B[2J\x1B[H\x1B[3J");
78122
78268
  }
78123
78269
  for (let i = 0;i < newLines.length; i++) {
78124
78270
  if (i > 0)
78125
- buffer2 += `\r
78126
- `;
78271
+ output2.append(`\r
78272
+ `);
78127
78273
  const line = newLines[i];
78128
78274
  const isImage = isImageLine(line);
78129
78275
  const imageReservedRows = isImage ? this.getKittyImageReservedRows(newLines, i) : 1;
78130
78276
  if (imageReservedRows > 1 && imageReservedRows <= height) {
78131
78277
  for (let row = 1;row < imageReservedRows; row++) {
78132
- buffer2 += `\r
78133
- `;
78278
+ output2.append(`\r
78279
+ `);
78134
78280
  }
78135
- buffer2 += `\x1B[${imageReservedRows - 1}A`;
78136
- buffer2 += line;
78137
- buffer2 += `\x1B[${imageReservedRows - 1}B`;
78281
+ output2.append(`\x1B[${imageReservedRows - 1}A`);
78282
+ output2.append(line);
78283
+ output2.append(`\x1B[${imageReservedRows - 1}B`);
78138
78284
  i += imageReservedRows - 1;
78139
78285
  continue;
78140
78286
  }
78141
- buffer2 += line;
78287
+ output2.append(line);
78142
78288
  }
78143
- buffer2 += "\x1B[?2026l";
78144
- this.terminal.write(buffer2);
78289
+ output2.append("\x1B[?2026l");
78290
+ output2.flush();
78145
78291
  this.cursorRow = Math.max(0, newLines.length - 1);
78146
78292
  this.hardwareCursorRow = this.cursorRow;
78147
78293
  if (clear) {
@@ -78221,8 +78367,9 @@ class TuiMainScreen extends TuiBase {
78221
78367
  }
78222
78368
  if (firstChanged >= newLines.length) {
78223
78369
  if (this.previousLines.length > newLines.length) {
78224
- let buffer2 = "\x1B[?2026h";
78225
- buffer2 += this.deleteChangedKittyImages(firstChanged, lastChanged);
78370
+ const output2 = new BoundedTerminalWriter((data) => this.terminal.write(data));
78371
+ output2.append("\x1B[?2026h");
78372
+ output2.append(this.deleteChangedKittyImages(firstChanged, lastChanged));
78226
78373
  const targetRow = Math.max(0, newLines.length - 1);
78227
78374
  if (targetRow < prevViewportTop) {
78228
78375
  logRedraw(`deleted lines moved viewport up (${targetRow} < ${prevViewportTop})`);
@@ -78231,10 +78378,10 @@ class TuiMainScreen extends TuiBase {
78231
78378
  }
78232
78379
  const lineDiff2 = computeLineDiff(targetRow);
78233
78380
  if (lineDiff2 > 0)
78234
- buffer2 += `\x1B[${lineDiff2}B`;
78381
+ output2.append(`\x1B[${lineDiff2}B`);
78235
78382
  else if (lineDiff2 < 0)
78236
- buffer2 += `\x1B[${-lineDiff2}A`;
78237
- buffer2 += "\r";
78383
+ output2.append(`\x1B[${-lineDiff2}A`);
78384
+ output2.append("\r");
78238
78385
  const extraLines = this.previousLines.length - newLines.length;
78239
78386
  if (extraLines > height) {
78240
78387
  logRedraw(`extraLines > height (${extraLines} > ${height})`);
@@ -78243,19 +78390,19 @@ class TuiMainScreen extends TuiBase {
78243
78390
  }
78244
78391
  const clearStartOffset = newLines.length === 0 ? 0 : 1;
78245
78392
  if (extraLines > 0 && clearStartOffset > 0) {
78246
- buffer2 += `\x1B[${clearStartOffset}B`;
78393
+ output2.append(`\x1B[${clearStartOffset}B`);
78247
78394
  }
78248
78395
  for (let i = 0;i < extraLines; i++) {
78249
- buffer2 += "\r\x1B[2K";
78396
+ output2.append("\r\x1B[2K");
78250
78397
  if (i < extraLines - 1)
78251
- buffer2 += "\x1B[1B";
78398
+ output2.append("\x1B[1B");
78252
78399
  }
78253
78400
  const moveBack = Math.max(0, extraLines - 1 + clearStartOffset);
78254
78401
  if (moveBack > 0) {
78255
- buffer2 += `\x1B[${moveBack}A`;
78402
+ output2.append(`\x1B[${moveBack}A`);
78256
78403
  }
78257
- buffer2 += "\x1B[?2026l";
78258
- this.terminal.write(buffer2);
78404
+ output2.append("\x1B[?2026l");
78405
+ output2.flush();
78259
78406
  this.cursorRow = targetRow;
78260
78407
  this.hardwareCursorRow = targetRow;
78261
78408
  }
@@ -78272,36 +78419,37 @@ class TuiMainScreen extends TuiBase {
78272
78419
  fullRender(true);
78273
78420
  return;
78274
78421
  }
78275
- let buffer = "\x1B[?2026h";
78276
- buffer += this.deleteChangedKittyImages(firstChanged, lastChanged);
78422
+ const output = new BoundedTerminalWriter((data) => this.terminal.write(data));
78423
+ output.append("\x1B[?2026h");
78424
+ output.append(this.deleteChangedKittyImages(firstChanged, lastChanged));
78277
78425
  const prevViewportBottom = prevViewportTop + height - 1;
78278
78426
  const moveTargetRow = appendStart ? firstChanged - 1 : firstChanged;
78279
78427
  if (moveTargetRow > prevViewportBottom) {
78280
78428
  const currentScreenRow = Math.max(0, Math.min(height - 1, hardwareCursorRow - prevViewportTop));
78281
78429
  const moveToBottom = height - 1 - currentScreenRow;
78282
78430
  if (moveToBottom > 0) {
78283
- buffer += `\x1B[${moveToBottom}B`;
78431
+ output.append(`\x1B[${moveToBottom}B`);
78284
78432
  }
78285
78433
  const scroll = moveTargetRow - prevViewportBottom;
78286
- buffer += `\r
78287
- `.repeat(scroll);
78434
+ output.append(`\r
78435
+ `.repeat(scroll));
78288
78436
  prevViewportTop += scroll;
78289
78437
  viewportTop += scroll;
78290
78438
  hardwareCursorRow = moveTargetRow;
78291
78439
  }
78292
78440
  const lineDiff = computeLineDiff(moveTargetRow);
78293
78441
  if (lineDiff > 0) {
78294
- buffer += `\x1B[${lineDiff}B`;
78442
+ output.append(`\x1B[${lineDiff}B`);
78295
78443
  } else if (lineDiff < 0) {
78296
- buffer += `\x1B[${-lineDiff}A`;
78444
+ output.append(`\x1B[${-lineDiff}A`);
78297
78445
  }
78298
- buffer += appendStart ? `\r
78299
- ` : "\r";
78446
+ output.append(appendStart ? `\r
78447
+ ` : "\r");
78300
78448
  const renderEnd = Math.min(lastChanged, newLines.length - 1);
78301
78449
  for (let i = firstChanged;i <= renderEnd; i++) {
78302
78450
  if (i > firstChanged)
78303
- buffer += `\r
78304
- `;
78451
+ output.append(`\r
78452
+ `);
78305
78453
  const line = newLines[i];
78306
78454
  const isImage = isImageLine(line);
78307
78455
  const imageReservedRows = isImage ? this.getKittyImageReservedRows(newLines, i, renderEnd) : 1;
@@ -78312,18 +78460,18 @@ class TuiMainScreen extends TuiBase {
78312
78460
  fullRender(true);
78313
78461
  return;
78314
78462
  }
78315
- buffer += "\x1B[2K";
78463
+ output.append("\x1B[2K");
78316
78464
  for (let row = 1;row < imageReservedRows; row++) {
78317
- buffer += `\r
78318
- \x1B[2K`;
78465
+ output.append(`\r
78466
+ \x1B[2K`);
78319
78467
  }
78320
- buffer += `\x1B[${imageReservedRows - 1}A`;
78321
- buffer += line;
78322
- buffer += `\x1B[${imageReservedRows - 1}B`;
78468
+ output.append(`\x1B[${imageReservedRows - 1}A`);
78469
+ output.append(line);
78470
+ output.append(`\x1B[${imageReservedRows - 1}B`);
78323
78471
  i += imageReservedRows - 1;
78324
78472
  continue;
78325
78473
  }
78326
- buffer += "\x1B[2K";
78474
+ output.append("\x1B[2K");
78327
78475
  if (!isImage && visibleWidth(line) > width) {
78328
78476
  const crashLogPath = path4.join(this.logDirectory, "pi-crash.log");
78329
78477
  const crashData = [
@@ -78350,23 +78498,23 @@ class TuiMainScreen extends TuiBase {
78350
78498
  `);
78351
78499
  throw new Error(errorMsg);
78352
78500
  }
78353
- buffer += line;
78501
+ output.append(line);
78354
78502
  }
78355
78503
  let finalCursorRow = renderEnd;
78356
78504
  if (this.previousLines.length > newLines.length) {
78357
78505
  if (renderEnd < newLines.length - 1) {
78358
78506
  const moveDown = newLines.length - 1 - renderEnd;
78359
- buffer += `\x1B[${moveDown}B`;
78507
+ output.append(`\x1B[${moveDown}B`);
78360
78508
  finalCursorRow = newLines.length - 1;
78361
78509
  }
78362
78510
  const extraLines = this.previousLines.length - newLines.length;
78363
78511
  for (let i = newLines.length;i < this.previousLines.length; i++) {
78364
- buffer += `\r
78365
- \x1B[2K`;
78512
+ output.append(`\r
78513
+ \x1B[2K`);
78366
78514
  }
78367
- buffer += `\x1B[${extraLines}A`;
78515
+ output.append(`\x1B[${extraLines}A`);
78368
78516
  }
78369
- buffer += "\x1B[?2026l";
78517
+ output.append("\x1B[?2026l");
78370
78518
  if (process.env.PI_TUI_DEBUG === "1") {
78371
78519
  const debugDir = "/tmp/tui";
78372
78520
  fs2.mkdirSync(debugDir, { recursive: true });
@@ -78391,12 +78539,12 @@ class TuiMainScreen extends TuiBase {
78391
78539
  JSON.stringify(this.previousLines, null, 2),
78392
78540
  "",
78393
78541
  "=== buffer ===",
78394
- JSON.stringify(buffer)
78542
+ `[${output.length} chars written in bounded chunks]`
78395
78543
  ].join(`
78396
78544
  `);
78397
78545
  fs2.writeFileSync(debugPath, debugData);
78398
78546
  }
78399
- this.terminal.write(buffer);
78547
+ output.flush();
78400
78548
  this.cursorRow = Math.max(0, newLines.length - 1);
78401
78549
  this.hardwareCursorRow = finalCursorRow;
78402
78550
  this.maxLinesRendered = Math.max(this.maxLinesRendered, newLines.length);
@@ -80304,7 +80452,7 @@ ${getProviderLoginHelp()}`;
80304
80452
  import { randomBytes } from "node:crypto";
80305
80453
  import { createWriteStream } from "node:fs";
80306
80454
  import { tmpdir } from "node:os";
80307
- import { join as join12 } from "node:path";
80455
+ import { join as join13 } from "node:path";
80308
80456
 
80309
80457
  // node_modules/@earendil-works/pi-coding-agent/dist/utils/ansi.js
80310
80458
  function ansiRegex({ onlyFirst = false } = {}) {
@@ -80327,7 +80475,7 @@ function stripAnsi(value2) {
80327
80475
 
80328
80476
  // node_modules/@earendil-works/pi-coding-agent/dist/utils/shell.js
80329
80477
  import { existsSync as existsSync3 } from "node:fs";
80330
- import { delimiter } from "node:path";
80478
+ import { delimiter, join as join12 } from "node:path";
80331
80479
  import { spawn as spawn2, spawnSync } from "child_process";
80332
80480
  function isLegacyWslBashPath(path7) {
80333
80481
  const normalized = path7.replace(/\//g, "\\").toLowerCase();
@@ -80461,11 +80609,12 @@ function killTrackedDetachedChildren() {
80461
80609
  function killProcessTree(pid) {
80462
80610
  if (process.platform === "win32") {
80463
80611
  try {
80464
- spawn2("taskkill", ["/F", "/T", "/PID", String(pid)], {
80612
+ const child = spawn2(join12(process.env.SystemRoot ?? "C:\\Windows", "System32", "taskkill.exe"), ["/F", "/T", "/PID", String(pid)], {
80465
80613
  stdio: "ignore",
80466
80614
  detached: true,
80467
80615
  windowsHide: true
80468
80616
  });
80617
+ child.once("error", () => {});
80469
80618
  } catch {}
80470
80619
  } else {
80471
80620
  try {
@@ -80665,7 +80814,7 @@ async function executeBashWithOperations(command, cwd, operations, options) {
80665
80814
  return;
80666
80815
  }
80667
80816
  const id = randomBytes(8).toString("hex");
80668
- tempFilePath = join12(tmpdir(), `pi-bash-${id}.log`);
80817
+ tempFilePath = join13(tmpdir(), `pi-bash-${id}.log`);
80669
80818
  tempFileStream = createWriteStream(tempFilePath);
80670
80819
  for (const chunk of outputChunks) {
80671
80820
  tempFileStream.write(chunk);
@@ -80850,7 +80999,7 @@ function convertToLlm(messages) {
80850
80999
  import { randomUUID } from "crypto";
80851
81000
  import { appendFileSync as appendFileSync3, closeSync, createReadStream, existsSync as existsSync4, mkdirSync as mkdirSync2, openSync, readdirSync as readdirSync3, readSync, statSync as statSync4, writeFileSync as writeFileSync2 } from "fs";
80852
81001
  import { readdir, stat } from "fs/promises";
80853
- import { join as join13, resolve as resolve2 } from "path";
81002
+ import { join as join14, resolve as resolve2 } from "path";
80854
81003
  import { createInterface } from "readline";
80855
81004
  import { StringDecoder } from "string_decoder";
80856
81005
  var CURRENT_SESSION_VERSION = 3;
@@ -81048,7 +81197,7 @@ function getDefaultSessionDirPath(cwd, agentDir = getAgentDir()) {
81048
81197
  const resolvedCwd = resolvePath(cwd);
81049
81198
  const resolvedAgentDir = resolvePath(agentDir);
81050
81199
  const safePath = `--${resolvedCwd.replace(/^[/\\]/, "").replace(/[/\\:]/g, "-")}--`;
81051
- return join13(resolvedAgentDir, "sessions", safePath);
81200
+ return join14(resolvedAgentDir, "sessions", safePath);
81052
81201
  }
81053
81202
  function getDefaultSessionDir(cwd, agentDir = getAgentDir()) {
81054
81203
  const sessionDir = getDefaultSessionDirPath(cwd, agentDir);
@@ -81081,11 +81230,11 @@ function loadEntriesFromFile(filePath) {
81081
81230
  if (!existsSync4(resolvedFilePath))
81082
81231
  return [];
81083
81232
  const entries = [];
81233
+ let pending = "";
81084
81234
  const fd = openSync(resolvedFilePath, "r");
81085
81235
  try {
81086
81236
  const decoder = new StringDecoder("utf8");
81087
81237
  const buffer = Buffer.allocUnsafe(SESSION_READ_BUFFER_SIZE);
81088
- let pending = "";
81089
81238
  while (true) {
81090
81239
  const bytesRead = readSync(fd, buffer, 0, buffer.length, null);
81091
81240
  if (bytesRead === 0)
@@ -81117,6 +81266,9 @@ function loadEntriesFromFile(filePath) {
81117
81266
  if (header.type !== "session" || typeof header.id !== "string") {
81118
81267
  return [];
81119
81268
  }
81269
+ if (pending)
81270
+ appendFileSync3(resolvedFilePath, `
81271
+ `);
81120
81272
  return entries;
81121
81273
  }
81122
81274
  function parseSessionHeaderCandidate(line) {
@@ -81188,7 +81340,7 @@ function findMostRecentSession(sessionDir, cwd) {
81188
81340
  const resolvedSessionDir = normalizePath(sessionDir);
81189
81341
  const resolvedCwd = cwd ? resolvePath(cwd) : undefined;
81190
81342
  try {
81191
- const files = readdirSync3(resolvedSessionDir).filter((f) => f.endsWith(".jsonl")).map((f) => join13(resolvedSessionDir, f)).map((path7) => ({ path: path7, header: readSessionHeaderForDiscovery(path7) })).filter((file) => file.header !== null && (!resolvedCwd || sessionCwdMatches(getSessionHeaderCwd(file.header), resolvedCwd))).map(({ path: path7 }) => ({ path: path7, mtime: statSync4(path7).mtime })).sort((a, b2) => b2.mtime.getTime() - a.mtime.getTime());
81343
+ const files = readdirSync3(resolvedSessionDir).filter((f) => f.endsWith(".jsonl")).map((f) => join14(resolvedSessionDir, f)).map((path7) => ({ path: path7, header: readSessionHeaderForDiscovery(path7) })).filter((file) => file.header !== null && (!resolvedCwd || sessionCwdMatches(getSessionHeaderCwd(file.header), resolvedCwd))).map(({ path: path7 }) => ({ path: path7, mtime: statSync4(path7).mtime })).sort((a, b2) => b2.mtime.getTime() - a.mtime.getTime());
81192
81344
  return files[0]?.path || null;
81193
81345
  } catch {
81194
81346
  return null;
@@ -81323,7 +81475,7 @@ async function listSessionsFromDir(dir, onProgress, progressOffset = 0, progress
81323
81475
  }
81324
81476
  try {
81325
81477
  const dirEntries = await readdir(dir);
81326
- const files = dirEntries.filter((f) => f.endsWith(".jsonl")).map((f) => join13(dir, f));
81478
+ const files = dirEntries.filter((f) => f.endsWith(".jsonl")).map((f) => join14(dir, f));
81327
81479
  const total = progressTotal ?? files.length;
81328
81480
  let loaded = 0;
81329
81481
  const results = await buildSessionInfosWithConcurrency(files, () => {
@@ -81417,7 +81569,7 @@ class SessionManager {
81417
81569
  this.flushed = false;
81418
81570
  if (this.persist) {
81419
81571
  const fileTimestamp = timestamp.replace(/[:.]/g, "-");
81420
- this.sessionFile = join13(this.getSessionDir(), `${fileTimestamp}_${this.sessionId}.jsonl`);
81572
+ this.sessionFile = join14(this.getSessionDir(), `${fileTimestamp}_${this.sessionId}.jsonl`);
81421
81573
  }
81422
81574
  return this.sessionFile;
81423
81575
  }
@@ -81749,7 +81901,7 @@ class SessionManager {
81749
81901
  const newSessionId = createSessionId();
81750
81902
  const timestamp = new Date().toISOString();
81751
81903
  const fileTimestamp = timestamp.replace(/[:.]/g, "-");
81752
- const newSessionFile = join13(this.getSessionDir(), `${fileTimestamp}_${newSessionId}.jsonl`);
81904
+ const newSessionFile = join14(this.getSessionDir(), `${fileTimestamp}_${newSessionId}.jsonl`);
81753
81905
  const header = {
81754
81906
  type: "session",
81755
81907
  version: CURRENT_SESSION_VERSION,
@@ -81870,7 +82022,7 @@ class SessionManager {
81870
82022
  const newSessionId = options?.id ?? createSessionId();
81871
82023
  const timestamp = new Date().toISOString();
81872
82024
  const fileTimestamp = timestamp.replace(/[:.]/g, "-");
81873
- const newSessionFile = join13(dir, `${fileTimestamp}_${newSessionId}.jsonl`);
82025
+ const newSessionFile = join14(dir, `${fileTimestamp}_${newSessionId}.jsonl`);
81874
82026
  const newHeader = {
81875
82027
  type: "session",
81876
82028
  version: CURRENT_SESSION_VERSION,
@@ -81911,13 +82063,13 @@ class SessionManager {
81911
82063
  return [];
81912
82064
  }
81913
82065
  const entries = await readdir(sessionsDir, { withFileTypes: true });
81914
- const dirs = entries.filter((entry) => entry.isDirectory() || entry.isSymbolicLink()).map((entry) => join13(sessionsDir, entry.name));
82066
+ const dirs = entries.filter((entry) => entry.isDirectory() || entry.isSymbolicLink()).map((entry) => join14(sessionsDir, entry.name));
81915
82067
  let totalFiles = 0;
81916
82068
  const dirFiles = [];
81917
82069
  for (const dir of dirs) {
81918
82070
  try {
81919
82071
  const files = (await readdir(dir)).filter((f) => f.endsWith(".jsonl"));
81920
- dirFiles.push(files.map((f) => join13(dir, f)));
82072
+ dirFiles.push(files.map((f) => join14(dir, f)));
81921
82073
  totalFiles += files.length;
81922
82074
  } catch {
81923
82075
  dirFiles.push([]);
@@ -82393,6 +82545,15 @@ Keep each section concise. Preserve exact file paths, function names, and error
82393
82545
  var UPDATE_SUMMARIZATION_PROMPT = `The messages above are NEW conversation messages to incorporate into the existing summary provided in <previous-summary> tags.
82394
82546
 
82395
82547
  ${UPDATE_SUMMARIZATION_INSTRUCTIONS}`;
82548
+ function getSummarizationFailure(response, label) {
82549
+ if (response.stopReason === "error") {
82550
+ return `${label} failed: ${response.errorMessage || "Unknown error"}`;
82551
+ }
82552
+ if (response.stopReason === "length") {
82553
+ return `${label} failed: generation hit the token cap and the summary is incomplete`;
82554
+ }
82555
+ return;
82556
+ }
82396
82557
  function createSummarizationOptions(model, maxTokens, apiKey, headers, env, signal, thinkingLevel, sessionId) {
82397
82558
  const options = { maxTokens, signal, apiKey, headers, env, sessionId };
82398
82559
  if (model.reasoning && thinkingLevel && thinkingLevel !== "off") {
@@ -82404,8 +82565,7 @@ async function completeSummarization(model, context, options, streamFn, retry, c
82404
82565
  const requestOptions = {
82405
82566
  ...options,
82406
82567
  cacheRetention: "none",
82407
- sessionId: options.sessionId ?? uuidv7(),
82408
- toolChoice: "none"
82568
+ sessionId: options.sessionId ?? uuidv7()
82409
82569
  };
82410
82570
  const produce = async () => streamFn ? (await streamFn(model, context, requestOptions)).result() : completeSimple(model, context, requestOptions);
82411
82571
  return retryAssistantCall(produce, retry, requestOptions.signal, callbacks);
@@ -82450,8 +82610,9 @@ ${previousSummary}
82450
82610
  promptText += basePrompt;
82451
82611
  const completionOptions = createSummarizationOptions(model, maxTokens, apiKey, headers, env, signal, thinkingLevel, sessionId);
82452
82612
  const response = await completeSummarization(model, buildSummarizationContext(promptText), completionOptions, streamFn, retry, callbacks);
82453
- if (response.stopReason === "error") {
82454
- throw new Error(`Summarization failed: ${response.errorMessage || "Unknown error"}`);
82613
+ const failure = getSummarizationFailure(response, "Summarization");
82614
+ if (failure) {
82615
+ throw new Error(failure);
82455
82616
  }
82456
82617
  if (response.content.some((block) => block.type === "toolCall")) {
82457
82618
  throw new Error("Summarization attempted to call a tool");
@@ -82584,8 +82745,9 @@ ${conversationText}
82584
82745
 
82585
82746
  ${TURN_PREFIX_SUMMARIZATION_PROMPT}`;
82586
82747
  const response = await completeSummarization(model, buildSummarizationContext(promptText), createSummarizationOptions(model, maxTokens, apiKey, headers, env, signal, thinkingLevel, sessionId), streamFn, retry, callbacks);
82587
- if (response.stopReason === "error") {
82588
- throw new Error(`Turn prefix summarization failed: ${response.errorMessage || "Unknown error"}`);
82748
+ const failure = getSummarizationFailure(response, "Turn prefix summarization");
82749
+ if (failure) {
82750
+ throw new Error(failure);
82589
82751
  }
82590
82752
  if (response.content.some((block) => block.type === "toolCall")) {
82591
82753
  throw new Error("Turn prefix summarization attempted to call a tool");
@@ -82751,8 +82913,9 @@ ${instructions}`;
82751
82913
  if (response.stopReason === "aborted") {
82752
82914
  return { aborted: true };
82753
82915
  }
82754
- if (response.stopReason === "error") {
82755
- return { error: response.errorMessage || "Summarization failed" };
82916
+ const failure = getSummarizationFailure(response, "Branch summarization");
82917
+ if (failure) {
82918
+ return { error: failure };
82756
82919
  }
82757
82920
  if (response.content.some((block) => block.type === "toolCall")) {
82758
82921
  return { error: "Branch summarization attempted to call a tool" };
@@ -82782,7 +82945,7 @@ var THINKING_LEVEL_OPTIONS = [
82782
82945
 
82783
82946
  // node_modules/@earendil-works/pi-coding-agent/dist/core/export-html/index.js
82784
82947
  import { existsSync as existsSync5, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
82785
- import { basename as basename3, join as join14 } from "path";
82948
+ import { basename as basename3, join as join15 } from "path";
82786
82949
  function parseColor(color) {
82787
82950
  const hexMatch = color.match(/^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/);
82788
82951
  if (hexMatch) {
@@ -82857,11 +83020,11 @@ function generateThemeVars(themeName) {
82857
83020
  }
82858
83021
  function generateHtml(sessionData, themeName) {
82859
83022
  const templateDir = getExportTemplateDir();
82860
- const template = readFileSync3(join14(templateDir, "template.html"), "utf-8");
82861
- const templateCss = readFileSync3(join14(templateDir, "template.css"), "utf-8");
82862
- const templateJs = readFileSync3(join14(templateDir, "template.js"), "utf-8");
82863
- const markedJs = readFileSync3(join14(templateDir, "vendor", "marked.min.js"), "utf-8");
82864
- const hljsJs = readFileSync3(join14(templateDir, "vendor", "highlight.min.js"), "utf-8");
83023
+ const template = readFileSync3(join15(templateDir, "template.html"), "utf-8");
83024
+ const templateCss = readFileSync3(join15(templateDir, "template.css"), "utf-8");
83025
+ const templateJs = readFileSync3(join15(templateDir, "template.js"), "utf-8");
83026
+ const markedJs = readFileSync3(join15(templateDir, "vendor", "marked.min.js"), "utf-8");
83027
+ const hljsJs = readFileSync3(join15(templateDir, "vendor", "highlight.min.js"), "utf-8");
82865
83028
  const themeVars = generateThemeVars(themeName);
82866
83029
  const colors = getResolvedThemeColors(themeName);
82867
83030
  const themeExport = getThemeExportColors(themeName);
@@ -83575,15 +83738,25 @@ function createAgentStream() {
83575
83738
  async function runLoop(initialContext, newMessages, initialConfig, signal, emit, streamFunction) {
83576
83739
  let currentContext = initialContext;
83577
83740
  let config = initialConfig;
83578
- let firstTurn = true;
83741
+ let lastCompletedTurn;
83579
83742
  let pendingMessages = await config.getSteeringMessages?.() || [];
83580
83743
  while (true) {
83581
83744
  let hasMoreToolCalls = true;
83582
83745
  while (hasMoreToolCalls || pendingMessages.length > 0) {
83583
- if (!firstTurn) {
83746
+ if (lastCompletedTurn) {
83747
+ const nextTurnSnapshot = await config.prepareNextTurn?.(lastCompletedTurn);
83748
+ if (nextTurnSnapshot) {
83749
+ currentContext = nextTurnSnapshot.context ?? currentContext;
83750
+ config = {
83751
+ ...config,
83752
+ model: nextTurnSnapshot.model ?? config.model,
83753
+ reasoning: nextTurnSnapshot.thinkingLevel === undefined ? config.reasoning : nextTurnSnapshot.thinkingLevel === "off" ? undefined : nextTurnSnapshot.thinkingLevel
83754
+ };
83755
+ }
83756
+ if (pendingMessages.length === 0) {
83757
+ pendingMessages = await config.getSteeringMessages?.() || [];
83758
+ }
83584
83759
  await emit({ type: "turn_start" });
83585
- } else {
83586
- firstTurn = false;
83587
83760
  }
83588
83761
  if (pendingMessages.length > 0) {
83589
83762
  for (const message2 of pendingMessages) {
@@ -83614,27 +83787,13 @@ async function runLoop(initialContext, newMessages, initialConfig, signal, emit,
83614
83787
  }
83615
83788
  }
83616
83789
  await emit({ type: "turn_end", message, toolResults });
83617
- const nextTurnContext = {
83790
+ lastCompletedTurn = {
83618
83791
  message,
83619
83792
  toolResults,
83620
83793
  context: currentContext,
83621
83794
  newMessages
83622
83795
  };
83623
- const nextTurnSnapshot = await config.prepareNextTurn?.(nextTurnContext);
83624
- if (nextTurnSnapshot) {
83625
- currentContext = nextTurnSnapshot.context ?? currentContext;
83626
- config = {
83627
- ...config,
83628
- model: nextTurnSnapshot.model ?? config.model,
83629
- reasoning: nextTurnSnapshot.thinkingLevel === undefined ? config.reasoning : nextTurnSnapshot.thinkingLevel === "off" ? undefined : nextTurnSnapshot.thinkingLevel
83630
- };
83631
- }
83632
- if (await config.shouldStopAfterTurn?.({
83633
- message,
83634
- toolResults,
83635
- context: currentContext,
83636
- newMessages
83637
- })) {
83796
+ if (await config.shouldStopAfterTurn?.(lastCompletedTurn)) {
83638
83797
  await emit({ type: "agent_end", messages: newMessages });
83639
83798
  return;
83640
83799
  }
@@ -91453,6 +91612,8 @@ class ExtensionRunner {
91453
91612
  shortcutDiagnostics = [];
91454
91613
  commandDiagnostics = [];
91455
91614
  staleMessage;
91615
+ uiPromptDepth = 0;
91616
+ activeUIPrompt;
91456
91617
  constructor(extensions, runtime, cwd, sessionManager, modelRegistry) {
91457
91618
  this.extensions = extensions;
91458
91619
  this.runtime = runtime;
@@ -91562,9 +91723,50 @@ class ExtensionRunner {
91562
91723
  this.reloadHandler = async () => {};
91563
91724
  }
91564
91725
  setUIContext(uiContext, mode = "print") {
91565
- this.uiContext = uiContext ?? noOpUIContext;
91726
+ this.uiContext = uiContext ? this.wrapUIPromptContext(uiContext) : noOpUIContext;
91566
91727
  this.mode = mode;
91567
91728
  }
91729
+ wrapUIPromptContext(ui) {
91730
+ return {
91731
+ ...ui,
91732
+ select: (title, options, opts) => this.withUIPrompt("select", title, () => ui.select(title, options, opts)),
91733
+ confirm: (title, message, opts) => this.withUIPrompt("confirm", title, () => ui.confirm(title, message, opts)),
91734
+ input: (title, placeholder, opts) => this.withUIPrompt("input", title, () => ui.input(title, placeholder, opts)),
91735
+ editor: (title, prefill) => this.withUIPrompt("editor", title, () => ui.editor(title, prefill)),
91736
+ custom: (factory, options) => this.withUIPrompt("custom", undefined, () => ui.custom(factory, options))
91737
+ };
91738
+ }
91739
+ withUIPrompt(kind, title, run) {
91740
+ const outerPrompt = this.uiPromptDepth++ === 0;
91741
+ if (outerPrompt) {
91742
+ this.activeUIPrompt = { kind, title };
91743
+ this.emitUIPromptEvent({ type: "ui_prompt_start", reason: "ui_prompt", kind, ...title ? { title } : {} });
91744
+ }
91745
+ const finish = () => {
91746
+ if (--this.uiPromptDepth > 0)
91747
+ return;
91748
+ this.uiPromptDepth = 0;
91749
+ const prompt = this.activeUIPrompt ?? { kind, title };
91750
+ this.activeUIPrompt = undefined;
91751
+ this.emitUIPromptEvent({
91752
+ type: "ui_prompt_end",
91753
+ reason: "ui_prompt",
91754
+ kind: prompt.kind,
91755
+ ...prompt.title ? { title: prompt.title } : {}
91756
+ });
91757
+ };
91758
+ try {
91759
+ return run().finally(finish);
91760
+ } catch (err2) {
91761
+ finish();
91762
+ throw err2;
91763
+ }
91764
+ }
91765
+ emitUIPromptEvent(event) {
91766
+ queueMicrotask(() => {
91767
+ this.emit(event);
91768
+ });
91769
+ }
91568
91770
  getUIContext() {
91569
91771
  return this.uiContext;
91570
91772
  }
@@ -92970,7 +93172,7 @@ class ModelRegistry {
92970
93172
 
92971
93173
  // node_modules/@earendil-works/pi-coding-agent/dist/core/prompt-templates.js
92972
93174
  import { existsSync as existsSync7, readdirSync as readdirSync5, readFileSync as readFileSync5, statSync as statSync6 } from "fs";
92973
- import { basename as basename4, dirname as dirname7, join as join16, resolve as resolve4, sep as sep3 } from "path";
93175
+ import { basename as basename4, dirname as dirname7, join as join17, resolve as resolve4, sep as sep3 } from "path";
92974
93176
  function parseCommandArgs2(argsString) {
92975
93177
  const args = [];
92976
93178
  let current = "";
@@ -93058,7 +93260,7 @@ function loadTemplatesFromDir2(dir, getSourceInfo) {
93058
93260
  try {
93059
93261
  const entries = readdirSync5(dir, { withFileTypes: true });
93060
93262
  for (const entry of entries) {
93061
- const fullPath = join16(dir, entry.name);
93263
+ const fullPath = join17(dir, entry.name);
93062
93264
  let isFile = entry.isFile();
93063
93265
  if (entry.isSymbolicLink()) {
93064
93266
  try {
@@ -93086,7 +93288,7 @@ function loadPromptTemplates2(options) {
93086
93288
  const promptPaths = options.promptPaths;
93087
93289
  const includeDefaults = options.includeDefaults;
93088
93290
  const templates = [];
93089
- const globalPromptsDir = join16(resolvedAgentDir, "prompts");
93291
+ const globalPromptsDir = join17(resolvedAgentDir, "prompts");
93090
93292
  const projectPromptsDir = resolve4(resolvedCwd, CONFIG_DIR_NAME, "prompts");
93091
93293
  const isUnderPath = (target, root) => {
93092
93294
  const normalizedRoot = resolve4(root);
@@ -93190,7 +93392,7 @@ function exportSessionToJsonl(sessionManager, outputPath, createTrailingEntries)
93190
93392
  // node_modules/@earendil-works/pi-coding-agent/dist/core/skills.js
93191
93393
  var import_ignore2 = __toESM(require_ignore(), 1);
93192
93394
  import { existsSync as existsSync9, readdirSync as readdirSync6, readFileSync as readFileSync6, statSync as statSync7 } from "fs";
93193
- import { basename as basename5, dirname as dirname9, join as join17, relative as relative2, resolve as resolve5, sep as sep4 } from "path";
93395
+ import { basename as basename5, dirname as dirname9, join as join18, relative as relative2, resolve as resolve5, sep as sep4 } from "path";
93194
93396
  var MAX_NAME_LENGTH2 = 64;
93195
93397
  var MAX_DESCRIPTION_LENGTH2 = 1024;
93196
93398
  var IGNORE_FILE_NAMES2 = [".gitignore", ".ignore", ".fdignore"];
@@ -93221,7 +93423,7 @@ function addIgnoreRules2(ig, dir, rootDir) {
93221
93423
  const relativeDir = relative2(rootDir, dir);
93222
93424
  const prefix = relativeDir ? `${toPosixPath(relativeDir)}/` : "";
93223
93425
  for (const filename of IGNORE_FILE_NAMES2) {
93224
- const ignorePath = join17(dir, filename);
93426
+ const ignorePath = join18(dir, filename);
93225
93427
  if (!existsSync9(ignorePath))
93226
93428
  continue;
93227
93429
  try {
@@ -93300,7 +93502,7 @@ function loadSkillsFromDirInternal2(dir, source, includeRootFiles, ignoreMatcher
93300
93502
  if (entry.name !== "SKILL.md") {
93301
93503
  continue;
93302
93504
  }
93303
- const fullPath = join17(dir, entry.name);
93505
+ const fullPath = join18(dir, entry.name);
93304
93506
  let isFile = entry.isFile();
93305
93507
  if (entry.isSymbolicLink()) {
93306
93508
  try {
@@ -93327,7 +93529,7 @@ function loadSkillsFromDirInternal2(dir, source, includeRootFiles, ignoreMatcher
93327
93529
  if (entry.name === "node_modules") {
93328
93530
  continue;
93329
93531
  }
93330
- const fullPath = join17(dir, entry.name);
93532
+ const fullPath = join18(dir, entry.name);
93331
93533
  let isDirectory = entry.isDirectory();
93332
93534
  let isFile = entry.isFile();
93333
93535
  if (entry.isSymbolicLink()) {
@@ -93478,10 +93680,10 @@ function loadSkills2(options) {
93478
93680
  }
93479
93681
  }
93480
93682
  if (includeDefaults) {
93481
- addSkills(loadSkillsFromDirInternal2(join17(resolvedAgentDir, "skills"), "user", true));
93683
+ addSkills(loadSkillsFromDirInternal2(join18(resolvedAgentDir, "skills"), "user", true));
93482
93684
  addSkills(loadSkillsFromDirInternal2(resolve5(resolvedCwd, CONFIG_DIR_NAME, "skills"), "project", true));
93483
93685
  }
93484
- const userSkillsDir = join17(resolvedAgentDir, "skills");
93686
+ const userSkillsDir = join18(resolvedAgentDir, "skills");
93485
93687
  const projectSkillsDir = resolve5(resolvedCwd, CONFIG_DIR_NAME, "skills");
93486
93688
  const isUnderPath = (target, root) => {
93487
93689
  const normalizedRoot = resolve5(root);
@@ -93722,10 +93924,10 @@ function getExperimentalToolSampling() {
93722
93924
  import { randomBytes as randomBytes2 } from "node:crypto";
93723
93925
  import { createWriteStream as createWriteStream2 } from "node:fs";
93724
93926
  import { tmpdir as tmpdir2 } from "node:os";
93725
- import { join as join18 } from "node:path";
93927
+ import { join as join19 } from "node:path";
93726
93928
  function defaultTempFilePath(prefix) {
93727
93929
  const id = randomBytes2(8).toString("hex");
93728
- return join18(tmpdir2(), `${prefix}-${id}.log`);
93930
+ return join19(tmpdir2(), `${prefix}-${id}.log`);
93729
93931
  }
93730
93932
  function byteLength(text) {
93731
93933
  return Buffer.byteLength(text, "utf-8");
@@ -95199,7 +95401,7 @@ import path8 from "path";
95199
95401
  import { spawnSync as spawnSync3 } from "child_process";
95200
95402
  import { chmodSync, createWriteStream as createWriteStream3, existsSync as existsSync10, mkdirSync as mkdirSync4, readdirSync as readdirSync7, renameSync, rmSync } from "fs";
95201
95403
  import { arch, platform } from "os";
95202
- import { join as join19 } from "path";
95404
+ import { join as join20 } from "path";
95203
95405
  import { Readable } from "stream";
95204
95406
  import { pipeline } from "stream/promises";
95205
95407
 
@@ -95299,7 +95501,7 @@ function getToolPath(tool) {
95299
95501
  const config = TOOLS[tool];
95300
95502
  if (!config)
95301
95503
  return null;
95302
- const localPath = join19(TOOLS_DIR, config.binaryName + (platform() === "win32" ? ".exe" : ""));
95504
+ const localPath = join20(TOOLS_DIR, config.binaryName + (platform() === "win32" ? ".exe" : ""));
95303
95505
  if (existsSync10(localPath)) {
95304
95506
  return localPath;
95305
95507
  }
@@ -95340,7 +95542,7 @@ function findBinaryRecursively(rootDir, binaryFileName) {
95340
95542
  continue;
95341
95543
  const entries = readdirSync7(currentDir, { withFileTypes: true });
95342
95544
  for (const entry of entries) {
95343
- const fullPath = join19(currentDir, entry.name);
95545
+ const fullPath = join20(currentDir, entry.name);
95344
95546
  if (entry.isFile() && entry.name === binaryFileName) {
95345
95547
  return fullPath;
95346
95548
  }
@@ -95381,7 +95583,7 @@ function extractTarGzArchive(archivePath, extractDir, assetName) {
95381
95583
  function getWindowsTarCommand() {
95382
95584
  const systemRoot = process.env.SystemRoot ?? process.env.WINDIR;
95383
95585
  if (systemRoot) {
95384
- const systemTar = join19(systemRoot, "System32", "tar.exe");
95586
+ const systemTar = join20(systemRoot, "System32", "tar.exe");
95385
95587
  if (existsSync10(systemTar)) {
95386
95588
  return systemTar;
95387
95589
  }
@@ -95438,11 +95640,11 @@ async function downloadTool(tool) {
95438
95640
  }
95439
95641
  mkdirSync4(TOOLS_DIR, { recursive: true });
95440
95642
  const downloadUrl = `https://github.com/${config.repo}/releases/download/${config.tagPrefix}${version}/${assetName}`;
95441
- const archivePath = join19(TOOLS_DIR, assetName);
95643
+ const archivePath = join20(TOOLS_DIR, assetName);
95442
95644
  const binaryExt = plat === "win32" ? ".exe" : "";
95443
- const binaryPath = join19(TOOLS_DIR, config.binaryName + binaryExt);
95645
+ const binaryPath = join20(TOOLS_DIR, config.binaryName + binaryExt);
95444
95646
  await downloadFile(downloadUrl, archivePath);
95445
- const extractDir = join19(TOOLS_DIR, `extract_tmp_${config.binaryName}_${process.pid}_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`);
95647
+ const extractDir = join20(TOOLS_DIR, `extract_tmp_${config.binaryName}_${process.pid}_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`);
95446
95648
  mkdirSync4(extractDir, { recursive: true });
95447
95649
  try {
95448
95650
  if (assetName.endsWith(".tar.gz")) {
@@ -95453,8 +95655,8 @@ async function downloadTool(tool) {
95453
95655
  throw new Error(`Unsupported archive format: ${assetName}`);
95454
95656
  }
95455
95657
  const binaryFileName = config.binaryName + binaryExt;
95456
- const extractedDir = join19(extractDir, assetName.replace(/\.(tar\.gz|zip)$/, ""));
95457
- const extractedBinaryCandidates = [join19(extractedDir, binaryFileName), join19(extractDir, binaryFileName)];
95658
+ const extractedDir = join20(extractDir, assetName.replace(/\.(tar\.gz|zip)$/, ""));
95659
+ const extractedBinaryCandidates = [join20(extractedDir, binaryFileName), join20(extractDir, binaryFileName)];
95458
95660
  let extractedBinary = extractedBinaryCandidates.find((candidate) => existsSync10(candidate));
95459
95661
  if (!extractedBinary) {
95460
95662
  extractedBinary = findBinaryRecursively(extractDir, binaryFileName) ?? undefined;
@@ -96964,6 +97166,7 @@ class AgentSession {
96964
97166
  _steeringMessages = [];
96965
97167
  _followUpMessages = [];
96966
97168
  _pendingNextTurnMessages = [];
97169
+ _pendingCustomMessages = [];
96967
97170
  _compactionAbortController = undefined;
96968
97171
  _autoCompactionAbortController = undefined;
96969
97172
  _overflowRecoveryAttempted = false;
@@ -97117,15 +97320,28 @@ class AgentSession {
97117
97320
  };
97118
97321
  };
97119
97322
  }
97323
+ async _compactBeforeNextAssistantResponse(context2) {
97324
+ const model = this.model;
97325
+ const settings = this.settingsManager.getCompactionSettings();
97326
+ if (!model || model.contextWindow <= 0 || !shouldCompact(estimateContextTokens(context2.messages).tokens, model.contextWindow, settings)) {
97327
+ return context2;
97328
+ }
97329
+ await this._runAutoCompaction("threshold", false);
97330
+ return {
97331
+ ...context2,
97332
+ messages: this.agent.state.messages.slice()
97333
+ };
97334
+ }
97120
97335
  _installAgentNextTurnRefresh() {
97121
97336
  const previousPrepareNextTurnWithContext = this.agent.prepareNextTurnWithContext ?? (this.agent.prepareNextTurn ? async (_turn, signal) => await this.agent.prepareNextTurn?.(signal) : undefined);
97122
97337
  this.agent.prepareNextTurnWithContext = async (turn, signal) => {
97123
- const previousSnapshot = await previousPrepareNextTurnWithContext?.(turn, signal);
97124
- const previousContext = previousSnapshot?.context ?? turn.context;
97338
+ const context2 = await this._compactBeforeNextAssistantResponse(turn.context);
97339
+ const previousSnapshot = await previousPrepareNextTurnWithContext?.({ ...turn, context: context2 }, signal);
97340
+ const nextContext = previousSnapshot?.context ?? context2;
97125
97341
  return {
97126
97342
  ...previousSnapshot,
97127
97343
  context: {
97128
- ...previousContext,
97344
+ ...nextContext,
97129
97345
  systemPrompt: this._systemPromptOverride ?? this._baseSystemPrompt,
97130
97346
  tools: this.agent.state.tools.slice()
97131
97347
  },
@@ -97220,6 +97436,9 @@ class AgentSession {
97220
97436
  }
97221
97437
  }
97222
97438
  }
97439
+ if (event.type === "turn_end") {
97440
+ this._flushPendingCustomMessages();
97441
+ }
97223
97442
  };
97224
97443
  _willRetryAfterAgentEnd(event) {
97225
97444
  const settings = this.settingsManager.getRetrySettings();
@@ -97497,6 +97716,7 @@ class AgentSession {
97497
97716
  } finally {
97498
97717
  this._systemPromptOverride = undefined;
97499
97718
  this._flushPendingBashMessages();
97719
+ this._flushPendingCustomMessages();
97500
97720
  await this._emitAgentSettled();
97501
97721
  }
97502
97722
  }
@@ -97569,6 +97789,7 @@ class AgentSession {
97569
97789
  return;
97570
97790
  }
97571
97791
  this._flushPendingBashMessages();
97792
+ this._flushPendingCustomMessages();
97572
97793
  if (!this.model) {
97573
97794
  throw new Error(formatNoModelSelectedMessage());
97574
97795
  }
@@ -97746,11 +97967,25 @@ ${args}` : skillBlock;
97746
97967
  }
97747
97968
  } else if (options?.triggerTurn) {
97748
97969
  await this._runAgentPrompt(appMessage);
97970
+ } else if (this.isStreaming) {
97971
+ this._pendingCustomMessages.push(appMessage);
97749
97972
  } else {
97750
- this.agent.state.messages.push(appMessage);
97751
- this.sessionManager.appendCustomMessageEntry(message.customType, message.content, message.display, message.details);
97752
- this._emit({ type: "message_start", message: appMessage });
97753
- this._emit({ type: "message_end", message: appMessage });
97973
+ this._appendCustomMessage(appMessage);
97974
+ }
97975
+ }
97976
+ _appendCustomMessage(appMessage) {
97977
+ this.agent.state.messages.push(appMessage);
97978
+ this.sessionManager.appendCustomMessageEntry(appMessage.customType, appMessage.content, appMessage.display, appMessage.details);
97979
+ this._emit({ type: "message_start", message: appMessage });
97980
+ this._emit({ type: "message_end", message: appMessage });
97981
+ }
97982
+ _flushPendingCustomMessages() {
97983
+ if (this._pendingCustomMessages.length === 0)
97984
+ return;
97985
+ const pending = this._pendingCustomMessages;
97986
+ this._pendingCustomMessages = [];
97987
+ for (const appMessage of pending) {
97988
+ this._appendCustomMessage(appMessage);
97754
97989
  }
97755
97990
  }
97756
97991
  async sendUserMessage(content, options) {
@@ -97832,10 +98067,25 @@ ${args}` : skillBlock;
97832
98067
  this.sessionManager.appendModelChange(model.provider, model.id);
97833
98068
  if (options.persist) {
97834
98069
  this.settingsManager.setDefaultModelAndProvider(model.provider, model.id);
98070
+ this._addPersistedDefaultToNonEmptyScope(model);
97835
98071
  }
97836
98072
  this.setThinkingLevel(thinkingLevel);
97837
98073
  await this._emitModelSelect(model, previousModel, "set");
97838
98074
  }
98075
+ _addPersistedDefaultToNonEmptyScope(model) {
98076
+ if (this._scopedModels.length === 0)
98077
+ return;
98078
+ if (this._scopedModels.some((scoped) => modelsAreEqual(scoped.model, model)))
98079
+ return;
98080
+ this._scopedModels = [...this._scopedModels, { model }];
98081
+ const enabledModels = this.settingsManager.getEnabledModels();
98082
+ if (!enabledModels?.length)
98083
+ return;
98084
+ const modelReference = `${model.provider}/${model.id}`;
98085
+ if (enabledModels.some((pattern) => pattern.toLowerCase() === modelReference.toLowerCase()))
98086
+ return;
98087
+ this.settingsManager.setEnabledModels([...enabledModels, modelReference]);
98088
+ }
97839
98089
  async cycleModel(direction = "forward", options = {}) {
97840
98090
  if (this._scopedModels.length > 0) {
97841
98091
  return this._cycleScopedModel(direction, options);
@@ -97859,6 +98109,7 @@ ${args}` : skillBlock;
97859
98109
  this.sessionManager.appendModelChange(next.model.provider, next.model.id);
97860
98110
  if (options.persist) {
97861
98111
  this.settingsManager.setDefaultModelAndProvider(next.model.provider, next.model.id);
98112
+ this._addPersistedDefaultToNonEmptyScope(next.model);
97862
98113
  }
97863
98114
  this.setThinkingLevel(thinkingLevel);
97864
98115
  await this._emitModelSelect(next.model, currentModel, "cycle");
@@ -97880,6 +98131,7 @@ ${args}` : skillBlock;
97880
98131
  this.sessionManager.appendModelChange(nextModel.provider, nextModel.id);
97881
98132
  if (options.persist) {
97882
98133
  this.settingsManager.setDefaultModelAndProvider(nextModel.provider, nextModel.id);
98134
+ this._addPersistedDefaultToNonEmptyScope(nextModel);
97883
98135
  }
97884
98136
  this.setThinkingLevel(thinkingLevel);
97885
98137
  await this._emitModelSelect(nextModel, currentModel, "cycle");
@@ -99037,7 +99289,7 @@ ${command}` : command;
99037
99289
  // node_modules/@earendil-works/pi-coding-agent/dist/core/auth-storage.js
99038
99290
  var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
99039
99291
  import { existsSync as existsSync11, mkdirSync as mkdirSync5, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
99040
- import { dirname as dirname13, join as join20 } from "path";
99292
+ import { dirname as dirname13, join as join21 } from "path";
99041
99293
  import { setTimeout as sleep2 } from "timers/promises";
99042
99294
 
99043
99295
  // node_modules/@earendil-works/pi-coding-agent/dist/utils/abort.js
@@ -99093,7 +99345,7 @@ var sharedAuthFileReadState;
99093
99345
 
99094
99346
  class FileAuthStorageBackend {
99095
99347
  authPath;
99096
- constructor(authPath = join20(getAgentDir(), "auth.json")) {
99348
+ constructor(authPath = join21(getAgentDir(), "auth.json")) {
99097
99349
  this.authPath = normalizePath(authPath);
99098
99350
  }
99099
99351
  ensureParentDir() {
@@ -99222,7 +99474,7 @@ class FileAuthStorageBackend {
99222
99474
  class ReadOnlyAuthStorage {
99223
99475
  authPath;
99224
99476
  data;
99225
- constructor(authPath = join20(getAgentDir(), "auth.json")) {
99477
+ constructor(authPath = join21(getAgentDir(), "auth.json")) {
99226
99478
  this.authPath = normalizePath(authPath);
99227
99479
  }
99228
99480
  load() {
@@ -99332,7 +99584,7 @@ class AuthStorage {
99332
99584
  }
99333
99585
  this.reload();
99334
99586
  }
99335
- static create(authPath = join20(getAgentDir(), "auth.json")) {
99587
+ static create(authPath = join21(getAgentDir(), "auth.json")) {
99336
99588
  const normalizedAuthPath = normalizePath(authPath);
99337
99589
  return new AuthStorage(new FileAuthStorageBackend(normalizedAuthPath), normalizedAuthPath);
99338
99590
  }
@@ -99455,7 +99707,7 @@ class AuthStorage {
99455
99707
  return entries.map(([providerId, credential]) => ({ providerId, type: credential.type }));
99456
99708
  }
99457
99709
  }
99458
- function readStoredCredential(providerId, authPath = join20(getAgentDir(), "auth.json")) {
99710
+ function readStoredCredential(providerId, authPath = join21(getAgentDir(), "auth.json")) {
99459
99711
  try {
99460
99712
  const data = JSON.parse(stripBom(readFileSync8(normalizePath(authPath), "utf-8")));
99461
99713
  return data[providerId];
@@ -101557,7 +101809,7 @@ async function findInitialModel(options) {
101557
101809
  return { model: undefined, thinkingLevel: DEFAULT_THINKING_LEVEL, fallbackMessage: undefined };
101558
101810
  }
101559
101811
  // node_modules/@earendil-works/pi-coding-agent/dist/core/model-runtime.js
101560
- import { dirname as dirname14, join as join22 } from "node:path";
101812
+ import { dirname as dirname14, join as join23 } from "node:path";
101561
101813
 
101562
101814
  // node_modules/@earendil-works/pi-coding-agent/dist/core/model-config.js
101563
101815
  import { readFile as readFile2 } from "node:fs/promises";
@@ -101821,7 +102073,7 @@ File: ${path11}`);
101821
102073
  }
101822
102074
 
101823
102075
  // node_modules/@earendil-works/pi-coding-agent/dist/core/models-store.js
101824
- import { join as join21 } from "node:path";
102076
+ import { join as join22 } from "node:path";
101825
102077
  var sharedModelsFileReadState;
101826
102078
 
101827
102079
  class InMemoryCodingAgentModelsStore {
@@ -101845,7 +102097,7 @@ class FileModelsStore {
101845
102097
  storage;
101846
102098
  path;
101847
102099
  readState;
101848
- constructor(path11 = join21(getAgentDir(), "models-store.json")) {
102100
+ constructor(path11 = join22(getAgentDir(), "models-store.json")) {
101849
102101
  this.path = normalizePath(path11);
101850
102102
  this.storage = new FileAuthStorageBackend(this.path);
101851
102103
  this.readState = sharedModelsFileReadState?.path === this.path ? sharedModelsFileReadState.readState : { data: {} };
@@ -102140,9 +102392,9 @@ class ModelRuntime {
102140
102392
  }
102141
102393
  static async create(options = {}) {
102142
102394
  const credentials = new RuntimeCredentials(options.credentials ?? AuthStorage.create(options.authPath));
102143
- const modelsPath = options.modelsPath === null ? undefined : options.modelsPath ?? join22(getAgentDir(), "models.json");
102395
+ const modelsPath = options.modelsPath === null ? undefined : options.modelsPath ?? join23(getAgentDir(), "models.json");
102144
102396
  const config = await ModelConfig.load(modelsPath);
102145
- const modelsStore = options.modelsStore ?? (modelsPath ? new FileModelsStore(options.modelsStorePath ?? join22(dirname14(modelsPath), "models-store.json")) : new InMemoryCodingAgentModelsStore);
102397
+ const modelsStore = options.modelsStore ?? (modelsPath ? new FileModelsStore(options.modelsStorePath ?? join23(dirname14(modelsPath), "models-store.json")) : new InMemoryCodingAgentModelsStore);
102146
102398
  const builtinModelDataGeneratedAt = getBuiltinModelDataGeneratedAt();
102147
102399
  const providers = builtinProviders().map((provider) => provider.id === "radius" ? provider : withRemoteCatalog(provider, options.catalogBaseUrl, builtinModelDataGeneratedAt));
102148
102400
  const runtime = new ModelRuntime(credentials, config, modelsPath, modelsStore, providers, process.env.PI_OFFLINE === undefined);
@@ -102630,7 +102882,7 @@ var import_ignore3 = __toESM(require_ignore(), 1);
102630
102882
  import { createHash } from "node:crypto";
102631
102883
  import { chmodSync as chmodSync2, existsSync as existsSync12, globSync, mkdirSync as mkdirSync6, readdirSync as readdirSync8, readFileSync as readFileSync9, rmSync as rmSync2, statSync as statSync8, writeFileSync as writeFileSync6 } from "node:fs";
102632
102884
  import { homedir as homedir7 } from "node:os";
102633
- import { basename as basename8, dirname as dirname15, join as join23, relative as relative4, resolve as resolve7, sep as sep7 } from "node:path";
102885
+ import { basename as basename8, dirname as dirname15, join as join24, relative as relative4, resolve as resolve7, sep as sep7 } from "node:path";
102634
102886
  var import_semver = __toESM(require_semver2(), 1);
102635
102887
 
102636
102888
  // node_modules/@earendil-works/pi-coding-agent/dist/utils/git.js
@@ -102953,7 +103205,7 @@ function getHomeDir() {
102953
103205
  return process.env.HOME || homedir7();
102954
103206
  }
102955
103207
  function getExtensionTempFolder(agentDir) {
102956
- const tempFolder = join23(agentDir, "tmp", "extensions");
103208
+ const tempFolder = join24(agentDir, "tmp", "extensions");
102957
103209
  mkdirSync6(tempFolder, { recursive: true, mode: 448 });
102958
103210
  chmodSync2(tempFolder, 448);
102959
103211
  return tempFolder;
@@ -102982,7 +103234,7 @@ function addIgnoreRules3(ig, dir, rootDir) {
102982
103234
  const relativeDir = relative4(rootDir, dir);
102983
103235
  const prefix = relativeDir ? `${toPosixPath3(relativeDir)}/` : "";
102984
103236
  for (const filename of IGNORE_FILE_NAMES3) {
102985
- const ignorePath = join23(dir, filename);
103237
+ const ignorePath = join24(dir, filename);
102986
103238
  if (!existsSync12(ignorePath))
102987
103239
  continue;
102988
103240
  try {
@@ -103032,7 +103284,7 @@ function collectFiles(dir, filePattern, skipNodeModules = true, ignoreMatcher, r
103032
103284
  continue;
103033
103285
  if (skipNodeModules && entry.name === "node_modules")
103034
103286
  continue;
103035
- const fullPath = join23(dir, entry.name);
103287
+ const fullPath = join24(dir, entry.name);
103036
103288
  let isDir = entry.isDirectory();
103037
103289
  let isFile = entry.isFile();
103038
103290
  if (entry.isSymbolicLink()) {
@@ -103070,7 +103322,7 @@ function collectSkillEntries(dir, mode, ignoreMatcher, rootDir) {
103070
103322
  if (entry.name !== "SKILL.md") {
103071
103323
  continue;
103072
103324
  }
103073
- const fullPath = join23(dir, entry.name);
103325
+ const fullPath = join24(dir, entry.name);
103074
103326
  let isFile = entry.isFile();
103075
103327
  if (entry.isSymbolicLink()) {
103076
103328
  try {
@@ -103090,7 +103342,7 @@ function collectSkillEntries(dir, mode, ignoreMatcher, rootDir) {
103090
103342
  continue;
103091
103343
  if (entry.name === "node_modules")
103092
103344
  continue;
103093
- const fullPath = join23(dir, entry.name);
103345
+ const fullPath = join24(dir, entry.name);
103094
103346
  let isDir = entry.isDirectory();
103095
103347
  let isFile = entry.isFile();
103096
103348
  if (entry.isSymbolicLink()) {
@@ -103123,7 +103375,7 @@ function collectAutoSkillEntries(dir, mode) {
103123
103375
  function findGitRepoRoot(startDir) {
103124
103376
  let dir = resolve7(startDir);
103125
103377
  while (true) {
103126
- if (existsSync12(join23(dir, ".git"))) {
103378
+ if (existsSync12(join24(dir, ".git"))) {
103127
103379
  return dir;
103128
103380
  }
103129
103381
  const parent = dirname15(dir);
@@ -103139,7 +103391,7 @@ function collectAncestorAgentsSkillDirs(startDir) {
103139
103391
  const gitRepoRoot = findGitRepoRoot(resolvedStartDir);
103140
103392
  let dir = resolvedStartDir;
103141
103393
  while (true) {
103142
- skillDirs.push(join23(dir, ".agents", "skills"));
103394
+ skillDirs.push(join24(dir, ".agents", "skills"));
103143
103395
  if (gitRepoRoot && dir === gitRepoRoot) {
103144
103396
  break;
103145
103397
  }
@@ -103164,7 +103416,7 @@ function collectAutoPromptEntries(dir) {
103164
103416
  continue;
103165
103417
  if (entry.name === "node_modules")
103166
103418
  continue;
103167
- const fullPath = join23(dir, entry.name);
103419
+ const fullPath = join24(dir, entry.name);
103168
103420
  let isFile = entry.isFile();
103169
103421
  if (entry.isSymbolicLink()) {
103170
103422
  try {
@@ -103196,7 +103448,7 @@ function collectAutoThemeEntries(dir) {
103196
103448
  continue;
103197
103449
  if (entry.name === "node_modules")
103198
103450
  continue;
103199
- const fullPath = join23(dir, entry.name);
103451
+ const fullPath = join24(dir, entry.name);
103200
103452
  let isFile = entry.isFile();
103201
103453
  if (entry.isSymbolicLink()) {
103202
103454
  try {
@@ -103216,7 +103468,7 @@ function collectAutoThemeEntries(dir) {
103216
103468
  return entries;
103217
103469
  }
103218
103470
  function resolveExtensionEntries2(dir) {
103219
- const packageJsonPath = join23(dir, "package.json");
103471
+ const packageJsonPath = join24(dir, "package.json");
103220
103472
  if (existsSync12(packageJsonPath)) {
103221
103473
  const manifest = readPiManifest(packageJsonPath);
103222
103474
  if (manifest?.extensions?.length) {
@@ -103232,8 +103484,8 @@ function resolveExtensionEntries2(dir) {
103232
103484
  }
103233
103485
  }
103234
103486
  }
103235
- const indexTs = join23(dir, "index.ts");
103236
- const indexJs = join23(dir, "index.js");
103487
+ const indexTs = join24(dir, "index.ts");
103488
+ const indexJs = join24(dir, "index.js");
103237
103489
  if (existsSync12(indexTs)) {
103238
103490
  return [indexTs];
103239
103491
  }
@@ -103259,7 +103511,7 @@ function collectAutoExtensionEntries(dir) {
103259
103511
  continue;
103260
103512
  if (entry.name === "node_modules")
103261
103513
  continue;
103262
- const fullPath = join23(dir, entry.name);
103514
+ const fullPath = join24(dir, entry.name);
103263
103515
  let isDir = entry.isDirectory();
103264
103516
  let isFile = entry.isFile();
103265
103517
  if (entry.isSymbolicLink()) {
@@ -103515,7 +103767,7 @@ class DefaultPackageManager {
103515
103767
  const packageSources = this.dedupePackages(allPackages);
103516
103768
  await this.resolvePackageSources(packageSources, accumulator, onMissing);
103517
103769
  const globalBaseDir = this.agentDir;
103518
- const projectBaseDir = join23(this.cwd, CONFIG_DIR_NAME);
103770
+ const projectBaseDir = join24(this.cwd, CONFIG_DIR_NAME);
103519
103771
  for (const resourceType of RESOURCE_TYPES) {
103520
103772
  const target = this.getTargetMap(accumulator, resourceType);
103521
103773
  const globalEntries = globalSettings[resourceType] ?? [];
@@ -103983,7 +104235,7 @@ class DefaultPackageManager {
103983
104235
  }
103984
104236
  }
103985
104237
  getInstalledNpmVersion(installedPath) {
103986
- const packageJsonPath = join23(installedPath, "package.json");
104238
+ const packageJsonPath = join24(installedPath, "package.json");
103987
104239
  if (!existsSync12(packageJsonPath))
103988
104240
  return;
103989
104241
  try {
@@ -104291,7 +104543,7 @@ class DefaultPackageManager {
104291
104543
  if (source.ref) {
104292
104544
  await this.runCommand("git", ["checkout", source.ref], { cwd: targetDir });
104293
104545
  }
104294
- const packageJsonPath = join23(targetDir, "package.json");
104546
+ const packageJsonPath = join24(targetDir, "package.json");
104295
104547
  if (existsSync12(packageJsonPath)) {
104296
104548
  await this.runNpmCommand(this.getGitDependencyInstallArgs(), { cwd: targetDir });
104297
104549
  }
@@ -104315,7 +104567,7 @@ class DefaultPackageManager {
104315
104567
  await this.ensureGitRef(targetDir, target.fetchArgs, target.ref);
104316
104568
  }
104317
104569
  hasMissingGitDependencies(targetDir) {
104318
- const packageJsonPath = join23(targetDir, "package.json");
104570
+ const packageJsonPath = join24(targetDir, "package.json");
104319
104571
  if (!existsSync12(packageJsonPath))
104320
104572
  return false;
104321
104573
  try {
@@ -104340,7 +104592,7 @@ class DefaultPackageManager {
104340
104592
  await this.runNpmCommand(this.getGitDependencyInstallArgs(), { cwd: targetDir });
104341
104593
  }
104342
104594
  getGitUpdateMarkerPath(targetDir) {
104343
- return join23(dirname15(targetDir), `.${basename8(targetDir)}.pi-update-incomplete`);
104595
+ return join24(dirname15(targetDir), `.${basename8(targetDir)}.pi-update-incomplete`);
104344
104596
  }
104345
104597
  async cleanAndInstallGitDependencies(targetDir, markerPath) {
104346
104598
  try {
@@ -104349,7 +104601,7 @@ class DefaultPackageManager {
104349
104601
  await this.repairMissingGitDependencies(targetDir).catch(() => {});
104350
104602
  throw error;
104351
104603
  }
104352
- const packageJsonPath = join23(targetDir, "package.json");
104604
+ const packageJsonPath = join24(targetDir, "package.json");
104353
104605
  if (existsSync12(packageJsonPath)) {
104354
104606
  await this.runNpmCommand(this.getGitDependencyInstallArgs(), { cwd: targetDir });
104355
104607
  }
@@ -104423,7 +104675,7 @@ class DefaultPackageManager {
104423
104675
  }
104424
104676
  markPathIgnoredByCloudSync(installRoot);
104425
104677
  this.ensureGitIgnore(installRoot);
104426
- const packageJsonPath = join23(installRoot, "package.json");
104678
+ const packageJsonPath = join24(installRoot, "package.json");
104427
104679
  if (!existsSync12(packageJsonPath)) {
104428
104680
  const pkgJson = { name: "pi-extensions", private: true };
104429
104681
  writeFileSync6(packageJsonPath, JSON.stringify(pkgJson, null, 2), "utf-8");
@@ -104433,7 +104685,7 @@ class DefaultPackageManager {
104433
104685
  if (!existsSync12(dir)) {
104434
104686
  mkdirSync6(dir, { recursive: true });
104435
104687
  }
104436
- const ignorePath = join23(dir, ".gitignore");
104688
+ const ignorePath = join24(dir, ".gitignore");
104437
104689
  if (!existsSync12(ignorePath)) {
104438
104690
  writeFileSync6(ignorePath, `*
104439
104691
  !.gitignore
@@ -104446,9 +104698,9 @@ class DefaultPackageManager {
104446
104698
  }
104447
104699
  if (scope === "project") {
104448
104700
  this.assertProjectTrustedForScope(scope);
104449
- return join23(this.cwd, CONFIG_DIR_NAME, "npm");
104701
+ return join24(this.cwd, CONFIG_DIR_NAME, "npm");
104450
104702
  }
104451
- return join23(this.agentDir, "npm");
104703
+ return join24(this.agentDir, "npm");
104452
104704
  }
104453
104705
  getGlobalNpmRoot() {
104454
104706
  const npmCommand = this.getNpmCommand();
@@ -104458,7 +104710,7 @@ class DefaultPackageManager {
104458
104710
  }
104459
104711
  if (this.getPackageManagerName() === "bun") {
104460
104712
  const binDir = this.runNpmCommandSync(["pm", "bin", "-g"]).trim();
104461
- this.globalNpmRoot = join23(dirname15(binDir), "install", "global", "node_modules");
104713
+ this.globalNpmRoot = join24(dirname15(binDir), "install", "global", "node_modules");
104462
104714
  } else {
104463
104715
  this.globalNpmRoot = this.runNpmCommandSync(["root", "-g"]).trim();
104464
104716
  }
@@ -104480,17 +104732,17 @@ class DefaultPackageManager {
104480
104732
  }
104481
104733
  getManagedNpmInstallPath(source, scope) {
104482
104734
  if (scope === "temporary") {
104483
- return join23(this.getTemporaryDir("npm"), "node_modules", source.name);
104735
+ return join24(this.getTemporaryDir("npm"), "node_modules", source.name);
104484
104736
  }
104485
104737
  if (scope === "project") {
104486
104738
  this.assertProjectTrustedForScope(scope);
104487
- return join23(this.cwd, CONFIG_DIR_NAME, "npm", "node_modules", source.name);
104739
+ return join24(this.cwd, CONFIG_DIR_NAME, "npm", "node_modules", source.name);
104488
104740
  }
104489
- return join23(this.agentDir, "npm", "node_modules", source.name);
104741
+ return join24(this.agentDir, "npm", "node_modules", source.name);
104490
104742
  }
104491
104743
  getLegacyGlobalNpmInstallPath(source) {
104492
104744
  try {
104493
- return this.getPnpmGlobalPackagePath(source.name) ?? join23(this.getGlobalNpmRoot(), source.name);
104745
+ return this.getPnpmGlobalPackagePath(source.name) ?? join24(this.getGlobalNpmRoot(), source.name);
104494
104746
  } catch {
104495
104747
  return;
104496
104748
  }
@@ -104519,9 +104771,9 @@ class DefaultPackageManager {
104519
104771
  }
104520
104772
  if (scope === "project") {
104521
104773
  this.assertProjectTrustedForScope(scope);
104522
- return join23(this.cwd, CONFIG_DIR_NAME, "git");
104774
+ return join24(this.cwd, CONFIG_DIR_NAME, "git");
104523
104775
  }
104524
- return join23(this.agentDir, "git");
104776
+ return join24(this.agentDir, "git");
104525
104777
  }
104526
104778
  getTemporaryDir(prefix, suffix) {
104527
104779
  const root = this.resolveManagedPath(getExtensionTempFolder(this.agentDir), prefix);
@@ -104539,7 +104791,7 @@ class DefaultPackageManager {
104539
104791
  getBaseDirForScope(scope) {
104540
104792
  if (scope === "project") {
104541
104793
  this.assertProjectTrustedForScope(scope);
104542
- return join23(this.cwd, CONFIG_DIR_NAME);
104794
+ return join24(this.cwd, CONFIG_DIR_NAME);
104543
104795
  }
104544
104796
  if (scope === "user") {
104545
104797
  return this.agentDir;
@@ -104567,7 +104819,7 @@ class DefaultPackageManager {
104567
104819
  }
104568
104820
  return true;
104569
104821
  }
104570
- const manifest = readPiManifest(join23(packageRoot, "package.json"));
104822
+ const manifest = readPiManifest(join24(packageRoot, "package.json"));
104571
104823
  if (manifest) {
104572
104824
  for (const resourceType of RESOURCE_TYPES) {
104573
104825
  const entries = manifest[resourceType];
@@ -104577,7 +104829,7 @@ class DefaultPackageManager {
104577
104829
  }
104578
104830
  let hasAnyDir = false;
104579
104831
  for (const resourceType of RESOURCE_TYPES) {
104580
- const dir = join23(packageRoot, resourceType);
104832
+ const dir = join24(packageRoot, resourceType);
104581
104833
  if (existsSync12(dir)) {
104582
104834
  const files = collectResourceFiles(dir, resourceType);
104583
104835
  for (const f of files) {
@@ -104589,13 +104841,13 @@ class DefaultPackageManager {
104589
104841
  return hasAnyDir;
104590
104842
  }
104591
104843
  collectDefaultResources(packageRoot, resourceType, target, metadata) {
104592
- const manifest = readPiManifest(join23(packageRoot, "package.json"));
104844
+ const manifest = readPiManifest(join24(packageRoot, "package.json"));
104593
104845
  const entries = manifest?.[resourceType];
104594
104846
  if (entries) {
104595
104847
  this.addManifestEntries(entries, packageRoot, resourceType, target, metadata);
104596
104848
  return;
104597
104849
  }
104598
- const dir = join23(packageRoot, resourceType);
104850
+ const dir = join24(packageRoot, resourceType);
104599
104851
  if (existsSync12(dir)) {
104600
104852
  const files = collectResourceFiles(dir, resourceType);
104601
104853
  for (const f of files) {
@@ -104628,7 +104880,7 @@ class DefaultPackageManager {
104628
104880
  }
104629
104881
  }
104630
104882
  collectManifestFiles(packageRoot, resourceType) {
104631
- const manifest = readPiManifest(join23(packageRoot, "package.json"));
104883
+ const manifest = readPiManifest(join24(packageRoot, "package.json"));
104632
104884
  const entries = manifest?.[resourceType];
104633
104885
  if (entries && entries.length > 0) {
104634
104886
  const allFiles2 = this.collectFilesFromManifestEntries(entries, packageRoot, resourceType);
@@ -104636,7 +104888,7 @@ class DefaultPackageManager {
104636
104888
  const enabledByManifest = manifestPatterns.length > 0 ? applyPatterns(allFiles2, manifestPatterns, packageRoot) : new Set(allFiles2);
104637
104889
  return { allFiles: Array.from(enabledByManifest), enabledByManifest };
104638
104890
  }
104639
- const conventionDir = join23(packageRoot, resourceType);
104891
+ const conventionDir = join24(packageRoot, resourceType);
104640
104892
  if (!existsSync12(conventionDir)) {
104641
104893
  return { allFiles: [], enabledByManifest: new Set };
104642
104894
  }
@@ -104702,18 +104954,18 @@ class DefaultPackageManager {
104702
104954
  themes: projectSettings.themes ?? []
104703
104955
  };
104704
104956
  const userDirs = {
104705
- extensions: join23(globalBaseDir, "extensions"),
104706
- skills: join23(globalBaseDir, "skills"),
104707
- prompts: join23(globalBaseDir, "prompts"),
104708
- themes: join23(globalBaseDir, "themes")
104957
+ extensions: join24(globalBaseDir, "extensions"),
104958
+ skills: join24(globalBaseDir, "skills"),
104959
+ prompts: join24(globalBaseDir, "prompts"),
104960
+ themes: join24(globalBaseDir, "themes")
104709
104961
  };
104710
104962
  const projectDirs = {
104711
- extensions: join23(projectBaseDir, "extensions"),
104712
- skills: join23(projectBaseDir, "skills"),
104713
- prompts: join23(projectBaseDir, "prompts"),
104714
- themes: join23(projectBaseDir, "themes")
104963
+ extensions: join24(projectBaseDir, "extensions"),
104964
+ skills: join24(projectBaseDir, "skills"),
104965
+ prompts: join24(projectBaseDir, "prompts"),
104966
+ themes: join24(projectBaseDir, "themes")
104715
104967
  };
104716
- const userAgentsSkillsDir = join23(getHomeDir(), ".agents", "skills");
104968
+ const userAgentsSkillsDir = join24(getHomeDir(), ".agents", "skills");
104717
104969
  const projectTrusted = this.settingsManager.isProjectTrusted();
104718
104970
  const projectAgentsSkillDirs = projectTrusted ? collectAncestorAgentsSkillDirs(this.cwd).filter((dir) => resolve7(dir) !== resolve7(userAgentsSkillsDir)) : [];
104719
104971
  const addResources = (resourceType, paths, metadata, overrides, baseDir) => {
@@ -104902,16 +105154,16 @@ class DefaultPackageManager {
104902
105154
  // node_modules/@earendil-works/pi-coding-agent/dist/core/resource-loader.js
104903
105155
  init_source();
104904
105156
  import { existsSync as existsSync15, readdirSync as readdirSync9, readFileSync as readFileSync12, statSync as statSync10 } from "node:fs";
104905
- import { basename as basename9, dirname as dirname18, join as join26, resolve as resolve9, sep as sep8 } from "node:path";
105157
+ import { basename as basename9, dirname as dirname18, join as join27, resolve as resolve9, sep as sep8 } from "node:path";
104906
105158
 
104907
105159
  // node_modules/@earendil-works/pi-coding-agent/dist/core/footer-data-provider.js
104908
105160
  import { execFile, spawnSync as spawnSync4 } from "child_process";
104909
105161
  import { existsSync as existsSync13, readFileSync as readFileSync10, statSync as statSync9, unwatchFile, watchFile } from "fs";
104910
- import { dirname as dirname16, join as join24, resolve as resolve8 } from "path";
105162
+ import { dirname as dirname16, join as join25, resolve as resolve8 } from "path";
104911
105163
  function findGitPaths(cwd) {
104912
105164
  let dir = cwd;
104913
105165
  while (true) {
104914
- const gitPath = join24(dir, ".git");
105166
+ const gitPath = join25(dir, ".git");
104915
105167
  if (existsSync13(gitPath)) {
104916
105168
  try {
104917
105169
  const stat2 = statSync9(gitPath);
@@ -104919,15 +105171,15 @@ function findGitPaths(cwd) {
104919
105171
  const content = readFileSync10(gitPath, "utf8").trim();
104920
105172
  if (content.startsWith("gitdir: ")) {
104921
105173
  const gitDir = resolve8(dir, content.slice(8).trim());
104922
- const headPath = join24(gitDir, "HEAD");
105174
+ const headPath = join25(gitDir, "HEAD");
104923
105175
  if (!existsSync13(headPath))
104924
105176
  return null;
104925
- const commonDirPath = join24(gitDir, "commondir");
105177
+ const commonDirPath = join25(gitDir, "commondir");
104926
105178
  const commonGitDir = existsSync13(commonDirPath) ? resolve8(gitDir, readFileSync10(commonDirPath, "utf8").trim()) : gitDir;
104927
105179
  return { repoDir: dir, commonGitDir, headPath };
104928
105180
  }
104929
105181
  } else if (stat2.isDirectory()) {
104930
- const headPath = join24(gitPath, "HEAD");
105182
+ const headPath = join25(gitPath, "HEAD");
104931
105183
  if (!existsSync13(headPath))
104932
105184
  return null;
104933
105185
  return { repoDir: dir, commonGitDir: gitPath, headPath };
@@ -105179,7 +105431,7 @@ class FooterDataProvider {
105179
105431
  if (!this.headWatcher && !pollGitHead) {
105180
105432
  return;
105181
105433
  }
105182
- const reftableDir = join24(this.gitPaths.commonGitDir, "reftable");
105434
+ const reftableDir = join25(this.gitPaths.commonGitDir, "reftable");
105183
105435
  if (existsSync13(reftableDir)) {
105184
105436
  this.reftableWatcher = watchWithErrorHandler(reftableDir, () => {
105185
105437
  this.scheduleRefresh();
@@ -105187,7 +105439,7 @@ class FooterDataProvider {
105187
105439
  if (!this.reftableWatcher) {
105188
105440
  return;
105189
105441
  }
105190
- const tablesListPath = join24(reftableDir, "tables.list");
105442
+ const tablesListPath = join25(reftableDir, "tables.list");
105191
105443
  if (existsSync13(tablesListPath)) {
105192
105444
  this.reftableTablesListPath = tablesListPath;
105193
105445
  this.reftableTablesListWatcher = watchWithErrorHandler(tablesListPath, () => {
@@ -105210,7 +105462,7 @@ class FooterDataProvider {
105210
105462
  var import_proper_lockfile2 = __toESM(require_proper_lockfile(), 1);
105211
105463
  import { randomUUID as randomUUID2 } from "crypto";
105212
105464
  import { existsSync as existsSync14, mkdirSync as mkdirSync7, readFileSync as readFileSync11, writeFileSync as writeFileSync7 } from "fs";
105213
- import { dirname as dirname17, join as join25 } from "path";
105465
+ import { dirname as dirname17, join as join26 } from "path";
105214
105466
 
105215
105467
  // node_modules/@earendil-works/pi-coding-agent/dist/core/http-dispatcher.js
105216
105468
  import { EventEmitter as EventEmitter3 } from "node:events";
@@ -105506,8 +105758,8 @@ class FileSettingsStorage {
105506
105758
  constructor(cwd, agentDir) {
105507
105759
  const resolvedCwd = resolvePath(cwd);
105508
105760
  const resolvedAgentDir = resolvePath(agentDir);
105509
- this.globalSettingsPath = join25(resolvedAgentDir, "settings.json");
105510
- this.projectSettingsPath = join25(resolvedCwd, CONFIG_DIR_NAME, "settings.json");
105761
+ this.globalSettingsPath = join26(resolvedAgentDir, "settings.json");
105762
+ this.projectSettingsPath = join26(resolvedCwd, CONFIG_DIR_NAME, "settings.json");
105511
105763
  }
105512
105764
  acquireLockSyncWithRetry(path11) {
105513
105765
  const maxAttempts = 10;
@@ -105603,8 +105855,8 @@ class SettingsManager {
105603
105855
  const resolvedAgentDir = resolvePath(agentDir);
105604
105856
  const storage = new FileSettingsStorage(resolvedCwd, resolvedAgentDir);
105605
105857
  return SettingsManager.fromStorageWithPaths(storage, options, {
105606
- global: join25(resolvedAgentDir, "settings.json"),
105607
- project: join25(resolvedCwd, CONFIG_DIR_NAME, "settings.json")
105858
+ global: join26(resolvedAgentDir, "settings.json"),
105859
+ project: join26(resolvedCwd, CONFIG_DIR_NAME, "settings.json")
105608
105860
  });
105609
105861
  }
105610
105862
  static fromStorage(storage, options = {}) {
@@ -106211,6 +106463,15 @@ class SettingsManager {
106211
106463
  getThinkingBudgets() {
106212
106464
  return this.settings.thinkingBudgets;
106213
106465
  }
106466
+ getTerminalCapabilityOverrides() {
106467
+ const terminal = this.settings.terminal;
106468
+ const images = terminal?.images;
106469
+ return {
106470
+ ...images === "kitty" || images === "iterm2" ? { images } : images === false ? { images: null } : {},
106471
+ ...typeof terminal?.trueColor === "boolean" ? { trueColor: terminal.trueColor } : {},
106472
+ ...typeof terminal?.hyperlinks === "boolean" ? { hyperlinks: terminal.hyperlinks } : {}
106473
+ };
106474
+ }
106214
106475
  getShowImages() {
106215
106476
  return this.settings.terminal?.showImages ?? true;
106216
106477
  }
@@ -106287,6 +106548,14 @@ class SettingsManager {
106287
106548
  this.markModified("fullscreenScrollbar");
106288
106549
  this.save();
106289
106550
  }
106551
+ getFullscreenCopyOnSelect() {
106552
+ return this.settings.fullscreenCopyOnSelect ?? true;
106553
+ }
106554
+ setFullscreenCopyOnSelect(enabled) {
106555
+ this.globalSettings.fullscreenCopyOnSelect = enabled;
106556
+ this.markModified("fullscreenCopyOnSelect");
106557
+ this.save();
106558
+ }
106290
106559
  getImageAutoResize() {
106291
106560
  return this.settings.images?.autoResize ?? true;
106292
106561
  }
@@ -106412,7 +106681,7 @@ function resolvePromptInput(input, description) {
106412
106681
  function loadContextFileFromDir(dir) {
106413
106682
  const candidates = ["AGENTS.override.md", "AGENTS.md", "AGENTS.MD", "CLAUDE.md", "CLAUDE.MD"];
106414
106683
  for (const filename of candidates) {
106415
- const filePath = join26(dir, filename);
106684
+ const filePath = join27(dir, filename);
106416
106685
  if (existsSync15(filePath)) {
106417
106686
  try {
106418
106687
  if (!statSync10(filePath).isFile()) {
@@ -106438,10 +106707,10 @@ function findShadowedContextFile(cwd) {
106438
106707
  const mainRepoRoot = dirname18(commonGitDir);
106439
106708
  if (!worktreeRoot.startsWith(`${mainRepoRoot}${sep8}`))
106440
106709
  return;
106441
- if (canonicalizePath(join26(mainRepoRoot, ".git")) !== commonGitDir)
106710
+ if (canonicalizePath(join27(mainRepoRoot, ".git")) !== commonGitDir)
106442
106711
  return;
106443
106712
  const worktreeContextFile = loadContextFileFromDir(worktreeRoot);
106444
- return worktreeContextFile ? join26(mainRepoRoot, basename9(worktreeContextFile.path)) : undefined;
106713
+ return worktreeContextFile ? join27(mainRepoRoot, basename9(worktreeContextFile.path)) : undefined;
106445
106714
  }
106446
106715
  function loadProjectContextFiles(options) {
106447
106716
  const resolvedCwd = resolvePath(options.cwd);
@@ -106810,7 +107079,7 @@ class DefaultResourceLoader {
106810
107079
  } catch {
106811
107080
  return resource.path;
106812
107081
  }
106813
- const skillFile = join26(resource.path, "SKILL.md");
107082
+ const skillFile = join27(resource.path, "SKILL.md");
106814
107083
  if (existsSync15(skillFile)) {
106815
107084
  if (!metadataByPath.has(skillFile)) {
106816
107085
  metadataByPath.set(skillFile, resource.metadata);
@@ -106936,16 +107205,16 @@ class DefaultResourceLoader {
106936
107205
  }
106937
107206
  const normalizedPath = resolve9(filePath);
106938
107207
  const agentRoots = [
106939
- join26(this.agentDir, "skills"),
106940
- join26(this.agentDir, "prompts"),
106941
- join26(this.agentDir, "themes"),
106942
- join26(this.agentDir, "extensions")
107208
+ join27(this.agentDir, "skills"),
107209
+ join27(this.agentDir, "prompts"),
107210
+ join27(this.agentDir, "themes"),
107211
+ join27(this.agentDir, "extensions")
106943
107212
  ];
106944
107213
  const projectRoots = [
106945
- join26(this.cwd, CONFIG_DIR_NAME, "skills"),
106946
- join26(this.cwd, CONFIG_DIR_NAME, "prompts"),
106947
- join26(this.cwd, CONFIG_DIR_NAME, "themes"),
106948
- join26(this.cwd, CONFIG_DIR_NAME, "extensions")
107214
+ join27(this.cwd, CONFIG_DIR_NAME, "skills"),
107215
+ join27(this.cwd, CONFIG_DIR_NAME, "prompts"),
107216
+ join27(this.cwd, CONFIG_DIR_NAME, "themes"),
107217
+ join27(this.cwd, CONFIG_DIR_NAME, "extensions")
106949
107218
  ];
106950
107219
  for (const root of agentRoots) {
106951
107220
  if (this.isUnderPath(normalizedPath, root)) {
@@ -106985,7 +107254,7 @@ class DefaultResourceLoader {
106985
107254
  const themes = [];
106986
107255
  const diagnostics = [];
106987
107256
  if (includeDefaults) {
106988
- const defaultDirs = [join26(this.agentDir, "themes"), join26(this.cwd, CONFIG_DIR_NAME, "themes")];
107257
+ const defaultDirs = [join27(this.agentDir, "themes"), join27(this.cwd, CONFIG_DIR_NAME, "themes")];
106989
107258
  for (const dir of defaultDirs) {
106990
107259
  this.loadThemesFromDir(dir, themes, diagnostics);
106991
107260
  }
@@ -107022,7 +107291,7 @@ class DefaultResourceLoader {
107022
107291
  let isFile = entry.isFile();
107023
107292
  if (entry.isSymbolicLink()) {
107024
107293
  try {
107025
- isFile = statSync10(join26(dir, entry.name)).isFile();
107294
+ isFile = statSync10(join27(dir, entry.name)).isFile();
107026
107295
  } catch {
107027
107296
  continue;
107028
107297
  }
@@ -107033,7 +107302,7 @@ class DefaultResourceLoader {
107033
107302
  if (!entry.name.endsWith(".json")) {
107034
107303
  continue;
107035
107304
  }
107036
- this.loadThemeFromFile(join26(dir, entry.name), themes, diagnostics);
107305
+ this.loadThemeFromFile(join27(dir, entry.name), themes, diagnostics);
107037
107306
  }
107038
107307
  } catch (error) {
107039
107308
  const message = error instanceof Error ? error.message : "failed to read theme directory";
@@ -107114,22 +107383,22 @@ class DefaultResourceLoader {
107114
107383
  return { themes: Array.from(seen.values()), diagnostics };
107115
107384
  }
107116
107385
  discoverSystemPromptFile() {
107117
- const projectPath = join26(this.cwd, CONFIG_DIR_NAME, "SYSTEM.md");
107386
+ const projectPath = join27(this.cwd, CONFIG_DIR_NAME, "SYSTEM.md");
107118
107387
  if (this.settingsManager.isProjectTrusted() && existsSync15(projectPath)) {
107119
107388
  return projectPath;
107120
107389
  }
107121
- const globalPath = join26(this.agentDir, "SYSTEM.md");
107390
+ const globalPath = join27(this.agentDir, "SYSTEM.md");
107122
107391
  if (existsSync15(globalPath)) {
107123
107392
  return globalPath;
107124
107393
  }
107125
107394
  return;
107126
107395
  }
107127
107396
  discoverAppendSystemPromptFile() {
107128
- const projectPath = join26(this.cwd, CONFIG_DIR_NAME, "APPEND_SYSTEM.md");
107397
+ const projectPath = join27(this.cwd, CONFIG_DIR_NAME, "APPEND_SYSTEM.md");
107129
107398
  if (this.settingsManager.isProjectTrusted() && existsSync15(projectPath)) {
107130
107399
  return projectPath;
107131
107400
  }
107132
- const globalPath = join26(this.agentDir, "APPEND_SYSTEM.md");
107401
+ const globalPath = join27(this.agentDir, "APPEND_SYSTEM.md");
107133
107402
  if (existsSync15(globalPath)) {
107134
107403
  return globalPath;
107135
107404
  }
@@ -107175,7 +107444,7 @@ class DefaultResourceLoader {
107175
107444
  }
107176
107445
  }
107177
107446
  // node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.js
107178
- import { join as join29 } from "node:path";
107447
+ import { join as join30 } from "node:path";
107179
107448
 
107180
107449
  // node_modules/@earendil-works/pi-coding-agent/dist/core/telemetry.js
107181
107450
  function isTruthyEnvFlag(value2) {
@@ -107255,7 +107524,7 @@ function mergeProviderAttributionHeaders(model, settingsManager, sessionId, ...h
107255
107524
 
107256
107525
  // node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-runtime.js
107257
107526
  import { copyFileSync, existsSync as existsSync17, mkdirSync as mkdirSync8 } from "node:fs";
107258
- import { basename as basename10, join as join28, resolve as resolve10 } from "node:path";
107527
+ import { basename as basename10, join as join29, resolve as resolve10 } from "node:path";
107259
107528
 
107260
107529
  // node_modules/@earendil-works/pi-coding-agent/dist/core/session-cwd.js
107261
107530
  import { existsSync as existsSync16 } from "node:fs";
@@ -107304,7 +107573,7 @@ function assertSessionCwdExists(sessionManager, fallbackCwd) {
107304
107573
  }
107305
107574
 
107306
107575
  // node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.js
107307
- import { join as join27 } from "node:path";
107576
+ import { join as join28 } from "node:path";
107308
107577
  function applyExtensionFlagValues(resourceLoader, extensionFlagValues) {
107309
107578
  if (!extensionFlagValues) {
107310
107579
  return [];
@@ -107349,8 +107618,8 @@ async function createAgentSessionServices(options) {
107349
107618
  const cwd = resolvePath(options.cwd);
107350
107619
  const agentDir = options.agentDir ? resolvePath(options.agentDir) : getAgentDir();
107351
107620
  const modelRuntime = options.modelRuntime ?? await ModelRuntime.create({
107352
- authPath: join27(agentDir, "auth.json"),
107353
- modelsPath: join27(agentDir, "models.json"),
107621
+ authPath: join28(agentDir, "auth.json"),
107622
+ modelsPath: join28(agentDir, "models.json"),
107354
107623
  signal: options.modelRuntimeSignal
107355
107624
  });
107356
107625
  const settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);
@@ -107645,7 +107914,7 @@ class AgentSessionRuntime {
107645
107914
  if (!existsSync17(sessionDir)) {
107646
107915
  mkdirSync8(sessionDir, { recursive: true });
107647
107916
  }
107648
- const destinationPath = join28(sessionDir, basename10(resolvedPath));
107917
+ const destinationPath = join29(sessionDir, basename10(resolvedPath));
107649
107918
  const beforeResult = await this.emitBeforeSwitch("resume", destinationPath);
107650
107919
  if (beforeResult.cancelled) {
107651
107920
  return beforeResult;
@@ -107690,8 +107959,8 @@ async function createAgentSession(options = {}) {
107690
107959
  const cwd = resolvePath(options.cwd ?? options.sessionManager?.getCwd() ?? process.cwd());
107691
107960
  const agentDir = options.agentDir ? resolvePath(options.agentDir) : getDefaultAgentDir();
107692
107961
  let resourceLoader = options.resourceLoader;
107693
- const authPath = options.agentDir ? join29(agentDir, "auth.json") : undefined;
107694
- const modelsPath = options.agentDir ? join29(agentDir, "models.json") : undefined;
107962
+ const authPath = options.agentDir ? join30(agentDir, "auth.json") : undefined;
107963
+ const modelsPath = options.agentDir ? join30(agentDir, "models.json") : undefined;
107695
107964
  const modelRuntime = options.modelRuntime ?? await ModelRuntime.create({ authPath, modelsPath });
107696
107965
  const settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);
107697
107966
  const sessionManager = options.sessionManager ?? SessionManager.create(cwd, getDefaultSessionDir(cwd, agentDir));
@@ -107871,7 +108140,7 @@ async function createAgentSession(options = {}) {
107871
108140
  var import_proper_lockfile3 = __toESM(require_proper_lockfile(), 1);
107872
108141
  import { existsSync as existsSync18, mkdirSync as mkdirSync9, readFileSync as readFileSync13, writeFileSync as writeFileSync8 } from "node:fs";
107873
108142
  import { homedir as homedir8 } from "node:os";
107874
- import { dirname as dirname19, join as join30 } from "node:path";
108143
+ import { dirname as dirname19, join as join31 } from "node:path";
107875
108144
  var TRUST_REQUIRING_PROJECT_CONFIG_RESOURCES = [
107876
108145
  "settings.json",
107877
108146
  "extensions",
@@ -108003,14 +108272,14 @@ function withTrustFileLock(path11, fn) {
108003
108272
  }
108004
108273
  function hasTrustRequiringProjectResources(cwd) {
108005
108274
  const homeDir = canonicalizePath(resolvePath(process.env.HOME || homedir8()));
108006
- const userAgentsSkillsDir = join30(homeDir, ".agents", "skills");
108275
+ const userAgentsSkillsDir = join31(homeDir, ".agents", "skills");
108007
108276
  let currentDir = canonicalizePath(resolvePath(cwd));
108008
- const configDir = join30(currentDir, CONFIG_DIR_NAME);
108009
- if (TRUST_REQUIRING_PROJECT_CONFIG_RESOURCES.some((entry) => existsSync18(join30(configDir, entry)))) {
108277
+ const configDir = join31(currentDir, CONFIG_DIR_NAME);
108278
+ if (TRUST_REQUIRING_PROJECT_CONFIG_RESOURCES.some((entry) => existsSync18(join31(configDir, entry)))) {
108010
108279
  return true;
108011
108280
  }
108012
108281
  while (true) {
108013
- const agentsSkillsDir = join30(currentDir, ".agents", "skills");
108282
+ const agentsSkillsDir = join31(currentDir, ".agents", "skills");
108014
108283
  if (agentsSkillsDir !== userAgentsSkillsDir && existsSync18(agentsSkillsDir)) {
108015
108284
  return true;
108016
108285
  }
@@ -108025,7 +108294,7 @@ function hasTrustRequiringProjectResources(cwd) {
108025
108294
  class ProjectTrustStore {
108026
108295
  trustPath;
108027
108296
  constructor(agentDir) {
108028
- this.trustPath = join30(resolvePath(agentDir), "trust.json");
108297
+ this.trustPath = join31(resolvePath(agentDir), "trust.json");
108029
108298
  }
108030
108299
  get(cwd) {
108031
108300
  return this.getEntry(cwd)?.decision ?? null;
@@ -108434,7 +108703,7 @@ import { existsSync as existsSync20 } from "fs";
108434
108703
 
108435
108704
  // node_modules/@earendil-works/pi-coding-agent/dist/core/keybindings.js
108436
108705
  import { existsSync as existsSync19, readFileSync as readFileSync14 } from "fs";
108437
- import { join as join31 } from "path";
108706
+ import { join as join32 } from "path";
108438
108707
  function useWindowsKeybindings(platform2 = process.platform, env = process.env) {
108439
108708
  return platform2 === "win32" || platform2 === "linux" && Boolean(env.WSL_DISTRO_NAME || env.WSL_INTEROP);
108440
108709
  }
@@ -108725,7 +108994,7 @@ class KeybindingsManager2 extends KeybindingsManager {
108725
108994
  this.configPath = configPath;
108726
108995
  }
108727
108996
  static create(agentDir = getAgentDir()) {
108728
- const configPath = join31(agentDir, "keybindings.json");
108997
+ const configPath = join32(agentDir, "keybindings.json");
108729
108998
  const userBindings = KeybindingsManager2.loadFromFile(configPath);
108730
108999
  return new KeybindingsManager2(userBindings, configPath);
108731
109000
  }
@@ -109037,6 +109306,7 @@ async function loadStartupThemes(settingsManager) {
109037
109306
  return loadThemes(resolvedPaths.themes);
109038
109307
  }
109039
109308
  async function createStartupTui(settingsManager) {
109309
+ setCapabilityOverrides(settingsManager.getTerminalCapabilityOverrides());
109040
109310
  setRegisteredThemes(await loadStartupThemes(settingsManager));
109041
109311
  const terminalTheme = detectTerminalBackgroundFromEnv().theme;
109042
109312
  initTheme(resolveThemeSetting(settingsManager.getThemeSetting(), terminalTheme) ?? terminalTheme);
@@ -110385,6 +110655,13 @@ class LlamaClient {
110385
110655
  throw new Error("Server is not running in llama.cpp router mode");
110386
110656
  return data;
110387
110657
  }
110658
+ async props(options = {}) {
110659
+ const payload = await this.request("/props", { signal: options.signal });
110660
+ if (typeof payload !== "object" || payload === null)
110661
+ return {};
110662
+ const { models_autoload: modelsAutoload } = payload;
110663
+ return typeof modelsAutoload === "boolean" ? { models_autoload: modelsAutoload } : {};
110664
+ }
110388
110665
  async load(model, signal) {
110389
110666
  await this.request("/models/load", { method: "POST", body: JSON.stringify({ model }), signal });
110390
110667
  }
@@ -110534,7 +110811,7 @@ class LlamaClient {
110534
110811
  // node_modules/@earendil-works/pi-coding-agent/dist/extensions/llama/huggingface.js
110535
110812
  import { readFile as readFile4 } from "node:fs/promises";
110536
110813
  import { homedir as homedir10 } from "node:os";
110537
- import { join as join32 } from "node:path";
110814
+ import { join as join33 } from "node:path";
110538
110815
  var DEFAULT_HUGGING_FACE_URL = "https://huggingface.co";
110539
110816
  var QUANTIZATION_PATTERN = /(?:^|[-_.])((?:UD-)?(?:IQ\d(?:_[A-Z0-9]+)+|Q\d(?:_[A-Z0-9]+)+|BF16|F16|F32|MXFP\d(?:_[A-Z0-9]+)*))$/iu;
110540
110817
  var SHARD_SUFFIX_PATTERN = /-\d{5}-of-\d{5}$/u;
@@ -110562,9 +110839,9 @@ async function findHuggingFaceToken(env = process.env) {
110562
110839
  return fromEnvironment;
110563
110840
  const paths = [
110564
110841
  env.HF_TOKEN_PATH,
110565
- env.HF_HOME ? join32(env.HF_HOME, "token") : undefined,
110566
- env.XDG_CACHE_HOME ? join32(env.XDG_CACHE_HOME, "huggingface", "token") : undefined,
110567
- join32(homedir10(), ".cache", "huggingface", "token")
110842
+ env.HF_HOME ? join33(env.HF_HOME, "token") : undefined,
110843
+ env.XDG_CACHE_HOME ? join33(env.XDG_CACHE_HOME, "huggingface", "token") : undefined,
110844
+ join33(homedir10(), ".cache", "huggingface", "token")
110568
110845
  ].filter((path11) => Boolean(path11));
110569
110846
  for (const path11 of new Set(paths)) {
110570
110847
  const token = await readToken(path11);
@@ -110680,8 +110957,21 @@ async function resolveServerUrl(ctx, credential) {
110680
110957
  const configured = credentialServerUrl(credential) ?? (await ctx.env("LLAMA_BASE_URL"))?.trim();
110681
110958
  return configured ? normalizeLlamaServerUrl(configured) : undefined;
110682
110959
  }
110683
- function modelIsSelectable(model) {
110684
- return model.status.value === "loaded" || model.status.value === "sleeping";
110960
+ function modelIsSelectable(model, routerAutoload) {
110961
+ if (model.status.value === "loaded")
110962
+ return true;
110963
+ if (model.status.value === "sleeping")
110964
+ return true;
110965
+ return routerAutoload && model.status.value === "unloaded" && !model.status.failed && model.source === "preset";
110966
+ }
110967
+ async function routerAutoloadEnabled(client, catalog, signal) {
110968
+ if (!catalog.some((model) => model.status.value === "unloaded" && model.source === "preset"))
110969
+ return false;
110970
+ try {
110971
+ return (await client.props({ signal })).models_autoload === true;
110972
+ } catch {
110973
+ return false;
110974
+ }
110685
110975
  }
110686
110976
  function toPiModel(model, serverUrl) {
110687
110977
  const reportedContextWindow = model.meta?.n_ctx ?? model.meta?.n_ctx_train;
@@ -110709,8 +110999,8 @@ function toPiModel(model, serverUrl) {
110709
110999
  }
110710
111000
  function createLlamaProvider() {
110711
111001
  let models = [];
110712
- const setCatalog = (catalog, serverUrl) => {
110713
- models = catalog.filter((model) => modelIsSelectable(model)).map((model) => toPiModel(model, serverUrl));
111002
+ const setCatalog = (catalog, serverUrl, options = {}) => {
111003
+ models = catalog.filter((model) => modelIsSelectable(model, options.routerAutoload === true)).map((model) => toPiModel(model, serverUrl));
110714
111004
  };
110715
111005
  const provider = {
110716
111006
  id: LLAMA_PROVIDER_ID,
@@ -110771,10 +111061,14 @@ function createLlamaProvider() {
110771
111061
  const serverUrl = credentialServerUrl(context2.credential);
110772
111062
  if (!serverUrl)
110773
111063
  return;
110774
- const catalog = await new LlamaClient(serverUrl, context2.credential.key).list({ signal: context2.signal });
111064
+ const client = new LlamaClient(serverUrl, context2.credential.key);
111065
+ const catalog = await client.list({ signal: context2.signal });
110775
111066
  if (context2.signal.aborted)
110776
111067
  return;
110777
- const refreshed = catalog.filter((model) => modelIsSelectable(model)).map((model) => toPiModel(model, serverUrl));
111068
+ const routerAutoload = await routerAutoloadEnabled(client, catalog, context2.signal);
111069
+ if (context2.signal.aborted)
111070
+ return;
111071
+ const refreshed = catalog.filter((model) => modelIsSelectable(model, routerAutoload)).map((model) => toPiModel(model, serverUrl));
110778
111072
  await context2.publish({
110779
111073
  persist: { models: refreshed, checkedAt: Date.now() },
110780
111074
  update: () => {
@@ -111415,14 +111709,14 @@ var builtInExtensions = [{ name: "llama.cpp", factory: llamaExtension, hidden: t
111415
111709
  // node_modules/@earendil-works/pi-coding-agent/dist/migrations.js
111416
111710
  init_source();
111417
111711
  import { existsSync as existsSync22, mkdirSync as mkdirSync10, readdirSync as readdirSync10, readFileSync as readFileSync15, renameSync as renameSync2, rmSync as rmSync3, writeFileSync as writeFileSync9 } from "fs";
111418
- import { dirname as dirname20, join as join33 } from "path";
111712
+ import { dirname as dirname20, join as join34 } from "path";
111419
111713
  var MIGRATION_GUIDE_URL = "https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/CHANGELOG.md#extensions-migration";
111420
111714
  var EXTENSIONS_DOC_URL = "https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/docs/extensions.md";
111421
111715
  function migrateAuthToAuthJson() {
111422
111716
  const agentDir = getAgentDir();
111423
- const authPath = join33(agentDir, "auth.json");
111424
- const oauthPath = join33(agentDir, "oauth.json");
111425
- const settingsPath = join33(agentDir, "settings.json");
111717
+ const authPath = join34(agentDir, "auth.json");
111718
+ const oauthPath = join34(agentDir, "oauth.json");
111719
+ const settingsPath = join34(agentDir, "settings.json");
111426
111720
  if (existsSync22(authPath))
111427
111721
  return [];
111428
111722
  const migrated = {};
@@ -111463,7 +111757,7 @@ function migrateSessionsFromAgentRoot() {
111463
111757
  const agentDir = getAgentDir();
111464
111758
  let files;
111465
111759
  try {
111466
- files = readdirSync10(agentDir).filter((f) => f.endsWith(".jsonl")).map((f) => join33(agentDir, f));
111760
+ files = readdirSync10(agentDir).filter((f) => f.endsWith(".jsonl")).map((f) => join34(agentDir, f));
111467
111761
  } catch {
111468
111762
  return;
111469
111763
  }
@@ -111481,12 +111775,12 @@ function migrateSessionsFromAgentRoot() {
111481
111775
  continue;
111482
111776
  const cwd = header.cwd;
111483
111777
  const safePath = `--${cwd.replace(/^[/\\]/, "").replace(/[/\\:]/g, "-")}--`;
111484
- const correctDir = join33(agentDir, "sessions", safePath);
111778
+ const correctDir = join34(agentDir, "sessions", safePath);
111485
111779
  if (!existsSync22(correctDir)) {
111486
111780
  mkdirSync10(correctDir, { recursive: true });
111487
111781
  }
111488
111782
  const fileName = file.split("/").pop() || file.split("\\").pop();
111489
- const newPath = join33(correctDir, fileName);
111783
+ const newPath = join34(correctDir, fileName);
111490
111784
  if (existsSync22(newPath))
111491
111785
  continue;
111492
111786
  renameSync2(file, newPath);
@@ -111494,8 +111788,8 @@ function migrateSessionsFromAgentRoot() {
111494
111788
  }
111495
111789
  }
111496
111790
  function migrateCommandsToPrompts(baseDir, label) {
111497
- const commandsDir = join33(baseDir, "commands");
111498
- const promptsDir = join33(baseDir, "prompts");
111791
+ const commandsDir = join34(baseDir, "commands");
111792
+ const promptsDir = join34(baseDir, "prompts");
111499
111793
  if (existsSync22(commandsDir) && !existsSync22(promptsDir)) {
111500
111794
  try {
111501
111795
  renameSync2(commandsDir, promptsDir);
@@ -111508,7 +111802,7 @@ function migrateCommandsToPrompts(baseDir, label) {
111508
111802
  return false;
111509
111803
  }
111510
111804
  function migrateKeybindingsConfigFile() {
111511
- const configPath = join33(getAgentDir(), "keybindings.json");
111805
+ const configPath = join34(getAgentDir(), "keybindings.json");
111512
111806
  if (!existsSync22(configPath))
111513
111807
  return;
111514
111808
  try {
@@ -111525,15 +111819,15 @@ function migrateKeybindingsConfigFile() {
111525
111819
  }
111526
111820
  function migrateToolsToBin() {
111527
111821
  const agentDir = getAgentDir();
111528
- const toolsDir = join33(agentDir, "tools");
111822
+ const toolsDir = join34(agentDir, "tools");
111529
111823
  const binDir = getBinDir();
111530
111824
  if (!existsSync22(toolsDir))
111531
111825
  return;
111532
111826
  const binaries = ["fd", "rg", "fd.exe", "rg.exe"];
111533
111827
  let movedAny = false;
111534
111828
  for (const bin of binaries) {
111535
- const oldPath = join33(toolsDir, bin);
111536
- const newPath = join33(binDir, bin);
111829
+ const oldPath = join34(toolsDir, bin);
111830
+ const newPath = join34(binDir, bin);
111537
111831
  if (existsSync22(oldPath)) {
111538
111832
  if (!existsSync22(binDir)) {
111539
111833
  mkdirSync10(binDir, { recursive: true });
@@ -111555,8 +111849,8 @@ function migrateToolsToBin() {
111555
111849
  }
111556
111850
  }
111557
111851
  function checkDeprecatedExtensionDirs(baseDir, label) {
111558
- const hooksDir = join33(baseDir, "hooks");
111559
- const toolsDir = join33(baseDir, "tools");
111852
+ const hooksDir = join34(baseDir, "hooks");
111853
+ const toolsDir = join34(baseDir, "tools");
111560
111854
  const warnings = [];
111561
111855
  if (existsSync22(hooksDir)) {
111562
111856
  warnings.push(`${label} hooks/ directory found. Hooks have been renamed to extensions.`);
@@ -111577,7 +111871,7 @@ function checkDeprecatedExtensionDirs(baseDir, label) {
111577
111871
  }
111578
111872
  function migrateExtensionSystem(cwd) {
111579
111873
  const agentDir = getAgentDir();
111580
- const projectDir = join33(cwd, CONFIG_DIR_NAME);
111874
+ const projectDir = join34(cwd, CONFIG_DIR_NAME);
111581
111875
  migrateCommandsToPrompts(agentDir, "Global");
111582
111876
  migrateCommandsToPrompts(projectDir, "Project");
111583
111877
  const warnings = [
@@ -111873,14 +112167,14 @@ import { spawnSync as spawnSync6 } from "child_process";
111873
112167
  import { randomUUID as randomUUID3 } from "crypto";
111874
112168
  import { readFileSync as readFileSync17, unlinkSync } from "fs";
111875
112169
  import { tmpdir as tmpdir3 } from "os";
111876
- import { join as join35 } from "path";
112170
+ import { join as join36 } from "path";
111877
112171
 
111878
112172
  // node_modules/@earendil-works/pi-coding-agent/dist/utils/clipboard-native.js
111879
112173
  import { createRequire as createRequire7 } from "module";
111880
- import { dirname as dirname21, join as join34 } from "path";
112174
+ import { dirname as dirname21, join as join35 } from "path";
111881
112175
  import { pathToFileURL as pathToFileURL3 } from "url";
111882
112176
  var moduleRequire2 = createRequire7(import.meta.url);
111883
- var executableDirRequire = createRequire7(pathToFileURL3(join34(dirname21(process.execPath), "package.json")).href);
112177
+ var executableDirRequire = createRequire7(pathToFileURL3(join35(dirname21(process.execPath), "package.json")).href);
111884
112178
  var hasDisplay = process.platform !== "linux" || Boolean(process.env.DISPLAY || process.env.WAYLAND_DISPLAY);
111885
112179
  function loadClipboardNative(requires = [moduleRequire2, executableDirRequire]) {
111886
112180
  for (const requireClipboard of requires) {
@@ -111994,7 +112288,7 @@ function isWSL(env = process.env) {
111994
112288
  }
111995
112289
  }
111996
112290
  function readClipboardImageViaPowerShell() {
111997
- const tmpFile = join35(tmpdir3(), `pi-wsl-clip-${randomUUID3()}.png`);
112291
+ const tmpFile = join36(tmpdir3(), `pi-wsl-clip-${randomUUID3()}.png`);
111998
112292
  try {
111999
112293
  const winPathResult = runCommand("wslpath", ["-w", tmpFile], { timeoutMs: DEFAULT_LIST_TIMEOUT_MS });
112000
112294
  if (!winPathResult.ok) {
@@ -113436,10 +113730,10 @@ class EarendilAnnouncementComponent extends Container {
113436
113730
  import { spawn as spawn9 } from "node:child_process";
113437
113731
  import { mkdtempSync, readFileSync as readFileSync19, rmSync as rmSync4, writeFileSync as writeFileSync10 } from "node:fs";
113438
113732
  import { tmpdir as tmpdir4 } from "node:os";
113439
- import { join as join36 } from "node:path";
113733
+ import { join as join37 } from "node:path";
113440
113734
  async function editInExternalEditor(options) {
113441
- const directory = mkdtempSync(join36(tmpdir4(), "pi-editor-"));
113442
- const filePath = join36(directory, "prompt.md");
113735
+ const directory = mkdtempSync(join37(tmpdir4(), "pi-editor-"));
113736
+ const filePath = join37(directory, "prompt.md");
113443
113737
  try {
113444
113738
  writeFileSync10(filePath, options.content, "utf-8");
113445
113739
  const [editor, ...editorArgs] = options.command.split(" ");
@@ -118934,6 +119228,13 @@ class SettingsSelectorComponent extends Container {
118934
119228
  currentValue: config.fullscreenScrollbar,
118935
119229
  values: ["auto", "always", "hidden"]
118936
119230
  },
119231
+ {
119232
+ id: "fullscreen-copy-on-select",
119233
+ label: "Fullscreen copy on select",
119234
+ description: "Automatically copy selected text in fullscreen mode; disable to copy selections with Ctrl+X",
119235
+ currentValue: config.fullscreenCopyOnSelect ? "true" : "false",
119236
+ values: ["true", "false"]
119237
+ },
118937
119238
  {
118938
119239
  id: "theme",
118939
119240
  label: "Theme",
@@ -119124,6 +119425,9 @@ class SettingsSelectorComponent extends Container {
119124
119425
  case "fullscreen-scrollbar":
119125
119426
  callbacks.onFullscreenScrollbarChange(newValue);
119126
119427
  break;
119428
+ case "fullscreen-copy-on-select":
119429
+ callbacks.onFullscreenCopyOnSelectChange(newValue === "true");
119430
+ break;
119127
119431
  case "theme":
119128
119432
  callbacks.onThemeChange(newValue);
119129
119433
  break;
@@ -121353,6 +121657,7 @@ function createInteractiveTui(options) {
121353
121657
  searchCurrentMatchStyle: (text) => theme.bold(theme.inverse(styleSearchMatch(text))),
121354
121658
  openUrl: openBrowser,
121355
121659
  onRightClickPaste: options.onRightClickPaste,
121660
+ copyOnSelect: options.fullscreenCopyOnSelect,
121356
121661
  copySelection: async (text) => {
121357
121662
  try {
121358
121663
  await copyToClipboard(text);
@@ -121493,6 +121798,7 @@ class InteractiveMode {
121493
121798
  }
121494
121799
  constructor(runtimeHost, options = {}) {
121495
121800
  this.runtimeHost = runtimeHost;
121801
+ setCapabilityOverrides(this.settingsManager.getTerminalCapabilityOverrides());
121496
121802
  const tuiMode = options.tuiMode ?? this.settingsManager.getTuiMode();
121497
121803
  this.options = { ...options, tuiMode };
121498
121804
  this.autoTrustOnReloadCwd = options.autoTrustOnReloadCwd;
@@ -121508,7 +121814,8 @@ class InteractiveMode {
121508
121814
  tuiMode,
121509
121815
  showHardwareCursor: this.settingsManager.getShowHardwareCursor(),
121510
121816
  logDirectory: getAgentDir(),
121511
- onRightClickPaste: this.onRightClickPaste
121817
+ onRightClickPaste: this.onRightClickPaste,
121818
+ fullscreenCopyOnSelect: this.settingsManager.getFullscreenCopyOnSelect()
121512
121819
  });
121513
121820
  this.ui = createInteractiveTuiReference(() => this.renderer);
121514
121821
  this.ui.setClearOnShrink(this.settingsManager.getClearOnShrink());
@@ -121737,7 +122044,8 @@ class InteractiveMode {
121737
122044
  showHardwareCursor,
121738
122045
  logDirectory: getAgentDir(),
121739
122046
  terminal,
121740
- onRightClickPaste: this.onRightClickPaste
122047
+ onRightClickPaste: this.onRightClickPaste,
122048
+ fullscreenCopyOnSelect: this.settingsManager.getFullscreenCopyOnSelect()
121741
122049
  });
121742
122050
  nextUi.setClearOnShrink(clearOnShrink);
121743
122051
  nextUi.onDebug = onDebug;
@@ -122573,8 +122881,12 @@ ${warningLines}`, 0, 0));
122573
122881
  this.transcriptScrollView?.setScrollbar(this.settingsManager.getFullscreenScrollbar());
122574
122882
  }
122575
122883
  applyRuntimeSettings() {
122884
+ setCapabilityOverrides(this.settingsManager.getTerminalCapabilityOverrides());
122576
122885
  configureHttpDispatcher(this.settingsManager.getHttpIdleTimeoutMs());
122577
122886
  this.applyFullscreenScrollbarSetting();
122887
+ if (this.renderer instanceof TuiAltScreen) {
122888
+ this.renderer.setCopyOnSelect(this.settingsManager.getFullscreenCopyOnSelect());
122889
+ }
122578
122890
  this.footer.setSession(this.session);
122579
122891
  this.footer.setAutoCompactEnabled(this.session.autoCompactionEnabled);
122580
122892
  this.footerDataProvider.setCwd(this.sessionManager.getCwd());
@@ -122710,6 +123022,9 @@ ${warningLines}`, 0, 0));
122710
123022
  this.statusContainer.addChild(this.idleStatus);
122711
123023
  }
122712
123024
  }
123025
+ showWorkingStatusIndicator() {
123026
+ this.showStatusIndicator(new WorkingStatusIndicator(this.ui, this.workingMessage ?? this.defaultWorkingMessage, this.workingIndicatorOptions));
123027
+ }
122713
123028
  setWorkingVisible(visible) {
122714
123029
  this.workingVisible = visible;
122715
123030
  if (!visible) {
@@ -122718,7 +123033,7 @@ ${warningLines}`, 0, 0));
122718
123033
  return;
122719
123034
  }
122720
123035
  if (this.session.isStreaming && this.activeStatusIndicator?.kind !== "working") {
122721
- this.showStatusIndicator(new WorkingStatusIndicator(this.ui, this.workingMessage ?? this.defaultWorkingMessage, this.workingIndicatorOptions));
123036
+ this.showWorkingStatusIndicator();
122722
123037
  }
122723
123038
  this.ui.requestRender();
122724
123039
  }
@@ -123235,7 +123550,7 @@ ${message}`, ["Yes", "No"], opts);
123235
123550
  this.defaultEditor.onAction("app.tools.expand", () => this.toggleToolOutputExpansion());
123236
123551
  this.defaultEditor.onAction("app.thinking.toggle", () => this.toggleThinkingBlockVisibility());
123237
123552
  this.defaultEditor.onAction("app.editor.external", () => void this.handleOpenExternalEditor());
123238
- this.defaultEditor.onAction("app.message.copy", () => void this.handleCopyCommand({ flashConfirmation: true }));
123553
+ this.defaultEditor.onAction("app.message.copy", () => void this.handleCopyCommand({ flashConfirmation: true, preferSelection: true }));
123239
123554
  this.defaultEditor.onAction("app.message.followUp", () => this.handleFollowUp());
123240
123555
  this.defaultEditor.onAction("app.message.dequeue", () => this.handleDequeue());
123241
123556
  this.defaultEditor.onAction("app.session.new", () => this.handleClearCommand());
@@ -123485,15 +123800,19 @@ ${message}`, ["Yes", "No"], opts);
123485
123800
  switch (event.type) {
123486
123801
  case "agent_start":
123487
123802
  this.pendingTools.clear();
123488
- if (this.settingsManager.getShowTerminalProgress()) {
123489
- this.ui.terminal.setProgress(true);
123490
- }
123491
123803
  if (this.retryEscapeHandler) {
123492
123804
  this.defaultEditor.onEscape = this.retryEscapeHandler;
123493
123805
  this.retryEscapeHandler = undefined;
123494
123806
  }
123807
+ break;
123808
+ case "turn_start":
123809
+ if (this.settingsManager.getShowTerminalProgress()) {
123810
+ this.ui.terminal.setProgress(true);
123811
+ }
123495
123812
  if (this.workingVisible) {
123496
- this.showStatusIndicator(new WorkingStatusIndicator(this.ui, this.workingMessage ?? this.defaultWorkingMessage, this.workingIndicatorOptions));
123813
+ if (this.activeStatusIndicator?.kind !== "working") {
123814
+ this.showWorkingStatusIndicator();
123815
+ }
123497
123816
  } else {
123498
123817
  this.clearStatusIndicator();
123499
123818
  }
@@ -124226,16 +124545,18 @@ ${message}`, ["Yes", "No"], opts);
124226
124545
  }
124227
124546
  this.showStatus(`Tool output: ${expanded ? "expanded" : "collapsed"}`);
124228
124547
  }
124548
+ updateThinkingBlockVisibility() {
124549
+ for (const child of this.chatContainer.children) {
124550
+ if (child instanceof AssistantMessageComponent) {
124551
+ child.setHideThinkingBlock(this.hideThinkingBlock);
124552
+ }
124553
+ }
124554
+ this.ui.requestRender();
124555
+ }
124229
124556
  toggleThinkingBlockVisibility() {
124230
124557
  this.hideThinkingBlock = !this.hideThinkingBlock;
124231
124558
  this.settingsManager.setHideThinkingBlock(this.hideThinkingBlock);
124232
- this.chatContainer.clear();
124233
- this.rebuildChatFromMessages();
124234
- if (this.streamingComponent && this.streamingMessage) {
124235
- this.streamingComponent.setHideThinkingBlock(this.hideThinkingBlock);
124236
- this.streamingComponent.updateContent(this.streamingMessage);
124237
- this.chatContainer.addChild(this.streamingComponent);
124238
- }
124559
+ this.updateThinkingBlockVisibility();
124239
124560
  this.showStatus(`Thinking blocks: ${this.hideThinkingBlock ? "hidden" : "visible"}`);
124240
124561
  }
124241
124562
  async handleOpenExternalEditor() {
@@ -124521,6 +124842,7 @@ ${packageLines}`, 1, 0));
124521
124842
  tuiMode: this.ui.mode,
124522
124843
  fullscreenExitOutput: this.settingsManager.getFullscreenExitOutput(),
124523
124844
  fullscreenScrollbar: this.settingsManager.getFullscreenScrollbar(),
124845
+ fullscreenCopyOnSelect: this.settingsManager.getFullscreenCopyOnSelect(),
124524
124846
  warnings: this.settingsManager.getWarnings()
124525
124847
  }, {
124526
124848
  onAutoCompactChange: (enabled) => {
@@ -124595,13 +124917,7 @@ ${packageLines}`, 1, 0));
124595
124917
  onHideThinkingBlockChange: (hidden) => {
124596
124918
  this.hideThinkingBlock = hidden;
124597
124919
  this.settingsManager.setHideThinkingBlock(hidden);
124598
- for (const child of this.chatContainer.children) {
124599
- if (child instanceof AssistantMessageComponent) {
124600
- child.setHideThinkingBlock(hidden);
124601
- }
124602
- }
124603
- this.chatContainer.clear();
124604
- this.rebuildChatFromMessages();
124920
+ this.updateThinkingBlockVisibility();
124605
124921
  },
124606
124922
  onMermaidRenderingModeChange: (mode) => {
124607
124923
  this.settingsManager.setMermaidRenderingMode(mode);
@@ -124693,6 +125009,11 @@ ${packageLines}`, 1, 0));
124693
125009
  this.settingsManager.setFullscreenScrollbar(mode);
124694
125010
  this.applyFullscreenScrollbarSetting();
124695
125011
  },
125012
+ onFullscreenCopyOnSelectChange: (enabled) => {
125013
+ this.settingsManager.setFullscreenCopyOnSelect(enabled);
125014
+ if (this.renderer instanceof TuiAltScreen)
125015
+ this.renderer.setCopyOnSelect(enabled);
125016
+ },
124696
125017
  onWarningsChange: (warnings) => {
124697
125018
  this.settingsManager.setWarnings(warnings);
124698
125019
  },
@@ -124866,6 +125187,7 @@ ${packageLines}`, 1, 0));
124866
125187
  const selectModel = async (model, persist) => {
124867
125188
  try {
124868
125189
  await this.session.setModel(model, { persist });
125190
+ this.updateAvailableProviderCount();
124869
125191
  this.footer.invalidate();
124870
125192
  this.updateEditorBorderColor();
124871
125193
  done();
@@ -125631,8 +125953,8 @@ ${packageLines}`, 1, 0));
125631
125953
  activeHeader.setExpanded(this.toolOutputExpanded);
125632
125954
  }
125633
125955
  setRegisteredThemes(this.session.resourceLoader.getThemes().themes);
125634
- await this.themeController.applyFromSettings();
125635
125956
  this.applyRuntimeSettings();
125957
+ await this.themeController.applyFromSettings();
125636
125958
  this.setupAutocompleteProvider();
125637
125959
  const runner = this.session.extensionRunner;
125638
125960
  this.setupExtensionShortcuts(runner);
@@ -125748,6 +126070,10 @@ ${packageLines}`, 1, 0));
125748
126070
  });
125749
126071
  }
125750
126072
  async handleCopyCommand(options = {}) {
126073
+ if (options.preferSelection && this.ui instanceof TuiAltScreen && !this.ui.getCopyOnSelect() && this.ui.hasActiveSelection()) {
126074
+ await this.ui.copyActiveSelectionToClipboard();
126075
+ return;
126076
+ }
125751
126077
  const text = this.session.getLastAssistantText();
125752
126078
  if (!text) {
125753
126079
  this.showError("No agent messages to copy yet.");
@@ -126437,6 +126763,10 @@ class RpcClient {
126437
126763
  async abort() {
126438
126764
  await this.send({ type: "abort" });
126439
126765
  }
126766
+ async clearQueue() {
126767
+ const response = await this.send({ type: "clear_queue" });
126768
+ return this.getData(response);
126769
+ }
126440
126770
  async newSession(parentSession) {
126441
126771
  const response = await this.send({ type: "new_session", parentSession });
126442
126772
  return this.getData(response);
@@ -126920,6 +127250,9 @@ async function runRpcMode(runtimeHost) {
126920
127250
  await session3.abort();
126921
127251
  return success(id, "abort");
126922
127252
  }
127253
+ case "clear_queue": {
127254
+ return success(id, "clear_queue", session3.clearQueue());
127255
+ }
126923
127256
  case "new_session": {
126924
127257
  const options = command.parentSession ? { parentSession: command.parentSession } : undefined;
126925
127258
  const result2 = await runtimeHost.newSession(options);
@@ -127202,13 +127535,13 @@ async function runRpcMode(runtimeHost) {
127202
127535
  }
127203
127536
  // node_modules/@earendil-works/pi-coding-agent/dist/package-manager-cli.js
127204
127537
  import { existsSync as existsSync26, mkdirSync as mkdirSync13, mkdtempSync as mkdtempSync2, readdirSync as readdirSync11, readFileSync as readFileSync21, renameSync as renameSync4, rmSync as rmSync6, writeFileSync as writeFileSync12 } from "node:fs";
127205
- import { join as join41, resolve as resolve15 } from "node:path";
127538
+ import { join as join42, resolve as resolve15 } from "node:path";
127206
127539
  init_source();
127207
127540
  var import_proper_lockfile4 = __toESM(require_proper_lockfile(), 1);
127208
127541
 
127209
127542
  // node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/config-selector.js
127210
127543
  import { homedir as homedir12 } from "node:os";
127211
- import { basename as basename12, dirname as dirname23, join as join39, relative as relative7 } from "node:path";
127544
+ import { basename as basename12, dirname as dirname23, join as join40, relative as relative7 } from "node:path";
127212
127545
  var RESOURCE_TYPES2 = ["extensions", "skills", "prompts", "themes"];
127213
127546
  var RESOURCE_TYPE_LABELS = {
127214
127547
  extensions: "Extensions",
@@ -127841,7 +128174,7 @@ class ResourceList {
127841
128174
  return item.metadata.scope === "project" ? "project" : "user";
127842
128175
  }
127843
128176
  getTopLevelBaseDir(scope) {
127844
- return scope === "project" ? join39(this.cwd, CONFIG_DIR_NAME) : this.agentDir;
128177
+ return scope === "project" ? join40(this.cwd, CONFIG_DIR_NAME) : this.agentDir;
127845
128178
  }
127846
128179
  getResourcePattern(item) {
127847
128180
  const scope = item.metadata.scope;
@@ -127930,7 +128263,7 @@ async function selectConfig(options) {
127930
128263
  // node_modules/@earendil-works/pi-coding-agent/dist/utils/windows-self-update.js
127931
128264
  import { randomUUID as randomUUID7 } from "node:crypto";
127932
128265
  import { copyFileSync as copyFileSync2, existsSync as existsSync25, mkdirSync as mkdirSync12, renameSync as renameSync3, rmSync as rmSync5 } from "node:fs";
127933
- import { basename as basename13, dirname as dirname24, join as join40, relative as relative8, resolve as resolve14, toNamespacedPath } from "node:path";
128266
+ import { basename as basename13, dirname as dirname24, join as join41, relative as relative8, resolve as resolve14, toNamespacedPath } from "node:path";
127934
128267
  var QUARANTINE_DIR_NAME = ".pi-native-quarantine";
127935
128268
  function normalizePath2(path14) {
127936
128269
  return toNamespacedPath(resolve14(path14));
@@ -127939,7 +128272,7 @@ function getQuarantineRoot(packageDir) {
127939
128272
  let current = resolve14(packageDir);
127940
128273
  while (true) {
127941
128274
  if (basename13(current).toLowerCase() === "node_modules") {
127942
- return join40(current, QUARANTINE_DIR_NAME);
128275
+ return join41(current, QUARANTINE_DIR_NAME);
127943
128276
  }
127944
128277
  const parent = dirname24(current);
127945
128278
  if (parent === current) {
@@ -127989,12 +128322,12 @@ function quarantineWindowsNativeDependencies(packageDir) {
127989
128322
  if (loadedFiles.length === 0) {
127990
128323
  return;
127991
128324
  }
127992
- const quarantineRunDir = join40(quarantineRoot, `${Date.now()}-${process.pid}-${randomUUID7()}`);
128325
+ const quarantineRunDir = join41(quarantineRoot, `${Date.now()}-${process.pid}-${randomUUID7()}`);
127993
128326
  for (const loadedFile of loadedFiles) {
127994
128327
  if (!existsSync25(loadedFile)) {
127995
128328
  continue;
127996
128329
  }
127997
- const quarantinePath = join40(quarantineRunDir, relative8(resolvedPackageDir, loadedFile));
128330
+ const quarantinePath = join41(quarantineRunDir, relative8(resolvedPackageDir, loadedFile));
127998
128331
  mkdirSync12(dirname24(quarantinePath), { recursive: true });
127999
128332
  renameSync3(loadedFile, quarantinePath);
128000
128333
  copyFileSync2(quarantinePath, loadedFile);
@@ -128010,10 +128343,10 @@ function getActiveManagedInstallRoot() {
128010
128343
  if (!configuredRoot)
128011
128344
  return;
128012
128345
  const managedRoot = resolve15(configuredRoot);
128013
- const releasesDir = canonicalizePath(join41(managedRoot, "releases"));
128346
+ const releasesDir = canonicalizePath(join42(managedRoot, "releases"));
128014
128347
  if (getCwdRelativePath(canonicalizePath(getPackageDir()), releasesDir) === undefined)
128015
128348
  return;
128016
- const markerPath = join41(managedRoot, MANAGED_INSTALL_MARKER);
128349
+ const markerPath = join42(managedRoot, MANAGED_INSTALL_MARKER);
128017
128350
  try {
128018
128351
  const marker = JSON.parse(readFileSync21(markerPath, "utf8"));
128019
128352
  if (marker.kind !== "pi-managed-install" || marker.schemaVersion !== 1 || marker.layout !== "releases-v1") {
@@ -128048,7 +128381,7 @@ async function runManagedNpmCi(stageDir) {
128048
128381
  throw new Error(`npm ${args.join(" ")} exited with code ${code ?? "unknown"}`);
128049
128382
  }
128050
128383
  function verifyManagedRelease(releaseDir, expectedVersion) {
128051
- const binPath = join41(releaseDir, "node_modules", ".bin", process.platform === "win32" ? `${APP_NAME}.cmd` : APP_NAME);
128384
+ const binPath = join42(releaseDir, "node_modules", ".bin", process.platform === "win32" ? `${APP_NAME}.cmd` : APP_NAME);
128052
128385
  const result2 = spawnProcessSync(binPath, ["--version"], {
128053
128386
  encoding: "utf8",
128054
128387
  stdio: ["ignore", "pipe", "pipe"]
@@ -128063,8 +128396,8 @@ function verifyManagedRelease(releaseDir, expectedVersion) {
128063
128396
  }
128064
128397
  }
128065
128398
  function activateManagedRelease(managedRoot, version) {
128066
- const currentPath = join41(managedRoot, "current-version");
128067
- const temporaryPath = join41(managedRoot, `current-version.tmp.${process.pid}-${Date.now()}`);
128399
+ const currentPath = join42(managedRoot, "current-version");
128400
+ const temporaryPath = join42(managedRoot, `current-version.tmp.${process.pid}-${Date.now()}`);
128068
128401
  try {
128069
128402
  writeFileSync12(temporaryPath, `${version}
128070
128403
  `);
@@ -128074,11 +128407,11 @@ function activateManagedRelease(managedRoot, version) {
128074
128407
  }
128075
128408
  }
128076
128409
  function cleanupManagedStaging(managedRoot) {
128077
- const stagingRoot = join41(managedRoot, "staging");
128410
+ const stagingRoot = join42(managedRoot, "staging");
128078
128411
  try {
128079
128412
  for (const entry of readdirSync11(stagingRoot)) {
128080
128413
  if (entry.startsWith("update-")) {
128081
- rmSync6(join41(stagingRoot, entry), { force: true, recursive: true });
128414
+ rmSync6(join42(stagingRoot, entry), { force: true, recursive: true });
128082
128415
  }
128083
128416
  }
128084
128417
  } catch {}
@@ -128093,7 +128426,7 @@ function cleanupManagedInstall() {
128093
128426
  if (!managedRoot)
128094
128427
  return;
128095
128428
  try {
128096
- const releaseLock = import_proper_lockfile4.default.lockSync(join41(managedRoot, "update"), { realpath: false });
128429
+ const releaseLock = import_proper_lockfile4.default.lockSync(join42(managedRoot, "update"), { realpath: false });
128097
128430
  try {
128098
128431
  cleanupManagedStaging(managedRoot);
128099
128432
  } finally {
@@ -128107,7 +128440,7 @@ async function runManagedSelfUpdate(managedRoot, version) {
128107
128440
  }
128108
128441
  let releaseLock;
128109
128442
  try {
128110
- releaseLock = await import_proper_lockfile4.default.lock(join41(managedRoot, "update"), { realpath: false });
128443
+ releaseLock = await import_proper_lockfile4.default.lock(join42(managedRoot, "update"), { realpath: false });
128111
128444
  } catch (error) {
128112
128445
  if (error instanceof Error && "code" in error && error.code === "ELOCKED") {
128113
128446
  throw new Error("Another managed Pi update is already running.");
@@ -128119,23 +128452,23 @@ async function runManagedSelfUpdate(managedRoot, version) {
128119
128452
  cleanupManagedStaging(managedRoot);
128120
128453
  const installerApiBase = (process.env.PI_INSTALLER_API_BASE?.trim() || DEFAULT_INSTALLER_API_BASE).replace(/\/+$/, "");
128121
128454
  const releaseUrl = `${installerApiBase}/${encodeURIComponent(version)}`;
128122
- const stagingRoot = join41(managedRoot, "staging");
128123
- const releasesRoot = join41(managedRoot, "releases");
128455
+ const stagingRoot = join42(managedRoot, "staging");
128456
+ const releasesRoot = join42(managedRoot, "releases");
128124
128457
  mkdirSync13(releasesRoot, { recursive: true });
128125
- const releaseDir = join41(releasesRoot, version);
128458
+ const releaseDir = join42(releasesRoot, version);
128126
128459
  if (existsSync26(releaseDir)) {
128127
128460
  verifyManagedRelease(releaseDir, version);
128128
128461
  activateManagedRelease(managedRoot, version);
128129
128462
  return;
128130
128463
  }
128131
128464
  mkdirSync13(stagingRoot, { recursive: true });
128132
- stageDir = mkdtempSync2(join41(stagingRoot, "update-"));
128465
+ stageDir = mkdtempSync2(join42(stagingRoot, "update-"));
128133
128466
  const [packageJsonContent, packageLockContent] = await Promise.all([
128134
128467
  fetchInstallerArtifact(`${releaseUrl}/package.json`, "package.json"),
128135
128468
  fetchInstallerArtifact(`${releaseUrl}/package-lock.json`, "package-lock.json")
128136
128469
  ]);
128137
- writeFileSync12(join41(stageDir, "package.json"), packageJsonContent);
128138
- writeFileSync12(join41(stageDir, "package-lock.json"), packageLockContent);
128470
+ writeFileSync12(join42(stageDir, "package.json"), packageJsonContent);
128471
+ writeFileSync12(join42(stageDir, "package-lock.json"), packageLockContent);
128139
128472
  await runManagedNpmCi(stageDir);
128140
128473
  verifyManagedRelease(stageDir, version);
128141
128474
  renameSync4(stageDir, releaseDir);
@@ -128462,8 +128795,8 @@ async function refreshModelCatalogs2(agentDir) {
128462
128795
  const timeout = setTimeout(() => controller.abort(), 15000);
128463
128796
  try {
128464
128797
  const modelRuntime = await ModelRuntime.create({
128465
- authPath: join41(agentDir, "auth.json"),
128466
- modelsPath: join41(agentDir, "models.json"),
128798
+ authPath: join42(agentDir, "auth.json"),
128799
+ modelsPath: join42(agentDir, "models.json"),
128467
128800
  allowModelNetwork: false,
128468
128801
  signal: controller.signal
128469
128802
  });
@@ -129464,6 +129797,7 @@ async function main(args, options) {
129464
129797
  time("createAgentSessionRuntime");
129465
129798
  const { services, session: session3, modelFallbackMessage } = runtime;
129466
129799
  const { settingsManager, modelRuntime, resourceLoader } = services;
129800
+ setCapabilityOverrides(settingsManager.getTerminalCapabilityOverrides());
129467
129801
  applyHttpProxySettings(settingsManager.getGlobalSettings().httpProxy);
129468
129802
  configureHttpDispatcher(settingsManager.getHttpIdleTimeoutMs());
129469
129803
  if (parsed.help) {
@@ -130313,8 +130647,8 @@ async function readJsonFile(path14) {
130313
130647
  }
130314
130648
  async function ensureOpenRouterModelsOverride(agentDir, env = process.env) {
130315
130649
  const baseUrl = getOpenRouterBaseUrl(env);
130316
- const modelsPath = join42(agentDir, "models.json");
130317
- const markerPath = join42(agentDir, OPENROUTER_OVERRIDE_MARKER);
130650
+ const modelsPath = join43(agentDir, "models.json");
130651
+ const markerPath = join43(agentDir, OPENROUTER_OVERRIDE_MARKER);
130318
130652
  if (baseUrl === DEFAULT_OPENROUTER_BASE_URL) {
130319
130653
  await revertOpenRouterModelsOverride(modelsPath, markerPath);
130320
130654
  return;
@@ -130433,8 +130767,8 @@ function resolveModel(modelStr, env = process.env) {
130433
130767
  return;
130434
130768
  }
130435
130769
  function createAgentsMdSymlink(cwd) {
130436
- const claudeMd = join42(cwd, "CLAUDE.md");
130437
- const agentsMd = join42(cwd, "AGENTS.md");
130770
+ const claudeMd = join43(cwd, "CLAUDE.md");
130771
+ const agentsMd = join43(cwd, "AGENTS.md");
130438
130772
  if (existsSync27(claudeMd) && !existsSync27(agentsMd)) {
130439
130773
  try {
130440
130774
  symlinkSync("CLAUDE.md", agentsMd);
@@ -130446,7 +130780,7 @@ function createAgentsMdSymlink(cwd) {
130446
130780
  return false;
130447
130781
  }
130448
130782
  function cleanupAgentsMdSymlink(cwd) {
130449
- const agentsMd = join42(cwd, "AGENTS.md");
130783
+ const agentsMd = join43(cwd, "AGENTS.md");
130450
130784
  try {
130451
130785
  if (existsSync27(agentsMd) && lstatSync(agentsMd).isSymbolicLink()) {
130452
130786
  unlinkSync3(agentsMd);