@code-yeongyu/senpi 2026.9.24-3 → 2026.9.25

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 (256) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/bundle/chunks/{app-server-command-OTRHYRIB.js → app-server-command-RB6QUPRI.js} +1 -1
  3. package/dist/bundle/chunks/{chunk-UM43CBL4.js → chunk-JJ3NJZBD.js} +118 -111
  4. package/dist/bundle/chunks/chunk-SGYEOIOJ.js +8 -0
  5. package/dist/bundle/chunks/chunk-YS5YEX4S.js +2 -0
  6. package/dist/bundle/chunks/{cli-main-TX6I4X4F.js → cli-main-KO53KYDN.js} +1 -1
  7. package/dist/bundle/chunks/{interactive-mode-UI5Q6FGY.js → interactive-mode-ABDNLJSI.js} +1 -1
  8. package/dist/bundle/chunks/{multi-session-host-D6HMI3RQ.js → multi-session-host-JV3MNWXZ.js} +1 -1
  9. package/dist/bundle/chunks/{package-manager-cli-3UWH3ZZS.js → package-manager-cli-ZYYAVCXU.js} +1 -1
  10. package/dist/bundle/chunks/{rpc-mode-LXIZHJSJ.js → rpc-mode-Q2OUJURB.js} +1 -1
  11. package/dist/bundle/chunks/runtime-session-XBT646O5.js +2 -0
  12. package/dist/bundle/chunks/session-worker.js +184 -177
  13. package/dist/bundle/cli.js +1 -1
  14. package/dist/bundle/index.js +1 -1
  15. package/dist/bundle/rpc-entry.js +1 -1
  16. package/dist/core/agent-session.d.ts.map +1 -1
  17. package/dist/core/agent-session.js +1 -1
  18. package/dist/core/agent-session.js.map +1 -1
  19. package/dist/core/extensions/builtin/cursor-cli-oauth/stream.d.ts +7 -0
  20. package/dist/core/extensions/builtin/cursor-cli-oauth/stream.d.ts.map +1 -1
  21. package/dist/core/extensions/builtin/cursor-cli-oauth/stream.js +23 -4
  22. package/dist/core/extensions/builtin/cursor-cli-oauth/stream.js.map +1 -1
  23. package/dist/core/extensions/builtin/terminal/durable-command.d.ts +11 -16
  24. package/dist/core/extensions/builtin/terminal/durable-command.d.ts.map +1 -1
  25. package/dist/core/extensions/builtin/terminal/durable-command.js +97 -43
  26. package/dist/core/extensions/builtin/terminal/durable-command.js.map +1 -1
  27. package/dist/core/extensions/builtin/terminal/durable-file.d.ts.map +1 -1
  28. package/dist/core/extensions/builtin/terminal/durable-file.js +11 -4
  29. package/dist/core/extensions/builtin/terminal/durable-file.js.map +1 -1
  30. package/dist/core/extensions/builtin/terminal/extension-state.d.ts +26 -0
  31. package/dist/core/extensions/builtin/terminal/extension-state.d.ts.map +1 -0
  32. package/dist/core/extensions/builtin/terminal/extension-state.js +151 -0
  33. package/dist/core/extensions/builtin/terminal/extension-state.js.map +1 -0
  34. package/dist/core/extensions/builtin/terminal/extension.d.ts.map +1 -1
  35. package/dist/core/extensions/builtin/terminal/extension.js +32 -308
  36. package/dist/core/extensions/builtin/terminal/extension.js.map +1 -1
  37. package/dist/core/extensions/builtin/terminal/lease-file.d.ts +52 -0
  38. package/dist/core/extensions/builtin/terminal/lease-file.d.ts.map +1 -0
  39. package/dist/core/extensions/builtin/terminal/lease-file.js +205 -0
  40. package/dist/core/extensions/builtin/terminal/lease-file.js.map +1 -0
  41. package/dist/core/extensions/builtin/terminal/lease-keeper.d.ts +33 -0
  42. package/dist/core/extensions/builtin/terminal/lease-keeper.d.ts.map +1 -0
  43. package/dist/core/extensions/builtin/terminal/lease-keeper.js +110 -0
  44. package/dist/core/extensions/builtin/terminal/lease-keeper.js.map +1 -0
  45. package/dist/core/extensions/builtin/terminal/manager.d.ts +1 -0
  46. package/dist/core/extensions/builtin/terminal/manager.d.ts.map +1 -1
  47. package/dist/core/extensions/builtin/terminal/manager.js +6 -0
  48. package/dist/core/extensions/builtin/terminal/manager.js.map +1 -1
  49. package/dist/core/extensions/builtin/terminal/manifest-lease.d.ts +48 -4
  50. package/dist/core/extensions/builtin/terminal/manifest-lease.d.ts.map +1 -1
  51. package/dist/core/extensions/builtin/terminal/manifest-lease.js +141 -59
  52. package/dist/core/extensions/builtin/terminal/manifest-lease.js.map +1 -1
  53. package/dist/core/extensions/builtin/terminal/monitor-registry.d.ts +2 -0
  54. package/dist/core/extensions/builtin/terminal/monitor-registry.d.ts.map +1 -1
  55. package/dist/core/extensions/builtin/terminal/monitor-registry.js +15 -10
  56. package/dist/core/extensions/builtin/terminal/monitor-registry.js.map +1 -1
  57. package/dist/core/extensions/builtin/terminal/monitor-state-dir.d.ts +11 -0
  58. package/dist/core/extensions/builtin/terminal/monitor-state-dir.d.ts.map +1 -0
  59. package/dist/core/extensions/builtin/terminal/monitor-state-dir.js +28 -0
  60. package/dist/core/extensions/builtin/terminal/monitor-state-dir.js.map +1 -0
  61. package/dist/core/extensions/builtin/terminal/orphan-reaper.d.ts +41 -0
  62. package/dist/core/extensions/builtin/terminal/orphan-reaper.d.ts.map +1 -0
  63. package/dist/core/extensions/builtin/terminal/orphan-reaper.js +131 -0
  64. package/dist/core/extensions/builtin/terminal/orphan-reaper.js.map +1 -0
  65. package/dist/core/extensions/builtin/terminal/process-identity.d.ts +21 -0
  66. package/dist/core/extensions/builtin/terminal/process-identity.d.ts.map +1 -0
  67. package/dist/core/extensions/builtin/terminal/process-identity.js +34 -0
  68. package/dist/core/extensions/builtin/terminal/process-identity.js.map +1 -0
  69. package/dist/core/extensions/builtin/terminal/process-start-probe.d.ts +6 -0
  70. package/dist/core/extensions/builtin/terminal/process-start-probe.d.ts.map +1 -0
  71. package/dist/core/extensions/builtin/terminal/process-start-probe.js +60 -0
  72. package/dist/core/extensions/builtin/terminal/process-start-probe.js.map +1 -0
  73. package/dist/core/extensions/builtin/terminal/prompt.d.ts.map +1 -1
  74. package/dist/core/extensions/builtin/terminal/prompt.js +8 -4
  75. package/dist/core/extensions/builtin/terminal/prompt.js.map +1 -1
  76. package/dist/core/extensions/builtin/terminal/restore-digest.d.ts +54 -0
  77. package/dist/core/extensions/builtin/terminal/restore-digest.d.ts.map +1 -0
  78. package/dist/core/extensions/builtin/terminal/restore-digest.js +133 -0
  79. package/dist/core/extensions/builtin/terminal/restore-digest.js.map +1 -0
  80. package/dist/core/extensions/builtin/terminal/restore-session.d.ts +56 -0
  81. package/dist/core/extensions/builtin/terminal/restore-session.d.ts.map +1 -0
  82. package/dist/core/extensions/builtin/terminal/restore-session.js +238 -0
  83. package/dist/core/extensions/builtin/terminal/restore-session.js.map +1 -0
  84. package/dist/core/extensions/builtin/terminal/restore.d.ts +52 -19
  85. package/dist/core/extensions/builtin/terminal/restore.d.ts.map +1 -1
  86. package/dist/core/extensions/builtin/terminal/restore.js +63 -138
  87. package/dist/core/extensions/builtin/terminal/restore.js.map +1 -1
  88. package/dist/core/extensions/builtin/terminal/runtime-session.d.ts +5 -0
  89. package/dist/core/extensions/builtin/terminal/runtime-session.d.ts.map +1 -1
  90. package/dist/core/extensions/builtin/terminal/runtime-session.js +17 -0
  91. package/dist/core/extensions/builtin/terminal/runtime-session.js.map +1 -1
  92. package/dist/core/extensions/builtin/terminal/session-activity.d.ts +8 -0
  93. package/dist/core/extensions/builtin/terminal/session-activity.d.ts.map +1 -0
  94. package/dist/core/extensions/builtin/terminal/session-activity.js +41 -0
  95. package/dist/core/extensions/builtin/terminal/session-activity.js.map +1 -0
  96. package/dist/core/extensions/builtin/terminal/shared.d.ts +14 -0
  97. package/dist/core/extensions/builtin/terminal/shared.d.ts.map +1 -1
  98. package/dist/core/extensions/builtin/terminal/shared.js +14 -0
  99. package/dist/core/extensions/builtin/terminal/shared.js.map +1 -1
  100. package/dist/core/extensions/builtin/terminal/terminal-manifest-model.d.ts +8 -0
  101. package/dist/core/extensions/builtin/terminal/terminal-manifest-model.d.ts.map +1 -1
  102. package/dist/core/extensions/builtin/terminal/terminal-manifest-model.js.map +1 -1
  103. package/dist/core/extensions/builtin/terminal/terminal-manifest-parse.d.ts +15 -0
  104. package/dist/core/extensions/builtin/terminal/terminal-manifest-parse.d.ts.map +1 -0
  105. package/dist/core/extensions/builtin/terminal/terminal-manifest-parse.js +148 -0
  106. package/dist/core/extensions/builtin/terminal/terminal-manifest-parse.js.map +1 -0
  107. package/dist/core/extensions/builtin/terminal/terminal-manifest.d.ts +15 -2
  108. package/dist/core/extensions/builtin/terminal/terminal-manifest.d.ts.map +1 -1
  109. package/dist/core/extensions/builtin/terminal/terminal-manifest.js +62 -11
  110. package/dist/core/extensions/builtin/terminal/terminal-manifest.js.map +1 -1
  111. package/dist/core/extensions/builtin/terminal/terminal-state-gc.d.ts +17 -0
  112. package/dist/core/extensions/builtin/terminal/terminal-state-gc.d.ts.map +1 -0
  113. package/dist/core/extensions/builtin/terminal/terminal-state-gc.js +81 -0
  114. package/dist/core/extensions/builtin/terminal/terminal-state-gc.js.map +1 -0
  115. package/dist/core/extensions/builtin/terminal/tools/context.d.ts +5 -0
  116. package/dist/core/extensions/builtin/terminal/tools/context.d.ts.map +1 -1
  117. package/dist/core/extensions/builtin/terminal/tools/context.js.map +1 -1
  118. package/dist/core/extensions/builtin/terminal/tools/kill-bash.d.ts.map +1 -1
  119. package/dist/core/extensions/builtin/terminal/tools/kill-bash.js +16 -1
  120. package/dist/core/extensions/builtin/terminal/tools/kill-bash.js.map +1 -1
  121. package/dist/core/extensions/builtin/terminal/tools/monitor-manifest-binding.d.ts +27 -0
  122. package/dist/core/extensions/builtin/terminal/tools/monitor-manifest-binding.d.ts.map +1 -0
  123. package/dist/core/extensions/builtin/terminal/tools/monitor-manifest-binding.js +75 -0
  124. package/dist/core/extensions/builtin/terminal/tools/monitor-manifest-binding.js.map +1 -0
  125. package/dist/core/extensions/builtin/terminal/tools/monitor-schema.d.ts +35 -0
  126. package/dist/core/extensions/builtin/terminal/tools/monitor-schema.d.ts.map +1 -0
  127. package/dist/core/extensions/builtin/terminal/tools/monitor-schema.js +67 -0
  128. package/dist/core/extensions/builtin/terminal/tools/monitor-schema.js.map +1 -0
  129. package/dist/core/extensions/builtin/terminal/tools/monitor.d.ts +14 -35
  130. package/dist/core/extensions/builtin/terminal/tools/monitor.d.ts.map +1 -1
  131. package/dist/core/extensions/builtin/terminal/tools/monitor.js +30 -110
  132. package/dist/core/extensions/builtin/terminal/tools/monitor.js.map +1 -1
  133. package/dist/core/extensions/builtin/todotools/first-turn.d.ts +7 -6
  134. package/dist/core/extensions/builtin/todotools/first-turn.d.ts.map +1 -1
  135. package/dist/core/extensions/builtin/todotools/first-turn.js +8 -8
  136. package/dist/core/extensions/builtin/todotools/first-turn.js.map +1 -1
  137. package/dist/core/extensions/builtin/todotools/index.js +1 -1
  138. package/dist/core/extensions/builtin/todotools/index.js.map +1 -1
  139. package/dist/core/extensions/builtin/todotools/todo-format.js +1 -1
  140. package/dist/core/extensions/builtin/todotools/todo-format.js.map +1 -1
  141. package/dist/core/extensions/builtin/ttsr/detectors/repetitive-turns.d.ts.map +1 -1
  142. package/dist/core/extensions/builtin/ttsr/detectors/repetitive-turns.js +4 -0
  143. package/dist/core/extensions/builtin/ttsr/detectors/repetitive-turns.js.map +1 -1
  144. package/dist/core/extensions/builtin/ttsr/prompts.js +1 -1
  145. package/dist/core/extensions/builtin/ttsr/prompts.js.map +1 -1
  146. package/dist/core/extensions/runner.d.ts +1 -0
  147. package/dist/core/extensions/runner.d.ts.map +1 -1
  148. package/dist/core/extensions/runner.js +1 -0
  149. package/dist/core/extensions/runner.js.map +1 -1
  150. package/dist/core/extensions/types.d.ts +6 -0
  151. package/dist/core/extensions/types.d.ts.map +1 -1
  152. package/dist/core/extensions/types.js.map +1 -1
  153. package/docs/extensions.md +2 -0
  154. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +12 -0
  155. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
  156. package/node_modules/@code-yeongyu/senpi-desktop-engine/README.md +31 -0
  157. package/node_modules/@code-yeongyu/senpi-desktop-engine/dist/handshake.d.ts +38 -0
  158. package/node_modules/@code-yeongyu/senpi-desktop-engine/dist/handshake.d.ts.map +1 -0
  159. package/node_modules/@code-yeongyu/senpi-desktop-engine/dist/handshake.js +117 -0
  160. package/node_modules/@code-yeongyu/senpi-desktop-engine/dist/handshake.js.map +1 -0
  161. package/node_modules/@code-yeongyu/senpi-desktop-engine/dist/index.d.ts +3 -0
  162. package/node_modules/@code-yeongyu/senpi-desktop-engine/dist/index.d.ts.map +1 -0
  163. package/node_modules/@code-yeongyu/senpi-desktop-engine/dist/index.js +3 -0
  164. package/node_modules/@code-yeongyu/senpi-desktop-engine/dist/index.js.map +1 -0
  165. package/node_modules/@code-yeongyu/senpi-desktop-engine/dist/locator.d.ts +42 -0
  166. package/node_modules/@code-yeongyu/senpi-desktop-engine/dist/locator.d.ts.map +1 -0
  167. package/node_modules/@code-yeongyu/senpi-desktop-engine/dist/locator.js +79 -0
  168. package/node_modules/@code-yeongyu/senpi-desktop-engine/dist/locator.js.map +1 -0
  169. package/node_modules/@code-yeongyu/senpi-desktop-engine/native/check-prebuild-fresh.mjs +160 -0
  170. package/node_modules/@code-yeongyu/senpi-desktop-engine/native/index.d.ts +20 -0
  171. package/node_modules/@code-yeongyu/senpi-desktop-engine/native/index.js +23 -0
  172. package/node_modules/@code-yeongyu/senpi-desktop-engine/native/prebuilds/darwin-arm64/senpi-desktop-engine +0 -0
  173. package/node_modules/@code-yeongyu/senpi-desktop-engine/package.json +53 -0
  174. package/node_modules/@code-yeongyu/senpi-desktop-prelude/README.md +20 -0
  175. package/node_modules/@code-yeongyu/senpi-desktop-prelude/dist/index.d.ts +2 -0
  176. package/node_modules/@code-yeongyu/senpi-desktop-prelude/dist/index.d.ts.map +1 -0
  177. package/node_modules/@code-yeongyu/senpi-desktop-prelude/dist/index.js +2 -0
  178. package/node_modules/@code-yeongyu/senpi-desktop-prelude/dist/index.js.map +1 -0
  179. package/node_modules/@code-yeongyu/senpi-desktop-prelude/package.json +44 -0
  180. package/node_modules/@code-yeongyu/senpi-desktop-protocol/README.md +20 -0
  181. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/audit.d.ts +38 -0
  182. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/audit.d.ts.map +1 -0
  183. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/audit.js +2 -0
  184. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/audit.js.map +1 -0
  185. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/call.d.ts +28 -0
  186. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/call.d.ts.map +1 -0
  187. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/call.js +102 -0
  188. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/call.js.map +1 -0
  189. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/engine-schema.generated.d.ts +14 -0
  190. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/engine-schema.generated.d.ts.map +1 -0
  191. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/engine-schema.generated.js +71 -0
  192. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/engine-schema.generated.js.map +1 -0
  193. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/index.d.ts +7 -0
  194. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/index.d.ts.map +1 -0
  195. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/index.js +4 -0
  196. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/index.js.map +1 -0
  197. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/json-rpc.d.ts +66 -0
  198. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/json-rpc.d.ts.map +1 -0
  199. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/json-rpc.js +8 -0
  200. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/json-rpc.js.map +1 -0
  201. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/session.d.ts +44 -0
  202. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/session.d.ts.map +1 -0
  203. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/session.js +2 -0
  204. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/session.js.map +1 -0
  205. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/wire.d.ts +59 -0
  206. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/wire.d.ts.map +1 -0
  207. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/wire.js +2 -0
  208. package/node_modules/@code-yeongyu/senpi-desktop-protocol/dist/wire.js.map +1 -0
  209. package/node_modules/@code-yeongyu/senpi-desktop-protocol/package.json +45 -0
  210. package/node_modules/@code-yeongyu/senpi-desktop-service/README.md +27 -0
  211. package/node_modules/@code-yeongyu/senpi-desktop-service/dist/index.d.ts +2 -0
  212. package/node_modules/@code-yeongyu/senpi-desktop-service/dist/index.d.ts.map +1 -0
  213. package/node_modules/@code-yeongyu/senpi-desktop-service/dist/index.js +2 -0
  214. package/node_modules/@code-yeongyu/senpi-desktop-service/dist/index.js.map +1 -0
  215. package/node_modules/@code-yeongyu/senpi-desktop-service/package.json +44 -0
  216. package/node_modules/@code-yeongyu/senpi-desktop-tool/README.md +20 -0
  217. package/node_modules/@code-yeongyu/senpi-desktop-tool/dist/index.d.ts +2 -0
  218. package/node_modules/@code-yeongyu/senpi-desktop-tool/dist/index.d.ts.map +1 -0
  219. package/node_modules/@code-yeongyu/senpi-desktop-tool/dist/index.js +2 -0
  220. package/node_modules/@code-yeongyu/senpi-desktop-tool/dist/index.js.map +1 -0
  221. package/node_modules/@code-yeongyu/senpi-desktop-tool/package.json +44 -0
  222. package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
  223. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  224. package/node_modules/@earendil-works/pi-ai/dist/providers/data/cerebras.json +1 -1
  225. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  226. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  227. package/node_modules/@earendil-works/pi-ai/package.json +2 -2
  228. package/node_modules/@earendil-works/pi-pty/dist/pipe-fallback.d.ts +2 -0
  229. package/node_modules/@earendil-works/pi-pty/dist/pipe-fallback.d.ts.map +1 -1
  230. package/node_modules/@earendil-works/pi-pty/dist/pipe-fallback.js +6 -0
  231. package/node_modules/@earendil-works/pi-pty/dist/pipe-fallback.js.map +1 -1
  232. package/node_modules/@earendil-works/pi-pty/dist/session-bun.d.ts +1 -0
  233. package/node_modules/@earendil-works/pi-pty/dist/session-bun.d.ts.map +1 -1
  234. package/node_modules/@earendil-works/pi-pty/dist/session-bun.js +1 -0
  235. package/node_modules/@earendil-works/pi-pty/dist/session-bun.js.map +1 -1
  236. package/node_modules/@earendil-works/pi-pty/dist/session-native.js +5 -0
  237. package/node_modules/@earendil-works/pi-pty/dist/session-native.js.map +1 -1
  238. package/node_modules/@earendil-works/pi-pty/dist/session-raw-tail.d.ts +11 -0
  239. package/node_modules/@earendil-works/pi-pty/dist/session-raw-tail.d.ts.map +1 -0
  240. package/node_modules/@earendil-works/pi-pty/dist/session-raw-tail.js +24 -0
  241. package/node_modules/@earendil-works/pi-pty/dist/session-raw-tail.js.map +1 -0
  242. package/node_modules/@earendil-works/pi-pty/dist/session-types.d.ts +2 -0
  243. package/node_modules/@earendil-works/pi-pty/dist/session-types.d.ts.map +1 -1
  244. package/node_modules/@earendil-works/pi-pty/dist/session-types.js.map +1 -1
  245. package/node_modules/@earendil-works/pi-pty/dist/session.d.ts +4 -5
  246. package/node_modules/@earendil-works/pi-pty/dist/session.d.ts.map +1 -1
  247. package/node_modules/@earendil-works/pi-pty/dist/session.js +11 -16
  248. package/node_modules/@earendil-works/pi-pty/dist/session.js.map +1 -1
  249. package/node_modules/@earendil-works/pi-pty/native/prebuilds/darwin-arm64/senpi_pty.darwin-arm64.node +0 -0
  250. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  251. package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
  252. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  253. package/package.json +22 -7
  254. package/dist/bundle/chunks/chunk-GFUZPFHN.js +0 -2
  255. package/dist/bundle/chunks/chunk-JBOV6VNK.js +0 -8
  256. package/dist/bundle/chunks/runtime-session-F3EXC44D.js +0 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal-manifest-parse.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/terminal-manifest-parse.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The terminal manifest's strict fail-closed parse: every field is checked, unknown keys are\n * ignored (so optional additions never need a version bump), and any malformed value throws\n * InvalidTerminalManifestError so a restore fails closed instead of guessing.\n */\n\nimport { InvalidSidecarStoreError, type SidecarStoreRef } from \"../../../session-sidecar-store.ts\";\nimport type { ChildProcessIdentity } from \"./process-identity.ts\";\nimport {\n\ttype ManifestBackgroundSession,\n\ttype ManifestMonitor,\n\tTERMINAL_MANIFEST_VERSION,\n\ttype TerminalManifest,\n\ttype TerminalManifestCheckpoint,\n} from \"./terminal-manifest-model.ts\";\n\nexport class InvalidTerminalManifestError extends InvalidSidecarStoreError {\n\tconstructor(message: string, options?: { cause?: unknown }) {\n\t\tsuper(message, options);\n\t\tthis.name = \"InvalidTerminalManifestError\";\n\t}\n}\n\ntype Raw = Record<string, unknown>;\n\nconst RUNTIME_KINDS = [\"command\", \"file\"] as const;\nconst DURABILITY_CLASSES = [\"ephemeral\", \"restartable-command\", \"checkpointed-file\"] as const;\nconst FILE_EVENTS = [\"create\", \"modify\"] as const;\nconst isStr = (value: unknown): value is string => typeof value === \"string\" && value.length > 0;\nconst isNum = (value: unknown): value is number => typeof value === \"number\" && Number.isFinite(value);\nconst isBool = (value: unknown): value is boolean => typeof value === \"boolean\";\nconst isObj = (value: unknown): value is Raw => typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nfunction invalid(message: string): never {\n\tthrow new InvalidTerminalManifestError(`terminal manifest is invalid: ${message}`);\n}\n\nfunction str(raw: Raw, field: string): string {\n\tif (!isStr(raw[field])) invalid(`field ${field} must be a non-empty string`);\n\treturn raw[field];\n}\n\nfunction num(raw: Raw, field: string): number {\n\tif (!isNum(raw[field])) invalid(`field ${field} must be a finite number`);\n\treturn raw[field];\n}\n\nfunction digest(raw: Raw, field: string): string {\n\tif (typeof raw[field] !== \"string\") invalid(`field ${field} must be a string`);\n\treturn raw[field];\n}\n\nfunction bool(raw: Raw, field: string): boolean {\n\tif (!isBool(raw[field])) invalid(`field ${field} must be a boolean`);\n\treturn raw[field];\n}\n\nfunction opt<T>(raw: Raw, field: string, required: (raw: Raw, field: string) => T): T | undefined {\n\treturn raw[field] === undefined ? undefined : required(raw, field);\n}\n\nfunction oneOf<T extends string>(values: readonly T[], raw: Raw, field: string): T {\n\tconst value = raw[field];\n\tif (typeof value !== \"string\" || !values.includes(value as T))\n\t\tinvalid(`field ${field} must be one of: ${values.join(\", \")}`);\n\treturn value as T;\n}\n\nfunction checkpoint(raw: unknown): TerminalManifestCheckpoint {\n\tif (!isObj(raw)) invalid(\"field lastCheckpoint must be an object\");\n\treturn {\n\t\tdev: num(raw, \"dev\"),\n\t\tino: num(raw, \"ino\"),\n\t\tsize: num(raw, \"size\"),\n\t\tmtimeMs: num(raw, \"mtimeMs\"),\n\t\t// A checkpoint without a digest cannot detect a same-size, same-mtime rewrite, so the field is\n\t\t// required — but an absent file legitimately checkpoints an empty digest, so \"\" is valid.\n\t\tdigest: digest(raw, \"digest\"),\n\t\tpresent: bool(raw, \"present\"),\n\t};\n}\n\nfunction fireWindow(raw: unknown): { startMs: number; count: number } {\n\tif (!isObj(raw)) invalid(\"field fireWindow must be an object\");\n\treturn { startMs: num(raw, \"startMs\"), count: num(raw, \"count\") };\n}\n\nfunction runtimeIdentity(raw: Raw, field: string): ChildProcessIdentity {\n\tconst value = raw[field];\n\tif (!isObj(value)) invalid(`field ${field} must be an object`);\n\tconst argv = value.argv;\n\tif (!Array.isArray(argv) || !argv.every(isStr)) invalid(`field ${field}.argv must be an array of strings`);\n\tconst pid = value.pid;\n\tif (!isNum(pid)) invalid(`field ${field}.pid must be a finite number`);\n\tconst groupId = value.processGroupId;\n\tif (groupId !== undefined && !isNum(groupId)) invalid(`field ${field}.processGroupId must be a finite number`);\n\treturn {\n\t\tpid,\n\t\t...(groupId !== undefined ? { processGroupId: groupId } : {}),\n\t\tstartedAtMs: num(value, \"startedAtMs\"),\n\t\tbootAtMs: num(value, \"bootAtMs\"),\n\t\targv,\n\t};\n}\n\nfunction parseMonitor(entry: unknown): ManifestMonitor {\n\tif (!isObj(entry)) invalid(\"a monitor entry must be an object\");\n\treturn {\n\t\tmonitorId: str(entry, \"monitorId\"),\n\t\tsessionId: str(entry, \"sessionId\"),\n\t\tdescription: str(entry, \"description\"),\n\t\truntimeKind: oneOf(RUNTIME_KINDS, entry, \"runtimeKind\"),\n\t\tdurabilityClass: oneOf(DURABILITY_CLASSES, entry, \"durabilityClass\"),\n\t\tcommand: opt(entry, \"command\", str),\n\t\tpath: opt(entry, \"path\", str),\n\t\tevent: opt(entry, \"event\", (raw, field) => oneOf(FILE_EVENTS, raw, field)),\n\t\tfilter: opt(entry, \"filter\", str),\n\t\tcwd: opt(entry, \"cwd\", str),\n\t\tapprovedParent: opt(entry, \"approvedParent\", str),\n\t\tcreatedAt: num(entry, \"createdAt\"),\n\t\texpiresAt: entry.expiresAt === undefined || entry.expiresAt === null ? null : num(entry, \"expiresAt\"),\n\t\tpersistent: bool(entry, \"persistent\"),\n\t\tsuspended: bool(entry, \"suspended\"),\n\t\tlastCheckpoint: entry.lastCheckpoint === null ? null : checkpoint(entry.lastCheckpoint),\n\t\tdeliveryPaused: bool(entry, \"deliveryPaused\"),\n\t\t// Unknown keys are ignored by this field-by-field parse, so a manifest written before\n\t\t// `wakeCount` was dropped still reads back cleanly; no version bump is needed. The same\n\t\t// rule makes `runtime` / `deadlineMs` optional additions that v1 readers skip.\n\t\tfireWindow: fireWindow(entry.fireWindow),\n\t\t...(entry.runtime === undefined ? {} : { runtime: runtimeIdentity(entry, \"runtime\") }),\n\t\t...(entry.deadlineMs === undefined ? {} : { deadlineMs: num(entry, \"deadlineMs\") }),\n\t};\n}\n\nfunction parseBackgroundSession(entry: unknown): ManifestBackgroundSession {\n\tif (!isObj(entry)) invalid(\"a background session entry must be an object\");\n\treturn {\n\t\tid: str(entry, \"id\"),\n\t\tcommand: str(entry, \"command\"),\n\t\tstartedAtMs: num(entry, \"startedAtMs\"),\n\t\t...(entry.runtime === undefined ? {} : { runtime: runtimeIdentity(entry, \"runtime\") }),\n\t};\n}\n\n/** Strict fail-closed domain parse; the sidecar store has already checked version and session. */\nexport function parseTerminalManifest(raw: unknown, ref: SidecarStoreRef): TerminalManifest {\n\tif (!isObj(raw)) invalid(\"the payload must be an object\");\n\tif (!Array.isArray(raw.monitors)) invalid(\"field monitors must be an array\");\n\tif (!Array.isArray(raw.backgroundSessions)) invalid(\"field backgroundSessions must be an array\");\n\treturn {\n\t\tversion: TERMINAL_MANIFEST_VERSION,\n\t\tsessionId: ref.sessionId,\n\t\tmonitors: raw.monitors.map(parseMonitor),\n\t\tbackgroundSessions: raw.backgroundSessions.map(parseBackgroundSession),\n\t\tupdatedAt: num(raw, \"updatedAt\"),\n\t};\n}\n"]}
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import { type SidecarStore } from "../../../session-sidecar-store.ts";
7
7
  import type { MonitorSnapshotEntry } from "./monitor-registry.ts";
8
- import { type ManifestMonitor, type MonitorRegistration, type TerminalManifest, type TerminalManifestCheckpoint, type TerminalManifestSession } from "./terminal-manifest-model.ts";
8
+ import { type ManifestBackgroundSession, type ManifestMonitor, type MonitorRegistration, type TerminalManifest, type TerminalManifestCheckpoint, type TerminalManifestSession } from "./terminal-manifest-model.ts";
9
9
  export type { CommandMonitorSpec, FileMonitorSpec, ManifestBackgroundSession, ManifestMonitor, MonitorDurabilityClass, MonitorRegistration, MonitorRuntimeKind, MonitorSpec, TerminalManifest, TerminalManifestCheckpoint, TerminalManifestSession, } from "./terminal-manifest-model.ts";
10
10
  export { DURABLE_MONITOR_EXPIRY_MS, TERMINAL_MANIFEST_CHECKPOINT_DEBOUNCE_MS, TERMINAL_MANIFEST_VERSION, } from "./terminal-manifest-model.ts";
11
11
  export declare function createTerminalManifestStore(session: TerminalManifestSession): SidecarStore<TerminalManifest>;
@@ -37,6 +37,19 @@ export declare class TerminalManifestWriter {
37
37
  * restart costs zero extra writes and the write-on-transition invariant holds.
38
38
  */
39
39
  adoptRestored(entry: ManifestMonitor): void;
40
+ /**
41
+ * Write the post-restore truth once: re-spawned watches carry their new runtime identity (so
42
+ * the NEXT crash stops them instead of starting copies), and entries that did not come back
43
+ * are gone (so they are never re-run). With nothing left, the manifest file is removed.
44
+ */
45
+ persistRestored(): Promise<void>;
46
+ /**
47
+ * Reload seam (SF-2): a reload generation starts with an empty writer, and its first
48
+ * transition would rewrite the manifest without the entries the previous generation
49
+ * recorded. Seed the live (non-suspended) entries and background sessions from disk
50
+ * without writing; a corrupt or absent manifest seeds nothing.
51
+ */
52
+ seedFromDisk(): Promise<void>;
40
53
  /**
41
54
  * Live durable-monitor count for admission control: entries that survive a restart.
42
55
  * Ephemeral entries are never counted, so any number of one-shot watches can coexist
@@ -56,7 +69,7 @@ export declare class TerminalManifestWriter {
56
69
  flush(): Promise<void>;
57
70
  /** Shutdown transition: flush checkpoints and mark every live monitor suspended in one write. */
58
71
  recordShutdown(): Promise<void>;
59
- recordBackgroundStart(id: string, command: string, startedAtMs?: number): Promise<void>;
72
+ recordBackgroundStart(id: string, command: string, startedAtMs?: number, runtime?: ManifestBackgroundSession["runtime"]): Promise<void>;
60
73
  recordBackgroundExit(id: string): Promise<void>;
61
74
  }
62
75
  //# sourceMappingURL=terminal-manifest.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"terminal-manifest.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/terminal-manifest.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAC1F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAGlE,OAAO,EAEN,KAAK,eAAe,EACpB,KAAK,mBAAmB,EAGxB,KAAK,gBAAgB,EACrB,KAAK,0BAA0B,EAC/B,KAAK,uBAAuB,EAC5B,MAAM,8BAA8B,CAAC;AAEtC,YAAY,EACX,kBAAkB,EAClB,eAAe,EACf,yBAAyB,EACzB,eAAe,EACf,sBAAsB,EACtB,mBAAmB,EACnB,kBAAkB,EAClB,WAAW,EACX,gBAAgB,EAChB,0BAA0B,EAC1B,uBAAuB,GACvB,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EACN,yBAAyB,EACzB,wCAAwC,EACxC,yBAAyB,GACzB,MAAM,8BAA8B,CAAC;AAEtC,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,uBAAuB,GAAG,YAAY,CAAC,gBAAgB,CAAC,CAQ5G;AAED,qBAAa,sBAAsB;;IAClC,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC,gBAAgB,CAAC,CAAC;IAS/C,6GAA6G;IAC7G,cAAc,EAAE,OAAO,CAAC;IAExB,YAAY,OAAO,EAAE;QAAE,OAAO,EAAE,uBAAuB,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;KAAE,EAKjG;IAED,cAAc,CAAC,YAAY,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAG/D;IAED;;;;;;;;;;;;;;;OAeG;IACH,aAAa,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,CAE1C;IAED;;;;OAIG;IACH,YAAY,IAAI,MAAM,CAIrB;IAED;;;;;OAKG;IACH,mBAAmB,CAAC,QAAQ,EAAE,SAAS,oBAAoB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA4B5E;IAED,wFAAwF;IACxF,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,0BAA0B,GAAG,IAAI,CAQlF;IAED,4EAA4E;IACtE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAU3B;IACD,iGAAiG;IAC3F,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAQpC;IAED,qBAAqB,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGtF;IAED,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE9C;CA6DD"}
1
+ {"version":3,"file":"terminal-manifest.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/terminal-manifest.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAC1F,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAElE,OAAO,EACN,KAAK,yBAAyB,EAC9B,KAAK,eAAe,EACpB,KAAK,mBAAmB,EAGxB,KAAK,gBAAgB,EACrB,KAAK,0BAA0B,EAC/B,KAAK,uBAAuB,EAC5B,MAAM,8BAA8B,CAAC;AAGtC,YAAY,EACX,kBAAkB,EAClB,eAAe,EACf,yBAAyB,EACzB,eAAe,EACf,sBAAsB,EACtB,mBAAmB,EACnB,kBAAkB,EAClB,WAAW,EACX,gBAAgB,EAChB,0BAA0B,EAC1B,uBAAuB,GACvB,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EACN,yBAAyB,EACzB,wCAAwC,EACxC,yBAAyB,GACzB,MAAM,8BAA8B,CAAC;AAEtC,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,uBAAuB,GAAG,YAAY,CAAC,gBAAgB,CAAC,CAQ5G;AAED,qBAAa,sBAAsB;;IAClC,QAAQ,CAAC,KAAK,EAAE,YAAY,CAAC,gBAAgB,CAAC,CAAC;IAS/C,6GAA6G;IAC7G,cAAc,EAAE,OAAO,CAAC;IAExB,YAAY,OAAO,EAAE;QAAE,OAAO,EAAE,uBAAuB,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;KAAE,EAKjG;IAED,cAAc,CAAC,YAAY,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAG/D;IAED;;;;;;;;;;;;;;;OAeG;IACH,aAAa,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,CAE1C;IAED;;;;OAIG;IACH,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAE/B;IAED;;;;;OAKG;IACG,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAUlC;IAED;;;;OAIG;IACH,YAAY,IAAI,MAAM,CAIrB;IAED;;;;;OAKG;IACH,mBAAmB,CAAC,QAAQ,EAAE,SAAS,oBAAoB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA4B5E;IAED,wFAAwF;IACxF,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,0BAA0B,GAAG,IAAI,CAQlF;IAED,4EAA4E;IACtE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAU3B;IACD,iGAAiG;IAC3F,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAQpC;IAED,qBAAqB,CACpB,EAAE,EAAE,MAAM,EACV,OAAO,EAAE,MAAM,EACf,WAAW,CAAC,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,yBAAyB,CAAC,SAAS,CAAC,GAC5C,OAAO,CAAC,IAAI,CAAC,CAQf;IAED,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE9C;CA2ED"}
@@ -3,11 +3,12 @@
3
3
  * persisting ONLY lifecycle transitions and debounced checkpoints of the record shaped in
4
4
  * `terminal-manifest-model.ts` — never per-line output and never a runtime handle.
5
5
  */
6
+ import { unlink } from "node:fs/promises";
6
7
  import { join } from "node:path";
7
8
  import { createSidecarStore } from "../../../session-sidecar-store.js";
8
- import { parseTerminalManifest } from "./restore.js";
9
9
  import { DURABLE_MONITOR_EXPIRY_MS } from "./shared.js";
10
10
  import { TERMINAL_MANIFEST_CHECKPOINT_DEBOUNCE_MS, TERMINAL_MANIFEST_VERSION, } from "./terminal-manifest-model.js";
11
+ import { parseTerminalManifest } from "./terminal-manifest-parse.js";
11
12
  // The data model is re-exported so every importer keeps this module as the manifest's single
12
13
  // entry point; nothing outside had to learn the model module's path.
13
14
  export { DURABLE_MONITOR_EXPIRY_MS, TERMINAL_MANIFEST_CHECKPOINT_DEBOUNCE_MS, TERMINAL_MANIFEST_VERSION, } from "./terminal-manifest-model.js";
@@ -58,6 +59,36 @@ export class TerminalManifestWriter {
58
59
  adoptRestored(entry) {
59
60
  this.#entries.set(entry.monitorId, { ...entry, suspended: false });
60
61
  }
62
+ /**
63
+ * Write the post-restore truth once: re-spawned watches carry their new runtime identity (so
64
+ * the NEXT crash stops them instead of starting copies), and entries that did not come back
65
+ * are gone (so they are never re-run). With nothing left, the manifest file is removed.
66
+ */
67
+ persistRestored() {
68
+ return this.#persist();
69
+ }
70
+ /**
71
+ * Reload seam (SF-2): a reload generation starts with an empty writer, and its first
72
+ * transition would rewrite the manifest without the entries the previous generation
73
+ * recorded. Seed the live (non-suspended) entries and background sessions from disk
74
+ * without writing; a corrupt or absent manifest seeds nothing.
75
+ */
76
+ async seedFromDisk() {
77
+ let state;
78
+ try {
79
+ state = await this.store.read();
80
+ }
81
+ catch {
82
+ return;
83
+ }
84
+ if (state === null)
85
+ return;
86
+ for (const entry of state.monitors)
87
+ if (!entry.suspended)
88
+ this.#entries.set(entry.monitorId, entry);
89
+ for (const background of state.backgroundSessions)
90
+ this.#backgrounds.set(background.id, background);
91
+ }
61
92
  /**
62
93
  * Live durable-monitor count for admission control: entries that survive a restart.
63
94
  * Ephemeral entries are never counted, so any number of one-shot watches can coexist
@@ -139,8 +170,13 @@ export class TerminalManifestWriter {
139
170
  this.#entries.set(monitorId, { ...entry, suspended: true });
140
171
  await this.#persist();
141
172
  }
142
- recordBackgroundStart(id, command, startedAtMs) {
143
- this.#backgrounds.set(id, { id, command, startedAtMs: startedAtMs ?? this.#now() });
173
+ recordBackgroundStart(id, command, startedAtMs, runtime) {
174
+ this.#backgrounds.set(id, {
175
+ id,
176
+ command,
177
+ startedAtMs: startedAtMs ?? this.#now(),
178
+ ...(runtime === undefined ? {} : { runtime }),
179
+ });
144
180
  return this.#persist();
145
181
  }
146
182
  recordBackgroundExit(id) {
@@ -154,7 +190,7 @@ export class TerminalManifestWriter {
154
190
  }
155
191
  this.#pending.clear();
156
192
  }
157
- #entryFor({ monitorId, spec }) {
193
+ #entryFor({ monitorId, spec, runtime, deadlineMs }) {
158
194
  const createdAt = this.#now();
159
195
  // A spec that omits `persistent` is ephemeral: the persisted field is a boolean the
160
196
  // strict parse rejects as undefined, so coerce here rather than trusting the caller.
@@ -185,16 +221,31 @@ export class TerminalManifestWriter {
185
221
  lastCheckpoint: null,
186
222
  deliveryPaused: false,
187
223
  fireWindow: { startMs: createdAt, count: 0 },
224
+ ...(runtime === undefined ? {} : { runtime }),
225
+ ...(deadlineMs === undefined || persistent ? {} : { deadlineMs }),
188
226
  };
189
227
  }
228
+ /** An empty manifest carries no state worth a file: unlink instead of writing `{[],[]}`. */
229
+ async #removeFile() {
230
+ try {
231
+ await unlink(this.store.filePath);
232
+ }
233
+ catch (error) {
234
+ if (!(typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT"))
235
+ throw error;
236
+ }
237
+ this.store.clear();
238
+ }
190
239
  #persist() {
191
- const run = this.#tail.then(() => this.store.write({
192
- version: TERMINAL_MANIFEST_VERSION,
193
- sessionId: this.#sessionId,
194
- monitors: [...this.#entries.values()],
195
- backgroundSessions: [...this.#backgrounds.values()],
196
- updatedAt: this.#now(),
197
- }));
240
+ const run = this.#tail.then(() => this.#entries.size === 0 && this.#backgrounds.size === 0
241
+ ? this.#removeFile()
242
+ : this.store.write({
243
+ version: TERMINAL_MANIFEST_VERSION,
244
+ sessionId: this.#sessionId,
245
+ monitors: [...this.#entries.values()],
246
+ backgroundSessions: [...this.#backgrounds.values()],
247
+ updatedAt: this.#now(),
248
+ }));
198
249
  this.#tail = run.then(() => undefined, (error) => {
199
250
  this.persistFailure = error;
200
251
  });
@@ -1 +1 @@
1
- {"version":3,"file":"terminal-manifest.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/terminal-manifest.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The manifest write side: `createTerminalManifestStore` plus `TerminalManifestWriter`,\n * persisting ONLY lifecycle transitions and debounced checkpoints of the record shaped in\n * `terminal-manifest-model.ts` — never per-line output and never a runtime handle.\n */\n\nimport { join } from \"node:path\";\nimport { createSidecarStore, type SidecarStore } from \"../../../session-sidecar-store.ts\";\nimport type { MonitorSnapshotEntry } from \"./monitor-registry.ts\";\nimport { parseTerminalManifest } from \"./restore.ts\";\nimport { DURABLE_MONITOR_EXPIRY_MS } from \"./shared.ts\";\nimport {\n\ttype ManifestBackgroundSession,\n\ttype ManifestMonitor,\n\ttype MonitorRegistration,\n\tTERMINAL_MANIFEST_CHECKPOINT_DEBOUNCE_MS,\n\tTERMINAL_MANIFEST_VERSION,\n\ttype TerminalManifest,\n\ttype TerminalManifestCheckpoint,\n\ttype TerminalManifestSession,\n} from \"./terminal-manifest-model.ts\";\n\nexport type {\n\tCommandMonitorSpec,\n\tFileMonitorSpec,\n\tManifestBackgroundSession,\n\tManifestMonitor,\n\tMonitorDurabilityClass,\n\tMonitorRegistration,\n\tMonitorRuntimeKind,\n\tMonitorSpec,\n\tTerminalManifest,\n\tTerminalManifestCheckpoint,\n\tTerminalManifestSession,\n} from \"./terminal-manifest-model.ts\";\n// The data model is re-exported so every importer keeps this module as the manifest's single\n// entry point; nothing outside had to learn the model module's path.\nexport {\n\tDURABLE_MONITOR_EXPIRY_MS,\n\tTERMINAL_MANIFEST_CHECKPOINT_DEBOUNCE_MS,\n\tTERMINAL_MANIFEST_VERSION,\n} from \"./terminal-manifest-model.ts\";\n\nexport function createTerminalManifestStore(session: TerminalManifestSession): SidecarStore<TerminalManifest> {\n\treturn createSidecarStore({\n\t\tbaseDir: join(session.getSessionDir(), \"extensions\", \"terminal\"),\n\t\tsessionId: session.getSessionId(),\n\t\tversion: TERMINAL_MANIFEST_VERSION,\n\t\ttempPrefix: \"terminal\",\n\t\tparse: parseTerminalManifest,\n\t});\n}\n\nexport class TerminalManifestWriter {\n\treadonly store: SidecarStore<TerminalManifest>;\n\treadonly #sessionId: string;\n\treadonly #debounceMs: number;\n\treadonly #now: () => number;\n\treadonly #entries = new Map<string, ManifestMonitor>();\n\treadonly #backgrounds = new Map<string, ManifestBackgroundSession>();\n\treadonly #pending = new Map<string, TerminalManifestCheckpoint>();\n\t#timer: ReturnType<typeof setTimeout> | undefined;\n\t#tail: Promise<void> = Promise.resolve();\n\t/** Last persist failure: transitions never reject, so a durability write can never fail a live tool call. */\n\tpersistFailure: unknown;\n\n\tconstructor(options: { session: TerminalManifestSession; debounceMs?: number; now?: () => number }) {\n\t\tthis.store = createTerminalManifestStore(options.session);\n\t\tthis.#sessionId = options.session.getSessionId();\n\t\tthis.#debounceMs = options.debounceMs ?? TERMINAL_MANIFEST_CHECKPOINT_DEBOUNCE_MS;\n\t\tthis.#now = options.now ?? Date.now;\n\t}\n\n\trecordRegister(registration: MonitorRegistration): Promise<void> {\n\t\tthis.#entries.set(registration.monitorId, this.#entryFor(registration));\n\t\treturn this.#persist();\n\t}\n\n\t/**\n\t * Re-adopt an entry a restore handler just brought back to life, so THIS generation's\n\t * in-memory map owns it again. Without this, the writer starts every generation empty and\n\t * the next persist (a register, a background start, a checkpoint flush, recordShutdown)\n\t * rewrites the manifest WITHOUT the restored monitors — the monitor survives one restart\n\t * and is erased on the second.\n\t *\n\t * Every persisted field is preserved verbatim, notably `createdAt` and `expiresAt`: the\n\t * durability deadline is set once at registration and a restore NEVER extends it. Only\n\t * `suspended` is cleared, because the monitor is live again in this process.\n\t *\n\t * Deliberately does NOT write: re-adoption is not a state transition, it is recovery of\n\t * state already on disk. The entry reaches the file again on the restore's own next\n\t * persist (the file class's checkpoint, any later transition, or recordShutdown), so a\n\t * restart costs zero extra writes and the write-on-transition invariant holds.\n\t */\n\tadoptRestored(entry: ManifestMonitor): void {\n\t\tthis.#entries.set(entry.monitorId, { ...entry, suspended: false });\n\t}\n\n\t/**\n\t * Live durable-monitor count for admission control: entries that survive a restart.\n\t * Ephemeral entries are never counted, so any number of one-shot watches can coexist\n\t * with the durable ones.\n\t */\n\tdurableCount(): number {\n\t\tlet count = 0;\n\t\tfor (const entry of this.#entries.values()) if (entry.durabilityClass !== \"ephemeral\") count += 1;\n\t\treturn count;\n\t}\n\n\t/**\n\t * Reconcile a registry transition snapshot (the bundle's single onChange consumer\n\t * forwards it here): settle removes entries, pause/resume/rearm flips deliveryPaused.\n\t * An entry missing its stable monitorId throws — never silently skipped; entries not\n\t * registered through the tool call site are left alone (durability spec unknown).\n\t */\n\tobserveMonitorState(snapshot: readonly MonitorSnapshotEntry[]): Promise<void> {\n\t\tconst live = new Map<string, { paused: boolean; fireWindow?: MonitorSnapshotEntry[\"fireWindow\"] }>();\n\t\tfor (const entry of snapshot) {\n\t\t\tif (typeof entry.monitorId !== \"string\" || entry.monitorId.length === 0) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`terminal manifest writer saw a monitor snapshot entry without a stable monitorId (runtime id ${entry.id}); surfacing instead of silently skipping it`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tlive.set(entry.monitorId, { paused: entry.paused, fireWindow: entry.fireWindow });\n\t\t}\n\t\tlet changed = false;\n\t\tfor (const [monitorId, known] of this.#entries) {\n\t\t\tconst current = live.get(monitorId);\n\t\t\tif (current === undefined) {\n\t\t\t\tif (known.suspended) continue; // shutdown-suspended entries are expected to be absent\n\t\t\t\tthis.#entries.delete(monitorId); // settle: the registry transitioned it out\n\t\t\t\tchanged = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// The live fire window rides every state transition — notably the auto-mute pause —\n\t\t\t// so a restart re-binds the burned budget instead of a fresh one.\n\t\t\tconst fireWindow = current.fireWindow ?? known.fireWindow;\n\t\t\tif (known.deliveryPaused !== current.paused || known.fireWindow.count !== fireWindow.count) {\n\t\t\t\tthis.#entries.set(monitorId, { ...known, deliveryPaused: current.paused, fireWindow });\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\t\treturn changed ? this.#persist() : Promise.resolve();\n\t}\n\n\t/** Debounced checkpoint persist: a burst inside the window collapses into one write. */\n\tscheduleCheckpoint(monitorId: string, checkpoint: TerminalManifestCheckpoint): void {\n\t\tthis.#pending.set(monitorId, checkpoint);\n\t\tif (this.#timer !== undefined) clearTimeout(this.#timer);\n\t\tthis.#timer = setTimeout(() => {\n\t\t\tthis.#timer = undefined;\n\t\t\tthis.#absorbPending();\n\t\t\tvoid this.#persist();\n\t\t}, this.#debounceMs);\n\t}\n\n\t/** Drain: apply any pending checkpoints and await every in-flight write. */\n\tasync flush(): Promise<void> {\n\t\tif (this.#timer !== undefined) {\n\t\t\tclearTimeout(this.#timer);\n\t\t\tthis.#timer = undefined;\n\t\t}\n\t\tif (this.#pending.size === 0) await this.#tail;\n\t\telse {\n\t\t\tthis.#absorbPending();\n\t\t\tawait this.#persist();\n\t\t}\n\t}\n\t/** Shutdown transition: flush checkpoints and mark every live monitor suspended in one write. */\n\tasync recordShutdown(): Promise<void> {\n\t\tif (this.#timer !== undefined) {\n\t\t\tclearTimeout(this.#timer);\n\t\t\tthis.#timer = undefined;\n\t\t}\n\t\tthis.#absorbPending();\n\t\tfor (const [monitorId, entry] of this.#entries) this.#entries.set(monitorId, { ...entry, suspended: true });\n\t\tawait this.#persist();\n\t}\n\n\trecordBackgroundStart(id: string, command: string, startedAtMs?: number): Promise<void> {\n\t\tthis.#backgrounds.set(id, { id, command, startedAtMs: startedAtMs ?? this.#now() });\n\t\treturn this.#persist();\n\t}\n\n\trecordBackgroundExit(id: string): Promise<void> {\n\t\treturn this.#backgrounds.delete(id) ? this.#persist() : Promise.resolve();\n\t}\n\t#absorbPending(): void {\n\t\tfor (const [monitorId, checkpoint] of this.#pending) {\n\t\t\tconst entry = this.#entries.get(monitorId);\n\t\t\tif (entry) this.#entries.set(monitorId, { ...entry, lastCheckpoint: checkpoint });\n\t\t}\n\t\tthis.#pending.clear();\n\t}\n\n\t#entryFor({ monitorId, spec }: MonitorRegistration): ManifestMonitor {\n\t\tconst createdAt = this.#now();\n\t\t// A spec that omits `persistent` is ephemeral: the persisted field is a boolean the\n\t\t// strict parse rejects as undefined, so coerce here rather than trusting the caller.\n\t\tconst persistent = spec.persistent === true;\n\t\treturn {\n\t\t\tmonitorId,\n\t\t\tsessionId: this.#sessionId,\n\t\t\tdescription: spec.description,\n\t\t\truntimeKind: spec.kind,\n\t\t\tdurabilityClass: !persistent\n\t\t\t\t? \"ephemeral\"\n\t\t\t\t: spec.kind === \"file\"\n\t\t\t\t\t? \"checkpointed-file\"\n\t\t\t\t\t: \"restartable-command\",\n\t\t\tcommand: spec.kind === \"command\" ? spec.command : undefined,\n\t\t\tpath: spec.kind === \"file\" ? spec.path : undefined,\n\t\t\tevent: spec.kind === \"file\" ? spec.event : undefined,\n\t\t\tfilter: spec.kind === \"command\" ? spec.filter : undefined,\n\t\t\tcwd: spec.cwd,\n\t\t\tapprovedParent: spec.kind === \"file\" ? spec.approvedParent : undefined,\n\t\t\tcreatedAt,\n\t\t\t// Absolute durability deadline for every restart-surviving entry, set once here and\n\t\t\t// never extended by a restore or a rearm. An ephemeral entry dies with the process,\n\t\t\t// so its runtime deadline stays the registry's business, not the manifest's.\n\t\t\texpiresAt: persistent ? createdAt + DURABLE_MONITOR_EXPIRY_MS : null,\n\t\t\tpersistent,\n\t\t\tsuspended: false,\n\t\t\tlastCheckpoint: null,\n\t\t\tdeliveryPaused: false,\n\t\t\tfireWindow: { startMs: createdAt, count: 0 },\n\t\t};\n\t}\n\n\t#persist(): Promise<void> {\n\t\tconst run = this.#tail.then(() =>\n\t\t\tthis.store.write({\n\t\t\t\tversion: TERMINAL_MANIFEST_VERSION,\n\t\t\t\tsessionId: this.#sessionId,\n\t\t\t\tmonitors: [...this.#entries.values()],\n\t\t\t\tbackgroundSessions: [...this.#backgrounds.values()],\n\t\t\t\tupdatedAt: this.#now(),\n\t\t\t}),\n\t\t);\n\t\tthis.#tail = run.then(\n\t\t\t() => undefined,\n\t\t\t(error) => {\n\t\t\t\tthis.persistFailure = error;\n\t\t\t},\n\t\t);\n\t\treturn this.#tail;\n\t}\n}\n"]}
1
+ {"version":3,"file":"terminal-manifest.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/terminal-manifest.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The manifest write side: `createTerminalManifestStore` plus `TerminalManifestWriter`,\n * persisting ONLY lifecycle transitions and debounced checkpoints of the record shaped in\n * `terminal-manifest-model.ts` — never per-line output and never a runtime handle.\n */\n\nimport { unlink } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { createSidecarStore, type SidecarStore } from \"../../../session-sidecar-store.ts\";\nimport type { MonitorSnapshotEntry } from \"./monitor-registry.ts\";\nimport { DURABLE_MONITOR_EXPIRY_MS } from \"./shared.ts\";\nimport {\n\ttype ManifestBackgroundSession,\n\ttype ManifestMonitor,\n\ttype MonitorRegistration,\n\tTERMINAL_MANIFEST_CHECKPOINT_DEBOUNCE_MS,\n\tTERMINAL_MANIFEST_VERSION,\n\ttype TerminalManifest,\n\ttype TerminalManifestCheckpoint,\n\ttype TerminalManifestSession,\n} from \"./terminal-manifest-model.ts\";\nimport { parseTerminalManifest } from \"./terminal-manifest-parse.ts\";\n\nexport type {\n\tCommandMonitorSpec,\n\tFileMonitorSpec,\n\tManifestBackgroundSession,\n\tManifestMonitor,\n\tMonitorDurabilityClass,\n\tMonitorRegistration,\n\tMonitorRuntimeKind,\n\tMonitorSpec,\n\tTerminalManifest,\n\tTerminalManifestCheckpoint,\n\tTerminalManifestSession,\n} from \"./terminal-manifest-model.ts\";\n// The data model is re-exported so every importer keeps this module as the manifest's single\n// entry point; nothing outside had to learn the model module's path.\nexport {\n\tDURABLE_MONITOR_EXPIRY_MS,\n\tTERMINAL_MANIFEST_CHECKPOINT_DEBOUNCE_MS,\n\tTERMINAL_MANIFEST_VERSION,\n} from \"./terminal-manifest-model.ts\";\n\nexport function createTerminalManifestStore(session: TerminalManifestSession): SidecarStore<TerminalManifest> {\n\treturn createSidecarStore({\n\t\tbaseDir: join(session.getSessionDir(), \"extensions\", \"terminal\"),\n\t\tsessionId: session.getSessionId(),\n\t\tversion: TERMINAL_MANIFEST_VERSION,\n\t\ttempPrefix: \"terminal\",\n\t\tparse: parseTerminalManifest,\n\t});\n}\n\nexport class TerminalManifestWriter {\n\treadonly store: SidecarStore<TerminalManifest>;\n\treadonly #sessionId: string;\n\treadonly #debounceMs: number;\n\treadonly #now: () => number;\n\treadonly #entries = new Map<string, ManifestMonitor>();\n\treadonly #backgrounds = new Map<string, ManifestBackgroundSession>();\n\treadonly #pending = new Map<string, TerminalManifestCheckpoint>();\n\t#timer: ReturnType<typeof setTimeout> | undefined;\n\t#tail: Promise<void> = Promise.resolve();\n\t/** Last persist failure: transitions never reject, so a durability write can never fail a live tool call. */\n\tpersistFailure: unknown;\n\n\tconstructor(options: { session: TerminalManifestSession; debounceMs?: number; now?: () => number }) {\n\t\tthis.store = createTerminalManifestStore(options.session);\n\t\tthis.#sessionId = options.session.getSessionId();\n\t\tthis.#debounceMs = options.debounceMs ?? TERMINAL_MANIFEST_CHECKPOINT_DEBOUNCE_MS;\n\t\tthis.#now = options.now ?? Date.now;\n\t}\n\n\trecordRegister(registration: MonitorRegistration): Promise<void> {\n\t\tthis.#entries.set(registration.monitorId, this.#entryFor(registration));\n\t\treturn this.#persist();\n\t}\n\n\t/**\n\t * Re-adopt an entry a restore handler just brought back to life, so THIS generation's\n\t * in-memory map owns it again. Without this, the writer starts every generation empty and\n\t * the next persist (a register, a background start, a checkpoint flush, recordShutdown)\n\t * rewrites the manifest WITHOUT the restored monitors — the monitor survives one restart\n\t * and is erased on the second.\n\t *\n\t * Every persisted field is preserved verbatim, notably `createdAt` and `expiresAt`: the\n\t * durability deadline is set once at registration and a restore NEVER extends it. Only\n\t * `suspended` is cleared, because the monitor is live again in this process.\n\t *\n\t * Deliberately does NOT write: re-adoption is not a state transition, it is recovery of\n\t * state already on disk. The entry reaches the file again on the restore's own next\n\t * persist (the file class's checkpoint, any later transition, or recordShutdown), so a\n\t * restart costs zero extra writes and the write-on-transition invariant holds.\n\t */\n\tadoptRestored(entry: ManifestMonitor): void {\n\t\tthis.#entries.set(entry.monitorId, { ...entry, suspended: false });\n\t}\n\n\t/**\n\t * Write the post-restore truth once: re-spawned watches carry their new runtime identity (so\n\t * the NEXT crash stops them instead of starting copies), and entries that did not come back\n\t * are gone (so they are never re-run). With nothing left, the manifest file is removed.\n\t */\n\tpersistRestored(): Promise<void> {\n\t\treturn this.#persist();\n\t}\n\n\t/**\n\t * Reload seam (SF-2): a reload generation starts with an empty writer, and its first\n\t * transition would rewrite the manifest without the entries the previous generation\n\t * recorded. Seed the live (non-suspended) entries and background sessions from disk\n\t * without writing; a corrupt or absent manifest seeds nothing.\n\t */\n\tasync seedFromDisk(): Promise<void> {\n\t\tlet state: TerminalManifest | null;\n\t\ttry {\n\t\t\tstate = await this.store.read();\n\t\t} catch {\n\t\t\treturn;\n\t\t}\n\t\tif (state === null) return;\n\t\tfor (const entry of state.monitors) if (!entry.suspended) this.#entries.set(entry.monitorId, entry);\n\t\tfor (const background of state.backgroundSessions) this.#backgrounds.set(background.id, background);\n\t}\n\n\t/**\n\t * Live durable-monitor count for admission control: entries that survive a restart.\n\t * Ephemeral entries are never counted, so any number of one-shot watches can coexist\n\t * with the durable ones.\n\t */\n\tdurableCount(): number {\n\t\tlet count = 0;\n\t\tfor (const entry of this.#entries.values()) if (entry.durabilityClass !== \"ephemeral\") count += 1;\n\t\treturn count;\n\t}\n\n\t/**\n\t * Reconcile a registry transition snapshot (the bundle's single onChange consumer\n\t * forwards it here): settle removes entries, pause/resume/rearm flips deliveryPaused.\n\t * An entry missing its stable monitorId throws — never silently skipped; entries not\n\t * registered through the tool call site are left alone (durability spec unknown).\n\t */\n\tobserveMonitorState(snapshot: readonly MonitorSnapshotEntry[]): Promise<void> {\n\t\tconst live = new Map<string, { paused: boolean; fireWindow?: MonitorSnapshotEntry[\"fireWindow\"] }>();\n\t\tfor (const entry of snapshot) {\n\t\t\tif (typeof entry.monitorId !== \"string\" || entry.monitorId.length === 0) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`terminal manifest writer saw a monitor snapshot entry without a stable monitorId (runtime id ${entry.id}); surfacing instead of silently skipping it`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tlive.set(entry.monitorId, { paused: entry.paused, fireWindow: entry.fireWindow });\n\t\t}\n\t\tlet changed = false;\n\t\tfor (const [monitorId, known] of this.#entries) {\n\t\t\tconst current = live.get(monitorId);\n\t\t\tif (current === undefined) {\n\t\t\t\tif (known.suspended) continue; // shutdown-suspended entries are expected to be absent\n\t\t\t\tthis.#entries.delete(monitorId); // settle: the registry transitioned it out\n\t\t\t\tchanged = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// The live fire window rides every state transition — notably the auto-mute pause —\n\t\t\t// so a restart re-binds the burned budget instead of a fresh one.\n\t\t\tconst fireWindow = current.fireWindow ?? known.fireWindow;\n\t\t\tif (known.deliveryPaused !== current.paused || known.fireWindow.count !== fireWindow.count) {\n\t\t\t\tthis.#entries.set(monitorId, { ...known, deliveryPaused: current.paused, fireWindow });\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\t\treturn changed ? this.#persist() : Promise.resolve();\n\t}\n\n\t/** Debounced checkpoint persist: a burst inside the window collapses into one write. */\n\tscheduleCheckpoint(monitorId: string, checkpoint: TerminalManifestCheckpoint): void {\n\t\tthis.#pending.set(monitorId, checkpoint);\n\t\tif (this.#timer !== undefined) clearTimeout(this.#timer);\n\t\tthis.#timer = setTimeout(() => {\n\t\t\tthis.#timer = undefined;\n\t\t\tthis.#absorbPending();\n\t\t\tvoid this.#persist();\n\t\t}, this.#debounceMs);\n\t}\n\n\t/** Drain: apply any pending checkpoints and await every in-flight write. */\n\tasync flush(): Promise<void> {\n\t\tif (this.#timer !== undefined) {\n\t\t\tclearTimeout(this.#timer);\n\t\t\tthis.#timer = undefined;\n\t\t}\n\t\tif (this.#pending.size === 0) await this.#tail;\n\t\telse {\n\t\t\tthis.#absorbPending();\n\t\t\tawait this.#persist();\n\t\t}\n\t}\n\t/** Shutdown transition: flush checkpoints and mark every live monitor suspended in one write. */\n\tasync recordShutdown(): Promise<void> {\n\t\tif (this.#timer !== undefined) {\n\t\t\tclearTimeout(this.#timer);\n\t\t\tthis.#timer = undefined;\n\t\t}\n\t\tthis.#absorbPending();\n\t\tfor (const [monitorId, entry] of this.#entries) this.#entries.set(monitorId, { ...entry, suspended: true });\n\t\tawait this.#persist();\n\t}\n\n\trecordBackgroundStart(\n\t\tid: string,\n\t\tcommand: string,\n\t\tstartedAtMs?: number,\n\t\truntime?: ManifestBackgroundSession[\"runtime\"],\n\t): Promise<void> {\n\t\tthis.#backgrounds.set(id, {\n\t\t\tid,\n\t\t\tcommand,\n\t\t\tstartedAtMs: startedAtMs ?? this.#now(),\n\t\t\t...(runtime === undefined ? {} : { runtime }),\n\t\t});\n\t\treturn this.#persist();\n\t}\n\n\trecordBackgroundExit(id: string): Promise<void> {\n\t\treturn this.#backgrounds.delete(id) ? this.#persist() : Promise.resolve();\n\t}\n\t#absorbPending(): void {\n\t\tfor (const [monitorId, checkpoint] of this.#pending) {\n\t\t\tconst entry = this.#entries.get(monitorId);\n\t\t\tif (entry) this.#entries.set(monitorId, { ...entry, lastCheckpoint: checkpoint });\n\t\t}\n\t\tthis.#pending.clear();\n\t}\n\n\t#entryFor({ monitorId, spec, runtime, deadlineMs }: MonitorRegistration): ManifestMonitor {\n\t\tconst createdAt = this.#now();\n\t\t// A spec that omits `persistent` is ephemeral: the persisted field is a boolean the\n\t\t// strict parse rejects as undefined, so coerce here rather than trusting the caller.\n\t\tconst persistent = spec.persistent === true;\n\t\treturn {\n\t\t\tmonitorId,\n\t\t\tsessionId: this.#sessionId,\n\t\t\tdescription: spec.description,\n\t\t\truntimeKind: spec.kind,\n\t\t\tdurabilityClass: !persistent\n\t\t\t\t? \"ephemeral\"\n\t\t\t\t: spec.kind === \"file\"\n\t\t\t\t\t? \"checkpointed-file\"\n\t\t\t\t\t: \"restartable-command\",\n\t\t\tcommand: spec.kind === \"command\" ? spec.command : undefined,\n\t\t\tpath: spec.kind === \"file\" ? spec.path : undefined,\n\t\t\tevent: spec.kind === \"file\" ? spec.event : undefined,\n\t\t\tfilter: spec.kind === \"command\" ? spec.filter : undefined,\n\t\t\tcwd: spec.cwd,\n\t\t\tapprovedParent: spec.kind === \"file\" ? spec.approvedParent : undefined,\n\t\t\tcreatedAt,\n\t\t\t// Absolute durability deadline for every restart-surviving entry, set once here and\n\t\t\t// never extended by a restore or a rearm. An ephemeral entry dies with the process,\n\t\t\t// so its runtime deadline stays the registry's business, not the manifest's.\n\t\t\texpiresAt: persistent ? createdAt + DURABLE_MONITOR_EXPIRY_MS : null,\n\t\t\tpersistent,\n\t\t\tsuspended: false,\n\t\t\tlastCheckpoint: null,\n\t\t\tdeliveryPaused: false,\n\t\t\tfireWindow: { startMs: createdAt, count: 0 },\n\t\t\t...(runtime === undefined ? {} : { runtime }),\n\t\t\t...(deadlineMs === undefined || persistent ? {} : { deadlineMs }),\n\t\t};\n\t}\n\n\t/** An empty manifest carries no state worth a file: unlink instead of writing `{[],[]}`. */\n\tasync #removeFile(): Promise<void> {\n\t\ttry {\n\t\t\tawait unlink(this.store.filePath);\n\t\t} catch (error) {\n\t\t\tif (!(typeof error === \"object\" && error !== null && \"code\" in error && error.code === \"ENOENT\")) throw error;\n\t\t}\n\t\tthis.store.clear();\n\t}\n\n\t#persist(): Promise<void> {\n\t\tconst run = this.#tail.then(() =>\n\t\t\tthis.#entries.size === 0 && this.#backgrounds.size === 0\n\t\t\t\t? this.#removeFile()\n\t\t\t\t: this.store.write({\n\t\t\t\t\t\tversion: TERMINAL_MANIFEST_VERSION,\n\t\t\t\t\t\tsessionId: this.#sessionId,\n\t\t\t\t\t\tmonitors: [...this.#entries.values()],\n\t\t\t\t\t\tbackgroundSessions: [...this.#backgrounds.values()],\n\t\t\t\t\t\tupdatedAt: this.#now(),\n\t\t\t\t\t}),\n\t\t);\n\t\tthis.#tail = run.then(\n\t\t\t() => undefined,\n\t\t\t(error) => {\n\t\t\t\tthis.persistFailure = error;\n\t\t\t},\n\t\t);\n\t\treturn this.#tail;\n\t}\n}\n"]}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Bounded GC of stale leases and empty manifests in the shared per-cwd terminal state dir.
3
+ */
4
+ import { type LeaseSelfIdentity } from "./manifest-lease.ts";
5
+ export declare function sweepTerminalStateDir(dir: string, options: {
6
+ self: LeaseSelfIdentity;
7
+ keep: ReadonlySet<string>;
8
+ limit?: number;
9
+ isProcessAlive?: (pid: number) => boolean;
10
+ readProcessStartMs?: (pid: number) => Promise<number | undefined>;
11
+ readdir?: (dir: string) => Promise<string[]>;
12
+ }): Promise<{
13
+ examined: number;
14
+ removedLeases: number;
15
+ removedManifests: number;
16
+ }>;
17
+ //# sourceMappingURL=terminal-state-gc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal-state-gc.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/terminal-state-gc.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,EAAiB,KAAK,iBAAiB,EAAmB,MAAM,qBAAqB,CAAC;AAiB7F,wBAAsB,qBAAqB,CAC1C,GAAG,EAAE,MAAM,EACX,OAAO,EAAE;IACR,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IAC1C,kBAAkB,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAClE,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CAC7C,GACC,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAA;CAAE,CAAC,CAkDhF"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Bounded GC of stale leases and empty manifests in the shared per-cwd terminal state dir.
3
+ */
4
+ import { readdir as defaultReaddir, readFile, stat, unlink } from "node:fs/promises";
5
+ import { join } from "node:path";
6
+ import { breakStaleLock, reclaimInspected, reclaimLockState } from "./lease-file.js";
7
+ import { classifyLease, readLeaseRecord } from "./manifest-lease.js";
8
+ import { readProcessStartMs as defaultReadProcessStartMs } from "./process-start-probe.js";
9
+ function isEnoent(error) {
10
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
11
+ }
12
+ async function unlinkIfPresent(path) {
13
+ try {
14
+ await unlink(path);
15
+ }
16
+ catch (error) {
17
+ if (!isEnoent(error))
18
+ throw error;
19
+ }
20
+ }
21
+ const ABANDONED_TEMP_MS = 30_000;
22
+ export async function sweepTerminalStateDir(dir, options) {
23
+ const listed = options.readdir ? await options.readdir(dir) : await defaultReaddir(dir);
24
+ const names = listed.slice(0, options.limit ?? 500);
25
+ const probes = {
26
+ isProcessAlive: options.isProcessAlive,
27
+ readProcessStartMs: options.readProcessStartMs ?? defaultReadProcessStartMs,
28
+ };
29
+ let removedLeases = 0;
30
+ let removedManifests = 0;
31
+ for (const name of names) {
32
+ if (options.keep.has(name))
33
+ continue;
34
+ const path = join(dir, name);
35
+ try {
36
+ // A reclaim lock goes only once its holder is gone; a temp file is published within
37
+ // milliseconds of being written, so one this old was abandoned by a crash.
38
+ if (name.endsWith(".lock")) {
39
+ const seen = await reclaimLockState(path, probes);
40
+ if (seen.state === "stale")
41
+ await breakStaleLock(path, seen.raw);
42
+ continue;
43
+ }
44
+ if (name.endsWith(".tmp") || name.endsWith(".reclaim") || name.endsWith(".broken")) {
45
+ const info = await stat(path).catch(() => undefined);
46
+ if (info !== undefined && Date.now() - info.mtimeMs > ABANDONED_TEMP_MS)
47
+ await unlinkIfPresent(path);
48
+ continue;
49
+ }
50
+ if (name.endsWith(".lease")) {
51
+ const raw = await readFile(path, "utf8");
52
+ const record = readLeaseRecord(raw);
53
+ const verdict = record === "unparseable" ? "dead" : await classifyLease(record, options.self, probes);
54
+ // Removal goes through the same inspected-record reclaim as an acquire, so a lease
55
+ // another process published while this sweep was probing is never deleted.
56
+ const stale = verdict === "dead" || verdict === "reused";
57
+ if (stale && (await reclaimInspected(path, raw, probes)).outcome === "removed") {
58
+ removedLeases += 1;
59
+ }
60
+ }
61
+ else if (name.endsWith(".json")) {
62
+ const parsed = JSON.parse(await readFile(path, "utf8"));
63
+ if (typeof parsed !== "object" || parsed === null)
64
+ continue;
65
+ if (!("monitors" in parsed) || !("backgroundSessions" in parsed))
66
+ continue;
67
+ const monitors = parsed.monitors;
68
+ const backgroundSessions = parsed.backgroundSessions;
69
+ if (!Array.isArray(monitors) || !Array.isArray(backgroundSessions))
70
+ continue;
71
+ if (monitors.length === 0 && backgroundSessions.length === 0) {
72
+ await unlinkIfPresent(path);
73
+ removedManifests += 1;
74
+ }
75
+ }
76
+ }
77
+ catch { }
78
+ }
79
+ return { examined: names.length, removedLeases, removedManifests };
80
+ }
81
+ //# sourceMappingURL=terminal-state-gc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal-state-gc.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/terminal-state-gc.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Bounded GC of stale leases and empty manifests in the shared per-cwd terminal state dir.\n */\n\nimport { readdir as defaultReaddir, readFile, stat, unlink } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { breakStaleLock, reclaimInspected, reclaimLockState } from \"./lease-file.ts\";\nimport { classifyLease, type LeaseSelfIdentity, readLeaseRecord } from \"./manifest-lease.ts\";\nimport { readProcessStartMs as defaultReadProcessStartMs } from \"./process-start-probe.ts\";\n\nfunction isEnoent(error: unknown): boolean {\n\treturn typeof error === \"object\" && error !== null && \"code\" in error && error.code === \"ENOENT\";\n}\n\nasync function unlinkIfPresent(path: string): Promise<void> {\n\ttry {\n\t\tawait unlink(path);\n\t} catch (error) {\n\t\tif (!isEnoent(error)) throw error;\n\t}\n}\n\nconst ABANDONED_TEMP_MS = 30_000;\n\nexport async function sweepTerminalStateDir(\n\tdir: string,\n\toptions: {\n\t\tself: LeaseSelfIdentity;\n\t\tkeep: ReadonlySet<string>;\n\t\tlimit?: number;\n\t\tisProcessAlive?: (pid: number) => boolean;\n\t\treadProcessStartMs?: (pid: number) => Promise<number | undefined>;\n\t\treaddir?: (dir: string) => Promise<string[]>;\n\t},\n): Promise<{ examined: number; removedLeases: number; removedManifests: number }> {\n\tconst listed = options.readdir ? await options.readdir(dir) : await defaultReaddir(dir);\n\tconst names = listed.slice(0, options.limit ?? 500);\n\tconst probes = {\n\t\tisProcessAlive: options.isProcessAlive,\n\t\treadProcessStartMs: options.readProcessStartMs ?? defaultReadProcessStartMs,\n\t};\n\tlet removedLeases = 0;\n\tlet removedManifests = 0;\n\tfor (const name of names) {\n\t\tif (options.keep.has(name)) continue;\n\t\tconst path = join(dir, name);\n\t\ttry {\n\t\t\t// A reclaim lock goes only once its holder is gone; a temp file is published within\n\t\t\t// milliseconds of being written, so one this old was abandoned by a crash.\n\t\t\tif (name.endsWith(\".lock\")) {\n\t\t\t\tconst seen = await reclaimLockState(path, probes);\n\t\t\t\tif (seen.state === \"stale\") await breakStaleLock(path, seen.raw);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (name.endsWith(\".tmp\") || name.endsWith(\".reclaim\") || name.endsWith(\".broken\")) {\n\t\t\t\tconst info = await stat(path).catch(() => undefined);\n\t\t\t\tif (info !== undefined && Date.now() - info.mtimeMs > ABANDONED_TEMP_MS) await unlinkIfPresent(path);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (name.endsWith(\".lease\")) {\n\t\t\t\tconst raw = await readFile(path, \"utf8\");\n\t\t\t\tconst record = readLeaseRecord(raw);\n\t\t\t\tconst verdict = record === \"unparseable\" ? \"dead\" : await classifyLease(record, options.self, probes);\n\t\t\t\t// Removal goes through the same inspected-record reclaim as an acquire, so a lease\n\t\t\t\t// another process published while this sweep was probing is never deleted.\n\t\t\t\tconst stale = verdict === \"dead\" || verdict === \"reused\";\n\t\t\t\tif (stale && (await reclaimInspected(path, raw, probes)).outcome === \"removed\") {\n\t\t\t\t\tremovedLeases += 1;\n\t\t\t\t}\n\t\t\t} else if (name.endsWith(\".json\")) {\n\t\t\t\tconst parsed: unknown = JSON.parse(await readFile(path, \"utf8\"));\n\t\t\t\tif (typeof parsed !== \"object\" || parsed === null) continue;\n\t\t\t\tif (!(\"monitors\" in parsed) || !(\"backgroundSessions\" in parsed)) continue;\n\t\t\t\tconst monitors = parsed.monitors;\n\t\t\t\tconst backgroundSessions = parsed.backgroundSessions;\n\t\t\t\tif (!Array.isArray(monitors) || !Array.isArray(backgroundSessions)) continue;\n\t\t\t\tif (monitors.length === 0 && backgroundSessions.length === 0) {\n\t\t\t\t\tawait unlinkIfPresent(path);\n\t\t\t\t\tremovedManifests += 1;\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {}\n\t}\n\treturn { examined: names.length, removedLeases, removedManifests };\n}\n"]}
@@ -32,6 +32,11 @@ export interface TerminalToolContext {
32
32
  readonly onMonitorRearmed?: (id: string) => void;
33
33
  /** Clears notifier bookkeeping when multiple paused monitors are resumed. */
34
34
  readonly onMonitorsResumed?: (ids: readonly string[]) => void;
35
+ /**
36
+ * Lazy persistence: bind the session's lease and manifest recorder before the first durable
37
+ * registration. Resolves immediately when persistence is already bound or unavailable.
38
+ */
39
+ readonly ensurePersistence?: () => Promise<void>;
35
40
  }
36
41
  /** Minimal tool-result shape returned by the terminal tools. */
37
42
  export interface TerminalToolResult {
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/terminal/tools/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE5E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD,iEAAiE;AACjE,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,8FAA8F;IAC9F,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC;IACvC,sFAAsF;IACtF,QAAQ,CAAC,MAAM,EAAE,MAAM,MAAM,CAAC,UAAU,CAAC;IACzC;;;OAGG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,OAAO,mBAAmB,EAAE,gBAAgB,GAAG,SAAS,CAAC;IAC5F,sEAAsE;IACtE,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5F,wFAAwF;IACxF,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAsB,KAAK,IAAI,CAAC;IAClF,sFAAsF;IACtF,QAAQ,CAAC,eAAe,CAAC,EAAE,eAAe,CAAC;IAC3C,kEAAkE;IAClE,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IACxD,4FAA4F;IAC5F,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,6EAA6E;IAC7E,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,KAAK,IAAI,CAAC;CAC9D;AAED,gEAAgE;AAChE,MAAM,WAAW,kBAAkB;IAClC,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IAC7C,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAChC,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,WAAW,CAAC,CAAC,EACnF,EAAE,EAAE,MAAM,GACR,MAAM,CAER;AAED,wBAAgB,UAAU,CACzB,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAC9D,kBAAkB,CAEpB;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,CAE5D;AAED,iGAAiG;AACjG,wBAAgB,aAAa,CAC5B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,aAAa,CAAC,MAAM,GAAG,SAAS,CAAC,EAC1C,KAAK,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,GAC9D,kBAAkB,CAEpB"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/terminal/tools/context.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/terminal/tools/context.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AA0C5D;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAChC,OAAmF,EACnF,EAAU;IAEV,OAAO,OAAO,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,UAAU,CACzB,IAAY,EACZ,KAAgE;IAEhE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAChG,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY;IACvC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACjF,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,aAAa,CAC5B,IAAY,EACZ,OAA0C,EAC1C,KAAgE;IAEhE,OAAO,EAAE,OAAO,EAAE,qBAAqB,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAC5G,CAAC","sourcesContent":["import type { TextContent } from \"@earendil-works/pi-ai\";\nimport type { TerminalManager } from \"../manager.ts\";\nimport type { MonitorEvent, MonitorRegistry } from \"../monitor-registry.ts\";\nimport { splitModelOnlyNotices } from \"../output-format.ts\";\nimport type { TerminalRuntimeSession } from \"../runtime-session.ts\";\nimport type { TimeoutAction } from \"../settings.ts\";\n\n/** Shared dependencies handed to every terminal tool factory. */\nexport interface TerminalToolContext {\n\treadonly manager: TerminalManager;\n\treadonly cwd: string;\n\t/** Explicit shell path from settings (settings-manager `shellPath`), if any. */\n\treadonly shellPath?: string;\n\treadonly defaultCols: number;\n\treadonly defaultRows: number;\n\t/** Configured foreground deadline behavior; omitted direct contexts default to background. */\n\treadonly timeoutAction?: TimeoutAction;\n\t/** Resolve the environment for spawned sessions (mirrors core bash `getShellEnv`). */\n\treadonly getEnv: () => NodeJS.ProcessEnv;\n\t/**\n\t * Current extension session context (set on session_start/model_select), used to\n\t * expose PI_* session metadata to spawned commands like the core bash tool does.\n\t */\n\treadonly getSessionContext?: () => import(\"../../../types.ts\").ExtensionContext | undefined;\n\t/** Registers a session when it transitions to background liveness. */\n\treadonly onBackgroundStart?: (id: string, description: string, startedAtMs: number) => void;\n\t/** Notified when a background session exits, so the notify layer can wake the agent. */\n\treadonly onBackgroundExit?: (id: string, runtime: TerminalRuntimeSession) => void;\n\t/** Session-scoped monitor state, sharing the terminal manager's bash-id namespace. */\n\treadonly monitorRegistry?: MonitorRegistry;\n\t/** Receives filtered monitor line and terminal-summary events. */\n\treadonly onMonitorEvent?: (event: MonitorEvent) => void;\n\t/** Resets session-global wake-budget delivery for a fresh or explicitly rearmed monitor. */\n\treadonly onMonitorRearmed?: (id: string) => void;\n\t/** Clears notifier bookkeeping when multiple paused monitors are resumed. */\n\treadonly onMonitorsResumed?: (ids: readonly string[]) => void;\n}\n\n/** Minimal tool-result shape returned by the terminal tools. */\nexport interface TerminalToolResult {\n\tcontent: TextContent[];\n\tdetails: Record<string, unknown> | undefined;\n\tisError?: boolean;\n}\n\n/**\n * Resolve a stable \"mon_\" monitor id to its current runtime id (bash_N/watch_N), passing a\n * runtime id through unchanged. Companion tools may run against a manager that does not\n * implement `resolveId` (narrower embedder/test managers expose `get` only); such managers\n * have never seen a `mon_` id, so falling back to the id verbatim preserves the lookup they\n * already supported. This is the single choke point for that rule — do not inline it.\n */\nexport function resolveTerminalId(\n\tmanager: Pick<TerminalManager, \"get\"> & Partial<Pick<TerminalManager, \"resolveId\">>,\n\tid: string,\n): string {\n\treturn manager.resolveId?.(id) ?? id;\n}\n\nexport function textResult(\n\ttext: string,\n\textra?: { details?: Record<string, unknown>; isError?: boolean },\n): TerminalToolResult {\n\treturn { content: [{ type: \"text\", text }], details: extra?.details, isError: extra?.isError };\n}\n\nexport function errorResult(text: string): TerminalToolResult {\n\treturn { content: [{ type: \"text\", text }], details: undefined, isError: true };\n}\n\n/** A result whose truncation/drop notices are model-only parts (see `splitModelOnlyNotices`). */\nexport function noticedResult(\n\ttext: string,\n\tnotices: ReadonlyArray<string | undefined>,\n\textra?: { details?: Record<string, unknown>; isError?: boolean },\n): TerminalToolResult {\n\treturn { content: splitModelOnlyNotices(text, notices), details: extra?.details, isError: extra?.isError };\n}\n"]}
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/terminal/tools/context.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AA+C5D;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAChC,OAAmF,EACnF,EAAU;IAEV,OAAO,OAAO,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,UAAU,CACzB,IAAY,EACZ,KAAgE;IAEhE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAChG,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAY;IACvC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACjF,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,aAAa,CAC5B,IAAY,EACZ,OAA0C,EAC1C,KAAgE;IAEhE,OAAO,EAAE,OAAO,EAAE,qBAAqB,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAC5G,CAAC","sourcesContent":["import type { TextContent } from \"@earendil-works/pi-ai\";\nimport type { TerminalManager } from \"../manager.ts\";\nimport type { MonitorEvent, MonitorRegistry } from \"../monitor-registry.ts\";\nimport { splitModelOnlyNotices } from \"../output-format.ts\";\nimport type { TerminalRuntimeSession } from \"../runtime-session.ts\";\nimport type { TimeoutAction } from \"../settings.ts\";\n\n/** Shared dependencies handed to every terminal tool factory. */\nexport interface TerminalToolContext {\n\treadonly manager: TerminalManager;\n\treadonly cwd: string;\n\t/** Explicit shell path from settings (settings-manager `shellPath`), if any. */\n\treadonly shellPath?: string;\n\treadonly defaultCols: number;\n\treadonly defaultRows: number;\n\t/** Configured foreground deadline behavior; omitted direct contexts default to background. */\n\treadonly timeoutAction?: TimeoutAction;\n\t/** Resolve the environment for spawned sessions (mirrors core bash `getShellEnv`). */\n\treadonly getEnv: () => NodeJS.ProcessEnv;\n\t/**\n\t * Current extension session context (set on session_start/model_select), used to\n\t * expose PI_* session metadata to spawned commands like the core bash tool does.\n\t */\n\treadonly getSessionContext?: () => import(\"../../../types.ts\").ExtensionContext | undefined;\n\t/** Registers a session when it transitions to background liveness. */\n\treadonly onBackgroundStart?: (id: string, description: string, startedAtMs: number) => void;\n\t/** Notified when a background session exits, so the notify layer can wake the agent. */\n\treadonly onBackgroundExit?: (id: string, runtime: TerminalRuntimeSession) => void;\n\t/** Session-scoped monitor state, sharing the terminal manager's bash-id namespace. */\n\treadonly monitorRegistry?: MonitorRegistry;\n\t/** Receives filtered monitor line and terminal-summary events. */\n\treadonly onMonitorEvent?: (event: MonitorEvent) => void;\n\t/** Resets session-global wake-budget delivery for a fresh or explicitly rearmed monitor. */\n\treadonly onMonitorRearmed?: (id: string) => void;\n\t/** Clears notifier bookkeeping when multiple paused monitors are resumed. */\n\treadonly onMonitorsResumed?: (ids: readonly string[]) => void;\n\t/**\n\t * Lazy persistence: bind the session's lease and manifest recorder before the first durable\n\t * registration. Resolves immediately when persistence is already bound or unavailable.\n\t */\n\treadonly ensurePersistence?: () => Promise<void>;\n}\n\n/** Minimal tool-result shape returned by the terminal tools. */\nexport interface TerminalToolResult {\n\tcontent: TextContent[];\n\tdetails: Record<string, unknown> | undefined;\n\tisError?: boolean;\n}\n\n/**\n * Resolve a stable \"mon_\" monitor id to its current runtime id (bash_N/watch_N), passing a\n * runtime id through unchanged. Companion tools may run against a manager that does not\n * implement `resolveId` (narrower embedder/test managers expose `get` only); such managers\n * have never seen a `mon_` id, so falling back to the id verbatim preserves the lookup they\n * already supported. This is the single choke point for that rule — do not inline it.\n */\nexport function resolveTerminalId(\n\tmanager: Pick<TerminalManager, \"get\"> & Partial<Pick<TerminalManager, \"resolveId\">>,\n\tid: string,\n): string {\n\treturn manager.resolveId?.(id) ?? id;\n}\n\nexport function textResult(\n\ttext: string,\n\textra?: { details?: Record<string, unknown>; isError?: boolean },\n): TerminalToolResult {\n\treturn { content: [{ type: \"text\", text }], details: extra?.details, isError: extra?.isError };\n}\n\nexport function errorResult(text: string): TerminalToolResult {\n\treturn { content: [{ type: \"text\", text }], details: undefined, isError: true };\n}\n\n/** A result whose truncation/drop notices are model-only parts (see `splitModelOnlyNotices`). */\nexport function noticedResult(\n\ttext: string,\n\tnotices: ReadonlyArray<string | undefined>,\n\textra?: { details?: Record<string, unknown>; isError?: boolean },\n): TerminalToolResult {\n\treturn { content: splitModelOnlyNotices(text, notices), details: extra?.details, isError: extra?.isError };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"kill-bash.d.ts","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/terminal/tools/kill-bash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,EAGN,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EAEvB,MAAM,cAAc,CAAC;AAEtB,eAAO,MAAM,cAAc;;;EAGzB,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,cAAc,CAAC,CAAC;AAE1D,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,mBAAmB;;;;;;;;;yBAO9B,MAAM,SAAS,aAAa,YAAY,WAAW,GAAG,OAAO,CAAC,kBAAkB,CAAC;EAgB7G"}
1
+ {"version":3,"file":"kill-bash.d.ts","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/terminal/tools/kill-bash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,EAGN,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EAEvB,MAAM,cAAc,CAAC;AAEtB,eAAO,MAAM,cAAc;;;EAGzB,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,cAAc,CAAC,CAAC;AAE1D,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,mBAAmB;;;;;;;;;yBAO9B,MAAM,SAAS,aAAa,YAAY,WAAW,GAAG,OAAO,CAAC,kBAAkB,CAAC;EA8B7G"}
@@ -1,4 +1,5 @@
1
1
  import { Type } from "typebox";
2
+ import { removeMonitorStateDir, terminalStateDir } from "../monitor-state-dir.js";
2
3
  import { TERMINAL_KILL_TOOL } from "../shared.js";
3
4
  import { errorResult, resolveTerminalId, textResult, } from "./context.js";
4
5
  export const killBashSchema = Type.Object({
@@ -13,21 +14,35 @@ export function createKillBashTool(ctx) {
13
14
  promptSnippet: "Tree-kill a background bash session (or all) with no orphans",
14
15
  parameters: killBashSchema,
15
16
  async execute(_toolCallId, input, _signal) {
17
+ // An explicit kill ends a standing watch for good, so its restore state dir goes with it.
18
+ // A process death does NOT come through here and keeps the dir for the next restore.
19
+ const terminalDir = terminalStateDir(ctx.getSessionContext?.());
20
+ const dropStateDir = async (monitorId) => {
21
+ if (terminalDir !== undefined && monitorId !== undefined)
22
+ await removeMonitorStateDir(terminalDir, monitorId);
23
+ };
16
24
  if (input.all) {
17
25
  const terminalCount = ctx.manager.size;
26
+ const monitorIds = (ctx.monitorRegistry?.snapshot() ?? []).map((entry) => entry.monitorId);
18
27
  const fileCount = (await ctx.monitorRegistry?.stopAllFiles()) ?? 0;
19
28
  await ctx.manager.teardown();
29
+ for (const monitorId of monitorIds)
30
+ await dropStateDir(monitorId);
20
31
  return textResult(`Killed ${terminalCount + fileCount} session(s).`);
21
32
  }
22
33
  if (!input.bash_id)
23
34
  return errorResult("Provide `bash_id` or set `all:true`.");
24
35
  const sessionId = resolveTerminalId(ctx.manager, input.bash_id);
25
- if (await ctx.monitorRegistry?.stopFile(sessionId))
36
+ const monitorId = input.bash_id.startsWith("mon_") ? input.bash_id : ctx.manager.monitorIdOf?.(sessionId);
37
+ if (await ctx.monitorRegistry?.stopFile(sessionId)) {
38
+ await dropStateDir(monitorId);
26
39
  return textResult(`Killed ${input.bash_id}.`);
40
+ }
27
41
  const runtime = ctx.manager.get(sessionId);
28
42
  if (!runtime)
29
43
  return errorResult(`No terminal session found with id: ${input.bash_id}`);
30
44
  await ctx.manager.stop(sessionId);
45
+ await dropStateDir(monitorId);
31
46
  return textResult(`Killed ${input.bash_id}.`);
32
47
  },
33
48
  };
@@ -1 +1 @@
1
- {"version":3,"file":"kill-bash.js","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/terminal/tools/kill-bash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EACN,WAAW,EACX,iBAAiB,EAGjB,UAAU,GACV,MAAM,cAAc,CAAC;AAEtB,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC;IACzC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,0BAA0B,EAAE,CAAC,CAAC;IAChF,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,0CAA0C,EAAE,CAAC,CAAC;CAC7F,CAAC,CAAC;AAIH,MAAM,UAAU,kBAAkB,CAAC,GAAwB;IAC1D,OAAO;QACN,IAAI,EAAE,kBAAkB;QACxB,KAAK,EAAE,WAAW;QAClB,WAAW,EAAE,oFAAoF;QACjG,aAAa,EAAE,8DAA8D;QAC7E,UAAU,EAAE,cAAc;QAC1B,KAAK,CAAC,OAAO,CAAC,WAAmB,EAAE,KAAoB,EAAE,OAAqB;YAC7E,IAAI,KAAK,CAAC,GAAG,EAAE,CAAC;gBACf,MAAM,aAAa,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC;gBACvC,MAAM,SAAS,GAAG,CAAC,MAAM,GAAG,CAAC,eAAe,EAAE,YAAY,EAAE,CAAC,IAAI,CAAC,CAAC;gBACnE,MAAM,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;gBAC7B,OAAO,UAAU,CAAC,UAAU,aAAa,GAAG,SAAS,cAAc,CAAC,CAAC;YACtE,CAAC;YACD,IAAI,CAAC,KAAK,CAAC,OAAO;gBAAE,OAAO,WAAW,CAAC,sCAAsC,CAAC,CAAC;YAC/E,MAAM,SAAS,GAAG,iBAAiB,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;YAChE,IAAI,MAAM,GAAG,CAAC,eAAe,EAAE,QAAQ,CAAC,SAAS,CAAC;gBAAE,OAAO,UAAU,CAAC,UAAU,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC;YAClG,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAC3C,IAAI,CAAC,OAAO;gBAAE,OAAO,WAAW,CAAC,sCAAsC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACxF,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAClC,OAAO,UAAU,CAAC,UAAU,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC;QAC/C,CAAC;KACD,CAAC;AACH,CAAC","sourcesContent":["import { type Static, Type } from \"typebox\";\nimport { TERMINAL_KILL_TOOL } from \"../shared.ts\";\nimport {\n\terrorResult,\n\tresolveTerminalId,\n\ttype TerminalToolContext,\n\ttype TerminalToolResult,\n\ttextResult,\n} from \"./context.ts\";\n\nexport const killBashSchema = Type.Object({\n\tbash_id: Type.Optional(Type.String({ description: \"Session id to tree-kill.\" })),\n\tall: Type.Optional(Type.Boolean({ description: \"Tree-kill every live background session.\" })),\n});\n\nexport type KillBashInput = Static<typeof killBashSchema>;\n\nexport function createKillBashTool(ctx: TerminalToolContext) {\n\treturn {\n\t\tname: TERMINAL_KILL_TOOL,\n\t\tlabel: \"kill_bash\",\n\t\tdescription: \"Terminate a background bash session (or all of them) and its process tree cleanly.\",\n\t\tpromptSnippet: \"Tree-kill a background bash session (or all) with no orphans\",\n\t\tparameters: killBashSchema,\n\t\tasync execute(_toolCallId: string, input: KillBashInput, _signal?: AbortSignal): Promise<TerminalToolResult> {\n\t\t\tif (input.all) {\n\t\t\t\tconst terminalCount = ctx.manager.size;\n\t\t\t\tconst fileCount = (await ctx.monitorRegistry?.stopAllFiles()) ?? 0;\n\t\t\t\tawait ctx.manager.teardown();\n\t\t\t\treturn textResult(`Killed ${terminalCount + fileCount} session(s).`);\n\t\t\t}\n\t\t\tif (!input.bash_id) return errorResult(\"Provide `bash_id` or set `all:true`.\");\n\t\t\tconst sessionId = resolveTerminalId(ctx.manager, input.bash_id);\n\t\t\tif (await ctx.monitorRegistry?.stopFile(sessionId)) return textResult(`Killed ${input.bash_id}.`);\n\t\t\tconst runtime = ctx.manager.get(sessionId);\n\t\t\tif (!runtime) return errorResult(`No terminal session found with id: ${input.bash_id}`);\n\t\t\tawait ctx.manager.stop(sessionId);\n\t\t\treturn textResult(`Killed ${input.bash_id}.`);\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"file":"kill-bash.js","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/terminal/tools/kill-bash.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Static, Type } from \"typebox\";\nimport { removeMonitorStateDir, terminalStateDir } from \"../monitor-state-dir.ts\";\nimport { TERMINAL_KILL_TOOL } from \"../shared.ts\";\nimport {\n\terrorResult,\n\tresolveTerminalId,\n\ttype TerminalToolContext,\n\ttype TerminalToolResult,\n\ttextResult,\n} from \"./context.ts\";\n\nexport const killBashSchema = Type.Object({\n\tbash_id: Type.Optional(Type.String({ description: \"Session id to tree-kill.\" })),\n\tall: Type.Optional(Type.Boolean({ description: \"Tree-kill every live background session.\" })),\n});\n\nexport type KillBashInput = Static<typeof killBashSchema>;\n\nexport function createKillBashTool(ctx: TerminalToolContext) {\n\treturn {\n\t\tname: TERMINAL_KILL_TOOL,\n\t\tlabel: \"kill_bash\",\n\t\tdescription: \"Terminate a background bash session (or all of them) and its process tree cleanly.\",\n\t\tpromptSnippet: \"Tree-kill a background bash session (or all) with no orphans\",\n\t\tparameters: killBashSchema,\n\t\tasync execute(_toolCallId: string, input: KillBashInput, _signal?: AbortSignal): Promise<TerminalToolResult> {\n\t\t\t// An explicit kill ends a standing watch for good, so its restore state dir goes with it.\n\t\t\t// A process death does NOT come through here and keeps the dir for the next restore.\n\t\t\tconst terminalDir = terminalStateDir(ctx.getSessionContext?.());\n\t\t\tconst dropStateDir = async (monitorId: string | undefined): Promise<void> => {\n\t\t\t\tif (terminalDir !== undefined && monitorId !== undefined)\n\t\t\t\t\tawait removeMonitorStateDir(terminalDir, monitorId);\n\t\t\t};\n\t\t\tif (input.all) {\n\t\t\t\tconst terminalCount = ctx.manager.size;\n\t\t\t\tconst monitorIds = (ctx.monitorRegistry?.snapshot() ?? []).map((entry) => entry.monitorId);\n\t\t\t\tconst fileCount = (await ctx.monitorRegistry?.stopAllFiles()) ?? 0;\n\t\t\t\tawait ctx.manager.teardown();\n\t\t\t\tfor (const monitorId of monitorIds) await dropStateDir(monitorId);\n\t\t\t\treturn textResult(`Killed ${terminalCount + fileCount} session(s).`);\n\t\t\t}\n\t\t\tif (!input.bash_id) return errorResult(\"Provide `bash_id` or set `all:true`.\");\n\t\t\tconst sessionId = resolveTerminalId(ctx.manager, input.bash_id);\n\t\t\tconst monitorId = input.bash_id.startsWith(\"mon_\") ? input.bash_id : ctx.manager.monitorIdOf?.(sessionId);\n\t\t\tif (await ctx.monitorRegistry?.stopFile(sessionId)) {\n\t\t\t\tawait dropStateDir(monitorId);\n\t\t\t\treturn textResult(`Killed ${input.bash_id}.`);\n\t\t\t}\n\t\t\tconst runtime = ctx.manager.get(sessionId);\n\t\t\tif (!runtime) return errorResult(`No terminal session found with id: ${input.bash_id}`);\n\t\t\tawait ctx.manager.stop(sessionId);\n\t\t\tawait dropStateDir(monitorId);\n\t\t\treturn textResult(`Killed ${input.bash_id}.`);\n\t\t},\n\t};\n}\n"]}
@@ -0,0 +1,27 @@
1
+ import type { MonitorRegistry } from "../monitor-registry.ts";
2
+ import type { MonitorRegistration, TerminalManifestWriter } from "../terminal-manifest.ts";
3
+ import { type TerminalToolContext, type TerminalToolResult } from "./context.ts";
4
+ export declare const MAX_PENDING_MONITOR_SPECS = 32;
5
+ /** Bind the session's manifest writer so monitor tool calls can hand it specs captured at the call site. */
6
+ export declare function bindTerminalManifestWriter(sessionId: string, writer: TerminalManifestWriter): void;
7
+ export declare function unbindTerminalManifestWriter(sessionId: string): void;
8
+ export declare function pendingDurableSpecCount(sessionId: string): number;
9
+ /** The durability session key for a tool context: the agent session id, when the context carries one. */
10
+ export declare function manifestSessionKey(ctx: TerminalToolContext): string | undefined;
11
+ /**
12
+ * Hand a spec captured at the monitor tool call site to the session's writer, or queue it until
13
+ * one binds. The write is awaited: the tool result must not claim a watch before its manifest
14
+ * entry exists on disk.
15
+ */
16
+ export declare function handMonitorSpec(sessionKey: string | undefined, registration: MonitorRegistration): Promise<void>;
17
+ /** Persist a durable file watch's baseline checkpoint through the writer's debounced path. */
18
+ export declare function handFileCheckpoint(sessionKey: string | undefined, monitorId: string, registry: MonitorRegistry, runtimeId: string): void;
19
+ /**
20
+ * Admission control for a durable create: refuse once the session already holds
21
+ * MAX_DURABLE_MONITORS restart-surviving monitors, counting both the bound writer's entries
22
+ * and the specs still queued for a writer. Checked BEFORE any spawn or registry registration
23
+ * so a refused call leaves no PTY and no manifest entry behind. A context with no session
24
+ * key persists nothing, so it has no durable population to cap.
25
+ */
26
+ export declare function durableAdmissionError(ctx: TerminalToolContext): TerminalToolResult | undefined;
27
+ //# sourceMappingURL=monitor-manifest-binding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"monitor-manifest-binding.d.ts","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/terminal/tools/monitor-manifest-binding.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,OAAO,KAAK,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAC3F,OAAO,EAAe,KAAK,mBAAmB,EAAE,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAS9F,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAE5C,4GAA4G;AAC5G,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,sBAAsB,GAAG,IAAI,CAKlG;AAED,wBAAgB,4BAA4B,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAEpE;AAED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAIjE;AAED,yGAAyG;AACzG,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,mBAAmB,GAAG,MAAM,GAAG,SAAS,CAE/E;AAED;;;;GAIG;AACH,wBAAsB,eAAe,CACpC,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,YAAY,EAAE,mBAAmB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAWf;AAED,8FAA8F;AAC9F,wBAAgB,kBAAkB,CACjC,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,eAAe,EACzB,SAAS,EAAE,MAAM,GACf,IAAI,CAIN;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,mBAAmB,GAAG,kBAAkB,GAAG,SAAS,CAQ9F"}