@stigmer/cli 3.18.1-dev.20260919070736 → 3.19.1-dev.20260920100552
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.
- package/commands/apply.d.ts.map +1 -1
- package/commands/apply.js +45 -101
- package/commands/apply.js.map +1 -1
- package/commands/install.js +2 -1
- package/commands/install.js.map +1 -1
- package/commands/marketplace.js +3 -3
- package/commands/marketplace.js.map +1 -1
- package/commands/push.js +3 -1
- package/commands/push.js.map +1 -1
- package/commands/validate.js +3 -4
- package/commands/validate.js.map +1 -1
- package/local/bootstrap.d.ts +1 -2
- package/local/bootstrap.d.ts.map +1 -1
- package/local/bootstrap.js +13 -41
- package/local/bootstrap.js.map +1 -1
- package/local/daemon/launch.d.ts +2 -2
- package/local/daemon/launch.d.ts.map +1 -1
- package/local/daemon/launch.js +2 -2
- package/local/daemon/launch.js.map +1 -1
- package/local/plugins/defaults.js +2 -2
- package/local/plugins/defaults.js.map +1 -1
- package/marketplace/config.d.ts.map +1 -1
- package/marketplace/config.js +13 -9
- package/marketplace/config.js.map +1 -1
- package/marketplace/render.d.ts.map +1 -1
- package/marketplace/render.js +1 -7
- package/marketplace/render.js.map +1 -1
- package/package.json +7 -7
- package/registry/index.d.ts +2 -2
- package/registry/index.d.ts.map +1 -1
- package/registry/index.js +2 -2
- package/registry/index.js.map +1 -1
- package/registry/metadata.d.ts +9 -0
- package/registry/metadata.d.ts.map +1 -1
- package/registry/metadata.js +14 -5
- package/registry/metadata.js.map +1 -1
- package/registry/registry.d.ts +9 -0
- package/registry/registry.d.ts.map +1 -1
- package/registry/registry.js +16 -1
- package/registry/registry.js.map +1 -1
- package/registry/verb-support.d.ts.map +1 -1
- package/registry/verb-support.js +0 -13
- package/registry/verb-support.js.map +1 -1
- package/resources/apply/apply.d.ts +11 -12
- package/resources/apply/apply.d.ts.map +1 -1
- package/resources/apply/apply.js +12 -21
- package/resources/apply/apply.js.map +1 -1
- package/resources/apply/handlers.js +2 -2
- package/resources/apply/handlers.js.map +1 -1
- package/resources/connect/oauth.d.ts.map +1 -1
- package/resources/connect/oauth.js +4 -1
- package/resources/connect/oauth.js.map +1 -1
- package/resources/delete.d.ts.map +1 -1
- package/resources/delete.js +0 -1
- package/resources/delete.js.map +1 -1
- package/resources/get-bindings.d.ts.map +1 -1
- package/resources/get-bindings.js +0 -5
- package/resources/get-bindings.js.map +1 -1
- package/resources/list.d.ts.map +1 -1
- package/resources/list.js +0 -1
- package/resources/list.js.map +1 -1
- package/resources/plugin.d.ts +27 -0
- package/resources/plugin.d.ts.map +1 -1
- package/resources/plugin.js +113 -8
- package/resources/plugin.js.map +1 -1
- package/resources/validate.d.ts.map +1 -1
- package/resources/validate.js +0 -2
- package/resources/validate.js.map +1 -1
- package/src/commands/apply.ts +40 -150
- package/src/commands/install.test.ts +20 -21
- package/src/commands/install.ts +2 -1
- package/src/commands/marketplace.test.ts +10 -19
- package/src/commands/marketplace.ts +3 -3
- package/src/commands/push.ts +6 -1
- package/src/commands/validate.ts +2 -4
- package/src/local/bootstrap.test.ts +15 -59
- package/src/local/bootstrap.ts +12 -53
- package/src/local/daemon/launch.ts +4 -4
- package/src/local/plugins/defaults.test.ts +28 -28
- package/src/local/plugins/defaults.ts +2 -2
- package/src/marketplace/__fixtures__/cursor-marketplace.ts +16 -12
- package/src/marketplace/config.test.ts +12 -28
- package/src/marketplace/config.ts +13 -9
- package/src/marketplace/install.test.ts +19 -19
- package/src/marketplace/read.test.ts +6 -6
- package/src/marketplace/render.ts +1 -10
- package/src/registry/index.ts +7 -1
- package/src/registry/metadata.ts +15 -5
- package/src/registry/registry.test.ts +1 -7
- package/src/registry/registry.ts +17 -1
- package/src/registry/verb-support.ts +0 -13
- package/src/resources/apply/apply.integration.test.ts +15 -3
- package/src/resources/apply/apply.ts +15 -26
- package/src/resources/apply/handlers.ts +2 -2
- package/src/resources/connect/oauth.test.ts +2 -2
- package/src/resources/connect/oauth.ts +4 -1
- package/src/resources/delete.ts +0 -1
- package/src/resources/get-bindings.ts +0 -5
- package/src/resources/list.ts +0 -1
- package/src/resources/plugin.test.ts +119 -2
- package/src/resources/plugin.ts +140 -8
- package/src/resources/validate.test.ts +0 -1
- package/src/resources/validate.ts +0 -2
- package/local/seedpack-retire.d.ts +0 -63
- package/local/seedpack-retire.d.ts.map +0 -1
- package/local/seedpack-retire.js +0 -361
- package/local/seedpack-retire.js.map +0 -1
- package/resources/apply/declarative.d.ts +0 -106
- package/resources/apply/declarative.d.ts.map +0 -1
- package/resources/apply/declarative.js +0 -397
- package/resources/apply/declarative.js.map +0 -1
- package/resources/apply/synth/project-track.d.ts +0 -21
- package/resources/apply/synth/project-track.d.ts.map +0 -1
- package/resources/apply/synth/project-track.js +0 -102
- package/resources/apply/synth/project-track.js.map +0 -1
- package/resources/apply/synth/reader.d.ts +0 -18
- package/resources/apply/synth/reader.d.ts.map +0 -1
- package/resources/apply/synth/reader.js +0 -55
- package/resources/apply/synth/reader.js.map +0 -1
- package/resources/apply/synth/runtime.d.ts +0 -8
- package/resources/apply/synth/runtime.d.ts.map +0 -1
- package/resources/apply/synth/runtime.js +0 -32
- package/resources/apply/synth/runtime.js.map +0 -1
- package/resources/apply/synth/synthesize.d.ts +0 -43
- package/resources/apply/synth/synthesize.d.ts.map +0 -1
- package/resources/apply/synth/synthesize.js +0 -115
- package/resources/apply/synth/synthesize.js.map +0 -1
- package/src/local/seedpack-retire.test.ts +0 -499
- package/src/local/seedpack-retire.ts +0 -474
- package/src/resources/apply/declarative.integration.test.ts +0 -204
- package/src/resources/apply/declarative.test.ts +0 -132
- package/src/resources/apply/declarative.ts +0 -491
- package/src/resources/apply/synth/capstone.integration.test.ts +0 -134
- package/src/resources/apply/synth/project-track.integration.test.ts +0 -194
- package/src/resources/apply/synth/project-track.ts +0 -126
- package/src/resources/apply/synth/reader.test.ts +0 -90
- package/src/resources/apply/synth/reader.ts +0 -68
- package/src/resources/apply/synth/runtime.test.ts +0 -29
- package/src/resources/apply/synth/runtime.ts +0 -39
- package/src/resources/apply/synth/synthesize.test.ts +0 -109
- package/src/resources/apply/synth/synthesize.ts +0 -161
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
// Runtime inference for SDK project synthesis.
|
|
2
|
-
//
|
|
3
|
-
// A project's `entry_point` extension determines which language runtime executes
|
|
4
|
-
// it — there is no explicit `runtime` field (the proto enum was removed; the
|
|
5
|
-
// extension is the single source of truth). Port of the Go CLI's
|
|
6
|
-
// `internal/cli/apply/runtime.go`; the extension table is kept in lockstep with
|
|
7
|
-
// the backend's `supportedEntryPointExtensions` (project validator).
|
|
8
|
-
|
|
9
|
-
import { extname } from "node:path";
|
|
10
|
-
import { UsageError } from "../../../errors/index.js";
|
|
11
|
-
|
|
12
|
-
/** Language runtime used to execute an SDK entry point. */
|
|
13
|
-
export type Runtime = "go" | "python" | "node";
|
|
14
|
-
|
|
15
|
-
// Extension → runtime. Keep in sync with the backend project validator and Go's
|
|
16
|
-
// extensionToRuntime.
|
|
17
|
-
const EXTENSION_TO_RUNTIME: ReadonlyMap<string, Runtime> = new Map([
|
|
18
|
-
[".go", "go"],
|
|
19
|
-
[".py", "python"],
|
|
20
|
-
[".ts", "node"],
|
|
21
|
-
[".js", "node"],
|
|
22
|
-
[".mts", "node"],
|
|
23
|
-
[".mjs", "node"],
|
|
24
|
-
]);
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Infer the runtime from an entry point's file extension. Throws a UsageError
|
|
28
|
-
* listing the supported extensions when the extension is unrecognized.
|
|
29
|
-
*/
|
|
30
|
-
export function inferRuntime(entryPoint: string): Runtime {
|
|
31
|
-
const ext = extname(entryPoint).toLowerCase();
|
|
32
|
-
const runtime = EXTENSION_TO_RUNTIME.get(ext);
|
|
33
|
-
if (runtime !== undefined) return runtime;
|
|
34
|
-
|
|
35
|
-
const supported = [...EXTENSION_TO_RUNTIME.keys()].join(", ");
|
|
36
|
-
throw new UsageError(
|
|
37
|
-
`cannot infer runtime from entry point '${entryPoint}' (extension '${ext}')\n\n` + `Supported extensions: ${supported}`,
|
|
38
|
-
);
|
|
39
|
-
}
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
// Synthesize orchestration with an injected spawn: asserts the env/cwd/command
|
|
2
|
-
// handed to the subprocess, the per-runtime command choice, the `.stigmer`
|
|
3
|
-
// output dir, and the actionable errors on non-zero exit / spawn failure /
|
|
4
|
-
// missing inputs.
|
|
5
|
-
|
|
6
|
-
import { existsSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
7
|
-
import { tmpdir } from "node:os";
|
|
8
|
-
import { isAbsolute, join } from "node:path";
|
|
9
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
10
|
-
import { runtimeCommand, type SpawnFn, synthesize } from "./synthesize.js";
|
|
11
|
-
|
|
12
|
-
let dir: string;
|
|
13
|
-
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
dir = mkdtempSync(join(tmpdir(), "synth-exec-"));
|
|
16
|
-
writeFileSync(join(dir, "index.ts"), "// entry");
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
afterEach(() => {
|
|
20
|
-
rmSync(dir, { recursive: true, force: true });
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
const ok: SpawnFn = async () => ({ exitCode: 0, stdout: "done", stderr: "" });
|
|
24
|
-
const noPrepare = () => {};
|
|
25
|
-
|
|
26
|
-
describe("synthesize", () => {
|
|
27
|
-
it("spawns the entry point with the synthesis env and cwd, creating .stigmer", async () => {
|
|
28
|
-
const calls: Array<{ command: string; args: readonly string[]; cwd: string; env: NodeJS.ProcessEnv }> = [];
|
|
29
|
-
const spawn: SpawnFn = async (command, args, options) => {
|
|
30
|
-
calls.push({ command, args, cwd: options.cwd, env: options.env });
|
|
31
|
-
return { exitCode: 0, stdout: "", stderr: "" };
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const result = await synthesize(
|
|
35
|
-
{ projectDir: dir, entryPoint: "index.ts", runtime: "node", orgId: "acme" },
|
|
36
|
-
{ spawn, prepare: noPrepare },
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
expect(calls).toHaveLength(1);
|
|
40
|
-
expect(calls[0].command).toBe("npx");
|
|
41
|
-
// The entry is passed as an absolute path (npx ignores cwd for relative).
|
|
42
|
-
expect(calls[0].args[0]).toBe("tsx");
|
|
43
|
-
expect(isAbsolute(calls[0].args[1])).toBe(true);
|
|
44
|
-
expect(calls[0].args[1].endsWith("/index.ts")).toBe(true);
|
|
45
|
-
expect(calls[0].cwd).toBe(result.outputDir.replace(/\/\.stigmer$/, ""));
|
|
46
|
-
expect(calls[0].env.STIGMER_OUT_DIR).toBe(result.outputDir);
|
|
47
|
-
expect(calls[0].env.STIGMER_ORG_ID).toBe("acme");
|
|
48
|
-
expect(result.outputDir.endsWith("/.stigmer")).toBe(true);
|
|
49
|
-
expect(existsSync(result.outputDir)).toBe(true);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it("omits STIGMER_ORG_ID when no org is given", async () => {
|
|
53
|
-
let env: NodeJS.ProcessEnv = {};
|
|
54
|
-
const spawn: SpawnFn = async (_c, _a, options) => {
|
|
55
|
-
env = options.env;
|
|
56
|
-
return { exitCode: 0, stdout: "", stderr: "" };
|
|
57
|
-
};
|
|
58
|
-
await synthesize({ projectDir: dir, entryPoint: "index.ts", runtime: "node", orgId: "" }, { spawn, prepare: noPrepare });
|
|
59
|
-
expect(env.STIGMER_ORG_ID).toBeUndefined();
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
it("maps a non-zero exit to an actionable error with stderr and guidance", async () => {
|
|
63
|
-
const spawn: SpawnFn = async () => ({ exitCode: 1, stdout: "", stderr: "ReferenceError: boom" });
|
|
64
|
-
await expect(
|
|
65
|
-
synthesize({ projectDir: dir, entryPoint: "index.ts", runtime: "node", orgId: "" }, { spawn, prepare: noPrepare }),
|
|
66
|
-
).rejects.toThrow(/SDK synthesis failed:[\s\S]*ReferenceError: boom[\s\S]*npm install/);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it("maps a spawn failure (missing binary) to an actionable error", async () => {
|
|
70
|
-
const spawn: SpawnFn = async () => {
|
|
71
|
-
throw new Error("spawn npx ENOENT");
|
|
72
|
-
};
|
|
73
|
-
await expect(
|
|
74
|
-
synthesize({ projectDir: dir, entryPoint: "index.ts", runtime: "node", orgId: "" }, { spawn, prepare: noPrepare }),
|
|
75
|
-
).rejects.toThrow(/SDK synthesis failed:[\s\S]*spawn npx ENOENT/);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it("rejects a missing entry point before spawning", async () => {
|
|
79
|
-
const spawn = vi.fn(ok);
|
|
80
|
-
await expect(
|
|
81
|
-
synthesize({ projectDir: dir, entryPoint: "missing.ts", runtime: "node", orgId: "" }, { spawn, prepare: noPrepare }),
|
|
82
|
-
).rejects.toThrow(/entry point not found/);
|
|
83
|
-
expect(spawn).not.toHaveBeenCalled();
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
it("rejects a missing project directory", async () => {
|
|
87
|
-
await expect(
|
|
88
|
-
synthesize({ projectDir: join(dir, "nope"), entryPoint: "index.ts", runtime: "node", orgId: "" }, { spawn: ok }),
|
|
89
|
-
).rejects.toThrow(/project directory not found/);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
it("enforces node readiness via the default prepare (node_modules missing)", async () => {
|
|
93
|
-
writeFileSync(join(dir, "package.json"), "{}");
|
|
94
|
-
await expect(
|
|
95
|
-
synthesize({ projectDir: dir, entryPoint: "index.ts", runtime: "node", orgId: "" }, { spawn: ok }),
|
|
96
|
-
).rejects.toThrow(/node_modules not found/);
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
describe("runtimeCommand", () => {
|
|
101
|
-
it("chooses the runner per runtime and extension", () => {
|
|
102
|
-
expect(runtimeCommand("go", "main.go")).toEqual(["go", "run", "main.go"]);
|
|
103
|
-
expect(runtimeCommand("python", "main.py")).toEqual(["python3", "main.py"]);
|
|
104
|
-
expect(runtimeCommand("node", "index.ts")).toEqual(["npx", "tsx", "index.ts"]);
|
|
105
|
-
expect(runtimeCommand("node", "index.mts")).toEqual(["npx", "tsx", "index.mts"]);
|
|
106
|
-
expect(runtimeCommand("node", "index.js")).toEqual(["node", "index.js"]);
|
|
107
|
-
expect(runtimeCommand("node", "index.mjs")).toEqual(["node", "index.mjs"]);
|
|
108
|
-
});
|
|
109
|
-
});
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
// SDK synthesis execution.
|
|
2
|
-
//
|
|
3
|
-
// Runs a project's `entry_point` as a subprocess with `STIGMER_OUT_DIR` (and
|
|
4
|
-
// `STIGMER_ORG_ID`) set; the program writes `.pb` files into that dir, which the
|
|
5
|
-
// reader then decodes. Uniform subprocess model for every runtime (DD-009 §5):
|
|
6
|
-
// go → `go run <entry>`
|
|
7
|
-
// python → `python3 <entry>`
|
|
8
|
-
// node → `npx tsx <entry>` for TS, `node <entry>` for JS
|
|
9
|
-
//
|
|
10
|
-
// `tsx` (not Go's `ts-node`) executes TypeScript entries — it is the runner the
|
|
11
|
-
// CLI ecosystem already standardizes on (DD-009 alternatives). The spawn is
|
|
12
|
-
// injected so the orchestration is unit-testable without a real subprocess
|
|
13
|
-
// (mirrors `connect/oauth.ts`). Port of `internal/cli/apply/synthesize.go`.
|
|
14
|
-
|
|
15
|
-
import { spawn } from "node:child_process";
|
|
16
|
-
import { existsSync, mkdirSync } from "node:fs";
|
|
17
|
-
import { extname, join, resolve } from "node:path";
|
|
18
|
-
import { UsageError } from "../../../errors/index.js";
|
|
19
|
-
import type { Runtime } from "./runtime.js";
|
|
20
|
-
|
|
21
|
-
/** Result of running a subprocess to completion. */
|
|
22
|
-
export interface SpawnResult {
|
|
23
|
-
readonly exitCode: number;
|
|
24
|
-
readonly stdout: string;
|
|
25
|
-
readonly stderr: string;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/** A function that runs a command to completion (injectable for tests). */
|
|
29
|
-
export type SpawnFn = (
|
|
30
|
-
command: string,
|
|
31
|
-
args: readonly string[],
|
|
32
|
-
options: { readonly cwd: string; readonly env: NodeJS.ProcessEnv },
|
|
33
|
-
) => Promise<SpawnResult>;
|
|
34
|
-
|
|
35
|
-
/** Inputs for one synthesis run. */
|
|
36
|
-
export interface SynthesizeOptions {
|
|
37
|
-
/** Directory containing the SDK code and stigmer.yaml. */
|
|
38
|
-
readonly projectDir: string;
|
|
39
|
-
/** Entry point file, relative to `projectDir`. */
|
|
40
|
-
readonly entryPoint: string;
|
|
41
|
-
/** Runtime inferred from the entry point extension. */
|
|
42
|
-
readonly runtime: Runtime;
|
|
43
|
-
/** Resolved org, injected as STIGMER_ORG_ID (empty = omit). */
|
|
44
|
-
readonly orgId: string;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** Injectable collaborators (defaults run real subprocesses / fs checks). */
|
|
48
|
-
export interface SynthesizeDeps {
|
|
49
|
-
readonly spawn?: SpawnFn;
|
|
50
|
-
readonly prepare?: (runtime: Runtime, projectDir: string) => void;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/** Outcome of synthesis: where the `.pb` files were written, plus SDK stdout. */
|
|
54
|
-
export interface SynthesizeResult {
|
|
55
|
-
readonly outputDir: string;
|
|
56
|
-
readonly stdout: string;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Execute the SDK entry point and leave the synthesized `.pb` files in
|
|
61
|
-
* `<projectDir>/.stigmer`. Validates inputs, runs runtime prep, spawns the
|
|
62
|
-
* program with the synthesis env, and maps a non-zero exit (or spawn failure)
|
|
63
|
-
* to an actionable error. The caller reads the output dir with the reader.
|
|
64
|
-
*/
|
|
65
|
-
export async function synthesize(opts: SynthesizeOptions, deps: SynthesizeDeps = {}): Promise<SynthesizeResult> {
|
|
66
|
-
if (opts.projectDir === "") throw new UsageError("project directory is required");
|
|
67
|
-
if (opts.entryPoint === "") throw new UsageError("entry point is required");
|
|
68
|
-
|
|
69
|
-
const projectDir = resolve(opts.projectDir);
|
|
70
|
-
if (!existsSync(projectDir)) throw new UsageError(`project directory not found: ${opts.projectDir}`);
|
|
71
|
-
const entryAbs = join(projectDir, opts.entryPoint);
|
|
72
|
-
if (!existsSync(entryAbs)) throw new UsageError(`entry point not found: ${opts.entryPoint}`);
|
|
73
|
-
|
|
74
|
-
const outputDir = join(projectDir, ".stigmer");
|
|
75
|
-
mkdirSync(outputDir, { recursive: true });
|
|
76
|
-
|
|
77
|
-
(deps.prepare ?? defaultPrepare)(opts.runtime, projectDir);
|
|
78
|
-
|
|
79
|
-
// Pass the ABSOLUTE entry path: `npx` resolves a relative entry against the
|
|
80
|
-
// npm project root (its "local prefix"), not the spawn cwd, so a relative path
|
|
81
|
-
// breaks for the node runtime. An absolute path is correct for every runtime;
|
|
82
|
-
// cwd stays the project dir so the program's own relative imports resolve.
|
|
83
|
-
const [command, ...args] = runtimeCommand(opts.runtime, entryAbs);
|
|
84
|
-
const env: NodeJS.ProcessEnv = { ...process.env, STIGMER_OUT_DIR: outputDir };
|
|
85
|
-
if (opts.orgId !== "") env.STIGMER_ORG_ID = opts.orgId;
|
|
86
|
-
|
|
87
|
-
let result: SpawnResult;
|
|
88
|
-
try {
|
|
89
|
-
result = await (deps.spawn ?? defaultSpawn)(command, args, { cwd: projectDir, env });
|
|
90
|
-
} catch (err) {
|
|
91
|
-
throw new UsageError(formatExecutionError(opts.runtime, "", (err as Error).message));
|
|
92
|
-
}
|
|
93
|
-
if (result.exitCode !== 0) {
|
|
94
|
-
throw new UsageError(formatExecutionError(opts.runtime, result.stderr, `exited with code ${result.exitCode}`));
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return { outputDir, stdout: result.stdout };
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/** Command + args to execute an entry point for the given runtime. */
|
|
101
|
-
export function runtimeCommand(runtime: Runtime, entryPoint: string): string[] {
|
|
102
|
-
switch (runtime) {
|
|
103
|
-
case "go":
|
|
104
|
-
return ["go", "run", entryPoint];
|
|
105
|
-
case "python":
|
|
106
|
-
return ["python3", entryPoint];
|
|
107
|
-
case "node": {
|
|
108
|
-
const ext = extname(entryPoint).toLowerCase();
|
|
109
|
-
// TypeScript entries run through tsx; plain JS runs on node directly.
|
|
110
|
-
return ext === ".ts" || ext === ".tsx" || ext === ".mts" ? ["npx", "tsx", entryPoint] : ["node", entryPoint];
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Lightweight, runtime-specific readiness checks (no subprocess). Unlike Go we
|
|
116
|
-
// do NOT auto-run `go mod tidy`; the entry-point run surfaces missing deps and
|
|
117
|
-
// the user resolves them — keeping the single subprocess the synthesis itself.
|
|
118
|
-
function defaultPrepare(runtime: Runtime, projectDir: string): void {
|
|
119
|
-
if (runtime === "node") {
|
|
120
|
-
if (!existsSync(join(projectDir, "package.json"))) {
|
|
121
|
-
throw new UsageError("package.json not found: run 'npm init' to initialize a Node.js project");
|
|
122
|
-
}
|
|
123
|
-
if (!existsSync(join(projectDir, "node_modules"))) {
|
|
124
|
-
throw new UsageError("node_modules not found: run 'npm install' to install dependencies");
|
|
125
|
-
}
|
|
126
|
-
} else if (runtime === "go" && !existsSync(join(projectDir, "go.mod"))) {
|
|
127
|
-
throw new UsageError("go.mod not found: run 'go mod init' to initialize a Go module");
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// Real subprocess: collects stdout/stderr, resolves with the exit code.
|
|
132
|
-
const defaultSpawn: SpawnFn = (command, args, options) =>
|
|
133
|
-
new Promise<SpawnResult>((resolvePromise, rejectPromise) => {
|
|
134
|
-
const child = spawn(command, [...args], { cwd: options.cwd, env: options.env });
|
|
135
|
-
let stdout = "";
|
|
136
|
-
let stderr = "";
|
|
137
|
-
child.stdout?.on("data", (chunk) => {
|
|
138
|
-
stdout += chunk.toString();
|
|
139
|
-
});
|
|
140
|
-
child.stderr?.on("data", (chunk) => {
|
|
141
|
-
stderr += chunk.toString();
|
|
142
|
-
});
|
|
143
|
-
child.on("error", (err) => rejectPromise(err));
|
|
144
|
-
child.on("close", (code) => resolvePromise({ exitCode: code ?? 0, stdout, stderr }));
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
// Actionable failure message: truncated stderr + runtime-specific guidance.
|
|
148
|
-
// Port of Go's formatExecutionError.
|
|
149
|
-
function formatExecutionError(runtime: Runtime, stderr: string, fallback: string): string {
|
|
150
|
-
let detail = stderr.length > 800 ? `${stderr.slice(0, 800)}\n... (truncated)` : stderr;
|
|
151
|
-
if (detail === "") detail = fallback;
|
|
152
|
-
|
|
153
|
-
const guidance =
|
|
154
|
-
runtime === "go"
|
|
155
|
-
? "Check for compile errors above. Run 'go build' to see full error output."
|
|
156
|
-
: runtime === "python"
|
|
157
|
-
? "If you see import errors, install your dependencies (e.g. pip install -r requirements.txt)."
|
|
158
|
-
: "If you see module errors, run 'npm install' to install dependencies.";
|
|
159
|
-
|
|
160
|
-
return `SDK synthesis failed:\n${detail}\n\n${guidance}`;
|
|
161
|
-
}
|