@code-yeongyu/senpi 2026.9.4-3 → 2026.9.5-2

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 (191) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/dist/core/agent-session.d.ts +17 -1
  3. package/dist/core/agent-session.d.ts.map +1 -1
  4. package/dist/core/agent-session.js +82 -2
  5. package/dist/core/agent-session.js.map +1 -1
  6. package/dist/core/compaction/compaction.d.ts.map +1 -1
  7. package/dist/core/compaction/compaction.js +4 -0
  8. package/dist/core/compaction/compaction.js.map +1 -1
  9. package/dist/core/extensions/builtin/claude-sdk-oauth/prompt-bridge.d.ts.map +1 -1
  10. package/dist/core/extensions/builtin/claude-sdk-oauth/prompt-bridge.js +2 -0
  11. package/dist/core/extensions/builtin/claude-sdk-oauth/prompt-bridge.js.map +1 -1
  12. package/dist/core/extensions/builtin/compaction/model-usability-budget.d.ts +5 -0
  13. package/dist/core/extensions/builtin/compaction/model-usability-budget.d.ts.map +1 -1
  14. package/dist/core/extensions/builtin/compaction/model-usability-budget.js +11 -4
  15. package/dist/core/extensions/builtin/compaction/model-usability-budget.js.map +1 -1
  16. package/dist/core/extensions/builtin/compaction/openai-remote-convert.d.ts.map +1 -1
  17. package/dist/core/extensions/builtin/compaction/openai-remote-convert.js +2 -0
  18. package/dist/core/extensions/builtin/compaction/openai-remote-convert.js.map +1 -1
  19. package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.d.ts +10 -6
  20. package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.d.ts.map +1 -1
  21. package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.js +27 -12
  22. package/dist/core/extensions/builtin/prompt-preset/gpt-6-astra.js.map +1 -1
  23. package/dist/core/extensions/builtin/recommended-models/index.d.ts +1 -1
  24. package/dist/core/extensions/builtin/recommended-models/index.d.ts.map +1 -1
  25. package/dist/core/extensions/builtin/recommended-models/index.js +1 -0
  26. package/dist/core/extensions/builtin/recommended-models/index.js.map +1 -1
  27. package/dist/core/extensions/builtin/service-tier.d.ts.map +1 -1
  28. package/dist/core/extensions/builtin/service-tier.js +12 -4
  29. package/dist/core/extensions/builtin/service-tier.js.map +1 -1
  30. package/dist/core/extensions/builtin/terminal/durable-command.d.ts +31 -0
  31. package/dist/core/extensions/builtin/terminal/durable-command.d.ts.map +1 -0
  32. package/dist/core/extensions/builtin/terminal/durable-command.js +96 -0
  33. package/dist/core/extensions/builtin/terminal/durable-command.js.map +1 -0
  34. package/dist/core/extensions/builtin/terminal/durable-file.d.ts +42 -0
  35. package/dist/core/extensions/builtin/terminal/durable-file.d.ts.map +1 -0
  36. package/dist/core/extensions/builtin/terminal/durable-file.js +102 -0
  37. package/dist/core/extensions/builtin/terminal/durable-file.js.map +1 -0
  38. package/dist/core/extensions/builtin/terminal/extension.d.ts.map +1 -1
  39. package/dist/core/extensions/builtin/terminal/extension.js +58 -13
  40. package/dist/core/extensions/builtin/terminal/extension.js.map +1 -1
  41. package/dist/core/extensions/builtin/terminal/monitor-notify.d.ts.map +1 -1
  42. package/dist/core/extensions/builtin/terminal/monitor-notify.js +5 -1
  43. package/dist/core/extensions/builtin/terminal/monitor-notify.js.map +1 -1
  44. package/dist/core/extensions/builtin/terminal/monitor-registry.d.ts +29 -0
  45. package/dist/core/extensions/builtin/terminal/monitor-registry.d.ts.map +1 -1
  46. package/dist/core/extensions/builtin/terminal/monitor-registry.js +49 -0
  47. package/dist/core/extensions/builtin/terminal/monitor-registry.js.map +1 -1
  48. package/dist/core/extensions/builtin/terminal/monitor-status.d.ts.map +1 -1
  49. package/dist/core/extensions/builtin/terminal/monitor-status.js +21 -1
  50. package/dist/core/extensions/builtin/terminal/monitor-status.js.map +1 -1
  51. package/dist/core/extensions/builtin/terminal/prompt.d.ts.map +1 -1
  52. package/dist/core/extensions/builtin/terminal/prompt.js +9 -5
  53. package/dist/core/extensions/builtin/terminal/prompt.js.map +1 -1
  54. package/dist/core/extensions/builtin/terminal/restore.d.ts +13 -0
  55. package/dist/core/extensions/builtin/terminal/restore.d.ts.map +1 -1
  56. package/dist/core/extensions/builtin/terminal/restore.js +31 -3
  57. package/dist/core/extensions/builtin/terminal/restore.js.map +1 -1
  58. package/dist/core/extensions/builtin/terminal/shared.d.ts +25 -0
  59. package/dist/core/extensions/builtin/terminal/shared.d.ts.map +1 -1
  60. package/dist/core/extensions/builtin/terminal/shared.js +25 -0
  61. package/dist/core/extensions/builtin/terminal/shared.js.map +1 -1
  62. package/dist/core/extensions/builtin/terminal/terminal-manifest-model.d.ts +91 -0
  63. package/dist/core/extensions/builtin/terminal/terminal-manifest-model.d.ts.map +1 -0
  64. package/dist/core/extensions/builtin/terminal/terminal-manifest-model.js +14 -0
  65. package/dist/core/extensions/builtin/terminal/terminal-manifest-model.js.map +1 -0
  66. package/dist/core/extensions/builtin/terminal/terminal-manifest.d.ts +29 -77
  67. package/dist/core/extensions/builtin/terminal/terminal-manifest.d.ts.map +1 -1
  68. package/dist/core/extensions/builtin/terminal/terminal-manifest.js +61 -15
  69. package/dist/core/extensions/builtin/terminal/terminal-manifest.js.map +1 -1
  70. package/dist/core/extensions/builtin/terminal/tools/monitor.d.ts.map +1 -1
  71. package/dist/core/extensions/builtin/terminal/tools/monitor.js +59 -11
  72. package/dist/core/extensions/builtin/terminal/tools/monitor.js.map +1 -1
  73. package/dist/core/footer-data-provider.d.ts.map +1 -1
  74. package/dist/core/footer-data-provider.js +18 -1
  75. package/dist/core/footer-data-provider.js.map +1 -1
  76. package/dist/core/messages.d.ts +7 -0
  77. package/dist/core/messages.d.ts.map +1 -1
  78. package/dist/core/messages.js +2 -0
  79. package/dist/core/messages.js.map +1 -1
  80. package/dist/core/retry-fallback/chains.d.ts +1 -13
  81. package/dist/core/retry-fallback/chains.d.ts.map +1 -1
  82. package/dist/core/retry-fallback/chains.js +3 -49
  83. package/dist/core/retry-fallback/chains.js.map +1 -1
  84. package/dist/core/retry-fallback/controller.d.ts.map +1 -1
  85. package/dist/core/retry-fallback/controller.js +4 -9
  86. package/dist/core/retry-fallback/controller.js.map +1 -1
  87. package/dist/core/retry-fallback/expansion.js +1 -1
  88. package/dist/core/retry-fallback/expansion.js.map +1 -1
  89. package/dist/core/retry-fallback/settings.d.ts +2 -4
  90. package/dist/core/retry-fallback/settings.d.ts.map +1 -1
  91. package/dist/core/retry-fallback/settings.js +7 -36
  92. package/dist/core/retry-fallback/settings.js.map +1 -1
  93. package/dist/core/sdk.d.ts.map +1 -1
  94. package/dist/core/sdk.js +6 -1
  95. package/dist/core/sdk.js.map +1 -1
  96. package/dist/core/session-manager.d.ts +12 -1
  97. package/dist/core/session-manager.d.ts.map +1 -1
  98. package/dist/core/session-manager.js +29 -3
  99. package/dist/core/session-manager.js.map +1 -1
  100. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  101. package/dist/modes/interactive/interactive-mode.js +14 -2
  102. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  103. package/docs/settings.md +1 -0
  104. package/docs/terminal-tools.md +35 -4
  105. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +26 -0
  106. package/node_modules/@code-yeongyu/senpi-codemode/README.md +2 -2
  107. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
  108. package/node_modules/@code-yeongyu/senpi-codemode/src/extension/session-manager.ts +8 -4
  109. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/display-image.js +162 -0
  110. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/prelude.ts +2 -2
  111. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/js/worker-runtime.js +29 -60
  112. package/node_modules/@code-yeongyu/senpi-codemode/src/kernels/py/prelude.py +66 -1
  113. package/node_modules/@code-yeongyu/senpi-codemode/src/prompt/eval-prompt.ts +12 -7
  114. package/node_modules/@code-yeongyu/senpi-codemode/src/tool/types.ts +2 -2
  115. package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts.map +1 -1
  116. package/node_modules/@earendil-works/pi-agent-core/dist/agent.js +3 -1
  117. package/node_modules/@earendil-works/pi-agent-core/dist/agent.js.map +1 -1
  118. package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.d.ts.map +1 -1
  119. package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js +17 -0
  120. package/node_modules/@earendil-works/pi-agent-core/dist/harness/agent-harness.js.map +1 -1
  121. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.d.ts.map +1 -1
  122. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.js +1 -0
  123. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/branch-summarization.js.map +1 -1
  124. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.d.ts.map +1 -1
  125. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js +1 -0
  126. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js.map +1 -1
  127. package/node_modules/@earendil-works/pi-agent-core/dist/harness/reducer.d.ts.map +1 -1
  128. package/node_modules/@earendil-works/pi-agent-core/dist/harness/reducer.js +6 -0
  129. package/node_modules/@earendil-works/pi-agent-core/dist/harness/reducer.js.map +1 -1
  130. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/context.d.ts +2 -1
  131. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/context.d.ts.map +1 -1
  132. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/context.js +5 -1
  133. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/context.js.map +1 -1
  134. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl/codec.d.ts.map +1 -1
  135. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl/codec.js +1 -0
  136. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/jsonl/codec.js.map +1 -1
  137. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/types.d.ts +7 -1
  138. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/types.d.ts.map +1 -1
  139. package/node_modules/@earendil-works/pi-agent-core/dist/harness/session/types.js.map +1 -1
  140. package/node_modules/@earendil-works/pi-agent-core/dist/types.d.ts +2 -0
  141. package/node_modules/@earendil-works/pi-agent-core/dist/types.d.ts.map +1 -1
  142. package/node_modules/@earendil-works/pi-agent-core/dist/types.js.map +1 -1
  143. package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
  144. package/node_modules/@earendil-works/pi-ai/dist/api/mistral-conversations.js +2 -0
  145. package/node_modules/@earendil-works/pi-ai/dist/api/mistral-conversations.js.map +1 -1
  146. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.d.ts +1 -1
  147. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.d.ts.map +1 -1
  148. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js +3 -1
  149. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js.map +1 -1
  150. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.d.ts.map +1 -1
  151. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +14 -9
  152. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js.map +1 -1
  153. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.d.ts +3 -3
  154. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.d.ts.map +1 -1
  155. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.js +15 -0
  156. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses-shared.js.map +1 -1
  157. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.d.ts +1 -1
  158. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.d.ts.map +1 -1
  159. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js +6 -4
  160. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js.map +1 -1
  161. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts +30 -0
  162. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts.map +1 -1
  163. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js +30 -0
  164. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js.map +1 -1
  165. package/node_modules/@earendil-works/pi-ai/dist/models.d.ts +3 -1
  166. package/node_modules/@earendil-works/pi-ai/dist/models.d.ts.map +1 -1
  167. package/node_modules/@earendil-works/pi-ai/dist/models.js +27 -3
  168. package/node_modules/@earendil-works/pi-ai/dist/models.js.map +1 -1
  169. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  170. package/node_modules/@earendil-works/pi-ai/dist/providers/data/azure-openai-responses.json +1 -1
  171. package/node_modules/@earendil-works/pi-ai/dist/providers/data/fireworks.json +1 -1
  172. package/node_modules/@earendil-works/pi-ai/dist/providers/data/github-copilot.json +1 -1
  173. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openai-codex.json +1 -1
  174. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openai.json +1 -1
  175. package/node_modules/@earendil-works/pi-ai/dist/providers/data/opencode.json +1 -1
  176. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  177. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  178. package/node_modules/@earendil-works/pi-ai/dist/providers/faux.d.ts.map +1 -1
  179. package/node_modules/@earendil-works/pi-ai/dist/providers/faux.js +2 -0
  180. package/node_modules/@earendil-works/pi-ai/dist/providers/faux.js.map +1 -1
  181. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts +8 -1
  182. package/node_modules/@earendil-works/pi-ai/dist/types.d.ts.map +1 -1
  183. package/node_modules/@earendil-works/pi-ai/dist/types.js.map +1 -1
  184. package/node_modules/@earendil-works/pi-ai/dist/utils/estimate.d.ts.map +1 -1
  185. package/node_modules/@earendil-works/pi-ai/dist/utils/estimate.js +2 -0
  186. package/node_modules/@earendil-works/pi-ai/dist/utils/estimate.js.map +1 -1
  187. package/node_modules/@earendil-works/pi-ai/package.json +2 -2
  188. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  189. package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
  190. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  191. package/package.json +7 -7
@@ -30,6 +30,31 @@ export const BACKGROUND_START_GRACE_MS = 250;
30
30
  * the agent blocked forever.
31
31
  */
32
32
  export const KILLED_SESSION_EXIT_GRACE_MS = 5000;
33
+ /**
34
+ * Admission cap on durable (restart-surviving) monitors per session. Ephemeral monitors
35
+ * never count against it: only entries the manifest keeps across a restart do.
36
+ */
37
+ export const MAX_DURABLE_MONITORS = 5;
38
+ /**
39
+ * Absolute lifetime of a durable monitor, measured from its registration. It is a deadline,
40
+ * never a sliding window: neither a restore nor a rearm extends it.
41
+ */
42
+ export const DURABLE_MONITOR_EXPIRY_MS = 7 * 24 * 60 * 60 * 1000;
43
+ /**
44
+ * Per-monitor rolling fire budget: one durable command watch may deliver at most this many
45
+ * matched line events inside any FIRE_BUDGET_WINDOW_MS window before the registry auto-mutes
46
+ * it. The session-global wake budget only counts consecutive line-only wakes on an idle
47
+ * session, so a busy session needs this per-monitor backstop against a runaway watch.
48
+ */
49
+ export const DEFAULT_DURABLE_MONITOR_FIRE_BUDGET = 200;
50
+ /** Width of the rolling fire-budget window: the budget replenishes after this span elapses. */
51
+ export const FIRE_BUDGET_WINDOW_MS = 24 * 60 * 60 * 1000;
52
+ /**
53
+ * The ONE summary emitted when the fire budget mutes a watch. Machine-consumed: the monitor
54
+ * notifier exempts exactly this summary from its completion handling, so the mute must not
55
+ * clear the session-global wake streak.
56
+ */
57
+ export const FIRE_BUDGET_AUTO_MUTE_SUMMARY = `auto-muted: fire budget (${DEFAULT_DURABLE_MONITOR_FIRE_BUDGET}/24h) reached; rearm to resume`;
33
58
  /**
34
59
  * Non-interactive environment for foreground one-shot commands (codex-style):
35
60
  * cooperative tools (`gh`, `git`, pagers, color libs) skip spinners/colors at
@@ -1 +1 @@
1
- {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/shared.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared constants and helpers for the persistent-terminal builtin extension.\n */\n\nexport const TERMINAL_BASH_TOOL = \"bash\";\nexport const TERMINAL_OUTPUT_TOOL = \"bash_output\";\nexport const TERMINAL_KILL_TOOL = \"kill_bash\";\nexport const TERMINAL_INPUT_TOOL = \"bash_input\";\nexport const TERMINAL_RESIZE_TOOL = \"bash_resize\";\nexport const TERMINAL_MONITOR_TOOL = \"monitor\";\n\n/** Companion tools that must never dangle without a live PTY `bash`. */\nexport const TERMINAL_COMPANION_TOOLS = [\n\tTERMINAL_OUTPUT_TOOL,\n\tTERMINAL_KILL_TOOL,\n\tTERMINAL_INPUT_TOOL,\n\tTERMINAL_RESIZE_TOOL,\n\tTERMINAL_MONITOR_TOOL,\n] as const;\n\nexport const DEFAULT_COLS = 120;\nexport const DEFAULT_ROWS = 40;\nexport const DEFAULT_SCROLLBACK = 10_000;\nexport const DEFAULT_MAX_SESSIONS = 32;\n/** Upper bound on decoded output retained per session for delta reads and `view:\"log\"`. */\nexport const MAX_SESSION_OUTPUT_CHARS = 1_000_000;\n/** Grace window used to capture a background command's early output before returning its id. */\nexport const BACKGROUND_START_GRACE_MS = 250;\n/**\n * After a foreground session has been killed (abort or timeout), how long to keep\n * waiting for its exit to settle before releasing the tool anyway. A surviving\n * descendant that holds the PTY open (or a kill that never lands) must not keep\n * the agent blocked forever.\n */\nexport const KILLED_SESSION_EXIT_GRACE_MS = 5000;\n\n/**\n * Non-interactive environment for foreground one-shot commands (codex-style):\n * cooperative tools (`gh`, `git`, pagers, color libs) skip spinners/colors at\n * the source instead of flooding the captured stream with redraw frames.\n * Background sessions keep the user's real TERM for interactive apps.\n */\nexport const FOREGROUND_ENV_OVERRIDES: Readonly<Record<string, string>> = {\n\tNO_COLOR: \"1\",\n\tTERM: \"dumb\",\n\tCOLORTERM: \"\",\n\tPAGER: \"cat\",\n\tGIT_PAGER: \"cat\",\n\tGH_PAGER: \"cat\",\n};\n\n/**\n * Named-key aliases the model can send via `bash_input {keys:[...]}`. Values are the\n * raw byte sequences a PTY expects (control chars + xterm cursor/function escapes).\n */\nconst KEY_SEQUENCES: Record<string, string> = {\n\tenter: \"\\r\",\n\treturn: \"\\r\",\n\ttab: \"\\t\",\n\tescape: \"\\x1b\",\n\tesc: \"\\x1b\",\n\tspace: \" \",\n\tbackspace: \"\\x7f\",\n\tdelete: \"\\x1b[3~\",\n\tup: \"\\x1b[A\",\n\tdown: \"\\x1b[B\",\n\tright: \"\\x1b[C\",\n\tleft: \"\\x1b[D\",\n\thome: \"\\x1b[H\",\n\tend: \"\\x1b[F\",\n\tpageup: \"\\x1b[5~\",\n\tpagedown: \"\\x1b[6~\",\n\t\"ctrl+c\": \"\\x03\",\n\t\"ctrl+d\": \"\\x04\",\n\t\"ctrl+z\": \"\\x1a\",\n\t\"ctrl+l\": \"\\x0c\",\n\t\"ctrl+u\": \"\\x15\",\n\t\"ctrl+a\": \"\\x01\",\n\t\"ctrl+e\": \"\\x05\",\n\t\"ctrl+\\\\\": \"\\x1c\",\n};\n\n/** Resolve a single named key to its PTY byte sequence, or null when unknown. */\nexport function resolveKeySequence(key: string): string | null {\n\tconst normalized = key.trim().toLowerCase();\n\tif (normalized.length === 0) return null;\n\tconst mapped = KEY_SEQUENCES[normalized];\n\tif (mapped !== undefined) return mapped;\n\t// Single printable character passes through verbatim.\n\tif ([...normalized].length === 1) return key;\n\treturn null;\n}\n\n/** Build a PTY-ready payload from a list of named keys, returning the unknown keys too. */\nexport function encodeKeys(keys: readonly string[]): { data: string; unknown: string[] } {\n\tlet data = \"\";\n\tconst unknown: string[] = [];\n\tfor (const key of keys) {\n\t\tconst sequence = resolveKeySequence(key);\n\t\tif (sequence === null) unknown.push(key);\n\t\telse data += sequence;\n\t}\n\treturn { data, unknown };\n}\n\n/** Compile a user-supplied regex, tolerating invalid patterns by returning null. */\nexport function safeRegExp(pattern: string): RegExp | null {\n\ttry {\n\t\treturn new RegExp(pattern);\n\t} catch {\n\t\treturn null;\n\t}\n}\n"]}
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/shared.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared constants and helpers for the persistent-terminal builtin extension.\n */\n\nexport const TERMINAL_BASH_TOOL = \"bash\";\nexport const TERMINAL_OUTPUT_TOOL = \"bash_output\";\nexport const TERMINAL_KILL_TOOL = \"kill_bash\";\nexport const TERMINAL_INPUT_TOOL = \"bash_input\";\nexport const TERMINAL_RESIZE_TOOL = \"bash_resize\";\nexport const TERMINAL_MONITOR_TOOL = \"monitor\";\n\n/** Companion tools that must never dangle without a live PTY `bash`. */\nexport const TERMINAL_COMPANION_TOOLS = [\n\tTERMINAL_OUTPUT_TOOL,\n\tTERMINAL_KILL_TOOL,\n\tTERMINAL_INPUT_TOOL,\n\tTERMINAL_RESIZE_TOOL,\n\tTERMINAL_MONITOR_TOOL,\n] as const;\n\nexport const DEFAULT_COLS = 120;\nexport const DEFAULT_ROWS = 40;\nexport const DEFAULT_SCROLLBACK = 10_000;\nexport const DEFAULT_MAX_SESSIONS = 32;\n/** Upper bound on decoded output retained per session for delta reads and `view:\"log\"`. */\nexport const MAX_SESSION_OUTPUT_CHARS = 1_000_000;\n/** Grace window used to capture a background command's early output before returning its id. */\nexport const BACKGROUND_START_GRACE_MS = 250;\n/**\n * After a foreground session has been killed (abort or timeout), how long to keep\n * waiting for its exit to settle before releasing the tool anyway. A surviving\n * descendant that holds the PTY open (or a kill that never lands) must not keep\n * the agent blocked forever.\n */\nexport const KILLED_SESSION_EXIT_GRACE_MS = 5000;\n\n/**\n * Admission cap on durable (restart-surviving) monitors per session. Ephemeral monitors\n * never count against it: only entries the manifest keeps across a restart do.\n */\nexport const MAX_DURABLE_MONITORS = 5;\n/**\n * Absolute lifetime of a durable monitor, measured from its registration. It is a deadline,\n * never a sliding window: neither a restore nor a rearm extends it.\n */\nexport const DURABLE_MONITOR_EXPIRY_MS = 7 * 24 * 60 * 60 * 1000;\n/**\n * Per-monitor rolling fire budget: one durable command watch may deliver at most this many\n * matched line events inside any FIRE_BUDGET_WINDOW_MS window before the registry auto-mutes\n * it. The session-global wake budget only counts consecutive line-only wakes on an idle\n * session, so a busy session needs this per-monitor backstop against a runaway watch.\n */\nexport const DEFAULT_DURABLE_MONITOR_FIRE_BUDGET = 200;\n/** Width of the rolling fire-budget window: the budget replenishes after this span elapses. */\nexport const FIRE_BUDGET_WINDOW_MS = 24 * 60 * 60 * 1000;\n/**\n * The ONE summary emitted when the fire budget mutes a watch. Machine-consumed: the monitor\n * notifier exempts exactly this summary from its completion handling, so the mute must not\n * clear the session-global wake streak.\n */\nexport const FIRE_BUDGET_AUTO_MUTE_SUMMARY = `auto-muted: fire budget (${DEFAULT_DURABLE_MONITOR_FIRE_BUDGET}/24h) reached; rearm to resume`;\n\n/**\n * Non-interactive environment for foreground one-shot commands (codex-style):\n * cooperative tools (`gh`, `git`, pagers, color libs) skip spinners/colors at\n * the source instead of flooding the captured stream with redraw frames.\n * Background sessions keep the user's real TERM for interactive apps.\n */\nexport const FOREGROUND_ENV_OVERRIDES: Readonly<Record<string, string>> = {\n\tNO_COLOR: \"1\",\n\tTERM: \"dumb\",\n\tCOLORTERM: \"\",\n\tPAGER: \"cat\",\n\tGIT_PAGER: \"cat\",\n\tGH_PAGER: \"cat\",\n};\n\n/**\n * Named-key aliases the model can send via `bash_input {keys:[...]}`. Values are the\n * raw byte sequences a PTY expects (control chars + xterm cursor/function escapes).\n */\nconst KEY_SEQUENCES: Record<string, string> = {\n\tenter: \"\\r\",\n\treturn: \"\\r\",\n\ttab: \"\\t\",\n\tescape: \"\\x1b\",\n\tesc: \"\\x1b\",\n\tspace: \" \",\n\tbackspace: \"\\x7f\",\n\tdelete: \"\\x1b[3~\",\n\tup: \"\\x1b[A\",\n\tdown: \"\\x1b[B\",\n\tright: \"\\x1b[C\",\n\tleft: \"\\x1b[D\",\n\thome: \"\\x1b[H\",\n\tend: \"\\x1b[F\",\n\tpageup: \"\\x1b[5~\",\n\tpagedown: \"\\x1b[6~\",\n\t\"ctrl+c\": \"\\x03\",\n\t\"ctrl+d\": \"\\x04\",\n\t\"ctrl+z\": \"\\x1a\",\n\t\"ctrl+l\": \"\\x0c\",\n\t\"ctrl+u\": \"\\x15\",\n\t\"ctrl+a\": \"\\x01\",\n\t\"ctrl+e\": \"\\x05\",\n\t\"ctrl+\\\\\": \"\\x1c\",\n};\n\n/** Resolve a single named key to its PTY byte sequence, or null when unknown. */\nexport function resolveKeySequence(key: string): string | null {\n\tconst normalized = key.trim().toLowerCase();\n\tif (normalized.length === 0) return null;\n\tconst mapped = KEY_SEQUENCES[normalized];\n\tif (mapped !== undefined) return mapped;\n\t// Single printable character passes through verbatim.\n\tif ([...normalized].length === 1) return key;\n\treturn null;\n}\n\n/** Build a PTY-ready payload from a list of named keys, returning the unknown keys too. */\nexport function encodeKeys(keys: readonly string[]): { data: string; unknown: string[] } {\n\tlet data = \"\";\n\tconst unknown: string[] = [];\n\tfor (const key of keys) {\n\t\tconst sequence = resolveKeySequence(key);\n\t\tif (sequence === null) unknown.push(key);\n\t\telse data += sequence;\n\t}\n\treturn { data, unknown };\n}\n\n/** Compile a user-supplied regex, tolerating invalid patterns by returning null. */\nexport function safeRegExp(pattern: string): RegExp | null {\n\ttry {\n\t\treturn new RegExp(pattern);\n\t} catch {\n\t\treturn null;\n\t}\n}\n"]}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * The terminal manifest's data model: the durable per-session record of live monitors and
3
+ * background sessions that `restore.ts` strict-parses back after a restart. Types and the
4
+ * constants that govern them live here; all runtime behaviour is in `terminal-manifest.ts`.
5
+ */
6
+ import type { SessionManager } from "../../../session-manager.ts";
7
+ export declare const TERMINAL_MANIFEST_VERSION = 1;
8
+ /** Minimum debounce for checkpoint writes; a burst inside this window collapses to one write. */
9
+ export declare const TERMINAL_MANIFEST_CHECKPOINT_DEBOUNCE_MS = 30000;
10
+ /**
11
+ * Re-exported so manifest consumers read one durability deadline. The value lives in
12
+ * `shared.ts` with the rest of the terminal caps; there is exactly one definition of it.
13
+ */
14
+ export { DURABLE_MONITOR_EXPIRY_MS } from "./shared.ts";
15
+ export type TerminalManifestSession = Pick<SessionManager, "getSessionDir" | "getSessionId">;
16
+ export type MonitorRuntimeKind = "command" | "file";
17
+ export type MonitorDurabilityClass = "ephemeral" | "restartable-command" | "checkpointed-file";
18
+ /**
19
+ * File-monitor checkpoint persisted by the writer: the registry's live identity tuple. `digest`
20
+ * is required — without it a same-size, same-mtime rewrite is undetectable across a restart.
21
+ */
22
+ export interface TerminalManifestCheckpoint {
23
+ readonly dev: number;
24
+ readonly ino: number;
25
+ readonly size: number;
26
+ readonly mtimeMs: number;
27
+ readonly digest: string;
28
+ readonly present: boolean;
29
+ }
30
+ export interface ManifestMonitor {
31
+ readonly monitorId: string;
32
+ /** Owning agent session id — never the bash_N/watch_N runtime id. */
33
+ readonly sessionId: string;
34
+ readonly description: string;
35
+ readonly runtimeKind: MonitorRuntimeKind;
36
+ readonly durabilityClass: MonitorDurabilityClass;
37
+ readonly command?: string;
38
+ readonly path?: string;
39
+ readonly event?: "create" | "modify";
40
+ readonly filter?: string;
41
+ readonly cwd?: string;
42
+ readonly approvedParent?: string;
43
+ readonly createdAt: number;
44
+ readonly expiresAt: number | null;
45
+ readonly persistent: boolean;
46
+ readonly suspended: boolean;
47
+ readonly lastCheckpoint: TerminalManifestCheckpoint | null;
48
+ readonly deliveryPaused: boolean;
49
+ readonly fireWindow: {
50
+ startMs: number;
51
+ count: number;
52
+ };
53
+ }
54
+ export interface ManifestBackgroundSession {
55
+ readonly id: string;
56
+ readonly command: string;
57
+ readonly startedAtMs: number;
58
+ }
59
+ export interface TerminalManifest {
60
+ readonly version: typeof TERMINAL_MANIFEST_VERSION;
61
+ readonly sessionId: string;
62
+ readonly monitors: readonly ManifestMonitor[];
63
+ readonly backgroundSessions: readonly ManifestBackgroundSession[];
64
+ readonly updatedAt: number;
65
+ }
66
+ /** What the monitor tool captures at its call site — the only place the branch inputs live. */
67
+ export interface CommandMonitorSpec {
68
+ readonly kind: "command";
69
+ readonly description: string;
70
+ readonly command: string;
71
+ readonly filter?: string;
72
+ readonly cwd?: string;
73
+ readonly persistent: boolean;
74
+ }
75
+ export interface FileMonitorSpec {
76
+ readonly kind: "file";
77
+ readonly description: string;
78
+ readonly path: string;
79
+ readonly event: "create" | "modify";
80
+ readonly timeoutMs: number;
81
+ readonly cwd: string;
82
+ readonly approvedParent?: string;
83
+ /** Persistent file watches are the durable `checkpointed-file` class; one-shot ones stay ephemeral. */
84
+ readonly persistent: boolean;
85
+ }
86
+ export type MonitorSpec = CommandMonitorSpec | FileMonitorSpec;
87
+ export interface MonitorRegistration {
88
+ readonly monitorId: string;
89
+ readonly spec: MonitorSpec;
90
+ }
91
+ //# sourceMappingURL=terminal-manifest-model.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal-manifest-model.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/terminal-manifest-model.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * The terminal manifest's data model: the durable per-session record of live monitors and
3
+ * background sessions that `restore.ts` strict-parses back after a restart. Types and the
4
+ * constants that govern them live here; all runtime behaviour is in `terminal-manifest.ts`.
5
+ */
6
+ export const TERMINAL_MANIFEST_VERSION = 1;
7
+ /** Minimum debounce for checkpoint writes; a burst inside this window collapses to one write. */
8
+ export const TERMINAL_MANIFEST_CHECKPOINT_DEBOUNCE_MS = 30_000;
9
+ /**
10
+ * Re-exported so manifest consumers read one durability deadline. The value lives in
11
+ * `shared.ts` with the rest of the terminal caps; there is exactly one definition of it.
12
+ */
13
+ export { DURABLE_MONITOR_EXPIRY_MS } from "./shared.js";
14
+ //# sourceMappingURL=terminal-manifest-model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"terminal-manifest-model.js","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/terminal-manifest-model.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC;AAC3C,iGAAiG;AACjG,MAAM,CAAC,MAAM,wCAAwC,GAAG,MAAM,CAAC;AAC/D;;;GAGG;AACH,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC","sourcesContent":["/**\n * The terminal manifest's data model: the durable per-session record of live monitors and\n * background sessions that `restore.ts` strict-parses back after a restart. Types and the\n * constants that govern them live here; all runtime behaviour is in `terminal-manifest.ts`.\n */\n\nimport type { SessionManager } from \"../../../session-manager.ts\";\n\nexport const TERMINAL_MANIFEST_VERSION = 1;\n/** Minimum debounce for checkpoint writes; a burst inside this window collapses to one write. */\nexport const TERMINAL_MANIFEST_CHECKPOINT_DEBOUNCE_MS = 30_000;\n/**\n * Re-exported so manifest consumers read one durability deadline. The value lives in\n * `shared.ts` with the rest of the terminal caps; there is exactly one definition of it.\n */\nexport { DURABLE_MONITOR_EXPIRY_MS } from \"./shared.ts\";\nexport type TerminalManifestSession = Pick<SessionManager, \"getSessionDir\" | \"getSessionId\">;\nexport type MonitorRuntimeKind = \"command\" | \"file\";\nexport type MonitorDurabilityClass = \"ephemeral\" | \"restartable-command\" | \"checkpointed-file\";\n/**\n * File-monitor checkpoint persisted by the writer: the registry's live identity tuple. `digest`\n * is required — without it a same-size, same-mtime rewrite is undetectable across a restart.\n */\nexport interface TerminalManifestCheckpoint {\n\treadonly dev: number;\n\treadonly ino: number;\n\treadonly size: number;\n\treadonly mtimeMs: number;\n\treadonly digest: string;\n\treadonly present: boolean;\n}\n\nexport interface ManifestMonitor {\n\treadonly monitorId: string;\n\t/** Owning agent session id — never the bash_N/watch_N runtime id. */\n\treadonly sessionId: string;\n\treadonly description: string;\n\treadonly runtimeKind: MonitorRuntimeKind;\n\treadonly durabilityClass: MonitorDurabilityClass;\n\treadonly command?: string;\n\treadonly path?: string;\n\treadonly event?: \"create\" | \"modify\";\n\treadonly filter?: string;\n\treadonly cwd?: string;\n\treadonly approvedParent?: string;\n\treadonly createdAt: number;\n\treadonly expiresAt: number | null;\n\treadonly persistent: boolean;\n\treadonly suspended: boolean;\n\treadonly lastCheckpoint: TerminalManifestCheckpoint | null;\n\treadonly deliveryPaused: boolean;\n\treadonly fireWindow: { startMs: number; count: number };\n}\n\nexport interface ManifestBackgroundSession {\n\treadonly id: string;\n\treadonly command: string;\n\treadonly startedAtMs: number;\n}\n\nexport interface TerminalManifest {\n\treadonly version: typeof TERMINAL_MANIFEST_VERSION;\n\treadonly sessionId: string;\n\treadonly monitors: readonly ManifestMonitor[];\n\treadonly backgroundSessions: readonly ManifestBackgroundSession[];\n\treadonly updatedAt: number;\n}\n\n/** What the monitor tool captures at its call site — the only place the branch inputs live. */\nexport interface CommandMonitorSpec {\n\treadonly kind: \"command\";\n\treadonly description: string;\n\treadonly command: string;\n\treadonly filter?: string;\n\treadonly cwd?: string;\n\treadonly persistent: boolean;\n}\n\nexport interface FileMonitorSpec {\n\treadonly kind: \"file\";\n\treadonly description: string;\n\treadonly path: string;\n\treadonly event: \"create\" | \"modify\";\n\treadonly timeoutMs: number;\n\treadonly cwd: string;\n\treadonly approvedParent?: string;\n\t/** Persistent file watches are the durable `checkpointed-file` class; one-shot ones stay ephemeral. */\n\treadonly persistent: boolean;\n}\nexport type MonitorSpec = CommandMonitorSpec | FileMonitorSpec;\n\nexport interface MonitorRegistration {\n\treadonly monitorId: string;\n\treadonly spec: MonitorSpec;\n}\n"]}
@@ -1,84 +1,13 @@
1
1
  /**
2
- * Per-session terminal manifest: the durable sidecar record of live monitors and background
3
- * sessions that `restore.ts` reads back after a restart. The writer persists ONLY lifecycle
4
- * transitions plus debounced checkpoints — never per-line output and never a runtime handle.
2
+ * The manifest write side: `createTerminalManifestStore` plus `TerminalManifestWriter`,
3
+ * persisting ONLY lifecycle transitions and debounced checkpoints of the record shaped in
4
+ * `terminal-manifest-model.ts` — never per-line output and never a runtime handle.
5
5
  */
6
- import type { SessionManager } from "../../../session-manager.ts";
7
6
  import { type SidecarStore } from "../../../session-sidecar-store.ts";
8
7
  import type { MonitorSnapshotEntry } from "./monitor-registry.ts";
9
- export declare const TERMINAL_MANIFEST_VERSION = 1;
10
- /** Minimum debounce for checkpoint writes; a burst inside this window collapses to one write. */
11
- export declare const TERMINAL_MANIFEST_CHECKPOINT_DEBOUNCE_MS = 30000;
12
- export type TerminalManifestSession = Pick<SessionManager, "getSessionDir" | "getSessionId">;
13
- export type MonitorRuntimeKind = "command" | "file";
14
- export type MonitorDurabilityClass = "ephemeral" | "restartable-command" | "checkpointed-file";
15
- /** File-monitor checkpoint persisted by the writer: the registry's live identity tuple. */
16
- export interface TerminalManifestCheckpoint {
17
- readonly dev: number;
18
- readonly ino: number;
19
- readonly size: number;
20
- readonly mtimeMs: number;
21
- }
22
- export interface ManifestMonitor {
23
- readonly monitorId: string;
24
- /** Owning agent session id — never the bash_N/watch_N runtime id. */
25
- readonly sessionId: string;
26
- readonly description: string;
27
- readonly runtimeKind: MonitorRuntimeKind;
28
- readonly durabilityClass: MonitorDurabilityClass;
29
- readonly command?: string;
30
- readonly path?: string;
31
- readonly event?: "create" | "modify";
32
- readonly filter?: string;
33
- readonly cwd?: string;
34
- readonly approvedParent?: string;
35
- readonly createdAt: number;
36
- readonly expiresAt: number | null;
37
- readonly persistent: boolean;
38
- readonly suspended: boolean;
39
- readonly lastCheckpoint: TerminalManifestCheckpoint | null;
40
- readonly deliveryPaused: boolean;
41
- readonly wakeCount: number;
42
- readonly fireWindow: {
43
- startMs: number;
44
- count: number;
45
- };
46
- }
47
- export interface ManifestBackgroundSession {
48
- readonly id: string;
49
- readonly command: string;
50
- readonly startedAtMs: number;
51
- }
52
- export interface TerminalManifest {
53
- readonly version: typeof TERMINAL_MANIFEST_VERSION;
54
- readonly sessionId: string;
55
- readonly monitors: readonly ManifestMonitor[];
56
- readonly backgroundSessions: readonly ManifestBackgroundSession[];
57
- readonly updatedAt: number;
58
- }
59
- /** What the monitor tool captures at its call site — the only place the branch inputs live. */
60
- export interface CommandMonitorSpec {
61
- readonly kind: "command";
62
- readonly description: string;
63
- readonly command: string;
64
- readonly filter?: string;
65
- readonly cwd?: string;
66
- readonly persistent: boolean;
67
- }
68
- export interface FileMonitorSpec {
69
- readonly kind: "file";
70
- readonly description: string;
71
- readonly path: string;
72
- readonly event: "create" | "modify";
73
- readonly timeoutMs: number;
74
- readonly cwd: string;
75
- readonly approvedParent?: string;
76
- }
77
- export type MonitorSpec = CommandMonitorSpec | FileMonitorSpec;
78
- export interface MonitorRegistration {
79
- readonly monitorId: string;
80
- readonly spec: MonitorSpec;
81
- }
8
+ import { type ManifestMonitor, type MonitorRegistration, type TerminalManifest, type TerminalManifestCheckpoint, type TerminalManifestSession } from "./terminal-manifest-model.ts";
9
+ export type { CommandMonitorSpec, FileMonitorSpec, ManifestBackgroundSession, ManifestMonitor, MonitorDurabilityClass, MonitorRegistration, MonitorRuntimeKind, MonitorSpec, TerminalManifest, TerminalManifestCheckpoint, TerminalManifestSession, } from "./terminal-manifest-model.ts";
10
+ export { DURABLE_MONITOR_EXPIRY_MS, TERMINAL_MANIFEST_CHECKPOINT_DEBOUNCE_MS, TERMINAL_MANIFEST_VERSION, } from "./terminal-manifest-model.ts";
82
11
  export declare function createTerminalManifestStore(session: TerminalManifestSession): SidecarStore<TerminalManifest>;
83
12
  export declare class TerminalManifestWriter {
84
13
  #private;
@@ -91,6 +20,29 @@ export declare class TerminalManifestWriter {
91
20
  now?: () => number;
92
21
  });
93
22
  recordRegister(registration: MonitorRegistration): Promise<void>;
23
+ /**
24
+ * Re-adopt an entry a restore handler just brought back to life, so THIS generation's
25
+ * in-memory map owns it again. Without this, the writer starts every generation empty and
26
+ * the next persist (a register, a background start, a checkpoint flush, recordShutdown)
27
+ * rewrites the manifest WITHOUT the restored monitors — the monitor survives one restart
28
+ * and is erased on the second.
29
+ *
30
+ * Every persisted field is preserved verbatim, notably `createdAt` and `expiresAt`: the
31
+ * durability deadline is set once at registration and a restore NEVER extends it. Only
32
+ * `suspended` is cleared, because the monitor is live again in this process.
33
+ *
34
+ * Deliberately does NOT write: re-adoption is not a state transition, it is recovery of
35
+ * state already on disk. The entry reaches the file again on the restore's own next
36
+ * persist (the file class's checkpoint, any later transition, or recordShutdown), so a
37
+ * restart costs zero extra writes and the write-on-transition invariant holds.
38
+ */
39
+ adoptRestored(entry: ManifestMonitor): void;
40
+ /**
41
+ * Live durable-monitor count for admission control: entries that survive a restart.
42
+ * Ephemeral entries are never counted, so any number of one-shot watches can coexist
43
+ * with the durable ones.
44
+ */
45
+ durableCount(): number;
94
46
  /**
95
47
  * Reconcile a registry transition snapshot (the bundle's single onChange consumer
96
48
  * forwards it here): settle removes entries, pause/resume/rearm flips deliveryPaused.
@@ -1 +1 @@
1
- {"version":3,"file":"terminal-manifest.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/builtin/terminal/terminal-manifest.ts"],"names":[],"mappings":"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"}
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;gBAEZ,OAAO,EAAE;QAAE,OAAO,EAAE,uBAAuB,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;KAAE;IAOlG,cAAc,CAAC,YAAY,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IAKhE;;;;;;;;;;;;;;;OAeG;IACH,aAAa,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI;IAI3C;;;;OAIG;IACH,YAAY,IAAI,MAAM;IAMtB;;;;;OAKG;IACH,mBAAmB,CAAC,QAAQ,EAAE,SAAS,oBAAoB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IA8B7E,wFAAwF;IACxF,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,0BAA0B,GAAG,IAAI;IAUnF,4EAA4E;IACtE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAW5B,iGAAiG;IAC3F,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAUrC,qBAAqB,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKvF,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CA+D/C"}
@@ -1,14 +1,16 @@
1
1
  /**
2
- * Per-session terminal manifest: the durable sidecar record of live monitors and background
3
- * sessions that `restore.ts` reads back after a restart. The writer persists ONLY lifecycle
4
- * transitions plus debounced checkpoints — never per-line output and never a runtime handle.
2
+ * The manifest write side: `createTerminalManifestStore` plus `TerminalManifestWriter`,
3
+ * persisting ONLY lifecycle transitions and debounced checkpoints of the record shaped in
4
+ * `terminal-manifest-model.ts` — never per-line output and never a runtime handle.
5
5
  */
6
6
  import { join } from "node:path";
7
7
  import { createSidecarStore } from "../../../session-sidecar-store.js";
8
8
  import { parseTerminalManifest } from "./restore.js";
9
- export const TERMINAL_MANIFEST_VERSION = 1;
10
- /** Minimum debounce for checkpoint writes; a burst inside this window collapses to one write. */
11
- export const TERMINAL_MANIFEST_CHECKPOINT_DEBOUNCE_MS = 30_000;
9
+ import { DURABLE_MONITOR_EXPIRY_MS } from "./shared.js";
10
+ import { TERMINAL_MANIFEST_CHECKPOINT_DEBOUNCE_MS, TERMINAL_MANIFEST_VERSION, } from "./terminal-manifest-model.js";
11
+ // The data model is re-exported so every importer keeps this module as the manifest's single
12
+ // entry point; nothing outside had to learn the model module's path.
13
+ export { DURABLE_MONITOR_EXPIRY_MS, TERMINAL_MANIFEST_CHECKPOINT_DEBOUNCE_MS, TERMINAL_MANIFEST_VERSION, } from "./terminal-manifest-model.js";
12
14
  export function createTerminalManifestStore(session) {
13
15
  return createSidecarStore({
14
16
  baseDir: join(session.getSessionDir(), "extensions", "terminal"),
@@ -37,6 +39,37 @@ export class TerminalManifestWriter {
37
39
  this.#entries.set(registration.monitorId, this.#entryFor(registration));
38
40
  return this.#persist();
39
41
  }
42
+ /**
43
+ * Re-adopt an entry a restore handler just brought back to life, so THIS generation's
44
+ * in-memory map owns it again. Without this, the writer starts every generation empty and
45
+ * the next persist (a register, a background start, a checkpoint flush, recordShutdown)
46
+ * rewrites the manifest WITHOUT the restored monitors — the monitor survives one restart
47
+ * and is erased on the second.
48
+ *
49
+ * Every persisted field is preserved verbatim, notably `createdAt` and `expiresAt`: the
50
+ * durability deadline is set once at registration and a restore NEVER extends it. Only
51
+ * `suspended` is cleared, because the monitor is live again in this process.
52
+ *
53
+ * Deliberately does NOT write: re-adoption is not a state transition, it is recovery of
54
+ * state already on disk. The entry reaches the file again on the restore's own next
55
+ * persist (the file class's checkpoint, any later transition, or recordShutdown), so a
56
+ * restart costs zero extra writes and the write-on-transition invariant holds.
57
+ */
58
+ adoptRestored(entry) {
59
+ this.#entries.set(entry.monitorId, { ...entry, suspended: false });
60
+ }
61
+ /**
62
+ * Live durable-monitor count for admission control: entries that survive a restart.
63
+ * Ephemeral entries are never counted, so any number of one-shot watches can coexist
64
+ * with the durable ones.
65
+ */
66
+ durableCount() {
67
+ let count = 0;
68
+ for (const entry of this.#entries.values())
69
+ if (entry.durabilityClass !== "ephemeral")
70
+ count += 1;
71
+ return count;
72
+ }
40
73
  /**
41
74
  * Reconcile a registry transition snapshot (the bundle's single onChange consumer
42
75
  * forwards it here): settle removes entries, pause/resume/rearm flips deliveryPaused.
@@ -49,19 +82,23 @@ export class TerminalManifestWriter {
49
82
  if (typeof entry.monitorId !== "string" || entry.monitorId.length === 0) {
50
83
  throw new Error(`terminal manifest writer saw a monitor snapshot entry without a stable monitorId (runtime id ${entry.id}); surfacing instead of silently skipping it`);
51
84
  }
52
- live.set(entry.monitorId, entry.paused);
85
+ live.set(entry.monitorId, { paused: entry.paused, fireWindow: entry.fireWindow });
53
86
  }
54
87
  let changed = false;
55
88
  for (const [monitorId, known] of this.#entries) {
56
- const paused = live.get(monitorId);
57
- if (paused === undefined) {
89
+ const current = live.get(monitorId);
90
+ if (current === undefined) {
58
91
  if (known.suspended)
59
92
  continue; // shutdown-suspended entries are expected to be absent
60
93
  this.#entries.delete(monitorId); // settle: the registry transitioned it out
61
94
  changed = true;
95
+ continue;
62
96
  }
63
- else if (known.deliveryPaused !== paused) {
64
- this.#entries.set(monitorId, { ...known, deliveryPaused: paused });
97
+ // The live fire window rides every state transition — notably the auto-mute pause —
98
+ // so a restart re-binds the burned budget instead of a fresh one.
99
+ const fireWindow = current.fireWindow ?? known.fireWindow;
100
+ if (known.deliveryPaused !== current.paused || known.fireWindow.count !== fireWindow.count) {
101
+ this.#entries.set(monitorId, { ...known, deliveryPaused: current.paused, fireWindow });
65
102
  changed = true;
66
103
  }
67
104
  }
@@ -119,12 +156,19 @@ export class TerminalManifestWriter {
119
156
  }
120
157
  #entryFor({ monitorId, spec }) {
121
158
  const createdAt = this.#now();
159
+ // A spec that omits `persistent` is ephemeral: the persisted field is a boolean the
160
+ // strict parse rejects as undefined, so coerce here rather than trusting the caller.
161
+ const persistent = spec.persistent === true;
122
162
  return {
123
163
  monitorId,
124
164
  sessionId: this.#sessionId,
125
165
  description: spec.description,
126
166
  runtimeKind: spec.kind,
127
- durabilityClass: spec.kind === "file" ? "checkpointed-file" : spec.persistent ? "restartable-command" : "ephemeral",
167
+ durabilityClass: !persistent
168
+ ? "ephemeral"
169
+ : spec.kind === "file"
170
+ ? "checkpointed-file"
171
+ : "restartable-command",
128
172
  command: spec.kind === "command" ? spec.command : undefined,
129
173
  path: spec.kind === "file" ? spec.path : undefined,
130
174
  event: spec.kind === "file" ? spec.event : undefined,
@@ -132,12 +176,14 @@ export class TerminalManifestWriter {
132
176
  cwd: spec.cwd,
133
177
  approvedParent: spec.kind === "file" ? spec.approvedParent : undefined,
134
178
  createdAt,
135
- expiresAt: spec.kind === "file" ? createdAt + spec.timeoutMs : null,
136
- persistent: spec.kind === "command" ? spec.persistent : false,
179
+ // Absolute durability deadline for every restart-surviving entry, set once here and
180
+ // never extended by a restore or a rearm. An ephemeral entry dies with the process,
181
+ // so its runtime deadline stays the registry's business, not the manifest's.
182
+ expiresAt: persistent ? createdAt + DURABLE_MONITOR_EXPIRY_MS : null,
183
+ persistent,
137
184
  suspended: false,
138
185
  lastCheckpoint: null,
139
186
  deliveryPaused: false,
140
- wakeCount: 0,
141
187
  fireWindow: { startMs: createdAt, count: 0 },
142
188
  };
143
189
  }
@@ -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 * Per-session terminal manifest: the durable sidecar record of live monitors and background\n * sessions that `restore.ts` reads back after a restart. The writer persists ONLY lifecycle\n * transitions plus debounced checkpoints — never per-line output and never a runtime handle.\n */\n\nimport { join } from \"node:path\";\nimport type { SessionManager } from \"../../../session-manager.ts\";\nimport { createSidecarStore, type SidecarStore } from \"../../../session-sidecar-store.ts\";\nimport type { MonitorSnapshotEntry } from \"./monitor-registry.ts\";\nimport { parseTerminalManifest } from \"./restore.ts\";\n\nexport const TERMINAL_MANIFEST_VERSION = 1;\n/** Minimum debounce for checkpoint writes; a burst inside this window collapses to one write. */\nexport const TERMINAL_MANIFEST_CHECKPOINT_DEBOUNCE_MS = 30_000;\nexport type TerminalManifestSession = Pick<SessionManager, \"getSessionDir\" | \"getSessionId\">;\nexport type MonitorRuntimeKind = \"command\" | \"file\";\nexport type MonitorDurabilityClass = \"ephemeral\" | \"restartable-command\" | \"checkpointed-file\";\n/** File-monitor checkpoint persisted by the writer: the registry's live identity tuple. */\nexport interface TerminalManifestCheckpoint {\n\treadonly dev: number;\n\treadonly ino: number;\n\treadonly size: number;\n\treadonly mtimeMs: number;\n}\n\nexport interface ManifestMonitor {\n\treadonly monitorId: string;\n\t/** Owning agent session id — never the bash_N/watch_N runtime id. */\n\treadonly sessionId: string;\n\treadonly description: string;\n\treadonly runtimeKind: MonitorRuntimeKind;\n\treadonly durabilityClass: MonitorDurabilityClass;\n\treadonly command?: string;\n\treadonly path?: string;\n\treadonly event?: \"create\" | \"modify\";\n\treadonly filter?: string;\n\treadonly cwd?: string;\n\treadonly approvedParent?: string;\n\treadonly createdAt: number;\n\treadonly expiresAt: number | null;\n\treadonly persistent: boolean;\n\treadonly suspended: boolean;\n\treadonly lastCheckpoint: TerminalManifestCheckpoint | null;\n\treadonly deliveryPaused: boolean;\n\treadonly wakeCount: number;\n\treadonly fireWindow: { startMs: number; count: number };\n}\n\nexport interface ManifestBackgroundSession {\n\treadonly id: string;\n\treadonly command: string;\n\treadonly startedAtMs: number;\n}\n\nexport interface TerminalManifest {\n\treadonly version: typeof TERMINAL_MANIFEST_VERSION;\n\treadonly sessionId: string;\n\treadonly monitors: readonly ManifestMonitor[];\n\treadonly backgroundSessions: readonly ManifestBackgroundSession[];\n\treadonly updatedAt: number;\n}\n\n/** What the monitor tool captures at its call site — the only place the branch inputs live. */\nexport interface CommandMonitorSpec {\n\treadonly kind: \"command\";\n\treadonly description: string;\n\treadonly command: string;\n\treadonly filter?: string;\n\treadonly cwd?: string;\n\treadonly persistent: boolean;\n}\n\nexport interface FileMonitorSpec {\n\treadonly kind: \"file\";\n\treadonly description: string;\n\treadonly path: string;\n\treadonly event: \"create\" | \"modify\";\n\treadonly timeoutMs: number;\n\treadonly cwd: string;\n\treadonly approvedParent?: string;\n}\nexport type MonitorSpec = CommandMonitorSpec | FileMonitorSpec;\n\nexport interface MonitorRegistration {\n\treadonly monitorId: string;\n\treadonly spec: MonitorSpec;\n}\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 * 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, boolean>();\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, entry.paused);\n\t\t}\n\t\tlet changed = false;\n\t\tfor (const [monitorId, known] of this.#entries) {\n\t\t\tconst paused = live.get(monitorId);\n\t\t\tif (paused === 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} else if (known.deliveryPaused !== paused) {\n\t\t\t\tthis.#entries.set(monitorId, { ...known, deliveryPaused: paused });\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\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:\n\t\t\t\tspec.kind === \"file\" ? \"checkpointed-file\" : spec.persistent ? \"restartable-command\" : \"ephemeral\",\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\texpiresAt: spec.kind === \"file\" ? createdAt + spec.timeoutMs : null,\n\t\t\tpersistent: spec.kind === \"command\" ? spec.persistent : false,\n\t\t\tsuspended: false,\n\t\t\tlastCheckpoint: null,\n\t\t\tdeliveryPaused: false,\n\t\t\twakeCount: 0,\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 { 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 +1 @@
1
- {"version":3,"file":"monitor.d.ts","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/terminal/tools/monitor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAI5C,OAAO,KAAK,EAAuB,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAC3F,OAAO,EAGN,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EAEvB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGhD,eAAO,MAAM,0BAA0B,SAAU,CAAC;AAClD,eAAO,MAAM,sBAAsB,UAAY,CAAC;AAEhD;;;;;GAKG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;EA+CxB,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,aAAa,CAAC,CAAC;AAkFxD,4GAA4G;AAC5G,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,sBAAsB,GAAG,IAAI,CAElG;AAED,wBAAgB,4BAA4B,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAEpE;AAaD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,mBAAmB;;;;;;;;;;;;;;;;;;yBAwB1C,MAAM,SACZ,YAAY,YACT,WAAW,cACT,SAAS,YACX;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,GACxB,OAAO,CAAC,kBAAkB,CAAC;EAuE/B"}
1
+ {"version":3,"file":"monitor.d.ts","sourceRoot":"","sources":["../../../../../../src/core/extensions/builtin/terminal/tools/monitor.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAU5C,OAAO,KAAK,EAAuB,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAC3F,OAAO,EAGN,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EAEvB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGhD,eAAO,MAAM,0BAA0B,SAAU,CAAC;AAClD,eAAO,MAAM,sBAAsB,UAAY,CAAC;AAEhD;;;;;GAKG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;EAkDxB,CAAC;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,aAAa,CAAC,CAAC;AA8FxD,4GAA4G;AAC5G,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,sBAAsB,GAAG,IAAI,CAElG;AAED,wBAAgB,4BAA4B,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAEpE;AAwCD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,mBAAmB;;;;;;;;;;;;;;;;;;yBAwB1C,MAAM,SACZ,YAAY,YACT,WAAW,cACT,SAAS,YACX;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,GACxB,OAAO,CAAC,kBAAkB,CAAC;EAiF/B"}