@bakapiano/ccsm 0.22.2 → 0.22.4

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.
Files changed (60) hide show
  1. package/CLAUDE.md +538 -538
  2. package/README.md +189 -189
  3. package/bin/ccsm.js +235 -235
  4. package/lib/cliActivity.js +139 -139
  5. package/lib/codexSeed.js +183 -183
  6. package/lib/config.js +274 -274
  7. package/lib/devices.js +229 -229
  8. package/lib/folders.js +124 -124
  9. package/lib/localCliSessions.js +519 -519
  10. package/lib/persistedSessions.js +129 -129
  11. package/lib/tunnel.js +621 -621
  12. package/lib/webTerminal.js +233 -231
  13. package/lib/workspace.js +233 -233
  14. package/package.json +57 -57
  15. package/public/css/base.css +99 -99
  16. package/public/css/cards.css +183 -183
  17. package/public/css/feedback.css +504 -504
  18. package/public/css/forms.css +453 -453
  19. package/public/css/layout.css +176 -176
  20. package/public/css/modal.css +190 -190
  21. package/public/css/responsive.css +176 -176
  22. package/public/css/sidebar.css +707 -707
  23. package/public/css/terminals.css +592 -592
  24. package/public/css/tokens.css +81 -81
  25. package/public/css/wco.css +196 -196
  26. package/public/css/widgets.css +2725 -2725
  27. package/public/index.html +152 -152
  28. package/public/js/api.js +371 -371
  29. package/public/js/backend.js +149 -149
  30. package/public/js/components/App.js +73 -73
  31. package/public/js/components/DirectoryPicker.js +203 -203
  32. package/public/js/components/EntityFormModal.js +153 -153
  33. package/public/js/components/Modal.js +57 -57
  34. package/public/js/components/OfflineBanner.js +67 -67
  35. package/public/js/components/PageTitleBar.js +13 -13
  36. package/public/js/components/PendingApprovalOverlay.js +128 -128
  37. package/public/js/components/Picker.js +179 -179
  38. package/public/js/components/Popover.js +55 -55
  39. package/public/js/components/RestartOverlay.js +36 -36
  40. package/public/js/components/Sidebar.js +380 -380
  41. package/public/js/components/TerminalInstance.js +187 -15
  42. package/public/js/components/TerminalResizeDebouncer.js +126 -0
  43. package/public/js/components/XtermTerminal.js +148 -14
  44. package/public/js/components/useDragSort.js +67 -67
  45. package/public/js/dialog.js +67 -67
  46. package/public/js/icons.js +212 -212
  47. package/public/js/main.js +296 -296
  48. package/public/js/pages/AboutPage.js +90 -90
  49. package/public/js/pages/ConfigurePage.js +713 -713
  50. package/public/js/pages/LaunchPage.js +421 -421
  51. package/public/js/pages/RemotePage.js +743 -743
  52. package/public/js/pages/SessionsPage.js +100 -100
  53. package/public/js/state.js +335 -335
  54. package/public/manifest.webmanifest +25 -0
  55. package/public/setup/index.html +567 -0
  56. package/scripts/dev.js +149 -149
  57. package/scripts/install.js +153 -153
  58. package/scripts/restart-helper.js +96 -96
  59. package/scripts/upgrade-helper.js +687 -687
  60. package/server.js +1807 -1807
@@ -1,96 +1,96 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- // Restart helper · spawned detached by /api/restart.
5
- //
6
- // Just like upgrade-helper but skips the `npm i` step. Server kicks
7
- // this off + gracefulShutdowns; helper waits for the port to free, then
8
- // respawns ccsm (which finds no live backend and starts a fresh one).
9
- //
10
- // Argv: node restart-helper.js <port> <pid>
11
-
12
- const fs = require('node:fs');
13
- const path = require('node:path');
14
- const os = require('node:os');
15
- const net = require('node:net');
16
- const { spawn } = require('node:child_process');
17
-
18
- const oldPort = Number(process.argv[2] || 7777);
19
- const oldPid = Number(process.argv[3] || 0);
20
-
21
- const HOME = process.env.CCSM_HOME || path.join(os.homedir(), '.ccsm');
22
- const LOG = path.join(HOME, 'restart.log');
23
- try { fs.mkdirSync(HOME, { recursive: true }); } catch {}
24
-
25
- function log(msg) {
26
- const line = `[${new Date().toISOString()}] ${msg}\n`;
27
- try { fs.appendFileSync(LOG, line); } catch {}
28
- }
29
-
30
- function sleep(ms) { return new Promise((r) => setTimeout(r, ms)); }
31
-
32
- function portFree(port, timeoutMs = 800) {
33
- return new Promise((resolve) => {
34
- const s = new net.Socket();
35
- let settled = false;
36
- const finish = (free) => { if (settled) return; settled = true; try { s.destroy(); } catch {} resolve(free); };
37
- s.setTimeout(timeoutMs);
38
- s.once('connect', () => finish(false));
39
- s.once('timeout', () => finish(true));
40
- s.once('error', () => finish(true));
41
- s.connect(port, '127.0.0.1');
42
- });
43
- }
44
-
45
- function pidAlive(pid) {
46
- if (!pid) return false;
47
- try { process.kill(pid, 0); return true; }
48
- catch (e) { return e.code === 'EPERM'; }
49
- }
50
-
51
- (async () => {
52
- log(`start · oldPort=${oldPort} oldPid=${oldPid}`);
53
-
54
- const deadline = Date.now() + 30_000;
55
- while (Date.now() < deadline) {
56
- const free = await portFree(oldPort);
57
- const dead = !pidAlive(oldPid);
58
- if (free && dead) break;
59
- await sleep(250);
60
- }
61
- log(`old server gone (or 30s elapsed) · respawning`);
62
-
63
- const isWin = process.platform === 'win32';
64
- const ccsmCmd = isWin ? 'ccsm.cmd' : 'ccsm';
65
- // Inherit env but DROP CCSM_NO_BROWSER so the respawned server pops a
66
- // fresh browser window — the frontend that triggered the restart
67
- // called window.close() in parallel, and the new window takes its
68
- // place without the OfflineBanner gap.
69
- const childEnv = { ...process.env };
70
- delete childEnv.CCSM_NO_BROWSER;
71
- let exe, exeArgs;
72
- if (isWin) {
73
- exe = process.env.ComSpec || 'cmd.exe';
74
- exeArgs = ['/d', '/s', '/c', ccsmCmd];
75
- } else {
76
- exe = ccsmCmd;
77
- exeArgs = [];
78
- }
79
- try {
80
- const child = spawn(exe, exeArgs, {
81
- detached: true,
82
- stdio: 'ignore',
83
- windowsHide: true,
84
- shell: false,
85
- env: childEnv,
86
- });
87
- child.unref();
88
- log(`respawned ${ccsmCmd} (via ${path.basename(exe)})`);
89
- } catch (e) {
90
- log(`respawn failed: ${e.message}`);
91
- process.exit(1);
92
- }
93
- })().catch((e) => {
94
- log(`fatal: ${e.message}`);
95
- process.exit(1);
96
- });
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // Restart helper · spawned detached by /api/restart.
5
+ //
6
+ // Just like upgrade-helper but skips the `npm i` step. Server kicks
7
+ // this off + gracefulShutdowns; helper waits for the port to free, then
8
+ // respawns ccsm (which finds no live backend and starts a fresh one).
9
+ //
10
+ // Argv: node restart-helper.js <port> <pid>
11
+
12
+ const fs = require('node:fs');
13
+ const path = require('node:path');
14
+ const os = require('node:os');
15
+ const net = require('node:net');
16
+ const { spawn } = require('node:child_process');
17
+
18
+ const oldPort = Number(process.argv[2] || 7777);
19
+ const oldPid = Number(process.argv[3] || 0);
20
+
21
+ const HOME = process.env.CCSM_HOME || path.join(os.homedir(), '.ccsm');
22
+ const LOG = path.join(HOME, 'restart.log');
23
+ try { fs.mkdirSync(HOME, { recursive: true }); } catch {}
24
+
25
+ function log(msg) {
26
+ const line = `[${new Date().toISOString()}] ${msg}\n`;
27
+ try { fs.appendFileSync(LOG, line); } catch {}
28
+ }
29
+
30
+ function sleep(ms) { return new Promise((r) => setTimeout(r, ms)); }
31
+
32
+ function portFree(port, timeoutMs = 800) {
33
+ return new Promise((resolve) => {
34
+ const s = new net.Socket();
35
+ let settled = false;
36
+ const finish = (free) => { if (settled) return; settled = true; try { s.destroy(); } catch {} resolve(free); };
37
+ s.setTimeout(timeoutMs);
38
+ s.once('connect', () => finish(false));
39
+ s.once('timeout', () => finish(true));
40
+ s.once('error', () => finish(true));
41
+ s.connect(port, '127.0.0.1');
42
+ });
43
+ }
44
+
45
+ function pidAlive(pid) {
46
+ if (!pid) return false;
47
+ try { process.kill(pid, 0); return true; }
48
+ catch (e) { return e.code === 'EPERM'; }
49
+ }
50
+
51
+ (async () => {
52
+ log(`start · oldPort=${oldPort} oldPid=${oldPid}`);
53
+
54
+ const deadline = Date.now() + 30_000;
55
+ while (Date.now() < deadline) {
56
+ const free = await portFree(oldPort);
57
+ const dead = !pidAlive(oldPid);
58
+ if (free && dead) break;
59
+ await sleep(250);
60
+ }
61
+ log(`old server gone (or 30s elapsed) · respawning`);
62
+
63
+ const isWin = process.platform === 'win32';
64
+ const ccsmCmd = isWin ? 'ccsm.cmd' : 'ccsm';
65
+ // Inherit env but DROP CCSM_NO_BROWSER so the respawned server pops a
66
+ // fresh browser window — the frontend that triggered the restart
67
+ // called window.close() in parallel, and the new window takes its
68
+ // place without the OfflineBanner gap.
69
+ const childEnv = { ...process.env };
70
+ delete childEnv.CCSM_NO_BROWSER;
71
+ let exe, exeArgs;
72
+ if (isWin) {
73
+ exe = process.env.ComSpec || 'cmd.exe';
74
+ exeArgs = ['/d', '/s', '/c', ccsmCmd];
75
+ } else {
76
+ exe = ccsmCmd;
77
+ exeArgs = [];
78
+ }
79
+ try {
80
+ const child = spawn(exe, exeArgs, {
81
+ detached: true,
82
+ stdio: 'ignore',
83
+ windowsHide: true,
84
+ shell: false,
85
+ env: childEnv,
86
+ });
87
+ child.unref();
88
+ log(`respawned ${ccsmCmd} (via ${path.basename(exe)})`);
89
+ } catch (e) {
90
+ log(`respawn failed: ${e.message}`);
91
+ process.exit(1);
92
+ }
93
+ })().catch((e) => {
94
+ log(`fatal: ${e.message}`);
95
+ process.exit(1);
96
+ });