@bakapiano/ccsm 0.22.6 → 0.22.7
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/CLAUDE.md +538 -538
- package/README.md +189 -189
- package/bin/ccsm.js +235 -235
- package/lib/cliActivity.js +139 -139
- package/lib/codexSeed.js +183 -183
- package/lib/config.js +279 -274
- package/lib/devices.js +229 -229
- package/lib/folders.js +124 -124
- package/lib/localCliSessions.js +519 -519
- package/lib/persistedSessions.js +129 -129
- package/lib/tunnel.js +621 -621
- package/lib/webTerminal.js +225 -225
- package/lib/workspace.js +233 -233
- package/package.json +57 -57
- package/public/css/base.css +99 -99
- package/public/css/cards.css +183 -183
- package/public/css/feedback.css +504 -504
- package/public/css/forms.css +453 -453
- package/public/css/layout.css +154 -154
- package/public/css/modal.css +190 -190
- package/public/css/responsive.css +176 -176
- package/public/css/sidebar.css +707 -707
- package/public/css/terminals.css +546 -546
- package/public/css/tokens.css +81 -81
- package/public/css/wco.css +196 -196
- package/public/css/widgets.css +2725 -2725
- package/public/index.html +152 -152
- package/public/js/api.js +371 -371
- package/public/js/backend.js +149 -149
- package/public/js/components/App.js +73 -73
- package/public/js/components/DirectoryPicker.js +203 -203
- package/public/js/components/EntityFormModal.js +153 -153
- package/public/js/components/Modal.js +57 -57
- package/public/js/components/OfflineBanner.js +67 -67
- package/public/js/components/PageTitleBar.js +13 -13
- package/public/js/components/PendingApprovalOverlay.js +128 -128
- package/public/js/components/Picker.js +179 -179
- package/public/js/components/Popover.js +55 -55
- package/public/js/components/RestartOverlay.js +36 -36
- package/public/js/components/Sidebar.js +380 -380
- package/public/js/components/TerminalInstance.js +28 -0
- package/public/js/components/useDragSort.js +67 -67
- package/public/js/dialog.js +67 -67
- package/public/js/icons.js +212 -212
- package/public/js/main.js +296 -296
- package/public/js/pages/AboutPage.js +90 -90
- package/public/js/pages/ConfigurePage.js +728 -713
- package/public/js/pages/LaunchPage.js +421 -421
- package/public/js/pages/RemotePage.js +743 -743
- package/public/js/pages/SessionsPage.js +53 -53
- package/public/js/state.js +335 -335
- package/scripts/dev.js +149 -149
- package/scripts/install.js +153 -153
- package/scripts/restart-helper.js +96 -96
- package/scripts/upgrade-helper.js +687 -687
- package/server.js +1820 -1807
- package/public/manifest.webmanifest +0 -25
- package/public/setup/index.html +0 -567
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
// Sessions page · the main pane. Shows the terminal for the currently
|
|
2
|
-
// selected session (activeSessionId), with a thin header providing
|
|
3
|
-
// session metadata + a session-tabs strip (future multi-tab support)
|
|
4
|
-
// and a kebab menu top-right for per-session actions. When a session is
|
|
5
|
-
// selected but not running we auto-resume it — no manual button.
|
|
6
|
-
|
|
1
|
+
// Sessions page · the main pane. Shows the terminal for the currently
|
|
2
|
+
// selected session (activeSessionId), with a thin header providing
|
|
3
|
+
// session metadata + a session-tabs strip (future multi-tab support)
|
|
4
|
+
// and a kebab menu top-right for per-session actions. When a session is
|
|
5
|
+
// selected but not running we auto-resume it — no manual button.
|
|
6
|
+
|
|
7
7
|
import { html } from '../html.js';
|
|
8
8
|
import { useEffect, useRef, useState } from 'preact/hooks';
|
|
9
9
|
import { activeSessionId, sessions, config, selectTab, selectSession, clockTick } from '../state.js';
|
|
@@ -29,7 +29,7 @@ function SessionTabs({ activeId, openSessions, onActivate, onClose, onReorder, o
|
|
|
29
29
|
<div class="session-tabs" role="tablist">
|
|
30
30
|
<div class="session-tabs-list">
|
|
31
31
|
${open.map((s) => {
|
|
32
|
-
const cli = (config.value?.clis || []).find((c) => c.id === s.cliId);
|
|
32
|
+
const cli = (config.value?.clis || []).find((c) => c.id === s.cliId);
|
|
33
33
|
const Icon = IconForCliType(cli?.type) || IconTerminal;
|
|
34
34
|
const t = s.title || s.workspace || s.id.slice(0, 12);
|
|
35
35
|
const isActive = s.id === activeId;
|
|
@@ -73,28 +73,28 @@ function SessionTabs({ activeId, openSessions, onActivate, onClose, onReorder, o
|
|
|
73
73
|
</button>
|
|
74
74
|
</div>`;
|
|
75
75
|
})}
|
|
76
|
-
${/* <button class="session-tab session-tab-add" onClick=${onNew} title="New session">
|
|
77
|
-
<${IconPlus} />
|
|
78
|
-
</button> */ null}
|
|
79
|
-
</div>
|
|
80
|
-
${kebab ? html`<div class="session-tabs-right">${kebab}</div>` : null}
|
|
81
|
-
</div>`;
|
|
82
|
-
}
|
|
83
|
-
|
|
76
|
+
${/* <button class="session-tab session-tab-add" onClick=${onNew} title="New session">
|
|
77
|
+
<${IconPlus} />
|
|
78
|
+
</button> */ null}
|
|
79
|
+
</div>
|
|
80
|
+
${kebab ? html`<div class="session-tabs-right">${kebab}</div>` : null}
|
|
81
|
+
</div>`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
84
|
function SessionMenu({ session, switchableClis, onRename, onDelete, onOpenEditor, onSwitchCli }) {
|
|
85
85
|
const [open, setOpen] = useState(false);
|
|
86
86
|
const anchor = useRef(null);
|
|
87
87
|
return html`
|
|
88
88
|
<button class="session-menu-btn" ref=${anchor}
|
|
89
89
|
aria-label="Session actions" title="Session actions"
|
|
90
|
-
onClick=${() => setOpen((v) => !v)}>
|
|
91
|
-
<${IconMoreVert} />
|
|
92
|
-
</button>
|
|
93
|
-
${open ? html`
|
|
94
|
-
<${Popover} anchor=${anchor} align="right" width=${200}
|
|
95
|
-
onClose=${() => setOpen(false)}>
|
|
96
|
-
<div class="session-menu">
|
|
97
|
-
<button class="session-menu-item" onClick=${() => { setOpen(false); onOpenEditor(); }}>
|
|
90
|
+
onClick=${() => setOpen((v) => !v)}>
|
|
91
|
+
<${IconMoreVert} />
|
|
92
|
+
</button>
|
|
93
|
+
${open ? html`
|
|
94
|
+
<${Popover} anchor=${anchor} align="right" width=${200}
|
|
95
|
+
onClose=${() => setOpen(false)}>
|
|
96
|
+
<div class="session-menu">
|
|
97
|
+
<button class="session-menu-item" onClick=${() => { setOpen(false); onOpenEditor(); }}>
|
|
98
98
|
<${IconExternal} /> Open in editor
|
|
99
99
|
</button>
|
|
100
100
|
${switchableClis.length ? html`
|
|
@@ -114,8 +114,8 @@ function SessionMenu({ session, switchableClis, onRename, onDelete, onOpenEditor
|
|
|
114
114
|
</button>
|
|
115
115
|
<button class="session-menu-item danger" onClick=${() => { setOpen(false); onDelete(); }}>
|
|
116
116
|
<${IconClose} /> Delete
|
|
117
|
-
</button>
|
|
118
|
-
</div>
|
|
117
|
+
</button>
|
|
118
|
+
</div>
|
|
119
119
|
</${Popover}>` : null}`;
|
|
120
120
|
}
|
|
121
121
|
|
|
@@ -152,17 +152,17 @@ export function SessionsPage() {
|
|
|
152
152
|
// Bumps to force the auto-resume effect to re-run on Retry without
|
|
153
153
|
// mutating any signal. Primitive in the dep array → identity changes.
|
|
154
154
|
const [retryNonce, setRetryNonce] = useState(0);
|
|
155
|
-
|
|
156
|
-
// No session selected → bounce to the Launch page. Done in an effect so
|
|
157
|
-
// we don't mutate signals during render. Returning null while the bounce
|
|
158
|
-
// is in flight avoids a flash of empty content.
|
|
159
|
-
useEffect(() => {
|
|
160
|
-
if (!session) selectTab('launch');
|
|
161
|
-
}, [session]);
|
|
162
|
-
|
|
163
|
-
// Auto-resume when the active session is exited. resumeSession() in
|
|
164
|
-
// api.js dedups in-flight calls per session id, so simultaneous fires
|
|
165
|
-
// from here and from Sidebar.onClick collapse into one request.
|
|
155
|
+
|
|
156
|
+
// No session selected → bounce to the Launch page. Done in an effect so
|
|
157
|
+
// we don't mutate signals during render. Returning null while the bounce
|
|
158
|
+
// is in flight avoids a flash of empty content.
|
|
159
|
+
useEffect(() => {
|
|
160
|
+
if (!session) selectTab('launch');
|
|
161
|
+
}, [session]);
|
|
162
|
+
|
|
163
|
+
// Auto-resume when the active session is exited. resumeSession() in
|
|
164
|
+
// api.js dedups in-flight calls per session id, so simultaneous fires
|
|
165
|
+
// from here and from Sidebar.onClick collapse into one request.
|
|
166
166
|
useEffect(() => {
|
|
167
167
|
if (!session) return;
|
|
168
168
|
if (session.status === 'running') { setResumeError(null); return; }
|
|
@@ -194,7 +194,7 @@ export function SessionsPage() {
|
|
|
194
194
|
}, [list, session?.id]);
|
|
195
195
|
|
|
196
196
|
if (!session) return null;
|
|
197
|
-
|
|
197
|
+
|
|
198
198
|
const cli = (config.value?.clis || []).find((c) => c.id === session.cliId);
|
|
199
199
|
const cliForSession = (s) => (config.value?.clis || []).find((c) => c.id === s.cliId);
|
|
200
200
|
const switchableClis = cli
|
|
@@ -275,21 +275,21 @@ export function SessionsPage() {
|
|
|
275
275
|
setActionBusy(false);
|
|
276
276
|
}
|
|
277
277
|
};
|
|
278
|
-
const onRename = async () => {
|
|
279
|
-
const next = await ccsmPrompt('Rename session', title, { okLabel: 'Save' });
|
|
280
|
-
if (next === null) return;
|
|
281
|
-
try { await setSessionTitle(session.id, next.trim()); }
|
|
282
|
-
catch (e) { setToast(e.message, 'error'); }
|
|
283
|
-
};
|
|
284
|
-
const onDelete = async () => {
|
|
285
|
-
const ok = await ccsmConfirm(`Delete session ${title}? PTY will be killed if alive.`, {
|
|
286
|
-
title: 'Delete session', okLabel: 'Delete', danger: true });
|
|
287
|
-
if (!ok) return;
|
|
288
|
-
try {
|
|
289
|
-
await deleteSession(session.id);
|
|
290
|
-
activeSessionId.value = null;
|
|
291
|
-
} catch (e) { setToast(e.message, 'error'); }
|
|
292
|
-
};
|
|
278
|
+
const onRename = async () => {
|
|
279
|
+
const next = await ccsmPrompt('Rename session', title, { okLabel: 'Save' });
|
|
280
|
+
if (next === null) return;
|
|
281
|
+
try { await setSessionTitle(session.id, next.trim()); }
|
|
282
|
+
catch (e) { setToast(e.message, 'error'); }
|
|
283
|
+
};
|
|
284
|
+
const onDelete = async () => {
|
|
285
|
+
const ok = await ccsmConfirm(`Delete session ${title}? PTY will be killed if alive.`, {
|
|
286
|
+
title: 'Delete session', okLabel: 'Delete', danger: true });
|
|
287
|
+
if (!ok) return;
|
|
288
|
+
try {
|
|
289
|
+
await deleteSession(session.id);
|
|
290
|
+
activeSessionId.value = null;
|
|
291
|
+
} catch (e) { setToast(e.message, 'error'); }
|
|
292
|
+
};
|
|
293
293
|
const onOpenEditor = async () => {
|
|
294
294
|
try {
|
|
295
295
|
const r = await openSessionInEditor(session.id);
|
|
@@ -316,7 +316,7 @@ export function SessionsPage() {
|
|
|
316
316
|
}
|
|
317
317
|
} catch (e) { setToast(e.message, 'error'); }
|
|
318
318
|
};
|
|
319
|
-
|
|
319
|
+
|
|
320
320
|
return html`
|
|
321
321
|
<${PageTitleBar} title=${html`
|
|
322
322
|
<span class="session-title-text" title=${title}>${title}</span>
|