@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/bin/cli.js
CHANGED
|
@@ -20,6 +20,7 @@ import { fileURLToPath } from "url";
|
|
|
20
20
|
import { createExpressMiddleware } from "@trpc/server/adapters/express";
|
|
21
21
|
import { applyWSSHandler } from "@trpc/server/adapters/ws";
|
|
22
22
|
import { agentManager as agentManager2 } from "@bytespell/amux/agents/manager";
|
|
23
|
+
import { setVerbose, debug } from "@bytespell/amux/lib/logger";
|
|
23
24
|
import "@bytespell/amux/db";
|
|
24
25
|
|
|
25
26
|
// src/db/index.ts
|
|
@@ -80,8 +81,8 @@ var windows = sqliteTable("windows", {
|
|
|
80
81
|
var panes = sqliteTable("panes", {
|
|
81
82
|
id: text("id").primaryKey(),
|
|
82
83
|
windowId: text("window_id").notNull().references(() => windows.id, { onDelete: "cascade" }),
|
|
83
|
-
/**
|
|
84
|
-
|
|
84
|
+
/** Content configuration. Null when pane type not yet selected. */
|
|
85
|
+
content: text("content", { mode: "json" }).$type(),
|
|
85
86
|
createdAt: integer("created_at", { mode: "timestamp_ms" }).notNull().default(sql`(unixepoch() * 1000)`)
|
|
86
87
|
});
|
|
87
88
|
var uiState = sqliteTable("ui_state", {
|
|
@@ -109,7 +110,7 @@ sqlite.exec(`
|
|
|
109
110
|
CREATE TABLE IF NOT EXISTS panes (
|
|
110
111
|
id TEXT PRIMARY KEY,
|
|
111
112
|
window_id TEXT NOT NULL REFERENCES windows(id) ON DELETE CASCADE,
|
|
112
|
-
|
|
113
|
+
content TEXT,
|
|
113
114
|
created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
|
|
114
115
|
);
|
|
115
116
|
|
|
@@ -118,6 +119,46 @@ sqlite.exec(`
|
|
|
118
119
|
value TEXT NOT NULL
|
|
119
120
|
);
|
|
120
121
|
`);
|
|
122
|
+
try {
|
|
123
|
+
const tableInfo = sqlite.prepare("PRAGMA table_info(panes)").all();
|
|
124
|
+
const hasSessionId = tableInfo.some((col) => col.name === "session_id");
|
|
125
|
+
const hasContent = tableInfo.some((col) => col.name === "content");
|
|
126
|
+
if (hasSessionId && !hasContent) {
|
|
127
|
+
sqlite.exec(`
|
|
128
|
+
-- Disable foreign keys temporarily
|
|
129
|
+
PRAGMA foreign_keys = OFF;
|
|
130
|
+
|
|
131
|
+
-- Create new table with content column
|
|
132
|
+
CREATE TABLE panes_new (
|
|
133
|
+
id TEXT PRIMARY KEY,
|
|
134
|
+
window_id TEXT NOT NULL REFERENCES windows(id) ON DELETE CASCADE,
|
|
135
|
+
content TEXT,
|
|
136
|
+
created_at INTEGER NOT NULL DEFAULT (unixepoch() * 1000)
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
-- Copy data, converting session_id to content JSON
|
|
140
|
+
INSERT INTO panes_new (id, window_id, content, created_at)
|
|
141
|
+
SELECT
|
|
142
|
+
id,
|
|
143
|
+
window_id,
|
|
144
|
+
CASE
|
|
145
|
+
WHEN session_id IS NOT NULL THEN json_object('type', 'session', 'sessionId', session_id)
|
|
146
|
+
ELSE NULL
|
|
147
|
+
END,
|
|
148
|
+
created_at
|
|
149
|
+
FROM panes;
|
|
150
|
+
|
|
151
|
+
-- Drop old table and rename new
|
|
152
|
+
DROP TABLE panes;
|
|
153
|
+
ALTER TABLE panes_new RENAME TO panes;
|
|
154
|
+
|
|
155
|
+
-- Re-enable foreign keys
|
|
156
|
+
PRAGMA foreign_keys = ON;
|
|
157
|
+
`);
|
|
158
|
+
console.log("[shella-db] Migrated panes from session_id to content column");
|
|
159
|
+
}
|
|
160
|
+
} catch {
|
|
161
|
+
}
|
|
121
162
|
|
|
122
163
|
// src/amuxBridge.ts
|
|
123
164
|
import { randomUUID } from "crypto";
|
|
@@ -141,8 +182,8 @@ function createAmuxBridge() {
|
|
|
141
182
|
if (!configId) {
|
|
142
183
|
const lastUsedRow = db2.select().from(appState).where(eq(appState.key, "last_used_agent_config_id")).get();
|
|
143
184
|
if (lastUsedRow?.value) {
|
|
144
|
-
const
|
|
145
|
-
if (
|
|
185
|
+
const config2 = db2.select().from(agentConfigs).where(eq(agentConfigs.id, lastUsedRow.value)).get();
|
|
186
|
+
if (config2) configId = config2.id;
|
|
146
187
|
}
|
|
147
188
|
if (!configId) {
|
|
148
189
|
const firstConfig = db2.select().from(agentConfigs).get();
|
|
@@ -156,11 +197,14 @@ function createAmuxBridge() {
|
|
|
156
197
|
}
|
|
157
198
|
const id = params.id ?? randomUUID();
|
|
158
199
|
const now = /* @__PURE__ */ new Date();
|
|
200
|
+
const config = db2.select().from(agentConfigs).where(eq(agentConfigs.id, configId)).get();
|
|
201
|
+
const initialTitle = config?.streamType === "pty" ? params.directory.split("/").pop() || null : null;
|
|
159
202
|
db2.insert(sessions).values({
|
|
160
203
|
id,
|
|
161
204
|
directory: params.directory,
|
|
162
205
|
agentConfigId: configId,
|
|
163
206
|
acpSessionId: null,
|
|
207
|
+
title: initialTitle,
|
|
164
208
|
model: null,
|
|
165
209
|
mode: null,
|
|
166
210
|
createdAt: now
|
|
@@ -196,17 +240,6 @@ function createAmuxBridge() {
|
|
|
196
240
|
respondPermission(sessionId, requestId, optionId) {
|
|
197
241
|
agentManager.respondPermission(sessionId, requestId, optionId);
|
|
198
242
|
},
|
|
199
|
-
async switchAgent(sessionId, agentConfigId) {
|
|
200
|
-
await agentManager.stopForSession(sessionId);
|
|
201
|
-
clearEventsForSession(sessionId);
|
|
202
|
-
db2.update(sessions).set({
|
|
203
|
-
agentConfigId,
|
|
204
|
-
acpSessionId: null,
|
|
205
|
-
model: null,
|
|
206
|
-
mode: null
|
|
207
|
-
}).where(eq(sessions.id, sessionId)).run();
|
|
208
|
-
db2.insert(appState).values({ key: "last_used_agent_config_id", value: agentConfigId }).onConflictDoUpdate({ target: appState.key, set: { value: agentConfigId } }).run();
|
|
209
|
-
},
|
|
210
243
|
subscribeToSession(sessionId, callback) {
|
|
211
244
|
const handler = (event) => {
|
|
212
245
|
if (event.sessionId === sessionId) {
|
|
@@ -220,6 +253,22 @@ function createAmuxBridge() {
|
|
|
220
253
|
const session = db2.select().from(sessions).where(eq(sessions.id, sessionId)).get();
|
|
221
254
|
if (!session) throw new Error(`Session ${sessionId} not found`);
|
|
222
255
|
return listFilesForAutocomplete(session.directory, partialPath, limit);
|
|
256
|
+
},
|
|
257
|
+
// Terminal operations
|
|
258
|
+
terminalWrite(sessionId, data) {
|
|
259
|
+
agentManager.terminalWrite(sessionId, data);
|
|
260
|
+
},
|
|
261
|
+
terminalResize(sessionId, cols, rows) {
|
|
262
|
+
agentManager.terminalResize(sessionId, cols, rows);
|
|
263
|
+
},
|
|
264
|
+
getTerminalScrollback(sessionId) {
|
|
265
|
+
return agentManager.getTerminalScrollback(sessionId);
|
|
266
|
+
},
|
|
267
|
+
isTerminalSession(sessionId) {
|
|
268
|
+
return agentManager.isTerminalSession(sessionId);
|
|
269
|
+
},
|
|
270
|
+
updateSessionTitle(sessionId, title) {
|
|
271
|
+
db2.update(sessions).set({ title }).where(eq(sessions.id, sessionId)).run();
|
|
223
272
|
}
|
|
224
273
|
};
|
|
225
274
|
}
|
|
@@ -363,7 +412,9 @@ var windowsRouter = router({
|
|
|
363
412
|
const allWindows = db.select().from(windows).orderBy(windows.createdAt).all();
|
|
364
413
|
const allPanes = db.select().from(panes).all();
|
|
365
414
|
const activeRow = db.select().from(uiState).where(eq2(uiState.key, "active_window_id")).get();
|
|
366
|
-
const sessionIds = [...new Set(
|
|
415
|
+
const sessionIds = [...new Set(
|
|
416
|
+
allPanes.map((p2) => p2.content?.type === "session" ? p2.content.sessionId : null).filter((id) => id !== null)
|
|
417
|
+
)];
|
|
367
418
|
const sessionsData = await amux.getSessions(sessionIds);
|
|
368
419
|
const sessionMap = new Map(sessionsData.map((s) => [s.id, s]));
|
|
369
420
|
const agentConfigs2 = await amux.getAgentConfigs();
|
|
@@ -372,7 +423,8 @@ var windowsRouter = router({
|
|
|
372
423
|
...w,
|
|
373
424
|
panes: allPanes.filter((p2) => p2.windowId === w.id).map((p2) => ({
|
|
374
425
|
...p2,
|
|
375
|
-
session
|
|
426
|
+
// Enrich session-type content with full session data
|
|
427
|
+
session: p2.content?.type === "session" ? sessionMap.get(p2.content.sessionId) ?? null : null
|
|
376
428
|
}))
|
|
377
429
|
})),
|
|
378
430
|
activeWindowId: activeRow?.value ?? allWindows[allWindows.length - 1]?.id ?? null,
|
|
@@ -388,19 +440,20 @@ var windowsRouter = router({
|
|
|
388
440
|
throw new Error(`Window ${input.id} not found`);
|
|
389
441
|
}
|
|
390
442
|
const windowPanes = db.select().from(panes).where(eq2(panes.windowId, input.id)).all();
|
|
391
|
-
const sessionIds = windowPanes.map((p2) => p2.sessionId);
|
|
443
|
+
const sessionIds = windowPanes.map((p2) => p2.content?.type === "session" ? p2.content.sessionId : null).filter((id) => id !== null);
|
|
392
444
|
const sessionsData = await amux.getSessions(sessionIds);
|
|
393
445
|
const sessionMap = new Map(sessionsData.map((s) => [s.id, s]));
|
|
394
446
|
return {
|
|
395
447
|
...window,
|
|
396
448
|
panes: windowPanes.map((p2) => ({
|
|
397
449
|
...p2,
|
|
398
|
-
session: sessionMap.get(p2.sessionId) ?? null
|
|
450
|
+
session: p2.content?.type === "session" ? sessionMap.get(p2.content.sessionId) ?? null : null
|
|
399
451
|
}))
|
|
400
452
|
};
|
|
401
453
|
}),
|
|
402
454
|
/**
|
|
403
455
|
* Create a new window with a single pane.
|
|
456
|
+
* If agentConfigId is not provided, pane is created with no content (shows picker).
|
|
404
457
|
*/
|
|
405
458
|
create: publicProcedure.input(z.object({
|
|
406
459
|
id: z.string().optional(),
|
|
@@ -409,10 +462,13 @@ var windowsRouter = router({
|
|
|
409
462
|
agentConfigId: z.string().optional()
|
|
410
463
|
})).mutation(async ({ input }) => {
|
|
411
464
|
const directory = input.directory ?? process.cwd();
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
465
|
+
let session = null;
|
|
466
|
+
if (input.agentConfigId) {
|
|
467
|
+
session = await amux.createSession({
|
|
468
|
+
directory,
|
|
469
|
+
agentConfigId: input.agentConfigId
|
|
470
|
+
});
|
|
471
|
+
}
|
|
416
472
|
const windowId = input.id ?? randomUUID2();
|
|
417
473
|
const paneId = randomUUID2();
|
|
418
474
|
const existingCount = db.select().from(windows).all().length;
|
|
@@ -421,14 +477,13 @@ var windowsRouter = router({
|
|
|
421
477
|
id: windowId,
|
|
422
478
|
title: input.title || generateTitle(existingCount, directory),
|
|
423
479
|
hasCustomTitle: !!input.title,
|
|
424
|
-
// Only true if title is non-empty string
|
|
425
480
|
layout,
|
|
426
481
|
activePaneId: paneId
|
|
427
482
|
}).run();
|
|
428
483
|
db.insert(panes).values({
|
|
429
484
|
id: paneId,
|
|
430
485
|
windowId,
|
|
431
|
-
sessionId: session.id
|
|
486
|
+
content: session ? { type: "session", sessionId: session.id } : null
|
|
432
487
|
}).run();
|
|
433
488
|
db.insert(uiState).values({ key: "active_window_id", value: windowId }).onConflictDoUpdate({ target: uiState.key, set: { value: windowId } }).run();
|
|
434
489
|
const newWindow = db.select().from(windows).where(eq2(windows.id, windowId)).get();
|
|
@@ -437,7 +492,7 @@ var windowsRouter = router({
|
|
|
437
492
|
...newWindow,
|
|
438
493
|
panes: newPanes.map((p2) => ({
|
|
439
494
|
...p2,
|
|
440
|
-
session: p2.sessionId === session.id ? session : null
|
|
495
|
+
session: session && p2.content?.type === "session" && p2.content.sessionId === session.id ? session : null
|
|
441
496
|
}))
|
|
442
497
|
};
|
|
443
498
|
}),
|
|
@@ -463,7 +518,9 @@ var windowsRouter = router({
|
|
|
463
518
|
delete: publicProcedure.input(z.object({ id: z.string() })).mutation(async ({ input }) => {
|
|
464
519
|
const windowPanes = db.select().from(panes).where(eq2(panes.windowId, input.id)).all();
|
|
465
520
|
for (const pane of windowPanes) {
|
|
466
|
-
|
|
521
|
+
if (pane.content?.type === "session") {
|
|
522
|
+
await amux.deleteSession(pane.content.sessionId);
|
|
523
|
+
}
|
|
467
524
|
}
|
|
468
525
|
db.delete(windows).where(eq2(windows.id, input.id)).run();
|
|
469
526
|
const activeRow = db.select().from(uiState).where(eq2(uiState.key, "active_window_id")).get();
|
|
@@ -499,7 +556,7 @@ function setAmuxBridge2(bridge) {
|
|
|
499
556
|
var layoutRouter = router({
|
|
500
557
|
/**
|
|
501
558
|
* Split a pane horizontally or vertically.
|
|
502
|
-
*
|
|
559
|
+
* If source pane has a session, clones it. Otherwise creates empty pane.
|
|
503
560
|
*/
|
|
504
561
|
split: publicProcedure.input(z2.object({
|
|
505
562
|
windowId: z2.string(),
|
|
@@ -513,25 +570,17 @@ var layoutRouter = router({
|
|
|
513
570
|
if (!sourcePane) {
|
|
514
571
|
throw new Error(`Pane ${input.paneId} not found`);
|
|
515
572
|
}
|
|
516
|
-
const
|
|
517
|
-
if (!
|
|
518
|
-
throw new Error(`
|
|
573
|
+
const window = db.select().from(windows).where(eq3(windows.id, input.windowId)).get();
|
|
574
|
+
if (!window) {
|
|
575
|
+
throw new Error(`Window ${input.windowId} not found`);
|
|
519
576
|
}
|
|
520
|
-
const
|
|
521
|
-
id: input.newSessionId,
|
|
522
|
-
directory: sourceSession.directory,
|
|
523
|
-
agentConfigId: sourceSession.agentConfigId
|
|
524
|
-
});
|
|
577
|
+
const newContent = null;
|
|
525
578
|
const newPaneId = input.newPaneId ?? randomUUID3();
|
|
526
579
|
db.insert(panes).values({
|
|
527
580
|
id: newPaneId,
|
|
528
581
|
windowId: input.windowId,
|
|
529
|
-
|
|
582
|
+
content: newContent
|
|
530
583
|
}).run();
|
|
531
|
-
const window = db.select().from(windows).where(eq3(windows.id, input.windowId)).get();
|
|
532
|
-
if (!window) {
|
|
533
|
-
throw new Error(`Window ${input.windowId} not found`);
|
|
534
|
-
}
|
|
535
584
|
const currentLayout = window.layout;
|
|
536
585
|
const newLayout = splitPane(currentLayout, input.paneId, newPaneId, input.direction);
|
|
537
586
|
db.update(windows).set({
|
|
@@ -539,27 +588,17 @@ var layoutRouter = router({
|
|
|
539
588
|
activePaneId: newPaneId,
|
|
540
589
|
lastAccessedAt: /* @__PURE__ */ new Date()
|
|
541
590
|
}).where(eq3(windows.id, input.windowId)).run();
|
|
542
|
-
await amux2.startAgent(newSession.id);
|
|
543
591
|
const now = /* @__PURE__ */ new Date();
|
|
544
592
|
return {
|
|
545
593
|
newPaneId,
|
|
546
|
-
newSessionId:
|
|
594
|
+
newSessionId: null,
|
|
547
595
|
layout: newLayout,
|
|
548
|
-
// Match exact shape from windows.list: { ...pane, session }
|
|
549
596
|
newPane: {
|
|
550
597
|
id: newPaneId,
|
|
551
598
|
windowId: input.windowId,
|
|
552
|
-
|
|
599
|
+
content: newContent,
|
|
553
600
|
createdAt: now.toISOString(),
|
|
554
|
-
session:
|
|
555
|
-
id: newSession.id,
|
|
556
|
-
directory: newSession.directory,
|
|
557
|
-
agentConfigId: newSession.agentConfigId,
|
|
558
|
-
model: newSession.model,
|
|
559
|
-
mode: newSession.mode,
|
|
560
|
-
createdAt: newSession.createdAt.toISOString(),
|
|
561
|
-
acpSessionId: newSession.acpSessionId
|
|
562
|
-
}
|
|
601
|
+
session: null
|
|
563
602
|
}
|
|
564
603
|
};
|
|
565
604
|
}),
|
|
@@ -581,11 +620,15 @@ var layoutRouter = router({
|
|
|
581
620
|
const currentLayout = window.layout;
|
|
582
621
|
const allPaneIds = getAllPaneIds(currentLayout);
|
|
583
622
|
if (allPaneIds.length === 1) {
|
|
584
|
-
|
|
623
|
+
if (pane.content?.type === "session") {
|
|
624
|
+
await amux2.deleteSession(pane.content.sessionId);
|
|
625
|
+
}
|
|
585
626
|
db.delete(windows).where(eq3(windows.id, input.windowId)).run();
|
|
586
627
|
return { windowClosed: true, layout: null, activePaneId: null };
|
|
587
628
|
}
|
|
588
|
-
|
|
629
|
+
if (pane.content?.type === "session") {
|
|
630
|
+
await amux2.deleteSession(pane.content.sessionId);
|
|
631
|
+
}
|
|
589
632
|
db.delete(panes).where(eq3(panes.id, input.paneId)).run();
|
|
590
633
|
const newLayout = removePane(currentLayout, input.paneId);
|
|
591
634
|
if (!newLayout) {
|
|
@@ -655,6 +698,78 @@ var layoutRouter = router({
|
|
|
655
698
|
const newLayout = updateRatio(currentLayout, input.path, input.ratio);
|
|
656
699
|
db.update(windows).set({ layout: newLayout }).where(eq3(windows.id, input.windowId)).run();
|
|
657
700
|
return { layout: newLayout };
|
|
701
|
+
}),
|
|
702
|
+
/**
|
|
703
|
+
* Set the session for an empty pane (used when user picks agent/shell type).
|
|
704
|
+
* Creates a session in amux and updates the pane.
|
|
705
|
+
*/
|
|
706
|
+
setSession: publicProcedure.input(z2.object({
|
|
707
|
+
paneId: z2.string(),
|
|
708
|
+
agentConfigId: z2.string(),
|
|
709
|
+
directory: z2.string().optional()
|
|
710
|
+
})).mutation(async ({ input }) => {
|
|
711
|
+
const pane = db.select().from(panes).where(eq3(panes.id, input.paneId)).get();
|
|
712
|
+
if (!pane) {
|
|
713
|
+
throw new Error(`Pane ${input.paneId} not found`);
|
|
714
|
+
}
|
|
715
|
+
if (pane.content) {
|
|
716
|
+
throw new Error(`Pane ${input.paneId} already has content`);
|
|
717
|
+
}
|
|
718
|
+
const session = await amux2.createSession({
|
|
719
|
+
directory: input.directory ?? process.cwd(),
|
|
720
|
+
agentConfigId: input.agentConfigId
|
|
721
|
+
});
|
|
722
|
+
db.update(panes).set({ content: { type: "session", sessionId: session.id } }).where(eq3(panes.id, input.paneId)).run();
|
|
723
|
+
await amux2.startAgent(session.id);
|
|
724
|
+
return {
|
|
725
|
+
sessionId: session.id,
|
|
726
|
+
content: { type: "session", sessionId: session.id },
|
|
727
|
+
session: {
|
|
728
|
+
id: session.id,
|
|
729
|
+
directory: session.directory,
|
|
730
|
+
agentConfigId: session.agentConfigId,
|
|
731
|
+
model: session.model,
|
|
732
|
+
mode: session.mode,
|
|
733
|
+
createdAt: session.createdAt.toISOString(),
|
|
734
|
+
acpSessionId: session.acpSessionId
|
|
735
|
+
}
|
|
736
|
+
};
|
|
737
|
+
}),
|
|
738
|
+
/**
|
|
739
|
+
* Set browser content for an empty pane.
|
|
740
|
+
*/
|
|
741
|
+
setBrowserContent: publicProcedure.input(z2.object({
|
|
742
|
+
paneId: z2.string(),
|
|
743
|
+
url: z2.string().url()
|
|
744
|
+
})).mutation(async ({ input }) => {
|
|
745
|
+
const pane = db.select().from(panes).where(eq3(panes.id, input.paneId)).get();
|
|
746
|
+
if (!pane) {
|
|
747
|
+
throw new Error(`Pane ${input.paneId} not found`);
|
|
748
|
+
}
|
|
749
|
+
if (pane.content) {
|
|
750
|
+
throw new Error(`Pane ${input.paneId} already has content`);
|
|
751
|
+
}
|
|
752
|
+
const content = { type: "browser", url: input.url };
|
|
753
|
+
db.update(panes).set({ content }).where(eq3(panes.id, input.paneId)).run();
|
|
754
|
+
return { content };
|
|
755
|
+
}),
|
|
756
|
+
/**
|
|
757
|
+
* Update the URL of an existing browser pane.
|
|
758
|
+
*/
|
|
759
|
+
updateBrowserUrl: publicProcedure.input(z2.object({
|
|
760
|
+
paneId: z2.string(),
|
|
761
|
+
url: z2.string().url()
|
|
762
|
+
})).mutation(async ({ input }) => {
|
|
763
|
+
const pane = db.select().from(panes).where(eq3(panes.id, input.paneId)).get();
|
|
764
|
+
if (!pane) {
|
|
765
|
+
throw new Error(`Pane ${input.paneId} not found`);
|
|
766
|
+
}
|
|
767
|
+
if (pane.content?.type !== "browser") {
|
|
768
|
+
throw new Error(`Pane ${input.paneId} is not a browser pane`);
|
|
769
|
+
}
|
|
770
|
+
const content = { type: "browser", url: input.url };
|
|
771
|
+
db.update(panes).set({ content }).where(eq3(panes.id, input.paneId)).run();
|
|
772
|
+
return { content };
|
|
658
773
|
})
|
|
659
774
|
});
|
|
660
775
|
|
|
@@ -674,7 +789,10 @@ function getSessionIdForPane(paneId) {
|
|
|
674
789
|
if (!pane) {
|
|
675
790
|
throw new Error(`Pane ${paneId} not found`);
|
|
676
791
|
}
|
|
677
|
-
|
|
792
|
+
if (pane.content?.type !== "session") {
|
|
793
|
+
throw new Error(`Pane ${paneId} is not a session pane`);
|
|
794
|
+
}
|
|
795
|
+
return pane.content.sessionId;
|
|
678
796
|
}
|
|
679
797
|
var agentsRouter = router({
|
|
680
798
|
/**
|
|
@@ -745,17 +863,6 @@ var agentsRouter = router({
|
|
|
745
863
|
amux3.respondPermission(sessionId, input.requestId, input.optionId);
|
|
746
864
|
return { ok: true };
|
|
747
865
|
}),
|
|
748
|
-
/**
|
|
749
|
-
* Switch to a different agent.
|
|
750
|
-
*/
|
|
751
|
-
switchAgent: publicProcedure.input(z3.object({
|
|
752
|
-
paneId: z3.string(),
|
|
753
|
-
agentConfigId: z3.string()
|
|
754
|
-
})).mutation(async ({ input }) => {
|
|
755
|
-
const sessionId = getSessionIdForPane(input.paneId);
|
|
756
|
-
await amux3.switchAgent(sessionId, input.agentConfigId);
|
|
757
|
-
return { ok: true };
|
|
758
|
-
}),
|
|
759
866
|
/**
|
|
760
867
|
* Subscribe to updates for a pane's agent session.
|
|
761
868
|
*/
|
|
@@ -781,7 +888,10 @@ function getSessionIdForPane2(paneId) {
|
|
|
781
888
|
if (!pane) {
|
|
782
889
|
throw new Error(`Pane ${paneId} not found`);
|
|
783
890
|
}
|
|
784
|
-
|
|
891
|
+
if (pane.content?.type !== "session") {
|
|
892
|
+
throw new Error(`Pane ${paneId} is not a session pane`);
|
|
893
|
+
}
|
|
894
|
+
return pane.content.sessionId;
|
|
785
895
|
}
|
|
786
896
|
var filesRouter = router({
|
|
787
897
|
/**
|
|
@@ -798,24 +908,97 @@ var filesRouter = router({
|
|
|
798
908
|
})
|
|
799
909
|
});
|
|
800
910
|
|
|
911
|
+
// src/trpc/terminals.ts
|
|
912
|
+
import { z as z5 } from "zod";
|
|
913
|
+
import { eq as eq6 } from "drizzle-orm";
|
|
914
|
+
var amux5;
|
|
915
|
+
function setAmuxBridge5(bridge) {
|
|
916
|
+
amux5 = bridge;
|
|
917
|
+
}
|
|
918
|
+
var paneInput2 = z5.object({
|
|
919
|
+
paneId: z5.string()
|
|
920
|
+
});
|
|
921
|
+
function getSessionIdForPane3(paneId) {
|
|
922
|
+
const pane = db.select().from(panes).where(eq6(panes.id, paneId)).get();
|
|
923
|
+
if (!pane) {
|
|
924
|
+
throw new Error(`Pane ${paneId} not found`);
|
|
925
|
+
}
|
|
926
|
+
if (pane.content?.type !== "session") {
|
|
927
|
+
throw new Error(`Pane ${paneId} is not a session pane`);
|
|
928
|
+
}
|
|
929
|
+
return pane.content.sessionId;
|
|
930
|
+
}
|
|
931
|
+
var terminalsRouter = router({
|
|
932
|
+
/**
|
|
933
|
+
* Write raw input to terminal (keystrokes from client).
|
|
934
|
+
*/
|
|
935
|
+
write: publicProcedure.input(
|
|
936
|
+
z5.object({
|
|
937
|
+
paneId: z5.string(),
|
|
938
|
+
data: z5.string()
|
|
939
|
+
})
|
|
940
|
+
).mutation(({ input }) => {
|
|
941
|
+
const sessionId = getSessionIdForPane3(input.paneId);
|
|
942
|
+
amux5.terminalWrite(sessionId, input.data);
|
|
943
|
+
return { ok: true };
|
|
944
|
+
}),
|
|
945
|
+
/**
|
|
946
|
+
* Resize terminal dimensions.
|
|
947
|
+
*/
|
|
948
|
+
resize: publicProcedure.input(
|
|
949
|
+
z5.object({
|
|
950
|
+
paneId: z5.string(),
|
|
951
|
+
cols: z5.number().int().positive(),
|
|
952
|
+
rows: z5.number().int().positive()
|
|
953
|
+
})
|
|
954
|
+
).mutation(({ input }) => {
|
|
955
|
+
const sessionId = getSessionIdForPane3(input.paneId);
|
|
956
|
+
amux5.terminalResize(sessionId, input.cols, input.rows);
|
|
957
|
+
return { ok: true };
|
|
958
|
+
}),
|
|
959
|
+
/**
|
|
960
|
+
* Check if a pane is a terminal session.
|
|
961
|
+
*/
|
|
962
|
+
isTerminal: publicProcedure.input(paneInput2).query(({ input }) => {
|
|
963
|
+
const sessionId = getSessionIdForPane3(input.paneId);
|
|
964
|
+
return { isTerminal: amux5.isTerminalSession(sessionId) };
|
|
965
|
+
}),
|
|
966
|
+
/**
|
|
967
|
+
* Set terminal title (from OSC escape sequence).
|
|
968
|
+
*/
|
|
969
|
+
setTitle: publicProcedure.input(z5.object({
|
|
970
|
+
paneId: z5.string(),
|
|
971
|
+
title: z5.string()
|
|
972
|
+
})).mutation(({ input }) => {
|
|
973
|
+
const sessionId = getSessionIdForPane3(input.paneId);
|
|
974
|
+
amux5.updateSessionTitle(sessionId, input.title);
|
|
975
|
+
return { ok: true };
|
|
976
|
+
})
|
|
977
|
+
});
|
|
978
|
+
|
|
801
979
|
// src/trpc/router.ts
|
|
802
|
-
function initializeRouters(
|
|
803
|
-
setAmuxBridge(
|
|
804
|
-
setAmuxBridge2(
|
|
805
|
-
setAmuxBridge3(
|
|
806
|
-
setAmuxBridge4(
|
|
980
|
+
function initializeRouters(amux6) {
|
|
981
|
+
setAmuxBridge(amux6);
|
|
982
|
+
setAmuxBridge2(amux6);
|
|
983
|
+
setAmuxBridge3(amux6);
|
|
984
|
+
setAmuxBridge4(amux6);
|
|
985
|
+
setAmuxBridge5(amux6);
|
|
807
986
|
}
|
|
808
987
|
var shellaRouter = router({
|
|
809
988
|
windows: windowsRouter,
|
|
810
989
|
layout: layoutRouter,
|
|
811
990
|
agents: agentsRouter,
|
|
812
|
-
files: filesRouter
|
|
991
|
+
files: filesRouter,
|
|
992
|
+
terminals: terminalsRouter
|
|
813
993
|
});
|
|
814
994
|
|
|
815
995
|
// src/index.ts
|
|
816
996
|
var __dirname = path2.dirname(fileURLToPath(import.meta.url));
|
|
817
997
|
function createShellaServer(options = {}) {
|
|
818
998
|
const port = options.port ?? 3067;
|
|
999
|
+
if (options.verbose) {
|
|
1000
|
+
setVerbose(true);
|
|
1001
|
+
}
|
|
819
1002
|
const amuxBridge = createAmuxBridge();
|
|
820
1003
|
initializeRouters(amuxBridge);
|
|
821
1004
|
const app = express();
|
|
@@ -832,17 +1015,24 @@ function createShellaServer(options = {}) {
|
|
|
832
1015
|
applyWSSHandler({ wss, router: shellaRouter });
|
|
833
1016
|
return {
|
|
834
1017
|
start: () => {
|
|
835
|
-
return new Promise((resolve) => {
|
|
1018
|
+
return new Promise((resolve, reject) => {
|
|
1019
|
+
server.once("error", (err) => {
|
|
1020
|
+
if (err.code === "EADDRINUSE") {
|
|
1021
|
+
reject(new Error(`Port ${port} is already in use. Kill the other process or use a different port.`));
|
|
1022
|
+
} else {
|
|
1023
|
+
reject(err);
|
|
1024
|
+
}
|
|
1025
|
+
});
|
|
836
1026
|
server.listen(port, () => {
|
|
837
1027
|
const url = `http://localhost:${port}`;
|
|
838
|
-
|
|
1028
|
+
debug("shella", `Running on ${url}`);
|
|
839
1029
|
options.onReady?.(url);
|
|
840
1030
|
resolve();
|
|
841
1031
|
});
|
|
842
1032
|
});
|
|
843
1033
|
},
|
|
844
1034
|
stop: async () => {
|
|
845
|
-
|
|
1035
|
+
debug("shella", "Shutting down...");
|
|
846
1036
|
wss.close();
|
|
847
1037
|
await agentManager2.stopAll();
|
|
848
1038
|
server.close();
|
|
@@ -883,6 +1073,7 @@ async function startCommand(options) {
|
|
|
883
1073
|
else log2("Starting server...");
|
|
884
1074
|
const shella = createShellaServer({
|
|
885
1075
|
port,
|
|
1076
|
+
verbose,
|
|
886
1077
|
onReady: (url) => {
|
|
887
1078
|
if (s) s.stop("Ready");
|
|
888
1079
|
const lanIp = getLanIp();
|
|
@@ -905,7 +1096,13 @@ ${dim("press ctrl+c to stop")}
|
|
|
905
1096
|
}
|
|
906
1097
|
}
|
|
907
1098
|
});
|
|
908
|
-
|
|
1099
|
+
try {
|
|
1100
|
+
await shella.start();
|
|
1101
|
+
} catch (err) {
|
|
1102
|
+
if (s) s.stop("Failed");
|
|
1103
|
+
p.log.error(err instanceof Error ? err.message : String(err));
|
|
1104
|
+
process.exit(1);
|
|
1105
|
+
}
|
|
909
1106
|
const shutdown = async () => {
|
|
910
1107
|
console.log("");
|
|
911
1108
|
console.log(dim("stopping..."));
|