@artenx/dshb 0.0.5 → 0.1.1

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 (167) hide show
  1. package/README.md +18 -0
  2. package/cordis.patch.yml +9 -9
  3. package/lib/auth/credentials.d.ts +30 -0
  4. package/lib/auth/credentials.js +121 -0
  5. package/lib/auth/credentials.js.map +1 -0
  6. package/lib/auth/decorate-webserver.d.ts +7 -0
  7. package/lib/auth/decorate-webserver.js +75 -0
  8. package/lib/auth/decorate-webserver.js.map +1 -0
  9. package/lib/auth/gate.d.ts +14 -0
  10. package/lib/auth/gate.js +45 -0
  11. package/lib/auth/gate.js.map +1 -0
  12. package/lib/auth/index.d.ts +8 -0
  13. package/lib/auth/index.js +51 -0
  14. package/lib/auth/index.js.map +1 -0
  15. package/lib/auth/login-page.d.ts +5 -0
  16. package/lib/auth/login-page.js +87 -0
  17. package/lib/auth/login-page.js.map +1 -0
  18. package/lib/auth/loopback-compat.d.ts +6 -0
  19. package/lib/auth/loopback-compat.js +94 -0
  20. package/lib/auth/loopback-compat.js.map +1 -0
  21. package/lib/auth/loopback.d.ts +7 -0
  22. package/lib/auth/loopback.js +24 -0
  23. package/lib/auth/loopback.js.map +1 -0
  24. package/lib/auth/ratelimit.d.ts +11 -0
  25. package/lib/auth/ratelimit.js +37 -0
  26. package/lib/auth/ratelimit.js.map +1 -0
  27. package/lib/auth/routes.d.ts +8 -0
  28. package/lib/auth/routes.js +224 -0
  29. package/lib/auth/routes.js.map +1 -0
  30. package/lib/auth/session.d.ts +11 -0
  31. package/lib/auth/session.js +52 -0
  32. package/lib/auth/session.js.map +1 -0
  33. package/lib/auth/startup.d.ts +15 -0
  34. package/lib/auth/startup.js +68 -0
  35. package/lib/auth/startup.js.map +1 -0
  36. package/lib/auth/webserver.d.ts +18 -0
  37. package/lib/auth/webserver.js +60 -0
  38. package/lib/auth/webserver.js.map +1 -0
  39. package/lib/client.js +2770 -0
  40. package/lib/client.js.map +1 -0
  41. package/lib/connection-sIX25pkS.d.ts +46 -0
  42. package/lib/core/audit.d.ts +16 -0
  43. package/lib/core/audit.js +38 -0
  44. package/lib/core/audit.js.map +1 -0
  45. package/lib/core/index.d.ts +8 -0
  46. package/lib/core/index.js +77 -0
  47. package/lib/core/index.js.map +1 -0
  48. package/lib/core/known-hosts.d.ts +23 -0
  49. package/lib/core/known-hosts.js +76 -0
  50. package/lib/core/known-hosts.js.map +1 -0
  51. package/lib/core/node-registry.d.ts +108 -0
  52. package/lib/core/node-registry.js +191 -0
  53. package/lib/core/node-registry.js.map +1 -0
  54. package/lib/core/routes.d.ts +9 -0
  55. package/lib/core/routes.js +404 -0
  56. package/lib/core/routes.js.map +1 -0
  57. package/lib/core/ssh-config.d.ts +23 -0
  58. package/lib/core/ssh-config.js +70 -0
  59. package/lib/core/ssh-config.js.map +1 -0
  60. package/lib/core/test.d.ts +43 -0
  61. package/lib/core/test.js +116 -0
  62. package/lib/core/test.js.map +1 -0
  63. package/lib/core/workspace-bindings.d.ts +28 -0
  64. package/lib/core/workspace-bindings.js +86 -0
  65. package/lib/core/workspace-bindings.js.map +1 -0
  66. package/lib/core/workspaces.d.ts +9 -0
  67. package/lib/core/workspaces.js +283 -0
  68. package/lib/core/workspaces.js.map +1 -0
  69. package/lib/exec-docker/daemon-runner.d.ts +21 -0
  70. package/lib/exec-docker/daemon-runner.js +326 -0
  71. package/lib/exec-docker/daemon-runner.js.map +1 -0
  72. package/lib/exec-docker/docker-backend.d.ts +48 -0
  73. package/lib/exec-docker/docker-backend.js +1 -0
  74. package/lib/exec-docker/docker-client.d.ts +46 -0
  75. package/lib/exec-docker/docker-client.js +302 -0
  76. package/lib/exec-docker/docker-client.js.map +1 -0
  77. package/lib/exec-docker/docker-routes.d.ts +6 -0
  78. package/lib/exec-docker/docker-routes.js +215 -0
  79. package/lib/exec-docker/docker-routes.js.map +1 -0
  80. package/lib/exec-docker/fs-provider.d.ts +50 -0
  81. package/lib/exec-docker/fs-provider.js +92 -0
  82. package/lib/exec-docker/fs-provider.js.map +1 -0
  83. package/lib/exec-docker/host-runner.d.ts +29 -0
  84. package/lib/exec-docker/host-runner.js +17 -0
  85. package/lib/exec-docker/host-runner.js.map +1 -0
  86. package/lib/exec-docker/index.d.ts +21 -0
  87. package/lib/exec-docker/index.js +137 -0
  88. package/lib/exec-docker/index.js.map +1 -0
  89. package/lib/exec-docker/process-provider.d.ts +20 -0
  90. package/lib/exec-docker/process-provider.js +75 -0
  91. package/lib/exec-docker/process-provider.js.map +1 -0
  92. package/lib/exec-docker/provision.d.ts +24 -0
  93. package/lib/exec-docker/provision.js +103 -0
  94. package/lib/exec-docker/provision.js.map +1 -0
  95. package/lib/exec-docker/remote-docker-cli.d.ts +52 -0
  96. package/lib/exec-docker/remote-docker-cli.js +155 -0
  97. package/lib/exec-docker/remote-docker-cli.js.map +1 -0
  98. package/lib/exec-docker/world.d.ts +37 -0
  99. package/lib/exec-docker/world.js +62 -0
  100. package/lib/exec-docker/world.js.map +1 -0
  101. package/lib/exec-ssh/connection-pool.d.ts +25 -0
  102. package/lib/exec-ssh/connection-pool.js +54 -0
  103. package/lib/exec-ssh/connection-pool.js.map +1 -0
  104. package/lib/exec-ssh/connection.d.ts +2 -0
  105. package/lib/exec-ssh/connection.js +125 -0
  106. package/lib/exec-ssh/connection.js.map +1 -0
  107. package/lib/exec-ssh/env-scrub.d.ts +7 -0
  108. package/lib/exec-ssh/env-scrub.js +40 -0
  109. package/lib/exec-ssh/env-scrub.js.map +1 -0
  110. package/lib/exec-ssh/executor.d.ts +46 -0
  111. package/lib/exec-ssh/executor.js +212 -0
  112. package/lib/exec-ssh/executor.js.map +1 -0
  113. package/lib/exec-ssh/fs-provider.d.ts +50 -0
  114. package/lib/exec-ssh/fs-provider.js +92 -0
  115. package/lib/exec-ssh/fs-provider.js.map +1 -0
  116. package/lib/exec-ssh/index.d.ts +16 -0
  117. package/lib/exec-ssh/index.js +30 -0
  118. package/lib/exec-ssh/index.js.map +1 -0
  119. package/lib/exec-ssh/process-provider.d.ts +20 -0
  120. package/lib/exec-ssh/process-provider.js +75 -0
  121. package/lib/exec-ssh/process-provider.js.map +1 -0
  122. package/lib/exec-ssh/runner.d.ts +13 -0
  123. package/lib/exec-ssh/runner.js +62 -0
  124. package/lib/exec-ssh/runner.js.map +1 -0
  125. package/lib/exec-ssh/world.d.ts +79 -0
  126. package/lib/exec-ssh/world.js +95 -0
  127. package/lib/exec-ssh/world.js.map +1 -0
  128. package/lib/index.d.ts +2 -0
  129. package/lib/index.js +2 -0
  130. package/lib/router/decorate-fs.d.ts +6 -0
  131. package/lib/router/decorate-fs.js +78 -0
  132. package/lib/router/decorate-fs.js.map +1 -0
  133. package/lib/router/decorate-shell.d.ts +6 -0
  134. package/lib/router/decorate-shell.js +35 -0
  135. package/lib/router/decorate-shell.js.map +1 -0
  136. package/lib/router/decorate-subprocess.d.ts +6 -0
  137. package/lib/router/decorate-subprocess.js +35 -0
  138. package/lib/router/decorate-subprocess.js.map +1 -0
  139. package/lib/router/index.d.ts +10 -0
  140. package/lib/router/index.js +21 -0
  141. package/lib/router/index.js.map +1 -0
  142. package/lib/router/resolve.d.ts +22 -0
  143. package/lib/router/resolve.js +45 -0
  144. package/lib/router/resolve.js.map +1 -0
  145. package/lib/router/router-fs.d.ts +25 -0
  146. package/lib/router/router-fs.js +64 -0
  147. package/lib/router/router-fs.js.map +1 -0
  148. package/lib/router/router-shell.d.ts +14 -0
  149. package/lib/router/router-shell.js +36 -0
  150. package/lib/router/router-shell.js.map +1 -0
  151. package/lib/router/router-subprocess.d.ts +13 -0
  152. package/lib/router/router-subprocess.js +33 -0
  153. package/lib/router/router-subprocess.js.map +1 -0
  154. package/lib/router/types.d.ts +2 -0
  155. package/lib/router/types.js +1 -0
  156. package/lib/types-C0TtEO7z.d.ts +67 -0
  157. package/lib/ui/decorate-picker.d.ts +6 -0
  158. package/lib/ui/decorate-picker.js +58 -0
  159. package/lib/ui/decorate-picker.js.map +1 -0
  160. package/lib/ui/index.d.ts +8 -0
  161. package/lib/ui/index.js +11 -0
  162. package/lib/ui/index.js.map +1 -0
  163. package/lib/ui/picker.d.ts +10 -0
  164. package/lib/ui/picker.js +58 -0
  165. package/lib/ui/picker.js.map +1 -0
  166. package/package.json +146 -13
  167. package/LICENSE +0 -21
@@ -0,0 +1,92 @@
1
+ //#region src/exec-docker/fs-provider.ts
2
+ var DockerFileSystem = class {
3
+ client;
4
+ constructor(client) {
5
+ this.client = client;
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.client.stat(target);
21
+ }
22
+ async lstat(path, _opts, _signal) {
23
+ return this.client.stat(path);
24
+ }
25
+ async readText(target, _signal) {
26
+ return (await this.client.readFile(target)).toString("utf8");
27
+ }
28
+ async streamText(target, _signal) {
29
+ const text = (await this.client.readFile(target)).toString("utf8");
30
+ return (async function* () {
31
+ yield text;
32
+ })();
33
+ }
34
+ async readBytes(target, _signal, maxBytes) {
35
+ const slice = (await this.client.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.client.listDir(target)).map((e) => ({
40
+ name: e.name,
41
+ path: `${target.replace(/\/+$/, "")}/${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.client.stat(target);
52
+ let before = null;
53
+ if (beforeInfo?.isFile) try {
54
+ before = normalizeLf((await this.client.readFile(target)).toString("utf8"));
55
+ } catch {
56
+ before = null;
57
+ }
58
+ const after = normalizeLf(content);
59
+ await this.client.writeFile(target, content);
60
+ const afterInfo = await this.client.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.client.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.client.writeFile(target, after);
81
+ const afterInfo = await this.client.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 { DockerFileSystem };
91
+
92
+ //# sourceMappingURL=fs-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs-provider.js","names":[],"sources":["../../src/exec-docker/fs-provider.ts"],"sourcesContent":["import type { DockerBackend } from './docker-backend.js'\n\nexport class DockerFileSystem {\n constructor(private readonly client: DockerBackend) {}\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.client.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.client.stat(path)\n }\n\n async readText(target: string, _signal?: AbortSignal): Promise<string> {\n const data = await this.client.readFile(target)\n return data.toString('utf8')\n }\n\n async streamText(target: string, _signal?: AbortSignal): Promise<AsyncIterable<string>> {\n const data = await this.client.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.client.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.client.listDir(target)\n return entries.map((e) => ({\n name: e.name,\n path: `${target.replace(/\\/+$/, '')}/${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.client.stat(target)\n let before: string | null = null\n if (beforeInfo?.isFile) {\n try {\n before = normalizeLf((await this.client.readFile(target)).toString('utf8'))\n } catch {\n before = null\n }\n }\n const after = normalizeLf(content)\n await this.client.writeFile(target, content)\n const afterInfo = await this.client.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.client.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.client.writeFile(target, after)\n const afterInfo = await this.client.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,29 @@
1
+ import { HostCommandRunner } from "./docker-backend.js";
2
+ import { Context } from "@deepseek-ai/cordis";
3
+ //#region src/exec-docker/host-runner.d.ts
4
+ interface SshExecutorLike {
5
+ exec(argv: string[], cwd: string, env?: Record<string, string>, stdinData?: Buffer): Promise<{
6
+ code: number;
7
+ stdout: string;
8
+ stderr: string;
9
+ }>;
10
+ }
11
+ declare function sshRunner(executor: SshExecutorLike): HostCommandRunner;
12
+ interface DockerNodeLike {
13
+ id: string;
14
+ type: string;
15
+ ssh?: unknown;
16
+ docker?: {
17
+ containerId?: string;
18
+ image?: string;
19
+ mode?: string;
20
+ resources?: {
21
+ cpus?: number;
22
+ memoryMB?: number;
23
+ };
24
+ };
25
+ }
26
+ declare function resolveHostRunner(ctx: Context, node: DockerNodeLike): Promise<HostCommandRunner | undefined>;
27
+ //#endregion
28
+ export { DockerNodeLike, resolveHostRunner, sshRunner };
29
+ //# sourceMappingURL=host-runner.d.ts.map
@@ -0,0 +1,17 @@
1
+ import { dockerDaemonRunner } from "./daemon-runner.js";
2
+ //#region src/exec-docker/host-runner.ts
3
+ function sshRunner(executor) {
4
+ return { run: async (argv, cwd) => executor.exec(argv, cwd ?? "/") };
5
+ }
6
+ async function resolveHostRunner(ctx, node) {
7
+ if (node.type === "remote-docker") {
8
+ const sshWorld = await ctx.get("dshbSshWorlds")?.ensure(node.id);
9
+ if (!sshWorld) return void 0;
10
+ return sshRunner(sshWorld.executor);
11
+ }
12
+ return dockerDaemonRunner();
13
+ }
14
+ //#endregion
15
+ export { resolveHostRunner, sshRunner };
16
+
17
+ //# sourceMappingURL=host-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"host-runner.js","names":[],"sources":["../../src/exec-docker/host-runner.ts"],"sourcesContent":["import type { Context } from '@deepseek-ai/cordis'\nimport type { HostCommandRunner } from './docker-backend.js'\nimport { dockerDaemonRunner } from './daemon-runner.js'\n\ninterface SshExecutorLike {\n exec(argv: string[], cwd: string, env?: Record<string, string>, stdinData?: Buffer): Promise<{ code: number; stdout: string; stderr: string }>\n}\n\nexport function sshRunner(executor: SshExecutorLike): HostCommandRunner {\n return {\n run: async (argv, cwd) => executor.exec(argv, cwd ?? '/'),\n }\n}\n\nexport interface DockerNodeLike {\n id: string\n type: string\n ssh?: unknown\n docker?: { containerId?: string; image?: string; mode?: string; resources?: { cpus?: number; memoryMB?: number } }\n}\n\nexport async function resolveHostRunner(ctx: Context, node: DockerNodeLike): Promise<HostCommandRunner | undefined> {\n if (node.type === 'remote-docker') {\n const sshWorlds = ctx.get('dshbSshWorlds') as { ensure(nodeId: string): Promise<{ executor: SshExecutorLike } | undefined> } | undefined\n const sshWorld = await sshWorlds?.ensure(node.id)\n if (!sshWorld) return undefined\n return sshRunner(sshWorld.executor)\n }\n return dockerDaemonRunner()\n}\n"],"mappings":";;AAQA,SAAgB,UAAU,UAA8C;CACtE,OAAO,EACL,KAAK,OAAO,MAAM,QAAQ,SAAS,KAAK,MAAM,OAAO,GAAG,EAC1D;AACF;AASA,eAAsB,kBAAkB,KAAc,MAA8D;CAClH,IAAI,KAAK,SAAS,iBAAiB;EAEjC,MAAM,WAAW,MADC,IAAI,IAAI,eACK,CAAC,EAAE,OAAO,KAAK,EAAE;EAChD,IAAI,CAAC,UAAU,OAAO,KAAA;EACtB,OAAO,UAAU,SAAS,QAAQ;CACpC;CACA,OAAO,mBAAmB;AAC5B"}
@@ -0,0 +1,21 @@
1
+ import { DockerBackend, HostCommandRunner } from "./docker-backend.js";
2
+ import { DockerClient } from "./docker-client.js";
3
+ import { DockerFileSystem } from "./fs-provider.js";
4
+ import { RemoteDockerCli } from "./remote-docker-cli.js";
5
+ import { DockerShellExecutor, DockerSubprocessRuntime } from "./process-provider.js";
6
+ import { DockerExecutionWorld, DockerWorldRegistry } from "./world.js";
7
+ import { ProvisionConfig, ProvisionResult, ProvisionStage, listContainers, provisionContainer, removeContainer } from "./provision.js";
8
+ import { Context } from "@deepseek-ai/cordis";
9
+ //#region src/exec-docker/index.d.ts
10
+ declare const name = "dshb-exec-docker";
11
+ declare const inject: string[];
12
+ interface ProvisionStatus {
13
+ state: 'provisioning' | 'ready' | 'failed';
14
+ error?: string;
15
+ containerId?: string;
16
+ updatedAt: string;
17
+ }
18
+ declare function apply(ctx: Context): void;
19
+ //#endregion
20
+ export { type DockerBackend, DockerClient, DockerExecutionWorld, DockerFileSystem, DockerShellExecutor, DockerSubprocessRuntime, DockerWorldRegistry, type HostCommandRunner, type ProvisionConfig, type ProvisionResult, type ProvisionStage, ProvisionStatus, RemoteDockerCli, apply, inject, listContainers, name, provisionContainer, removeContainer };
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,137 @@
1
+ import { sharedWorldResolver } from "../router/resolve.js";
2
+ import { DockerClient } from "./docker-client.js";
3
+ import { RemoteDockerCli } from "./remote-docker-cli.js";
4
+ import { DockerFileSystem } from "./fs-provider.js";
5
+ import { DockerShellExecutor, DockerSubprocessRuntime } from "./process-provider.js";
6
+ import { DockerExecutionWorld, DockerWorldRegistry } from "./world.js";
7
+ import { listContainers, provisionContainer, removeContainer } from "./provision.js";
8
+ import { resolveHostRunner } from "./host-runner.js";
9
+ import { registerDockerRoutes } from "./docker-routes.js";
10
+ //#region src/exec-docker/index.ts
11
+ const name = "dshb-exec-docker";
12
+ const inject = ["nodeRegistry", "webServer"];
13
+ function apply(ctx) {
14
+ const worlds = new DockerWorldRegistry();
15
+ const provisionStatuses = /* @__PURE__ */ new Map();
16
+ ctx.provide("dshbDockerWorlds", worlds);
17
+ sharedWorldResolver().setRegistry({ get: (nodeId) => worlds.get(nodeId) });
18
+ ctx.provide("dshbDockerWorldsGeneric", { ensure: async (nodeId) => {
19
+ const node = ctx.get("nodeRegistry")?.get(nodeId);
20
+ if (!node) return void 0;
21
+ if (node.type === "local-docker" && node.docker?.containerId) return worlds.ensure(nodeId, new DockerClient(node.docker.containerId));
22
+ if (node.type === "remote-docker" && node.docker?.containerId && node.ssh) {
23
+ if (!ctx.get("dshbSshPool")) return void 0;
24
+ const sshWorlds = ctx.get("dshbSshWorlds");
25
+ if (!sshWorlds) return void 0;
26
+ const sshWorld = await sshWorlds.ensure(nodeId);
27
+ if (!sshWorld) return void 0;
28
+ return worlds.ensure(nodeId, new RemoteDockerCli(sshWorld.executor, node.docker.containerId));
29
+ }
30
+ } });
31
+ ctx.provide("dshbDockerProvisioner", {
32
+ provision: async (nodeId) => {
33
+ const node = ctx.get("nodeRegistry")?.get(nodeId);
34
+ if (!node) throw new Error(`node ${nodeId} not found`);
35
+ if (node.type !== "local-docker" && node.type !== "remote-docker") throw new Error("节点不是 Docker 类型");
36
+ const image = node.docker?.image;
37
+ if (!image) throw new Error("节点未配置镜像");
38
+ const runner = await resolveHostRunner(ctx, node);
39
+ if (!runner) throw new Error("节点执行通道未就绪");
40
+ const name = `dshb-${nodeId}`;
41
+ provisionStatuses.set(nodeId, {
42
+ state: "provisioning",
43
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
44
+ });
45
+ try {
46
+ const result = await provisionContainer(runner, {
47
+ image,
48
+ cpus: node.docker?.resources?.cpus,
49
+ memoryMB: node.docker?.resources?.memoryMB,
50
+ name
51
+ });
52
+ await ctx.get("nodeRegistry")?.update(nodeId, { docker: {
53
+ ...node.docker,
54
+ containerId: result.containerId,
55
+ mode: "managed"
56
+ } });
57
+ provisionStatuses.set(nodeId, {
58
+ state: "ready",
59
+ containerId: result.containerId,
60
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
61
+ });
62
+ return result;
63
+ } catch (err) {
64
+ provisionStatuses.set(nodeId, {
65
+ state: "failed",
66
+ error: err instanceof Error ? err.message : String(err),
67
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
68
+ });
69
+ throw err;
70
+ }
71
+ },
72
+ status: (nodeId) => provisionStatuses.get(nodeId)
73
+ });
74
+ ctx.provide("dshbDockerTester", { test: async (node) => {
75
+ try {
76
+ const runner = await resolveHostRunner(ctx, node);
77
+ if (!runner) return {
78
+ ok: false,
79
+ reachable: false,
80
+ error: "执行通道未就绪",
81
+ category: "network"
82
+ };
83
+ const info = await runner.run([
84
+ "docker",
85
+ "info",
86
+ "--format",
87
+ "{{.ServerVersion}}"
88
+ ]);
89
+ if (info.code !== 0) return {
90
+ ok: false,
91
+ reachable: false,
92
+ error: `Docker 守护进程不可用: ${(info.stderr || info.stdout).trim()}`,
93
+ category: "unknown"
94
+ };
95
+ const containerId = node.docker?.containerId;
96
+ if (!containerId) return {
97
+ ok: false,
98
+ reachable: false,
99
+ error: "未关联容器,请先创建并启动容器",
100
+ category: "unknown"
101
+ };
102
+ const inspect = await runner.run([
103
+ "docker",
104
+ "inspect",
105
+ "--format",
106
+ "{{.State.Running}}",
107
+ containerId
108
+ ]);
109
+ if (inspect.code !== 0) return {
110
+ ok: false,
111
+ reachable: false,
112
+ error: "容器不存在或已删除"
113
+ };
114
+ if (inspect.stdout.trim() !== "true") return {
115
+ ok: false,
116
+ reachable: false,
117
+ error: "容器已停止"
118
+ };
119
+ return {
120
+ ok: true,
121
+ reachable: true
122
+ };
123
+ } catch (err) {
124
+ return {
125
+ ok: false,
126
+ reachable: false,
127
+ error: err instanceof Error ? err.message : String(err),
128
+ category: "unknown"
129
+ };
130
+ }
131
+ } });
132
+ registerDockerRoutes(ctx);
133
+ }
134
+ //#endregion
135
+ export { DockerClient, DockerExecutionWorld, DockerFileSystem, DockerShellExecutor, DockerSubprocessRuntime, DockerWorldRegistry, RemoteDockerCli, apply, inject, listContainers, name, provisionContainer, removeContainer };
136
+
137
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/exec-docker/index.ts"],"sourcesContent":["import type { Context } from '@deepseek-ai/cordis'\nimport type {} from '@deepseek-ai/dsh-host-webserver'\nimport type { DockerBackend } from './docker-backend.js'\nimport { DockerWorldRegistry } from './world.js'\nimport { RemoteDockerCli } from './remote-docker-cli.js'\nimport { DockerClient } from './docker-client.js'\nimport { registerDockerRoutes } from './docker-routes.js'\nimport { listContainers, provisionContainer } from './provision.js'\nimport { resolveHostRunner, type DockerNodeLike } from './host-runner.js'\nimport { sharedWorldResolver } from '../router/resolve.js'\n\ninterface NodeRegistryLike {\n get(id: string): { id: string; type: string; ssh?: { host: string; port: number; username: string }; docker?: { containerId?: string; image?: string; mode?: 'existing' | 'managed'; resources?: { cpus?: number; memoryMB?: number } } } | undefined\n}\n\ninterface SshExecutorLike {\n exec(argv: string[], cwd: string, env?: Record<string, string>, stdinData?: Buffer): Promise<{ code: number; stdout: string; stderr: string }>\n}\n\nexport const name = 'dshb-exec-docker'\n\nexport const inject = ['nodeRegistry', 'webServer']\n\nexport interface ProvisionStatus {\n state: 'provisioning' | 'ready' | 'failed'\n error?: string\n containerId?: string\n updatedAt: string\n}\n\nexport function apply(ctx: Context): void {\n const worlds = new DockerWorldRegistry()\n const provisionStatuses = new Map<string, ProvisionStatus>()\n ctx.provide('dshbDockerWorlds', worlds)\n sharedWorldResolver().setRegistry({\n get: (nodeId: string) => worlds.get(nodeId),\n })\n ctx.provide('dshbDockerWorldsGeneric', {\n ensure: async (nodeId: string) => {\n const nodeRegistry = ctx.get('nodeRegistry') as NodeRegistryLike | undefined\n const node = nodeRegistry?.get(nodeId)\n if (!node) return undefined\n if (node.type === 'local-docker' && node.docker?.containerId) {\n return worlds.ensure(nodeId, new DockerClient(node.docker.containerId))\n }\n if (node.type === 'remote-docker' && node.docker?.containerId && node.ssh) {\n const sshPool = ctx.get('dshbSshPool') as { acquire(target: unknown, secrets: unknown): { getClient(): Promise<unknown> } } | undefined\n if (!sshPool) return undefined\n const sshWorlds = ctx.get('dshbSshWorlds') as { ensure(nodeId: string): Promise<{ executor: SshExecutorLike } | undefined> } | undefined\n if (!sshWorlds) return undefined\n const sshWorld = await sshWorlds.ensure(nodeId)\n if (!sshWorld) return undefined\n return worlds.ensure(nodeId, new RemoteDockerCli(sshWorld.executor, node.docker.containerId))\n }\n return undefined\n },\n })\n ctx.provide('dshbDockerProvisioner', {\n provision: async (nodeId: string) => {\n const nodeRegistry = ctx.get('nodeRegistry') as NodeRegistryLike | undefined\n const node = nodeRegistry?.get(nodeId)\n if (!node) throw new Error(`node ${nodeId} not found`)\n if (node.type !== 'local-docker' && node.type !== 'remote-docker') throw new Error('节点不是 Docker 类型')\n const image = node.docker?.image\n if (!image) throw new Error('节点未配置镜像')\n const runner = await resolveHostRunner(ctx, node)\n if (!runner) throw new Error('节点执行通道未就绪')\n const name = `dshb-${nodeId}`\n provisionStatuses.set(nodeId, { state: 'provisioning', updatedAt: new Date().toISOString() })\n try {\n const result = await provisionContainer(runner, {\n image,\n cpus: node.docker?.resources?.cpus,\n memoryMB: node.docker?.resources?.memoryMB,\n name,\n })\n const registry = ctx.get('nodeRegistry') as { update(id: string, input: { docker: Record<string, unknown> }): Promise<unknown> } | undefined\n await registry?.update(nodeId, { docker: { ...node.docker, containerId: result.containerId, mode: 'managed' } })\n provisionStatuses.set(nodeId, { state: 'ready', containerId: result.containerId, updatedAt: new Date().toISOString() })\n return result\n } catch (err) {\n provisionStatuses.set(nodeId, { state: 'failed', error: err instanceof Error ? err.message : String(err), updatedAt: new Date().toISOString() })\n throw err\n }\n },\n status: (nodeId: string) => provisionStatuses.get(nodeId),\n })\n ctx.provide('dshbDockerTester', {\n test: async (node: DockerNodeLike) => {\n try {\n const runner = await resolveHostRunner(ctx, node)\n if (!runner) return { ok: false, reachable: false, error: '执行通道未就绪', category: 'network' }\n const info = await runner.run(['docker', 'info', '--format', '{{.ServerVersion}}'])\n if (info.code !== 0) return { ok: false, reachable: false, error: `Docker 守护进程不可用: ${(info.stderr || info.stdout).trim()}`, category: 'unknown' }\n const containerId = node.docker?.containerId\n if (!containerId) return { ok: false, reachable: false, error: '未关联容器,请先创建并启动容器', category: 'unknown' }\n const inspect = await runner.run(['docker', 'inspect', '--format', '{{.State.Running}}', containerId])\n if (inspect.code !== 0) return { ok: false, reachable: false, error: '容器不存在或已删除' }\n if (inspect.stdout.trim() !== 'true') return { ok: false, reachable: false, error: '容器已停止' }\n return { ok: true, reachable: true }\n } catch (err) {\n return { ok: false, reachable: false, error: err instanceof Error ? err.message : String(err), category: 'unknown' }\n }\n },\n })\n registerDockerRoutes(ctx)\n}\n\nexport { DockerClient } from './docker-client.js'\nexport { RemoteDockerCli } from './remote-docker-cli.js'\nexport { DockerExecutionWorld, DockerWorldRegistry } from './world.js'\nexport { DockerFileSystem } from './fs-provider.js'\nexport { DockerShellExecutor, DockerSubprocessRuntime } from './process-provider.js'\nexport { provisionContainer, listContainers, removeContainer } from './provision.js'\nexport type { ProvisionConfig, ProvisionResult, ProvisionStage } from './provision.js'\nexport type { DockerBackend, HostCommandRunner } from './docker-backend.js'\n"],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import { DockerBackend } from "./docker-backend.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-docker/process-provider.d.ts
5
+ declare class DockerShellExecutor {
6
+ private readonly client;
7
+ constructor(client: DockerBackend);
8
+ resolve(request: ShellExecRequest): ShellExecSpec;
9
+ run(spec: ShellExecSpec): Promise<ShellRunResult>;
10
+ start(spec: ShellExecSpec): ShellProcess;
11
+ }
12
+ declare class DockerSubprocessRuntime {
13
+ private readonly client;
14
+ constructor(client: DockerBackend);
15
+ spawn(spec: SubprocessSpawnSpec): SubprocessHandle;
16
+ spawnTerminal(spec: SubprocessTerminalSpawnSpec): Promise<SubprocessTerminalHandle>;
17
+ }
18
+ //#endregion
19
+ export { DockerShellExecutor, DockerSubprocessRuntime };
20
+ //# sourceMappingURL=process-provider.d.ts.map
@@ -0,0 +1,75 @@
1
+ //#region src/exec-docker/process-provider.ts
2
+ var DockerShellExecutor = class {
3
+ client;
4
+ constructor(client) {
5
+ this.client = client;
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.client.exec([
21
+ "bash",
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: 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 DockerSubprocessRuntime = class {
48
+ client;
49
+ constructor(client) {
50
+ this.client = client;
51
+ }
52
+ spawn(spec) {
53
+ return {
54
+ pid: -1,
55
+ done: this.client.exec(spec.argv, spec.cwd, spec.env ?? {}).then((r) => ({
56
+ exitCode: r.code,
57
+ signal: null
58
+ })),
59
+ kill: () => {}
60
+ };
61
+ }
62
+ async spawnTerminal(spec) {
63
+ const pty = await this.client.pty(spec.argv, spec.cwd, spec.cols ?? 80, spec.rows ?? 24);
64
+ return {
65
+ write: (data) => pty.stream.write(data),
66
+ resize: (cols, rows) => pty.resize(cols, rows),
67
+ onData: (cb) => pty.stream.on("data", (chunk) => cb(chunk.toString("utf8"))),
68
+ kill: () => pty.kill()
69
+ };
70
+ }
71
+ };
72
+ //#endregion
73
+ export { DockerShellExecutor, DockerSubprocessRuntime };
74
+
75
+ //# sourceMappingURL=process-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-provider.js","names":[],"sources":["../../src/exec-docker/process-provider.ts"],"sourcesContent":["import type { DockerBackend } from './docker-backend.js'\nimport type { ShellExecRequest, ShellExecSpec, ShellProcess, ShellRunResult } from '@deepseek-ai/dsh-shell'\nimport type { CollectedOutput, SubprocessHandle, SubprocessSpawnSpec, SubprocessTerminalHandle, SubprocessTerminalSpawnSpec } from '@deepseek-ai/dsh-subprocess'\n\nexport class DockerShellExecutor {\n constructor(private readonly client: DockerBackend) {}\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.client.exec(['bash', '-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: 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 return {\n pid: -1,\n done: promise,\n kill: () => {\n void promise\n },\n } as unknown as ShellProcess\n }\n}\n\nexport class DockerSubprocessRuntime {\n constructor(private readonly client: DockerBackend) {}\n\n spawn(spec: SubprocessSpawnSpec): SubprocessHandle {\n const promise = this.client.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: 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.client.pty(spec.argv as string[], spec.cwd, (spec as { cols?: number }).cols ?? 80, (spec as { rows?: number }).rows ?? 24)\n const handle: SubprocessTerminalHandle = {\n write: (data: string) => pty.stream.write(data),\n resize: (cols: number, rows: number) => pty.resize(cols, rows),\n onData: (cb: (data: string) => void) => pty.stream.on('data', (chunk: Buffer) => cb(chunk.toString('utf8'))),\n kill: () => pty.kill(),\n } as unknown as SubprocessTerminalHandle\n return handle\n }\n}\n"],"mappings":";AAIA,IAAa,sBAAb,MAAiC;CACF;CAA7B,YAAY,QAAwC;EAAvB,KAAA,SAAA;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,OAAO,KAAK;GAAC;GAAQ;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,QAAQ;GACR,UAAU;GACV,SAAS;GACT,WAAW,KAAK;GAChB,QAAQ,QAAQ,OAAO,MAAM;GAC7B,QAAQ,QAAQ,OAAO,MAAM;EAC/B;CACF;CAEA,MAAM,MAAmC;EAEvC,OAAO;GACL,KAAK;GACL,MAHc,KAAK,IAAI,IAGX;GACZ,YAAY,CAEZ;EACF;CACF;AACF;AAEA,IAAa,0BAAb,MAAqC;CACN;CAA7B,YAAY,QAAwC;EAAvB,KAAA,SAAA;CAAwB;CAErD,MAAM,MAA6C;EASjD,OAAO;GANL,KAAK;GACL,MAHc,KAAK,OAAO,KAAK,KAAK,MAAkB,KAAK,KAAM,KAAK,OAAO,CAAC,CAGlE,CAAC,CAAC,MAAM,OAAO;IAAE,UAAU,EAAE;IAAM,QAAQ;GAA8B,EAAE;GACvF,YAAY,CAEZ;EAEU;CACd;CAEA,MAAM,cAAc,MAAsE;EACxF,MAAM,MAAM,MAAM,KAAK,OAAO,IAAI,KAAK,MAAkB,KAAK,KAAM,KAA2B,QAAQ,IAAK,KAA2B,QAAQ,EAAE;EAOjJ,OAAO;GALL,QAAQ,SAAiB,IAAI,OAAO,MAAM,IAAI;GAC9C,SAAS,MAAc,SAAiB,IAAI,OAAO,MAAM,IAAI;GAC7D,SAAS,OAA+B,IAAI,OAAO,GAAG,SAAS,UAAkB,GAAG,MAAM,SAAS,MAAM,CAAC,CAAC;GAC3G,YAAY,IAAI,KAAK;EAEX;CACd;AACF"}
@@ -0,0 +1,24 @@
1
+ import { HostCommandRunner } from "./docker-backend.js";
2
+ //#region src/exec-docker/provision.d.ts
3
+ interface ProvisionConfig {
4
+ image: string;
5
+ cpus?: number;
6
+ memoryMB?: number;
7
+ name?: string;
8
+ }
9
+ interface ProvisionResult {
10
+ containerId: string;
11
+ name: string;
12
+ }
13
+ type ProvisionStage = 'pull' | 'create' | 'wait' | 'ready';
14
+ declare function provisionContainer(runner: HostCommandRunner, config: ProvisionConfig, onStage?: (stage: ProvisionStage, detail?: string) => void, timeoutMs?: number): Promise<ProvisionResult>;
15
+ declare function listContainers(runner: HostCommandRunner): Promise<Array<{
16
+ id: string;
17
+ name: string;
18
+ status: string;
19
+ image: string;
20
+ }>>;
21
+ declare function removeContainer(runner: HostCommandRunner, containerId: string): Promise<void>;
22
+ //#endregion
23
+ export { ProvisionConfig, ProvisionResult, ProvisionStage, listContainers, provisionContainer, removeContainer };
24
+ //# sourceMappingURL=provision.d.ts.map
@@ -0,0 +1,103 @@
1
+ //#region src/exec-docker/provision.ts
2
+ async function provisionContainer(runner, config, onStage, timeoutMs = 6e4) {
3
+ const name = config.name ?? `dshb-${Date.now()}`;
4
+ const inspectExisting = await runner.run([
5
+ "docker",
6
+ "inspect",
7
+ "--format",
8
+ "{{.Id}} {{.State.Running}}",
9
+ name
10
+ ]);
11
+ if (inspectExisting.code === 0) {
12
+ const [containerId, running] = inspectExisting.stdout.trim().split(" ");
13
+ if (running === "true") {
14
+ onStage?.("ready", `容器 ${name} 已在运行`);
15
+ return {
16
+ containerId: containerId ?? name,
17
+ name
18
+ };
19
+ }
20
+ if ((await runner.run([
21
+ "docker",
22
+ "start",
23
+ name
24
+ ])).code === 0) {
25
+ onStage?.("ready", `容器 ${name} 已重新启动`);
26
+ return {
27
+ containerId: containerId ?? name,
28
+ name
29
+ };
30
+ }
31
+ }
32
+ onStage?.("pull", `拉取镜像 ${config.image}`);
33
+ const pull = await runner.run([
34
+ "docker",
35
+ "pull",
36
+ config.image
37
+ ]);
38
+ if (pull.code !== 0) throw new Error(`镜像拉取失败: ${pull.stderr.trim() || pull.stdout.trim()}`);
39
+ onStage?.("create", `创建容器`);
40
+ const createArgs = [
41
+ "docker",
42
+ "run",
43
+ "-d",
44
+ "--name",
45
+ name
46
+ ];
47
+ if (config.cpus) createArgs.push("--cpus", String(config.cpus));
48
+ if (config.memoryMB && config.memoryMB >= 6) createArgs.push("-m", `${config.memoryMB}m`);
49
+ createArgs.push(config.image, "sleep", "infinity");
50
+ const create = await runner.run(createArgs);
51
+ if (create.code !== 0) throw new Error(`容器创建失败: ${create.stderr.trim() || create.stdout.trim()}`);
52
+ const containerId = create.stdout.trim();
53
+ if (!containerId) throw new Error("容器创建失败:无容器 ID");
54
+ onStage?.("wait", `等待容器就绪`);
55
+ const deadline = Date.now() + timeoutMs;
56
+ while (Date.now() < deadline) {
57
+ if ((await runner.run([
58
+ "docker",
59
+ "inspect",
60
+ "--format",
61
+ "{{.State.Running}}",
62
+ containerId
63
+ ])).stdout.trim() === "true") {
64
+ onStage?.("ready", `容器 ${name} 就绪`);
65
+ return {
66
+ containerId,
67
+ name
68
+ };
69
+ }
70
+ await new Promise((r) => setTimeout(r, 1e3));
71
+ }
72
+ throw new Error(`容器启动超时(${Math.round(timeoutMs / 1e3)} 秒)`);
73
+ }
74
+ async function listContainers(runner) {
75
+ const result = await runner.run([
76
+ "docker",
77
+ "ps",
78
+ "--format",
79
+ "{{.ID}} {{.Names}} {{.Status}} {{.Image}}"
80
+ ]);
81
+ if (result.code !== 0) return [];
82
+ return result.stdout.split("\n").filter((line) => line.trim()).map((line) => {
83
+ const [id, name, status, image] = line.split(" ");
84
+ return {
85
+ id: id?.trim() ?? "",
86
+ name: name?.trim() ?? "",
87
+ status: status?.trim() ?? "",
88
+ image: image?.trim() ?? ""
89
+ };
90
+ });
91
+ }
92
+ async function removeContainer(runner, containerId) {
93
+ await runner.run([
94
+ "docker",
95
+ "rm",
96
+ "-f",
97
+ containerId
98
+ ]);
99
+ }
100
+ //#endregion
101
+ export { listContainers, provisionContainer, removeContainer };
102
+
103
+ //# sourceMappingURL=provision.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provision.js","names":[],"sources":["../../src/exec-docker/provision.ts"],"sourcesContent":["import type { HostCommandRunner } from './docker-backend.js'\n\nexport interface ProvisionConfig {\n image: string\n cpus?: number\n memoryMB?: number\n name?: string\n}\n\nexport interface ProvisionResult {\n containerId: string\n name: string\n}\n\nexport type ProvisionStage = 'pull' | 'create' | 'wait' | 'ready'\n\nexport async function provisionContainer(\n runner: HostCommandRunner,\n config: ProvisionConfig,\n onStage?: (stage: ProvisionStage, detail?: string) => void,\n timeoutMs = 60_000,\n): Promise<ProvisionResult> {\n const name = config.name ?? `dshb-${Date.now()}`\n\n const inspectExisting = await runner.run(['docker', 'inspect', '--format', '{{.Id}}\\t{{.State.Running}}', name])\n if (inspectExisting.code === 0) {\n const [containerId, running] = inspectExisting.stdout.trim().split('\\t')\n if (running === 'true') {\n onStage?.('ready', `容器 ${name} 已在运行`)\n return { containerId: containerId ?? name, name }\n }\n const startResult = await runner.run(['docker', 'start', name])\n if (startResult.code === 0) {\n onStage?.('ready', `容器 ${name} 已重新启动`)\n return { containerId: containerId ?? name, name }\n }\n }\n\n onStage?.('pull', `拉取镜像 ${config.image}`)\n const pull = await runner.run(['docker', 'pull', config.image])\n if (pull.code !== 0) throw new Error(`镜像拉取失败: ${pull.stderr.trim() || pull.stdout.trim()}`)\n\n onStage?.('create', `创建容器`)\n const createArgs = ['docker', 'run', '-d', '--name', name]\n if (config.cpus) createArgs.push('--cpus', String(config.cpus))\n if (config.memoryMB && config.memoryMB >= 6) createArgs.push('-m', `${config.memoryMB}m`)\n createArgs.push(config.image, 'sleep', 'infinity')\n const create = await runner.run(createArgs)\n if (create.code !== 0) throw new Error(`容器创建失败: ${create.stderr.trim() || create.stdout.trim()}`)\n const containerId = create.stdout.trim()\n if (!containerId) throw new Error('容器创建失败:无容器 ID')\n\n onStage?.('wait', `等待容器就绪`)\n const deadline = Date.now() + timeoutMs\n while (Date.now() < deadline) {\n const inspect = await runner.run(['docker', 'inspect', '--format', '{{.State.Running}}', containerId])\n if (inspect.stdout.trim() === 'true') {\n onStage?.('ready', `容器 ${name} 就绪`)\n return { containerId, name }\n }\n await new Promise((r) => setTimeout(r, 1000))\n }\n throw new Error(`容器启动超时(${Math.round(timeoutMs / 1000)} 秒)`)\n}\n\nexport async function listContainers(runner: HostCommandRunner): Promise<Array<{ id: string; name: string; status: string; image: string }>> {\n const result = await runner.run(['docker', 'ps', '--format', '{{.ID}}\\t{{.Names}}\\t{{.Status}}\\t{{.Image}}'])\n if (result.code !== 0) return []\n return result.stdout\n .split('\\n')\n .filter((line) => line.trim())\n .map((line) => {\n const [id, name, status, image] = line.split('\\t')\n return { id: id?.trim() ?? '', name: name?.trim() ?? '', status: status?.trim() ?? '', image: image?.trim() ?? '' }\n })\n}\n\nexport async function removeContainer(runner: HostCommandRunner, containerId: string): Promise<void> {\n await runner.run(['docker', 'rm', '-f', containerId])\n}\n"],"mappings":";AAgBA,eAAsB,mBACpB,QACA,QACA,SACA,YAAY,KACc;CAC1B,MAAM,OAAO,OAAO,QAAQ,QAAQ,KAAK,IAAI;CAE7C,MAAM,kBAAkB,MAAM,OAAO,IAAI;EAAC;EAAU;EAAW;EAAY;EAA+B;CAAI,CAAC;CAC/G,IAAI,gBAAgB,SAAS,GAAG;EAC9B,MAAM,CAAC,aAAa,WAAW,gBAAgB,OAAO,KAAK,CAAC,CAAC,MAAM,GAAI;EACvE,IAAI,YAAY,QAAQ;GACtB,UAAU,SAAS,MAAM,KAAK,MAAM;GACpC,OAAO;IAAE,aAAa,eAAe;IAAM;GAAK;EAClD;EAEA,KAAI,MADsB,OAAO,IAAI;GAAC;GAAU;GAAS;EAAI,CAAC,EAAA,CAC9C,SAAS,GAAG;GAC1B,UAAU,SAAS,MAAM,KAAK,OAAO;GACrC,OAAO;IAAE,aAAa,eAAe;IAAM;GAAK;EAClD;CACF;CAEA,UAAU,QAAQ,QAAQ,OAAO,OAAO;CACxC,MAAM,OAAO,MAAM,OAAO,IAAI;EAAC;EAAU;EAAQ,OAAO;CAAK,CAAC;CAC9D,IAAI,KAAK,SAAS,GAAG,MAAM,IAAI,MAAM,WAAW,KAAK,OAAO,KAAK,KAAK,KAAK,OAAO,KAAK,GAAG;CAE1F,UAAU,UAAU,MAAM;CAC1B,MAAM,aAAa;EAAC;EAAU;EAAO;EAAM;EAAU;CAAI;CACzD,IAAI,OAAO,MAAM,WAAW,KAAK,UAAU,OAAO,OAAO,IAAI,CAAC;CAC9D,IAAI,OAAO,YAAY,OAAO,YAAY,GAAG,WAAW,KAAK,MAAM,GAAG,OAAO,SAAS,EAAE;CACxF,WAAW,KAAK,OAAO,OAAO,SAAS,UAAU;CACjD,MAAM,SAAS,MAAM,OAAO,IAAI,UAAU;CAC1C,IAAI,OAAO,SAAS,GAAG,MAAM,IAAI,MAAM,WAAW,OAAO,OAAO,KAAK,KAAK,OAAO,OAAO,KAAK,GAAG;CAChG,MAAM,cAAc,OAAO,OAAO,KAAK;CACvC,IAAI,CAAC,aAAa,MAAM,IAAI,MAAM,eAAe;CAEjD,UAAU,QAAQ,QAAQ;CAC1B,MAAM,WAAW,KAAK,IAAI,IAAI;CAC9B,OAAO,KAAK,IAAI,IAAI,UAAU;EAE5B,KAAI,MADkB,OAAO,IAAI;GAAC;GAAU;GAAW;GAAY;GAAsB;EAAW,CAAC,EAAA,CACzF,OAAO,KAAK,MAAM,QAAQ;GACpC,UAAU,SAAS,MAAM,KAAK,IAAI;GAClC,OAAO;IAAE;IAAa;GAAK;EAC7B;EACA,MAAM,IAAI,SAAS,MAAM,WAAW,GAAG,GAAI,CAAC;CAC9C;CACA,MAAM,IAAI,MAAM,UAAU,KAAK,MAAM,YAAY,GAAI,EAAE,IAAI;AAC7D;AAEA,eAAsB,eAAe,QAAwG;CAC3I,MAAM,SAAS,MAAM,OAAO,IAAI;EAAC;EAAU;EAAM;EAAY;CAA8C,CAAC;CAC5G,IAAI,OAAO,SAAS,GAAG,OAAO,CAAC;CAC/B,OAAO,OAAO,OACX,MAAM,IAAI,CAAC,CACX,QAAQ,SAAS,KAAK,KAAK,CAAC,CAAC,CAC7B,KAAK,SAAS;EACb,MAAM,CAAC,IAAI,MAAM,QAAQ,SAAS,KAAK,MAAM,GAAI;EACjD,OAAO;GAAE,IAAI,IAAI,KAAK,KAAK;GAAI,MAAM,MAAM,KAAK,KAAK;GAAI,QAAQ,QAAQ,KAAK,KAAK;GAAI,OAAO,OAAO,KAAK,KAAK;EAAG;CACpH,CAAC;AACL;AAEA,eAAsB,gBAAgB,QAA2B,aAAoC;CACnG,MAAM,OAAO,IAAI;EAAC;EAAU;EAAM;EAAM;CAAW,CAAC;AACtD"}
@@ -0,0 +1,52 @@
1
+ import { DockerBackend } from "./docker-backend.js";
2
+ //#region src/exec-docker/remote-docker-cli.d.ts
3
+ interface SshExecutorLike {
4
+ exec(argv: string[], cwd: string, env?: Record<string, string>, stdinData?: Buffer): Promise<{
5
+ code: number;
6
+ stdout: string;
7
+ stderr: string;
8
+ }>;
9
+ }
10
+ declare class RemoteDockerCli implements DockerBackend {
11
+ private readonly ssh;
12
+ private readonly containerId;
13
+ constructor(ssh: SshExecutorLike, containerId: string);
14
+ exec(argv: string[], cwd: string, env?: Record<string, string>, stdinData?: Buffer): Promise<{
15
+ code: number;
16
+ stdout: string;
17
+ stderr: string;
18
+ }>;
19
+ execShell(command: string, cwd: string): Promise<{
20
+ code: number;
21
+ stdout: string;
22
+ stderr: string;
23
+ }>;
24
+ readFile(path: string): Promise<Buffer>;
25
+ writeFile(path: string, content: Buffer | string): Promise<void>;
26
+ listDir(path: string): Promise<Array<{
27
+ name: string;
28
+ isDir: boolean;
29
+ isFile: boolean;
30
+ isSymlink: boolean;
31
+ size: number;
32
+ mtime: number;
33
+ }>>;
34
+ stat(path: string): Promise<{
35
+ size: number;
36
+ mtime: number;
37
+ isDirectory: boolean;
38
+ isFile: boolean;
39
+ } | undefined>;
40
+ mkdir(path: string): Promise<void>;
41
+ remove(path: string): Promise<void>;
42
+ rename(src: string, dest: string): Promise<void>;
43
+ ensureRg(): Promise<void>;
44
+ pty(argv: string[], cwd: string, cols: number, rows: number): Promise<{
45
+ stream: NodeJS.ReadWriteStream;
46
+ resize: (c: number, r: number) => void;
47
+ kill: () => void;
48
+ }>;
49
+ }
50
+ //#endregion
51
+ export { RemoteDockerCli };
52
+ //# sourceMappingURL=remote-docker-cli.d.ts.map