@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.
- package/agent/index.js +354 -8
- package/agent/index.js.map +1 -1
- package/agent-manager-V47DLMYP-26VYXTSG.js +8 -0
- package/{chunk-DODGBBTE.js → chunk-6547GLUJ.js} +24 -7
- package/chunk-6547GLUJ.js.map +1 -0
- package/{dist-HZBWBT6S.js → dist-2H7XZQCV.js} +1233 -379
- package/dist-2H7XZQCV.js.map +1 -0
- package/index.js +5 -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-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-U2le7KBO.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-BPEaZrXC.js → EditorIcon-DOV6wP8X.js} +2 -2
- package/web/assets/{EmptyState.vue-Be8_w2rR.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-7rLK-ucb.js → KanbanBoardPage-DzFRgXlJ.js} +6 -6
- 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/{ProcessMetrics-CLa8mdh2.js → ProcessMetrics-9RjmvDOk.js} +2 -2
- 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-qR90sHHe.js → ScalarIconEyeSlash.vue-CwJnZ-zD.js} +1 -1
- package/web/assets/{ScalarIconTrash.vue-Ll6Zw6_W.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/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/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-CAixUN8B.js → ViewLayoutContent.vue-DP_GK_Ip.js} +1 -1
- 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-Do-EC8XW.js → autocomplete-CK9Z1-Wz.js} +4 -4
- package/web/assets/card-DadsU5ZI.js +32 -0
- package/web/assets/{checkbox-C2hHZbMO.js → checkbox-4z5ftHhs.js} +3 -3
- package/web/assets/{chip-CD3EONN7.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-BzsFOrHs.js → cssMode-CIUATcSv.js} +1 -1
- package/web/assets/dist-BLSATgV0.js +1 -0
- package/web/assets/{dist-CiBpb7F_.js → dist-Cp1hgSqY.js} +2 -2
- package/web/assets/{dist-BmCpMB7W.js → dist-CpE_ZYIQ.js} +1 -1
- package/web/assets/dist-DR4LqG1l.js +192 -0
- package/web/assets/{divider-C7F2jaMI.js → divider-D-vBLTer.js} +2 -2
- package/web/assets/editor.store-COpS72tz.js +1 -0
- package/web/assets/{fieldset-kJDAoVaz.js → fieldset-CSlJxjpZ.js} +2 -2
- package/web/assets/{freemarker2-qyf3DfQl.js → freemarker2-Dsxb69Av.js} +1 -1
- package/web/assets/{handlebars-Dt_j38Ok.js → handlebars-ChbvHuc-.js} +1 -1
- package/web/assets/{html-BM6JBSDe.js → html-DOIF2Zpc.js} +1 -1
- package/web/assets/{htmlMode-BWrj-eTf.js → htmlMode-DKICvQwb.js} +1 -1
- package/web/assets/index-A6eiSk8H.css +1 -0
- package/web/assets/{index-Dviyssba.js → index-C0UzL9Y-.js} +281 -246
- package/web/assets/{javascript-Nwj2LVeE.js → javascript-Bmt68E8X.js} +1 -1
- package/web/assets/{jsonMode-xQ2R28Fq.js → jsonMode-CYcvn9c0.js} +1 -1
- package/web/assets/{keyboard-CidI6qyD.js → keyboard-DZklF_AY.js} +2 -2
- package/web/assets/{lib-Bpt_o5V9.js → lib-B5TdN_ca.js} +1 -1
- package/web/assets/{library-CcEqwrWR.js → library-DtrGq8p8.js} +1 -1
- package/web/assets/{liquid-CNc1r-Ln.js → liquid-3ot_oRqd.js} +1 -1
- package/web/assets/{mdx-D5yTipSh.js → mdx-Cm1rlDNM.js} +1 -1
- package/web/assets/{mediaTypes-pLZCmXiT.js → mediaTypes-Bz4C7Sle.js} +2 -2
- package/web/assets/{message-B6M86BRU.js → message-DFReN7Fq.js} +2 -2
- package/web/assets/{minus-wesZvWq4.js → minus-t_EQEzUj.js} +2 -2
- package/web/assets/{multiselect-CHEmtEFg.js → multiselect-BZbgA1pl.js} +3 -3
- package/web/assets/{password-ISam7EYg.js → password-D82un95s.js} +4 -4
- package/web/assets/{plus-BBMmFC_c.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-BOLsEvIQ.js → python-BuQCsdKw.js} +1 -1
- package/web/assets/{radiobutton-DwoOAEAF.js → radiobutton-Btattklk.js} +2 -2
- package/web/assets/{razor-JsBDv4HY.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-DBInUEl5.js → tabpanel-CIyzJ44J.js} +3 -3
- package/web/assets/{tag-CQlI4fJK.js → tag-DV-szbCr.js} +2 -2
- package/web/assets/trpc-wp_QsEqG.js +1 -0
- package/web/assets/{tsMode-C7uad5vV.js → tsMode-ChD0IpIg.js} +1 -1
- package/web/assets/{typescript-C2IozRX9.js → typescript-BRYpIqKe.js} +1 -1
- package/web/assets/urls-CoBMqtDH.js +12 -0
- package/web/assets/{use-tree-walker-CJHEPXgB.js → use-tree-walker-M4-Gn01v.js} +1 -1
- package/web/assets/useAiChatDrawer-BhlTNoXz.js +1 -0
- package/web/assets/{useClipboard-DtO-z5Ls.js → useClipboard-Cro2wlg3.js} +1 -1
- package/web/assets/{useLayout-D-FCdkqa.js → useLayout-BciG4r-1.js} +1 -1
- package/web/assets/{usePluginManager-CPTBi3rk.js → usePluginManager-BonTfGSN.js} +1 -1
- package/web/assets/useSidebar-77_u4hef.js +1 -0
- package/web/assets/{vue-router-DSROI5EH.js → vue-router-DdBypSuY.js} +1 -1
- package/web/assets/{xml-DtJwg-5S.js → xml-Cz29Bxul.js} +1 -1
- package/web/assets/{yaml-sPGHMYDm.js → yaml-CiZl2tNW.js} +1 -1
- package/web/index.html +2 -2
- package/agent-manager-A4E5CXFT-6PJDFN7J.js +0 -8
- package/chunk-DODGBBTE.js.map +0 -1
- package/dist-HZBWBT6S.js.map +0 -1
- package/web/assets/AddressBar.vue-D_8vQPIF.js +0 -1
- package/web/assets/AgentScalarChatInterface.vue-Be-LbA03.js +0 -13
- package/web/assets/AgentTerminalPage-BZmmd1H1.js +0 -36
- package/web/assets/AgentTerminalPage-EX_n6P3x.css +0 -1
- package/web/assets/AiChatPage-kTk6yC6d.js +0 -1
- package/web/assets/AppLayout-jbNML_m4.js +0 -1
- package/web/assets/AuditPage-S4kDjrZ5.js +0 -1
- package/web/assets/CodeInput.vue-nIhSM0FX.js +0 -1
- package/web/assets/Collection.vue-CkwnxBu4.js +0 -1
- package/web/assets/CollectionAuthentication.vue-CiZinGpr.js +0 -1
- package/web/assets/CollectionCookies.vue-BLEJqAhX.js +0 -1
- package/web/assets/CollectionEnvironment.vue-3bWtuG1B.js +0 -1
- package/web/assets/CollectionOverview.vue-BheZFfD3.js +0 -1
- package/web/assets/CollectionScripts.vue-CsY6tWxk.js +0 -1
- package/web/assets/CollectionServers.vue-Ja8mYDaK.js +0 -1
- package/web/assets/CollectionSettings.vue-DOB9JUg8.js +0 -1
- package/web/assets/CollectionSync.vue-B-uKwdTU.js +0 -1
- package/web/assets/CommandActionInput.vue-BBijVqe7.js +0 -1
- package/web/assets/Cookies.vue-DgVzSolJ.js +0 -1
- package/web/assets/DashboardPage-BwZPpURp.js +0 -1
- package/web/assets/DataTable.vue-DXTWz2Vi.js +0 -1
- package/web/assets/DataTableCheckbox.vue-BA5yHmxd.js +0 -1
- package/web/assets/DataTableInput.vue-DpeNUUXc.js +0 -1
- package/web/assets/DeleteSidebarListElement.vue-C2SV2geU.js +0 -1
- package/web/assets/EditSidebarListElement.vue-DvvYjTMO.js +0 -1
- package/web/assets/Environment.vue-D0PdeVIp.js +0 -1
- package/web/assets/EnvironmentForm-Dm3dFrSU.js +0 -108
- package/web/assets/EnvironmentFormPage-ByVELlly.js +0 -1
- package/web/assets/EnvironmentListPage-DvaTK4NF.js +0 -1
- package/web/assets/EnvironmentModal.vue-Bssf0U5X.js +0 -1
- package/web/assets/EnvironmentSelector-4kpQpg5e.js +0 -1
- package/web/assets/Form.vue-Dv4a31zh.js +0 -1
- package/web/assets/IconSelector.vue-BsYvff6K.js +0 -1
- package/web/assets/KanbanListPage-Dn35VrDc.js +0 -1
- package/web/assets/LaunchProjectPage-Byemtd9C.js +0 -1
- package/web/assets/LaunchServicesPage-CHiV6T5Y.js +0 -1
- package/web/assets/LogViewer-KtrKiUZw.js +0 -3
- package/web/assets/ProcessControls-DfFxf6jZ.js +0 -1
- package/web/assets/ProcessDetailPage-BOI85Xo7.js +0 -1
- package/web/assets/ProjectDetailPage-CTEt0DSq.js +0 -1
- package/web/assets/ProjectListPage-BrTIxp9K.js +0 -1
- package/web/assets/RandomJobTestPage-D2OB5pqD.js +0 -2
- package/web/assets/Request.vue-DHQd9eyp.js +0 -1
- package/web/assets/RequestAuth.vue-CEVOgzEk.js +0 -1
- package/web/assets/RequestRoot.vue-BEtC7IEP.js +0 -19
- package/web/assets/ScalarAsciiArt.vue-CyYmv9BB.js +0 -2
- package/web/assets/ScenarioEditorPage-xCx9aW1X.js +0 -14
- package/web/assets/ServerVariablesForm.vue-D9sjD4AT.js +0 -1
- package/web/assets/ServiceControlsBar-DKYIgScL.js +0 -1
- package/web/assets/ServiceDetailPage-B5qBCc9A.js +0 -2
- package/web/assets/ServiceFormPage-BNpWmyj_.js +0 -1
- package/web/assets/Settings.vue-DWPIjz57.js +0 -1
- package/web/assets/SettingsPage-C5lWJT0Z.js +0 -225
- package/web/assets/SetupKeyPage-BiqO4PQr.js +0 -1
- package/web/assets/SetupPage-FEUuQSQ2.js +0 -1
- package/web/assets/Sidebar.vue-DVHNacfA.js +0 -1
- package/web/assets/SidebarButton.vue-C4QDgSym.js +0 -1
- package/web/assets/SidebarListElement.vue-Ch1aI_Bz.js +0 -1
- package/web/assets/UnlockPage-Dhg0hoP-.js +0 -1
- package/web/assets/VariablesTable-DFJHJ9DF.js +0 -1
- package/web/assets/ViewLayout.vue-svdAMKVP.js +0 -1
- package/web/assets/ViewLayoutSection.vue-C9VAyihF.js +0 -1
- package/web/assets/active-entities-Dpd4ny38.js +0 -1
- package/web/assets/api-reference-C9jD1TQ9.js +0 -1
- package/web/assets/card-CeTOcGyS.js +0 -32
- package/web/assets/column-xfOef4Rh.js +0 -763
- package/web/assets/core-Dq8cnTTd.js +0 -1
- package/web/assets/dist-CQoPOD_o.js +0 -192
- package/web/assets/dist-US_vG96F.js +0 -1
- package/web/assets/editor.store-Dzhoqquh.js +0 -1
- package/web/assets/index-DXutsd9M.css +0 -1
- package/web/assets/pretty-ms-Bj2IaA2r.js +0 -202
- package/web/assets/process.store-cvjJzD3H.js +0 -1
- package/web/assets/project.store-C94-7i6c.js +0 -1
- package/web/assets/router-BgHCboHx.js +0 -1
- package/web/assets/settings.store-BGScNTnu.js +0 -1
- package/web/assets/store-a88gBDkh.js +0 -1840
- package/web/assets/trpc-CgAubgRH.js +0 -1
- package/web/assets/urls-BuNgEu0U.js +0 -12
- package/web/assets/useAiChatDrawer-D6TRHaNu.js +0 -1
- package/web/assets/useSidebar-BoK12gD1.js +0 -1
- /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,
|
|
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}${
|
|
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 =
|
|
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:
|
|
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
|
|
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 =
|
|
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);
|