@treeseed/sdk 0.12.46 → 0.12.47

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.
@@ -440,7 +440,12 @@ function checkoutTaskBranchFromStaging(cwd, branchName, { createIfMissing = true
440
440
  function checkoutNewTaskBranchWithChanges(cwd, branchName, { pushIfCreated = false } = {}) {
441
441
  const repoDir = repoRoot(cwd);
442
442
  if (currentBranch(repoDir) !== STAGING_BRANCH) {
443
- throw new Error(`Dirty change adoption requires ${repoDir} to be on ${STAGING_BRANCH}.`);
443
+ const stagingHead = remoteBranchExists(repoDir, STAGING_BRANCH) ? remoteHeadCommit(repoDir, STAGING_BRANCH) : null;
444
+ const canNormalizeStagingCheckout = gitStatusPorcelain(repoDir).length === 0 && stagingHead !== null && headCommit(repoDir) === stagingHead;
445
+ if (!canNormalizeStagingCheckout) {
446
+ throw new Error(`Dirty change adoption requires ${repoDir} to be on ${STAGING_BRANCH}.`);
447
+ }
448
+ syncBranchWithOrigin(repoDir, STAGING_BRANCH);
444
449
  }
445
450
  if (branchExists(repoDir, branchName) || remoteBranchExists(repoDir, branchName)) {
446
451
  throw new Error(`Dirty change adoption requires a new branch; ${branchName} already exists.`);
@@ -743,7 +743,7 @@ function syncDirectGitDependencyLockfileEntries(node, options, references) {
743
743
  if (!dependencies || typeof dependencies !== "object" || Array.isArray(dependencies)) continue;
744
744
  const dependencyMap = dependencies;
745
745
  const current = dependencyMap[reference.packageName];
746
- if (typeof current === "string" && /(?:git|github:|#[0-9a-f]{7,40}$)/iu.test(current) && current !== manifestSpec) {
746
+ if (typeof current === "string" && current !== manifestSpec) {
747
747
  dependencyMap[reference.packageName] = manifestSpec;
748
748
  changed = true;
749
749
  }
@@ -8,30 +8,17 @@ export declare function runReleaseVerifyCommand(input: {
8
8
  ok: boolean;
9
9
  skipped: boolean;
10
10
  reason: string;
11
- status?: undefined;
12
- signal?: undefined;
13
- command?: undefined;
14
11
  dependencies?: undefined;
15
- stdout?: undefined;
16
- stderr?: undefined;
17
12
  } | {
18
13
  ok: boolean;
19
- status: number | null;
20
- signal: NodeJS.Signals | null;
21
- command: import("../../index.js").TreeseedPackageCommand;
14
+ skipped: boolean;
15
+ reason: string;
22
16
  dependencies: {
23
- status: "not-applicable";
24
- } | {
25
- status: "ready";
26
- } | {
27
- status: "restored";
28
- } | {
29
- status: "workspace-linked";
17
+ status: "staging-proof-reused";
18
+ candidatePath: string;
19
+ packageCommit: string;
20
+ rootCommit: string;
30
21
  };
31
- stdout: string;
32
- stderr: string;
33
- skipped?: undefined;
34
- reason?: undefined;
35
22
  }>;
36
23
  export declare function runTemplateReleaseVerifyCommand(input: {
37
24
  tenantRoot: string;
@@ -1,42 +1,27 @@
1
- import { spawn, spawnSync } from "node:child_process";
2
- import { existsSync, mkdirSync, writeFileSync } from "node:fs";
1
+ import { spawnSync } from "node:child_process";
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
3
  import { dirname, resolve } from "node:path";
4
4
  import { findTreeseedPackageAdapter } from "../../operations/services/package-adapters.js";
5
5
  import { checkedOutTemplateRepositories } from "../../operations/services/managed-repositories.js";
6
6
  import { runTreeseedGitText } from "../../operations/services/git-runner.js";
7
- import { ensureLocalWorkspaceLinks } from "../../operations/services/workspace-dependency-mode.js";
8
- function ensureReleaseVerifyDependencies(input) {
9
- if (!existsSync(resolve(input.packageDir, "package.json")) || !existsSync(resolve(input.packageDir, "package-lock.json"))) {
10
- return { status: "not-applicable" };
7
+ function requireMatchingStageCandidate(tenantRoot, packageId, packageDir) {
8
+ const candidatePath = resolve(tenantRoot, ".treeseed/workflow/stage-candidates/latest.json");
9
+ if (!existsSync(candidatePath)) {
10
+ throw new Error(`Release verification requires a successful staged candidate; ${candidatePath} is missing.`);
11
11
  }
12
- const env = { ...process.env, ...input.env ?? {} };
13
- const inspection = spawnSync("npm", ["ls", "--depth=0", "--workspaces=false"], {
14
- cwd: input.packageDir,
15
- env,
16
- encoding: "utf8"
17
- });
18
- if (inspection.status === 0) return { status: "ready" };
19
- input.onProgress?.("Package dependencies are incomplete; restoring the standalone lockfile installation.");
20
- const install = spawnSync("npm", [
21
- "ci",
22
- "--ignore-scripts",
23
- "--workspaces=false",
24
- "--no-audit",
25
- "--no-fund"
26
- ], {
27
- cwd: input.packageDir,
28
- env,
29
- encoding: "utf8"
30
- });
31
- if (install.status !== 0) {
32
- throw new Error([
33
- "Standalone package dependency hydration failed before release verification.",
34
- install.stderr,
35
- install.stdout
36
- ].filter(Boolean).join("\n").trim());
12
+ const candidate = JSON.parse(readFileSync(candidatePath, "utf8"));
13
+ const packageProof = candidate.packages?.find((entry) => entry.name === packageId);
14
+ const packageHead = runTreeseedGitText(["rev-parse", "HEAD"], { cwd: packageDir, mode: "read" }).trim();
15
+ const rootHead = runTreeseedGitText(["rev-parse", "HEAD"], { cwd: tenantRoot, mode: "read" }).trim();
16
+ if (candidate.targetBranch !== "staging" || candidate.root?.verified !== true || candidate.root.commit !== rootHead || packageProof?.verified !== true || packageProof.commit !== packageHead) {
17
+ throw new Error(`Release verification requires ${packageId} and the Market root to match the latest verified staging candidate.`);
37
18
  }
38
- ensureLocalWorkspaceLinks(input.tenantRoot, { env: input.env });
39
- return { status: "restored" };
19
+ return {
20
+ status: "staging-proof-reused",
21
+ candidatePath,
22
+ packageCommit: packageHead,
23
+ rootCommit: rootHead
24
+ };
40
25
  }
41
26
  async function runReleaseVerifyCommand(input) {
42
27
  const adapter = findTreeseedPackageAdapter(input.tenantRoot, input.packageId);
@@ -51,54 +36,13 @@ async function runReleaseVerifyCommand(input) {
51
36
  reason: `${input.packageId} has no release verify command.`
52
37
  };
53
38
  }
54
- const dependencies = adapter.capabilities.localOnly ? (() => {
55
- ensureLocalWorkspaceLinks(input.tenantRoot, { env: input.env });
56
- return { status: "workspace-linked" };
57
- })() : ensureReleaseVerifyDependencies({
58
- tenantRoot: input.tenantRoot,
59
- packageDir: adapter.dir,
60
- env: input.env,
61
- onProgress: input.onProgress
62
- });
63
- const renderedCommand = [command.command, ...command.args].join(" ");
64
- input.onProgress?.(`Running ${input.packageId} release verification: ${renderedCommand}`);
65
- const started = Date.now();
66
- let stdout = "";
67
- let stderr = "";
68
- const result = await new Promise((resolve2, reject) => {
69
- const child = spawn(command.command, command.args, {
70
- cwd: command.cwd,
71
- env: { ...process.env, ...input.env ?? {} },
72
- stdio: ["ignore", "pipe", "pipe"]
73
- });
74
- const heartbeat = setInterval(() => {
75
- input.onProgress?.(`Still running ${input.packageId} release verification after ${Math.round((Date.now() - started) / 1e3)}s.`);
76
- }, 3e4);
77
- child.stdout?.on("data", (chunk) => {
78
- stdout += String(chunk);
79
- });
80
- child.stderr?.on("data", (chunk) => {
81
- stderr += String(chunk);
82
- });
83
- child.on("error", (error) => {
84
- clearInterval(heartbeat);
85
- reject(error);
86
- });
87
- child.on("close", (status, signal) => {
88
- clearInterval(heartbeat);
89
- resolve2({ status, signal });
90
- });
91
- });
92
- const elapsedSeconds = Math.round((Date.now() - started) / 1e3);
93
- input.onProgress?.(`${input.packageId} release verification ${result.status === 0 ? "passed" : "failed"} in ${elapsedSeconds}s.`);
39
+ const stagingProof = requireMatchingStageCandidate(input.tenantRoot, input.packageId, adapter.dir);
40
+ input.onProgress?.(`Reusing exact-SHA staging verification for ${input.packageId} at ${stagingProof.packageCommit.slice(0, 12)}.`);
94
41
  return {
95
- ok: (result.status ?? 1) === 0,
96
- status: result.status,
97
- signal: result.signal,
98
- command,
99
- dependencies,
100
- stdout,
101
- stderr
42
+ ok: true,
43
+ skipped: true,
44
+ reason: `${input.packageId} matches the latest verified staging candidate; tag workflows perform independent release verification before publication or deployment.`,
45
+ dependencies: stagingProof
102
46
  };
103
47
  }
104
48
  function runTemplateCommand(command, cwd, env) {
@@ -2133,8 +2133,12 @@ function productionPackageDeployGates(root, versions) {
2133
2133
  function prepareAdapterReleaseMetadata(root, pkg, version) {
2134
2134
  const adapter = discoverTreeseedPackageAdapters(root).find((entry) => entry.id === pkg.name || entry.name === pkg.name);
2135
2135
  if (adapter?.kind === "beam-elixir-rust" && existsSync(resolve(pkg.dir, "scripts", "bump-release-version.ts"))) {
2136
- run("tsx", ["scripts/bump-release-version.ts", version], { cwd: pkg.dir });
2137
- return { status: "updated", adapter: adapter.id, command: "tsx scripts/bump-release-version.ts" };
2136
+ const tsx = resolve(root, "node_modules/.bin/tsx");
2137
+ if (!existsSync(tsx)) {
2138
+ throw new Error(`TreeSeed release requires the workspace tsx executable at ${tsx}. Run trsd install and restore workspace dependencies before retrying.`);
2139
+ }
2140
+ run(tsx, ["scripts/bump-release-version.ts", version], { cwd: pkg.dir });
2141
+ return { status: "updated", adapter: adapter.id, command: `${tsx} scripts/bump-release-version.ts` };
2138
2142
  }
2139
2143
  if (existsSync(resolve(pkg.dir, "package.json"))) {
2140
2144
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@treeseed/sdk",
3
- "version": "0.12.46",
3
+ "version": "0.12.47",
4
4
  "description": "Shared Treeseed SDK for content-backed and D1-backed object models.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {