@rightkit/release 0.2.172 → 0.2.174
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.
- package/README.md +10 -4
- package/bin/darwin/rightkit-swap +0 -0
- package/bin/darwin/rightkit-swap.sign.json +1 -1
- package/cli/right-release.mjs +7 -3
- package/development-signing.mjs +135 -4
- package/development.mjs +27 -12
- package/in-place-install.mjs +32 -7
- package/install-app-windows.mjs +108 -17
- package/install-app.mjs +32 -8
- package/install-tauri-devid.mjs +231 -0
- package/inventory-check.mjs +1 -1
- package/mac-bundle-signing.mjs +143 -1
- package/mac-package-recipe.mjs +304 -0
- package/mac-signing-matrix.mjs +73 -6
- package/macos-signing-session.mjs +12 -2
- package/media-sidecar.mjs +1 -1
- package/package-recipe-targets.mjs +245 -0
- package/package.json +1 -1
- package/portable-development.mjs +9 -9
- package/project-type.mjs +1 -1
- package/qa-build-features.mjs +7 -1
- package/recipe-build.mjs +346 -0
- package/release.mjs +27 -9
- package/rightkit-signing-agent.mjs +10 -4
- package/rightkit-sync.mjs +1 -1
- package/rightkit-versions.json +11 -6
- package/runtime-budgets.mjs +14 -5
- package/stage-binary.mjs +1 -1
- package/stage-sidecar-command.mjs +73 -0
- package/stage-sidecar.mjs +839 -0
- package/swift-mac-dmg.mjs +2 -1
- package/win-package-recipe.mjs +321 -0
package/runtime-budgets.mjs
CHANGED
|
@@ -199,7 +199,7 @@ export function renderRuntimeBudgetBody(budget) {
|
|
|
199
199
|
const host = `${m.host?.os}/${m.host?.arch}${m.host?.model ? ` (${m.host.model})` : ""}`;
|
|
200
200
|
const scale = `${count(m.dataScale?.count)} ${m.dataScale?.unit} (${m.dataScale?.description})`;
|
|
201
201
|
const app = m.scope === "installed" && m.app ? `, app ${m.app.name} ${m.app.version}` : "";
|
|
202
|
-
const observed = BUDGET_FIGURES.map((k) => `${FIGURE_LABEL[k]} ${m.observed?.[k] === undefined ? "n/a" : FORMAT[k](m.observed[k])}`).join(", ");
|
|
202
|
+
const observed = BUDGET_FIGURES.map((k) => `${FIGURE_LABEL[k]} ${m.observed?.[k] === undefined || m.observed?.[k] === null ? "n/a (not measurable on this host)" : FORMAT[k](m.observed[k])}`).join(", ");
|
|
203
203
|
out.push(`- Measured: ${host}, ${budget.crate} ${m.crateVersion} at ${String(m.commit).slice(0, 12)}, ${scale}, ${m.scope}${app}, \`${m.command}\`, ${m.date}, evidence ${String(m.evidence?.sha256 ?? "none").slice(0, 12)}: ${observed}.`);
|
|
204
204
|
}
|
|
205
205
|
return out;
|
|
@@ -291,6 +291,10 @@ export function measurementStaleness(commit, crateDir, git = defaultGit, deps =
|
|
|
291
291
|
|
|
292
292
|
// ---------------------------------------------------------------- bench evidence
|
|
293
293
|
|
|
294
|
+
// Figures a host cannot measure by design. macOS has no per-process disk-operation count (rightkit-child-process
|
|
295
|
+
// usage.rs: ru_inblock/ru_oublock stay 0 there), so disk_ops_per_s may be "unavailable" on darwin only.
|
|
296
|
+
export const HOST_UNAVAILABLE_FIGURES = Object.freeze({ darwin: Object.freeze(["diskOpsPerSecond"]) });
|
|
297
|
+
export const figureUnavailableOn = (os, key) => (HOST_UNAVAILABLE_FIGURES[os] ?? []).includes(key);
|
|
294
298
|
const RESULT_NUMBERS = Object.freeze({ resident_bytes: "residentMemoryBytes", idle_cpu_percent: "idleCpuPercent", wakeups_per_s: "wakeupsPerSecond", disk_ops_per_s: "diskOpsPerSecond", scale_count: "scaleCount" });
|
|
295
299
|
const RESULT_WORDS = Object.freeze(["crate", "version", "scale_unit"]);
|
|
296
300
|
|
|
@@ -312,7 +316,8 @@ export function parseBudgetResult(text) {
|
|
|
312
316
|
for (const key of RESULT_WORDS) { if (!nonEmpty(fields[key])) problems.push(`missing field ${key}`); else value[key] = fields[key]; }
|
|
313
317
|
for (const [key, name] of Object.entries(RESULT_NUMBERS)) {
|
|
314
318
|
const n = Number(fields[key]);
|
|
315
|
-
if (fields[key] ===
|
|
319
|
+
if (fields[key] === "unavailable" && name !== "residentMemoryBytes" && name !== "scaleCount") value[name] = null;
|
|
320
|
+
else if (fields[key] === undefined || fields[key] === "" || !Number.isFinite(n) || n < 0) problems.push(`field ${key} must be a non-negative number`);
|
|
316
321
|
else value[name] = n;
|
|
317
322
|
}
|
|
318
323
|
return problems.length ? { ok: false, problems } : { ok: true, problems: [], value };
|
|
@@ -412,6 +417,7 @@ function validateMeasurement(m, index) {
|
|
|
412
417
|
}
|
|
413
418
|
if (!nonEmpty(m.command)) problems.push(`${at} has no command`);
|
|
414
419
|
for (const key of BUDGET_FIGURES) {
|
|
420
|
+
if (m.observed?.[key] === null && figureUnavailableOn(m.host?.os, key)) continue;
|
|
415
421
|
if (!isNumber(m.observed?.[key]) || m.observed[key] < 0) problems.push(`${at} observed.${key} must be a non-negative number`);
|
|
416
422
|
}
|
|
417
423
|
if (isNumber(m.observed?.residentMemoryBytes) && m.observed.residentMemoryBytes === 0) {
|
|
@@ -507,12 +513,12 @@ export function evaluateRuntimeBudget({ crate, crateDir, version, evidence, requ
|
|
|
507
513
|
}
|
|
508
514
|
for (const { m, index } of counted) {
|
|
509
515
|
for (const key of BUDGET_FIGURES) {
|
|
510
|
-
if (ceilings[key] !== undefined && m.observed[key] > ceilings[key]) {
|
|
516
|
+
if (ceilings[key] !== undefined && m.observed[key] !== null && m.observed[key] > ceilings[key]) {
|
|
511
517
|
problems.push(`measurement[${index}] on ${m.host.os}/${m.host.arch} exceeds the ${FIGURE_LABEL[key]} ceiling: observed ${m.observed[key]} > ${ceilings[key]}`);
|
|
512
518
|
}
|
|
513
519
|
}
|
|
514
520
|
}
|
|
515
|
-
const withinCeilings = (m) => BUDGET_FIGURES.every((key) => ceilings[key] !== undefined && m.observed[key] <= ceilings[key]);
|
|
521
|
+
const withinCeilings = (m) => BUDGET_FIGURES.every((key) => ceilings[key] !== undefined && (m.observed[key] === null ? figureUnavailableOn(m.host?.os, key) : m.observed[key] <= ceilings[key]));
|
|
516
522
|
const atScale = (m) => requiredScale !== null && m.dataScale.unit === requiredScale.unit && m.dataScale.count >= requiredScale.minCount;
|
|
517
523
|
const staleness = new Map();
|
|
518
524
|
const stale = (m) => {
|
|
@@ -768,7 +774,7 @@ export function appRuntimeBudgetAdoptionCheck({ appRoot, app, version, cargoLock
|
|
|
768
774
|
if (evidenceProblems.length) { problems.push(`${crate}: ${evidenceProblems.join("; ")}`); return false; }
|
|
769
775
|
if (m.app.name !== app) { problems.push(`${crate}: measurement[${index}] is for app ${m.app.name}, not ${app}`); return false; }
|
|
770
776
|
if (version && m.app.version !== version) { problems.push(`${crate}: measurement[${index}] was taken at ${app} ${m.app.version}, not the current ${version}`); return false; }
|
|
771
|
-
const over = BUDGET_FIGURES.filter((k) => m.observed[k] > ceilings[k]);
|
|
777
|
+
const over = BUDGET_FIGURES.filter((k) => m.observed[k] !== null && m.observed[k] > ceilings[k]);
|
|
772
778
|
if (over.length) { problems.push(`${crate}: measurement[${index}] exceeds ${over.join(", ")}`); return false; }
|
|
773
779
|
if (m.dataScale.unit !== requiredScale.unit || m.dataScale.count < requiredScale.minCount) { problems.push(`${crate}: measurement[${index}] is below the required scale ${requiredScale.minCount} ${requiredScale.unit}`); return false; }
|
|
774
780
|
return true;
|
|
@@ -813,6 +819,9 @@ export function recordMeasurement({ crateDir, resultFile, scope, command, descri
|
|
|
813
819
|
const v = parsed.value;
|
|
814
820
|
if (v.crate !== pkg.name) throw new Error(`bench output is for ${v.crate}, crate is ${pkg.name}`);
|
|
815
821
|
if (v.version !== pkg.version) throw new Error(`bench output is for version ${v.version}, crate is ${pkg.version}`);
|
|
822
|
+
for (const key of BUDGET_FIGURES) {
|
|
823
|
+
if (v[key] === null && !figureUnavailableOn(host.os, key)) throw new Error(`bench output rejected: ${key} is unavailable, which is allowed only where the host cannot measure it (${JSON.stringify(HOST_UNAVAILABLE_FIGURES)})`);
|
|
824
|
+
}
|
|
816
825
|
if (!SCOPES.includes(scope)) throw new Error(`--scope must be one of ${SCOPES.join(", ")}`);
|
|
817
826
|
if (scope === "installed" && !(nonEmpty(app?.name) && nonEmpty(app?.version))) throw new Error("--scope installed needs --app and --app-version");
|
|
818
827
|
if (!nonEmpty(command)) throw new Error("--command (the exact bench command) is required");
|
package/stage-binary.mjs
CHANGED
|
@@ -9,7 +9,7 @@ import { resolveTargetRoot } from "./cargo-target.mjs";
|
|
|
9
9
|
* The build broker writes Cargo output to per-generation folders (`<managed>/rightkit-build-control/ws/<hash>/g/<gen>/...`)
|
|
10
10
|
* and `cargo-guard` uses a hashed `dev-targets/<project>-<hash>` folder. Those are build output only: their path is not
|
|
11
11
|
* stable, so NOTHING may run from them. macOS ties privacy grants to the path an app runs from, so a dev or QA binary is
|
|
12
|
-
* copied in place to `<root>/.rightkit-dev-bin/<triple-or-host>/<name>` (
|
|
12
|
+
* copied in place to `<root>/.rightkit-dev-bin/<triple-or-host>/<name>` (replaced in place, no `.previous` kept) and run from there.
|
|
13
13
|
*/
|
|
14
14
|
export const DEV_STAGE_DIRECTORY = ".rightkit-dev-bin";
|
|
15
15
|
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// `right-release stage-sidecar [--config right-release.config.mjs] [--target <triple>] [--check] [--json]` (bogusyogi/rightkit#345):
|
|
3
|
+
// stages the config's declarative `sidecars` into src-tauri/binaries with Tauri externalBin naming. `--check` validates
|
|
4
|
+
// the manifest and prints the plan without building, downloading, copying or deleting anything (for template gates).
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { pathToFileURL } from "node:url";
|
|
7
|
+
import { planSidecarStaging, resolveTargetTriple, stageSidecars } from "./stage-sidecar.mjs";
|
|
8
|
+
|
|
9
|
+
export function parseStageSidecarArgs(argv) {
|
|
10
|
+
const opts = { config: "right-release.config.mjs", target: undefined, json: false, check: false };
|
|
11
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
12
|
+
const arg = argv[i];
|
|
13
|
+
if (arg === "--config" || arg === "--target") {
|
|
14
|
+
const value = argv[i + 1];
|
|
15
|
+
if (!value || value.startsWith("--")) throw new Error(`${arg} needs a value`);
|
|
16
|
+
opts[arg.slice(2)] = value;
|
|
17
|
+
i += 1;
|
|
18
|
+
} else if (arg === "--json") opts.json = true;
|
|
19
|
+
else if (arg === "--check") opts.check = true;
|
|
20
|
+
else throw new Error(`unknown stage-sidecar argument: ${arg}`);
|
|
21
|
+
}
|
|
22
|
+
return opts;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const NODE_ARCH = { x64: "x86_64", arm64: "aarch64" };
|
|
26
|
+
const NODE_OS = { darwin: "apple-darwin", win32: "pc-windows-msvc", linux: "unknown-linux-gnu" };
|
|
27
|
+
|
|
28
|
+
/** Host triple from Node alone (no subprocess), so `--check` stays free of effects. */
|
|
29
|
+
export function nodeHostTriple(platform = process.platform, arch = process.arch) {
|
|
30
|
+
const cpu = NODE_ARCH[arch];
|
|
31
|
+
const system = NODE_OS[platform];
|
|
32
|
+
if (!cpu || !system) throw new Error(`cannot derive a target triple from ${platform}/${arch}; pass --target`);
|
|
33
|
+
return `${cpu}-${system}`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Human-readable plan lines for `--check`. */
|
|
37
|
+
export function formatSidecarPlan(plan) {
|
|
38
|
+
const lines = [`right-release stage-sidecar --check: target ${plan.target}, mode ${plan.mode}, stageDir ${plan.stageDir}${plan.wipeStageDir ? " (wipeStageDir)" : ""}`];
|
|
39
|
+
for (const entry of plan.entries) {
|
|
40
|
+
if (entry.skipped) lines.push(` [${entry.index}] ${entry.kind}: skipped (platforms ${entry.platforms.join(",")})`);
|
|
41
|
+
else lines.push(` [${entry.index}] ${entry.kind}: ${entry.outputs.join(", ")}${entry.externalBin ? " (externalBin)" : ""}${entry.clean ? " (clean)" : ""}${entry.url ? ` <- ${entry.url}` : ""}`);
|
|
42
|
+
}
|
|
43
|
+
if (plan.nestedBrokerRisk) lines.push(" warning: running inside an outer broker build; staging would fail with STAGE_SIDECAR_NESTED_BROKER (run stage-sidecar in recipe prepare, before the Tauri build)");
|
|
44
|
+
lines.push("right-release stage-sidecar --check: manifest is valid; nothing was staged");
|
|
45
|
+
return lines;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function main() {
|
|
49
|
+
const opts = parseStageSidecarArgs(process.argv.slice(2));
|
|
50
|
+
const configPath = path.resolve(opts.config);
|
|
51
|
+
const appRoot = path.dirname(configPath);
|
|
52
|
+
const loaded = await import(pathToFileURL(configPath).href);
|
|
53
|
+
const config = loaded.default ?? loaded.config ?? loaded;
|
|
54
|
+
if (config?.sidecars === undefined) throw new Error(`${opts.config} declares no sidecars`);
|
|
55
|
+
if (opts.check) {
|
|
56
|
+
const target = opts.target ?? process.env.TAURI_ENV_TARGET_TRIPLE ?? nodeHostTriple();
|
|
57
|
+
const plan = planSidecarStaging({ manifest: config.sidecars, target });
|
|
58
|
+
if (opts.json) console.log(JSON.stringify(plan, null, 2));
|
|
59
|
+
else for (const line of formatSidecarPlan(plan)) console.log(line);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const target = resolveTargetTriple({ target: opts.target, cwd: appRoot });
|
|
63
|
+
const result = await stageSidecars({ appRoot, manifest: config.sidecars, target });
|
|
64
|
+
if (opts.json) console.log(JSON.stringify(result, null, 2));
|
|
65
|
+
else {
|
|
66
|
+
for (const file of result.files ?? []) console.log(`right-release stage-sidecar: staged ${typeof file === "string" ? file : file.path ?? JSON.stringify(file)}`);
|
|
67
|
+
console.log(`right-release stage-sidecar: externalBin ${JSON.stringify(result.externalBinNames ?? [])}; receipt ${result.receiptPath}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (import.meta.url === pathToFileURL(process.argv[1] ?? "").href) {
|
|
72
|
+
main().catch((error) => { console.error(`right-release stage-sidecar: ${error.code ? `[${error.code}] ` : ""}${error.message}`); process.exitCode = 1; });
|
|
73
|
+
}
|