@bakapiano/ccsm 0.4.0 → 0.6.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.
package/public/index.html CHANGED
@@ -3,181 +3,503 @@
3
3
  <head>
4
4
  <meta charset="utf-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1" />
6
- <title>ccsm — Claude Code Session Manager</title>
6
+ <title>CCSM — Claude CLI Sessions Manager</title>
7
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
8
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
9
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
10
+ <link
11
+ rel="stylesheet"
12
+ href="https://fonts.googleapis.com/css2?family=Geist:wght@300..700&family=JetBrains+Mono:wght@400..600&display=swap"
13
+ />
7
14
  <link rel="stylesheet" href="/styles.css" />
8
15
  </head>
9
16
  <body>
10
- <header class="topbar">
11
- <div class="brand">
12
- <span class="logo">⌘</span>
13
- <span>ccsm</span>
14
- <small id="serverInfo"></small>
15
- </div>
16
- <div class="topbar-actions">
17
- <label class="toggle">
18
- <input type="checkbox" id="autoRefresh" checked />
19
- <span>auto-refresh</span>
20
- </label>
21
- <button id="refreshBtn" class="btn">refresh</button>
22
- <button id="finderBtn" class="btn btn-accent" title="Open a new Claude Code session pointed at the session-manager data folder">
23
- ask claude to find a session
24
- </button>
25
- </div>
26
- </header>
17
+ <div class="app">
18
+ <!-- ─────────── Sidebar ─────────── -->
19
+ <aside class="sidebar" id="sidebar" data-collapsed="false">
20
+ <div class="sidebar-brand">
21
+ <span class="brand-mark" aria-hidden="true">
22
+ <!-- terminal window with ccsm inside · matches favicon -->
23
+ <svg viewBox="0 0 32 32" width="32" height="32">
24
+ <rect x="2" y="4" width="28" height="24" rx="3" fill="#c45f3f"/>
25
+ <line x1="2" y1="10" x2="30" y2="10" stroke="#faf9f5" stroke-width="0.6" opacity="0.45"/>
26
+ <circle cx="6" cy="7" r="1" fill="#faf9f5"/>
27
+ <circle cx="9.5" cy="7" r="1" fill="#faf9f5" opacity="0.65"/>
28
+ <circle cx="13" cy="7" r="1" fill="#faf9f5" opacity="0.4"/>
29
+ <text x="16" y="19.5"
30
+ text-anchor="middle"
31
+ dominant-baseline="central"
32
+ font-family="'JetBrains Mono', 'Cascadia Mono', 'Consolas', monospace"
33
+ font-weight="700"
34
+ font-size="10"
35
+ fill="#faf9f5">ccsm</text>
36
+ </svg>
37
+ </span>
38
+ <span class="brand-name">CCSM<span class="brand-dot">.</span></span>
39
+ </div>
27
40
 
28
- <main>
29
- <section class="panel">
30
- <header class="panel-header">
31
- <h2>live sessions</h2>
32
- <span id="sessionsMeta" class="muted"></span>
33
- </header>
34
- <div class="table-wrap">
35
- <table id="sessionsTable" class="data-table">
36
- <thead>
37
- <tr>
38
- <th></th>
39
- <th>title</th>
40
- <th>cwd</th>
41
- <th>updated</th>
42
- <th>started</th>
43
- <th>pid</th>
44
- <th></th>
45
- </tr>
46
- </thead>
47
- <tbody></tbody>
48
- </table>
41
+ <nav class="sidebar-nav" role="tablist" aria-label="Sections">
42
+ <button class="nav-item" data-tab="sessions" role="tab" aria-selected="true">
43
+ <span class="nav-icon" aria-hidden="true">
44
+ <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
45
+ <line x1="3" y1="6" x2="21" y2="6"/>
46
+ <line x1="3" y1="12" x2="21" y2="12"/>
47
+ <line x1="3" y1="18" x2="14" y2="18"/>
48
+ </svg>
49
+ </span>
50
+ <span class="nav-label">Sessions</span>
51
+ <span class="nav-badge" id="navCount-sessions">0</span>
52
+ </button>
53
+ <button class="nav-item" data-tab="launch" role="tab" aria-selected="false">
54
+ <span class="nav-icon" aria-hidden="true">
55
+ <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
56
+ <path d="M7 17L17 7"/>
57
+ <path d="M9 7h8v8"/>
58
+ </svg>
59
+ </span>
60
+ <span class="nav-label">Launch</span>
61
+ </button>
62
+ <button class="nav-item" data-tab="configure" role="tab" aria-selected="false">
63
+ <span class="nav-icon" aria-hidden="true">
64
+ <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
65
+ <circle cx="12" cy="12" r="3"/>
66
+ <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33h0a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51h0a1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82v0a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/>
67
+ </svg>
68
+ </span>
69
+ <span class="nav-label">Configure</span>
70
+ </button>
71
+ </nav>
72
+
73
+ <div class="sidebar-divider"></div>
74
+
75
+ <div class="sidebar-utility">
76
+ <button class="util-item" id="refreshBtn" title="refresh">
77
+ <span class="nav-icon" aria-hidden="true">
78
+ <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round">
79
+ <polyline points="23 4 23 10 17 10"/>
80
+ <polyline points="1 20 1 14 7 14"/>
81
+ <path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/>
82
+ </svg>
83
+ </span>
84
+ <span class="nav-label">Refresh</span>
85
+ </button>
49
86
  </div>
50
- </section>
51
87
 
52
- <section class="panel">
53
- <header class="panel-header">
54
- <h2>recently closed</h2>
55
- <span id="recentMeta" class="muted"></span>
56
- </header>
57
- <div class="table-wrap">
58
- <table id="recentTable" class="data-table">
59
- <thead>
60
- <tr>
61
- <th>title</th>
62
- <th>cwd</th>
63
- <th>branch</th>
64
- <th>updated</th>
65
- <th>started</th>
66
- <th></th>
67
- </tr>
68
- </thead>
69
- <tbody></tbody>
70
- </table>
88
+ <div class="sidebar-foot">
89
+ <button class="collapse-toggle" id="collapseBtn" aria-label="collapse sidebar">
90
+ <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
91
+ <polyline points="15 18 9 12 15 6"/>
92
+ </svg>
93
+ </button>
71
94
  </div>
72
- </section>
95
+ </aside>
73
96
 
74
- <section class="panel">
75
- <header class="panel-header">
76
- <h2>snapshot</h2>
77
- <span id="snapshotMeta" class="muted"></span>
97
+ <!-- ─────────── Main ─────────── -->
98
+ <main class="main">
99
+ <header class="page-head">
100
+ <div class="page-head-inner">
101
+ <h1 class="page-title" id="pageTitle">Sessions</h1>
102
+ <p class="page-subtitle" id="pageSubtitle">Live and recently-closed Claude Code sessions on this machine.</p>
103
+ </div>
104
+ <div class="page-head-meta">
105
+ <span class="server-status" id="serverStatus" data-state="connecting" title="backend status">
106
+ <span class="status-pulse" aria-hidden="true"></span>
107
+ <span class="server-status-label" id="serverStatusLabel">connecting…</span>
108
+ </span>
109
+ <span class="ph-divider">·</span>
110
+ <span class="ph-stat"><span class="ph-key">Port</span> <span class="ph-val" id="hdPort">—</span></span>
111
+ <span class="ph-divider">·</span>
112
+ <span class="ph-stat"><span class="ph-key">Terminal</span> <span class="ph-val" id="hdTerminal">—</span></span>
113
+ <span class="ph-divider">·</span>
114
+ <span class="ph-stat"><span class="ph-key">Now</span> <span class="ph-val" id="hdTime">—</span></span>
115
+ </div>
78
116
  </header>
79
- <div class="panel-body row gap">
80
- <button id="snapshotSaveBtn" class="btn">save snapshot now</button>
81
- <button id="snapshotRestoreBtn" class="btn btn-primary">restore latest snapshot</button>
82
- <select id="historySelect" class="select" title="restore a historical snapshot">
83
- <option value="">history…</option>
84
- </select>
85
- <button id="historyRestoreBtn" class="btn">restore selected</button>
117
+
118
+ <div class="content">
119
+ <!-- ─── Sessions tab ─── -->
120
+ <section class="tab-panel" data-panel="sessions" data-active>
121
+ <div class="page-actions">
122
+ <span class="page-actions-hint">Looking through your past conversations?</span>
123
+ <button class="action primary" id="finderInlineBtn" title="open a Claude session with context on the ccsm data dir">
124
+ <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
125
+ <circle cx="11" cy="11" r="7"/>
126
+ <line x1="21" y1="21" x2="16.65" y2="16.65"/>
127
+ </svg>
128
+ Ask Claude to find a session
129
+ </button>
130
+ </div>
131
+
132
+ <article class="card" id="favoritesCard" data-fold-key="favorites">
133
+ <header class="card-head">
134
+ <button class="card-fold" data-fold aria-label="collapse">
135
+ <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
136
+ </button>
137
+ <div class="card-titles">
138
+ <h2 class="card-title">
139
+ Favorites
140
+ <svg class="title-icon title-icon-after" viewBox="0 0 24 24" width="14" height="14" fill="currentColor" stroke="none" aria-hidden="true">
141
+ <polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/>
142
+ </svg>
143
+ </h2>
144
+ <p class="card-meta" id="favoritesMeta">click ☆ on any row to pin sessions here</p>
145
+ </div>
146
+ </header>
147
+ <div class="card-body card-body-flush">
148
+ <div class="table-scroll">
149
+ <table class="data" id="favoritesTable">
150
+ <thead>
151
+ <tr>
152
+ <th>Title</th>
153
+ <th>Working directory</th>
154
+ <th>Branch</th>
155
+ <th class="num">Pinned</th>
156
+ <th class="col-actions"></th>
157
+ </tr>
158
+ </thead>
159
+ <tbody></tbody>
160
+ </table>
161
+ </div>
162
+ <div class="empty" id="favoritesEmpty">No favorites yet. Star a session row to pin it here.</div>
163
+ <footer class="pagination" id="favoritesPagination" hidden>
164
+ <button class="action subtle small" id="favPrevBtn" disabled>← Prev</button>
165
+ <span class="pagination-info">Page <strong id="favPageNum">1</strong> of <strong id="favPageTotal">1</strong> · <span id="favTotal">0</span> total</span>
166
+ <button class="action subtle small" id="favNextBtn" disabled>Next →</button>
167
+ <select id="favPageSize" class="input" style="max-width: 100px;">
168
+ <option value="10" selected>10 / page</option>
169
+ <option value="20">20 / page</option>
170
+ <option value="50">50 / page</option>
171
+ </select>
172
+ </footer>
173
+ </div>
174
+ </article>
175
+
176
+ <article class="card" data-fold-key="sessions">
177
+ <header class="card-head">
178
+ <button class="card-fold" data-fold aria-label="collapse">
179
+ <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
180
+ </button>
181
+ <div class="card-titles">
182
+ <h2 class="card-title">Live sessions</h2>
183
+ <p class="card-meta" id="sessionsMeta">awaiting…</p>
184
+ </div>
185
+ </header>
186
+ <div class="card-body card-body-flush">
187
+ <div class="table-scroll">
188
+ <table class="data" id="sessionsTable">
189
+ <thead>
190
+ <tr>
191
+ <th class="col-mark"></th>
192
+ <th>Title</th>
193
+ <th>Working directory</th>
194
+ <th class="num">Updated</th>
195
+ <th class="num">Started</th>
196
+ <th class="num">PID</th>
197
+ <th class="col-actions"></th>
198
+ </tr>
199
+ </thead>
200
+ <tbody></tbody>
201
+ </table>
202
+ </div>
203
+ <div class="empty" id="sessionsEmpty" hidden>No live sessions detected.</div>
204
+ <footer class="pagination" id="sessionsPagination" hidden>
205
+ <button class="action subtle small" id="sessPrevBtn" disabled>← Prev</button>
206
+ <span class="pagination-info">Page <strong id="sessPageNum">1</strong> of <strong id="sessPageTotal">1</strong> · <span id="sessTotal">0</span> total</span>
207
+ <button class="action subtle small" id="sessNextBtn" disabled>Next →</button>
208
+ <select id="sessPageSize" class="input" style="max-width: 100px;">
209
+ <option value="10" selected>10 / page</option>
210
+ <option value="20">20 / page</option>
211
+ <option value="50">50 / page</option>
212
+ </select>
213
+ </footer>
214
+ </div>
215
+ </article>
216
+
217
+ <article class="card" data-fold-key="recent">
218
+ <header class="card-head">
219
+ <button class="card-fold" data-fold aria-label="collapse">
220
+ <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>
221
+ </button>
222
+ <div class="card-titles">
223
+ <h2 class="card-title">Recently closed</h2>
224
+ <p class="card-meta" id="recentMeta">…</p>
225
+ </div>
226
+ </header>
227
+ <div class="card-body card-body-flush">
228
+ <div class="table-scroll">
229
+ <table class="data" id="recentTable">
230
+ <thead>
231
+ <tr>
232
+ <th>Title</th>
233
+ <th>Working directory</th>
234
+ <th>Branch</th>
235
+ <th class="num">Last activity</th>
236
+ <th class="num">Started</th>
237
+ <th class="col-actions"></th>
238
+ </tr>
239
+ </thead>
240
+ <tbody></tbody>
241
+ </table>
242
+ </div>
243
+ <div class="empty" id="recentEmpty" hidden>Nothing in <code>~/.claude/projects/</code>.</div>
244
+ <footer class="pagination" id="recentPagination" hidden>
245
+ <button class="action subtle small" id="recentPrevBtn" disabled>← Prev</button>
246
+ <span class="pagination-info">Page <strong id="recentPageNum">1</strong> of <strong id="recentPageTotal">1</strong> · <span id="recentTotal">0</span> total</span>
247
+ <button class="action subtle small" id="recentNextBtn" disabled>Next →</button>
248
+ <select id="recentPageSize" class="input" style="max-width: 100px;">
249
+ <option value="10" selected>10 / page</option>
250
+ <option value="20">20 / page</option>
251
+ <option value="50">50 / page</option>
252
+ </select>
253
+ </footer>
254
+ </div>
255
+ </article>
256
+ </section>
257
+
258
+ <!-- ─── Launch tab ─── -->
259
+ <section class="tab-panel" data-panel="launch">
260
+ <article class="card">
261
+ <header class="card-head">
262
+ <div class="card-titles">
263
+ <h2 class="card-title">New session</h2>
264
+ <p class="card-meta">Picks an unused workspace, clones missing repos, opens <code>claude</code> in a fresh terminal.</p>
265
+ </div>
266
+ </header>
267
+ <div class="card-body">
268
+ <div class="form-row">
269
+ <span class="form-label">Repos</span>
270
+ <div class="chip-row" id="repoPicker">
271
+ <span class="muted-text">no repos configured · add some in <strong>Configure</strong></span>
272
+ </div>
273
+ </div>
274
+ <div class="form-row">
275
+ <label class="form-label" for="workspaceSelect">Workspace</label>
276
+ <select id="workspaceSelect" class="input narrow">
277
+ <option value="">auto — find or create unused</option>
278
+ </select>
279
+ <button class="action primary" id="newSessionBtn">Launch new session</button>
280
+ </div>
281
+ <div id="newSessionProgress" class="progress-list"></div>
282
+ <div class="post-result" id="newSessionResult"></div>
283
+ </div>
284
+ </article>
285
+
286
+ <article class="card">
287
+ <header class="card-head">
288
+ <div class="card-titles">
289
+ <h2 class="card-title">Snapshot &amp; restore</h2>
290
+ <p class="card-meta" id="snapshotMeta">…</p>
291
+ </div>
292
+ </header>
293
+ <div class="card-body">
294
+ <div class="row gap-row">
295
+ <button class="action" id="snapshotSaveBtn">Save snapshot now</button>
296
+ <button class="action primary" id="snapshotRestoreBtn">Restore latest</button>
297
+ <span class="divider-dot">·</span>
298
+ <select id="historySelect" class="input narrow">
299
+ <option value="">history…</option>
300
+ </select>
301
+ <button class="action" id="historyRestoreBtn">Restore selected</button>
302
+ </div>
303
+ <details class="snapshot-detail">
304
+ <summary>View snapshot contents</summary>
305
+ <pre id="snapshotPreview" class="preview"></pre>
306
+ </details>
307
+ </div>
308
+ </article>
309
+
310
+ <article class="card">
311
+ <header class="card-head">
312
+ <div class="card-titles">
313
+ <h2 class="card-title">Workspaces on disk</h2>
314
+ <p class="card-meta">Under <code id="workDirDisplay">…</code></p>
315
+ </div>
316
+ </header>
317
+ <div class="card-body">
318
+ <div id="workspaceList" class="workspace-grid"></div>
319
+ </div>
320
+ </article>
321
+ </section>
322
+
323
+ <!-- ─── Configure tab ─── -->
324
+ <section class="tab-panel" data-panel="configure">
325
+ <div class="dirty-banner" id="configDirtyBanner" hidden>
326
+ <span class="dirty-dot"></span>
327
+ <span class="dirty-text">You have unsaved changes</span>
328
+ <button class="action small primary" id="dirtyBannerSaveBtn">Save now</button>
329
+ <button class="action small subtle" id="dirtyBannerDiscardBtn">Discard</button>
330
+ </div>
331
+ <article class="card">
332
+ <header class="card-head">
333
+ <div class="card-titles">
334
+ <h2 class="card-title">Settings</h2>
335
+ <p class="card-meta">Persisted to <code>~/.ccsm/config.json</code></p>
336
+ </div>
337
+ </header>
338
+ <div class="card-body">
339
+ <div class="config-grid">
340
+ <label class="field">
341
+ <span class="label">Port</span>
342
+ <input id="cfgPort" type="number" />
343
+ <span class="hint">restart server to apply</span>
344
+ </label>
345
+ <label class="field">
346
+ <span class="label">Work directory</span>
347
+ <input id="cfgWorkDir" type="text" />
348
+ </label>
349
+ <label class="field">
350
+ <span class="label">Snapshot interval (ms)</span>
351
+ <input id="cfgInterval" type="number" min="5000" />
352
+ </label>
353
+ <label class="field">
354
+ <span class="label">History kept</span>
355
+ <input id="cfgKeep" type="number" min="1" />
356
+ </label>
357
+ <label class="field">
358
+ <span class="label">Claude command</span>
359
+ <input id="cfgClaudeCommand" type="text" placeholder="claude" />
360
+ <span class="hint">alias / function / exe name</span>
361
+ </label>
362
+ <label class="field">
363
+ <span class="label">Terminal</span>
364
+ <select id="cfgTerminal" class="input"></select>
365
+ </label>
366
+ <label class="field">
367
+ <span class="label">Command shell <span class="hint inline">(wt only)</span></span>
368
+ <select id="cfgCommandShell" class="input">
369
+ <option value="pwsh">pwsh · PowerShell 7</option>
370
+ <option value="powershell">powershell · Windows PowerShell 5.1</option>
371
+ <option value="none">none · run command directly</option>
372
+ </select>
373
+ </label>
374
+ <label class="field">
375
+ <span class="label">Browser open mode</span>
376
+ <select id="cfgBrowserMode" class="input">
377
+ <option value="app">app · Edge/Chrome chromeless</option>
378
+ <option value="tab">tab · default browser</option>
379
+ <option value="none">off · don't open</option>
380
+ </select>
381
+ </label>
382
+ <label class="field toggle">
383
+ <input id="cfgAutoFocus" type="checkbox" />
384
+ <span class="toggle-text">
385
+ <span class="label">Auto-focus on launch</span>
386
+ <span class="hint">raise newly-launched terminal window</span>
387
+ </span>
388
+ </label>
389
+ <label class="field toggle">
390
+ <input id="cfgFocusCenter" type="checkbox" />
391
+ <span class="toggle-text">
392
+ <span class="label">Move focused window to screen center</span>
393
+ <span class="hint">centers the focused window on whichever monitor the cursor is on</span>
394
+ </span>
395
+ </label>
396
+ <label class="field full">
397
+ <span class="label">Finder prompt</span>
398
+ <textarea id="cfgFinderPrompt" rows="3"></textarea>
399
+ <span class="hint">passed as initial prompt to the finder session</span>
400
+ </label>
401
+
402
+ <div class="field full">
403
+ <div class="repos-head">
404
+ <span class="label">Repositories</span>
405
+ <button class="action small" id="addRepoBtn">+ Add repo</button>
406
+ </div>
407
+ <table class="data repos-table" id="reposTable">
408
+ <thead>
409
+ <tr>
410
+ <th>Name</th>
411
+ <th>URL</th>
412
+ <th class="num">Default</th>
413
+ <th class="col-actions"></th>
414
+ </tr>
415
+ </thead>
416
+ <tbody></tbody>
417
+ </table>
418
+ </div>
419
+
420
+ <div class="form-actions full">
421
+ <button class="action primary" id="saveConfigBtn">Save configuration</button>
422
+ <span class="muted-text" id="configSavedAt"></span>
423
+ </div>
424
+ </div>
425
+ </div>
426
+ </article>
427
+ </section>
86
428
  </div>
87
- <details class="panel-body">
88
- <summary>show snapshot contents</summary>
89
- <pre id="snapshotPreview" class="preview"></pre>
90
- </details>
91
- </section>
92
-
93
- <section class="panel">
94
- <header class="panel-header">
95
- <h2>new session</h2>
96
- <span class="muted">picks an unused workspace under workDir, clones missing repos, opens a fresh wt window with <code>claude</code></span>
429
+
430
+ <footer class="footer-status">
431
+ <span class="fs-key">Data</span> <span class="fs-val" id="footData">—</span>
432
+ <span class="fs-divider">·</span>
433
+ <span class="fs-key">Workspaces</span> <span class="fs-val" id="footWorkDir">—</span>
434
+ </footer>
435
+ </main>
436
+ </div>
437
+
438
+ <!-- Floating "new session" action button always visible bottom-right -->
439
+ <button class="fab" id="newSessionFab" title="Launch new session" aria-label="Launch new session">
440
+ <svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
441
+ <line x1="12" y1="5" x2="12" y2="19"/>
442
+ <line x1="5" y1="12" x2="19" y2="12"/>
443
+ </svg>
444
+ </button>
445
+
446
+ <!-- New-session modal -->
447
+ <div class="modal-backdrop" id="newSessionModal" hidden role="dialog" aria-modal="true" aria-labelledby="modalTitle">
448
+ <div class="modal">
449
+ <header class="modal-head">
450
+ <h2 id="modalTitle">Launch new session</h2>
451
+ <button class="modal-close" id="modalCloseBtn" aria-label="close">
452
+ <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
453
+ </button>
97
454
  </header>
98
- <div class="panel-body">
99
- <div class="row gap" id="repoPicker"></div>
100
- <div class="row gap" style="margin-top: 8px;">
101
- <label for="workspaceSelect">workspace:</label>
102
- <select id="workspaceSelect" class="select">
103
- <option value="">(auto — find or create unused)</option>
104
- </select>
105
- <button id="newSessionBtn" class="btn btn-primary">launch new session</button>
455
+ <div class="modal-body">
456
+ <p class="modal-hint">Pick an unused workspace, clone any missing repos, open <code>claude</code> in a fresh terminal.</p>
457
+
458
+ <div class="form-row">
459
+ <span class="form-label">Repos</span>
460
+ <div class="chip-row" id="modalRepoPicker"></div>
106
461
  </div>
107
- <div id="newSessionProgress" class="progress-list"></div>
108
- <div id="newSessionResult" class="muted small"></div>
109
- </div>
110
- <details class="panel-body">
111
- <summary>workspaces under workDir</summary>
112
- <div id="workspaceList" class="workspace-list"></div>
113
- </details>
114
- </section>
115
-
116
- <section class="panel">
117
- <header class="panel-header"><h2>config</h2></header>
118
- <div class="panel-body grid-2">
119
- <label>port (restart server to apply)
120
- <input id="cfgPort" type="number" />
121
- </label>
122
- <label>work dir
123
- <input id="cfgWorkDir" type="text" />
124
- </label>
125
- <label>snapshot interval (ms)
126
- <input id="cfgInterval" type="number" min="5000" />
127
- </label>
128
- <label>history kept
129
- <input id="cfgKeep" type="number" min="1" />
130
- </label>
131
- <label>claude command
132
- <input id="cfgClaudeCommand" type="text" placeholder="claude" />
133
- </label>
134
- <label>terminal
135
- <select id="cfgTerminal" class="select"></select>
136
- </label>
137
- <label>command shell (for wt; lets PowerShell aliases / functions resolve)
138
- <select id="cfgCommandShell" class="select">
139
- <option value="pwsh">pwsh (PowerShell 7)</option>
140
- <option value="powershell">powershell (Windows PowerShell 5.1)</option>
141
- <option value="none">none — run command directly via wt</option>
142
- </select>
143
- </label>
144
- <label class="full" style="flex-direction: row; align-items: center; gap: 8px;">
145
- <input id="cfgAutoFocus" type="checkbox" />
146
- <span style="color: var(--text);">auto-focus newly launched window</span>
147
- </label>
148
- <label>browser open mode (on server start)
149
- <select id="cfgBrowserMode" class="select">
150
- <option value="app">app — Edge/Chrome chromeless window</option>
151
- <option value="tab">tab — default browser, normal tab</option>
152
- <option value="none">off — don't open anything</option>
153
- </select>
154
- </label>
155
- <label class="full">finder prompt
156
- <textarea id="cfgFinderPrompt" rows="3"></textarea>
157
- </label>
158
- <div class="full">
159
- <div class="row" style="justify-content: space-between; align-items: center;">
160
- <strong>repos</strong>
161
- <button id="addRepoBtn" class="btn small">+ add repo</button>
462
+
463
+ <details class="repos-inline-config">
464
+ <summary>Manage repos</summary>
465
+ <div class="repos-inline-body">
466
+ <table class="data repos-table" id="modalReposTable">
467
+ <thead>
468
+ <tr>
469
+ <th>Name</th>
470
+ <th>URL</th>
471
+ <th class="num">Default</th>
472
+ <th class="col-actions"></th>
473
+ </tr>
474
+ </thead>
475
+ <tbody></tbody>
476
+ </table>
477
+ <div class="repos-inline-actions">
478
+ <button class="action small" id="modalAddRepoBtn">+ Add repo</button>
479
+ <button class="action small primary" id="modalSaveReposBtn">Save changes</button>
480
+ <span class="muted-text" id="modalReposSavedAt"></span>
481
+ </div>
162
482
  </div>
163
- <table id="reposTable" class="data-table">
164
- <thead>
165
- <tr>
166
- <th>name</th><th>url</th><th>default selected</th><th></th>
167
- </tr>
168
- </thead>
169
- <tbody></tbody>
170
- </table>
483
+ </details>
484
+
485
+ <div class="form-row">
486
+ <label class="form-label" for="modalWorkspaceSelect">Workspace</label>
487
+ <select id="modalWorkspaceSelect" class="input narrow">
488
+ <option value="">auto — find or create unused</option>
489
+ </select>
171
490
  </div>
491
+
492
+ <div id="modalProgress" class="progress-list"></div>
493
+ <div class="post-result" id="modalResult"></div>
172
494
  </div>
173
- <div class="panel-body">
174
- <button id="saveConfigBtn" class="btn btn-primary">save config</button>
175
- <span id="configSavedAt" class="muted small"></span>
176
- </div>
177
- </section>
178
- </main>
495
+ <footer class="modal-foot">
496
+ <button class="action" id="modalCancelBtn">Cancel</button>
497
+ <button class="action primary" id="modalLaunchBtn">Launch new session</button>
498
+ </footer>
499
+ </div>
500
+ </div>
179
501
 
180
- <div id="toast" class="toast"></div>
502
+ <div id="toast" class="toast" role="status" aria-live="polite"></div>
181
503
 
182
504
  <script src="/app.js" defer></script>
183
505
  </body>