@astralyn/pi 0.87.1 → 0.87.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 (275) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/bundle/chunks/{chunk-CDMUKIXY.js → chunk-NBIUJDV6.js} +1 -1
  3. package/dist/bundle/chunks/{chunk-772GXEFD.js → chunk-RFLBIA5Z.js} +69 -69
  4. package/dist/bundle/chunks/{virtual-modules-LQO2MG3T.js → virtual-modules-GOHLE5JL.js} +1 -1
  5. package/dist/bundle/cli.js +1 -1
  6. package/dist/bundle/index.js +1 -1
  7. package/dist/bundle/rpc-entry.js +1 -1
  8. package/dist/config.d.ts +1 -1
  9. package/dist/config.d.ts.map +1 -1
  10. package/dist/config.js.map +1 -1
  11. package/dist/core/agent-session-runtime.d.ts +9 -0
  12. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  13. package/dist/core/agent-session-runtime.js +158 -157
  14. package/dist/core/agent-session-runtime.js.map +1 -1
  15. package/dist/core/agent-session.d.ts +14 -0
  16. package/dist/core/agent-session.d.ts.map +1 -1
  17. package/dist/core/agent-session.js +437 -434
  18. package/dist/core/agent-session.js.map +1 -1
  19. package/dist/core/background/types.d.ts +2 -0
  20. package/dist/core/background/types.d.ts.map +1 -1
  21. package/dist/core/background/types.js.map +1 -1
  22. package/dist/core/extensions/distribution-api.d.ts +41 -0
  23. package/dist/core/extensions/distribution-api.d.ts.map +1 -0
  24. package/dist/core/extensions/distribution-api.js +12 -0
  25. package/dist/core/extensions/distribution-api.js.map +1 -0
  26. package/dist/core/extensions/index.d.ts +1 -1
  27. package/dist/core/extensions/index.d.ts.map +1 -1
  28. package/dist/core/extensions/index.js.map +1 -1
  29. package/dist/core/extensions/loader.d.ts.map +1 -1
  30. package/dist/core/extensions/loader.js +1 -0
  31. package/dist/core/extensions/loader.js.map +1 -1
  32. package/dist/core/extensions/runner.d.ts.map +1 -1
  33. package/dist/core/extensions/runner.js +0 -2
  34. package/dist/core/extensions/runner.js.map +1 -1
  35. package/dist/core/extensions/types.d.ts +15 -45
  36. package/dist/core/extensions/types.d.ts.map +1 -1
  37. package/dist/core/extensions/types.js +1 -11
  38. package/dist/core/extensions/types.js.map +1 -1
  39. package/dist/core/extensions/virtual-modules.d.ts.map +1 -1
  40. package/dist/core/extensions/virtual-modules.js +2 -1
  41. package/dist/core/extensions/virtual-modules.js.map +1 -1
  42. package/dist/core/keybinding-registry.d.ts +11 -0
  43. package/dist/core/keybinding-registry.d.ts.map +1 -0
  44. package/dist/core/keybinding-registry.js +24 -0
  45. package/dist/core/keybinding-registry.js.map +1 -0
  46. package/dist/core/keybindings.d.ts +4 -64
  47. package/dist/core/keybindings.d.ts.map +1 -1
  48. package/dist/core/keybindings.js +2 -41
  49. package/dist/core/keybindings.js.map +1 -1
  50. package/dist/core/model-config.d.ts +70 -2
  51. package/dist/core/model-config.d.ts.map +1 -1
  52. package/dist/core/model-config.js +2 -26
  53. package/dist/core/model-config.js.map +1 -1
  54. package/dist/core/resource-loader.d.ts.map +1 -1
  55. package/dist/core/resource-loader.js +5 -11
  56. package/dist/core/resource-loader.js.map +1 -1
  57. package/dist/core/tools/bash.d.ts.map +1 -1
  58. package/dist/core/tools/bash.js +2 -2
  59. package/dist/core/tools/bash.js.map +1 -1
  60. package/dist/core/tools/shell-execution.d.ts +1 -0
  61. package/dist/core/tools/shell-execution.d.ts.map +1 -1
  62. package/dist/core/tools/shell-execution.js +21 -0
  63. package/dist/core/tools/shell-execution.js.map +1 -1
  64. package/dist/core/trust-manager.d.ts.map +1 -1
  65. package/dist/core/trust-manager.js +11 -48
  66. package/dist/core/trust-manager.js.map +1 -1
  67. package/dist/extensions/background/index.d.ts +2 -0
  68. package/dist/extensions/background/index.d.ts.map +1 -1
  69. package/dist/extensions/background/index.js +17 -0
  70. package/dist/extensions/background/index.js.map +1 -1
  71. package/dist/extensions/background/keybindings.d.ts +10 -0
  72. package/dist/extensions/background/keybindings.d.ts.map +1 -0
  73. package/dist/extensions/background/keybindings.js +14 -0
  74. package/dist/extensions/background/keybindings.js.map +1 -0
  75. package/dist/extensions/background/manager.d.ts +2 -0
  76. package/dist/extensions/background/manager.d.ts.map +1 -1
  77. package/dist/extensions/background/manager.js +1 -0
  78. package/dist/extensions/background/manager.js.map +1 -1
  79. package/dist/extensions/btw/controller.d.ts +1 -0
  80. package/dist/extensions/btw/controller.d.ts.map +1 -1
  81. package/dist/extensions/btw/controller.js +5 -5
  82. package/dist/extensions/btw/controller.js.map +1 -1
  83. package/dist/extensions/btw/index.js +1 -2
  84. package/dist/extensions/btw/index.js.map +1 -1
  85. package/dist/extensions/btw/keybindings.d.ts +10 -0
  86. package/dist/extensions/btw/keybindings.d.ts.map +1 -0
  87. package/dist/extensions/btw/keybindings.js +8 -0
  88. package/dist/extensions/btw/keybindings.js.map +1 -0
  89. package/dist/extensions/btw/panel.d.ts +1 -0
  90. package/dist/extensions/btw/panel.d.ts.map +1 -1
  91. package/dist/extensions/btw/panel.js +1 -0
  92. package/dist/extensions/btw/panel.js.map +1 -1
  93. package/dist/extensions/list-keybindings.d.ts +8 -0
  94. package/dist/extensions/list-keybindings.d.ts.map +1 -0
  95. package/dist/extensions/list-keybindings.js +8 -0
  96. package/dist/extensions/list-keybindings.js.map +1 -0
  97. package/dist/extensions/provider/compat-fields.d.ts.map +1 -1
  98. package/dist/extensions/provider/compat-fields.js +23 -3
  99. package/dist/extensions/provider/compat-fields.js.map +1 -1
  100. package/dist/extensions/provider/connection.d.ts.map +1 -1
  101. package/dist/extensions/provider/connection.js +1 -1
  102. package/dist/extensions/provider/connection.js.map +1 -1
  103. package/dist/extensions/provider/constants.d.ts +2 -0
  104. package/dist/extensions/provider/constants.d.ts.map +1 -1
  105. package/dist/extensions/provider/constants.js +2 -0
  106. package/dist/extensions/provider/constants.js.map +1 -1
  107. package/dist/extensions/provider/keybindings.d.ts +9 -0
  108. package/dist/extensions/provider/keybindings.d.ts.map +1 -0
  109. package/dist/extensions/provider/keybindings.js +12 -0
  110. package/dist/extensions/provider/keybindings.js.map +1 -0
  111. package/dist/extensions/provider/probe.d.ts +8 -4
  112. package/dist/extensions/provider/probe.d.ts.map +1 -1
  113. package/dist/extensions/provider/probe.js +169 -11
  114. package/dist/extensions/provider/probe.js.map +1 -1
  115. package/dist/extensions/provider/ui/builtin-data.d.ts +1 -0
  116. package/dist/extensions/provider/ui/builtin-data.d.ts.map +1 -1
  117. package/dist/extensions/provider/ui/builtin-data.js +1 -0
  118. package/dist/extensions/provider/ui/builtin-data.js.map +1 -1
  119. package/dist/extensions/provider/ui/compat.d.ts +1 -0
  120. package/dist/extensions/provider/ui/compat.d.ts.map +1 -1
  121. package/dist/extensions/provider/ui/compat.js +1 -0
  122. package/dist/extensions/provider/ui/compat.js.map +1 -1
  123. package/dist/extensions/provider/ui/dictionary.d.ts +1 -0
  124. package/dist/extensions/provider/ui/dictionary.d.ts.map +1 -1
  125. package/dist/extensions/provider/ui/dictionary.js +1 -0
  126. package/dist/extensions/provider/ui/dictionary.js.map +1 -1
  127. package/dist/extensions/provider/ui/editor.d.ts +1 -0
  128. package/dist/extensions/provider/ui/editor.d.ts.map +1 -1
  129. package/dist/extensions/provider/ui/editor.js +1 -0
  130. package/dist/extensions/provider/ui/editor.js.map +1 -1
  131. package/dist/extensions/provider/ui/fetch-models.d.ts +5 -3
  132. package/dist/extensions/provider/ui/fetch-models.d.ts.map +1 -1
  133. package/dist/extensions/provider/ui/fetch-models.js +28 -3
  134. package/dist/extensions/provider/ui/fetch-models.js.map +1 -1
  135. package/dist/extensions/provider/ui/model-fields.d.ts +1 -0
  136. package/dist/extensions/provider/ui/model-fields.d.ts.map +1 -1
  137. package/dist/extensions/provider/ui/model-fields.js +1 -0
  138. package/dist/extensions/provider/ui/model-fields.js.map +1 -1
  139. package/dist/extensions/provider/ui/model-options.d.ts +1 -0
  140. package/dist/extensions/provider/ui/model-options.d.ts.map +1 -1
  141. package/dist/extensions/provider/ui/model-options.js +1 -0
  142. package/dist/extensions/provider/ui/model-options.js.map +1 -1
  143. package/dist/extensions/provider/ui/provider-fields.d.ts +1 -0
  144. package/dist/extensions/provider/ui/provider-fields.d.ts.map +1 -1
  145. package/dist/extensions/provider/ui/provider-fields.js +1 -0
  146. package/dist/extensions/provider/ui/provider-fields.js.map +1 -1
  147. package/dist/extensions/question/dialog.d.ts +1 -0
  148. package/dist/extensions/question/dialog.d.ts.map +1 -1
  149. package/dist/extensions/question/dialog.js +1 -0
  150. package/dist/extensions/question/dialog.js.map +1 -1
  151. package/dist/extensions/question/keybindings.d.ts +2 -0
  152. package/dist/extensions/question/keybindings.d.ts.map +1 -0
  153. package/dist/extensions/question/keybindings.js +3 -0
  154. package/dist/extensions/question/keybindings.js.map +1 -0
  155. package/dist/index.d.ts +1 -1
  156. package/dist/index.d.ts.map +1 -1
  157. package/dist/index.js.map +1 -1
  158. package/dist/modes/interactive/editor-host.d.ts +43 -0
  159. package/dist/modes/interactive/editor-host.d.ts.map +1 -0
  160. package/dist/modes/interactive/editor-host.js +83 -0
  161. package/dist/modes/interactive/editor-host.js.map +1 -0
  162. package/dist/modes/interactive/interactive-mode.d.ts +1 -11
  163. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  164. package/dist/modes/interactive/interactive-mode.js +300 -360
  165. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  166. package/dist/modes/interactive/tool-chat.d.ts +21 -0
  167. package/dist/modes/interactive/tool-chat.d.ts.map +1 -0
  168. package/dist/modes/interactive/tool-chat.js +58 -0
  169. package/dist/modes/interactive/tool-chat.js.map +1 -0
  170. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  171. package/dist/modes/rpc/rpc-mode.js +0 -2
  172. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  173. package/dist/utils/path-identity.d.ts +12 -0
  174. package/dist/utils/path-identity.d.ts.map +1 -0
  175. package/dist/utils/path-identity.js +63 -0
  176. package/dist/utils/path-identity.js.map +1 -0
  177. package/dist/utils/shell.d.ts +0 -1
  178. package/dist/utils/shell.d.ts.map +1 -1
  179. package/dist/utils/shell.js +0 -21
  180. package/dist/utils/shell.js.map +1 -1
  181. package/dist/utils/syntax-highlight.d.ts +2 -0
  182. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  183. package/dist/utils/syntax-highlight.js +2 -0
  184. package/dist/utils/syntax-highlight.js.map +1 -1
  185. package/docs/bundled/extensions/provider.md +7 -3
  186. package/docs/extensions.md +15 -5
  187. package/examples/extensions/README.md +34 -14
  188. package/examples/extensions/auto-commit-on-exit.ts +1 -1
  189. package/examples/extensions/bash-spawn-hook.ts +2 -2
  190. package/examples/extensions/bookmark.ts +1 -1
  191. package/examples/extensions/border-status-editor.ts +6 -1
  192. package/examples/extensions/built-in-tool-renderer.ts +2 -2
  193. package/examples/extensions/claude-rules.ts +1 -1
  194. package/examples/extensions/commands.ts +1 -1
  195. package/examples/extensions/confirm-destructive.ts +1 -1
  196. package/examples/extensions/custom-compaction.ts +2 -2
  197. package/examples/extensions/custom-footer.ts +1 -1
  198. package/examples/extensions/custom-header.ts +2 -2
  199. package/examples/extensions/custom-provider-anthropic/index.ts +6 -6
  200. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  201. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  202. package/examples/extensions/custom-provider-gitlab-duo/index.ts +3 -3
  203. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  204. package/examples/extensions/dirty-repo-guard.ts +1 -1
  205. package/examples/extensions/doom-overlay/index.ts +1 -1
  206. package/examples/extensions/dynamic-resources/dynamic.json +3 -1
  207. package/examples/extensions/dynamic-resources/index.ts +1 -1
  208. package/examples/extensions/dynamic-tools.ts +1 -1
  209. package/examples/extensions/entry-renderer.ts +1 -1
  210. package/examples/extensions/event-bus.ts +1 -1
  211. package/examples/extensions/file-trigger.ts +1 -1
  212. package/examples/extensions/git-checkpoint.ts +1 -1
  213. package/examples/extensions/git-merge-and-resolve.ts +1 -1
  214. package/examples/extensions/github-issue-autocomplete.ts +1 -1
  215. package/examples/extensions/gondolin/index.ts +9 -7
  216. package/examples/extensions/gondolin/package-lock.json +2 -2
  217. package/examples/extensions/gondolin/package.json +1 -1
  218. package/examples/extensions/handoff.ts +2 -2
  219. package/examples/extensions/hello.ts +1 -1
  220. package/examples/extensions/hidden-thinking-label.ts +1 -1
  221. package/examples/extensions/inline-bash.ts +1 -1
  222. package/examples/extensions/input-transform-streaming.ts +1 -1
  223. package/examples/extensions/input-transform.ts +1 -1
  224. package/examples/extensions/interactive-shell.ts +1 -1
  225. package/examples/extensions/mac-system-theme.ts +1 -1
  226. package/examples/extensions/message-renderer.ts +1 -1
  227. package/examples/extensions/minimal-mode.ts +2 -2
  228. package/examples/extensions/modal-editor.ts +1 -1
  229. package/examples/extensions/model-status.ts +1 -1
  230. package/examples/extensions/notify.ts +1 -1
  231. package/examples/extensions/overlay-qa-tests.ts +3 -3
  232. package/examples/extensions/overlay-test.ts +1 -1
  233. package/examples/extensions/permission-gate.ts +1 -1
  234. package/examples/extensions/pirate.ts +1 -1
  235. package/examples/extensions/plan-mode/index.ts +1 -1
  236. package/examples/extensions/preset.ts +2 -2
  237. package/examples/extensions/project-trust.ts +3 -3
  238. package/examples/extensions/prompt-customizer.ts +1 -1
  239. package/examples/extensions/protected-paths.ts +1 -1
  240. package/examples/extensions/provider-payload.ts +1 -1
  241. package/examples/extensions/qna.ts +2 -2
  242. package/examples/extensions/question.ts +1 -1
  243. package/examples/extensions/questionnaire.ts +1 -1
  244. package/examples/extensions/rainbow-editor.ts +1 -1
  245. package/examples/extensions/reload-runtime.ts +1 -1
  246. package/examples/extensions/rpc-demo.ts +1 -1
  247. package/examples/extensions/sandbox/index.ts +2 -2
  248. package/examples/extensions/sandbox/package-lock.json +2 -2
  249. package/examples/extensions/sandbox/package.json +1 -1
  250. package/examples/extensions/send-user-message.ts +1 -1
  251. package/examples/extensions/session-name.ts +1 -1
  252. package/examples/extensions/shutdown-command.ts +1 -1
  253. package/examples/extensions/snake.ts +1 -1
  254. package/examples/extensions/space-invaders.ts +1 -1
  255. package/examples/extensions/ssh.ts +2 -2
  256. package/examples/extensions/status-line.ts +1 -1
  257. package/examples/extensions/structured-output.ts +1 -1
  258. package/examples/extensions/summarize.ts +2 -3
  259. package/examples/extensions/system-prompt-header.ts +1 -1
  260. package/examples/extensions/tic-tac-toe.ts +1 -1
  261. package/examples/extensions/timed-confirm.ts +1 -1
  262. package/examples/extensions/titlebar-spinner.ts +1 -1
  263. package/examples/extensions/todo.ts +1 -1
  264. package/examples/extensions/tool-override.ts +1 -1
  265. package/examples/extensions/tools.ts +2 -2
  266. package/examples/extensions/trigger-compact.ts +1 -1
  267. package/examples/extensions/truncated-tool.ts +4 -4
  268. package/examples/extensions/widget-placement.ts +1 -1
  269. package/examples/extensions/with-deps/index.ts +1 -1
  270. package/examples/extensions/with-deps/package-lock.json +2 -2
  271. package/examples/extensions/with-deps/package.json +1 -1
  272. package/examples/extensions/working-indicator.ts +1 -1
  273. package/examples/extensions/working-message-test.ts +1 -1
  274. package/npm-shrinkwrap.json +2 -2
  275. package/package.json +1 -1
@@ -118,128 +118,111 @@ export class AgentSessionRuntime {
118
118
  await withSession(this.session.createReplacedSessionContext());
119
119
  }
120
120
  }
121
- async switchSession(sessionPath, options) {
121
+ /**
122
+ * Hold the outgoing session's background delivery across a replacement. The
123
+ * pause belongs to the session current at entry, not the replacement.
124
+ */
125
+ async withBackgroundPaused(operation) {
122
126
  const resumeBackground = this.session.pauseBackgroundNotifications();
123
127
  try {
124
- const beforeResult = await this.emitBeforeSwitch("resume", sessionPath);
125
- if (beforeResult.cancelled) {
126
- return beforeResult;
127
- }
128
- const previousSessionFile = this.session.sessionFile;
129
- let sessionManager = SessionManager.open(sessionPath, undefined, options?.cwdOverride);
130
- assertSessionCwdExists(sessionManager, this.cwd);
131
- await this.teardownCurrent("resume", sessionManager.getSessionFile());
132
- // Resuming the current file must include usage persisted during teardown.
133
- sessionManager = SessionManager.open(sessionPath, undefined, options?.cwdOverride);
134
- this.apply(await this.createRuntime({
135
- cwd: sessionManager.getCwd(),
136
- agentDir: this.services.agentDir,
137
- sessionManager,
138
- sessionStartEvent: { type: "session_start", reason: "resume", previousSessionFile },
139
- projectTrustContext: options?.projectTrustContextFactory?.(sessionManager.getCwd()),
140
- }));
141
- await this.finishSessionReplacement(options?.withSession);
142
- return { cancelled: false };
128
+ return await operation();
143
129
  }
144
130
  finally {
145
131
  resumeBackground();
146
132
  }
147
133
  }
134
+ async switchSession(sessionPath, options) {
135
+ return this.withBackgroundPaused(() => this.switchSessionBody(sessionPath, options));
136
+ }
137
+ async switchSessionBody(sessionPath, options) {
138
+ const beforeResult = await this.emitBeforeSwitch("resume", sessionPath);
139
+ if (beforeResult.cancelled) {
140
+ return beforeResult;
141
+ }
142
+ const previousSessionFile = this.session.sessionFile;
143
+ let sessionManager = SessionManager.open(sessionPath, undefined, options?.cwdOverride);
144
+ assertSessionCwdExists(sessionManager, this.cwd);
145
+ await this.teardownCurrent("resume", sessionManager.getSessionFile());
146
+ // Resuming the current file must include usage persisted during teardown.
147
+ sessionManager = SessionManager.open(sessionPath, undefined, options?.cwdOverride);
148
+ this.apply(await this.createRuntime({
149
+ cwd: sessionManager.getCwd(),
150
+ agentDir: this.services.agentDir,
151
+ sessionManager,
152
+ sessionStartEvent: { type: "session_start", reason: "resume", previousSessionFile },
153
+ projectTrustContext: options?.projectTrustContextFactory?.(sessionManager.getCwd()),
154
+ }));
155
+ await this.finishSessionReplacement(options?.withSession);
156
+ return { cancelled: false };
157
+ }
148
158
  async newSession(options) {
149
- const resumeBackground = this.session.pauseBackgroundNotifications();
150
- try {
151
- const beforeResult = await this.emitBeforeSwitch("new");
152
- if (beforeResult.cancelled) {
153
- return beforeResult;
154
- }
155
- const previousSessionFile = this.session.sessionFile;
156
- const sessionDir = this.session.sessionManager.getSessionDir();
157
- const sessionManager = this.session.sessionManager.isPersisted()
158
- ? SessionManager.create(this.cwd, sessionDir)
159
- : SessionManager.inMemory(this.cwd);
160
- if (options?.parentSession) {
161
- sessionManager.newSession({ parentSession: options.parentSession });
162
- }
163
- await this.teardownCurrent("new", sessionManager.getSessionFile());
164
- this.apply(await this.createRuntime({
165
- cwd: this.cwd,
166
- agentDir: this.services.agentDir,
167
- sessionManager,
168
- sessionStartEvent: { type: "session_start", reason: "new", previousSessionFile },
169
- }));
170
- if (options?.setup) {
171
- await options.setup(this.session.sessionManager);
172
- this.session.refreshContext();
173
- }
174
- await this.finishSessionReplacement(options?.withSession);
175
- return { cancelled: false };
159
+ return this.withBackgroundPaused(() => this.newSessionBody(options));
160
+ }
161
+ async newSessionBody(options) {
162
+ const beforeResult = await this.emitBeforeSwitch("new");
163
+ if (beforeResult.cancelled) {
164
+ return beforeResult;
176
165
  }
177
- finally {
178
- resumeBackground();
166
+ const previousSessionFile = this.session.sessionFile;
167
+ const sessionDir = this.session.sessionManager.getSessionDir();
168
+ const sessionManager = this.session.sessionManager.isPersisted()
169
+ ? SessionManager.create(this.cwd, sessionDir)
170
+ : SessionManager.inMemory(this.cwd);
171
+ if (options?.parentSession) {
172
+ sessionManager.newSession({ parentSession: options.parentSession });
173
+ }
174
+ await this.teardownCurrent("new", sessionManager.getSessionFile());
175
+ this.apply(await this.createRuntime({
176
+ cwd: this.cwd,
177
+ agentDir: this.services.agentDir,
178
+ sessionManager,
179
+ sessionStartEvent: { type: "session_start", reason: "new", previousSessionFile },
180
+ }));
181
+ if (options?.setup) {
182
+ await options.setup(this.session.sessionManager);
183
+ this.session.refreshContext();
179
184
  }
185
+ await this.finishSessionReplacement(options?.withSession);
186
+ return { cancelled: false };
180
187
  }
181
188
  async fork(entryId, options) {
182
- const resumeBackground = this.session.pauseBackgroundNotifications();
183
- try {
184
- const position = options?.position ?? "before";
185
- const beforeResult = await this.emitBeforeFork(entryId, { position });
186
- if (beforeResult.cancelled) {
187
- return { cancelled: true };
188
- }
189
- let targetLeafId;
190
- let selectedText;
191
- const selectedEntry = this.session.sessionManager.getEntry(entryId);
192
- if (!selectedEntry) {
189
+ return this.withBackgroundPaused(() => this.forkBody(entryId, options));
190
+ }
191
+ async forkBody(entryId, options) {
192
+ const position = options?.position ?? "before";
193
+ const beforeResult = await this.emitBeforeFork(entryId, { position });
194
+ if (beforeResult.cancelled) {
195
+ return { cancelled: true };
196
+ }
197
+ let targetLeafId;
198
+ let selectedText;
199
+ const selectedEntry = this.session.sessionManager.getEntry(entryId);
200
+ if (!selectedEntry) {
201
+ throw new Error("Invalid entry ID for forking");
202
+ }
203
+ if (position === "at") {
204
+ targetLeafId = selectedEntry.id;
205
+ }
206
+ else {
207
+ if (selectedEntry.type !== "message" || selectedEntry.message.role !== "user") {
193
208
  throw new Error("Invalid entry ID for forking");
194
209
  }
195
- if (position === "at") {
196
- targetLeafId = selectedEntry.id;
197
- }
198
- else {
199
- if (selectedEntry.type !== "message" || selectedEntry.message.role !== "user") {
200
- throw new Error("Invalid entry ID for forking");
201
- }
202
- targetLeafId = selectedEntry.parentId;
203
- selectedText = extractUserMessageText(selectedEntry.message.content);
210
+ targetLeafId = selectedEntry.parentId;
211
+ selectedText = extractUserMessageText(selectedEntry.message.content);
212
+ }
213
+ const previousSessionFile = this.session.sessionFile;
214
+ if (this.session.sessionManager.isPersisted()) {
215
+ const currentSessionFile = this.session.sessionFile;
216
+ if (!currentSessionFile) {
217
+ throw new Error("Persisted session is missing a session file");
204
218
  }
205
- const previousSessionFile = this.session.sessionFile;
206
- if (this.session.sessionManager.isPersisted()) {
207
- const currentSessionFile = this.session.sessionFile;
208
- if (!currentSessionFile) {
209
- throw new Error("Persisted session is missing a session file");
210
- }
211
- const sessionDir = this.session.sessionManager.getSessionDir();
212
- if (!targetLeafId) {
213
- const sessionManager = SessionManager.create(this.cwd, sessionDir);
214
- sessionManager.newSession({ parentSession: currentSessionFile });
215
- await this.teardownCurrent("fork", sessionManager.getSessionFile());
216
- this.apply(await this.createRuntime({
217
- cwd: this.cwd,
218
- agentDir: this.services.agentDir,
219
- sessionManager,
220
- sessionStartEvent: { type: "session_start", reason: "fork", previousSessionFile },
221
- }));
222
- await this.finishSessionReplacement(options?.withSession);
223
- return { cancelled: false, selectedText };
224
- }
225
- if (!existsSync(currentSessionFile)) {
226
- throw new Error("This session has not been saved yet. Wait for the first assistant response before cloning or forking it.");
227
- }
228
- // Validate and honor vetoes before closing admission, but settle owned
229
- // usage before reading the source file for the fork.
230
- const forkingCurrentLeaf = targetLeafId === this.session.sessionManager.getLeafId();
231
- this.session.background.close();
232
- await Promise.all([this.session.background.shutdown(), this.session.abort()]);
233
- if (forkingCurrentLeaf)
234
- targetLeafId = this.session.sessionManager.getLeafId();
235
- const sessionManager = SessionManager.open(currentSessionFile, sessionDir);
236
- const forkedSessionPath = sessionManager.createBranchedSession(targetLeafId);
237
- if (!forkedSessionPath) {
238
- throw new Error("Failed to create forked session");
239
- }
219
+ const sessionDir = this.session.sessionManager.getSessionDir();
220
+ if (!targetLeafId) {
221
+ const sessionManager = SessionManager.create(this.cwd, sessionDir);
222
+ sessionManager.newSession({ parentSession: currentSessionFile });
240
223
  await this.teardownCurrent("fork", sessionManager.getSessionFile());
241
224
  this.apply(await this.createRuntime({
242
- cwd: sessionManager.getCwd(),
225
+ cwd: this.cwd,
243
226
  agentDir: this.services.agentDir,
244
227
  sessionManager,
245
228
  sessionStartEvent: { type: "session_start", reason: "fork", previousSessionFile },
@@ -247,19 +230,24 @@ export class AgentSessionRuntime {
247
230
  await this.finishSessionReplacement(options?.withSession);
248
231
  return { cancelled: false, selectedText };
249
232
  }
250
- const sessionManager = this.session.sessionManager;
251
- const forkingCurrentLeaf = targetLeafId !== null && targetLeafId === sessionManager.getLeafId();
252
- await this.teardownCurrent("fork", sessionManager.getSessionFile());
253
- if (forkingCurrentLeaf)
254
- targetLeafId = sessionManager.getLeafId();
255
- if (!targetLeafId) {
256
- sessionManager.newSession({ parentSession: previousSessionFile });
233
+ if (!existsSync(currentSessionFile)) {
234
+ throw new Error("This session has not been saved yet. Wait for the first assistant response before cloning or forking it.");
257
235
  }
258
- else {
259
- sessionManager.createBranchedSession(targetLeafId);
236
+ // Validate and honor vetoes before closing admission, but settle owned
237
+ // usage before reading the source file for the fork.
238
+ const forkingCurrentLeaf = targetLeafId === this.session.sessionManager.getLeafId();
239
+ this.session.background.close();
240
+ await Promise.all([this.session.background.shutdown(), this.session.abort()]);
241
+ if (forkingCurrentLeaf)
242
+ targetLeafId = this.session.sessionManager.getLeafId();
243
+ const sessionManager = SessionManager.open(currentSessionFile, sessionDir);
244
+ const forkedSessionPath = sessionManager.createBranchedSession(targetLeafId);
245
+ if (!forkedSessionPath) {
246
+ throw new Error("Failed to create forked session");
260
247
  }
248
+ await this.teardownCurrent("fork", sessionManager.getSessionFile());
261
249
  this.apply(await this.createRuntime({
262
- cwd: this.cwd,
250
+ cwd: sessionManager.getCwd(),
263
251
  agentDir: this.services.agentDir,
264
252
  sessionManager,
265
253
  sessionStartEvent: { type: "session_start", reason: "fork", previousSessionFile },
@@ -267,9 +255,25 @@ export class AgentSessionRuntime {
267
255
  await this.finishSessionReplacement(options?.withSession);
268
256
  return { cancelled: false, selectedText };
269
257
  }
270
- finally {
271
- resumeBackground();
258
+ const sessionManager = this.session.sessionManager;
259
+ const forkingCurrentLeaf = targetLeafId !== null && targetLeafId === sessionManager.getLeafId();
260
+ await this.teardownCurrent("fork", sessionManager.getSessionFile());
261
+ if (forkingCurrentLeaf)
262
+ targetLeafId = sessionManager.getLeafId();
263
+ if (!targetLeafId) {
264
+ sessionManager.newSession({ parentSession: previousSessionFile });
265
+ }
266
+ else {
267
+ sessionManager.createBranchedSession(targetLeafId);
272
268
  }
269
+ this.apply(await this.createRuntime({
270
+ cwd: this.cwd,
271
+ agentDir: this.services.agentDir,
272
+ sessionManager,
273
+ sessionStartEvent: { type: "session_start", reason: "fork", previousSessionFile },
274
+ }));
275
+ await this.finishSessionReplacement(options?.withSession);
276
+ return { cancelled: false, selectedText };
273
277
  }
274
278
  /**
275
279
  * Import a session JSONL file and switch runtime state to the imported session.
@@ -279,49 +283,46 @@ export class AgentSessionRuntime {
279
283
  * @throws {MissingSessionCwdError} When the imported session cwd cannot be resolved and no override is provided.
280
284
  */
281
285
  async importFromJsonl(inputPath, cwdOverride) {
282
- const resumeBackground = this.session.pauseBackgroundNotifications();
283
- try {
284
- const resolvedPath = resolvePath(inputPath);
285
- if (!existsSync(resolvedPath)) {
286
- throw new SessionImportFileNotFoundError(resolvedPath);
287
- }
288
- const sessionDir = this.session.sessionManager.getSessionDir();
289
- if (!existsSync(sessionDir)) {
290
- mkdirSync(sessionDir, { recursive: true });
291
- }
292
- let destinationPath = join(sessionDir, basename(resolvedPath));
293
- const sourceAlreadyStored = resolve(destinationPath) === resolvedPath;
294
- if (!sourceAlreadyStored) {
295
- const { name, ext } = parse(destinationPath);
296
- let suffix = 1;
297
- while (existsSync(destinationPath)) {
298
- destinationPath = join(sessionDir, `${name}-${suffix++}${ext}`);
299
- }
300
- }
301
- const beforeResult = await this.emitBeforeSwitch("resume", destinationPath);
302
- if (beforeResult.cancelled) {
303
- return beforeResult;
304
- }
305
- const previousSessionFile = this.session.sessionFile;
306
- if (!sourceAlreadyStored) {
307
- copyFileSync(resolvedPath, destinationPath, constants.COPYFILE_EXCL);
286
+ return this.withBackgroundPaused(() => this.importFromJsonlBody(inputPath, cwdOverride));
287
+ }
288
+ async importFromJsonlBody(inputPath, cwdOverride) {
289
+ const resolvedPath = resolvePath(inputPath);
290
+ if (!existsSync(resolvedPath)) {
291
+ throw new SessionImportFileNotFoundError(resolvedPath);
292
+ }
293
+ const sessionDir = this.session.sessionManager.getSessionDir();
294
+ if (!existsSync(sessionDir)) {
295
+ mkdirSync(sessionDir, { recursive: true });
296
+ }
297
+ let destinationPath = join(sessionDir, basename(resolvedPath));
298
+ const sourceAlreadyStored = resolve(destinationPath) === resolvedPath;
299
+ if (!sourceAlreadyStored) {
300
+ const { name, ext } = parse(destinationPath);
301
+ let suffix = 1;
302
+ while (existsSync(destinationPath)) {
303
+ destinationPath = join(sessionDir, `${name}-${suffix++}${ext}`);
308
304
  }
309
- let sessionManager = SessionManager.open(destinationPath, sessionDir, cwdOverride);
310
- assertSessionCwdExists(sessionManager, this.cwd);
311
- await this.teardownCurrent("resume", sessionManager.getSessionFile());
312
- sessionManager = SessionManager.open(destinationPath, sessionDir, cwdOverride);
313
- this.apply(await this.createRuntime({
314
- cwd: sessionManager.getCwd(),
315
- agentDir: this.services.agentDir,
316
- sessionManager,
317
- sessionStartEvent: { type: "session_start", reason: "resume", previousSessionFile },
318
- }));
319
- await this.finishSessionReplacement();
320
- return { cancelled: false };
321
305
  }
322
- finally {
323
- resumeBackground();
306
+ const beforeResult = await this.emitBeforeSwitch("resume", destinationPath);
307
+ if (beforeResult.cancelled) {
308
+ return beforeResult;
309
+ }
310
+ const previousSessionFile = this.session.sessionFile;
311
+ if (!sourceAlreadyStored) {
312
+ copyFileSync(resolvedPath, destinationPath, constants.COPYFILE_EXCL);
324
313
  }
314
+ let sessionManager = SessionManager.open(destinationPath, sessionDir, cwdOverride);
315
+ assertSessionCwdExists(sessionManager, this.cwd);
316
+ await this.teardownCurrent("resume", sessionManager.getSessionFile());
317
+ sessionManager = SessionManager.open(destinationPath, sessionDir, cwdOverride);
318
+ this.apply(await this.createRuntime({
319
+ cwd: sessionManager.getCwd(),
320
+ agentDir: this.services.agentDir,
321
+ sessionManager,
322
+ sessionStartEvent: { type: "session_start", reason: "resume", previousSessionFile },
323
+ }));
324
+ await this.finishSessionReplacement();
325
+ return { cancelled: false };
325
326
  }
326
327
  async dispose() {
327
328
  this.session.background.close();
@@ -1 +1 @@
1
- {"version":3,"file":"agent-session-runtime.js","sourceRoot":"","sources":["../../src/core/agent-session-runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import { constants, copyFileSync, existsSync, mkdirSync } from \"node:fs\";\nimport { basename, join, parse, resolve } from \"node:path\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport type { AgentSession } from \"./agent-session.ts\";\nimport type { AgentSessionRuntimeDiagnostic, AgentSessionServices } from \"./agent-session-services.ts\";\nimport type {\n\tProjectTrustContext,\n\tReplacedSessionContext,\n\tSessionShutdownEvent,\n\tSessionStartEvent,\n} from \"./extensions/index.ts\";\nimport { emitSessionShutdownEvent } from \"./extensions/runner.ts\";\nimport type { CreateAgentSessionResult } from \"./sdk.ts\";\nimport { assertSessionCwdExists } from \"./session-cwd.ts\";\nimport { SessionManager } from \"./session-manager.ts\";\n\n/**\n * Result returned by runtime creation.\n *\n * The caller gets the created session, its cwd-bound services, and all\n * diagnostics collected during setup.\n */\nexport interface CreateAgentSessionRuntimeResult extends CreateAgentSessionResult {\n\tservices: AgentSessionServices;\n\tdiagnostics: AgentSessionRuntimeDiagnostic[];\n}\n\n/**\n * Creates a full runtime for a target cwd and session manager.\n *\n * The factory closes over process-global fixed inputs, recreates cwd-bound\n * services for the effective cwd, resolves session options against those\n * services, and finally creates the AgentSession.\n */\nexport type CreateAgentSessionRuntimeFactory = (options: {\n\tcwd: string;\n\tagentDir: string;\n\tsessionManager: SessionManager;\n\tsessionStartEvent?: SessionStartEvent;\n\tprojectTrustContext?: ProjectTrustContext;\n}) => Promise<CreateAgentSessionRuntimeResult>;\n\n/**\n * Thrown when /import references a JSONL file path that does not exist.\n */\nexport class SessionImportFileNotFoundError extends Error {\n\treadonly filePath: string;\n\n\tconstructor(filePath: string) {\n\t\tsuper(`File not found: ${filePath}`);\n\t\tthis.name = \"SessionImportFileNotFoundError\";\n\t\tthis.filePath = filePath;\n\t}\n}\n\nfunction extractUserMessageText(content: string | Array<{ type: string; text?: string }>): string {\n\tif (typeof content === \"string\") {\n\t\treturn content;\n\t}\n\n\treturn content\n\t\t.filter((part): part is { type: \"text\"; text: string } => part.type === \"text\" && typeof part.text === \"string\")\n\t\t.map((part) => part.text)\n\t\t.join(\"\");\n}\n\n/**\n * Owns the current AgentSession plus its cwd-bound services.\n *\n * Session replacement methods tear down the current runtime first, then create\n * and apply the next runtime. If creation fails, the error is propagated to the\n * caller. The caller is responsible for user-facing error handling.\n */\nexport class AgentSessionRuntime {\n\tprivate rebindSession?: (session: AgentSession) => Promise<void>;\n\tprivate beforeSessionInvalidate?: () => void;\n\tprivate _session: AgentSession;\n\tprivate _services: AgentSessionServices;\n\tprivate readonly createRuntime: CreateAgentSessionRuntimeFactory;\n\tprivate _diagnostics: AgentSessionRuntimeDiagnostic[];\n\tprivate _modelFallbackMessage?: string;\n\n\tconstructor(\n\t\t_session: AgentSession,\n\t\t_services: AgentSessionServices,\n\t\tcreateRuntime: CreateAgentSessionRuntimeFactory,\n\t\t_diagnostics: AgentSessionRuntimeDiagnostic[] = [],\n\t\t_modelFallbackMessage?: string,\n\t) {\n\t\tthis._session = _session;\n\t\tthis._services = _services;\n\t\tthis.createRuntime = createRuntime;\n\t\tthis._diagnostics = _diagnostics;\n\t\tthis._modelFallbackMessage = _modelFallbackMessage;\n\t}\n\n\tget services(): AgentSessionServices {\n\t\treturn this._services;\n\t}\n\n\tget session(): AgentSession {\n\t\treturn this._session;\n\t}\n\n\tget cwd(): string {\n\t\treturn this._services.cwd;\n\t}\n\n\tget diagnostics(): readonly AgentSessionRuntimeDiagnostic[] {\n\t\treturn this._diagnostics;\n\t}\n\n\tget modelFallbackMessage(): string | undefined {\n\t\treturn this._modelFallbackMessage;\n\t}\n\n\tsetRebindSession(rebindSession?: (session: AgentSession) => Promise<void>): void {\n\t\tthis.rebindSession = rebindSession;\n\t}\n\n\t/**\n\t * Set a synchronous callback that runs after `session_shutdown` handlers finish\n\t * but before the current session is invalidated.\n\t *\n\t * This is for host-owned UI teardown that must not yield to the event loop,\n\t * such as detaching extension-provided TUI components before the old extension\n\t * context becomes stale.\n\t */\n\tsetBeforeSessionInvalidate(beforeSessionInvalidate?: () => void): void {\n\t\tthis.beforeSessionInvalidate = beforeSessionInvalidate;\n\t}\n\n\tprivate async emitBeforeSwitch(\n\t\treason: \"new\" | \"resume\",\n\t\ttargetSessionFile?: string,\n\t): Promise<{ cancelled: boolean }> {\n\t\tconst runner = this.session.extensionRunner;\n\t\tif (!runner.hasHandlers(\"session_before_switch\")) {\n\t\t\treturn { cancelled: false };\n\t\t}\n\n\t\tconst result = await runner.emit({\n\t\t\ttype: \"session_before_switch\",\n\t\t\treason,\n\t\t\ttargetSessionFile,\n\t\t});\n\t\treturn { cancelled: result?.cancel === true };\n\t}\n\n\tprivate async emitBeforeFork(\n\t\tentryId: string,\n\t\toptions: { position: \"before\" | \"at\" },\n\t): Promise<{ cancelled: boolean }> {\n\t\tconst runner = this.session.extensionRunner;\n\t\tif (!runner.hasHandlers(\"session_before_fork\")) {\n\t\t\treturn { cancelled: false };\n\t\t}\n\n\t\tconst result = await runner.emit({\n\t\t\ttype: \"session_before_fork\",\n\t\t\tentryId,\n\t\t\t...options,\n\t\t});\n\t\treturn { cancelled: result?.cancel === true };\n\t}\n\n\tprivate async teardownCurrent(reason: SessionShutdownEvent[\"reason\"], targetSessionFile?: string): Promise<void> {\n\t\tthis.session.background.close();\n\t\t// Stop the main loop immediately too, while bounded worker cleanup runs.\n\t\t// Both must finish before extension shutdown and runtime invalidation.\n\t\tawait Promise.all([this.session.background.shutdown(), this.session.abort()]);\n\t\tawait emitSessionShutdownEvent(this.session.extensionRunner, {\n\t\t\ttype: \"session_shutdown\",\n\t\t\treason,\n\t\t\ttargetSessionFile,\n\t\t});\n\t\tthis.beforeSessionInvalidate?.();\n\t\tthis.session.dispose();\n\t}\n\n\tprivate apply(result: CreateAgentSessionRuntimeResult): void {\n\t\tthis._session = result.session;\n\t\tthis._services = result.services;\n\t\tthis._diagnostics = result.diagnostics;\n\t\tthis._modelFallbackMessage = result.modelFallbackMessage;\n\t}\n\n\tprivate async finishSessionReplacement(withSession?: (ctx: ReplacedSessionContext) => Promise<void>): Promise<void> {\n\t\tif (this.rebindSession) {\n\t\t\tawait this.rebindSession(this.session);\n\t\t}\n\t\tif (withSession) {\n\t\t\tawait withSession(this.session.createReplacedSessionContext());\n\t\t}\n\t}\n\n\tasync switchSession(\n\t\tsessionPath: string,\n\t\toptions?: {\n\t\t\tcwdOverride?: string;\n\t\t\twithSession?: (ctx: ReplacedSessionContext) => Promise<void>;\n\t\t\tprojectTrustContextFactory?: (cwd: string) => ProjectTrustContext;\n\t\t},\n\t): Promise<{ cancelled: boolean }> {\n\t\tconst resumeBackground = this.session.pauseBackgroundNotifications();\n\t\ttry {\n\t\t\tconst beforeResult = await this.emitBeforeSwitch(\"resume\", sessionPath);\n\t\t\tif (beforeResult.cancelled) {\n\t\t\t\treturn beforeResult;\n\t\t\t}\n\n\t\t\tconst previousSessionFile = this.session.sessionFile;\n\t\t\tlet sessionManager = SessionManager.open(sessionPath, undefined, options?.cwdOverride);\n\t\t\tassertSessionCwdExists(sessionManager, this.cwd);\n\t\t\tawait this.teardownCurrent(\"resume\", sessionManager.getSessionFile());\n\t\t\t// Resuming the current file must include usage persisted during teardown.\n\t\t\tsessionManager = SessionManager.open(sessionPath, undefined, options?.cwdOverride);\n\t\t\tthis.apply(\n\t\t\t\tawait this.createRuntime({\n\t\t\t\t\tcwd: sessionManager.getCwd(),\n\t\t\t\t\tagentDir: this.services.agentDir,\n\t\t\t\t\tsessionManager,\n\t\t\t\t\tsessionStartEvent: { type: \"session_start\", reason: \"resume\", previousSessionFile },\n\t\t\t\t\tprojectTrustContext: options?.projectTrustContextFactory?.(sessionManager.getCwd()),\n\t\t\t\t}),\n\t\t\t);\n\t\t\tawait this.finishSessionReplacement(options?.withSession);\n\t\t\treturn { cancelled: false };\n\t\t} finally {\n\t\t\tresumeBackground();\n\t\t}\n\t}\n\n\tasync newSession(options?: {\n\t\tparentSession?: string;\n\t\tsetup?: (sessionManager: SessionManager) => Promise<void>;\n\t\twithSession?: (ctx: ReplacedSessionContext) => Promise<void>;\n\t}): Promise<{ cancelled: boolean }> {\n\t\tconst resumeBackground = this.session.pauseBackgroundNotifications();\n\t\ttry {\n\t\t\tconst beforeResult = await this.emitBeforeSwitch(\"new\");\n\t\t\tif (beforeResult.cancelled) {\n\t\t\t\treturn beforeResult;\n\t\t\t}\n\n\t\t\tconst previousSessionFile = this.session.sessionFile;\n\t\t\tconst sessionDir = this.session.sessionManager.getSessionDir();\n\t\t\tconst sessionManager = this.session.sessionManager.isPersisted()\n\t\t\t\t? SessionManager.create(this.cwd, sessionDir)\n\t\t\t\t: SessionManager.inMemory(this.cwd);\n\t\t\tif (options?.parentSession) {\n\t\t\t\tsessionManager.newSession({ parentSession: options.parentSession });\n\t\t\t}\n\n\t\t\tawait this.teardownCurrent(\"new\", sessionManager.getSessionFile());\n\t\t\tthis.apply(\n\t\t\t\tawait this.createRuntime({\n\t\t\t\t\tcwd: this.cwd,\n\t\t\t\t\tagentDir: this.services.agentDir,\n\t\t\t\t\tsessionManager,\n\t\t\t\t\tsessionStartEvent: { type: \"session_start\", reason: \"new\", previousSessionFile },\n\t\t\t\t}),\n\t\t\t);\n\t\t\tif (options?.setup) {\n\t\t\t\tawait options.setup(this.session.sessionManager);\n\t\t\t\tthis.session.refreshContext();\n\t\t\t}\n\t\t\tawait this.finishSessionReplacement(options?.withSession);\n\t\t\treturn { cancelled: false };\n\t\t} finally {\n\t\t\tresumeBackground();\n\t\t}\n\t}\n\n\tasync fork(\n\t\tentryId: string,\n\t\toptions?: { position?: \"before\" | \"at\"; withSession?: (ctx: ReplacedSessionContext) => Promise<void> },\n\t): Promise<{ cancelled: boolean; selectedText?: string }> {\n\t\tconst resumeBackground = this.session.pauseBackgroundNotifications();\n\t\ttry {\n\t\t\tconst position = options?.position ?? \"before\";\n\t\t\tconst beforeResult = await this.emitBeforeFork(entryId, { position });\n\t\t\tif (beforeResult.cancelled) {\n\t\t\t\treturn { cancelled: true };\n\t\t\t}\n\t\t\tlet targetLeafId: string | null;\n\t\t\tlet selectedText: string | undefined;\n\n\t\t\tconst selectedEntry = this.session.sessionManager.getEntry(entryId);\n\t\t\tif (!selectedEntry) {\n\t\t\t\tthrow new Error(\"Invalid entry ID for forking\");\n\t\t\t}\n\n\t\t\tif (position === \"at\") {\n\t\t\t\ttargetLeafId = selectedEntry.id;\n\t\t\t} else {\n\t\t\t\tif (selectedEntry.type !== \"message\" || selectedEntry.message.role !== \"user\") {\n\t\t\t\t\tthrow new Error(\"Invalid entry ID for forking\");\n\t\t\t\t}\n\t\t\t\ttargetLeafId = selectedEntry.parentId;\n\t\t\t\tselectedText = extractUserMessageText(selectedEntry.message.content);\n\t\t\t}\n\n\t\t\tconst previousSessionFile = this.session.sessionFile;\n\t\t\tif (this.session.sessionManager.isPersisted()) {\n\t\t\t\tconst currentSessionFile = this.session.sessionFile;\n\t\t\t\tif (!currentSessionFile) {\n\t\t\t\t\tthrow new Error(\"Persisted session is missing a session file\");\n\t\t\t\t}\n\t\t\t\tconst sessionDir = this.session.sessionManager.getSessionDir();\n\t\t\t\tif (!targetLeafId) {\n\t\t\t\t\tconst sessionManager = SessionManager.create(this.cwd, sessionDir);\n\t\t\t\t\tsessionManager.newSession({ parentSession: currentSessionFile });\n\t\t\t\t\tawait this.teardownCurrent(\"fork\", sessionManager.getSessionFile());\n\t\t\t\t\tthis.apply(\n\t\t\t\t\t\tawait this.createRuntime({\n\t\t\t\t\t\t\tcwd: this.cwd,\n\t\t\t\t\t\t\tagentDir: this.services.agentDir,\n\t\t\t\t\t\t\tsessionManager,\n\t\t\t\t\t\t\tsessionStartEvent: { type: \"session_start\", reason: \"fork\", previousSessionFile },\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t\tawait this.finishSessionReplacement(options?.withSession);\n\t\t\t\t\treturn { cancelled: false, selectedText };\n\t\t\t\t}\n\n\t\t\t\tif (!existsSync(currentSessionFile)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\"This session has not been saved yet. Wait for the first assistant response before cloning or forking it.\",\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\t// Validate and honor vetoes before closing admission, but settle owned\n\t\t\t\t// usage before reading the source file for the fork.\n\t\t\t\tconst forkingCurrentLeaf = targetLeafId === this.session.sessionManager.getLeafId();\n\t\t\t\tthis.session.background.close();\n\t\t\t\tawait Promise.all([this.session.background.shutdown(), this.session.abort()]);\n\t\t\t\tif (forkingCurrentLeaf) targetLeafId = this.session.sessionManager.getLeafId()!;\n\t\t\t\tconst sessionManager = SessionManager.open(currentSessionFile, sessionDir);\n\t\t\t\tconst forkedSessionPath = sessionManager.createBranchedSession(targetLeafId);\n\t\t\t\tif (!forkedSessionPath) {\n\t\t\t\t\tthrow new Error(\"Failed to create forked session\");\n\t\t\t\t}\n\t\t\t\tawait this.teardownCurrent(\"fork\", sessionManager.getSessionFile());\n\t\t\t\tthis.apply(\n\t\t\t\t\tawait this.createRuntime({\n\t\t\t\t\t\tcwd: sessionManager.getCwd(),\n\t\t\t\t\t\tagentDir: this.services.agentDir,\n\t\t\t\t\t\tsessionManager,\n\t\t\t\t\t\tsessionStartEvent: { type: \"session_start\", reason: \"fork\", previousSessionFile },\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tawait this.finishSessionReplacement(options?.withSession);\n\t\t\t\treturn { cancelled: false, selectedText };\n\t\t\t}\n\n\t\t\tconst sessionManager = this.session.sessionManager;\n\t\t\tconst forkingCurrentLeaf = targetLeafId !== null && targetLeafId === sessionManager.getLeafId();\n\t\t\tawait this.teardownCurrent(\"fork\", sessionManager.getSessionFile());\n\t\t\tif (forkingCurrentLeaf) targetLeafId = sessionManager.getLeafId();\n\t\t\tif (!targetLeafId) {\n\t\t\t\tsessionManager.newSession({ parentSession: previousSessionFile });\n\t\t\t} else {\n\t\t\t\tsessionManager.createBranchedSession(targetLeafId);\n\t\t\t}\n\t\t\tthis.apply(\n\t\t\t\tawait this.createRuntime({\n\t\t\t\t\tcwd: this.cwd,\n\t\t\t\t\tagentDir: this.services.agentDir,\n\t\t\t\t\tsessionManager,\n\t\t\t\t\tsessionStartEvent: { type: \"session_start\", reason: \"fork\", previousSessionFile },\n\t\t\t\t}),\n\t\t\t);\n\t\t\tawait this.finishSessionReplacement(options?.withSession);\n\t\t\treturn { cancelled: false, selectedText };\n\t\t} finally {\n\t\t\tresumeBackground();\n\t\t}\n\t}\n\n\t/**\n\t * Import a session JSONL file and switch runtime state to the imported session.\n\t *\n\t * @returns `{ cancelled: true }` when cancelled by `session_before_switch`, otherwise `{ cancelled: false }`.\n\t * @throws {SessionImportFileNotFoundError} When the input path does not exist.\n\t * @throws {MissingSessionCwdError} When the imported session cwd cannot be resolved and no override is provided.\n\t */\n\tasync importFromJsonl(inputPath: string, cwdOverride?: string): Promise<{ cancelled: boolean }> {\n\t\tconst resumeBackground = this.session.pauseBackgroundNotifications();\n\t\ttry {\n\t\t\tconst resolvedPath = resolvePath(inputPath);\n\t\t\tif (!existsSync(resolvedPath)) {\n\t\t\t\tthrow new SessionImportFileNotFoundError(resolvedPath);\n\t\t\t}\n\n\t\t\tconst sessionDir = this.session.sessionManager.getSessionDir();\n\t\t\tif (!existsSync(sessionDir)) {\n\t\t\t\tmkdirSync(sessionDir, { recursive: true });\n\t\t\t}\n\n\t\t\tlet destinationPath = join(sessionDir, basename(resolvedPath));\n\t\t\tconst sourceAlreadyStored = resolve(destinationPath) === resolvedPath;\n\t\t\tif (!sourceAlreadyStored) {\n\t\t\t\tconst { name, ext } = parse(destinationPath);\n\t\t\t\tlet suffix = 1;\n\t\t\t\twhile (existsSync(destinationPath)) {\n\t\t\t\t\tdestinationPath = join(sessionDir, `${name}-${suffix++}${ext}`);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst beforeResult = await this.emitBeforeSwitch(\"resume\", destinationPath);\n\t\t\tif (beforeResult.cancelled) {\n\t\t\t\treturn beforeResult;\n\t\t\t}\n\n\t\t\tconst previousSessionFile = this.session.sessionFile;\n\t\t\tif (!sourceAlreadyStored) {\n\t\t\t\tcopyFileSync(resolvedPath, destinationPath, constants.COPYFILE_EXCL);\n\t\t\t}\n\n\t\t\tlet sessionManager = SessionManager.open(destinationPath, sessionDir, cwdOverride);\n\t\t\tassertSessionCwdExists(sessionManager, this.cwd);\n\t\t\tawait this.teardownCurrent(\"resume\", sessionManager.getSessionFile());\n\t\t\tsessionManager = SessionManager.open(destinationPath, sessionDir, cwdOverride);\n\t\t\tthis.apply(\n\t\t\t\tawait this.createRuntime({\n\t\t\t\t\tcwd: sessionManager.getCwd(),\n\t\t\t\t\tagentDir: this.services.agentDir,\n\t\t\t\t\tsessionManager,\n\t\t\t\t\tsessionStartEvent: { type: \"session_start\", reason: \"resume\", previousSessionFile },\n\t\t\t\t}),\n\t\t\t);\n\t\t\tawait this.finishSessionReplacement();\n\t\t\treturn { cancelled: false };\n\t\t} finally {\n\t\t\tresumeBackground();\n\t\t}\n\t}\n\n\tasync dispose(): Promise<void> {\n\t\tthis.session.background.close();\n\t\tawait Promise.all([this.session.background.shutdown(), this.session.abort()]);\n\t\tawait emitSessionShutdownEvent(this.session.extensionRunner, {\n\t\t\ttype: \"session_shutdown\",\n\t\t\treason: \"quit\",\n\t\t});\n\t\tthis.beforeSessionInvalidate?.();\n\t\tthis.session.dispose();\n\t}\n}\n\n/**\n * Create the initial runtime from a runtime factory and initial session target.\n *\n * The same factory is stored on the returned AgentSessionRuntime and reused for\n * later /new, /resume, /fork, and import flows.\n */\nexport async function createAgentSessionRuntime(\n\tcreateRuntime: CreateAgentSessionRuntimeFactory,\n\toptions: {\n\t\tcwd: string;\n\t\tagentDir: string;\n\t\tsessionManager: SessionManager;\n\t\tsessionStartEvent?: SessionStartEvent;\n\t},\n): Promise<AgentSessionRuntime> {\n\tassertSessionCwdExists(options.sessionManager, options.cwd);\n\tconst result = await createRuntime(options);\n\treturn new AgentSessionRuntime(\n\t\tresult.session,\n\t\tresult.services,\n\t\tcreateRuntime,\n\t\tresult.diagnostics,\n\t\tresult.modelFallbackMessage,\n\t);\n}\n\nexport {\n\ttype AgentSessionRuntimeDiagnostic,\n\ttype AgentSessionServices,\n\ttype CreateAgentSessionFromServicesOptions,\n\ttype CreateAgentSessionServicesOptions,\n\tcreateAgentSessionFromServices,\n\tcreateAgentSessionServices,\n} from \"./agent-session-services.ts\";\n"]}
1
+ {"version":3,"file":"agent-session-runtime.js","sourceRoot":"","sources":["../../src/core/agent-session-runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import { constants, copyFileSync, existsSync, mkdirSync } from \"node:fs\";\nimport { basename, join, parse, resolve } from \"node:path\";\nimport { resolvePath } from \"../utils/paths.ts\";\nimport type { AgentSession } from \"./agent-session.ts\";\nimport type { AgentSessionRuntimeDiagnostic, AgentSessionServices } from \"./agent-session-services.ts\";\nimport type {\n\tProjectTrustContext,\n\tReplacedSessionContext,\n\tSessionShutdownEvent,\n\tSessionStartEvent,\n} from \"./extensions/index.ts\";\nimport { emitSessionShutdownEvent } from \"./extensions/runner.ts\";\nimport type { CreateAgentSessionResult } from \"./sdk.ts\";\nimport { assertSessionCwdExists } from \"./session-cwd.ts\";\nimport { SessionManager } from \"./session-manager.ts\";\n\n/**\n * Result returned by runtime creation.\n *\n * The caller gets the created session, its cwd-bound services, and all\n * diagnostics collected during setup.\n */\nexport interface CreateAgentSessionRuntimeResult extends CreateAgentSessionResult {\n\tservices: AgentSessionServices;\n\tdiagnostics: AgentSessionRuntimeDiagnostic[];\n}\n\n/**\n * Creates a full runtime for a target cwd and session manager.\n *\n * The factory closes over process-global fixed inputs, recreates cwd-bound\n * services for the effective cwd, resolves session options against those\n * services, and finally creates the AgentSession.\n */\nexport type CreateAgentSessionRuntimeFactory = (options: {\n\tcwd: string;\n\tagentDir: string;\n\tsessionManager: SessionManager;\n\tsessionStartEvent?: SessionStartEvent;\n\tprojectTrustContext?: ProjectTrustContext;\n}) => Promise<CreateAgentSessionRuntimeResult>;\n\n/**\n * Thrown when /import references a JSONL file path that does not exist.\n */\nexport class SessionImportFileNotFoundError extends Error {\n\treadonly filePath: string;\n\n\tconstructor(filePath: string) {\n\t\tsuper(`File not found: ${filePath}`);\n\t\tthis.name = \"SessionImportFileNotFoundError\";\n\t\tthis.filePath = filePath;\n\t}\n}\n\nfunction extractUserMessageText(content: string | Array<{ type: string; text?: string }>): string {\n\tif (typeof content === \"string\") {\n\t\treturn content;\n\t}\n\n\treturn content\n\t\t.filter((part): part is { type: \"text\"; text: string } => part.type === \"text\" && typeof part.text === \"string\")\n\t\t.map((part) => part.text)\n\t\t.join(\"\");\n}\n\n/**\n * Owns the current AgentSession plus its cwd-bound services.\n *\n * Session replacement methods tear down the current runtime first, then create\n * and apply the next runtime. If creation fails, the error is propagated to the\n * caller. The caller is responsible for user-facing error handling.\n */\nexport class AgentSessionRuntime {\n\tprivate rebindSession?: (session: AgentSession) => Promise<void>;\n\tprivate beforeSessionInvalidate?: () => void;\n\tprivate _session: AgentSession;\n\tprivate _services: AgentSessionServices;\n\tprivate readonly createRuntime: CreateAgentSessionRuntimeFactory;\n\tprivate _diagnostics: AgentSessionRuntimeDiagnostic[];\n\tprivate _modelFallbackMessage?: string;\n\n\tconstructor(\n\t\t_session: AgentSession,\n\t\t_services: AgentSessionServices,\n\t\tcreateRuntime: CreateAgentSessionRuntimeFactory,\n\t\t_diagnostics: AgentSessionRuntimeDiagnostic[] = [],\n\t\t_modelFallbackMessage?: string,\n\t) {\n\t\tthis._session = _session;\n\t\tthis._services = _services;\n\t\tthis.createRuntime = createRuntime;\n\t\tthis._diagnostics = _diagnostics;\n\t\tthis._modelFallbackMessage = _modelFallbackMessage;\n\t}\n\n\tget services(): AgentSessionServices {\n\t\treturn this._services;\n\t}\n\n\tget session(): AgentSession {\n\t\treturn this._session;\n\t}\n\n\tget cwd(): string {\n\t\treturn this._services.cwd;\n\t}\n\n\tget diagnostics(): readonly AgentSessionRuntimeDiagnostic[] {\n\t\treturn this._diagnostics;\n\t}\n\n\tget modelFallbackMessage(): string | undefined {\n\t\treturn this._modelFallbackMessage;\n\t}\n\n\tsetRebindSession(rebindSession?: (session: AgentSession) => Promise<void>): void {\n\t\tthis.rebindSession = rebindSession;\n\t}\n\n\t/**\n\t * Set a synchronous callback that runs after `session_shutdown` handlers finish\n\t * but before the current session is invalidated.\n\t *\n\t * This is for host-owned UI teardown that must not yield to the event loop,\n\t * such as detaching extension-provided TUI components before the old extension\n\t * context becomes stale.\n\t */\n\tsetBeforeSessionInvalidate(beforeSessionInvalidate?: () => void): void {\n\t\tthis.beforeSessionInvalidate = beforeSessionInvalidate;\n\t}\n\n\tprivate async emitBeforeSwitch(\n\t\treason: \"new\" | \"resume\",\n\t\ttargetSessionFile?: string,\n\t): Promise<{ cancelled: boolean }> {\n\t\tconst runner = this.session.extensionRunner;\n\t\tif (!runner.hasHandlers(\"session_before_switch\")) {\n\t\t\treturn { cancelled: false };\n\t\t}\n\n\t\tconst result = await runner.emit({\n\t\t\ttype: \"session_before_switch\",\n\t\t\treason,\n\t\t\ttargetSessionFile,\n\t\t});\n\t\treturn { cancelled: result?.cancel === true };\n\t}\n\n\tprivate async emitBeforeFork(\n\t\tentryId: string,\n\t\toptions: { position: \"before\" | \"at\" },\n\t): Promise<{ cancelled: boolean }> {\n\t\tconst runner = this.session.extensionRunner;\n\t\tif (!runner.hasHandlers(\"session_before_fork\")) {\n\t\t\treturn { cancelled: false };\n\t\t}\n\n\t\tconst result = await runner.emit({\n\t\t\ttype: \"session_before_fork\",\n\t\t\tentryId,\n\t\t\t...options,\n\t\t});\n\t\treturn { cancelled: result?.cancel === true };\n\t}\n\n\tprivate async teardownCurrent(reason: SessionShutdownEvent[\"reason\"], targetSessionFile?: string): Promise<void> {\n\t\tthis.session.background.close();\n\t\t// Stop the main loop immediately too, while bounded worker cleanup runs.\n\t\t// Both must finish before extension shutdown and runtime invalidation.\n\t\tawait Promise.all([this.session.background.shutdown(), this.session.abort()]);\n\t\tawait emitSessionShutdownEvent(this.session.extensionRunner, {\n\t\t\ttype: \"session_shutdown\",\n\t\t\treason,\n\t\t\ttargetSessionFile,\n\t\t});\n\t\tthis.beforeSessionInvalidate?.();\n\t\tthis.session.dispose();\n\t}\n\n\tprivate apply(result: CreateAgentSessionRuntimeResult): void {\n\t\tthis._session = result.session;\n\t\tthis._services = result.services;\n\t\tthis._diagnostics = result.diagnostics;\n\t\tthis._modelFallbackMessage = result.modelFallbackMessage;\n\t}\n\n\tprivate async finishSessionReplacement(withSession?: (ctx: ReplacedSessionContext) => Promise<void>): Promise<void> {\n\t\tif (this.rebindSession) {\n\t\t\tawait this.rebindSession(this.session);\n\t\t}\n\t\tif (withSession) {\n\t\t\tawait withSession(this.session.createReplacedSessionContext());\n\t\t}\n\t}\n\n\t/**\n\t * Hold the outgoing session's background delivery across a replacement. The\n\t * pause belongs to the session current at entry, not the replacement.\n\t */\n\tprivate async withBackgroundPaused<T>(operation: () => Promise<T>): Promise<T> {\n\t\tconst resumeBackground = this.session.pauseBackgroundNotifications();\n\t\ttry {\n\t\t\treturn await operation();\n\t\t} finally {\n\t\t\tresumeBackground();\n\t\t}\n\t}\n\n\tasync switchSession(\n\t\tsessionPath: string,\n\t\toptions?: {\n\t\t\tcwdOverride?: string;\n\t\t\twithSession?: (ctx: ReplacedSessionContext) => Promise<void>;\n\t\t\tprojectTrustContextFactory?: (cwd: string) => ProjectTrustContext;\n\t\t},\n\t): Promise<{ cancelled: boolean }> {\n\t\treturn this.withBackgroundPaused(() => this.switchSessionBody(sessionPath, options));\n\t}\n\n\tprivate async switchSessionBody(\n\t\tsessionPath: string,\n\t\toptions?: {\n\t\t\tcwdOverride?: string;\n\t\t\twithSession?: (ctx: ReplacedSessionContext) => Promise<void>;\n\t\t\tprojectTrustContextFactory?: (cwd: string) => ProjectTrustContext;\n\t\t},\n\t): Promise<{ cancelled: boolean }> {\n\t\tconst beforeResult = await this.emitBeforeSwitch(\"resume\", sessionPath);\n\t\tif (beforeResult.cancelled) {\n\t\t\treturn beforeResult;\n\t\t}\n\n\t\tconst previousSessionFile = this.session.sessionFile;\n\t\tlet sessionManager = SessionManager.open(sessionPath, undefined, options?.cwdOverride);\n\t\tassertSessionCwdExists(sessionManager, this.cwd);\n\t\tawait this.teardownCurrent(\"resume\", sessionManager.getSessionFile());\n\t\t// Resuming the current file must include usage persisted during teardown.\n\t\tsessionManager = SessionManager.open(sessionPath, undefined, options?.cwdOverride);\n\t\tthis.apply(\n\t\t\tawait this.createRuntime({\n\t\t\t\tcwd: sessionManager.getCwd(),\n\t\t\t\tagentDir: this.services.agentDir,\n\t\t\t\tsessionManager,\n\t\t\t\tsessionStartEvent: { type: \"session_start\", reason: \"resume\", previousSessionFile },\n\t\t\t\tprojectTrustContext: options?.projectTrustContextFactory?.(sessionManager.getCwd()),\n\t\t\t}),\n\t\t);\n\t\tawait this.finishSessionReplacement(options?.withSession);\n\t\treturn { cancelled: false };\n\t}\n\n\tasync newSession(options?: {\n\t\tparentSession?: string;\n\t\tsetup?: (sessionManager: SessionManager) => Promise<void>;\n\t\twithSession?: (ctx: ReplacedSessionContext) => Promise<void>;\n\t}): Promise<{ cancelled: boolean }> {\n\t\treturn this.withBackgroundPaused(() => this.newSessionBody(options));\n\t}\n\n\tprivate async newSessionBody(options?: {\n\t\tparentSession?: string;\n\t\tsetup?: (sessionManager: SessionManager) => Promise<void>;\n\t\twithSession?: (ctx: ReplacedSessionContext) => Promise<void>;\n\t}): Promise<{ cancelled: boolean }> {\n\t\tconst beforeResult = await this.emitBeforeSwitch(\"new\");\n\t\tif (beforeResult.cancelled) {\n\t\t\treturn beforeResult;\n\t\t}\n\n\t\tconst previousSessionFile = this.session.sessionFile;\n\t\tconst sessionDir = this.session.sessionManager.getSessionDir();\n\t\tconst sessionManager = this.session.sessionManager.isPersisted()\n\t\t\t? SessionManager.create(this.cwd, sessionDir)\n\t\t\t: SessionManager.inMemory(this.cwd);\n\t\tif (options?.parentSession) {\n\t\t\tsessionManager.newSession({ parentSession: options.parentSession });\n\t\t}\n\n\t\tawait this.teardownCurrent(\"new\", sessionManager.getSessionFile());\n\t\tthis.apply(\n\t\t\tawait this.createRuntime({\n\t\t\t\tcwd: this.cwd,\n\t\t\t\tagentDir: this.services.agentDir,\n\t\t\t\tsessionManager,\n\t\t\t\tsessionStartEvent: { type: \"session_start\", reason: \"new\", previousSessionFile },\n\t\t\t}),\n\t\t);\n\t\tif (options?.setup) {\n\t\t\tawait options.setup(this.session.sessionManager);\n\t\t\tthis.session.refreshContext();\n\t\t}\n\t\tawait this.finishSessionReplacement(options?.withSession);\n\t\treturn { cancelled: false };\n\t}\n\n\tasync fork(\n\t\tentryId: string,\n\t\toptions?: { position?: \"before\" | \"at\"; withSession?: (ctx: ReplacedSessionContext) => Promise<void> },\n\t): Promise<{ cancelled: boolean; selectedText?: string }> {\n\t\treturn this.withBackgroundPaused(() => this.forkBody(entryId, options));\n\t}\n\n\tprivate async forkBody(\n\t\tentryId: string,\n\t\toptions?: { position?: \"before\" | \"at\"; withSession?: (ctx: ReplacedSessionContext) => Promise<void> },\n\t): Promise<{ cancelled: boolean; selectedText?: string }> {\n\t\tconst position = options?.position ?? \"before\";\n\t\tconst beforeResult = await this.emitBeforeFork(entryId, { position });\n\t\tif (beforeResult.cancelled) {\n\t\t\treturn { cancelled: true };\n\t\t}\n\t\tlet targetLeafId: string | null;\n\t\tlet selectedText: string | undefined;\n\n\t\tconst selectedEntry = this.session.sessionManager.getEntry(entryId);\n\t\tif (!selectedEntry) {\n\t\t\tthrow new Error(\"Invalid entry ID for forking\");\n\t\t}\n\n\t\tif (position === \"at\") {\n\t\t\ttargetLeafId = selectedEntry.id;\n\t\t} else {\n\t\t\tif (selectedEntry.type !== \"message\" || selectedEntry.message.role !== \"user\") {\n\t\t\t\tthrow new Error(\"Invalid entry ID for forking\");\n\t\t\t}\n\t\t\ttargetLeafId = selectedEntry.parentId;\n\t\t\tselectedText = extractUserMessageText(selectedEntry.message.content);\n\t\t}\n\n\t\tconst previousSessionFile = this.session.sessionFile;\n\t\tif (this.session.sessionManager.isPersisted()) {\n\t\t\tconst currentSessionFile = this.session.sessionFile;\n\t\t\tif (!currentSessionFile) {\n\t\t\t\tthrow new Error(\"Persisted session is missing a session file\");\n\t\t\t}\n\t\t\tconst sessionDir = this.session.sessionManager.getSessionDir();\n\t\t\tif (!targetLeafId) {\n\t\t\t\tconst sessionManager = SessionManager.create(this.cwd, sessionDir);\n\t\t\t\tsessionManager.newSession({ parentSession: currentSessionFile });\n\t\t\t\tawait this.teardownCurrent(\"fork\", sessionManager.getSessionFile());\n\t\t\t\tthis.apply(\n\t\t\t\t\tawait this.createRuntime({\n\t\t\t\t\t\tcwd: this.cwd,\n\t\t\t\t\t\tagentDir: this.services.agentDir,\n\t\t\t\t\t\tsessionManager,\n\t\t\t\t\t\tsessionStartEvent: { type: \"session_start\", reason: \"fork\", previousSessionFile },\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tawait this.finishSessionReplacement(options?.withSession);\n\t\t\t\treturn { cancelled: false, selectedText };\n\t\t\t}\n\n\t\t\tif (!existsSync(currentSessionFile)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"This session has not been saved yet. Wait for the first assistant response before cloning or forking it.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\t// Validate and honor vetoes before closing admission, but settle owned\n\t\t\t// usage before reading the source file for the fork.\n\t\t\tconst forkingCurrentLeaf = targetLeafId === this.session.sessionManager.getLeafId();\n\t\t\tthis.session.background.close();\n\t\t\tawait Promise.all([this.session.background.shutdown(), this.session.abort()]);\n\t\t\tif (forkingCurrentLeaf) targetLeafId = this.session.sessionManager.getLeafId()!;\n\t\t\tconst sessionManager = SessionManager.open(currentSessionFile, sessionDir);\n\t\t\tconst forkedSessionPath = sessionManager.createBranchedSession(targetLeafId);\n\t\t\tif (!forkedSessionPath) {\n\t\t\t\tthrow new Error(\"Failed to create forked session\");\n\t\t\t}\n\t\t\tawait this.teardownCurrent(\"fork\", sessionManager.getSessionFile());\n\t\t\tthis.apply(\n\t\t\t\tawait this.createRuntime({\n\t\t\t\t\tcwd: sessionManager.getCwd(),\n\t\t\t\t\tagentDir: this.services.agentDir,\n\t\t\t\t\tsessionManager,\n\t\t\t\t\tsessionStartEvent: { type: \"session_start\", reason: \"fork\", previousSessionFile },\n\t\t\t\t}),\n\t\t\t);\n\t\t\tawait this.finishSessionReplacement(options?.withSession);\n\t\t\treturn { cancelled: false, selectedText };\n\t\t}\n\n\t\tconst sessionManager = this.session.sessionManager;\n\t\tconst forkingCurrentLeaf = targetLeafId !== null && targetLeafId === sessionManager.getLeafId();\n\t\tawait this.teardownCurrent(\"fork\", sessionManager.getSessionFile());\n\t\tif (forkingCurrentLeaf) targetLeafId = sessionManager.getLeafId();\n\t\tif (!targetLeafId) {\n\t\t\tsessionManager.newSession({ parentSession: previousSessionFile });\n\t\t} else {\n\t\t\tsessionManager.createBranchedSession(targetLeafId);\n\t\t}\n\t\tthis.apply(\n\t\t\tawait this.createRuntime({\n\t\t\t\tcwd: this.cwd,\n\t\t\t\tagentDir: this.services.agentDir,\n\t\t\t\tsessionManager,\n\t\t\t\tsessionStartEvent: { type: \"session_start\", reason: \"fork\", previousSessionFile },\n\t\t\t}),\n\t\t);\n\t\tawait this.finishSessionReplacement(options?.withSession);\n\t\treturn { cancelled: false, selectedText };\n\t}\n\n\t/**\n\t * Import a session JSONL file and switch runtime state to the imported session.\n\t *\n\t * @returns `{ cancelled: true }` when cancelled by `session_before_switch`, otherwise `{ cancelled: false }`.\n\t * @throws {SessionImportFileNotFoundError} When the input path does not exist.\n\t * @throws {MissingSessionCwdError} When the imported session cwd cannot be resolved and no override is provided.\n\t */\n\tasync importFromJsonl(inputPath: string, cwdOverride?: string): Promise<{ cancelled: boolean }> {\n\t\treturn this.withBackgroundPaused(() => this.importFromJsonlBody(inputPath, cwdOverride));\n\t}\n\n\tprivate async importFromJsonlBody(inputPath: string, cwdOverride?: string): Promise<{ cancelled: boolean }> {\n\t\tconst resolvedPath = resolvePath(inputPath);\n\t\tif (!existsSync(resolvedPath)) {\n\t\t\tthrow new SessionImportFileNotFoundError(resolvedPath);\n\t\t}\n\n\t\tconst sessionDir = this.session.sessionManager.getSessionDir();\n\t\tif (!existsSync(sessionDir)) {\n\t\t\tmkdirSync(sessionDir, { recursive: true });\n\t\t}\n\n\t\tlet destinationPath = join(sessionDir, basename(resolvedPath));\n\t\tconst sourceAlreadyStored = resolve(destinationPath) === resolvedPath;\n\t\tif (!sourceAlreadyStored) {\n\t\t\tconst { name, ext } = parse(destinationPath);\n\t\t\tlet suffix = 1;\n\t\t\twhile (existsSync(destinationPath)) {\n\t\t\t\tdestinationPath = join(sessionDir, `${name}-${suffix++}${ext}`);\n\t\t\t}\n\t\t}\n\t\tconst beforeResult = await this.emitBeforeSwitch(\"resume\", destinationPath);\n\t\tif (beforeResult.cancelled) {\n\t\t\treturn beforeResult;\n\t\t}\n\n\t\tconst previousSessionFile = this.session.sessionFile;\n\t\tif (!sourceAlreadyStored) {\n\t\t\tcopyFileSync(resolvedPath, destinationPath, constants.COPYFILE_EXCL);\n\t\t}\n\n\t\tlet sessionManager = SessionManager.open(destinationPath, sessionDir, cwdOverride);\n\t\tassertSessionCwdExists(sessionManager, this.cwd);\n\t\tawait this.teardownCurrent(\"resume\", sessionManager.getSessionFile());\n\t\tsessionManager = SessionManager.open(destinationPath, sessionDir, cwdOverride);\n\t\tthis.apply(\n\t\t\tawait this.createRuntime({\n\t\t\t\tcwd: sessionManager.getCwd(),\n\t\t\t\tagentDir: this.services.agentDir,\n\t\t\t\tsessionManager,\n\t\t\t\tsessionStartEvent: { type: \"session_start\", reason: \"resume\", previousSessionFile },\n\t\t\t}),\n\t\t);\n\t\tawait this.finishSessionReplacement();\n\t\treturn { cancelled: false };\n\t}\n\n\tasync dispose(): Promise<void> {\n\t\tthis.session.background.close();\n\t\tawait Promise.all([this.session.background.shutdown(), this.session.abort()]);\n\t\tawait emitSessionShutdownEvent(this.session.extensionRunner, {\n\t\t\ttype: \"session_shutdown\",\n\t\t\treason: \"quit\",\n\t\t});\n\t\tthis.beforeSessionInvalidate?.();\n\t\tthis.session.dispose();\n\t}\n}\n\n/**\n * Create the initial runtime from a runtime factory and initial session target.\n *\n * The same factory is stored on the returned AgentSessionRuntime and reused for\n * later /new, /resume, /fork, and import flows.\n */\nexport async function createAgentSessionRuntime(\n\tcreateRuntime: CreateAgentSessionRuntimeFactory,\n\toptions: {\n\t\tcwd: string;\n\t\tagentDir: string;\n\t\tsessionManager: SessionManager;\n\t\tsessionStartEvent?: SessionStartEvent;\n\t},\n): Promise<AgentSessionRuntime> {\n\tassertSessionCwdExists(options.sessionManager, options.cwd);\n\tconst result = await createRuntime(options);\n\treturn new AgentSessionRuntime(\n\t\tresult.session,\n\t\tresult.services,\n\t\tcreateRuntime,\n\t\tresult.diagnostics,\n\t\tresult.modelFallbackMessage,\n\t);\n}\n\nexport {\n\ttype AgentSessionRuntimeDiagnostic,\n\ttype AgentSessionServices,\n\ttype CreateAgentSessionFromServicesOptions,\n\ttype CreateAgentSessionServicesOptions,\n\tcreateAgentSessionFromServices,\n\tcreateAgentSessionServices,\n} from \"./agent-session-services.ts\";\n"]}
@@ -275,6 +275,11 @@ export declare class AgentSession {
275
275
  pauseBackgroundNotifications(): () => void;
276
276
  /** Explicit retry after a host delivery failure; never spins on a timer by itself. */
277
277
  retryBackgroundNotifications(): void;
278
+ /**
279
+ * Run a lifecycle operation with delivery paused across its asynchronous gaps.
280
+ * Lifecycle methods are thin shells over upstream bodies so those keep upstream's shape.
281
+ */
282
+ private _withBackgroundPaused;
278
283
  get modelRuntime(): ModelRuntime;
279
284
  /** Capture stable state before any asynchronous context preparation. Never includes a partial stream. */
280
285
  getContextSnapshot(): Promise<ContextSnapshot>;
@@ -307,7 +312,12 @@ export declare class AgentSession {
307
312
  private _emitSessionCompactFailed;
308
313
  private _getIdleWaitPromise;
309
314
  private _resolveIdleWaitIfIdle;
315
+ /**
316
+ * Background completions stay paused until runs requested by settled handlers have started,
317
+ * so a deferred prompt never races a delivery for the same idle gap.
318
+ */
310
319
  private _emitAgentSettled;
320
+ private _emitAgentSettledBody;
311
321
  /**
312
322
  * Persist model/custom messages and consume queued context only after the append succeeds.
313
323
  * Returns the persisted entry ID, which boundary events and recovery omissions resolve later.
@@ -628,6 +638,7 @@ export declare class AgentSession {
628
638
  * @param customInstructions Optional instructions for the compaction summary
629
639
  */
630
640
  compact(customInstructions?: string): Promise<CompactionResult>;
641
+ private _compactBody;
631
642
  /**
632
643
  * Cancel in-progress compaction (manual or auto).
633
644
  */
@@ -669,6 +680,7 @@ export declare class AgentSession {
669
680
  * @returns Whether the post-run loop should call `agent.continue()`
670
681
  */
671
682
  private _runAutoCompaction;
683
+ private _runAutoCompactionBody;
672
684
  /**
673
685
  * Toggle auto-compaction setting.
674
686
  */
@@ -676,6 +688,7 @@ export declare class AgentSession {
676
688
  /** Whether auto-compaction is enabled */
677
689
  get autoCompactionEnabled(): boolean;
678
690
  bindExtensions(bindings: ExtensionBindings): Promise<void>;
691
+ private _bindExtensionsBody;
679
692
  private extendResourcesFromExtensions;
680
693
  private buildExtensionResourcePaths;
681
694
  private getExtensionSourceLabel;
@@ -687,6 +700,7 @@ export declare class AgentSession {
687
700
  reload(options?: {
688
701
  beforeSessionStart?: () => void | Promise<void>;
689
702
  }): Promise<void>;
703
+ private _reloadBody;
690
704
  /**
691
705
  * Check if an error is retryable (overloaded, rate limit, server errors).
692
706
  * Context overflow errors are NOT retryable (handled by compaction instead).