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
97 lines
2.9 KiB
JavaScript
97 lines
2.9 KiB
JavaScript
import { createHash } from "node:crypto";
|
|
import { spawnSync } from "node:child_process";
|
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
import { dirname, resolve } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const scriptDir = dirname(fileURLToPath(import.meta.url));
|
|
const repoRoot = resolve(scriptDir, "../..");
|
|
const lockPath = resolve(
|
|
repoRoot,
|
|
"packages/clients/market-go/source.lock.json"
|
|
);
|
|
|
|
if (resolve(process.argv[1] ?? "") === fileURLToPath(import.meta.url)) {
|
|
main(process.argv.slice(2));
|
|
}
|
|
|
|
export function main(args) {
|
|
const lock = JSON.parse(readFileSync(lockPath, "utf8"));
|
|
const checkOnly = args.includes("--check");
|
|
const sourceRoot = argumentValue(args, "--source-root");
|
|
|
|
if (checkOnly && sourceRoot) {
|
|
throw new Error("--check and --source-root cannot be used together");
|
|
}
|
|
if (!checkOnly && !sourceRoot) {
|
|
throw new Error(
|
|
"Market client sync requires --source-root pointing to a tsh-server checkout"
|
|
);
|
|
}
|
|
if (sourceRoot) {
|
|
verifySourceCheckout(sourceRoot, lock.commit);
|
|
}
|
|
|
|
for (const file of lock.files) {
|
|
const targetPath = resolve(repoRoot, file.target);
|
|
if (checkOnly) {
|
|
if (!existsSync(targetPath)) {
|
|
throw new Error(
|
|
`Generated Market client file is missing: ${file.target}`
|
|
);
|
|
}
|
|
const content = readFileSync(targetPath);
|
|
verifyDigest(file, content, "generated target");
|
|
continue;
|
|
}
|
|
|
|
const content = readPinnedLocalFile(sourceRoot, file.source);
|
|
verifyDigest(file, content, "pinned source");
|
|
mkdirSync(dirname(targetPath), { recursive: true });
|
|
writeFileSync(targetPath, content);
|
|
}
|
|
}
|
|
|
|
export function verifySourceCheckout(root, expectedCommit) {
|
|
const result = spawnSync("git", ["-C", resolve(root), "rev-parse", "HEAD"], {
|
|
encoding: "utf8"
|
|
});
|
|
if (result.error || result.status !== 0) {
|
|
throw new Error(
|
|
`Cannot read Market client source checkout commit: ${String(result.stderr ?? "").trim() || result.error?.message || "git rev-parse failed"}`
|
|
);
|
|
}
|
|
const actualCommit = result.stdout.trim();
|
|
if (actualCommit !== expectedCommit) {
|
|
throw new Error(
|
|
`Market client source checkout is at ${actualCommit}; expected ${expectedCommit}`
|
|
);
|
|
}
|
|
}
|
|
|
|
function argumentValue(args, name) {
|
|
const index = args.indexOf(name);
|
|
if (index === -1) {
|
|
return undefined;
|
|
}
|
|
const value = args[index + 1];
|
|
if (!value || value.startsWith("--")) {
|
|
throw new Error(`${name} requires a value`);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
function readPinnedLocalFile(root, source) {
|
|
const absoluteRoot = resolve(root);
|
|
return readFileSync(resolve(absoluteRoot, source));
|
|
}
|
|
|
|
function verifyDigest(file, content, label) {
|
|
const actual = createHash("sha256").update(content).digest("hex");
|
|
if (actual !== file.sha256) {
|
|
throw new Error(
|
|
`${label} ${file.source} has SHA-256 ${actual}; expected ${file.sha256}`
|
|
);
|
|
}
|
|
}
|