specrails-desktop 2.20.1 → 2.22.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 (540) hide show
  1. package/README.md +3 -2
  2. package/client/dist/assets/{ActivityFeedPage-3WSqRYVx.js → ActivityFeedPage-roDyKGuv.js} +1 -1
  3. package/client/dist/assets/AgentBrowserCapture-BsXnWa4j.js +1 -0
  4. package/client/dist/assets/{AgentModeCodePane-Cnsea6eZ.js → AgentModeCodePane-o97EJvbJ.js} +2 -2
  5. package/client/dist/assets/AgentModeJobsPane-CLtpPxPM.js +1 -0
  6. package/client/dist/assets/AgentsPage-eNSo_ZcC.js +86 -0
  7. package/client/dist/assets/AnalyticsPage-cAJ60_Ex.js +1 -0
  8. package/client/dist/assets/{BarChart-C6If656N.js → BarChart-NLtK7xAY.js} +1 -1
  9. package/client/dist/assets/CodePage-B5rum8ZB.js +2 -0
  10. package/client/dist/assets/DesktopAnalyticsPage-DSuvG6Tq.js +1 -0
  11. package/client/dist/assets/DocsDialog-Bo38G3Yc.js +11 -0
  12. package/client/dist/assets/DocsPage-BNkiBBrC.js +11 -0
  13. package/client/dist/assets/{ExportDropdown-CezTK0EX.js → ExportDropdown-DCV8PN4-.js} +1 -1
  14. package/client/dist/assets/IntegrationsPage-BMJOzpPz.js +3 -0
  15. package/client/dist/assets/InteractiveJobComposer-aLduNs5R.js +19 -0
  16. package/client/dist/assets/JobDetailModal-kpkUWJIS.js +1 -0
  17. package/client/dist/assets/JobDetailPage-CFeqlrPU.js +1 -0
  18. package/client/dist/assets/JobsPage-fuwhXy2I.js +1 -0
  19. package/client/dist/assets/LoopBuilderPage-DP66322C.js +7 -0
  20. package/client/dist/assets/LoopPreviewModal-CpmBhE31.js +1 -0
  21. package/client/dist/assets/LoopsPage-CvQ18VUx.js +1 -0
  22. package/client/dist/assets/ProjectSettingsDialog-Deq4pwvq.js +1 -0
  23. package/client/dist/assets/TemplatePreviewModal-DziOj2Ct.js +1 -0
  24. package/client/dist/assets/agent-Csh4kP2S.js +1 -0
  25. package/client/dist/assets/agent-Cz_jgQX32.js +1 -0
  26. package/client/dist/assets/agent-D3vcIvaz2.js +1 -0
  27. package/client/dist/assets/agent-Dnbt0V4e.js +1 -0
  28. package/client/dist/assets/agent-HolR7QrZ.js +1 -0
  29. package/client/dist/assets/agent-Ka0rRWJy.js +1 -0
  30. package/client/dist/assets/agent-Te3yysMd.js +1 -0
  31. package/client/dist/assets/agent-vM4_iLDk2.js +1 -0
  32. package/client/dist/assets/{upload-CRtTj4Co.js → brain-kFJuEDNH.js} +1 -1
  33. package/client/dist/assets/{browser-DEEO-OSi.js → browser-BPkhILSJ.js} +1 -1
  34. package/client/dist/assets/{browser-BTivfZKE2.js → browser-BijVYG0Y2.js} +1 -1
  35. package/client/dist/assets/{browser-bpO3onlS.js → browser-BqLqJVVT.js} +1 -1
  36. package/client/dist/assets/{browser-DlSXtfu5.js → browser-Cc0iDqUi.js} +1 -1
  37. package/client/dist/assets/browser-CdS6O1Qb.js +1 -0
  38. package/client/dist/assets/{browser-BKP6hqQC2.js → browser-Cvg-QHvd2.js} +1 -1
  39. package/client/dist/assets/{browser-INCUyduh.js → browser-FRv8P02E.js} +1 -1
  40. package/client/dist/assets/{browser-DlKLfT612.js → browser-rWKj-RR_2.js} +1 -1
  41. package/client/dist/assets/code-BRcDlze52.js +1 -0
  42. package/client/dist/assets/code-BdMy3Ffq.js +1 -0
  43. package/client/dist/assets/code-CeQ0FZpC.js +1 -0
  44. package/client/dist/assets/code-CqCcRThR.js +1 -0
  45. package/client/dist/assets/code-DgeHz9CB.js +1 -0
  46. package/client/dist/assets/code-DzC1rMk12.js +1 -0
  47. package/client/dist/assets/code-UPVvmAKM2.js +1 -0
  48. package/client/dist/assets/code-thSEptMx.js +1 -0
  49. package/client/dist/assets/{common-QjVnq9XP2.js → common-BM3LFLCE2.js} +1 -1
  50. package/client/dist/assets/{common-CeQUwuHt2.js → common-Bwafujnc2.js} +1 -1
  51. package/client/dist/assets/{common-Bb64s3Bm.js → common-C-vU-j-I.js} +1 -1
  52. package/client/dist/assets/{common-KbQuTSGg.js → common-C5HKSbbz.js} +1 -1
  53. package/client/dist/assets/{common-BPQQkgJZ.js → common-CYaT2yHp.js} +1 -1
  54. package/client/dist/assets/{common-DPxotRK9.js → common-DhWTkocg.js} +1 -1
  55. package/client/dist/assets/{common-k5MTOHpn.js → common-DiPTT7V_2.js} +1 -1
  56. package/client/dist/assets/{common-C8ZD5upH2.js → common-DmqBPwZG.js} +1 -1
  57. package/client/dist/assets/{cssMode-DsArsSCT.js → cssMode-DBHbkBvI.js} +1 -1
  58. package/client/dist/assets/dashboard-BaStj_a_.js +1 -0
  59. package/client/dist/assets/dashboard-Bi6ugu5Q.js +1 -0
  60. package/client/dist/assets/dashboard-BmqTn3L02.js +1 -0
  61. package/client/dist/assets/dashboard-CvT8lOCT.js +1 -0
  62. package/client/dist/assets/dashboard-D7Pmeavq2.js +1 -0
  63. package/client/dist/assets/dashboard-DAnWdAac2.js +1 -0
  64. package/client/dist/assets/dashboard-JnYy2WLg.js +1 -0
  65. package/client/dist/assets/dashboard-L47YsFS_.js +1 -0
  66. package/client/dist/assets/{dist-js-BQn4yxaw.js → dist-js-BZSiJDbG.js} +1 -1
  67. package/client/dist/assets/{dist-js-BAWSqVtr.js → dist-js-DKpmIJlQ.js} +1 -1
  68. package/client/dist/assets/{editor.main-G3Sl9C67.js → editor.main-C9J2ikJK.js} +2 -2
  69. package/client/dist/assets/{freemarker2-pBzQNgFi.js → freemarker2-J5iIIIK-.js} +1 -1
  70. package/client/dist/assets/{handlebars-CtBTCnBI.js → handlebars-DSw1l_tw.js} +1 -1
  71. package/client/dist/assets/{html-Dx3DYBzY.js → html-h2-wE1Lj.js} +1 -1
  72. package/client/dist/assets/{htmlMode-In7frFOo.js → htmlMode-Cc_ij7lW.js} +1 -1
  73. package/client/dist/assets/index-DM6heiGa.js +155 -0
  74. package/client/dist/assets/index-DPX6_xIC.css +2 -0
  75. package/client/dist/assets/{javascript-BKcn-YkN.js → javascript-C1q3xv6N.js} +1 -1
  76. package/client/dist/assets/jira-B3613-gj.js +1 -0
  77. package/client/dist/assets/jira-BHAKtc4B.js +1 -0
  78. package/client/dist/assets/jira-Be369RIR2.js +1 -0
  79. package/client/dist/assets/jira-CPpgA-5z2.js +1 -0
  80. package/client/dist/assets/jira-D5efgwp_.js +1 -0
  81. package/client/dist/assets/jira-DS7ownDy.js +1 -0
  82. package/client/dist/assets/jira-bDs7Im2C.js +1 -0
  83. package/client/dist/assets/jira-uNH1gETL2.js +1 -0
  84. package/client/dist/assets/jobs-1GV2-4zd2.js +1 -0
  85. package/client/dist/assets/jobs-26F9gGcE.js +1 -0
  86. package/client/dist/assets/jobs-BgQzB0Sx2.js +1 -0
  87. package/client/dist/assets/jobs-BqWui9_f.js +1 -0
  88. package/client/dist/assets/jobs-CE8qeIYj.js +1 -0
  89. package/client/dist/assets/jobs-D5sZzgLs.js +1 -0
  90. package/client/dist/assets/jobs-DzeuASRf.js +1 -0
  91. package/client/dist/assets/jobs-Wh7dn28q2.js +1 -0
  92. package/client/dist/assets/{jsonMode-jNREoQ3C.js → jsonMode-CeaCdEhr.js} +1 -1
  93. package/client/dist/assets/{lib-C-g8QbZl.js → lib-B2nCKzmA.js} +1 -1
  94. package/client/dist/assets/{liquid-CtRkGqBu.js → liquid-eFsVK0V-.js} +1 -1
  95. package/client/dist/assets/loops-BvEenWBy.js +1 -0
  96. package/client/dist/assets/loops-CBiWd9Hf.js +1 -0
  97. package/client/dist/assets/loops-DNGiYKll2.js +1 -0
  98. package/client/dist/assets/{loops-Y3FQsUCh.js → loops-DjOtVXRo.js} +1 -1
  99. package/client/dist/assets/loops-HTHf-xu32.js +1 -0
  100. package/client/dist/assets/loops-YYV2bwjd.js +1 -0
  101. package/client/dist/assets/loops-hXgncEpF2.js +1 -0
  102. package/client/dist/assets/loops-kYbydDyN.js +1 -0
  103. package/client/dist/assets/{lspLanguageFeatures-Cl3gvD_W.js → lspLanguageFeatures-DT3-bbhn.js} +1 -1
  104. package/client/dist/assets/{mdx-B_nJldHz.js → mdx-Fuwnh1cX.js} +1 -1
  105. package/client/dist/assets/{monaco.contribution-PUeaZk8T.js → monaco.contribution-Desq7oq4.js} +2 -2
  106. package/client/dist/assets/{python-DS1Ce-A6.js → python-BgoEs6Cj.js} +1 -1
  107. package/client/dist/assets/{razor-L41Qg9OK.js → razor-CM1sPMMq.js} +1 -1
  108. package/client/dist/assets/{settings-BPq9nCJm.js → settings-BOHOmHkb.js} +1 -1
  109. package/client/dist/assets/{settings-r8Qq2Gzp2.js → settings-BlEA_7h02.js} +1 -1
  110. package/client/dist/assets/{settings-C-m3yEZ2.js → settings-BsJMsWGc.js} +1 -1
  111. package/client/dist/assets/{settings-zZr7NzuB.js → settings-D6qY9_UI.js} +1 -1
  112. package/client/dist/assets/{settings-VgCsjaYf.js → settings-DZJeXoRV.js} +1 -1
  113. package/client/dist/assets/settings-Mr7MnJbf.js +1 -0
  114. package/client/dist/assets/{settings-BWHGtmU12.js → settings-TNga5gIF2.js} +1 -1
  115. package/client/dist/assets/{settings-DZj7Uqy32.js → settings-lFoaYT-s2.js} +1 -1
  116. package/client/dist/assets/setup-B590KsTX.js +1 -0
  117. package/client/dist/assets/setup-BkyGoby6.js +1 -0
  118. package/client/dist/assets/setup-CEj6uY3-2.js +1 -0
  119. package/client/dist/assets/setup-CbIerFGf2.js +1 -0
  120. package/client/dist/assets/setup-CmU6bTCV2.js +1 -0
  121. package/client/dist/assets/setup-D674kWQH.js +1 -0
  122. package/client/dist/assets/setup-VNqXyB6Y.js +1 -0
  123. package/client/dist/assets/setup-iY8vH8pB.js +1 -0
  124. package/client/dist/assets/specs-C9Sd7BhH2.js +1 -0
  125. package/client/dist/assets/specs-CBDvEYKv.js +1 -0
  126. package/client/dist/assets/specs-CIPr9reA2.js +1 -0
  127. package/client/dist/assets/specs-CWtKcVDC.js +1 -0
  128. package/client/dist/assets/specs-CmEZY57v.js +1 -0
  129. package/client/dist/assets/specs-D2clrt2c2.js +1 -0
  130. package/client/dist/assets/specs-DTplt2XM.js +1 -0
  131. package/client/dist/assets/specs-PozUNhqb.js +1 -0
  132. package/client/dist/assets/{tsMode-BC1g186U.js → tsMode-BmT8WogI.js} +1 -1
  133. package/client/dist/assets/{typescript-BGlRGvJW.js → typescript-CQrQPsoW.js} +1 -1
  134. package/client/dist/assets/upload-CLAzW1mS.js +1 -0
  135. package/client/dist/assets/{value-D9aLbxw-.js → value-DSwzyyWR.js} +1 -1
  136. package/client/dist/assets/{workers-CXcXtO3b.js → workers-U0UXyLUf.js} +1 -1
  137. package/client/dist/assets/{xml-JdZZaIhJ.js → xml-WRxJs8_I.js} +1 -1
  138. package/client/dist/assets/{yaml-Cm82BVBt.js → yaml-CjpSTjJU.js} +1 -1
  139. package/client/dist/index.html +14 -14
  140. package/docs/customizing.md +2 -2
  141. package/docs/gemini.md +15 -4
  142. package/docs/guide/de/insights/3-code-explorer.md +6 -0
  143. package/docs/guide/de/integrations/3-jira-integration.md +1 -1
  144. package/docs/guide/de/integrations/6-agent-chat.md +5 -0
  145. package/docs/guide/de/pipeline/1-rails-and-jobs.md +6 -6
  146. package/docs/guide/de/pipeline/2-the-job-detail-view.md +27 -2
  147. package/docs/guide/de/pipeline/3-batch-implement-and-multi-feature.md +9 -5
  148. package/docs/guide/de/pipeline/5-the-loop-builder.md +1 -1
  149. package/docs/guide/de/specs/1-specs-and-the-backlog.md +3 -2
  150. package/docs/guide/en/insights/3-code-explorer.md +6 -0
  151. package/docs/guide/en/integrations/3-jira-integration.md +1 -1
  152. package/docs/guide/en/integrations/6-agent-chat.md +5 -0
  153. package/docs/guide/en/pipeline/1-rails-and-jobs.md +6 -6
  154. package/docs/guide/en/pipeline/2-the-job-detail-view.md +27 -2
  155. package/docs/guide/en/pipeline/3-batch-implement-and-multi-feature.md +10 -4
  156. package/docs/guide/en/pipeline/5-the-loop-builder.md +1 -1
  157. package/docs/guide/en/specs/1-specs-and-the-backlog.md +3 -2
  158. package/docs/guide/es/insights/3-code-explorer.md +6 -0
  159. package/docs/guide/es/integrations/3-jira-integration.md +1 -1
  160. package/docs/guide/es/integrations/6-agent-chat.md +5 -0
  161. package/docs/guide/es/pipeline/1-rails-and-jobs.md +6 -6
  162. package/docs/guide/es/pipeline/2-the-job-detail-view.md +27 -2
  163. package/docs/guide/es/pipeline/3-batch-implement-and-multi-feature.md +9 -5
  164. package/docs/guide/es/pipeline/5-the-loop-builder.md +1 -1
  165. package/docs/guide/es/specs/1-specs-and-the-backlog.md +3 -2
  166. package/docs/guide/fr/insights/3-code-explorer.md +6 -0
  167. package/docs/guide/fr/integrations/3-jira-integration.md +1 -1
  168. package/docs/guide/fr/integrations/6-agent-chat.md +5 -0
  169. package/docs/guide/fr/pipeline/1-rails-and-jobs.md +6 -6
  170. package/docs/guide/fr/pipeline/2-the-job-detail-view.md +27 -2
  171. package/docs/guide/fr/pipeline/3-batch-implement-and-multi-feature.md +9 -5
  172. package/docs/guide/fr/pipeline/5-the-loop-builder.md +1 -1
  173. package/docs/guide/fr/specs/1-specs-and-the-backlog.md +3 -2
  174. package/docs/guide/it/insights/3-code-explorer.md +6 -0
  175. package/docs/guide/it/integrations/3-jira-integration.md +1 -1
  176. package/docs/guide/it/integrations/6-agent-chat.md +5 -0
  177. package/docs/guide/it/pipeline/1-rails-and-jobs.md +6 -6
  178. package/docs/guide/it/pipeline/2-the-job-detail-view.md +27 -2
  179. package/docs/guide/it/pipeline/3-batch-implement-and-multi-feature.md +10 -6
  180. package/docs/guide/it/pipeline/5-the-loop-builder.md +1 -1
  181. package/docs/guide/it/specs/1-specs-and-the-backlog.md +3 -2
  182. package/docs/guide/ja/insights/3-code-explorer.md +6 -0
  183. package/docs/guide/ja/integrations/3-jira-integration.md +1 -1
  184. package/docs/guide/ja/integrations/6-agent-chat.md +5 -0
  185. package/docs/guide/ja/pipeline/1-rails-and-jobs.md +6 -6
  186. package/docs/guide/ja/pipeline/2-the-job-detail-view.md +27 -2
  187. package/docs/guide/ja/pipeline/3-batch-implement-and-multi-feature.md +9 -5
  188. package/docs/guide/ja/pipeline/5-the-loop-builder.md +1 -1
  189. package/docs/guide/ja/specs/1-specs-and-the-backlog.md +3 -2
  190. package/docs/guide/pt/insights/3-code-explorer.md +6 -0
  191. package/docs/guide/pt/integrations/3-jira-integration.md +1 -1
  192. package/docs/guide/pt/integrations/6-agent-chat.md +5 -0
  193. package/docs/guide/pt/pipeline/1-rails-and-jobs.md +6 -6
  194. package/docs/guide/pt/pipeline/2-the-job-detail-view.md +27 -2
  195. package/docs/guide/pt/pipeline/3-batch-implement-and-multi-feature.md +9 -5
  196. package/docs/guide/pt/pipeline/5-the-loop-builder.md +1 -1
  197. package/docs/guide/pt/specs/1-specs-and-the-backlog.md +3 -2
  198. package/docs/guide/zh/insights/3-code-explorer.md +6 -0
  199. package/docs/guide/zh/integrations/3-jira-integration.md +1 -1
  200. package/docs/guide/zh/integrations/6-agent-chat.md +5 -0
  201. package/docs/guide/zh/pipeline/1-rails-and-jobs.md +6 -6
  202. package/docs/guide/zh/pipeline/2-the-job-detail-view.md +27 -2
  203. package/docs/guide/zh/pipeline/3-batch-implement-and-multi-feature.md +10 -6
  204. package/docs/guide/zh/pipeline/5-the-loop-builder.md +1 -1
  205. package/docs/guide/zh/specs/1-specs-and-the-backlog.md +3 -2
  206. package/docs/internals/README.md +5 -0
  207. package/docs/internals/adding-a-provider.md +15 -3
  208. package/docs/internals/api-reference.md +6 -5
  209. package/docs/internals/browser-capture-performance.md +93 -0
  210. package/docs/internals/code-explorer-story.md +135 -0
  211. package/docs/internals/gemini-mcp-registration.md +53 -0
  212. package/docs/internals/interactive-jobs.md +212 -0
  213. package/docs/internals/loop-step-log-explorer.md +146 -0
  214. package/docs/internals/safe-pr-review-flow.md +367 -0
  215. package/docs/mcp.md +1 -1
  216. package/docs/running-pipelines.md +6 -2
  217. package/package.json +1 -1
  218. package/server/dist/agent-chat-manager.js +211 -0
  219. package/server/dist/agent-chat-registry.js +20 -0
  220. package/server/dist/agent-chat-router.js +22 -0
  221. package/server/dist/agent-mcp-config.js +45 -4
  222. package/server/dist/agent-operator-prompt.js +149 -56
  223. package/server/dist/agent-store.js +25 -0
  224. package/server/dist/agent-tier.js +6 -1
  225. package/server/dist/browser-capture-manager.js +184 -34
  226. package/server/dist/browser-playwright.js +98 -13
  227. package/server/dist/code-explorer-router.js +92 -0
  228. package/server/dist/db.js +102 -0
  229. package/server/dist/file-provenance.js +54 -1
  230. package/server/dist/file-story-manager.js +170 -0
  231. package/server/dist/file-story.js +148 -0
  232. package/server/dist/file-summary-generator.js +5 -4
  233. package/server/dist/git-guardrails.js +62 -0
  234. package/server/dist/index.js +5 -0
  235. package/server/dist/integration-branch.js +63 -0
  236. package/server/dist/interactive-job-session.js +226 -18
  237. package/server/dist/jira/jira-adf.js +9 -0
  238. package/server/dist/jira/jira-materializer.js +27 -4
  239. package/server/dist/jira/jira-status-resolver.js +12 -4
  240. package/server/dist/jira/jira-sync-manager.js +130 -2
  241. package/server/dist/jira-router.js +1 -1
  242. package/server/dist/loop-effect.js +12 -0
  243. package/server/dist/loop-executors.js +92 -22
  244. package/server/dist/loop-run-manager.js +354 -28
  245. package/server/dist/mcp/guide.js +18 -7
  246. package/server/dist/mcp/tools/jira.js +1 -1
  247. package/server/dist/mcp/tools/jobs.js +14 -5
  248. package/server/dist/mcp/tools/rails.js +137 -12
  249. package/server/dist/mcp/tools/specs.js +35 -9
  250. package/server/dist/mcp/tools/types.js +49 -0
  251. package/server/dist/mobile/mobile-ws.js +4 -0
  252. package/server/dist/path-resolver.js +46 -0
  253. package/server/dist/pr-body.js +240 -0
  254. package/server/dist/pr-naming.js +210 -0
  255. package/server/dist/pr-publisher.js +68 -0
  256. package/server/dist/project-registry.js +77 -17
  257. package/server/dist/project-router-jobs.js +53 -13
  258. package/server/dist/project-router-settings.js +33 -0
  259. package/server/dist/project-router-terminals.js +16 -0
  260. package/server/dist/project-router-tickets.js +57 -3
  261. package/server/dist/project-router.js +52 -13
  262. package/server/dist/queue-manager.js +268 -83
  263. package/server/dist/rail-isolated-launch.js +324 -34
  264. package/server/dist/rail-isolation.js +32 -5
  265. package/server/dist/rail-pr-decision.js +519 -0
  266. package/server/dist/rail-pr-delivery.js +75 -0
  267. package/server/dist/rail-pr-store.js +175 -0
  268. package/server/dist/rail-worktrees-store.js +18 -0
  269. package/server/dist/rails-router.js +241 -17
  270. package/server/dist/rails-store.js +78 -1
  271. package/server/dist/setup-prerequisites.js +105 -0
  272. package/server/dist/smash-runner.js +3 -1
  273. package/server/dist/ticket-store.js +7 -3
  274. package/server/dist/workspace-resolution.js +27 -0
  275. package/server/dist/worktree-manager.js +42 -7
  276. package/server/dist/worktree-overlay.js +261 -0
  277. package/client/dist/assets/AgentBrowserCapture-BlGDZahz.js +0 -1
  278. package/client/dist/assets/AgentModeJobsPane-CyNR-9BO.js +0 -1
  279. package/client/dist/assets/AgentsPage-dNsEsY_x.js +0 -86
  280. package/client/dist/assets/AnalyticsPage-BAxmR0HQ.js +0 -1
  281. package/client/dist/assets/CodePage-Crc4BBQN.js +0 -2
  282. package/client/dist/assets/DesktopAnalyticsPage-IXSnbCce.js +0 -1
  283. package/client/dist/assets/DocsDialog-Bc4hx7oW.js +0 -11
  284. package/client/dist/assets/DocsPage-bEU4t9c6.js +0 -11
  285. package/client/dist/assets/IntegrationsPage-wq2CezEL.js +0 -3
  286. package/client/dist/assets/JobDetailPage-BBcPk3j8.js +0 -1
  287. package/client/dist/assets/JobsPage-DXrSPlwa.js +0 -1
  288. package/client/dist/assets/LogViewer-BoYbwvbU.js +0 -16
  289. package/client/dist/assets/LoopBuilderPage-CiUMAuWz.js +0 -7
  290. package/client/dist/assets/LoopsPage-Xrp6W5XW.js +0 -1
  291. package/client/dist/assets/ProjectSettingsDialog-BU98L5JD.js +0 -1
  292. package/client/dist/assets/agent-B7GdHP3Z.js +0 -1
  293. package/client/dist/assets/agent-BHmcgoJf.js +0 -1
  294. package/client/dist/assets/agent-BdY_fii4.js +0 -1
  295. package/client/dist/assets/agent-C32FOi9v.js +0 -1
  296. package/client/dist/assets/agent-CiFQxoaZ2.js +0 -1
  297. package/client/dist/assets/agent-CtAag7V6.js +0 -1
  298. package/client/dist/assets/agent-DE4Mp1fY2.js +0 -1
  299. package/client/dist/assets/agent-DK8qovyG2.js +0 -1
  300. package/client/dist/assets/browser-ZB1afzjZ.js +0 -1
  301. package/client/dist/assets/code-BFxE1Yt62.js +0 -1
  302. package/client/dist/assets/code-BefYOm5Q.js +0 -1
  303. package/client/dist/assets/code-BkXpJt99.js +0 -1
  304. package/client/dist/assets/code-C6Sq7_t8.js +0 -1
  305. package/client/dist/assets/code-CGj3w-2N.js +0 -1
  306. package/client/dist/assets/code-Dfsxc9o82.js +0 -1
  307. package/client/dist/assets/code-Y5urks5s2.js +0 -1
  308. package/client/dist/assets/code-wtcs0ivb.js +0 -1
  309. package/client/dist/assets/dashboard-B8032psZ.js +0 -1
  310. package/client/dist/assets/dashboard-BHGKtxty2.js +0 -1
  311. package/client/dist/assets/dashboard-CXnoUgN22.js +0 -1
  312. package/client/dist/assets/dashboard-Ccyxqy7d.js +0 -1
  313. package/client/dist/assets/dashboard-CoED_41r.js +0 -1
  314. package/client/dist/assets/dashboard-Dc5ZAgMN.js +0 -1
  315. package/client/dist/assets/dashboard-JMY8ueD3.js +0 -1
  316. package/client/dist/assets/dashboard-tkWr1aHD2.js +0 -1
  317. package/client/dist/assets/index-BHPbzyg6.css +0 -2
  318. package/client/dist/assets/index-n2PmJGF6.js +0 -152
  319. package/client/dist/assets/jira-BcZzX9122.js +0 -1
  320. package/client/dist/assets/jira-CTYs7LA12.js +0 -1
  321. package/client/dist/assets/jira-D2nN39e92.js +0 -1
  322. package/client/dist/assets/jira-DJxmIkyr.js +0 -1
  323. package/client/dist/assets/jira-DXMoAKWD.js +0 -1
  324. package/client/dist/assets/jira-IhC1ROIc.js +0 -1
  325. package/client/dist/assets/jira-Iw575fN8.js +0 -1
  326. package/client/dist/assets/jira-kbWZY7jH.js +0 -1
  327. package/client/dist/assets/jobs-BqF79kHz2.js +0 -1
  328. package/client/dist/assets/jobs-C1XM5urS.js +0 -1
  329. package/client/dist/assets/jobs-C5UjG0262.js +0 -1
  330. package/client/dist/assets/jobs-DBfaHTxC.js +0 -1
  331. package/client/dist/assets/jobs-DM4BDPdg.js +0 -1
  332. package/client/dist/assets/jobs-Da5OkZmf2.js +0 -1
  333. package/client/dist/assets/jobs-JJdnuQ03.js +0 -1
  334. package/client/dist/assets/jobs-SI34ML8I.js +0 -1
  335. package/client/dist/assets/loops-BR4FmOv12.js +0 -1
  336. package/client/dist/assets/loops-BgX_uudn.js +0 -1
  337. package/client/dist/assets/loops-Bpl2j2LP.js +0 -1
  338. package/client/dist/assets/loops-CQuuMlyZ.js +0 -1
  339. package/client/dist/assets/loops-DW8hSMdS2.js +0 -1
  340. package/client/dist/assets/loops-Q2muu8hW2.js +0 -1
  341. package/client/dist/assets/loops-q7CNDvfK.js +0 -1
  342. package/client/dist/assets/settings-CY8udi0e.js +0 -1
  343. package/client/dist/assets/setup-CNMdCHHt2.js +0 -1
  344. package/client/dist/assets/setup-Cag4XrbL2.js +0 -1
  345. package/client/dist/assets/setup-D9IHGoWU.js +0 -1
  346. package/client/dist/assets/setup-Dg6Ba3JT.js +0 -1
  347. package/client/dist/assets/setup-DyK36RIW.js +0 -1
  348. package/client/dist/assets/setup-G4ZvDKxX.js +0 -1
  349. package/client/dist/assets/setup-aTlGxuwi2.js +0 -1
  350. package/client/dist/assets/setup-kWsoAeHQ.js +0 -1
  351. package/client/dist/assets/specs-BFSUPa122.js +0 -1
  352. package/client/dist/assets/specs-BMzip1WY2.js +0 -1
  353. package/client/dist/assets/specs-BYeAbIEy.js +0 -1
  354. package/client/dist/assets/specs-C-mtLcXw.js +0 -1
  355. package/client/dist/assets/specs-CAzpvADd2.js +0 -1
  356. package/client/dist/assets/specs-CyRIw_IR.js +0 -1
  357. package/client/dist/assets/specs-DMm7gB_l.js +0 -1
  358. package/client/dist/assets/specs-DuottM0Z.js +0 -1
  359. /package/client/dist/assets/{abap-CpHUwCVK.js → abap-D0E4FfVW.js} +0 -0
  360. /package/client/dist/assets/{activity-DemHQS7l.js → activity--iN4Ad2R2.js} +0 -0
  361. /package/client/dist/assets/{activity-B_71BWg3.js → activity-6hM_ZSg9.js} +0 -0
  362. /package/client/dist/assets/{activity-DHv2V5Oi.js → activity-BZNfOdiS.js} +0 -0
  363. /package/client/dist/assets/{activity-D0rfjQzT2.js → activity-BuVo5sPB.js} +0 -0
  364. /package/client/dist/assets/{activity-BpTTj_PH.js → activity-CIOLxGvh.js} +0 -0
  365. /package/client/dist/assets/{activity-D2e62vbV2.js → activity-D2r2h3SE2.js} +0 -0
  366. /package/client/dist/assets/{activity-Ch-wbr0C2.js → activity-DtxrAUMo2.js} +0 -0
  367. /package/client/dist/assets/{addon-image-Ba-TY3wr.js → addon-image-CwoZj17F.js} +0 -0
  368. /package/client/dist/assets/{addon-ligatures-T4ARLiuu.js → addon-ligatures-CWDrED80.js} +0 -0
  369. /package/client/dist/assets/{addon-webgl-Cd73n8eh.js → addon-webgl-DMbGeI_u.js} +0 -0
  370. /package/client/dist/assets/{addspec-xwRX_Pnf.js → addspec-BMtLZLW62.js} +0 -0
  371. /package/client/dist/assets/{addspec-l_zU5gla.js → addspec-CP0HRuxY.js} +0 -0
  372. /package/client/dist/assets/{addspec-Dio-H5z0.js → addspec-CRuvWn8d.js} +0 -0
  373. /package/client/dist/assets/{addspec-D6L4ZteP.js → addspec-D-JLDsUV.js} +0 -0
  374. /package/client/dist/assets/{addspec-CrEm6Fzr2.js → addspec-DfhDbg5c.js} +0 -0
  375. /package/client/dist/assets/{addspec-B6Ns8KU02.js → addspec-bsNDdqRm2.js} +0 -0
  376. /package/client/dist/assets/{addspec-qGyH7MHy2.js → addspec-mgPOt5q02.js} +0 -0
  377. /package/client/dist/assets/{agents-OzxCLVW1.js → agents-78bTZGZh.js} +0 -0
  378. /package/client/dist/assets/{agents-hv3sqmPm2.js → agents-BLhWCmDS2.js} +0 -0
  379. /package/client/dist/assets/{agents-CHgCudUV.js → agents-BUdEi3-N.js} +0 -0
  380. /package/client/dist/assets/{agents-Dumx4JiM2.js → agents-BpoUaoW92.js} +0 -0
  381. /package/client/dist/assets/{agents-CnaPeSyw.js → agents-CWo-KyAB.js} +0 -0
  382. /package/client/dist/assets/{agents-Xh-zYHUx2.js → agents-DDtCJ5M02.js} +0 -0
  383. /package/client/dist/assets/{agents-DuhLEaQ_.js → agents-bvyRLczL.js} +0 -0
  384. /package/client/dist/assets/{agentstudio-CCthUdzR.js → agentstudio-BMQxc_bz.js} +0 -0
  385. /package/client/dist/assets/{agentstudio-CcH8Ckql2.js → agentstudio-COZriimI2.js} +0 -0
  386. /package/client/dist/assets/{agentstudio-Bo91kfUd2.js → agentstudio-CWgXG5W52.js} +0 -0
  387. /package/client/dist/assets/{agentstudio-VJOa_NVO.js → agentstudio-C_Jq8Tl4.js} +0 -0
  388. /package/client/dist/assets/{agentstudio-BIxikDf_.js → agentstudio-Dtq3dGYk.js} +0 -0
  389. /package/client/dist/assets/{agentstudio-Bz8cP8_c.js → agentstudio-jKMTdT70.js} +0 -0
  390. /package/client/dist/assets/{agentstudio-DARgYg5Z2.js → agentstudio-sI27TpBu2.js} +0 -0
  391. /package/client/dist/assets/{aiedit-5ZXN4cep2.js → aiedit-6CHdb_iv2.js} +0 -0
  392. /package/client/dist/assets/{aiedit-B7gAJZVC.js → aiedit-B03pD_Na.js} +0 -0
  393. /package/client/dist/assets/{aiedit-D92V-kUW.js → aiedit-BtRqRxML.js} +0 -0
  394. /package/client/dist/assets/{aiedit-D9ualLVJ.js → aiedit-eMN4eQPF.js} +0 -0
  395. /package/client/dist/assets/{aiedit-h48tJU0V2.js → aiedit-hknZlly82.js} +0 -0
  396. /package/client/dist/assets/{aiedit-xkA_mR2a2.js → aiedit-igmw-ZoZ2.js} +0 -0
  397. /package/client/dist/assets/{aiedit-7B2dvCv-.js → aiedit-pc5JDUq1.js} +0 -0
  398. /package/client/dist/assets/{analytics-slx4X1mu2.js → analytics-BWMUZ2Pq2.js} +0 -0
  399. /package/client/dist/assets/{analytics-uRNP6yAJ.js → analytics-Bj-SmKHa.js} +0 -0
  400. /package/client/dist/assets/{analytics-WF1I49ln.js → analytics-C5dpiS0o.js} +0 -0
  401. /package/client/dist/assets/{analytics-CBvaxOId.js → analytics-CCprAqk3.js} +0 -0
  402. /package/client/dist/assets/{analytics-BakymH7Z2.js → analytics-CR1TJqUi2.js} +0 -0
  403. /package/client/dist/assets/{analytics-B7bPj6u_2.js → analytics-DfNdXR0y2.js} +0 -0
  404. /package/client/dist/assets/{analytics-DZ74aQ54.js → analytics-rmHuJv0V.js} +0 -0
  405. /package/client/dist/assets/{apex-DlD7oJX6.js → apex-D_X_8J4d.js} +0 -0
  406. /package/client/dist/assets/{atom-one-dark-BrRN8wBy.js → atom-one-dark-BMDPFwRZ.js} +0 -0
  407. /package/client/dist/assets/{attachments-C11tOKZ_.js → attachments-BgBNSqQd.js} +0 -0
  408. /package/client/dist/assets/{attachments-Bnbyj2PN.js → attachments-BjyMmrwE.js} +0 -0
  409. /package/client/dist/assets/{attachments-CIeLa8l12.js → attachments-C9GTTJsx2.js} +0 -0
  410. /package/client/dist/assets/{attachments-DslHfa-L.js → attachments-DCZOL1RU.js} +0 -0
  411. /package/client/dist/assets/{attachments-C-gyrCOb.js → attachments-DL-bPy9E.js} +0 -0
  412. /package/client/dist/assets/{attachments-Cxrs0pyL2.js → attachments-DPCmkFZu2.js} +0 -0
  413. /package/client/dist/assets/{attachments-TTPsc0a52.js → attachments-rNn1ekRy2.js} +0 -0
  414. /package/client/dist/assets/{azcli-CmXFAbc-.js → azcli-PZLnZ3jH.js} +0 -0
  415. /package/client/dist/assets/{bat-DdNJq4hH.js → bat-KlBOxpO4.js} +0 -0
  416. /package/client/dist/assets/{bicep-Bppz7WOA.js → bicep-CgG9oF3V.js} +0 -0
  417. /package/client/dist/assets/{cameligo-0MRMdSmg.js → cameligo-6R45j6Ph.js} +0 -0
  418. /package/client/dist/assets/{chat-BvHrebKC2.js → chat-BgL3zv6x2.js} +0 -0
  419. /package/client/dist/assets/{chat-CZyiLJvQ.js → chat-Bh3NdgJs.js} +0 -0
  420. /package/client/dist/assets/{chat-DKYP7NnC.js → chat-Bom6bqK3.js} +0 -0
  421. /package/client/dist/assets/{chat-5mdg_YIc2.js → chat-DdwZjT8K2.js} +0 -0
  422. /package/client/dist/assets/{chat-wkTIy9rX.js → chat-Dnwg-NpQ.js} +0 -0
  423. /package/client/dist/assets/{chat-BpYxnkr4.js → chat-DsbwJhus.js} +0 -0
  424. /package/client/dist/assets/{chat-BGax2nV62.js → chat-vylxqR0P2.js} +0 -0
  425. /package/client/dist/assets/{clojure-B5dKj863.js → clojure-CLAAMO7J.js} +0 -0
  426. /package/client/dist/assets/{clsx-1dnHRn8W.js → clsx-CNmW0Nip.js} +0 -0
  427. /package/client/dist/assets/{coffee-DSbWjzk7.js → coffee-AruSygo-.js} +0 -0
  428. /package/client/dist/assets/{commands-uz_uKT242.js → commands-C4Y3C-PF2.js} +0 -0
  429. /package/client/dist/assets/{commands-Bb7MnPqn2.js → commands-CSDs9q_2.js} +0 -0
  430. /package/client/dist/assets/{commands-C_7zZwJf.js → commands-DkU0qliq.js} +0 -0
  431. /package/client/dist/assets/{commands-D_6B8lfU.js → commands-JWMfGDmr.js} +0 -0
  432. /package/client/dist/assets/{commands-DBc5llLi2.js → commands-RHOchN4n2.js} +0 -0
  433. /package/client/dist/assets/{commands-CQkdthjF.js → commands-u-4eEHCN.js} +0 -0
  434. /package/client/dist/assets/{commands-DhZNhSbl.js → commands-xHDDGfcP2.js} +0 -0
  435. /package/client/dist/assets/{cpp-SBF8SAh9.js → cpp-DEE5r4Pw.js} +0 -0
  436. /package/client/dist/assets/{csharp-Lzuq_1t-.js → csharp-BVXJUvbK.js} +0 -0
  437. /package/client/dist/assets/{csp-BEzxZqi1.js → csp-cXOF0JoV.js} +0 -0
  438. /package/client/dist/assets/{css-C3D3PKln.js → css-C_zQuAoy.js} +0 -0
  439. /package/client/dist/assets/{cypher-CQ3dEPmv.js → cypher-t95m_Q-O.js} +0 -0
  440. /package/client/dist/assets/{dart-DCPmxolI.js → dart-B4r1Tg-e.js} +0 -0
  441. /package/client/dist/assets/{dockerfile-B_2_aaTO.js → dockerfile-6mt7zHQw.js} +0 -0
  442. /package/client/dist/assets/{ecl-rADUeXsV.js → ecl-DEY_Fz_Q.js} +0 -0
  443. /package/client/dist/assets/{editor.api2-T7u8kQWG.js → editor.api2-C3B0tp2x.js} +0 -0
  444. /package/client/dist/assets/{elixir-DOd-TuJO.js → elixir-R6-q1c5t.js} +0 -0
  445. /package/client/dist/assets/{explore-BHEhNekP2.js → explore-B7fblXBb2.js} +0 -0
  446. /package/client/dist/assets/{explore-DAsroA482.js → explore-BHtEpoNN2.js} +0 -0
  447. /package/client/dist/assets/{explore-UwHHj2ux.js → explore-C0k8HrkN.js} +0 -0
  448. /package/client/dist/assets/{explore-DaXiW9-6.js → explore-CNBzrEPS.js} +0 -0
  449. /package/client/dist/assets/{explore-CWlAXx0f2.js → explore-D_mWBYCS2.js} +0 -0
  450. /package/client/dist/assets/{explore-DG1CtYqT.js → explore-Dahc1lOx.js} +0 -0
  451. /package/client/dist/assets/{explore-DMSGAnhK.js → explore-UvW1jEMa.js} +0 -0
  452. /package/client/dist/assets/{flow9-Bf7zg_j0.js → flow9-CNQvHBOt.js} +0 -0
  453. /package/client/dist/assets/{format-command-BHymDa4r.js → format-command-CuWuRvka.js} +0 -0
  454. /package/client/dist/assets/{fsharp-BqROZjbA.js → fsharp-vPZkFXwv.js} +0 -0
  455. /package/client/dist/assets/{go-oQTP5uLe.js → go-KUzBMYJ_.js} +0 -0
  456. /package/client/dist/assets/{graphql-CSHfTU3q.js → graphql-C3W0rCsD.js} +0 -0
  457. /package/client/dist/assets/{hcl-CeG-RoFJ.js → hcl-BOOMFSNX.js} +0 -0
  458. /package/client/dist/assets/{ini-B2Dv4ohc.js → ini-CFat1WJr.js} +0 -0
  459. /package/client/dist/assets/{integrations-CAF21FbQ.js → integrations-4KZnYECp.js} +0 -0
  460. /package/client/dist/assets/{integrations-CHCgning2.js → integrations-7W266oqF2.js} +0 -0
  461. /package/client/dist/assets/{integrations-B-JVE1_D.js → integrations-BNuauK3o.js} +0 -0
  462. /package/client/dist/assets/{integrations-BAujIDoE.js → integrations-CHy8tnpV.js} +0 -0
  463. /package/client/dist/assets/{integrations-DS5FFMes.js → integrations-Cl_wD5AI.js} +0 -0
  464. /package/client/dist/assets/{integrations-axZN4--n2.js → integrations-Cy8nZ_dv2.js} +0 -0
  465. /package/client/dist/assets/{integrations-CtsOpq2D2.js → integrations-zMqY4VU12.js} +0 -0
  466. /package/client/dist/assets/{java-aUDDeufb.js → java-Dee-CNAM.js} +0 -0
  467. /package/client/dist/assets/{julia-C5LbruO5.js → julia-CGNlLYuU.js} +0 -0
  468. /package/client/dist/assets/{kotlin-C6mOuSKk.js → kotlin-CY7lhknJ.js} +0 -0
  469. /package/client/dist/assets/{less-D5qC3caW.js → less-D0KN7hfJ.js} +0 -0
  470. /package/client/dist/assets/{lexon-Dr2La-fj.js → lexon-CuRJufPs.js} +0 -0
  471. /package/client/dist/assets/{lua-Zy6u5z6Z.js → lua-DHvH62Zf.js} +0 -0
  472. /package/client/dist/assets/{m3-C7XHeDz_.js → m3-tlthQ8Fo.js} +0 -0
  473. /package/client/dist/assets/{markdown-PiF7r-2h.js → markdown-Dbx1LgUZ.js} +0 -0
  474. /package/client/dist/assets/{mcp-B_nWlxZa2.js → mcp-CjVKXAhD2.js} +0 -0
  475. /package/client/dist/assets/{mcp-B8omp_Cd.js → mcp-Dcl-XxkR.js} +0 -0
  476. /package/client/dist/assets/{mcp-DTCCrYHz2.js → mcp-DtbxuH3V2.js} +0 -0
  477. /package/client/dist/assets/{mcp-DytBbASZ.js → mcp-H-gnQUdN.js} +0 -0
  478. /package/client/dist/assets/{mcp-D_oPS6Zc.js → mcp-N1nzp8oL.js} +0 -0
  479. /package/client/dist/assets/{mcp-Cb2jtHP72.js → mcp-XJNRfxVp2.js} +0 -0
  480. /package/client/dist/assets/{mcp-DPqm2C8-.js → mcp-sRmWE8WJ.js} +0 -0
  481. /package/client/dist/assets/{mips-nn07GiyE.js → mips-D_O3IUz_.js} +0 -0
  482. /package/client/dist/assets/{msdax-DaKFVMST.js → msdax-C_ZmCnRt.js} +0 -0
  483. /package/client/dist/assets/{mysql-C6d6xrbU.js → mysql-C-dCEYSX.js} +0 -0
  484. /package/client/dist/assets/{nav-Cibp2KWF.js → nav-40HzpIFb.js} +0 -0
  485. /package/client/dist/assets/{nav-DtTnF9xd.js → nav-8yPhBn00.js} +0 -0
  486. /package/client/dist/assets/{nav-Danf5sRf2.js → nav-B6PkGfTk2.js} +0 -0
  487. /package/client/dist/assets/{nav-Bqhyfbcj2.js → nav-BHqMLrS72.js} +0 -0
  488. /package/client/dist/assets/{nav-CQb9y1km.js → nav-CGy4yx3C.js} +0 -0
  489. /package/client/dist/assets/{nav-BAsYcqdw2.js → nav-CXEDcRdv2.js} +0 -0
  490. /package/client/dist/assets/{nav-BRrNlZkr.js → nav-EI_OhEAo.js} +0 -0
  491. /package/client/dist/assets/{objective-c-B6KMtI-k.js → objective-c-DZY9Aqxd.js} +0 -0
  492. /package/client/dist/assets/{pascal-DYr8MPE7.js → pascal-BVHLXoor.js} +0 -0
  493. /package/client/dist/assets/{pascaligo-B3pd-jJ_.js → pascaligo-XdG_6u3k.js} +0 -0
  494. /package/client/dist/assets/{perl-z2xUzoaL.js → perl-b9QV0BcD.js} +0 -0
  495. /package/client/dist/assets/{pgsql-DUvT-09-.js → pgsql-Du5FDOgT.js} +0 -0
  496. /package/client/dist/assets/{php-CGyOmJfy.js → php-WJD0z2Z_.js} +0 -0
  497. /package/client/dist/assets/{pla-CMqgvyD0.js → pla-CbciTf2w.js} +0 -0
  498. /package/client/dist/assets/{postiats-Dx5LUn4Z.js → postiats-C1QxmvVq.js} +0 -0
  499. /package/client/dist/assets/{powerquery-DazYxvJ6.js → powerquery-BEYDhPLZ.js} +0 -0
  500. /package/client/dist/assets/{powershell-B3nwlDka.js → powershell-CfaYw4XL.js} +0 -0
  501. /package/client/dist/assets/{protobuf-BGuu2u2s.js → protobuf-pwZEDOYa.js} +0 -0
  502. /package/client/dist/assets/{pug-Dbte1MXA.js → pug-5ftqSPVe.js} +0 -0
  503. /package/client/dist/assets/{qsharp-DJLwBOvG.js → qsharp-uI6qZMq4.js} +0 -0
  504. /package/client/dist/assets/{r-DmGBRSHj.js → r-BK54P1EG.js} +0 -0
  505. /package/client/dist/assets/{redis-VvUYn0a4.js → redis-DI0yd7kN.js} +0 -0
  506. /package/client/dist/assets/{redshift-6GdDrxg3.js → redshift-Dov26eyI.js} +0 -0
  507. /package/client/dist/assets/{restructuredtext-CfAB8aRU.js → restructuredtext-QqJ_1dC-.js} +0 -0
  508. /package/client/dist/assets/{ruby-CIYK6MXY.js → ruby-5WjveeVb.js} +0 -0
  509. /package/client/dist/assets/{rust-CTHZfjj9.js → rust-BzVSfqFH.js} +0 -0
  510. /package/client/dist/assets/{sb-CkKTdkz_.js → sb-DMIUfT-3.js} +0 -0
  511. /package/client/dist/assets/{scala-Bx-Wr9TM.js → scala-CSKA7lqt.js} +0 -0
  512. /package/client/dist/assets/{scheme-Dcfi6f83.js → scheme-CojOP2Qc.js} +0 -0
  513. /package/client/dist/assets/{scss-ByL-7PFQ.js → scss-DoBZGJG6.js} +0 -0
  514. /package/client/dist/assets/{shell-Csnb9Yqd.js → shell-YOaE4udl.js} +0 -0
  515. /package/client/dist/assets/{solidity-Dbw5-0QP.js → solidity-l3jSyVLu.js} +0 -0
  516. /package/client/dist/assets/{sophia-ZQ3saZQx.js → sophia-BhSGTaQJ.js} +0 -0
  517. /package/client/dist/assets/{sparql-BEtOel8u.js → sparql-qhk6QD9w.js} +0 -0
  518. /package/client/dist/assets/{sql-DGPDbzB7.js → sql-DoO3y21-.js} +0 -0
  519. /package/client/dist/assets/{st-GeW2MOgh.js → st-ChZAY8oG.js} +0 -0
  520. /package/client/dist/assets/{swift-BVYTN8jq.js → swift-D290Tr7_.js} +0 -0
  521. /package/client/dist/assets/{systemverilog-Deg2a8Lr.js → systemverilog-DsxzgJ-o.js} +0 -0
  522. /package/client/dist/assets/{tcl-6DnLmROF.js → tcl-BKDUHAAR.js} +0 -0
  523. /package/client/dist/assets/{terminal-CDiOAmBd2.js → terminal-BRm03iFA2.js} +0 -0
  524. /package/client/dist/assets/{terminal-CJN-mQMc.js → terminal-De2Brd23.js} +0 -0
  525. /package/client/dist/assets/{terminal-CYB4TiAd.js → terminal-DxQWCqSD2.js} +0 -0
  526. /package/client/dist/assets/{terminal-DsaDTq5N2.js → terminal-WSAvHXoU.js} +0 -0
  527. /package/client/dist/assets/{terminal-DTQ_dPqi2.js → terminal-Z7KsDM_n.js} +0 -0
  528. /package/client/dist/assets/{terminal-58ReNaya.js → terminal-cqfd3EDV.js} +0 -0
  529. /package/client/dist/assets/{terminal-DawP8xNL.js → terminal-xGbCZJHg.js} +0 -0
  530. /package/client/dist/assets/{tickets-DoRTUYRT.js → tickets-B7zT4IRf.js} +0 -0
  531. /package/client/dist/assets/{tickets-DBfFePwk2.js → tickets-BoXom7l8.js} +0 -0
  532. /package/client/dist/assets/{tickets-DvohTziT2.js → tickets-C3b8cHhd2.js} +0 -0
  533. /package/client/dist/assets/{tickets-Da15iaRw.js → tickets-CFXnJsYF.js} +0 -0
  534. /package/client/dist/assets/{tickets-CujsZvkf.js → tickets-CWYFvx1W2.js} +0 -0
  535. /package/client/dist/assets/{tickets-Df6pee-O2.js → tickets-DTHo9c3C.js} +0 -0
  536. /package/client/dist/assets/{tickets-CNvIilmP.js → tickets-SuX_HkK4.js} +0 -0
  537. /package/client/dist/assets/{twig-XbbXW9Yz.js → twig-UpZQaM8G.js} +0 -0
  538. /package/client/dist/assets/{typespec-CRlV8GhI.js → typespec-DzaKvN8i.js} +0 -0
  539. /package/client/dist/assets/{vb-BHE2izPH.js → vb-CZpbb7tk.js} +0 -0
  540. /package/client/dist/assets/{wgsl-Bf5vkfmY.js → wgsl-CNt3OIvl.js} +0 -0
@@ -0,0 +1,135 @@
1
+ # Code explorer: the construction story
2
+
3
+ > Companion to the "Code explorer (read-only)" section of `CLAUDE.md`. This doc
4
+ > covers the per-file **construction story** — the narrative layer that tells a
5
+ > non-developer, for any file, HOW it was built: which specs intervened and what
6
+ > each one contributed.
7
+
8
+ ## Problem
9
+
10
+ `file_provenance` (migration 22) records *that* a job touched a file, and
11
+ `file_provenance_diffs` (migration 23) stores the raw patch — but nothing told
12
+ the *story*: no per-intervention line stats, no plain-language "what did spec
13
+ #37 change in THIS file" narrative, and — critically — **loop runs recorded no
14
+ provenance at all**. Both loop paths settle outside `QueueManager` (whose
15
+ post-exit hook was the only provenance producer):
16
+
17
+ - **Isolated worktree rails** (`rail-isolated-launch.ts`) — the run's writes
18
+ happen in a per-ticket worktree and settle in the launch's own promise chain.
19
+ - **Shared-cwd rails** (`rails-router.ts` `launchLoopRun`) — the run settles in
20
+ the router's `.then`/`.catch`.
21
+
22
+ So the entire loop-based implement path (the default rail mode) was invisible
23
+ to the Code explorer.
24
+
25
+ ## Persistence (migration 37)
26
+
27
+ `file_story_contributions` in the per-project `jobs.sqlite`:
28
+
29
+ | column | meaning |
30
+ | --- | --- |
31
+ | `provenance_id` (PK) | 1:1 with `file_provenance.id` |
32
+ | `job_id`, `file_path` | denormalised identity for path-scoped queries |
33
+ | `added_lines`, `removed_lines` | unified-diff stats (`computeDiffStats`) |
34
+ | `patch_excerpt` | ≤ 4 KB excerpt (`excerptPatch`; full patch stays in `file_provenance_diffs`) |
35
+ | `summary` | nullable — the AI contribution paragraph |
36
+ | `summary_model`, `summary_generated_at` | generation metadata |
37
+
38
+ Stats rows are written **inside `recordProvenanceForJob`'s transaction**
39
+ (`server/file-provenance.ts`), for every provenance row that has a collected
40
+ patch. That means every producer — QueueManager jobs AND the loop seam — gets
41
+ stats with zero extra calls. The prepare is guarded (like the migration-23
42
+ `insertPatch`) so a pre-37 DB degrades cleanly.
43
+
44
+ ## The loop-run seam (`server/file-story.ts`)
45
+
46
+ `recordLoopRunProvenance({ db, projectId, runId, ticketId, repoDir, snapshot,
47
+ broadcast })` is the single chokepoint that mirrors QueueManager's
48
+ `_recordProvenance`: gated by `isCodeExplorerEnabled()`, diff + patches +
49
+ `recordProvenanceForJob` + per-row `file.provenance_updated` broadcast, and the
50
+ `provenance.large_job` warn at >50 files. It never throws. `job_id` is the
51
+ **loop run id**, so the existing `/code/diff?jobId=` endpoint and job-context
52
+ filters key off it unchanged.
53
+
54
+ Wiring:
55
+
56
+ - `rail-isolated-launch.ts` — snapshots each fresh worktree at allocation
57
+ (after the overlay, so overlay files land in the snapshot's untracked set and
58
+ are never attributed to the run) and records at settle, on BOTH the success
59
+ and failure paths, before `commitWorktree`. Once-per-run guard (the `.catch`
60
+ also catches commit failures thrown after the `.then` recorded). Injectable
61
+ via `IsolatedLaunchIO.snapshot` / `.recordProvenance`.
62
+ - `rails-router.ts` `launchLoopRun` — snapshots the **repo**
63
+ (`loopExec.repoDir` when relocated, else the cwd — never the workspace) and
64
+ records in `.then`/`.catch` with the same once-guard.
65
+ - `queue-manager.ts` — **unchanged**. Its existing `recordProvenanceForJob`
66
+ call now also writes stats because the insert rides the same function.
67
+
68
+ ## Story assembly + generation
69
+
70
+ - `getFileStory(db, path, getTicketSpec)` (`file-story.ts`) — provenance rows
71
+ (oldest-first: a construction story reads forward in time) LEFT JOINed with
72
+ contributions, enriched with the spec's live title/status via
73
+ `ProjectContext.getTicketSpec` (failure-tolerant, memoised per call).
74
+ - `FileStoryManager.explain(...)` (`file-story-manager.ts`) — the on-demand,
75
+ budget-gated contribution generator. Prompt = spec title + change kind + the
76
+ stored patch (full patch preferred, excerpt fallback, honest "(not stored)"
77
+ note otherwise). Reuses `createFileSummaryGenerator`'s spawn/parse skeleton
78
+ via the new `systemPrompt` override — same haiku-class default model, same
79
+ timeout/kill/partial-usage semantics. **Deliberate decisions:** it shares the
80
+ file-summary monthly budget (`summary_monthly_budget_usd`) and records
81
+ `ai_invocations.surface = 'file-summary'` — one budget and one analytics
82
+ bucket cover the whole Code-section AI spend; no new Surface member. In-flight
83
+ dedupe per `provenanceId`; the synchronous gates (not-found/budget) run
84
+ BEFORE registering in-flight so a budget skip is never cached. Persists via
85
+ `setContributionSummary` (inserts a summary-only row for patchless historical
86
+ touches).
87
+
88
+ ## REST + WS
89
+
90
+ - `GET /api/projects/:id/code/file/story?path=` → `{ path, story: FileStoryEntry[] }`
91
+ (same traversal/deny-list/gitignore guards as `/summary`; works for deleted
92
+ files — their story is still told).
93
+ - `POST /api/projects/:id/code/file/story/explain?path=` body
94
+ `{ provenanceId, overrideBudget? }` → `{ ok:true }` | 200 `{ skipped:'budget' }`
95
+ (client shows the inline override) | 404 | 500.
96
+ - WS `file.story_updated` `{ projectId, path, provenanceId, ok, reason? }` —
97
+ open viewers of that file refetch; `spending.invalidated` fires alongside.
98
+
99
+ The `FileStoryManager` is constructed per-`ProjectContext` at the code-router
100
+ mount site (`project-router.ts`), memoised with the router.
101
+
102
+ ## Client
103
+
104
+ `ConstructionStory.tsx` (in `client/src/components/code-explorer/`) renders the
105
+ premium vertical timeline: glass cards on a dotted rail, each with kind
106
+ icon/label, the spec chip (`#id · title`, click → `TicketDetailModal` via the
107
+ `onOpenTicket` prop), status pill, `+N/−N` stats, date, and the contribution
108
+ paragraph — or the honest fallback (kind + spec + date, spec-less variants for
109
+ `ticket_id IS NULL`) with the **Explain this change** button (budget skip →
110
+ inline "Generate anyway" override). The run-id footer filters the Code page by
111
+ job. `FileViewer`'s bottom panel hosts it behind a **Story | Log** toggle
112
+ (default `story`, persisted per project at
113
+ `localStorage['specrails-desktop:code-history-mode:<projectId>']`); Log is the
114
+ pre-existing `ProvenanceTimeline` with on-demand diffs, unchanged.
115
+
116
+ **Agent-Mode parity is free**: the mission **Files** pane
117
+ (`AgentModeCodePane.tsx`) embeds `CodePage` → `FileViewer`, so the story panel
118
+ appears there with no extra code (the component only uses `getApiBase()`,
119
+ props, and WS — nothing route-dependent).
120
+
121
+ i18n: the `story.*` block in the `code` namespace, all 8 locales (parity test
122
+ enforced).
123
+
124
+ ## Fallback ladder (locked design)
125
+
126
+ Contribution text sources, in order: (a) the persisted AI `summary`; (b) the
127
+ honest fallback — kind + spec + date only, never an invented claim. Diff stats
128
+ render whenever migration-37 rows exist; historical (pre-37) touches show the
129
+ bare provenance facts.
130
+
131
+ ## Out of scope / future
132
+
133
+ Auto-generating contributions at provenance-record time (cost); a
134
+ whole-file "biography" paragraph synthesised from all chapters; multi-ticket
135
+ attribution (primary ticket only, unchanged from the base feature).
@@ -0,0 +1,53 @@
1
+ # Gemini MCP registration (as-built facts + known gap)
2
+
3
+ How MCP servers actually reach gemini-cli, what the app does about it today, and the surfaces
4
+ where the historical `.mcp.json` assumption still silently fails. All claims verified
5
+ empirically against **gemini-cli 0.49.0**.
6
+
7
+ ## The facts
8
+
9
+ - **gemini-cli has NEVER read `.mcp.json`.** That file is a Claude convention. Gemini's only
10
+ MCP surface is the `mcpServers` object in **settings.json** — user scope (`~/.gemini/
11
+ settings.json`) or project scope (`<cwd>/.gemini/settings.json`).
12
+ - **An untrusted cwd suppresses MCP entirely.** With the trusted-folders gate unresolved, a
13
+ headless (`gemini -p`) run exits **55** with `FatalUntrustedWorkspaceError`. The app-wide
14
+ antidote is `GEMINI_CLI_TRUST_WORKSPACE=true` injected per spawn — the pattern
15
+ `chat-manager` / `queue-manager` / `util/cli-prompt.ts` already use for every gemini spawn.
16
+ - **Gemini exposes MCP tools under an FQN prefix**: `mcp_<server>_<tool>` — for the Specrails
17
+ server, `mcp_specrails_<canonical name>` (e.g. `mcp_specrails_specrails_specs`). The agent-chat
18
+ operator prompt (`server/agent-operator-prompt.ts`) notes this so the model calls the right
19
+ names on gemini.
20
+
21
+ ## What works today: agent chat
22
+
23
+ `server/agent-mcp-config.ts` `prepareAgentMcp` (the desktop agent chat / Mission Control
24
+ wiring) handles gemini correctly: it merges the `specrails` server entry into
25
+ `<agent-cwd>/.gemini/settings.json` (merge-safe — read-if-exists, only the owned key touched)
26
+ AND returns `env: { GEMINI_CLI_TRUST_WORKSPACE: 'true' }` for the spawn. The generic
27
+ project-json `.mcp.json` write still happens alongside (harmless — gemini ignores it; it keeps
28
+ the path uniform for any future project-json provider).
29
+
30
+ ## Known DEFERRED gap: every other 'project-json' gemini consumer
31
+
32
+ The `mcpRegistration: 'project-json'` capability value really means **claude-style
33
+ `.mcp.json`**. Every other consumer of that flag still writes/relies on `.mcp.json`, which
34
+ gemini never loads — so on those surfaces an MCP server is registered but **silently never
35
+ loads** for gemini:
36
+
37
+ | Surface | What it does today | Effect on gemini |
38
+ |---|---|---|
39
+ | Plugins on rails (`server/plugin-manager.ts`, e.g. Serena) | surgical merge into `<project>/.mcp.json` for `project-json` providers | plugin installs "successfully", MCP server never loads in gemini rail spawns |
40
+ | Workspace MCP (`server/agent-mcp-config.ts` `mergeSpecrailsIntoWorkspaceMcp`, via `workspace-manager.ts`) | writes `<workspace>/.mcp.json` | not read by gemini |
41
+ | Explore `context_scope.mcp` (`server/chat-manager.ts`) | spawns from `<project.path>` so `.mcp.json` loads | loads nothing on gemini |
42
+
43
+ Fixing these means writing into the repo's / workspace's `.gemini/settings.json`, which
44
+ intersects the **pristine-repo / artifact-relocation policy** (the app must not mutate the
45
+ user's repo, and `.gemini/` in the repo belongs to the user) — that is its own future change,
46
+ deliberately not bundled with the agent-chat fix.
47
+
48
+ ## Doc corrections this note anchors
49
+
50
+ - `docs/internals/adding-a-provider.md` no longer claims "`project-json` ⇒ nothing to add":
51
+ project-json is the claude `.mcp.json` mechanism; a provider with its own config surface
52
+ (gemini) needs explicit wiring + any trust env.
53
+ - `docs/gemini.md` no longer claims Serena-style plugins "work" on gemini rails.
@@ -0,0 +1,212 @@
1
+ # Interactive jobs (as-built)
2
+
3
+ Every claude job — Job Detail (board) and the mission-mode job modal alike — renders a bottom
4
+ agent-style composer while the job runs. This doc is the as-built record of the session model
5
+ behind it: the transport, the two settle modes, the loop-step ownership design, the accounting
6
+ reconciliation, and the failure interplay. User-facing behaviour: the in-app guide's
7
+ [Job Detail view](../guide/en/pipeline/2-the-job-detail-view.md) page. Code:
8
+ `server/interactive-job-session.ts`, `server/queue-manager.ts` (the interactive branch of
9
+ `_startJob`), `server/loop-executors.ts` `planInteractiveAiStep`, `server/loop-run-manager.ts`
10
+ `_runInteractiveAiStep`, `server/project-router-jobs.ts` (the two manager-agnostic routes),
11
+ `client/src/components/InteractiveJobComposer.tsx`.
12
+
13
+ ## Session model
14
+
15
+ A standard job spawns `claude -p <prompt>` once and settles when the child closes. An
16
+ **interactive** job instead keeps ONE `claude -p --input-format stream-json` child resident
17
+ across many user turns — the same persistent-stdin transport `ExploreStdinSessions` uses for
18
+ Explore chat. Each user prompt is a newline-delimited stream-json message written to stdin; the
19
+ agent works; the turn ends on a `result` event **without killing the child**. A prompt that
20
+ arrives mid-stream queues behind the active turn and runs next (`job.turn_user` carries
21
+ `queued: true`); the job still tends to continue its plan — messages are steering, not
22
+ interruption.
23
+
24
+ `InteractiveJobSession` owns the transport plus per-turn streaming/persistence/accounting. The
25
+ owner (QueueManager or the loop engine) owns spawn-arg construction and the terminal settle
26
+ (slot release, rail/ticket completion, `ai_invocations`) via the `onSettle(SettleInfo)`
27
+ callback. Turn-id tagging (`_activeTurnId` / `_lastSettledTurnId`) guarantees a stray, late, or
28
+ duplicate `result` frame can never be folded into the next turn's totals (BUG-INTJOB-03).
29
+
30
+ ### The spike that unlocked the flip
31
+
32
+ The original interactive path was ultracode-only because ultracode sends prose, not a slash
33
+ command. Spike-verified 2026-07-03 against **claude 2.1.198**: the claude CLI expands slash
34
+ commands arriving as stream-json stdin user frames **exactly like the argv `-p "/cmd"` path**
35
+ (evidence pointer: the dated comment block above the interactive gate in
36
+ `server/queue-manager.ts` `_startJob`, and `loop-executors.ts` `planInteractiveAiStep`). That
37
+ makes every job — `/specrails:implement`, `/specrails:batch-implement`, distilled loop commands,
38
+ custom commands — transport-compatible, so the default flipped to interactive for every
39
+ persistent-stdin-capable provider.
40
+
41
+ ## Gating
42
+
43
+ Derived at **spawn time** (not enqueue) in `QueueManager._startJob`, so a queued job that
44
+ survives a server restart (the in-memory selection map is lost) still spawns interactive:
45
+
46
+ ```
47
+ spawnInteractive = isInteractiveJobsEnabled() // SPECRAILS_INTERACTIVE_JOBS !== 'false'
48
+ && adapter.capabilities.persistentStdin // claude only today
49
+ && (EnqueueOptions.interactive ?? true) // tri-state per-job override
50
+ ```
51
+
52
+ - `EnqueueOptions.interactive`: `false` = force the legacy one-shot spawn, `true` = force
53
+ interactive where capable, `undefined` = default ON.
54
+ - codex/gemini (`persistentStdin: false`) always take the one-shot path — graceful, no
55
+ composer, byte-identical to before.
56
+ - The rails launch body still accepts a legacy `interactive` param; it is **ignored** (wire
57
+ compat — the spawn-time gate decides).
58
+
59
+ ## `settleMode` semantics
60
+
61
+ | | `'finalize'` | `'auto'` |
62
+ |---|---|---|
63
+ | Who gets it | ultracode/Freestyle QueueManager jobs (claude) | every other interactive job + ALL loop ai-steps |
64
+ | End of session | explicit human **Finalize** only (SIGTERM → 2s → SIGKILL) | **quiescence**: a turn `result` arrived, nothing queued, no write in flight |
65
+ | Idle between turns | by design (awaiting the human) | only transiently (microtask window) |
66
+ | Wedge detector | never armed | the queue's zombie-timeout budget, reset on any raw child output; silence for the whole budget → fold in-flight turn, settle `crashed` |
67
+ | Composer action | **Finalize Job** | **Wrap up now** (QueueManager) / **Settle this step** (loop step) |
68
+
69
+ **Quiescence detail:** the auto-settle is deferred to a microtask after the `result` so anything
70
+ in the same synchronous stdout batch is observed first, and re-checked — a user prompt that
71
+ slipped in meanwhile queues/writes a new turn and **extends the session** instead. An explicit
72
+ `finalize()` always settles immediately in either mode.
73
+
74
+ ## Loop-step ownership and routing
75
+
76
+ All dashboard rail launches (factory `Implement`/`Batch`/`Freestyle` and custom loops) run
77
+ through the `LoopRunManager`. When interactive jobs are enabled and the provider supports
78
+ persistent stdin, each claude **ai-step** runs as its own `InteractiveJobSession`
79
+ (`planInteractiveAiStep` builds the spawn plan; `_runInteractiveAiStep` owns the lifecycle):
80
+
81
+ - **`runId` = the job row id.** The loop run's backing `jobs` row is created with `id = runId`,
82
+ so `/jobs/:id/*` routes address the run directly. `markJobInteractive` stamps the row when the
83
+ first interactive step goes live (idempotent), so `GET /jobs/:id` advertises the affordance.
84
+ - **Turns go to the ACTIVE step's session** (`_interactiveSteps: Map<runId, session>`). Between
85
+ steps — decider, shell nodes, step boundaries — there is no session: `POST /messages` 409s,
86
+ and the composer shows a gentle waiting state instead (driven by the `job.interactive`
87
+ broadcast, `acceptingTurns: false` at step settle / `true` at step start). A between-steps
88
+ `GET /jobs/:id` still reports `interactiveSettleMode: 'auto'` via the `loop_runs` row so the
89
+ client can phrase the waiting state truthfully.
90
+ - **Finalize settles the current STEP**, not the run: the session settles `'finalized'`, the
91
+ `SettleInfo` maps onto the same `AiStepResult` shape the one-shot executor returns, and the
92
+ loop advances with whatever the step produced (history, changeId capture, fail-fast all
93
+ untouched).
94
+ - **Shared event seq:** the session draws event seq numbers from the engine's monotonic
95
+ allocator (`nextEventSeq`) because the loop engine persists its own step-boundary/log events
96
+ on the same job id — private counters would collide/replay out of order.
97
+ - **Teardown matrix** (never leaks the child, never double-settles — `_settle` is idempotent):
98
+ quiescence / explicit finalize → `'finalized'` (step ok); step timeout → `session.abort()` →
99
+ fold in-flight turn → `'crashed'`; run cancel → `abort()` → `'crashed'` → engine settles the
100
+ run `'stopped'` at the next boundary; manager shutdown / project removal → `dispose()` (kill,
101
+ NO settle; the startup orphan sweeps reconcile rows on next boot). No zombie timer is armed on
102
+ loop steps — the loop's ai-step timeout bounds the whole step and is the sole watchdog
103
+ (byte-parity with the one-shot loop path, which has no zombie detector either).
104
+
105
+ ## Accounting reconciliation
106
+
107
+ Two writers, one clean split — nothing double-records:
108
+
109
+ - **The session feeds live job-row totals.** Every completed turn's REAL usage is summed onto
110
+ the `jobs` row as it lands (`accumulateInteractiveTurn`), so the live Job Detail totals are
111
+ honest (never an estimate) and the composer's `N turns · $X` line is real money. The
112
+ persistent transport reports `total_cost_usd`/`num_turns` **cumulatively** per turn, so the
113
+ session records deltas against a per-child baseline (clamped ≥ 0) — summing raw readings
114
+ would count turn 1 N times (COST-ACCOUNTING-AUDIT HIGH-2). Token fields are per-turn and sum
115
+ directly.
116
+ - **The engine/owner is the sole `ai_invocations` authority.** QueueManager writes one row at
117
+ settle from the summed `SettleInfo` totals; the loop engine writes one `record()` row per
118
+ step the same way. The session itself never writes an invocation row.
119
+ - **Mid-turn kill = fold, not drop.** A finalize/crash/timeout mid-turn folds the in-flight
120
+ turn's streamed per-assistant-event usage via `finaliseInvocationResult` and prices it from
121
+ the rate card (`estimated: true` → the row and job get the estimated badge; CRIT-4). Idempotent
122
+ (`_inflightFolded`) so a settle and a shutdown snapshot can't fold twice.
123
+ - **Active duration ≠ wall clock.** `activeDurationMs` sums only write→result segments,
124
+ excluding idle time between turns, so a long-open `'finalize'` session doesn't inflate
125
+ per-ticket duration analytics (LOW-15).
126
+
127
+ ## Zero-work settles (failure semantics)
128
+
129
+ Live evidence (run `01f41203`): a mistyped `/specrails:implement` made the claude CLI emit a
130
+ **synthetic** terminal result frame — `{subtype:'success', is_error:false, num_turns:0,
131
+ total_cost_usd:0, duration_api_ms:0, result:'Unknown command: /specrails:implement'}` — and exit
132
+ cleanly. No model ever ran, yet the settle looked like a success (the job "completed" at $0; a
133
+ factory loop then "succeeded" via verify/fix without implementing). Strictness rule: **if the
134
+ command didn't actually run, the settle is FAILED.**
135
+
136
+ - **The predicate is shared and whole-life.** `isZeroWorkSettle` (exported from
137
+ `server/interactive-job-session.ts`) judges the session/step's WHOLE accumulated life: it is
138
+ zero-work when `num_turns === 0` accumulated AND no assistant-derived event was ever observed
139
+ (`isModelWorkEvent`: text-delta / tool-use / assistant frames / usage-carrying events; `result`
140
+ frames do NOT count — the synthetic no-op IS a result frame) AND all four token counters are
141
+ zero. Belt-and-braces: a final result text matching `/^Unknown command:/` marks zero-work even
142
+ if the numeric accounting drifted — but only when no assistant event was seen, so a multi-turn
143
+ session that did real work earlier and merely **ended** on a synthetic frame (the user sent
144
+ `/help` late) is NOT zero-work and still completes.
145
+ - **The session evaluates it at settle** and hands `SettleInfo.zeroWork` to the owner. It also
146
+ surfaces the reason as a visible stderr transcript line (`✖ Zero work performed — the command
147
+ never ran: Unknown command: …`) — necessary because `extractDisplayText` drops `result` frames,
148
+ so the synthetic text would otherwise never appear in the log.
149
+ - **QueueManager** (`_settleInteractiveJob`): a zero-work `'finalized'` settle stamps the job
150
+ `'failed'` (exit code 1, failed `ai_invocations` row, dependents skipped) — **in both settle
151
+ modes**, so an ultracode Finalize after only the synthetic frame is also a failure. A canceled
152
+ job stays `'canceled'`.
153
+ - **LoopRunManager** (ai-steps): a zero-work settle makes the step's `AiStepResult` `failed` and
154
+ its `loop_step_end` `status:'failed'`, and it **routes exactly like a crashed step** — the run
155
+ policy is unchanged (graph-dependent continue + the `AI_FAILFAST_THRESHOLD` consecutive-failure
156
+ abort); zero-work counts toward that streak like a no-output crash (its `Unknown command:` text
157
+ is a CLI synthetic, not model output), so a persistently-unresolvable command aborts the run the
158
+ same way a dead provider does. The one-shot loop path derives the same predicate at the engine
159
+ from the step result's accumulated signals (one-shot `text` accumulates only from assistant
160
+ text-deltas, so non-empty text ⇒ assistant events were seen).
161
+
162
+ ## Zombie / timeout interplay
163
+
164
+ - **One-shot jobs**: unchanged — the queue's zombie timer kills a silent child.
165
+ - **Interactive `'auto'`**: the same zombie budget is armed *inside* the session (reset on any
166
+ stdout/stderr `data`); firing folds the in-flight turn and settles `'crashed'`.
167
+ - **Interactive `'finalize'`**: no timer at all — an idle session awaiting Finalize is the
168
+ feature. QueueManager's queue-level timer is never armed for interactive jobs.
169
+ - **Loop ai-steps**: no zombie timer; the step timeout aborts the session (`'crashed'`,
170
+ `errorText: 'AI step timed out'`), partial work accounted.
171
+ - **Finalize hard-deadline**: SIGTERM → 2s → SIGKILL, plus a forced settle if the child never
172
+ emits `close` (D-state / signal-swallowing) so the queue slot can never leak.
173
+ - **Undeliverable turns**: a confirmed-failed stdin write (destroyed/EPIPE) is surfaced as a
174
+ delivery-failure note and settles `'crashed'` — a turn is only echoed to the transcript after
175
+ delivery is confirmed. Prompts still queued when the session ends are surfaced in the
176
+ transcript (`N queued prompt(s) were not sent`), never dropped silently.
177
+
178
+ ## Surface state on the wire
179
+
180
+ - `GET /jobs/:id` → `interactiveSettleMode: 'finalize' | 'auto' | null` +
181
+ `interactiveAcceptingTurns: boolean` (S3 — lets the composer phrase Finalize vs wrap-up vs
182
+ waiting truthfully; `null`/`false` while queued, refetched on the queued→running flip).
183
+ - `POST /:projectId/jobs/:id/messages` / `POST .../finalize` — **manager-agnostic**: QueueManager
184
+ is tried first, then LoopRunManager. `202` accepted/scheduled, `403` kill-switch off, `409` no
185
+ live session.
186
+ - WS: `job.turn_user` (echo + `queued` flag), `job.turn_done` (running totals), `job.finalized`
187
+ (final totals + terminal status), `job.interactive` (`acceptingTurns` flip on loop-step
188
+ start/settle).
189
+ - Provenance: interactive QueueManager jobs snapshot the repo working tree pre-spawn and diff at
190
+ settle, exactly like one-shots (Code Explorer attribution intact).
191
+
192
+ ## Kill-switch matrix
193
+
194
+ | Setting | Effect |
195
+ |---|---|
196
+ | `SPECRAILS_INTERACTIVE_JOBS=false` (server) | Byte-identical legacy everywhere: every job spawns one-shot, `/messages` + `/finalize` return 403, loop ai-steps one-shot, no `job.*` interactive events. |
197
+ | `VITE_FEATURE_INTERACTIVE_JOBS=false` (client build) | Hides the composer UI; the server behaviour is unchanged (pair it with the server flag for a full opt-out). |
198
+ | `EnqueueOptions.interactive: false` (per job) | That one job spawns one-shot; everything else unaffected. |
199
+ | Provider without `persistentStdin` (codex, gemini) | Automatic one-shot fallback, no error, no composer. |
200
+ | Default (nothing set) | Interactive ON for every claude job and every claude loop ai-step. |
201
+
202
+ ## Bare-mode launches (same branch)
203
+
204
+ Also part of this change: a `POST /rails/:i/launch` carrying a bare legacy `mode` and **no
205
+ `loopId`** (MCP tools, mobile, direct REST) now derives the matching **factory loop** when Loops
206
+ are enabled (`rails-router.ts`), so every launch door runs through the LoopRunManager like the
207
+ dashboard — identical worktree isolation and ask-first PR flow. Without this, an agent-launched
208
+ implement landed in the bare QueueManager branch: shared cwd, `SPECRAILS_GIT_AUTO=false`, no
209
+ delivery row — stranded uncommitted work. Loops disabled ⇒ the legacy QueueManager path,
210
+ unchanged. Relatedly, the agent-chat operator prompt gained the ask-confirmation-once
211
+ turn-discipline rule (`server/agent-operator-prompt.ts`): a confirmation question is asked
212
+ exactly once and ends the reply — the answer arrives as the next user message.
@@ -0,0 +1,146 @@
1
+ # Loop-step log explorer
2
+
3
+ The premium log surface for **loop runs**. When a job's `command` starts with `loop:`, both job views — the board's Job Detail page (`client/src/pages/JobDetailPage.tsx`, `variant="page"`) and the mission-mode job modal (`client/src/components/JobDetailModal.tsx`, `variant="glass"`) — mount `LoopStepExplorer` (`client/src/components/loop-log/LoopStepExplorer.tsx`) instead of the flat `LogViewer`. Non-loop jobs keep the legacy `LogViewer` byte-identical.
4
+
5
+ The explorer does **not** introduce a second log pipeline. It consumes the exact same `events` array (persisted rows + live WS frames) and the exact same line parser (`parseEvent → mergeAssistantLines → applyDiffDetection` from `LogViewer`), then *segments* the result by three structured events the loop engine already persists on the run's backing job row.
6
+
7
+ ## Event contract
8
+
9
+ Emitted by `server/loop-run-manager.ts` (payload interfaces are exported there — `LoopStepEventPayload`, `LoopStepEndEventPayload`, `LoopGraphEventPayload`). All three ride the run's job row as ordinary persisted `events` rows plus `event` WS broadcasts (`event_type` below, `payload` = JSON of the interface). Purely additive to the existing stream — no DB migration.
10
+
11
+ ### `loop_graph` — once, at run start
12
+
13
+ Emitted after the run-header log lines, before the first `loop_step`. It is the run's graph **snapshot**, verbatim, so historical replay stays faithful when the loop is later edited or deleted (`loop_runs` stores no graph).
14
+
15
+ ```ts
16
+ interface LoopGraphEventPayload {
17
+ graph: LoopGraph
18
+ loopId: string
19
+ loopName: string // display name; falls back to the loop id
20
+ provider: string
21
+ model: string
22
+ iterationLimit: number
23
+ }
24
+ ```
25
+
26
+ ### `loop_step` — appended + broadcast BEFORE each step spawns
27
+
28
+ ```ts
29
+ interface LoopStepEventPayload {
30
+ index: number // 1-based ordinal within the WHOLE run (monotonic across iterations)
31
+ kind: 'ai-step' | 'shell' | 'decider'
32
+ title: string
33
+ nodeId: string // resolves against loop_graph's snapshot
34
+ iteration: number // 1-based pass at emission; increments when a Decider evaluates
35
+ // (the Decider itself belongs to the pass it closes)
36
+ template?: string // ai-step only — the AUTHORED prompt (raw {{cmd:X}} string),
37
+ // present only when rendering changed it (a plain free-text
38
+ // prompt would duplicate command). Capped at ~1000 chars + '…'.
39
+ command?: string // ai-step only — the RENDERED prompt actually sent (magic
40
+ // commands expanded, spec/run/const tokens resolved; excludes
41
+ // the injected cross-iteration history). Capped at ~2000 chars + '…'.
42
+ }
43
+ ```
44
+
45
+ **Removed flat-log lines (log hygiene).** The engine used to open every ai-step with two log lines — `Template: …` and `Command: …`. Once the explorer landed those were pure noise (they duplicated what belongs to the step header), so they are **no longer emitted for any step**; the information rides the `loop_step` payload fields above instead, and the step body opens directly on real output. The per-kind *signal* lines are unchanged: the decider's `Goal: …` and the shell's `$ <command>` / `(exit N)` still stream in the flat log, as does the `🧑 <command>` echo of an interactive session (that is the real transcript — not deduped). Legacy runs recorded before this change simply lack the payload fields (client tolerates `undefined` → no disclosure) and keep their old `Template:`/`Command:` lines in the replayed body.
46
+
47
+ The client surfaces `template`/`command` as a subtle **ⓘ disclosure** in the step-box header (`LoopStepSection`): collapsed by default, expands a compact monospace detail block with per-field copy controls, rendered independently of the body collapse state.
48
+
49
+ ### `loop_step_end` — appended + broadcast at each step's tail
50
+
51
+ ```ts
52
+ interface LoopStepEndEventPayload {
53
+ index: number // matches the opening loop_step's index
54
+ nodeId: string
55
+ status: 'ok' | 'failed'
56
+ exitCode: number | null // shell steps: the real exit code; ai-step/decider: null
57
+ durationMs: number // executor-reported, else the step's wall-clock
58
+ decision?: 'continue' | 'stop' // decider steps only — the verdict the run routed by
59
+ }
60
+ ```
61
+
62
+ A step torn down by manager shutdown / project removal (disposed, never settles) gets **no** end event — that absence is meaningful (see the status model). A traversal exception, by contrast, *does* close the open step as `failed` on the settle path.
63
+
64
+ **Zero-work steps end `failed`.** An ai-step whose settle consumed no model work — the claude CLI's synthetic `Unknown command:` result frame (`num_turns` 0, no assistant events, zero usage; run `01f41203`) — ends `status:'failed'`, never `'ok'`: the step's command never actually ran (`isZeroWorkSettle`, shared with QueueManager — see [interactive-jobs.md](interactive-jobs.md)). Because the `Template:`/`Command:` flat-log lines are gone and `result` frames carry no display text, the reason is surfaced as a stderr-style line **inside the step's segment** (before its `loop_step_end`): `✖ Zero work performed — the command never ran: Unknown command: …` — emitted by the interactive session at settle, or by the engine itself on the one-shot path. Run-level routing is unchanged: the step routes exactly like a crashed step (graph-dependent continue + the consecutive-failure fail-fast abort, which zero-work steps count toward).
65
+
66
+ ### Seq guarantees
67
+
68
+ The run owns a single monotonic seq allocator (`takeSeq` in `runLoop`), **shared with an interactive step session** that persists its own provider events/logs on the same job id:
69
+
70
+ - `loop_graph` precedes the first `loop_step`.
71
+ - Each `loop_step_end` is appended **after its step's last persisted output line** — every emit site sits past the step's settle `await`, and the interactive session takes its seqs from the same allocator synchronously as it streams, so the end event's seq is always greater.
72
+ - Live WS frames carry no reliable seq, so the client groups in **arrival order**; a refetch (which replays `getJobEvents ORDER BY seq`) reconciles naturally because the model is derived from whatever `events` currently holds.
73
+
74
+ The engine also still emits the flat-log divider line per step (`━━━━━━ Step N · title ━━━━━━`) so the plain `LogViewer`/export view stays readable. Inside the explorer that divider duplicates the step-box header, so `groupByLoopStep` drops it (`STEP_DIVIDER_RE`).
75
+
76
+ ## Grouping model (`loop-log-model.ts`)
77
+
78
+ `groupByLoopStep(events)` is a pure function returning a `LoopLogModel`:
79
+
80
+ - **Setup bucket** — every line seen before the first `loop_step` (run banner, worktree notice…) lands in `setup`, rendered as a collapsible **Setup** section.
81
+ - **Segments** — each `loop_step` opens a new bucket; ordinary events are bucketed to the last-seen step. A `loop_step_end` attaches to the **last** segment with a matching `index` (arrival-ordered). Malformed/unparseable payloads are tolerated and skipped.
82
+ - **Live activity** — while a step streams, `deriveFrameActivity` keeps the segment's `lastActivity` (the "Reading file…"-style label shown on the running step's header).
83
+ - **Legacy tolerance** — runs recorded before the enrichment may lack `nodeId`/`iteration` (both tolerated as `null`) and lack `loop_graph` entirely; iteration badges and the iteration counter simply hide, and the strip falls back (below).
84
+
85
+ ## Status model
86
+
87
+ `segmentStatus(seg, { isLast, jobSettled })`:
88
+
89
+ | Condition | Status |
90
+ |---|---|
91
+ | `end` present | `end.status` (`ok` / `failed`) |
92
+ | No end, last segment, job running | `running` |
93
+ | No end, last segment, job settled | **`interrupted`** |
94
+ | No end, earlier segment | `unknown` (the loop advanced past it — no status glyph; overview chips render it as done) |
95
+
96
+ **Interrupted rule.** The contract says an end event may only be missing when the step was torn down mid-flight (dispose/shutdown/project removal), so *missing end + settled run* renders the dashed amber **Interrupted** treatment on both the step box and its overview chip.
97
+
98
+ **Legacy caveat (accepted v1).** Completed runs recorded **before** the enrichment have no `loop_step_end` rows at all, so their *final* step renders as Interrupted even though the run finished normally (mid-run steps are `unknown` → shown as done). Accepted for v1 — enriching historical rows was judged not worth a backfill.
99
+
100
+ ## Overview strip (`LoopOverviewStrip.tsx`)
101
+
102
+ One chip per graph node, states `pending → running → ok / failed / interrupted`:
103
+
104
+ - **With `loop_graph`**: chips follow `traversalOrder(graph)` — DFS from Start, continue-branch first — so the strip reads start → body… → decider → end (the loop-back edge is implied). The End chip derives from the job outcome (`pending` until settled, then ok/failed).
105
+ - **Decider chips** carry the latest verdict as an icon (continue = loop-back, stop = exit).
106
+ - **Iteration counter** (right-aligned): `Iteration {current}/{limit}` when a limit is known, else a compact `iter {count}` badge; hidden entirely on legacy runs with no iteration data.
107
+ - **Legacy fallback (no `loop_graph`)**: a linear strip derived from the `loop_step`s actually seen, one chip per distinct node identity in first-seen order. Node identity is `nodeId` when present, else `kind::cleanedTitle` with the legacy `"(iteration N)"` suffix stripped (`nodeKeyForSegment`), so repeat passes over the same node collapse into one chip.
108
+ - Clicking a chip focuses that node's **latest** step box (expands + smooth-scrolls to it).
109
+
110
+ ## Follow-mode interaction design
111
+
112
+ - **Follow (default)**: exactly the latest section is open — the running step, the final step once settled, or Setup when no step has started — with autoscroll pinned to the bottom. A "Following live" pulse shows in the toolbar while the job runs.
113
+ - **Any manual interaction pauses follow**: toggling/focusing a section, expand/collapse-all, or scrolling more than 80px up from the bottom (programmatic scrolls land *at* the bottom so they never trip this — same idiom as `LogViewer`'s autoscroll). The current expansion state is captured as the manual set.
114
+ - **Resume follow**: while paused on a running job (and not filtering), a floating pill re-enters follow mode and scrolls back to live.
115
+ - **Filtering** searches every section: while the filter is non-empty, all sections are treated as expanded; clearing it restores the previous mode.
116
+ - **Copy**: each step header carries its own copy button (per-step lines only; the control lives outside the toggle so the header stays a valid button), and the toolbar copy grabs the whole log with `── Step N · title ──` separators.
117
+
118
+ ## Performance
119
+
120
+ - **Collapsed sections render nothing** — the body subtree is not mounted, so a 10k-line settled step costs one header row.
121
+ - `LoopStepSection` is memoized with a custom comparator over `(segment.key, lines.length, tail-line content, end fields, lastActivity, status, collapsed, filter)` — a WS flush that only grows the running step never re-renders settled boxes. The tail-content check matters because a streamed assistant continuation merges *into* the last line (no length change).
122
+ - Both surfaces already batch incoming WS events via `requestAnimationFrame` before they reach the model; `groupByLoopStep` recomputes per flush, memoized on `events` (and UI language, since `parseEvent` localises the result summary line).
123
+
124
+ ## Ticket refs in log lines
125
+
126
+ `#N` ticket refs in prose log lines (both the flat `LogViewer` and the step boxes here, which share `LogLine`) linkify into a quiet underline-dotted affordance opening the board's `TicketDetailModal` — ticket-only (`components/log-ticket-refs.tsx` feeds `splitAgentRefs` an empty job-uuid set, so job ids never linkify — no modal-in-modal), with diff-styled/stderr lines and markdown code excluded; project scope threads via one optional `projectId` prop (mission `JobDetailModal` passes its own; the board page defaults to the active project) through `useLogTicketActions`, which reuses the agent-chat verify-then-open flow and `agent:refs.*` copy.
127
+
128
+ ## The JobDetailModal stdout fix
129
+
130
+ Shipped with this feature: the mission-mode modal's WS handler previously appended only `stderr` `log` frames as synthetic events. Loop-run engine lines (`▶ Loop … started`, shell output, step dividers) stream as **stdout** `log` frames, so a live loop in the modal never grew — the log looked frozen until reopen. The handler now appends both stdout and stderr, matching `JobDetailPage`'s behaviour.
131
+
132
+ ## i18n
133
+
134
+ All explorer strings live under the `jobs` namespace, `loopExplorer.*` (16 keys — setup, iteration, iterationBadge, follow, resumeFollow, expandAll, collapseAll, copyStep, copied, stepDetail, stepDetailTemplate, stepDetailCommand, copyCommand, interrupted, waiting, stepMapAria), translated in all 8 locales. Chip fallback labels reuse `loops:builder.nodes.*`.
135
+
136
+ ## Files
137
+
138
+ | File | Role |
139
+ |---|---|
140
+ | `server/loop-run-manager.ts` | Event emission (`emitStep` / `emitStepEnd` / `loop_graph`), exported payload types, seq allocator |
141
+ | `client/src/components/loop-log/loop-log-model.ts` | Pure grouping/status/chip model |
142
+ | `client/src/components/loop-log/LoopStepExplorer.tsx` | Container: follow mode, filter, copy, toolbar |
143
+ | `client/src/components/loop-log/LoopOverviewStrip.tsx` | Live chip strip + iteration counter |
144
+ | `client/src/components/loop-log/LoopStepSection.tsx` | Per-step / Setup collapsible sections (memoized) |
145
+ | `client/src/components/loop-log/loop-node-visuals.ts` | Node-kind icon + accent mapping |
146
+ | `client/src/components/loop-log/__tests__/` | Model + explorer tests |