@runeya/runeya 2.0.10 → 2.0.11

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 (226) hide show
  1. package/agent/index.js +354 -8
  2. package/agent/index.js.map +1 -1
  3. package/agent-manager-V47DLMYP-26VYXTSG.js +8 -0
  4. package/{chunk-DODGBBTE.js → chunk-6547GLUJ.js} +24 -7
  5. package/chunk-6547GLUJ.js.map +1 -0
  6. package/{dist-HZBWBT6S.js → dist-2H7XZQCV.js} +1233 -379
  7. package/dist-2H7XZQCV.js.map +1 -0
  8. package/index.js +5 -1
  9. package/index.js.map +1 -1
  10. package/package.json +1 -1
  11. package/web/assets/AddressBar.vue-BxQkuTJ-.js +1 -0
  12. package/web/assets/AgentScalarChatInterface.vue-BZyh4z8j.js +13 -0
  13. package/web/assets/AgentTerminalPage-SWnqcTm-.js +1 -0
  14. package/web/assets/AgentTerminalPage-anYDkj7H.css +1 -0
  15. package/web/assets/AiChatPage-PJvieNVr.js +1 -0
  16. package/web/assets/AppLayout-qD2ReaTx.js +1 -0
  17. package/web/assets/AuditPage-DCvW5-HA.js +1 -0
  18. package/web/assets/CodeInput.vue-DDs5Eel7.js +1 -0
  19. package/web/assets/Collection.vue-HH2Z976J.js +1 -0
  20. package/web/assets/CollectionAuthentication.vue-BbsKOTJ9.js +1 -0
  21. package/web/assets/CollectionCookies.vue-Dzlq0l8S.js +1 -0
  22. package/web/assets/CollectionEnvironment.vue-BS9B1OU-.js +1 -0
  23. package/web/assets/CollectionOverview.vue-DXXQHn9J.js +1 -0
  24. package/web/assets/CollectionScripts.vue-TVNOxHuu.js +1 -0
  25. package/web/assets/CollectionServers.vue-DDyH4n80.js +1 -0
  26. package/web/assets/CollectionSettings.vue-BD5QvG5c.js +1 -0
  27. package/web/assets/CollectionSync.vue-g_NhkdXC.js +1 -0
  28. package/web/assets/CommandActionInput.vue-Cot3fJDd.js +1 -0
  29. package/web/assets/Cookies.vue-X8bc_7ud.js +1 -0
  30. package/web/assets/DashboardPage-BuP2oOo3.js +1 -0
  31. package/web/assets/DataTable.vue-DmcNIRcD.js +1 -0
  32. package/web/assets/DataTableCheckbox.vue-B7bvOQ_f.js +1 -0
  33. package/web/assets/{DataTableHeader.vue-U2le7KBO.js → DataTableHeader.vue-D5k0UCfl.js} +1 -1
  34. package/web/assets/DataTableInput.vue-DVUCY60y.js +1 -0
  35. package/web/assets/DeleteSidebarListElement.vue-CAri6AWj.js +1 -0
  36. package/web/assets/EditSidebarListElement.vue-DFY1ZZNE.js +1 -0
  37. package/web/assets/{EditorIcon-BPEaZrXC.js → EditorIcon-DOV6wP8X.js} +2 -2
  38. package/web/assets/{EmptyState.vue-Be8_w2rR.js → EmptyState.vue-watFzTsD.js} +2 -2
  39. package/web/assets/Environment.vue-BbpisYLs.js +1 -0
  40. package/web/assets/EnvironmentForm-CyJtNH2k.js +108 -0
  41. package/web/assets/EnvironmentFormPage-Du4EXZlm.js +1 -0
  42. package/web/assets/EnvironmentListPage-1Jdh0AWO.js +1 -0
  43. package/web/assets/EnvironmentModal.vue-DaI310h8.js +1 -0
  44. package/web/assets/EnvironmentSelector-BPhBcKYj.js +1 -0
  45. package/web/assets/Form.vue-CMWUiD6f.js +1 -0
  46. package/web/assets/IconSelector.vue-90PWhHNq.js +1 -0
  47. package/web/assets/{KanbanBoardPage-7rLK-ucb.js → KanbanBoardPage-DzFRgXlJ.js} +6 -6
  48. package/web/assets/KanbanListPage-O3T-L6z3.js +1 -0
  49. package/web/assets/LaunchProjectPage-B2m_PflY.js +1 -0
  50. package/web/assets/LaunchServicesPage-DgfE9971.js +1 -0
  51. package/web/assets/LogViewer-CXVXsymr.js +3 -0
  52. package/web/assets/ProcessControls-DVQwL-qx.js +1 -0
  53. package/web/assets/ProcessDetailPage-8GtSwfXG.js +1 -0
  54. package/web/assets/{ProcessMetrics-CLa8mdh2.js → ProcessMetrics-9RjmvDOk.js} +2 -2
  55. package/web/assets/ProjectDetailPage-B3s8bbmw.js +1 -0
  56. package/web/assets/ProjectListPage-HQ9gZWHw.js +1 -0
  57. package/web/assets/RandomJobTestPage-DAM5nNLf.js +2 -0
  58. package/web/assets/Request.vue-DiF4lAAD.js +1 -0
  59. package/web/assets/RequestAuth.vue-DHU9RNUf.js +1 -0
  60. package/web/assets/RequestRoot.vue-BiM2Tr20.js +19 -0
  61. package/web/assets/ScalarAsciiArt.vue-2vz_9aEa.js +2 -0
  62. package/web/assets/{ScalarIconEyeSlash.vue-qR90sHHe.js → ScalarIconEyeSlash.vue-CwJnZ-zD.js} +1 -1
  63. package/web/assets/{ScalarIconTrash.vue-Ll6Zw6_W.js → ScalarIconTrash.vue-DAEOI9Kk.js} +1 -1
  64. package/web/assets/ScenarioEditorPage-BzPL_7Up.js +14 -0
  65. package/web/assets/ServerVariablesForm.vue-Dj2R8IEV.js +1 -0
  66. package/web/assets/ServiceControlsBar-CsHZTuPK.js +1 -0
  67. package/web/assets/ServiceDetailPage-Csf55wQD.js +2 -0
  68. package/web/assets/ServiceFormPage-DDJYv2z3.js +1 -0
  69. package/web/assets/Settings.vue-Dyzw_xwE.js +1 -0
  70. package/web/assets/SettingsPage-CYQGpGyw.js +225 -0
  71. package/web/assets/SetupKeyPage-CnaFhUR6.js +1 -0
  72. package/web/assets/SetupPage-sqBZmTQ9.js +1 -0
  73. package/web/assets/Sidebar.vue-DqiliUT_.js +1 -0
  74. package/web/assets/SidebarButton.vue-MCBoC3jO.js +1 -0
  75. package/web/assets/SidebarListElement.vue-DswWWg_S.js +1 -0
  76. package/web/assets/UnlockPage-rDy89SdE.js +1 -0
  77. package/web/assets/VariablesTable-CEaksHyg.js +1 -0
  78. package/web/assets/{VariablesTable-BtdK5olT.css → VariablesTable-W4rxlL35.css} +1 -1
  79. package/web/assets/ViewLayout.vue-CgpeQh3K.js +1 -0
  80. package/web/assets/{ViewLayoutContent.vue-CAixUN8B.js → ViewLayoutContent.vue-DP_GK_Ip.js} +1 -1
  81. package/web/assets/ViewLayoutSection.vue-YQYzkcAB.js +1 -0
  82. package/web/assets/active-entities-CWFFm964.js +1 -0
  83. package/web/assets/api-reference-UJl6P2J4.js +1 -0
  84. package/web/assets/{autocomplete-Do-EC8XW.js → autocomplete-CK9Z1-Wz.js} +4 -4
  85. package/web/assets/card-DadsU5ZI.js +32 -0
  86. package/web/assets/{checkbox-C2hHZbMO.js → checkbox-4z5ftHhs.js} +3 -3
  87. package/web/assets/{chip-CD3EONN7.js → chip-KJbF4Jjk.js} +2 -2
  88. package/web/assets/column-Cp1kVQOt.js +763 -0
  89. package/web/assets/core-7y546zlP.js +1 -0
  90. package/web/assets/{cssMode-BzsFOrHs.js → cssMode-CIUATcSv.js} +1 -1
  91. package/web/assets/dist-BLSATgV0.js +1 -0
  92. package/web/assets/{dist-CiBpb7F_.js → dist-Cp1hgSqY.js} +2 -2
  93. package/web/assets/{dist-BmCpMB7W.js → dist-CpE_ZYIQ.js} +1 -1
  94. package/web/assets/dist-DR4LqG1l.js +192 -0
  95. package/web/assets/{divider-C7F2jaMI.js → divider-D-vBLTer.js} +2 -2
  96. package/web/assets/editor.store-COpS72tz.js +1 -0
  97. package/web/assets/{fieldset-kJDAoVaz.js → fieldset-CSlJxjpZ.js} +2 -2
  98. package/web/assets/{freemarker2-qyf3DfQl.js → freemarker2-Dsxb69Av.js} +1 -1
  99. package/web/assets/{handlebars-Dt_j38Ok.js → handlebars-ChbvHuc-.js} +1 -1
  100. package/web/assets/{html-BM6JBSDe.js → html-DOIF2Zpc.js} +1 -1
  101. package/web/assets/{htmlMode-BWrj-eTf.js → htmlMode-DKICvQwb.js} +1 -1
  102. package/web/assets/index-A6eiSk8H.css +1 -0
  103. package/web/assets/{index-Dviyssba.js → index-C0UzL9Y-.js} +281 -246
  104. package/web/assets/{javascript-Nwj2LVeE.js → javascript-Bmt68E8X.js} +1 -1
  105. package/web/assets/{jsonMode-xQ2R28Fq.js → jsonMode-CYcvn9c0.js} +1 -1
  106. package/web/assets/{keyboard-CidI6qyD.js → keyboard-DZklF_AY.js} +2 -2
  107. package/web/assets/{lib-Bpt_o5V9.js → lib-B5TdN_ca.js} +1 -1
  108. package/web/assets/{library-CcEqwrWR.js → library-DtrGq8p8.js} +1 -1
  109. package/web/assets/{liquid-CNc1r-Ln.js → liquid-3ot_oRqd.js} +1 -1
  110. package/web/assets/{mdx-D5yTipSh.js → mdx-Cm1rlDNM.js} +1 -1
  111. package/web/assets/{mediaTypes-pLZCmXiT.js → mediaTypes-Bz4C7Sle.js} +2 -2
  112. package/web/assets/{message-B6M86BRU.js → message-DFReN7Fq.js} +2 -2
  113. package/web/assets/{minus-wesZvWq4.js → minus-t_EQEzUj.js} +2 -2
  114. package/web/assets/{multiselect-CHEmtEFg.js → multiselect-BZbgA1pl.js} +3 -3
  115. package/web/assets/{password-ISam7EYg.js → password-D82un95s.js} +4 -4
  116. package/web/assets/{plus-BBMmFC_c.js → plus-B-AhHpHU.js} +6 -6
  117. package/web/assets/pretty-ms-XBeIOdhN.js +202 -0
  118. package/web/assets/process.store-jv0SI_6q.js +1 -0
  119. package/web/assets/project.store-DHXLE6Lv.js +1 -0
  120. package/web/assets/{python-BOLsEvIQ.js → python-BuQCsdKw.js} +1 -1
  121. package/web/assets/{radiobutton-DwoOAEAF.js → radiobutton-Btattklk.js} +2 -2
  122. package/web/assets/{razor-JsBDv4HY.js → razor-DgnEPQLs.js} +1 -1
  123. package/web/assets/router-w5lyb-nn.js +1 -0
  124. package/web/assets/settings.store-bNnLJ43c.js +1 -0
  125. package/web/assets/store-DWOu5TTl.js +1840 -0
  126. package/web/assets/{tabpanel-DBInUEl5.js → tabpanel-CIyzJ44J.js} +3 -3
  127. package/web/assets/{tag-CQlI4fJK.js → tag-DV-szbCr.js} +2 -2
  128. package/web/assets/trpc-wp_QsEqG.js +1 -0
  129. package/web/assets/{tsMode-C7uad5vV.js → tsMode-ChD0IpIg.js} +1 -1
  130. package/web/assets/{typescript-C2IozRX9.js → typescript-BRYpIqKe.js} +1 -1
  131. package/web/assets/urls-CoBMqtDH.js +12 -0
  132. package/web/assets/{use-tree-walker-CJHEPXgB.js → use-tree-walker-M4-Gn01v.js} +1 -1
  133. package/web/assets/useAiChatDrawer-BhlTNoXz.js +1 -0
  134. package/web/assets/{useClipboard-DtO-z5Ls.js → useClipboard-Cro2wlg3.js} +1 -1
  135. package/web/assets/{useLayout-D-FCdkqa.js → useLayout-BciG4r-1.js} +1 -1
  136. package/web/assets/{usePluginManager-CPTBi3rk.js → usePluginManager-BonTfGSN.js} +1 -1
  137. package/web/assets/useSidebar-77_u4hef.js +1 -0
  138. package/web/assets/{vue-router-DSROI5EH.js → vue-router-DdBypSuY.js} +1 -1
  139. package/web/assets/{xml-DtJwg-5S.js → xml-Cz29Bxul.js} +1 -1
  140. package/web/assets/{yaml-sPGHMYDm.js → yaml-CiZl2tNW.js} +1 -1
  141. package/web/index.html +2 -2
  142. package/agent-manager-A4E5CXFT-6PJDFN7J.js +0 -8
  143. package/chunk-DODGBBTE.js.map +0 -1
  144. package/dist-HZBWBT6S.js.map +0 -1
  145. package/web/assets/AddressBar.vue-D_8vQPIF.js +0 -1
  146. package/web/assets/AgentScalarChatInterface.vue-Be-LbA03.js +0 -13
  147. package/web/assets/AgentTerminalPage-BZmmd1H1.js +0 -36
  148. package/web/assets/AgentTerminalPage-EX_n6P3x.css +0 -1
  149. package/web/assets/AiChatPage-kTk6yC6d.js +0 -1
  150. package/web/assets/AppLayout-jbNML_m4.js +0 -1
  151. package/web/assets/AuditPage-S4kDjrZ5.js +0 -1
  152. package/web/assets/CodeInput.vue-nIhSM0FX.js +0 -1
  153. package/web/assets/Collection.vue-CkwnxBu4.js +0 -1
  154. package/web/assets/CollectionAuthentication.vue-CiZinGpr.js +0 -1
  155. package/web/assets/CollectionCookies.vue-BLEJqAhX.js +0 -1
  156. package/web/assets/CollectionEnvironment.vue-3bWtuG1B.js +0 -1
  157. package/web/assets/CollectionOverview.vue-BheZFfD3.js +0 -1
  158. package/web/assets/CollectionScripts.vue-CsY6tWxk.js +0 -1
  159. package/web/assets/CollectionServers.vue-Ja8mYDaK.js +0 -1
  160. package/web/assets/CollectionSettings.vue-DOB9JUg8.js +0 -1
  161. package/web/assets/CollectionSync.vue-B-uKwdTU.js +0 -1
  162. package/web/assets/CommandActionInput.vue-BBijVqe7.js +0 -1
  163. package/web/assets/Cookies.vue-DgVzSolJ.js +0 -1
  164. package/web/assets/DashboardPage-BwZPpURp.js +0 -1
  165. package/web/assets/DataTable.vue-DXTWz2Vi.js +0 -1
  166. package/web/assets/DataTableCheckbox.vue-BA5yHmxd.js +0 -1
  167. package/web/assets/DataTableInput.vue-DpeNUUXc.js +0 -1
  168. package/web/assets/DeleteSidebarListElement.vue-C2SV2geU.js +0 -1
  169. package/web/assets/EditSidebarListElement.vue-DvvYjTMO.js +0 -1
  170. package/web/assets/Environment.vue-D0PdeVIp.js +0 -1
  171. package/web/assets/EnvironmentForm-Dm3dFrSU.js +0 -108
  172. package/web/assets/EnvironmentFormPage-ByVELlly.js +0 -1
  173. package/web/assets/EnvironmentListPage-DvaTK4NF.js +0 -1
  174. package/web/assets/EnvironmentModal.vue-Bssf0U5X.js +0 -1
  175. package/web/assets/EnvironmentSelector-4kpQpg5e.js +0 -1
  176. package/web/assets/Form.vue-Dv4a31zh.js +0 -1
  177. package/web/assets/IconSelector.vue-BsYvff6K.js +0 -1
  178. package/web/assets/KanbanListPage-Dn35VrDc.js +0 -1
  179. package/web/assets/LaunchProjectPage-Byemtd9C.js +0 -1
  180. package/web/assets/LaunchServicesPage-CHiV6T5Y.js +0 -1
  181. package/web/assets/LogViewer-KtrKiUZw.js +0 -3
  182. package/web/assets/ProcessControls-DfFxf6jZ.js +0 -1
  183. package/web/assets/ProcessDetailPage-BOI85Xo7.js +0 -1
  184. package/web/assets/ProjectDetailPage-CTEt0DSq.js +0 -1
  185. package/web/assets/ProjectListPage-BrTIxp9K.js +0 -1
  186. package/web/assets/RandomJobTestPage-D2OB5pqD.js +0 -2
  187. package/web/assets/Request.vue-DHQd9eyp.js +0 -1
  188. package/web/assets/RequestAuth.vue-CEVOgzEk.js +0 -1
  189. package/web/assets/RequestRoot.vue-BEtC7IEP.js +0 -19
  190. package/web/assets/ScalarAsciiArt.vue-CyYmv9BB.js +0 -2
  191. package/web/assets/ScenarioEditorPage-xCx9aW1X.js +0 -14
  192. package/web/assets/ServerVariablesForm.vue-D9sjD4AT.js +0 -1
  193. package/web/assets/ServiceControlsBar-DKYIgScL.js +0 -1
  194. package/web/assets/ServiceDetailPage-B5qBCc9A.js +0 -2
  195. package/web/assets/ServiceFormPage-BNpWmyj_.js +0 -1
  196. package/web/assets/Settings.vue-DWPIjz57.js +0 -1
  197. package/web/assets/SettingsPage-C5lWJT0Z.js +0 -225
  198. package/web/assets/SetupKeyPage-BiqO4PQr.js +0 -1
  199. package/web/assets/SetupPage-FEUuQSQ2.js +0 -1
  200. package/web/assets/Sidebar.vue-DVHNacfA.js +0 -1
  201. package/web/assets/SidebarButton.vue-C4QDgSym.js +0 -1
  202. package/web/assets/SidebarListElement.vue-Ch1aI_Bz.js +0 -1
  203. package/web/assets/UnlockPage-Dhg0hoP-.js +0 -1
  204. package/web/assets/VariablesTable-DFJHJ9DF.js +0 -1
  205. package/web/assets/ViewLayout.vue-svdAMKVP.js +0 -1
  206. package/web/assets/ViewLayoutSection.vue-C9VAyihF.js +0 -1
  207. package/web/assets/active-entities-Dpd4ny38.js +0 -1
  208. package/web/assets/api-reference-C9jD1TQ9.js +0 -1
  209. package/web/assets/card-CeTOcGyS.js +0 -32
  210. package/web/assets/column-xfOef4Rh.js +0 -763
  211. package/web/assets/core-Dq8cnTTd.js +0 -1
  212. package/web/assets/dist-CQoPOD_o.js +0 -192
  213. package/web/assets/dist-US_vG96F.js +0 -1
  214. package/web/assets/editor.store-Dzhoqquh.js +0 -1
  215. package/web/assets/index-DXutsd9M.css +0 -1
  216. package/web/assets/pretty-ms-Bj2IaA2r.js +0 -202
  217. package/web/assets/process.store-cvjJzD3H.js +0 -1
  218. package/web/assets/project.store-C94-7i6c.js +0 -1
  219. package/web/assets/router-BgHCboHx.js +0 -1
  220. package/web/assets/settings.store-BGScNTnu.js +0 -1
  221. package/web/assets/store-a88gBDkh.js +0 -1840
  222. package/web/assets/trpc-CgAubgRH.js +0 -1
  223. package/web/assets/urls-BuNgEu0U.js +0 -12
  224. package/web/assets/useAiChatDrawer-D6TRHaNu.js +0 -1
  225. package/web/assets/useSidebar-BoK12gD1.js +0 -1
  226. /package/{agent-manager-A4E5CXFT-6PJDFN7J.js.map → agent-manager-V47DLMYP-26VYXTSG.js.map} +0 -0
package/agent/index.js CHANGED
@@ -3153,7 +3153,7 @@ var HealthChecker = class extends EventEmitter6 {
3153
3153
  this.stopChecking(id);
3154
3154
  }
3155
3155
  }
3156
- async checkHttp(processId, path, timeout, maxRetries, method = "GET", expectedStatus = 200) {
3156
+ async checkHttp(processId, path3, timeout, maxRetries, method = "GET", expectedStatus = 200) {
3157
3157
  const proc = processStore.get(processId);
3158
3158
  if (!proc || proc.state !== "running") {
3159
3159
  this.updateResult(processId, "unknown", 0);
@@ -3164,7 +3164,7 @@ var HealthChecker = class extends EventEmitter6 {
3164
3164
  this.updateResult(processId, "unknown", 0);
3165
3165
  return;
3166
3166
  }
3167
- const url = `http://localhost:${port}${path}`;
3167
+ const url = `http://localhost:${port}${path3}`;
3168
3168
  let failures = this.failureCounts.get(processId) ?? 0;
3169
3169
  try {
3170
3170
  const response = await fetch(url, {
@@ -4831,6 +4831,26 @@ import { spawn as spawn4 } from "child_process";
4831
4831
  import { EventEmitter as EventEmitter9 } from "events";
4832
4832
  import { randomUUID as randomUUID5 } from "crypto";
4833
4833
  import { fileURLToPath } from "url";
4834
+ import { createRequire } from "module";
4835
+ import { existsSync as existsSync2 } from "fs";
4836
+ import * as pty2 from "node-pty";
4837
+ function resolveMcpServerPath() {
4838
+ try {
4839
+ const req = createRequire(import.meta.url);
4840
+ return req.resolve("@runeya/packages-mcp-server");
4841
+ } catch {
4842
+ }
4843
+ const candidates = [
4844
+ new URL("../../../packages/mcp-server/dist/index.js", import.meta.url),
4845
+ new URL("../../../../packages/mcp-server/dist/index.js", import.meta.url),
4846
+ new URL("../mcp-server/index.js", import.meta.url)
4847
+ ];
4848
+ for (const c of candidates) {
4849
+ const p = fileURLToPath(c);
4850
+ if (existsSync2(p)) return p;
4851
+ }
4852
+ throw new Error("Could not locate @runeya/packages-mcp-server (built dist not found)");
4853
+ }
4834
4854
  var MAX_BUFFER_LINES = 1e5;
4835
4855
  var MAX_CONCURRENT_SPAWNS = 10;
4836
4856
  var CLEANUP_INTERVAL_MS = 6e4;
@@ -4852,13 +4872,16 @@ var AiSpawnManager = class {
4852
4872
  const args = [...opts.args];
4853
4873
  if (opts.enableMcp && opts.cli === "claude") {
4854
4874
  try {
4855
- const mcpServerPath = fileURLToPath(new URL("../mcp-server/index.js", import.meta.url));
4875
+ const mcpServerPath = resolveMcpServerPath();
4856
4876
  const mcpConfig = JSON.stringify({
4857
4877
  mcpServers: {
4858
4878
  runeya: {
4859
4879
  command: "node",
4860
4880
  args: [mcpServerPath],
4861
- env: opts.mcpApiBaseUrl ? { RUNEYA_BASE_URL: opts.mcpApiBaseUrl } : {}
4881
+ env: {
4882
+ ...opts.mcpApiBaseUrl ? { RUNEYA_BASE_URL: opts.mcpApiBaseUrl } : {},
4883
+ ...opts.mcpApiToken ? { RUNEYA_API_TOKEN: opts.mcpApiToken } : {}
4884
+ }
4862
4885
  }
4863
4886
  }
4864
4887
  });
@@ -4880,10 +4903,12 @@ var AiSpawnManager = class {
4880
4903
  exitCode: null,
4881
4904
  buffer: [],
4882
4905
  proc,
4906
+ ptyProc: null,
4883
4907
  emitter,
4884
4908
  createdAt: Date.now(),
4885
4909
  doneAt: null,
4886
- acked: false
4910
+ acked: false,
4911
+ lastChunkAt: null
4887
4912
  };
4888
4913
  this.spawns.set(spawnId, entry);
4889
4914
  if (opts.stdinData) {
@@ -4968,8 +4993,119 @@ var AiSpawnManager = class {
4968
4993
  }
4969
4994
  return true;
4970
4995
  }
4996
+ if (entry.ptyProc) {
4997
+ try {
4998
+ entry.ptyProc.kill();
4999
+ } catch {
5000
+ }
5001
+ return true;
5002
+ }
4971
5003
  return false;
4972
5004
  }
5005
+ // ── PTY mode ────────────────────────────────────────────────────────────
5006
+ spawnPty(opts) {
5007
+ const running = [...this.spawns.values()].filter((s) => s.status === "running").length;
5008
+ if (running >= MAX_CONCURRENT_SPAWNS) {
5009
+ throw new Error(`Max concurrent AI spawns reached (${MAX_CONCURRENT_SPAWNS})`);
5010
+ }
5011
+ const spawnId = randomUUID5();
5012
+ const emitter = new EventEmitter9();
5013
+ const args = [...opts.args];
5014
+ if (opts.enableMcp && opts.cli === "claude") {
5015
+ try {
5016
+ const mcpServerPath = resolveMcpServerPath();
5017
+ const mcpConfig = JSON.stringify({
5018
+ mcpServers: {
5019
+ runeya: {
5020
+ command: "node",
5021
+ args: [mcpServerPath],
5022
+ env: {
5023
+ ...opts.mcpApiBaseUrl ? { RUNEYA_BASE_URL: opts.mcpApiBaseUrl } : {},
5024
+ ...opts.mcpApiToken ? { RUNEYA_API_TOKEN: opts.mcpApiToken } : {}
5025
+ }
5026
+ }
5027
+ }
5028
+ });
5029
+ args.push("--mcp-config", mcpConfig);
5030
+ } catch (err) {
5031
+ console.warn("[ai-spawn-manager] Failed to resolve MCP server path:", err.message);
5032
+ }
5033
+ }
5034
+ const env2 = opts.env ? { ...process.env, ...opts.env } : process.env;
5035
+ const ptyProc = pty2.spawn(opts.cli, args, {
5036
+ name: "xterm-256color",
5037
+ cols: opts.cols ?? 120,
5038
+ rows: opts.rows ?? 30,
5039
+ cwd: opts.cwd || process.cwd(),
5040
+ env: env2
5041
+ });
5042
+ const entry = {
5043
+ spawnId,
5044
+ sessionId: opts.sessionId,
5045
+ cli: opts.cli,
5046
+ status: "running",
5047
+ exitCode: null,
5048
+ buffer: [],
5049
+ proc: null,
5050
+ ptyProc,
5051
+ emitter,
5052
+ createdAt: Date.now(),
5053
+ doneAt: null,
5054
+ acked: false,
5055
+ lastChunkAt: null
5056
+ };
5057
+ this.spawns.set(spawnId, entry);
5058
+ ptyProc.onData((data) => {
5059
+ this.pushChunk(entry, { type: "pty-data", data });
5060
+ });
5061
+ ptyProc.onExit(({ exitCode }) => {
5062
+ entry.status = exitCode === 0 ? "done" : "error";
5063
+ entry.exitCode = exitCode;
5064
+ entry.doneAt = Date.now();
5065
+ entry.ptyProc = null;
5066
+ this.pushChunk(entry, { type: "exit", data: "", code: exitCode });
5067
+ });
5068
+ console.log(`[ai-spawn-manager] Spawned PTY ${opts.cli} (${spawnId}), args: ${opts.args.length}, cwd: ${opts.cwd ?? "(default)"}, ${opts.cols ?? 120}x${opts.rows ?? 30}`);
5069
+ return spawnId;
5070
+ }
5071
+ writePty(spawnId, data) {
5072
+ const entry = this.spawns.get(spawnId);
5073
+ if (!entry || !entry.ptyProc) return false;
5074
+ try {
5075
+ entry.ptyProc.write(data);
5076
+ return true;
5077
+ } catch {
5078
+ return false;
5079
+ }
5080
+ }
5081
+ /** Return a running PTY spawn matching the given logical sessionId, if any. */
5082
+ findPtyBySessionId(sessionId) {
5083
+ for (const entry of this.spawns.values()) {
5084
+ if (entry.sessionId === sessionId && entry.status === "running" && entry.ptyProc !== null) {
5085
+ return {
5086
+ spawnId: entry.spawnId,
5087
+ cli: entry.cli,
5088
+ status: entry.status,
5089
+ exitCode: entry.exitCode,
5090
+ bufferLength: entry.buffer.length,
5091
+ createdAt: entry.createdAt,
5092
+ doneAt: entry.doneAt,
5093
+ lastChunkAt: entry.lastChunkAt
5094
+ };
5095
+ }
5096
+ }
5097
+ return null;
5098
+ }
5099
+ resizePty(spawnId, cols, rows) {
5100
+ const entry = this.spawns.get(spawnId);
5101
+ if (!entry || !entry.ptyProc) return false;
5102
+ try {
5103
+ entry.ptyProc.resize(cols, rows);
5104
+ return true;
5105
+ } catch {
5106
+ return false;
5107
+ }
5108
+ }
4973
5109
  list() {
4974
5110
  return [...this.spawns.values()].map((e) => ({
4975
5111
  spawnId: e.spawnId,
@@ -4978,7 +5114,8 @@ var AiSpawnManager = class {
4978
5114
  exitCode: e.exitCode,
4979
5115
  bufferLength: e.buffer.length,
4980
5116
  createdAt: e.createdAt,
4981
- doneAt: e.doneAt
5117
+ doneAt: e.doneAt,
5118
+ lastChunkAt: e.lastChunkAt
4982
5119
  }));
4983
5120
  }
4984
5121
  ack(spawnId) {
@@ -4993,6 +5130,9 @@ var AiSpawnManager = class {
4993
5130
  entry.buffer.shift();
4994
5131
  }
4995
5132
  entry.buffer.push(chunk);
5133
+ if (chunk.type === "stdout" || chunk.type === "stderr" || chunk.type === "pty-data") {
5134
+ entry.lastChunkAt = Date.now();
5135
+ }
4996
5136
  entry.emitter.emit("chunk");
4997
5137
  if (chunk.type === "exit") {
4998
5138
  entry.emitter.emit("done");
@@ -5025,13 +5165,19 @@ var AiSpawnManager = class {
5025
5165
  } catch {
5026
5166
  }
5027
5167
  }
5168
+ if (entry.ptyProc) {
5169
+ try {
5170
+ entry.ptyProc.kill();
5171
+ } catch {
5172
+ }
5173
+ }
5028
5174
  }
5029
5175
  }
5030
5176
  };
5031
5177
  var aiSpawnManager = new AiSpawnManager();
5032
5178
 
5033
5179
  // src/services/codex-app-server-manager.ts
5034
- import { spawn as spawn5 } from "child_process";
5180
+ import { spawn as spawn6 } from "child_process";
5035
5181
  import { createInterface as createInterface2 } from "readline";
5036
5182
  import { EventEmitter as EventEmitter10 } from "events";
5037
5183
  var REQUEST_TIMEOUT_MS = 3e5;
@@ -5059,7 +5205,7 @@ var CodexAppServerManager = class extends EventEmitter10 {
5059
5205
  }
5060
5206
  }
5061
5207
  async doConnect() {
5062
- this.proc = spawn5("codex", ["app-server"], {
5208
+ this.proc = spawn6("codex", ["app-server"], {
5063
5209
  stdio: ["pipe", "pipe", "pipe"],
5064
5210
  env: { ...process.env, ...this.extraEnv }
5065
5211
  });
@@ -5170,7 +5316,142 @@ var CodexAppServerManager = class extends EventEmitter10 {
5170
5316
  };
5171
5317
  var codexAppServerManager = new CodexAppServerManager();
5172
5318
 
5319
+ // src/services/ai-context-files.ts
5320
+ import { mkdir as mkdir4, writeFile as writeFile4 } from "fs/promises";
5321
+ import path from "path";
5322
+ import os2 from "os";
5323
+ var ROOT_DIR_NAME = "runeya-ai-context";
5324
+ function sanitizeName(name) {
5325
+ let safe = name.replace(/[^A-Za-z0-9._-]/g, "_");
5326
+ if (!safe || safe === "." || safe === "..") safe = "context";
5327
+ if (!/\.[A-Za-z0-9]+$/.test(safe)) safe += ".md";
5328
+ return safe;
5329
+ }
5330
+ function sanitizeSessionId(sessionId) {
5331
+ const safe = sessionId.replace(/[^A-Za-z0-9._-]/g, "_");
5332
+ return safe || "session";
5333
+ }
5334
+ async function writeContextFiles(sessionId, files) {
5335
+ const baseDir = path.join(os2.tmpdir(), ROOT_DIR_NAME, sanitizeSessionId(sessionId));
5336
+ await mkdir4(baseDir, { recursive: true });
5337
+ const paths = [];
5338
+ const usedNames = /* @__PURE__ */ new Set();
5339
+ for (let i = 0; i < files.length; i++) {
5340
+ const file = files[i];
5341
+ let name = sanitizeName(file.name);
5342
+ if (usedNames.has(name)) {
5343
+ const ext = path.extname(name);
5344
+ const base = name.slice(0, name.length - ext.length);
5345
+ name = `${base}-${i}${ext}`;
5346
+ }
5347
+ usedNames.add(name);
5348
+ const fullPath = path.join(baseDir, name);
5349
+ await writeFile4(fullPath, file.content, "utf8");
5350
+ paths.push(fullPath);
5351
+ }
5352
+ return paths;
5353
+ }
5354
+
5355
+ // src/services/ai-paste-image.ts
5356
+ import { mkdir as mkdir5, writeFile as writeFile5, unlink as unlink2 } from "fs/promises";
5357
+ import path2 from "path";
5358
+ import os3 from "os";
5359
+ import { randomUUID as randomUUID6 } from "crypto";
5360
+ import { spawn as spawn7 } from "child_process";
5361
+ var TMP_DIR_NAME = "runeya-ai-paste";
5362
+ var MIME_TO_EXT = {
5363
+ "image/png": "png",
5364
+ "image/jpeg": "jpg",
5365
+ "image/jpg": "jpg",
5366
+ "image/gif": "gif",
5367
+ "image/webp": "webp",
5368
+ "image/bmp": "bmp"
5369
+ };
5370
+ function extForMime(mime) {
5371
+ return MIME_TO_EXT[mime.toLowerCase()] ?? "png";
5372
+ }
5373
+ function runCmd(cmd, args, stdin, timeoutMs = 5e3) {
5374
+ return new Promise((resolve) => {
5375
+ let settled = false;
5376
+ const settle = (code, stderr) => {
5377
+ if (settled) return;
5378
+ settled = true;
5379
+ resolve({ code, stderr });
5380
+ };
5381
+ try {
5382
+ const child = spawn7(cmd, args, { stdio: ["pipe", "ignore", "pipe"] });
5383
+ let stderr = "";
5384
+ child.stderr.on("data", (c) => {
5385
+ stderr += c.toString();
5386
+ });
5387
+ child.on("error", (err) => settle(127, err.message));
5388
+ child.on("exit", (code) => settle(code ?? 1, stderr));
5389
+ const t2 = setTimeout(() => {
5390
+ try {
5391
+ child.kill("SIGKILL");
5392
+ } catch {
5393
+ }
5394
+ settle(124, "timeout");
5395
+ }, timeoutMs);
5396
+ child.on("exit", () => clearTimeout(t2));
5397
+ if (stdin) {
5398
+ child.stdin.on("error", () => {
5399
+ });
5400
+ child.stdin.end(stdin);
5401
+ } else {
5402
+ child.stdin.end();
5403
+ }
5404
+ } catch (err) {
5405
+ settle(127, err.message);
5406
+ }
5407
+ });
5408
+ }
5409
+ async function savePastedImage(base64, mimeType, sessionId) {
5410
+ const buf = Buffer.from(base64, "base64");
5411
+ if (buf.length === 0) throw new Error("Empty image payload");
5412
+ const ext = extForMime(mimeType);
5413
+ const baseDir = path2.join(
5414
+ os3.tmpdir(),
5415
+ TMP_DIR_NAME,
5416
+ sessionId ? sessionId.replace(/[^A-Za-z0-9._-]/g, "_") : "default"
5417
+ );
5418
+ await mkdir5(baseDir, { recursive: true });
5419
+ const tmpPath = path2.join(baseDir, `paste-${Date.now()}-${randomUUID6().slice(0, 8)}.${ext}`);
5420
+ await writeFile5(tmpPath, buf);
5421
+ const { method, error } = await tryWriteClipboard(buf, mimeType, tmpPath);
5422
+ return { tmpPath, clipboardMethod: method, clipboardError: error };
5423
+ }
5424
+ async function tryWriteClipboard(buf, mimeType, tmpPath) {
5425
+ const normalizedMime = mimeType.toLowerCase();
5426
+ const errors = [];
5427
+ if (process.platform === "darwin") {
5428
+ const klass = normalizedMime === "image/jpeg" || normalizedMime === "image/jpg" ? "JPEG picture" : "PNGf";
5429
+ const script = `set the clipboard to (read (POSIX file "${tmpPath.replace(/"/g, '\\"')}") as \xABclass ${klass}\xBB)`;
5430
+ const r = await runCmd("osascript", ["-e", script]);
5431
+ if (r.code === 0) return { method: "pbcopy" };
5432
+ errors.push(`osascript: ${r.stderr.trim()}`);
5433
+ }
5434
+ if (process.platform === "linux") {
5435
+ const r = await runCmd("xclip", ["-selection", "clipboard", "-t", normalizedMime, "-i"], buf);
5436
+ if (r.code === 0) return { method: "xclip" };
5437
+ errors.push(`xclip: ${r.stderr.trim() || `exit ${r.code}`}`);
5438
+ const r2 = await runCmd("wl-copy", ["--type", normalizedMime], buf);
5439
+ if (r2.code === 0) return { method: "wl-copy" };
5440
+ errors.push(`wl-copy: ${r2.stderr.trim() || `exit ${r2.code}`}`);
5441
+ }
5442
+ if (process.platform === "win32") {
5443
+ const ps = `Add-Type -AssemblyName System.Windows.Forms; Add-Type -AssemblyName System.Drawing; $img = [System.Drawing.Image]::FromFile("${tmpPath.replace(/\\/g, "\\\\")}"); [System.Windows.Forms.Clipboard]::SetImage($img); $img.Dispose()`;
5444
+ const r = await runCmd("powershell.exe", ["-NoProfile", "-NonInteractive", "-Command", ps]);
5445
+ if (r.code === 0) return { method: "powershell" };
5446
+ errors.push(`powershell: ${r.stderr.trim() || `exit ${r.code}`}`);
5447
+ }
5448
+ return { method: null, error: errors.join(" | ") || "no clipboard tool available" };
5449
+ }
5450
+
5173
5451
  // src/trpc/routers/ai.ts
5452
+ var MAX_CONTEXT_FILES = 20;
5453
+ var MAX_CONTEXT_FILE_BYTES = 1e6;
5454
+ var MAX_CONTEXT_TOTAL_BYTES = 5e6;
5174
5455
  var aiRouter = router({
5175
5456
  /** Spawn an AI CLI process. Returns a spawnId for streaming. */
5176
5457
  spawn: protectedProcedure.input(z25.object({
@@ -5201,6 +5482,71 @@ var aiRouter = router({
5201
5482
  });
5202
5483
  }
5203
5484
  }),
5485
+ /** Spawn an AI CLI process in a PTY (interactive mode). Returns spawnId. */
5486
+ spawnPty: protectedProcedure.input(z25.object({
5487
+ cli: z25.string().max(64),
5488
+ args: z25.array(z25.string().max(5e5)),
5489
+ env: z25.record(z25.string().max(256), z25.string().max(5e5)).optional(),
5490
+ cwd: z25.string().max(4096).optional(),
5491
+ cols: z25.number().int().min(1).max(1e3).optional(),
5492
+ rows: z25.number().int().min(1).max(1e3).optional(),
5493
+ sessionId: z25.string().max(128).optional(),
5494
+ enableMcp: z25.boolean().optional(),
5495
+ mcpApiBaseUrl: z25.string().max(512).optional(),
5496
+ mcpApiToken: z25.string().max(8192).optional()
5497
+ })).mutation(({ input }) => {
5498
+ const spawnId = aiSpawnManager.spawnPty(input);
5499
+ return { spawnId };
5500
+ }),
5501
+ /** Find a running PTY spawn by its logical sessionId (for re-attach). */
5502
+ findPtyBySession: protectedProcedure.input(z25.object({ sessionId: z25.string().max(128) })).query(({ input }) => {
5503
+ return aiSpawnManager.findPtyBySessionId(input.sessionId);
5504
+ }),
5505
+ /** Write input to a PTY spawn (user keystrokes). */
5506
+ writePty: protectedProcedure.input(z25.object({
5507
+ spawnId: z25.string().max(128),
5508
+ data: z25.string().max(1e6)
5509
+ })).mutation(({ input }) => {
5510
+ const ok = aiSpawnManager.writePty(input.spawnId, input.data);
5511
+ return { ok };
5512
+ }),
5513
+ /** Write attached-context files for an AI session to a temp dir. Returns absolute paths. */
5514
+ writeContextFiles: protectedProcedure.input(z25.object({
5515
+ sessionId: z25.string().min(1).max(128),
5516
+ files: z25.array(z25.object({
5517
+ name: z25.string().min(1).max(256),
5518
+ content: z25.string().max(MAX_CONTEXT_FILE_BYTES)
5519
+ })).min(1).max(MAX_CONTEXT_FILES)
5520
+ }).refine(
5521
+ (val) => val.files.reduce((sum, f) => sum + f.content.length, 0) <= MAX_CONTEXT_TOTAL_BYTES,
5522
+ { message: `Total context size exceeds ${MAX_CONTEXT_TOTAL_BYTES} bytes` }
5523
+ )).mutation(async ({ input }) => {
5524
+ const paths = await writeContextFiles(input.sessionId, input.files);
5525
+ return { paths };
5526
+ }),
5527
+ /**
5528
+ * Save a pasted image to disk and try to populate the agent's system clipboard
5529
+ * so Claude's native paste detection picks it up. Returns the tmp path and
5530
+ * which clipboard method (if any) succeeded — caller decides whether to send
5531
+ * Ctrl+V (\x16) or inject `@<path>` into the PTY.
5532
+ */
5533
+ pasteImage: protectedProcedure.input(z25.object({
5534
+ sessionId: z25.string().max(128).optional(),
5535
+ mimeType: z25.string().max(64),
5536
+ base64: z25.string().max(15e6)
5537
+ })).mutation(async ({ input }) => {
5538
+ const res = await savePastedImage(input.base64, input.mimeType, input.sessionId);
5539
+ return res;
5540
+ }),
5541
+ /** Resize a PTY spawn. */
5542
+ resizePty: protectedProcedure.input(z25.object({
5543
+ spawnId: z25.string().max(128),
5544
+ cols: z25.number().int().min(1).max(1e3),
5545
+ rows: z25.number().int().min(1).max(1e3)
5546
+ })).mutation(({ input }) => {
5547
+ const ok = aiSpawnManager.resizePty(input.spawnId, input.cols, input.rows);
5548
+ return { ok };
5549
+ }),
5204
5550
  /** Kill a running AI spawn. */
5205
5551
  kill: protectedProcedure.input(z25.object({ spawnId: z25.string().max(128) })).mutation(({ input }) => {
5206
5552
  const killed = aiSpawnManager.kill(input.spawnId);