@runeya/runeya 2.0.9 → 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.
- package/agent/index.js +513 -52
- package/agent/index.js.map +1 -1
- package/agent-manager-V47DLMYP-26VYXTSG.js +8 -0
- package/{chunk-BSPKMRKW.js → chunk-6547GLUJ.js} +49 -16
- package/chunk-6547GLUJ.js.map +1 -0
- package/{dist-PSPHMTZN.js → dist-2H7XZQCV.js} +1255 -378
- package/dist-2H7XZQCV.js.map +1 -0
- package/index.js +6 -1
- package/index.js.map +1 -1
- package/package.json +1 -1
- package/web/assets/AddressBar.vue-BxQkuTJ-.js +1 -0
- package/web/assets/AgentScalarChatInterface.vue-BZyh4z8j.js +13 -0
- package/web/assets/AgentTerminalPage-SWnqcTm-.js +1 -0
- package/web/assets/AgentTerminalPage-anYDkj7H.css +1 -0
- package/web/assets/AiChatPage-PJvieNVr.js +1 -0
- package/web/assets/AppLayout-CDtyYNWp.css +1 -0
- package/web/assets/AppLayout-qD2ReaTx.js +1 -0
- package/web/assets/AuditPage-DCvW5-HA.js +1 -0
- package/web/assets/CodeInput.vue-DDs5Eel7.js +1 -0
- package/web/assets/Collection.vue-HH2Z976J.js +1 -0
- package/web/assets/CollectionAuthentication.vue-BbsKOTJ9.js +1 -0
- package/web/assets/CollectionCookies.vue-Dzlq0l8S.js +1 -0
- package/web/assets/CollectionEnvironment.vue-BS9B1OU-.js +1 -0
- package/web/assets/CollectionOverview.vue-DXXQHn9J.js +1 -0
- package/web/assets/CollectionScripts.vue-TVNOxHuu.js +1 -0
- package/web/assets/CollectionServers.vue-DDyH4n80.js +1 -0
- package/web/assets/CollectionSettings.vue-BD5QvG5c.js +1 -0
- package/web/assets/CollectionSync.vue-g_NhkdXC.js +1 -0
- package/web/assets/CommandActionInput.vue-Cot3fJDd.js +1 -0
- package/web/assets/Cookies.vue-X8bc_7ud.js +1 -0
- package/web/assets/DashboardPage-BuP2oOo3.js +1 -0
- package/web/assets/DataTable.vue-DmcNIRcD.js +1 -0
- package/web/assets/DataTableCheckbox.vue-B7bvOQ_f.js +1 -0
- package/web/assets/{DataTableHeader.vue-ByesjY2f.js → DataTableHeader.vue-D5k0UCfl.js} +1 -1
- package/web/assets/DataTableInput.vue-DVUCY60y.js +1 -0
- package/web/assets/DeleteSidebarListElement.vue-CAri6AWj.js +1 -0
- package/web/assets/EditSidebarListElement.vue-DFY1ZZNE.js +1 -0
- package/web/assets/{EditorIcon-B70ii4EM.js → EditorIcon-DOV6wP8X.js} +2 -2
- package/web/assets/{EmptyState.vue-CcnWPtfW.js → EmptyState.vue-watFzTsD.js} +2 -2
- package/web/assets/Environment.vue-BbpisYLs.js +1 -0
- package/web/assets/EnvironmentForm-CyJtNH2k.js +108 -0
- package/web/assets/EnvironmentFormPage-Du4EXZlm.js +1 -0
- package/web/assets/EnvironmentListPage-1Jdh0AWO.js +1 -0
- package/web/assets/EnvironmentModal.vue-DaI310h8.js +1 -0
- package/web/assets/EnvironmentSelector-BPhBcKYj.js +1 -0
- package/web/assets/Form.vue-CMWUiD6f.js +1 -0
- package/web/assets/IconSelector.vue-90PWhHNq.js +1 -0
- package/web/assets/KanbanBoardPage-DzFRgXlJ.js +141 -0
- package/web/assets/KanbanListPage-O3T-L6z3.js +1 -0
- package/web/assets/LaunchProjectPage-B2m_PflY.js +1 -0
- package/web/assets/LaunchServicesPage-DgfE9971.js +1 -0
- package/web/assets/LogViewer-CXVXsymr.js +3 -0
- package/web/assets/ProcessControls-DVQwL-qx.js +1 -0
- package/web/assets/ProcessDetailPage-8GtSwfXG.js +1 -0
- package/web/assets/ProcessDetailPage-CzGUsQM9.css +1 -0
- package/web/assets/ProcessMetrics-9RjmvDOk.js +51 -0
- package/web/assets/ProjectDetailPage-B3s8bbmw.js +1 -0
- package/web/assets/ProjectListPage-HQ9gZWHw.js +1 -0
- package/web/assets/RandomJobTestPage-DAM5nNLf.js +2 -0
- package/web/assets/Request.vue-DiF4lAAD.js +1 -0
- package/web/assets/RequestAuth.vue-DHU9RNUf.js +1 -0
- package/web/assets/RequestRoot.vue-BiM2Tr20.js +19 -0
- package/web/assets/ScalarAsciiArt.vue-2vz_9aEa.js +2 -0
- package/web/assets/{ScalarIconEyeSlash.vue-DWKhR_BX.js → ScalarIconEyeSlash.vue-CwJnZ-zD.js} +1 -1
- package/web/assets/{ScalarIconTrash.vue-CtSwrO5S.js → ScalarIconTrash.vue-DAEOI9Kk.js} +1 -1
- package/web/assets/ScenarioEditorPage-BzPL_7Up.js +14 -0
- package/web/assets/ServerVariablesForm.vue-Dj2R8IEV.js +1 -0
- package/web/assets/ServiceControlsBar-CsHZTuPK.js +1 -0
- package/web/assets/ServiceDetailPage-Csf55wQD.js +2 -0
- package/web/assets/ServiceDetailPage-znbWajpt.css +1 -0
- package/web/assets/ServiceFormPage-DDJYv2z3.js +1 -0
- package/web/assets/Settings.vue-Dyzw_xwE.js +1 -0
- package/web/assets/SettingsPage-CYQGpGyw.js +225 -0
- package/web/assets/SettingsPage-CgJN_IL7.css +1 -0
- package/web/assets/SetupKeyPage-CnaFhUR6.js +1 -0
- package/web/assets/SetupPage-sqBZmTQ9.js +1 -0
- package/web/assets/Sidebar.vue-DqiliUT_.js +1 -0
- package/web/assets/SidebarButton.vue-MCBoC3jO.js +1 -0
- package/web/assets/SidebarListElement.vue-DswWWg_S.js +1 -0
- package/web/assets/UnlockPage-rDy89SdE.js +1 -0
- package/web/assets/VariablesTable-CEaksHyg.js +1 -0
- package/web/assets/{VariablesTable-BtdK5olT.css → VariablesTable-W4rxlL35.css} +1 -1
- package/web/assets/ViewLayout.vue-CgpeQh3K.js +1 -0
- package/web/assets/ViewLayoutContent.vue-DP_GK_Ip.js +1 -0
- package/web/assets/ViewLayoutSection.vue-YQYzkcAB.js +1 -0
- package/web/assets/active-entities-CWFFm964.js +1 -0
- package/web/assets/api-reference-UJl6P2J4.js +1 -0
- package/web/assets/autocomplete-CK9Z1-Wz.js +422 -0
- package/web/assets/card-DadsU5ZI.js +32 -0
- package/web/assets/{checkbox-C0sXsL9e.js → checkbox-4z5ftHhs.js} +3 -3
- package/web/assets/{chip-rnk9_cKV.js → chip-KJbF4Jjk.js} +2 -2
- package/web/assets/column-Cp1kVQOt.js +763 -0
- package/web/assets/core-7y546zlP.js +1 -0
- package/web/assets/{cssMode-DdlczEni.js → cssMode-CIUATcSv.js} +1 -1
- package/web/assets/dist-BLSATgV0.js +1 -0
- package/web/assets/{dist-DBBhfLmf.js → dist-Cp1hgSqY.js} +3 -3
- package/web/assets/{dist-DeOvPbza.js → dist-CpE_ZYIQ.js} +1 -1
- package/web/assets/dist-DR4LqG1l.js +192 -0
- package/web/assets/{divider-D6L7p-FU.js → divider-D-vBLTer.js} +2 -2
- package/web/assets/editor.store-COpS72tz.js +1 -0
- package/web/assets/{fieldset-CiwzR0un.js → fieldset-CSlJxjpZ.js} +2 -2
- package/web/assets/{freemarker2-_wLEdPSz.js → freemarker2-Dsxb69Av.js} +1 -1
- package/web/assets/{handlebars-66zKrSAk.js → handlebars-ChbvHuc-.js} +1 -1
- package/web/assets/{html-oM24gnvF.js → html-DOIF2Zpc.js} +1 -1
- package/web/assets/{htmlMode-D65_fKu-.js → htmlMode-DKICvQwb.js} +1 -1
- package/web/assets/index-A6eiSk8H.css +1 -0
- package/web/assets/{index-D5xJxOo2.js → index-C0UzL9Y-.js} +269 -234
- package/web/assets/{javascript-D-njx6Yh.js → javascript-Bmt68E8X.js} +1 -1
- package/web/assets/{jsonMode-bqHogKpM.js → jsonMode-CYcvn9c0.js} +1 -1
- package/web/assets/{keyboard-BzTLpobK.js → keyboard-DZklF_AY.js} +2 -2
- package/web/assets/{lib-CPo2W-Kx.js → lib-B5TdN_ca.js} +4 -4
- package/web/assets/{library-DmdL5Pgv.js → library-DtrGq8p8.js} +1 -1
- package/web/assets/{liquid-BDL70fhI.js → liquid-3ot_oRqd.js} +1 -1
- package/web/assets/{mdx-Bo_N_Jd-.js → mdx-Cm1rlDNM.js} +1 -1
- package/web/assets/{mediaTypes-Cnm-r_sv.js → mediaTypes-Bz4C7Sle.js} +2 -2
- package/web/assets/{message-gtjFpAbc.js → message-DFReN7Fq.js} +2 -2
- package/web/assets/{minus-C5Lsl7Wp.js → minus-t_EQEzUj.js} +2 -2
- package/web/assets/{multiselect-BlmCsiSW.js → multiselect-BZbgA1pl.js} +3 -3
- package/web/assets/{password-RYOg4soC.js → password-D82un95s.js} +4 -4
- package/web/assets/{plus-C52I3-BN.js → plus-B-AhHpHU.js} +6 -6
- package/web/assets/pretty-ms-XBeIOdhN.js +202 -0
- package/web/assets/process.store-jv0SI_6q.js +1 -0
- package/web/assets/project.store-DHXLE6Lv.js +1 -0
- package/web/assets/{python-D1UXSNgK.js → python-BuQCsdKw.js} +1 -1
- package/web/assets/{radiobutton-B0t-WlKP.js → radiobutton-Btattklk.js} +2 -2
- package/web/assets/{razor-Bd4GOtMe.js → razor-DgnEPQLs.js} +1 -1
- package/web/assets/router-w5lyb-nn.js +1 -0
- package/web/assets/settings.store-bNnLJ43c.js +1 -0
- package/web/assets/store-DWOu5TTl.js +1840 -0
- package/web/assets/{tabpanel-geoVG-sX.js → tabpanel-CIyzJ44J.js} +3 -3
- package/web/assets/{tag-Dv5CaUPa.js → tag-DV-szbCr.js} +2 -2
- package/web/assets/trpc-wp_QsEqG.js +1 -0
- package/web/assets/{tsMode-BkM4CkKr.js → tsMode-ChD0IpIg.js} +1 -1
- package/web/assets/{typescript-CUKl0qxN.js → typescript-BRYpIqKe.js} +1 -1
- package/web/assets/urls-CoBMqtDH.js +12 -0
- package/web/assets/{use-tree-walker-E64HILpa.js → use-tree-walker-M4-Gn01v.js} +1 -1
- package/web/assets/useAiChatDrawer-BhlTNoXz.js +1 -0
- package/web/assets/{useClipboard-Bep2crMO.js → useClipboard-Cro2wlg3.js} +1 -1
- package/web/assets/{useLayout-F9XKAPPL.js → useLayout-BciG4r-1.js} +1 -1
- package/web/assets/{usePluginManager-yL67GqCi.js → usePluginManager-BonTfGSN.js} +1 -1
- package/web/assets/useSidebar-77_u4hef.js +1 -0
- package/web/assets/{vue-router-uE6ClrN-.js → vue-router-DdBypSuY.js} +1 -1
- package/web/assets/{xml-DMOW2yTg.js → xml-Cz29Bxul.js} +1 -1
- package/web/assets/{yaml-D2q3K0ZL.js → yaml-CiZl2tNW.js} +1 -1
- package/web/index.html +2 -2
- package/agent-manager-UP3PJ35X-LO6B3XKF.js +0 -8
- package/chunk-BSPKMRKW.js.map +0 -1
- package/dist-PSPHMTZN.js.map +0 -1
- package/web/assets/AddressBar.vue-BOHUxRhN.js +0 -1
- package/web/assets/AgentPage-BTWkJvqr.css +0 -1
- package/web/assets/AgentPage-DFHxsu-9.js +0 -2
- package/web/assets/AgentScalarChatInterface.vue-Cxxiyyj8.js +0 -13
- package/web/assets/AgentTerminalPage-D-T5emEl.js +0 -36
- package/web/assets/AgentTerminalPage-EX_n6P3x.css +0 -1
- package/web/assets/AiChatPage-C81mFvv5.js +0 -1
- package/web/assets/ApiDocsPage-CMGvcGEJ.js +0 -5
- package/web/assets/ApiDocsPage-D2Z0wqGZ.css +0 -1
- package/web/assets/AppLayout-D10vX1fo.js +0 -1
- package/web/assets/AppLayout-sngalCCj.css +0 -1
- package/web/assets/AuditPage-DZiwogoY.js +0 -1
- package/web/assets/CodeInput.vue-8aNMYCYM.js +0 -1
- package/web/assets/Collection.vue-N8zZa4pa.js +0 -1
- package/web/assets/CollectionAuthentication.vue-cJOxjafo.js +0 -1
- package/web/assets/CollectionCookies.vue-DrFQqbwv.js +0 -1
- package/web/assets/CollectionEnvironment.vue-DWPTZ8qx.js +0 -1
- package/web/assets/CollectionOverview.vue-1Qf130d5.js +0 -1
- package/web/assets/CollectionScripts.vue-DhcFFz80.js +0 -1
- package/web/assets/CollectionServers.vue-h7E03W0v.js +0 -1
- package/web/assets/CollectionSettings.vue-CFrOwl7U.js +0 -1
- package/web/assets/CollectionSync.vue-PV_tIrJS.js +0 -1
- package/web/assets/CommandActionInput.vue-L7AcEf6T.js +0 -1
- package/web/assets/Cookies.vue-_P19OjMm.js +0 -1
- package/web/assets/DashboardPage-BUDWnuJT.js +0 -1
- package/web/assets/DataTable.vue-DYVeGQPP.js +0 -1
- package/web/assets/DataTableCheckbox.vue-n2xCTJj1.js +0 -1
- package/web/assets/DataTableInput.vue-uPpuKzrX.js +0 -1
- package/web/assets/DeleteSidebarListElement.vue-CBIb58rU.js +0 -1
- package/web/assets/EditSidebarListElement.vue-DqTVSZtI.js +0 -1
- package/web/assets/Environment.vue-Cgx06nkH.js +0 -1
- package/web/assets/EnvironmentForm-iBZzqZKd.js +0 -108
- package/web/assets/EnvironmentFormPage-YVxAAreT.js +0 -1
- package/web/assets/EnvironmentListPage-CHYDJ_c-.js +0 -1
- package/web/assets/EnvironmentModal.vue-BJNYZuPC.js +0 -1
- package/web/assets/EnvironmentSelector-BZn_taec.js +0 -1
- package/web/assets/Form.vue-NLXFw40d.js +0 -1
- package/web/assets/IconSelector.vue-Ykh6DAln.js +0 -1
- package/web/assets/KanbanBoardPage-gtXv0ZhK.js +0 -141
- package/web/assets/KanbanListPage-DMNSYO_o.js +0 -1
- package/web/assets/LaunchProjectPage-DSyBuhky.js +0 -1
- package/web/assets/LaunchServicesPage-CiGkiqwE.js +0 -1
- package/web/assets/LogViewer-DBVkaZnm.js +0 -3
- package/web/assets/ProcessControls-Cya4eb3d.js +0 -1
- package/web/assets/ProcessDetailPage-8ypC6zkc.js +0 -1
- package/web/assets/ProcessDetailPage-B0qGKtvQ.css +0 -1
- package/web/assets/ProcessMetrics-CxRgbaUS.js +0 -1
- package/web/assets/ProjectDetailPage-a1lTAjKP.js +0 -1
- package/web/assets/ProjectListPage-Dewqu8Dm.js +0 -1
- package/web/assets/RandomJobTestPage-E6mevkqw.js +0 -2
- package/web/assets/Request.vue-DQPTi6ur.js +0 -1
- package/web/assets/RequestAuth.vue-DV5nNO3f.js +0 -1
- package/web/assets/RequestRoot.vue-DKlASKU5.js +0 -19
- package/web/assets/ScalarAsciiArt.vue-mk9jZSKh.js +0 -2
- package/web/assets/ScenarioEditorPage-DogHTbNU.js +0 -14
- package/web/assets/ServerVariablesForm.vue-DYmWiAuz.js +0 -1
- package/web/assets/ServiceControlsBar-B8Sm6p9E.js +0 -1
- package/web/assets/ServiceDetailPage-BriHTCpT.css +0 -1
- package/web/assets/ServiceDetailPage-DpWLccOg.js +0 -2
- package/web/assets/ServiceFormPage-DQbOgtB3.js +0 -1
- package/web/assets/Settings.vue-buoYkM3l.js +0 -1
- package/web/assets/SettingsPage-CCjZq5jP.js +0 -508
- package/web/assets/SettingsPage-vGhb_tlY.css +0 -1
- package/web/assets/SetupKeyPage-BdSpJPDR.js +0 -1
- package/web/assets/SetupPage-BsWaVllB.js +0 -1
- package/web/assets/Sidebar.vue-DntMEn5m.js +0 -1
- package/web/assets/SidebarButton.vue-DTin2zI2.js +0 -1
- package/web/assets/SidebarListElement.vue-zlfRLuE5.js +0 -1
- package/web/assets/UnlockPage-CmwRV1XA.js +0 -1
- package/web/assets/VariablesTable-C8lxLV1V.js +0 -1
- package/web/assets/ViewLayout.vue-C7w_U_o6.js +0 -1
- package/web/assets/ViewLayoutContent.vue-CAXM5eIo.js +0 -1
- package/web/assets/ViewLayoutSection.vue-BzJIsja7.js +0 -1
- package/web/assets/active-entities-C2TbBQeI.js +0 -1
- package/web/assets/api-reference-BJkGMKQj.js +0 -1
- package/web/assets/autocomplete-CxPmwkcZ.js +0 -308
- package/web/assets/card-D5_gGGD-.js +0 -32
- package/web/assets/column-ChvIrUdH.js +0 -763
- package/web/assets/core-wYvkV3-A.js +0 -1
- package/web/assets/dist-BHh6fQzR.js +0 -1
- package/web/assets/dist-ZJ37S89a.js +0 -192
- package/web/assets/editor.store-CWtgIxvE.js +0 -1
- package/web/assets/index-Pqvy10Qz.css +0 -1
- package/web/assets/pretty-ms-BBvjfSt1.js +0 -202
- package/web/assets/process.store-3BOses3z.js +0 -1
- package/web/assets/project.store-emr8mjg8.js +0 -1
- package/web/assets/router-DHhyM3YQ.js +0 -1
- package/web/assets/settings.store-CDr0Mia7.js +0 -1
- package/web/assets/store-CZKREOuj.js +0 -1840
- package/web/assets/toggleswitch-DNzwv4Lc.js +0 -115
- package/web/assets/trpc-B-vyi6vd.js +0 -1
- package/web/assets/urls-BqL-MrG5.js +0 -12
- package/web/assets/useAiChatDrawer-uS6dsG6x.js +0 -1
- package/web/assets/useSidebar-DVRRagIa.js +0 -1
- /package/{agent-manager-UP3PJ35X-LO6B3XKF.js.map → agent-manager-V47DLMYP-26VYXTSG.js.map} +0 -0
- /package/web/assets/{_plugin-vue_export-helper-C7ztIXtE.js → _plugin-vue_export-helper-BVSTY9ge.js} +0 -0
- /package/web/assets/{abap-C4tHUUCU.js → abap-BF8nUS5p.js} +0 -0
- /package/web/assets/{apex-6cG6aG-w.js → apex-Bbj_Fak2.js} +0 -0
- /package/web/assets/{azcli-51BngrSU.js → azcli-B8w3JS7J.js} +0 -0
- /package/web/assets/{base64-uZi92-DX.js → base64-CG47Jc3Y.js} +0 -0
- /package/web/assets/{bat-BDcdVSIt.js → bat-CaNuqacB.js} +0 -0
- /package/web/assets/{bicep-Cg0BCcky.js → bicep-DAvnLugW.js} +0 -0
- /package/web/assets/{cameligo-C3ekVui9.js → cameligo-BlI8LCmP.js} +0 -0
- /package/web/assets/{clojure-Ci5xNgh_.js → clojure-CxxhrBQl.js} +0 -0
- /package/web/assets/{coffee-xsRz4GKy.js → coffee-SkbnTBhO.js} +0 -0
- /package/web/assets/{cpp-B2gW4e23.js → cpp-Dm2HJxj0.js} +0 -0
- /package/web/assets/{csharp-SRujvHqy.js → csharp-BOGHPGcq.js} +0 -0
- /package/web/assets/{csp-Cr-ll6gP.js → csp-CMA_7tOs.js} +0 -0
- /package/web/assets/{css-BYTJZCno.js → css-DU8LSGcn.js} +0 -0
- /package/web/assets/{cypher-AmQ0R_D3.js → cypher-BZPsEDmT.js} +0 -0
- /package/web/assets/{dart-Du01a0J5.js → dart-C1tIJhFk.js} +0 -0
- /package/web/assets/{dist-DkaYBczY.js → dist-BPIMeATj.js} +0 -0
- /package/web/assets/{dockerfile-Dtlk9wqf.js → dockerfile-z4dmGi5q.js} +0 -0
- /package/web/assets/{ecl-CpmVnLkK.js → ecl-Rv9JwhOI.js} +0 -0
- /package/web/assets/{elixir-B3MVAC8k.js → elixir-DL6xFSed.js} +0 -0
- /package/web/assets/{flow9-Chkly0RN.js → flow9-DFZ52-2d.js} +0 -0
- /package/web/assets/{fsharp-CZvMkppk.js → fsharp-RvVOB9Dm.js} +0 -0
- /package/web/assets/{go-dT2iT7lt.js → go-B2USMDMv.js} +0 -0
- /package/web/assets/{graphql-DmObWyBD.js → graphql-CsHpCYeJ.js} +0 -0
- /package/web/assets/{hcl-D1x5Oyp4.js → hcl-CK021J-J.js} +0 -0
- /package/web/assets/{ini-Bg2o1S3s.js → ini-v1EoSUxR.js} +0 -0
- /package/web/assets/{java-XviKSSn5.js → java-CUXpSPxY.js} +0 -0
- /package/web/assets/{julia-DfTIwUGh.js → julia-DwKveiZg.js} +0 -0
- /package/web/assets/{kotlin-CNaIBh9d.js → kotlin-SsG_4ZBt.js} +0 -0
- /package/web/assets/{less-D7o76tXd.js → less-BviquM8A.js} +0 -0
- /package/web/assets/{lexon-Dd374QjV.js → lexon-C8G_qWst.js} +0 -0
- /package/web/assets/{lua-DZKuiFbY.js → lua-xqYje_o5.js} +0 -0
- /package/web/assets/{m3-CbwRx9Bb.js → m3-B5PetinG.js} +0 -0
- /package/web/assets/{markdown-DwLB5Rib.js → markdown-BksexNux.js} +0 -0
- /package/web/assets/{mips-DLbIq1yM.js → mips-DKSTezUQ.js} +0 -0
- /package/web/assets/{msdax-D4IjoZ6m.js → msdax-SeFNE86e.js} +0 -0
- /package/web/assets/{mysql-DQL_jy6H.js → mysql-5TQWJDdB.js} +0 -0
- /package/web/assets/{objective-c-D74wM5bv.js → objective-c-DeaYl08g.js} +0 -0
- /package/web/assets/{pascal-5tRlZk4O.js → pascal-CGBtIfZg.js} +0 -0
- /package/web/assets/{pascaligo-CAE4rAEt.js → pascaligo-B85wuk0w.js} +0 -0
- /package/web/assets/{perl-DREAbuQT.js → perl-Bl61zsEQ.js} +0 -0
- /package/web/assets/{pgsql-DASKdyAW.js → pgsql-KgXv5Cq7.js} +0 -0
- /package/web/assets/{php-C37ZWqoO.js → php-KRRf0kxu.js} +0 -0
- /package/web/assets/{pla-v5u9R8i1.js → pla-CFpO6lSz.js} +0 -0
- /package/web/assets/{postiats-Szt5m-7G.js → postiats-B0jQ-DXO.js} +0 -0
- /package/web/assets/{powerquery-BzVrUSu3.js → powerquery-T9Ge5xUx.js} +0 -0
- /package/web/assets/{powershell-BdbPbX_X.js → powershell-rmYjKoE4.js} +0 -0
- /package/web/assets/{protobuf-qqDa50tu.js → protobuf-B--9ME3E.js} +0 -0
- /package/web/assets/{pug-Cu20UQ5w.js → pug-y0-ppnAV.js} +0 -0
- /package/web/assets/{qsharp-DcbHL5X7.js → qsharp-DobgOAC8.js} +0 -0
- /package/web/assets/{r-Bvig6Flk.js → r-BHQZIThn.js} +0 -0
- /package/web/assets/{redis-BxHDcW3-.js → redis-DMHMVIni.js} +0 -0
- /package/web/assets/{redshift-B8dvlzjH.js → redshift-ilRjY5HF.js} +0 -0
- /package/web/assets/{restructuredtext-npodtAFM.js → restructuredtext-jr4YYJbv.js} +0 -0
- /package/web/assets/{ruby-DiofbcJD.js → ruby-D-h_0NIs.js} +0 -0
- /package/web/assets/{rust-BjYid3-m.js → rust-VxeTSQU2.js} +0 -0
- /package/web/assets/{sb-CzcPAP71.js → sb-BlhKufrP.js} +0 -0
- /package/web/assets/{scala-Ci4wFrYi.js → scala-IAk6nSCU.js} +0 -0
- /package/web/assets/{scheme-D3iWhvP7.js → scheme-Dggdm5LS.js} +0 -0
- /package/web/assets/{scss-DdlqDgmu.js → scss-Bzj9Cp1q.js} +0 -0
- /package/web/assets/{shell-Bawb9gbH.js → shell-CSwYJdGJ.js} +0 -0
- /package/web/assets/{solidity-Z2Sq8PBC.js → solidity-DnWqIXnk.js} +0 -0
- /package/web/assets/{sophia--yD-H1Ow.js → sophia-ClaYC_5N.js} +0 -0
- /package/web/assets/{sparql-0vv3-wLi.js → sparql-CfjIZAcz.js} +0 -0
- /package/web/assets/{sql-0gdWKhmJ.js → sql-DxdJ7snd.js} +0 -0
- /package/web/assets/{st-rE-x-DTZ.js → st-DJgQE1uj.js} +0 -0
- /package/web/assets/{swift-CSKeG8Ne.js → swift-5cz3wIvv.js} +0 -0
- /package/web/assets/{systemverilog-CblNM3Im.js → systemverilog-C8-7QuIt.js} +0 -0
- /package/web/assets/{tcl-BYnzj-GZ.js → tcl-C99u42o5.js} +0 -0
- /package/web/assets/{twig-DiGWiEtp.js → twig-Cv9kOcBK.js} +0 -0
- /package/web/assets/{typespec-a6xMcpXw.js → typespec-DF1s-ehc.js} +0 -0
- /package/web/assets/{uuid-B9GFVXPm.js → uuid-6HQMUkhT.js} +0 -0
- /package/web/assets/{vb---51HVMC.js → vb-4mpz9ITX.js} +0 -0
- /package/web/assets/{w3c-keyname-DDCGDLuI.js → w3c-keyname-emj7Fjc1.js} +0 -0
- /package/web/assets/{wgsl-2A8z4pT5.js → wgsl-xExw6Z08.js} +0 -0
package/agent/index.js
CHANGED
|
@@ -397,6 +397,7 @@ var DockerRunner = class {
|
|
|
397
397
|
);
|
|
398
398
|
return {
|
|
399
399
|
pid: void 0,
|
|
400
|
+
containerName,
|
|
400
401
|
stdout,
|
|
401
402
|
stderr,
|
|
402
403
|
exitPromise,
|
|
@@ -526,6 +527,7 @@ var DockerRunner = class {
|
|
|
526
527
|
})();
|
|
527
528
|
return {
|
|
528
529
|
pid: void 0,
|
|
530
|
+
containerName,
|
|
529
531
|
stdout,
|
|
530
532
|
stderr,
|
|
531
533
|
exitPromise,
|
|
@@ -572,6 +574,7 @@ var DockerRunner = class {
|
|
|
572
574
|
);
|
|
573
575
|
return {
|
|
574
576
|
pid: void 0,
|
|
577
|
+
containerName,
|
|
575
578
|
stdout,
|
|
576
579
|
stderr,
|
|
577
580
|
exitPromise,
|
|
@@ -902,7 +905,13 @@ var NotificationPreferencesSchema = z5.object({
|
|
|
902
905
|
ai_conversation_error: z5.boolean().default(true),
|
|
903
906
|
service_error_log: z5.boolean().default(true),
|
|
904
907
|
service_status_changed: z5.boolean().default(true),
|
|
905
|
-
service_health_changed: z5.boolean().default(true)
|
|
908
|
+
service_health_changed: z5.boolean().default(true),
|
|
909
|
+
/** Service IDs excluded from error-log notifications */
|
|
910
|
+
service_error_log_excluded: z5.array(z5.string().max(100)).max(500).default([]),
|
|
911
|
+
/** Service IDs excluded from status-change notifications */
|
|
912
|
+
service_status_changed_excluded: z5.array(z5.string().max(100)).max(500).default([]),
|
|
913
|
+
/** Service IDs excluded from health-change notifications */
|
|
914
|
+
service_health_changed_excluded: z5.array(z5.string().max(100)).max(500).default([])
|
|
906
915
|
});
|
|
907
916
|
var SettingsSchema = z5.object({
|
|
908
917
|
mode: z5.enum(["local-simple", "cloud"]),
|
|
@@ -931,7 +940,10 @@ var SettingsPrivateSchema = z5.object({
|
|
|
931
940
|
ai_conversation_error: true,
|
|
932
941
|
service_error_log: true,
|
|
933
942
|
service_status_changed: true,
|
|
934
|
-
service_health_changed: true
|
|
943
|
+
service_health_changed: true,
|
|
944
|
+
service_error_log_excluded: [],
|
|
945
|
+
service_status_changed_excluded: [],
|
|
946
|
+
service_health_changed_excluded: []
|
|
935
947
|
})),
|
|
936
948
|
traefikConfig: TraefikConfigSchema.optional()
|
|
937
949
|
});
|
|
@@ -948,9 +960,6 @@ var safePath = z6.string().min(1).max(4096).refine(
|
|
|
948
960
|
).refine(
|
|
949
961
|
(p) => !/(^|[/\\])\.\.([/\\]|$)/.test(p),
|
|
950
962
|
{ message: "path must not contain path-traversal sequences (..)" }
|
|
951
|
-
).refine(
|
|
952
|
-
(p) => p.startsWith("/") || /^[A-Za-z]:[/\\]/.test(p),
|
|
953
|
-
{ message: "path must be absolute" }
|
|
954
963
|
);
|
|
955
964
|
var ConsoleLogSourceSchema = z6.object({
|
|
956
965
|
type: z6.literal("console")
|
|
@@ -959,7 +968,8 @@ var FileLogSourceSchema = z6.object({
|
|
|
959
968
|
type: z6.literal("file"),
|
|
960
969
|
path: safePath,
|
|
961
970
|
encoding: z6.string().max(32).default("utf-8"),
|
|
962
|
-
startFromEnd: z6.boolean().default(true)
|
|
971
|
+
startFromEnd: z6.boolean().default(true),
|
|
972
|
+
createIfNotExists: z6.boolean().default(false)
|
|
963
973
|
});
|
|
964
974
|
var MongoLogSourceSchema = z6.object({
|
|
965
975
|
type: z6.literal("mongo"),
|
|
@@ -2010,6 +2020,21 @@ var FileLogSource = class extends EventEmitter2 {
|
|
|
2010
2020
|
this.emitSystemLog(processId, `[FileLogSource] Permission denied: ${this.config.path}`, "error");
|
|
2011
2021
|
return;
|
|
2012
2022
|
}
|
|
2023
|
+
if (nodeErr.code === "ENOENT" && this.config.createIfNotExists) {
|
|
2024
|
+
try {
|
|
2025
|
+
await fsPromises.mkdir(
|
|
2026
|
+
(await import("path")).dirname(this.config.path),
|
|
2027
|
+
{ recursive: true }
|
|
2028
|
+
);
|
|
2029
|
+
await fsPromises.writeFile(this.config.path, "", { flag: "a" });
|
|
2030
|
+
this.emitSystemLog(processId, `[FileLogSource] File created: ${this.config.path}`, "info");
|
|
2031
|
+
break;
|
|
2032
|
+
} catch (createErr) {
|
|
2033
|
+
const ce = createErr;
|
|
2034
|
+
this.emitSystemLog(processId, `[FileLogSource] Failed to create file: ${ce.message}`, "error");
|
|
2035
|
+
return;
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2013
2038
|
attempts++;
|
|
2014
2039
|
if (attempts >= RETRY_ATTEMPTS) {
|
|
2015
2040
|
this.emitSystemLog(processId, `[FileLogSource] File not found after ${RETRY_ATTEMPTS} retries: ${this.config.path}`, "error");
|
|
@@ -2475,7 +2500,47 @@ function createLogSource(config, logBuffer, logParser) {
|
|
|
2475
2500
|
|
|
2476
2501
|
// src/services/metrics-collector.ts
|
|
2477
2502
|
import pidusage from "pidusage";
|
|
2503
|
+
import { execFile } from "child_process";
|
|
2478
2504
|
import { EventEmitter as EventEmitter5 } from "events";
|
|
2505
|
+
async function getDockerStats(containerName) {
|
|
2506
|
+
return new Promise((resolve) => {
|
|
2507
|
+
execFile(
|
|
2508
|
+
"docker",
|
|
2509
|
+
["stats", "--no-stream", "--format", "{{json .}}", containerName],
|
|
2510
|
+
{ timeout: 5e3 },
|
|
2511
|
+
(err, stdout) => {
|
|
2512
|
+
if (err || !stdout.trim()) {
|
|
2513
|
+
resolve(null);
|
|
2514
|
+
return;
|
|
2515
|
+
}
|
|
2516
|
+
try {
|
|
2517
|
+
const data = JSON.parse(stdout.trim());
|
|
2518
|
+
const cpu = parseFloat(data.CPUPerc.replace("%", ""));
|
|
2519
|
+
const memStr = data.MemUsage.split("/")[0].trim();
|
|
2520
|
+
const memory = parseMemBytes(memStr);
|
|
2521
|
+
resolve({ cpu: isNaN(cpu) ? 0 : cpu, memory });
|
|
2522
|
+
} catch {
|
|
2523
|
+
resolve(null);
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2526
|
+
);
|
|
2527
|
+
});
|
|
2528
|
+
}
|
|
2529
|
+
function parseMemBytes(str) {
|
|
2530
|
+
const m = str.match(/^([\d.]+)\s*(B|kB|MB|MiB|GiB|GB)$/i);
|
|
2531
|
+
if (!m) return 0;
|
|
2532
|
+
const val = parseFloat(m[1]);
|
|
2533
|
+
const unit = m[2].toLowerCase();
|
|
2534
|
+
const multipliers = {
|
|
2535
|
+
b: 1,
|
|
2536
|
+
kb: 1e3,
|
|
2537
|
+
mb: 1e6,
|
|
2538
|
+
mib: 1024 * 1024,
|
|
2539
|
+
gib: 1024 ** 3,
|
|
2540
|
+
gb: 1e9
|
|
2541
|
+
};
|
|
2542
|
+
return Math.round(val * (multipliers[unit] ?? 1));
|
|
2543
|
+
}
|
|
2479
2544
|
var MetricsCollector = class extends EventEmitter5 {
|
|
2480
2545
|
intervals = /* @__PURE__ */ new Map();
|
|
2481
2546
|
intervalMs;
|
|
@@ -2483,7 +2548,7 @@ var MetricsCollector = class extends EventEmitter5 {
|
|
|
2483
2548
|
super();
|
|
2484
2549
|
this.intervalMs = intervalMs;
|
|
2485
2550
|
}
|
|
2486
|
-
/** Start collecting metrics for a process */
|
|
2551
|
+
/** Start collecting metrics for a native process (by PID). */
|
|
2487
2552
|
startCollecting(processId, pid) {
|
|
2488
2553
|
this.stopCollecting(processId);
|
|
2489
2554
|
const interval = setInterval(async () => {
|
|
@@ -2502,6 +2567,25 @@ var MetricsCollector = class extends EventEmitter5 {
|
|
|
2502
2567
|
}, this.intervalMs);
|
|
2503
2568
|
this.intervals.set(processId, interval);
|
|
2504
2569
|
}
|
|
2570
|
+
/** Start collecting metrics for a Docker container (by container name). */
|
|
2571
|
+
startCollectingDocker(processId, containerName) {
|
|
2572
|
+
this.stopCollecting(processId);
|
|
2573
|
+
const interval = setInterval(async () => {
|
|
2574
|
+
const stats = await getDockerStats(containerName);
|
|
2575
|
+
if (!stats) {
|
|
2576
|
+
this.stopCollecting(processId);
|
|
2577
|
+
return;
|
|
2578
|
+
}
|
|
2579
|
+
const metrics = {
|
|
2580
|
+
processId,
|
|
2581
|
+
cpu: stats.cpu,
|
|
2582
|
+
memory: stats.memory,
|
|
2583
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2584
|
+
};
|
|
2585
|
+
this.emit("metrics", metrics);
|
|
2586
|
+
}, this.intervalMs);
|
|
2587
|
+
this.intervals.set(processId, interval);
|
|
2588
|
+
}
|
|
2505
2589
|
/** Stop collecting metrics for a process */
|
|
2506
2590
|
stopCollecting(processId) {
|
|
2507
2591
|
const interval = this.intervals.get(processId);
|
|
@@ -2510,23 +2594,31 @@ var MetricsCollector = class extends EventEmitter5 {
|
|
|
2510
2594
|
this.intervals.delete(processId);
|
|
2511
2595
|
}
|
|
2512
2596
|
}
|
|
2513
|
-
/** Get current metrics for a process (one-shot, uses first active PID) */
|
|
2597
|
+
/** Get current metrics for a process (one-shot, uses first active PID or container name). */
|
|
2514
2598
|
async getMetrics(processId) {
|
|
2515
2599
|
const proc = processStore.get(processId);
|
|
2516
2600
|
if (!proc) return null;
|
|
2517
2601
|
const activePid = proc.commandProcesses.find((cp) => cp.pid !== null)?.pid;
|
|
2518
|
-
if (
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2602
|
+
if (activePid) {
|
|
2603
|
+
try {
|
|
2604
|
+
const stats = await pidusage(activePid);
|
|
2605
|
+
return {
|
|
2606
|
+
processId,
|
|
2607
|
+
cpu: stats.cpu,
|
|
2608
|
+
memory: stats.memory,
|
|
2609
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
2610
|
+
};
|
|
2611
|
+
} catch {
|
|
2612
|
+
}
|
|
2613
|
+
}
|
|
2614
|
+
const containerName = proc.commandProcesses.find((cp) => cp.containerName)?.containerName;
|
|
2615
|
+
if (containerName) {
|
|
2616
|
+
const stats = await getDockerStats(containerName);
|
|
2617
|
+
if (stats) {
|
|
2618
|
+
return { processId, ...stats, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
|
|
2619
|
+
}
|
|
2529
2620
|
}
|
|
2621
|
+
return null;
|
|
2530
2622
|
}
|
|
2531
2623
|
/** Stop all collection intervals */
|
|
2532
2624
|
stopAll() {
|
|
@@ -2548,8 +2640,8 @@ import { homedir as homedir4 } from "os";
|
|
|
2548
2640
|
import { z as z20 } from "zod";
|
|
2549
2641
|
|
|
2550
2642
|
// src/services/traefik-manager.ts
|
|
2551
|
-
import { spawn, execFile } from "child_process";
|
|
2552
|
-
import { mkdir as
|
|
2643
|
+
import { spawn, execFile as execFile2 } from "child_process";
|
|
2644
|
+
import { mkdir as mkdir3, writeFile as writeFile3, rename, chmod, access as access2, readFile } from "fs/promises";
|
|
2553
2645
|
import { X509Certificate } from "crypto";
|
|
2554
2646
|
import { join as join2 } from "path";
|
|
2555
2647
|
import { homedir as homedir3, platform } from "os";
|
|
@@ -2575,7 +2667,7 @@ var TraefikManager = class {
|
|
|
2575
2667
|
}
|
|
2576
2668
|
async atomicWrite(filePath, content) {
|
|
2577
2669
|
const tmpPath = filePath + ".tmp";
|
|
2578
|
-
await
|
|
2670
|
+
await writeFile3(tmpPath, content, "utf-8");
|
|
2579
2671
|
await rename(tmpPath, filePath);
|
|
2580
2672
|
}
|
|
2581
2673
|
async applyConfig(config) {
|
|
@@ -2584,7 +2676,7 @@ var TraefikManager = class {
|
|
|
2584
2676
|
await this.stop();
|
|
2585
2677
|
return;
|
|
2586
2678
|
}
|
|
2587
|
-
await
|
|
2679
|
+
await mkdir3(this.dynamicDir, { recursive: true });
|
|
2588
2680
|
await this.writeStaticConfig(config);
|
|
2589
2681
|
await this.regenerateDynamic();
|
|
2590
2682
|
await this.stop();
|
|
@@ -2629,7 +2721,7 @@ var TraefikManager = class {
|
|
|
2629
2721
|
await this.atomicWrite(this.staticConfigPath, yaml);
|
|
2630
2722
|
}
|
|
2631
2723
|
async regenerateDynamic() {
|
|
2632
|
-
await
|
|
2724
|
+
await mkdir3(this.dynamicDir, { recursive: true });
|
|
2633
2725
|
const processes = processStore.getAll();
|
|
2634
2726
|
const entries = processes.flatMap(
|
|
2635
2727
|
(p) => (p.serviceConfig.localUrls ?? []).map((lu) => ({ url: lu.url, port: lu.port }))
|
|
@@ -2714,7 +2806,7 @@ var TraefikManager = class {
|
|
|
2714
2806
|
}
|
|
2715
2807
|
async ensureAcmeJson() {
|
|
2716
2808
|
try {
|
|
2717
|
-
await
|
|
2809
|
+
await writeFile3(this.acmeStorePath, "{}", { flag: "wx" });
|
|
2718
2810
|
} catch (err) {
|
|
2719
2811
|
if (err.code !== "EEXIST") throw err;
|
|
2720
2812
|
}
|
|
@@ -2779,7 +2871,7 @@ var TraefikManager = class {
|
|
|
2779
2871
|
this.debounceTimer = null;
|
|
2780
2872
|
}
|
|
2781
2873
|
await new Promise((resolve) => {
|
|
2782
|
-
|
|
2874
|
+
execFile2("docker", ["rm", "-f", "runeya-traefik"], { timeout: 1e4 }, () => resolve());
|
|
2783
2875
|
});
|
|
2784
2876
|
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
2785
2877
|
}
|
|
@@ -2821,7 +2913,7 @@ var TraefikManager = class {
|
|
|
2821
2913
|
}
|
|
2822
2914
|
async getLogs(lines = 100) {
|
|
2823
2915
|
return new Promise((resolve) => {
|
|
2824
|
-
|
|
2916
|
+
execFile2("docker", ["logs", "--tail", String(lines), "runeya-traefik"], { timeout: 1e4 }, (err, stdout, stderr) => {
|
|
2825
2917
|
if (err) {
|
|
2826
2918
|
resolve("");
|
|
2827
2919
|
return;
|
|
@@ -2840,7 +2932,7 @@ var TraefikManager = class {
|
|
|
2840
2932
|
}
|
|
2841
2933
|
async forceRenewCert() {
|
|
2842
2934
|
if (!this.config?.enabled) throw new Error("Traefik non activ\xE9");
|
|
2843
|
-
await
|
|
2935
|
+
await writeFile3(this.acmeStorePath, "{}", "utf-8");
|
|
2844
2936
|
await chmod(this.acmeStorePath, 384);
|
|
2845
2937
|
await this.stop();
|
|
2846
2938
|
await this.spawnTraefik(this.config);
|
|
@@ -2872,7 +2964,7 @@ var TraefikManager = class {
|
|
|
2872
2964
|
let dockerAvailable = false;
|
|
2873
2965
|
try {
|
|
2874
2966
|
await new Promise((resolve, reject) => {
|
|
2875
|
-
|
|
2967
|
+
execFile2("docker", ["info", "--format", "{{.ServerVersion}}"], { timeout: 5e3 }, (err) => {
|
|
2876
2968
|
if (err) reject(err);
|
|
2877
2969
|
else resolve();
|
|
2878
2970
|
});
|
|
@@ -2892,7 +2984,7 @@ var TraefikManager = class {
|
|
|
2892
2984
|
if (dockerAvailable) {
|
|
2893
2985
|
try {
|
|
2894
2986
|
const output = await new Promise((resolve, reject) => {
|
|
2895
|
-
|
|
2987
|
+
execFile2("docker", ["inspect", "--format", "{{.State.Running}}", "runeya-traefik"], { timeout: 5e3 }, (err, stdout) => {
|
|
2896
2988
|
if (err) reject(err);
|
|
2897
2989
|
else resolve(stdout.trim());
|
|
2898
2990
|
});
|
|
@@ -3061,7 +3153,7 @@ var HealthChecker = class extends EventEmitter6 {
|
|
|
3061
3153
|
this.stopChecking(id);
|
|
3062
3154
|
}
|
|
3063
3155
|
}
|
|
3064
|
-
async checkHttp(processId,
|
|
3156
|
+
async checkHttp(processId, path3, timeout, maxRetries, method = "GET", expectedStatus = 200) {
|
|
3065
3157
|
const proc = processStore.get(processId);
|
|
3066
3158
|
if (!proc || proc.state !== "running") {
|
|
3067
3159
|
this.updateResult(processId, "unknown", 0);
|
|
@@ -3072,7 +3164,7 @@ var HealthChecker = class extends EventEmitter6 {
|
|
|
3072
3164
|
this.updateResult(processId, "unknown", 0);
|
|
3073
3165
|
return;
|
|
3074
3166
|
}
|
|
3075
|
-
const url = `http://localhost:${port}${
|
|
3167
|
+
const url = `http://localhost:${port}${path3}`;
|
|
3076
3168
|
let failures = this.failureCounts.get(processId) ?? 0;
|
|
3077
3169
|
try {
|
|
3078
3170
|
const response = await fetch(url, {
|
|
@@ -3390,6 +3482,7 @@ var ProcessManager = class extends EventEmitter7 {
|
|
|
3390
3482
|
commandId: cmd.id,
|
|
3391
3483
|
runnerProcess,
|
|
3392
3484
|
pid: null,
|
|
3485
|
+
containerName: runnerProcess.containerName ?? null,
|
|
3393
3486
|
exitCode: null
|
|
3394
3487
|
};
|
|
3395
3488
|
proc.commandProcesses = [...proc.commandProcesses, cmdProcess];
|
|
@@ -3475,6 +3568,7 @@ var ProcessManager = class extends EventEmitter7 {
|
|
|
3475
3568
|
commandId: cmd.id,
|
|
3476
3569
|
runnerProcess,
|
|
3477
3570
|
pid: runnerProcess.pid ?? null,
|
|
3571
|
+
containerName: runnerProcess.containerName ?? null,
|
|
3478
3572
|
exitCode: null
|
|
3479
3573
|
};
|
|
3480
3574
|
proc.commandProcesses = [...proc.commandProcesses, cmdProcess];
|
|
@@ -3489,6 +3583,8 @@ var ProcessManager = class extends EventEmitter7 {
|
|
|
3489
3583
|
this.consoleLogSource.attach(processId, runnerProcess.stdout, runnerProcess.stderr, runnerProcess.pid ?? null);
|
|
3490
3584
|
if (runnerProcess.pid) {
|
|
3491
3585
|
this.metricsCollector.startCollecting(processId, runnerProcess.pid);
|
|
3586
|
+
} else if (runnerProcess.containerName) {
|
|
3587
|
+
this.metricsCollector.startCollectingDocker(processId, runnerProcess.containerName);
|
|
3492
3588
|
}
|
|
3493
3589
|
runnerProcess.exitPromise.then(({ exitCode, signal, error }) => {
|
|
3494
3590
|
const current = processStore.get(processId);
|
|
@@ -3650,9 +3746,26 @@ var ProcessManager = class extends EventEmitter7 {
|
|
|
3650
3746
|
const proc = this.activeShortcuts.get(key);
|
|
3651
3747
|
if (proc) proc.kill("SIGTERM");
|
|
3652
3748
|
}
|
|
3653
|
-
cancelAdHocCommand(processId) {
|
|
3654
|
-
const
|
|
3655
|
-
if (
|
|
3749
|
+
cancelAdHocCommand(processId, commandId) {
|
|
3750
|
+
const targets = [];
|
|
3751
|
+
if (commandId) {
|
|
3752
|
+
const key = `${processId}:${commandId}`;
|
|
3753
|
+
const proc = this.activeAdHocCommands.get(key);
|
|
3754
|
+
if (proc) targets.push(proc);
|
|
3755
|
+
} else {
|
|
3756
|
+
for (const [key, proc] of this.activeAdHocCommands) {
|
|
3757
|
+
if (key.startsWith(`${processId}:`)) targets.push(proc);
|
|
3758
|
+
}
|
|
3759
|
+
}
|
|
3760
|
+
for (const proc of targets) {
|
|
3761
|
+
proc.kill("SIGTERM");
|
|
3762
|
+
void Promise.race([
|
|
3763
|
+
proc.exitPromise,
|
|
3764
|
+
new Promise((resolve) => setTimeout(resolve, 3e3))
|
|
3765
|
+
]).then((result) => {
|
|
3766
|
+
if (result === void 0) proc.kill("SIGKILL");
|
|
3767
|
+
});
|
|
3768
|
+
}
|
|
3656
3769
|
}
|
|
3657
3770
|
/** Execute a shortcut command and stream its output as logs for the given process */
|
|
3658
3771
|
async executeShortcut(processId, shortcut) {
|
|
@@ -3692,7 +3805,7 @@ var ProcessManager = class extends EventEmitter7 {
|
|
|
3692
3805
|
return { exitCode };
|
|
3693
3806
|
}
|
|
3694
3807
|
/** Execute an ad-hoc command and stream its output as logs for the given process */
|
|
3695
|
-
async executeAdHocCommand(processId, command, cwd) {
|
|
3808
|
+
async executeAdHocCommand(processId, command, cwd, commandId) {
|
|
3696
3809
|
const proc = processStore.get(processId);
|
|
3697
3810
|
if (!proc) throw new Error(`Process ${processId} not found`);
|
|
3698
3811
|
const jsParsers = proc.serviceConfig.resolvedLogParsers ?? [];
|
|
@@ -3712,10 +3825,11 @@ var ProcessManager = class extends EventEmitter7 {
|
|
|
3712
3825
|
this.consoleLogSource.addSystemLog(processId, `Failed to start: ${err instanceof Error ? err.message : String(err)}`, "error", { id: randomUUID3(), type: "command-fail", header: command, state: "self" });
|
|
3713
3826
|
return { exitCode: 1 };
|
|
3714
3827
|
}
|
|
3715
|
-
|
|
3828
|
+
const cmdKey = `${processId}:${commandId ?? randomUUID3()}`;
|
|
3829
|
+
this.activeAdHocCommands.set(cmdKey, runnerProcess);
|
|
3716
3830
|
this.consoleLogSource.attach(processId, runnerProcess.stdout, runnerProcess.stderr, runnerProcess.pid ?? null);
|
|
3717
3831
|
const { exitCode, signal, error } = await runnerProcess.exitPromise;
|
|
3718
|
-
this.activeAdHocCommands.delete(
|
|
3832
|
+
this.activeAdHocCommands.delete(cmdKey);
|
|
3719
3833
|
if (signal) {
|
|
3720
3834
|
this.consoleLogSource.addSystemLog(processId, `command cancelled`, "info");
|
|
3721
3835
|
} else if (exitCode !== 0) {
|
|
@@ -3967,17 +4081,18 @@ var processRouter = router({
|
|
|
3967
4081
|
return { success: true };
|
|
3968
4082
|
}),
|
|
3969
4083
|
/** Cancel a running ad-hoc command */
|
|
3970
|
-
cancelAdHocCommand: protectedProcedure.input(z22.object({ id: z22.string().max(128) })).mutation(({ input }) => {
|
|
3971
|
-
processManager.cancelAdHocCommand(input.id);
|
|
4084
|
+
cancelAdHocCommand: protectedProcedure.input(z22.object({ id: z22.string().max(128), commandId: z22.string().max(128).optional() })).mutation(({ input }) => {
|
|
4085
|
+
processManager.cancelAdHocCommand(input.id, input.commandId);
|
|
3972
4086
|
return { success: true };
|
|
3973
4087
|
}),
|
|
3974
4088
|
/** Execute an ad-hoc command and stream output into the process log */
|
|
3975
4089
|
executeAdHocCommand: protectedProcedure.input(z22.object({
|
|
3976
4090
|
id: z22.string().max(128),
|
|
3977
4091
|
command: z22.string().min(1).max(4096),
|
|
3978
|
-
cwd: z22.string().max(4096).optional()
|
|
4092
|
+
cwd: z22.string().max(4096).optional(),
|
|
4093
|
+
commandId: z22.string().max(128).optional()
|
|
3979
4094
|
})).mutation(async ({ input }) => {
|
|
3980
|
-
const result = await processManager.executeAdHocCommand(input.id, input.command, input.cwd);
|
|
4095
|
+
const result = await processManager.executeAdHocCommand(input.id, input.command, input.cwd, input.commandId);
|
|
3981
4096
|
return result;
|
|
3982
4097
|
}),
|
|
3983
4098
|
/** List active log source types for a process */
|
|
@@ -4113,9 +4228,9 @@ var processRouter = router({
|
|
|
4113
4228
|
|
|
4114
4229
|
// src/trpc/routers/health.ts
|
|
4115
4230
|
import { networkInterfaces as networkInterfaces2 } from "os";
|
|
4116
|
-
import { execFile as
|
|
4231
|
+
import { execFile as execFile3 } from "child_process";
|
|
4117
4232
|
import { promisify } from "util";
|
|
4118
|
-
var execFileAsync = promisify(
|
|
4233
|
+
var execFileAsync = promisify(execFile3);
|
|
4119
4234
|
var startedAt = Date.now();
|
|
4120
4235
|
function getLanIp2() {
|
|
4121
4236
|
const nets = networkInterfaces2();
|
|
@@ -4280,12 +4395,12 @@ var terminalRouter = router({
|
|
|
4280
4395
|
// src/trpc/routers/git.ts
|
|
4281
4396
|
import { z as z24 } from "zod";
|
|
4282
4397
|
import { TRPCError as TRPCError4 } from "@trpc/server";
|
|
4283
|
-
import { execFile as
|
|
4398
|
+
import { execFile as execFile4, spawn as spawn3 } from "child_process";
|
|
4284
4399
|
import { promisify as promisify2 } from "util";
|
|
4285
4400
|
import { existsSync, watch as fsWatch } from "fs";
|
|
4286
4401
|
import { promises as fsPromises2 } from "fs";
|
|
4287
4402
|
import { join as join4, resolve as resolvePath } from "path";
|
|
4288
|
-
var execFileAsync2 = promisify2(
|
|
4403
|
+
var execFileAsync2 = promisify2(execFile4);
|
|
4289
4404
|
var GIT_TIMEOUT = 15e3;
|
|
4290
4405
|
var DIFF_MAX_BYTES = 512 * 1024;
|
|
4291
4406
|
var CWD_SCHEMA = z24.string().min(1).max(4096);
|
|
@@ -4716,6 +4831,26 @@ import { spawn as spawn4 } from "child_process";
|
|
|
4716
4831
|
import { EventEmitter as EventEmitter9 } from "events";
|
|
4717
4832
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
4718
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
|
+
}
|
|
4719
4854
|
var MAX_BUFFER_LINES = 1e5;
|
|
4720
4855
|
var MAX_CONCURRENT_SPAWNS = 10;
|
|
4721
4856
|
var CLEANUP_INTERVAL_MS = 6e4;
|
|
@@ -4737,13 +4872,16 @@ var AiSpawnManager = class {
|
|
|
4737
4872
|
const args = [...opts.args];
|
|
4738
4873
|
if (opts.enableMcp && opts.cli === "claude") {
|
|
4739
4874
|
try {
|
|
4740
|
-
const mcpServerPath =
|
|
4875
|
+
const mcpServerPath = resolveMcpServerPath();
|
|
4741
4876
|
const mcpConfig = JSON.stringify({
|
|
4742
4877
|
mcpServers: {
|
|
4743
4878
|
runeya: {
|
|
4744
4879
|
command: "node",
|
|
4745
4880
|
args: [mcpServerPath],
|
|
4746
|
-
env:
|
|
4881
|
+
env: {
|
|
4882
|
+
...opts.mcpApiBaseUrl ? { RUNEYA_BASE_URL: opts.mcpApiBaseUrl } : {},
|
|
4883
|
+
...opts.mcpApiToken ? { RUNEYA_API_TOKEN: opts.mcpApiToken } : {}
|
|
4884
|
+
}
|
|
4747
4885
|
}
|
|
4748
4886
|
}
|
|
4749
4887
|
});
|
|
@@ -4765,10 +4903,12 @@ var AiSpawnManager = class {
|
|
|
4765
4903
|
exitCode: null,
|
|
4766
4904
|
buffer: [],
|
|
4767
4905
|
proc,
|
|
4906
|
+
ptyProc: null,
|
|
4768
4907
|
emitter,
|
|
4769
4908
|
createdAt: Date.now(),
|
|
4770
4909
|
doneAt: null,
|
|
4771
|
-
acked: false
|
|
4910
|
+
acked: false,
|
|
4911
|
+
lastChunkAt: null
|
|
4772
4912
|
};
|
|
4773
4913
|
this.spawns.set(spawnId, entry);
|
|
4774
4914
|
if (opts.stdinData) {
|
|
@@ -4853,8 +4993,119 @@ var AiSpawnManager = class {
|
|
|
4853
4993
|
}
|
|
4854
4994
|
return true;
|
|
4855
4995
|
}
|
|
4996
|
+
if (entry.ptyProc) {
|
|
4997
|
+
try {
|
|
4998
|
+
entry.ptyProc.kill();
|
|
4999
|
+
} catch {
|
|
5000
|
+
}
|
|
5001
|
+
return true;
|
|
5002
|
+
}
|
|
4856
5003
|
return false;
|
|
4857
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
|
+
}
|
|
4858
5109
|
list() {
|
|
4859
5110
|
return [...this.spawns.values()].map((e) => ({
|
|
4860
5111
|
spawnId: e.spawnId,
|
|
@@ -4863,7 +5114,8 @@ var AiSpawnManager = class {
|
|
|
4863
5114
|
exitCode: e.exitCode,
|
|
4864
5115
|
bufferLength: e.buffer.length,
|
|
4865
5116
|
createdAt: e.createdAt,
|
|
4866
|
-
doneAt: e.doneAt
|
|
5117
|
+
doneAt: e.doneAt,
|
|
5118
|
+
lastChunkAt: e.lastChunkAt
|
|
4867
5119
|
}));
|
|
4868
5120
|
}
|
|
4869
5121
|
ack(spawnId) {
|
|
@@ -4878,6 +5130,9 @@ var AiSpawnManager = class {
|
|
|
4878
5130
|
entry.buffer.shift();
|
|
4879
5131
|
}
|
|
4880
5132
|
entry.buffer.push(chunk);
|
|
5133
|
+
if (chunk.type === "stdout" || chunk.type === "stderr" || chunk.type === "pty-data") {
|
|
5134
|
+
entry.lastChunkAt = Date.now();
|
|
5135
|
+
}
|
|
4881
5136
|
entry.emitter.emit("chunk");
|
|
4882
5137
|
if (chunk.type === "exit") {
|
|
4883
5138
|
entry.emitter.emit("done");
|
|
@@ -4910,13 +5165,19 @@ var AiSpawnManager = class {
|
|
|
4910
5165
|
} catch {
|
|
4911
5166
|
}
|
|
4912
5167
|
}
|
|
5168
|
+
if (entry.ptyProc) {
|
|
5169
|
+
try {
|
|
5170
|
+
entry.ptyProc.kill();
|
|
5171
|
+
} catch {
|
|
5172
|
+
}
|
|
5173
|
+
}
|
|
4913
5174
|
}
|
|
4914
5175
|
}
|
|
4915
5176
|
};
|
|
4916
5177
|
var aiSpawnManager = new AiSpawnManager();
|
|
4917
5178
|
|
|
4918
5179
|
// src/services/codex-app-server-manager.ts
|
|
4919
|
-
import { spawn as
|
|
5180
|
+
import { spawn as spawn6 } from "child_process";
|
|
4920
5181
|
import { createInterface as createInterface2 } from "readline";
|
|
4921
5182
|
import { EventEmitter as EventEmitter10 } from "events";
|
|
4922
5183
|
var REQUEST_TIMEOUT_MS = 3e5;
|
|
@@ -4944,7 +5205,7 @@ var CodexAppServerManager = class extends EventEmitter10 {
|
|
|
4944
5205
|
}
|
|
4945
5206
|
}
|
|
4946
5207
|
async doConnect() {
|
|
4947
|
-
this.proc =
|
|
5208
|
+
this.proc = spawn6("codex", ["app-server"], {
|
|
4948
5209
|
stdio: ["pipe", "pipe", "pipe"],
|
|
4949
5210
|
env: { ...process.env, ...this.extraEnv }
|
|
4950
5211
|
});
|
|
@@ -5055,7 +5316,142 @@ var CodexAppServerManager = class extends EventEmitter10 {
|
|
|
5055
5316
|
};
|
|
5056
5317
|
var codexAppServerManager = new CodexAppServerManager();
|
|
5057
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
|
+
|
|
5058
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;
|
|
5059
5455
|
var aiRouter = router({
|
|
5060
5456
|
/** Spawn an AI CLI process. Returns a spawnId for streaming. */
|
|
5061
5457
|
spawn: protectedProcedure.input(z25.object({
|
|
@@ -5086,6 +5482,71 @@ var aiRouter = router({
|
|
|
5086
5482
|
});
|
|
5087
5483
|
}
|
|
5088
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
|
+
}),
|
|
5089
5550
|
/** Kill a running AI spawn. */
|
|
5090
5551
|
kill: protectedProcedure.input(z25.object({ spawnId: z25.string().max(128) })).mutation(({ input }) => {
|
|
5091
5552
|
const killed = aiSpawnManager.kill(input.spawnId);
|