源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,279 @@
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { existsSync, readFileSync } from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { resolveGolangciLintBinary } from "./golangci-lint-tool.mjs";
|
||||
|
||||
const scriptDirectory = dirname(fileURLToPath(import.meta.url));
|
||||
const workspaceRoot = join(scriptDirectory, "..", "..");
|
||||
const nodeModulesDirectory = join(workspaceRoot, "node_modules");
|
||||
const nodeVersionFile = join(workspaceRoot, ".node-version");
|
||||
const packageJsonPath = join(workspaceRoot, "package.json");
|
||||
const goModPath = join(workspaceRoot, "services", "tuttid", "go.mod");
|
||||
const golangciVersionFile = join(
|
||||
workspaceRoot,
|
||||
"services",
|
||||
"tuttid",
|
||||
".golangci-lint-version"
|
||||
);
|
||||
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
||||
const minimumNodeMajor = Number.parseInt(
|
||||
readFileSync(nodeVersionFile, "utf8").trim(),
|
||||
10
|
||||
);
|
||||
const pinnedPnpmVersion = parsePnpmVersion(packageJson.packageManager);
|
||||
const requiredGoPrefix = parseGoVersionPrefix(readFileSync(goModPath, "utf8"));
|
||||
const pinnedGolangciVersion = readFileSync(golangciVersionFile, "utf8").trim();
|
||||
const argumentsList = process.argv.slice(2);
|
||||
const onlyCheck = parseOnlyCheck(argumentsList);
|
||||
const installTarget = parseInstallTarget(argumentsList);
|
||||
|
||||
if (installTarget === "golangci-lint") {
|
||||
installGolangciLint();
|
||||
}
|
||||
|
||||
const checks = buildChecks();
|
||||
|
||||
const failedChecks = checks.filter((check) => !check.ok);
|
||||
|
||||
console.log("tutti developer setup");
|
||||
for (const check of checks) {
|
||||
console.log(
|
||||
`${check.ok ? "PASS" : "FAIL"} ${check.name}: ${check.ok ? check.success : check.failure}`
|
||||
);
|
||||
}
|
||||
|
||||
if (failedChecks.length > 0) {
|
||||
console.log("");
|
||||
console.log("recommended next steps:");
|
||||
if (onlyCheck === "golangci-lint") {
|
||||
console.log("1. pnpm install:golangci-lint");
|
||||
console.log("2. Rerun `pnpm check:golangci-version`.");
|
||||
} else {
|
||||
console.log(
|
||||
"1. Use Node.js from `.node-version` and pnpm from `packageManager`."
|
||||
);
|
||||
console.log("2. Install Go matching `services/tuttid/go.mod`.");
|
||||
console.log("3. Run `pnpm install`.");
|
||||
console.log("4. Run `pnpm install:golangci-lint`.");
|
||||
console.log("5. Rerun `pnpm setup:dev`.");
|
||||
}
|
||||
process.exitCode = 1;
|
||||
} else {
|
||||
console.log("");
|
||||
if (onlyCheck === "golangci-lint") {
|
||||
console.log("golangci-lint version matches the repository pin.");
|
||||
} else {
|
||||
console.log(
|
||||
"environment looks ready for `pnpm lint`, `pnpm typecheck`, and `pnpm check:full`."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function buildChecks() {
|
||||
const allChecks = [
|
||||
{
|
||||
name: "node",
|
||||
...checkNode()
|
||||
},
|
||||
{
|
||||
name: "pnpm",
|
||||
...checkPnpm()
|
||||
},
|
||||
{
|
||||
name: "go",
|
||||
...checkGo()
|
||||
},
|
||||
{
|
||||
name: "workspace dependencies",
|
||||
ok: existsSync(nodeModulesDirectory),
|
||||
success: "workspace dependencies look installed",
|
||||
failure: "run `pnpm install`"
|
||||
},
|
||||
{
|
||||
name: "golangci-lint",
|
||||
...checkGolangciLint()
|
||||
}
|
||||
];
|
||||
|
||||
if (onlyCheck === null) {
|
||||
return allChecks;
|
||||
}
|
||||
|
||||
return allChecks.filter((check) => check.name === onlyCheck);
|
||||
}
|
||||
|
||||
function checkNode() {
|
||||
const currentMajor = Number.parseInt(
|
||||
process.versions.node.split(".")[0] ?? "",
|
||||
10
|
||||
);
|
||||
const ok = Number.isFinite(currentMajor) && currentMajor >= minimumNodeMajor;
|
||||
|
||||
return {
|
||||
ok,
|
||||
success: `found ${process.version}`,
|
||||
failure: `expected Node.js ${minimumNodeMajor} or newer, found ${process.version}`
|
||||
};
|
||||
}
|
||||
|
||||
function checkPnpm() {
|
||||
const result = spawnSync("pnpm", ["--version"], {
|
||||
cwd: workspaceRoot,
|
||||
encoding: "utf8"
|
||||
});
|
||||
|
||||
if (result.error?.code === "ENOENT") {
|
||||
return {
|
||||
ok: false,
|
||||
success: "",
|
||||
failure: `install pnpm ${pinnedPnpmVersion}`
|
||||
};
|
||||
}
|
||||
|
||||
const version = result.stdout.trim();
|
||||
return {
|
||||
ok: version === pinnedPnpmVersion,
|
||||
success: `found ${version}`,
|
||||
failure: `expected pnpm ${pinnedPnpmVersion}, found ${version || "unknown version"}`
|
||||
};
|
||||
}
|
||||
|
||||
function checkGo() {
|
||||
const result = spawnSync("go", ["version"], {
|
||||
cwd: workspaceRoot,
|
||||
encoding: "utf8"
|
||||
});
|
||||
|
||||
if (result.error?.code === "ENOENT") {
|
||||
return {
|
||||
ok: false,
|
||||
success: "",
|
||||
failure: `install Go ${requiredGoPrefix.replace("go", "")}.x`
|
||||
};
|
||||
}
|
||||
|
||||
const output = `${result.stdout ?? ""}${result.stderr ?? ""}`.trim();
|
||||
return {
|
||||
ok: output.includes(requiredGoPrefix),
|
||||
success: output,
|
||||
failure: `expected ${requiredGoPrefix}.x, found \`${output || "unknown version"}\``
|
||||
};
|
||||
}
|
||||
|
||||
function checkGolangciLint() {
|
||||
const binary = resolveGolangciLintBinary({ cwd: workspaceRoot });
|
||||
const result = spawnSync(binary, ["version"], {
|
||||
cwd: workspaceRoot,
|
||||
encoding: "utf8"
|
||||
});
|
||||
|
||||
if (result.error?.code === "ENOENT") {
|
||||
return {
|
||||
ok: false,
|
||||
success: "",
|
||||
failure: `install ${pinnedGolangciVersion} with \`pnpm install:golangci-lint\``
|
||||
};
|
||||
}
|
||||
|
||||
const output = `${result.stdout ?? ""}${result.stderr ?? ""}`;
|
||||
const normalizedExpected = pinnedGolangciVersion.replace(/^v/, "");
|
||||
|
||||
if (!output.includes(normalizedExpected)) {
|
||||
return {
|
||||
ok: false,
|
||||
success: "",
|
||||
failure: `expected ${pinnedGolangciVersion}, found \`${output.trim() || "unknown version"}\``
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
ok: true,
|
||||
success: `found ${pinnedGolangciVersion}`,
|
||||
failure: ""
|
||||
};
|
||||
}
|
||||
|
||||
function parseOnlyCheck(argumentsList) {
|
||||
const onlyArgument = argumentsList.find((argument) =>
|
||||
argument.startsWith("--only=")
|
||||
);
|
||||
if (!onlyArgument) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const value = onlyArgument.slice("--only=".length);
|
||||
if (
|
||||
["node", "pnpm", "go", "workspace dependencies", "golangci-lint"].includes(
|
||||
value
|
||||
)
|
||||
) {
|
||||
return value;
|
||||
}
|
||||
|
||||
throw new Error(`unsupported setup-dev check target: ${value}`);
|
||||
}
|
||||
|
||||
function parseInstallTarget(argumentsList) {
|
||||
const installArgument = argumentsList.find((argument) =>
|
||||
argument.startsWith("--install=")
|
||||
);
|
||||
if (!installArgument) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const value = installArgument.slice("--install=".length);
|
||||
if (value === "golangci-lint") {
|
||||
return value;
|
||||
}
|
||||
|
||||
throw new Error(`unsupported setup-dev install target: ${value}`);
|
||||
}
|
||||
|
||||
function parsePnpmVersion(packageManager) {
|
||||
const match = /^pnpm@(.+)$/.exec(packageManager);
|
||||
if (!match) {
|
||||
throw new Error(`unsupported packageManager value: ${packageManager}`);
|
||||
}
|
||||
// corepack may pin an integrity suffix (pnpm@x.y.z+sha512....) that
|
||||
// `pnpm --version` never reports, so compare on the bare version only.
|
||||
return match[1].split("+")[0];
|
||||
}
|
||||
|
||||
function parseGoVersionPrefix(goMod) {
|
||||
const match = /^go\s+(\d+\.\d+)(?:\.\d+)?$/m.exec(goMod);
|
||||
if (!match) {
|
||||
throw new Error("unable to parse Go version from services/tuttid/go.mod");
|
||||
}
|
||||
return `go${match[1]}`;
|
||||
}
|
||||
|
||||
function installGolangciLint() {
|
||||
const goPathResult = spawnSync("go", ["env", "GOPATH"], {
|
||||
cwd: workspaceRoot,
|
||||
encoding: "utf8"
|
||||
});
|
||||
|
||||
if (goPathResult.error?.code === "ENOENT" || goPathResult.status !== 0) {
|
||||
console.error(
|
||||
"Go is required to resolve GOPATH before installing golangci-lint."
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const goPath = goPathResult.stdout.trim();
|
||||
const installDir = join(goPath, "bin");
|
||||
const command = `curl -sSfL https://golangci-lint.run/install.sh | sh -s -- -b "${installDir}" "${pinnedGolangciVersion}"`;
|
||||
|
||||
console.log(
|
||||
`Installing golangci-lint ${pinnedGolangciVersion} to ${installDir}`
|
||||
);
|
||||
const result = spawnSync("sh", ["-c", command], {
|
||||
cwd: workspaceRoot,
|
||||
stdio: "inherit"
|
||||
});
|
||||
|
||||
if (result.status !== 0) {
|
||||
process.exit(result.status ?? 1);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user