@godxjp/ui 26.1.0 → 26.2.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.
- package/dist/contracts/measurement.json +1 -1
- package/dist/styles/control.css +8 -8
- package/dist/styles/float-button-layout.css +1 -1
- package/dist/styles/focus-ring.css +1 -1
- package/dist/styles/layout.css +8 -1
- package/dist/styles/shell-layout.css +5 -5
- package/dist/tokens/components/control.css +7 -6
- package/dist/tokens/components/float-button.css +1 -1
- package/dist/tokens/components/segmented.css +1 -1
- package/dist/tokens/components/shell.css +4 -4
- package/dist/tokens/foundation.css +4 -7
- package/docs/CUSTOMER-THEMING.md +4 -0
- package/package.json +2 -2
- package/scripts/_agent-setup.mjs +23 -3
- package/scripts/cli.mjs +63 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$comment": "AUTO-GENERATED by scripts/gen-measurement-contract.mjs — do not edit. Read this instead of guessing: docs/MEASUREMENT-CONTRACT.md.",
|
|
3
|
-
"version": "26.
|
|
3
|
+
"version": "26.2.0",
|
|
4
4
|
"targetSize": {
|
|
5
5
|
"standard": "WCAG 2.2 SC 2.5.8 Target Size (Minimum), level AA — 24×24 CSS px",
|
|
6
6
|
"min": 24,
|
package/dist/styles/control.css
CHANGED
|
@@ -1119,7 +1119,7 @@
|
|
|
1119
1119
|
}
|
|
1120
1120
|
|
|
1121
1121
|
.ui-segmented-item:not([data-state="checked"]):not([data-disabled]):hover {
|
|
1122
|
-
background: hsl(var(--segmented-item-hover-background));
|
|
1122
|
+
background: hsl(var(--segmented-item-hover-background, var(--accent)));
|
|
1123
1123
|
color: hsl(var(--segmented-item-hover-color));
|
|
1124
1124
|
}
|
|
1125
1125
|
.ui-segmented-item:not([data-state="checked"]):not([data-disabled]):active {
|
|
@@ -2722,7 +2722,7 @@
|
|
|
2722
2722
|
}
|
|
2723
2723
|
|
|
2724
2724
|
.ui-control--filled:hover:not(:disabled):not([readonly]):not([data-disabled]) {
|
|
2725
|
-
background-color: hsl(var(--control-variant-filled-hover-background));
|
|
2725
|
+
background-color: hsl(var(--control-variant-filled-hover-background, var(--accent)));
|
|
2726
2726
|
}
|
|
2727
2727
|
|
|
2728
2728
|
.ui-control--borderless {
|
|
@@ -2939,7 +2939,7 @@
|
|
|
2939
2939
|
}
|
|
2940
2940
|
|
|
2941
2941
|
.ui-slider-dot[data-active="true"] {
|
|
2942
|
-
border-color: hsl(var(--slider-dot-active-border-color));
|
|
2942
|
+
border-color: hsl(var(--slider-dot-active-border-color, var(--primary)));
|
|
2943
2943
|
}
|
|
2944
2944
|
|
|
2945
2945
|
.ui-slider-tooltip {
|
|
@@ -3053,14 +3053,14 @@
|
|
|
3053
3053
|
}
|
|
3054
3054
|
|
|
3055
3055
|
.ui-radio-button[data-state="checked"] {
|
|
3056
|
-
color: hsl(var(--choice-button-selected-color));
|
|
3057
|
-
border-color: hsl(var(--choice-button-selected-border-color));
|
|
3056
|
+
color: hsl(var(--choice-button-selected-color, var(--primary)));
|
|
3057
|
+
border-color: hsl(var(--choice-button-selected-border-color, var(--primary)));
|
|
3058
3058
|
}
|
|
3059
3059
|
|
|
3060
3060
|
.ui-radio-button-bar[data-button-style="solid"] .ui-radio-button[data-state="checked"] {
|
|
3061
|
-
color: hsl(var(--choice-button-solid-color));
|
|
3062
|
-
background: hsl(var(--choice-button-solid-background));
|
|
3063
|
-
border-color: hsl(var(--choice-button-solid-background));
|
|
3061
|
+
color: hsl(var(--choice-button-solid-color, var(--primary-foreground)));
|
|
3062
|
+
background: hsl(var(--choice-button-solid-background, var(--primary)));
|
|
3063
|
+
border-color: hsl(var(--choice-button-solid-background, var(--primary)));
|
|
3064
3064
|
}
|
|
3065
3065
|
|
|
3066
3066
|
.ui-radio-button[data-disabled] {
|
|
@@ -143,7 +143,7 @@
|
|
|
143
143
|
content: "";
|
|
144
144
|
inset: 0;
|
|
145
145
|
background: conic-gradient(
|
|
146
|
-
var(--float-button-progress-color) var(--float-button-progress-offset),
|
|
146
|
+
var(--float-button-progress-color, hsl(var(--primary))) var(--float-button-progress-offset),
|
|
147
147
|
var(--float-button-progress-track-color) var(--float-button-progress-offset)
|
|
148
148
|
);
|
|
149
149
|
mask: radial-gradient(
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
.ui-otp-slot[data-active="true"],
|
|
54
54
|
.ui-otp-group[data-appearance="grouped"]:has(.ui-otp-slot[data-active="true"]) {
|
|
55
55
|
outline: var(--focus-ring-width) solid
|
|
56
|
-
hsl(var(--focus-outline-color) / var(--focus-ring-opacity, 1));
|
|
56
|
+
hsl(var(--focus-outline-color, var(--focus-ring-color, var(--ring))) / var(--focus-ring-opacity, 1));
|
|
57
57
|
outline-offset: var(--focus-ring-offset);
|
|
58
58
|
|
|
59
59
|
transition:
|
package/dist/styles/layout.css
CHANGED
|
@@ -96,7 +96,14 @@
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
.ui-brand-glow {
|
|
99
|
-
background-image: var(
|
|
99
|
+
background-image: var(
|
|
100
|
+
--brand-glow,
|
|
101
|
+
radial-gradient(
|
|
102
|
+
ellipse var(--brand-glow-size) at var(--brand-glow-position),
|
|
103
|
+
hsl(var(--brand-glow-color, var(--primary)) / var(--brand-glow-alpha)),
|
|
104
|
+
transparent 70%
|
|
105
|
+
)
|
|
106
|
+
);
|
|
100
107
|
pointer-events: none;
|
|
101
108
|
}
|
|
102
109
|
|
|
@@ -1434,8 +1434,8 @@
|
|
|
1434
1434
|
}
|
|
1435
1435
|
|
|
1436
1436
|
.ui-app-launcher-tile:hover {
|
|
1437
|
-
background: hsl(var(--app-launcher-tile-hover-background));
|
|
1438
|
-
color: hsl(var(--app-launcher-tile-hover-color));
|
|
1437
|
+
background: hsl(var(--app-launcher-tile-hover-background, var(--accent)));
|
|
1438
|
+
color: hsl(var(--app-launcher-tile-hover-color, var(--accent-foreground)));
|
|
1439
1439
|
}
|
|
1440
1440
|
|
|
1441
1441
|
.ui-app-launcher-tile[aria-current="page"] {
|
|
@@ -2040,14 +2040,14 @@
|
|
|
2040
2040
|
}
|
|
2041
2041
|
|
|
2042
2042
|
.ui-topbar-item:hover {
|
|
2043
|
-
background: hsl(var(--topbar-item-hover-background));
|
|
2044
|
-
color: hsl(var(--topbar-item-hover-color));
|
|
2043
|
+
background: hsl(var(--topbar-item-hover-background, var(--accent)));
|
|
2044
|
+
color: hsl(var(--topbar-item-hover-color, var(--accent-foreground)));
|
|
2045
2045
|
}
|
|
2046
2046
|
|
|
2047
2047
|
.ui-topbar-item:active,
|
|
2048
2048
|
.ui-topbar-item[data-state="open"] {
|
|
2049
2049
|
background: hsl(var(--topbar-item-active-background));
|
|
2050
|
-
color: hsl(var(--topbar-item-hover-color));
|
|
2050
|
+
color: hsl(var(--topbar-item-hover-color, var(--accent-foreground)));
|
|
2051
2051
|
}
|
|
2052
2052
|
|
|
2053
2053
|
.ui-topbar-item:disabled,
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
--number-input-touch-height: var(--band-height-2xl);
|
|
36
36
|
|
|
37
37
|
--control-variant-filled-background: var(--muted);
|
|
38
|
-
--control-variant-filled-hover-background:
|
|
38
|
+
--control-variant-filled-hover-background: initial;
|
|
39
39
|
|
|
40
40
|
--control-count-font-size: var(--font-size-sm);
|
|
41
41
|
--control-count-color: var(--muted-foreground);
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
--slider-dot-size: var(--slider-track-height);
|
|
59
59
|
--slider-dot-background: var(--background);
|
|
60
60
|
--slider-dot-border-color: var(--border);
|
|
61
|
-
--slider-dot-active-border-color:
|
|
61
|
+
--slider-dot-active-border-color: initial;
|
|
62
62
|
--slider-tooltip-background: var(--popover);
|
|
63
63
|
--slider-tooltip-color: var(--popover-foreground);
|
|
64
64
|
--slider-tooltip-font-size: var(--font-size-xs);
|
|
@@ -69,10 +69,11 @@
|
|
|
69
69
|
--choice-button-background: var(--background);
|
|
70
70
|
--choice-button-color: var(--foreground);
|
|
71
71
|
--choice-button-border-color: var(--input);
|
|
72
|
-
|
|
73
|
-
--choice-button-selected-
|
|
74
|
-
--choice-button-
|
|
75
|
-
--choice-button-solid-
|
|
72
|
+
|
|
73
|
+
--choice-button-selected-color: initial;
|
|
74
|
+
--choice-button-selected-border-color: initial;
|
|
75
|
+
--choice-button-solid-background: initial;
|
|
76
|
+
--choice-button-solid-color: initial;
|
|
76
77
|
|
|
77
78
|
--toggle-focus-ring-width: var(--stroke-lg);
|
|
78
79
|
--toggle-focus-ring-alpha: 1;
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
|
|
33
33
|
--float-button-progress-offset: 0turn;
|
|
34
34
|
--float-button-progress-width: var(--space-1);
|
|
35
|
-
--float-button-progress-color:
|
|
35
|
+
--float-button-progress-color: initial;
|
|
36
36
|
--float-button-progress-track-color: hsl(var(--border));
|
|
37
37
|
|
|
38
38
|
--float-button-motion-translate: var(--float-button-size);
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
--segmented-item-hover-color: var(--foreground);
|
|
18
18
|
--segmented-item-selected-color: var(--foreground);
|
|
19
19
|
|
|
20
|
-
--segmented-item-hover-background:
|
|
20
|
+
--segmented-item-hover-background: initial;
|
|
21
21
|
--segmented-item-active-background: var(--secondary);
|
|
22
22
|
|
|
23
23
|
--segmented-item-selected-background: var(--background);
|
|
@@ -110,8 +110,8 @@
|
|
|
110
110
|
--topbar-item-radius: var(--radius-sharp);
|
|
111
111
|
--topbar-item-color: var(--muted-foreground);
|
|
112
112
|
|
|
113
|
-
--topbar-item-hover-background:
|
|
114
|
-
--topbar-item-hover-color:
|
|
113
|
+
--topbar-item-hover-background: initial;
|
|
114
|
+
--topbar-item-hover-color: initial;
|
|
115
115
|
--topbar-item-active-background: var(--secondary);
|
|
116
116
|
|
|
117
117
|
--topbar-item-badge-offset-block: var(--space-1);
|
|
@@ -158,8 +158,8 @@
|
|
|
158
158
|
--app-launcher-tile-min-height: var(--control-height-comfortable);
|
|
159
159
|
--app-launcher-tile-radius: var(--radius);
|
|
160
160
|
--app-launcher-tile-color: var(--foreground);
|
|
161
|
-
--app-launcher-tile-hover-background:
|
|
162
|
-
--app-launcher-tile-hover-color:
|
|
161
|
+
--app-launcher-tile-hover-background: initial;
|
|
162
|
+
--app-launcher-tile-hover-color: initial;
|
|
163
163
|
|
|
164
164
|
--app-launcher-tile-current-background: initial;
|
|
165
165
|
--app-launcher-mark-size: 2.5rem;
|
|
@@ -100,19 +100,16 @@
|
|
|
100
100
|
|
|
101
101
|
--shadow-glow: 0 0 0 0 transparent;
|
|
102
102
|
|
|
103
|
-
--brand-glow-color:
|
|
103
|
+
--brand-glow-color: initial;
|
|
104
104
|
--brand-glow-alpha: 0.18;
|
|
105
105
|
--brand-glow-size: 60% 50%;
|
|
106
106
|
--brand-glow-position: 50% 0%;
|
|
107
|
-
--brand-glow:
|
|
108
|
-
ellipse var(--brand-glow-size) at var(--brand-glow-position),
|
|
109
|
-
hsl(var(--brand-glow-color) / var(--brand-glow-alpha)),
|
|
110
|
-
transparent 70%
|
|
111
|
-
);
|
|
107
|
+
--brand-glow: initial;
|
|
112
108
|
|
|
113
109
|
--focus-outline: 1;
|
|
114
110
|
--focus-outline-weight: var(--stroke-hairline);
|
|
115
|
-
|
|
111
|
+
|
|
112
|
+
--focus-outline-color: initial;
|
|
116
113
|
|
|
117
114
|
--control-outline-width: calc(var(--stroke-md) * var(--focus-outline));
|
|
118
115
|
--focus-outline-offset: 0px;
|
package/docs/CUSTOMER-THEMING.md
CHANGED
|
@@ -243,6 +243,9 @@ The interaction states are **derived from the `--primary` in scope, at the eleme
|
|
|
243
243
|
| `--control-outline` | **yes** — the focused field's halo (`--control-outline-alpha` stays per theme) | light `h s calc(l - 5.3)`, dark `h calc(s * 0.99) calc(l - 25.1)` |
|
|
244
244
|
| `--primary-border` | **yes** (painted by no package surface; kept for the measurement in DESIGN-AUTHORITY) | light `h calc(s * 0.68) calc(l + 16)`, dark `h calc(s * 0.467) calc(l * 0.27043)` |
|
|
245
245
|
| `--sidebar-item-active-foreground` | **yes** — defaults to the live `--primary-active` | — |
|
|
246
|
+
| `--focus-outline-color` | **yes, through `--ring`** — every keyboard-focus outline (gh#687) | `var(--focus-ring-color, var(--ring))`, read at the focused element — so it follows the `--ring` you set in the scope |
|
|
247
|
+
| Radio button bar selected (`--choice-button-*`), Slider active dot, BackTop progress, `.ui-brand-glow` | **yes** (gh#687) | `var(--primary)` / `var(--primary-foreground)` at the call site |
|
|
248
|
+
| Topbar item / AppLauncher tile / Segmented / filled-control hover | **follow `--accent`** (gh#687) | `var(--accent)` / `var(--accent-foreground)` at the call site |
|
|
246
249
|
| `--primary-foreground` | **no — set it** | the label on a filled primary; you choose it for your seed |
|
|
247
250
|
| `--ring` | **only on the element that declares `--primary`** — set it in a nested scope | `var(--primary)` on `:root` / `.dark`. `--ring` is a public role read as `hsl(var(--ring))` in consumer CSS, so it cannot become a live default; a scope below `<html>` inherits the root's |
|
|
248
251
|
| `--destructive-*`, `--control-outline-error` | no — not brand | literals |
|
|
@@ -251,6 +254,7 @@ On the package seed these produce exactly the identity kit values the tier used
|
|
|
251
254
|
|
|
252
255
|
**Rules that come with it:**
|
|
253
256
|
|
|
257
|
+
- **No token tier binds to a scoped role at `:root`.** Every knob whose default is `--primary`, `--primary-foreground`, `--ring`, `--accent` or `--accent-foreground` is `initial`, with the role as the call-site fallback — `--ring` itself is the one exception (above). `tenant-scope-freeze-687.test.ts` holds it.
|
|
254
258
|
- **Override a state only by setting its knob** (`--primary-hover: 221 90% 72%`). A set knob wins over the derived default, in its own scope and below.
|
|
255
259
|
- **Read a state through its fallback, not bare.** The four knobs are `initial` so that the default can resolve at the painting element (docs/TOKENS.md, the freeze rule). `hsl(var(--primary-hover))` on its own therefore paints nothing — use the utility (`bg-primary-hover`) or `hsl(var(--primary-hover, from hsl(var(--primary)) var(--primary-hover-channels)))`.
|
|
256
260
|
- **Label polarity.** The theme's pair steps AWAY from that theme's default label: `darken` under a light label, `lighten` under a dark one, which keeps a label that clears 4.5:1 at rest at 4.5:1 in hover and pressed for every seed (measured, `derived-seed-sweep.test.ts`). If your seed needs the OTHER polarity of label (a pale yellow with dark text in the light theme), point the pair at it too — `applyPrimaryColor()` does this automatically from the label it picks:
|
package/package.json
CHANGED
package/scripts/_agent-setup.mjs
CHANGED
|
@@ -45,6 +45,19 @@ function mcpEntryMatches(a, b) {
|
|
|
45
45
|
return keysA.every((k) => envA[k] === envB[k]);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
/**
|
|
49
|
+
* True when `entry` is the shape THIS package writes (`npx @godxjp/ui-mcp@<pin>`, env at most
|
|
50
|
+
* GODX_UI_VERSION), whatever pin and version it carries. Such an entry is ours to move forward on
|
|
51
|
+
* upgrade: treating it as custom left consumers on the MCP of the release they first installed
|
|
52
|
+
* (a `@godxjp/ui-mcp@25.4.0` pin survived the upgrade to 26.x).
|
|
53
|
+
*/
|
|
54
|
+
function isPackageWrittenMcpEntry(entry) {
|
|
55
|
+
if (entry?.command !== "npx") return false;
|
|
56
|
+
const args = entry.args ?? [];
|
|
57
|
+
if (args.length !== 1 || !/^@godxjp\/ui-mcp@[^\s]+$/.test(args[0])) return false;
|
|
58
|
+
return Object.keys(entry.env ?? {}).every((key) => key === "GODX_UI_VERSION");
|
|
59
|
+
}
|
|
60
|
+
|
|
48
61
|
function mcpConfigMismatchMessage(root, existing, expected) {
|
|
49
62
|
const ui = readConsumerUiMetadata(root);
|
|
50
63
|
const pin = expected.args?.[0] ?? "@godxjp/ui-mcp";
|
|
@@ -347,7 +360,11 @@ export function refreshBlock(current, next, startMarker, endMarker) {
|
|
|
347
360
|
if (!endMarker) return null;
|
|
348
361
|
const j = current.indexOf(endMarker, first);
|
|
349
362
|
if (j < 0) return null;
|
|
350
|
-
|
|
363
|
+
// `next` ends in its own newline, and the old block's newline is still the first character after
|
|
364
|
+
// the end marker — keeping both grew the file by one blank line on every refresh.
|
|
365
|
+
let tail = current.slice(j + endMarker.length);
|
|
366
|
+
if (next.endsWith("\n") && tail.startsWith("\n")) tail = tail.slice(1);
|
|
367
|
+
return current.slice(0, first) + next + tail;
|
|
351
368
|
}
|
|
352
369
|
|
|
353
370
|
export function ensureMcpJson(root) {
|
|
@@ -369,10 +386,13 @@ export function ensureMcpJson(root) {
|
|
|
369
386
|
}
|
|
370
387
|
json.mcpServers = json.mcpServers ?? {};
|
|
371
388
|
if (json.mcpServers[MCP_KEY]) {
|
|
372
|
-
if (
|
|
389
|
+
if (mcpEntryMatches(json.mcpServers[MCP_KEY], expected)) return "present";
|
|
390
|
+
if (!isPackageWrittenMcpEntry(json.mcpServers[MCP_KEY])) {
|
|
373
391
|
return mcpConfigMismatchMessage(root, json.mcpServers[MCP_KEY], expected);
|
|
374
392
|
}
|
|
375
|
-
|
|
393
|
+
json.mcpServers[MCP_KEY] = expected;
|
|
394
|
+
writeFileAtomic(path, JSON.stringify(json, null, 2) + "\n");
|
|
395
|
+
return "refreshed";
|
|
376
396
|
}
|
|
377
397
|
const created = read.state === "missing";
|
|
378
398
|
json.mcpServers[MCP_KEY] = expected;
|
package/scripts/cli.mjs
CHANGED
|
@@ -18,13 +18,74 @@ const MAP = {
|
|
|
18
18
|
"visual-audit": "visual-audit.mjs",
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
+
// `<command> --help` is answered HERE: the scripts take free positional arguments, so a `--help`
|
|
22
|
+
// forwarded to ui-audit used to be read as nothing and ran a full audit instead of printing help.
|
|
23
|
+
const HELP = {
|
|
24
|
+
"init-agent": `godxjp-ui init-agent
|
|
25
|
+
|
|
26
|
+
Install the agent forcing-kit into the current consumer app (run it from the app root):
|
|
27
|
+
.mcp.json the godx-ui MCP server
|
|
28
|
+
.claude/settings.json a PostToolUse hook that audits every Write/Edit of a .tsx file
|
|
29
|
+
.claude/godxjp-ui-workflow.md
|
|
30
|
+
CLAUDE.md the godxjp-ui mandate block
|
|
31
|
+
Idempotent. Refuses inside the @godxjp/ui repo itself. Restart the agent afterwards.`,
|
|
32
|
+
"sync-rules": `godxjp-ui sync-rules
|
|
33
|
+
|
|
34
|
+
Refresh the package-owned agent files for the installed @godxjp/ui version: the godx-ui entry in
|
|
35
|
+
.mcp.json, the managed CLAUDE.md block, .claude/godxjp-ui-workflow.md and .ai/rules/godxjp-ui.md.
|
|
36
|
+
It is the postinstall step, run by hand — use it when the app installs with ignore-scripts=true,
|
|
37
|
+
where postinstall never runs and the rules go stale. Silent no-op in CI and when opted out.`,
|
|
38
|
+
audit: `godxjp-ui audit [dir …] [--changed] [--format json] [--quiet] [--rules]
|
|
39
|
+
|
|
40
|
+
Static UI-standardization audit over source (regex, no browser, fast). Exits non-zero on errors.
|
|
41
|
+
dir … directories or files to scan
|
|
42
|
+
--changed scan what this branch changed vs origin/main (committed, staged, untracked);
|
|
43
|
+
fails rather than reporting clean when origin/main cannot be resolved
|
|
44
|
+
--format json machine-readable findings
|
|
45
|
+
--quiet print errors only (warnings hidden)
|
|
46
|
+
--rules print the rule catalog as JSON and exit
|
|
47
|
+
Pre-commit: npx godxjp-ui audit resources/js || exit 1`,
|
|
48
|
+
"visual-audit": `godxjp-ui visual-audit [--format json] [--strict] <baseUrl> [route …]
|
|
49
|
+
|
|
50
|
+
Runtime audit (Playwright + axe-core) against an app you are ALREADY running locally.
|
|
51
|
+
baseUrl the running app, e.g. http://localhost:5173
|
|
52
|
+
route … paths appended to baseUrl (default "/")
|
|
53
|
+
--strict exit non-zero on any finding, not only errors
|
|
54
|
+
--format json machine-readable findings
|
|
55
|
+
--rules print the visual rule catalog as JSON and exit
|
|
56
|
+
Needs the playwright peer installed.`,
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const USAGE = `usage: godxjp-ui <command> [args]
|
|
60
|
+
|
|
61
|
+
commands:
|
|
62
|
+
init-agent install the agent forcing-kit (MCP + auto-audit hook + CLAUDE.md mandate)
|
|
63
|
+
sync-rules refresh package-owned agent rules (postinstall, by hand)
|
|
64
|
+
audit static UI audit over source
|
|
65
|
+
visual-audit runtime audit (Playwright + axe-core) against a running app
|
|
66
|
+
|
|
67
|
+
godxjp-ui <command> --help details and flags for one command`;
|
|
68
|
+
|
|
69
|
+
const isHelp = (arg) => arg === "--help" || arg === "-h" || arg === "help";
|
|
21
70
|
const [cmd, ...rest] = process.argv.slice(2);
|
|
71
|
+
|
|
72
|
+
if (cmd === undefined || isHelp(cmd)) {
|
|
73
|
+
const topic = isHelp(cmd) ? rest[0] : undefined;
|
|
74
|
+
console.log(topic && HELP[topic] ? HELP[topic] : USAGE);
|
|
75
|
+
process.exit(cmd === undefined ? 1 : 0);
|
|
76
|
+
}
|
|
22
77
|
const script = MAP[cmd];
|
|
23
78
|
if (!script) {
|
|
24
|
-
console.error(
|
|
79
|
+
console.error(`unknown command: ${cmd}\n\n${USAGE}`);
|
|
25
80
|
process.exit(1);
|
|
26
81
|
}
|
|
82
|
+
if (rest.includes("--help") || rest.includes("-h")) {
|
|
83
|
+
console.log(HELP[cmd]);
|
|
84
|
+
process.exit(0);
|
|
85
|
+
}
|
|
27
86
|
const env =
|
|
28
|
-
cmd === "sync-rules"
|
|
87
|
+
cmd === "sync-rules"
|
|
88
|
+
? { ...process.env, INIT_CWD: process.env.INIT_CWD ?? process.cwd() }
|
|
89
|
+
: process.env;
|
|
29
90
|
const r = spawnSync("node", [join(HERE, script), ...rest], { stdio: "inherit", env });
|
|
30
91
|
process.exit(r.status ?? 0);
|