@artenx/dshb 0.0.5 → 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.
Files changed (166) hide show
  1. package/cordis.patch.yml +9 -9
  2. package/lib/auth/credentials.d.ts +30 -0
  3. package/lib/auth/credentials.js +121 -0
  4. package/lib/auth/credentials.js.map +1 -0
  5. package/lib/auth/decorate-webserver.d.ts +7 -0
  6. package/lib/auth/decorate-webserver.js +75 -0
  7. package/lib/auth/decorate-webserver.js.map +1 -0
  8. package/lib/auth/gate.d.ts +14 -0
  9. package/lib/auth/gate.js +45 -0
  10. package/lib/auth/gate.js.map +1 -0
  11. package/lib/auth/index.d.ts +8 -0
  12. package/lib/auth/index.js +51 -0
  13. package/lib/auth/index.js.map +1 -0
  14. package/lib/auth/login-page.d.ts +5 -0
  15. package/lib/auth/login-page.js +87 -0
  16. package/lib/auth/login-page.js.map +1 -0
  17. package/lib/auth/loopback-compat.d.ts +6 -0
  18. package/lib/auth/loopback-compat.js +94 -0
  19. package/lib/auth/loopback-compat.js.map +1 -0
  20. package/lib/auth/loopback.d.ts +7 -0
  21. package/lib/auth/loopback.js +24 -0
  22. package/lib/auth/loopback.js.map +1 -0
  23. package/lib/auth/ratelimit.d.ts +11 -0
  24. package/lib/auth/ratelimit.js +37 -0
  25. package/lib/auth/ratelimit.js.map +1 -0
  26. package/lib/auth/routes.d.ts +8 -0
  27. package/lib/auth/routes.js +224 -0
  28. package/lib/auth/routes.js.map +1 -0
  29. package/lib/auth/session.d.ts +11 -0
  30. package/lib/auth/session.js +52 -0
  31. package/lib/auth/session.js.map +1 -0
  32. package/lib/auth/startup.d.ts +15 -0
  33. package/lib/auth/startup.js +68 -0
  34. package/lib/auth/startup.js.map +1 -0
  35. package/lib/auth/webserver.d.ts +18 -0
  36. package/lib/auth/webserver.js +60 -0
  37. package/lib/auth/webserver.js.map +1 -0
  38. package/lib/client.js +2770 -0
  39. package/lib/client.js.map +1 -0
  40. package/lib/connection-sIX25pkS.d.ts +46 -0
  41. package/lib/core/audit.d.ts +16 -0
  42. package/lib/core/audit.js +38 -0
  43. package/lib/core/audit.js.map +1 -0
  44. package/lib/core/index.d.ts +8 -0
  45. package/lib/core/index.js +77 -0
  46. package/lib/core/index.js.map +1 -0
  47. package/lib/core/known-hosts.d.ts +23 -0
  48. package/lib/core/known-hosts.js +76 -0
  49. package/lib/core/known-hosts.js.map +1 -0
  50. package/lib/core/node-registry.d.ts +108 -0
  51. package/lib/core/node-registry.js +191 -0
  52. package/lib/core/node-registry.js.map +1 -0
  53. package/lib/core/routes.d.ts +9 -0
  54. package/lib/core/routes.js +404 -0
  55. package/lib/core/routes.js.map +1 -0
  56. package/lib/core/ssh-config.d.ts +23 -0
  57. package/lib/core/ssh-config.js +70 -0
  58. package/lib/core/ssh-config.js.map +1 -0
  59. package/lib/core/test.d.ts +43 -0
  60. package/lib/core/test.js +116 -0
  61. package/lib/core/test.js.map +1 -0
  62. package/lib/core/workspace-bindings.d.ts +28 -0
  63. package/lib/core/workspace-bindings.js +86 -0
  64. package/lib/core/workspace-bindings.js.map +1 -0
  65. package/lib/core/workspaces.d.ts +9 -0
  66. package/lib/core/workspaces.js +283 -0
  67. package/lib/core/workspaces.js.map +1 -0
  68. package/lib/exec-docker/daemon-runner.d.ts +21 -0
  69. package/lib/exec-docker/daemon-runner.js +326 -0
  70. package/lib/exec-docker/daemon-runner.js.map +1 -0
  71. package/lib/exec-docker/docker-backend.d.ts +48 -0
  72. package/lib/exec-docker/docker-backend.js +1 -0
  73. package/lib/exec-docker/docker-client.d.ts +46 -0
  74. package/lib/exec-docker/docker-client.js +302 -0
  75. package/lib/exec-docker/docker-client.js.map +1 -0
  76. package/lib/exec-docker/docker-routes.d.ts +6 -0
  77. package/lib/exec-docker/docker-routes.js +215 -0
  78. package/lib/exec-docker/docker-routes.js.map +1 -0
  79. package/lib/exec-docker/fs-provider.d.ts +50 -0
  80. package/lib/exec-docker/fs-provider.js +92 -0
  81. package/lib/exec-docker/fs-provider.js.map +1 -0
  82. package/lib/exec-docker/host-runner.d.ts +29 -0
  83. package/lib/exec-docker/host-runner.js +17 -0
  84. package/lib/exec-docker/host-runner.js.map +1 -0
  85. package/lib/exec-docker/index.d.ts +21 -0
  86. package/lib/exec-docker/index.js +137 -0
  87. package/lib/exec-docker/index.js.map +1 -0
  88. package/lib/exec-docker/process-provider.d.ts +20 -0
  89. package/lib/exec-docker/process-provider.js +75 -0
  90. package/lib/exec-docker/process-provider.js.map +1 -0
  91. package/lib/exec-docker/provision.d.ts +24 -0
  92. package/lib/exec-docker/provision.js +103 -0
  93. package/lib/exec-docker/provision.js.map +1 -0
  94. package/lib/exec-docker/remote-docker-cli.d.ts +52 -0
  95. package/lib/exec-docker/remote-docker-cli.js +155 -0
  96. package/lib/exec-docker/remote-docker-cli.js.map +1 -0
  97. package/lib/exec-docker/world.d.ts +37 -0
  98. package/lib/exec-docker/world.js +62 -0
  99. package/lib/exec-docker/world.js.map +1 -0
  100. package/lib/exec-ssh/connection-pool.d.ts +25 -0
  101. package/lib/exec-ssh/connection-pool.js +54 -0
  102. package/lib/exec-ssh/connection-pool.js.map +1 -0
  103. package/lib/exec-ssh/connection.d.ts +2 -0
  104. package/lib/exec-ssh/connection.js +125 -0
  105. package/lib/exec-ssh/connection.js.map +1 -0
  106. package/lib/exec-ssh/env-scrub.d.ts +7 -0
  107. package/lib/exec-ssh/env-scrub.js +40 -0
  108. package/lib/exec-ssh/env-scrub.js.map +1 -0
  109. package/lib/exec-ssh/executor.d.ts +46 -0
  110. package/lib/exec-ssh/executor.js +212 -0
  111. package/lib/exec-ssh/executor.js.map +1 -0
  112. package/lib/exec-ssh/fs-provider.d.ts +50 -0
  113. package/lib/exec-ssh/fs-provider.js +92 -0
  114. package/lib/exec-ssh/fs-provider.js.map +1 -0
  115. package/lib/exec-ssh/index.d.ts +16 -0
  116. package/lib/exec-ssh/index.js +30 -0
  117. package/lib/exec-ssh/index.js.map +1 -0
  118. package/lib/exec-ssh/process-provider.d.ts +20 -0
  119. package/lib/exec-ssh/process-provider.js +75 -0
  120. package/lib/exec-ssh/process-provider.js.map +1 -0
  121. package/lib/exec-ssh/runner.d.ts +13 -0
  122. package/lib/exec-ssh/runner.js +62 -0
  123. package/lib/exec-ssh/runner.js.map +1 -0
  124. package/lib/exec-ssh/world.d.ts +79 -0
  125. package/lib/exec-ssh/world.js +95 -0
  126. package/lib/exec-ssh/world.js.map +1 -0
  127. package/lib/index.d.ts +2 -0
  128. package/lib/index.js +2 -0
  129. package/lib/router/decorate-fs.d.ts +6 -0
  130. package/lib/router/decorate-fs.js +78 -0
  131. package/lib/router/decorate-fs.js.map +1 -0
  132. package/lib/router/decorate-shell.d.ts +6 -0
  133. package/lib/router/decorate-shell.js +35 -0
  134. package/lib/router/decorate-shell.js.map +1 -0
  135. package/lib/router/decorate-subprocess.d.ts +6 -0
  136. package/lib/router/decorate-subprocess.js +35 -0
  137. package/lib/router/decorate-subprocess.js.map +1 -0
  138. package/lib/router/index.d.ts +10 -0
  139. package/lib/router/index.js +21 -0
  140. package/lib/router/index.js.map +1 -0
  141. package/lib/router/resolve.d.ts +22 -0
  142. package/lib/router/resolve.js +45 -0
  143. package/lib/router/resolve.js.map +1 -0
  144. package/lib/router/router-fs.d.ts +25 -0
  145. package/lib/router/router-fs.js +64 -0
  146. package/lib/router/router-fs.js.map +1 -0
  147. package/lib/router/router-shell.d.ts +14 -0
  148. package/lib/router/router-shell.js +36 -0
  149. package/lib/router/router-shell.js.map +1 -0
  150. package/lib/router/router-subprocess.d.ts +13 -0
  151. package/lib/router/router-subprocess.js +33 -0
  152. package/lib/router/router-subprocess.js.map +1 -0
  153. package/lib/router/types.d.ts +2 -0
  154. package/lib/router/types.js +1 -0
  155. package/lib/types-C0TtEO7z.d.ts +67 -0
  156. package/lib/ui/decorate-picker.d.ts +6 -0
  157. package/lib/ui/decorate-picker.js +58 -0
  158. package/lib/ui/decorate-picker.js.map +1 -0
  159. package/lib/ui/index.d.ts +8 -0
  160. package/lib/ui/index.js +11 -0
  161. package/lib/ui/index.js.map +1 -0
  162. package/lib/ui/picker.d.ts +10 -0
  163. package/lib/ui/picker.js +58 -0
  164. package/lib/ui/picker.js.map +1 -0
  165. package/package.json +150 -10
  166. package/LICENSE +0 -21
@@ -0,0 +1,212 @@
1
+ import { REMOTE_RUNNER_COMMAND, encodeRunnerPayload } from "./runner.js";
2
+ import { homedir } from "node:os";
3
+ import { existsSync, readFileSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ //#region src/exec-ssh/executor.ts
6
+ var SshExecutor = class {
7
+ connection;
8
+ nodeId;
9
+ audit;
10
+ sftpCache = null;
11
+ constructor(connection, nodeId = "unknown", audit) {
12
+ this.connection = connection;
13
+ this.nodeId = nodeId;
14
+ this.audit = audit;
15
+ }
16
+ async exec(argv, cwd, env = {}, stdinData) {
17
+ const client = await this.connection.getClient();
18
+ const body = encodeRunnerPayload({
19
+ argv,
20
+ cwd,
21
+ env
22
+ });
23
+ const input = stdinData ? Buffer.concat([body, stdinData]) : body;
24
+ return new Promise((resolve, reject) => {
25
+ client.exec(REMOTE_RUNNER_COMMAND, (err, channel) => {
26
+ if (err) {
27
+ reject(err);
28
+ return;
29
+ }
30
+ const stdout = [];
31
+ const stderr = [];
32
+ channel.stdout.on("data", (chunk) => stdout.push(chunk));
33
+ channel.stderr.on("data", (chunk) => stderr.push(chunk));
34
+ channel.on("close", (code, signal) => {
35
+ this.audit?.("exec", argv.join(" "), `code=${code ?? 0}`);
36
+ resolve({
37
+ code: code ?? 0,
38
+ signal,
39
+ stdout: Buffer.concat(stdout).toString("utf8"),
40
+ stderr: Buffer.concat(stderr).toString("utf8")
41
+ });
42
+ });
43
+ channel.on("error", reject);
44
+ channel.end(input);
45
+ });
46
+ });
47
+ }
48
+ async sftp() {
49
+ if (this.sftpCache) return this.sftpCache;
50
+ const client = await this.connection.getClient();
51
+ this.sftpCache = new Promise((resolve, reject) => {
52
+ client.sftp((err, sftp) => {
53
+ if (err) reject(err);
54
+ else resolve(sftp);
55
+ });
56
+ });
57
+ return this.sftpCache;
58
+ }
59
+ async readFile(path) {
60
+ const sftp = await this.sftp();
61
+ return new Promise((resolve, reject) => {
62
+ sftp.readFile(path, (err, data) => err ? reject(err) : resolve(data));
63
+ });
64
+ }
65
+ async writeFile(path, content) {
66
+ const sftp = await this.sftp();
67
+ const tmp = `${path}.dshb-tmp-${process.pid}-${Date.now()}`;
68
+ return new Promise((resolve, reject) => {
69
+ sftp.writeFile(tmp, content, (writeErr) => {
70
+ if (writeErr) {
71
+ reject(writeErr);
72
+ return;
73
+ }
74
+ sftp.ext_openssh_rename(tmp, path, (renameErr) => {
75
+ if (renameErr) reject(renameErr);
76
+ else {
77
+ this.audit?.("write", path, "ok");
78
+ resolve();
79
+ }
80
+ });
81
+ });
82
+ });
83
+ }
84
+ async listDir(path) {
85
+ const sftp = await this.sftp();
86
+ return new Promise((resolve, reject) => {
87
+ sftp.readdir(path, (err, list) => {
88
+ if (err) {
89
+ reject(err);
90
+ return;
91
+ }
92
+ resolve(list.map((e) => ({
93
+ name: e.filename,
94
+ isDir: e.attrs.isDirectory(),
95
+ isFile: e.attrs.isFile(),
96
+ isSymlink: e.attrs.isSymbolicLink(),
97
+ size: Number(e.attrs.size),
98
+ mtime: e.attrs.mtime * 1e3
99
+ })));
100
+ });
101
+ });
102
+ }
103
+ async stat(path) {
104
+ const sftp = await this.sftp();
105
+ return new Promise((resolve) => {
106
+ sftp.stat(path, (err, stats) => {
107
+ if (err) {
108
+ resolve(void 0);
109
+ return;
110
+ }
111
+ resolve({
112
+ size: Number(stats.size),
113
+ mtime: stats.mtime * 1e3,
114
+ isDirectory: stats.isDirectory(),
115
+ isFile: stats.isFile()
116
+ });
117
+ });
118
+ });
119
+ }
120
+ async mkdir(path) {
121
+ const sftp = await this.sftp();
122
+ return new Promise((resolve, reject) => {
123
+ sftp.mkdir(path, (err) => err ? reject(err) : resolve());
124
+ });
125
+ }
126
+ async remove(path) {
127
+ const sftp = await this.sftp();
128
+ return new Promise((resolve, reject) => {
129
+ sftp.unlink(path, (err) => {
130
+ if (err) reject(err);
131
+ else {
132
+ this.audit?.("remove", path, "ok");
133
+ resolve();
134
+ }
135
+ });
136
+ });
137
+ }
138
+ async rename(src, dest) {
139
+ const sftp = await this.sftp();
140
+ return new Promise((resolve, reject) => {
141
+ sftp.ext_openssh_rename(src, dest, (err) => {
142
+ if (err) reject(err);
143
+ else {
144
+ this.audit?.("move", `${src} -> ${dest}`, "ok");
145
+ resolve();
146
+ }
147
+ });
148
+ });
149
+ }
150
+ async ensureRg() {
151
+ if ((await this.exec([
152
+ "sh",
153
+ "-c",
154
+ "command -v rg || echo \"__DShB_RG_MISSING__\""
155
+ ], "/")).stdout.includes("__DShB_RG_MISSING__")) {
156
+ const localRg = process.env.DSHB_LOCAL_RG ?? findLocalRg();
157
+ if (!localRg) return;
158
+ const remoteRgDir = "~/.dshb/bin";
159
+ await this.exec([
160
+ "mkdir",
161
+ "-p",
162
+ remoteRgDir
163
+ ], "/");
164
+ const remoteRg = `${remoteRgDir}/rg`;
165
+ const content = readFileSync(localRg);
166
+ await this.writeFile(remoteRg, content);
167
+ await this.exec([
168
+ "chmod",
169
+ "+x",
170
+ remoteRg
171
+ ], "/");
172
+ }
173
+ }
174
+ async pty(argv, cwd, _env, cols, rows) {
175
+ const client = await this.connection.getClient();
176
+ const q = (s) => `'${s.replace(/'/g, "'\\''")}'`;
177
+ const cmdParts = argv.map(q);
178
+ const command = `bash -c 'cd "$0" && exec env -i HOME="$HOME" PATH="\${PATH:-/usr/local/bin:/usr/bin:/bin}" "$@"' ${q(cwd)} ${cmdParts.join(" ")}`;
179
+ return new Promise((resolve, reject) => {
180
+ client.exec(command, { pty: {
181
+ cols,
182
+ rows,
183
+ term: "xterm-256color"
184
+ } }, (err, channel) => {
185
+ if (err) {
186
+ reject(err);
187
+ return;
188
+ }
189
+ resolve({
190
+ channel,
191
+ onData: (cb) => channel.on("data", cb),
192
+ resize: (c, r) => channel.setWindow(c, r, 0, 0),
193
+ kill: () => channel.close()
194
+ });
195
+ });
196
+ });
197
+ }
198
+ };
199
+ function findLocalRg() {
200
+ const candidates = [
201
+ join(homedir(), ".dsh", "node_modules", ".bin", "rg"),
202
+ join(homedir(), ".dsh", "node_modules", "@vscode", "ripgrep", "bin", "rg"),
203
+ join(homedir(), "go", "bin", "rg"),
204
+ "/usr/local/bin/rg",
205
+ "/usr/bin/rg"
206
+ ];
207
+ for (const c of candidates) if (existsSync(c)) return c;
208
+ }
209
+ //#endregion
210
+ export { SshExecutor };
211
+
212
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","names":[],"sources":["../../src/exec-ssh/executor.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport { encodeRunnerPayload, REMOTE_RUNNER_COMMAND, type RunnerPayload } from './runner.js'\nimport type { SshConnection } from './connection.js'\n\nexport interface ExecResult {\n code: number\n signal?: string\n stdout: string\n stderr: string\n}\n\nexport class SshExecutor {\n private sftpCache: Promise<import('ssh2').SFTPWrapper> | null = null\n\n constructor(\n private readonly connection: SshConnection,\n private readonly nodeId = 'unknown',\n private readonly audit?: (op: string, target: string, result: string) => void,\n ) {}\n\n async exec(argv: string[], cwd: string, env: Record<string, string> = {}, stdinData?: Buffer): Promise<ExecResult> {\n const client = await this.connection.getClient()\n const payload: RunnerPayload = { argv, cwd, env }\n const body = encodeRunnerPayload(payload)\n const input = stdinData ? Buffer.concat([body, stdinData]) : body\n return new Promise((resolve, reject) => {\n client.exec(REMOTE_RUNNER_COMMAND, (err, channel) => {\n if (err) {\n reject(err)\n return\n }\n const stdout: Buffer[] = []\n const stderr: Buffer[] = []\n channel.stdout.on('data', (chunk: Buffer) => stdout.push(chunk))\n channel.stderr.on('data', (chunk: Buffer) => stderr.push(chunk))\n channel.on('close', (code: number, signal: string) => {\n this.audit?.('exec', argv.join(' '), `code=${code ?? 0}`)\n resolve({\n code: code ?? 0,\n signal,\n stdout: Buffer.concat(stdout).toString('utf8'),\n stderr: Buffer.concat(stderr).toString('utf8'),\n })\n })\n channel.on('error', reject)\n channel.end(input)\n })\n })\n }\n\n async sftp(): Promise<import('ssh2').SFTPWrapper> {\n if (this.sftpCache) return this.sftpCache\n const client = await this.connection.getClient()\n this.sftpCache = new Promise((resolve, reject) => {\n client.sftp((err, sftp) => {\n if (err) reject(err)\n else resolve(sftp)\n })\n })\n return this.sftpCache\n }\n\n async readFile(path: string): Promise<Buffer> {\n const sftp = await this.sftp()\n return new Promise((resolve, reject) => {\n sftp.readFile(path, (err, data) => (err ? reject(err) : resolve(data)))\n })\n }\n\n async writeFile(path: string, content: Buffer | string): Promise<void> {\n const sftp = await this.sftp()\n const tmp = `${path}.dshb-tmp-${process.pid}-${Date.now()}`\n return new Promise((resolve, reject) => {\n sftp.writeFile(tmp, content, (writeErr) => {\n if (writeErr) {\n reject(writeErr)\n return\n }\n sftp.ext_openssh_rename(tmp, path, (renameErr) => {\n if (renameErr) reject(renameErr)\n else {\n this.audit?.('write', path, 'ok')\n resolve()\n }\n })\n })\n })\n }\n\n async listDir(path: string): Promise<Array<{ name: string; isDir: boolean; isFile: boolean; isSymlink: boolean; size: number; mtime: number }>> {\n const sftp = await this.sftp()\n return new Promise((resolve, reject) => {\n sftp.readdir(path, (err, list) => {\n if (err) {\n reject(err)\n return\n }\n resolve(\n list.map((e) => ({\n name: e.filename,\n isDir: e.attrs.isDirectory(),\n isFile: e.attrs.isFile(),\n isSymlink: e.attrs.isSymbolicLink(),\n size: Number(e.attrs.size),\n mtime: e.attrs.mtime * 1000,\n })),\n )\n })\n })\n }\n\n async stat(path: string): Promise<{ size: number; mtime: number; isDirectory: boolean; isFile: boolean } | undefined> {\n const sftp = await this.sftp()\n return new Promise((resolve) => {\n sftp.stat(path, (err, stats) => {\n if (err) {\n resolve(undefined)\n return\n }\n resolve({ size: Number(stats.size), mtime: stats.mtime * 1000, isDirectory: stats.isDirectory(), isFile: stats.isFile() })\n })\n })\n }\n\n async mkdir(path: string): Promise<void> {\n const sftp = await this.sftp()\n return new Promise((resolve, reject) => {\n sftp.mkdir(path, (err) => (err ? reject(err) : resolve()))\n })\n }\n\n async remove(path: string): Promise<void> {\n const sftp = await this.sftp()\n return new Promise((resolve, reject) => {\n sftp.unlink(path, (err) => {\n if (err) reject(err)\n else {\n this.audit?.('remove', path, 'ok')\n resolve()\n }\n })\n })\n }\n\n async rename(src: string, dest: string): Promise<void> {\n const sftp = await this.sftp()\n return new Promise((resolve, reject) => {\n sftp.ext_openssh_rename(src, dest, (err) => {\n if (err) reject(err)\n else {\n this.audit?.('move', `${src} -> ${dest}`, 'ok')\n resolve()\n }\n })\n })\n }\n\n async ensureRg(): Promise<void> {\n const result = await this.exec(['sh', '-c', 'command -v rg || echo \"__DShB_RG_MISSING__\"'], '/')\n if (result.stdout.includes('__DShB_RG_MISSING__')) {\n const localRg = process.env.DSHB_LOCAL_RG ?? findLocalRg()\n if (!localRg) return\n const remoteRgDir = '~/.dshb/bin'\n await this.exec(['mkdir', '-p', remoteRgDir], '/')\n const remoteRg = `${remoteRgDir}/rg`\n const content = readFileSync(localRg)\n await this.writeFile(remoteRg, content)\n await this.exec(['chmod', '+x', remoteRg], '/')\n }\n }\n\n async pty(argv: string[], cwd: string, _env: Record<string, string>, cols: number, rows: number): Promise<{ channel: import('ssh2').ClientChannel; onData: (cb: (chunk: Buffer) => void) => void; resize: (cols: number, rows: number) => void; kill: () => void }> {\n const client = await this.connection.getClient()\n const q = (s: string) => `'${s.replace(/'/g, \"'\\\\''\")}'`\n const cmdParts = argv.map(q)\n const command = `bash -c 'cd \"$0\" && exec env -i HOME=\"$HOME\" PATH=\"\\${PATH:-/usr/local/bin:/usr/bin:/bin}\" \"$@\"' ${q(cwd)} ${cmdParts.join(' ')}`\n return new Promise((resolve, reject) => {\n client.exec(\n command,\n { pty: { cols, rows, term: 'xterm-256color' } },\n (err, channel) => {\n if (err) {\n reject(err)\n return\n }\n resolve({\n channel,\n onData: (cb) => channel.on('data', cb),\n resize: (c, r) => channel.setWindow(c, r, 0, 0),\n kill: () => channel.close(),\n })\n },\n )\n })\n }\n}\n\nfunction findLocalRg(): string | undefined {\n const candidates = [\n join(homedir(), '.dsh', 'node_modules', '.bin', 'rg'),\n join(homedir(), '.dsh', 'node_modules', '@vscode', 'ripgrep', 'bin', 'rg'),\n join(homedir(), 'go', 'bin', 'rg'),\n '/usr/local/bin/rg',\n '/usr/bin/rg',\n ]\n for (const c of candidates) if (existsSync(c)) return c\n return undefined\n}\n"],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import { SshExecutor } from "./executor.js";
2
+ //#region src/exec-ssh/fs-provider.d.ts
3
+ declare class SshFileSystem {
4
+ private readonly executor;
5
+ constructor(executor: SshExecutor);
6
+ resolve(path: string): Promise<string>;
7
+ processPath(target: string): string;
8
+ fileUrl(target: string): string;
9
+ contains(parent: string, child: string): boolean;
10
+ stat(target: string, _signal?: AbortSignal): Promise<{
11
+ size: number;
12
+ mtime: number;
13
+ isDirectory: boolean;
14
+ isFile: boolean;
15
+ } | undefined>;
16
+ lstat(path: string, _opts?: {
17
+ cwd?: string;
18
+ }, _signal?: AbortSignal): Promise<{
19
+ size: number;
20
+ mtime: number;
21
+ isDirectory: boolean;
22
+ isFile: boolean;
23
+ } | undefined>;
24
+ readText(target: string, _signal?: AbortSignal): Promise<string>;
25
+ streamText(target: string, _signal?: AbortSignal): Promise<AsyncIterable<string>>;
26
+ readBytes(target: string, _signal: AbortSignal | undefined, maxBytes: number): Promise<Uint8Array>;
27
+ listDir(target: string, _signal?: AbortSignal): Promise<Array<{
28
+ name: string;
29
+ path: string;
30
+ isDirectory: boolean;
31
+ isFile: boolean;
32
+ isSymlink: boolean;
33
+ size: number;
34
+ mtime: number;
35
+ }>>;
36
+ writeText(target: string, content: string, _expected?: unknown, _signal?: AbortSignal, _policy?: unknown): Promise<{
37
+ operation: 'create' | 'update';
38
+ version: string;
39
+ before: string | null;
40
+ after: string;
41
+ }>;
42
+ editText(target: string, edit: unknown, _expected?: unknown, _signal?: AbortSignal, _policy?: unknown): Promise<{
43
+ version: string;
44
+ before: string;
45
+ after: string;
46
+ }>;
47
+ }
48
+ //#endregion
49
+ export { SshFileSystem };
50
+ //# sourceMappingURL=fs-provider.d.ts.map
@@ -0,0 +1,92 @@
1
+ //#region src/exec-ssh/fs-provider.ts
2
+ var SshFileSystem = class {
3
+ executor;
4
+ constructor(executor) {
5
+ this.executor = executor;
6
+ }
7
+ async resolve(path) {
8
+ return path;
9
+ }
10
+ processPath(target) {
11
+ return target;
12
+ }
13
+ fileUrl(target) {
14
+ return `file://${target}`;
15
+ }
16
+ contains(parent, child) {
17
+ return child === parent || child.startsWith(`${parent}/`);
18
+ }
19
+ async stat(target, _signal) {
20
+ return this.executor.stat(target);
21
+ }
22
+ async lstat(path, _opts, _signal) {
23
+ return this.executor.stat(path);
24
+ }
25
+ async readText(target, _signal) {
26
+ return (await this.executor.readFile(target)).toString("utf8");
27
+ }
28
+ async streamText(target, _signal) {
29
+ const text = (await this.executor.readFile(target)).toString("utf8");
30
+ return (async function* () {
31
+ yield text;
32
+ })();
33
+ }
34
+ async readBytes(target, _signal, maxBytes) {
35
+ const slice = (await this.executor.readFile(target)).subarray(0, maxBytes);
36
+ return new Uint8Array(slice.buffer, slice.byteOffset, slice.byteLength);
37
+ }
38
+ async listDir(target, _signal) {
39
+ return (await this.executor.listDir(target)).map((e) => ({
40
+ name: e.name,
41
+ path: `${target}/${e.name}`,
42
+ isDirectory: e.isDir,
43
+ isFile: e.isFile,
44
+ isSymlink: e.isSymlink,
45
+ size: e.size,
46
+ mtime: e.mtime
47
+ }));
48
+ }
49
+ async writeText(target, content, _expected, _signal, _policy) {
50
+ const normalizeLf = (s) => s.replace(/\r\n/g, "\n");
51
+ const beforeInfo = await this.executor.stat(target);
52
+ let before = null;
53
+ if (beforeInfo?.isFile) try {
54
+ before = normalizeLf((await this.executor.readFile(target)).toString("utf8"));
55
+ } catch {
56
+ before = null;
57
+ }
58
+ const after = normalizeLf(content);
59
+ await this.executor.writeFile(target, content);
60
+ const afterInfo = await this.executor.stat(target);
61
+ const version = `${afterInfo?.size ?? content.length}:${afterInfo?.mtime ?? Date.now()}`;
62
+ return {
63
+ operation: before === null ? "create" : "update",
64
+ version,
65
+ before,
66
+ after
67
+ };
68
+ }
69
+ async editText(target, edit, _expected, _signal, _policy) {
70
+ const normalizeLf = (s) => s.replace(/\r\n/g, "\n");
71
+ const before = normalizeLf((await this.executor.readFile(target)).toString("utf8"));
72
+ const req = edit;
73
+ const oldString = normalizeLf(String(req.oldString ?? ""));
74
+ if (oldString.length === 0) throw new Error("edit oldString must be non-empty");
75
+ const newString = normalizeLf(String(req.newString ?? ""));
76
+ const matches = before.split(oldString).length - 1;
77
+ if (matches === 0) throw new Error("edit oldString not found in file");
78
+ if (!req.replaceAll && matches !== 1) throw new Error(`edit oldString matched ${matches} times; expected exactly one`);
79
+ const after = req.replaceAll ? before.split(oldString).join(newString) : before.replace(oldString, newString);
80
+ await this.executor.writeFile(target, after);
81
+ const afterInfo = await this.executor.stat(target);
82
+ return {
83
+ version: `${afterInfo?.size ?? after.length}:${afterInfo?.mtime ?? Date.now()}`,
84
+ before,
85
+ after
86
+ };
87
+ }
88
+ };
89
+ //#endregion
90
+ export { SshFileSystem };
91
+
92
+ //# sourceMappingURL=fs-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs-provider.js","names":[],"sources":["../../src/exec-ssh/fs-provider.ts"],"sourcesContent":["import type { SshExecutor } from './executor.js'\n\nexport class SshFileSystem {\n constructor(private readonly executor: SshExecutor) {}\n\n async resolve(path: string): Promise<string> {\n return path\n }\n\n processPath(target: string): string {\n return target\n }\n\n fileUrl(target: string): string {\n return `file://${target}`\n }\n\n contains(parent: string, child: string): boolean {\n return child === parent || child.startsWith(`${parent}/`)\n }\n\n async stat(target: string, _signal?: AbortSignal): Promise<{ size: number; mtime: number; isDirectory: boolean; isFile: boolean } | undefined> {\n return this.executor.stat(target)\n }\n\n async lstat(path: string, _opts?: { cwd?: string }, _signal?: AbortSignal): Promise<{ size: number; mtime: number; isDirectory: boolean; isFile: boolean } | undefined> {\n return this.executor.stat(path)\n }\n\n async readText(target: string, _signal?: AbortSignal): Promise<string> {\n const data = await this.executor.readFile(target)\n return data.toString('utf8')\n }\n\n async streamText(target: string, _signal?: AbortSignal): Promise<AsyncIterable<string>> {\n const data = await this.executor.readFile(target)\n const text = data.toString('utf8')\n return (async function* () {\n yield text\n })()\n }\n\n async readBytes(target: string, _signal: AbortSignal | undefined, maxBytes: number): Promise<Uint8Array> {\n const data = await this.executor.readFile(target)\n const slice = data.subarray(0, maxBytes)\n return new Uint8Array(slice.buffer, slice.byteOffset, slice.byteLength)\n }\n\n async listDir(target: string, _signal?: AbortSignal): Promise<Array<{ name: string; path: string; isDirectory: boolean; isFile: boolean; isSymlink: boolean; size: number; mtime: number }>> {\n const entries = await this.executor.listDir(target)\n return entries.map((e) => ({\n name: e.name,\n path: `${target}/${e.name}`,\n isDirectory: e.isDir,\n isFile: e.isFile,\n isSymlink: e.isSymlink,\n size: e.size,\n mtime: e.mtime,\n }))\n }\n\n async writeText(target: string, content: string, _expected?: unknown, _signal?: AbortSignal, _policy?: unknown): Promise<{ operation: 'create' | 'update'; version: string; before: string | null; after: string }> {\n const normalizeLf = (s: string) => s.replace(/\\r\\n/g, '\\n')\n const beforeInfo = await this.executor.stat(target)\n let before: string | null = null\n if (beforeInfo?.isFile) {\n try {\n before = normalizeLf((await this.executor.readFile(target)).toString('utf8'))\n } catch {\n before = null\n }\n }\n const after = normalizeLf(content)\n await this.executor.writeFile(target, content)\n const afterInfo = await this.executor.stat(target)\n const version = `${afterInfo?.size ?? content.length}:${afterInfo?.mtime ?? Date.now()}`\n return { operation: before === null ? 'create' : 'update', version, before, after }\n }\n\n async editText(target: string, edit: unknown, _expected?: unknown, _signal?: AbortSignal, _policy?: unknown): Promise<{ version: string; before: string; after: string }> {\n const normalizeLf = (s: string) => s.replace(/\\r\\n/g, '\\n')\n const before = normalizeLf((await this.executor.readFile(target)).toString('utf8'))\n const req = edit as { oldString: string; newString: string; replaceAll: boolean }\n const oldString = normalizeLf(String(req.oldString ?? ''))\n if (oldString.length === 0) throw new Error('edit oldString must be non-empty')\n const newString = normalizeLf(String(req.newString ?? ''))\n const matches = before.split(oldString).length - 1\n if (matches === 0) throw new Error('edit oldString not found in file')\n if (!req.replaceAll && matches !== 1) throw new Error(`edit oldString matched ${matches} times; expected exactly one`)\n const after = req.replaceAll ? before.split(oldString).join(newString) : before.replace(oldString, newString)\n await this.executor.writeFile(target, after)\n const afterInfo = await this.executor.stat(target)\n const version = `${afterInfo?.size ?? after.length}:${afterInfo?.mtime ?? Date.now()}`\n return { version, before, after }\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import { c as classifySshError, i as SshErrorCategory, l as toConnectionError, o as SshSecrets, r as SshConnectionError, s as SshTarget } from "../connection-sIX25pkS.js";
2
+ import { SshConnectionPool } from "./connection-pool.js";
3
+ import { scrubEnv, shouldScrubVar } from "./env-scrub.js";
4
+ import { SshExecutor } from "./executor.js";
5
+ import { SshFileSystem } from "./fs-provider.js";
6
+ import { SshShellExecutor, SshSubprocessRuntime } from "./process-provider.js";
7
+ import { SshExecutionWorld, SshNodeConfig, SshWorldRegistry } from "./world.js";
8
+ import { REMOTE_RUNNER_COMMAND, REMOTE_RUNNER_SCRIPT, encodeRunnerPayload } from "./runner.js";
9
+ import { Context } from "@deepseek-ai/cordis";
10
+ //#region src/exec-ssh/index.d.ts
11
+ declare const name = "dshb-exec-ssh";
12
+ declare const inject: string[];
13
+ declare function apply(ctx: Context): void;
14
+ //#endregion
15
+ export { REMOTE_RUNNER_COMMAND, REMOTE_RUNNER_SCRIPT, type SshConnectionError, SshConnectionPool, type SshErrorCategory, SshExecutionWorld, SshExecutor, SshFileSystem, type SshNodeConfig, type SshSecrets, SshShellExecutor, SshSubprocessRuntime, type SshTarget, SshWorldRegistry, apply, classifySshError, encodeRunnerPayload, inject, name, scrubEnv, shouldScrubVar, toConnectionError };
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,30 @@
1
+ import { sharedWorldResolver } from "../router/resolve.js";
2
+ import { classifySshError, toConnectionError } from "./connection.js";
3
+ import { SshConnectionPool } from "./connection-pool.js";
4
+ import { REMOTE_RUNNER_COMMAND, REMOTE_RUNNER_SCRIPT, encodeRunnerPayload } from "./runner.js";
5
+ import { SshExecutor } from "./executor.js";
6
+ import { SshFileSystem } from "./fs-provider.js";
7
+ import { SshShellExecutor, SshSubprocessRuntime } from "./process-provider.js";
8
+ import { SshExecutionWorld, SshWorldRegistry } from "./world.js";
9
+ import { scrubEnv, shouldScrubVar } from "./env-scrub.js";
10
+ //#region src/exec-ssh/index.ts
11
+ const name = "dshb-exec-ssh";
12
+ const inject = ["nodeRegistry"];
13
+ function apply(ctx) {
14
+ const pool = new SshConnectionPool(ctx);
15
+ const nodeRegistry = ctx.get("nodeRegistry");
16
+ const audit = ctx.get("dshbAudit");
17
+ const worlds = new SshWorldRegistry(pool, nodeRegistry, audit ? (id, op, t, r) => audit.log(id, op, t, r) : void 0);
18
+ ctx.provide("dshbSshPool", pool);
19
+ ctx.provide("dshbSshWorlds", worlds);
20
+ ctx.provide("dshbWorlds", { ensure: (nodeId) => worlds.ensure(nodeId) });
21
+ sharedWorldResolver().setRegistry({ get: (nodeId) => {
22
+ const node = nodeRegistry?.get(nodeId);
23
+ if (node && (node.type === "remote-docker" || node.type === "local-docker")) return void 0;
24
+ return worlds.get(nodeId);
25
+ } });
26
+ }
27
+ //#endregion
28
+ export { REMOTE_RUNNER_COMMAND, REMOTE_RUNNER_SCRIPT, SshConnectionPool, SshExecutionWorld, SshExecutor, SshFileSystem, SshShellExecutor, SshSubprocessRuntime, SshWorldRegistry, apply, classifySshError, encodeRunnerPayload, inject, name, scrubEnv, shouldScrubVar, toConnectionError };
29
+
30
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/exec-ssh/index.ts"],"sourcesContent":["import type { Context } from '@deepseek-ai/cordis'\nimport { sharedWorldResolver } from '../router/resolve.js'\nimport { SshConnectionPool } from './connection-pool.js'\nimport { SshWorldRegistry } from './world.js'\n\nexport const name = 'dshb-exec-ssh'\n\nexport const inject = ['nodeRegistry']\n\nexport function apply(ctx: Context): void {\n const pool = new SshConnectionPool(ctx)\n const nodeRegistry = ctx.get('nodeRegistry') as ConstructorParameters<typeof SshWorldRegistry>[1]\n const audit = ctx.get('dshbAudit') as { log(nodeId: string, op: string, target: string, result: string): void } | undefined\n const worlds = new SshWorldRegistry(pool, nodeRegistry, audit ? (id, op, t, r) => audit.log(id, op, t, r) : undefined)\n ctx.provide('dshbSshPool', pool)\n ctx.provide('dshbSshWorlds', worlds)\n ctx.provide('dshbWorlds', {\n ensure: (nodeId: string) => worlds.ensure(nodeId),\n })\n sharedWorldResolver().setRegistry({\n get: (nodeId: string) => {\n const node = nodeRegistry?.get(nodeId)\n if (node && (node.type === 'remote-docker' || node.type === 'local-docker')) return undefined\n return worlds.get(nodeId)\n },\n })\n}\n\nexport { SshConnectionPool } from './connection-pool.js'\nexport { classifySshError, toConnectionError } from './connection.js'\nexport type { SshConnectionError, SshErrorCategory, SshTarget, SshSecrets } from './connection.js'\nexport { shouldScrubVar, scrubEnv } from './env-scrub.js'\nexport { SshExecutor } from './executor.js'\nexport { SshFileSystem } from './fs-provider.js'\nexport { SshShellExecutor, SshSubprocessRuntime } from './process-provider.js'\nexport { SshExecutionWorld, SshWorldRegistry } from './world.js'\nexport type { SshNodeConfig } from './world.js'\nexport { encodeRunnerPayload, REMOTE_RUNNER_COMMAND, REMOTE_RUNNER_SCRIPT } from './runner.js'\n"],"mappings":";;;;;;;;;;AAKA,MAAa,OAAO;AAEpB,MAAa,SAAS,CAAC,cAAc;AAErC,SAAgB,MAAM,KAAoB;CACxC,MAAM,OAAO,IAAI,kBAAkB,GAAG;CACtC,MAAM,eAAe,IAAI,IAAI,cAAc;CAC3C,MAAM,QAAQ,IAAI,IAAI,WAAW;CACjC,MAAM,SAAS,IAAI,iBAAiB,MAAM,cAAc,SAAS,IAAI,IAAI,GAAG,MAAM,MAAM,IAAI,IAAI,IAAI,GAAG,CAAC,IAAI,KAAA,CAAS;CACrH,IAAI,QAAQ,eAAe,IAAI;CAC/B,IAAI,QAAQ,iBAAiB,MAAM;CACnC,IAAI,QAAQ,cAAc,EACxB,SAAS,WAAmB,OAAO,OAAO,MAAM,EAClD,CAAC;CACD,oBAAoB,CAAC,CAAC,YAAY,EAChC,MAAM,WAAmB;EACvB,MAAM,OAAO,cAAc,IAAI,MAAM;EACrC,IAAI,SAAS,KAAK,SAAS,mBAAmB,KAAK,SAAS,iBAAiB,OAAO,KAAA;EACpF,OAAO,OAAO,IAAI,MAAM;CAC1B,EACF,CAAC;AACH"}
@@ -0,0 +1,20 @@
1
+ import { SshExecutor } from "./executor.js";
2
+ import { SubprocessHandle, SubprocessSpawnSpec, SubprocessTerminalHandle, SubprocessTerminalSpawnSpec } from "@deepseek-ai/dsh-subprocess";
3
+ import { ShellExecRequest, ShellExecSpec, ShellProcess, ShellRunResult } from "@deepseek-ai/dsh-shell";
4
+ //#region src/exec-ssh/process-provider.d.ts
5
+ declare class SshShellExecutor {
6
+ private readonly executor;
7
+ constructor(executor: SshExecutor);
8
+ resolve(request: ShellExecRequest): ShellExecSpec;
9
+ run(spec: ShellExecSpec): Promise<ShellRunResult>;
10
+ start(spec: ShellExecSpec): ShellProcess;
11
+ }
12
+ declare class SshSubprocessRuntime {
13
+ private readonly executor;
14
+ constructor(executor: SshExecutor);
15
+ spawn(spec: SubprocessSpawnSpec): SubprocessHandle;
16
+ spawnTerminal(spec: SubprocessTerminalSpawnSpec): Promise<SubprocessTerminalHandle>;
17
+ }
18
+ //#endregion
19
+ export { SshShellExecutor, SshSubprocessRuntime };
20
+ //# sourceMappingURL=process-provider.d.ts.map
@@ -0,0 +1,75 @@
1
+ //#region src/exec-ssh/process-provider.ts
2
+ var SshShellExecutor = class {
3
+ executor;
4
+ constructor(executor) {
5
+ this.executor = executor;
6
+ }
7
+ resolve(request) {
8
+ return {
9
+ command: request.command,
10
+ workdir: request.workdir ?? "/",
11
+ timeoutMs: request.timeoutMs ?? 6e4,
12
+ stdoutMaxBytes: request.stdoutMaxBytes ?? 1048576,
13
+ signal: request.signal,
14
+ stdin: request.stdin,
15
+ env: request.env,
16
+ sandboxPolicy: request.sandboxPolicy
17
+ };
18
+ }
19
+ async run(spec) {
20
+ const result = await this.executor.exec([
21
+ "sh",
22
+ "-c",
23
+ spec.command
24
+ ], spec.workdir, spec.env ?? {}, spec.stdin !== void 0 ? Buffer.from(spec.stdin) : void 0);
25
+ const collect = (text) => ({
26
+ text,
27
+ truncated: false
28
+ });
29
+ return {
30
+ exitCode: result.code,
31
+ signal: result.signal ?? null,
32
+ timedOut: false,
33
+ aborted: false,
34
+ timeoutMs: spec.timeoutMs,
35
+ stdout: collect(result.stdout),
36
+ stderr: collect(result.stderr)
37
+ };
38
+ }
39
+ start(spec) {
40
+ return {
41
+ pid: -1,
42
+ done: this.run(spec),
43
+ kill: () => {}
44
+ };
45
+ }
46
+ };
47
+ var SshSubprocessRuntime = class {
48
+ executor;
49
+ constructor(executor) {
50
+ this.executor = executor;
51
+ }
52
+ spawn(spec) {
53
+ return {
54
+ pid: -1,
55
+ done: this.executor.exec(spec.argv, spec.cwd, spec.env ?? {}).then((r) => ({
56
+ exitCode: r.code,
57
+ signal: r.signal ?? null
58
+ })),
59
+ kill: () => {}
60
+ };
61
+ }
62
+ async spawnTerminal(spec) {
63
+ const pty = await this.executor.pty(spec.argv, spec.cwd, spec.env ?? {}, spec.cols ?? 80, spec.rows ?? 24);
64
+ return {
65
+ write: (data) => pty.channel.stdin.write(data),
66
+ resize: (cols, rows) => pty.resize(cols, rows),
67
+ onData: (cb) => pty.onData((chunk) => cb(chunk.toString("utf8"))),
68
+ kill: () => pty.kill()
69
+ };
70
+ }
71
+ };
72
+ //#endregion
73
+ export { SshShellExecutor, SshSubprocessRuntime };
74
+
75
+ //# sourceMappingURL=process-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-provider.js","names":[],"sources":["../../src/exec-ssh/process-provider.ts"],"sourcesContent":["import type { ShellExecRequest, ShellExecSpec, ShellProcess, ShellRunResult } from '@deepseek-ai/dsh-shell'\nimport type { CollectedOutput, SubprocessHandle, SubprocessSpawnSpec, SubprocessTerminalHandle, SubprocessTerminalSpawnSpec } from '@deepseek-ai/dsh-subprocess'\nimport type { SshExecutor } from './executor.js'\n\nexport class SshShellExecutor {\n constructor(private readonly executor: SshExecutor) {}\n\n resolve(request: ShellExecRequest): ShellExecSpec {\n return {\n command: request.command,\n workdir: request.workdir ?? '/',\n timeoutMs: request.timeoutMs ?? 60_000,\n stdoutMaxBytes: request.stdoutMaxBytes ?? 1024 * 1024,\n signal: request.signal,\n stdin: request.stdin,\n env: request.env,\n sandboxPolicy: request.sandboxPolicy,\n } as ShellExecSpec\n }\n\n async run(spec: ShellExecSpec): Promise<ShellRunResult> {\n const result = await this.executor.exec(['sh', '-c', spec.command], spec.workdir, (spec.env ?? {}) as Record<string, string>, spec.stdin !== undefined ? Buffer.from(spec.stdin) : undefined)\n const collect = (text: string): CollectedOutput => ({ text, truncated: false })\n return {\n exitCode: result.code,\n signal: (result.signal ?? null) as NodeJS.Signals | null,\n timedOut: false,\n aborted: false,\n timeoutMs: spec.timeoutMs,\n stdout: collect(result.stdout),\n stderr: collect(result.stderr),\n } as unknown as ShellRunResult\n }\n\n start(spec: ShellExecSpec): ShellProcess {\n const promise = this.run(spec)\n const proc: ShellProcess = {\n pid: -1,\n done: promise,\n kill: () => {\n void promise\n },\n } as unknown as ShellProcess\n return proc\n }\n}\n\nexport class SshSubprocessRuntime {\n constructor(private readonly executor: SshExecutor) {}\n\n spawn(spec: SubprocessSpawnSpec): SubprocessHandle {\n const promise = this.executor.exec(spec.argv as string[], spec.cwd, (spec.env ?? {}) as Record<string, string>)\n const handle: SubprocessHandle = {\n pid: -1,\n done: promise.then((r) => ({ exitCode: r.code, signal: (r.signal ?? null) as NodeJS.Signals | null })),\n kill: () => {\n void promise\n },\n } as unknown as SubprocessHandle\n return handle\n }\n\n async spawnTerminal(spec: SubprocessTerminalSpawnSpec): Promise<SubprocessTerminalHandle> {\n const pty = await this.executor.pty(spec.argv as string[], spec.cwd, (spec.env ?? {}) as Record<string, string>, (spec as { cols?: number }).cols ?? 80, (spec as { rows?: number }).rows ?? 24)\n const handle: SubprocessTerminalHandle = {\n write: (data: string) => pty.channel.stdin.write(data),\n resize: (cols: number, rows: number) => pty.resize(cols, rows),\n onData: (cb: (data: string) => void) => pty.onData((chunk) => cb(chunk.toString('utf8'))),\n kill: () => pty.kill(),\n } as unknown as SubprocessTerminalHandle\n return handle\n }\n}\n"],"mappings":";AAIA,IAAa,mBAAb,MAA8B;CACC;CAA7B,YAAY,UAAwC;EAAvB,KAAA,WAAA;CAAwB;CAErD,QAAQ,SAA0C;EAChD,OAAO;GACL,SAAS,QAAQ;GACjB,SAAS,QAAQ,WAAW;GAC5B,WAAW,QAAQ,aAAa;GAChC,gBAAgB,QAAQ,kBAAkB;GAC1C,QAAQ,QAAQ;GAChB,OAAO,QAAQ;GACf,KAAK,QAAQ;GACb,eAAe,QAAQ;EACzB;CACF;CAEA,MAAM,IAAI,MAA8C;EACtD,MAAM,SAAS,MAAM,KAAK,SAAS,KAAK;GAAC;GAAM;GAAM,KAAK;EAAO,GAAG,KAAK,SAAU,KAAK,OAAO,CAAC,GAA8B,KAAK,UAAU,KAAA,IAAY,OAAO,KAAK,KAAK,KAAK,IAAI,KAAA,CAAS;EAC5L,MAAM,WAAW,UAAmC;GAAE;GAAM,WAAW;EAAM;EAC7E,OAAO;GACL,UAAU,OAAO;GACjB,QAAS,OAAO,UAAU;GAC1B,UAAU;GACV,SAAS;GACT,WAAW,KAAK;GAChB,QAAQ,QAAQ,OAAO,MAAM;GAC7B,QAAQ,QAAQ,OAAO,MAAM;EAC/B;CACF;CAEA,MAAM,MAAmC;EASvC,OAAO;GANL,KAAK;GACL,MAHc,KAAK,IAAI,IAGX;GACZ,YAAY,CAEZ;EAEQ;CACZ;AACF;AAEA,IAAa,uBAAb,MAAkC;CACH;CAA7B,YAAY,UAAwC;EAAvB,KAAA,WAAA;CAAwB;CAErD,MAAM,MAA6C;EASjD,OAAO;GANL,KAAK;GACL,MAHc,KAAK,SAAS,KAAK,KAAK,MAAkB,KAAK,KAAM,KAAK,OAAO,CAAC,CAGpE,CAAC,CAAC,MAAM,OAAO;IAAE,UAAU,EAAE;IAAM,QAAS,EAAE,UAAU;GAA+B,EAAE;GACrG,YAAY,CAEZ;EAEU;CACd;CAEA,MAAM,cAAc,MAAsE;EACxF,MAAM,MAAM,MAAM,KAAK,SAAS,IAAI,KAAK,MAAkB,KAAK,KAAM,KAAK,OAAO,CAAC,GAA+B,KAA2B,QAAQ,IAAK,KAA2B,QAAQ,EAAE;EAO/L,OAAO;GALL,QAAQ,SAAiB,IAAI,QAAQ,MAAM,MAAM,IAAI;GACrD,SAAS,MAAc,SAAiB,IAAI,OAAO,MAAM,IAAI;GAC7D,SAAS,OAA+B,IAAI,QAAQ,UAAU,GAAG,MAAM,SAAS,MAAM,CAAC,CAAC;GACxF,YAAY,IAAI,KAAK;EAEX;CACd;AACF"}
@@ -0,0 +1,13 @@
1
+ //#region src/exec-ssh/runner.d.ts
2
+ interface RunnerPayload {
3
+ argv: string[];
4
+ cwd: string;
5
+ env: Record<string, string>;
6
+ }
7
+ declare function encodeRunnerPayload(payload: RunnerPayload): Buffer;
8
+ declare const REMOTE_RUNNER_SCRIPT = "set -u\nif ! command -v base64 >/dev/null 2>&1; then echo \"runner: base64 not found\" >&2; exit 127; fi\ndec() {\n printf '%s' \"$1\" | base64 -d 2>/dev/null || printf '%s' \"$1\" | base64 -D 2>/dev/null\n}\nreadline_crlf() {\n IFS= read -r line\n line=${line%$'\\r'}\n}\nreadline_crlf\ncwd=$(dec \"$line\")\nreadline_crlf\nargc=$(dec \"$line\")\nargv=()\ni=0\nwhile [ \"$i\" -lt \"$argc\" ]; do\n readline_crlf\n argv+=(\"$(dec \"$line\")\")\n i=$((i + 1))\ndone\nreadline_crlf\nenvc=$(dec \"$line\")\nenv_vars=()\ni=0\nwhile [ \"$i\" -lt \"$envc\" ]; do\n readline_crlf\n kv=$(dec \"$line\")\n k=${kv%%=*}\n v=${kv#*=}\n env_vars+=(\"$k=$v\")\n i=$((i + 1))\ndone\nreadline_crlf\n[ \"$line\" = \".\" ] || { echo \"runner: protocol error\" >&2; exit 126; }\ncd \"$cwd\" 2>/dev/null || { echo \"runner: cwd not found: $cwd\" >&2; exit 126; }\nexec env -i HOME=\"$HOME\" PATH=\"${PATH:-/usr/local/bin:/usr/bin:/bin}\" ${env_vars[@]+\"${env_vars[@]}\"} \"${argv[@]}\"\n";
9
+ declare const REMOTE_RUNNER_COMMAND: string;
10
+ declare function isRunnerSafe(command: string): boolean;
11
+ //#endregion
12
+ export { REMOTE_RUNNER_COMMAND, REMOTE_RUNNER_SCRIPT, RunnerPayload, encodeRunnerPayload, isRunnerSafe };
13
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1,62 @@
1
+ //#region src/exec-ssh/runner.ts
2
+ function encodeLine(value) {
3
+ return Buffer.from(`${value}\n`, "utf8").toString("base64");
4
+ }
5
+ function encodeRunnerPayload(payload) {
6
+ const lines = [];
7
+ lines.push(encodeLine(payload.cwd));
8
+ lines.push(encodeLine(String(payload.argv.length)));
9
+ for (const arg of payload.argv) lines.push(encodeLine(arg));
10
+ const envEntries = Object.entries(payload.env);
11
+ lines.push(encodeLine(String(envEntries.length)));
12
+ for (const [k, v] of envEntries) lines.push(encodeLine(`${k}=${v}`));
13
+ lines.push(".");
14
+ return Buffer.from(`${lines.join("\n")}\n`, "utf8");
15
+ }
16
+ const RUNNER_SCRIPT = `set -u
17
+ if ! command -v base64 >/dev/null 2>&1; then echo "runner: base64 not found" >&2; exit 127; fi
18
+ dec() {
19
+ printf '%s' "$1" | base64 -d 2>/dev/null || printf '%s' "$1" | base64 -D 2>/dev/null
20
+ }
21
+ readline_crlf() {
22
+ IFS= read -r line
23
+ line=\${line%$'\\r'}
24
+ }
25
+ readline_crlf
26
+ cwd=$(dec "$line")
27
+ readline_crlf
28
+ argc=$(dec "$line")
29
+ argv=()
30
+ i=0
31
+ while [ "$i" -lt "$argc" ]; do
32
+ readline_crlf
33
+ argv+=("$(dec "$line")")
34
+ i=$((i + 1))
35
+ done
36
+ readline_crlf
37
+ envc=$(dec "$line")
38
+ env_vars=()
39
+ i=0
40
+ while [ "$i" -lt "$envc" ]; do
41
+ readline_crlf
42
+ kv=$(dec "$line")
43
+ k=\${kv%%=*}
44
+ v=\${kv#*=}
45
+ env_vars+=("$k=$v")
46
+ i=$((i + 1))
47
+ done
48
+ readline_crlf
49
+ [ "$line" = "." ] || { echo "runner: protocol error" >&2; exit 126; }
50
+ cd "$cwd" 2>/dev/null || { echo "runner: cwd not found: $cwd" >&2; exit 126; }
51
+ exec env -i HOME="$HOME" PATH="\${PATH:-/usr/local/bin:/usr/bin:/bin}" \${env_vars[@]+"\${env_vars[@]}"} "\${argv[@]}"
52
+ `;
53
+ const RUNNER_SCRIPT_B64 = Buffer.from(RUNNER_SCRIPT, "utf8").toString("base64");
54
+ const REMOTE_RUNNER_SCRIPT = RUNNER_SCRIPT;
55
+ const REMOTE_RUNNER_COMMAND = `bash -c "$(echo ${RUNNER_SCRIPT_B64} | base64 -d)"`;
56
+ function isRunnerSafe(command) {
57
+ return command === REMOTE_RUNNER_COMMAND || command.includes(RUNNER_SCRIPT_B64);
58
+ }
59
+ //#endregion
60
+ export { REMOTE_RUNNER_COMMAND, REMOTE_RUNNER_SCRIPT, encodeRunnerPayload, isRunnerSafe };
61
+
62
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","names":[],"sources":["../../src/exec-ssh/runner.ts"],"sourcesContent":["export interface RunnerPayload {\n argv: string[]\n cwd: string\n env: Record<string, string>\n}\n\nfunction encodeLine(value: string): string {\n return Buffer.from(`${value}\\n`, 'utf8').toString('base64')\n}\n\nexport function encodeRunnerPayload(payload: RunnerPayload): Buffer {\n const lines: string[] = []\n lines.push(encodeLine(payload.cwd))\n lines.push(encodeLine(String(payload.argv.length)))\n for (const arg of payload.argv) lines.push(encodeLine(arg))\n const envEntries = Object.entries(payload.env)\n lines.push(encodeLine(String(envEntries.length)))\n for (const [k, v] of envEntries) lines.push(encodeLine(`${k}=${v}`))\n lines.push('.')\n return Buffer.from(`${lines.join('\\n')}\\n`, 'utf8')\n}\n\nconst RUNNER_SCRIPT = `set -u\nif ! command -v base64 >/dev/null 2>&1; then echo \"runner: base64 not found\" >&2; exit 127; fi\ndec() {\n printf '%s' \"$1\" | base64 -d 2>/dev/null || printf '%s' \"$1\" | base64 -D 2>/dev/null\n}\nreadline_crlf() {\n IFS= read -r line\n line=\\${line%$'\\\\r'}\n}\nreadline_crlf\ncwd=$(dec \"$line\")\nreadline_crlf\nargc=$(dec \"$line\")\nargv=()\ni=0\nwhile [ \"$i\" -lt \"$argc\" ]; do\n readline_crlf\n argv+=(\"$(dec \"$line\")\")\n i=$((i + 1))\ndone\nreadline_crlf\nenvc=$(dec \"$line\")\nenv_vars=()\ni=0\nwhile [ \"$i\" -lt \"$envc\" ]; do\n readline_crlf\n kv=$(dec \"$line\")\n k=\\${kv%%=*}\n v=\\${kv#*=}\n env_vars+=(\"$k=$v\")\n i=$((i + 1))\ndone\nreadline_crlf\n[ \"$line\" = \".\" ] || { echo \"runner: protocol error\" >&2; exit 126; }\ncd \"$cwd\" 2>/dev/null || { echo \"runner: cwd not found: $cwd\" >&2; exit 126; }\nexec env -i HOME=\"$HOME\" PATH=\"\\${PATH:-/usr/local/bin:/usr/bin:/bin}\" \\${env_vars[@]+\"\\${env_vars[@]}\"} \"\\${argv[@]}\"\n`\n\nconst RUNNER_SCRIPT_B64 = Buffer.from(RUNNER_SCRIPT, 'utf8').toString('base64')\n\nexport const REMOTE_RUNNER_SCRIPT = RUNNER_SCRIPT\n\nexport const REMOTE_RUNNER_COMMAND = `bash -c \"$(echo ${RUNNER_SCRIPT_B64} | base64 -d)\"`\n\nexport function isRunnerSafe(command: string): boolean {\n return command === REMOTE_RUNNER_COMMAND || command.includes(RUNNER_SCRIPT_B64)\n}\n"],"mappings":";AAMA,SAAS,WAAW,OAAuB;CACzC,OAAO,OAAO,KAAK,GAAG,MAAM,KAAK,MAAM,CAAC,CAAC,SAAS,QAAQ;AAC5D;AAEA,SAAgB,oBAAoB,SAAgC;CAClE,MAAM,QAAkB,CAAC;CACzB,MAAM,KAAK,WAAW,QAAQ,GAAG,CAAC;CAClC,MAAM,KAAK,WAAW,OAAO,QAAQ,KAAK,MAAM,CAAC,CAAC;CAClD,KAAK,MAAM,OAAO,QAAQ,MAAM,MAAM,KAAK,WAAW,GAAG,CAAC;CAC1D,MAAM,aAAa,OAAO,QAAQ,QAAQ,GAAG;CAC7C,MAAM,KAAK,WAAW,OAAO,WAAW,MAAM,CAAC,CAAC;CAChD,KAAK,MAAM,CAAC,GAAG,MAAM,YAAY,MAAM,KAAK,WAAW,GAAG,EAAE,GAAG,GAAG,CAAC;CACnE,MAAM,KAAK,GAAG;CACd,OAAO,OAAO,KAAK,GAAG,MAAM,KAAK,IAAI,EAAE,KAAK,MAAM;AACpD;AAEA,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCtB,MAAM,oBAAoB,OAAO,KAAK,eAAe,MAAM,CAAC,CAAC,SAAS,QAAQ;AAE9E,MAAa,uBAAuB;AAEpC,MAAa,wBAAwB,mBAAmB,kBAAkB;AAE1E,SAAgB,aAAa,SAA0B;CACrD,OAAO,YAAY,yBAAyB,QAAQ,SAAS,iBAAiB;AAChF"}