@team-work/sandbox-client 0.1.1-beta.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.
Files changed (99) hide show
  1. package/README.md +69 -0
  2. package/dist/cli/config-cmd.d.ts +3 -0
  3. package/dist/cli/config-cmd.js +60 -0
  4. package/dist/cli/config-cmd.js.map +1 -0
  5. package/dist/cli/index.d.ts +2 -0
  6. package/dist/cli/index.js +30 -0
  7. package/dist/cli/index.js.map +1 -0
  8. package/dist/cli/list-cmd.d.ts +3 -0
  9. package/dist/cli/list-cmd.js +36 -0
  10. package/dist/cli/list-cmd.js.map +1 -0
  11. package/dist/cli/log-cmd.d.ts +3 -0
  12. package/dist/cli/log-cmd.js +118 -0
  13. package/dist/cli/log-cmd.js.map +1 -0
  14. package/dist/cli/start-cmd.d.ts +3 -0
  15. package/dist/cli/start-cmd.js +69 -0
  16. package/dist/cli/start-cmd.js.map +1 -0
  17. package/dist/cli/status-cmd.d.ts +3 -0
  18. package/dist/cli/status-cmd.js +46 -0
  19. package/dist/cli/status-cmd.js.map +1 -0
  20. package/dist/cli/stop-cmd.d.ts +3 -0
  21. package/dist/cli/stop-cmd.js +115 -0
  22. package/dist/cli/stop-cmd.js.map +1 -0
  23. package/dist/cli/update-cmd.d.ts +3 -0
  24. package/dist/cli/update-cmd.js +16 -0
  25. package/dist/cli/update-cmd.js.map +1 -0
  26. package/dist/client/frames.d.ts +111 -0
  27. package/dist/client/frames.js +22 -0
  28. package/dist/client/frames.js.map +1 -0
  29. package/dist/client/handshake.d.ts +7 -0
  30. package/dist/client/handshake.js +83 -0
  31. package/dist/client/handshake.js.map +1 -0
  32. package/dist/client/protocol.d.ts +36 -0
  33. package/dist/client/protocol.js +39 -0
  34. package/dist/client/protocol.js.map +1 -0
  35. package/dist/client/ws-client.d.ts +48 -0
  36. package/dist/client/ws-client.js +272 -0
  37. package/dist/client/ws-client.js.map +1 -0
  38. package/dist/config/index.d.ts +6 -0
  39. package/dist/config/index.js +68 -0
  40. package/dist/config/index.js.map +1 -0
  41. package/dist/config/paths.d.ts +14 -0
  42. package/dist/config/paths.js +41 -0
  43. package/dist/config/paths.js.map +1 -0
  44. package/dist/config/schema.d.ts +17 -0
  45. package/dist/config/schema.js +52 -0
  46. package/dist/config/schema.js.map +1 -0
  47. package/dist/daemon/detach.d.ts +17 -0
  48. package/dist/daemon/detach.js +30 -0
  49. package/dist/daemon/detach.js.map +1 -0
  50. package/dist/daemon/launch.d.ts +15 -0
  51. package/dist/daemon/launch.js +70 -0
  52. package/dist/daemon/launch.js.map +1 -0
  53. package/dist/daemon/signal.d.ts +7 -0
  54. package/dist/daemon/signal.js +22 -0
  55. package/dist/daemon/signal.js.map +1 -0
  56. package/dist/handlers/rpc/exec-shell.d.ts +13 -0
  57. package/dist/handlers/rpc/exec-shell.js +52 -0
  58. package/dist/handlers/rpc/exec-shell.js.map +1 -0
  59. package/dist/handlers/rpc/file-ops.d.ts +17 -0
  60. package/dist/handlers/rpc/file-ops.js +163 -0
  61. package/dist/handlers/rpc/file-ops.js.map +1 -0
  62. package/dist/handlers/rpc/router.d.ts +9 -0
  63. package/dist/handlers/rpc/router.js +98 -0
  64. package/dist/handlers/rpc/router.js.map +1 -0
  65. package/dist/handlers/terminal/manager.d.ts +20 -0
  66. package/dist/handlers/terminal/manager.js +75 -0
  67. package/dist/handlers/terminal/manager.js.map +1 -0
  68. package/dist/handlers/terminal/pty-session.d.ts +17 -0
  69. package/dist/handlers/terminal/pty-session.js +76 -0
  70. package/dist/handlers/terminal/pty-session.js.map +1 -0
  71. package/dist/handlers/terminal/router.d.ts +6 -0
  72. package/dist/handlers/terminal/router.js +25 -0
  73. package/dist/handlers/terminal/router.js.map +1 -0
  74. package/dist/instance/id.d.ts +5 -0
  75. package/dist/instance/id.js +17 -0
  76. package/dist/instance/id.js.map +1 -0
  77. package/dist/instance/store.d.ts +33 -0
  78. package/dist/instance/store.js +155 -0
  79. package/dist/instance/store.js.map +1 -0
  80. package/dist/instance/types.d.ts +28 -0
  81. package/dist/instance/types.js +7 -0
  82. package/dist/instance/types.js.map +1 -0
  83. package/dist/logging/logger.d.ts +11 -0
  84. package/dist/logging/logger.js +42 -0
  85. package/dist/logging/logger.js.map +1 -0
  86. package/dist/system/report.d.ts +2 -0
  87. package/dist/system/report.js +61 -0
  88. package/dist/system/report.js.map +1 -0
  89. package/dist/update/self-update.d.ts +8 -0
  90. package/dist/update/self-update.js +41 -0
  91. package/dist/update/self-update.js.map +1 -0
  92. package/dist/utils/info.d.ts +11 -0
  93. package/dist/utils/info.js +21 -0
  94. package/dist/utils/info.js.map +1 -0
  95. package/dist/utils/pem.d.ts +15 -0
  96. package/dist/utils/pem.js +31 -0
  97. package/dist/utils/pem.js.map +1 -0
  98. package/package.json +44 -0
  99. package/scripts/fix-pty-perms.js +30 -0
@@ -0,0 +1,155 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.tokenHash = tokenHash;
4
+ exports.loadInstance = loadInstance;
5
+ exports.saveInstance = saveInstance;
6
+ exports.removeInstance = removeInstance;
7
+ exports.listInstances = listInstances;
8
+ exports.updateInstance = updateInstance;
9
+ exports.setStatus = setStatus;
10
+ exports.isPidAlive = isPidAlive;
11
+ exports.purgeDeadInstances = purgeDeadInstances;
12
+ exports.findRunningBySandboxId = findRunningBySandboxId;
13
+ exports.killInstance = killInstance;
14
+ const node_crypto_1 = require("node:crypto");
15
+ const node_fs_1 = require("node:fs");
16
+ const node_path_1 = require("node:path");
17
+ const paths_js_1 = require("../config/paths.js");
18
+ /**
19
+ * 实例状态文件 CRUD:~/.tw/instances/<id>.json(权限 0600)。
20
+ */
21
+ function ensureDir() {
22
+ if (!(0, node_fs_1.existsSync)(paths_js_1.INSTANCES_DIR)) {
23
+ (0, node_fs_1.mkdirSync)(paths_js_1.INSTANCES_DIR, { recursive: true });
24
+ }
25
+ }
26
+ function tokenHash(privateKey) {
27
+ return 'sha256:' + (0, node_crypto_1.createHash)('sha256').update(privateKey).digest('hex');
28
+ }
29
+ function loadInstance(id) {
30
+ const file = (0, paths_js_1.instanceStateFile)(id);
31
+ if (!(0, node_fs_1.existsSync)(file))
32
+ return null;
33
+ try {
34
+ return JSON.parse((0, node_fs_1.readFileSync)(file, 'utf8'));
35
+ }
36
+ catch {
37
+ return null;
38
+ }
39
+ }
40
+ function saveInstance(rec) {
41
+ ensureDir();
42
+ const file = (0, paths_js_1.instanceStateFile)(rec.id);
43
+ (0, node_fs_1.writeFileSync)(file, JSON.stringify(rec, null, 2), { mode: 0o600 });
44
+ (0, node_fs_1.chmodSync)(file, 0o600);
45
+ }
46
+ function removeInstance(id) {
47
+ const file = (0, paths_js_1.instanceStateFile)(id);
48
+ if ((0, node_fs_1.existsSync)(file))
49
+ (0, node_fs_1.unlinkSync)(file);
50
+ }
51
+ /** 列出所有实例状态记录 */
52
+ function listInstances() {
53
+ ensureDir();
54
+ const files = (0, node_fs_1.readdirSync)(paths_js_1.INSTANCES_DIR).filter((f) => f.endsWith('.json'));
55
+ const records = [];
56
+ for (const f of files) {
57
+ try {
58
+ records.push(JSON.parse((0, node_fs_1.readFileSync)((0, node_path_1.join)(paths_js_1.INSTANCES_DIR, f), 'utf8')));
59
+ }
60
+ catch {
61
+ // 跳过损坏文件
62
+ }
63
+ }
64
+ return records;
65
+ }
66
+ /** 更新实例部分字段 */
67
+ function updateInstance(id, patch) {
68
+ const cur = loadInstance(id);
69
+ if (!cur)
70
+ return null;
71
+ const next = { ...cur, ...patch };
72
+ saveInstance(next);
73
+ return next;
74
+ }
75
+ function setStatus(id, status, wsState) {
76
+ const patch = { status, lastSeenAt: new Date().toISOString() };
77
+ if (wsState)
78
+ patch.wsState = wsState;
79
+ updateInstance(id, patch);
80
+ }
81
+ /** 进程是否存活(kill 0 探测,不发信号) */
82
+ function isPidAlive(pid) {
83
+ try {
84
+ process.kill(pid, 0);
85
+ return true;
86
+ }
87
+ catch {
88
+ return false;
89
+ }
90
+ }
91
+ /**
92
+ * 清理 PID 已死的残留记录——daemon 正常退出已自删,但崩溃(SIGKILL/段错误)
93
+ * 来不及自删时会留下 stale "running" 记录。此函数自愈:遍历全部记录,PID 死则删文件。
94
+ * 返回清理条数。
95
+ */
96
+ function purgeDeadInstances() {
97
+ let n = 0;
98
+ for (const r of listInstances()) {
99
+ if (!isPidAlive(r.pid)) {
100
+ removeInstance(r.id);
101
+ n++;
102
+ }
103
+ }
104
+ return n;
105
+ }
106
+ /** 按 sandboxId 找到仍在运行的实例(PID 存活、status=running) */
107
+ function findRunningBySandboxId(sandboxId) {
108
+ for (const r of listInstances()) {
109
+ if (r.sandboxId === sandboxId && isPidAlive(r.pid) && r.status === 'running') {
110
+ return r;
111
+ }
112
+ }
113
+ return null;
114
+ }
115
+ /**
116
+ * 终止某实例进程并清理其记录。同步等待 SIGTERM,超时 SIGKILL(最多约 5s)。
117
+ * 用于「同 sandboxId 只允许一个进程」时,start 前杀掉旧实例。
118
+ */
119
+ async function killInstance(id) {
120
+ const rec = loadInstance(id);
121
+ if (!rec) {
122
+ return { rec: null, ok: true, note: `实例不存在: ${id}` };
123
+ }
124
+ if (!isPidAlive(rec.pid)) {
125
+ removeInstance(id);
126
+ return { rec, ok: true, note: `实例 ${id} (pid ${rec.pid}) 已不在运行,清理记录` };
127
+ }
128
+ try {
129
+ process.kill(rec.pid, 'SIGTERM');
130
+ }
131
+ catch {
132
+ removeInstance(id);
133
+ return { rec, ok: false, note: `发送 SIGTERM 到 ${id} (pid ${rec.pid}) 失败` };
134
+ }
135
+ // 等 5s,仍存活则 SIGKILL
136
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
137
+ for (let i = 0; i < 50; i++) {
138
+ await sleep(100);
139
+ if (!isPidAlive(rec.pid))
140
+ break;
141
+ }
142
+ if (isPidAlive(rec.pid)) {
143
+ try {
144
+ process.kill(rec.pid, 'SIGKILL');
145
+ }
146
+ catch {
147
+ // ignore
148
+ }
149
+ await sleep(200);
150
+ }
151
+ const ok = !isPidAlive(rec.pid);
152
+ removeInstance(id);
153
+ return { rec, ok, note: ok ? `已终止 ${id} (pid ${rec.pid})` : `无法终止 ${id} (pid ${rec.pid})` };
154
+ }
155
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/instance/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * 实例状态记录。持久化到 ~/.tw/instances/<id>.json(权限 0600)。
3
+ * token/privateKey 仅存 sha256 摘要,绝不存明文。
4
+ */
5
+ export type InstanceStatus = 'running' | 'exited' | 'unknown';
6
+ export type WsState = 'connecting' | 'authing' | 'connected' | 'reconnecting' | 'exiting' | 'exited';
7
+ export interface InstanceRecord {
8
+ /** 实例 id,如 inst-20260805-1a2b3c */
9
+ id: string;
10
+ /** 守护进程 pid */
11
+ pid: number;
12
+ /** sandboxId(握手用) */
13
+ sandboxId: string;
14
+ /** privateKey 的 sha256 摘要,仅用于识别,不可逆推原 key */
15
+ tokenHash: string;
16
+ /** sandbox ws 地址 */
17
+ serverUrl: string;
18
+ /** 启动时间 ISO */
19
+ startedAt: string;
20
+ /** 实例状态 */
21
+ status: InstanceStatus;
22
+ /** ws 连接状态 */
23
+ wsState: WsState;
24
+ /** 最近一次心跳/活动时间 ISO */
25
+ lastSeenAt: string;
26
+ /** 日志文件路径 */
27
+ logFile: string;
28
+ }
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ /**
3
+ * 实例状态记录。持久化到 ~/.tw/instances/<id>.json(权限 0600)。
4
+ * token/privateKey 仅存 sha256 摘要,绝不存明文。
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/instance/types.ts"],"names":[],"mappings":";AAAA;;;GAGG"}
@@ -0,0 +1,11 @@
1
+ import { Logger } from 'pino';
2
+ export type { Logger };
3
+ /**
4
+ * 初始化 pino 日志,按 logDir + instanceId 落盘。
5
+ * 结构化字段:time/level/reqId/sessionId/msg。前台调试走 stderr,后台走文件。
6
+ *
7
+ * 文件 destination 用 sync:true 同步写——daemon 在 auth-fail 时毫秒级退出,
8
+ * 异步缓冲会被 process.exit 丢弃导致日志文件为空;同步写保证每条日志即时落盘。
9
+ */
10
+ export declare function initLogger(logDir: string, instanceId: string, foreground?: boolean): Logger;
11
+ export declare function getLogger(): Logger;
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.initLogger = initLogger;
7
+ exports.getLogger = getLogger;
8
+ const node_fs_1 = require("node:fs");
9
+ const node_path_1 = require("node:path");
10
+ const pino_1 = __importDefault(require("pino"));
11
+ const paths_js_1 = require("../config/paths.js");
12
+ let logger = null;
13
+ /**
14
+ * 初始化 pino 日志,按 logDir + instanceId 落盘。
15
+ * 结构化字段:time/level/reqId/sessionId/msg。前台调试走 stderr,后台走文件。
16
+ *
17
+ * 文件 destination 用 sync:true 同步写——daemon 在 auth-fail 时毫秒级退出,
18
+ * 异步缓冲会被 process.exit 丢弃导致日志文件为空;同步写保证每条日志即时落盘。
19
+ */
20
+ function initLogger(logDir, instanceId, foreground = false) {
21
+ const dir = logDir || paths_js_1.DEFAULT_LOG_DIR;
22
+ if (!(0, node_fs_1.existsSync)(dir))
23
+ (0, node_fs_1.mkdirSync)(dir, { recursive: true });
24
+ const file = (0, node_path_1.join)(dir, `${instanceId}.log`);
25
+ const dest = foreground
26
+ ? process.stderr
27
+ : pino_1.default.destination({ dest: file, sync: true });
28
+ logger = (0, pino_1.default)({
29
+ level: process.env.TW_LOG_LEVEL || 'info',
30
+ base: { instanceId },
31
+ timestamp: pino_1.default.stdTimeFunctions.isoTime,
32
+ }, dest);
33
+ return logger;
34
+ }
35
+ function getLogger() {
36
+ if (!logger) {
37
+ // 兜底:命令行场景(非 daemon)用控制台 logger
38
+ logger = (0, pino_1.default)({ level: process.env.TW_LOG_LEVEL || 'info' }, process.stderr);
39
+ }
40
+ return logger;
41
+ }
42
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/logging/logger.ts"],"names":[],"mappings":";;;;;AAkBA,gCAkBC;AAED,8BAMC;AA5CD,qCAAgD;AAChD,yCAAiC;AAEjC,gDAAoC;AAEpC,iDAAqD;AAIrD,IAAI,MAAM,GAAkB,IAAI,CAAC;AAEjC;;;;;;GAMG;AACH,SAAgB,UAAU,CAAC,MAAc,EAAE,UAAkB,EAAE,UAAU,GAAG,KAAK;IAC/E,MAAM,GAAG,GAAG,MAAM,IAAI,0BAAe,CAAC;IACtC,IAAI,CAAC,IAAA,oBAAU,EAAC,GAAG,CAAC;QAAE,IAAA,mBAAS,EAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,MAAM,IAAI,GAAG,IAAA,gBAAI,EAAC,GAAG,EAAE,GAAG,UAAU,MAAM,CAAC,CAAC;IAE5C,MAAM,IAAI,GAA2B,UAAU;QAC7C,CAAC,CAAC,OAAO,CAAC,MAAM;QAChB,CAAC,CAAC,cAAI,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAEjD,MAAM,GAAG,IAAA,cAAI,EACX;QACE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,MAAM;QACzC,IAAI,EAAE,EAAE,UAAU,EAAE;QACpB,SAAS,EAAE,cAAI,CAAC,gBAAgB,CAAC,OAAO;KACzC,EACD,IAAI,CACL,CAAC;IACF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAgB,SAAS;IACvB,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,gCAAgC;QAChC,MAAM,GAAG,IAAA,cAAI,EAAC,EAAE,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,MAAM,EAAE,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/E,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { SandboxConfig } from '../client/frames.js';
2
+ export declare function collectConfig(): SandboxConfig;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.collectConfig = collectConfig;
4
+ const node_os_1 = require("node:os");
5
+ const node_fs_1 = require("node:fs");
6
+ const info_js_1 = require("../utils/info.js");
7
+ /** 取本机主要 IPv4(非内网回环) */
8
+ function getIp() {
9
+ const ifaces = (0, node_os_1.networkInterfaces)();
10
+ for (const list of Object.values(ifaces)) {
11
+ if (!list)
12
+ continue;
13
+ for (const ni of list) {
14
+ if (ni.family === 'IPv4' && !ni.internal)
15
+ return ni.address;
16
+ }
17
+ }
18
+ return '127.0.0.1';
19
+ }
20
+ /** os 描述,如 'darwin 25.4.0 arm64' */
21
+ function getOs() {
22
+ return `${(0, node_os_1.platform)()} ${(0, node_os_1.type)()} ${process.arch}`;
23
+ }
24
+ /** cpu 摘要 */
25
+ function getCpu() {
26
+ const c = (0, node_os_1.cpus)();
27
+ if (!c.length)
28
+ return 'unknown';
29
+ const m = c[0].model;
30
+ return `${m} x${c.length}`;
31
+ }
32
+ /** 字节 → GB 整数(二进制 GiB:/ 1024³),与 sandbox mock-cli 约定一致 */
33
+ function bytesToGb(bytes) {
34
+ return Math.round(bytes / 1024 / 1024 / 1024);
35
+ }
36
+ /** 内存 GB:os.totalmem() 返回字节,转 GB */
37
+ function getMemoryGb() {
38
+ return bytesToGb((0, node_os_1.totalmem)());
39
+ }
40
+ /** 硬盘 GB:取根分区总容量。Node 18.15+ 提供 fs.statfsSync,取不到回 0 */
41
+ function getStorageGb() {
42
+ try {
43
+ const target = process.platform === 'win32' ? (process.env.SystemDrive || 'C:\\') : '/';
44
+ const stats = (0, node_fs_1.statfsSync)(target);
45
+ return bytesToGb(stats.bsize * stats.blocks);
46
+ }
47
+ catch {
48
+ return 0;
49
+ }
50
+ }
51
+ function collectConfig() {
52
+ return {
53
+ ip: getIp(),
54
+ os: getOs(),
55
+ cpu: getCpu(),
56
+ memory: getMemoryGb(),
57
+ storage: getStorageGb(),
58
+ cliVersion: (0, info_js_1.getPkgInfo)().version,
59
+ };
60
+ }
61
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/system/report.ts"],"names":[],"mappings":";;AAoDA,sCASC;AA7DD,qCAA4E;AAC5E,qCAAqC;AAErC,8CAA8C;AAG9C,wBAAwB;AACxB,SAAS,KAAK;IACZ,MAAM,MAAM,GAAG,IAAA,2BAAiB,GAAE,CAAC;IACnC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QACzC,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,KAAK,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;YACtB,IAAI,EAAE,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,EAAE,CAAC,QAAQ;gBAAE,OAAO,EAAE,CAAC,OAAO,CAAC;QAC9D,CAAC;IACH,CAAC;IACD,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,oCAAoC;AACpC,SAAS,KAAK;IACZ,OAAO,GAAG,IAAA,kBAAQ,GAAE,IAAI,IAAA,cAAI,GAAE,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;AACnD,CAAC;AAED,aAAa;AACb,SAAS,MAAM;IACb,MAAM,CAAC,GAAG,IAAA,cAAI,GAAE,CAAC;IACjB,IAAI,CAAC,CAAC,CAAC,MAAM;QAAE,OAAO,SAAS,CAAC;IAChC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACrB,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC;AAC7B,CAAC;AAED,0DAA0D;AAC1D,SAAS,SAAS,CAAC,KAAa;IAC9B,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC;AAChD,CAAC;AAED,oCAAoC;AACpC,SAAS,WAAW;IAClB,OAAO,SAAS,CAAC,IAAA,kBAAQ,GAAE,CAAC,CAAC;AAC/B,CAAC;AAED,wDAAwD;AACxD,SAAS,YAAY;IACnB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QACxF,MAAM,KAAK,GAAG,IAAA,oBAAU,EAAC,MAAM,CAAC,CAAC;QACjC,OAAO,SAAS,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC;AAED,SAAgB,aAAa;IAC3B,OAAO;QACL,EAAE,EAAE,KAAK,EAAE;QACX,EAAE,EAAE,KAAK,EAAE;QACX,GAAG,EAAE,MAAM,EAAE;QACb,MAAM,EAAE,WAAW,EAAE;QACrB,OAAO,EAAE,YAAY,EAAE;QACvB,UAAU,EAAE,IAAA,oBAAU,GAAE,CAAC,OAAO;KACjC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * 自更新:读当前包 name/version,npm view 取最新,npm i -g <name>@latest。
3
+ * 返回结果描述字符串供命令层打印。
4
+ */
5
+ export declare function selfUpdate(): {
6
+ changed: boolean;
7
+ message: string;
8
+ };
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.selfUpdate = selfUpdate;
4
+ const node_child_process_1 = require("node:child_process");
5
+ const info_js_1 = require("../utils/info.js");
6
+ /**
7
+ * 自更新:读当前包 name/version,npm view 取最新,npm i -g <name>@latest。
8
+ * 返回结果描述字符串供命令层打印。
9
+ */
10
+ function selfUpdate() {
11
+ const { name } = (0, info_js_1.getPkgInfo)();
12
+ const current = (0, info_js_1.getPkgInfo)().version;
13
+ // npm view <name> version(取最新发布版本)
14
+ const view = (0, node_child_process_1.spawnSync)('npm', ['view', name, 'version'], { encoding: 'utf8' });
15
+ if (view.status !== 0) {
16
+ return {
17
+ changed: false,
18
+ message: `查询最新版本失败:${(view.stderr || view.stdout || '').trim() || 'npm view 失败'}`,
19
+ };
20
+ }
21
+ const latest = view.stdout.trim();
22
+ if (!latest) {
23
+ return { changed: false, message: '无法解析最新版本号' };
24
+ }
25
+ if (latest === current) {
26
+ return { changed: false, message: `已是最新版本 ${current}` };
27
+ }
28
+ // npm i -g <name>@latest
29
+ const install = (0, node_child_process_1.spawnSync)('npm', ['i', '-g', `${name}@latest`], {
30
+ encoding: 'utf8',
31
+ stdio: 'inherit',
32
+ });
33
+ if (install.status !== 0) {
34
+ return { changed: false, message: `更新失败(npm 退出码 ${install.status})` };
35
+ }
36
+ return {
37
+ changed: true,
38
+ message: `已更新 ${current} → ${latest};请重启正在运行的 tw 实例以生效。`,
39
+ };
40
+ }
41
+ //# sourceMappingURL=self-update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"self-update.js","sourceRoot":"","sources":["../../src/update/self-update.ts"],"names":[],"mappings":";;AAQA,gCAiCC;AAzCD,2DAA+C;AAE/C,8CAA8C;AAE9C;;;GAGG;AACH,SAAgB,UAAU;IACxB,MAAM,EAAE,IAAI,EAAE,GAAG,IAAA,oBAAU,GAAE,CAAC;IAC9B,MAAM,OAAO,GAAG,IAAA,oBAAU,GAAE,CAAC,OAAO,CAAC;IAErC,mCAAmC;IACnC,MAAM,IAAI,GAAG,IAAA,8BAAS,EAAC,KAAK,EAAE,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAC/E,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO;YACL,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,YAAY,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,aAAa,EAAE;SAClF,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IAClC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;IAClD,CAAC;IAED,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;QACvB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,OAAO,EAAE,EAAE,CAAC;IAC1D,CAAC;IAED,yBAAyB;IACzB,MAAM,OAAO,GAAG,IAAA,8BAAS,EAAC,KAAK,EAAE,CAAC,GAAG,EAAE,IAAI,EAAE,GAAG,IAAI,SAAS,CAAC,EAAE;QAC9D,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,SAAS;KACjB,CAAC,CAAC;IACH,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,gBAAgB,OAAO,CAAC,MAAM,GAAG,EAAE,CAAC;IACxE,CAAC;IACD,OAAO;QACL,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,OAAO,OAAO,MAAM,MAAM,qBAAqB;KACzD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,11 @@
1
+ interface PkgInfo {
2
+ name: string;
3
+ version: string;
4
+ }
5
+ /**
6
+ * 读取 package.json 的 name / version。
7
+ * dist 输出为 CJS,无法用 import attribute 加载 .json,改走 fs。
8
+ * dist/<dir>/file.js → 根 package.json = __dirname/../..
9
+ */
10
+ export declare function getPkgInfo(): PkgInfo;
11
+ export {};
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getPkgInfo = getPkgInfo;
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
+ let cached = null;
7
+ /**
8
+ * 读取 package.json 的 name / version。
9
+ * dist 输出为 CJS,无法用 import attribute 加载 .json,改走 fs。
10
+ * dist/<dir>/file.js → 根 package.json = __dirname/../..
11
+ */
12
+ function getPkgInfo() {
13
+ if (cached)
14
+ return cached;
15
+ const file = (0, node_path_1.resolve)(__dirname, '..', '..', 'package.json');
16
+ const raw = (0, node_fs_1.readFileSync)(file, 'utf8');
17
+ const parsed = JSON.parse(raw);
18
+ cached = { name: parsed.name, version: parsed.version };
19
+ return cached;
20
+ }
21
+ //# sourceMappingURL=info.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"info.js","sourceRoot":"","sources":["../../src/utils/info.ts"],"names":[],"mappings":";;AAeA,gCAOC;AAtBD,qCAAuC;AACvC,yCAAoC;AAOpC,IAAI,MAAM,GAAmB,IAAI,CAAC;AAElC;;;;GAIG;AACH,SAAgB,UAAU;IACxB,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,MAAM,IAAI,GAAG,IAAA,mBAAO,EAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;IAC5D,MAAM,GAAG,GAAG,IAAA,sBAAY,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,CAAC;IAC1C,MAAM,GAAG,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;IACxD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * 私钥归一化:复现 Node `generateKeyPairSync('rsa', { privateKeyEncoding: { type: 'pkcs8', format: 'pem' } })`
3
+ * 的输出格式,以字节匹配 sandbox DB 中 `oauth_sandbox.private_key`。
4
+ *
5
+ * 背景:oauth `SandboxesService.list()` 对外脱敏时去掉了 PEM 首尾与所有空白,
6
+ * 用户从 UI 复制到的是纯 base64 body;而 sandbox `findByPrivateKeyMatch` 用
7
+ * `safeEqual(row.privateKey, privateKey)` 精确比对 DB 原值(完整 PEM)。两者不一致
8
+ * → 鉴权失败 4001。本函数把用户输入还原成 DB 侧的完整 PEM。
9
+ *
10
+ * 支持三种输入:
11
+ * - 纯 base64 body(UI 复制):重排 64 字符/行 + 加 BEGIN/END PRIVATE KEY 首尾 + 尾换行
12
+ * - 带字面 \n 的 PEM(mock-cli 风格):\n 转真换行
13
+ * - 已带 PEM 首尾的真换行串:原样返回(补尾换行)
14
+ */
15
+ export declare function normalizePrivateKey(key: string): string;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizePrivateKey = normalizePrivateKey;
4
+ /**
5
+ * 私钥归一化:复现 Node `generateKeyPairSync('rsa', { privateKeyEncoding: { type: 'pkcs8', format: 'pem' } })`
6
+ * 的输出格式,以字节匹配 sandbox DB 中 `oauth_sandbox.private_key`。
7
+ *
8
+ * 背景:oauth `SandboxesService.list()` 对外脱敏时去掉了 PEM 首尾与所有空白,
9
+ * 用户从 UI 复制到的是纯 base64 body;而 sandbox `findByPrivateKeyMatch` 用
10
+ * `safeEqual(row.privateKey, privateKey)` 精确比对 DB 原值(完整 PEM)。两者不一致
11
+ * → 鉴权失败 4001。本函数把用户输入还原成 DB 侧的完整 PEM。
12
+ *
13
+ * 支持三种输入:
14
+ * - 纯 base64 body(UI 复制):重排 64 字符/行 + 加 BEGIN/END PRIVATE KEY 首尾 + 尾换行
15
+ * - 带字面 \n 的 PEM(mock-cli 风格):\n 转真换行
16
+ * - 已带 PEM 首尾的真换行串:原样返回(补尾换行)
17
+ */
18
+ function normalizePrivateKey(key) {
19
+ let k = (key ?? '').replace(/\\n/g, '\n').trim();
20
+ if (k.includes('-----BEGIN')) {
21
+ if (!k.endsWith('\n'))
22
+ k += '\n';
23
+ return k;
24
+ }
25
+ const body = k.replace(/\s/g, '');
26
+ if (!body)
27
+ return k;
28
+ const lines = body.match(/.{1,64}/g) ?? [body];
29
+ return `-----BEGIN PRIVATE KEY-----\n${lines.join('\n')}\n-----END PRIVATE KEY-----\n`;
30
+ }
31
+ //# sourceMappingURL=pem.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pem.js","sourceRoot":"","sources":["../../src/utils/pem.ts"],"names":[],"mappings":";;AAcA,kDAUC;AAxBD;;;;;;;;;;;;;GAaG;AACH,SAAgB,mBAAmB,CAAC,GAAW;IAC7C,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;IACjD,IAAI,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QAC7B,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,CAAC,IAAI,IAAI,CAAC;QACjC,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAClC,IAAI,CAAC,IAAI;QAAE,OAAO,CAAC,CAAC;IACpB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/C,OAAO,gCAAgC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,+BAA+B,CAAC;AACzF,CAAC"}
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@team-work/sandbox-client",
3
+ "version": "0.1.1-beta.0",
4
+ "description": "team-work sandbox CLI client — connect to sandbox WS server and accept remote shell / pty / file operations",
5
+ "bin": {
6
+ "tw": "dist/cli/index.js"
7
+ },
8
+ "main": "dist/index.js",
9
+ "types": "dist/index.d.ts",
10
+ "scripts": {
11
+ "build": "tsc -p tsconfig.json",
12
+ "dev": "tsc -p tsconfig.json --watch --sourceMap",
13
+ "start": "node dist/cli/index.js",
14
+ "postinstall": "node scripts/fix-pty-perms.js",
15
+ "prepublishOnly": "npm run build"
16
+ },
17
+ "engines": {
18
+ "node": ">=18"
19
+ },
20
+ "files": [
21
+ "dist",
22
+ "scripts",
23
+ "README.md"
24
+ ],
25
+ "keywords": [
26
+ "team-work",
27
+ "sandbox",
28
+ "cli",
29
+ "websocket",
30
+ "pty"
31
+ ],
32
+ "license": "MIT",
33
+ "dependencies": {
34
+ "commander": "^12.1.0",
35
+ "node-pty": "^1.0.0",
36
+ "pino": "^9.5.0",
37
+ "ws": "^8.18.0"
38
+ },
39
+ "devDependencies": {
40
+ "@types/node": "^20.14.0",
41
+ "@types/ws": "^8.5.12",
42
+ "typescript": "^5.5.4"
43
+ }
44
+ }
@@ -0,0 +1,30 @@
1
+ // node-pty 预编译二进制(prebuilds/<arch>/spawn-helper)经 npm 解包后常丢失可执行位,
2
+ // 导致 pty.spawn 同步抛 `posix_spawnp failed.`(EACCES),CLI 守护进程一开终端就崩。
3
+ // postinstall 时补回 +x,保证各平台 prebuild 都可执行。
4
+ const { chmodSync, existsSync, readdirSync, statSync } = require('node:fs');
5
+ const { join } = require('node:path');
6
+
7
+ const prebuildDir = join(__dirname, '..', 'node_modules', 'node-pty', 'prebuilds');
8
+ if (!existsSync(prebuildDir)) {
9
+ // 无预编译包(从源码编译的场景)——跳过
10
+ process.exit(0);
11
+ }
12
+
13
+ let touched = 0;
14
+ for (const arch of readdirSync(prebuildDir)) {
15
+ const dir = join(prebuildDir, arch);
16
+ if (!statSync(dir).isDirectory()) continue;
17
+ for (const bin of readdirSync(dir)) {
18
+ // spawn-helper 是 posix_spawn 拉起的可执行;pty.node 是 .node 动态库(也顺带补位,无害)
19
+ if (bin === 'spawn-helper' || bin.endsWith('.node')) {
20
+ const p = join(dir, bin);
21
+ try {
22
+ chmodSync(p, 0o755);
23
+ touched++;
24
+ } catch (err) {
25
+ console.warn(`[fix-pty-perms] chmod failed: ${p} (${err.message})`);
26
+ }
27
+ }
28
+ }
29
+ }
30
+ console.log(`[fix-pty-perms] ensured executable bit on ${touched} file(s) under node-pty/prebuilds`);