@bytespell/shella 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/cli.js +277 -80
- package/dist/bin/cli.js.map +1 -1
- package/dist/index.js +269 -79
- package/dist/index.js.map +1 -1
- package/dist/public/assets/{_baseUniq-ofDPcIU7.js → _baseUniq-xMBLm_vj.js} +1 -1
- package/{public/assets/arc-CN1QbtAQ.js → dist/public/assets/arc-CCivY36l.js} +1 -1
- package/{public/assets/architectureDiagram-VXUJARFQ-B7xrwB3a.js → dist/public/assets/architectureDiagram-VXUJARFQ-Cx1ftnZs.js} +1 -1
- package/{public/assets/blockDiagram-VD42YOAC-ByLGlNws.js → dist/public/assets/blockDiagram-VD42YOAC-Dd5J4pAa.js} +1 -1
- package/dist/public/assets/{c4Diagram-YG6GDRKO-YpYx4Aj8.js → c4Diagram-YG6GDRKO-C4yoJFk1.js} +1 -1
- package/dist/public/assets/channel-CgkYY8Ci.js +1 -0
- package/dist/public/assets/{chunk-4BX2VUAB-D0zp96k1.js → chunk-4BX2VUAB-CiImuKHD.js} +1 -1
- package/dist/public/assets/{chunk-55IACEB6-C5GJeIrO.js → chunk-55IACEB6-V6l1i-_P.js} +1 -1
- package/{public/assets/chunk-B4BG7PRW-Ci17wd3H.js → dist/public/assets/chunk-B4BG7PRW-DU8Wql9S.js} +1 -1
- package/{public/assets/chunk-DI55MBZ5-B2XMqfQC.js → dist/public/assets/chunk-DI55MBZ5-B_Jw-lhj.js} +1 -1
- package/dist/public/assets/{chunk-FMBD7UC4-Crk5_wey.js → chunk-FMBD7UC4-C1LlA37K.js} +1 -1
- package/dist/public/assets/{chunk-QN33PNHL-DqQoCDuG.js → chunk-QN33PNHL-CcgyTGxJ.js} +1 -1
- package/dist/public/assets/{chunk-QZHKN3VN-DtbXtmmy.js → chunk-QZHKN3VN-C2H0lOPM.js} +1 -1
- package/dist/public/assets/{chunk-TZMSLE5B-Boi_YcuZ.js → chunk-TZMSLE5B-Cp4Dpzkh.js} +1 -1
- package/dist/public/assets/classDiagram-2ON5EDUG-BuYVNwmc.js +1 -0
- package/dist/public/assets/classDiagram-v2-WZHVMYZB-BuYVNwmc.js +1 -0
- package/dist/public/assets/clone-mkrd6lC9.js +1 -0
- package/dist/public/assets/{code-block-IT6T5CEO-BAcnOjsj.js → code-block-IT6T5CEO-DOOuyfxG.js} +1 -1
- package/dist/public/assets/{cose-bilkent-S5V4N54A-DAIcBIuP.js → cose-bilkent-S5V4N54A-DefjjRca.js} +1 -1
- package/dist/public/assets/{dagre-6UL2VRFP-zz51dmH0.js → dagre-6UL2VRFP-hHpxpOKX.js} +1 -1
- package/dist/public/assets/demo.svg +1 -0
- package/dist/public/assets/{diagram-PSM6KHXK-bVpD6rI7.js → diagram-PSM6KHXK-ZgZ2X0Q-.js} +1 -1
- package/dist/public/assets/{diagram-QEK2KX5R-I8YB5Wm0.js → diagram-QEK2KX5R-gCeAqKj1.js} +1 -1
- package/dist/public/assets/{diagram-S2PKOQOG-D1xlOPWJ.js → diagram-S2PKOQOG-9IyVqMFa.js} +1 -1
- package/{public/assets/erDiagram-Q2GNP2WA-DEdjbB3m.js → dist/public/assets/erDiagram-Q2GNP2WA-Dzm33cik.js} +1 -1
- package/{public/assets/flowDiagram-NV44I4VS-BBCU2dfK.js → dist/public/assets/flowDiagram-NV44I4VS-BamNhi0g.js} +1 -1
- package/dist/public/assets/{ganttDiagram-JELNMOA3-B0jnifD_.js → ganttDiagram-JELNMOA3-CrECl9wX.js} +1 -1
- package/dist/public/assets/{gitGraphDiagram-NY62KEGX-BX21wvJS.js → gitGraphDiagram-NY62KEGX-C7_E64uK.js} +1 -1
- package/dist/public/assets/{graph-BE95p5Ca.js → graph-CtTAhETf.js} +1 -1
- package/dist/public/assets/index-Czr2q0NP.css +1 -0
- package/dist/public/assets/index-kEIJA0pC.js +1781 -0
- package/dist/public/assets/{infoDiagram-WHAUD3N6-CrU0UXwW.js → infoDiagram-WHAUD3N6-CLOougXO.js} +1 -1
- package/dist/public/assets/{journeyDiagram-XKPGCS4Q-DzukVB-1.js → journeyDiagram-XKPGCS4Q-g0dISD-I.js} +1 -1
- package/{public/assets/kanban-definition-3W4ZIXB7-CJVLdxxJ.js → dist/public/assets/kanban-definition-3W4ZIXB7-DFIVrLyR.js} +1 -1
- package/dist/public/assets/{layout-CM_3juMX.js → layout-DolajoeL.js} +1 -1
- package/dist/public/assets/{linear-BXRjo7t5.js → linear-B5Hf7uIN.js} +1 -1
- package/dist/public/assets/{mermaid.core-Hp60xAyJ.js → mermaid.core-DqP3HtOk.js} +5 -5
- package/dist/public/assets/{min-oqogeQSX.js → min-UFvm8GLY.js} +1 -1
- package/dist/public/assets/{mindmap-definition-VGOIOE7T-CCgMWgfM.js → mindmap-definition-VGOIOE7T-CnSTRcIt.js} +1 -1
- package/dist/public/assets/{pieDiagram-ADFJNKIX-DAkNkjx-.js → pieDiagram-ADFJNKIX-CuMH9Po8.js} +1 -1
- package/{public/assets/quadrantDiagram-AYHSOK5B-CPEqSA2x.js → dist/public/assets/quadrantDiagram-AYHSOK5B-6i0SX3Xo.js} +1 -1
- package/dist/public/assets/{requirementDiagram-UZGBJVZJ-jOv297_A.js → requirementDiagram-UZGBJVZJ-ChwO2HU-.js} +1 -1
- package/dist/public/assets/{sankeyDiagram-TZEHDZUN-CwvAKmpc.js → sankeyDiagram-TZEHDZUN-DG-8crEL.js} +1 -1
- package/dist/public/assets/{sequenceDiagram-WL72ISMW-D_WZ2ogT.js → sequenceDiagram-WL72ISMW-BQH_OfEp.js} +1 -1
- package/{public/assets/stateDiagram-FKZM4ZOC-tqYMmK3v.js → dist/public/assets/stateDiagram-FKZM4ZOC-CBOkbVQn.js} +1 -1
- package/dist/public/assets/stateDiagram-v2-4FDKWEC3-BqHz04Bh.js +1 -0
- package/{public/assets/timeline-definition-IT6M3QCI-BIqJkdQ0.js → dist/public/assets/timeline-definition-IT6M3QCI-CkNd8y6W.js} +1 -1
- package/dist/public/assets/{treemap-KMMF4GRG-CmJM6xaw.js → treemap-KMMF4GRG-D6z_eudj.js} +1 -1
- package/dist/public/assets/{xychartDiagram-PRI3JC2R-D7-tZ8iR.js → xychartDiagram-PRI3JC2R-B5wk4XRt.js} +1 -1
- package/dist/public/favicon-16.ico +0 -0
- package/dist/public/favicon-32.ico +0 -0
- package/dist/public/favicon-48.ico +0 -0
- package/dist/public/favicon.svg +4 -0
- package/dist/public/index.html +2 -2
- package/dist/public/logo-1024.png +0 -0
- package/dist/public/logo-128.png +0 -0
- package/dist/public/logo-16.png +0 -0
- package/dist/public/logo-256.png +0 -0
- package/dist/public/logo-32.png +0 -0
- package/dist/public/logo-48.png +0 -0
- package/dist/public/logo-512.png +0 -0
- package/dist/public/logo-64.png +0 -0
- package/package.json +6 -2
- package/public/assets/{_baseUniq-ofDPcIU7.js → _baseUniq-xMBLm_vj.js} +1 -1
- package/{dist/public/assets/arc-CN1QbtAQ.js → public/assets/arc-CCivY36l.js} +1 -1
- package/{dist/public/assets/architectureDiagram-VXUJARFQ-B7xrwB3a.js → public/assets/architectureDiagram-VXUJARFQ-Cx1ftnZs.js} +1 -1
- package/{dist/public/assets/blockDiagram-VD42YOAC-ByLGlNws.js → public/assets/blockDiagram-VD42YOAC-Dd5J4pAa.js} +1 -1
- package/public/assets/{c4Diagram-YG6GDRKO-YpYx4Aj8.js → c4Diagram-YG6GDRKO-C4yoJFk1.js} +1 -1
- package/public/assets/channel-CgkYY8Ci.js +1 -0
- package/public/assets/{chunk-4BX2VUAB-D0zp96k1.js → chunk-4BX2VUAB-CiImuKHD.js} +1 -1
- package/public/assets/{chunk-55IACEB6-C5GJeIrO.js → chunk-55IACEB6-V6l1i-_P.js} +1 -1
- package/{dist/public/assets/chunk-B4BG7PRW-Ci17wd3H.js → public/assets/chunk-B4BG7PRW-DU8Wql9S.js} +1 -1
- package/{dist/public/assets/chunk-DI55MBZ5-B2XMqfQC.js → public/assets/chunk-DI55MBZ5-B_Jw-lhj.js} +1 -1
- package/public/assets/{chunk-FMBD7UC4-Crk5_wey.js → chunk-FMBD7UC4-C1LlA37K.js} +1 -1
- package/public/assets/{chunk-QN33PNHL-DqQoCDuG.js → chunk-QN33PNHL-CcgyTGxJ.js} +1 -1
- package/public/assets/{chunk-QZHKN3VN-DtbXtmmy.js → chunk-QZHKN3VN-C2H0lOPM.js} +1 -1
- package/public/assets/{chunk-TZMSLE5B-Boi_YcuZ.js → chunk-TZMSLE5B-Cp4Dpzkh.js} +1 -1
- package/public/assets/classDiagram-2ON5EDUG-BuYVNwmc.js +1 -0
- package/public/assets/classDiagram-v2-WZHVMYZB-BuYVNwmc.js +1 -0
- package/public/assets/clone-mkrd6lC9.js +1 -0
- package/public/assets/{code-block-IT6T5CEO-BAcnOjsj.js → code-block-IT6T5CEO-DOOuyfxG.js} +1 -1
- package/public/assets/{cose-bilkent-S5V4N54A-DAIcBIuP.js → cose-bilkent-S5V4N54A-DefjjRca.js} +1 -1
- package/public/assets/{dagre-6UL2VRFP-zz51dmH0.js → dagre-6UL2VRFP-hHpxpOKX.js} +1 -1
- package/public/assets/demo.svg +1 -0
- package/public/assets/{diagram-PSM6KHXK-bVpD6rI7.js → diagram-PSM6KHXK-ZgZ2X0Q-.js} +1 -1
- package/public/assets/{diagram-QEK2KX5R-I8YB5Wm0.js → diagram-QEK2KX5R-gCeAqKj1.js} +1 -1
- package/public/assets/{diagram-S2PKOQOG-D1xlOPWJ.js → diagram-S2PKOQOG-9IyVqMFa.js} +1 -1
- package/{dist/public/assets/erDiagram-Q2GNP2WA-DEdjbB3m.js → public/assets/erDiagram-Q2GNP2WA-Dzm33cik.js} +1 -1
- package/{dist/public/assets/flowDiagram-NV44I4VS-BBCU2dfK.js → public/assets/flowDiagram-NV44I4VS-BamNhi0g.js} +1 -1
- package/public/assets/{ganttDiagram-JELNMOA3-B0jnifD_.js → ganttDiagram-JELNMOA3-CrECl9wX.js} +1 -1
- package/public/assets/{gitGraphDiagram-NY62KEGX-BX21wvJS.js → gitGraphDiagram-NY62KEGX-C7_E64uK.js} +1 -1
- package/public/assets/{graph-BE95p5Ca.js → graph-CtTAhETf.js} +1 -1
- package/public/assets/index-Czr2q0NP.css +1 -0
- package/public/assets/index-kEIJA0pC.js +1781 -0
- package/public/assets/{infoDiagram-WHAUD3N6-CrU0UXwW.js → infoDiagram-WHAUD3N6-CLOougXO.js} +1 -1
- package/public/assets/{journeyDiagram-XKPGCS4Q-DzukVB-1.js → journeyDiagram-XKPGCS4Q-g0dISD-I.js} +1 -1
- package/{dist/public/assets/kanban-definition-3W4ZIXB7-CJVLdxxJ.js → public/assets/kanban-definition-3W4ZIXB7-DFIVrLyR.js} +1 -1
- package/public/assets/{layout-CM_3juMX.js → layout-DolajoeL.js} +1 -1
- package/public/assets/{linear-BXRjo7t5.js → linear-B5Hf7uIN.js} +1 -1
- package/public/assets/{mermaid.core-Hp60xAyJ.js → mermaid.core-DqP3HtOk.js} +5 -5
- package/public/assets/{min-oqogeQSX.js → min-UFvm8GLY.js} +1 -1
- package/public/assets/{mindmap-definition-VGOIOE7T-CCgMWgfM.js → mindmap-definition-VGOIOE7T-CnSTRcIt.js} +1 -1
- package/public/assets/{pieDiagram-ADFJNKIX-DAkNkjx-.js → pieDiagram-ADFJNKIX-CuMH9Po8.js} +1 -1
- package/{dist/public/assets/quadrantDiagram-AYHSOK5B-CPEqSA2x.js → public/assets/quadrantDiagram-AYHSOK5B-6i0SX3Xo.js} +1 -1
- package/public/assets/{requirementDiagram-UZGBJVZJ-jOv297_A.js → requirementDiagram-UZGBJVZJ-ChwO2HU-.js} +1 -1
- package/public/assets/{sankeyDiagram-TZEHDZUN-CwvAKmpc.js → sankeyDiagram-TZEHDZUN-DG-8crEL.js} +1 -1
- package/public/assets/{sequenceDiagram-WL72ISMW-D_WZ2ogT.js → sequenceDiagram-WL72ISMW-BQH_OfEp.js} +1 -1
- package/{dist/public/assets/stateDiagram-FKZM4ZOC-tqYMmK3v.js → public/assets/stateDiagram-FKZM4ZOC-CBOkbVQn.js} +1 -1
- package/public/assets/stateDiagram-v2-4FDKWEC3-BqHz04Bh.js +1 -0
- package/{dist/public/assets/timeline-definition-IT6M3QCI-BIqJkdQ0.js → public/assets/timeline-definition-IT6M3QCI-CkNd8y6W.js} +1 -1
- package/public/assets/{treemap-KMMF4GRG-CmJM6xaw.js → treemap-KMMF4GRG-D6z_eudj.js} +1 -1
- package/public/assets/{xychartDiagram-PRI3JC2R-D7-tZ8iR.js → xychartDiagram-PRI3JC2R-B5wk4XRt.js} +1 -1
- package/public/favicon-16.ico +0 -0
- package/public/favicon-32.ico +0 -0
- package/public/favicon-48.ico +0 -0
- package/public/favicon.svg +4 -0
- package/public/index.html +2 -2
- package/public/logo-1024.png +0 -0
- package/public/logo-128.png +0 -0
- package/public/logo-16.png +0 -0
- package/public/logo-256.png +0 -0
- package/public/logo-32.png +0 -0
- package/public/logo-48.png +0 -0
- package/public/logo-512.png +0 -0
- package/public/logo-64.png +0 -0
- package/dist/public/assets/channel-BtuRdvAy.js +0 -1
- package/dist/public/assets/classDiagram-2ON5EDUG-CDjYhjfv.js +0 -1
- package/dist/public/assets/classDiagram-v2-WZHVMYZB-CDjYhjfv.js +0 -1
- package/dist/public/assets/clone-C8pGQ3Xy.js +0 -1
- package/dist/public/assets/index-CA2Ed_I8.css +0 -1
- package/dist/public/assets/index-CbxztLlk.js +0 -1701
- package/dist/public/assets/stateDiagram-v2-4FDKWEC3-BF0ecSBs.js +0 -1
- package/public/assets/channel-BtuRdvAy.js +0 -1
- package/public/assets/classDiagram-2ON5EDUG-CDjYhjfv.js +0 -1
- package/public/assets/classDiagram-v2-WZHVMYZB-CDjYhjfv.js +0 -1
- package/public/assets/clone-C8pGQ3Xy.js +0 -1
- package/public/assets/index-CA2Ed_I8.css +0 -1
- package/public/assets/index-CbxztLlk.js +0 -1701
- package/public/assets/stateDiagram-v2-4FDKWEC3-BF0ecSBs.js +0 -1
package/dist/index.js
CHANGED
|
@@ -13,6 +13,7 @@ import { fileURLToPath } from "url";
|
|
|
13
13
|
import { createExpressMiddleware } from "@trpc/server/adapters/express";
|
|
14
14
|
import { applyWSSHandler } from "@trpc/server/adapters/ws";
|
|
15
15
|
import { agentManager as agentManager2 } from "@bytespell/amux/agents/manager";
|
|
16
|
+
import { setVerbose, debug } from "@bytespell/amux/lib/logger";
|
|
16
17
|
import "@bytespell/amux/db";
|
|
17
18
|
|
|
18
19
|
// src/db/index.ts
|
|
@@ -73,8 +74,8 @@ var windows = sqliteTable("windows", {
|
|
|
73
74
|
var panes = sqliteTable("panes", {
|
|
74
75
|
id: text("id").primaryKey(),
|
|
75
76
|
windowId: text("window_id").notNull().references(() => windows.id, { onDelete: "cascade" }),
|
|
76
|
-
/**
|
|
77
|
-
|
|
77
|
+
/** Content configuration. Null when pane type not yet selected. */
|
|
78
|
+
content: text("content", { mode: "json" }).$type(),
|
|
78
79
|
createdAt: integer("created_at", { mode: "timestamp_ms" }).notNull().default(sql`(unixepoch() * 1000)`)
|
|
79
80
|
});
|
|
80
81
|
var uiState = sqliteTable("ui_state", {
|
|
@@ -102,7 +103,7 @@ sqlite.exec(`
|
|
|
102
103
|
CREATE TABLE IF NOT EXISTS panes (
|
|
103
104
|
id TEXT PRIMARY KEY,
|
|
104
105
|
window_id TEXT NOT NULL REFERENCES windows(id) ON DELETE CASCADE,
|
|
105
|
-
|
|
106
|
+
content TEXT,
|
|
106
107
|
created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
|
|
107
108
|
);
|
|
108
109
|
|
|
@@ -111,6 +112,46 @@ sqlite.exec(`
|
|
|
111
112
|
value TEXT NOT NULL
|
|
112
113
|
);
|
|
113
114
|
`);
|
|
115
|
+
try {
|
|
116
|
+
const tableInfo = sqlite.prepare("PRAGMA table_info(panes)").all();
|
|
117
|
+
const hasSessionId = tableInfo.some((col) => col.name === "session_id");
|
|
118
|
+
const hasContent = tableInfo.some((col) => col.name === "content");
|
|
119
|
+
if (hasSessionId && !hasContent) {
|
|
120
|
+
sqlite.exec(`
|
|
121
|
+
-- Disable foreign keys temporarily
|
|
122
|
+
PRAGMA foreign_keys = OFF;
|
|
123
|
+
|
|
124
|
+
-- Create new table with content column
|
|
125
|
+
CREATE TABLE panes_new (
|
|
126
|
+
id TEXT PRIMARY KEY,
|
|
127
|
+
window_id TEXT NOT NULL REFERENCES windows(id) ON DELETE CASCADE,
|
|
128
|
+
content TEXT,
|
|
129
|
+
created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
-- Copy data, converting session_id to content JSON
|
|
133
|
+
INSERT INTO panes_new (id, window_id, content, created_at)
|
|
134
|
+
SELECT
|
|
135
|
+
id,
|
|
136
|
+
window_id,
|
|
137
|
+
CASE
|
|
138
|
+
WHEN session_id IS NOT NULL THEN json_object('type', 'session', 'sessionId', session_id)
|
|
139
|
+
ELSE NULL
|
|
140
|
+
END,
|
|
141
|
+
created_at
|
|
142
|
+
FROM panes;
|
|
143
|
+
|
|
144
|
+
-- Drop old table and rename new
|
|
145
|
+
DROP TABLE panes;
|
|
146
|
+
ALTER TABLE panes_new RENAME TO panes;
|
|
147
|
+
|
|
148
|
+
-- Re-enable foreign keys
|
|
149
|
+
PRAGMA foreign_keys = ON;
|
|
150
|
+
`);
|
|
151
|
+
console.log("[shella-db] Migrated panes from session_id to content column");
|
|
152
|
+
}
|
|
153
|
+
} catch {
|
|
154
|
+
}
|
|
114
155
|
|
|
115
156
|
// src/amuxBridge.ts
|
|
116
157
|
import { randomUUID } from "crypto";
|
|
@@ -134,8 +175,8 @@ function createAmuxBridge() {
|
|
|
134
175
|
if (!configId) {
|
|
135
176
|
const lastUsedRow = db2.select().from(appState).where(eq(appState.key, "last_used_agent_config_id")).get();
|
|
136
177
|
if (lastUsedRow?.value) {
|
|
137
|
-
const
|
|
138
|
-
if (
|
|
178
|
+
const config2 = db2.select().from(agentConfigs).where(eq(agentConfigs.id, lastUsedRow.value)).get();
|
|
179
|
+
if (config2) configId = config2.id;
|
|
139
180
|
}
|
|
140
181
|
if (!configId) {
|
|
141
182
|
const firstConfig = db2.select().from(agentConfigs).get();
|
|
@@ -149,11 +190,14 @@ function createAmuxBridge() {
|
|
|
149
190
|
}
|
|
150
191
|
const id = params.id ?? randomUUID();
|
|
151
192
|
const now = /* @__PURE__ */ new Date();
|
|
193
|
+
const config = db2.select().from(agentConfigs).where(eq(agentConfigs.id, configId)).get();
|
|
194
|
+
const initialTitle = config?.streamType === "pty" ? params.directory.split("/").pop() || null : null;
|
|
152
195
|
db2.insert(sessions).values({
|
|
153
196
|
id,
|
|
154
197
|
directory: params.directory,
|
|
155
198
|
agentConfigId: configId,
|
|
156
199
|
acpSessionId: null,
|
|
200
|
+
title: initialTitle,
|
|
157
201
|
model: null,
|
|
158
202
|
mode: null,
|
|
159
203
|
createdAt: now
|
|
@@ -189,17 +233,6 @@ function createAmuxBridge() {
|
|
|
189
233
|
respondPermission(sessionId, requestId, optionId) {
|
|
190
234
|
agentManager.respondPermission(sessionId, requestId, optionId);
|
|
191
235
|
},
|
|
192
|
-
async switchAgent(sessionId, agentConfigId) {
|
|
193
|
-
await agentManager.stopForSession(sessionId);
|
|
194
|
-
clearEventsForSession(sessionId);
|
|
195
|
-
db2.update(sessions).set({
|
|
196
|
-
agentConfigId,
|
|
197
|
-
acpSessionId: null,
|
|
198
|
-
model: null,
|
|
199
|
-
mode: null
|
|
200
|
-
}).where(eq(sessions.id, sessionId)).run();
|
|
201
|
-
db2.insert(appState).values({ key: "last_used_agent_config_id", value: agentConfigId }).onConflictDoUpdate({ target: appState.key, set: { value: agentConfigId } }).run();
|
|
202
|
-
},
|
|
203
236
|
subscribeToSession(sessionId, callback) {
|
|
204
237
|
const handler = (event) => {
|
|
205
238
|
if (event.sessionId === sessionId) {
|
|
@@ -213,6 +246,22 @@ function createAmuxBridge() {
|
|
|
213
246
|
const session = db2.select().from(sessions).where(eq(sessions.id, sessionId)).get();
|
|
214
247
|
if (!session) throw new Error(`Session ${sessionId} not found`);
|
|
215
248
|
return listFilesForAutocomplete(session.directory, partialPath, limit);
|
|
249
|
+
},
|
|
250
|
+
// Terminal operations
|
|
251
|
+
terminalWrite(sessionId, data) {
|
|
252
|
+
agentManager.terminalWrite(sessionId, data);
|
|
253
|
+
},
|
|
254
|
+
terminalResize(sessionId, cols, rows) {
|
|
255
|
+
agentManager.terminalResize(sessionId, cols, rows);
|
|
256
|
+
},
|
|
257
|
+
getTerminalScrollback(sessionId) {
|
|
258
|
+
return agentManager.getTerminalScrollback(sessionId);
|
|
259
|
+
},
|
|
260
|
+
isTerminalSession(sessionId) {
|
|
261
|
+
return agentManager.isTerminalSession(sessionId);
|
|
262
|
+
},
|
|
263
|
+
updateSessionTitle(sessionId, title) {
|
|
264
|
+
db2.update(sessions).set({ title }).where(eq(sessions.id, sessionId)).run();
|
|
216
265
|
}
|
|
217
266
|
};
|
|
218
267
|
}
|
|
@@ -356,7 +405,9 @@ var windowsRouter = router({
|
|
|
356
405
|
const allWindows = db.select().from(windows).orderBy(windows.createdAt).all();
|
|
357
406
|
const allPanes = db.select().from(panes).all();
|
|
358
407
|
const activeRow = db.select().from(uiState).where(eq2(uiState.key, "active_window_id")).get();
|
|
359
|
-
const sessionIds = [...new Set(
|
|
408
|
+
const sessionIds = [...new Set(
|
|
409
|
+
allPanes.map((p) => p.content?.type === "session" ? p.content.sessionId : null).filter((id) => id !== null)
|
|
410
|
+
)];
|
|
360
411
|
const sessionsData = await amux.getSessions(sessionIds);
|
|
361
412
|
const sessionMap = new Map(sessionsData.map((s) => [s.id, s]));
|
|
362
413
|
const agentConfigs2 = await amux.getAgentConfigs();
|
|
@@ -365,7 +416,8 @@ var windowsRouter = router({
|
|
|
365
416
|
...w,
|
|
366
417
|
panes: allPanes.filter((p) => p.windowId === w.id).map((p) => ({
|
|
367
418
|
...p,
|
|
368
|
-
session
|
|
419
|
+
// Enrich session-type content with full session data
|
|
420
|
+
session: p.content?.type === "session" ? sessionMap.get(p.content.sessionId) ?? null : null
|
|
369
421
|
}))
|
|
370
422
|
})),
|
|
371
423
|
activeWindowId: activeRow?.value ?? allWindows[allWindows.length - 1]?.id ?? null,
|
|
@@ -381,19 +433,20 @@ var windowsRouter = router({
|
|
|
381
433
|
throw new Error(`Window ${input.id} not found`);
|
|
382
434
|
}
|
|
383
435
|
const windowPanes = db.select().from(panes).where(eq2(panes.windowId, input.id)).all();
|
|
384
|
-
const sessionIds = windowPanes.map((p) => p.sessionId);
|
|
436
|
+
const sessionIds = windowPanes.map((p) => p.content?.type === "session" ? p.content.sessionId : null).filter((id) => id !== null);
|
|
385
437
|
const sessionsData = await amux.getSessions(sessionIds);
|
|
386
438
|
const sessionMap = new Map(sessionsData.map((s) => [s.id, s]));
|
|
387
439
|
return {
|
|
388
440
|
...window,
|
|
389
441
|
panes: windowPanes.map((p) => ({
|
|
390
442
|
...p,
|
|
391
|
-
session: sessionMap.get(p.sessionId) ?? null
|
|
443
|
+
session: p.content?.type === "session" ? sessionMap.get(p.content.sessionId) ?? null : null
|
|
392
444
|
}))
|
|
393
445
|
};
|
|
394
446
|
}),
|
|
395
447
|
/**
|
|
396
448
|
* Create a new window with a single pane.
|
|
449
|
+
* If agentConfigId is not provided, pane is created with no content (shows picker).
|
|
397
450
|
*/
|
|
398
451
|
create: publicProcedure.input(z.object({
|
|
399
452
|
id: z.string().optional(),
|
|
@@ -402,10 +455,13 @@ var windowsRouter = router({
|
|
|
402
455
|
agentConfigId: z.string().optional()
|
|
403
456
|
})).mutation(async ({ input }) => {
|
|
404
457
|
const directory = input.directory ?? process.cwd();
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
458
|
+
let session = null;
|
|
459
|
+
if (input.agentConfigId) {
|
|
460
|
+
session = await amux.createSession({
|
|
461
|
+
directory,
|
|
462
|
+
agentConfigId: input.agentConfigId
|
|
463
|
+
});
|
|
464
|
+
}
|
|
409
465
|
const windowId = input.id ?? randomUUID2();
|
|
410
466
|
const paneId = randomUUID2();
|
|
411
467
|
const existingCount = db.select().from(windows).all().length;
|
|
@@ -414,14 +470,13 @@ var windowsRouter = router({
|
|
|
414
470
|
id: windowId,
|
|
415
471
|
title: input.title || generateTitle(existingCount, directory),
|
|
416
472
|
hasCustomTitle: !!input.title,
|
|
417
|
-
// Only true if title is non-empty string
|
|
418
473
|
layout,
|
|
419
474
|
activePaneId: paneId
|
|
420
475
|
}).run();
|
|
421
476
|
db.insert(panes).values({
|
|
422
477
|
id: paneId,
|
|
423
478
|
windowId,
|
|
424
|
-
sessionId: session.id
|
|
479
|
+
content: session ? { type: "session", sessionId: session.id } : null
|
|
425
480
|
}).run();
|
|
426
481
|
db.insert(uiState).values({ key: "active_window_id", value: windowId }).onConflictDoUpdate({ target: uiState.key, set: { value: windowId } }).run();
|
|
427
482
|
const newWindow = db.select().from(windows).where(eq2(windows.id, windowId)).get();
|
|
@@ -430,7 +485,7 @@ var windowsRouter = router({
|
|
|
430
485
|
...newWindow,
|
|
431
486
|
panes: newPanes.map((p) => ({
|
|
432
487
|
...p,
|
|
433
|
-
session: p.sessionId === session.id ? session : null
|
|
488
|
+
session: session && p.content?.type === "session" && p.content.sessionId === session.id ? session : null
|
|
434
489
|
}))
|
|
435
490
|
};
|
|
436
491
|
}),
|
|
@@ -456,7 +511,9 @@ var windowsRouter = router({
|
|
|
456
511
|
delete: publicProcedure.input(z.object({ id: z.string() })).mutation(async ({ input }) => {
|
|
457
512
|
const windowPanes = db.select().from(panes).where(eq2(panes.windowId, input.id)).all();
|
|
458
513
|
for (const pane of windowPanes) {
|
|
459
|
-
|
|
514
|
+
if (pane.content?.type === "session") {
|
|
515
|
+
await amux.deleteSession(pane.content.sessionId);
|
|
516
|
+
}
|
|
460
517
|
}
|
|
461
518
|
db.delete(windows).where(eq2(windows.id, input.id)).run();
|
|
462
519
|
const activeRow = db.select().from(uiState).where(eq2(uiState.key, "active_window_id")).get();
|
|
@@ -492,7 +549,7 @@ function setAmuxBridge2(bridge) {
|
|
|
492
549
|
var layoutRouter = router({
|
|
493
550
|
/**
|
|
494
551
|
* Split a pane horizontally or vertically.
|
|
495
|
-
*
|
|
552
|
+
* If source pane has a session, clones it. Otherwise creates empty pane.
|
|
496
553
|
*/
|
|
497
554
|
split: publicProcedure.input(z2.object({
|
|
498
555
|
windowId: z2.string(),
|
|
@@ -506,25 +563,17 @@ var layoutRouter = router({
|
|
|
506
563
|
if (!sourcePane) {
|
|
507
564
|
throw new Error(`Pane ${input.paneId} not found`);
|
|
508
565
|
}
|
|
509
|
-
const
|
|
510
|
-
if (!
|
|
511
|
-
throw new Error(`
|
|
566
|
+
const window = db.select().from(windows).where(eq3(windows.id, input.windowId)).get();
|
|
567
|
+
if (!window) {
|
|
568
|
+
throw new Error(`Window ${input.windowId} not found`);
|
|
512
569
|
}
|
|
513
|
-
const
|
|
514
|
-
id: input.newSessionId,
|
|
515
|
-
directory: sourceSession.directory,
|
|
516
|
-
agentConfigId: sourceSession.agentConfigId
|
|
517
|
-
});
|
|
570
|
+
const newContent = null;
|
|
518
571
|
const newPaneId = input.newPaneId ?? randomUUID3();
|
|
519
572
|
db.insert(panes).values({
|
|
520
573
|
id: newPaneId,
|
|
521
574
|
windowId: input.windowId,
|
|
522
|
-
|
|
575
|
+
content: newContent
|
|
523
576
|
}).run();
|
|
524
|
-
const window = db.select().from(windows).where(eq3(windows.id, input.windowId)).get();
|
|
525
|
-
if (!window) {
|
|
526
|
-
throw new Error(`Window ${input.windowId} not found`);
|
|
527
|
-
}
|
|
528
577
|
const currentLayout = window.layout;
|
|
529
578
|
const newLayout = splitPane(currentLayout, input.paneId, newPaneId, input.direction);
|
|
530
579
|
db.update(windows).set({
|
|
@@ -532,27 +581,17 @@ var layoutRouter = router({
|
|
|
532
581
|
activePaneId: newPaneId,
|
|
533
582
|
lastAccessedAt: /* @__PURE__ */ new Date()
|
|
534
583
|
}).where(eq3(windows.id, input.windowId)).run();
|
|
535
|
-
await amux2.startAgent(newSession.id);
|
|
536
584
|
const now = /* @__PURE__ */ new Date();
|
|
537
585
|
return {
|
|
538
586
|
newPaneId,
|
|
539
|
-
newSessionId:
|
|
587
|
+
newSessionId: null,
|
|
540
588
|
layout: newLayout,
|
|
541
|
-
// Match exact shape from windows.list: { ...pane, session }
|
|
542
589
|
newPane: {
|
|
543
590
|
id: newPaneId,
|
|
544
591
|
windowId: input.windowId,
|
|
545
|
-
|
|
592
|
+
content: newContent,
|
|
546
593
|
createdAt: now.toISOString(),
|
|
547
|
-
session:
|
|
548
|
-
id: newSession.id,
|
|
549
|
-
directory: newSession.directory,
|
|
550
|
-
agentConfigId: newSession.agentConfigId,
|
|
551
|
-
model: newSession.model,
|
|
552
|
-
mode: newSession.mode,
|
|
553
|
-
createdAt: newSession.createdAt.toISOString(),
|
|
554
|
-
acpSessionId: newSession.acpSessionId
|
|
555
|
-
}
|
|
594
|
+
session: null
|
|
556
595
|
}
|
|
557
596
|
};
|
|
558
597
|
}),
|
|
@@ -574,11 +613,15 @@ var layoutRouter = router({
|
|
|
574
613
|
const currentLayout = window.layout;
|
|
575
614
|
const allPaneIds = getAllPaneIds(currentLayout);
|
|
576
615
|
if (allPaneIds.length === 1) {
|
|
577
|
-
|
|
616
|
+
if (pane.content?.type === "session") {
|
|
617
|
+
await amux2.deleteSession(pane.content.sessionId);
|
|
618
|
+
}
|
|
578
619
|
db.delete(windows).where(eq3(windows.id, input.windowId)).run();
|
|
579
620
|
return { windowClosed: true, layout: null, activePaneId: null };
|
|
580
621
|
}
|
|
581
|
-
|
|
622
|
+
if (pane.content?.type === "session") {
|
|
623
|
+
await amux2.deleteSession(pane.content.sessionId);
|
|
624
|
+
}
|
|
582
625
|
db.delete(panes).where(eq3(panes.id, input.paneId)).run();
|
|
583
626
|
const newLayout = removePane(currentLayout, input.paneId);
|
|
584
627
|
if (!newLayout) {
|
|
@@ -648,6 +691,78 @@ var layoutRouter = router({
|
|
|
648
691
|
const newLayout = updateRatio(currentLayout, input.path, input.ratio);
|
|
649
692
|
db.update(windows).set({ layout: newLayout }).where(eq3(windows.id, input.windowId)).run();
|
|
650
693
|
return { layout: newLayout };
|
|
694
|
+
}),
|
|
695
|
+
/**
|
|
696
|
+
* Set the session for an empty pane (used when user picks agent/shell type).
|
|
697
|
+
* Creates a session in amux and updates the pane.
|
|
698
|
+
*/
|
|
699
|
+
setSession: publicProcedure.input(z2.object({
|
|
700
|
+
paneId: z2.string(),
|
|
701
|
+
agentConfigId: z2.string(),
|
|
702
|
+
directory: z2.string().optional()
|
|
703
|
+
})).mutation(async ({ input }) => {
|
|
704
|
+
const pane = db.select().from(panes).where(eq3(panes.id, input.paneId)).get();
|
|
705
|
+
if (!pane) {
|
|
706
|
+
throw new Error(`Pane ${input.paneId} not found`);
|
|
707
|
+
}
|
|
708
|
+
if (pane.content) {
|
|
709
|
+
throw new Error(`Pane ${input.paneId} already has content`);
|
|
710
|
+
}
|
|
711
|
+
const session = await amux2.createSession({
|
|
712
|
+
directory: input.directory ?? process.cwd(),
|
|
713
|
+
agentConfigId: input.agentConfigId
|
|
714
|
+
});
|
|
715
|
+
db.update(panes).set({ content: { type: "session", sessionId: session.id } }).where(eq3(panes.id, input.paneId)).run();
|
|
716
|
+
await amux2.startAgent(session.id);
|
|
717
|
+
return {
|
|
718
|
+
sessionId: session.id,
|
|
719
|
+
content: { type: "session", sessionId: session.id },
|
|
720
|
+
session: {
|
|
721
|
+
id: session.id,
|
|
722
|
+
directory: session.directory,
|
|
723
|
+
agentConfigId: session.agentConfigId,
|
|
724
|
+
model: session.model,
|
|
725
|
+
mode: session.mode,
|
|
726
|
+
createdAt: session.createdAt.toISOString(),
|
|
727
|
+
acpSessionId: session.acpSessionId
|
|
728
|
+
}
|
|
729
|
+
};
|
|
730
|
+
}),
|
|
731
|
+
/**
|
|
732
|
+
* Set browser content for an empty pane.
|
|
733
|
+
*/
|
|
734
|
+
setBrowserContent: publicProcedure.input(z2.object({
|
|
735
|
+
paneId: z2.string(),
|
|
736
|
+
url: z2.string().url()
|
|
737
|
+
})).mutation(async ({ input }) => {
|
|
738
|
+
const pane = db.select().from(panes).where(eq3(panes.id, input.paneId)).get();
|
|
739
|
+
if (!pane) {
|
|
740
|
+
throw new Error(`Pane ${input.paneId} not found`);
|
|
741
|
+
}
|
|
742
|
+
if (pane.content) {
|
|
743
|
+
throw new Error(`Pane ${input.paneId} already has content`);
|
|
744
|
+
}
|
|
745
|
+
const content = { type: "browser", url: input.url };
|
|
746
|
+
db.update(panes).set({ content }).where(eq3(panes.id, input.paneId)).run();
|
|
747
|
+
return { content };
|
|
748
|
+
}),
|
|
749
|
+
/**
|
|
750
|
+
* Update the URL of an existing browser pane.
|
|
751
|
+
*/
|
|
752
|
+
updateBrowserUrl: publicProcedure.input(z2.object({
|
|
753
|
+
paneId: z2.string(),
|
|
754
|
+
url: z2.string().url()
|
|
755
|
+
})).mutation(async ({ input }) => {
|
|
756
|
+
const pane = db.select().from(panes).where(eq3(panes.id, input.paneId)).get();
|
|
757
|
+
if (!pane) {
|
|
758
|
+
throw new Error(`Pane ${input.paneId} not found`);
|
|
759
|
+
}
|
|
760
|
+
if (pane.content?.type !== "browser") {
|
|
761
|
+
throw new Error(`Pane ${input.paneId} is not a browser pane`);
|
|
762
|
+
}
|
|
763
|
+
const content = { type: "browser", url: input.url };
|
|
764
|
+
db.update(panes).set({ content }).where(eq3(panes.id, input.paneId)).run();
|
|
765
|
+
return { content };
|
|
651
766
|
})
|
|
652
767
|
});
|
|
653
768
|
|
|
@@ -667,7 +782,10 @@ function getSessionIdForPane(paneId) {
|
|
|
667
782
|
if (!pane) {
|
|
668
783
|
throw new Error(`Pane ${paneId} not found`);
|
|
669
784
|
}
|
|
670
|
-
|
|
785
|
+
if (pane.content?.type !== "session") {
|
|
786
|
+
throw new Error(`Pane ${paneId} is not a session pane`);
|
|
787
|
+
}
|
|
788
|
+
return pane.content.sessionId;
|
|
671
789
|
}
|
|
672
790
|
var agentsRouter = router({
|
|
673
791
|
/**
|
|
@@ -738,17 +856,6 @@ var agentsRouter = router({
|
|
|
738
856
|
amux3.respondPermission(sessionId, input.requestId, input.optionId);
|
|
739
857
|
return { ok: true };
|
|
740
858
|
}),
|
|
741
|
-
/**
|
|
742
|
-
* Switch to a different agent.
|
|
743
|
-
*/
|
|
744
|
-
switchAgent: publicProcedure.input(z3.object({
|
|
745
|
-
paneId: z3.string(),
|
|
746
|
-
agentConfigId: z3.string()
|
|
747
|
-
})).mutation(async ({ input }) => {
|
|
748
|
-
const sessionId = getSessionIdForPane(input.paneId);
|
|
749
|
-
await amux3.switchAgent(sessionId, input.agentConfigId);
|
|
750
|
-
return { ok: true };
|
|
751
|
-
}),
|
|
752
859
|
/**
|
|
753
860
|
* Subscribe to updates for a pane's agent session.
|
|
754
861
|
*/
|
|
@@ -774,7 +881,10 @@ function getSessionIdForPane2(paneId) {
|
|
|
774
881
|
if (!pane) {
|
|
775
882
|
throw new Error(`Pane ${paneId} not found`);
|
|
776
883
|
}
|
|
777
|
-
|
|
884
|
+
if (pane.content?.type !== "session") {
|
|
885
|
+
throw new Error(`Pane ${paneId} is not a session pane`);
|
|
886
|
+
}
|
|
887
|
+
return pane.content.sessionId;
|
|
778
888
|
}
|
|
779
889
|
var filesRouter = router({
|
|
780
890
|
/**
|
|
@@ -791,24 +901,97 @@ var filesRouter = router({
|
|
|
791
901
|
})
|
|
792
902
|
});
|
|
793
903
|
|
|
904
|
+
// src/trpc/terminals.ts
|
|
905
|
+
import { z as z5 } from "zod";
|
|
906
|
+
import { eq as eq6 } from "drizzle-orm";
|
|
907
|
+
var amux5;
|
|
908
|
+
function setAmuxBridge5(bridge) {
|
|
909
|
+
amux5 = bridge;
|
|
910
|
+
}
|
|
911
|
+
var paneInput2 = z5.object({
|
|
912
|
+
paneId: z5.string()
|
|
913
|
+
});
|
|
914
|
+
function getSessionIdForPane3(paneId) {
|
|
915
|
+
const pane = db.select().from(panes).where(eq6(panes.id, paneId)).get();
|
|
916
|
+
if (!pane) {
|
|
917
|
+
throw new Error(`Pane ${paneId} not found`);
|
|
918
|
+
}
|
|
919
|
+
if (pane.content?.type !== "session") {
|
|
920
|
+
throw new Error(`Pane ${paneId} is not a session pane`);
|
|
921
|
+
}
|
|
922
|
+
return pane.content.sessionId;
|
|
923
|
+
}
|
|
924
|
+
var terminalsRouter = router({
|
|
925
|
+
/**
|
|
926
|
+
* Write raw input to terminal (keystrokes from client).
|
|
927
|
+
*/
|
|
928
|
+
write: publicProcedure.input(
|
|
929
|
+
z5.object({
|
|
930
|
+
paneId: z5.string(),
|
|
931
|
+
data: z5.string()
|
|
932
|
+
})
|
|
933
|
+
).mutation(({ input }) => {
|
|
934
|
+
const sessionId = getSessionIdForPane3(input.paneId);
|
|
935
|
+
amux5.terminalWrite(sessionId, input.data);
|
|
936
|
+
return { ok: true };
|
|
937
|
+
}),
|
|
938
|
+
/**
|
|
939
|
+
* Resize terminal dimensions.
|
|
940
|
+
*/
|
|
941
|
+
resize: publicProcedure.input(
|
|
942
|
+
z5.object({
|
|
943
|
+
paneId: z5.string(),
|
|
944
|
+
cols: z5.number().int().positive(),
|
|
945
|
+
rows: z5.number().int().positive()
|
|
946
|
+
})
|
|
947
|
+
).mutation(({ input }) => {
|
|
948
|
+
const sessionId = getSessionIdForPane3(input.paneId);
|
|
949
|
+
amux5.terminalResize(sessionId, input.cols, input.rows);
|
|
950
|
+
return { ok: true };
|
|
951
|
+
}),
|
|
952
|
+
/**
|
|
953
|
+
* Check if a pane is a terminal session.
|
|
954
|
+
*/
|
|
955
|
+
isTerminal: publicProcedure.input(paneInput2).query(({ input }) => {
|
|
956
|
+
const sessionId = getSessionIdForPane3(input.paneId);
|
|
957
|
+
return { isTerminal: amux5.isTerminalSession(sessionId) };
|
|
958
|
+
}),
|
|
959
|
+
/**
|
|
960
|
+
* Set terminal title (from OSC escape sequence).
|
|
961
|
+
*/
|
|
962
|
+
setTitle: publicProcedure.input(z5.object({
|
|
963
|
+
paneId: z5.string(),
|
|
964
|
+
title: z5.string()
|
|
965
|
+
})).mutation(({ input }) => {
|
|
966
|
+
const sessionId = getSessionIdForPane3(input.paneId);
|
|
967
|
+
amux5.updateSessionTitle(sessionId, input.title);
|
|
968
|
+
return { ok: true };
|
|
969
|
+
})
|
|
970
|
+
});
|
|
971
|
+
|
|
794
972
|
// src/trpc/router.ts
|
|
795
|
-
function initializeRouters(
|
|
796
|
-
setAmuxBridge(
|
|
797
|
-
setAmuxBridge2(
|
|
798
|
-
setAmuxBridge3(
|
|
799
|
-
setAmuxBridge4(
|
|
973
|
+
function initializeRouters(amux6) {
|
|
974
|
+
setAmuxBridge(amux6);
|
|
975
|
+
setAmuxBridge2(amux6);
|
|
976
|
+
setAmuxBridge3(amux6);
|
|
977
|
+
setAmuxBridge4(amux6);
|
|
978
|
+
setAmuxBridge5(amux6);
|
|
800
979
|
}
|
|
801
980
|
var shellaRouter = router({
|
|
802
981
|
windows: windowsRouter,
|
|
803
982
|
layout: layoutRouter,
|
|
804
983
|
agents: agentsRouter,
|
|
805
|
-
files: filesRouter
|
|
984
|
+
files: filesRouter,
|
|
985
|
+
terminals: terminalsRouter
|
|
806
986
|
});
|
|
807
987
|
|
|
808
988
|
// src/index.ts
|
|
809
989
|
var __dirname = path2.dirname(fileURLToPath(import.meta.url));
|
|
810
990
|
function createShellaServer(options = {}) {
|
|
811
991
|
const port = options.port ?? 3067;
|
|
992
|
+
if (options.verbose) {
|
|
993
|
+
setVerbose(true);
|
|
994
|
+
}
|
|
812
995
|
const amuxBridge = createAmuxBridge();
|
|
813
996
|
initializeRouters(amuxBridge);
|
|
814
997
|
const app = express();
|
|
@@ -825,17 +1008,24 @@ function createShellaServer(options = {}) {
|
|
|
825
1008
|
applyWSSHandler({ wss, router: shellaRouter });
|
|
826
1009
|
return {
|
|
827
1010
|
start: () => {
|
|
828
|
-
return new Promise((resolve) => {
|
|
1011
|
+
return new Promise((resolve, reject) => {
|
|
1012
|
+
server.once("error", (err) => {
|
|
1013
|
+
if (err.code === "EADDRINUSE") {
|
|
1014
|
+
reject(new Error(`Port ${port} is already in use. Kill the other process or use a different port.`));
|
|
1015
|
+
} else {
|
|
1016
|
+
reject(err);
|
|
1017
|
+
}
|
|
1018
|
+
});
|
|
829
1019
|
server.listen(port, () => {
|
|
830
1020
|
const url = `http://localhost:${port}`;
|
|
831
|
-
|
|
1021
|
+
debug("shella", `Running on ${url}`);
|
|
832
1022
|
options.onReady?.(url);
|
|
833
1023
|
resolve();
|
|
834
1024
|
});
|
|
835
1025
|
});
|
|
836
1026
|
},
|
|
837
1027
|
stop: async () => {
|
|
838
|
-
|
|
1028
|
+
debug("shella", "Shutting down...");
|
|
839
1029
|
wss.close();
|
|
840
1030
|
await agentManager2.stopAll();
|
|
841
1031
|
server.close();
|