termi-board 0.1.0

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.
@@ -0,0 +1,643 @@
1
+ var U = Object.defineProperty;
2
+ var N = (r, e, t) => e in r ? U(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t;
3
+ var S = (r, e, t) => N(r, typeof e != "symbol" ? e + "" : e, t);
4
+ import { ipcMain as d, app as w, BrowserWindow as v, dialog as H, Menu as x, shell as R } from "electron";
5
+ import { fileURLToPath as L } from "node:url";
6
+ import l from "node:path";
7
+ import { existsSync as A, readFileSync as B, mkdirSync as _, writeFileSync as O, statSync as M } from "node:fs";
8
+ import { randomUUID as $ } from "node:crypto";
9
+ import { execFile as j } from "node:child_process";
10
+ import { readlink as J } from "node:fs/promises";
11
+ import { promisify as V } from "node:util";
12
+ import { spawn as q } from "node-pty";
13
+ const n = {
14
+ bootstrap: "termi-board/bootstrap",
15
+ closeSession: "termi-board/close-session",
16
+ createSession: "termi-board/create-session",
17
+ getSessionBuffer: "termi-board/get-session-buffer",
18
+ pickDirectory: "termi-board/pick-directory",
19
+ renameSession: "termi-board/rename-session",
20
+ reorderSessions: "termi-board/reorder-sessions",
21
+ resizeSession: "termi-board/resize-session",
22
+ restartSession: "termi-board/restart-session",
23
+ sessionData: "termi-board/session-data",
24
+ setActiveSession: "termi-board/set-active-session",
25
+ state: "termi-board/state",
26
+ writeToSession: "termi-board/write-to-session"
27
+ }, T = ["#ffab45", "#5ca8ff", "#68e0a3", "#ff7790", "#c593ff", "#f4d35e"], k = 12e4, G = V(j);
28
+ function C() {
29
+ return process.platform;
30
+ }
31
+ function b(r) {
32
+ return (r == null ? void 0 : r.trim().replace(/\s+/g, " ")) ?? "";
33
+ }
34
+ function X(r) {
35
+ return r.length > k ? r.slice(-k) : r;
36
+ }
37
+ function K(r) {
38
+ if (r === "win32") {
39
+ const i = process.env.COMSPEC || "powershell.exe", o = l.basename(i).replace(/\.exe$/i, "");
40
+ return o.toLowerCase().includes("powershell") ? {
41
+ args: ["-NoLogo"],
42
+ command: i,
43
+ label: "PowerShell"
44
+ } : {
45
+ args: [],
46
+ command: i,
47
+ label: o
48
+ };
49
+ }
50
+ const e = process.env.SHELL || "/bin/zsh", t = l.basename(e);
51
+ return {
52
+ args: ["bash", "fish", "ksh", "sh", "zsh"].some((i) => t.includes(i)) ? ["-l"] : [],
53
+ command: e,
54
+ label: t
55
+ };
56
+ }
57
+ function f(r, e) {
58
+ const t = e();
59
+ if (!t || t.isDestroyed() || r.sender !== t.webContents || r.senderFrame !== t.webContents.mainFrame)
60
+ return !1;
61
+ const s = r.senderFrame.url, i = t.webContents.getURL();
62
+ return !!s && s === i;
63
+ }
64
+ class Q {
65
+ constructor(e) {
66
+ S(this, "activeSessionId", null);
67
+ S(this, "initialized", !1);
68
+ S(this, "orderedIds", []);
69
+ S(this, "sessions", /* @__PURE__ */ new Map());
70
+ this.getWindow = e;
71
+ }
72
+ get defaultWorkingDirectory() {
73
+ return w.getPath("home");
74
+ }
75
+ get workspaceFilePath() {
76
+ return l.join(w.getPath("userData"), "termi-board.workspace.json");
77
+ }
78
+ async ensureInitialized() {
79
+ if (this.initialized)
80
+ return;
81
+ const e = this.loadWorkspace();
82
+ e.sessions.length === 0 ? this.createSession(void 0, {
83
+ broadcast: !1,
84
+ makeActive: !0,
85
+ persist: !1
86
+ }) : (e.sessions.forEach((t, s) => {
87
+ this.createSession(t, {
88
+ broadcast: !1,
89
+ index: s,
90
+ makeActive: !1,
91
+ persist: !1
92
+ });
93
+ }), this.activeSessionId = e.activeSessionId && this.sessions.has(e.activeSessionId) ? e.activeSessionId : this.orderedIds[0] ?? null), this.initialized = !0, this.persistWorkspace();
94
+ }
95
+ getActiveSessionId() {
96
+ return this.activeSessionId;
97
+ }
98
+ getState() {
99
+ return {
100
+ activeSessionId: this.activeSessionId,
101
+ homeDirectory: this.defaultWorkingDirectory,
102
+ platform: C(),
103
+ sessions: this.orderedIds.map((e) => this.sessions.get(e)).filter((e) => !!e).map((e, t) => this.serializeSession(e, t))
104
+ };
105
+ }
106
+ createSession(e, t = {}) {
107
+ const s = e && "id" in e && e.id ? e.id : $(), i = b(e == null ? void 0 : e.title) || this.generateTitle(), o = this.resolveWorkingDirectory(e == null ? void 0 : e.cwd), a = e && "accent" in e && e.accent ? e.accent : this.pickAccent(), h = Date.now(), u = {
108
+ accent: a,
109
+ buffer: "",
110
+ createdAt: h,
111
+ cwd: o,
112
+ cwdRefreshInFlight: !1,
113
+ cwdRefreshTimeout: null,
114
+ exitCode: null,
115
+ generation: 0,
116
+ id: s,
117
+ pty: null,
118
+ shell: "",
119
+ status: "running",
120
+ title: i,
121
+ updatedAt: h
122
+ };
123
+ this.sessions.set(s, u), this.insertSessionId(s, t.index);
124
+ try {
125
+ this.spawnShell(u);
126
+ } catch (D) {
127
+ throw this.sessions.delete(s), this.orderedIds = this.orderedIds.filter((z) => z !== s), D;
128
+ }
129
+ return (t.makeActive ?? !0) && (this.activeSessionId = s), (t.persist ?? !0) && this.persistWorkspace(), (t.broadcast ?? !0) && this.broadcastState(), this.serializeSession(u, this.orderedIds.indexOf(s));
130
+ }
131
+ closeSession(e) {
132
+ const t = this.sessions.get(e);
133
+ if (!t)
134
+ return;
135
+ const s = this.orderedIds.indexOf(e);
136
+ this.sessions.delete(e), this.orderedIds = this.orderedIds.filter((i) => i !== e), this.activeSessionId === e && (this.activeSessionId = this.orderedIds[s] ?? this.orderedIds[s - 1] ?? null);
137
+ try {
138
+ this.clearWorkingDirectoryRefresh(t), t.pty.kill();
139
+ } catch {
140
+ }
141
+ this.persistWorkspace(), this.broadcastState();
142
+ }
143
+ restartSession(e) {
144
+ const t = this.sessions.get(e);
145
+ if (t) {
146
+ try {
147
+ t.pty.kill();
148
+ } catch {
149
+ }
150
+ return this.spawnShell(t), this.persistWorkspace(), this.broadcastState(), this.serializeSession(t, this.orderedIds.indexOf(e));
151
+ }
152
+ }
153
+ renameSession(e) {
154
+ const t = this.sessions.get(e.id);
155
+ if (!t)
156
+ return;
157
+ const s = b(e.title);
158
+ return s ? (t.title = s, t.updatedAt = Date.now(), this.persistWorkspace(), this.broadcastState(), this.serializeSession(t, this.orderedIds.indexOf(t.id))) : this.serializeSession(t, this.orderedIds.indexOf(t.id));
159
+ }
160
+ reorderSessions(e) {
161
+ const t = e.orderedIds.filter((i) => this.sessions.has(i)), s = this.orderedIds.filter((i) => !t.includes(i));
162
+ return this.orderedIds = [...t, ...s], this.persistWorkspace(), this.broadcastState(), this.getState();
163
+ }
164
+ setActiveSession(e) {
165
+ this.sessions.has(e) && (this.activeSessionId = e, this.persistWorkspace(), this.broadcastState());
166
+ }
167
+ writeToSession(e) {
168
+ const t = this.sessions.get(e.id);
169
+ !t || t.status !== "running" || (t.pty.write(e.data), this.scheduleWorkingDirectoryRefresh(t.id, 220));
170
+ }
171
+ resizeSession(e) {
172
+ const t = this.sessions.get(e.id);
173
+ !t || t.status !== "running" || e.cols < 2 || e.rows < 2 || t.pty.resize(e.cols, e.rows);
174
+ }
175
+ getSessionBuffer(e) {
176
+ var t;
177
+ return ((t = this.sessions.get(e)) == null ? void 0 : t.buffer) ?? "";
178
+ }
179
+ dispose() {
180
+ this.sessions.forEach((e) => {
181
+ try {
182
+ this.clearWorkingDirectoryRefresh(e), e.pty.kill();
183
+ } catch {
184
+ }
185
+ });
186
+ }
187
+ broadcastSessionData(e) {
188
+ const t = this.getWindow();
189
+ !t || t.isDestroyed() || t.webContents.send(n.sessionData, e);
190
+ }
191
+ broadcastState() {
192
+ const e = this.getWindow();
193
+ !e || e.isDestroyed() || e.webContents.send(n.state, this.getState());
194
+ }
195
+ generateTitle() {
196
+ const e = new Set(Array.from(this.sessions.values(), (s) => s.title));
197
+ let t = 1;
198
+ for (; e.has(`Terminal ${t}`); )
199
+ t += 1;
200
+ return `Terminal ${t}`;
201
+ }
202
+ insertSessionId(e, t) {
203
+ if (typeof t != "number" || t < 0 || t >= this.orderedIds.length) {
204
+ this.orderedIds.push(e);
205
+ return;
206
+ }
207
+ this.orderedIds.splice(t, 0, e);
208
+ }
209
+ loadWorkspace() {
210
+ if (!A(this.workspaceFilePath))
211
+ return {
212
+ activeSessionId: null,
213
+ sessions: []
214
+ };
215
+ try {
216
+ const e = JSON.parse(B(this.workspaceFilePath, "utf8")), t = Array.isArray(e.sessions) ? e.sessions.flatMap((s) => {
217
+ if (!s || typeof s != "object")
218
+ return [];
219
+ const i = s;
220
+ return typeof i.id != "string" || typeof i.title != "string" || typeof i.cwd != "string" || typeof i.accent != "string" ? [] : [{
221
+ accent: i.accent,
222
+ cwd: i.cwd,
223
+ id: i.id,
224
+ title: i.title
225
+ }];
226
+ }) : [];
227
+ return {
228
+ activeSessionId: typeof e.activeSessionId == "string" ? e.activeSessionId : null,
229
+ sessions: t
230
+ };
231
+ } catch {
232
+ return {
233
+ activeSessionId: null,
234
+ sessions: []
235
+ };
236
+ }
237
+ }
238
+ persistWorkspace() {
239
+ const e = {
240
+ activeSessionId: this.activeSessionId && this.sessions.has(this.activeSessionId) ? this.activeSessionId : null,
241
+ sessions: this.orderedIds.map((t) => this.sessions.get(t)).filter((t) => !!t).map((t) => ({
242
+ accent: t.accent,
243
+ cwd: t.cwd,
244
+ id: t.id,
245
+ title: t.title
246
+ }))
247
+ };
248
+ _(l.dirname(this.workspaceFilePath), { recursive: !0 }), O(this.workspaceFilePath, JSON.stringify(e, null, 2));
249
+ }
250
+ pickAccent() {
251
+ return T[this.orderedIds.length % T.length];
252
+ }
253
+ resolveWorkingDirectory(e) {
254
+ const t = b(e) ? l.resolve(e) : this.defaultWorkingDirectory;
255
+ if (!A(t))
256
+ return this.defaultWorkingDirectory;
257
+ try {
258
+ return M(t).isDirectory() ? t : this.defaultWorkingDirectory;
259
+ } catch {
260
+ return this.defaultWorkingDirectory;
261
+ }
262
+ }
263
+ serializeSession(e, t) {
264
+ return {
265
+ accent: e.accent,
266
+ createdAt: e.createdAt,
267
+ cwd: e.cwd,
268
+ exitCode: e.exitCode,
269
+ generation: e.generation,
270
+ id: e.id,
271
+ order: t,
272
+ shell: e.shell,
273
+ status: e.status,
274
+ title: e.title,
275
+ updatedAt: e.updatedAt
276
+ };
277
+ }
278
+ clearWorkingDirectoryRefresh(e) {
279
+ e.cwdRefreshTimeout && (clearTimeout(e.cwdRefreshTimeout), e.cwdRefreshTimeout = null), e.cwdRefreshInFlight = !1;
280
+ }
281
+ scheduleWorkingDirectoryRefresh(e, t = 140) {
282
+ const s = this.sessions.get(e);
283
+ !s || s.status !== "running" || (s.cwdRefreshTimeout && clearTimeout(s.cwdRefreshTimeout), s.cwdRefreshTimeout = setTimeout(() => {
284
+ s.cwdRefreshTimeout = null, this.refreshWorkingDirectory(e);
285
+ }, t));
286
+ }
287
+ async refreshWorkingDirectory(e) {
288
+ const t = this.sessions.get(e);
289
+ if (!t || t.status !== "running" || t.cwdRefreshInFlight)
290
+ return;
291
+ t.cwdRefreshInFlight = !0;
292
+ const s = t.generation, i = t.pty.pid;
293
+ try {
294
+ const o = await this.readWorkingDirectory(i), a = this.sessions.get(e);
295
+ if (!a || a.generation !== s || a.status !== "running" || !o || o === a.cwd)
296
+ return;
297
+ a.cwd = o, a.updatedAt = Date.now(), this.persistWorkspace(), this.broadcastState();
298
+ } finally {
299
+ const o = this.sessions.get(e);
300
+ o && o.generation === s && (o.cwdRefreshInFlight = !1);
301
+ }
302
+ }
303
+ async readWorkingDirectory(e) {
304
+ if (!Number.isInteger(e) || e <= 0)
305
+ return null;
306
+ try {
307
+ return await J(`/proc/${e}/cwd`);
308
+ } catch {
309
+ }
310
+ const t = process.platform === "darwin" ? "/usr/sbin/lsof" : "lsof";
311
+ try {
312
+ const { stdout: s } = await G(t, ["-a", "-d", "cwd", "-p", String(e), "-Fn"], {
313
+ maxBuffer: 8192,
314
+ timeout: 1200,
315
+ windowsHide: !0
316
+ }), i = s.split(/\r?\n/u).find((o) => o.startsWith("n") && o.length > 1);
317
+ return i ? i.slice(1) : null;
318
+ } catch {
319
+ return null;
320
+ }
321
+ }
322
+ spawnShell(e) {
323
+ const t = K(C()), s = e.generation + 1;
324
+ this.clearWorkingDirectoryRefresh(e);
325
+ const i = q(t.command, t.args, {
326
+ cols: 120,
327
+ cwd: e.cwd,
328
+ env: {
329
+ ...process.env,
330
+ COLORTERM: "truecolor",
331
+ TERM: "xterm-256color"
332
+ },
333
+ name: "xterm-256color",
334
+ rows: 32
335
+ });
336
+ e.buffer = "", e.exitCode = null, e.generation = s, e.pty = i, e.shell = t.label, e.status = "running", e.updatedAt = Date.now(), this.scheduleWorkingDirectoryRefresh(e.id, 60), i.onData((o) => {
337
+ const a = this.sessions.get(e.id);
338
+ !a || a.generation !== s || (a.buffer = X(a.buffer + o), a.updatedAt = Date.now(), this.broadcastSessionData({ data: o, id: e.id }), this.scheduleWorkingDirectoryRefresh(e.id));
339
+ }), i.onExit(({ exitCode: o }) => {
340
+ const a = this.sessions.get(e.id);
341
+ !a || a.generation !== s || (this.clearWorkingDirectoryRefresh(a), a.exitCode = typeof o == "number" ? o : null, a.status = "exited", a.updatedAt = Date.now(), this.persistWorkspace(), this.broadcastState());
342
+ });
343
+ }
344
+ }
345
+ function Y(r, e) {
346
+ d.removeHandler(n.bootstrap), d.handle(n.bootstrap, async (t) => {
347
+ if (!f(t, e))
348
+ throw new Error("Untrusted IPC sender.");
349
+ return await r.ensureInitialized(), r.getState();
350
+ }), d.removeHandler(n.createSession), d.handle(n.createSession, async (t, s) => {
351
+ if (!f(t, e))
352
+ throw new Error("Untrusted IPC sender.");
353
+ return await r.ensureInitialized(), r.createSession(s);
354
+ }), d.removeHandler(n.closeSession), d.handle(n.closeSession, async (t, s) => {
355
+ if (!f(t, e))
356
+ throw new Error("Untrusted IPC sender.");
357
+ await r.ensureInitialized(), r.closeSession(s);
358
+ }), d.removeHandler(n.restartSession), d.handle(n.restartSession, async (t, s) => {
359
+ if (!f(t, e))
360
+ throw new Error("Untrusted IPC sender.");
361
+ return await r.ensureInitialized(), r.restartSession(s);
362
+ }), d.removeHandler(n.renameSession), d.handle(n.renameSession, async (t, s) => {
363
+ if (!f(t, e))
364
+ throw new Error("Untrusted IPC sender.");
365
+ return await r.ensureInitialized(), r.renameSession(s);
366
+ }), d.removeHandler(n.reorderSessions), d.handle(n.reorderSessions, async (t, s) => {
367
+ if (!f(t, e))
368
+ throw new Error("Untrusted IPC sender.");
369
+ return await r.ensureInitialized(), r.reorderSessions(s);
370
+ }), d.removeHandler(n.setActiveSession), d.handle(n.setActiveSession, async (t, s) => {
371
+ if (!f(t, e))
372
+ throw new Error("Untrusted IPC sender.");
373
+ await r.ensureInitialized(), r.setActiveSession(s);
374
+ }), d.removeHandler(n.getSessionBuffer), d.handle(n.getSessionBuffer, async (t, s) => {
375
+ if (!f(t, e))
376
+ throw new Error("Untrusted IPC sender.");
377
+ return await r.ensureInitialized(), r.getSessionBuffer(s);
378
+ }), d.removeAllListeners(n.writeToSession), d.on(n.writeToSession, (t, s) => {
379
+ f(t, e) && r.writeToSession(s);
380
+ }), d.removeAllListeners(n.resizeSession), d.on(n.resizeSession, (t, s) => {
381
+ f(t, e) && r.resizeSession(s);
382
+ });
383
+ }
384
+ const P = l.dirname(L(import.meta.url));
385
+ process.env.APP_ROOT = l.join(P, "..");
386
+ const I = process.env.VITE_DEV_SERVER_URL, we = l.join(process.env.APP_ROOT, "dist-electron"), W = l.join(process.env.APP_ROOT, "dist");
387
+ process.env.VITE_PUBLIC = I ? l.join(process.env.APP_ROOT, "public") : W;
388
+ const g = process.env.TERMINAL_DASHBOARD_DEMO_CAPTURE_DIR || "", y = process.env.TERMINAL_DASHBOARD_USER_DATA || "";
389
+ y && (_(y, { recursive: !0 }), w.setPath("userData", y));
390
+ let c;
391
+ const m = new Q(() => c);
392
+ function E(r) {
393
+ try {
394
+ return new URL(r).protocol === "https:";
395
+ } catch {
396
+ return !1;
397
+ }
398
+ }
399
+ function Z() {
400
+ if (I) {
401
+ const r = new URL(I);
402
+ return g && r.searchParams.set("demo", "1"), {
403
+ type: "url",
404
+ value: r.toString()
405
+ };
406
+ }
407
+ return {
408
+ type: "file",
409
+ value: l.join(W, "index.html")
410
+ };
411
+ }
412
+ function p(r) {
413
+ return new Promise((e) => {
414
+ setTimeout(e, r);
415
+ });
416
+ }
417
+ async function ee(r) {
418
+ if (!g)
419
+ return;
420
+ _(g, { recursive: !0 });
421
+ async function e(u) {
422
+ return r.webContents.executeJavaScript(u, !0);
423
+ }
424
+ async function t(u) {
425
+ const D = await r.webContents.capturePage();
426
+ O(l.join(g, u), D.toPNG());
427
+ }
428
+ async function s() {
429
+ for (let u = 0; u < 120; u += 1) {
430
+ if (await e("Boolean(window.__terminalDashboardDemo?.isReady)"))
431
+ return;
432
+ await p(250);
433
+ }
434
+ throw new Error("The demo renderer did not become ready in time.");
435
+ }
436
+ const i = w.getPath("home"), o = process.env.APP_ROOT || i, a = l.join(i, "Documents");
437
+ await s(), await p(1200), await e(`
438
+ (async () => {
439
+ window.__terminalDashboardDemo?.clearHighlight()
440
+ window.__terminalDashboardDemo?.setCaption('Watch multiple terminal sessions in one board.')
441
+ window.__terminalDashboardDemo?.setExpandedSession(null)
442
+ window.__terminalDashboardDemo?.setFileDropActive(false)
443
+ const state = await window.terminalDashboard.bootstrap()
444
+ const currentIds = state.sessions.map((session) => session.id)
445
+ for (let index = currentIds.length - 1; index > 0; index -= 1) {
446
+ await window.terminalDashboard.closeSession(currentIds[index])
447
+ }
448
+ await window.terminalDashboard.renameSession({ id: currentIds[0], title: 'Terminal 1' })
449
+ await window.terminalDashboard.createSession({ cwd: ${JSON.stringify(o)} })
450
+ await window.terminalDashboard.createSession({ cwd: ${JSON.stringify(i)} })
451
+ const nextState = await window.terminalDashboard.bootstrap()
452
+ for (const session of nextState.sessions) {
453
+ window.terminalDashboard.writeToSession({ id: session.id, data: 'pwd\\r' })
454
+ }
455
+ return nextState.sessions.map((session) => session.id)
456
+ })()
457
+ `), await p(1800), await t("01-board.png"), await e(`
458
+ (async () => {
459
+ window.__terminalDashboardDemo?.setCaption('Add a terminal instantly with +.')
460
+ window.__terminalDashboardDemo?.highlight('.icon-button--primary')
461
+ await window.terminalDashboard.createSession({ cwd: ${JSON.stringify(i)} })
462
+ const state = await window.terminalDashboard.bootstrap()
463
+ const newestSession = state.sessions.at(-1)
464
+ if (newestSession) {
465
+ window.terminalDashboard.writeToSession({ id: newestSession.id, data: 'pwd\\r' })
466
+ }
467
+ })()
468
+ `), await p(1500), await t("02-plus.png");
469
+ const h = await e(`
470
+ (async () => {
471
+ window.__terminalDashboardDemo?.setCaption('Drop a folder to open a terminal there.')
472
+ window.__terminalDashboardDemo?.clearHighlight()
473
+ window.__terminalDashboardDemo?.highlight('.terminal-stage__panel')
474
+ window.__terminalDashboardDemo?.setFileDropActive(true)
475
+ await window.terminalDashboard.createSession({ cwd: ${JSON.stringify(a)} })
476
+ const state = await window.terminalDashboard.bootstrap()
477
+ const newestSession = state.sessions.at(-1)
478
+ if (newestSession) {
479
+ window.terminalDashboard.writeToSession({ id: newestSession.id, data: 'pwd\\r' })
480
+ }
481
+ return newestSession?.id ?? null
482
+ })()
483
+ `);
484
+ if (await p(1500), await t("03-drop.png"), !h)
485
+ throw new Error("Failed to create the folder-drop demo session.");
486
+ await e(`
487
+ (async () => {
488
+ window.__terminalDashboardDemo?.setFileDropActive(false)
489
+ await window.terminalDashboard.renameSession({ id: ${JSON.stringify(h)}, title: 'Docs Review' })
490
+ window.__terminalDashboardDemo?.setCaption('Rename a session inline to keep context clear.')
491
+ window.__terminalDashboardDemo?.clearHighlight()
492
+ window.__terminalDashboardDemo?.highlight('[data-session-id="${h}"]')
493
+ })()
494
+ `), await p(1400), await t("04-rename.png"), await e(`
495
+ (async () => {
496
+ const state = await window.terminalDashboard.bootstrap()
497
+ const orderedIds = state.sessions.map((session) => session.id)
498
+ const reorderedIds = [${JSON.stringify(h)}].concat(
499
+ orderedIds.filter((sessionId) => sessionId !== ${JSON.stringify(h)})
500
+ )
501
+ await window.terminalDashboard.reorderSessions({ orderedIds: reorderedIds })
502
+ await window.terminalDashboard.setActiveSession(${JSON.stringify(h)})
503
+ window.__terminalDashboardDemo?.setCaption('Reorder the dashboard by dragging session headers.')
504
+ window.__terminalDashboardDemo?.clearHighlight()
505
+ window.__terminalDashboardDemo?.highlight('[data-sidebar-session-id="${h}"]')
506
+ })()
507
+ `), await p(1500), await t("05-reorder.png"), await e(`
508
+ (async () => {
509
+ await window.terminalDashboard.setActiveSession(${JSON.stringify(h)})
510
+ window.__terminalDashboardDemo?.setExpandedSession(${JSON.stringify(h)})
511
+ window.__terminalDashboardDemo?.setCaption('Expand one session when you need full focus.')
512
+ window.__terminalDashboardDemo?.clearHighlight()
513
+ window.__terminalDashboardDemo?.highlight('[data-session-id="${h}"] .terminal-pane__expand')
514
+ })()
515
+ `), await p(1500), await t("06-expand.png"), await e(`
516
+ (() => {
517
+ window.__terminalDashboardDemo?.clearHighlight()
518
+ window.__terminalDashboardDemo?.setCaption(null)
519
+ window.__terminalDashboardDemo?.setFileDropActive(false)
520
+ return true
521
+ })()
522
+ `), await p(600), w.quit();
523
+ }
524
+ function te() {
525
+ const r = [
526
+ {
527
+ label: "Workspace",
528
+ submenu: [
529
+ {
530
+ label: "New Terminal",
531
+ accelerator: "CmdOrCtrl+T",
532
+ click: () => {
533
+ m.ensureInitialized().then(() => {
534
+ m.createSession();
535
+ });
536
+ }
537
+ },
538
+ {
539
+ label: "Restart Active Terminal",
540
+ accelerator: "CmdOrCtrl+Shift+R",
541
+ click: () => {
542
+ m.ensureInitialized().then(() => {
543
+ const e = m.getActiveSessionId();
544
+ e && m.restartSession(e);
545
+ });
546
+ }
547
+ },
548
+ {
549
+ label: "Close Active Terminal",
550
+ accelerator: "CmdOrCtrl+Shift+W",
551
+ click: () => {
552
+ m.ensureInitialized().then(() => {
553
+ const e = m.getActiveSessionId();
554
+ e && m.closeSession(e);
555
+ });
556
+ }
557
+ },
558
+ { type: "separator" },
559
+ process.platform === "darwin" ? { role: "close" } : { role: "quit" }
560
+ ]
561
+ },
562
+ {
563
+ label: "Edit",
564
+ submenu: [
565
+ { role: "undo" },
566
+ { role: "redo" },
567
+ { type: "separator" },
568
+ { role: "cut" },
569
+ { role: "copy" },
570
+ { role: "paste" },
571
+ { role: "selectAll" }
572
+ ]
573
+ },
574
+ {
575
+ label: "View",
576
+ submenu: [
577
+ { role: "reload" },
578
+ { role: "forceReload" },
579
+ { role: "toggleDevTools" },
580
+ { type: "separator" },
581
+ { role: "togglefullscreen" }
582
+ ]
583
+ }
584
+ ];
585
+ return process.platform === "darwin" && r.unshift({
586
+ label: w.name,
587
+ submenu: [{ role: "about" }, { type: "separator" }, { role: "services" }, { type: "separator" }, { role: "hide" }, { role: "hideOthers" }, { role: "unhide" }, { type: "separator" }, { role: "quit" }]
588
+ }), x.buildFromTemplate(r);
589
+ }
590
+ function F() {
591
+ const r = Z();
592
+ c = new v({
593
+ width: 1560,
594
+ height: 980,
595
+ minWidth: 1120,
596
+ minHeight: 720,
597
+ title: "TermiBoard",
598
+ backgroundColor: "#07111b",
599
+ titleBarStyle: process.platform === "darwin" ? "hiddenInset" : "default",
600
+ show: !1,
601
+ webPreferences: {
602
+ preload: l.join(P, "preload.mjs"),
603
+ contextIsolation: !0,
604
+ nodeIntegration: !1
605
+ }
606
+ }), c.once("ready-to-show", () => {
607
+ c == null || c.show();
608
+ }), g && c.webContents.once("did-finish-load", () => {
609
+ c && ee(c).catch((e) => {
610
+ console.error("[demo-capture]", e), w.exit(1);
611
+ });
612
+ }), c.on("closed", () => {
613
+ c = null;
614
+ }), c.webContents.setWindowOpenHandler(({ url: e }) => (E(e) && R.openExternal(e), { action: "deny" })), c.webContents.on("will-navigate", (e, t) => {
615
+ t !== (c == null ? void 0 : c.webContents.getURL()) && (e.preventDefault(), E(t) && R.openExternal(t));
616
+ }), r.type === "url" ? c.loadURL(r.value) : c.loadFile(r.value);
617
+ }
618
+ w.on("window-all-closed", () => {
619
+ process.platform !== "darwin" && (w.quit(), c = null);
620
+ });
621
+ w.on("activate", () => {
622
+ v.getAllWindows().length === 0 && F();
623
+ });
624
+ w.whenReady().then(() => {
625
+ w.setName("TermiBoard"), Y(m, () => c), d.removeHandler(n.pickDirectory), d.handle(n.pickDirectory, async (r, e) => {
626
+ const t = v.fromWebContents(r.sender);
627
+ if (!t || t.isDestroyed() || t !== c || r.senderFrame !== t.webContents.mainFrame)
628
+ return null;
629
+ const s = await H.showOpenDialog(t, {
630
+ defaultPath: e == null ? void 0 : e.defaultPath,
631
+ properties: ["createDirectory", "openDirectory"]
632
+ });
633
+ return s.canceled ? null : s.filePaths[0] ?? null;
634
+ }), x.setApplicationMenu(te()), F();
635
+ });
636
+ w.on("before-quit", () => {
637
+ m.dispose();
638
+ });
639
+ export {
640
+ we as MAIN_DIST,
641
+ W as RENDERER_DIST,
642
+ I as VITE_DEV_SERVER_URL
643
+ };
@@ -0,0 +1 @@
1
+ "use strict";const s=require("electron"),r={bootstrap:"termi-board/bootstrap",closeSession:"termi-board/close-session",createSession:"termi-board/create-session",getSessionBuffer:"termi-board/get-session-buffer",pickDirectory:"termi-board/pick-directory",renameSession:"termi-board/rename-session",reorderSessions:"termi-board/reorder-sessions",resizeSession:"termi-board/resize-session",restartSession:"termi-board/restart-session",sessionData:"termi-board/session-data",setActiveSession:"termi-board/set-active-session",state:"termi-board/state",writeToSession:"termi-board/write-to-session"},n={bootstrap:()=>s.ipcRenderer.invoke(r.bootstrap),createSession:e=>s.ipcRenderer.invoke(r.createSession,e),closeSession:e=>s.ipcRenderer.invoke(r.closeSession,e),restartSession:e=>s.ipcRenderer.invoke(r.restartSession,e),renameSession:e=>s.ipcRenderer.invoke(r.renameSession,e),reorderSessions:e=>s.ipcRenderer.invoke(r.reorderSessions,e),pickDirectory:e=>s.ipcRenderer.invoke(r.pickDirectory,e),readClipboardText:()=>Promise.resolve(s.clipboard.readText()),writeClipboardText:e=>Promise.resolve(s.clipboard.writeText(e)),setActiveSession:e=>s.ipcRenderer.invoke(r.setActiveSession,e),writeToSession:e=>s.ipcRenderer.send(r.writeToSession,e),resizeSession:e=>s.ipcRenderer.send(r.resizeSession,e),getSessionBuffer:e=>s.ipcRenderer.invoke(r.getSessionBuffer,e),getPathForFile:e=>s.webUtils.getPathForFile(e),onState:e=>{const i=(t,o)=>{e(o)};return s.ipcRenderer.on(r.state,i),()=>{s.ipcRenderer.off(r.state,i)}},onSessionData:e=>{const i=(t,o)=>{e(o)};return s.ipcRenderer.on(r.sessionData,i),()=>{s.ipcRenderer.off(r.sessionData,i)}}};s.contextBridge.exposeInMainWorld("terminalDashboard",n);
@@ -0,0 +1,46 @@
1
+ // @see - https://www.electron.build/configuration/configuration
2
+ {
3
+ "$schema": "https://raw.githubusercontent.com/electron-userland/electron-builder/master/packages/app-builder-lib/scheme.json",
4
+ "appId": "com.codex.termiboard",
5
+ "asar": true,
6
+ "asarUnpack": [
7
+ "node_modules/node-pty/**/*"
8
+ ],
9
+ "productName": "TermiBoard",
10
+ "directories": {
11
+ "output": "release/${version}"
12
+ },
13
+ "files": [
14
+ "dist",
15
+ "dist-electron"
16
+ ],
17
+ "mac": {
18
+ "target": [
19
+ "dmg"
20
+ ],
21
+ "artifactName": "${productName}-Mac-${version}-Installer.${ext}"
22
+ },
23
+ "win": {
24
+ "target": [
25
+ {
26
+ "target": "nsis",
27
+ "arch": [
28
+ "x64"
29
+ ]
30
+ }
31
+ ],
32
+ "artifactName": "${productName}-Windows-${version}-Setup.${ext}"
33
+ },
34
+ "nsis": {
35
+ "oneClick": false,
36
+ "perMachine": false,
37
+ "allowToChangeInstallationDirectory": true,
38
+ "deleteAppDataOnUninstall": false
39
+ },
40
+ "linux": {
41
+ "target": [
42
+ "AppImage"
43
+ ],
44
+ "artifactName": "${productName}-Linux-${version}.${ext}"
45
+ }
46
+ }