@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
@@ -17,6 +17,8 @@ exports.loadSessionMeta = loadSessionMeta;
17
17
  exports.updateSessionStats = updateSessionStats;
18
18
  exports.resumeSession = resumeSession;
19
19
  exports.updateSessionGoalBinding = updateSessionGoalBinding;
20
+ exports.clearSessionGoalBinding = clearSessionGoalBinding;
21
+ exports.restoreSessionGoalBinding = restoreSessionGoalBinding;
20
22
  exports.updateSessionHarnessState = updateSessionHarnessState;
21
23
  exports.loadSessionHarnessState = loadSessionHarnessState;
22
24
  exports.updateSessionSkills = updateSessionSkills;
@@ -70,6 +72,8 @@ function sanitizeTraceEvent(event) {
70
72
  'permissionReason',
71
73
  'continuationHint',
72
74
  'goalStopReason',
75
+ 'budgetExceededReason',
76
+ 'lastToolSummary',
73
77
  ]) {
74
78
  if (typeof sanitized[key] === 'string') {
75
79
  sanitized[key] = (0, redaction_1.redactTraceText)(sanitized[key]);
@@ -143,6 +147,14 @@ function sanitizeTraceEvent(event) {
143
147
  // Project helpers
144
148
  // ============================================================================
145
149
  const MAX_CACHE_SIZE = 256;
150
+ const SESSION_CATALOG_VERSION = 1;
151
+ let sessionCatalogCache = null;
152
+ function getSessionCatalogPath() {
153
+ return (0, path_1.join)((0, config_dir_1.getConfigDir)(), 'session-catalog.json');
154
+ }
155
+ function emptySessionCatalog() {
156
+ return { version: SESSION_CATALOG_VERSION, sessions: {} };
157
+ }
146
158
  /**
147
159
  * Evict the oldest entries when a Map exceeds MAX_CACHE_SIZE.
148
160
  * Simple LRU approximation: delete the first (oldest) entries until
@@ -286,6 +298,114 @@ exports.SESSION_SIDECAR_SUFFIXES = [
286
298
  '.goal.json',
287
299
  '.index.json',
288
300
  ];
301
+ function readSessionCatalogFile(path) {
302
+ try {
303
+ const parsed = JSON.parse((0, fs_1.readFileSync)(path, 'utf-8'));
304
+ if (parsed.version !== SESSION_CATALOG_VERSION ||
305
+ !parsed.sessions ||
306
+ typeof parsed.sessions !== 'object' ||
307
+ Array.isArray(parsed.sessions)) {
308
+ return null;
309
+ }
310
+ for (const [id, session] of Object.entries(parsed.sessions)) {
311
+ if (!session ||
312
+ session.id !== id ||
313
+ typeof session.projectPath !== 'string' ||
314
+ !session.projectPath) {
315
+ return null;
316
+ }
317
+ }
318
+ return parsed;
319
+ }
320
+ catch (error) {
321
+ (0, debug_log_1.debugError)('session-storage.readCatalog', error, path);
322
+ return null;
323
+ }
324
+ }
325
+ function cacheSessionCatalog(path, catalog) {
326
+ try {
327
+ const stat = (0, fs_1.statSync)(path);
328
+ sessionCatalogCache = { path, mtimeMs: stat.mtimeMs, size: stat.size, catalog };
329
+ }
330
+ catch (error) {
331
+ (0, debug_log_1.debugError)('session-storage.cacheCatalog', error, path);
332
+ sessionCatalogCache = null;
333
+ }
334
+ return catalog;
335
+ }
336
+ function readCachedSessionCatalog(path) {
337
+ if (!(0, fs_1.existsSync)(path))
338
+ return null;
339
+ try {
340
+ const stat = (0, fs_1.statSync)(path);
341
+ if (sessionCatalogCache?.path === path &&
342
+ sessionCatalogCache.mtimeMs === stat.mtimeMs &&
343
+ sessionCatalogCache.size === stat.size) {
344
+ return sessionCatalogCache.catalog;
345
+ }
346
+ }
347
+ catch (error) {
348
+ (0, debug_log_1.debugError)('session-storage.statCatalog', error, path);
349
+ return null;
350
+ }
351
+ const catalog = readSessionCatalogFile(path);
352
+ return catalog ? cacheSessionCatalog(path, catalog) : null;
353
+ }
354
+ function scanSessionCatalog() {
355
+ const catalog = emptySessionCatalog();
356
+ const projectsDir = (0, config_dir_1.getProjectsDir)();
357
+ if (!(0, fs_1.existsSync)(projectsDir))
358
+ return catalog;
359
+ for (const projectKey of (0, fs_1.readdirSync)(projectsDir)) {
360
+ const projectSessionsDir = (0, path_1.join)(projectsDir, projectKey, 'sessions');
361
+ if (!(0, fs_1.existsSync)(projectSessionsDir))
362
+ continue;
363
+ for (const file of (0, fs_1.readdirSync)(projectSessionsDir).filter(isSessionMetaFile)) {
364
+ const sourcePath = (0, path_1.join)(projectSessionsDir, file);
365
+ const rawSession = parseSessionMetaFile(sourcePath);
366
+ if (!rawSession)
367
+ continue;
368
+ const normalized = tryNormalizeSessionMeta(rawSession, sourcePath);
369
+ if (!normalized)
370
+ continue;
371
+ const previous = catalog.sessions[normalized.id];
372
+ if (!previous ||
373
+ (normalized.updatedAt ?? normalized.startTime) > (previous.updatedAt ?? previous.startTime)) {
374
+ catalog.sessions[normalized.id] = normalized;
375
+ }
376
+ }
377
+ }
378
+ return catalog;
379
+ }
380
+ function writeSessionCatalog(path, catalog) {
381
+ (0, atomic_write_1.atomicWriteFileSync)(path, JSON.stringify(catalog), { mode: 0o600 });
382
+ cacheSessionCatalog(path, catalog);
383
+ }
384
+ function loadOrRebuildSessionCatalog() {
385
+ (0, config_dir_1.ensureConfigDir)();
386
+ const path = getSessionCatalogPath();
387
+ const cached = readCachedSessionCatalog(path);
388
+ if (cached)
389
+ return cached;
390
+ return (0, file_lock_1.withFileLockSync)(path, () => {
391
+ const current = readCachedSessionCatalog(path);
392
+ if (current)
393
+ return current;
394
+ const rebuilt = scanSessionCatalog();
395
+ writeSessionCatalog(path, rebuilt);
396
+ return rebuilt;
397
+ }, { waitMs: 10000 });
398
+ }
399
+ function updateSessionCatalog(update) {
400
+ (0, config_dir_1.ensureConfigDir)();
401
+ const path = getSessionCatalogPath();
402
+ return (0, file_lock_1.withFileLockSync)(path, () => {
403
+ const catalog = readSessionCatalogFile(path) ?? scanSessionCatalog();
404
+ update(catalog);
405
+ writeSessionCatalog(path, catalog);
406
+ return catalog;
407
+ }, { waitMs: 10000 });
408
+ }
289
409
  function parseHarnessSidecarFile(path) {
290
410
  try {
291
411
  const content = (0, fs_1.readFileSync)(path, 'utf-8');
@@ -321,14 +441,6 @@ function parseCompactCheckpointFile(path) {
321
441
  return null;
322
442
  }
323
443
  }
324
- function upsertNewestSession(sessionsById, session) {
325
- const existing = sessionsById.get(session.id);
326
- const existingTime = existing ? (existing.updatedAt ?? existing.startTime) : 0;
327
- const nextTime = session.updatedAt ?? session.startTime;
328
- if (!existing || nextTime >= existingTime) {
329
- sessionsById.set(session.id, session);
330
- }
331
- }
332
444
  function sortSessionsNewestFirst(sessions) {
333
445
  return sessions.sort((a, b) => (b.updatedAt ?? b.startTime) - (a.updatedAt ?? a.startTime));
334
446
  }
@@ -388,17 +500,42 @@ function saveSessionMeta(session) {
388
500
  function writeSessionMetaUnlocked(session) {
389
501
  const normalized = normalizeSessionMeta(session);
390
502
  (0, config_dir_1.ensureProjectDir)(normalized.projectPath);
391
- (0, atomic_write_1.atomicWriteFileSync)((0, config_dir_1.getProjectSessionMetaPath)(normalized.projectPath, normalized.id), JSON.stringify(normalized, null, 2), { mode: 0o600 });
503
+ const metaPath = (0, config_dir_1.getProjectSessionMetaPath)(normalized.projectPath, normalized.id);
504
+ (0, atomic_write_1.atomicWriteFileSync)(metaPath, JSON.stringify(normalized, null, 2), { mode: 0o600 });
505
+ updateSessionCatalog(catalog => {
506
+ catalog.sessions[normalized.id] = normalized;
507
+ });
392
508
  }
393
509
  function findSessionMetaPath(sessionId) {
394
- const projectsDir = (0, config_dir_1.getProjectsDir)();
395
- if (!(0, fs_1.existsSync)(projectsDir))
510
+ const catalog = loadOrRebuildSessionCatalog();
511
+ const indexed = catalog.sessions[sessionId];
512
+ const findUnindexedCandidate = () => {
513
+ const projectsDir = (0, config_dir_1.getProjectsDir)();
514
+ if (!(0, fs_1.existsSync)(projectsDir))
515
+ return null;
516
+ for (const projectKey of (0, fs_1.readdirSync)(projectsDir)) {
517
+ const candidate = (0, path_1.join)(projectsDir, projectKey, 'sessions', `${sessionId}.json`);
518
+ const session = (0, fs_1.existsSync)(candidate) ? readSessionMetaAtPath(candidate) : null;
519
+ if (!session)
520
+ continue;
521
+ updateSessionCatalog(current => {
522
+ current.sessions[session.id] = session;
523
+ });
524
+ return candidate;
525
+ }
396
526
  return null;
397
- for (const projectKey of (0, fs_1.readdirSync)(projectsDir)) {
398
- const path = (0, path_1.join)(projectsDir, projectKey, 'sessions', `${sessionId}.json`);
399
- if ((0, fs_1.existsSync)(path) && readSessionMetaAtPath(path))
400
- return path;
401
- }
527
+ };
528
+ if (!indexed)
529
+ return findUnindexedCandidate();
530
+ const path = (0, config_dir_1.getProjectSessionMetaPath)(indexed.projectPath, sessionId);
531
+ if ((0, fs_1.existsSync)(path))
532
+ return path;
533
+ const migratedPath = findUnindexedCandidate();
534
+ if (migratedPath)
535
+ return migratedPath;
536
+ updateSessionCatalog(current => {
537
+ delete current.sessions[sessionId];
538
+ });
402
539
  return null;
403
540
  }
404
541
  function readSessionMetaAtPath(path) {
@@ -477,6 +614,40 @@ function updateSessionGoalBinding(sessionId, goal) {
477
614
  session.updatedAtIso = new Date(session.updatedAt).toISOString();
478
615
  });
479
616
  }
617
+ /**
618
+ * Clear a completed Goal binding without clobbering a newer Goal selected by
619
+ * another Orion process. A missing binding is already converged; a different
620
+ * binding is a lifecycle conflict and fails closed.
621
+ */
622
+ function clearSessionGoalBinding(sessionId, expectedGoalId) {
623
+ return mutateSessionMeta(sessionId, session => {
624
+ if (session.activeGoalId && session.activeGoalId !== expectedGoalId) {
625
+ throw new Error(`Session Goal binding changed from ${expectedGoalId} to ${session.activeGoalId}; refusing to clear the newer Goal.`);
626
+ }
627
+ session.activeGoalId = undefined;
628
+ session.activeGoalObjective = undefined;
629
+ session.updatedAt = Date.now();
630
+ session.updatedAtIso = new Date(session.updatedAt).toISOString();
631
+ });
632
+ }
633
+ /**
634
+ * Restore a Goal binding after a later sidecar mutation failed. A different
635
+ * active binding belongs to a newer lifecycle and must never be overwritten.
636
+ */
637
+ function restoreSessionGoalBinding(sessionId, goal, expectedClearedAt) {
638
+ return mutateSessionMeta(sessionId, session => {
639
+ if (session.activeGoalId && session.activeGoalId !== goal.goalId) {
640
+ throw new Error(`Session Goal binding changed from ${goal.goalId} to ${session.activeGoalId}; refusing to overwrite the newer Goal during rollback.`);
641
+ }
642
+ if (!session.activeGoalId && session.updatedAt !== expectedClearedAt) {
643
+ throw new Error(`Session metadata changed after Goal ${goal.goalId} was cleared; refusing to overwrite newer session state during rollback.`);
644
+ }
645
+ session.activeGoalId = goal.goalId;
646
+ session.activeGoalObjective = goal.objective;
647
+ session.updatedAt = Date.now();
648
+ session.updatedAtIso = new Date(session.updatedAt).toISOString();
649
+ });
650
+ }
480
651
  /**
481
652
  * 更新会话 Harness 状态。
482
653
  */
@@ -658,8 +829,7 @@ function endSession(sessionId) {
658
829
  * 更新会话任务摘要
659
830
  * 从会话消息中提取关键信息并更新元数据
660
831
  */
661
- function updateSessionSummary(sessionId, messages) {
662
- // 提取工具使用列表
832
+ function summarizeSessionMessages(messages) {
663
833
  const toolsUsed = [];
664
834
  const filesModified = [];
665
835
  for (const msg of messages) {
@@ -685,15 +855,52 @@ function updateSessionSummary(sessionId, messages) {
685
855
  }
686
856
  // 提取任务摘要(从第一个用户消息)
687
857
  const firstUserMsg = messages.find(m => m.role === 'user' && m.content);
688
- const taskSummary = (0, redaction_1.redactTraceText)(firstUserMsg?.content ?? '').slice(0, 100);
689
- mutateSessionMeta(sessionId, session => {
690
- session.toolsUsed = [...new Set(toolsUsed)]; // unique
691
- session.filesModified = [...new Set(filesModified)]; // unique
692
- session.taskSummary =
693
- taskSummary.length > 100 ? taskSummary.slice(0, 100) + '...' : taskSummary;
694
- session.messageCount = messages.length;
858
+ const taskText = (0, redaction_1.redactTraceText)(firstUserMsg?.content ?? '');
859
+ const taskSummary = taskText.length > 100 ? `${taskText.slice(0, 100)}...` : taskText;
860
+ return {
861
+ toolsUsed: [...new Set(toolsUsed)],
862
+ filesModified: [...new Set(filesModified)],
863
+ taskSummary,
864
+ messageCount: messages.length,
865
+ };
866
+ }
867
+ function mergeMessageSummary(session, message) {
868
+ if (!session.taskSummary && message.role === 'user' && message.content) {
869
+ const taskText = (0, redaction_1.redactTraceText)(message.content);
870
+ session.taskSummary = taskText.length > 100 ? `${taskText.slice(0, 100)}...` : taskText;
871
+ }
872
+ if (message.role !== 'assistant' || !message.tool_calls)
873
+ return;
874
+ const tools = new Set(session.toolsUsed ?? []);
875
+ const files = new Set(session.filesModified ?? []);
876
+ for (const toolCall of message.tool_calls) {
877
+ tools.add(toolCall.function.name);
878
+ if (toolCall.function.name !== 'write_file' && toolCall.function.name !== 'edit_file')
879
+ continue;
880
+ try {
881
+ const args = JSON.parse(toolCall.function.arguments);
882
+ if (typeof args.path === 'string')
883
+ files.add(args.path);
884
+ }
885
+ catch (error) {
886
+ (0, debug_log_1.debugError)('session-storage.parseToolArgs', error, toolCall.function.name);
887
+ }
888
+ }
889
+ session.toolsUsed = [...tools];
890
+ session.filesModified = [...files];
891
+ }
892
+ function updateSessionSummary(sessionId, _messages) {
893
+ // Callers may hold a stale transcript snapshot. Re-read under the same lock
894
+ // used by append/delete so reconciliation can never roll metadata backwards.
895
+ withLockedSession(sessionId, session => {
896
+ const summary = summarizeSessionMessages(readSessionMessagesForSession(session));
897
+ session.toolsUsed = summary.toolsUsed;
898
+ session.filesModified = summary.filesModified;
899
+ session.taskSummary = summary.taskSummary;
900
+ session.messageCount = summary.messageCount;
695
901
  session.updatedAt = Date.now();
696
902
  session.updatedAtIso = new Date(session.updatedAt).toISOString();
903
+ writeSessionMetaUnlocked(session);
697
904
  });
698
905
  }
699
906
  /**
@@ -774,6 +981,7 @@ function appendSessionMessage(sessionId, message) {
774
981
  // Keep transcript, metadata, and search index inside the same session
775
982
  // critical section so concurrent processes cannot lose counters.
776
983
  (0, session_index_1.updateSessionIndex)(sessionId, session.projectPath, message);
984
+ mergeMessageSummary(session, message);
777
985
  session.updatedAt = Date.now();
778
986
  session.updatedAtIso = new Date(session.updatedAt).toISOString();
779
987
  session.messageCount = (session.messageCount ?? 0) + 1;
@@ -795,6 +1003,7 @@ function appendSessionMessages(sessionId, messages) {
795
1003
  });
796
1004
  for (const message of messages) {
797
1005
  (0, session_index_1.updateSessionIndex)(sessionId, session.projectPath, message);
1006
+ mergeMessageSummary(session, message);
798
1007
  }
799
1008
  session.updatedAt = Date.now();
800
1009
  session.updatedAtIso = new Date(session.updatedAt).toISOString();
@@ -832,6 +1041,10 @@ function overwriteSessionMessagesUnlocked(session, messages) {
832
1041
  (0, session_index_1.updateSessionIndex)(session.id, session.projectPath, message);
833
1042
  }
834
1043
  session.messageCount = messages.length;
1044
+ const summary = summarizeSessionMessages(messages);
1045
+ session.toolsUsed = summary.toolsUsed;
1046
+ session.filesModified = summary.filesModified;
1047
+ session.taskSummary = summary.taskSummary;
835
1048
  session.updatedAt = Date.now();
836
1049
  session.updatedAtIso = new Date(session.updatedAt).toISOString();
837
1050
  writeSessionMetaUnlocked(session);
@@ -918,63 +1131,61 @@ function readSessionMessagesForSession(session) {
918
1131
  }
919
1132
  }
920
1133
  function appendSessionTraceEvent(sessionId, event) {
921
- const session = loadSessionMeta(sessionId);
922
- if (!session)
923
- return null;
924
- (0, config_dir_1.ensureConfigDir)();
925
- const safeEvent = sanitizeTraceEvent(event);
926
- const traceEvent = {
927
- ...safeEvent,
928
- sessionId,
929
- turnId: String(safeEvent.turnId),
930
- timestamp: safeEvent.timestamp ?? Date.now(),
931
- };
932
- (0, fs_1.appendFileSync)((0, config_dir_1.getProjectSessionTracePath)(session.projectPath, sessionId), `${JSON.stringify(traceEvent)}\n`, { mode: 0o600 });
933
- return traceEvent;
1134
+ return withLockedSession(sessionId, session => {
1135
+ (0, config_dir_1.ensureConfigDir)();
1136
+ const safeEvent = sanitizeTraceEvent(event);
1137
+ const traceEvent = {
1138
+ ...safeEvent,
1139
+ sessionId,
1140
+ turnId: String(safeEvent.turnId),
1141
+ timestamp: safeEvent.timestamp ?? Date.now(),
1142
+ };
1143
+ (0, fs_1.appendFileSync)((0, config_dir_1.getProjectSessionTracePath)(session.projectPath, sessionId), `${JSON.stringify(traceEvent)}\n`, { mode: 0o600 });
1144
+ return traceEvent;
1145
+ });
934
1146
  }
935
1147
  function readSessionTraceEvents(sessionId) {
936
- const session = loadSessionMeta(sessionId);
937
- if (!session)
938
- return [];
939
- const path = (0, config_dir_1.getProjectSessionTracePath)(session.projectPath, sessionId);
940
- if (!(0, fs_1.existsSync)(path))
941
- return [];
942
- try {
943
- const content = (0, fs_1.readFileSync)(path, 'utf-8');
944
- return content
945
- .trim()
946
- .split('\n')
947
- .filter(Boolean)
948
- .flatMap(line => {
949
- try {
950
- const parsed = JSON.parse(line);
951
- if (!parsed.type || !parsed.turnId || !parsed.timestamp)
1148
+ return (withLockedSession(sessionId, session => {
1149
+ const path = (0, config_dir_1.getProjectSessionTracePath)(session.projectPath, sessionId);
1150
+ if (!(0, fs_1.existsSync)(path))
1151
+ return [];
1152
+ try {
1153
+ const content = (0, fs_1.readFileSync)(path, 'utf-8');
1154
+ return content
1155
+ .trim()
1156
+ .split('\n')
1157
+ .filter(Boolean)
1158
+ .flatMap(line => {
1159
+ try {
1160
+ const parsed = JSON.parse(line);
1161
+ if (!parsed.type || !parsed.turnId || !parsed.timestamp)
1162
+ return [];
1163
+ const sanitized = sanitizeTraceEvent({
1164
+ ...parsed,
1165
+ turnId: String(parsed.turnId),
1166
+ });
1167
+ return [
1168
+ {
1169
+ ...sanitized,
1170
+ sessionId,
1171
+ turnId: String(sanitized.turnId),
1172
+ },
1173
+ ];
1174
+ }
1175
+ catch (error) {
1176
+ // Drop only the malformed trace line, keep the rest of the trace.
1177
+ (0, debug_log_1.debugError)('session-storage.parseTraceLine', error);
952
1178
  return [];
953
- const sanitized = sanitizeTraceEvent({
954
- ...parsed,
955
- turnId: String(parsed.turnId),
956
- });
957
- return [
958
- {
959
- ...sanitized,
960
- sessionId,
961
- turnId: String(sanitized.turnId),
962
- },
963
- ];
964
- }
965
- catch (error) {
966
- // Drop only the malformed trace line, keep the rest of the trace.
967
- (0, debug_log_1.debugError)('session-storage.parseTraceLine', error);
968
- return [];
969
- }
970
- });
971
- }
972
- catch (error) {
973
- // An empty trace looks like "nothing happened" instead of "trace
974
- // unreadable", which misleads anyone debugging a past run.
975
- (0, debug_log_1.debugError)('session-storage.readTraceEvents', error, path);
976
- return [];
977
- }
1179
+ }
1180
+ });
1181
+ }
1182
+ catch (error) {
1183
+ // An empty trace looks like "nothing happened" instead of "trace
1184
+ // unreadable", which misleads anyone debugging a past run.
1185
+ (0, debug_log_1.debugError)('session-storage.readTraceEvents', error, path);
1186
+ return [];
1187
+ }
1188
+ }) ?? []);
978
1189
  }
979
1190
  /**
980
1191
  * 读取会话消息并转换为 Message 格式(用于恢复对话历史)
@@ -1017,27 +1228,7 @@ function sessionMessageToModelMessage(message) {
1017
1228
  * 列出所有会话
1018
1229
  */
1019
1230
  function listSessions(limit) {
1020
- (0, config_dir_1.ensureConfigDir)();
1021
- const sessionsById = new Map();
1022
- const projectsDir = (0, config_dir_1.getProjectsDir)();
1023
- if ((0, fs_1.existsSync)(projectsDir)) {
1024
- for (const projectKey of (0, fs_1.readdirSync)(projectsDir)) {
1025
- const projectSessionsDir = (0, path_1.join)(projectsDir, projectKey, 'sessions');
1026
- if (!(0, fs_1.existsSync)(projectSessionsDir))
1027
- continue;
1028
- const files = (0, fs_1.readdirSync)(projectSessionsDir).filter(isSessionMetaFile);
1029
- for (const file of files) {
1030
- const rawSession = parseSessionMetaFile((0, path_1.join)(projectSessionsDir, file));
1031
- if (!rawSession)
1032
- continue;
1033
- const sourcePath = (0, path_1.join)(projectSessionsDir, file);
1034
- const normalized = tryNormalizeSessionMeta(rawSession, sourcePath);
1035
- if (normalized)
1036
- upsertNewestSession(sessionsById, normalized);
1037
- }
1038
- }
1039
- }
1040
- const sessions = sortSessionsNewestFirst(Array.from(sessionsById.values()));
1231
+ const sessions = sortSessionsNewestFirst(Object.values(loadOrRebuildSessionCatalog().sessions));
1041
1232
  return limit ? sessions.slice(0, limit) : sessions;
1042
1233
  }
1043
1234
  /**
@@ -1045,21 +1236,7 @@ function listSessions(limit) {
1045
1236
  */
1046
1237
  function listProjectSessions(projectPath, limit) {
1047
1238
  const canonicalProjectPath = resolveProjectPath(projectPath);
1048
- const sessionsById = new Map();
1049
- const projectSessionsDir = (0, config_dir_1.getProjectSessionsDir)(canonicalProjectPath);
1050
- if ((0, fs_1.existsSync)(projectSessionsDir)) {
1051
- const files = (0, fs_1.readdirSync)(projectSessionsDir).filter(isSessionMetaFile);
1052
- for (const file of files) {
1053
- const rawSession = parseSessionMetaFile((0, path_1.join)(projectSessionsDir, file));
1054
- if (!rawSession)
1055
- continue;
1056
- const sourcePath = (0, path_1.join)(projectSessionsDir, file);
1057
- const normalized = tryNormalizeSessionMeta(rawSession, sourcePath);
1058
- if (normalized)
1059
- upsertNewestSession(sessionsById, normalized);
1060
- }
1061
- }
1062
- const sessions = sortSessionsNewestFirst(Array.from(sessionsById.values()));
1239
+ const sessions = sortSessionsNewestFirst(Object.values(loadOrRebuildSessionCatalog().sessions).filter(session => session.projectPath === canonicalProjectPath));
1063
1240
  return limit ? sessions.slice(0, limit) : sessions;
1064
1241
  }
1065
1242
  /**
@@ -1138,6 +1315,9 @@ function deleteSession(sessionId) {
1138
1315
  deleted = true;
1139
1316
  }
1140
1317
  }
1318
+ updateSessionCatalog(catalog => {
1319
+ delete catalog.sessions[sessionId];
1320
+ });
1141
1321
  return deleted;
1142
1322
  }) ?? false);
1143
1323
  }