




















1+import { spawnSync } from "node:child_process";
2+import { chmodSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
3+import { tmpdir } from "node:os";
4+import path from "node:path";
5+import { afterEach, describe, expect, it } from "vitest";
6+7+const tempDirs: string[] = [];
8+const repoRoot = process.cwd();
9+10+function makeFakeCrabbox(helpText: string): string {
11+const binDir = mkdtempSync(path.join(tmpdir(), "openclaw-fake-crabbox-"));
12+tempDirs.push(binDir);
13+const crabboxPath = path.join(binDir, "crabbox");
14+const script = [
15+"#!/usr/bin/env node",
16+"const args = process.argv.slice(2);",
17+'if (args[0] === "--version") {',
18+' console.log("crabbox 0.15.0");',
19+" process.exit(0);",
20+"}",
21+'if (args[0] === "run" && args[1] === "--help") {',
22+` process.stdout.write(${JSON.stringify(helpText)});`,
23+" process.exit(0);",
24+"}",
25+"console.log(JSON.stringify(args));",
26+].join("\n");
27+writeFileSync(crabboxPath, `${script}\n`, "utf8");
28+writeFileSync(
29+`${crabboxPath}.cmd`,
30+`@echo off\r\n"${process.execPath}" "%~dp0crabbox" %*\r\n`,
31+"utf8",
32+);
33+chmodSync(crabboxPath, 0o755);
34+return binDir;
35+}
36+37+function runWrapper(helpText: string, args: string[]) {
38+const binDir = makeFakeCrabbox(helpText);
39+return spawnSync(process.execPath, ["scripts/crabbox-wrapper.mjs", ...args], {
40+cwd: repoRoot,
41+encoding: "utf8",
42+env: {
43+ ...process.env,
44+PATH: `${binDir}${path.delimiter}${process.env.PATH ?? ""}`,
45+},
46+});
47+}
48+49+afterEach(() => {
50+for (const dir of tempDirs.splice(0)) {
51+rmSync(dir, { recursive: true, force: true });
52+}
53+});
54+55+describe("scripts/crabbox-wrapper", () => {
56+it("accepts advertised canonical providers from Crabbox help", () => {
57+const result = runWrapper(
58+"provider: hetzner, aws, local-container, blacksmith-testbox, or cloudflare\n",
59+["run", "--provider", "local-container", "--", "echo ok"],
60+);
61+62+expect(result.status).toBe(0);
63+expect(result.stdout).toContain('"local-container"');
64+});
65+66+it("accepts advertised providers from wrapped Crabbox help", () => {
67+const result = runWrapper(
68+[
69+"provider: hetzner, aws, local-container, blacksmith-testbox,",
70+" docker, or cloudflare (default: aws)",
71+"",
72+].join("\n"),
73+["run", "--provider", "docker", "--", "echo ok"],
74+);
75+76+expect(result.status).toBe(0);
77+expect(result.stdout).toContain('"docker"');
78+expect(result.stderr).toContain(
79+"providers=hetzner,aws,local-container,blacksmith-testbox,docker,cloudflare",
80+);
81+});
82+83+it("accepts Crabbox provider aliases when their canonical provider is advertised", () => {
84+const helpText = [
85+"provider: hetzner, aws, gcp, local-container, blacksmith-testbox,",
86+" namespace-devbox, runpod, semaphore, cloudflare, railway, exe-dev, or ssh",
87+"",
88+].join("\n");
89+const aliases = [
90+"blacksmith",
91+"cf",
92+"container",
93+"docker",
94+"exe",
95+"exedev",
96+"google",
97+"google-cloud",
98+"local-docker",
99+"namespace",
100+"namespace-devboxes",
101+"rail",
102+"railwayapp",
103+"run-pod",
104+"runpodio",
105+"sem",
106+"static",
107+"static-ssh",
108+];
109+110+for (const alias of aliases) {
111+const result = runWrapper(helpText, ["run", "--provider", alias, "--", "echo ok"]);
112+113+expect(result.status, alias).toBe(0);
114+expect(result.stdout).toContain(`"${alias}"`);
115+}
116+});
117+118+it("accepts Crabbox provider aliases when upstream help omits Tensorlake", () => {
119+const helpText = [
120+"provider: hetzner, aws, gcp, local-container, blacksmith-testbox,",
121+" namespace-devbox, runpod, semaphore, cloudflare, railway, exe-dev, or ssh",
122+"",
123+].join("\n");
124+125+for (const provider of ["tensorlake", "tl", "tensorlake-sbx"]) {
126+const result = runWrapper(helpText, ["run", "--provider", provider, "--", "echo ok"]);
127+128+expect(result.status, provider).toBe(0);
129+expect(result.stdout).toContain(`"${provider}"`);
130+}
131+});
132+133+it("keeps unsupported provider selections rejected", () => {
134+const result = runWrapper(
135+"provider: hetzner, aws, local-container, blacksmith-testbox, or cloudflare\n",
136+["run", "--provider", "bogus", "--", "echo ok"],
137+);
138+139+expect(result.status).toBe(2);
140+expect(result.stderr).toContain("selected binary does not advertise provider bogus");
141+});
142+143+it("parses provider choices from the --provider flag help format", () => {
144+const result = runWrapper(
145+"Usage: crabbox run [options]\n --provider hetzner|aws|local-container|blacksmith-testbox|cloudflare\n",
146+["run", "--provider", "aws", "--", "echo ok"],
147+);
148+149+expect(result.status).toBe(0);
150+expect(result.stderr).toContain(
151+"providers=hetzner,aws,local-container,blacksmith-testbox,cloudflare",
152+);
153+});
154+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。