@dreamboard-games/cli 0.1.30-alpha.2 → 0.1.30-alpha.3
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/dist/agent-verifier/agent-workspace-verifier.mjs +227 -0
- package/dist/agent-verifier/agent-workspace-verifier.mjs.map +1 -0
- package/dist/agent-verifier/chunk-3UKQVWLV.mjs +1744 -0
- package/dist/agent-verifier/chunk-3UKQVWLV.mjs.map +1 -0
- package/dist/agent-verifier/chunk-776W3UGV.mjs +167 -0
- package/dist/agent-verifier/chunk-776W3UGV.mjs.map +1 -0
- package/dist/agent-verifier/chunk-7WWGFAAU.mjs +729 -0
- package/dist/agent-verifier/chunk-7WWGFAAU.mjs.map +1 -0
- package/dist/agent-verifier/chunk-A64ZZUZV.mjs +261 -0
- package/dist/agent-verifier/chunk-A64ZZUZV.mjs.map +1 -0
- package/dist/agent-verifier/chunk-E7SSWJXJ.mjs +3137 -0
- package/dist/agent-verifier/chunk-E7SSWJXJ.mjs.map +1 -0
- package/dist/agent-verifier/chunk-F2DIOJJZ.mjs +302 -0
- package/dist/agent-verifier/chunk-F2DIOJJZ.mjs.map +1 -0
- package/dist/agent-verifier/chunk-G42BGGG2.mjs +70 -0
- package/dist/agent-verifier/chunk-G42BGGG2.mjs.map +1 -0
- package/dist/agent-verifier/chunk-H76MT5UR.mjs +57 -0
- package/dist/agent-verifier/chunk-H76MT5UR.mjs.map +1 -0
- package/dist/agent-verifier/chunk-HGMUAL33.mjs +39 -0
- package/dist/agent-verifier/chunk-HGMUAL33.mjs.map +1 -0
- package/dist/agent-verifier/chunk-IAYRNVUC.mjs +49 -0
- package/dist/agent-verifier/chunk-IAYRNVUC.mjs.map +1 -0
- package/dist/agent-verifier/chunk-JGT4P4UD.mjs +45 -0
- package/dist/agent-verifier/chunk-JGT4P4UD.mjs.map +1 -0
- package/dist/agent-verifier/chunk-LUZ7KE6H.mjs +79 -0
- package/dist/agent-verifier/chunk-LUZ7KE6H.mjs.map +1 -0
- package/dist/agent-verifier/chunk-NAK77WXW.mjs +767 -0
- package/dist/agent-verifier/chunk-NAK77WXW.mjs.map +1 -0
- package/dist/agent-verifier/chunk-O4YCPU7C.mjs +2913 -0
- package/dist/agent-verifier/chunk-O4YCPU7C.mjs.map +1 -0
- package/dist/agent-verifier/chunk-S34FRJHS.mjs +222 -0
- package/dist/agent-verifier/chunk-S34FRJHS.mjs.map +1 -0
- package/dist/agent-verifier/chunk-SH5JKYOB.mjs +226 -0
- package/dist/agent-verifier/chunk-SH5JKYOB.mjs.map +1 -0
- package/dist/agent-verifier/chunk-SKI2ESE5.mjs +44 -0
- package/dist/agent-verifier/chunk-SKI2ESE5.mjs.map +1 -0
- package/dist/agent-verifier/chunk-TAEQKBJB.mjs +107 -0
- package/dist/agent-verifier/chunk-TAEQKBJB.mjs.map +1 -0
- package/dist/agent-verifier/chunk-UIOLGH4A.mjs +150 -0
- package/dist/agent-verifier/chunk-UIOLGH4A.mjs.map +1 -0
- package/dist/agent-verifier/chunk-UIZNWRM6.mjs +2432 -0
- package/dist/agent-verifier/chunk-UIZNWRM6.mjs.map +1 -0
- package/dist/agent-verifier/chunk-VS573ERH.mjs +14523 -0
- package/dist/agent-verifier/chunk-VS573ERH.mjs.map +1 -0
- package/dist/agent-verifier/chunk-W3N3QJ4V.mjs +624 -0
- package/dist/agent-verifier/chunk-W3N3QJ4V.mjs.map +1 -0
- package/dist/agent-verifier/chunk-XGWCY624.mjs +185 -0
- package/dist/agent-verifier/chunk-XGWCY624.mjs.map +1 -0
- package/dist/agent-verifier/chunk-XQXDOBYB.mjs +382 -0
- package/dist/agent-verifier/chunk-XQXDOBYB.mjs.map +1 -0
- package/dist/agent-verifier/chunk-YE7UAO3T.mjs +129 -0
- package/dist/agent-verifier/chunk-YE7UAO3T.mjs.map +1 -0
- package/dist/agent-verifier/chunk-ZEELHSY3.mjs +20 -0
- package/dist/agent-verifier/chunk-ZEELHSY3.mjs.map +1 -0
- package/dist/agent-verifier/compile-TEQVA46V.mjs +312 -0
- package/dist/agent-verifier/compile-TEQVA46V.mjs.map +1 -0
- package/dist/agent-verifier/global-config-Y2NTSK4R.mjs +18 -0
- package/dist/agent-verifier/global-config-Y2NTSK4R.mjs.map +1 -0
- package/dist/agent-verifier/keychain-backend-SPQWGKZN.mjs +135 -0
- package/dist/agent-verifier/keychain-backend-SPQWGKZN.mjs.map +1 -0
- package/dist/agent-verifier/local-files-JFOQQZDL.mjs +45 -0
- package/dist/agent-verifier/local-files-JFOQQZDL.mjs.map +1 -0
- package/dist/agent-verifier/local-typecheck-XVGWI75X.mjs +10 -0
- package/dist/agent-verifier/local-typecheck-XVGWI75X.mjs.map +1 -0
- package/dist/agent-verifier/materialize-workspace-ZAVGQQSF.mjs +89 -0
- package/dist/agent-verifier/materialize-workspace-ZAVGQQSF.mjs.map +1 -0
- package/dist/agent-verifier/project-state-K576C2TE.mjs +33 -0
- package/dist/agent-verifier/project-state-K576C2TE.mjs.map +1 -0
- package/dist/agent-verifier/prompt-MJRJMOGQ.mjs +756 -0
- package/dist/agent-verifier/prompt-MJRJMOGQ.mjs.map +1 -0
- package/dist/agent-verifier/reducer-bundle-preflight-LXNJUBKL.mjs +20 -0
- package/dist/agent-verifier/reducer-bundle-preflight-LXNJUBKL.mjs.map +1 -0
- package/dist/agent-verifier/reducer-contract-preflight-TUMQ43JV.mjs +11 -0
- package/dist/agent-verifier/reducer-contract-preflight-TUMQ43JV.mjs.map +1 -0
- package/dist/agent-verifier/reducer-native-test-harness-CHX5MBL5.mjs +50 -0
- package/dist/agent-verifier/reducer-native-test-harness-CHX5MBL5.mjs.map +1 -0
- package/dist/agent-verifier/static-scaffold-R7SVDRQI.mjs +27 -0
- package/dist/agent-verifier/static-scaffold-R7SVDRQI.mjs.map +1 -0
- package/dist/agent-verifier/sync-THAI546U.mjs +588 -0
- package/dist/agent-verifier/sync-THAI546U.mjs.map +1 -0
- package/dist/agent-verifier/test-AFAQFKOB.mjs +353 -0
- package/dist/agent-verifier/test-AFAQFKOB.mjs.map +1 -0
- package/dist/agent-verifier/workspace-codegen-2ZMQRIKJ.mjs +10 -0
- package/dist/agent-verifier/workspace-codegen-2ZMQRIKJ.mjs.map +1 -0
- package/dist/agent-verifier/workspace-dependencies-NOOQBK6I.mjs +15 -0
- package/dist/agent-verifier/workspace-dependencies-NOOQBK6I.mjs.map +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/utils/atomic-file.ts
|
|
4
|
+
import { constants as fsConstants, promises as fs } from "fs";
|
|
5
|
+
import path from "path";
|
|
6
|
+
import crypto from "crypto";
|
|
7
|
+
async function atomicWriteFile(targetPath, contents, options = {}) {
|
|
8
|
+
if (contents.length === 0) {
|
|
9
|
+
throw new Error(
|
|
10
|
+
`Refusing to atomicWriteFile an empty payload to ${targetPath}`
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
const mode = options.mode ?? 384;
|
|
14
|
+
const shouldFsync = options.fsync ?? true;
|
|
15
|
+
const dir = path.dirname(targetPath);
|
|
16
|
+
await fs.mkdir(dir, { recursive: true });
|
|
17
|
+
const suffix = crypto.randomBytes(6).toString("hex");
|
|
18
|
+
const tmpPath = `${targetPath}.tmp-${process.pid}-${suffix}`;
|
|
19
|
+
const fh = await fs.open(
|
|
20
|
+
tmpPath,
|
|
21
|
+
fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL,
|
|
22
|
+
mode
|
|
23
|
+
);
|
|
24
|
+
try {
|
|
25
|
+
await fh.writeFile(contents, "utf8");
|
|
26
|
+
try {
|
|
27
|
+
await fh.chmod(mode);
|
|
28
|
+
} catch {
|
|
29
|
+
}
|
|
30
|
+
if (shouldFsync) {
|
|
31
|
+
try {
|
|
32
|
+
await fh.sync();
|
|
33
|
+
} catch {
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
} finally {
|
|
37
|
+
await fh.close();
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
await fs.rename(tmpPath, targetPath);
|
|
41
|
+
} catch (err) {
|
|
42
|
+
await fs.unlink(tmpPath).catch(() => void 0);
|
|
43
|
+
throw err;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async function withFileLock(lockPath, fn, options = {}) {
|
|
47
|
+
const retries = options.retries ?? 100;
|
|
48
|
+
const minDelayMs = options.minDelayMs ?? 20;
|
|
49
|
+
const maxDelayMs = options.maxDelayMs ?? 200;
|
|
50
|
+
const staleMs = options.staleMs ?? 3e4;
|
|
51
|
+
await fs.mkdir(path.dirname(lockPath), { recursive: true });
|
|
52
|
+
let attempt = 0;
|
|
53
|
+
let acquired = false;
|
|
54
|
+
while (!acquired) {
|
|
55
|
+
try {
|
|
56
|
+
const fh = await fs.open(
|
|
57
|
+
lockPath,
|
|
58
|
+
fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL,
|
|
59
|
+
384
|
|
60
|
+
);
|
|
61
|
+
await fh.writeFile(`${process.pid}
|
|
62
|
+
`, "utf8");
|
|
63
|
+
await fh.close();
|
|
64
|
+
acquired = true;
|
|
65
|
+
break;
|
|
66
|
+
} catch (err) {
|
|
67
|
+
const code = err.code;
|
|
68
|
+
if (code !== "EEXIST") {
|
|
69
|
+
throw err;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
let stat = null;
|
|
73
|
+
try {
|
|
74
|
+
stat = await fs.stat(lockPath);
|
|
75
|
+
} catch {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (stat !== null) {
|
|
79
|
+
const ageMs = Date.now() - stat.mtimeMs;
|
|
80
|
+
if (ageMs > staleMs) {
|
|
81
|
+
await fs.unlink(lockPath).catch(() => void 0);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
attempt += 1;
|
|
86
|
+
if (attempt >= retries) {
|
|
87
|
+
throw new Error(
|
|
88
|
+
`Timed out acquiring file lock at ${lockPath} after ${retries} attempts.`
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
const jitter = Math.floor(
|
|
92
|
+
Math.random() * Math.max(1, maxDelayMs - minDelayMs)
|
|
93
|
+
);
|
|
94
|
+
await new Promise((resolve) => setTimeout(resolve, minDelayMs + jitter));
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
return await fn();
|
|
98
|
+
} finally {
|
|
99
|
+
await fs.unlink(lockPath).catch(() => void 0);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export {
|
|
104
|
+
atomicWriteFile,
|
|
105
|
+
withFileLock
|
|
106
|
+
};
|
|
107
|
+
//# sourceMappingURL=chunk-TAEQKBJB.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/atomic-file.ts"],"sourcesContent":["/**\n * Primitives for safely mutating local state files owned by the CLI.\n *\n * Two guarantees:\n * - Writes are atomic-ish: we stage the payload in a sibling temp file with\n * the target permissions, fsync the contents, then `rename` over the target.\n * On POSIX `rename` within the same directory is atomic; on Windows it is\n * atomic within the same volume which is always the case for files we write\n * inside `~/.dreamboard`.\n * - We refuse to clobber a file with an empty payload. The original bug that\n * wiped refresh tokens on a failing `sync`/`compile` hinged on `undefined`\n * JSON values being persisted and reloaded as `{}`. Forbidding empty\n * writes here removes that entire failure mode at the primitive level.\n *\n * Additionally, `withFileLock` provides a cross-process advisory lock built on\n * `O_CREAT | O_EXCL` so that parallel CLI invocations (e.g. `dreamboard sync`\n * running while `dreamboard compile` is in flight) serialize around mutations\n * of the same credential state.\n */\n\nimport { constants as fsConstants, promises as fs, type Stats } from \"node:fs\";\nimport path from \"node:path\";\nimport crypto from \"node:crypto\";\n\nexport type AtomicWriteOptions = {\n /** File mode applied to the written file (default: 0o600). */\n mode?: number;\n /** Call `fsync` on the temp file before renaming. Default: true. */\n fsync?: boolean;\n};\n\nexport async function atomicWriteFile(\n targetPath: string,\n contents: string,\n options: AtomicWriteOptions = {},\n): Promise<void> {\n if (contents.length === 0) {\n throw new Error(\n `Refusing to atomicWriteFile an empty payload to ${targetPath}`,\n );\n }\n const mode = options.mode ?? 0o600;\n const shouldFsync = options.fsync ?? true;\n const dir = path.dirname(targetPath);\n await fs.mkdir(dir, { recursive: true });\n\n const suffix = crypto.randomBytes(6).toString(\"hex\");\n const tmpPath = `${targetPath}.tmp-${process.pid}-${suffix}`;\n\n const fh = await fs.open(\n tmpPath,\n fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL,\n mode,\n );\n try {\n await fh.writeFile(contents, \"utf8\");\n try {\n await fh.chmod(mode);\n } catch {\n // Some filesystems (e.g. network volumes, Windows) refuse chmod.\n // Ignoring here is safe: the `open` call above already created the\n // file with the requested mode on systems that honor it.\n }\n if (shouldFsync) {\n try {\n await fh.sync();\n } catch {\n // Best-effort. Not all backends (tmpfs on some platforms) support fsync.\n }\n }\n } finally {\n await fh.close();\n }\n\n try {\n await fs.rename(tmpPath, targetPath);\n } catch (err) {\n await fs.unlink(tmpPath).catch(() => undefined);\n throw err;\n }\n}\n\nexport type FileLockOptions = {\n /** Max number of acquisition attempts before giving up. Default: 100. */\n retries?: number;\n /** Minimum backoff between retries in ms. Default: 20. */\n minDelayMs?: number;\n /** Maximum backoff between retries in ms. Default: 200. */\n maxDelayMs?: number;\n /**\n * A lockfile older than this is considered stale and forcibly removed.\n * Guards against crashed processes leaving a permanent lock. Default: 30s.\n */\n staleMs?: number;\n};\n\nexport async function withFileLock<T>(\n lockPath: string,\n fn: () => Promise<T>,\n options: FileLockOptions = {},\n): Promise<T> {\n const retries = options.retries ?? 100;\n const minDelayMs = options.minDelayMs ?? 20;\n const maxDelayMs = options.maxDelayMs ?? 200;\n const staleMs = options.staleMs ?? 30_000;\n\n await fs.mkdir(path.dirname(lockPath), { recursive: true });\n\n let attempt = 0;\n let acquired = false;\n while (!acquired) {\n try {\n const fh = await fs.open(\n lockPath,\n fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_EXCL,\n 0o600,\n );\n await fh.writeFile(`${process.pid}\\n`, \"utf8\");\n await fh.close();\n acquired = true;\n break;\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code !== \"EEXIST\") {\n throw err;\n }\n }\n\n let stat: Stats | null = null;\n try {\n stat = await fs.stat(lockPath);\n } catch {\n continue;\n }\n if (stat !== null) {\n const ageMs = Date.now() - stat.mtimeMs;\n if (ageMs > staleMs) {\n await fs.unlink(lockPath).catch(() => undefined);\n continue;\n }\n }\n\n attempt += 1;\n if (attempt >= retries) {\n throw new Error(\n `Timed out acquiring file lock at ${lockPath} after ${retries} attempts.`,\n );\n }\n const jitter = Math.floor(\n Math.random() * Math.max(1, maxDelayMs - minDelayMs),\n );\n await new Promise((resolve) => setTimeout(resolve, minDelayMs + jitter));\n }\n\n try {\n return await fn();\n } finally {\n await fs.unlink(lockPath).catch(() => undefined);\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
MANIFEST_TYPECHECK_CONFIG_FILE
|
|
4
|
+
} from "./chunk-H76MT5UR.mjs";
|
|
5
|
+
|
|
6
|
+
// src/services/project/local-typecheck.ts
|
|
7
|
+
import { spawn } from "child_process";
|
|
8
|
+
import { lstat } from "fs/promises";
|
|
9
|
+
import { createRequire } from "module";
|
|
10
|
+
import path from "path";
|
|
11
|
+
var TYPESCRIPT_BIN_PATH_SEGMENTS = [
|
|
12
|
+
"node_modules",
|
|
13
|
+
"typescript",
|
|
14
|
+
"bin",
|
|
15
|
+
"tsc"
|
|
16
|
+
];
|
|
17
|
+
var CLI_PACKAGE_TYPESCRIPT_CLI = resolveCliPackageTypescriptCli();
|
|
18
|
+
function resolveCliPackageTypescriptCli() {
|
|
19
|
+
try {
|
|
20
|
+
const require2 = createRequire(import.meta.url);
|
|
21
|
+
return require2.resolve("typescript/bin/tsc");
|
|
22
|
+
} catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function getProjectNodeModules(projectRoot) {
|
|
27
|
+
return path.join(projectRoot, "node_modules");
|
|
28
|
+
}
|
|
29
|
+
function getProjectTypescriptCli(projectRoot) {
|
|
30
|
+
return path.join(projectRoot, ...TYPESCRIPT_BIN_PATH_SEGMENTS);
|
|
31
|
+
}
|
|
32
|
+
async function pathExists(targetPath) {
|
|
33
|
+
try {
|
|
34
|
+
await lstat(targetPath);
|
|
35
|
+
return true;
|
|
36
|
+
} catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async function ensureTypecheckDependencies(projectRoot) {
|
|
41
|
+
if (await pathExists(getProjectNodeModules(projectRoot))) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
return `Skipping local typecheck: workspace dependencies are not installed at ${getProjectNodeModules(projectRoot)}. Run \`dreamboard sync\` to reconcile workspace dependencies first.`;
|
|
45
|
+
}
|
|
46
|
+
async function resolveTypecheckRunner(projectRoot) {
|
|
47
|
+
const localTypescriptCli = getProjectTypescriptCli(projectRoot);
|
|
48
|
+
if (await pathExists(localTypescriptCli)) {
|
|
49
|
+
return {
|
|
50
|
+
command: process.execPath,
|
|
51
|
+
argsPrefix: [localTypescriptCli]
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
if (CLI_PACKAGE_TYPESCRIPT_CLI && await pathExists(CLI_PACKAGE_TYPESCRIPT_CLI)) {
|
|
55
|
+
return {
|
|
56
|
+
command: process.execPath,
|
|
57
|
+
argsPrefix: [CLI_PACKAGE_TYPESCRIPT_CLI]
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const globalTscAvailable = await new Promise((resolve) => {
|
|
61
|
+
const child = spawn("tsc", ["--version"], {
|
|
62
|
+
env: process.env,
|
|
63
|
+
stdio: "ignore"
|
|
64
|
+
});
|
|
65
|
+
child.on("error", () => {
|
|
66
|
+
resolve(false);
|
|
67
|
+
});
|
|
68
|
+
child.on("close", (code) => {
|
|
69
|
+
resolve(code === 0);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
if (!globalTscAvailable) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
command: "tsc",
|
|
77
|
+
argsPrefix: []
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
async function runTypecheckProject(runner, projectRoot, projectPath) {
|
|
81
|
+
return new Promise((resolve, reject) => {
|
|
82
|
+
const child = spawn(
|
|
83
|
+
runner.command,
|
|
84
|
+
[...runner.argsPrefix, "--noEmit", "-p", projectPath],
|
|
85
|
+
{
|
|
86
|
+
cwd: projectRoot,
|
|
87
|
+
env: process.env,
|
|
88
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
let stdout = "";
|
|
92
|
+
let stderr = "";
|
|
93
|
+
child.stdout.on("data", (chunk) => {
|
|
94
|
+
stdout += chunk.toString();
|
|
95
|
+
});
|
|
96
|
+
child.stderr.on("data", (chunk) => {
|
|
97
|
+
stderr += chunk.toString();
|
|
98
|
+
});
|
|
99
|
+
child.on("error", (error) => {
|
|
100
|
+
reject(new Error(`Failed to start local typecheck. ${error.message}`));
|
|
101
|
+
});
|
|
102
|
+
child.on("close", (code) => {
|
|
103
|
+
const output = [stdout, stderr].filter(Boolean).join("\n").trim();
|
|
104
|
+
resolve({
|
|
105
|
+
success: code === 0,
|
|
106
|
+
output
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
async function runLocalTypecheck(projectRoot) {
|
|
112
|
+
const dependencySkipReason = await ensureTypecheckDependencies(projectRoot);
|
|
113
|
+
if (dependencySkipReason) {
|
|
114
|
+
return {
|
|
115
|
+
success: true,
|
|
116
|
+
skipped: true,
|
|
117
|
+
output: dependencySkipReason
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
const runner = await resolveTypecheckRunner(projectRoot);
|
|
121
|
+
if (!runner) {
|
|
122
|
+
return {
|
|
123
|
+
success: true,
|
|
124
|
+
skipped: true,
|
|
125
|
+
output: "Skipping local typecheck: TypeScript CLI was not found in workspace dependencies or on PATH."
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
const results = await Promise.all(
|
|
129
|
+
[
|
|
130
|
+
MANIFEST_TYPECHECK_CONFIG_FILE,
|
|
131
|
+
"app/tsconfig.json",
|
|
132
|
+
"ui/tsconfig.json"
|
|
133
|
+
].map(
|
|
134
|
+
(projectPath) => runTypecheckProject(runner, projectRoot, projectPath)
|
|
135
|
+
)
|
|
136
|
+
);
|
|
137
|
+
const firstFailure = results.find((result) => !result.success);
|
|
138
|
+
if (firstFailure) {
|
|
139
|
+
return firstFailure;
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
success: true,
|
|
143
|
+
output: ""
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export {
|
|
148
|
+
runLocalTypecheck
|
|
149
|
+
};
|
|
150
|
+
//# sourceMappingURL=chunk-UIOLGH4A.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/services/project/local-typecheck.ts"],"sourcesContent":["import { MANIFEST_TYPECHECK_CONFIG_FILE } from \"../../constants.js\";\nimport { spawn } from \"node:child_process\";\nimport { lstat } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport path from \"node:path\";\n\nexport type LocalTypecheckResult = {\n success: boolean;\n output: string;\n skipped?: boolean;\n};\n\ntype TypecheckRunner = {\n command: string;\n argsPrefix: string[];\n};\n\nconst TYPESCRIPT_BIN_PATH_SEGMENTS = [\n \"node_modules\",\n \"typescript\",\n \"bin\",\n \"tsc\",\n];\n\n// TypeScript shipped with the CLI package itself; used as a fallback when the\n// user's workspace does not provide its own `typescript` install.\nconst CLI_PACKAGE_TYPESCRIPT_CLI = resolveCliPackageTypescriptCli();\n\nfunction resolveCliPackageTypescriptCli(): string | null {\n try {\n const require = createRequire(import.meta.url);\n return require.resolve(\"typescript/bin/tsc\");\n } catch {\n return null;\n }\n}\n\nfunction getProjectNodeModules(projectRoot: string): string {\n return path.join(projectRoot, \"node_modules\");\n}\n\nfunction getProjectTypescriptCli(projectRoot: string): string {\n return path.join(projectRoot, ...TYPESCRIPT_BIN_PATH_SEGMENTS);\n}\n\nasync function pathExists(targetPath: string): Promise<boolean> {\n try {\n await lstat(targetPath);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function ensureTypecheckDependencies(\n projectRoot: string,\n): Promise<string | null> {\n if (await pathExists(getProjectNodeModules(projectRoot))) {\n return null;\n }\n\n return `Skipping local typecheck: workspace dependencies are not installed at ${getProjectNodeModules(projectRoot)}. Run \\`dreamboard sync\\` to reconcile workspace dependencies first.`;\n}\n\nasync function resolveTypecheckRunner(\n projectRoot: string,\n): Promise<TypecheckRunner | null> {\n const localTypescriptCli = getProjectTypescriptCli(projectRoot);\n if (await pathExists(localTypescriptCli)) {\n return {\n command: process.execPath,\n argsPrefix: [localTypescriptCli],\n };\n }\n\n if (\n CLI_PACKAGE_TYPESCRIPT_CLI &&\n (await pathExists(CLI_PACKAGE_TYPESCRIPT_CLI))\n ) {\n return {\n command: process.execPath,\n argsPrefix: [CLI_PACKAGE_TYPESCRIPT_CLI],\n };\n }\n\n const globalTscAvailable = await new Promise<boolean>((resolve) => {\n const child = spawn(\"tsc\", [\"--version\"], {\n env: process.env,\n stdio: \"ignore\",\n });\n\n child.on(\"error\", () => {\n resolve(false);\n });\n child.on(\"close\", (code) => {\n resolve(code === 0);\n });\n });\n\n if (!globalTscAvailable) {\n return null;\n }\n\n return {\n command: \"tsc\",\n argsPrefix: [],\n };\n}\n\nasync function runTypecheckProject(\n runner: TypecheckRunner,\n projectRoot: string,\n projectPath: string,\n): Promise<LocalTypecheckResult> {\n return new Promise((resolve, reject) => {\n const child = spawn(\n runner.command,\n [...runner.argsPrefix, \"--noEmit\", \"-p\", projectPath],\n {\n cwd: projectRoot,\n env: process.env,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n },\n );\n\n let stdout = \"\";\n let stderr = \"\";\n\n child.stdout.on(\"data\", (chunk) => {\n stdout += chunk.toString();\n });\n child.stderr.on(\"data\", (chunk) => {\n stderr += chunk.toString();\n });\n child.on(\"error\", (error) => {\n reject(new Error(`Failed to start local typecheck. ${error.message}`));\n });\n child.on(\"close\", (code) => {\n const output = [stdout, stderr].filter(Boolean).join(\"\\n\").trim();\n resolve({\n success: code === 0,\n output,\n });\n });\n });\n}\n\nexport async function runLocalTypecheck(\n projectRoot: string,\n): Promise<LocalTypecheckResult> {\n const dependencySkipReason = await ensureTypecheckDependencies(projectRoot);\n if (dependencySkipReason) {\n return {\n success: true,\n skipped: true,\n output: dependencySkipReason,\n };\n }\n\n const runner = await resolveTypecheckRunner(projectRoot);\n if (!runner) {\n return {\n success: true,\n skipped: true,\n output:\n \"Skipping local typecheck: TypeScript CLI was not found in workspace dependencies or on PATH.\",\n };\n }\n\n // The three projects are independent (no cross-project references), so\n // checking them in parallel roughly halves wall-clock time without changing\n // correctness. The slowest project (typically `ui/tsconfig.json`) bounds the\n // total cost.\n const results = await Promise.all(\n [\n MANIFEST_TYPECHECK_CONFIG_FILE,\n \"app/tsconfig.json\",\n \"ui/tsconfig.json\",\n ].map((projectPath) =>\n runTypecheckProject(runner, projectRoot, projectPath),\n ),\n );\n\n const firstFailure = results.find((result) => !result.success);\n if (firstFailure) {\n return firstFailure;\n }\n\n return {\n success: true,\n output: \"\",\n };\n}\n"],"mappings":"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","names":["require"]}
|