@rightkit/release 0.2.154 → 0.2.155

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.
@@ -86,7 +86,9 @@ if (first === "--version" || first === "-v") {
86
86
  run("apple-profile-renew.mjs", args.slice(1));
87
87
  } else if (first === "publish") {
88
88
  const rest = args.slice(1);
89
- if (rest[0] === "cargo") {
89
+ if ((rest[0] === "cargo" || rest[0] === "npm") && rest.includes("--local")) {
90
+ run("local-publish.mjs", rest);
91
+ } else if (rest[0] === "cargo") {
90
92
  run("publish-cargo.mjs", rest.slice(1));
91
93
  } else if (rest[0] === "npm") {
92
94
  run("publication-gate.mjs", rest.slice(1));
@@ -202,6 +204,9 @@ Commands:
202
204
  Publish the gated tarball with the Keychain token
203
205
  (npm-rightkit-publish) and verify registry bytes
204
206
  publish cargo --crate <name> [--dry-run] Test, inspect, scan, and publish one crates.io package
207
+ publish npm --package @rightkit/<name> --local Mac-only local publish under the committed local-build grant
208
+ publish cargo --crate <name> --local (.rightkit-local-build.json): runs the unit's CI tests, packs, writes darwin-only
209
+ evidence, then the same publication gate and publisher; refuses without the grant
205
210
  publish swift [--dry-run] [--evidence <file>] [--workspace <dir>]
206
211
  Check main, a clean tree, and the publication evidence, then tag RightKitSwift at its VERSION on origin
207
212
  inventory check [--json] [--warn-only] [--md <file>] [--no-cache]
package/deps.mjs CHANGED
File without changes
@@ -41,7 +41,7 @@ export const LOCAL_BUILD_FILE = ".rightkit-local-build.json";
41
41
 
42
42
  // Adrian's local-build opt-in (2026-10-14): a committed .rightkit-local-build.json naming this exact
43
43
  // repository allows local build, test and publish. Mirrors the build-control hook's check.
44
- function localBuildGranted(root) {
44
+ export function localBuildGranted(root) {
45
45
  if (!root) return false;
46
46
  try {
47
47
  const grant = JSON.parse(readFileSync(path.join(root, LOCAL_BUILD_FILE), "utf8"));
@@ -0,0 +1,246 @@
1
+ #!/usr/bin/env node
2
+ // `right-release publish npm|cargo ... --local`: publish ONE @rightkit npm package or crate from the Mac under
3
+ // Adrian's local-build grant (2026-10-14, committed .rightkit-local-build.json). It does not weaken the
4
+ // publication gate: it runs the unit's own CI tests (ci/gate.config.json, ci/asset-gated.json,
5
+ // scripts/ci/gate.mjs semantics), packs the artifact, writes a schema-1 evidence file with one darwin receipt
6
+ // (hostPolicy "darwin-only"), then calls the EXISTING enforcePublicationGate and the EXISTING publisher
7
+ // (publishGatedTarball for npm, runCargoPublish for cargo). There is no way to skip a test or the evidence.
8
+ import crypto from "node:crypto";
9
+ import fs from "node:fs";
10
+ import os from "node:os";
11
+ import path from "node:path";
12
+ import { fileURLToPath, pathToFileURL } from "node:url";
13
+ import { spawnSync } from "./background-process.mjs";
14
+ import { runCargoSync } from "./managed-cargo.mjs";
15
+ import { localBuildGranted, LOCAL_BUILD_FILE } from "./execution-policy.mjs";
16
+ import { GATE_SCHEMA, defaultEvidencePath, enforcePublicationGate, publishGatedTarball } from "./publication-gate.mjs";
17
+ import { runCargoPublish } from "./publish-cargo.mjs";
18
+ import { cargoIndexUrl } from "./cargo-registry-readback.mjs";
19
+ import { readCargoPackage } from "./crate-graph.mjs";
20
+ import { recordPublished } from "./rightkit-sync.mjs";
21
+
22
+ export const LOCAL_OPERATOR = "agent (local-build grant)";
23
+ export const LOCAL_HOST_POLICY_REASON = "Adrian 2026-10-14 local-build grant (.rightkit-local-build.json); Windows covered by the next CI run";
24
+ const STEP_TIMEOUT_MS = 30 * 60 * 1000;
25
+
26
+ export class LocalPublishError extends Error {
27
+ constructor(message) { super(message); this.name = "LocalPublishError"; }
28
+ }
29
+ const refuse = (message) => { throw new LocalPublishError(message); };
30
+
31
+ export function parseLocalPublishArgs(kind, argv, cwd = process.cwd()) {
32
+ const flag = kind === "npm" ? "--package" : "--crate";
33
+ let unit; let workspace; let local = false;
34
+ for (let i = 0; i < argv.length; i += 1) {
35
+ const arg = argv[i];
36
+ if (arg === "--local") local = true;
37
+ else if (arg === flag) unit = argv[++i];
38
+ else if (arg === "--workspace") workspace = argv[++i];
39
+ else refuse(`unknown publish ${kind} --local option: ${arg} (accepted: ${flag} <name>, --workspace <dir>, --local)`);
40
+ }
41
+ if (!local) refuse("--local is required");
42
+ if (kind === "npm" && !/^@rightkit\/[a-z0-9-]+$/.test(unit ?? "")) refuse("publish npm --local requires --package @rightkit/<name>");
43
+ if (kind === "cargo" && !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(unit ?? "")) refuse("publish cargo --local requires --crate <name>");
44
+ return { kind, unit, workspaceRoot: path.resolve(workspace ?? cwd) };
45
+ }
46
+
47
+ function defaultGit(args, cwd) {
48
+ const result = spawnSync("git", args, { cwd, encoding: "utf8", windowsHide: true });
49
+ if (result.error || result.status !== 0) return null;
50
+ return (result.stdout ?? "").trim();
51
+ }
52
+
53
+ const defaultReadJson = (file) => { try { return JSON.parse(fs.readFileSync(file, "utf8")); } catch { return null; } };
54
+
55
+ async function defaultRegistryHas({ kind, name, version }) {
56
+ if (kind === "npm") {
57
+ const view = spawnSync("npm", ["view", `${name}@${version}`, "version", "--prefer-online", "--registry", "https://registry.npmjs.org/"], { encoding: "utf8", windowsHide: true });
58
+ const out = `${view.stdout ?? ""}${view.stderr ?? ""}`;
59
+ if (!view.error && view.status === 0) return (view.stdout ?? "").trim() === version;
60
+ if (/E404|404 Not Found/i.test(out)) return false;
61
+ throw new Error(`cannot read the npm registry for ${name}@${version}: ${out.trim().slice(0, 200)}`);
62
+ }
63
+ const response = await fetch(cargoIndexUrl(name), { headers: { Accept: "text/plain", "Cache-Control": "no-cache", "User-Agent": "rightkit-release" }, redirect: "error", signal: AbortSignal.timeout(30_000) });
64
+ if (response.status === 404) return false;
65
+ if (!response.ok) throw new Error(`crates.io index answered ${response.status} for ${name}`);
66
+ return (await response.text()).split(/\r?\n/).filter((line) => line.trim()).some((line) => { try { return JSON.parse(line).vers === version; } catch { return false; } });
67
+ }
68
+
69
+ function defaultRun(command, args, options) {
70
+ const settings = { encoding: "utf8", maxBuffer: 512 * 1024 * 1024, timeout: STEP_TIMEOUT_MS, windowsHide: true, ...options };
71
+ return command === "cargo" ? runCargoSync(args, settings) : spawnSync(command, args, settings);
72
+ }
73
+
74
+ async function defaultLoadWorkspaceModules(workspaceRoot) {
75
+ const load = (file) => import(pathToFileURL(path.join(workspaceRoot, "scripts", "ci", file)).href);
76
+ const [results, upload] = await Promise.all([load("test-results.mjs"), load("upload.mjs")]);
77
+ return { results, checkNpmTarball: upload.checkNpmTarball };
78
+ }
79
+
80
+ /** The CI gate's commands for one unit (scripts/ci/gate.mjs npmGate/rustGate), mirrored exactly. */
81
+ export function localTestPlan({ kind, unit, dir, config, manifest }) {
82
+ if (kind === "npm") {
83
+ if (!manifest?.scripts?.test) refuse(`${unit} has no test script; --local never publishes an untested package`);
84
+ return {
85
+ id: `npm:${dir}`, featureLabels: ["default"],
86
+ steps: [
87
+ { command: "pnpm", args: ["-r", "--workspace-concurrency=1", "run", "build"], test: false },
88
+ { command: "pnpm", args: ["--dir", dir, "run", "test"], test: true },
89
+ ],
90
+ };
91
+ }
92
+ const entry = config?.rust?.[unit] ?? {};
93
+ if (entry.os && !entry.os.includes("macos")) refuse(`${unit} is restricted to ${entry.os.join(", ")} by ci/gate.config.json; it cannot be qualified on this Mac`);
94
+ const featureSets = entry.featureSets ?? [[]];
95
+ const steps = [];
96
+ for (const features of featureSets) {
97
+ steps.push({ command: "cargo", args: ["test", "-p", unit, ...features, "--no-fail-fast", "--", "--show-output"], test: true });
98
+ if (entry.alsoSerial) steps.push({ command: "cargo", args: ["test", "-p", unit, ...features, "--no-fail-fast", "--", "--test-threads=1", "--show-output"], test: true });
99
+ }
100
+ steps.push({ command: "cargo", args: ["clippy", "-p", unit, "--no-deps", "--all-targets", ...featureSets[0], "--", "-D", "warnings"], test: false });
101
+ return { id: `rust:${unit}`, featureLabels: featureSets.map((features) => features.join(" ") || "default"), steps };
102
+ }
103
+
104
+ const sha256 = (bytes) => crypto.createHash("sha256").update(bytes).digest("hex");
105
+ const tarballName = (name, version) => `${name.replace(/^@/, "").replace("/", "-")}-${version}.tgz`;
106
+ const tail = (text, lines = 40) => String(text ?? "").split(/\r?\n/).slice(-lines).join("\n");
107
+
108
+ export async function runLocalPublish(kind, argv, deps = {}) {
109
+ const log = deps.log ?? ((line) => process.stdout.write(`${line}\n`));
110
+ const { unit, workspaceRoot } = parseLocalPublishArgs(kind, argv, deps.cwd);
111
+ const platform = deps.platform ?? process.platform;
112
+ const git = deps.git ?? defaultGit;
113
+ const readJson = deps.readJson ?? defaultReadJson;
114
+ const run = deps.run ?? defaultRun;
115
+
116
+ // 1. Preconditions, fail closed.
117
+ if (!(deps.localBuildGranted ?? localBuildGranted)(workspaceRoot)) refuse(`--local needs the local-build grant: a committed ${LOCAL_BUILD_FILE} (allow "build-test-publish") naming this repository at ${workspaceRoot}`);
118
+ if (platform !== "darwin") refuse(`--local publishes from the Mac only (host policy: darwin-only); this host is ${platform}`);
119
+ const dir = kind === "npm" ? `packages/${unit.slice("@rightkit/".length)}` : `crates/${unit}`;
120
+ const unitPath = path.join(workspaceRoot, dir);
121
+ if (!fs.existsSync(unitPath)) refuse(`unit directory not found: ${unitPath}`);
122
+ let manifest = null; let version;
123
+ if (kind === "npm") {
124
+ manifest = readJson(path.join(unitPath, "package.json")) ?? refuse(`cannot read ${dir}/package.json`);
125
+ if (manifest.name !== unit) refuse(`${dir}/package.json is ${manifest.name}, not ${unit}`);
126
+ if (manifest.private === true) refuse(`${unit} is private and is never published`);
127
+ version = manifest.version;
128
+ } else {
129
+ const pkg = (deps.readCargoPackage ?? readCargoPackage)(unitPath);
130
+ if (pkg.name !== unit) refuse(`Cargo.toml [package].name ${JSON.stringify(pkg.name)} differs from --crate ${unit}`);
131
+ version = pkg.version;
132
+ }
133
+ if (typeof version !== "string" || !version.trim()) refuse(`${unit} has no literal version`);
134
+ const head = git(["rev-parse", "HEAD"], workspaceRoot);
135
+ if (!head || !/^[0-9a-f]{40}$/.test(head)) refuse("cannot resolve HEAD");
136
+ const dirty = git(["status", "--porcelain", "--", dir], workspaceRoot);
137
+ if (dirty === null) refuse(`cannot read git status for ${dir}`);
138
+ if (dirty !== "") refuse(`tree is not clean for ${dir}; commit first:\n${dirty}`);
139
+ if (await (deps.registryHas ?? defaultRegistryHas)({ kind, name: unit, version })) refuse(`${unit}@${version} is already on the ${kind === "npm" ? "npm" : "crates.io"} registry; bump the version`);
140
+ log(`[right-release] local publish ${kind}:${unit}@${version} at ${head.slice(0, 12)} (local-build grant, darwin-only policy)`);
141
+
142
+ // 2. The unit's own tests, exactly as the CI gate defines them.
143
+ const gateConfig = readJson(path.join(workspaceRoot, "ci", "gate.config.json")) ?? {};
144
+ const assetGated = readJson(path.join(workspaceRoot, "ci", "asset-gated.json")) ?? {};
145
+ const gatedSection = assetGated[kind === "npm" ? "npm" : "crates"] ?? {};
146
+ const isAssetGated = Object.hasOwn(gatedSection, unit);
147
+ const plan = localTestPlan({ kind, unit, dir, config: gateConfig, manifest });
148
+ const modules = await (deps.loadWorkspaceModules ?? defaultLoadWorkspaceModules)(workspaceRoot);
149
+ const { ResultScanner, TEST_COMMAND, judgeUnit } = modules.results;
150
+ // Run the unit's tests under hosted-CI conditions: no inherited credentials (a managed host refuses a
151
+ // token from the environment) and no sibling product checkouts (CI holds rightkit alone).
152
+ const inherited = Object.fromEntries(Object.entries(deps.env ?? process.env).filter(([key]) => !/(TOKEN|SECRET|PASSWORD|API_KEY|PRIVATE_KEY)/i.test(key)));
153
+ const env = { ...inherited, RIGHTKIT_REQUIRE_ASSETS: isAssetGated ? "0" : "1", RIGHTKIT_ISOLATED_CHECKOUT: "1", CARGO_TERM_COLOR: "never" };
154
+ const steps = [];
155
+ for (const step of plan.steps) {
156
+ const commandText = `${step.command} ${step.args.join(" ")}`;
157
+ log(`[right-release] ${plan.id}: ${commandText}`);
158
+ const result = run(step.command, step.args, { cwd: workspaceRoot, env });
159
+ const row = { command: commandText, ok: false, isTest: step.test && TEST_COMMAND.test(commandText) };
160
+ if (result.error || result.status !== 0) {
161
+ steps.push(row);
162
+ refuse(`${plan.id} step failed (${result.error?.message ?? `exit ${result.status}`}): ${commandText}\n${tail(`${result.stdout ?? ""}\n${result.stderr ?? ""}`)}`);
163
+ }
164
+ row.ok = true;
165
+ if (row.isTest) {
166
+ const out = new ResultScanner(); const err = new ResultScanner();
167
+ out.push(result.stdout ?? ""); err.push(result.stderr ?? "");
168
+ const a = out.finish(); const b = err.finish();
169
+ Object.assign(row, { executed: a.executed + b.executed, failed: a.failed + b.failed, ignored: a.ignored + b.ignored, skipped: a.skipped + b.skipped, binaries: a.binaries + b.binaries });
170
+ }
171
+ steps.push(row);
172
+ }
173
+ const verdict = judgeUnit({ name: unit, steps: steps.map((s) => ({ ...s, unit: plan.id })), allowIgnored: [], allowMissingAssets: isAssetGated ? [unit] : [] });
174
+ if (verdict.status === "fail" || steps.some((s) => s.failed > 0)) refuse(`${plan.id} not qualified: ${verdict.problems.join("; ") || "failed tests reported"}`);
175
+ if (!(verdict.executed > 0)) refuse(`${plan.id} executed no test`);
176
+ log(`[right-release] ${plan.id}: ${verdict.executed} passed, 0 failed, ${verdict.skipped} skipped, ${verdict.ignored} ignored${isAssetGated ? " (asset-gated: RIGHTKIT_REQUIRE_ASSETS=0, skips recorded)" : ""}`);
177
+
178
+ // 3. Pack the artifact and hash it.
179
+ const scratch = fs.mkdtempSync(path.join(deps.tmpdir ?? os.tmpdir(), "rk-local-publish-"));
180
+ const cleanup = () => fs.rmSync(scratch, { recursive: true, force: true });
181
+ try {
182
+ let artifactFile; const packCommands = [];
183
+ if (kind === "npm") {
184
+ const args = ["--dir", dir, "pack", "--pack-destination", scratch];
185
+ packCommands.push(`pnpm ${args.join(" ")}`);
186
+ const packed = run("pnpm", args, { cwd: workspaceRoot, env });
187
+ if (packed.error || packed.status !== 0) refuse(`pnpm pack failed for ${unit}\n${tail(`${packed.stdout ?? ""}\n${packed.stderr ?? ""}`)}`);
188
+ artifactFile = path.join(scratch, tarballName(unit, version));
189
+ if (!fs.existsSync(artifactFile)) refuse(`pnpm pack did not produce ${path.basename(artifactFile)}`);
190
+ const checked = modules.checkNpmTarball({ file: artifactFile, name: unit, version, dir, spawn: deps.spawnSync ?? spawnSync });
191
+ if (checked.problems.length) refuse(`${unit}: packed tarball refused:\n - ${checked.problems.join("\n - ")}`);
192
+ } else {
193
+ packCommands.push(`cargo package --locked -p ${unit}`);
194
+ const packed = run("cargo", ["package", "--locked", "-p", unit], { cwd: workspaceRoot, env });
195
+ if (packed.error || packed.status !== 0) refuse(`cargo package failed for ${unit}\n${tail(`${packed.stdout ?? ""}\n${packed.stderr ?? ""}`)}`);
196
+ packCommands.push("cargo metadata --format-version 1 --no-deps");
197
+ const meta = run("cargo", ["metadata", "--format-version", "1", "--no-deps"], { cwd: workspaceRoot, env });
198
+ let targetDir;
199
+ try { targetDir = JSON.parse(meta.stdout).target_directory; } catch { /* refused below */ }
200
+ if (meta.status !== 0 || typeof targetDir !== "string" || !path.isAbsolute(targetDir)) refuse("cannot read the Cargo target directory");
201
+ artifactFile = path.join(targetDir, "package", `${unit}-${version}.crate`);
202
+ if (!fs.existsSync(artifactFile)) refuse(`cargo package did not produce ${artifactFile}`);
203
+ }
204
+ const artifactSha256 = sha256(fs.readFileSync(artifactFile));
205
+
206
+ // 4. Evidence in the normal schema, then the EXISTING gate.
207
+ const commands = [...plan.steps.map((s) => `${s.command} ${s.args.join(" ")}`), ...packCommands];
208
+ const timestamp = (deps.now ?? (() => new Date().toISOString()))();
209
+ const evidence = {
210
+ schema: GATE_SCHEMA, kind, name: unit, version, commit: head, artifactSha256,
211
+ hostPolicy: "darwin-only", hostPolicyReason: LOCAL_HOST_POLICY_REASON,
212
+ runs: [{
213
+ host: { os: "darwin", arch: deps.arch ?? process.arch }, commit: head, features: plan.featureLabels, artifactSha256,
214
+ command: commands.join(" && "), operator: LOCAL_OPERATOR, timestamp,
215
+ passed: verdict.executed, failed: 0, skipped: verdict.skipped, ignored: verdict.ignored,
216
+ requireAssets: env.RIGHTKIT_REQUIRE_ASSETS, assetGated: isAssetGated,
217
+ steps: steps.map(({ command, ok, executed, failed, ignored, skipped, binaries }) => ({ command, ok, ...(executed === undefined ? {} : { executed, failed, ignored, skipped, binaries }) })),
218
+ }],
219
+ };
220
+ const evidencePath = path.resolve(defaultEvidencePath(workspaceRoot, kind, unit));
221
+ fs.mkdirSync(path.dirname(evidencePath), { recursive: true });
222
+ fs.writeFileSync(evidencePath, `${JSON.stringify(evidence, null, 2)}\n`);
223
+ log(`[right-release] wrote ${evidencePath} (artifact sha256 ${artifactSha256})`);
224
+ const gateOptions = { kind, name: unit, version, packagePath: unitPath, evidencePath };
225
+ (deps.enforceGate ?? enforcePublicationGate)(gateOptions, { write: (line) => log(line.replace(/\n$/, "")) });
226
+
227
+ // 5. The EXISTING publish path.
228
+ if (kind === "npm") {
229
+ (deps.publishGatedTarball ?? publishGatedTarball)({ name: unit, version, tarball: artifactFile, evidencePath }, deps.publishDeps ?? {});
230
+ } else {
231
+ const published = await (deps.runCargoPublish ?? runCargoPublish)({ crate: unit, dryRun: false, allowDirty: false, workspaceRoot, evidence: evidencePath }, undefined, deps.cargoDeps ?? {});
232
+ (deps.recordPublished ?? recordPublished)({ registry: "cargo", name: published.name, version: published.version });
233
+ }
234
+ log(`[right-release] published ${unit}@${version}`);
235
+ return { kind, name: unit, version, commit: head, artifactSha256, evidencePath };
236
+ } finally {
237
+ cleanup();
238
+ }
239
+ }
240
+
241
+ const realOrSelf = (file) => { try { return fs.realpathSync(file); } catch { return path.resolve(file); } };
242
+ if (process.argv[1] && realOrSelf(process.argv[1]) === realOrSelf(fileURLToPath(import.meta.url))) {
243
+ const [kind, ...rest] = process.argv.slice(2);
244
+ if (kind !== "npm" && kind !== "cargo") { process.stderr.write("right-release publish --local: expected npm or cargo\n"); process.exitCode = 2; }
245
+ else runLocalPublish(kind, rest).catch((error) => { process.stderr.write(`right-release publish ${kind} --local: ${error.message}\n`); process.exitCode = 1; });
246
+ }
package/lsclean.sh CHANGED
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rightkit/release",
3
- "version": "0.2.154",
3
+ "version": "0.2.155",
4
4
  "description": "Portable release CLI/SDK with fail-closed public GitHub Releases and private R2 + RightApps distribution.",
5
5
  "license": "MIT OR Apache-2.0",
6
6
  "type": "module",
@@ -29,14 +29,6 @@
29
29
  "!standalone-clone-evidence.json"
30
30
  ],
31
31
  "sideEffects": false,
32
- "scripts": {
33
- "test": "node --test --test-concurrency=1 --test-force-exit *.test.mjs",
34
- "test:registry-parity": "node registry-parity.mjs --allow-unpublished",
35
- "test:signer:windows": "node sign-release-manifest.integration.mjs",
36
- "prepublishOnly": "pnpm test && pnpm test:signer:windows && pnpm test:registry-parity",
37
- "doctor:all": "node --test right-suite-contract.test.mjs",
38
- "verify:standalone": "node standalone-clone-verify.mjs"
39
- },
40
32
  "publishConfig": {
41
33
  "registry": "https://registry.npmjs.org/",
42
34
  "access": "public"
@@ -46,8 +38,14 @@
46
38
  "url": "git+https://github.com/Orthic-Labs/rightkit.git",
47
39
  "directory": "packages/release"
48
40
  },
49
- "packageManager": "pnpm@11.24.0",
50
41
  "dependencies": {
51
42
  "smol-toml": "1.9.0"
43
+ },
44
+ "scripts": {
45
+ "test": "node --test --test-concurrency=1 --test-force-exit *.test.mjs",
46
+ "test:registry-parity": "node registry-parity.mjs --allow-unpublished",
47
+ "test:signer:windows": "node sign-release-manifest.integration.mjs",
48
+ "doctor:all": "node --test right-suite-contract.test.mjs",
49
+ "verify:standalone": "node standalone-clone-verify.mjs"
52
50
  }
53
- }
51
+ }
package/release.mjs CHANGED
File without changes
@@ -27,7 +27,7 @@
27
27
  "@rightkit/platform-ui": "0.2.7",
28
28
  "@rightkit/qa": "0.4.7",
29
29
  "@rightkit/qa-chrome": "0.1.5",
30
- "@rightkit/release": "0.2.154",
30
+ "@rightkit/release": "0.2.155",
31
31
  "@rightkit/settings-ui": "0.4.3",
32
32
  "@rightkit/tauri": "0.2.0",
33
33
  "@rightkit/theme": "0.2.3"
package/upload-large.mjs CHANGED
File without changes