@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
@@ -1,10 +1,24 @@
1
- import { mkdir, open, readFile, unlink } from "node:fs/promises";
1
+ import { randomUUID } from "node:crypto";
2
+ import { mkdir } from "node:fs/promises";
2
3
  import { join } from "node:path";
3
- function errorCode(error) {
4
- if (typeof error === "object" && error !== null && "code" in error && typeof error.code === "string") {
5
- return error.code;
6
- }
7
- return undefined;
4
+ import { errorCode, publishExclusive, publishReplace, readLeaseText, reclaimInspected, unlinkIfPresent, } from "./lease-file.js";
5
+ import { ownProcessStartedAtMs, PROCESS_START_TOLERANCE_MS, processBootAtMs, sameProcessStart, } from "./process-identity.js";
6
+ import { readProcessStartMs as defaultReadProcessStartMs } from "./process-start-probe.js";
7
+ export const LEASE_RECORD_VERSION = 2;
8
+ const generationTokens = new Map();
9
+ /**
10
+ * Tokens held by generations of THIS process that are still running. A same-pid lease is a live
11
+ * holder only when its token is here (a sibling session generation, or a racing waiter that won);
12
+ * a token that is not here was minted by a generation that has shut down, even one whose
13
+ * shutdown never reached the release (the 10 s shutdown cap), so it is ours to re-enter.
14
+ */
15
+ const liveTokens = new Set();
16
+ export function currentLeaseToken(encodedSessionId) {
17
+ return generationTokens.get(encodedSessionId);
18
+ }
19
+ /** Mark a generation's token dead the moment its shutdown starts, before any slow flush. */
20
+ export function retireLeaseToken(token) {
21
+ liveTokens.delete(token);
8
22
  }
9
23
  function probeAlive(pid, probe) {
10
24
  try {
@@ -22,84 +36,152 @@ function probeAlive(pid, probe) {
22
36
  throw error;
23
37
  }
24
38
  }
25
- async function readLease(path) {
26
- let raw;
27
- try {
28
- raw = await readFile(path, "utf8");
29
- }
30
- catch (error) {
31
- if (errorCode(error) === "ENOENT")
32
- return "missing";
33
- throw error;
34
- }
39
+ const isFiniteNumber = (value) => typeof value === "number" && Number.isFinite(value);
40
+ export function readLeaseRecord(raw) {
35
41
  try {
36
42
  const parsed = JSON.parse(raw);
37
43
  if (typeof parsed !== "object" || parsed === null)
38
44
  return "unparseable";
39
- const pid = parsed.pid;
40
- const startedAtMs = parsed.startedAtMs;
41
- if (typeof pid !== "number" ||
42
- !Number.isFinite(pid) ||
43
- typeof startedAtMs !== "number" ||
44
- !Number.isFinite(startedAtMs)) {
45
+ const candidate = parsed;
46
+ if (!isFiniteNumber(candidate.pid) || !isFiniteNumber(candidate.startedAtMs))
45
47
  return "unparseable";
46
- }
47
- return { pid, startedAtMs };
48
+ return {
49
+ pid: candidate.pid,
50
+ startedAtMs: candidate.startedAtMs,
51
+ ...(isFiniteNumber(candidate.v) ? { v: candidate.v } : {}),
52
+ ...(typeof candidate.token === "string" ? { token: candidate.token } : {}),
53
+ ...(isFiniteNumber(candidate.bootAtMs) ? { bootAtMs: candidate.bootAtMs } : {}),
54
+ ...(isFiniteNumber(candidate.processStartedAtMs) ? { processStartedAtMs: candidate.processStartedAtMs } : {}),
55
+ ...(isFiniteNumber(candidate.acquiredAtMs) ? { acquiredAtMs: candidate.acquiredAtMs } : {}),
56
+ };
48
57
  }
49
58
  catch {
50
59
  return "unparseable";
51
60
  }
52
61
  }
53
- async function exclusiveCreate(path, record) {
54
- const file = await open(path, "wx");
55
- try {
56
- await file.writeFile(JSON.stringify(record), "utf8");
57
- }
58
- finally {
59
- await file.close();
60
- }
62
+ async function readLeaseFile(path) {
63
+ const raw = await readLeaseText(path);
64
+ return raw === undefined ? "missing" : readLeaseRecord(raw);
61
65
  }
62
- async function unlinkIfPresent(path) {
63
- try {
64
- await unlink(path);
65
- }
66
- catch (error) {
67
- if (errorCode(error) !== "ENOENT")
68
- throw error;
66
+ /**
67
+ * Decide what an existing lease is. A pid alone is never trusted: the holder is alive only when
68
+ * its pid answers AND its recorded start instant matches the process now wearing that pid
69
+ * (probed on this cold path only). A boot mismatch alone never reclaims an alive pid. Our own
70
+ * pid is "self" only when the file carries the token this process minted for the session (or a
71
+ * legacy record without one): a multi-session host holds many sessions under one pid, and a
72
+ * lease another live generation in this process owns is a live holder, not a re-entry.
73
+ */
74
+ export async function classifyLease(existing, self, probes) {
75
+ if (existing.pid === self.pid) {
76
+ if (existing.token !== undefined && (probes.liveTokens ?? liveTokens).has(existing.token))
77
+ return "live-foreign";
78
+ return "self";
69
79
  }
70
- }
71
- async function tryAcquire(path, record, isProcessAlive, retry) {
80
+ if (!probeAlive(existing.pid, probes.isProcessAlive))
81
+ return "dead";
82
+ let observedStart;
72
83
  try {
73
- await exclusiveCreate(path, record);
74
- return { acquired: true, path, pid: record.pid };
84
+ observedStart = await probes.readProcessStartMs(existing.pid);
75
85
  }
76
- catch (error) {
77
- if (errorCode(error) !== "EEXIST")
78
- throw error;
79
- const existing = await readLease(path);
80
- const reclaimable = existing === "missing" || existing === "unparseable" || !probeAlive(existing.pid, isProcessAlive);
81
- if (reclaimable && retry) {
82
- await unlinkIfPresent(path);
83
- return tryAcquire(path, record, isProcessAlive, false);
84
- }
85
- if (existing === "missing" || existing === "unparseable")
86
- throw error;
87
- return { acquired: false, holder: existing };
86
+ catch {
87
+ observedStart = undefined;
88
88
  }
89
+ if (observedStart === undefined)
90
+ return "live-foreign";
91
+ if (existing.processStartedAtMs === undefined) {
92
+ // A v1 record's startedAtMs is when the lease was taken, so its holder started no later
93
+ // than that; a process that started afterwards on the same pid is a reuse.
94
+ return observedStart <= existing.startedAtMs + PROCESS_START_TOLERANCE_MS ? "live-foreign" : "reused";
95
+ }
96
+ return sameProcessStart(existing.processStartedAtMs, observedStart) ? "live-foreign" : "reused";
97
+ }
98
+ function holderOf(record) {
99
+ return {
100
+ pid: record.pid,
101
+ startedAtMs: record.startedAtMs,
102
+ ...(record.bootAtMs !== undefined ? { bootAtMs: record.bootAtMs } : {}),
103
+ };
89
104
  }
90
105
  export async function acquireTerminalLease(options) {
91
- const pid = options.pid ?? process.pid;
92
- const startedAtMs = (options.now ?? Date.now)();
106
+ const now = (options.now ?? Date.now)();
107
+ const self = options.self ?? {
108
+ pid: options.pid ?? process.pid,
109
+ bootAtMs: processBootAtMs(),
110
+ processStartedAtMs: ownProcessStartedAtMs(),
111
+ };
112
+ const pid = options.pid ?? self.pid;
93
113
  const path = join(options.dir, `${options.encodedSessionId}.lease`);
94
114
  await mkdir(options.dir, { recursive: true });
95
- return tryAcquire(path, { pid, startedAtMs }, options.isProcessAlive, true);
115
+ const token = randomUUID();
116
+ const record = {
117
+ v: LEASE_RECORD_VERSION,
118
+ token,
119
+ pid,
120
+ startedAtMs: now,
121
+ bootAtMs: self.bootAtMs,
122
+ processStartedAtMs: self.processStartedAtMs,
123
+ acquiredAtMs: now,
124
+ };
125
+ const acquired = () => {
126
+ generationTokens.set(options.encodedSessionId, token);
127
+ liveTokens.add(token);
128
+ return { acquired: true, path, pid, token };
129
+ };
130
+ const probes = {
131
+ isProcessAlive: options.isProcessAlive,
132
+ readProcessStartMs: options.readProcessStartMs ?? defaultReadProcessStartMs,
133
+ };
134
+ const content = JSON.stringify(record);
135
+ for (let attempt = 0; attempt < 3; attempt += 1) {
136
+ try {
137
+ await publishExclusive(path, content);
138
+ return acquired();
139
+ }
140
+ catch (error) {
141
+ if (errorCode(error) !== "EEXIST")
142
+ throw error;
143
+ }
144
+ const raw = await readLeaseText(path);
145
+ if (raw === undefined)
146
+ continue;
147
+ const existing = readLeaseRecord(raw);
148
+ const verdict = existing === "unparseable" ? "dead" : await classifyLease(existing, { ...self, pid }, probes);
149
+ if (verdict === "self") {
150
+ await publishReplace(path, content);
151
+ return acquired();
152
+ }
153
+ if (verdict === "live-foreign" && existing !== "unparseable")
154
+ return { acquired: false, holder: holderOf(existing) };
155
+ // Only the record judged stale is removed; a racer's fresh lease makes the next try lose cleanly.
156
+ const reclaim = await reclaimInspected(path, raw, probes);
157
+ // Someone is reclaiming right now: wait on that live process, never on the stale record.
158
+ if (reclaim.outcome === "busy" && reclaim.holder !== undefined) {
159
+ const { pid: holderPid, processStartedAtMs, bootAtMs } = reclaim.holder;
160
+ return { acquired: false, holder: { pid: holderPid, startedAtMs: processStartedAtMs, bootAtMs } };
161
+ }
162
+ }
163
+ const raw = await readLeaseText(path);
164
+ const last = raw === undefined ? "unparseable" : readLeaseRecord(raw);
165
+ if (last !== "unparseable" && (await classifyLease(last, { ...self, pid }, probes)) === "live-foreign") {
166
+ return { acquired: false, holder: holderOf(last) };
167
+ }
168
+ throw new Error(`terminal lease ${path} kept changing while it was being acquired`);
96
169
  }
170
+ /** Release only the generation that acquired: a stale release from an earlier generation is a no-op. */
97
171
  export async function releaseTerminalLease(handle) {
98
- const existing = await readLease(handle.path);
172
+ const existing = await readLeaseFile(handle.path);
99
173
  if (existing === "missing" || existing === "unparseable")
100
174
  return;
101
175
  if (existing.pid !== handle.pid)
102
176
  return;
177
+ if (handle.token !== undefined && existing.token !== undefined && existing.token !== handle.token)
178
+ return;
103
179
  await unlinkIfPresent(handle.path);
180
+ if (existing.token !== undefined) {
181
+ liveTokens.delete(existing.token);
182
+ for (const [sessionId, token] of generationTokens)
183
+ if (token === existing.token)
184
+ generationTokens.delete(sessionId);
185
+ }
104
186
  }
105
187
  //# sourceMappingURL=manifest-lease.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"manifest-lease.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/manifest-lease.ts"],"names":[],"mappings":"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","sourcesContent":["import { mkdir, open, readFile, unlink } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nexport type AcquireTerminalLeaseOptions = {\n\tdir: string;\n\tencodedSessionId: string;\n\tpid?: number;\n\tnow?: () => number;\n\tisProcessAlive?: (pid: number) => boolean;\n};\n\nexport type AcquireTerminalLeaseResult =\n\t| { acquired: true; path: string; pid: number }\n\t| { acquired: false; holder: { pid: number; startedAtMs: number } };\n\ntype LeaseRecord = { pid: number; startedAtMs: number };\n\nfunction errorCode(error: unknown): string | undefined {\n\tif (typeof error === \"object\" && error !== null && \"code\" in error && typeof error.code === \"string\") {\n\t\treturn error.code;\n\t}\n\treturn undefined;\n}\n\nfunction probeAlive(pid: number, probe?: (pid: number) => boolean): boolean {\n\ttry {\n\t\tif (probe) return probe(pid);\n\t\tprocess.kill(pid, 0);\n\t\treturn true;\n\t} catch (error) {\n\t\tconst code = errorCode(error);\n\t\tif (code === \"EPERM\") return true;\n\t\tif (code === \"ESRCH\") return false;\n\t\tthrow error;\n\t}\n}\n\nasync function readLease(path: string): Promise<LeaseRecord | \"missing\" | \"unparseable\"> {\n\tlet raw: string;\n\ttry {\n\t\traw = await readFile(path, \"utf8\");\n\t} catch (error) {\n\t\tif (errorCode(error) === \"ENOENT\") return \"missing\";\n\t\tthrow error;\n\t}\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(raw);\n\t\tif (typeof parsed !== \"object\" || parsed === null) return \"unparseable\";\n\t\tconst pid = (parsed as { pid?: unknown }).pid;\n\t\tconst startedAtMs = (parsed as { startedAtMs?: unknown }).startedAtMs;\n\t\tif (\n\t\t\ttypeof pid !== \"number\" ||\n\t\t\t!Number.isFinite(pid) ||\n\t\t\ttypeof startedAtMs !== \"number\" ||\n\t\t\t!Number.isFinite(startedAtMs)\n\t\t) {\n\t\t\treturn \"unparseable\";\n\t\t}\n\t\treturn { pid, startedAtMs };\n\t} catch {\n\t\treturn \"unparseable\";\n\t}\n}\n\nasync function exclusiveCreate(path: string, record: LeaseRecord): Promise<void> {\n\tconst file = await open(path, \"wx\");\n\ttry {\n\t\tawait file.writeFile(JSON.stringify(record), \"utf8\");\n\t} finally {\n\t\tawait file.close();\n\t}\n}\n\nasync function unlinkIfPresent(path: string): Promise<void> {\n\ttry {\n\t\tawait unlink(path);\n\t} catch (error) {\n\t\tif (errorCode(error) !== \"ENOENT\") throw error;\n\t}\n}\n\nasync function tryAcquire(\n\tpath: string,\n\trecord: LeaseRecord,\n\tisProcessAlive: ((pid: number) => boolean) | undefined,\n\tretry: boolean,\n): Promise<AcquireTerminalLeaseResult> {\n\ttry {\n\t\tawait exclusiveCreate(path, record);\n\t\treturn { acquired: true, path, pid: record.pid };\n\t} catch (error) {\n\t\tif (errorCode(error) !== \"EEXIST\") throw error;\n\t\tconst existing = await readLease(path);\n\t\tconst reclaimable =\n\t\t\texisting === \"missing\" || existing === \"unparseable\" || !probeAlive(existing.pid, isProcessAlive);\n\t\tif (reclaimable && retry) {\n\t\t\tawait unlinkIfPresent(path);\n\t\t\treturn tryAcquire(path, record, isProcessAlive, false);\n\t\t}\n\t\tif (existing === \"missing\" || existing === \"unparseable\") throw error;\n\t\treturn { acquired: false, holder: existing };\n\t}\n}\n\nexport async function acquireTerminalLease(options: AcquireTerminalLeaseOptions): Promise<AcquireTerminalLeaseResult> {\n\tconst pid = options.pid ?? process.pid;\n\tconst startedAtMs = (options.now ?? Date.now)();\n\tconst path = join(options.dir, `${options.encodedSessionId}.lease`);\n\tawait mkdir(options.dir, { recursive: true });\n\treturn tryAcquire(path, { pid, startedAtMs }, options.isProcessAlive, true);\n}\n\nexport async function releaseTerminalLease(handle: { path: string; pid: number }): Promise<void> {\n\tconst existing = await readLease(handle.path);\n\tif (existing === \"missing\" || existing === \"unparseable\") return;\n\tif (existing.pid !== handle.pid) return;\n\tawait unlinkIfPresent(handle.path);\n}\n"]}
1
+ {"version":3,"file":"manifest-lease.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/manifest-lease.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport {\n\terrorCode,\n\tpublishExclusive,\n\tpublishReplace,\n\treadLeaseText,\n\treclaimInspected,\n\tunlinkIfPresent,\n} from \"./lease-file.ts\";\nimport {\n\townProcessStartedAtMs,\n\tPROCESS_START_TOLERANCE_MS,\n\tprocessBootAtMs,\n\tsameProcessStart,\n} from \"./process-identity.ts\";\nimport { readProcessStartMs as defaultReadProcessStartMs } from \"./process-start-probe.ts\";\n\nexport const LEASE_RECORD_VERSION = 2;\n\nexport interface LeaseSelfIdentity {\n\treadonly pid: number;\n\treadonly bootAtMs: number;\n\treadonly processStartedAtMs: number;\n}\n\n/**\n * `startedAtMs` duplicates `acquiredAtMs` on purpose: a senpi build that still runs the v1 lease\n * reader parses `{pid, startedAtMs}` and must not see this file as unparseable (which it reclaims).\n */\nexport interface LeaseRecord {\n\treadonly v?: number;\n\treadonly token?: string;\n\treadonly pid: number;\n\treadonly startedAtMs: number;\n\treadonly bootAtMs?: number;\n\treadonly processStartedAtMs?: number;\n\treadonly acquiredAtMs?: number;\n}\n\nexport interface LeaseHolder {\n\treadonly pid: number;\n\treadonly startedAtMs: number;\n\treadonly bootAtMs?: number;\n}\n\nexport type AcquireTerminalLeaseOptions = {\n\tdir: string;\n\tencodedSessionId: string;\n\tpid?: number;\n\tnow?: () => number;\n\tself?: LeaseSelfIdentity;\n\tisProcessAlive?: (pid: number) => boolean;\n\treadProcessStartMs?: (pid: number) => Promise<number | undefined>;\n};\n\nexport type AcquireTerminalLeaseResult =\n\t| { acquired: true; path: string; pid: number; token: string }\n\t| { acquired: false; holder: LeaseHolder };\n\nexport type LeaseClassification = \"self\" | \"dead\" | \"reused\" | \"live-foreign\";\n\nconst generationTokens = new Map<string, string>();\n/**\n * Tokens held by generations of THIS process that are still running. A same-pid lease is a live\n * holder only when its token is here (a sibling session generation, or a racing waiter that won);\n * a token that is not here was minted by a generation that has shut down, even one whose\n * shutdown never reached the release (the 10 s shutdown cap), so it is ours to re-enter.\n */\nconst liveTokens = new Set<string>();\n\nexport function currentLeaseToken(encodedSessionId: string): string | undefined {\n\treturn generationTokens.get(encodedSessionId);\n}\n\n/** Mark a generation's token dead the moment its shutdown starts, before any slow flush. */\nexport function retireLeaseToken(token: string): void {\n\tliveTokens.delete(token);\n}\n\nfunction probeAlive(pid: number, probe?: (pid: number) => boolean): boolean {\n\ttry {\n\t\tif (probe) return probe(pid);\n\t\tprocess.kill(pid, 0);\n\t\treturn true;\n\t} catch (error) {\n\t\tconst code = errorCode(error);\n\t\tif (code === \"EPERM\") return true;\n\t\tif (code === \"ESRCH\") return false;\n\t\tthrow error;\n\t}\n}\n\nconst isFiniteNumber = (value: unknown): value is number => typeof value === \"number\" && Number.isFinite(value);\n\nexport function readLeaseRecord(raw: string): LeaseRecord | \"unparseable\" {\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(raw);\n\t\tif (typeof parsed !== \"object\" || parsed === null) return \"unparseable\";\n\t\tconst candidate = parsed as Record<string, unknown>;\n\t\tif (!isFiniteNumber(candidate.pid) || !isFiniteNumber(candidate.startedAtMs)) return \"unparseable\";\n\t\treturn {\n\t\t\tpid: candidate.pid,\n\t\t\tstartedAtMs: candidate.startedAtMs,\n\t\t\t...(isFiniteNumber(candidate.v) ? { v: candidate.v } : {}),\n\t\t\t...(typeof candidate.token === \"string\" ? { token: candidate.token } : {}),\n\t\t\t...(isFiniteNumber(candidate.bootAtMs) ? { bootAtMs: candidate.bootAtMs } : {}),\n\t\t\t...(isFiniteNumber(candidate.processStartedAtMs) ? { processStartedAtMs: candidate.processStartedAtMs } : {}),\n\t\t\t...(isFiniteNumber(candidate.acquiredAtMs) ? { acquiredAtMs: candidate.acquiredAtMs } : {}),\n\t\t};\n\t} catch {\n\t\treturn \"unparseable\";\n\t}\n}\n\nasync function readLeaseFile(path: string): Promise<LeaseRecord | \"missing\" | \"unparseable\"> {\n\tconst raw = await readLeaseText(path);\n\treturn raw === undefined ? \"missing\" : readLeaseRecord(raw);\n}\n\n/**\n * Decide what an existing lease is. A pid alone is never trusted: the holder is alive only when\n * its pid answers AND its recorded start instant matches the process now wearing that pid\n * (probed on this cold path only). A boot mismatch alone never reclaims an alive pid. Our own\n * pid is \"self\" only when the file carries the token this process minted for the session (or a\n * legacy record without one): a multi-session host holds many sessions under one pid, and a\n * lease another live generation in this process owns is a live holder, not a re-entry.\n */\nexport async function classifyLease(\n\texisting: LeaseRecord,\n\tself: LeaseSelfIdentity,\n\tprobes: {\n\t\treadonly isProcessAlive?: (pid: number) => boolean;\n\t\treadonly readProcessStartMs: (pid: number) => Promise<number | undefined>;\n\t\treadonly liveTokens?: ReadonlySet<string>;\n\t},\n): Promise<LeaseClassification> {\n\tif (existing.pid === self.pid) {\n\t\tif (existing.token !== undefined && (probes.liveTokens ?? liveTokens).has(existing.token)) return \"live-foreign\";\n\t\treturn \"self\";\n\t}\n\tif (!probeAlive(existing.pid, probes.isProcessAlive)) return \"dead\";\n\tlet observedStart: number | undefined;\n\ttry {\n\t\tobservedStart = await probes.readProcessStartMs(existing.pid);\n\t} catch {\n\t\tobservedStart = undefined;\n\t}\n\tif (observedStart === undefined) return \"live-foreign\";\n\tif (existing.processStartedAtMs === undefined) {\n\t\t// A v1 record's startedAtMs is when the lease was taken, so its holder started no later\n\t\t// than that; a process that started afterwards on the same pid is a reuse.\n\t\treturn observedStart <= existing.startedAtMs + PROCESS_START_TOLERANCE_MS ? \"live-foreign\" : \"reused\";\n\t}\n\treturn sameProcessStart(existing.processStartedAtMs, observedStart) ? \"live-foreign\" : \"reused\";\n}\n\nfunction holderOf(record: LeaseRecord): LeaseHolder {\n\treturn {\n\t\tpid: record.pid,\n\t\tstartedAtMs: record.startedAtMs,\n\t\t...(record.bootAtMs !== undefined ? { bootAtMs: record.bootAtMs } : {}),\n\t};\n}\n\nexport async function acquireTerminalLease(options: AcquireTerminalLeaseOptions): Promise<AcquireTerminalLeaseResult> {\n\tconst now = (options.now ?? Date.now)();\n\tconst self: LeaseSelfIdentity = options.self ?? {\n\t\tpid: options.pid ?? process.pid,\n\t\tbootAtMs: processBootAtMs(),\n\t\tprocessStartedAtMs: ownProcessStartedAtMs(),\n\t};\n\tconst pid = options.pid ?? self.pid;\n\tconst path = join(options.dir, `${options.encodedSessionId}.lease`);\n\tawait mkdir(options.dir, { recursive: true });\n\tconst token = randomUUID();\n\tconst record: LeaseRecord = {\n\t\tv: LEASE_RECORD_VERSION,\n\t\ttoken,\n\t\tpid,\n\t\tstartedAtMs: now,\n\t\tbootAtMs: self.bootAtMs,\n\t\tprocessStartedAtMs: self.processStartedAtMs,\n\t\tacquiredAtMs: now,\n\t};\n\tconst acquired = (): AcquireTerminalLeaseResult => {\n\t\tgenerationTokens.set(options.encodedSessionId, token);\n\t\tliveTokens.add(token);\n\t\treturn { acquired: true, path, pid, token };\n\t};\n\tconst probes = {\n\t\tisProcessAlive: options.isProcessAlive,\n\t\treadProcessStartMs: options.readProcessStartMs ?? defaultReadProcessStartMs,\n\t};\n\tconst content = JSON.stringify(record);\n\tfor (let attempt = 0; attempt < 3; attempt += 1) {\n\t\ttry {\n\t\t\tawait publishExclusive(path, content);\n\t\t\treturn acquired();\n\t\t} catch (error) {\n\t\t\tif (errorCode(error) !== \"EEXIST\") throw error;\n\t\t}\n\t\tconst raw = await readLeaseText(path);\n\t\tif (raw === undefined) continue;\n\t\tconst existing = readLeaseRecord(raw);\n\t\tconst verdict = existing === \"unparseable\" ? \"dead\" : await classifyLease(existing, { ...self, pid }, probes);\n\t\tif (verdict === \"self\") {\n\t\t\tawait publishReplace(path, content);\n\t\t\treturn acquired();\n\t\t}\n\t\tif (verdict === \"live-foreign\" && existing !== \"unparseable\")\n\t\t\treturn { acquired: false, holder: holderOf(existing) };\n\t\t// Only the record judged stale is removed; a racer's fresh lease makes the next try lose cleanly.\n\t\tconst reclaim = await reclaimInspected(path, raw, probes);\n\t\t// Someone is reclaiming right now: wait on that live process, never on the stale record.\n\t\tif (reclaim.outcome === \"busy\" && reclaim.holder !== undefined) {\n\t\t\tconst { pid: holderPid, processStartedAtMs, bootAtMs } = reclaim.holder;\n\t\t\treturn { acquired: false, holder: { pid: holderPid, startedAtMs: processStartedAtMs, bootAtMs } };\n\t\t}\n\t}\n\tconst raw = await readLeaseText(path);\n\tconst last = raw === undefined ? \"unparseable\" : readLeaseRecord(raw);\n\tif (last !== \"unparseable\" && (await classifyLease(last, { ...self, pid }, probes)) === \"live-foreign\") {\n\t\treturn { acquired: false, holder: holderOf(last) };\n\t}\n\tthrow new Error(`terminal lease ${path} kept changing while it was being acquired`);\n}\n\n/** Release only the generation that acquired: a stale release from an earlier generation is a no-op. */\nexport async function releaseTerminalLease(handle: { path: string; pid: number; token?: string }): Promise<void> {\n\tconst existing = await readLeaseFile(handle.path);\n\tif (existing === \"missing\" || existing === \"unparseable\") return;\n\tif (existing.pid !== handle.pid) return;\n\tif (handle.token !== undefined && existing.token !== undefined && existing.token !== handle.token) return;\n\tawait unlinkIfPresent(handle.path);\n\tif (existing.token !== undefined) {\n\t\tliveTokens.delete(existing.token);\n\t\tfor (const [sessionId, token] of generationTokens)\n\t\t\tif (token === existing.token) generationTokens.delete(sessionId);\n\t}\n}\n"]}
@@ -111,6 +111,8 @@ export declare class MonitorRegistry {
111
111
  } | undefined;
112
112
  /** Emit one restored-watch line through the SAME sink a live watch uses (coalescing, wake budget). */
113
113
  emitFileLine(id: string, line: string): boolean;
114
+ /** Inject one line into a live command or file watch's event stream (e.g. a restore notice). */
115
+ emitLine(id: string, line: string): boolean;
114
116
  stopFile(id: string): Promise<boolean>;
115
117
  stopAllFiles(): Promise<number>;
116
118
  register(options: RegisterMonitorOptions): string;
@@ -1 +1 @@
1
- {"version":3,"file":"monitor-registry.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/monitor-registry.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACX,yBAAyB,IAAI,iBAAiB,EAC9C,0BAA0B,IAAI,kBAAkB,EAChD,MAAM,2BAA2B,CAAC;AAInC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEnE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAGrE,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,YAAY,GAAG,gBAAgB,GAAG,mBAAmB,CAAC;AAElE,MAAM,MAAM,kBAAkB,GAAG,SAAS,GAAG,YAAY,GAAG,WAAW,CAAC;AAExE,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC9B;AAID,gGAAgG;AAChG,wBAAgB,iBAAiB,IAAI,MAAM,CAa1C;AAED,MAAM,MAAM,iBAAiB,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AACnE,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,6FAA6F;IAC7F,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,2FAA2F;IAC3F,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,2FAA2F;IAC3F,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,CAAC,EAAE,iBAAiB,CAAC;CACxC;AAED,YAAY,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,CAAC;AAEtD,MAAM,WAAW,sBAAsB;IACtC,uGAAuG;IACvG,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,SAAS,oBAAoB,EAAE,KAAK,IAAI,CAAC;IACxE,gGAAgG;IAChG,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,SAAS,oBAAoB,EAAE,KAAK,IAAI,CAAC;IACtE,sEAAsE;IACtE,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACtD,qEAAqE;IACrE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAC;CAC7C;AAED,MAAM,WAAW,0BAA0B;IAC1C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,mFAAmF;IACnF,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACpC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,gGAAgG;IAChG,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,mFAAmF;IACnF,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,sBAAsB,CAAC;IACzC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,4FAA4F;IAC5F,QAAQ,CAAC,eAAe,CAAC,EAAE,sBAAsB,CAAC;IAClD,yFAAyF;IACzF,QAAQ,CAAC,UAAU,CAAC,EAAE,iBAAiB,CAAC;IACxC,4EAA4E;IAC5E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC5B;AAoED;;;;GAIG;AACH,qBAAa,eAAe;;IAe3B,YAAY,IAAI,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,EAAE,OAAO,CAAC,EAAE,sBAAsB,EAMhF;IAED,oFAAoF;IACpF,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,IAAI,CAO/B;IAED,QAAQ,IAAI,SAAS,oBAAoB,EAAE,CAgB1C;IAEK,YAAY,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CA+LlG;IAED,6FAA6F;IAC7F,cAAc,CAAC,EAAE,EAAE,MAAM;;;;;;;kBAKxB;IAED,sGAAsG;IACtG,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAK9C;IAEK,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAK3C;IAEK,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAMpC;IA8HD,QAAQ,CAAC,OAAO,EAAE,sBAAsB,GAAG,MAAM,CAkChD;IAED,KAAK,CAAC,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAWtC;IAED,QAAQ,IAAI,MAAM,EAAE,CAEnB;IAED,MAAM,CAAC,GAAG,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,mBAAmB,EAAE,CAgBrD;IAED,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE/B;IAED,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,kBAAkB,CAMpC;IAED,+GAA+G;IAC/G,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,iBAAiB,GAAG,OAAO,CAOzE;IAED,OAAO,IAAI,IAAI,CAQd;CAsID"}
1
+ {"version":3,"file":"monitor-registry.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/monitor-registry.ts"],"names":[],"mappings":"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"}
@@ -232,6 +232,7 @@ export class MonitorRegistry {
232
232
  cleanupRegistration();
233
233
  throw new Error("Cannot create file monitor: monitor registry is disposed.");
234
234
  }
235
+ const persistent = options.persistent ?? options.expiresAt !== undefined;
235
236
  const record = {
236
237
  id,
237
238
  monitorId: options.monitorId ?? allocateMonitorId(),
@@ -240,10 +241,8 @@ export class MonitorRegistry {
240
241
  startedAtMs: Date.now(),
241
242
  command: null,
242
243
  filter: null,
243
- persistent: options.persistent ?? options.expiresAt !== undefined,
244
- deadlineMs: (options.persistent ?? options.expiresAt !== undefined)
245
- ? null
246
- : (options.deadlineMs ?? Date.now() + options.timeoutMs),
244
+ persistent,
245
+ deadlineMs: persistent ? null : (options.deadlineMs ?? Date.now() + options.timeoutMs),
247
246
  fireCount: 0,
248
247
  lastFiredAtMs: null,
249
248
  expiresAt: options.expiresAt,
@@ -267,11 +266,13 @@ export class MonitorRegistry {
267
266
  dirtyPasses: 0,
268
267
  dirtyWindowStartedAt: 0,
269
268
  checking: undefined,
270
- deadline: setTimeout(() => {
271
- const current = this.#files.get(id);
272
- if (current)
273
- this.#settleFile(current, "watcher timed_out");
274
- }, options.timeoutMs),
269
+ deadline: persistent
270
+ ? undefined
271
+ : setTimeout(() => {
272
+ const current = this.#files.get(id);
273
+ if (current)
274
+ this.#settleFile(current, "watcher timed_out");
275
+ }, options.timeoutMs),
275
276
  };
276
277
  this.#files.set(id, record);
277
278
  if (this.#parked)
@@ -292,7 +293,11 @@ export class MonitorRegistry {
292
293
  }
293
294
  /** Emit one restored-watch line through the SAME sink a live watch uses (coalescing, wake budget). */
294
295
  emitFileLine(id, line) {
295
- const record = this.#files.get(id);
296
+ return this.#files.has(id) && this.emitLine(id, line);
297
+ }
298
+ /** Inject one line into a live command or file watch's event stream (e.g. a restore notice). */
299
+ emitLine(id, line) {
300
+ const record = this.#records.get(id) ?? this.#files.get(id);
296
301
  if (!record || record.settled)
297
302
  return false;
298
303
  this.#emitForRecord(record, { type: "line", id: record.id, description: record.description, line });