@treeseed/sdk 0.3.2 → 0.3.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.
@@ -124,6 +124,8 @@ try {
124
124
  type: 'module',
125
125
  scripts: {
126
126
  'verify:direct': 'node --input-type=module -e "console.log(\'treeseed-sdk-smoke-verify\')"',
127
+ 'verify:local': 'node --input-type=module -e "process.env.TREESEED_VERIFY_DRIVER=\'direct\'; console.log(\'treeseed-sdk-smoke-verify-local\')"',
128
+ 'verify:action': 'node --input-type=module -e "process.env.TREESEED_VERIFY_DRIVER=\'act\'; console.log(\'treeseed-sdk-smoke-verify-action\')"',
127
129
  },
128
130
  }, null, 2)}\n`, 'utf8');
129
131
  run(process.execPath, ['--input-type=module', '-e', 'await import("@treeseed/sdk/verification");'], installRoot);
@@ -4,6 +4,11 @@ export type TreeseedVerifyDriverOptions = {
4
4
  driver?: TreeseedVerifyDriver;
5
5
  eventName?: string;
6
6
  write?: (message: string, stream?: 'stdout' | 'stderr') => void;
7
+ runCommand?: (command: string, args: string[], cwd: string) => number;
8
+ checkCommand?: (command: string, args: string[], cwd: string) => {
9
+ ok: boolean;
10
+ detail: string;
11
+ };
7
12
  };
8
13
  export type TreeseedVerifyDriverStatus = {
9
14
  packageRoot: string;
@@ -15,6 +20,11 @@ export type TreeseedVerifyDriverStatus = {
15
20
  ghActAvailable: boolean;
16
21
  dockerAvailable: boolean;
17
22
  canUseAct: boolean;
23
+ workspaceRoot: string | null;
24
+ currentPackageName: string | null;
25
+ localTreeseedPackageNames: string[];
26
+ localTreeseedSiblingDependencies: string[];
27
+ prefersDirectForLocalWorkspace: boolean;
18
28
  };
19
29
  export declare function getTreeseedVerifyDriverStatus(options?: TreeseedVerifyDriverOptions): TreeseedVerifyDriverStatus;
20
30
  export declare function runTreeseedVerifyDriver(options?: TreeseedVerifyDriverOptions): number;
@@ -1,5 +1,5 @@
1
- import { existsSync } from "node:fs";
2
- import { spawnSync } from "node:child_process";
1
+ import { existsSync, readdirSync, readFileSync } from "node:fs";
2
+ import * as childProcess from "node:child_process";
3
3
  import { basename, resolve } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  function defaultWrite(message, stream = "stdout") {
@@ -8,7 +8,7 @@ function defaultWrite(message, stream = "stdout") {
8
8
  `);
9
9
  }
10
10
  function run(command, args, cwd) {
11
- const result = spawnSync(command, args, {
11
+ const result = childProcess.spawnSync(command, args, {
12
12
  cwd,
13
13
  env: process.env,
14
14
  stdio: "inherit"
@@ -16,7 +16,7 @@ function run(command, args, cwd) {
16
16
  return result.status ?? 1;
17
17
  }
18
18
  function check(command, args, cwd) {
19
- const result = spawnSync(command, args, {
19
+ const result = childProcess.spawnSync(command, args, {
20
20
  cwd,
21
21
  env: process.env,
22
22
  stdio: "pipe",
@@ -28,6 +28,76 @@ function check(command, args, cwd) {
28
28
  ${result.stdout ?? ""}`.trim()
29
29
  };
30
30
  }
31
+ function readPackageManifest(packageJsonPath) {
32
+ if (!existsSync(packageJsonPath)) {
33
+ return null;
34
+ }
35
+ try {
36
+ return JSON.parse(readFileSync(packageJsonPath, "utf8"));
37
+ } catch {
38
+ return null;
39
+ }
40
+ }
41
+ function findWorkspaceRoot(packageRoot) {
42
+ let current = packageRoot;
43
+ while (true) {
44
+ const packagesRoot = resolve(current, "packages");
45
+ if (existsSync(packagesRoot)) {
46
+ const packageDirs = readdirSync(packagesRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => resolve(packagesRoot, entry.name)).filter((dirPath) => existsSync(resolve(dirPath, "package.json")));
47
+ if (packageDirs.length > 0) {
48
+ return {
49
+ workspaceRoot: current,
50
+ packageDirs
51
+ };
52
+ }
53
+ }
54
+ const parent = resolve(current, "..");
55
+ if (parent === current) {
56
+ return null;
57
+ }
58
+ current = parent;
59
+ }
60
+ }
61
+ function resolveLocalWorkspaceContext(packageRoot) {
62
+ const currentManifest = readPackageManifest(resolve(packageRoot, "package.json"));
63
+ const currentPackageName = typeof currentManifest?.name === "string" ? currentManifest.name : null;
64
+ const workspace = findWorkspaceRoot(packageRoot);
65
+ if (!workspace) {
66
+ return {
67
+ workspaceRoot: null,
68
+ currentPackageName,
69
+ localTreeseedPackageNames: [],
70
+ localTreeseedSiblingDependencies: []
71
+ };
72
+ }
73
+ const localPackages = workspace.packageDirs.map((dirPath) => ({
74
+ dirPath,
75
+ manifest: readPackageManifest(resolve(dirPath, "package.json"))
76
+ })).filter((entry) => Boolean(entry.manifest?.name));
77
+ const currentPackage = localPackages.find((entry) => entry.dirPath === packageRoot);
78
+ if (!currentPackage) {
79
+ return {
80
+ workspaceRoot: null,
81
+ currentPackageName,
82
+ localTreeseedPackageNames: [],
83
+ localTreeseedSiblingDependencies: []
84
+ };
85
+ }
86
+ const localTreeseedPackageNames = localPackages.map((entry) => entry.manifest.name).filter((name) => name.startsWith("@treeseed/")).sort();
87
+ const localTreeseedPackageSet = new Set(localTreeseedPackageNames);
88
+ const declaredDependencies = {
89
+ ...currentPackage.manifest.dependencies ?? {},
90
+ ...currentPackage.manifest.devDependencies ?? {},
91
+ ...currentPackage.manifest.peerDependencies ?? {}
92
+ };
93
+ const localTreeseedSiblingDependencies = Object.keys(declaredDependencies).filter((name) => name.startsWith("@treeseed/")).filter((name) => localTreeseedPackageSet.has(name)).sort();
94
+ return {
95
+ workspaceRoot: workspace.workspaceRoot,
96
+ currentPackageName: currentPackage.manifest.name ?? currentPackageName,
97
+ localTreeseedPackageNames,
98
+ localTreeseedSiblingDependencies
99
+ };
100
+ }
31
101
  function getTreeseedVerifyDriverStatus(options = {}) {
32
102
  const packageRoot = resolve(options.packageRoot ?? process.cwd());
33
103
  const workflowPath = resolve(packageRoot, ".github", "workflows", "verify.yml");
@@ -35,8 +105,11 @@ function getTreeseedVerifyDriverStatus(options = {}) {
35
105
  const eventName = options.eventName ?? process.env.TREESEED_VERIFY_EVENT ?? "workflow_dispatch";
36
106
  const inGitHubActions = process.env.GITHUB_ACTIONS === "true";
37
107
  const workflowPresent = existsSync(workflowPath);
38
- const ghAct = check("gh", ["act", "--version"], packageRoot);
39
- const docker = check("docker", ["info"], packageRoot);
108
+ const workspace = resolveLocalWorkspaceContext(packageRoot);
109
+ const checkCommand = options.checkCommand ?? check;
110
+ const ghAct = checkCommand("gh", ["act", "--version"], packageRoot);
111
+ const docker = checkCommand("docker", ["info"], packageRoot);
112
+ const prefersDirectForLocalWorkspace = !inGitHubActions && driver === "auto" && workspace.localTreeseedSiblingDependencies.length > 0;
40
113
  return {
41
114
  packageRoot,
42
115
  workflowPath,
@@ -46,14 +119,21 @@ function getTreeseedVerifyDriverStatus(options = {}) {
46
119
  workflowPresent,
47
120
  ghActAvailable: ghAct.ok,
48
121
  dockerAvailable: docker.ok,
49
- canUseAct: workflowPresent && ghAct.ok && docker.ok
122
+ canUseAct: workflowPresent && ghAct.ok && docker.ok,
123
+ workspaceRoot: workspace.workspaceRoot,
124
+ currentPackageName: workspace.currentPackageName,
125
+ localTreeseedPackageNames: workspace.localTreeseedPackageNames,
126
+ localTreeseedSiblingDependencies: workspace.localTreeseedSiblingDependencies,
127
+ prefersDirectForLocalWorkspace
50
128
  };
51
129
  }
52
130
  function runTreeseedVerifyDriver(options = {}) {
53
131
  const write = options.write ?? defaultWrite;
54
132
  const status = getTreeseedVerifyDriverStatus(options);
133
+ const runCommand = options.runCommand ?? run;
134
+ const checkCommand = options.checkCommand ?? check;
55
135
  if (status.driver === "direct" || status.inGitHubActions) {
56
- return run("npm", ["run", "verify:direct"], status.packageRoot);
136
+ return runCommand("npm", ["run", "verify:direct"], status.packageRoot);
57
137
  }
58
138
  if (status.driver === "act") {
59
139
  if (!status.workflowPresent) {
@@ -61,19 +141,22 @@ function runTreeseedVerifyDriver(options = {}) {
61
141
  return 1;
62
142
  }
63
143
  if (!status.ghActAvailable) {
64
- const detail = check("gh", ["act", "--version"], status.packageRoot).detail;
144
+ const detail = checkCommand("gh", ["act", "--version"], status.packageRoot).detail;
65
145
  write(detail || "Treeseed verify requires `gh act` when TREESEED_VERIFY_DRIVER=act.", "stderr");
66
146
  return 1;
67
147
  }
68
148
  if (!status.dockerAvailable) {
69
- const detail = check("docker", ["info"], status.packageRoot).detail;
149
+ const detail = checkCommand("docker", ["info"], status.packageRoot).detail;
70
150
  write(detail || "Treeseed verify requires a running Docker daemon when TREESEED_VERIFY_DRIVER=act.", "stderr");
71
151
  return 1;
72
152
  }
73
- return run("gh", ["act", status.eventName, "-W", ".github/workflows/verify.yml", "-j", "verify"], status.packageRoot);
153
+ return runCommand("gh", ["act", status.eventName, "-W", ".github/workflows/verify.yml", "-j", "verify"], status.packageRoot);
154
+ }
155
+ if (status.prefersDirectForLocalWorkspace) {
156
+ return runCommand("npm", ["run", "verify:direct"], status.packageRoot);
74
157
  }
75
158
  if (status.canUseAct) {
76
- return run("gh", ["act", status.eventName, "-W", ".github/workflows/verify.yml", "-j", "verify"], status.packageRoot);
159
+ return runCommand("gh", ["act", status.eventName, "-W", ".github/workflows/verify.yml", "-j", "verify"], status.packageRoot);
77
160
  }
78
161
  if (!status.workflowPresent) {
79
162
  write("Treeseed verify warning: package-local verify workflow is missing; falling back to verify:direct.", "stderr");
@@ -82,7 +165,7 @@ function runTreeseedVerifyDriver(options = {}) {
82
165
  } else if (!status.dockerAvailable) {
83
166
  write("Treeseed verify warning: Docker is unavailable; falling back to verify:direct.", "stderr");
84
167
  }
85
- return run("npm", ["run", "verify:direct"], status.packageRoot);
168
+ return runCommand("npm", ["run", "verify:direct"], status.packageRoot);
86
169
  }
87
170
  const invokedPath = process.argv[1] ? resolve(process.argv[1]) : "";
88
171
  const invokedBasename = basename(invokedPath);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@treeseed/sdk",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "Shared Treeseed SDK for content-backed and D1-backed object models.",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {
@@ -41,6 +41,8 @@
41
41
  "fixtures:check": "node ./scripts/run-ts.mjs ./scripts/fixture-tools.ts check",
42
42
  "lint": "npm run fixtures:check && npm run build:dist",
43
43
  "verify:direct": "npm run release:verify",
44
+ "verify:local": "node --input-type=module -e \"process.env.TREESEED_VERIFY_DRIVER='direct'; await import('@treeseed/sdk/scripts/verify-driver')\"",
45
+ "verify:action": "node --input-type=module -e \"process.env.TREESEED_VERIFY_DRIVER='act'; await import('@treeseed/sdk/scripts/verify-driver')\"",
44
46
  "verify": "node ./scripts/verify-driver.mjs",
45
47
  "release:setup": "npm run setup:ci",
46
48
  "release:check-tag": "node ./scripts/run-ts.mjs ./scripts/assert-release-tag-version.ts",