@gjsify/cli 0.64.10 → 0.64.11
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/dist/cli.gjs.mjs +42 -42
- package/lib/commands/devtools.js +1 -1
- package/lib/commands/dlx.d.ts +7 -0
- package/lib/commands/dlx.js +6 -1
- package/lib/commands/publish.js +4 -3
- package/lib/commands/ship.js +9 -2
- package/lib/utils/dlx-cache.d.ts +6 -0
- package/lib/utils/dlx-cache.js +1 -1
- package/lib/utils/install-backend-native.js +3 -2
- package/lib/utils/install-backend.d.ts +10 -0
- package/lib/utils/install-backend.js +3 -1
- package/lib/utils/publish-readback.d.ts +2 -0
- package/lib/utils/publish-readback.js +20 -0
- package/lib/utils/ship/gtk-runtime-acquire.js +6 -0
- package/package.json +20 -20
package/lib/commands/devtools.js
CHANGED
|
@@ -62,7 +62,7 @@ system.exit(await runDevtoolsCli(system.programArgs));
|
|
|
62
62
|
* `instances` — so anything a rig does by hand over `gdbus` has a scriptable spelling.
|
|
63
63
|
*/
|
|
64
64
|
export const devtoolsCommand = {
|
|
65
|
-
command: 'devtools',
|
|
65
|
+
command: 'devtools <operation> [operands..]',
|
|
66
66
|
description: 'Drive a running devtools-enabled app from a script: capture a screenshot to a file, find a widget, ' +
|
|
67
67
|
'activate it, send a key. Peer of `gjsify debug`, which speaks MCP for an AI agent.',
|
|
68
68
|
builder: (yargs) => yargs
|
package/lib/commands/dlx.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Command } from '../types/index.js';
|
|
2
2
|
import { type ParsedSpec } from '../utils/parse-spec.js';
|
|
3
|
+
import { type PlatformTarget } from '../utils/platform-check.js';
|
|
3
4
|
interface DlxOptions {
|
|
4
5
|
spec: string;
|
|
5
6
|
binOrArg?: string;
|
|
@@ -31,6 +32,12 @@ export interface EnsureOpts {
|
|
|
31
32
|
* Part of the cache key, so the gjs and node trees never share an entry.
|
|
32
33
|
*/
|
|
33
34
|
extraSpecs?: readonly string[];
|
|
35
|
+
/**
|
|
36
|
+
* Install the tree for this platform rather than the host's: a package that is
|
|
37
|
+
* copied into another machine's artifact (`gjsify ship` fetching a darwin GTK
|
|
38
|
+
* closure on Linux). Part of the cache key.
|
|
39
|
+
*/
|
|
40
|
+
platform?: PlatformTarget;
|
|
34
41
|
}
|
|
35
42
|
/**
|
|
36
43
|
* Resolve (installing + caching when remote) the on-disk directory of a package
|
package/lib/commands/dlx.js
CHANGED
|
@@ -16,6 +16,7 @@ import { resolveGjsEntry } from '../utils/resolve-gjs-entry.js';
|
|
|
16
16
|
import { doubleDashArgs } from '../utils/double-dash-args.js';
|
|
17
17
|
import { cacheDirFor, createCacheKey, getValidCachedPkg, makePrepareDir, resolveInstalledPkgDir, symlinkSwap, } from '../utils/dlx-cache.js';
|
|
18
18
|
import { installPackages, makeProgressReporter } from '../utils/install-backend.js';
|
|
19
|
+
import { describePlatformTarget } from '../utils/platform-check.js';
|
|
19
20
|
export const dlxCommand = {
|
|
20
21
|
command: 'dlx <spec> [binOrArg] [extraArgs..]',
|
|
21
22
|
description: 'Run the GJS bundle of an npm-published package without installing it locally.',
|
|
@@ -118,7 +119,10 @@ export async function ensurePkgDir(parsed, opts) {
|
|
|
118
119
|
return { pkgDir: parsed.path, cachedPkgName: null };
|
|
119
120
|
}
|
|
120
121
|
const specs = [parsed.spec, ...(opts.extraSpecs ?? [])];
|
|
121
|
-
const cacheKey = createCacheKey({
|
|
122
|
+
const cacheKey = createCacheKey({
|
|
123
|
+
packages: specs,
|
|
124
|
+
...(opts.platform ? { platform: describePlatformTarget(opts.platform) } : {}),
|
|
125
|
+
});
|
|
122
126
|
const cacheDir = cacheDirFor(cacheKey);
|
|
123
127
|
const cached = opts.cacheMaxAge > 0 ? getValidCachedPkg(cacheDir, opts.cacheMaxAge) : undefined;
|
|
124
128
|
if (cached) {
|
|
@@ -145,6 +149,7 @@ export async function ensurePkgDir(parsed, opts) {
|
|
|
145
149
|
lockfile: true,
|
|
146
150
|
frozen: opts.frozen,
|
|
147
151
|
progress,
|
|
152
|
+
...(opts.platform ? { platform: opts.platform } : {}),
|
|
148
153
|
});
|
|
149
154
|
const liveTarget = symlinkSwap(cacheDir, prepareDir);
|
|
150
155
|
return {
|
package/lib/commands/publish.js
CHANGED
|
@@ -48,7 +48,7 @@ import { buildPublishHeaders, escapePackageName } from '../utils/publish-headers
|
|
|
48
48
|
import { packWorkspace } from './pack.js';
|
|
49
49
|
import { getNpmTrustedToken, hasGithubOidcEnv, OidcExchangeError, OidcUnavailableError } from '../utils/npm-oidc.js';
|
|
50
50
|
import { diagnose404, is404DiagnosticCandidate } from '../utils/publish-diagnose.js';
|
|
51
|
-
import { DEFAULT_VERIFY_BUDGET_MS, formatUnconfirmedPublish, probePackageName, verifyPublishedVersion, } from '../utils/publish-readback.js';
|
|
51
|
+
import { budgetForPayload, DEFAULT_VERIFY_BUDGET_MS, formatUnconfirmedPublish, probePackageName, verifyPublishedVersion, } from '../utils/publish-readback.js';
|
|
52
52
|
import { collectWorkspacePins, REQUIRED_BLOCK } from '../utils/publish-pins.js';
|
|
53
53
|
import { appendLedger, DEFAULT_HOLD_WAIT_MS, findUnavailablePins, holdsPublish, markHeldPublished, pendingEntries, readLedger, recordUnserved, renderLedgerSummary, settleUnserved, summariseReasons, } from '../utils/publish-hold.js';
|
|
54
54
|
import { describeClass, statusTokenFromEnv } from '../utils/publish-status.js';
|
|
@@ -584,9 +584,10 @@ export async function publishWorkspace(input) {
|
|
|
584
584
|
* `publish-unconfirmed`. Same origin, same credential, one request later.
|
|
585
585
|
*/
|
|
586
586
|
const readBack = async () => {
|
|
587
|
-
const
|
|
588
|
-
if (
|
|
587
|
+
const configuredMs = input.verifyBudgetMs ?? DEFAULT_VERIFY_BUDGET_MS;
|
|
588
|
+
if (configuredMs <= 0)
|
|
589
589
|
return undefined;
|
|
590
|
+
const budgetMs = budgetForPayload(configuredMs, bodyStr.length);
|
|
590
591
|
return verifyPublishedVersion({
|
|
591
592
|
registry: registryClean,
|
|
592
593
|
name: packed.name,
|
package/lib/commands/ship.js
CHANGED
|
@@ -786,12 +786,19 @@ async function resolveCarriedRuntime(layout, settings, projectDir) {
|
|
|
786
786
|
return empty;
|
|
787
787
|
// The closure is fetched, not installed: a project that lists it puts a second
|
|
788
788
|
// GLib next to Homebrew's in its dev tree (see `gtk-runtime-acquire.ts`).
|
|
789
|
+
// Fetched FOR THE TARGET: on a Linux host the package's own `os`/`cpu` gate
|
|
790
|
+
// refused it as EBADPLATFORM, and every macOS and Windows artifact assembled
|
|
791
|
+
// on Linux shipped without GTK, starting only where Homebrew happened to have it.
|
|
789
792
|
const acquired = await acquireGtkRuntime({
|
|
790
793
|
target,
|
|
791
794
|
version: cliVersion(),
|
|
792
795
|
discovery: { cwd: projectDir },
|
|
793
|
-
ensure: async (spec) => (await ensurePkgDir(parseSpec(spec), {
|
|
794
|
-
|
|
796
|
+
ensure: async (spec) => (await ensurePkgDir(parseSpec(spec), {
|
|
797
|
+
verbose: false,
|
|
798
|
+
cacheMaxAge: DLX_CACHE_MAX_AGE_MIN,
|
|
799
|
+
frozen: false,
|
|
800
|
+
platform: { os: layout.os, cpu: settings.arch },
|
|
801
|
+
})).pkgDir,
|
|
795
802
|
log: (message) => console.log(`${LOG} ${message}`),
|
|
796
803
|
});
|
|
797
804
|
return stageAppRuntime({
|
package/lib/utils/dlx-cache.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
interface CacheKeyOpts {
|
|
2
2
|
packages: string[];
|
|
3
3
|
registries?: Record<string, string>;
|
|
4
|
+
/**
|
|
5
|
+
* The platform the tree was installed FOR (`darwin-arm64`), when not the host's.
|
|
6
|
+
* The same specs filter to a different tree per platform. Absent, the key is
|
|
7
|
+
* the one it always was, so existing cache entries stay valid.
|
|
8
|
+
*/
|
|
9
|
+
platform?: string;
|
|
4
10
|
}
|
|
5
11
|
/** Stable, sorted JSON hash of inputs. */
|
|
6
12
|
export declare function createCacheKey(opts: CacheKeyOpts): string;
|
package/lib/utils/dlx-cache.js
CHANGED
|
@@ -19,7 +19,7 @@ function lexCompare(a, b) {
|
|
|
19
19
|
export function createCacheKey(opts) {
|
|
20
20
|
const sortedPkgs = [...opts.packages].sort(lexCompare);
|
|
21
21
|
const sortedRegs = Object.entries(opts.registries ?? {}).sort(([a], [b]) => lexCompare(a, b));
|
|
22
|
-
const payload = JSON.stringify([sortedPkgs, sortedRegs]);
|
|
22
|
+
const payload = JSON.stringify(opts.platform === undefined ? [sortedPkgs, sortedRegs] : [sortedPkgs, sortedRegs, opts.platform]);
|
|
23
23
|
return createHash('sha256').update(payload).digest('hex');
|
|
24
24
|
}
|
|
25
25
|
/** $XDG_CACHE_HOME/gjsify/dlx — created if missing. */
|
|
@@ -143,8 +143,9 @@ async function installPackagesNativeLocked(opts, npmrc, log) {
|
|
|
143
143
|
// The triple this install materialises FOR. Normally the running host;
|
|
144
144
|
// `--os/--cpu/--libc` (npm's config keys, read from the environment by
|
|
145
145
|
// `resolveHostPlatform`) override it, which is what makes the darwin/win32/musl
|
|
146
|
-
// branches reviewable from one machine.
|
|
147
|
-
|
|
146
|
+
// branches reviewable from one machine. A caller that installs for another
|
|
147
|
+
// machine's artifact (`opts.platform`) wins over both.
|
|
148
|
+
const target = opts.platform ?? resolveHostPlatform();
|
|
148
149
|
const force = readPlatformForce(process.env);
|
|
149
150
|
log('install: platform target %s%s', describePlatformTarget(target), force ? ' (--force: checks bypassed)' : '');
|
|
150
151
|
let nodes;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ProgressReporter } from './install-progress.js';
|
|
2
|
+
import type { PlatformTarget } from './platform-check.js';
|
|
2
3
|
export type { ProgressEvent, ProgressPhase, ProgressReporter } from './install-progress.js';
|
|
3
4
|
export { makeProgressReporter } from './install-progress.js';
|
|
4
5
|
export interface InstallOptions {
|
|
@@ -79,6 +80,15 @@ export interface InstallOptions {
|
|
|
79
80
|
* and the warning falls back to bare ranges.
|
|
80
81
|
*/
|
|
81
82
|
specOrigins?: Map<string, string[]>;
|
|
83
|
+
/**
|
|
84
|
+
* The `os`/`cpu`/`libc` triple to install FOR, instead of the host's (and of
|
|
85
|
+
* `npm_config_os`/`_cpu`/`_libc`). For a tree that is copied into an artifact
|
|
86
|
+
* for another machine and never run here — `gjsify ship` assembling a darwin or
|
|
87
|
+
* win32 bundle on Linux fetches that target's GTK closure, whose `os`/`cpu`
|
|
88
|
+
* gate would otherwise refuse it as EBADPLATFORM (ADR 0024 § A1). The npm
|
|
89
|
+
* backend passes it on as `--os`/`--cpu`/`--libc`.
|
|
90
|
+
*/
|
|
91
|
+
platform?: PlatformTarget;
|
|
82
92
|
}
|
|
83
93
|
export interface InstallResult {
|
|
84
94
|
/** Requested top-level packages with the version each resolved to. Empty for
|
|
@@ -24,7 +24,7 @@ export async function installPackages(opts) {
|
|
|
24
24
|
const installed = await installPackagesNative(opts);
|
|
25
25
|
return { installed };
|
|
26
26
|
}
|
|
27
|
-
async function installViaNpm({ prefix, specs, verbose, registry }) {
|
|
27
|
+
async function installViaNpm({ prefix, specs, verbose, registry, platform }) {
|
|
28
28
|
if (specs.length === 0) {
|
|
29
29
|
throw new Error('installPackages: empty specs list');
|
|
30
30
|
}
|
|
@@ -42,6 +42,8 @@ async function installViaNpm({ prefix, specs, verbose, registry }) {
|
|
|
42
42
|
'--prefix',
|
|
43
43
|
prefix,
|
|
44
44
|
...(verbose ? ['--loglevel', 'verbose'] : ['--loglevel', 'warn']),
|
|
45
|
+
...(platform ? ['--os', platform.os, '--cpu', platform.cpu] : []),
|
|
46
|
+
...(platform?.libc ? ['--libc', platform.libc] : []),
|
|
45
47
|
...specs,
|
|
46
48
|
];
|
|
47
49
|
// Through `spawnToCompletion` because a bare `spawn('npm', …)` is ENOENT on
|
|
@@ -146,6 +146,8 @@ export declare function probeTimeoutFor(configuredMs: number, remainingMs: numbe
|
|
|
146
146
|
* state is what the `recorded-not-served` verdict names.
|
|
147
147
|
*/
|
|
148
148
|
export declare const DEFAULT_VERIFY_BUDGET_MS = 600000;
|
|
149
|
+
/** The read-back budget for a payload: `configuredMs`, longer if it is the default and the upload is large. */
|
|
150
|
+
export declare function budgetForPayload(configuredMs: number, payloadBytes: number): number;
|
|
149
151
|
/**
|
|
150
152
|
* Poll the registry until `name@version` resolves, or the budget runs out, then
|
|
151
153
|
* say WHICH of the three states it found (see {@link ReadbackVerdict}).
|
|
@@ -138,6 +138,26 @@ export function probeTimeoutFor(configuredMs, remainingMs) {
|
|
|
138
138
|
* state is what the `recorded-not-served` verdict names.
|
|
139
139
|
*/
|
|
140
140
|
export const DEFAULT_VERIFY_BUDGET_MS = 600_000;
|
|
141
|
+
/**
|
|
142
|
+
* Payload size above which the DEFAULT window starts to grow, and the growth per MiB.
|
|
143
|
+
*
|
|
144
|
+
* v0.64.9, run 40145205912: `@gjsify/gtk-runtime-win32-arm64` PUT 69.7 MB, got a 202,
|
|
145
|
+
* and the read-back gave up after 600 s with `not-published`; the registry's `time`
|
|
146
|
+
* map recorded the version 20 s later. The lag scales with what npm has to ingest,
|
|
147
|
+
* and the 600 s ceiling was measured on packages of a few MB. So the window grows by
|
|
148
|
+
* 10 s per MiB past 32 MiB (that package: ~945 s). Only the PATIENT default grows —
|
|
149
|
+
* an explicit short budget (the sweep's `--verify-timeout 5`) is a caller's decision.
|
|
150
|
+
* An upload npm accepted but never recorded still ends in `not-published`.
|
|
151
|
+
*/
|
|
152
|
+
const LARGE_PAYLOAD_BYTES = 32 * 1024 * 1024;
|
|
153
|
+
const EXTRA_BUDGET_PER_MIB_MS = 10_000;
|
|
154
|
+
/** The read-back budget for a payload: `configuredMs`, longer if it is the default and the upload is large. */
|
|
155
|
+
export function budgetForPayload(configuredMs, payloadBytes) {
|
|
156
|
+
if (configuredMs < DEFAULT_VERIFY_BUDGET_MS || payloadBytes <= LARGE_PAYLOAD_BYTES)
|
|
157
|
+
return configuredMs;
|
|
158
|
+
const extraMiB = (payloadBytes - LARGE_PAYLOAD_BYTES) / (1024 * 1024);
|
|
159
|
+
return configuredMs + Math.ceil(extraMiB) * EXTRA_BUDGET_PER_MIB_MS;
|
|
160
|
+
}
|
|
141
161
|
/**
|
|
142
162
|
* Make one probe's URL uncacheable, by giving it a key no cache holds.
|
|
143
163
|
*
|
|
@@ -40,6 +40,12 @@ export async function acquireGtkRuntime(input) {
|
|
|
40
40
|
return { kind: 'present' };
|
|
41
41
|
const name = gtkRuntimePackageName(input.target);
|
|
42
42
|
const spec = `${name}@${input.version}`;
|
|
43
|
+
// An offline build, or a suite that must not download 100 MB per run, stages what is
|
|
44
|
+
// reachable and nothing more. The e2e suites that assert "a project without the packages
|
|
45
|
+
// stages no runtime" held only while the fetch failed on Linux for every foreign target.
|
|
46
|
+
if ((discovery.env ?? process.env)['GJSIFY_GTK_RUNTIME_FETCH'] === '0') {
|
|
47
|
+
return { kind: 'failed', reason: `GJSIFY_GTK_RUNTIME_FETCH=0 turned off the fetch of ${spec}` };
|
|
48
|
+
}
|
|
43
49
|
input.log?.(`${name} is not installed here, and is not meant to be — fetching ${spec} into the cache ` +
|
|
44
50
|
'(about 100 MB, once)');
|
|
45
51
|
let dir;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/cli",
|
|
3
|
-
"version": "0.64.
|
|
3
|
+
"version": "0.64.11",
|
|
4
4
|
"description": "CLI for Gjsify",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -142,22 +142,22 @@
|
|
|
142
142
|
"cli"
|
|
143
143
|
],
|
|
144
144
|
"dependencies": {
|
|
145
|
-
"@gjsify/blueprint": "^0.64.
|
|
146
|
-
"@gjsify/buffer": "^0.64.
|
|
147
|
-
"@gjsify/create-app": "^0.64.
|
|
148
|
-
"@gjsify/node-globals": "^0.64.
|
|
149
|
-
"@gjsify/node-polyfills": "^0.64.
|
|
150
|
-
"@gjsify/npm-registry": "^0.64.
|
|
151
|
-
"@gjsify/resolve-npm": "^0.64.
|
|
152
|
-
"@gjsify/rolldown-plugin-gjsify": "^0.64.
|
|
153
|
-
"@gjsify/vite-plugin-blueprint": "^0.64.
|
|
154
|
-
"@gjsify/rolldown-plugin-pnp": "^0.64.
|
|
155
|
-
"@gjsify/semver": "^0.64.
|
|
156
|
-
"@gjsify/tar": "^0.64.
|
|
157
|
-
"@gjsify/tsc": "^0.64.
|
|
158
|
-
"@gjsify/utils": "^0.64.
|
|
159
|
-
"@gjsify/web-polyfills": "^0.64.
|
|
160
|
-
"@gjsify/workspace": "^0.64.
|
|
145
|
+
"@gjsify/blueprint": "^0.64.11",
|
|
146
|
+
"@gjsify/buffer": "^0.64.11",
|
|
147
|
+
"@gjsify/create-app": "^0.64.11",
|
|
148
|
+
"@gjsify/node-globals": "^0.64.11",
|
|
149
|
+
"@gjsify/node-polyfills": "^0.64.11",
|
|
150
|
+
"@gjsify/npm-registry": "^0.64.11",
|
|
151
|
+
"@gjsify/resolve-npm": "^0.64.11",
|
|
152
|
+
"@gjsify/rolldown-plugin-gjsify": "^0.64.11",
|
|
153
|
+
"@gjsify/vite-plugin-blueprint": "^0.64.11",
|
|
154
|
+
"@gjsify/rolldown-plugin-pnp": "^0.64.11",
|
|
155
|
+
"@gjsify/semver": "^0.64.11",
|
|
156
|
+
"@gjsify/tar": "^0.64.11",
|
|
157
|
+
"@gjsify/tsc": "^0.64.11",
|
|
158
|
+
"@gjsify/utils": "^0.64.11",
|
|
159
|
+
"@gjsify/web-polyfills": "^0.64.11",
|
|
160
|
+
"@gjsify/workspace": "^0.64.11",
|
|
161
161
|
"acorn": "^8.17.0",
|
|
162
162
|
"cosmiconfig": "^9.0.2",
|
|
163
163
|
"get-tsconfig": "^4.14.0",
|
|
@@ -166,13 +166,13 @@
|
|
|
166
166
|
"yargs": "^18.0.0"
|
|
167
167
|
},
|
|
168
168
|
"devDependencies": {
|
|
169
|
-
"@gjsify/unit": "^0.64.
|
|
169
|
+
"@gjsify/unit": "^0.64.11",
|
|
170
170
|
"@types/yargs": "^17.0.35",
|
|
171
171
|
"typescript": "^6.0.3"
|
|
172
172
|
},
|
|
173
173
|
"peerDependencies": {
|
|
174
|
-
"@gjsify/oxfmt-native": "^0.64.
|
|
175
|
-
"@gjsify/rolldown-native": "^0.64.
|
|
174
|
+
"@gjsify/oxfmt-native": "^0.64.11",
|
|
175
|
+
"@gjsify/rolldown-native": "^0.64.11"
|
|
176
176
|
},
|
|
177
177
|
"peerDependenciesMeta": {
|
|
178
178
|
"@gjsify/oxfmt-native": {
|