@gjsify/cli 0.4.34 → 0.4.36

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.
@@ -0,0 +1,109 @@
1
+ // `gjsify tsc [tscArgs..]` — Run the TypeScript compiler under GJS via the
2
+ // committed `@gjsify/tsc` bundle (`@gjsify/tsc/bundle` → `dist/tsc.gjs.mjs`).
3
+ //
4
+ // Thin delegator: resolves the bundle path through `createRequire` anchored
5
+ // at the workspace root (falling back to cwd), then spawns
6
+ // `gjs -m <bundle> [tscArgs..]` with LD_LIBRARY_PATH + GI_TYPELIB_PATH set
7
+ // for any installed native gjsify packages (mirrors `gjsify run` exactly).
8
+ // Forwards the child's exit code so CI/scripts see real tsc semantics.
9
+ //
10
+ // Equivalent to invoking the `gjsify-tsc` bin from the @gjsify/tsc package
11
+ // directly — this command just spares the user from having to discover the
12
+ // bin path or remember the bare package name.
13
+ //
14
+ // @gjsify/tsc is a runtime dependency of @gjsify/cli (declared in
15
+ // package.json) so the resolve below succeeds out of the box for any
16
+ // `gjsify install`-managed workspace. The install-hint branch only fires
17
+ // if the dep was removed or the consumer is running a forked CLI.
18
+ //
19
+ // Reference: packages/infra/cli/src/commands/run.ts (env-setup precedent).
20
+ import { spawn } from 'node:child_process';
21
+ import { createRequire } from 'node:module';
22
+ import { pathToFileURL } from 'node:url';
23
+ import { detectNativePackages, buildNativeEnv } from '../utils/detect-native-packages.js';
24
+ import { findWorkspaceRoot } from '../utils/workspace-root.js';
25
+ export const tscCommand = {
26
+ command: 'tsc [tscArgs..]',
27
+ description: 'Run TypeScript compiler (tsc) under GJS via the @gjsify/tsc bundle. All arguments are passed through to tsc. Equivalent to `gjsify-tsc <args>` from the @gjsify/tsc bin.',
28
+ builder: (yargs) =>
29
+ // Pass-through subcommand: tsc owns the entire flag namespace
30
+ // (`--version`, `--help`, `--noEmit`, `-p`, …). Disable yargs's
31
+ // built-in `--version` / `--help` for this command so they don't
32
+ // intercept tsc's own flags (without this, `gjsify tsc --version`
33
+ // would print the gjsify CLI version instead of tsc's). Treat any
34
+ // unknown option as a positional so EVERY flag flows through to
35
+ // `tscArgs`.
36
+ yargs
37
+ .parserConfiguration({
38
+ 'unknown-options-as-args': true,
39
+ })
40
+ .version(false)
41
+ .help(false)
42
+ .positional('tscArgs', {
43
+ description: 'Arguments forwarded verbatim to tsc (e.g. `--version`, `-p tsconfig.json`).',
44
+ type: 'string',
45
+ array: true,
46
+ default: [],
47
+ }),
48
+ handler: async (args) => {
49
+ // `unknown-options-as-args` parks unrecognised flags in `args._`
50
+ // (yargs's positional-overflow channel) — `args.tscArgs` only
51
+ // captures bare positionals, not pass-through flags. `_[0]` is
52
+ // the command name (`tsc`), strip it; the rest is forwarded
53
+ // verbatim, preserving the original flag order.
54
+ const overflow = (args._ ?? []).slice(1).map(String);
55
+ const explicit = args.tscArgs ?? [];
56
+ // When `_` has anything beyond the command name, it already
57
+ // includes both flags AND any bare positionals in the original
58
+ // order — use it directly. Fall back to the explicit positional
59
+ // array for the args-free invocation.
60
+ const tscArgs = overflow.length > 0 ? overflow : explicit;
61
+ const cwd = process.cwd();
62
+ // Anchor resolution at the workspace root so a sub-package `cwd`
63
+ // (e.g. `packages/web/fetch`) still finds the hoisted `@gjsify/tsc`
64
+ // at the root's `node_modules`. Falls back to cwd for standalone
65
+ // (non-monorepo) projects that have the package locally.
66
+ const anchorDir = findWorkspaceRoot(cwd) ?? cwd;
67
+ const anchor = pathToFileURL(`${anchorDir}/__gjsify_tsc__.js`).href;
68
+ const require = createRequire(anchor);
69
+ let bundlePath;
70
+ try {
71
+ bundlePath = require.resolve('@gjsify/tsc/bundle');
72
+ }
73
+ catch {
74
+ console.error('gjsify tsc: @gjsify/tsc is not installed.');
75
+ console.error(' Install with: gjsify install --save-dev @gjsify/tsc');
76
+ process.exit(1);
77
+ }
78
+ // Mirror `gjsify run`'s native-env composition so any future
79
+ // typescript-the-bundle code path that reaches a native bridge
80
+ // (today: none — tsc itself is pure JS) still finds the right
81
+ // typelibs. Costs ~one fs scan per invocation, same as run.
82
+ const nativePackages = detectNativePackages(cwd);
83
+ const nativeEnv = buildNativeEnv(nativePackages);
84
+ const env = {
85
+ ...process.env,
86
+ ...nativeEnv,
87
+ };
88
+ const gjsArgs = ['-m', bundlePath, ...tscArgs];
89
+ const child = spawn('gjs', gjsArgs, { env, stdio: 'inherit' });
90
+ await new Promise((resolvePromise) => {
91
+ child.on('close', (code) => {
92
+ process.exit(code ?? 1);
93
+ });
94
+ child.on('error', (err) => {
95
+ if (err.code === 'ENOENT') {
96
+ console.error('gjsify tsc: `gjs` not found on PATH. Install GJS (e.g. `dnf install gjs`).');
97
+ }
98
+ else {
99
+ console.error(`gjsify tsc: ${err.message}`);
100
+ }
101
+ process.exit(1);
102
+ });
103
+ // Never resolves naturally — process.exit() above terminates
104
+ // the program once the child closes. The promise just keeps
105
+ // the handler alive while gjs runs.
106
+ void resolvePromise;
107
+ });
108
+ },
109
+ };
@@ -0,0 +1,7 @@
1
+ import type { Command } from '../types/index.js';
2
+ interface WhoamiOptions {
3
+ registry?: string;
4
+ json?: boolean;
5
+ }
6
+ export declare const whoamiCommand: Command<unknown, WhoamiOptions>;
7
+ export {};
@@ -0,0 +1,118 @@
1
+ // `gjsify whoami [--registry <url>] [--json]`
2
+ //
3
+ // Prints the npm-registry username for the current `~/.npmrc` token. The
4
+ // natural CLI surface for the `whoami(registry, npmrc)` helper introduced
5
+ // in #390 (originally as the dead-token-vs-missing-package diagnostic for
6
+ // `gjsify publish`).
7
+ //
8
+ // Goal: maintainers should be able to verify `~/.npmrc` auth without the
9
+ // extra `curl + Authorization: Bearer …` dance documented in AGENTS.md.
10
+ // The four observable outcomes map to:
11
+ //
12
+ // 1. `{username: "..."}` from the registry → print
13
+ // Logged in as: <username>
14
+ // Registry: <url>
15
+ // exit 0.
16
+ // 2. `{}` from the registry → the token exists in npmrc but the
17
+ // registry no longer accepts it. Emit a clear "token appears dead or
18
+ // revoked" message plus the refresh instructions, exit 1.
19
+ // 3. No `_authToken` (and no basic-auth) in any resolved npmrc → emit
20
+ // a "no token configured" message pointing at `npm login`, exit 1.
21
+ // 4. Network / non-2xx / non-JSON error → surface the underlying
22
+ // error message + registry URL, exit 1.
23
+ //
24
+ // With `--json` every branch emits a single-line JSON object instead of
25
+ // the human-readable text — useful for CI scripts that want to gate
26
+ // behavior on `username` without parsing free-form output.
27
+ //
28
+ // Reference: `npm whoami` (refs/npm-cli/lib/commands/whoami.js).
29
+ import { DEFAULT_REGISTRY, whoami } from '@gjsify/npm-registry';
30
+ import { hasAnyCredential, loadNpmrc } from '../utils/load-npmrc.js';
31
+ export const whoamiCommand = {
32
+ command: 'whoami',
33
+ description: 'Print the npm-registry username for the current ~/.npmrc token. Clear failure message when the token is dead, missing, or the registry is unreachable.',
34
+ builder: (yargs) => yargs
35
+ .option('registry', {
36
+ description: `Registry URL to probe. Default: scope-aware lookup from .npmrc (falls back to ${DEFAULT_REGISTRY}).`,
37
+ type: 'string',
38
+ })
39
+ .option('json', {
40
+ description: 'Emit `{username, registry}` (or `{error, registry}`) as a single-line JSON object.',
41
+ type: 'boolean',
42
+ default: false,
43
+ }),
44
+ handler: async (args) => {
45
+ const npmrc = await loadNpmrc(process.cwd());
46
+ // Registry resolution order matches `gjsify publish`:
47
+ // `--registry` flag > `$npm_config_registry` > `.npmrc` registry >
48
+ // `DEFAULT_REGISTRY`. The scope-aware `registryFor()` lookup is
49
+ // intentionally NOT used here — `whoami` is account-scoped, not
50
+ // package-scoped, so the user's *default* registry is what they
51
+ // want to verify.
52
+ const registry = args.registry ?? process.env.npm_config_registry ?? npmrc.registry ?? DEFAULT_REGISTRY;
53
+ const registryClean = registry.endsWith('/') ? registry.slice(0, -1) : registry;
54
+ const asJson = args.json === true;
55
+ // Branch 3 — no credential configured at all. Catch this before
56
+ // the network call so the message points at the real fix
57
+ // (`npm login`) instead of a registry-side 401.
58
+ if (!hasAnyCredential(npmrc)) {
59
+ if (asJson) {
60
+ process.stdout.write(`${JSON.stringify({ error: 'no-token-configured', registry: registryClean })}\n`);
61
+ }
62
+ else {
63
+ process.stderr.write([
64
+ 'gjsify whoami: no npm token configured.',
65
+ '',
66
+ `No \`_authToken\` found in ~/.npmrc / $NPM_CONFIG_USERCONFIG / .npmrc for ${registryClean}.`,
67
+ '',
68
+ 'Add one via: npm login',
69
+ 'Then verify: gjsify whoami',
70
+ ].join('\n') + '\n');
71
+ }
72
+ process.exit(1);
73
+ }
74
+ let result;
75
+ try {
76
+ result = await whoami(registry, npmrc);
77
+ }
78
+ catch (err) {
79
+ // Branch 4 — network / non-2xx / parse failure.
80
+ const message = err instanceof Error ? err.message : String(err);
81
+ if (asJson) {
82
+ process.stdout.write(`${JSON.stringify({ error: message, registry: registryClean })}\n`);
83
+ }
84
+ else {
85
+ process.stderr.write(`gjsify whoami: ${message}\n`);
86
+ process.stderr.write(`Registry: ${registryClean}\n`);
87
+ }
88
+ process.exit(1);
89
+ return; // unreachable but pleases the type narrower
90
+ }
91
+ if (result.username && result.username.length > 0) {
92
+ // Branch 1 — live token.
93
+ if (asJson) {
94
+ process.stdout.write(`${JSON.stringify({ username: result.username, registry: registryClean })}\n`);
95
+ }
96
+ else {
97
+ process.stdout.write(`Logged in as: ${result.username}\n`);
98
+ process.stdout.write(`Registry: ${registryClean}\n`);
99
+ }
100
+ return;
101
+ }
102
+ // Branch 2 — dead/revoked token (registry returned `{}`).
103
+ if (asJson) {
104
+ process.stdout.write(`${JSON.stringify({ error: 'dead-token', registry: registryClean })}\n`);
105
+ }
106
+ else {
107
+ process.stderr.write([
108
+ 'gjsify whoami: token appears dead or revoked (registry returned an empty whoami response).',
109
+ '',
110
+ 'Refresh via: npm login',
111
+ 'Then verify: gjsify whoami',
112
+ '',
113
+ 'For the @gjsify scope, see AGENTS.md > "New @gjsify/* package: first-publish + Trusted Publisher bootstrap".',
114
+ ].join('\n') + '\n');
115
+ }
116
+ process.exit(1);
117
+ },
118
+ };
@@ -3,6 +3,10 @@ interface WorkspaceCmdOptions {
3
3
  name: string;
4
4
  script: string;
5
5
  args?: string[];
6
+ 'with-dependencies'?: boolean;
7
+ 'continue-on-error'?: boolean;
8
+ 'include-dev'?: boolean;
9
+ verbose?: boolean;
6
10
  }
7
11
  export declare const workspaceCommand: Command<unknown, WorkspaceCmdOptions>;
8
12
  export {};
@@ -3,8 +3,19 @@
3
3
  // Equivalent to `yarn workspace <name> run <script>`: locates the named
4
4
  // workspace in the current monorepo, then runs the script there. Used
5
5
  // extensively in gjsify's own root `package.json` (17 call sites).
6
+ //
7
+ // With `--with-dependencies` / `-d` (synonym: `--topological` / `-t`) the
8
+ // command first runs the SAME script in every transitive workspace
9
+ // dependency, in topological build order, then in the target package.
10
+ // Skips deps that don't declare the script (`--if-present` behaviour).
11
+ // Stops on the first failure unless `--continue-on-error` is passed.
12
+ //
13
+ // This replaces the manual `gjsify workspace <A> build && gjsify workspace
14
+ // <B> build && …` chains in root `build:infra` scripts: cascade build
15
+ // failures on uninbuilt workspace deps are the single biggest local-dev
16
+ // pain point in this monorepo.
6
17
  import { spawn } from 'node:child_process';
7
- import { discoverWorkspaces } from '@gjsify/workspace';
18
+ import { buildDependencyGraph, discoverWorkspaces, topologicalSort, } from '@gjsify/workspace';
8
19
  import { findWorkspaceRoot } from '../utils/workspace-root.js';
9
20
  export const workspaceCommand = {
10
21
  command: 'workspace <name> <script> [args..]',
@@ -24,6 +35,31 @@ export const workspaceCommand = {
24
35
  description: 'Extra arguments forwarded to the script.',
25
36
  type: 'string',
26
37
  array: true,
38
+ })
39
+ .option('with-dependencies', {
40
+ // `-t`/`--topological` is the same flag spelled the way
41
+ // `gjsify foreach` already spells it — kept as an alias so
42
+ // muscle memory transfers.
43
+ description: 'Pre-build the target workspace\'s transitive workspace dependencies in topological order before running the script in the target. Deps that don\'t declare the script are skipped (--if-present behaviour). Replaces manual `gjsify workspace A build && gjsify workspace B build && …` chains.',
44
+ type: 'boolean',
45
+ alias: ['d', 't', 'topological'],
46
+ default: false,
47
+ })
48
+ .option('include-dev', {
49
+ description: 'When --with-dependencies is set, also walk devDependencies (production deps only by default — matches `gjsify foreach -t`).',
50
+ type: 'boolean',
51
+ default: false,
52
+ })
53
+ .option('continue-on-error', {
54
+ description: 'When --with-dependencies is set, keep running remaining deps after one fails (default: stop on first failure).',
55
+ type: 'boolean',
56
+ default: false,
57
+ })
58
+ .option('verbose', {
59
+ description: 'Echo every spawned command before running it.',
60
+ type: 'boolean',
61
+ alias: 'v',
62
+ default: false,
27
63
  }),
28
64
  handler: async (args) => {
29
65
  // Walk up to the monorepo root — `gjsify workspace` is often
@@ -31,50 +67,141 @@ export const workspaceCommand = {
31
67
  // `build:deps` calls `gjsify workspace @gjsify/adwaita-web …`),
32
68
  // where process.cwd() is the child workspace, not the monorepo root.
33
69
  const root = findWorkspaceRoot(process.cwd()) ?? process.cwd();
34
- const workspaces = discoverWorkspaces(root);
35
- const target = workspaces.find((w) => w.name === args.name);
70
+ const allWorkspaces = discoverWorkspaces(root);
71
+ const target = allWorkspaces.find((w) => w.name === args.name);
36
72
  if (!target) {
37
- console.error(`gjsify workspace: no workspace named "${args.name}" — discovered ${workspaces.length} workspace(s)`);
73
+ console.error(`gjsify workspace: no workspace named "${args.name}" — discovered ${allWorkspaces.length} workspace(s)`);
38
74
  process.exit(1);
39
75
  }
40
- const scripts = target.manifest.scripts ?? {};
41
- if (typeof scripts[args.script] !== 'string') {
76
+ const runner = detectPackageManager();
77
+ const verbose = args.verbose === true;
78
+ const withDeps = args['with-dependencies'] === true;
79
+ const continueOnError = args['continue-on-error'] === true;
80
+ const targetScripts = target.manifest.scripts ?? {};
81
+ if (typeof targetScripts[args.script] !== 'string') {
42
82
  console.error(`gjsify workspace: workspace "${args.name}" has no script "${args.script}"`);
43
83
  process.exit(1);
44
84
  }
45
- const runner = detectPackageManager();
46
- const argv = runner === 'gjsify'
47
- ? ['run', args.script, ...(args.args ?? [])]
48
- : ['run', args.script, ...(args.args && args.args.length > 0 ? ['--', ...args.args] : [])];
49
- // Default FORCE_COLOR=1 unless the user explicitly opted out (matches
50
- // yarn / npm / gjsify run behaviour) — without this, tools that key
51
- // on isTTY (chalk, picocolors, biome) drop colors when stdout is a
52
- // pipe, including GitHub Actions where the log viewer renders ANSI
53
- // fine.
54
- const colorEnv = process.env.FORCE_COLOR !== undefined || process.env.NO_COLOR !== undefined ? {} : { FORCE_COLOR: '1' };
55
- await new Promise((resolve, reject) => {
56
- const child = spawn(runner, argv, {
57
- cwd: target.location,
58
- stdio: 'inherit',
59
- env: { ...process.env, ...colorEnv },
60
- });
61
- child.on('close', (code) => {
62
- if (code === 0)
63
- resolve();
64
- else
65
- reject(new Error(`${runner} ${argv.join(' ')} exited with code ${code}`));
66
- });
67
- child.on('error', reject);
68
- }).catch((err) => {
69
- console.error(err.message);
85
+ // Build the run-list: either just the target, or its transitive
86
+ // workspace-dep closure in topological order followed by the
87
+ // target itself.
88
+ let runList;
89
+ if (withDeps) {
90
+ const closure = collectTransitiveClosure(target, allWorkspaces, args['include-dev'] === true);
91
+ // Sort the closure topologically using the shared @gjsify/workspace
92
+ // algorithm same code path that drives `gjsify foreach -t`.
93
+ const graph = buildDependencyGraph(closure, { includeDev: args['include-dev'] === true });
94
+ runList = topologicalSort(graph);
95
+ }
96
+ else {
97
+ runList = [target];
98
+ }
99
+ const failures = [];
100
+ for (const ws of runList) {
101
+ const scripts = ws.manifest.scripts ?? {};
102
+ if (typeof scripts[args.script] !== 'string') {
103
+ // Skip deps that don't declare the script — mirrors
104
+ // `gjsify foreach`'s --if-present behaviour. The target
105
+ // itself was validated above; this branch only filters
106
+ // intermediate deps.
107
+ if (verbose)
108
+ console.error(`[${ws.name}] (no "${args.script}" script — skipping)`);
109
+ continue;
110
+ }
111
+ try {
112
+ await runOne(ws, args.script, args.args ?? [], runner, verbose);
113
+ }
114
+ catch (err) {
115
+ const e = err instanceof Error ? err : new Error(String(err));
116
+ console.error(`[${ws.name}] ${e.message}`);
117
+ if (!continueOnError) {
118
+ process.exit(1);
119
+ }
120
+ failures.push({ workspace: ws.name, error: e });
121
+ }
122
+ }
123
+ if (failures.length > 0) {
124
+ console.error(`gjsify workspace: ${failures.length} workspace(s) failed: ${failures.map((f) => f.workspace).join(', ')}`);
70
125
  process.exit(1);
71
- });
126
+ }
72
127
  // ensureMainLoop() (called inside spawn) keeps GJS alive after the
73
128
  // child exits — without an explicit process.exit() the success path
74
129
  // would park the loop forever.
75
130
  process.exit(0);
76
131
  },
77
132
  };
133
+ /**
134
+ * Walk the workspace-dep graph from `target`, collecting every transitive
135
+ * workspace dependency (production + optional, plus devDependencies when
136
+ * `includeDev`). The returned list includes `target` itself so the caller
137
+ * can pass it straight to `buildDependencyGraph` / `topologicalSort`.
138
+ */
139
+ function collectTransitiveClosure(target, allWorkspaces, includeDev) {
140
+ const byName = new Map();
141
+ for (const ws of allWorkspaces)
142
+ byName.set(ws.name, ws);
143
+ const seen = new Set();
144
+ const out = [];
145
+ const stack = [target];
146
+ while (stack.length > 0) {
147
+ const ws = stack.pop();
148
+ if (seen.has(ws.name))
149
+ continue;
150
+ seen.add(ws.name);
151
+ out.push(ws);
152
+ const m = ws.manifest;
153
+ const blocks = [
154
+ m.dependencies,
155
+ includeDev ? m.devDependencies : undefined,
156
+ m.optionalDependencies,
157
+ // peerDependencies excluded by default (yarn does the same)
158
+ ];
159
+ for (const block of blocks) {
160
+ if (!block)
161
+ continue;
162
+ for (const [depName, spec] of Object.entries(block)) {
163
+ if (typeof spec !== 'string')
164
+ continue;
165
+ if (!spec.startsWith('workspace:'))
166
+ continue;
167
+ const dep = byName.get(depName);
168
+ if (!dep)
169
+ continue;
170
+ if (!seen.has(dep.name))
171
+ stack.push(dep);
172
+ }
173
+ }
174
+ }
175
+ return out;
176
+ }
177
+ async function runOne(ws, script, extraArgs, runner, verbose) {
178
+ const argv = runner === 'gjsify'
179
+ ? ['run', script, ...extraArgs]
180
+ : ['run', script, ...(extraArgs.length > 0 ? ['--', ...extraArgs] : [])];
181
+ if (verbose) {
182
+ console.error(`[${ws.name}] $ ${runner} ${argv.join(' ')}`);
183
+ }
184
+ // Default FORCE_COLOR=1 unless the user explicitly opted out (matches
185
+ // yarn / npm / gjsify run behaviour) — without this, tools that key
186
+ // on isTTY (chalk, picocolors, biome) drop colors when stdout is a
187
+ // pipe, including GitHub Actions where the log viewer renders ANSI
188
+ // fine.
189
+ const colorEnv = process.env.FORCE_COLOR !== undefined || process.env.NO_COLOR !== undefined ? {} : { FORCE_COLOR: '1' };
190
+ await new Promise((resolve, reject) => {
191
+ const child = spawn(runner, argv, {
192
+ cwd: ws.location,
193
+ stdio: 'inherit',
194
+ env: { ...process.env, ...colorEnv },
195
+ });
196
+ child.on('close', (code) => {
197
+ if (code === 0)
198
+ resolve();
199
+ else
200
+ reject(new Error(`${runner} ${argv.join(' ')} exited with code ${code}`));
201
+ });
202
+ child.on('error', reject);
203
+ });
204
+ }
78
205
  function detectPackageManager() {
79
206
  const ua = process.env.npm_config_user_agent ?? '';
80
207
  if (ua.startsWith('yarn/'))
package/lib/index.js CHANGED
@@ -4,7 +4,7 @@ import { dirname, join } from 'node:path';
4
4
  import { fileURLToPath } from 'node:url';
5
5
  import yargs from 'yargs';
6
6
  import { hideBin } from 'yargs/helpers';
7
- import { buildCommand as build, testCommand as test, runCommand as run, infoCommand as info, systemCheckCommand as systemCheck, checkCommand as check, showcaseCommand as showcase, createCommand as create, gresourceCommand as gresource, gettextCommand as gettext, gsettingsCommand as gsettings, flatpakCommand as flatpak, dlxCommand as dlx, installCommand as install, foreachCommand as foreach, workspaceCommand as workspace, packCommand as pack, publishCommand as publish, selfUpdateCommand as selfUpdate, generateInstallerCommand as generateInstaller, uninstallCommand as uninstall, formatCommand as format, lintCommand as lint, fixCommand as fix, upgradeCommand as upgrade, barrelsCommand as barrels, } from './commands/index.js';
7
+ import { buildCommand as build, testCommand as test, runCommand as run, infoCommand as info, systemCheckCommand as systemCheck, checkCommand as check, showcaseCommand as showcase, createCommand as create, gresourceCommand as gresource, gettextCommand as gettext, gsettingsCommand as gsettings, flatpakCommand as flatpak, dlxCommand as dlx, installCommand as install, foreachCommand as foreach, workspaceCommand as workspace, packCommand as pack, publishCommand as publish, whoamiCommand as whoami, selfUpdateCommand as selfUpdate, generateInstallerCommand as generateInstaller, uninstallCommand as uninstall, formatCommand as format, lintCommand as lint, fixCommand as fix, upgradeCommand as upgrade, barrelsCommand as barrels, tscCommand as tsc, affectedCommand as affected, } from './commands/index.js';
8
8
  import { APP_NAME } from './constants.js';
9
9
  // Detect which runtime is executing the CLI (GJS or Node.js).
10
10
  // GJS MUST be checked first because @gjsify/process sets
@@ -79,6 +79,7 @@ await cli
79
79
  .command(workspace.command, workspace.description, workspace.builder, workspace.handler)
80
80
  .command(pack.command, pack.description, pack.builder, pack.handler)
81
81
  .command(publish.command, publish.description, publish.builder, publish.handler)
82
+ .command(whoami.command, whoami.description, whoami.builder, whoami.handler)
82
83
  .command(selfUpdate.command, selfUpdate.description, selfUpdate.builder, selfUpdate.handler)
83
84
  .command(generateInstaller.command, generateInstaller.description, generateInstaller.builder, generateInstaller.handler)
84
85
  .command(uninstall.command, uninstall.description, uninstall.builder, uninstall.handler)
@@ -87,6 +88,8 @@ await cli
87
88
  .command(lint.command, lint.description, lint.builder, lint.handler)
88
89
  .command(fix.command, fix.description, fix.builder, fix.handler)
89
90
  .command(barrels.command, barrels.description, barrels.builder, barrels.handler)
91
+ .command(tsc.command, tsc.description, tsc.builder, tsc.handler)
92
+ .command(affected.command, affected.description, affected.builder, affected.handler)
90
93
  .demandCommand(1)
91
94
  .epilogue(`Running on ${runtimeLabel()}`)
92
95
  .help()
@@ -6,5 +6,5 @@ Icon={{APP_ID}}
6
6
  Terminal=false
7
7
  Type=Application
8
8
  Categories={{CATEGORIES_LINE}}
9
- {{KEYWORDS_LINE}}StartupNotify=true
9
+ {{KEYWORDS_LINE}}{{MIMETYPES_LINE}}StartupNotify=true
10
10
  StartupWMClass={{APP_ID}}