@orion-agents/orion-code 0.1.6 → 0.1.8

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 (320) hide show
  1. package/README.md +80 -46
  2. package/README.zh-CN.md +58 -20
  3. package/dist/cli.js +7 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/core-command-handlers.d.ts.map +1 -1
  6. package/dist/commands/core-command-handlers.js +4 -4
  7. package/dist/commands/core-command-handlers.js.map +1 -1
  8. package/dist/commands/diagnostic-command-handlers.d.ts.map +1 -1
  9. package/dist/commands/diagnostic-command-handlers.js +3 -0
  10. package/dist/commands/diagnostic-command-handlers.js.map +1 -1
  11. package/dist/commands/model-command-handlers.d.ts +2 -3
  12. package/dist/commands/model-command-handlers.d.ts.map +1 -1
  13. package/dist/commands/model-command-handlers.js +0 -54
  14. package/dist/commands/model-command-handlers.js.map +1 -1
  15. package/dist/commands/model-commands.d.ts.map +1 -1
  16. package/dist/commands/model-commands.js +0 -22
  17. package/dist/commands/model-commands.js.map +1 -1
  18. package/dist/commands/registry.d.ts.map +1 -1
  19. package/dist/commands/registry.js +56 -13
  20. package/dist/commands/registry.js.map +1 -1
  21. package/dist/commands/system-commands.d.ts.map +1 -1
  22. package/dist/commands/system-commands.js +76 -2
  23. package/dist/commands/system-commands.js.map +1 -1
  24. package/dist/commands/target-command.js +1 -1
  25. package/dist/commands/target-command.js.map +1 -1
  26. package/dist/commands/types.d.ts +3 -2
  27. package/dist/commands/types.d.ts.map +1 -1
  28. package/dist/commands/types.js +2 -3
  29. package/dist/commands/types.js.map +1 -1
  30. package/dist/commands/workflow-command-handlers.d.ts +2 -1
  31. package/dist/commands/workflow-command-handlers.d.ts.map +1 -1
  32. package/dist/commands/workflow-command-handlers.js +26 -0
  33. package/dist/commands/workflow-command-handlers.js.map +1 -1
  34. package/dist/commands/workflow-commands.d.ts.map +1 -1
  35. package/dist/commands/workflow-commands.js +11 -0
  36. package/dist/commands/workflow-commands.js.map +1 -1
  37. package/dist/core/checkpoint.d.ts.map +1 -1
  38. package/dist/core/checkpoint.js +9 -8
  39. package/dist/core/checkpoint.js.map +1 -1
  40. package/dist/framework/agent-mode.d.ts +47 -0
  41. package/dist/framework/agent-mode.d.ts.map +1 -0
  42. package/dist/framework/agent-mode.js +152 -0
  43. package/dist/framework/agent-mode.js.map +1 -0
  44. package/dist/framework/prompt.d.ts +5 -0
  45. package/dist/framework/prompt.d.ts.map +1 -1
  46. package/dist/framework/prompt.js +46 -9
  47. package/dist/framework/prompt.js.map +1 -1
  48. package/dist/framework/query.d.ts +4 -0
  49. package/dist/framework/query.d.ts.map +1 -1
  50. package/dist/framework/query.js +10 -0
  51. package/dist/framework/query.js.map +1 -1
  52. package/dist/framework/store.d.ts.map +1 -1
  53. package/dist/framework/store.js +4 -4
  54. package/dist/framework/store.js.map +1 -1
  55. package/dist/framework/tool-scheduler.d.ts +18 -12
  56. package/dist/framework/tool-scheduler.d.ts.map +1 -1
  57. package/dist/framework/tool-scheduler.js +74 -50
  58. package/dist/framework/tool-scheduler.js.map +1 -1
  59. package/dist/framework/tool-state.d.ts +2 -0
  60. package/dist/framework/tool-state.d.ts.map +1 -1
  61. package/dist/framework/tool-state.js +1 -0
  62. package/dist/framework/tool-state.js.map +1 -1
  63. package/dist/framework/tool.d.ts +16 -0
  64. package/dist/framework/tool.d.ts.map +1 -1
  65. package/dist/framework/tool.js +9 -0
  66. package/dist/framework/tool.js.map +1 -1
  67. package/dist/print-ui/launch.d.ts +1 -0
  68. package/dist/print-ui/launch.d.ts.map +1 -1
  69. package/dist/print-ui/launch.js +5 -2
  70. package/dist/print-ui/launch.js.map +1 -1
  71. package/dist/runtime/agent-runtime-controller.d.ts +20 -1
  72. package/dist/runtime/agent-runtime-controller.d.ts.map +1 -1
  73. package/dist/runtime/agent-runtime-controller.js +250 -21
  74. package/dist/runtime/agent-runtime-controller.js.map +1 -1
  75. package/dist/runtime/agent-runtime-protocol.d.ts +31 -1
  76. package/dist/runtime/agent-runtime-protocol.d.ts.map +1 -1
  77. package/dist/runtime/agent-runtime-protocol.js +12 -0
  78. package/dist/runtime/agent-runtime-protocol.js.map +1 -1
  79. package/dist/runtime/chat-checkpoint.d.ts.map +1 -1
  80. package/dist/runtime/chat-checkpoint.js +2 -5
  81. package/dist/runtime/chat-checkpoint.js.map +1 -1
  82. package/dist/runtime/chat-command-scope.d.ts +5 -0
  83. package/dist/runtime/chat-command-scope.d.ts.map +1 -0
  84. package/dist/runtime/chat-command-scope.js +22 -0
  85. package/dist/runtime/chat-command-scope.js.map +1 -0
  86. package/dist/runtime/chat-controller.d.ts +2 -0
  87. package/dist/runtime/chat-controller.d.ts.map +1 -1
  88. package/dist/runtime/chat-controller.js +50 -58
  89. package/dist/runtime/chat-controller.js.map +1 -1
  90. package/dist/runtime/chat-presentation.d.ts +6 -3
  91. package/dist/runtime/chat-presentation.d.ts.map +1 -1
  92. package/dist/runtime/chat-presentation.js +30 -6
  93. package/dist/runtime/chat-presentation.js.map +1 -1
  94. package/dist/runtime/goals/coordinator.d.ts +5 -0
  95. package/dist/runtime/goals/coordinator.d.ts.map +1 -1
  96. package/dist/runtime/goals/coordinator.js +102 -19
  97. package/dist/runtime/goals/coordinator.js.map +1 -1
  98. package/dist/runtime/goals/evidence.d.ts +10 -0
  99. package/dist/runtime/goals/evidence.d.ts.map +1 -1
  100. package/dist/runtime/goals/evidence.js +18 -0
  101. package/dist/runtime/goals/evidence.js.map +1 -1
  102. package/dist/runtime/goals/lifecycle.d.ts +13 -0
  103. package/dist/runtime/goals/lifecycle.d.ts.map +1 -0
  104. package/dist/runtime/goals/lifecycle.js +46 -0
  105. package/dist/runtime/goals/lifecycle.js.map +1 -0
  106. package/dist/runtime/goals/objective.d.ts +18 -0
  107. package/dist/runtime/goals/objective.d.ts.map +1 -0
  108. package/dist/runtime/goals/objective.js +60 -0
  109. package/dist/runtime/goals/objective.js.map +1 -0
  110. package/dist/runtime/goals/presentation.d.ts.map +1 -1
  111. package/dist/runtime/goals/presentation.js +4 -0
  112. package/dist/runtime/goals/presentation.js.map +1 -1
  113. package/dist/runtime/goals/prompt.d.ts.map +1 -1
  114. package/dist/runtime/goals/prompt.js +9 -2
  115. package/dist/runtime/goals/prompt.js.map +1 -1
  116. package/dist/runtime/goals/tools.d.ts +2 -0
  117. package/dist/runtime/goals/tools.d.ts.map +1 -1
  118. package/dist/runtime/goals/tools.js +20 -26
  119. package/dist/runtime/goals/tools.js.map +1 -1
  120. package/dist/runtime/goals/types.d.ts +8 -1
  121. package/dist/runtime/goals/types.d.ts.map +1 -1
  122. package/dist/runtime/goals/types.js +5 -0
  123. package/dist/runtime/goals/types.js.map +1 -1
  124. package/dist/runtime/loop-budget.d.ts +7 -0
  125. package/dist/runtime/loop-budget.d.ts.map +1 -1
  126. package/dist/runtime/loop-budget.js +22 -4
  127. package/dist/runtime/loop-budget.js.map +1 -1
  128. package/dist/runtime/ui-events.d.ts +48 -1
  129. package/dist/runtime/ui-events.d.ts.map +1 -1
  130. package/dist/runtime/ui-events.js.map +1 -1
  131. package/dist/runtime/ui-view-model.d.ts +10 -1
  132. package/dist/runtime/ui-view-model.d.ts.map +1 -1
  133. package/dist/runtime/ui-view-model.js +93 -4
  134. package/dist/runtime/ui-view-model.js.map +1 -1
  135. package/dist/services/bounded-response.d.ts +12 -0
  136. package/dist/services/bounded-response.d.ts.map +1 -0
  137. package/dist/services/bounded-response.js +67 -0
  138. package/dist/services/bounded-response.js.map +1 -0
  139. package/dist/services/concurrent-sessions.d.ts +1 -0
  140. package/dist/services/concurrent-sessions.d.ts.map +1 -1
  141. package/dist/services/concurrent-sessions.js +35 -22
  142. package/dist/services/concurrent-sessions.js.map +1 -1
  143. package/dist/services/config.d.ts.map +1 -1
  144. package/dist/services/config.js +29 -9
  145. package/dist/services/config.js.map +1 -1
  146. package/dist/services/file-lock.d.ts.map +1 -1
  147. package/dist/services/file-lock.js +60 -27
  148. package/dist/services/file-lock.js.map +1 -1
  149. package/dist/services/global-config.d.ts +16 -0
  150. package/dist/services/global-config.d.ts.map +1 -1
  151. package/dist/services/global-config.js +140 -38
  152. package/dist/services/global-config.js.map +1 -1
  153. package/dist/services/goal-storage.d.ts +1 -1
  154. package/dist/services/goal-storage.d.ts.map +1 -1
  155. package/dist/services/goal-storage.js +14 -4
  156. package/dist/services/goal-storage.js.map +1 -1
  157. package/dist/services/project-instructions.d.ts +8 -0
  158. package/dist/services/project-instructions.d.ts.map +1 -1
  159. package/dist/services/project-instructions.js +95 -38
  160. package/dist/services/project-instructions.js.map +1 -1
  161. package/dist/services/provider-resilience/request-gate.d.ts +9 -5
  162. package/dist/services/provider-resilience/request-gate.d.ts.map +1 -1
  163. package/dist/services/provider-resilience/request-gate.js +71 -23
  164. package/dist/services/provider-resilience/request-gate.js.map +1 -1
  165. package/dist/services/session-storage.d.ts +18 -5
  166. package/dist/services/session-storage.d.ts.map +1 -1
  167. package/dist/services/session-storage.js +295 -115
  168. package/dist/services/session-storage.js.map +1 -1
  169. package/dist/services/tool-allowlist.d.ts +4 -4
  170. package/dist/services/tool-allowlist.js +4 -4
  171. package/dist/services/web-search-adapters.d.ts.map +1 -1
  172. package/dist/services/web-search-adapters.js +24 -10
  173. package/dist/services/web-search-adapters.js.map +1 -1
  174. package/dist/services/web-search-mcp.d.ts.map +1 -1
  175. package/dist/services/web-search-mcp.js +13 -3
  176. package/dist/services/web-search-mcp.js.map +1 -1
  177. package/dist/services/workspace-containment.d.ts +8 -0
  178. package/dist/services/workspace-containment.d.ts.map +1 -0
  179. package/dist/services/workspace-containment.js +44 -0
  180. package/dist/services/workspace-containment.js.map +1 -0
  181. package/dist/terminal-ui/completion.d.ts.map +1 -1
  182. package/dist/terminal-ui/completion.js +5 -1
  183. package/dist/terminal-ui/completion.js.map +1 -1
  184. package/dist/terminal-ui/launch.d.ts +5 -0
  185. package/dist/terminal-ui/launch.d.ts.map +1 -1
  186. package/dist/terminal-ui/launch.js +53 -17
  187. package/dist/terminal-ui/launch.js.map +1 -1
  188. package/dist/tools/bash_security.d.ts.map +1 -1
  189. package/dist/tools/bash_security.js +12 -2
  190. package/dist/tools/bash_security.js.map +1 -1
  191. package/dist/tools/git.d.ts.map +1 -1
  192. package/dist/tools/git.js +47 -12
  193. package/dist/tools/git.js.map +1 -1
  194. package/dist/tools/index.d.ts.map +1 -1
  195. package/dist/tools/index.js +128 -54
  196. package/dist/tools/index.js.map +1 -1
  197. package/dist/tools/plan.d.ts +2 -3
  198. package/dist/tools/plan.d.ts.map +1 -1
  199. package/dist/tools/plan.js +36 -34
  200. package/dist/tools/plan.js.map +1 -1
  201. package/dist/tools/web.d.ts.map +1 -1
  202. package/dist/tools/web.js +11 -2
  203. package/dist/tools/web.js.map +1 -1
  204. package/dist/tui-core/input-parser.d.ts +1 -1
  205. package/dist/tui-core/input-parser.d.ts.map +1 -1
  206. package/dist/tui-core/input-parser.js +1 -0
  207. package/dist/tui-core/input-parser.js.map +1 -1
  208. package/dist/tui-core/style.d.ts +11 -0
  209. package/dist/tui-core/style.d.ts.map +1 -1
  210. package/dist/tui-core/style.js +68 -9
  211. package/dist/tui-core/style.js.map +1 -1
  212. package/dist/tui-ui/chrome-view-model.d.ts +19 -0
  213. package/dist/tui-ui/chrome-view-model.d.ts.map +1 -0
  214. package/dist/tui-ui/chrome-view-model.js +168 -0
  215. package/dist/tui-ui/chrome-view-model.js.map +1 -0
  216. package/dist/tui-ui/inline-surface.d.ts +1 -1
  217. package/dist/tui-ui/inline-surface.d.ts.map +1 -1
  218. package/dist/tui-ui/inline-surface.js +24 -16
  219. package/dist/tui-ui/inline-surface.js.map +1 -1
  220. package/dist/tui-ui/launch.d.ts.map +1 -1
  221. package/dist/tui-ui/launch.js +38 -2
  222. package/dist/tui-ui/launch.js.map +1 -1
  223. package/dist/tui-ui/layout.d.ts +5 -1
  224. package/dist/tui-ui/layout.d.ts.map +1 -1
  225. package/dist/tui-ui/layout.js +101 -73
  226. package/dist/tui-ui/layout.js.map +1 -1
  227. package/dist/tui-ui/pixel-mascot.d.ts +5 -0
  228. package/dist/tui-ui/pixel-mascot.d.ts.map +1 -0
  229. package/dist/tui-ui/pixel-mascot.js +33 -0
  230. package/dist/tui-ui/pixel-mascot.js.map +1 -0
  231. package/dist/tui-ui/runner.d.ts +25 -1
  232. package/dist/tui-ui/runner.d.ts.map +1 -1
  233. package/dist/tui-ui/runner.js +181 -0
  234. package/dist/tui-ui/runner.js.map +1 -1
  235. package/dist/tui-ui/state.d.ts +11 -1
  236. package/dist/tui-ui/state.d.ts.map +1 -1
  237. package/dist/tui-ui/state.js +101 -13
  238. package/dist/tui-ui/state.js.map +1 -1
  239. package/dist/tui-ui/terminal-image.d.ts +13 -3
  240. package/dist/tui-ui/terminal-image.d.ts.map +1 -1
  241. package/dist/tui-ui/terminal-image.js +25 -7
  242. package/dist/tui-ui/terminal-image.js.map +1 -1
  243. package/dist/tui-ui/theme-profile.d.ts +4 -0
  244. package/dist/tui-ui/theme-profile.d.ts.map +1 -1
  245. package/dist/tui-ui/theme-profile.js +21 -5
  246. package/dist/tui-ui/theme-profile.js.map +1 -1
  247. package/dist/tui-ui/theme.d.ts +5 -2
  248. package/dist/tui-ui/theme.d.ts.map +1 -1
  249. package/dist/tui-ui/theme.js +21 -1
  250. package/dist/tui-ui/theme.js.map +1 -1
  251. package/dist/tui-ui/transcript-layout.d.ts.map +1 -1
  252. package/dist/tui-ui/transcript-layout.js +38 -29
  253. package/dist/tui-ui/transcript-layout.js.map +1 -1
  254. package/dist/ui/command-panel.d.ts +2 -0
  255. package/dist/ui/command-panel.d.ts.map +1 -1
  256. package/dist/ui/command-panel.js +46 -20
  257. package/dist/ui/command-panel.js.map +1 -1
  258. package/dist/ui/file-completion.d.ts.map +1 -1
  259. package/dist/ui/file-completion.js +12 -6
  260. package/dist/ui/file-completion.js.map +1 -1
  261. package/dist/ui/shared/command-palette.d.ts.map +1 -1
  262. package/dist/ui/shared/command-palette.js +13 -9
  263. package/dist/ui/shared/command-palette.js.map +1 -1
  264. package/dist/ui/shared/text.d.ts +2 -0
  265. package/dist/ui/shared/text.d.ts.map +1 -1
  266. package/dist/ui/shared/text.js +20 -12
  267. package/dist/ui/shared/text.js.map +1 -1
  268. package/dist/ui/suggestions.d.ts.map +1 -1
  269. package/dist/ui/suggestions.js +7 -6
  270. package/dist/ui/suggestions.js.map +1 -1
  271. package/npm-shrinkwrap.json +7148 -0
  272. package/package.json +14 -8
  273. package/dist/ink/index.d.ts +0 -54
  274. package/dist/ink/index.d.ts.map +0 -1
  275. package/dist/ink/index.js +0 -111
  276. package/dist/ink/index.js.map +0 -1
  277. package/dist/ui-v2/components/command-palette.d.ts +0 -2
  278. package/dist/ui-v2/components/command-palette.d.ts.map +0 -1
  279. package/dist/ui-v2/components/command-palette.js +0 -18
  280. package/dist/ui-v2/components/command-palette.js.map +0 -1
  281. package/dist/ui-v2/components/edit-preview-picker.d.ts +0 -26
  282. package/dist/ui-v2/components/edit-preview-picker.d.ts.map +0 -1
  283. package/dist/ui-v2/components/edit-preview-picker.js +0 -79
  284. package/dist/ui-v2/components/edit-preview-picker.js.map +0 -1
  285. package/dist/ui-v2/components/session-picker.d.ts +0 -19
  286. package/dist/ui-v2/components/session-picker.d.ts.map +0 -1
  287. package/dist/ui-v2/components/session-picker.js +0 -52
  288. package/dist/ui-v2/components/session-picker.js.map +0 -1
  289. package/dist/ui-v2/components/shell.d.ts +0 -36
  290. package/dist/ui-v2/components/shell.d.ts.map +0 -1
  291. package/dist/ui-v2/components/shell.js +0 -131
  292. package/dist/ui-v2/components/shell.js.map +0 -1
  293. package/dist/ui-v2/index.d.ts +0 -11
  294. package/dist/ui-v2/index.d.ts.map +0 -1
  295. package/dist/ui-v2/index.js +0 -27
  296. package/dist/ui-v2/index.js.map +0 -1
  297. package/dist/ui-v2/runtime/text.d.ts +0 -2
  298. package/dist/ui-v2/runtime/text.d.ts.map +0 -1
  299. package/dist/ui-v2/runtime/text.js +0 -18
  300. package/dist/ui-v2/runtime/text.js.map +0 -1
  301. package/dist/ui-v2/state/input-reducer.d.ts +0 -39
  302. package/dist/ui-v2/state/input-reducer.d.ts.map +0 -1
  303. package/dist/ui-v2/state/input-reducer.js +0 -82
  304. package/dist/ui-v2/state/input-reducer.js.map +0 -1
  305. package/dist/ui-v2/state/picker.d.ts +0 -16
  306. package/dist/ui-v2/state/picker.d.ts.map +0 -1
  307. package/dist/ui-v2/state/picker.js +0 -52
  308. package/dist/ui-v2/state/picker.js.map +0 -1
  309. package/dist/ui-v2/state/sessions.d.ts +0 -15
  310. package/dist/ui-v2/state/sessions.d.ts.map +0 -1
  311. package/dist/ui-v2/state/sessions.js +0 -70
  312. package/dist/ui-v2/state/sessions.js.map +0 -1
  313. package/dist/ui-v2/state/suggestions.d.ts +0 -2
  314. package/dist/ui-v2/state/suggestions.d.ts.map +0 -1
  315. package/dist/ui-v2/state/suggestions.js +0 -18
  316. package/dist/ui-v2/state/suggestions.js.map +0 -1
  317. package/dist/ui-v2/types.d.ts +0 -2
  318. package/dist/ui-v2/types.d.ts.map +0 -1
  319. package/dist/ui-v2/types.js +0 -18
  320. package/dist/ui-v2/types.js.map +0 -1
@@ -21,6 +21,8 @@ const session_storage_1 = require("../services/session-storage");
21
21
  const external_assertion_1 = require("../framework/external-assertion");
22
22
  const global_config_1 = require("../services/global-config");
23
23
  const tool_allowlist_1 = require("../services/tool-allowlist");
24
+ const agent_mode_1 = require("../framework/agent-mode");
25
+ const lifecycle_1 = require("./goals/lifecycle");
24
26
  function isExitInput(input) {
25
27
  const parsed = (0, parser_1.parseInput)(input.trim());
26
28
  return parsed.isCommand && ['exit', 'quit', 'q'].includes(parsed.name);
@@ -98,6 +100,9 @@ class AgentRuntimeController {
98
100
  this.goalProviderReservedTokens = 0;
99
101
  this.nextPermissionRequestId = 1;
100
102
  this.queuedCommands = [];
103
+ this.followupQueue = [];
104
+ this.followupQueueLimit = 16;
105
+ this.nextFollowupId = 1;
101
106
  /** v0.2.24: optional goal coordinator for /target mode. */
102
107
  this.goalCoordinator = null;
103
108
  this.goalCoordinatorSessionId = null;
@@ -111,18 +116,31 @@ class AgentRuntimeController {
111
116
  this.captureGoalEvidence(event);
112
117
  const result = downstream.emit(event);
113
118
  if (event.type === 'session_restored') {
119
+ if (this.followupQueue.length > 0) {
120
+ this.followupQueue.splice(0);
121
+ this.emitFollowupQueue();
122
+ }
114
123
  this.restoreGoalForSession(event.event.sessionId, event.event.projectPath);
115
124
  }
116
125
  return result;
117
126
  },
118
127
  };
128
+ this.agentModeLifecycle =
129
+ options.agentModeLifecycle ?? new agent_mode_1.AgentModeLifecycleController(options.runtime.store);
130
+ this.agentModeLifecycle.subscribe(snapshot => {
131
+ this.eventSink.emit({ type: 'agent_mode_changed', snapshot });
132
+ });
119
133
  const events = (0, agent_runtime_protocol_1.createUiEventSinkFromAgentRuntimeEvents)(this.eventSink);
120
134
  this.runner =
121
135
  options.runner ?? new chat_controller_1.AgentChatController(options.runtime, events, this.createChatOptions());
136
+ this.emitAgentModeSnapshot();
122
137
  }
123
138
  hasActiveTurn() {
124
139
  return this.turnController.hasActiveTurn();
125
140
  }
141
+ getFollowupQueue() {
142
+ return this.followupQueue;
143
+ }
126
144
  /** v0.1.1: shared /target command handling for all renderers. */
127
145
  handleTargetInput(rawInput) {
128
146
  if (/^\/target(?:\s|$)/iu.test(rawInput.trim())) {
@@ -243,7 +261,11 @@ class AgentRuntimeController {
243
261
  this.abortGoalOwnedExecution();
244
262
  executionRevoked = true;
245
263
  }
246
- success = coord.clear();
264
+ success = (0, lifecycle_1.clearGoalLifecycle)(coord) !== null;
265
+ if (success && this.followupQueue.length > 0) {
266
+ this.followupQueue.splice(0);
267
+ this.emitFollowupQueue();
268
+ }
247
269
  if (hadGoal && !success) {
248
270
  error = this.failClosedGoalMutation(coord, input.action, new Error('Target clear did not remove the active Goal.'), executionRevoked, previousGoalId);
249
271
  }
@@ -281,23 +303,21 @@ class AgentRuntimeController {
281
303
  }
282
304
  }
283
305
  }
284
- if (success) {
306
+ if (success && input.action !== 'clear') {
285
307
  const { updateSessionGoalBinding } = require('../services/session-storage');
286
308
  updateSessionGoalBinding(coord.boundSessionId, coord.goal);
287
- if (input.action === 'clear' && previousGoalId) {
288
- this.emitGoalEvent({ type: 'goal_cleared', goalId: previousGoalId, reason: 'user_clear' });
289
- }
290
- else {
291
- const snapshot = coord.snapshot();
292
- if (snapshot) {
293
- this.emitGoalEvent({
294
- type: 'goal_updated',
295
- goal: snapshot,
296
- reason: `target_${input.action}`,
297
- });
298
- }
309
+ const snapshot = coord.snapshot();
310
+ if (snapshot) {
311
+ this.emitGoalEvent({
312
+ type: 'goal_updated',
313
+ goal: snapshot,
314
+ reason: `target_${input.action}`,
315
+ });
299
316
  }
300
317
  }
318
+ if (success && input.action === 'clear' && previousGoalId) {
319
+ this.emitGoalEvent({ type: 'goal_cleared', goalId: previousGoalId, reason: 'user_clear' });
320
+ }
301
321
  const statusText = this.formatTargetStatus(coord);
302
322
  this.emitAppend({ role: 'system', title: 'target', content: statusText });
303
323
  if (success &&
@@ -346,6 +366,10 @@ class AgentRuntimeController {
346
366
  switch (input.type) {
347
367
  case 'submit':
348
368
  return this.submit(input.text);
369
+ case 'queue_followup':
370
+ return this.queueFollowup(input.text);
371
+ case 'manage_followup_queue':
372
+ return this.manageFollowupQueue(input.action, input.itemId);
349
373
  case 'select_session':
350
374
  return this.submit(resumeSessionInput(input.sessionId, input.allProjects));
351
375
  case 'permission_decision':
@@ -359,8 +383,47 @@ class AgentRuntimeController {
359
383
  return this.handleGoalControl(input);
360
384
  case 'permission_mode_change':
361
385
  return this.applyPermissionModeChange(input.value);
386
+ case 'cycle_agent_mode':
387
+ return this.cycleAgentMode();
362
388
  }
363
389
  }
390
+ queueFollowup(input) {
391
+ const text = input.trim();
392
+ if (!text)
393
+ return { type: 'empty' };
394
+ if (!this.turnController.hasActiveTurn()) {
395
+ this.emitStatus('Nothing is running; press Enter to submit this message now.');
396
+ return { type: 'command_ignored' };
397
+ }
398
+ if (this.followupQueue.length >= this.followupQueueLimit) {
399
+ this.emitStatus(`Follow-up queue is full (${this.followupQueueLimit}).`);
400
+ return { type: 'followup_queue_full' };
401
+ }
402
+ const item = {
403
+ id: `followup-${this.nextFollowupId++}`,
404
+ text,
405
+ queuedAt: Date.now(),
406
+ };
407
+ this.followupQueue.push(item);
408
+ this.emitFollowupQueue();
409
+ this.emitStatus(`Queued follow-up ${this.followupQueue.length}/${this.followupQueueLimit}.`);
410
+ return { type: 'followup_queued', itemId: item.id };
411
+ }
412
+ manageFollowupQueue(action, itemId) {
413
+ if (action === 'clear') {
414
+ this.followupQueue.splice(0);
415
+ }
416
+ else if (itemId) {
417
+ const index = this.followupQueue.findIndex(item => item.id === itemId);
418
+ if (index >= 0)
419
+ this.followupQueue.splice(index, 1);
420
+ }
421
+ this.emitFollowupQueue();
422
+ this.emitStatus(this.followupQueue.length > 0
423
+ ? `${this.followupQueue.length} follow-up(s) queued.`
424
+ : 'Follow-up queue is empty.');
425
+ return { type: 'followup_queue_changed' };
426
+ }
364
427
  submit(input) {
365
428
  const submitted = input.trim();
366
429
  if (!submitted)
@@ -372,6 +435,22 @@ class AgentRuntimeController {
372
435
  if ((0, target_command_1.isTargetCommand)(submitted)) {
373
436
  return this.handleTargetInput(submitted).runtimeResult;
374
437
  }
438
+ const activeSession = this.options.runtime.getSession();
439
+ const activeGoalCoordinator = this.ensureGoalCoordinator(false);
440
+ if (activeSession && activeGoalCoordinator?.goal) {
441
+ const abandonment = (0, tools_1.authorizeGoalAbandonment)({
442
+ inputKind: 'user',
443
+ text: submitted,
444
+ sessionId: activeSession.id,
445
+ persistAsUserMessage: true,
446
+ echoToTranscript: true,
447
+ generation: activeGoalCoordinator.generation,
448
+ });
449
+ if (abandonment.authorized) {
450
+ this.emitAppend(submittedEntry(submitted));
451
+ return this.handleTargetInput('/goal exit').runtimeResult;
452
+ }
453
+ }
375
454
  const parsedInput = (0, parser_1.parseInput)(submitted);
376
455
  if (parsedInput.isCommand && parsedInput.name === 'clear') {
377
456
  this.emitClearView();
@@ -783,7 +862,52 @@ class AgentRuntimeController {
783
862
  this.emitGoalEvent({ type: 'goal_updated', goal: snapshot, reason: 'turn_finalized' });
784
863
  if (terminalEvent)
785
864
  this.emitGoalEvent(terminalEvent);
865
+ if (terminalEvent?.type === 'goal_completed') {
866
+ this.autoExitCompletedGoal(coord, snapshot.goalId, 'completion_auto_exit');
867
+ }
868
+ }
869
+ }
870
+ /**
871
+ * Leave Goal mode after a passed completion audit while retaining the
872
+ * terminal sidecar as the durable completion receipt. The conditional
873
+ * session mutation prevents a stale completion from clearing a newer Goal.
874
+ */
875
+ autoExitCompletedGoal(coord, goalId, reason) {
876
+ if (coord.goal?.goalId !== goalId ||
877
+ coord.goal.status !== 'complete' ||
878
+ coord.goal.completionAudit?.passed !== true) {
879
+ return false;
880
+ }
881
+ try {
882
+ const { clearSessionGoalBinding } = require('../services/session-storage');
883
+ const session = clearSessionGoalBinding(coord.boundSessionId, goalId);
884
+ if (!session) {
885
+ throw new Error(`Session ${coord.boundSessionId} was not found while clearing Goal mode.`);
886
+ }
887
+ if (!coord.detachCompletedReceipt(goalId)) {
888
+ throw new Error(`Completed Goal ${goalId} could not be detached from the live runtime.`);
889
+ }
890
+ }
891
+ catch (cause) {
892
+ const detail = (0, redaction_1.redactTraceText)(cause instanceof Error ? cause.message : String(cause)).slice(0, 600);
893
+ const message = `Goal completed, but automatic Goal-mode exit could not clear the session binding. The completed Goal remains terminal and will be reconciled on restore. ${detail}`;
894
+ this.emitAppend({
895
+ role: 'error',
896
+ title: 'goal auto-exit',
897
+ content: message,
898
+ errorLayer: 'session',
899
+ });
900
+ this.emitStatus(message);
901
+ return false;
902
+ }
903
+ this.continuationScheduleEpoch += 1;
904
+ this.rejectPendingPermissions();
905
+ if (this.followupQueue.length > 0) {
906
+ this.followupQueue.splice(0);
907
+ this.emitFollowupQueue();
786
908
  }
909
+ this.emitGoalEvent({ type: 'goal_cleared', goalId, reason });
910
+ return true;
787
911
  }
788
912
  failClosedGoalPersistence(coord, goalId, error, operation) {
789
913
  const message = this.failClosedGoalMutation(coord, operation, error, false, goalId);
@@ -932,6 +1056,7 @@ class AgentRuntimeController {
932
1056
  if (!this.requestIsCurrent(nextRequest))
933
1057
  break;
934
1058
  const request = nextRequest;
1059
+ const planCompletionBeforeRequest = this.agentModeLifecycle.completionRevision();
935
1060
  const nextInput = request.text?.trim() ||
936
1061
  'Continue pursuing the active goal from its persisted plan and evidence.';
937
1062
  if ((this.options.echoSubmittedInput ?? true) &&
@@ -993,6 +1118,13 @@ class AgentRuntimeController {
993
1118
  preserveTerminalGoalStatus = Boolean(finalizedGoal?.completionAudit ||
994
1119
  (toolContext?.pendingTerminalRequest?.requestedStatus === 'blocked' &&
995
1120
  finalizedGoal?.status !== 'blocked'));
1121
+ const completedPlan = this.agentModeLifecycle.completedPlanSince(planCompletionBeforeRequest) ?? undefined;
1122
+ // A shortcut pressed during the turn affects the next logical request,
1123
+ // never the permissions or tools of the request that just completed.
1124
+ // exit_plan_mode consumes a pending next mode while saving the plan;
1125
+ // every other request applies it here at the same boundary.
1126
+ if (!completedPlan)
1127
+ this.agentModeLifecycle.applyPending();
996
1128
  if (revision?.trim()) {
997
1129
  const currentCoord = this.ensureGoalCoordinator(false);
998
1130
  const currentGoal = currentCoord?.goal?.status === 'active' ? currentCoord.goal : undefined;
@@ -1021,12 +1153,36 @@ class AgentRuntimeController {
1021
1153
  };
1022
1154
  }
1023
1155
  }
1156
+ else if (completedPlan) {
1157
+ const currentCoord = this.ensureGoalCoordinator(false);
1158
+ const currentGoal = currentCoord?.goal?.status === 'active' ? currentCoord.goal : undefined;
1159
+ nextRequest = {
1160
+ inputKind: 'plan_execution',
1161
+ text: `Execute the saved plan now. Continue autonomously from the plan and verify the result.\n\n${completedPlan}`,
1162
+ sessionId: this.options.runtime.getSession()?.id ?? request.sessionId,
1163
+ goal: currentGoal
1164
+ ? {
1165
+ goalId: currentGoal.goalId,
1166
+ revision: currentGoal.revision,
1167
+ continuationIndex: currentGoal.continuationCount,
1168
+ }
1169
+ : undefined,
1170
+ persistAsUserMessage: false,
1171
+ echoToTranscript: false,
1172
+ generation: currentCoord?.generation ?? 0,
1173
+ };
1174
+ this.emitStatus('Plan saved · starting execution in the selected mode.');
1175
+ }
1024
1176
  else {
1025
1177
  const queuedCommand = this.queuedCommands.shift();
1026
- nextRequest = queuedCommand
1178
+ const queuedFollowup = queuedCommand ? undefined : this.followupQueue.shift();
1179
+ if (queuedFollowup)
1180
+ this.emitFollowupQueue();
1181
+ const queuedInput = queuedCommand ?? queuedFollowup?.text;
1182
+ nextRequest = queuedInput
1027
1183
  ? {
1028
1184
  inputKind: 'user',
1029
- text: queuedCommand,
1185
+ text: queuedInput,
1030
1186
  sessionId: this.options.runtime.getSession()?.id ?? request.sessionId,
1031
1187
  persistAsUserMessage: true,
1032
1188
  echoToTranscript: false,
@@ -1081,6 +1237,27 @@ class AgentRuntimeController {
1081
1237
  emitProcessing(processing) {
1082
1238
  this.eventSink.emit({ type: 'processing_changed', processing });
1083
1239
  }
1240
+ emitFollowupQueue() {
1241
+ this.eventSink.emit({
1242
+ type: 'followup_queue_changed',
1243
+ snapshot: { items: [...this.followupQueue], limit: this.followupQueueLimit },
1244
+ });
1245
+ }
1246
+ emitAgentModeSnapshot() {
1247
+ this.eventSink.emit({
1248
+ type: 'agent_mode_changed',
1249
+ snapshot: this.agentModeLifecycle.snapshot(),
1250
+ });
1251
+ }
1252
+ cycleAgentMode() {
1253
+ const deferred = this.turnController.hasActiveTurn();
1254
+ const snapshot = this.agentModeLifecycle.cycle({ defer: deferred });
1255
+ return {
1256
+ type: 'agent_mode_changed',
1257
+ snapshot,
1258
+ appliesFrom: deferred ? 'next-logical-request' : 'immediate',
1259
+ };
1260
+ }
1084
1261
  emitGoalEvent(event) {
1085
1262
  this.eventSink.emit({ type: 'goal_event', event });
1086
1263
  }
@@ -1166,6 +1343,11 @@ class AgentRuntimeController {
1166
1343
  .filter(Boolean)
1167
1344
  .join(' ')
1168
1345
  : undefined;
1346
+ const goalRuntimeSubject = (0, evidence_1.describeGoalRuntimeEvidence)({
1347
+ name: event.event.name,
1348
+ success: event.event.success,
1349
+ error: event.event.error,
1350
+ });
1169
1351
  const record = {
1170
1352
  id: `evidence:${(0, crypto_1.randomUUID)()}`,
1171
1353
  goalId: goal.goalId,
@@ -1173,7 +1355,11 @@ class AgentRuntimeController {
1173
1355
  objectiveRevision: goal.contract?.objectiveRevision ?? 0,
1174
1356
  turnId: context.turnId,
1175
1357
  kind,
1176
- subject: (0, redaction_1.redactTraceText)(assertionSubject || event.event.summary || event.event.error || event.event.name).slice(0, 512),
1358
+ subject: (0, redaction_1.redactTraceText)(assertionSubject ||
1359
+ goalRuntimeSubject ||
1360
+ event.event.summary ||
1361
+ event.event.error ||
1362
+ event.event.name).slice(0, 512),
1177
1363
  result,
1178
1364
  sourceRef: `tool:${event.event.callId}:${event.event.name}`,
1179
1365
  capturedAt,
@@ -1201,10 +1387,25 @@ class AgentRuntimeController {
1201
1387
  this.continuationScheduleEpoch += 1;
1202
1388
  this.goalCoordinator = null;
1203
1389
  this.goalCoordinatorSessionId = null;
1204
- const coord = this.bindGoalCoordinator(sessionId, true, projectPath);
1390
+ const coord = this.bindGoalCoordinator(sessionId, true, projectPath, true);
1205
1391
  const snapshot = coord?.snapshot();
1206
- if (snapshot)
1392
+ if (!snapshot)
1393
+ return;
1394
+ if (snapshot.status === 'complete' && coord.goal?.completionAudit?.passed === true) {
1395
+ // A completed sidecar with no active binding is a historical receipt,
1396
+ // not an active Goal to restore. Only replay the completion lifecycle
1397
+ // when recovering the crash window between the terminal write and the
1398
+ // conditional binding clear.
1207
1399
  this.emitGoalEvent({ type: 'goal_restored', goal: snapshot });
1400
+ this.emitGoalEvent({
1401
+ type: 'goal_completed',
1402
+ goal: snapshot,
1403
+ audit: coord.goal.completionAudit,
1404
+ });
1405
+ this.autoExitCompletedGoal(coord, snapshot.goalId, 'completion_recovery_auto_exit');
1406
+ return;
1407
+ }
1408
+ this.emitGoalEvent({ type: 'goal_restored', goal: snapshot });
1208
1409
  }
1209
1410
  async requestToolPermission(request) {
1210
1411
  if (request.abortSignal?.aborted || this.stopping)
@@ -1281,7 +1482,7 @@ class AgentRuntimeController {
1281
1482
  if (input.payload?.confirmed && coord.goal !== null) {
1282
1483
  this.abortGoalOwnedExecution();
1283
1484
  executionRevoked = true;
1284
- if (!coord.clear()) {
1485
+ if (!(0, lifecycle_1.clearGoalLifecycle)(coord)) {
1285
1486
  const message = this.failClosedGoalMutation(coord, input.action, new Error('Target clear did not remove the active Goal.'), executionRevoked, goalIdBeforeMutation);
1286
1487
  this.emitGoalMutationError(message);
1287
1488
  }
@@ -1319,10 +1520,37 @@ class AgentRuntimeController {
1319
1520
  }
1320
1521
  return this.bindGoalCoordinator(sessionId, true, session.projectPath || this.options.runtime.cwd);
1321
1522
  }
1322
- bindGoalCoordinator(sessionId, recoverActive, projectPath) {
1523
+ bindGoalCoordinator(sessionId, recoverActive, projectPath, restoreMissingBinding = false) {
1323
1524
  const { GoalCoordinator } = require('./goals/coordinator');
1324
1525
  const coord = new GoalCoordinator(projectPath, sessionId);
1325
1526
  coord.load(recoverActive);
1527
+ if (coord.goal) {
1528
+ const { loadSessionMeta, restoreSessionGoalBinding } = require('../services/session-storage');
1529
+ const session = loadSessionMeta(sessionId);
1530
+ if (coord.goal.status === 'complete' &&
1531
+ coord.goal.completionAudit?.passed === true &&
1532
+ session?.activeGoalId !== coord.goal.goalId) {
1533
+ coord.detachCompletedReceipt(coord.goal.goalId);
1534
+ }
1535
+ else if (restoreMissingBinding && !session?.activeGoalId) {
1536
+ try {
1537
+ const restored = session
1538
+ ? restoreSessionGoalBinding(sessionId, coord.goal, session.updatedAt ?? session.startTime)
1539
+ : null;
1540
+ if (!restored) {
1541
+ throw new Error(`Session ${sessionId} was not found while restoring its Goal binding.`);
1542
+ }
1543
+ }
1544
+ catch (cause) {
1545
+ this.emitAppend({
1546
+ role: 'error',
1547
+ title: 'target recovery',
1548
+ content: `Goal sidecar ${coord.goal.goalId} remains paused, but its session binding could not be restored safely. ${(0, redaction_1.redactTraceText)(cause instanceof Error ? cause.message : String(cause))}`,
1549
+ errorLayer: 'session',
1550
+ });
1551
+ }
1552
+ }
1553
+ }
1326
1554
  if (coord.lastLoadIssue) {
1327
1555
  this.emitAppend({
1328
1556
  role: 'error',
@@ -1438,6 +1666,7 @@ class AgentRuntimeController {
1438
1666
  const chatOptions = {
1439
1667
  uiCapabilities,
1440
1668
  uiRenderer: resolvedRenderer,
1669
+ agentModeLifecycle: this.agentModeLifecycle,
1441
1670
  onVerificationStateChange: state => this.turnController.setVerificationState(state),
1442
1671
  ...(this.options.chatOptions ?? {}),
1443
1672
  };