@gjsify/cli 0.27.0 → 0.28.0

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.
@@ -93,13 +93,21 @@ function diagnoseNativeEngine() {
93
93
  const facade = path.join(pkgDir, 'lib', 'esm', 'index.js');
94
94
  if (!existsSync(facade)) {
95
95
  return (`The engine's JS facade is NOT BUILT: ${facade} does not exist.\n` +
96
- 'It is a BUILD OUTPUT, not something `gjsify install` produces — so a freshly cloned or freshly ' +
97
- 'installed tree never has it, and every `gjsify build` under GJS fails here until it is built once. ' +
96
+ 'It is a BUILD OUTPUT, so this is almost certainly a clone of the gjsify REPOSITORY rather than a ' +
97
+ 'consumer install: in a clone, node_modules/@gjsify/rolldown-native is a symlink to the workspace ' +
98
+ 'package, whose `lib/` no `gjsify install` produces. An installed package from npm is NOT affected — ' +
99
+ 'the published tarball does contain `lib/esm/index.js` (verified against 0.26.1), so a consumer that ' +
100
+ 'hit this message should report it.\n' +
98
101
  'Building it needs a bundler, which is why it cannot bootstrap itself under GJS; the Node CLI entry ' +
99
- 'does it instead. From the gjsify repo root:\n' +
102
+ 'does it instead. From the gjsify repo root — NOTE both of these REQUIRE Node:\n' +
100
103
  ' gjsify run build:infra # the full cold-tree chain (recommended)\n' +
101
104
  ' node scripts/bootstrap-native-facades.mjs # just the facades, if the rest is already built\n' +
102
- 'Both are idempotent and skip already-built facades in seconds.');
105
+ 'Both are idempotent and skip already-built facades in seconds.\n' +
106
+ 'ON A NODE-LESS GJS HOST there is currently no in-repo way out, and saying so is the point — this ' +
107
+ 'message used to recommend those two commands unconditionally, and on such a host BOTH fail (the ' +
108
+ "second directly, the first at `@gjsify/create-app`'s `node scripts/process-template.mjs`). Until " +
109
+ 'that is closed, seed `lib/` from the published package — which ships it — or from a host that has ' +
110
+ 'Node. Tracked in `status/open-todos.md` ("A Node-less host cannot bootstrap a fresh CLONE").');
103
111
  }
104
112
  return ('The JS facade is built, so this is the typelib/prebuild lookup failing. Most likely the CLI bundle was ' +
105
113
  'invoked DIRECTLY (`gjs -m …/cli.gjs.mjs`, or by executing dist/cli.gjs.mjs), which bypasses the `gjsify` ' +
@@ -1,6 +1,7 @@
1
1
  import type { Command } from '../types/index.js';
2
2
  interface DebugCliOptions {
3
3
  busName?: string;
4
+ address?: string;
4
5
  profile?: string;
5
6
  globals?: string;
6
7
  out?: string;
@@ -43,26 +43,32 @@ function deriveBrowserAppId(name) {
43
43
  function hasDep(pkg, name) {
44
44
  return Boolean(pkg.dependencies?.[name] || pkg.devDependencies?.[name]);
45
45
  }
46
- function generateEntry(profile, busNameBase, name, version) {
46
+ function generateEntry(profile, busNameBase, name, version, address) {
47
+ const base = JSON.stringify(busNameBase);
48
+ // Only emit the option when an address was actually given: an `address:
49
+ // undefined` in the generated entry would read like a decision, when the
50
+ // bridge's own precedence (env var → published address file → session bus)
51
+ // is what should apply.
52
+ const options = address ? `, { address: ${JSON.stringify(address)} }` : '';
47
53
  if (profile === 'storybook') {
48
54
  return `// Auto-generated by \`gjsify debug\` — do not edit by hand.
49
55
  import { runDevtoolsMcp, storybookProfile } from '@gjsify/devtools-mcp';
50
56
 
51
- await runDevtoolsMcp(storybookProfile(${JSON.stringify(busNameBase)}));
57
+ await runDevtoolsMcp(storybookProfile(${base}${options}));
52
58
  `;
53
59
  }
54
60
  if (profile === 'browser') {
55
61
  return `// Auto-generated by \`gjsify debug\` — do not edit by hand.
56
62
  import { runDevtoolsMcp, browserProfile } from '@gjsify/devtools-mcp';
57
63
 
58
- await runDevtoolsMcp(browserProfile(${JSON.stringify(busNameBase)}));
64
+ await runDevtoolsMcp(browserProfile(${base}${options}));
59
65
  `;
60
66
  }
61
67
  if (profile === 'cdp') {
62
68
  return `// Auto-generated by \`gjsify debug\` — do not edit by hand.
63
69
  import { runDevtoolsMcp, cdpProfile } from '@gjsify/devtools-mcp';
64
70
 
65
- await runDevtoolsMcp(cdpProfile(${JSON.stringify(busNameBase)}));
71
+ await runDevtoolsMcp(cdpProfile(${base}${options}));
66
72
  `;
67
73
  }
68
74
  return `// Auto-generated by \`gjsify debug\` — do not edit by hand.
@@ -71,7 +77,7 @@ import { runDevtoolsMcp } from '@gjsify/devtools-mcp';
71
77
  await runDevtoolsMcp({
72
78
  name: ${JSON.stringify(name)},
73
79
  version: ${JSON.stringify(version)},
74
- busNameBase: ${JSON.stringify(busNameBase)},
80
+ busNameBase: ${base},${address ? `\n address: ${JSON.stringify(address)},` : ''}
75
81
  });
76
82
  `;
77
83
  }
@@ -82,6 +88,12 @@ export const debugCommand = {
82
88
  .option('bus-name', {
83
89
  description: 'App DBus base name (default: gjsify.devtools.busNameBase, or the storybook app-id)',
84
90
  type: 'string',
91
+ })
92
+ .option('address', {
93
+ description: 'Peer D-Bus address of the app (unix:path=… / nonce-tcp:…) instead of the session bus — for ' +
94
+ 'macOS/Windows, which have no session bus. Default: GJSIFY_DEVTOOLS_ADDRESS, then the address ' +
95
+ 'file the app publishes, then the session bus',
96
+ type: 'string',
85
97
  })
86
98
  .option('profile', {
87
99
  description: 'Tool profile: generic | storybook | browser | cdp (default: auto — storybook if @gjsify/storybook is a dep, browser if @gjsify/devtools-browser is, cdp if @gjsify/devtools-cdp is, else generic)',
@@ -133,9 +145,10 @@ export const debugCommand = {
133
145
  mkdirSync(cacheDir, { recursive: true });
134
146
  const entryPath = join(cacheDir, 'entry.ts');
135
147
  const outPath = args.out ? resolve(cwd, args.out) : join(cacheDir, 'bridge.gjs.mjs');
136
- writeFileSync(entryPath, generateEntry(profile, busNameBase, name, version));
148
+ const address = args.address ?? config.address;
149
+ writeFileSync(entryPath, generateEntry(profile, busNameBase, name, version, address));
137
150
  // stderr only — stdout is the MCP JSON-RPC channel.
138
- console.error(`[gjsify debug] profile=${profile} bus=${busNameBase}`);
151
+ console.error(`[gjsify debug] profile=${profile} bus=${busNameBase}${address ? ` address=${address}` : ''}`);
139
152
  // In-process build (runtime-agnostic), then launch with stdio inherited
140
153
  // so the bridge's JSON-RPC stdin/stdout are the client's pipes.
141
154
  const { runCli } = await import('../cli-app.js');
@@ -61,6 +61,38 @@ export interface PackWorkspaceOptions {
61
61
  * `wsDir` to an absolute path.
62
62
  */
63
63
  export declare function packWorkspace(wsDir: string, opts?: PackWorkspaceOptions): Promise<PackResult>;
64
+ /**
65
+ * Walk the workspace and return the list of files to include in the tarball,
66
+ * relative to `wsDir`. Mirrors npm pack's selection rules:
67
+ *
68
+ * - If pkg.files exists: the array is an ALLOWLIST that overrides
69
+ * .gitignore / .npmignore entirely. Every file under an allowlisted
70
+ * path/dir ships from disk; only the hardcoded implicit-exclusion set
71
+ * (node_modules, .git, lockfiles, … — applied by `walkAll` /
72
+ * `expandFilesPatterns`) and npm's always-ignore names are dropped.
73
+ * This matches `npm pack`: a `files` entry re-includes a path even when
74
+ * .gitignore/.npmignore would drop it (verified against `npm pack
75
+ * --dry-run`). Trimming `files`-allowlisted content by .gitignore
76
+ * silently dropped build-generated-but-allowlisted files like
77
+ * adwaita-web's `src/styles.generated.ts` (gitignored, allowlisted via
78
+ * `files: ["src"]`) — shipping a broken tarball whose `src/index.ts`
79
+ * imported a file the tarball didn't contain.
80
+ * - Otherwise: walk everything, apply .npmignore + .gitignore, drop the
81
+ * implicit-exclusion set (node_modules, .git, …)
82
+ *
83
+ * package.json, README*, LICENSE*, NOTICE* and the `bin`/`main` files are
84
+ * always force-included regardless of the rules above.
85
+ *
86
+ * EXPORTED because `scripts/verify-tarball-outputs.mjs` — the repo-wide
87
+ * "is every declared entry point actually in the tarball" post-condition —
88
+ * must ask THIS function and no other. The packer-glob incident is precisely
89
+ * what a second oracle costs: `npm pack` expanded `lib/lib*.d.ts` while
90
+ * `gjsify publish` did not, so a check written against `npm pack --dry-run`
91
+ * would have been green for the whole v0.4.37–0.7.2 window in which the
92
+ * published `@gjsify/tsc` shipped an empty `lib/`. The tarballs are produced
93
+ * here, so the check has to be answered here.
94
+ */
95
+ export declare function collectPackedFiles(wsDir: string, pkg: Record<string, unknown>): string[];
64
96
  /**
65
97
  * Collect every `types`/`typings` path a consumer's TypeScript would resolve for
66
98
  * this package: the top-level `types`/`typings` fields plus every value under a
@@ -124,7 +124,7 @@ export async function packWorkspace(wsDir, opts = {}) {
124
124
  // default set). The package.json itself is always included with the
125
125
  // rewritten contents. We use the post-script `pkgAfterScripts` here so
126
126
  // that any `files` array modified by a prepack script is honored.
127
- const filesToPack = collectFiles(wsDir, pkgAfterScripts);
127
+ const filesToPack = collectPackedFiles(wsDir, pkgAfterScripts);
128
128
  // Guard against the #655 class of bug: a `types`/`typings` declaration that
129
129
  // physically exists in the workspace but is excluded from the tarball by the
130
130
  // `files` allowlist. A mass-added `files: ["lib"]` (Phase D.7d, #179) silently
@@ -198,8 +198,17 @@ export async function packWorkspace(wsDir, opts = {}) {
198
198
  *
199
199
  * package.json, README*, LICENSE*, NOTICE* and the `bin`/`main` files are
200
200
  * always force-included regardless of the rules above.
201
+ *
202
+ * EXPORTED because `scripts/verify-tarball-outputs.mjs` — the repo-wide
203
+ * "is every declared entry point actually in the tarball" post-condition —
204
+ * must ask THIS function and no other. The packer-glob incident is precisely
205
+ * what a second oracle costs: `npm pack` expanded `lib/lib*.d.ts` while
206
+ * `gjsify publish` did not, so a check written against `npm pack --dry-run`
207
+ * would have been green for the whole v0.4.37–0.7.2 window in which the
208
+ * published `@gjsify/tsc` shipped an empty `lib/`. The tarballs are produced
209
+ * here, so the check has to be answered here.
201
210
  */
202
- function collectFiles(wsDir, pkg) {
211
+ export function collectPackedFiles(wsDir, pkg) {
203
212
  const always = forceIncluded(pkg);
204
213
  const filesField = Array.isArray(pkg.files)
205
214
  ? pkg.files.filter((f) => typeof f === 'string')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gjsify/cli",
3
- "version": "0.27.0",
3
+ "version": "0.28.0",
4
4
  "description": "CLI for Gjsify",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -112,7 +112,7 @@
112
112
  "clear": "gjsify clear lib dist tsconfig.tsbuildinfo",
113
113
  "check": "gjsify tsc --noEmit",
114
114
  "start": "node lib/index.js",
115
- "build": "tsc && node scripts/build-assets.mjs",
115
+ "build": "gjsify tsc && node scripts/build-assets.mjs",
116
116
  "build:gjs-bundle": "node lib/index.js build src/index.ts --app gjs --outfile dist/cli.gjs.mjs --shebang",
117
117
  "build:affected-bundle": "node lib/index.js build src/affected-entry.ts --app gjs --outfile dist/affected.gjs.mjs",
118
118
  "build:test:node": "node lib/index.js build src/test.mts --app node --outfile dist/test.node.mjs",
@@ -129,19 +129,19 @@
129
129
  "cli"
130
130
  ],
131
131
  "dependencies": {
132
- "@gjsify/buffer": "^0.27.0",
133
- "@gjsify/create-app": "^0.27.0",
134
- "@gjsify/node-globals": "^0.27.0",
135
- "@gjsify/node-polyfills": "^0.27.0",
136
- "@gjsify/npm-registry": "^0.27.0",
137
- "@gjsify/resolve-npm": "^0.27.0",
138
- "@gjsify/rolldown-plugin-gjsify": "^0.27.0",
139
- "@gjsify/rolldown-plugin-pnp": "^0.27.0",
140
- "@gjsify/semver": "^0.27.0",
141
- "@gjsify/tar": "^0.27.0",
142
- "@gjsify/tsc": "^0.27.0",
143
- "@gjsify/web-polyfills": "^0.27.0",
144
- "@gjsify/workspace": "^0.27.0",
132
+ "@gjsify/buffer": "^0.28.0",
133
+ "@gjsify/create-app": "^0.28.0",
134
+ "@gjsify/node-globals": "^0.28.0",
135
+ "@gjsify/node-polyfills": "^0.28.0",
136
+ "@gjsify/npm-registry": "^0.28.0",
137
+ "@gjsify/resolve-npm": "^0.28.0",
138
+ "@gjsify/rolldown-plugin-gjsify": "^0.28.0",
139
+ "@gjsify/rolldown-plugin-pnp": "^0.28.0",
140
+ "@gjsify/semver": "^0.28.0",
141
+ "@gjsify/tar": "^0.28.0",
142
+ "@gjsify/tsc": "^0.28.0",
143
+ "@gjsify/web-polyfills": "^0.28.0",
144
+ "@gjsify/workspace": "^0.28.0",
145
145
  "cosmiconfig": "^9.0.2",
146
146
  "get-tsconfig": "^4.14.0",
147
147
  "pkg-types": "^2.3.1",
@@ -149,13 +149,13 @@
149
149
  "yargs": "^18.0.0"
150
150
  },
151
151
  "devDependencies": {
152
- "@gjsify/unit": "^0.27.0",
152
+ "@gjsify/unit": "^0.28.0",
153
153
  "@types/yargs": "^17.0.35",
154
154
  "typescript": "^6.0.3"
155
155
  },
156
156
  "peerDependencies": {
157
- "@gjsify/oxfmt-native": "^0.27.0",
158
- "@gjsify/rolldown-native": "^0.27.0"
157
+ "@gjsify/oxfmt-native": "^0.28.0",
158
+ "@gjsify/rolldown-native": "^0.28.0"
159
159
  },
160
160
  "peerDependenciesMeta": {
161
161
  "@gjsify/oxfmt-native": {