@code-yeongyu/senpi 2026.8.6 → 2026.8.9

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 (154) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/dist/core/agent-session.d.ts +10 -0
  3. package/dist/core/agent-session.d.ts.map +1 -1
  4. package/dist/core/agent-session.js +71 -50
  5. package/dist/core/agent-session.js.map +1 -1
  6. package/dist/core/extensions/builtin/bash-timeout/index.d.ts +2 -2
  7. package/dist/core/extensions/builtin/bash-timeout/index.d.ts.map +1 -1
  8. package/dist/core/extensions/builtin/bash-timeout/index.js +17 -20
  9. package/dist/core/extensions/builtin/bash-timeout/index.js.map +1 -1
  10. package/dist/core/extensions/builtin/bash-timeout/timeout.d.ts +7 -12
  11. package/dist/core/extensions/builtin/bash-timeout/timeout.d.ts.map +1 -1
  12. package/dist/core/extensions/builtin/bash-timeout/timeout.js +11 -19
  13. package/dist/core/extensions/builtin/bash-timeout/timeout.js.map +1 -1
  14. package/dist/core/extensions/builtin/goal/cache-warm.d.ts +2 -0
  15. package/dist/core/extensions/builtin/goal/cache-warm.d.ts.map +1 -1
  16. package/dist/core/extensions/builtin/goal/cache-warm.js.map +1 -1
  17. package/dist/core/extensions/builtin/goal/monitor-continuation-types.d.ts +1 -0
  18. package/dist/core/extensions/builtin/goal/monitor-continuation-types.d.ts.map +1 -1
  19. package/dist/core/extensions/builtin/goal/monitor-continuation-types.js.map +1 -1
  20. package/dist/core/extensions/builtin/goal/monitor-continuation.d.ts.map +1 -1
  21. package/dist/core/extensions/builtin/goal/monitor-continuation.js +76 -35
  22. package/dist/core/extensions/builtin/goal/monitor-continuation.js.map +1 -1
  23. package/dist/core/extensions/builtin/goal/prompt.d.ts +1 -1
  24. package/dist/core/extensions/builtin/goal/prompt.d.ts.map +1 -1
  25. package/dist/core/extensions/builtin/goal/prompt.js +21 -7
  26. package/dist/core/extensions/builtin/goal/prompt.js.map +1 -1
  27. package/dist/core/extensions/builtin/goal/wait-progress.d.ts +3 -1
  28. package/dist/core/extensions/builtin/goal/wait-progress.d.ts.map +1 -1
  29. package/dist/core/extensions/builtin/goal/wait-progress.js +27 -3
  30. package/dist/core/extensions/builtin/goal/wait-progress.js.map +1 -1
  31. package/dist/core/extensions/builtin/goal/wait-ticker.d.ts +4 -3
  32. package/dist/core/extensions/builtin/goal/wait-ticker.d.ts.map +1 -1
  33. package/dist/core/extensions/builtin/goal/wait-ticker.js +6 -6
  34. package/dist/core/extensions/builtin/goal/wait-ticker.js.map +1 -1
  35. package/dist/core/extensions/builtin/import-repro.d.ts.map +1 -1
  36. package/dist/core/extensions/builtin/import-repro.js +9 -0
  37. package/dist/core/extensions/builtin/import-repro.js.map +1 -1
  38. package/dist/core/extensions/builtin/model-fallback/settings.d.ts.map +1 -1
  39. package/dist/core/extensions/builtin/model-fallback/settings.js +21 -1
  40. package/dist/core/extensions/builtin/model-fallback/settings.js.map +1 -1
  41. package/dist/core/extensions/builtin/resumption-channel-event.d.ts +13 -0
  42. package/dist/core/extensions/builtin/resumption-channel-event.d.ts.map +1 -0
  43. package/dist/core/extensions/builtin/resumption-channel-event.js +13 -0
  44. package/dist/core/extensions/builtin/resumption-channel-event.js.map +1 -0
  45. package/dist/core/extensions/builtin/terminal/extension.d.ts.map +1 -1
  46. package/dist/core/extensions/builtin/terminal/extension.js +20 -0
  47. package/dist/core/extensions/builtin/terminal/extension.js.map +1 -1
  48. package/dist/core/extensions/builtin/terminal/session-bundle.d.ts +5 -1
  49. package/dist/core/extensions/builtin/terminal/session-bundle.d.ts.map +1 -1
  50. package/dist/core/extensions/builtin/terminal/session-bundle.js +19 -2
  51. package/dist/core/extensions/builtin/terminal/session-bundle.js.map +1 -1
  52. package/dist/core/extensions/builtin/terminal/tools/bash.d.ts.map +1 -1
  53. package/dist/core/extensions/builtin/terminal/tools/bash.js +24 -10
  54. package/dist/core/extensions/builtin/terminal/tools/bash.js.map +1 -1
  55. package/dist/core/extensions/builtin/terminal/tools/context.d.ts +2 -0
  56. package/dist/core/extensions/builtin/terminal/tools/context.d.ts.map +1 -1
  57. package/dist/core/extensions/builtin/terminal/tools/context.js.map +1 -1
  58. package/dist/core/extensions/builtin/terminal/tools/foreground-window.d.ts +11 -0
  59. package/dist/core/extensions/builtin/terminal/tools/foreground-window.d.ts.map +1 -0
  60. package/dist/core/extensions/builtin/terminal/tools/foreground-window.js +16 -0
  61. package/dist/core/extensions/builtin/terminal/tools/foreground-window.js.map +1 -0
  62. package/dist/core/extensions/builtin/terminal/tools/sleep-wait.d.ts +28 -0
  63. package/dist/core/extensions/builtin/terminal/tools/sleep-wait.d.ts.map +1 -0
  64. package/dist/core/extensions/builtin/terminal/tools/sleep-wait.js +75 -0
  65. package/dist/core/extensions/builtin/terminal/tools/sleep-wait.js.map +1 -0
  66. package/dist/core/extensions/builtin/tps.d.ts.map +1 -1
  67. package/dist/core/extensions/builtin/tps.js +3 -3
  68. package/dist/core/extensions/builtin/tps.js.map +1 -1
  69. package/dist/core/retry-fallback/chains.d.ts +13 -1
  70. package/dist/core/retry-fallback/chains.d.ts.map +1 -1
  71. package/dist/core/retry-fallback/chains.js +80 -8
  72. package/dist/core/retry-fallback/chains.js.map +1 -1
  73. package/dist/core/retry-fallback/controller.d.ts +2 -0
  74. package/dist/core/retry-fallback/controller.d.ts.map +1 -1
  75. package/dist/core/retry-fallback/controller.js.map +1 -1
  76. package/dist/core/retry-fallback/expansion.d.ts +46 -0
  77. package/dist/core/retry-fallback/expansion.d.ts.map +1 -0
  78. package/dist/core/retry-fallback/expansion.js +113 -0
  79. package/dist/core/retry-fallback/expansion.js.map +1 -0
  80. package/dist/core/retry-fallback/hint-policy.d.ts +14 -0
  81. package/dist/core/retry-fallback/hint-policy.d.ts.map +1 -1
  82. package/dist/core/retry-fallback/hint-policy.js +14 -0
  83. package/dist/core/retry-fallback/hint-policy.js.map +1 -1
  84. package/dist/core/retry-fallback/settings.d.ts +6 -0
  85. package/dist/core/retry-fallback/settings.d.ts.map +1 -1
  86. package/dist/core/retry-fallback/settings.js +12 -10
  87. package/dist/core/retry-fallback/settings.js.map +1 -1
  88. package/dist/core/retry-fallback/validate.d.ts.map +1 -1
  89. package/dist/core/retry-fallback/validate.js +14 -1
  90. package/dist/core/retry-fallback/validate.js.map +1 -1
  91. package/dist/main.d.ts.map +1 -1
  92. package/dist/main.js +18 -3
  93. package/dist/main.js.map +1 -1
  94. package/dist/modes/interactive/components/favorite-models-selector.d.ts +4 -0
  95. package/dist/modes/interactive/components/favorite-models-selector.d.ts.map +1 -1
  96. package/dist/modes/interactive/components/favorite-models-selector.js +23 -7
  97. package/dist/modes/interactive/components/favorite-models-selector.js.map +1 -1
  98. package/dist/modes/interactive/components/model-selector.d.ts +1 -0
  99. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  100. package/dist/modes/interactive/components/model-selector.js +11 -7
  101. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  102. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  103. package/dist/modes/interactive/interactive-mode.js +25 -6
  104. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  105. package/dist/modes/interactive/model-search-rank.d.ts +13 -0
  106. package/dist/modes/interactive/model-search-rank.d.ts.map +1 -0
  107. package/dist/modes/interactive/model-search-rank.js +200 -0
  108. package/dist/modes/interactive/model-search-rank.js.map +1 -0
  109. package/dist/modes/interactive/model-search.d.ts +0 -5
  110. package/dist/modes/interactive/model-search.d.ts.map +1 -1
  111. package/dist/modes/interactive/model-search.js +0 -9
  112. package/dist/modes/interactive/model-search.js.map +1 -1
  113. package/dist/modes/rpc/session-command-router.d.ts.map +1 -1
  114. package/dist/modes/rpc/session-command-router.js +3 -2
  115. package/dist/modes/rpc/session-command-router.js.map +1 -1
  116. package/dist/modes/rpc/session-registry.d.ts +1 -1
  117. package/dist/modes/rpc/session-registry.d.ts.map +1 -1
  118. package/dist/modes/rpc/session-registry.js +3 -3
  119. package/dist/modes/rpc/session-registry.js.map +1 -1
  120. package/docs/settings.md +1 -1
  121. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +36 -0
  122. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
  123. package/node_modules/@code-yeongyu/senpi-codemode/src/extension/resumption-channel.ts +29 -0
  124. package/node_modules/@code-yeongyu/senpi-codemode/src/index.ts +10 -0
  125. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/detached-cell-manager.ts +26 -1
  126. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/render.ts +2 -1
  127. package/node_modules/@earendil-works/pi-agent-core/dist/empty-assistant-recovery.d.ts.map +1 -1
  128. package/node_modules/@earendil-works/pi-agent-core/dist/empty-assistant-recovery.js +4 -7
  129. package/node_modules/@earendil-works/pi-agent-core/dist/empty-assistant-recovery.js.map +1 -1
  130. package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
  131. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts +1 -0
  132. package/node_modules/@earendil-works/pi-ai/dist/index.d.ts.map +1 -1
  133. package/node_modules/@earendil-works/pi-ai/dist/index.js +1 -0
  134. package/node_modules/@earendil-works/pi-ai/dist/index.js.map +1 -1
  135. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  136. package/node_modules/@earendil-works/pi-ai/dist/providers/data/github-copilot.json +1 -1
  137. package/node_modules/@earendil-works/pi-ai/dist/providers/data/huggingface.json +1 -1
  138. package/node_modules/@earendil-works/pi-ai/dist/providers/data/nvidia.json +1 -1
  139. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode-go.json +1 -1
  140. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode.json +1 -1
  141. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  142. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  143. package/node_modules/@earendil-works/pi-ai/dist/utils/visible-text.d.ts +4 -0
  144. package/node_modules/@earendil-works/pi-ai/dist/utils/visible-text.d.ts.map +1 -0
  145. package/node_modules/@earendil-works/pi-ai/dist/utils/visible-text.js +8 -0
  146. package/node_modules/@earendil-works/pi-ai/dist/utils/visible-text.js.map +1 -0
  147. package/node_modules/@earendil-works/pi-ai/package.json +1 -1
  148. package/node_modules/@earendil-works/pi-pty/dist/pipe-fallback.d.ts +12 -0
  149. package/node_modules/@earendil-works/pi-pty/dist/pipe-fallback.d.ts.map +1 -1
  150. package/node_modules/@earendil-works/pi-pty/dist/pipe-fallback.js +34 -2
  151. package/node_modules/@earendil-works/pi-pty/dist/pipe-fallback.js.map +1 -1
  152. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  153. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  154. package/package.json +6 -6
@@ -1 +1 @@
1
- {"version":3,"file":"import-repro.js","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/import-repro.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGhE,MAAM,UAAU,GAAG,oBAAoB,CAAC;AACxC,MAAM,WAAW,GAAG,2EAA2E,CAAC;AAChG,MAAM,YAAY,GAAG,+DAA+D,CAAC;AACrF,MAAM,YAAY,GAAG,sEAAsE,CAAC;AAC5F,MAAM,mBAAmB,GAAG,kEAAkE,CAAC;AAC/F,MAAM,eAAe,GAAG,sEAAsE,CAAC;AA8B/F,SAAS,QAAQ,CAChB,GAAW,EACX,GAAW;IAKX,IAAI,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACrD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;IAC1E,CAAC;IAED,MAAM,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IAC3C,IAAI,UAAU;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;IAE3D,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACzC,IAAI,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;IAEzD,MAAM,UAAU,GAAG,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IAC3C,IAAI,UAAU;QAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;IAE1G,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC;IAE3D,MAAM,IAAI,KAAK,CAAC,0FAA0F,GAAG,EAAE,CAAC,CAAC;AAClH,CAAC;AAED,SAAS,iBAAiB,CAAC,GAAW;IACrC,MAAM,YAAY,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,SAAS,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;IACzE,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACJ,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IACjE,CAAC;IACD,MAAM,MAAM,GAAG,MAAgC,CAAC;IAChD,IACC,MAAM,CAAC,IAAI,KAAK,SAAS;QACzB,OAAO,MAAM,CAAC,EAAE,KAAK,QAAQ;QAC7B,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ;QAC9B,MAAM,CAAC,GAAG,KAAK,EAAE,EAChB,CAAC;QACF,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,MAAuB,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;AACxD,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAY;IACvC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IAC1C,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IAE9E,IAAI,IAAa,CAAC;IAClB,IAAI,CAAC;QACJ,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IACrE,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,WAAW,GAAG,IAAoC,CAAC;IACzD,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC;IAClC,IAAI,MAAM,EAAE,IAAI,KAAK,SAAS,IAAI,OAAO,MAAM,CAAC,EAAE,KAAK,QAAQ,IAAI,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;QACnG,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;QACzC,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IAClE,CAAC;IAED,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IACrF,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;AACnD,CAAC;AAID,SAAS,gBAAgB,CAAC,KAAa;IACtC,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED,SAAS,YAAY,CAAC,KAAa;IAClC,OAAO,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,0BAA0B,CAAC,KAAa;IAChD,OAAO,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,eAAe,CAAC,KAAa;IACrC,MAAM,OAAO,GAAG,0BAA0B,CAAC,KAAK,CAAC,CAAC;IAClD,OAAO,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAC5D,CAAC;AAED,SAAS,wBAAwB,CAAC,KAAa;IAC9C,MAAM,OAAO,GAAG,0BAA0B,CAAC,KAAK,CAAC,CAAC;IAClD,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC3D,IAAI,UAAU,EAAE,CAAC;QAChB,OAAO,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE,CAAC;IAC5F,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;IACxD,IAAI,SAAS,EAAE,CAAC;QACf,OAAO,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE,CAAC;IAC1F,CAAC;IAED,OAAO,SAAS,CAAC;AAClB,CAAC;AAED,SAAS,qBAAqB,CAAC,SAAiB;IAC/C,MAAM,OAAO,GAAG,0BAA0B,CAAC,SAAS,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,IAAI,OAAO;QAAE,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAEnC,MAAM,UAAU,GAAG,wBAAwB,CAAC,OAAO,CAAC,CAAC;IACrD,IAAI,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;QACvD,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAChD,QAAQ,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,KAAK,MAAM,aAAa,EAAE,CAAC,CAAC;QACvD,QAAQ,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC,CAAC;QAC7C,QAAQ,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;QAC3D,QAAQ,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC;SACzB,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;AACvC,CAAC;AAED,SAAS,gBAAgB,CAAC,SAAiB;IAC1C,MAAM,IAAI,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC;IACxC,OAAO,uBAAuB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AAC9D,CAAC;AAED,SAAS,qBAAqB,CAAC,GAAW;IACzC,IAAI,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IAC/E,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC;IACvC,OAAO,SAAS,CAAC;AAClB,CAAC;AAED,SAAS,gBAAgB;IACxB,OAAO,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;AAC1D,CAAC;AAED,SAAS,6BAA6B,CAAC,SAAiB;IACvD,MAAM,cAAc,GAAG,qBAAqB,CAAC,SAAS,CAAC,CAAC;IACxD,MAAM,aAAa,GAAG,gBAAgB,EAAE,CAAC;IACzC,IAAI,cAAc,KAAK,SAAS,IAAI,cAAc,KAAK,aAAa;QAAE,OAAO,SAAS,CAAC;IACvF,IAAI,aAAa,KAAK,MAAM,EAAE,CAAC;QAC9B,OAAO,gFAAgF,CAAC;IACzF,CAAC;IACD,OAAO,+EAA+E,CAAC;AACxF,CAAC;AAED,mFAAmF;AACnF,SAAS,iBAAiB,CAAC,GAAW,EAAE,SAAiB,EAAE,SAAiB;IAC3E,MAAM,MAAM,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAC3C,IAAI,SAAS,GAAG,GAAG,CAAC;IAEpB,KAAK,MAAM,aAAa,IAAI,qBAAqB,CAAC,SAAS,CAAC,EAAE,CAAC;QAC9D,IAAI,aAAa,KAAK,SAAS;YAAE,SAAS;QAC1C,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,gBAAgB,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3E,CAAC;IAED,MAAM,aAAa,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;IAClD,IAAI,aAAa,EAAE,CAAC;QACnB,MAAM,WAAW,GAAG,YAAY,CAAC,aAAa,CAAC,CAAC;QAChD,MAAM,mBAAmB,GAAG;YAC3B,IAAI,MAAM,CAAC,4BAA4B,WAAW,EAAE,EAAE,GAAG,CAAC;YAC1D,IAAI,MAAM,CAAC,6BAA6B,WAAW,EAAE,EAAE,GAAG,CAAC;SAC3D,CAAC;QACF,KAAK,MAAM,OAAO,IAAI,mBAAmB,EAAE,CAAC;YAC3C,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAChD,CAAC;IACF,CAAC;IAED,OAAO,SAAS,CAAC;AAClB,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,GAAW;IACnC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,6BAA6B,EAAE,EAAE,CAAC,CAAC;IAC1F,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,mBAAmB,GAAG,UAAU,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;AAC9B,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,IAAc;IACzC,IAAI,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC,OAAO,CAAC;IACzD,IAAI,CAAC,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,aAAa,IAAI,CAAC,QAAQ,IAAI,WAAW,iBAAiB,CAAC,CAAC;IAC/F,OAAO,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACtC,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,KAAa,EAAE,IAAY,EAAE,KAAa;IACxE,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,OAAO,IAAI,EAAE,CAAC;QACb,MAAM,QAAQ,GAAG,MAAM,KAAK,CAC3B,gCAAgC,kBAAkB,CAAC,KAAK,CAAC,IAAI,kBAAkB,CAAC,IAAI,CAAC,WAAW,kBAAkB,CAAC,KAAK,CAAC,+BAA+B,IAAI,EAAE,EAC9J,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,6BAA6B,EAAE,sBAAsB,EAAE,YAAY,EAAE,EAAE,CAC5F,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAE7F,MAAM,QAAQ,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAmB,CAAC;QAC3D,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAChC,IAAI,OAAO,CAAC,IAAI,EAAE,KAAK,KAAK,qBAAqB;gBAAE,SAAS;YAC5D,KAAK,MAAM,KAAK,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;gBACxE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YACxB,CAAC;QACF,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,GAAG,GAAG;YAAE,MAAM;QACjC,IAAI,EAAE,CAAC;IACR,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9B,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,oDAAoD,KAAK,IAAI,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC;IAC3G,OAAO,MAAM,CAAC;AACf,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,MAAc;IAC7C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,gCAAgC,MAAM,EAAE,EAAE;QACtE,OAAO,EAAE;YACR,MAAM,EAAE,6BAA6B;YACrC,sBAAsB,EAAE,YAAY;SACpC;KACD,CAAC,CAAC;IACH,IAAI,CAAC,QAAQ,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,MAAM,UAAU,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IAE7F,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAiB,CAAC;IACrD,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IAC9C,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC1E,IAAI,SAAS;QAAE,OAAO,iBAAiB,CAAC,MAAM,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC;IAEvE,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IACxE,IAAI,QAAQ;QAAE,OAAO,kBAAkB,CAAC,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEtE,MAAM,IAAI,KAAK,CAAC,QAAQ,MAAM,sCAAsC,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,CAAC,OAAO,WAAW,EAAgB;IACxC,EAAE,CAAC,eAAe,CAAC,IAAI,EAAE;QACxB,WAAW,EAAE,6FAA6F;QAC1G,OAAO,EAAE,KAAK,EAAE,IAAY,EAAE,GAA4B,EAAE,EAAE;YAC7D,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YACxB,IAAI,CAAC,GAAG,EAAE,CAAC;gBACV,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,kEAAkE,EAAE,OAAO,CAAC,CAAC;gBAC3F,OAAO;YACR,CAAC;YAED,IAAI,CAAC;gBACJ,MAAM,SAAS,GAAG,GAAG,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC;gBAC9C,MAAM,UAAU,GAAG,GAAG,CAAC,cAAc,CAAC,aAAa,EAAE,CAAC;gBACtD,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;gBAE3C,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,gCAAgC,GAAG,KAAK,EAAE,MAAM,CAAC,CAAC;gBAEhE,IAAI,UAAkB,CAAC;gBACvB,IAAI,OAAiD,CAAC;gBACtD,IAAI,SAAS,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;oBAC/B,OAAO,GAAG,MAAM,gBAAgB,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;oBAC/C,UAAU,GAAG,GAAG,SAAS,CAAC,EAAE,QAAQ,CAAC;gBACtC,CAAC;qBAAM,IAAI,SAAS,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;oBACvC,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,SAAS,CAAC,KAAK,EAAE,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC;oBACvF,OAAO,GAAG,MAAM,gBAAgB,CAAC,MAAM,CAAC,CAAC;oBACzC,UAAU,GAAG,GAAG,MAAM,QAAQ,CAAC;gBAChC,CAAC;qBAAM,CAAC;oBACP,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC;wBAAE,MAAM,IAAI,KAAK,CAAC,2BAA2B,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC;oBAC9F,MAAM,GAAG,GAAG,YAAY,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;oBACjD,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC;oBAC9F,UAAU,GAAG,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;gBACpE,CAAC;gBAED,MAAM,cAAc,GAAG,6BAA6B,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACzE,MAAM,SAAS,GAAG,iBAAiB,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;gBAClF,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;gBACjD,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;oBAC7B,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC,OAAO,CACrC,0BAA0B,EAC1B,aAAa,WAAW,+CAA+C,CACvE,CAAC;oBACF,IAAI,CAAC,SAAS,EAAE,CAAC;wBAChB,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,kBAAkB,EAAE,SAAS,CAAC,CAAC;wBAC7C,OAAO;oBACR,CAAC;gBACF,CAAC;gBACD,aAAa,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;gBAEtC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,oBAAoB,OAAO,CAAC,MAAM,CAAC,EAAE,SAAS,OAAO,CAAC,MAAM,CAAC,GAAG,OAAO,SAAS,GAAG,EAAE,MAAM,CAAC,CAAC;gBAC3G,MAAM,GAAG,CAAC,aAAa,CAAC,WAAW,EAAE;oBACpC,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;wBAC9B,IAAI,CAAC,cAAc;4BAAE,OAAO;wBAC5B,MAAM,OAAO,CAAC,WAAW,CACxB;4BACC,UAAU,EAAE,cAAc;4BAC1B,OAAO,EAAE,cAAc;4BACvB,OAAO,EAAE,IAAI;4BACb,OAAO,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,EAAE,SAAS,EAAE;yBACrD,EACD,EAAE,WAAW,EAAE,KAAK,EAAE,CACtB,CAAC;oBACH,CAAC;iBACD,CAAC,CAAC;YACJ,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YACzF,CAAC;QACF,CAAC;KACD,CAAC,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Import a pi session shared as a gist by the issue-analysis CI workflow\n * (.github/workflows/issue-analysis.yml) and switch to it.\n *\n * The CI job runs in a high-entropy checkout directory; this command rewrites\n * the recorded cwd to the local checkout, installs the session file into the\n * current session directory, and switches to it.\n *\n * Usage:\n * /ir b4d100022aefb12f25dd2d8485e0a82a\n * /ir https://gist.github.com/mitsuhiko/b4d100022aefb12f25dd2d8485e0a82a\n * /ir https://pi.dev/session/#b4d100022aefb12f25dd2d8485e0a82a\n * /ir https://github.com/earendil-works/pi/issues/123\n *\n * pi \"/ir <gist-id>\"\n */\n\nimport { Buffer } from \"node:buffer\";\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { basename, isAbsolute, join, resolve } from \"node:path\";\nimport type { ExtensionAPI, ExtensionCommandContext } from \"../types.ts\";\n\nconst GIST_ID_RE = /^[0-9a-fA-F]{20,}$/;\nconst GIST_URL_RE = /^https:\\/\\/gist\\.github\\.com\\/(?:[^/]+\\/)?([0-9a-fA-F]{20,})(?:[/#?].*)?$/;\nconst SHARE_URL_RE = /^https:\\/\\/pi\\.dev\\/session\\/#([0-9a-fA-F]{20,})(?:[/#?].*)?$/;\nconst ISSUE_URL_RE = /^https:\\/\\/github\\.com\\/([^/]+)\\/([^/]+)\\/issues\\/(\\d+)(?:[/#?].*)?$/;\nconst GIST_URL_IN_TEXT_RE = /https:\\/\\/gist\\.github\\.com\\/(?:[^/\\s]+\\/)?([0-9a-fA-F]{20,})\\b/g;\nconst SESSION_DATA_RE = /<script id=\"session-data\" type=\"application\\/json\">([^<]+)<\\/script>/;\n\ninterface SessionHeader {\n\ttype: \"session\";\n\tid: string;\n\tcwd: string;\n\t[key: string]: unknown;\n}\n\ninterface ExportedSessionData {\n\theader: SessionHeader | null;\n\tentries: Array<Record<string, unknown>>;\n}\n\ninterface GistFile {\n\tfilename?: string;\n\traw_url?: string;\n\tcontent?: string;\n\ttruncated?: boolean;\n}\n\ninterface GistResponse {\n\tfiles?: Record<string, GistFile>;\n}\n\ninterface IssueComment {\n\tbody?: string | null;\n\tuser?: { login?: string } | null;\n}\n\nfunction parseRef(\n\tref: string,\n\tcwd: string,\n):\n\t| { type: \"gist\"; id: string }\n\t| { type: \"file\"; path: string }\n\t| { type: \"issue\"; owner: string; repo: string; issue: string } {\n\tif (ref.endsWith(\".html\") || ref.endsWith(\".jsonl\")) {\n\t\treturn { type: \"file\", path: isAbsolute(ref) ? ref : resolve(cwd, ref) };\n\t}\n\n\tconst shareMatch = ref.match(SHARE_URL_RE);\n\tif (shareMatch) return { type: \"gist\", id: shareMatch[1] };\n\n\tconst gistMatch = ref.match(GIST_URL_RE);\n\tif (gistMatch) return { type: \"gist\", id: gistMatch[1] };\n\n\tconst issueMatch = ref.match(ISSUE_URL_RE);\n\tif (issueMatch) return { type: \"issue\", owner: issueMatch[1], repo: issueMatch[2], issue: issueMatch[3] };\n\n\tif (GIST_ID_RE.test(ref)) return { type: \"gist\", id: ref };\n\n\tthrow new Error(`expected a gist ID, gist URL, pi.dev share URL, issue URL, .html file, or .jsonl file: ${ref}`);\n}\n\nfunction parseSessionJsonl(raw: string): { header: SessionHeader; jsonl: string } {\n\tconst newlineIndex = raw.indexOf(\"\\n\");\n\tconst firstLine = newlineIndex === -1 ? raw : raw.slice(0, newlineIndex);\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(firstLine);\n\t} catch {\n\t\tthrow new Error(\"first line of session file is not valid JSON\");\n\t}\n\tconst header = parsed as Partial<SessionHeader>;\n\tif (\n\t\theader.type !== \"session\" ||\n\t\ttypeof header.id !== \"string\" ||\n\t\ttypeof header.cwd !== \"string\" ||\n\t\theader.cwd === \"\"\n\t) {\n\t\tthrow new Error(\"session file has no valid session header with a cwd\");\n\t}\n\treturn { header: header as SessionHeader, jsonl: raw };\n}\n\nfunction decodeExportedHtml(html: string): { header: SessionHeader; jsonl: string } {\n\tconst match = html.match(SESSION_DATA_RE);\n\tif (!match) throw new Error(\"HTML does not contain embedded pi session data\");\n\n\tlet data: unknown;\n\ttry {\n\t\tdata = JSON.parse(Buffer.from(match[1], \"base64\").toString(\"utf8\"));\n\t} catch {\n\t\tthrow new Error(\"embedded pi session data is not valid JSON\");\n\t}\n\n\tconst sessionData = data as Partial<ExportedSessionData>;\n\tconst header = sessionData.header;\n\tif (header?.type !== \"session\" || typeof header.id !== \"string\" || typeof header.cwd !== \"string\") {\n\t\tthrow new Error(\"embedded pi session data has no valid session header\");\n\t}\n\tif (!Array.isArray(sessionData.entries)) {\n\t\tthrow new Error(\"embedded pi session data has no entries array\");\n\t}\n\n\tconst lines = [header, ...sessionData.entries].map((entry) => JSON.stringify(entry));\n\treturn { header, jsonl: `${lines.join(\"\\n\")}\\n` };\n}\n\ntype SessionPlatform = \"windows\" | \"unix\" | \"unknown\";\n\nfunction escapeJsonString(value: string): string {\n\treturn JSON.stringify(value).slice(1, -1);\n}\n\nfunction escapeRegExp(value: string): string {\n\treturn value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction trimTrailingPathSeparators(value: string): string {\n\treturn value.replace(/[\\\\/]+$/, \"\");\n}\n\nfunction getPathTailName(value: string): string {\n\tconst trimmed = trimTrailingPathSeparators(value);\n\treturn trimmed.split(/[\\\\/]/).filter(Boolean).at(-1) ?? \"\";\n}\n\nfunction getWindowsDrivePathParts(value: string): { drive: string; rest: string } | undefined {\n\tconst trimmed = trimTrailingPathSeparators(value);\n\tconst driveMatch = trimmed.match(/^([A-Za-z]):[\\\\/](.*)$/);\n\tif (driveMatch) {\n\t\treturn { drive: driveMatch[1].toUpperCase(), rest: driveMatch[2].replace(/[\\\\/]+/g, \"/\") };\n\t}\n\n\tconst msysMatch = trimmed.match(/^\\/([A-Za-z])\\/(.*)$/);\n\tif (msysMatch) {\n\t\treturn { drive: msysMatch[1].toUpperCase(), rest: msysMatch[2].replace(/[\\\\/]+/g, \"/\") };\n\t}\n\n\treturn undefined;\n}\n\nfunction getCwdRewriteVariants(sourceCwd: string): string[] {\n\tconst trimmed = trimTrailingPathSeparators(sourceCwd);\n\tconst variants = new Set<string>();\n\tif (trimmed) variants.add(trimmed);\n\n\tconst driveParts = getWindowsDrivePathParts(trimmed);\n\tif (driveParts) {\n\t\tconst rest = driveParts.rest.replace(/^\\/+|\\/+$/g, \"\");\n\t\tconst backslashRest = rest.replace(/\\//g, \"\\\\\");\n\t\tvariants.add(`${driveParts.drive}:\\\\${backslashRest}`);\n\t\tvariants.add(`${driveParts.drive}:/${rest}`);\n\t\tvariants.add(`/${driveParts.drive.toLowerCase()}/${rest}`);\n\t\tvariants.add(`/${driveParts.drive}/${rest}`);\n\t}\n\n\treturn Array.from(variants)\n\t\t.filter(Boolean)\n\t\t.sort((a, b) => b.length - a.length);\n}\n\nfunction getCiWorkdirName(sourceCwd: string): string | undefined {\n\tconst name = getPathTailName(sourceCwd);\n\treturn /^pi-ci-[0-9a-f]{32}$/i.test(name) ? name : undefined;\n}\n\nfunction detectSessionPlatform(cwd: string): SessionPlatform {\n\tif (/^[A-Za-z]:[\\\\/]/.test(cwd) || /^\\/[A-Za-z]\\//.test(cwd)) return \"windows\";\n\tif (cwd.startsWith(\"/\")) return \"unix\";\n\treturn \"unknown\";\n}\n\nfunction getLocalPlatform(): Exclude<SessionPlatform, \"unknown\"> {\n\treturn process.platform === \"win32\" ? \"windows\" : \"unix\";\n}\n\nfunction getPlatformContinuationNotice(sourceCwd: string): string | undefined {\n\tconst sourcePlatform = detectSessionPlatform(sourceCwd);\n\tconst localPlatform = getLocalPlatform();\n\tif (sourcePlatform === \"unknown\" || sourcePlatform === localPlatform) return undefined;\n\tif (localPlatform === \"unix\") {\n\t\treturn \"This session was continued on a non-Windows machine; paths are now Unix style.\";\n\t}\n\treturn \"This session was continued on a Windows machine; paths are now Windows style.\";\n}\n\n/** Rewrite occurrences of the recorded CI cwd (JSON-escaped) to the target cwd. */\nfunction rewriteSessionCwd(raw: string, sourceCwd: string, targetCwd: string): string {\n\tconst target = escapeJsonString(targetCwd);\n\tlet rewritten = raw;\n\n\tfor (const sourceVariant of getCwdRewriteVariants(sourceCwd)) {\n\t\tif (sourceVariant === targetCwd) continue;\n\t\trewritten = rewritten.split(escapeJsonString(sourceVariant)).join(target);\n\t}\n\n\tconst ciWorkdirName = getCiWorkdirName(sourceCwd);\n\tif (ciWorkdirName) {\n\t\tconst escapedName = escapeRegExp(ciWorkdirName);\n\t\tconst windowsPathPatterns = [\n\t\t\tnew RegExp(`[A-Za-z]:(?:[^\"\\\\r\\\\n])*?${escapedName}`, \"g\"),\n\t\t\tnew RegExp(`/[A-Za-z]/(?:[^\"\\\\r\\\\n])*?${escapedName}`, \"g\"),\n\t\t];\n\t\tfor (const pattern of windowsPathPatterns) {\n\t\t\trewritten = rewritten.replace(pattern, target);\n\t\t}\n\t}\n\n\treturn rewritten;\n}\n\nasync function fetchText(url: string): Promise<string> {\n\tconst response = await fetch(url, { headers: { Accept: \"application/vnd.github+json\" } });\n\tif (!response.ok) {\n\t\tthrow new Error(`failed to fetch ${url}: HTTP ${response.status}`);\n\t}\n\treturn await response.text();\n}\n\nasync function readGistFile(file: GistFile): Promise<string> {\n\tif (file.content && !file.truncated) return file.content;\n\tif (!file.raw_url) throw new Error(`gist file ${file.filename ?? \"<unknown>\"} has no raw URL`);\n\treturn await fetchText(file.raw_url);\n}\n\nasync function findIssueGistId(owner: string, repo: string, issue: string): Promise<string> {\n\tconst gistIds: string[] = [];\n\tlet page = 1;\n\twhile (true) {\n\t\tconst response = await fetch(\n\t\t\t`https://api.github.com/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/issues/${encodeURIComponent(issue)}/comments?per_page=100&page=${page}`,\n\t\t\t{ headers: { Accept: \"application/vnd.github+json\", \"X-GitHub-Api-Version\": \"2022-11-28\" } },\n\t\t);\n\t\tif (!response.ok) throw new Error(`failed to fetch issue comments: HTTP ${response.status}`);\n\n\t\tconst comments = (await response.json()) as IssueComment[];\n\t\tfor (const comment of comments) {\n\t\t\tif (comment.user?.login !== \"github-actions[bot]\") continue;\n\t\t\tfor (const match of (comment.body ?? \"\").matchAll(GIST_URL_IN_TEXT_RE)) {\n\t\t\t\tgistIds.push(match[1]);\n\t\t\t}\n\t\t}\n\n\t\tif (comments.length < 100) break;\n\t\tpage++;\n\t}\n\n\tconst gistId = gistIds.at(-1);\n\tif (!gistId) throw new Error(`no github-actions gist link found in comments on ${owner}/${repo}#${issue}`);\n\treturn gistId;\n}\n\nasync function fetchGistSession(gistId: string): Promise<{ header: SessionHeader; jsonl: string }> {\n\tconst response = await fetch(`https://api.github.com/gists/${gistId}`, {\n\t\theaders: {\n\t\t\tAccept: \"application/vnd.github+json\",\n\t\t\t\"X-GitHub-Api-Version\": \"2022-11-28\",\n\t\t},\n\t});\n\tif (!response.ok) throw new Error(`failed to fetch gist ${gistId}: HTTP ${response.status}`);\n\n\tconst gist = (await response.json()) as GistResponse;\n\tconst files = Object.values(gist.files ?? {});\n\tconst jsonlFile = files.find((file) => file.filename?.endsWith(\".jsonl\"));\n\tif (jsonlFile) return parseSessionJsonl(await readGistFile(jsonlFile));\n\n\tconst htmlFile = files.find((file) => file.filename?.endsWith(\".html\"));\n\tif (htmlFile) return decodeExportedHtml(await readGistFile(htmlFile));\n\n\tthrow new Error(`gist ${gistId} has no .jsonl or .html session file`);\n}\n\nexport default function (pi: ExtensionAPI) {\n\tpi.registerCommand(\"ir\", {\n\t\tdescription: \"Import a CI issue-analysis session from a gist ID, share URL, or issue URL and switch to it\",\n\t\thandler: async (args: string, ctx: ExtensionCommandContext) => {\n\t\t\tconst ref = args.trim();\n\t\t\tif (!ref) {\n\t\t\t\tctx.ui.notify(\"Usage: /ir <gist-id | gist-url | pi.dev/session URL | issue URL>\", \"error\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst targetCwd = ctx.sessionManager.getCwd();\n\t\t\t\tconst sessionDir = ctx.sessionManager.getSessionDir();\n\t\t\t\tconst parsedRef = parseRef(ref, targetCwd);\n\n\t\t\t\tctx.ui.notify(`Importing repro session from ${ref}...`, \"info\");\n\n\t\t\t\tlet sourceName: string;\n\t\t\t\tlet decoded: { header: SessionHeader; jsonl: string };\n\t\t\t\tif (parsedRef.type === \"gist\") {\n\t\t\t\t\tdecoded = await fetchGistSession(parsedRef.id);\n\t\t\t\t\tsourceName = `${parsedRef.id}.jsonl`;\n\t\t\t\t} else if (parsedRef.type === \"issue\") {\n\t\t\t\t\tconst gistId = await findIssueGistId(parsedRef.owner, parsedRef.repo, parsedRef.issue);\n\t\t\t\t\tdecoded = await fetchGistSession(gistId);\n\t\t\t\t\tsourceName = `${gistId}.jsonl`;\n\t\t\t\t} else {\n\t\t\t\t\tif (!existsSync(parsedRef.path)) throw new Error(`session file not found: ${parsedRef.path}`);\n\t\t\t\t\tconst raw = readFileSync(parsedRef.path, \"utf8\");\n\t\t\t\t\tdecoded = parsedRef.path.endsWith(\".html\") ? decodeExportedHtml(raw) : parseSessionJsonl(raw);\n\t\t\t\t\tsourceName = basename(parsedRef.path).replace(/\\.html$/, \".jsonl\");\n\t\t\t\t}\n\n\t\t\t\tconst platformNotice = getPlatformContinuationNotice(decoded.header.cwd);\n\t\t\t\tconst rewritten = rewriteSessionCwd(decoded.jsonl, decoded.header.cwd, targetCwd);\n\t\t\t\tconst destination = join(sessionDir, sourceName);\n\t\t\t\tif (existsSync(destination)) {\n\t\t\t\t\tconst overwrite = await ctx.ui.confirm(\n\t\t\t\t\t\t\"Session already imported\",\n\t\t\t\t\t\t`Overwrite ${destination}? Local changes to that session will be lost.`,\n\t\t\t\t\t);\n\t\t\t\t\tif (!overwrite) {\n\t\t\t\t\t\tctx.ui.notify(\"Import cancelled\", \"warning\");\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\twriteFileSync(destination, rewritten);\n\n\t\t\t\tctx.ui.notify(`Imported session ${decoded.header.id} (cwd ${decoded.header.cwd} -> ${targetCwd})`, \"info\");\n\t\t\t\tawait ctx.switchSession(destination, {\n\t\t\t\t\twithSession: async (nextCtx) => {\n\t\t\t\t\t\tif (!platformNotice) return;\n\t\t\t\t\t\tawait nextCtx.sendMessage(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcustomType: \"import-repro\",\n\t\t\t\t\t\t\t\tcontent: platformNotice,\n\t\t\t\t\t\t\t\tdisplay: true,\n\t\t\t\t\t\t\t\tdetails: { sourceCwd: decoded.header.cwd, targetCwd },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{ triggerTurn: false },\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tctx.ui.notify(`ir: ${error instanceof Error ? error.message : String(error)}`, \"error\");\n\t\t\t}\n\t\t},\n\t});\n}\n"]}
1
+ {"version":3,"file":"import-repro.js","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/import-repro.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Import a pi session shared as a gist by the issue-analysis CI workflow\n * (.github/workflows/issue-analysis.yml) and switch to it.\n *\n * The CI job runs in a high-entropy checkout directory; this command rewrites\n * the recorded cwd to the local checkout, installs the session file into the\n * current session directory, and switches to it.\n *\n * Usage:\n * /ir b4d100022aefb12f25dd2d8485e0a82a\n * /ir https://gist.github.com/mitsuhiko/b4d100022aefb12f25dd2d8485e0a82a\n * /ir https://pi.dev/session/#b4d100022aefb12f25dd2d8485e0a82a\n * /ir https://github.com/earendil-works/pi/issues/123\n *\n * pi \"/ir <gist-id>\"\n */\n\nimport { Buffer } from \"node:buffer\";\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { basename, isAbsolute, join, resolve } from \"node:path\";\nimport type { ExtensionAPI, ExtensionCommandContext } from \"../types.ts\";\n\nconst GIST_ID_RE = /^[0-9a-fA-F]{20,}$/;\nconst GIST_URL_RE = /^https:\\/\\/gist\\.github\\.com\\/(?:[^/]+\\/)?([0-9a-fA-F]{20,})(?:[/#?].*)?$/;\nconst SHARE_URL_RE = /^https:\\/\\/pi\\.dev\\/session\\/#([0-9a-fA-F]{20,})(?:[/#?].*)?$/;\nconst ISSUE_URL_RE = /^https:\\/\\/github\\.com\\/([^/]+)\\/([^/]+)\\/issues\\/(\\d+)(?:[/#?].*)?$/;\nconst GIST_URL_IN_TEXT_RE = /https:\\/\\/gist\\.github\\.com\\/(?:[^/\\s]+\\/)?([0-9a-fA-F]{20,})\\b/g;\nconst SESSION_DATA_RE = /<script id=\"session-data\" type=\"application\\/json\">([^<]+)<\\/script>/;\n\ninterface SessionHeader {\n\ttype: \"session\";\n\tid: string;\n\tcwd: string;\n\t[key: string]: unknown;\n}\n\ninterface ExportedSessionData {\n\theader: SessionHeader | null;\n\tentries: Array<Record<string, unknown>>;\n}\n\ninterface GistFile {\n\tfilename?: string;\n\traw_url?: string;\n\tcontent?: string;\n\ttruncated?: boolean;\n}\n\ninterface GistResponse {\n\tfiles?: Record<string, GistFile>;\n}\n\ninterface IssueComment {\n\tbody?: string | null;\n\tuser?: { login?: string } | null;\n}\n\nfunction parseRef(\n\tref: string,\n\tcwd: string,\n):\n\t| { type: \"gist\"; id: string }\n\t| { type: \"file\"; path: string }\n\t| { type: \"issue\"; owner: string; repo: string; issue: string } {\n\tif (ref.endsWith(\".html\") || ref.endsWith(\".jsonl\")) {\n\t\treturn { type: \"file\", path: isAbsolute(ref) ? ref : resolve(cwd, ref) };\n\t}\n\n\tconst shareMatch = ref.match(SHARE_URL_RE);\n\tif (shareMatch) return { type: \"gist\", id: shareMatch[1] };\n\n\tconst gistMatch = ref.match(GIST_URL_RE);\n\tif (gistMatch) return { type: \"gist\", id: gistMatch[1] };\n\n\tconst issueMatch = ref.match(ISSUE_URL_RE);\n\tif (issueMatch) return { type: \"issue\", owner: issueMatch[1], repo: issueMatch[2], issue: issueMatch[3] };\n\n\tif (GIST_ID_RE.test(ref)) return { type: \"gist\", id: ref };\n\n\tthrow new Error(`expected a gist ID, gist URL, pi.dev share URL, issue URL, .html file, or .jsonl file: ${ref}`);\n}\n\nfunction parseSessionJsonl(raw: string): { header: SessionHeader; jsonl: string } {\n\tconst newlineIndex = raw.indexOf(\"\\n\");\n\tconst firstLine = newlineIndex === -1 ? raw : raw.slice(0, newlineIndex);\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(firstLine);\n\t} catch {\n\t\tthrow new Error(\"first line of session file is not valid JSON\");\n\t}\n\tconst header = parsed as Partial<SessionHeader>;\n\tif (\n\t\theader.type !== \"session\" ||\n\t\ttypeof header.id !== \"string\" ||\n\t\ttypeof header.cwd !== \"string\" ||\n\t\theader.cwd === \"\"\n\t) {\n\t\tthrow new Error(\"session file has no valid session header with a cwd\");\n\t}\n\treturn { header: header as SessionHeader, jsonl: raw };\n}\n\nfunction decodeExportedHtml(html: string): { header: SessionHeader; jsonl: string } {\n\tconst match = html.match(SESSION_DATA_RE);\n\tif (!match) throw new Error(\"HTML does not contain embedded pi session data\");\n\n\tlet data: unknown;\n\ttry {\n\t\tdata = JSON.parse(Buffer.from(match[1], \"base64\").toString(\"utf8\"));\n\t} catch {\n\t\tthrow new Error(\"embedded pi session data is not valid JSON\");\n\t}\n\n\tconst sessionData = data as Partial<ExportedSessionData>;\n\tconst header = sessionData.header;\n\tif (header?.type !== \"session\" || typeof header.id !== \"string\" || typeof header.cwd !== \"string\") {\n\t\tthrow new Error(\"embedded pi session data has no valid session header\");\n\t}\n\tif (!Array.isArray(sessionData.entries)) {\n\t\tthrow new Error(\"embedded pi session data has no entries array\");\n\t}\n\n\tconst lines = [header, ...sessionData.entries].map((entry) => JSON.stringify(entry));\n\treturn { header, jsonl: `${lines.join(\"\\n\")}\\n` };\n}\n\ntype SessionPlatform = \"windows\" | \"unix\" | \"unknown\";\n\nfunction escapeJsonString(value: string): string {\n\treturn JSON.stringify(value).slice(1, -1);\n}\n\nfunction escapeRegExp(value: string): string {\n\treturn value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction trimTrailingPathSeparators(value: string): string {\n\treturn value.replace(/[\\\\/]+$/, \"\");\n}\n\nfunction getPathTailName(value: string): string {\n\tconst trimmed = trimTrailingPathSeparators(value);\n\treturn trimmed.split(/[\\\\/]/).filter(Boolean).at(-1) ?? \"\";\n}\n\nfunction getWindowsDrivePathParts(value: string): { drive: string; rest: string } | undefined {\n\tconst trimmed = trimTrailingPathSeparators(value);\n\tconst driveMatch = trimmed.match(/^([A-Za-z]):[\\\\/](.*)$/);\n\tif (driveMatch) {\n\t\treturn { drive: driveMatch[1].toUpperCase(), rest: driveMatch[2].replace(/[\\\\/]+/g, \"/\") };\n\t}\n\n\tconst msysMatch = trimmed.match(/^\\/([A-Za-z])\\/(.*)$/);\n\tif (msysMatch) {\n\t\treturn { drive: msysMatch[1].toUpperCase(), rest: msysMatch[2].replace(/[\\\\/]+/g, \"/\") };\n\t}\n\n\treturn undefined;\n}\n\nfunction getCwdRewriteVariants(sourceCwd: string): string[] {\n\tconst trimmed = trimTrailingPathSeparators(sourceCwd);\n\tconst variants = new Set<string>();\n\tif (trimmed) variants.add(trimmed);\n\n\tconst driveParts = getWindowsDrivePathParts(trimmed);\n\tif (driveParts) {\n\t\tconst rest = driveParts.rest.replace(/^\\/+|\\/+$/g, \"\");\n\t\tconst backslashRest = rest.replace(/\\//g, \"\\\\\");\n\t\tvariants.add(`${driveParts.drive}:\\\\${backslashRest}`);\n\t\tvariants.add(`${driveParts.drive}:/${rest}`);\n\t\tvariants.add(`/${driveParts.drive.toLowerCase()}/${rest}`);\n\t\tvariants.add(`/${driveParts.drive}/${rest}`);\n\t}\n\n\treturn Array.from(variants)\n\t\t.filter(Boolean)\n\t\t.sort((a, b) => b.length - a.length);\n}\n\nfunction getCiWorkdirName(sourceCwd: string): string | undefined {\n\tconst name = getPathTailName(sourceCwd);\n\treturn /^pi-ci-[0-9a-f]{32}$/i.test(name) ? name : undefined;\n}\n\nfunction detectSessionPlatform(cwd: string): SessionPlatform {\n\tif (/^[A-Za-z]:[\\\\/]/.test(cwd) || /^\\/[A-Za-z]\\//.test(cwd)) return \"windows\";\n\tif (cwd.startsWith(\"/\")) return \"unix\";\n\treturn \"unknown\";\n}\n\nfunction getLocalPlatform(): Exclude<SessionPlatform, \"unknown\"> {\n\treturn process.platform === \"win32\" ? \"windows\" : \"unix\";\n}\n\nfunction getPlatformContinuationNotice(sourceCwd: string): string | undefined {\n\tconst sourcePlatform = detectSessionPlatform(sourceCwd);\n\tconst localPlatform = getLocalPlatform();\n\tif (sourcePlatform === \"unknown\" || sourcePlatform === localPlatform) return undefined;\n\tif (localPlatform === \"unix\") {\n\t\treturn \"This session was continued on a non-Windows machine; paths are now Unix style.\";\n\t}\n\treturn \"This session was continued on a Windows machine; paths are now Windows style.\";\n}\n\n/** Rewrite occurrences of the recorded CI cwd (JSON-escaped) to the target cwd. */\nfunction rewriteSessionCwd(raw: string, sourceCwd: string, targetCwd: string): string {\n\tconst target = escapeJsonString(targetCwd);\n\tlet rewritten = raw;\n\n\tfor (const sourceVariant of getCwdRewriteVariants(sourceCwd)) {\n\t\tif (sourceVariant === targetCwd) continue;\n\t\trewritten = rewritten.split(escapeJsonString(sourceVariant)).join(target);\n\t}\n\n\tconst ciWorkdirName = getCiWorkdirName(sourceCwd);\n\tif (ciWorkdirName) {\n\t\tconst escapedName = escapeRegExp(ciWorkdirName);\n\t\tconst windowsPathPatterns = [\n\t\t\tnew RegExp(`[A-Za-z]:(?:[^\"\\\\r\\\\n])*?${escapedName}`, \"g\"),\n\t\t\tnew RegExp(`/[A-Za-z]/(?:[^\"\\\\r\\\\n])*?${escapedName}`, \"g\"),\n\t\t];\n\t\tfor (const pattern of windowsPathPatterns) {\n\t\t\trewritten = rewritten.replace(pattern, target);\n\t\t}\n\t}\n\n\treturn rewritten;\n}\n\nasync function fetchText(url: string): Promise<string> {\n\tconst response = await fetch(url, { headers: { Accept: \"application/vnd.github+json\" } });\n\tif (!response.ok) {\n\t\tthrow new Error(`failed to fetch ${url}: HTTP ${response.status}`);\n\t}\n\treturn await response.text();\n}\n\nasync function readGistFile(file: GistFile): Promise<string> {\n\tif (file.content && !file.truncated) return file.content;\n\tif (!file.raw_url) throw new Error(`gist file ${file.filename ?? \"<unknown>\"} has no raw URL`);\n\treturn await fetchText(file.raw_url);\n}\n\nasync function findIssueGistId(owner: string, repo: string, issue: string): Promise<string> {\n\tconst gistIds: string[] = [];\n\tlet page = 1;\n\twhile (true) {\n\t\tconst response = await fetch(\n\t\t\t`https://api.github.com/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/issues/${encodeURIComponent(issue)}/comments?per_page=100&page=${page}`,\n\t\t\t{ headers: { Accept: \"application/vnd.github+json\", \"X-GitHub-Api-Version\": \"2022-11-28\" } },\n\t\t);\n\t\tif (!response.ok) throw new Error(`failed to fetch issue comments: HTTP ${response.status}`);\n\n\t\tconst comments = (await response.json()) as IssueComment[];\n\t\tfor (const comment of comments) {\n\t\t\tif (comment.user?.login !== \"github-actions[bot]\") continue;\n\t\t\tfor (const match of (comment.body ?? \"\").matchAll(GIST_URL_IN_TEXT_RE)) {\n\t\t\t\tgistIds.push(match[1]);\n\t\t\t}\n\t\t}\n\n\t\tif (comments.length < 100) break;\n\t\tpage++;\n\t}\n\n\tconst gistId = gistIds.at(-1);\n\tif (!gistId) throw new Error(`no github-actions gist link found in comments on ${owner}/${repo}#${issue}`);\n\treturn gistId;\n}\n\nasync function fetchGistSession(gistId: string): Promise<{ header: SessionHeader; jsonl: string }> {\n\tconst response = await fetch(`https://api.github.com/gists/${gistId}`, {\n\t\theaders: {\n\t\t\tAccept: \"application/vnd.github+json\",\n\t\t\t\"X-GitHub-Api-Version\": \"2022-11-28\",\n\t\t},\n\t});\n\tif (!response.ok) throw new Error(`failed to fetch gist ${gistId}: HTTP ${response.status}`);\n\n\tconst gist = (await response.json()) as GistResponse;\n\tconst files = Object.values(gist.files ?? {});\n\tconst jsonlFile = files.find((file) => file.filename?.endsWith(\".jsonl\"));\n\tif (jsonlFile) return parseSessionJsonl(await readGistFile(jsonlFile));\n\n\tconst htmlFile = files.find((file) => file.filename?.endsWith(\".html\"));\n\tif (htmlFile) return decodeExportedHtml(await readGistFile(htmlFile));\n\n\tthrow new Error(`gist ${gistId} has no .jsonl or .html session file`);\n}\n\nexport default function (pi: ExtensionAPI) {\n\tpi.registerCommand(\"ir\", {\n\t\tdescription: \"Import a CI issue-analysis session from a gist ID, share URL, or issue URL and switch to it\",\n\t\thandler: async (args: string, ctx: ExtensionCommandContext) => {\n\t\t\t// Session replacement aborts and disposes the live session; never start\n\t\t\t// that while a run or compaction is active. Commands dispatch immediately\n\t\t\t// now (see extensions/builtin/changes.md), so this handler can be entered\n\t\t\t// mid-turn. isCompacting is checked separately because isIdle() is true\n\t\t\t// during compaction without streaming.\n\t\t\tif (!ctx.isIdle() || ctx.isCompacting?.() === true) {\n\t\t\t\tctx.ui.notify(\"/ir is unavailable while the agent is working\", \"warning\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst ref = args.trim();\n\t\t\tif (!ref) {\n\t\t\t\tctx.ui.notify(\"Usage: /ir <gist-id | gist-url | pi.dev/session URL | issue URL>\", \"error\");\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tconst targetCwd = ctx.sessionManager.getCwd();\n\t\t\t\tconst sessionDir = ctx.sessionManager.getSessionDir();\n\t\t\t\tconst parsedRef = parseRef(ref, targetCwd);\n\n\t\t\t\tctx.ui.notify(`Importing repro session from ${ref}...`, \"info\");\n\n\t\t\t\tlet sourceName: string;\n\t\t\t\tlet decoded: { header: SessionHeader; jsonl: string };\n\t\t\t\tif (parsedRef.type === \"gist\") {\n\t\t\t\t\tdecoded = await fetchGistSession(parsedRef.id);\n\t\t\t\t\tsourceName = `${parsedRef.id}.jsonl`;\n\t\t\t\t} else if (parsedRef.type === \"issue\") {\n\t\t\t\t\tconst gistId = await findIssueGistId(parsedRef.owner, parsedRef.repo, parsedRef.issue);\n\t\t\t\t\tdecoded = await fetchGistSession(gistId);\n\t\t\t\t\tsourceName = `${gistId}.jsonl`;\n\t\t\t\t} else {\n\t\t\t\t\tif (!existsSync(parsedRef.path)) throw new Error(`session file not found: ${parsedRef.path}`);\n\t\t\t\t\tconst raw = readFileSync(parsedRef.path, \"utf8\");\n\t\t\t\t\tdecoded = parsedRef.path.endsWith(\".html\") ? decodeExportedHtml(raw) : parseSessionJsonl(raw);\n\t\t\t\t\tsourceName = basename(parsedRef.path).replace(/\\.html$/, \".jsonl\");\n\t\t\t\t}\n\n\t\t\t\tconst platformNotice = getPlatformContinuationNotice(decoded.header.cwd);\n\t\t\t\tconst rewritten = rewriteSessionCwd(decoded.jsonl, decoded.header.cwd, targetCwd);\n\t\t\t\tconst destination = join(sessionDir, sourceName);\n\t\t\t\tif (existsSync(destination)) {\n\t\t\t\t\tconst overwrite = await ctx.ui.confirm(\n\t\t\t\t\t\t\"Session already imported\",\n\t\t\t\t\t\t`Overwrite ${destination}? Local changes to that session will be lost.`,\n\t\t\t\t\t);\n\t\t\t\t\tif (!overwrite) {\n\t\t\t\t\t\tctx.ui.notify(\"Import cancelled\", \"warning\");\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\twriteFileSync(destination, rewritten);\n\n\t\t\t\tctx.ui.notify(`Imported session ${decoded.header.id} (cwd ${decoded.header.cwd} -> ${targetCwd})`, \"info\");\n\t\t\t\tawait ctx.switchSession(destination, {\n\t\t\t\t\twithSession: async (nextCtx) => {\n\t\t\t\t\t\tif (!platformNotice) return;\n\t\t\t\t\t\tawait nextCtx.sendMessage(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcustomType: \"import-repro\",\n\t\t\t\t\t\t\t\tcontent: platformNotice,\n\t\t\t\t\t\t\t\tdisplay: true,\n\t\t\t\t\t\t\t\tdetails: { sourceCwd: decoded.header.cwd, targetCwd },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{ triggerTurn: false },\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tctx.ui.notify(`ir: ${error instanceof Error ? error.message : String(error)}`, \"error\");\n\t\t\t}\n\t\t},\n\t});\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/model-fallback/settings.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACzG,OAAO,KAAK,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAEtF,MAAM,MAAM,gBAAgB,GAAG,qBAAqB,CAAC;AASrD,wBAAgB,oBAAoB,CACnC,QAAQ,EAAE,wBAAwB,EAClC,MAAM,EAAE,mBAAmB,GACzB,gBAAgB,CAElB;AAED,wBAAsB,sBAAsB,CAC3C,QAAQ,EAAE,wBAAwB,EAClC,MAAM,EAAE,mBAAmB,EAC3B,MAAM,EAAE,CAAC,QAAQ,EAAE,wBAAwB,KAAK,OAAO,CAAC,IAAI,CAAC,GAC3D,OAAO,CAAC,gBAAgB,CAAC,CAG3B;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,EAAE,WAAW,oBAAc,GAAG,OAAO,CAE9G"}
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/model-fallback/settings.ts"],"names":[],"mappings":"AACA,OAAO,EAA8B,KAAK,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACzG,OAAO,KAAK,EAAE,wBAAwB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAEtF,MAAM,MAAM,gBAAgB,GAAG,qBAAqB,CAAC;AAiCrD,wBAAgB,oBAAoB,CACnC,QAAQ,EAAE,wBAAwB,EAClC,MAAM,EAAE,mBAAmB,GACzB,gBAAgB,CAElB;AAED,wBAAsB,sBAAsB,CAC3C,QAAQ,EAAE,wBAAwB,EAClC,MAAM,EAAE,mBAAmB,EAC3B,MAAM,EAAE,CAAC,QAAQ,EAAE,wBAAwB,KAAK,OAAO,CAAC,IAAI,CAAC,GAC3D,OAAO,CAAC,gBAAgB,CAAC,CAG3B;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,EAAE,WAAW,oBAAc,GAAG,OAAO,CAE9G"}
@@ -1,8 +1,28 @@
1
1
  import { canonicalizeFallbackChains } from "../../../retry-fallback/chains.js";
2
+ /**
3
+ * `/fallback` shows what the user can act on. A bare default expands across every
4
+ * provider in the builtin catalog that publishes the model, so canonicalizing
5
+ * against the full registry listed chains for providers the user cannot select
6
+ * (no credentials). Scope the display to selectable models; the runtime keeps
7
+ * using the full registry so a chain still resolves for the active model.
8
+ */
9
+ function displayLookup(models) {
10
+ if (Array.isArray(models))
11
+ return models;
12
+ const registry = models;
13
+ if (typeof registry.getAvailable !== "function")
14
+ return models;
15
+ const available = registry.getAvailable();
16
+ return {
17
+ getAll: () => (available.length > 0 ? available : registry.getAll()),
18
+ isUsingOAuth: (model) => registry.isUsingOAuth?.(model) === true,
19
+ hasConfiguredAuth: (model) => registry.hasConfiguredAuth?.(model) === true,
20
+ };
21
+ }
2
22
  function withAvailableChains(settings, models) {
3
23
  return {
4
24
  ...settings,
5
- chains: canonicalizeFallbackChains(settings.chains, models),
25
+ chains: canonicalizeFallbackChains(settings.chains, displayLookup(models)),
6
26
  };
7
27
  }
8
28
  export function loadFallbackSettings(settings, models) {
@@ -1 +1 @@
1
- {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/model-fallback/settings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAA4B,MAAM,mCAAmC,CAAC;AAKzG,SAAS,mBAAmB,CAAC,QAA0B,EAAE,MAA2B;IACnF,OAAO;QACN,GAAG,QAAQ;QACX,MAAM,EAAE,0BAA0B,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;KAC3D,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CACnC,QAAkC,EAClC,MAA2B;IAE3B,OAAO,mBAAmB,CAAC,QAAQ,CAAC,wBAAwB,EAAE,EAAE,MAAM,CAAC,CAAC;AACzE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC3C,QAAkC,EAClC,MAA2B,EAC3B,MAA6D;IAE7D,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;IACvB,OAAO,mBAAmB,CAAC,QAAQ,CAAC,wBAAwB,EAAE,EAAE,MAAM,CAAC,CAAC;AACzE,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,IAAkC,EAAE,WAAW,GAAG,OAAO,CAAC,GAAG;IACpG,OAAO,IAAI,KAAK,IAAI,IAAI,WAAW,CAAC,iBAAiB,KAAK,GAAG,CAAC;AAC/D,CAAC","sourcesContent":["import { canonicalizeFallbackChains, type FallbackModelLookup } from \"../../../retry-fallback/chains.ts\";\nimport type { ExtensionSessionSettings, RetryFallbackSettings } from \"../../types.ts\";\n\nexport type FallbackSettings = RetryFallbackSettings;\n\nfunction withAvailableChains(settings: FallbackSettings, models: FallbackModelLookup): FallbackSettings {\n\treturn {\n\t\t...settings,\n\t\tchains: canonicalizeFallbackChains(settings.chains, models),\n\t};\n}\n\nexport function loadFallbackSettings(\n\tsettings: ExtensionSessionSettings,\n\tmodels: FallbackModelLookup,\n): FallbackSettings {\n\treturn withAvailableChains(settings.getRetryFallbackSettings(), models);\n}\n\nexport async function updateFallbackSettings(\n\tsettings: ExtensionSessionSettings,\n\tmodels: FallbackModelLookup,\n\tupdate: (settings: ExtensionSessionSettings) => Promise<void>,\n): Promise<FallbackSettings> {\n\tawait update(settings);\n\treturn withAvailableChains(settings.getRetryFallbackSettings(), models);\n}\n\nexport function isModelFallbackDisabled(flag: boolean | string | undefined, environment = process.env): boolean {\n\treturn flag === true || environment.SENPI_NO_FALLBACK === \"1\";\n}\n"]}
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/model-fallback/settings.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,0BAA0B,EAA4B,MAAM,mCAAmC,CAAC;AAKzG;;;;;;GAMG;AACH,SAAS,aAAa,CAAC,MAA2B;IACjD,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IACzC,MAAM,QAAQ,GAAG,MAKhB,CAAC;IACF,IAAI,OAAO,QAAQ,CAAC,YAAY,KAAK,UAAU;QAAE,OAAO,MAAM,CAAC;IAC/D,MAAM,SAAS,GAAG,QAAQ,CAAC,YAAY,EAAE,CAAC;IAC1C,OAAO;QACN,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QACpE,YAAY,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,KAAK,IAAI;QAChE,iBAAiB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,CAAC,iBAAiB,EAAE,CAAC,KAAK,CAAC,KAAK,IAAI;KAC1E,CAAC;AACH,CAAC;AAED,SAAS,mBAAmB,CAAC,QAA0B,EAAE,MAA2B;IACnF,OAAO;QACN,GAAG,QAAQ;QACX,MAAM,EAAE,0BAA0B,CAAC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;KAC1E,CAAC;AACH,CAAC;AAED,MAAM,UAAU,oBAAoB,CACnC,QAAkC,EAClC,MAA2B;IAE3B,OAAO,mBAAmB,CAAC,QAAQ,CAAC,wBAAwB,EAAE,EAAE,MAAM,CAAC,CAAC;AACzE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC3C,QAAkC,EAClC,MAA2B,EAC3B,MAA6D;IAE7D,MAAM,MAAM,CAAC,QAAQ,CAAC,CAAC;IACvB,OAAO,mBAAmB,CAAC,QAAQ,CAAC,wBAAwB,EAAE,EAAE,MAAM,CAAC,CAAC;AACzE,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,IAAkC,EAAE,WAAW,GAAG,OAAO,CAAC,GAAG;IACpG,OAAO,IAAI,KAAK,IAAI,IAAI,WAAW,CAAC,iBAAiB,KAAK,GAAG,CAAC;AAC/D,CAAC","sourcesContent":["import type { Api, Model } from \"@earendil-works/pi-ai\";\nimport { canonicalizeFallbackChains, type FallbackModelLookup } from \"../../../retry-fallback/chains.ts\";\nimport type { ExtensionSessionSettings, RetryFallbackSettings } from \"../../types.ts\";\n\nexport type FallbackSettings = RetryFallbackSettings;\n\n/**\n * `/fallback` shows what the user can act on. A bare default expands across every\n * provider in the builtin catalog that publishes the model, so canonicalizing\n * against the full registry listed chains for providers the user cannot select\n * (no credentials). Scope the display to selectable models; the runtime keeps\n * using the full registry so a chain still resolves for the active model.\n */\nfunction displayLookup(models: FallbackModelLookup): FallbackModelLookup {\n\tif (Array.isArray(models)) return models;\n\tconst registry = models as {\n\t\tgetAll(): Model<Api>[];\n\t\tgetAvailable?(): Model<Api>[];\n\t\tisUsingOAuth?(model: Model<Api>): boolean;\n\t\thasConfiguredAuth?(model: Model<Api>): boolean;\n\t};\n\tif (typeof registry.getAvailable !== \"function\") return models;\n\tconst available = registry.getAvailable();\n\treturn {\n\t\tgetAll: () => (available.length > 0 ? available : registry.getAll()),\n\t\tisUsingOAuth: (model) => registry.isUsingOAuth?.(model) === true,\n\t\thasConfiguredAuth: (model) => registry.hasConfiguredAuth?.(model) === true,\n\t};\n}\n\nfunction withAvailableChains(settings: FallbackSettings, models: FallbackModelLookup): FallbackSettings {\n\treturn {\n\t\t...settings,\n\t\tchains: canonicalizeFallbackChains(settings.chains, displayLookup(models)),\n\t};\n}\n\nexport function loadFallbackSettings(\n\tsettings: ExtensionSessionSettings,\n\tmodels: FallbackModelLookup,\n): FallbackSettings {\n\treturn withAvailableChains(settings.getRetryFallbackSettings(), models);\n}\n\nexport async function updateFallbackSettings(\n\tsettings: ExtensionSessionSettings,\n\tmodels: FallbackModelLookup,\n\tupdate: (settings: ExtensionSessionSettings) => Promise<void>,\n): Promise<FallbackSettings> {\n\tawait update(settings);\n\treturn withAvailableChains(settings.getRetryFallbackSettings(), models);\n}\n\nexport function isModelFallbackDisabled(flag: boolean | string | undefined, environment = process.env): boolean {\n\treturn flag === true || environment.SENPI_NO_FALLBACK === \"1\";\n}\n"]}
@@ -0,0 +1,13 @@
1
+ export declare const RESUMPTION_CHANNEL_STATE_EVENT = "resumption_channel_state";
2
+ export interface ResumptionChannelEntry {
3
+ readonly id: string;
4
+ readonly description: string;
5
+ readonly startedAtMs: number;
6
+ }
7
+ export interface ResumptionChannelStateEvent {
8
+ readonly source: string;
9
+ readonly activeCount: number;
10
+ readonly channels?: readonly ResumptionChannelEntry[];
11
+ }
12
+ export declare function isResumptionChannelStateEvent(data: unknown): data is ResumptionChannelStateEvent;
13
+ //# sourceMappingURL=resumption-channel-event.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resumption-channel-event.d.ts","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/resumption-channel-event.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,8BAA8B,6BAA6B,CAAC;AAEzE,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,2BAA2B;IAC3C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,sBAAsB,EAAE,CAAC;CACtD;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,2BAA2B,CAYhG"}
@@ -0,0 +1,13 @@
1
+ export const RESUMPTION_CHANNEL_STATE_EVENT = "resumption_channel_state";
2
+ export function isResumptionChannelStateEvent(data) {
3
+ return (typeof data === "object" &&
4
+ data !== null &&
5
+ "source" in data &&
6
+ typeof data.source === "string" &&
7
+ data.source.length > 0 &&
8
+ "activeCount" in data &&
9
+ typeof data.activeCount === "number" &&
10
+ Number.isInteger(data.activeCount) &&
11
+ data.activeCount >= 0);
12
+ }
13
+ //# sourceMappingURL=resumption-channel-event.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resumption-channel-event.js","sourceRoot":"","sources":["../../../../src/core/extensions/builtin/resumption-channel-event.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,8BAA8B,GAAG,0BAA0B,CAAC;AAczE,MAAM,UAAU,6BAA6B,CAAC,IAAa;IAC1D,OAAO,CACN,OAAO,IAAI,KAAK,QAAQ;QACxB,IAAI,KAAK,IAAI;QACb,QAAQ,IAAI,IAAI;QAChB,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ;QAC/B,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC;QACtB,aAAa,IAAI,IAAI;QACrB,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ;QACpC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,CAAC;QAClC,IAAI,CAAC,WAAW,IAAI,CAAC,CACrB,CAAC;AACH,CAAC","sourcesContent":["export const RESUMPTION_CHANNEL_STATE_EVENT = \"resumption_channel_state\";\n\nexport interface ResumptionChannelEntry {\n\treadonly id: string;\n\treadonly description: string;\n\treadonly startedAtMs: number;\n}\n\nexport interface ResumptionChannelStateEvent {\n\treadonly source: string;\n\treadonly activeCount: number;\n\treadonly channels?: readonly ResumptionChannelEntry[];\n}\n\nexport function isResumptionChannelStateEvent(data: unknown): data is ResumptionChannelStateEvent {\n\treturn (\n\t\ttypeof data === \"object\" &&\n\t\tdata !== null &&\n\t\t\"source\" in data &&\n\t\ttypeof data.source === \"string\" &&\n\t\tdata.source.length > 0 &&\n\t\t\"activeCount\" in data &&\n\t\ttypeof data.activeCount === \"number\" &&\n\t\tNumber.isInteger(data.activeCount) &&\n\t\tdata.activeCount >= 0\n\t);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/extension.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,gBAAgB,CAAC;AA+IrE,wBAAgB,yBAAyB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAsGhE;eAEc,yBAAyB"}
1
+ {"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/extension.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAoB,MAAM,gBAAgB,CAAC;AAmKrE,wBAAgB,yBAAyB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAsGhE;eAEc,yBAAyB"}
@@ -2,6 +2,7 @@ import { getShellEnv } from "../../../../utils/shell.js";
2
2
  import { SettingsManager } from "../../../settings-manager.js";
3
3
  import { isAnthropicBashEnabled } from "../anthropic-bash/index.js";
4
4
  import { TERMINAL_MONITOR_STATE_EVENT } from "../monitor-state-event.js";
5
+ import { RESUMPTION_CHANNEL_STATE_EVENT } from "../resumption-channel-event.js";
5
6
  import { MonitorNotifier } from "./monitor-notify.js";
6
7
  import { MONITOR_STATUS_KEY } from "./monitor-status.js";
7
8
  import { MonitorStatusTicker } from "./monitor-status-ticker.js";
@@ -41,6 +42,22 @@ function bundleSinks(pi, state) {
41
42
  startedAtMs: entry.startedAtMs,
42
43
  })),
43
44
  });
45
+ pi.events?.emit(RESUMPTION_CHANNEL_STATE_EVENT, {
46
+ source: "terminal-monitor",
47
+ activeCount: snapshot.length,
48
+ channels: snapshot.map((entry) => ({
49
+ id: entry.id,
50
+ description: entry.description,
51
+ startedAtMs: entry.startedAtMs,
52
+ })),
53
+ });
54
+ },
55
+ onBackgroundState: (snapshot) => {
56
+ pi.events?.emit(RESUMPTION_CHANNEL_STATE_EVENT, {
57
+ source: "terminal-bash",
58
+ activeCount: snapshot.length,
59
+ channels: snapshot,
60
+ });
44
61
  },
45
62
  onBackgroundExit: (id, runtime) => state.notifier?.notifyCompletion(id, runtime),
46
63
  };
@@ -82,6 +99,9 @@ function buildToolContext(pi, state) {
82
99
  getSessionContext: () => state.ctx,
83
100
  // Exit listeners registered before a reload reach the post-reload owner through the
84
101
  // shared bundle, so this must dispatch via the bundle, never the instance notifier.
102
+ onBackgroundStart: (id, description, startedAtMs) => {
103
+ state.bundle?.notifyBackgroundStart(id, description, startedAtMs);
104
+ },
85
105
  onBackgroundExit: (id, runtime) => {
86
106
  state.bundle?.notifyBackgroundExit(id, runtime);
87
107
  },
@@ -1 +1 @@
1
- {"version":3,"file":"extension.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/extension.ts"],"names":[],"mappings":"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","sourcesContent":["import { getShellEnv } from \"../../../../utils/shell.ts\";\nimport { SettingsManager } from \"../../../settings-manager.ts\";\nimport type { ExtensionAPI, ExtensionContext } from \"../../types.ts\";\nimport { isAnthropicBashEnabled } from \"../anthropic-bash/index.ts\";\nimport { TERMINAL_MONITOR_STATE_EVENT } from \"../monitor-state-event.ts\";\nimport { MonitorNotifier } from \"./monitor-notify.ts\";\nimport { MONITOR_STATUS_KEY } from \"./monitor-status.ts\";\nimport { MonitorStatusTicker } from \"./monitor-status-ticker.ts\";\nimport { TerminalNotifier } from \"./notify.ts\";\nimport { TERMINAL_PROMPT_SECTION } from \"./prompt.ts\";\nimport type { TerminalRuntimeSession } from \"./runtime-session.ts\";\nimport {\n\tclaimParkedBundle,\n\tparkBundle,\n\ttype TerminalEventSinks,\n\tTerminalSessionBundle,\n\tteardownParkedBundle,\n} from \"./session-bundle.ts\";\nimport { loadTerminalSettings, type ResolvedTerminalSettings, TERMINAL_SETTINGS_DEFAULTS } from \"./settings.ts\";\nimport { TERMINAL_BASH_TOOL, TERMINAL_COMPANION_TOOLS } from \"./shared.ts\";\nimport { createPtyBashTool } from \"./tools/bash.ts\";\nimport { createBashInputTool } from \"./tools/bash-input.ts\";\nimport { createBashOutputTool } from \"./tools/bash-output.ts\";\nimport { createBashResizeTool } from \"./tools/bash-resize.ts\";\nimport type { TerminalToolContext } from \"./tools/context.ts\";\nimport { createKillBashTool } from \"./tools/kill-bash.ts\";\nimport { createMonitorTool } from \"./tools/monitor.ts\";\n\ninterface TerminalExtensionState {\n\tbundle: TerminalSessionBundle | null;\n\tsettings: ResolvedTerminalSettings;\n\tnotifier: TerminalNotifier | null;\n\tmonitorNotifier: MonitorNotifier | null;\n\tstatusTicker: MonitorStatusTicker;\n\tctx: ExtensionContext | undefined;\n\tshellPath: string | undefined;\n\tsteppedAside: boolean;\n\tnoticeShown: boolean;\n}\n\n/** Tests and SDK callers may hand partial contexts without a session manager. */\nfunction sessionKeyOf(ctx: ExtensionContext | undefined): string | undefined {\n\treturn ctx?.sessionManager?.getSessionId?.();\n}\n\nfunction createBundle(state: TerminalExtensionState): TerminalSessionBundle {\n\treturn new TerminalSessionBundle({\n\t\tmaxSessions: state.settings.maxSessions,\n\t\tscrollback: state.settings.scrollback,\n\t});\n}\n\n/** Sinks read the live instance state at call time, so notifier swaps need no re-bind. */\nfunction bundleSinks(pi: ExtensionAPI, state: TerminalExtensionState): TerminalEventSinks {\n\treturn {\n\t\tonMonitorEvent: (event) => state.monitorNotifier?.notifyEvent(event),\n\t\tonMonitorState: (snapshot) => {\n\t\t\tstate.statusTicker.sync(snapshot);\n\t\t\tpi.events?.emit(TERMINAL_MONITOR_STATE_EVENT, {\n\t\t\t\tactiveCount: snapshot.length,\n\t\t\t\tmonitors: snapshot.map((entry) => ({\n\t\t\t\t\tid: entry.id,\n\t\t\t\t\tdescription: entry.description,\n\t\t\t\t\tpaused: entry.paused,\n\t\t\t\t\tstartedAtMs: entry.startedAtMs,\n\t\t\t\t})),\n\t\t\t});\n\t\t},\n\t\tonBackgroundExit: (id, runtime) => state.notifier?.notifyCompletion(id, runtime),\n\t};\n}\n\nfunction buildToolContext(pi: ExtensionAPI, state: TerminalExtensionState): TerminalToolContext {\n\tconst requireBundle = (): TerminalSessionBundle => {\n\t\t// Lazily create a bundle so the tools work even when invoked directly (e.g. via the\n\t\t// SDK) before `session_start` initializes one. `session_start` replaces it with a\n\t\t// settings-configured bundle and tears down any earlier one.\n\t\tif (!state.bundle) {\n\t\t\tstate.bundle = createBundle(state);\n\t\t\tstate.bundle.bind(bundleSinks(pi, state));\n\t\t}\n\t\treturn state.bundle;\n\t};\n\treturn {\n\t\tget manager() {\n\t\t\treturn requireBundle().manager;\n\t\t},\n\t\tget cwd() {\n\t\t\treturn state.ctx?.cwd ?? process.cwd();\n\t\t},\n\t\tget shellPath() {\n\t\t\treturn state.shellPath;\n\t\t},\n\t\tget defaultCols() {\n\t\t\treturn state.settings.defaultCols;\n\t\t},\n\t\tget defaultRows() {\n\t\t\treturn state.settings.defaultRows;\n\t\t},\n\t\tget timeoutAction() {\n\t\t\treturn state.settings.timeoutAction;\n\t\t},\n\t\tget monitorRegistry() {\n\t\t\treturn requireBundle().monitors;\n\t\t},\n\t\tgetEnv: () => getShellEnv(),\n\t\tgetSessionContext: () => state.ctx,\n\t\t// Exit listeners registered before a reload reach the post-reload owner through the\n\t\t// shared bundle, so this must dispatch via the bundle, never the instance notifier.\n\t\tonBackgroundExit: (id: string, runtime: TerminalRuntimeSession) => {\n\t\t\tstate.bundle?.notifyBackgroundExit(id, runtime);\n\t\t},\n\t\tonMonitorRearmed: (id: string) => state.monitorNotifier?.rearm(id),\n\t};\n}\n\nfunction shouldStepAside(ctx: ExtensionContext | undefined): boolean {\n\treturn isAnthropicBashEnabled() && ctx?.model?.api === \"anthropic-messages\";\n}\n\n/**\n * Keep the tool surface consistent with anthropic-bash. When native Anthropic bash is active,\n * the provider replaces the PTY `bash` function, but the companions stay active because `monitor`\n * creates its own PTY session and bash_output/input/resize/kill operate on that shared registry.\n * Otherwise the PTY `bash` + companions are (re)activated. Re-evaluated on session_start AND\n * model_select.\n */\nfunction syncToolset(pi: ExtensionAPI, state: TerminalExtensionState): void {\n\tconst stepAside = shouldStepAside(state.ctx);\n\tconst active = new Set(pi.getActiveTools());\n\tif (stepAside) {\n\t\tfor (const companion of TERMINAL_COMPANION_TOOLS) active.add(companion);\n\t\tif (!state.noticeShown) {\n\t\t\tstate.ctx?.ui.notify(\"native Anthropic bash active — monitor sessions remain available\", \"info\");\n\t\t\tstate.noticeShown = true;\n\t\t}\n\t} else {\n\t\tactive.add(TERMINAL_BASH_TOOL);\n\t\tfor (const companion of TERMINAL_COMPANION_TOOLS) active.add(companion);\n\t\tstate.noticeShown = false;\n\t}\n\tstate.steppedAside = stepAside;\n\tpi.setActiveTools([...active]);\n}\n\nexport function registerTerminalExtension(pi: ExtensionAPI): void {\n\tconst state: TerminalExtensionState = {\n\t\tbundle: null,\n\t\tsettings: TERMINAL_SETTINGS_DEFAULTS,\n\t\tnotifier: null,\n\t\tmonitorNotifier: null,\n\t\tstatusTicker: new MonitorStatusTicker({\n\t\t\trender: (status) => {\n\t\t\t\tconst ctx = state.ctx;\n\t\t\t\tctx?.ui.setStatus(\n\t\t\t\t\tMONITOR_STATUS_KEY,\n\t\t\t\t\tstatus === undefined || ctx.mode !== \"tui\"\n\t\t\t\t\t\t? status\n\t\t\t\t\t\t: ctx.ui.theme.bg(\"selectedBg\", ctx.ui.theme.fg(\"text\", status)),\n\t\t\t\t);\n\t\t\t},\n\t\t}),\n\t\tctx: undefined,\n\t\tshellPath: undefined,\n\t\tsteppedAside: false,\n\t\tnoticeShown: false,\n\t};\n\tconst toolCtx = buildToolContext(pi, state);\n\n\tpi.registerTool(createPtyBashTool(toolCtx));\n\tpi.registerTool(createBashOutputTool(toolCtx));\n\tpi.registerTool(createBashInputTool(toolCtx));\n\tpi.registerTool(createBashResizeTool(toolCtx));\n\tpi.registerTool(createKillBashTool(toolCtx));\n\tpi.registerTool(createMonitorTool(toolCtx));\n\n\tpi.on(\"session_start\", async (event, ctx) => {\n\t\tstate.ctx = ctx;\n\t\tconst settingsManager = SettingsManager.create(ctx.cwd);\n\t\tstate.settings = loadTerminalSettings(settingsManager);\n\t\tstate.shellPath = settingsManager.getShellPath();\n\t\tstate.notifier = new TerminalNotifier({\n\t\t\tsendMessage: (message, options) => pi.sendMessage(message, options),\n\t\t\tgetContext: () => state.ctx,\n\t\t\tgetMode: () => state.settings.notify,\n\t\t});\n\t\tstate.monitorNotifier?.dispose();\n\t\tstate.monitorNotifier = new MonitorNotifier({\n\t\t\tsendMessage: (message, options) => pi.sendMessage(message, options),\n\t\t\tgetContext: () => state.ctx,\n\t\t\tgetMode: () => state.settings.notify,\n\t\t\tgetSettings: () => state.settings.monitor,\n\t\t\tpauseMonitors: () => state.bundle?.monitors.pauseAll() ?? [],\n\t\t});\n\t\tconst sessionKey = sessionKeyOf(ctx);\n\t\tif (event.reason === \"reload\") {\n\t\t\tconst claimed = sessionKey === undefined ? undefined : claimParkedBundle(sessionKey);\n\t\t\tif (claimed) {\n\t\t\t\tawait state.bundle?.teardown();\n\t\t\t\tstate.bundle = claimed;\n\t\t\t}\n\t\t} else {\n\t\t\tif (sessionKey !== undefined) await teardownParkedBundle(sessionKey);\n\t\t\tawait state.bundle?.teardown();\n\t\t\tstate.bundle = createBundle(state);\n\t\t}\n\t\tstate.bundle ??= createBundle(state);\n\t\tstate.bundle.bind(bundleSinks(pi, state));\n\t\tsyncToolset(pi, state);\n\t});\n\n\tpi.on(\"model_select\", async (event, ctx) => {\n\t\tstate.ctx = { ...ctx, model: event.model };\n\t\tsyncToolset(pi, state);\n\t});\n\n\tpi.on(\"input\", (event) => {\n\t\tif (event.source !== \"extension\") state.monitorNotifier?.noteActivity();\n\t});\n\n\tpi.on(\"tool_call\", () => {\n\t\tstate.monitorNotifier?.noteActivity();\n\t});\n\n\tpi.on(\"before_agent_start\", async (event) => {\n\t\tif (state.steppedAside) return undefined;\n\t\treturn { systemPrompt: `${event.systemPrompt}\\n${TERMINAL_PROMPT_SECTION}` };\n\t});\n\n\tpi.on(\"session_shutdown\", async (event, ctx) => {\n\t\tstate.monitorNotifier?.dispose();\n\t\tstate.monitorNotifier = null;\n\t\tstate.notifier = null;\n\t\tstate.statusTicker.stop();\n\t\tconst sessionKey = sessionKeyOf(ctx) ?? sessionKeyOf(state.ctx);\n\t\tif (event.reason === \"reload\" && state.bundle && sessionKey !== undefined) {\n\t\t\t// Keep state.bundle referenced: exit listeners captured by this instance's tool\n\t\t\t// context still route through the shared bundle after the new owner claims it.\n\t\t\tstate.bundle.park();\n\t\t\tawait parkBundle(sessionKey, state.bundle);\n\t\t\treturn;\n\t\t}\n\t\tconst bundle = state.bundle;\n\t\tstate.bundle = null;\n\t\tawait bundle?.teardown();\n\t\tif (sessionKey !== undefined) await teardownParkedBundle(sessionKey);\n\t});\n}\n\nexport default registerTerminalExtension;\n"]}
1
+ {"version":3,"file":"extension.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/extension.ts"],"names":[],"mappings":"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","sourcesContent":["import { getShellEnv } from \"../../../../utils/shell.ts\";\nimport { SettingsManager } from \"../../../settings-manager.ts\";\nimport type { ExtensionAPI, ExtensionContext } from \"../../types.ts\";\nimport { isAnthropicBashEnabled } from \"../anthropic-bash/index.ts\";\nimport { TERMINAL_MONITOR_STATE_EVENT } from \"../monitor-state-event.ts\";\nimport { RESUMPTION_CHANNEL_STATE_EVENT } from \"../resumption-channel-event.ts\";\nimport { MonitorNotifier } from \"./monitor-notify.ts\";\nimport { MONITOR_STATUS_KEY } from \"./monitor-status.ts\";\nimport { MonitorStatusTicker } from \"./monitor-status-ticker.ts\";\nimport { TerminalNotifier } from \"./notify.ts\";\nimport { TERMINAL_PROMPT_SECTION } from \"./prompt.ts\";\nimport type { TerminalRuntimeSession } from \"./runtime-session.ts\";\nimport {\n\tclaimParkedBundle,\n\tparkBundle,\n\ttype TerminalEventSinks,\n\tTerminalSessionBundle,\n\tteardownParkedBundle,\n} from \"./session-bundle.ts\";\nimport { loadTerminalSettings, type ResolvedTerminalSettings, TERMINAL_SETTINGS_DEFAULTS } from \"./settings.ts\";\nimport { TERMINAL_BASH_TOOL, TERMINAL_COMPANION_TOOLS } from \"./shared.ts\";\nimport { createPtyBashTool } from \"./tools/bash.ts\";\nimport { createBashInputTool } from \"./tools/bash-input.ts\";\nimport { createBashOutputTool } from \"./tools/bash-output.ts\";\nimport { createBashResizeTool } from \"./tools/bash-resize.ts\";\nimport type { TerminalToolContext } from \"./tools/context.ts\";\nimport { createKillBashTool } from \"./tools/kill-bash.ts\";\nimport { createMonitorTool } from \"./tools/monitor.ts\";\n\ninterface TerminalExtensionState {\n\tbundle: TerminalSessionBundle | null;\n\tsettings: ResolvedTerminalSettings;\n\tnotifier: TerminalNotifier | null;\n\tmonitorNotifier: MonitorNotifier | null;\n\tstatusTicker: MonitorStatusTicker;\n\tctx: ExtensionContext | undefined;\n\tshellPath: string | undefined;\n\tsteppedAside: boolean;\n\tnoticeShown: boolean;\n}\n\n/** Tests and SDK callers may hand partial contexts without a session manager. */\nfunction sessionKeyOf(ctx: ExtensionContext | undefined): string | undefined {\n\treturn ctx?.sessionManager?.getSessionId?.();\n}\n\nfunction createBundle(state: TerminalExtensionState): TerminalSessionBundle {\n\treturn new TerminalSessionBundle({\n\t\tmaxSessions: state.settings.maxSessions,\n\t\tscrollback: state.settings.scrollback,\n\t});\n}\n\n/** Sinks read the live instance state at call time, so notifier swaps need no re-bind. */\nfunction bundleSinks(pi: ExtensionAPI, state: TerminalExtensionState): TerminalEventSinks {\n\treturn {\n\t\tonMonitorEvent: (event) => state.monitorNotifier?.notifyEvent(event),\n\t\tonMonitorState: (snapshot) => {\n\t\t\tstate.statusTicker.sync(snapshot);\n\t\t\tpi.events?.emit(TERMINAL_MONITOR_STATE_EVENT, {\n\t\t\t\tactiveCount: snapshot.length,\n\t\t\t\tmonitors: snapshot.map((entry) => ({\n\t\t\t\t\tid: entry.id,\n\t\t\t\t\tdescription: entry.description,\n\t\t\t\t\tpaused: entry.paused,\n\t\t\t\t\tstartedAtMs: entry.startedAtMs,\n\t\t\t\t})),\n\t\t\t});\n\t\t\tpi.events?.emit(RESUMPTION_CHANNEL_STATE_EVENT, {\n\t\t\t\tsource: \"terminal-monitor\",\n\t\t\t\tactiveCount: snapshot.length,\n\t\t\t\tchannels: snapshot.map((entry) => ({\n\t\t\t\t\tid: entry.id,\n\t\t\t\t\tdescription: entry.description,\n\t\t\t\t\tstartedAtMs: entry.startedAtMs,\n\t\t\t\t})),\n\t\t\t});\n\t\t},\n\t\tonBackgroundState: (snapshot) => {\n\t\t\tpi.events?.emit(RESUMPTION_CHANNEL_STATE_EVENT, {\n\t\t\t\tsource: \"terminal-bash\",\n\t\t\t\tactiveCount: snapshot.length,\n\t\t\t\tchannels: snapshot,\n\t\t\t});\n\t\t},\n\t\tonBackgroundExit: (id, runtime) => state.notifier?.notifyCompletion(id, runtime),\n\t};\n}\n\nfunction buildToolContext(pi: ExtensionAPI, state: TerminalExtensionState): TerminalToolContext {\n\tconst requireBundle = (): TerminalSessionBundle => {\n\t\t// Lazily create a bundle so the tools work even when invoked directly (e.g. via the\n\t\t// SDK) before `session_start` initializes one. `session_start` replaces it with a\n\t\t// settings-configured bundle and tears down any earlier one.\n\t\tif (!state.bundle) {\n\t\t\tstate.bundle = createBundle(state);\n\t\t\tstate.bundle.bind(bundleSinks(pi, state));\n\t\t}\n\t\treturn state.bundle;\n\t};\n\treturn {\n\t\tget manager() {\n\t\t\treturn requireBundle().manager;\n\t\t},\n\t\tget cwd() {\n\t\t\treturn state.ctx?.cwd ?? process.cwd();\n\t\t},\n\t\tget shellPath() {\n\t\t\treturn state.shellPath;\n\t\t},\n\t\tget defaultCols() {\n\t\t\treturn state.settings.defaultCols;\n\t\t},\n\t\tget defaultRows() {\n\t\t\treturn state.settings.defaultRows;\n\t\t},\n\t\tget timeoutAction() {\n\t\t\treturn state.settings.timeoutAction;\n\t\t},\n\t\tget monitorRegistry() {\n\t\t\treturn requireBundle().monitors;\n\t\t},\n\t\tgetEnv: () => getShellEnv(),\n\t\tgetSessionContext: () => state.ctx,\n\t\t// Exit listeners registered before a reload reach the post-reload owner through the\n\t\t// shared bundle, so this must dispatch via the bundle, never the instance notifier.\n\t\tonBackgroundStart: (id: string, description: string, startedAtMs: number) => {\n\t\t\tstate.bundle?.notifyBackgroundStart(id, description, startedAtMs);\n\t\t},\n\t\tonBackgroundExit: (id: string, runtime: TerminalRuntimeSession) => {\n\t\t\tstate.bundle?.notifyBackgroundExit(id, runtime);\n\t\t},\n\t\tonMonitorRearmed: (id: string) => state.monitorNotifier?.rearm(id),\n\t};\n}\n\nfunction shouldStepAside(ctx: ExtensionContext | undefined): boolean {\n\treturn isAnthropicBashEnabled() && ctx?.model?.api === \"anthropic-messages\";\n}\n\n/**\n * Keep the tool surface consistent with anthropic-bash. When native Anthropic bash is active,\n * the provider replaces the PTY `bash` function, but the companions stay active because `monitor`\n * creates its own PTY session and bash_output/input/resize/kill operate on that shared registry.\n * Otherwise the PTY `bash` + companions are (re)activated. Re-evaluated on session_start AND\n * model_select.\n */\nfunction syncToolset(pi: ExtensionAPI, state: TerminalExtensionState): void {\n\tconst stepAside = shouldStepAside(state.ctx);\n\tconst active = new Set(pi.getActiveTools());\n\tif (stepAside) {\n\t\tfor (const companion of TERMINAL_COMPANION_TOOLS) active.add(companion);\n\t\tif (!state.noticeShown) {\n\t\t\tstate.ctx?.ui.notify(\"native Anthropic bash active — monitor sessions remain available\", \"info\");\n\t\t\tstate.noticeShown = true;\n\t\t}\n\t} else {\n\t\tactive.add(TERMINAL_BASH_TOOL);\n\t\tfor (const companion of TERMINAL_COMPANION_TOOLS) active.add(companion);\n\t\tstate.noticeShown = false;\n\t}\n\tstate.steppedAside = stepAside;\n\tpi.setActiveTools([...active]);\n}\n\nexport function registerTerminalExtension(pi: ExtensionAPI): void {\n\tconst state: TerminalExtensionState = {\n\t\tbundle: null,\n\t\tsettings: TERMINAL_SETTINGS_DEFAULTS,\n\t\tnotifier: null,\n\t\tmonitorNotifier: null,\n\t\tstatusTicker: new MonitorStatusTicker({\n\t\t\trender: (status) => {\n\t\t\t\tconst ctx = state.ctx;\n\t\t\t\tctx?.ui.setStatus(\n\t\t\t\t\tMONITOR_STATUS_KEY,\n\t\t\t\t\tstatus === undefined || ctx.mode !== \"tui\"\n\t\t\t\t\t\t? status\n\t\t\t\t\t\t: ctx.ui.theme.bg(\"selectedBg\", ctx.ui.theme.fg(\"text\", status)),\n\t\t\t\t);\n\t\t\t},\n\t\t}),\n\t\tctx: undefined,\n\t\tshellPath: undefined,\n\t\tsteppedAside: false,\n\t\tnoticeShown: false,\n\t};\n\tconst toolCtx = buildToolContext(pi, state);\n\n\tpi.registerTool(createPtyBashTool(toolCtx));\n\tpi.registerTool(createBashOutputTool(toolCtx));\n\tpi.registerTool(createBashInputTool(toolCtx));\n\tpi.registerTool(createBashResizeTool(toolCtx));\n\tpi.registerTool(createKillBashTool(toolCtx));\n\tpi.registerTool(createMonitorTool(toolCtx));\n\n\tpi.on(\"session_start\", async (event, ctx) => {\n\t\tstate.ctx = ctx;\n\t\tconst settingsManager = SettingsManager.create(ctx.cwd);\n\t\tstate.settings = loadTerminalSettings(settingsManager);\n\t\tstate.shellPath = settingsManager.getShellPath();\n\t\tstate.notifier = new TerminalNotifier({\n\t\t\tsendMessage: (message, options) => pi.sendMessage(message, options),\n\t\t\tgetContext: () => state.ctx,\n\t\t\tgetMode: () => state.settings.notify,\n\t\t});\n\t\tstate.monitorNotifier?.dispose();\n\t\tstate.monitorNotifier = new MonitorNotifier({\n\t\t\tsendMessage: (message, options) => pi.sendMessage(message, options),\n\t\t\tgetContext: () => state.ctx,\n\t\t\tgetMode: () => state.settings.notify,\n\t\t\tgetSettings: () => state.settings.monitor,\n\t\t\tpauseMonitors: () => state.bundle?.monitors.pauseAll() ?? [],\n\t\t});\n\t\tconst sessionKey = sessionKeyOf(ctx);\n\t\tif (event.reason === \"reload\") {\n\t\t\tconst claimed = sessionKey === undefined ? undefined : claimParkedBundle(sessionKey);\n\t\t\tif (claimed) {\n\t\t\t\tawait state.bundle?.teardown();\n\t\t\t\tstate.bundle = claimed;\n\t\t\t}\n\t\t} else {\n\t\t\tif (sessionKey !== undefined) await teardownParkedBundle(sessionKey);\n\t\t\tawait state.bundle?.teardown();\n\t\t\tstate.bundle = createBundle(state);\n\t\t}\n\t\tstate.bundle ??= createBundle(state);\n\t\tstate.bundle.bind(bundleSinks(pi, state));\n\t\tsyncToolset(pi, state);\n\t});\n\n\tpi.on(\"model_select\", async (event, ctx) => {\n\t\tstate.ctx = { ...ctx, model: event.model };\n\t\tsyncToolset(pi, state);\n\t});\n\n\tpi.on(\"input\", (event) => {\n\t\tif (event.source !== \"extension\") state.monitorNotifier?.noteActivity();\n\t});\n\n\tpi.on(\"tool_call\", () => {\n\t\tstate.monitorNotifier?.noteActivity();\n\t});\n\n\tpi.on(\"before_agent_start\", async (event) => {\n\t\tif (state.steppedAside) return undefined;\n\t\treturn { systemPrompt: `${event.systemPrompt}\\n${TERMINAL_PROMPT_SECTION}` };\n\t});\n\n\tpi.on(\"session_shutdown\", async (event, ctx) => {\n\t\tstate.monitorNotifier?.dispose();\n\t\tstate.monitorNotifier = null;\n\t\tstate.notifier = null;\n\t\tstate.statusTicker.stop();\n\t\tconst sessionKey = sessionKeyOf(ctx) ?? sessionKeyOf(state.ctx);\n\t\tif (event.reason === \"reload\" && state.bundle && sessionKey !== undefined) {\n\t\t\t// Keep state.bundle referenced: exit listeners captured by this instance's tool\n\t\t\t// context still route through the shared bundle after the new owner claims it.\n\t\t\tstate.bundle.park();\n\t\t\tawait parkBundle(sessionKey, state.bundle);\n\t\t\treturn;\n\t\t}\n\t\tconst bundle = state.bundle;\n\t\tstate.bundle = null;\n\t\tawait bundle?.teardown();\n\t\tif (sessionKey !== undefined) await teardownParkedBundle(sessionKey);\n\t});\n}\n\nexport default registerTerminalExtension;\n"]}
@@ -1,9 +1,11 @@
1
+ import type { ResumptionChannelEntry } from "../resumption-channel-event.ts";
1
2
  import { TerminalManager, type TerminalManagerOptions } from "./manager.ts";
2
3
  import { type MonitorEvent, MonitorRegistry, type MonitorSnapshotEntry } from "./monitor-registry.ts";
3
4
  import type { TerminalRuntimeSession } from "./runtime-session.ts";
4
5
  export interface TerminalEventSinks {
5
6
  readonly onMonitorEvent: (event: MonitorEvent) => void;
6
7
  readonly onMonitorState: (snapshot: readonly MonitorSnapshotEntry[]) => void;
8
+ readonly onBackgroundState: (snapshot: readonly ResumptionChannelEntry[]) => void;
7
9
  readonly onBackgroundExit: (id: string, runtime: TerminalRuntimeSession) => void;
8
10
  }
9
11
  /**
@@ -18,9 +20,11 @@ export declare class TerminalSessionBundle {
18
20
  readonly manager: TerminalManager;
19
21
  readonly monitors: MonitorRegistry;
20
22
  constructor(options: TerminalManagerOptions);
21
- /** Install live sinks, re-publish monitor state, and flush everything buffered while parked. */
23
+ /** Install live sinks, re-publish channel state, and flush everything buffered while parked. */
22
24
  bind(sinks: TerminalEventSinks): void;
23
25
  park(): void;
26
+ backgroundSnapshot(): readonly ResumptionChannelEntry[];
27
+ notifyBackgroundStart(id: string, description: string, startedAtMs?: number): void;
24
28
  notifyBackgroundExit(id: string, runtime: TerminalRuntimeSession): void;
25
29
  teardown(): Promise<void>;
26
30
  }
@@ -1 +1 @@
1
- {"version":3,"file":"session-bundle.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/session-bundle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAC5E,OAAO,EAAE,KAAK,YAAY,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AACtG,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEnE,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,cAAc,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IACvD,QAAQ,CAAC,cAAc,EAAE,CAAC,QAAQ,EAAE,SAAS,oBAAoB,EAAE,KAAK,IAAI,CAAC;IAC7E,QAAQ,CAAC,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAsB,KAAK,IAAI,CAAC;CACjF;AAKD;;;;;;GAMG;AACH,qBAAa,qBAAqB;;IACjC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IAMnC,YAAY,OAAO,EAAE,sBAAsB,EAK1C;IAED,gGAAgG;IAChG,IAAI,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI,CAUpC;IAED,IAAI,IAAI,IAAI,CAEX;IAED,oBAAoB,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAsB,GAAG,IAAI,CAQtE;IAEK,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAQ9B;CAWD;AAID,kGAAkG;AAClG,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAIjG;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,qBAAqB,GAAG,SAAS,CAIvF;AAED,wBAAsB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI5E"}
1
+ {"version":3,"file":"session-bundle.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/session-bundle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAC7E,OAAO,EAAE,eAAe,EAAE,KAAK,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAC5E,OAAO,EAAE,KAAK,YAAY,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AACtG,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEnE,MAAM,WAAW,kBAAkB;IAClC,QAAQ,CAAC,cAAc,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IACvD,QAAQ,CAAC,cAAc,EAAE,CAAC,QAAQ,EAAE,SAAS,oBAAoB,EAAE,KAAK,IAAI,CAAC;IAC7E,QAAQ,CAAC,iBAAiB,EAAE,CAAC,QAAQ,EAAE,SAAS,sBAAsB,EAAE,KAAK,IAAI,CAAC;IAClF,QAAQ,CAAC,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAsB,KAAK,IAAI,CAAC;CACjF;AAKD;;;;;;GAMG;AACH,qBAAa,qBAAqB;;IACjC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IAOnC,YAAY,OAAO,EAAE,sBAAsB,EAK1C;IAED,gGAAgG;IAChG,IAAI,CAAC,KAAK,EAAE,kBAAkB,GAAG,IAAI,CAWpC;IAED,IAAI,IAAI,IAAI,CAEX;IAED,kBAAkB,IAAI,SAAS,sBAAsB,EAAE,CAEtD;IAED,qBAAqB,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,SAAa,GAAG,IAAI,CAIrF;IAED,oBAAoB,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAsB,GAAG,IAAI,CAStE;IAEK,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAY9B;CAWD;AAID,kGAAkG;AAClG,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAIjG;AAED,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,qBAAqB,GAAG,SAAS,CAIvF;AAED,wBAAsB,oBAAoB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI5E"}
@@ -13,6 +13,7 @@ export class TerminalSessionBundle {
13
13
  #sinks = null;
14
14
  #parkedMonitorEvents = [];
15
15
  #parkedExits = new Map();
16
+ #backgrounds = new Map();
16
17
  #torndown = false;
17
18
  constructor(options) {
18
19
  this.manager = new TerminalManager(options);
@@ -20,7 +21,7 @@ export class TerminalSessionBundle {
20
21
  onChange: (snapshot) => this.#sinks?.onMonitorState(snapshot),
21
22
  });
22
23
  }
23
- /** Install live sinks, re-publish monitor state, and flush everything buffered while parked. */
24
+ /** Install live sinks, re-publish channel state, and flush everything buffered while parked. */
24
25
  bind(sinks) {
25
26
  if (this.#torndown)
26
27
  return;
@@ -30,6 +31,7 @@ export class TerminalSessionBundle {
30
31
  const parkedExits = [...this.#parkedExits];
31
32
  this.#parkedExits.clear();
32
33
  sinks.onMonitorState(this.monitors.snapshot());
34
+ sinks.onBackgroundState(this.backgroundSnapshot());
33
35
  for (const event of parkedMonitorEvents)
34
36
  sinks.onMonitorEvent(event);
35
37
  for (const [id, runtime] of parkedExits)
@@ -38,9 +40,20 @@ export class TerminalSessionBundle {
38
40
  park() {
39
41
  this.#sinks = null;
40
42
  }
43
+ backgroundSnapshot() {
44
+ return [...this.#backgrounds.values()];
45
+ }
46
+ notifyBackgroundStart(id, description, startedAtMs = Date.now()) {
47
+ if (this.#torndown)
48
+ return;
49
+ this.#backgrounds.set(id, { id, description, startedAtMs });
50
+ this.#sinks?.onBackgroundState(this.backgroundSnapshot());
51
+ }
41
52
  notifyBackgroundExit(id, runtime) {
42
53
  if (this.#torndown)
43
54
  return;
55
+ if (this.#backgrounds.delete(id))
56
+ this.#sinks?.onBackgroundState(this.backgroundSnapshot());
44
57
  if (this.#sinks) {
45
58
  this.#sinks.onBackgroundExit(id, runtime);
46
59
  return;
@@ -52,10 +65,14 @@ export class TerminalSessionBundle {
52
65
  async teardown() {
53
66
  if (this.#torndown)
54
67
  return;
55
- this.#torndown = true;
56
68
  this.#parkedMonitorEvents = [];
57
69
  this.#parkedExits.clear();
58
70
  this.monitors.dispose();
71
+ if (this.#backgrounds.size > 0) {
72
+ this.#backgrounds.clear();
73
+ this.#sinks?.onBackgroundState([]);
74
+ }
75
+ this.#torndown = true;
59
76
  this.#sinks = null;
60
77
  await this.manager.teardown();
61
78
  }
@@ -1 +1 @@
1
- {"version":3,"file":"session-bundle.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/session-bundle.ts"],"names":[],"mappings":"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","sourcesContent":["import { TerminalManager, type TerminalManagerOptions } from \"./manager.ts\";\nimport { type MonitorEvent, MonitorRegistry, type MonitorSnapshotEntry } from \"./monitor-registry.ts\";\nimport type { TerminalRuntimeSession } from \"./runtime-session.ts\";\n\nexport interface TerminalEventSinks {\n\treadonly onMonitorEvent: (event: MonitorEvent) => void;\n\treadonly onMonitorState: (snapshot: readonly MonitorSnapshotEntry[]) => void;\n\treadonly onBackgroundExit: (id: string, runtime: TerminalRuntimeSession) => void;\n}\n\nconst MAX_PARKED_MONITOR_EVENTS = 100;\nconst MAX_PARKED_EXITS = 32;\n\n/**\n * The long-lived terminal runtime for one agent session: the PTY session manager plus\n * the monitor registry. A session reload replaces the extension runner and re-runs the\n * extension factory, so this state must outlive any single extension instance; event\n * routing goes through mutable sinks the current owner instance binds. While parked\n * (the reload window, or a headless reload that never re-binds) events buffer bounded.\n */\nexport class TerminalSessionBundle {\n\treadonly manager: TerminalManager;\n\treadonly monitors: MonitorRegistry;\n\t#sinks: TerminalEventSinks | null = null;\n\t#parkedMonitorEvents: MonitorEvent[] = [];\n\t#parkedExits = new Map<string, TerminalRuntimeSession>();\n\t#torndown = false;\n\n\tconstructor(options: TerminalManagerOptions) {\n\t\tthis.manager = new TerminalManager(options);\n\t\tthis.monitors = new MonitorRegistry((event) => this.#dispatchMonitorEvent(event), {\n\t\t\tonChange: (snapshot) => this.#sinks?.onMonitorState(snapshot),\n\t\t});\n\t}\n\n\t/** Install live sinks, re-publish monitor state, and flush everything buffered while parked. */\n\tbind(sinks: TerminalEventSinks): void {\n\t\tif (this.#torndown) return;\n\t\tthis.#sinks = sinks;\n\t\tconst parkedMonitorEvents = this.#parkedMonitorEvents;\n\t\tthis.#parkedMonitorEvents = [];\n\t\tconst parkedExits = [...this.#parkedExits];\n\t\tthis.#parkedExits.clear();\n\t\tsinks.onMonitorState(this.monitors.snapshot());\n\t\tfor (const event of parkedMonitorEvents) sinks.onMonitorEvent(event);\n\t\tfor (const [id, runtime] of parkedExits) sinks.onBackgroundExit(id, runtime);\n\t}\n\n\tpark(): void {\n\t\tthis.#sinks = null;\n\t}\n\n\tnotifyBackgroundExit(id: string, runtime: TerminalRuntimeSession): void {\n\t\tif (this.#torndown) return;\n\t\tif (this.#sinks) {\n\t\t\tthis.#sinks.onBackgroundExit(id, runtime);\n\t\t\treturn;\n\t\t}\n\t\tif (this.#parkedExits.size >= MAX_PARKED_EXITS) return;\n\t\tthis.#parkedExits.set(id, runtime);\n\t}\n\n\tasync teardown(): Promise<void> {\n\t\tif (this.#torndown) return;\n\t\tthis.#torndown = true;\n\t\tthis.#parkedMonitorEvents = [];\n\t\tthis.#parkedExits.clear();\n\t\tthis.monitors.dispose();\n\t\tthis.#sinks = null;\n\t\tawait this.manager.teardown();\n\t}\n\n\t#dispatchMonitorEvent(event: MonitorEvent): void {\n\t\tif (this.#torndown) return;\n\t\tif (this.#sinks) {\n\t\t\tthis.#sinks.onMonitorEvent(event);\n\t\t\treturn;\n\t\t}\n\t\tthis.#parkedMonitorEvents.push(event);\n\t\tif (this.#parkedMonitorEvents.length > MAX_PARKED_MONITOR_EVENTS) this.#parkedMonitorEvents.shift();\n\t}\n}\n\nconst parkedBundles = new Map<string, TerminalSessionBundle>();\n\n/** Park a bundle across a reload; at most one parked bundle per session, older ones torn down. */\nexport async function parkBundle(sessionKey: string, bundle: TerminalSessionBundle): Promise<void> {\n\tconst previous = parkedBundles.get(sessionKey);\n\tparkedBundles.set(sessionKey, bundle);\n\tif (previous && previous !== bundle) await previous.teardown();\n}\n\nexport function claimParkedBundle(sessionKey: string): TerminalSessionBundle | undefined {\n\tconst bundle = parkedBundles.get(sessionKey);\n\tparkedBundles.delete(sessionKey);\n\treturn bundle;\n}\n\nexport async function teardownParkedBundle(sessionKey: string): Promise<void> {\n\tconst bundle = parkedBundles.get(sessionKey);\n\tparkedBundles.delete(sessionKey);\n\tawait bundle?.teardown();\n}\n"]}
1
+ {"version":3,"file":"session-bundle.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/session-bundle.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ResumptionChannelEntry } from \"../resumption-channel-event.ts\";\nimport { TerminalManager, type TerminalManagerOptions } from \"./manager.ts\";\nimport { type MonitorEvent, MonitorRegistry, type MonitorSnapshotEntry } from \"./monitor-registry.ts\";\nimport type { TerminalRuntimeSession } from \"./runtime-session.ts\";\n\nexport interface TerminalEventSinks {\n\treadonly onMonitorEvent: (event: MonitorEvent) => void;\n\treadonly onMonitorState: (snapshot: readonly MonitorSnapshotEntry[]) => void;\n\treadonly onBackgroundState: (snapshot: readonly ResumptionChannelEntry[]) => void;\n\treadonly onBackgroundExit: (id: string, runtime: TerminalRuntimeSession) => void;\n}\n\nconst MAX_PARKED_MONITOR_EVENTS = 100;\nconst MAX_PARKED_EXITS = 32;\n\n/**\n * The long-lived terminal runtime for one agent session: the PTY session manager plus\n * the monitor registry. A session reload replaces the extension runner and re-runs the\n * extension factory, so this state must outlive any single extension instance; event\n * routing goes through mutable sinks the current owner instance binds. While parked\n * (the reload window, or a headless reload that never re-binds) events buffer bounded.\n */\nexport class TerminalSessionBundle {\n\treadonly manager: TerminalManager;\n\treadonly monitors: MonitorRegistry;\n\t#sinks: TerminalEventSinks | null = null;\n\t#parkedMonitorEvents: MonitorEvent[] = [];\n\t#parkedExits = new Map<string, TerminalRuntimeSession>();\n\t#backgrounds = new Map<string, ResumptionChannelEntry>();\n\t#torndown = false;\n\n\tconstructor(options: TerminalManagerOptions) {\n\t\tthis.manager = new TerminalManager(options);\n\t\tthis.monitors = new MonitorRegistry((event) => this.#dispatchMonitorEvent(event), {\n\t\t\tonChange: (snapshot) => this.#sinks?.onMonitorState(snapshot),\n\t\t});\n\t}\n\n\t/** Install live sinks, re-publish channel state, and flush everything buffered while parked. */\n\tbind(sinks: TerminalEventSinks): void {\n\t\tif (this.#torndown) return;\n\t\tthis.#sinks = sinks;\n\t\tconst parkedMonitorEvents = this.#parkedMonitorEvents;\n\t\tthis.#parkedMonitorEvents = [];\n\t\tconst parkedExits = [...this.#parkedExits];\n\t\tthis.#parkedExits.clear();\n\t\tsinks.onMonitorState(this.monitors.snapshot());\n\t\tsinks.onBackgroundState(this.backgroundSnapshot());\n\t\tfor (const event of parkedMonitorEvents) sinks.onMonitorEvent(event);\n\t\tfor (const [id, runtime] of parkedExits) sinks.onBackgroundExit(id, runtime);\n\t}\n\n\tpark(): void {\n\t\tthis.#sinks = null;\n\t}\n\n\tbackgroundSnapshot(): readonly ResumptionChannelEntry[] {\n\t\treturn [...this.#backgrounds.values()];\n\t}\n\n\tnotifyBackgroundStart(id: string, description: string, startedAtMs = Date.now()): void {\n\t\tif (this.#torndown) return;\n\t\tthis.#backgrounds.set(id, { id, description, startedAtMs });\n\t\tthis.#sinks?.onBackgroundState(this.backgroundSnapshot());\n\t}\n\n\tnotifyBackgroundExit(id: string, runtime: TerminalRuntimeSession): void {\n\t\tif (this.#torndown) return;\n\t\tif (this.#backgrounds.delete(id)) this.#sinks?.onBackgroundState(this.backgroundSnapshot());\n\t\tif (this.#sinks) {\n\t\t\tthis.#sinks.onBackgroundExit(id, runtime);\n\t\t\treturn;\n\t\t}\n\t\tif (this.#parkedExits.size >= MAX_PARKED_EXITS) return;\n\t\tthis.#parkedExits.set(id, runtime);\n\t}\n\n\tasync teardown(): Promise<void> {\n\t\tif (this.#torndown) return;\n\t\tthis.#parkedMonitorEvents = [];\n\t\tthis.#parkedExits.clear();\n\t\tthis.monitors.dispose();\n\t\tif (this.#backgrounds.size > 0) {\n\t\t\tthis.#backgrounds.clear();\n\t\t\tthis.#sinks?.onBackgroundState([]);\n\t\t}\n\t\tthis.#torndown = true;\n\t\tthis.#sinks = null;\n\t\tawait this.manager.teardown();\n\t}\n\n\t#dispatchMonitorEvent(event: MonitorEvent): void {\n\t\tif (this.#torndown) return;\n\t\tif (this.#sinks) {\n\t\t\tthis.#sinks.onMonitorEvent(event);\n\t\t\treturn;\n\t\t}\n\t\tthis.#parkedMonitorEvents.push(event);\n\t\tif (this.#parkedMonitorEvents.length > MAX_PARKED_MONITOR_EVENTS) this.#parkedMonitorEvents.shift();\n\t}\n}\n\nconst parkedBundles = new Map<string, TerminalSessionBundle>();\n\n/** Park a bundle across a reload; at most one parked bundle per session, older ones torn down. */\nexport async function parkBundle(sessionKey: string, bundle: TerminalSessionBundle): Promise<void> {\n\tconst previous = parkedBundles.get(sessionKey);\n\tparkedBundles.set(sessionKey, bundle);\n\tif (previous && previous !== bundle) await previous.teardown();\n}\n\nexport function claimParkedBundle(sessionKey: string): TerminalSessionBundle | undefined {\n\tconst bundle = parkedBundles.get(sessionKey);\n\tparkedBundles.delete(sessionKey);\n\treturn bundle;\n}\n\nexport async function teardownParkedBundle(sessionKey: string): Promise<void> {\n\tconst bundle = parkedBundles.get(sessionKey);\n\tparkedBundles.delete(sessionKey);\n\tawait bundle?.teardown();\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/terminal/tools/bash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAWjE,OAAO,EAAe,KAAK,mBAAmB,EAAE,KAAK,kBAAkB,EAAc,MAAM,cAAc,CAAC;AAI1G,eAAO,MAAM,aAAa;;;;;;;EAiBxB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,aAAa,CAAC,CAAC;AAcxD,MAAM,WAAW,gBAAgB;IAChC,QAAQ,IAAI,IAAI,CAAC;IACjB,KAAK,IAAI,IAAI,CAAC;IACd,OAAO,IAAI,IAAI,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,IAAI,EAAE,UAAU,SAA0B,GAAG,gBAAgB,CA2C/G;AAID,KAAK,gBAAgB,GAAG;IACvB,cAAc,CAAC,EAAE;QAAE,YAAY,EAAE,MAAM,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IAC1F,KAAK,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AAyQF,mDAAmD;AACnD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,mBAAmB;;;;;;;;;;;;;;yBAU1C,MAAM,SACZ,YAAY,WACV,WAAW,aACT,uBAAuB,YACxB,gBAAgB,GACxB,OAAO,CAAC,kBAAkB,CAAC;EAQ/B"}
1
+ {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/terminal/tools/bash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAWjE,OAAO,EAAe,KAAK,mBAAmB,EAAE,KAAK,kBAAkB,EAAc,MAAM,cAAc,CAAC;AAM1G,eAAO,MAAM,aAAa;;;;;;;EAiBxB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,aAAa,CAAC,CAAC;AAcxD,MAAM,WAAW,gBAAgB;IAChC,QAAQ,IAAI,IAAI,CAAC;IACjB,KAAK,IAAI,IAAI,CAAC;IACd,OAAO,IAAI,IAAI,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,IAAI,EAAE,UAAU,SAA0B,GAAG,gBAAgB,CA2C/G;AAID,KAAK,gBAAgB,GAAG;IACvB,cAAc,CAAC,EAAE;QAAE,YAAY,EAAE,MAAM,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC;IAC1F,KAAK,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;CACb,CAAC;AA0RF,mDAAmD;AACnD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,mBAAmB;;;;;;;;;;;;;;yBAU1C,MAAM,SACZ,YAAY,WACV,WAAW,aACT,uBAAuB,YACxB,gBAAgB,GACxB,OAAO,CAAC,kBAAkB,CAAC;EAQ/B"}
@@ -3,11 +3,13 @@ import { formatTerminalToolOutput } from "../output-format.js";
3
3
  import { BACKGROUND_START_GRACE_MS, DEFAULT_COLS, DEFAULT_ROWS, FOREGROUND_ENV_OVERRIDES, KILLED_SESSION_EXIT_GRACE_MS, TERMINAL_BASH_TOOL, } from "../shared.js";
4
4
  import { errorResult, textResult } from "./context.js";
5
5
  import { createForegroundDetachGate } from "./foreground-detach.js";
6
+ import { resolveForegroundWindowSeconds, SLEEP_WAIT_WINDOW_SECONDS } from "./foreground-window.js";
7
+ import { classifySleepWait } from "./sleep-wait.js";
6
8
  import { describeExit, spawnCommandSession } from "./spawn.js";
7
9
  export const ptyBashSchema = Type.Object({
8
10
  command: Type.String({ description: "Shell command to execute in a PTY-backed session." }),
9
11
  timeout: Type.Optional(Type.Number({
10
- description: "Foreground kill deadline in seconds. Ignored for run_in_background sessions (they live until exit or kill_bash).",
12
+ description: "Process kill deadline in seconds (default 1800). Foreground blocking stops at the ~60s window: a command still running then auto-detaches to a live background session instead of being killed. Ignored for run_in_background sessions (they live until exit or kill_bash).",
11
13
  })),
12
14
  description: Type.Optional(Type.String({ description: "Short human-readable label for this command." })),
13
15
  run_in_background: Type.Optional(Type.Boolean({
@@ -134,16 +136,21 @@ function raceExitWithKillGrace(runtime, signal, timeoutMs) {
134
136
  }
135
137
  });
136
138
  }
137
- function resolveAutoDetachDelayMs(ctx, input) {
139
+ /**
140
+ * How long the model blocks before a still-running command is handed to a live
141
+ * background session. A sleep-wait detaches almost immediately: its remaining
142
+ * time is pure waiting, which the completion notification delivers for free.
143
+ */
144
+ function resolveAutoDetachDelayMs(ctx, input, sleepWait) {
138
145
  if (ctx.timeoutAction === "kill")
139
146
  return undefined;
140
- const budgetSeconds = ctx.getSessionContext?.()?.getPromptCacheSafeWaitSeconds?.();
141
- if (budgetSeconds === undefined || !Number.isFinite(budgetSeconds))
142
- return undefined;
147
+ const windowSeconds = sleepWait
148
+ ? Math.min(SLEEP_WAIT_WINDOW_SECONDS, resolveForegroundWindowSeconds(process.env))
149
+ : resolveForegroundWindowSeconds(process.env);
143
150
  const timeoutSeconds = input.timeout !== undefined && Number.isFinite(input.timeout) ? input.timeout : Infinity;
144
- if (timeoutSeconds <= budgetSeconds)
151
+ if (timeoutSeconds <= windowSeconds)
145
152
  return undefined;
146
- return Math.max(0, Math.trunc(budgetSeconds * 1000));
153
+ return Math.max(0, Math.trunc(windowSeconds * 1000));
147
154
  }
148
155
  function scheduleDetachedSweep(ctx, id, runtime, timeoutMs, startedAt) {
149
156
  if (timeoutMs === undefined)
@@ -193,7 +200,8 @@ async function runForeground(ctx, input, cols, rows, signal, cwd, onUpdate, exec
193
200
  const updateEmitter = onUpdate ? createThrottledEmitter(emitOutputUpdate) : undefined;
194
201
  onUpdate?.({ content: [], details: undefined });
195
202
  const unsubscribeOutput = onUpdate ? runtime.onOutput(() => updateEmitter?.schedule()) : undefined;
196
- const detachDelayMs = resolveAutoDetachDelayMs(ctx, input);
203
+ const sleepWait = classifySleepWait(input.command);
204
+ const detachDelayMs = resolveAutoDetachDelayMs(ctx, input, sleepWait);
197
205
  let outcome;
198
206
  if (detachDelayMs === undefined) {
199
207
  // Interrupt means "stop now": SIGKILL the whole process group in one shot.
@@ -250,6 +258,7 @@ async function runForeground(ctx, input, cols, rows, signal, cwd, onUpdate, exec
250
258
  }
251
259
  if (outcome === "detached") {
252
260
  scheduleDetachedSweep(ctx, id, runtime, timeoutMs, startedAt);
261
+ ctx.onBackgroundStart?.(id, input.description ?? input.command, startedAt);
253
262
  if (ctx.onBackgroundExit)
254
263
  runtime.session.onExit(() => ctx.onBackgroundExit?.(id, runtime));
255
264
  const delta = runtime.readDelta();
@@ -257,11 +266,15 @@ async function runForeground(ctx, input, cols, rows, signal, cwd, onUpdate, exec
257
266
  const timeoutNote = input.timeout !== undefined && Number.isFinite(input.timeout)
258
267
  ? `not killed; the original ${input.timeout}s timeout still applies`
259
268
  : "not killed; it will run until exit or kill_bash";
260
- return textResult(`Command is still running; auto-detached to background with ID: ${id} (${timeoutNote}).\n\nPartial output:\n${partialOutput}\n\nContinue other work; completion will be reported automatically with exit status and output tail. Use bash_output({ bash_id: "${id}" }) only to peek at new output. monitor cannot attach to this session; use it for future event-driven launches. Use kill_bash({ bash_id: "${id}" }) to stop this session.`, {
269
+ const guidance = sleepWait
270
+ ? `This command is a wait (${sleepWait.seconds}s sleep), so it detached immediately; the wait continues in the background. Do nothing and end your turn — completion will be reported automatically with exit status and output tail. Do NOT poll bash_output({ bash_id: "${id}" }) for it. When you are waiting for a pattern in a command's output, launch it with monitor({ command, filter }) instead so matching lines arrive as events. Use kill_bash({ bash_id: "${id}" }) to stop this session.`
271
+ : `Continue other work; completion will be reported automatically with exit status and output tail. Use bash_output({ bash_id: "${id}" }) only to peek at new output. monitor cannot attach to this session; use it for future event-driven launches. Use kill_bash({ bash_id: "${id}" }) to stop this session.`;
272
+ return textResult(`Command is still running; auto-detached to background with ID: ${id} (${timeoutNote}).\n\nPartial output:\n${partialOutput}\n\n${guidance}`, {
261
273
  details: {
262
274
  bash_id: id,
263
275
  background: true,
264
276
  auto_detached: true,
277
+ ...(sleepWait ? { sleep_wait: true } : {}),
265
278
  status: "running",
266
279
  ...(delta.droppedChars > 0 ? { droppedChars: delta.droppedChars } : {}),
267
280
  },
@@ -305,6 +318,7 @@ async function runBackground(ctx, input, cols, rows, cwd, execCtx) {
305
318
  cwd,
306
319
  envOverrides: sessionEnvOverrides(ctx, execCtx),
307
320
  });
321
+ ctx.onBackgroundStart?.(id, input.description ?? input.command, Date.now());
308
322
  if (ctx.onBackgroundExit)
309
323
  runtime.session.onExit(() => ctx.onBackgroundExit?.(id, runtime));
310
324
  // Capture any output the command emits within a short grace window (or its exit).
@@ -322,7 +336,7 @@ export function createPtyBashTool(ctx) {
322
336
  return {
323
337
  name: TERMINAL_BASH_TOOL,
324
338
  label: "bash",
325
- description: "Execute a shell command in a persistent PTY-backed session. Set run_in_background:true for long-lived or interactive sessions; steer them with bash_input, snapshot with bash_output, tear down with kill_bash. To wait on observable state (a build finishing, a server coming up, a log line), never run sleep or poll loops — subscribe with the monitor tool instead. Foreground timeout is a kill deadline in seconds.",
339
+ description: "Execute a shell command in a persistent PTY-backed session. Set run_in_background:true for long-lived or interactive sessions; steer them with bash_input, snapshot with bash_output, tear down with kill_bash. To wait on observable state (a build finishing, a server coming up, a log line), never run sleep or poll loops — subscribe with the monitor tool instead. Foreground blocking stops at the ~60s window and a still-running command auto-detaches to a live background session; `timeout` is the process kill deadline in seconds.",
326
340
  promptSnippet: "Run shell commands; run_in_background:true for long-lived/interactive PTY sessions",
327
341
  promptGuidelines: ["Inspect PI_* environment variables for current model and session details."],
328
342
  parameters: ptyBashSchema,