@sortedyuan/maybecode 0.3.2 → 0.5.0

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 (295) hide show
  1. package/README.md +166 -55
  2. package/README.zh-CN.md +267 -0
  3. package/dist/application.d.ts +40 -34
  4. package/dist/application.d.ts.map +1 -1
  5. package/dist/application.js +290 -170
  6. package/dist/application.js.map +1 -1
  7. package/dist/args.d.ts +2 -2
  8. package/dist/args.d.ts.map +1 -1
  9. package/dist/args.js +50 -27
  10. package/dist/args.js.map +1 -1
  11. package/dist/bin.js +82 -71
  12. package/dist/bin.js.map +4 -4
  13. package/dist/cli/chunk-3IORPKBL.js +3572 -0
  14. package/dist/cli/chunk-3IORPKBL.js.map +7 -0
  15. package/dist/cli/{chunk-LVTRXPDS.js → chunk-4B2Z6KW7.js} +1547 -1536
  16. package/dist/cli/chunk-4B2Z6KW7.js.map +7 -0
  17. package/dist/cli/{chunk-JT6VBKOM.js → chunk-4WG6JIJJ.js} +127 -33
  18. package/dist/cli/{chunk-JT6VBKOM.js.map → chunk-4WG6JIJJ.js.map} +3 -3
  19. package/dist/cli/{chunk-K5JWPNSY.js → chunk-5SLWALZK.js} +3521 -16164
  20. package/dist/cli/chunk-5SLWALZK.js.map +7 -0
  21. package/dist/cli/chunk-MNBYXL5Y.js +132 -0
  22. package/dist/cli/chunk-MNBYXL5Y.js.map +7 -0
  23. package/dist/cli/{chunk-F4XRPLUM.js → chunk-SLWLUEHQ.js} +226 -86
  24. package/dist/cli/chunk-SLWLUEHQ.js.map +7 -0
  25. package/dist/cli/chunk-UQDZ55LQ.js +199 -0
  26. package/dist/cli/chunk-UQDZ55LQ.js.map +7 -0
  27. package/dist/cli/{chunk-7ISOHFS7.js → chunk-WMSG5ZTR.js} +717 -388
  28. package/dist/cli/chunk-WMSG5ZTR.js.map +7 -0
  29. package/dist/cli/chunk-WVIRS76R.js +4057 -0
  30. package/dist/cli/chunk-WVIRS76R.js.map +7 -0
  31. package/dist/cli/{chunk-HOU5ITUK.js → chunk-XTEMRAQW.js} +1 -1
  32. package/dist/cli/chunk-XTEMRAQW.js.map +7 -0
  33. package/dist/cli/chunk-Z3BOPBVU.js +91 -0
  34. package/dist/cli/chunk-Z3BOPBVU.js.map +7 -0
  35. package/dist/cli/{configured-WHY3GGAJ.js → configured-ACNM6TRQ.js} +10 -9
  36. package/dist/cli/{file-type-R2T7TBHI.js → file-type-HLHPV7WC.js} +817 -13
  37. package/dist/cli/file-type-HLHPV7WC.js.map +7 -0
  38. package/dist/cli/mcp-auth-XD5U7WCV.js +74 -0
  39. package/dist/cli/mcp-auth-XD5U7WCV.js.map +7 -0
  40. package/dist/cli/onboarding-WQWCPYEO.js +530 -0
  41. package/dist/cli/onboarding-WQWCPYEO.js.map +7 -0
  42. package/dist/cli/onboarding-check-HRRI5OJ7.js +32 -0
  43. package/dist/cli/onboarding-check-HRRI5OJ7.js.map +7 -0
  44. package/dist/cli/{retained-tui-VJ3VX4R3.js → retained-tui-QF5VMYLC.js} +788 -332
  45. package/dist/cli/retained-tui-QF5VMYLC.js.map +7 -0
  46. package/dist/cli/{sixel-LWTCM76G.js → sixel-ISZ4FZ3U.js} +37 -37
  47. package/dist/cli/{sixel-LWTCM76G.js.map → sixel-ISZ4FZ3U.js.map} +1 -1
  48. package/dist/cli/{team-T7G7PPNN.js → team-O2I5BXHM.js} +7 -6
  49. package/dist/cli/{team-v2-JGBBQ7FR.js → team-v2-YYO2G7DJ.js} +816 -390
  50. package/dist/cli/team-v2-YYO2G7DJ.js.map +7 -0
  51. package/dist/cli/{web-server-FOMNPY7Q.js → web-server-SXMH6FGA.js} +55 -19
  52. package/dist/cli/web-server-SXMH6FGA.js.map +7 -0
  53. package/dist/cli/{web-ui-COB6PKC5.js → web-ui-UWQUFE4W.js} +7 -6
  54. package/dist/config-schema.json +337 -0
  55. package/dist/configured.d.ts +18 -11
  56. package/dist/configured.d.ts.map +1 -1
  57. package/dist/configured.js +213 -390
  58. package/dist/configured.js.map +1 -1
  59. package/dist/controller.d.ts +19 -18
  60. package/dist/controller.d.ts.map +1 -1
  61. package/dist/delegation-commands.d.ts +1 -1
  62. package/dist/delegation-commands.d.ts.map +1 -1
  63. package/dist/delegation-commands.js +8 -8
  64. package/dist/delegation-commands.js.map +1 -1
  65. package/dist/errors.d.ts +2 -1
  66. package/dist/errors.d.ts.map +1 -1
  67. package/dist/errors.js +2 -1
  68. package/dist/errors.js.map +1 -1
  69. package/dist/events.d.ts +8 -6
  70. package/dist/events.d.ts.map +1 -1
  71. package/dist/fork-picker.d.ts.map +1 -1
  72. package/dist/fork-picker.js +19 -5
  73. package/dist/fork-picker.js.map +1 -1
  74. package/dist/git-request.d.ts +6 -6
  75. package/dist/git-request.d.ts.map +1 -1
  76. package/dist/git-request.js +28 -15
  77. package/dist/git-request.js.map +1 -1
  78. package/dist/goal-commands.d.ts +1 -1
  79. package/dist/goal-commands.d.ts.map +1 -1
  80. package/dist/goal-commands.js +12 -5
  81. package/dist/goal-commands.js.map +1 -1
  82. package/dist/index.d.ts +5 -37
  83. package/dist/index.d.ts.map +1 -1
  84. package/dist/index.js +3 -36
  85. package/dist/index.js.map +1 -1
  86. package/dist/instructions.d.ts +2 -7
  87. package/dist/instructions.d.ts.map +1 -1
  88. package/dist/instructions.js +7 -15
  89. package/dist/instructions.js.map +1 -1
  90. package/dist/keymap.d.ts +2 -2
  91. package/dist/keymap.d.ts.map +1 -1
  92. package/dist/keymap.js +2 -2
  93. package/dist/keymap.js.map +1 -1
  94. package/dist/maybecode-config.schema.json +1765 -0
  95. package/dist/mcp-auth.d.ts +1 -1
  96. package/dist/mcp-auth.d.ts.map +1 -1
  97. package/dist/mcp-auth.js +11 -8
  98. package/dist/mcp-auth.js.map +1 -1
  99. package/dist/mcp-commands.d.ts.map +1 -1
  100. package/dist/mcp-commands.js +18 -4
  101. package/dist/mcp-commands.js.map +1 -1
  102. package/dist/mcp-interaction-ui.d.ts.map +1 -1
  103. package/dist/mcp-interaction-ui.js +11 -4
  104. package/dist/mcp-interaction-ui.js.map +1 -1
  105. package/dist/media-history.d.ts +1 -1
  106. package/dist/media-history.d.ts.map +1 -1
  107. package/dist/media-history.js +8 -2
  108. package/dist/media-history.js.map +1 -1
  109. package/dist/model-picker.d.ts.map +1 -1
  110. package/dist/model-picker.js +10 -11
  111. package/dist/model-picker.js.map +1 -1
  112. package/dist/model-transition.d.ts +11 -0
  113. package/dist/model-transition.d.ts.map +1 -0
  114. package/dist/model-transition.js +48 -0
  115. package/dist/model-transition.js.map +1 -0
  116. package/dist/model.d.ts +2 -2
  117. package/dist/model.d.ts.map +1 -1
  118. package/dist/model.js +8 -4
  119. package/dist/model.js.map +1 -1
  120. package/dist/onboarding-check.d.ts +3 -0
  121. package/dist/onboarding-check.d.ts.map +1 -0
  122. package/dist/onboarding-check.js +22 -0
  123. package/dist/onboarding-check.js.map +1 -0
  124. package/dist/onboarding.d.ts +6 -0
  125. package/dist/onboarding.d.ts.map +1 -0
  126. package/dist/onboarding.js +463 -0
  127. package/dist/onboarding.js.map +1 -0
  128. package/dist/plugins/application.d.ts +6 -4
  129. package/dist/plugins/application.d.ts.map +1 -1
  130. package/dist/plugins/application.js +106 -52
  131. package/dist/plugins/application.js.map +1 -1
  132. package/dist/plugins/instructions.d.ts +1 -1
  133. package/dist/plugins/instructions.d.ts.map +1 -1
  134. package/dist/plugins/instructions.js +24 -11
  135. package/dist/plugins/instructions.js.map +1 -1
  136. package/dist/plugins/resources.d.ts +2 -2
  137. package/dist/plugins/resources.d.ts.map +1 -1
  138. package/dist/plugins/resources.js +22 -12
  139. package/dist/plugins/resources.js.map +1 -1
  140. package/dist/policy.d.ts +1 -1
  141. package/dist/policy.d.ts.map +1 -1
  142. package/dist/policy.js +59 -11
  143. package/dist/policy.js.map +1 -1
  144. package/dist/run.d.ts +2 -0
  145. package/dist/run.d.ts.map +1 -1
  146. package/dist/run.js +38 -33
  147. package/dist/run.js.map +1 -1
  148. package/dist/runtime-instructions.d.ts +1 -1
  149. package/dist/runtime-instructions.d.ts.map +1 -1
  150. package/dist/runtime-instructions.js +15 -7
  151. package/dist/runtime-instructions.js.map +1 -1
  152. package/dist/session-navigation.d.ts +6 -0
  153. package/dist/session-navigation.d.ts.map +1 -0
  154. package/dist/session-navigation.js +64 -0
  155. package/dist/session-navigation.js.map +1 -0
  156. package/dist/session-picker.d.ts +1 -1
  157. package/dist/session-picker.d.ts.map +1 -1
  158. package/dist/session-picker.js +23 -32
  159. package/dist/session-picker.js.map +1 -1
  160. package/dist/settings.d.ts +718 -0
  161. package/dist/settings.d.ts.map +1 -0
  162. package/dist/settings.js +14 -0
  163. package/dist/settings.js.map +1 -0
  164. package/dist/skills.d.ts +1 -1
  165. package/dist/skills.d.ts.map +1 -1
  166. package/dist/skills.js +10 -12
  167. package/dist/skills.js.map +1 -1
  168. package/dist/slash-commands.d.ts +2 -2
  169. package/dist/slash-commands.d.ts.map +1 -1
  170. package/dist/slash-commands.js +149 -67
  171. package/dist/slash-commands.js.map +1 -1
  172. package/dist/team-execution.d.ts +10 -0
  173. package/dist/team-execution.d.ts.map +1 -0
  174. package/dist/team-execution.js +29 -0
  175. package/dist/team-execution.js.map +1 -0
  176. package/dist/team-patches.d.ts.map +1 -1
  177. package/dist/team-patches.js +149 -52
  178. package/dist/team-patches.js.map +1 -1
  179. package/dist/team-plan.d.ts +2 -2
  180. package/dist/team-plan.d.ts.map +1 -1
  181. package/dist/team-plan.js +115 -34
  182. package/dist/team-plan.js.map +1 -1
  183. package/dist/team-recovery.d.ts +1 -1
  184. package/dist/team-recovery.d.ts.map +1 -1
  185. package/dist/team-recovery.js +40 -10
  186. package/dist/team-recovery.js.map +1 -1
  187. package/dist/team-v2.d.ts.map +1 -1
  188. package/dist/team-v2.js +335 -104
  189. package/dist/team-v2.js.map +1 -1
  190. package/dist/team-verification.d.ts +4 -2
  191. package/dist/team-verification.d.ts.map +1 -1
  192. package/dist/team-verification.js +300 -97
  193. package/dist/team-verification.js.map +1 -1
  194. package/dist/team.d.ts +2 -2
  195. package/dist/team.d.ts.map +1 -1
  196. package/dist/team.js +172 -62
  197. package/dist/team.js.map +1 -1
  198. package/dist/terminal-web.d.ts +1 -0
  199. package/dist/terminal-web.d.ts.map +1 -1
  200. package/dist/terminal-web.js +28 -10
  201. package/dist/terminal-web.js.map +1 -1
  202. package/dist/ui/actions.d.ts.map +1 -1
  203. package/dist/ui/actions.js.map +1 -1
  204. package/dist/ui/retained-tui.d.ts.map +1 -1
  205. package/dist/ui/retained-tui.js +231 -173
  206. package/dist/ui/retained-tui.js.map +1 -1
  207. package/dist/ui/{prototype-view.d.ts → terminal-view.d.ts} +7 -7
  208. package/dist/ui/terminal-view.d.ts.map +1 -0
  209. package/dist/ui/{prototype-view.js → terminal-view.js} +185 -98
  210. package/dist/ui/terminal-view.js.map +1 -0
  211. package/dist/web-commands.d.ts.map +1 -1
  212. package/dist/web-commands.js +160 -57
  213. package/dist/web-commands.js.map +1 -1
  214. package/dist/web-extension.d.ts.map +1 -1
  215. package/dist/web-extension.js +14 -4
  216. package/dist/web-extension.js.map +1 -1
  217. package/dist/web-server.d.ts.map +1 -1
  218. package/dist/web-server.js +2 -1
  219. package/dist/web-server.js.map +1 -1
  220. package/dist/web-ui.d.ts.map +1 -1
  221. package/dist/web-ui.js +167 -40
  222. package/dist/web-ui.js.map +1 -1
  223. package/dist/workspace-configuration.d.ts +7 -0
  224. package/dist/workspace-configuration.d.ts.map +1 -0
  225. package/dist/workspace-configuration.js +134 -0
  226. package/dist/workspace-configuration.js.map +1 -0
  227. package/dist/workspace-state.d.ts +20 -0
  228. package/dist/workspace-state.d.ts.map +1 -0
  229. package/dist/workspace-state.js +2 -0
  230. package/dist/workspace-state.js.map +1 -0
  231. package/dist/workspace.d.ts +26 -43
  232. package/dist/workspace.d.ts.map +1 -1
  233. package/dist/workspace.js +261 -323
  234. package/dist/workspace.js.map +1 -1
  235. package/package.json +21 -31
  236. package/dist/cli/chunk-7ISOHFS7.js.map +0 -7
  237. package/dist/cli/chunk-F4XRPLUM.js.map +0 -7
  238. package/dist/cli/chunk-H7SNBFO4.js +0 -5522
  239. package/dist/cli/chunk-H7SNBFO4.js.map +0 -7
  240. package/dist/cli/chunk-HOU5ITUK.js.map +0 -7
  241. package/dist/cli/chunk-K5JWPNSY.js.map +0 -7
  242. package/dist/cli/chunk-LVTRXPDS.js.map +0 -7
  243. package/dist/cli/chunk-VAZMCNBB.js +0 -686
  244. package/dist/cli/chunk-VAZMCNBB.js.map +0 -7
  245. package/dist/cli/chunk-WOFEI42C.js +0 -7820
  246. package/dist/cli/chunk-WOFEI42C.js.map +0 -7
  247. package/dist/cli/file-type-R2T7TBHI.js.map +0 -7
  248. package/dist/cli/mcp-auth-UNRHSIKJ.js +0 -63
  249. package/dist/cli/mcp-auth-UNRHSIKJ.js.map +0 -7
  250. package/dist/cli/retained-tui-VJ3VX4R3.js.map +0 -7
  251. package/dist/cli/team-v2-JGBBQ7FR.js.map +0 -7
  252. package/dist/cli/tui-SA74DKMA.js +0 -1705
  253. package/dist/cli/tui-SA74DKMA.js.map +0 -7
  254. package/dist/cli/web-server-FOMNPY7Q.js.map +0 -7
  255. package/dist/delegation.d.ts +0 -2
  256. package/dist/delegation.d.ts.map +0 -1
  257. package/dist/delegation.js +0 -2
  258. package/dist/delegation.js.map +0 -1
  259. package/dist/history-memory.d.ts +0 -2
  260. package/dist/history-memory.d.ts.map +0 -1
  261. package/dist/history-memory.js +0 -2
  262. package/dist/history-memory.js.map +0 -1
  263. package/dist/subagent-budget.d.ts +0 -2
  264. package/dist/subagent-budget.d.ts.map +0 -1
  265. package/dist/subagent-budget.js +0 -2
  266. package/dist/subagent-budget.js.map +0 -1
  267. package/dist/subagent-files.d.ts +0 -2
  268. package/dist/subagent-files.d.ts.map +0 -1
  269. package/dist/subagent-files.js +0 -2
  270. package/dist/subagent-files.js.map +0 -1
  271. package/dist/subagent-host.d.ts +0 -2
  272. package/dist/subagent-host.d.ts.map +0 -1
  273. package/dist/subagent-host.js +0 -2
  274. package/dist/subagent-host.js.map +0 -1
  275. package/dist/subagent-instructions.d.ts +0 -2
  276. package/dist/subagent-instructions.d.ts.map +0 -1
  277. package/dist/subagent-instructions.js +0 -2
  278. package/dist/subagent-instructions.js.map +0 -1
  279. package/dist/subagents.d.ts +0 -2
  280. package/dist/subagents.d.ts.map +0 -1
  281. package/dist/subagents.js +0 -2
  282. package/dist/subagents.js.map +0 -1
  283. package/dist/summarizer.d.ts +0 -2
  284. package/dist/summarizer.d.ts.map +0 -1
  285. package/dist/summarizer.js +0 -2
  286. package/dist/summarizer.js.map +0 -1
  287. package/dist/tui.d.ts +0 -7
  288. package/dist/tui.d.ts.map +0 -1
  289. package/dist/tui.js +0 -1109
  290. package/dist/tui.js.map +0 -1
  291. package/dist/ui/prototype-view.d.ts.map +0 -1
  292. package/dist/ui/prototype-view.js.map +0 -1
  293. /package/dist/cli/{configured-WHY3GGAJ.js.map → configured-ACNM6TRQ.js.map} +0 -0
  294. /package/dist/cli/{team-T7G7PPNN.js.map → team-O2I5BXHM.js.map} +0 -0
  295. /package/dist/cli/{web-ui-COB6PKC5.js.map → web-ui-UWQUFE4W.js.map} +0 -0
package/dist/workspace.js CHANGED
@@ -1,14 +1,14 @@
1
- import { isAbsolute, relative, resolve } from "node:path";
2
1
  import { randomUUID } from "node:crypto";
3
2
  import { mediaHistory } from "./media-history.js";
4
- import { MaybeCodeUsageError } from "./errors.js";
5
3
  import { parsePermissionMode } from "./policy.js";
6
- import { AgentWorkspace } from "@sortedyuan/application";
7
- import { observabilityService } from "@sortedyuan/plugin-observability";
8
- import { GitCheckpointError, GitWorkspaceConflictError, ProjectGitWorkspace } from "@sortedyuan/application/git-workspace";
9
- import { AsyncEventQueue, RunCancelledError, isStreamingMayEvent, } from "@sortedyuan/core";
4
+ import { observabilityService } from "@sortedyuan/observability/plugin";
5
+ import { GitCheckpointError, GitWorkspaceConflictError, } from "@sortedyuan/may/application/git-workspace";
6
+ import { AsyncEventQueue, RunCancelledError, isStreamingMayEvent, omitUndefined, } from "@sortedyuan/may/core";
10
7
  import { mcpResourceToUserMessage, mcpPromptToUserMessage, mcpTaskToUserMessage, } from "@sortedyuan/mcp";
11
- import { MaybeCodeApplication, } from "./application.js";
8
+ import { GOAL_STATE_KEY } from "@sortedyuan/may/goals";
9
+ import { openWorkspaceConfiguration } from "./workspace-configuration.js";
10
+ import { unknownReasoningEffort, withModelConfiguration } from "./model-transition.js";
11
+ import { workspaceForkPoints } from "./session-navigation.js";
12
12
  /** MaybeCode model policy around the reusable multi-session workspace. */
13
13
  export class MaybeCodeWorkspace {
14
14
  events;
@@ -16,7 +16,7 @@ export class MaybeCodeWorkspace {
16
16
  state;
17
17
  eventQueue = new AsyncEventQueue({
18
18
  maxBufferedValues: 1024,
19
- isDroppable: (event) => event.type === "mcp.resource.updated" || event.type === "run.event" && isStreamingMayEvent(event.event),
19
+ isDroppable: (event) => event.type === "mcp.resource.updated" || (event.type === "run.event" && isStreamingMayEvent(event.event)),
20
20
  });
21
21
  managerEventRelay;
22
22
  mcpEventRelays = new Set();
@@ -43,79 +43,7 @@ export class MaybeCodeWorkspace {
43
43
  this.connectMcpEvents();
44
44
  }
45
45
  static async open(options) {
46
- if (options.delegationNotifications !== undefined && typeof options.delegationNotifications !== "boolean") {
47
- throw new TypeError("delegationNotifications must be boolean");
48
- }
49
- const state = {
50
- rootWorkspace: resolve(options.workspace),
51
- git: new Map(),
52
- createdSessions: new Map(),
53
- options: withoutSelection({
54
- ...options,
55
- permissionMode: parsePermissionMode(options.permissionMode ?? "default"),
56
- workspace: resolve(options.workspace),
57
- }),
58
- };
59
- if (state.options.git !== false)
60
- state.git.set(state.rootWorkspace, await ProjectGitWorkspace.open({
61
- ...state.options.git, workspace: state.rootWorkspace, deferInitialization: true,
62
- excludedPaths: [...(state.options.git?.excludedPaths ?? []), ...workspaceStoragePaths(state.options, state.rootWorkspace)],
63
- }));
64
- const manager = await AgentWorkspace.open({
65
- workspace: state.options.workspace,
66
- store: state.options.store,
67
- catalog: state.options.catalog,
68
- workspacePaths: async () => [state.rootWorkspace, ...((await state.git.get(state.rootWorkspace)?.listWorktrees()) ?? [])
69
- .filter(tree => tree.status !== "deleted").map(tree => tree.workspace)],
70
- openApplication: async (selection) => {
71
- const workspace = selection.workspace ?? state.options.workspace;
72
- if (workspace !== state.options.workspace && (state.options.tools || state.options.additionalTools || state.options.toolSource) && !state.options.configureWorkspace) {
73
- throw new Error("Custom workspace tools require configureWorkspace before creating or opening a worktree");
74
- }
75
- const configured = await state.options.configureWorkspace?.(workspace);
76
- let gitWorkspace = state.git.get(workspace);
77
- if (state.options.git !== false && !gitWorkspace) {
78
- gitWorkspace = await ProjectGitWorkspace.open({ ...state.options.git, workspace, deferInitialization: true,
79
- excludedPaths: [...(state.options.git?.excludedPaths ?? []), ...workspaceStoragePaths(state.options, workspace)] });
80
- state.git.set(workspace, gitWorkspace);
81
- }
82
- let nextOptions = { ...state.options, ...configured, workspace,
83
- modelRuntimeOptions: state.options.modelRuntimeOptions ?? configuredModelOptions(state.options, state.options.modelInfo?.profile) };
84
- if (selection.fork) {
85
- if (!state.options.store.inspect)
86
- throw new Error("Historical model selection requires read-only Session inspection");
87
- const history = await state.options.store.inspect(selection.fork.sessionId);
88
- const event = [...history].reverse().find(item => item.seq <= selection.fork.positionSeq && item.type === "state.updated" && item.key === "maybecode.model");
89
- if (event?.type === "state.updated") {
90
- const saved = readHistoricalModel(event.value);
91
- if (saved.profile && nextOptions.createModelConfiguration) {
92
- const configuration = await nextOptions.createModelConfiguration(saved.profile, saved.runtimeOptions);
93
- assertHistoricalModel(saved, configuration.modelInfo);
94
- nextOptions = withModelConfiguration(nextOptions, configuration, saved.runtimeOptions);
95
- }
96
- else {
97
- assertHistoricalModel(saved, nextOptions.modelInfo);
98
- nextOptions = { ...nextOptions, modelRuntimeOptions: saved.runtimeOptions };
99
- }
100
- }
101
- }
102
- const app = await MaybeCodeApplication.open({ ...applicationOptions(nextOptions, state),
103
- ...(gitWorkspace ? { gitWorkspace } : {}),
104
- ...(selection.fork ? { fork: selection.fork } : {}),
105
- ...(selection.metadata ? { sessionMetadata: selection.metadata } : {}),
106
- ...(selection.sessionId ? { sessionId: selection.sessionId } : {}), resume: selection.resume });
107
- state.options = nextOptions;
108
- if (!selection.resume && !selection.fork)
109
- state.createdSessions.set(app.sessionId, workspace);
110
- return app;
111
- },
112
- ...(options.sessionId === undefined
113
- ? {}
114
- : { sessionId: options.sessionId }),
115
- ...(options.autoResume === undefined
116
- ? {}
117
- : { autoResume: options.autoResume }),
118
- });
46
+ const { state, manager } = await openWorkspaceConfiguration(options);
119
47
  const product = new MaybeCodeWorkspace(state, manager);
120
48
  await product.syncWorktreeProcess();
121
49
  return product;
@@ -123,86 +51,85 @@ export class MaybeCodeWorkspace {
123
51
  get sessionId() {
124
52
  return this.manager.sessionId;
125
53
  }
126
- get workspace() { return this.manager.workspace; }
127
- get git() { return this.state.git.get(this.workspace); }
54
+ get workspace() {
55
+ return this.manager.workspace;
56
+ }
57
+ /** Application of the active Session; a Session change replaces it. */
58
+ get application() {
59
+ return this.manager.activeApplication;
60
+ }
61
+ /** Run a state change on the Session queue of the active application. */
62
+ transition(action, options) {
63
+ return this.manager.runStateTransition(action, options);
64
+ }
65
+ get git() {
66
+ return this.state.git.get(this.workspace);
67
+ }
128
68
  async getWorkspaceGit() {
129
69
  if (!this.git)
130
70
  return { path: this.workspace, status: "disabled", autoCommit: false };
131
71
  try {
132
72
  const status = await this.git.summary();
133
- return { path: this.workspace, status: status.state === "unborn" || status.state === "unmanaged" && status.autoCommit && !status.readOnly ? "initializing" : status.state === "unmanaged" ? "disabled" : "ready",
134
- autoCommit: status.autoCommit && !status.readOnly, detached: status.detached,
135
- ...(status.branch ? { branch: status.branch } : {}), ...(status.commit ? { commit: status.commit } : {}) };
73
+ return {
74
+ path: this.workspace,
75
+ status: status.state === "unborn" || (status.state === "unmanaged" && status.autoCommit && !status.readOnly)
76
+ ? "initializing"
77
+ : status.state === "unmanaged"
78
+ ? "disabled"
79
+ : "ready",
80
+ autoCommit: status.autoCommit && !status.readOnly,
81
+ detached: status.detached,
82
+ ...(status.branch ? { branch: status.branch } : {}),
83
+ ...(status.commit ? { commit: status.commit } : {}),
84
+ };
136
85
  }
137
86
  catch (error) {
138
- return { path: this.workspace, status: "error", autoCommit: this.git.autoCommit, error: error instanceof Error ? error.message : String(error) };
87
+ return {
88
+ path: this.workspace,
89
+ status: "error",
90
+ autoCommit: this.git.autoCommit,
91
+ error: error instanceof Error ? error.message : String(error),
92
+ };
139
93
  }
140
94
  }
141
95
  async getForkPoints(sessionId) {
142
- const nodes = await this.manager.readSessionBranchTree();
143
- const checkpoints = await this.git?.checkpoints() ?? [];
144
- const sessions = await this.listSessions();
145
- const worktrees = await this.git?.listWorktrees() ?? [];
146
- const checkpointFor = (sourceId, runId) => {
147
- const seen = new Set();
148
- while (!seen.has(sourceId)) {
149
- seen.add(sourceId);
150
- const checkpoint = [...checkpoints].reverse().find(item => item.sessionId === sourceId && (item.runId === runId || item.runIds?.includes(runId)));
151
- if (checkpoint)
152
- return checkpoint;
153
- const source = nodes.find(node => node.sessionId === sourceId)?.fork;
154
- if (!source)
155
- return undefined;
156
- sourceId = source.sessionId;
157
- }
158
- throw new Error("Session branch lineage contains a cycle");
159
- };
160
- return nodes.flatMap(node => {
161
- if (sessionId && node.sessionId !== sessionId)
162
- return [];
163
- const workspace = sessions.find(session => session.id === node.sessionId)?.workspace;
164
- const worktree = worktrees.find(tree => tree.workspace === workspace);
165
- const workspaceReady = worktree === undefined || worktree.status === "ready";
166
- return node.positions.map((position, index) => {
167
- const checkpoint = checkpointFor(node.sessionId, position.runId);
168
- const completeRequest = checkpoint?.runIds?.length ? checkpoint.runId === position.runId : true;
169
- const parent = index ? node.positions[index - 1] : undefined;
170
- return { id: `${node.sessionId}:${position.positionSeq}`, sessionId: node.sessionId, runId: position.runId,
171
- createdAt: position.timestamp, userPreview: position.request, assistantPreview: position.response,
172
- available: position.available && completeRequest && workspaceReady,
173
- ...(!workspaceReady ? { reason: "The managed worktree did not finish initialization; inspect its diagnostic" } :
174
- !completeRequest ? { reason: "The selected Run belongs to an unfinished part of this request" } : position.reason ? { reason: position.reason } : {}),
175
- ...(parent ? { parentPointId: `${node.sessionId}:${parent.positionSeq}` } : node.fork ? { parentPointId: `${node.fork.sessionId}:${node.fork.positionSeq}` } : {}),
176
- ...(checkpoint?.commit ? { commit: checkpoint.commit } : {}), ...(checkpoint?.branch ? { branch: checkpoint.branch } : {}),
177
- worktreeAvailable: position.available && completeRequest && workspaceReady && this.git?.readOnly !== true && checkpoint?.commit !== undefined && ["committed", "unchanged"].includes(checkpoint.status) };
178
- });
179
- });
96
+ return workspaceForkPoints(this.manager, () => this.git, () => this.listSessions(), sessionId);
180
97
  }
181
98
  async forkSession(pointId, mode) {
182
99
  return this.runWorkspaceOperation(() => this.forkWorkspaceSession(pointId, mode));
183
100
  }
184
101
  async forkWorkspaceSession(pointId, mode) {
185
- const point = (await this.getForkPoints()).find(item => item.id === pointId);
102
+ const point = (await this.getForkPoints()).find((item) => item.id === pointId);
186
103
  if (!point?.available)
187
104
  throw new Error(point?.reason ?? "Session history position is unavailable");
188
105
  const positionSeq = Number(point.id.slice(point.sessionId.length + 1));
189
106
  const git = this.git;
190
107
  const checkpoint = await this.checkpointForRun(point.sessionId, point.runId);
191
- const sourceWorkspace = (await this.listSessions()).find(session => session.id === point.sessionId)?.workspace;
108
+ const sourceWorkspace = (await this.listSessions()).find((session) => session.id === point.sessionId)?.workspace;
192
109
  if (!sourceWorkspace)
193
110
  throw new Error("Source Session workspace is unavailable");
194
111
  let tree;
195
112
  if (mode === "worktree") {
196
113
  if (!git || !checkpoint?.commit || !point.worktreeAvailable)
197
114
  throw new Error("Selected reply has no complete Git checkpoint");
198
- tree = await git.createWorktree({ sessionId: point.sessionId, historyPosition: positionSeq, checkpointId: checkpoint.id });
115
+ tree = await git.createWorktree({
116
+ sessionId: point.sessionId,
117
+ historyPosition: positionSeq,
118
+ checkpointId: checkpoint.id,
119
+ });
199
120
  }
200
121
  let sessionId;
201
122
  try {
202
123
  sessionId = await this.manager.forkSession(point.sessionId, positionSeq, {
203
124
  ...(tree ? { workspace: tree.workspace } : {}),
204
- metadata: { workspaceFork: { mode, sourceWorkspace, sourceCommit: point.commit ?? null,
205
- ...(tree ? { worktreeId: tree.id } : { currentFiles: true }) } },
125
+ metadata: {
126
+ workspaceFork: {
127
+ mode,
128
+ sourceWorkspace,
129
+ sourceCommit: point.commit ?? null,
130
+ ...(tree ? { worktreeId: tree.id } : { currentFiles: true }),
131
+ },
132
+ },
206
133
  });
207
134
  if (tree)
208
135
  await git.attachWorktreeSession(tree.id, sessionId);
@@ -218,7 +145,7 @@ export class MaybeCodeWorkspace {
218
145
  }
219
146
  async getCheckpoints(sessionId = this.sessionId) {
220
147
  const points = await this.getForkPoints(sessionId);
221
- const checkpoints = await this.git?.checkpoints() ?? [];
148
+ const checkpoints = (await this.git?.checkpoints()) ?? [];
222
149
  const sourceIds = [sessionId];
223
150
  while (true) {
224
151
  const created = (await this.manager.readSessionHistory(sourceIds[sourceIds.length - 1]))[0];
@@ -227,21 +154,31 @@ export class MaybeCodeWorkspace {
227
154
  if (sourceIds.includes(created.fork.sessionId))
228
155
  throw new Error("Session branch lineage contains a cycle");
229
156
  sourceIds.push(created.fork.sessionId);
230
- if (!(await this.listSessions()).some(session => session.id === created.fork.sessionId))
157
+ if (!(await this.listSessions()).some((session) => session.id === created.fork.sessionId))
231
158
  break;
232
159
  }
233
- return points.map(point => {
160
+ return points.map((point) => {
234
161
  let checkpoint;
235
162
  for (const sourceId of sourceIds) {
236
- checkpoint = [...checkpoints].reverse().find(item => item.sessionId === sourceId && (item.runId === point.runId || item.runIds?.includes(point.runId)));
163
+ checkpoint = [...checkpoints]
164
+ .reverse()
165
+ .find((item) => item.sessionId === sourceId && (item.runId === point.runId || item.runIds?.includes(point.runId)));
237
166
  if (checkpoint)
238
167
  break;
239
168
  }
240
- return { runId: point.runId, pointId: point.id,
241
- ...(checkpoint?.fromCommit ? { startCommit: checkpoint.fromCommit } : {}), ...(checkpoint?.commit ? { endCommit: checkpoint.commit } : {}),
169
+ return {
170
+ runId: point.runId,
171
+ pointId: point.id,
172
+ ...(checkpoint?.fromCommit ? { startCommit: checkpoint.fromCommit } : {}),
173
+ ...(checkpoint?.commit ? { endCommit: checkpoint.commit } : {}),
242
174
  ...(checkpoint?.branch ? { branch: checkpoint.branch } : {}),
243
- status: checkpoint?.status === "failed" ? "failed" : !checkpoint || checkpoint.status === "uncommitted" ? "unavailable" : "saved",
244
- ...(checkpoint?.error ? { error: checkpoint.error } : {}), };
175
+ status: checkpoint?.status === "failed"
176
+ ? "failed"
177
+ : !checkpoint || checkpoint.status === "uncommitted"
178
+ ? "unavailable"
179
+ : "saved",
180
+ ...(checkpoint?.error ? { error: checkpoint.error } : {}),
181
+ };
245
182
  });
246
183
  }
247
184
  async checkpointForRun(sessionId, runId) {
@@ -261,20 +198,28 @@ export class MaybeCodeWorkspace {
261
198
  throw new Error("Session branch lineage contains a cycle");
262
199
  }
263
200
  async getWorktrees() {
264
- return ((await this.git?.listWorktrees()) ?? []).filter(tree => tree.status !== "deleted").map(tree => ({
265
- id: tree.id, path: tree.workspace, branch: tree.branch, sourceSessionId: tree.sourceSessionId,
266
- pointId: `${tree.sourceSessionId}:${tree.historyPosition}`, commit: tree.commit, sessionIds: tree.sessions,
267
- status: tree.status === "failed" ? "error" : tree.status === "creating" ? "creating" : "ready", ...(tree.error ? { error: tree.error } : {}),
201
+ return ((await this.git?.listWorktrees()) ?? [])
202
+ .filter((tree) => tree.status !== "deleted")
203
+ .map((tree) => ({
204
+ id: tree.id,
205
+ path: tree.workspace,
206
+ branch: tree.branch,
207
+ sourceSessionId: tree.sourceSessionId,
208
+ pointId: `${tree.sourceSessionId}:${tree.historyPosition}`,
209
+ commit: tree.commit,
210
+ sessionIds: tree.sessions,
211
+ status: tree.status === "failed" ? "error" : tree.status === "creating" ? "creating" : "ready",
212
+ ...(tree.error ? { error: tree.error } : {}),
268
213
  }));
269
214
  }
270
215
  async openWorktree(id) {
271
216
  return this.runWorkspaceOperation(() => this.openWorkspaceWorktree(id));
272
217
  }
273
218
  async openWorkspaceWorktree(id) {
274
- const tree = (await this.getWorktrees()).find(item => item.id === id);
219
+ const tree = (await this.getWorktrees()).find((item) => item.id === id);
275
220
  if (!tree || tree.status !== "ready")
276
221
  throw new Error("Managed worktree is unavailable");
277
- const session = (await this.listSessions()).find(item => tree.sessionIds.includes(item.id));
222
+ const session = (await this.listSessions()).find((item) => tree.sessionIds.includes(item.id));
278
223
  if (!session)
279
224
  throw new Error("Worktree has no available Session");
280
225
  await this.resumeWorkspaceSession(session.id);
@@ -284,13 +229,13 @@ export class MaybeCodeWorkspace {
284
229
  }
285
230
  async deleteWorkspaceWorktree(id) {
286
231
  const git = this.requireGit();
287
- const tree = (await git.listWorktrees()).find(item => item.id === id);
232
+ const tree = (await git.listWorktrees()).find((item) => item.id === id);
288
233
  if (!tree)
289
234
  throw new Error("Managed worktree is unavailable");
290
235
  if (tree.workspace === this.workspace)
291
236
  throw new Error("Switch to another workspace before deleting this worktree");
292
237
  for (const sessionId of tree.sessions) {
293
- if ((await this.listSessions()).some(session => session.id === sessionId))
238
+ if ((await this.listSessions()).some((session) => session.id === sessionId))
294
239
  throw new Error("Delete or move associated Sessions before deleting this worktree");
295
240
  await git.attachWorktreeSession(id, sessionId, false);
296
241
  }
@@ -318,11 +263,24 @@ export class MaybeCodeWorkspace {
318
263
  if (!from)
319
264
  throw new Error("Git comparison has no available initial version");
320
265
  const diff = await git.diff({ from, ...(to ? { to } : {}) });
321
- const files = diff.files.map(file => ({ path: file.path, ...(file.previousPath ? { previousPath: file.previousPath } : {}),
266
+ const files = diff.files.map((file) => ({
267
+ path: file.path,
268
+ ...(file.previousPath ? { previousPath: file.previousPath } : {}),
322
269
  status: file.status === "typechanged" || file.status === "unknown" ? "modified" : file.status,
323
- binary: file.binary, additions: file.insertions, deletions: file.deletions, patch: file.patch }));
324
- return { scope: query.scope, title: query.scope === "run" ? "本轮文件变化" : query.scope === "session" ? "Session 文件变化" : "当前工作区文件变化",
325
- from: diff.from, ...(diff.to ? { to: diff.to } : {}), ...(query.runId ? { runId: query.runId } : {}), uncommitted: !diff.to, files };
270
+ binary: file.binary,
271
+ additions: file.insertions,
272
+ deletions: file.deletions,
273
+ patch: file.patch,
274
+ }));
275
+ return {
276
+ scope: query.scope,
277
+ title: query.scope === "run" ? "本轮文件变化" : query.scope === "session" ? "Session 文件变化" : "当前工作区文件变化",
278
+ from: diff.from,
279
+ ...(diff.to ? { to: diff.to } : {}),
280
+ ...(query.runId ? { runId: query.runId } : {}),
281
+ uncommitted: !diff.to,
282
+ files,
283
+ };
326
284
  }
327
285
  async previewRestore(runId, paths) {
328
286
  return this.runWorkspaceOperation(() => this.previewWorkspaceRestore(runId, paths));
@@ -338,21 +296,38 @@ export class MaybeCodeWorkspace {
338
296
  const previewId = randomUUID();
339
297
  this.restorePreviews.clear();
340
298
  this.restorePreviews.set(previewId, { sessionId: this.sessionId, preview });
341
- return { previewId, diff: { scope: "run", runId, title: "文件恢复预览", to: preview.commit,
342
- uncommitted: true, restorePreviewId: previewId, files: preview.files.map(file => ({
343
- path: file.path, status: file.targetMode === undefined ? "deleted" : file.beforeFingerprint === undefined ? "added" : "modified",
344
- binary: file.binary, additions: 0, deletions: 0, patch: file.patch,
345
- })) } };
299
+ return {
300
+ previewId,
301
+ diff: {
302
+ scope: "run",
303
+ runId,
304
+ title: "文件恢复预览",
305
+ to: preview.commit,
306
+ uncommitted: true,
307
+ restorePreviewId: previewId,
308
+ files: preview.files.map((file) => ({
309
+ path: file.path,
310
+ status: file.targetMode === undefined ? "deleted" : file.beforeFingerprint === undefined ? "added" : "modified",
311
+ binary: file.binary,
312
+ additions: 0,
313
+ deletions: 0,
314
+ patch: file.patch,
315
+ })),
316
+ },
317
+ };
346
318
  }
347
319
  async restoreFiles(previewId) {
348
- return this.runWorkspaceOperation(() => this.manager.runStateTransition(() => this.restoreWorkspaceFiles(previewId)));
320
+ return this.runWorkspaceOperation(() => this.transition(() => this.restoreWorkspaceFiles(previewId)));
349
321
  }
350
322
  async restoreWorkspaceFiles(previewId) {
351
323
  const saved = this.restorePreviews.get(previewId);
352
324
  if (!saved || saved.sessionId !== this.sessionId || saved.preview.workspace !== this.workspace)
353
325
  throw new Error("File restore preview is no longer available");
354
326
  try {
355
- const checkpoint = await this.requireGit().restore(saved.preview, { sessionId: this.sessionId, commitMessage: "Restore selected files from a session checkpoint" });
327
+ const checkpoint = await this.requireGit().restore(saved.preview, {
328
+ sessionId: this.sessionId,
329
+ commitMessage: "Restore selected files from a session checkpoint",
330
+ });
356
331
  this.restorePreviews.delete(previewId);
357
332
  this.eventQueue.push({ type: "workspace.git.changed", checkpoint });
358
333
  }
@@ -369,7 +344,7 @@ export class MaybeCodeWorkspace {
369
344
  }
370
345
  assertWorkspaceIdle() {
371
346
  this.throwIfClosed();
372
- if (this.isRunning || this.getGoal()?.status === "active" || this.getMcpInteractions().length)
347
+ if (this.isRunning || this.application.getGoal()?.status === "active" || this.getMcpInteractions().length)
373
348
  throw new Error("Finish the active operation before changing the workspace");
374
349
  }
375
350
  assertNoWorkspaceOperation() {
@@ -382,24 +357,28 @@ export class MaybeCodeWorkspace {
382
357
  this.assertWorkspaceIdle();
383
358
  else
384
359
  this.assertNoWorkspaceOperation();
385
- if (this.getGoal()?.status === "active")
360
+ if (this.application.getGoal()?.status === "active")
386
361
  throw new GitWorkspaceConflictError("Pause or finish the active Goal before changing the workspace");
387
362
  const previousSessionId = this.sessionId;
388
363
  const previousOptions = this.state.options;
389
- const operation = Promise.resolve().then(work).catch(error => {
364
+ const operation = Promise.resolve()
365
+ .then(work)
366
+ .catch((error) => {
390
367
  if (this.sessionId === previousSessionId)
391
368
  this.state.options = previousOptions;
392
369
  throw error;
393
370
  });
394
371
  this.workspaceOperation = operation;
395
- return operation.finally(() => { if (this.workspaceOperation === operation)
396
- this.workspaceOperation = undefined; });
372
+ return operation.finally(() => {
373
+ if (this.workspaceOperation === operation)
374
+ this.workspaceOperation = undefined;
375
+ });
397
376
  }
398
377
  async syncWorktreeProcess() {
399
378
  const git = this.state.git.get(this.state.rootWorkspace);
400
379
  if (!git || git.readOnly)
401
380
  return;
402
- const tree = (await git.listWorktrees()).find(item => item.workspace === this.workspace && item.status === "ready");
381
+ const tree = (await git.listWorktrees()).find((item) => item.workspace === this.workspace && item.status === "ready");
403
382
  if (this.worktreeProcessId && this.worktreeProcessId !== tree?.id)
404
383
  await git.trackWorktreeProcess(this.worktreeProcessId, process.pid, false);
405
384
  this.worktreeProcessId = tree?.id;
@@ -424,10 +403,10 @@ export class MaybeCodeWorkspace {
424
403
  this.assertNoWorkspaceOperation();
425
404
  this.throwIfClosed();
426
405
  parsePermissionMode(mode);
427
- await this.manager.runStateTransition(() => {
406
+ await this.transition(() => {
428
407
  if (mode === this.permissionMode)
429
408
  return;
430
- if (this.isRunning || this.getGoal()?.status === "active" || this.getMcpInteractions().length > 0) {
409
+ if (this.isRunning || this.application.getGoal()?.status === "active" || this.getMcpInteractions().length > 0) {
431
410
  throw new Error("Pause or cancel the current operation before changing permission mode");
432
411
  }
433
412
  this.state.options = { ...this.state.options, permissionMode: mode };
@@ -435,48 +414,37 @@ export class MaybeCodeWorkspace {
435
414
  }, { activeOperationMessage: "Pause or cancel the current operation before changing permission mode" });
436
415
  }
437
416
  get isRunning() {
438
- return this.workspaceOperation !== undefined || this.manager.isRunning || this.mcpOperationController !== undefined || this.pendingInputs.size > 0 || this.pendingSteering > 0;
417
+ return (this.workspaceOperation !== undefined ||
418
+ this.manager.isRunning ||
419
+ this.mcpOperationController !== undefined ||
420
+ this.pendingInputs.size > 0 ||
421
+ this.pendingSteering > 0);
439
422
  }
440
- get instructions() {
441
- return this.manager.activeApplication.instructions;
442
- }
443
- listSkills() {
444
- const skills = this.manager.activeApplication.skills;
445
- const active = new Map(skills?.listActive().map((item) => [item.name, item]));
446
- const all = new Map(skills?.registry.list().map((item) => [item.name, item]));
447
- for (const [name, item] of active)
448
- all.set(name, item);
449
- return [...all.values()].map((item) => ({ ...item, active: active.has(item.name) }));
450
- }
451
- getSkillDiagnostics() { return this.manager.activeApplication.skills?.registry.diagnostics ?? []; }
452
423
  readSkill(name) {
453
424
  this.assertNoWorkspaceOperation();
454
- return this.manager.runStateTransition(async (app) => {
455
- if (!app.skills)
425
+ return this.transition(async ({ agent }) => {
426
+ if (!agent.skills)
456
427
  throw new Error("Skills are disabled");
457
- return app.skills.listActive().find((item) => item.name === name) ?? app.skills.registry.load(name);
428
+ return agent.skills.listActive().find((item) => item.name === name) ?? agent.skills.registry.load(name);
458
429
  }, { requireIdle: false });
459
430
  }
460
431
  activateSkill(name) {
461
432
  this.assertNoWorkspaceOperation();
462
- return this.manager.runStateTransition((app) => app.activateSkill(name));
433
+ return this.transition((app) => app.activateSkill(name));
463
434
  }
464
435
  submitSkill(name, input) {
465
436
  this.assertNoWorkspaceOperation();
466
437
  return this.manager.submitPrepared(async () => {
467
- await this.manager.activeApplication.activateSkill(name);
438
+ await this.application.activateSkill(name);
468
439
  return { input: `Use the ${name} skill for this task:\n${input}` };
469
440
  });
470
441
  }
471
- get modelInfo() {
472
- return this.manager.activeApplication.modelInfo;
473
- }
474
442
  async getMcpStatus() {
475
443
  this.throwIfClosed();
476
444
  return this.mcp?.status() ?? [];
477
445
  }
478
446
  get mcp() {
479
- return this.manager.activeApplication.mcp ?? this.state.options.mcp;
447
+ return this.application.mcp ?? this.state.options.mcp;
480
448
  }
481
449
  getMcpInteractions() {
482
450
  const interactions = this.mcp?.interactions;
@@ -495,13 +463,15 @@ export class MaybeCodeWorkspace {
495
463
  const request = this.getMcpInteractions().find((entry) => entry.id === id);
496
464
  return request === undefined ? false : this.mcp.interactions.respond(id, request.owner, response);
497
465
  }
498
- mcpOwner() { return { workspaceId: this.workspace, sessionId: this.sessionId }; }
466
+ mcpOwner() {
467
+ return { workspaceId: this.workspace, sessionId: this.sessionId };
468
+ }
499
469
  /** 活动请求的子 Session 保留自己的 MCP 身份与授权记录。 */
500
470
  delegatedSessions() {
501
- return this.manager.activeApplication.ownedDelegatedSessions();
471
+ return this.application.ownedDelegatedSessions();
502
472
  }
503
473
  ownsSession(sessionId) {
504
- return sessionId === this.sessionId || this.manager.activeApplication.ownsSession(sessionId);
474
+ return sessionId === this.sessionId || this.application.ownsSession(sessionId);
505
475
  }
506
476
  async refreshMcp(serverId) {
507
477
  this.assertNoWorkspaceOperation();
@@ -528,45 +498,52 @@ export class MaybeCodeWorkspace {
528
498
  return this.mcp?.listTasks?.(this.mcpOwner()) ?? Promise.resolve([]);
529
499
  }
530
500
  getMcpTask(serverId, id, options = {}) {
531
- return this.mcpOperation((signal) => this.manager.runStateTransition(() => this.mcpMethod("getTask")(serverId, id, { ...options, signal, owner: this.mcpOwner() })), options.signal);
501
+ return this.mcpOperation((signal) => this.transition(() => this.mcpMethod("getTask")(serverId, id, { ...options, signal, owner: this.mcpOwner() })), options.signal);
532
502
  }
533
503
  updateMcpTask(serverId, id, options = {}) {
534
- return this.mcpOperation((signal) => this.manager.runStateTransition(() => this.mcpMethod("updateTask")(serverId, id, { ...options, signal, owner: this.mcpOwner() })), options.signal);
504
+ return this.mcpOperation((signal) => this.transition(() => this.mcpMethod("updateTask")(serverId, id, { ...options, signal, owner: this.mcpOwner() })), options.signal);
535
505
  }
536
506
  waitMcpTask(serverId, id, options = {}) {
537
- return this.mcpOperation((signal) => this.manager.runStateTransition(() => this.mcpMethod("waitTask")(serverId, id, { ...options, signal, owner: this.mcpOwner() })), options.signal);
507
+ return this.mcpOperation((signal) => this.transition(() => this.mcpMethod("waitTask")(serverId, id, { ...options, signal, owner: this.mcpOwner() })), options.signal);
538
508
  }
539
509
  cancelMcpTask(serverId, id, options = {}) {
540
- return this.mcpOperation((signal) => this.manager.runStateTransition(() => this.mcpMethod("cancelTask")(serverId, id, { ...options, signal, owner: this.mcpOwner() })), options.signal);
510
+ return this.mcpOperation((signal) => this.transition(() => this.mcpMethod("cancelTask")(serverId, id, { ...options, signal, owner: this.mcpOwner() })), options.signal);
541
511
  }
542
512
  forgetMcpTask(serverId, id) {
543
- return this.mcpOperation(() => this.manager.runStateTransition(() => this.mcpMethod("forgetTask")(serverId, id, this.mcpOwner())));
513
+ return this.mcpOperation(() => this.transition(() => this.mcpMethod("forgetTask")(serverId, id, this.mcpOwner())));
544
514
  }
545
515
  submitMcpTask(serverId, id, instruction) {
546
516
  return this.mcpOperation((signal) => this.manager.submitPrepared(async () => ({
547
- input: mcpTaskToUserMessage(await this.mcpMethod("getTask")(serverId, id, { signal, owner: this.mcpOwner() }), instruction), signal,
517
+ input: mcpTaskToUserMessage(await this.mcpMethod("getTask")(serverId, id, { signal, owner: this.mcpOwner() }), instruction),
518
+ signal,
548
519
  })));
549
520
  }
550
521
  readMcpResource(serverId, uri, options = {}) {
551
- return this.mcpOperation((signal) => this.manager.runStateTransition(() => this.mcpMethod("readResource")(serverId, uri, { ...options, signal, owner: this.mcpOwner() })), options.signal);
522
+ return this.mcpOperation((signal) => this.transition(() => this.mcpMethod("readResource")(serverId, uri, { ...options, signal, owner: this.mcpOwner() })), options.signal);
552
523
  }
553
524
  readMcpResourceTemplate(serverId, template, variables, options = {}) {
554
- return this.mcpOperation((signal) => this.manager.runStateTransition(() => this.mcpMethod("readResourceTemplate")(serverId, template, variables, { ...options, signal, owner: this.mcpOwner() })), options.signal);
525
+ return this.mcpOperation((signal) => this.transition(() => this.mcpMethod("readResourceTemplate")(serverId, template, variables, {
526
+ ...options,
527
+ signal,
528
+ owner: this.mcpOwner(),
529
+ })), options.signal);
555
530
  }
556
531
  getMcpPrompt(serverId, name, args, options = {}) {
557
- return this.mcpOperation((signal) => this.manager.runStateTransition(() => this.mcpMethod("getPrompt")(serverId, name, args, { ...options, signal, owner: this.mcpOwner() })), options.signal);
532
+ return this.mcpOperation((signal) => this.transition(() => this.mcpMethod("getPrompt")(serverId, name, args, { ...options, signal, owner: this.mcpOwner() })), options.signal);
558
533
  }
559
534
  completeMcp(serverId, params, options = {}) {
560
- return this.mcpOperation((signal) => this.manager.runStateTransition(() => this.mcpMethod("complete")(serverId, params, { ...options, signal, owner: this.mcpOwner() })), options.signal);
535
+ return this.mcpOperation((signal) => this.transition(() => this.mcpMethod("complete")(serverId, params, { ...options, signal, owner: this.mcpOwner() })), options.signal);
561
536
  }
562
537
  submitMcpResource(serverId, uri, instruction) {
563
538
  return this.mcpOperation((signal) => this.manager.submitPrepared(async () => ({
564
- input: mcpResourceToUserMessage(await this.mcpMethod("readResource")(serverId, uri, { signal, owner: this.mcpOwner() }), instruction), signal,
539
+ input: mcpResourceToUserMessage(await this.mcpMethod("readResource")(serverId, uri, { signal, owner: this.mcpOwner() }), instruction),
540
+ signal,
565
541
  })));
566
542
  }
567
543
  submitMcpPrompt(serverId, name, args) {
568
544
  return this.mcpOperation((signal) => this.manager.submitPrepared(async () => ({
569
- input: mcpPromptToUserMessage(await this.mcpMethod("getPrompt")(serverId, name, args, { signal, owner: this.mcpOwner() })), signal,
545
+ input: mcpPromptToUserMessage(await this.mcpMethod("getPrompt")(serverId, name, args, { signal, owner: this.mcpOwner() })),
546
+ signal,
570
547
  })));
571
548
  }
572
549
  watchMcpResource(serverId, uri) {
@@ -577,7 +554,7 @@ export class MaybeCodeWorkspace {
577
554
  return this.mcpWatches.get(key);
578
555
  const watch = await this.mcpMethod("subscribeResource")(serverId, uri, { signal, owner: this.mcpOwner() });
579
556
  this.mcpWatches.set(key, watch);
580
- void (async () => {
557
+ this.trackMcpRelay((async () => {
581
558
  for await (const event of watch.events) {
582
559
  if (!this.closed && owner.workspaceId === this.workspace && owner.sessionId === this.sessionId)
583
560
  this.eventQueue.push({ type: "mcp.resource.updated", serverId, uri: event.uri });
@@ -587,7 +564,7 @@ export class MaybeCodeWorkspace {
587
564
  this.mcpWatches.delete(key);
588
565
  if (!this.closed && owner.workspaceId === this.workspace && owner.sessionId === this.sessionId)
589
566
  this.eventQueue.push({ type: "mcp.resource.watch-closed", serverId, uri, reason });
590
- })();
567
+ })());
591
568
  return watch;
592
569
  });
593
570
  }
@@ -607,7 +584,11 @@ export class MaybeCodeWorkspace {
607
584
  throw new Error("Cannot start an MCP user operation while another operation is active");
608
585
  const controller = new AbortController();
609
586
  this.mcpOperationController = controller;
610
- const signal = AbortSignal.any([controller.signal, this.mcpLifetime.signal, ...(external === undefined ? [] : [external])]);
587
+ const signal = AbortSignal.any([
588
+ controller.signal,
589
+ this.mcpLifetime.signal,
590
+ ...(external === undefined ? [] : [external]),
591
+ ]);
611
592
  try {
612
593
  signal.throwIfAborted();
613
594
  return await work(signal);
@@ -622,7 +603,10 @@ export class MaybeCodeWorkspace {
622
603
  const controller = new AbortController();
623
604
  this.pendingInputs.add(controller);
624
605
  try {
625
- return await this.manager.submit({ ...options, signal: options.signal === undefined ? controller.signal : AbortSignal.any([controller.signal, options.signal]) });
606
+ return await this.manager.submit({
607
+ ...options,
608
+ signal: options.signal === undefined ? controller.signal : AbortSignal.any([controller.signal, options.signal]),
609
+ });
626
610
  }
627
611
  finally {
628
612
  this.pendingInputs.delete(controller);
@@ -633,7 +617,7 @@ export class MaybeCodeWorkspace {
633
617
  const epoch = this.inputEpoch;
634
618
  this.pendingSteering++;
635
619
  try {
636
- return await this.manager.runStateTransition(app => {
620
+ return await this.transition((app) => {
637
621
  if (epoch !== this.inputEpoch)
638
622
  throw new RunCancelledError("Input cancelled before acceptance");
639
623
  return app.steer(options);
@@ -643,15 +627,20 @@ export class MaybeCodeWorkspace {
643
627
  this.pendingSteering--;
644
628
  }
645
629
  }
646
- listSteeringInputs() { return this.manager.activeApplication.listSteeringInputs(); }
647
- getGoal() { return this.manager.activeApplication.getGoal(); }
648
630
  startGoal(objective, budget) {
649
631
  this.assertNoWorkspaceOperation();
650
- return this.manager.runStateTransition(app => app.startGoal(objective, budget));
632
+ return this.transition((app) => app.startGoal(objective, budget));
633
+ }
634
+ resumeGoal() {
635
+ this.assertNoWorkspaceOperation();
636
+ return this.transition((app) => app.resumeGoal());
637
+ }
638
+ pauseGoal() {
639
+ return this.transition((app) => app.pauseGoal(), { requireIdle: false });
640
+ }
641
+ cancelGoal() {
642
+ return this.transition((app) => app.cancelGoal(), { requireIdle: false });
651
643
  }
652
- resumeGoal() { this.assertNoWorkspaceOperation(); return this.manager.runStateTransition(app => app.resumeGoal()); }
653
- pauseGoal() { return this.manager.runStateTransition(app => app.pauseGoal(), { requireIdle: false }); }
654
- cancelGoal() { return this.manager.runStateTransition(app => app.cancelGoal(), { requireIdle: false }); }
655
644
  retry() {
656
645
  this.assertNoWorkspaceOperation();
657
646
  return this.manager.retry();
@@ -667,15 +656,24 @@ export class MaybeCodeWorkspace {
667
656
  resolveApproval(requestId, decision, options) {
668
657
  return this.manager.resolveApproval(requestId, decision, options);
669
658
  }
670
- get persistentRulesEnabled() { return this.manager.activeApplication.persistentRulesEnabled; }
671
- listPermissionRules(scopeId) { return this.manager.listPermissionRules(scopeId); }
672
- createPermissionRule(check, options) { return this.manager.createPermissionRule(check, options); }
673
- createPermissionRuleFrom(id, options) { return this.manager.runStateTransition(app => app.createPermissionRuleFrom(id, options)); }
674
- revokePermissionRule(id) { return this.manager.revokePermissionRule(id); }
659
+ listPermissionRules(scopeId) {
660
+ return this.manager.listPermissionRules(scopeId);
661
+ }
662
+ createPermissionRule(check, options) {
663
+ return this.manager.createPermissionRule(check, options);
664
+ }
665
+ createPermissionRuleFrom(id, options) {
666
+ return this.transition((app) => app.createPermissionRuleFrom(id, options));
667
+ }
668
+ revokePermissionRule(id) {
669
+ return this.manager.revokePermissionRule(id);
670
+ }
675
671
  listSessions() {
676
672
  return this.manager.listSessions();
677
673
  }
678
- async readSessionHistory(sessionId) { return mediaHistory(await this.manager.readSessionHistory(sessionId)); }
674
+ async readSessionHistory(sessionId) {
675
+ return mediaHistory(await this.manager.readSessionHistory(sessionId));
676
+ }
679
677
  async newSession() {
680
678
  return this.runWorkspaceOperation(() => this.newWorkspaceSession(), false);
681
679
  }
@@ -719,7 +717,7 @@ export class MaybeCodeWorkspace {
719
717
  const selected = (this.state.options.modelProfiles ?? []).find((candidate) => candidate.name === profile);
720
718
  if (selected === undefined)
721
719
  throw new Error(`Unknown model profile "${profile}"`);
722
- const result = await this.manager.runStateTransition(async (current) => {
720
+ const result = await this.transition(async (current) => {
723
721
  if (current.modelInfo?.profile === profile && !current.modelUpdateFailed) {
724
722
  this.manager.emit({ type: "model.changed", model: current.modelInfo });
725
723
  return current.modelInfo;
@@ -738,7 +736,7 @@ export class MaybeCodeWorkspace {
738
736
  this.assertModelChangeAllowed();
739
737
  await current.updateModel({
740
738
  ...configuration,
741
- ...(nextOptions.modelRuntimeOptions === undefined ? {} : { modelRuntimeOptions: nextOptions.modelRuntimeOptions }),
739
+ ...omitUndefined({ modelRuntimeOptions: nextOptions.modelRuntimeOptions }),
742
740
  });
743
741
  this.state.options = nextOptions;
744
742
  this.manager.emit({ type: "model.changed", model: current.modelInfo });
@@ -757,7 +755,7 @@ export class MaybeCodeWorkspace {
757
755
  setDefaultModel(profile) {
758
756
  this.assertNoWorkspaceOperation();
759
757
  this.throwIfClosed();
760
- return this.manager.runStateTransition(async () => {
758
+ return this.transition(async () => {
761
759
  const profiles = this.state.options.modelProfiles ?? [];
762
760
  if (!profiles.some((candidate) => candidate.name === profile)) {
763
761
  throw new Error(`Unknown model profile "${profile}"`);
@@ -779,7 +777,7 @@ export class MaybeCodeWorkspace {
779
777
  }
780
778
  async getReasoningEffort() {
781
779
  this.throwIfClosed();
782
- const profile = this.modelInfo?.profile;
780
+ const profile = this.application.modelInfo?.profile;
783
781
  if (profile === undefined)
784
782
  return unknownReasoningEffort();
785
783
  const resolveCapabilities = this.state.options.resolveModelCapabilities;
@@ -793,45 +791,42 @@ export class MaybeCodeWorkspace {
793
791
  const overridden = typeof override === "string" && (override !== configured || requested === override);
794
792
  const effectiveEffort = typeof override === "string"
795
793
  ? override
796
- : configured ?? (capabilities.status === "known"
797
- ? capabilities.defaultEffort
798
- : undefined);
794
+ : (configured ?? (capabilities.status === "known" ? capabilities.defaultEffort : undefined));
799
795
  return {
800
796
  status: capabilities.status,
801
797
  source: capabilities.source,
802
- efforts: capabilities.status === "known"
803
- ? [...capabilities.efforts]
804
- : [],
805
- ...(capabilities.status === "known" &&
806
- capabilities.defaultEffort !== undefined
807
- ? { defaultEffort: capabilities.defaultEffort }
808
- : {}),
809
- ...(effectiveEffort === undefined ? {} : { effectiveEffort }),
798
+ efforts: capabilities.status === "known" ? [...capabilities.efforts] : [],
799
+ ...omitUndefined({
800
+ defaultEffort: capabilities.status === "known" ? capabilities.defaultEffort : undefined,
801
+ effectiveEffort,
802
+ }),
810
803
  overridden,
811
804
  };
812
805
  }
813
- async getModelCapabilities(profile = this.modelInfo?.profile, refresh = false) {
806
+ async getModelCapabilities(profile = this.application.modelInfo?.profile, refresh = false) {
814
807
  if (profile === undefined || this.state.options.resolveModelCapabilities === undefined) {
815
808
  throw new Error("The active workspace does not provide model capability discovery");
816
809
  }
817
- if (!(this.state.options.modelProfiles ?? []).some(model => model.name === profile)) {
810
+ if (!(this.state.options.modelProfiles ?? []).some((model) => model.name === profile)) {
818
811
  throw new Error(`Unknown model profile: ${profile}`);
819
812
  }
820
813
  return this.state.options.resolveModelCapabilities(profile, { refresh });
821
814
  }
822
815
  get modelCapabilitiesAvailable() {
823
- return this.modelInfo?.profile !== undefined && this.state.options.resolveModelCapabilities !== undefined;
816
+ return (this.application.modelInfo?.profile !== undefined && this.state.options.resolveModelCapabilities !== undefined);
824
817
  }
825
818
  getTelemetry(query = {}) {
826
819
  const sessionId = query.sessionId ?? this.sessionId;
827
820
  if (!this.ownsSession(sessionId))
828
821
  throw new Error("Telemetry session does not belong to this workspace");
829
- return this.manager.activeApplication.getOptionalService(observabilityService)?.diagnostics?.getDiagnostics({ ...query, sessionId });
822
+ return this.application.agent
823
+ .getOptionalService(observabilityService)
824
+ ?.diagnostics?.getDiagnostics({ ...query, sessionId });
830
825
  }
831
826
  async setReasoningEffort(effort) {
832
827
  this.assertNoWorkspaceOperation();
833
828
  this.throwIfClosed();
834
- await this.manager.runStateTransition(async (current) => {
829
+ await this.transition(async (current) => {
835
830
  this.assertModelChangeAllowed();
836
831
  const profile = current.modelInfo?.profile;
837
832
  if (profile === undefined) {
@@ -859,7 +854,7 @@ export class MaybeCodeWorkspace {
859
854
  this.assertModelChangeAllowed();
860
855
  await current.updateModel({
861
856
  ...configuration,
862
- ...(nextOptions.modelRuntimeOptions === undefined ? {} : { modelRuntimeOptions: nextOptions.modelRuntimeOptions }),
857
+ ...omitUndefined({ modelRuntimeOptions: nextOptions.modelRuntimeOptions }),
863
858
  });
864
859
  this.state.options = nextOptions;
865
860
  if (effort === undefined)
@@ -874,20 +869,16 @@ export class MaybeCodeWorkspace {
874
869
  async history() {
875
870
  return mediaHistory(await this.manager.history());
876
871
  }
877
- listRecoveries() { return this.manager.listRecoveries(); }
878
- resolveRecovery(id, finding) { this.assertNoWorkspaceOperation(); return this.manager.resolveRecovery(id, finding); }
879
- listDelegationRequests() {
880
- return this.manager.activeApplication.listDelegationRequests();
872
+ listRecoveries() {
873
+ return this.manager.listRecoveries();
881
874
  }
882
- getDelegationState() {
883
- return this.manager.activeApplication.getDelegationState();
884
- }
885
- delegationToolRecords(taskId) {
886
- return this.manager.activeApplication.delegationToolRecords(taskId);
875
+ resolveRecovery(id, finding) {
876
+ this.assertNoWorkspaceOperation();
877
+ return this.manager.resolveRecovery(id, finding);
887
878
  }
888
879
  resolveDelegationRecovery(requestId, taskId, finding, outcome) {
889
880
  this.assertNoWorkspaceOperation();
890
- return this.manager.activeApplication.resolveDelegationRecovery(requestId, taskId, finding, outcome);
881
+ return this.application.resolveDelegationRecovery(requestId, taskId, finding, outcome);
891
882
  }
892
883
  queryHistory(query) {
893
884
  return this.manager.queryHistory(query);
@@ -900,7 +891,7 @@ export class MaybeCodeWorkspace {
900
891
  return this.manager.compactContext(strategy);
901
892
  }
902
893
  close() {
903
- return this.closing ??= this.closeOnce();
894
+ return (this.closing ??= this.closeOnce());
904
895
  }
905
896
  async closeOnce() {
906
897
  this.closed = true;
@@ -918,7 +909,9 @@ export class MaybeCodeWorkspace {
918
909
  }
919
910
  if (this.worktreeProcessId) {
920
911
  try {
921
- await this.state.git.get(this.state.rootWorkspace).trackWorktreeProcess(this.worktreeProcessId, process.pid, false);
912
+ await this.state.git
913
+ .get(this.state.rootWorkspace)
914
+ .trackWorktreeProcess(this.worktreeProcessId, process.pid, false);
922
915
  }
923
916
  catch (error) {
924
917
  failures.push(error);
@@ -930,7 +923,7 @@ export class MaybeCodeWorkspace {
930
923
  catch (error) {
931
924
  failures.push(error);
932
925
  }
933
- await watchesClosing;
926
+ failures.push(...(await watchesClosing).flatMap((result) => (result.status === "rejected" ? [result.reason] : [])));
934
927
  try {
935
928
  await this.disconnectMcpEvents();
936
929
  await Promise.all([this.managerEventRelay, ...this.mcpEventRelays]);
@@ -950,9 +943,12 @@ export class MaybeCodeWorkspace {
950
943
  const { store, catalog } = this.state.options;
951
944
  for (const [sessionId, workspace] of this.state.createdSessions) {
952
945
  const history = await store.read(sessionId);
953
- if (history.some(event => event.type === "input.submitted" ||
954
- event.type === "input.steering.queued" || event.type === "run.started" ||
955
- event.type === "assistant.completed" || event.type === "session.created" && event.fork !== undefined))
946
+ if (history.some((event) => event.type === "input.submitted" ||
947
+ event.type === "input.steering.queued" ||
948
+ event.type === "run.started" ||
949
+ event.type === "assistant.completed" ||
950
+ (event.type === "session.created" && event.fork !== undefined) ||
951
+ (event.type === "state.updated" && event.key === GOAL_STATE_KEY)))
956
952
  continue;
957
953
  if (!store.delete || !catalog.remove)
958
954
  throw new Error("Empty Session cleanup requires store and catalog deletion support");
@@ -1006,85 +1002,27 @@ export class MaybeCodeWorkspace {
1006
1002
  const iterators = [...this.mcpEventIterators];
1007
1003
  this.mcpEventIterators.clear();
1008
1004
  this.observedMcp = undefined;
1009
- const results = await Promise.allSettled(iterators.map(async (iterator) => { await iterator.return?.(); }));
1010
- const errors = results.flatMap(result => result.status === "rejected" ? [result.reason] : []);
1005
+ const results = await Promise.allSettled(iterators.map(async (iterator) => {
1006
+ await iterator.return?.();
1007
+ }));
1008
+ const errors = results.flatMap((result) => (result.status === "rejected" ? [result.reason] : []));
1011
1009
  if (errors.length)
1012
1010
  throw new AggregateError(errors, "MCP event streams failed to close");
1013
1011
  }
1014
1012
  trackMcpRelay(operation) {
1015
- this.mcpEventRelays.add(operation);
1016
- void operation.then(() => this.mcpEventRelays.delete(operation), error => {
1017
- this.mcpEventRelays.delete(operation);
1013
+ const task = operation.then(() => {
1014
+ this.mcpEventRelays.delete(task);
1015
+ }, (error) => {
1016
+ this.mcpEventRelays.delete(task);
1018
1017
  this.mcpRelayErrors.push(error);
1019
1018
  if (!this.closed)
1020
1019
  this.cancel("MCP event forwarding failed");
1021
1020
  });
1021
+ this.mcpEventRelays.add(task);
1022
1022
  }
1023
1023
  throwIfClosed() {
1024
1024
  if (this.closed)
1025
1025
  throw new Error("MaybeCode workspace is closed");
1026
1026
  }
1027
1027
  }
1028
- function withoutSelection(options) {
1029
- const { sessionId: _sessionId, autoResume: _autoResume, ...base } = options;
1030
- return base;
1031
- }
1032
- function workspaceStoragePaths(options, workspace) {
1033
- const store = options.store;
1034
- const catalog = options.catalog;
1035
- return [store.directory, catalog.path, resolve(workspace, ".may", "permission-rules.json"),
1036
- resolve(workspace, ".may", "permission-rules.json.lock")].filter((value) => {
1037
- if (typeof value !== "string")
1038
- return false;
1039
- const path = relative(workspace, resolve(value));
1040
- return path !== "" && path !== ".." && !path.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) && !isAbsolute(path);
1041
- });
1042
- }
1043
- function applicationOptions(options, state) {
1044
- const { permissionMode: _permissionMode, delegationNotifications: _delegationNotifications, catalog: _catalog, modelProfiles: _modelProfiles, createModelConfiguration: _createModelConfiguration, resolveModelCapabilities: _resolveModelCapabilities, persistDefaultModel: _persistDefaultModel, closeOwnedResources: _closeOwnedResources, mcp: _mcp, git: _git, configureWorkspace: _configureWorkspace, ...application } = options;
1045
- return { ...application, permissionModeSource: () => state.options.permissionMode ?? "default" };
1046
- }
1047
- function unknownReasoningEffort() {
1048
- return {
1049
- status: "unknown",
1050
- source: "unknown",
1051
- efforts: [],
1052
- overridden: false,
1053
- };
1054
- }
1055
- function withModelConfiguration(options, configuration, runtimeOptions) {
1056
- const { model: _model, modelInfo: _modelInfo, contextBudget: _contextBudget, ...unchanged } = options;
1057
- return {
1058
- ...unchanged,
1059
- model: configuration.model,
1060
- modelInfo: configuration.modelInfo,
1061
- modelRuntimeOptions: runtimeOptions ?? configuredModelOptions(options, configuration.modelInfo.profile),
1062
- ...(configuration.contextBudget === undefined
1063
- ? {}
1064
- : { contextBudget: configuration.contextBudget }),
1065
- };
1066
- }
1067
- function configuredModelOptions(options, profile) {
1068
- const effort = options.modelProfiles?.find(item => item.name === profile)?.reasoningEffort;
1069
- return effort === undefined ? {} : { reasoningEffort: effort };
1070
- }
1071
- function readHistoricalModel(value) {
1072
- if (!value || typeof value !== "object" || Array.isArray(value))
1073
- throw new MaybeCodeUsageError("Historical model identity is invalid");
1074
- const saved = value;
1075
- for (const key of ["provider", "model"])
1076
- if (typeof saved[key] !== "string" || !saved[key])
1077
- throw new MaybeCodeUsageError(`Historical model ${key} is invalid`);
1078
- for (const key of ["profile", "adapter"])
1079
- if (saved[key] !== undefined && typeof saved[key] !== "string")
1080
- throw new MaybeCodeUsageError(`Historical model ${key} is invalid`);
1081
- if (!saved.runtimeOptions || typeof saved.runtimeOptions !== "object" || Array.isArray(saved.runtimeOptions))
1082
- throw new MaybeCodeUsageError("Historical model options are invalid");
1083
- return saved;
1084
- }
1085
- function assertHistoricalModel(saved, current) {
1086
- if (!current || saved.provider !== current.provider || saved.model !== current.model || saved.adapter !== current.adapter) {
1087
- throw new MaybeCodeUsageError("The selected history position requires its original provider, model and adapter configuration");
1088
- }
1089
- }
1090
1028
  //# sourceMappingURL=workspace.js.map