@greatstore/cli 0.1.3 → 0.1.5
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/CHANGELOG.md +26 -0
- package/dist/cli.js +270 -16
- package/dist/gs-skill/references/store-admin.md +11 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,32 @@
|
|
|
3
3
|
All notable changes to `@greatstore/cli` are recorded here. The format
|
|
4
4
|
follows [Keep a Changelog](https://keepachangelog.com/).
|
|
5
5
|
|
|
6
|
+
## 0.1.5 — 2026-09-12
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
- `gs apps push` says when a component's source changed but its bundle did
|
|
10
|
+
not — "did you forget to build?" — instead of reporting a successful push
|
|
11
|
+
of code that was never built.
|
|
12
|
+
- A rebuilt bundle is now pushed even when the source is untouched. Such a
|
|
13
|
+
change was reported as "unchanged" and never uploaded.
|
|
14
|
+
|
|
15
|
+
## 0.1.4 — 2026-09-12
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- Edit one theme field at a time: `gs configure set --theme.fontFamily Manrope
|
|
19
|
+
--theme.radius sharp`. Theme writes merge into the stored theme, so a
|
|
20
|
+
one-field change no longer means retyping the whole object (and no longer
|
|
21
|
+
drops the keys you left out). `--replace` writes a theme outright.
|
|
22
|
+
- `gs configure set --help` prints every field it accepts with its type and
|
|
23
|
+
legal values, and a mistyped field name or value is now rejected with the
|
|
24
|
+
valid list before anything is sent.
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
- Rejected configuration writes say what was wrong with them — the field and
|
|
28
|
+
the values it accepts — instead of "Request rejected."
|
|
29
|
+
- Commands no longer wait on a version check every run, which takes about half
|
|
30
|
+
a second off each one.
|
|
31
|
+
|
|
6
32
|
## 0.1.3 — 2026-09-12
|
|
7
33
|
|
|
8
34
|
### Changed
|
package/dist/cli.js
CHANGED
|
@@ -442,7 +442,7 @@ async function sendOnce(url, options, accessToken) {
|
|
|
442
442
|
} catch {
|
|
443
443
|
}
|
|
444
444
|
const identifier = parsed.code ?? parsed.error;
|
|
445
|
-
const message = buildErrorMessage(res.status, identifier, parsed.detail);
|
|
445
|
+
const message = options.validationDetail && res.status === 400 && parsed.error ? parsed.error : buildErrorMessage(res.status, identifier, parsed.detail);
|
|
446
446
|
throw new HttpError(res.status, message, parsed.code ?? parsed.error);
|
|
447
447
|
}
|
|
448
448
|
var KNOWN_ERROR_MESSAGES = {
|
|
@@ -711,6 +711,164 @@ function realPath(p) {
|
|
|
711
711
|
}
|
|
712
712
|
}
|
|
713
713
|
|
|
714
|
+
// src/commands/configure/theme-fields.ts
|
|
715
|
+
var THEME_FIELDS = {
|
|
716
|
+
mode: {
|
|
717
|
+
kind: "string",
|
|
718
|
+
values: ["auto", "light", "dark", "custom"],
|
|
719
|
+
help: "Color scheme. `auto` follows the shopper's system preference.",
|
|
720
|
+
brandVisible: true
|
|
721
|
+
},
|
|
722
|
+
radius: {
|
|
723
|
+
kind: "string",
|
|
724
|
+
values: ["sharp", "default", "rounded"],
|
|
725
|
+
help: "Corner rounding preset applied to every surface.",
|
|
726
|
+
brandVisible: true
|
|
727
|
+
},
|
|
728
|
+
panelPosition: {
|
|
729
|
+
kind: "string",
|
|
730
|
+
values: ["left", "right", "middle"],
|
|
731
|
+
help: "Where the chat panel sits on desktop.",
|
|
732
|
+
brandVisible: true
|
|
733
|
+
},
|
|
734
|
+
fontFamily: {
|
|
735
|
+
kind: "string",
|
|
736
|
+
help: "Primary font family name.",
|
|
737
|
+
brandVisible: true
|
|
738
|
+
},
|
|
739
|
+
secondaryFontFamily: {
|
|
740
|
+
kind: "string",
|
|
741
|
+
help: "Font family for the assistant's chat bubbles.",
|
|
742
|
+
brandVisible: true
|
|
743
|
+
},
|
|
744
|
+
mobileBottomBar: {
|
|
745
|
+
kind: "boolean",
|
|
746
|
+
help: "Show the compact bottom bar on mobile.",
|
|
747
|
+
brandVisible: true
|
|
748
|
+
},
|
|
749
|
+
zIndex: {
|
|
750
|
+
kind: "integer",
|
|
751
|
+
help: "Stacking order of the chat panel on the host page."
|
|
752
|
+
},
|
|
753
|
+
brandColor: { kind: "color", help: "Accent color.", brandVisible: true },
|
|
754
|
+
surfaceColor: { kind: "color", help: "Background color.", brandVisible: true },
|
|
755
|
+
textColor: { kind: "color", help: "Text color.", brandVisible: true },
|
|
756
|
+
surface: { kind: "color", help: "Panel background." },
|
|
757
|
+
surfaceSecondary: { kind: "color", help: "Secondary background." },
|
|
758
|
+
surfaceAccent: { kind: "color", help: "Accented background." },
|
|
759
|
+
surfaceHover: { kind: "color", help: "Hovered background." },
|
|
760
|
+
foreground: { kind: "color", help: "Body text." },
|
|
761
|
+
foregroundSecondary: { kind: "color", help: "Secondary text." },
|
|
762
|
+
foregroundMuted: { kind: "color", help: "Muted text." },
|
|
763
|
+
foregroundAccent: { kind: "color", help: "Accented text." },
|
|
764
|
+
border: { kind: "color", help: "Border color." },
|
|
765
|
+
borderFocus: { kind: "color", help: "Focus-ring color." },
|
|
766
|
+
primary: { kind: "color", help: "Primary button background." },
|
|
767
|
+
primaryForeground: { kind: "color", help: "Primary button text." },
|
|
768
|
+
primaryHover: { kind: "color", help: "Primary button hover." },
|
|
769
|
+
primaryMuted: { kind: "color", help: "Muted primary background." },
|
|
770
|
+
primaryMutedForeground: { kind: "color", help: "Muted primary text." },
|
|
771
|
+
primaryTint: { kind: "color", help: "Primary tint wash." },
|
|
772
|
+
link: { kind: "color", help: "Link color." }
|
|
773
|
+
};
|
|
774
|
+
function suggestThemeFields(input) {
|
|
775
|
+
const target = input.toLowerCase();
|
|
776
|
+
return Object.keys(THEME_FIELDS).map((name) => {
|
|
777
|
+
const lower = name.toLowerCase();
|
|
778
|
+
return {
|
|
779
|
+
name,
|
|
780
|
+
distance: editDistance(target, lower),
|
|
781
|
+
prefix: commonPrefixLength(target, lower)
|
|
782
|
+
};
|
|
783
|
+
}).filter(
|
|
784
|
+
({ name, distance, prefix }) => distance <= Math.max(2, name.length / 3) || prefix >= 4
|
|
785
|
+
).sort((a, b) => b.prefix - a.prefix || a.distance - b.distance).slice(0, 3).map(({ name }) => name);
|
|
786
|
+
}
|
|
787
|
+
function commonPrefixLength(a, b) {
|
|
788
|
+
let i = 0;
|
|
789
|
+
while (i < a.length && i < b.length && a[i] === b[i]) i++;
|
|
790
|
+
return i;
|
|
791
|
+
}
|
|
792
|
+
function editDistance(a, b) {
|
|
793
|
+
let prev = Array.from({ length: b.length + 1 }, (_, i) => i);
|
|
794
|
+
for (let i = 1; i <= a.length; i++) {
|
|
795
|
+
const row = [i];
|
|
796
|
+
for (let j = 1; j <= b.length; j++) {
|
|
797
|
+
row[j] = Math.min(
|
|
798
|
+
(prev[j] ?? 0) + 1,
|
|
799
|
+
(row[j - 1] ?? 0) + 1,
|
|
800
|
+
(prev[j - 1] ?? 0) + (a[i - 1] === b[j - 1] ? 0 : 1)
|
|
801
|
+
);
|
|
802
|
+
}
|
|
803
|
+
prev = row;
|
|
804
|
+
}
|
|
805
|
+
return prev[b.length] ?? 0;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
// src/commands/configure/help.ts
|
|
809
|
+
var CONFIGURE_HELP = `gs configure \u2014 view and edit a store's configuration.
|
|
810
|
+
|
|
811
|
+
Usage:
|
|
812
|
+
gs configure Show the current configuration.
|
|
813
|
+
gs configure set --<field> <value> Save one or more fields.
|
|
814
|
+
gs configure upload <kind> <file> Upload icon / logoLight / logoDark.
|
|
815
|
+
gs configure clear <kind> Remove an uploaded asset.
|
|
816
|
+
|
|
817
|
+
Run \`gs configure set --help\` for the full field list.
|
|
818
|
+
|
|
819
|
+
Flags:
|
|
820
|
+
--store <slug> Which store to act on (default: nearest .gsrc).
|
|
821
|
+
--json Machine-readable output.
|
|
822
|
+
`;
|
|
823
|
+
function themeFieldLines() {
|
|
824
|
+
const rows = Object.entries(THEME_FIELDS).map(([name, field]) => {
|
|
825
|
+
const type = field.values ? field.values.join(" | ") : field.kind === "color" ? "<css color>" : field.kind === "boolean" ? "true | false" : field.kind === "integer" ? "<integer>" : "<name>";
|
|
826
|
+
return { flag: ` --theme.${name} ${type}`, help: field.help };
|
|
827
|
+
});
|
|
828
|
+
const width = Math.max(...rows.map((r) => r.flag.length)) + 2;
|
|
829
|
+
return rows.map((r) => `${r.flag.padEnd(width)}${r.help}`).join("\n");
|
|
830
|
+
}
|
|
831
|
+
function brandVisibleNames() {
|
|
832
|
+
return Object.entries(THEME_FIELDS).filter(([, field]) => field.brandVisible).map(([name]) => name).join(", ");
|
|
833
|
+
}
|
|
834
|
+
function configureSetHelp() {
|
|
835
|
+
return `gs configure set \u2014 save configuration fields.
|
|
836
|
+
|
|
837
|
+
Only the fields you pass are written; everything else is left alone. Pass an
|
|
838
|
+
empty value to clear a field (e.g. --displayName "").
|
|
839
|
+
|
|
840
|
+
Store fields:
|
|
841
|
+
--displayName <text> Store name shown to shoppers.
|
|
842
|
+
--assistantName <text> What the assistant calls itself.
|
|
843
|
+
--storeLink <url> Where "visit the store" points.
|
|
844
|
+
--extraOrigins <a,b,c> Extra origins allowed to embed the widget.
|
|
845
|
+
--cspScriptHosts <a,b,c> Extra script hosts to allow.
|
|
846
|
+
--cspConnectHosts <a,b,c> Extra connect hosts to allow.
|
|
847
|
+
|
|
848
|
+
Theme fields (merge into the stored theme):
|
|
849
|
+
${themeFieldLines()}
|
|
850
|
+
|
|
851
|
+
Whole-object theme writes:
|
|
852
|
+
--theme '<json>' Merge this JSON object into the stored theme.
|
|
853
|
+
--themeFile <path> Same, read from a file.
|
|
854
|
+
--replace Replace the theme outright instead of merging.
|
|
855
|
+
--theme "" Clear the theme entirely.
|
|
856
|
+
|
|
857
|
+
These are shopper-visible, so confirm them with the merchant before writing:
|
|
858
|
+
${brandVisibleNames()}
|
|
859
|
+
|
|
860
|
+
Examples:
|
|
861
|
+
gs configure set --theme.fontFamily Manrope --theme.radius sharp
|
|
862
|
+
gs configure set --theme.brandColor "#1e1d66"
|
|
863
|
+
gs configure set --theme '{"mode":"dark"}' --replace
|
|
864
|
+
`;
|
|
865
|
+
}
|
|
866
|
+
function configureHelp(sub) {
|
|
867
|
+
if (sub === void 0 || sub === "show") return CONFIGURE_HELP;
|
|
868
|
+
if (sub === "set") return configureSetHelp();
|
|
869
|
+
return void 0;
|
|
870
|
+
}
|
|
871
|
+
|
|
714
872
|
// src/commands/apps/init.ts
|
|
715
873
|
import * as fs4 from "fs";
|
|
716
874
|
import * as path5 from "path";
|
|
@@ -747,7 +905,7 @@ function applyTemplate(content, vars) {
|
|
|
747
905
|
}
|
|
748
906
|
|
|
749
907
|
// src/version.ts
|
|
750
|
-
var CLI_VERSION = true ? "0.1.
|
|
908
|
+
var CLI_VERSION = true ? "0.1.5" : "0.0.0-dev";
|
|
751
909
|
|
|
752
910
|
// src/commands/apps/init.ts
|
|
753
911
|
var NAME_REGEX = /^[a-z][a-z0-9_]*$/;
|
|
@@ -1686,7 +1844,8 @@ function computeComponentHashes(componentDir) {
|
|
|
1686
1844
|
}
|
|
1687
1845
|
return {
|
|
1688
1846
|
manifestHash,
|
|
1689
|
-
sourceHash: hashFile(path9.join(componentDir, "component.tsx"))
|
|
1847
|
+
sourceHash: hashFile(path9.join(componentDir, "component.tsx")),
|
|
1848
|
+
bundleHash: hashFile(path9.join(componentDir, "bundle.js"))
|
|
1690
1849
|
};
|
|
1691
1850
|
}
|
|
1692
1851
|
function readSyncState(componentDir) {
|
|
@@ -1698,7 +1857,8 @@ function readSyncState(componentDir) {
|
|
|
1698
1857
|
return {
|
|
1699
1858
|
version: parsed.version,
|
|
1700
1859
|
manifestHash: parsed.manifestHash,
|
|
1701
|
-
sourceHash: parsed.sourceHash
|
|
1860
|
+
sourceHash: parsed.sourceHash,
|
|
1861
|
+
...typeof parsed.bundleHash === "string" ? { bundleHash: parsed.bundleHash } : {}
|
|
1702
1862
|
};
|
|
1703
1863
|
}
|
|
1704
1864
|
return null;
|
|
@@ -1853,13 +2013,15 @@ async function pullOne(opts) {
|
|
|
1853
2013
|
writeSyncState(componentDir, {
|
|
1854
2014
|
version: data.version,
|
|
1855
2015
|
manifestHash: hashString(manifestText),
|
|
1856
|
-
sourceHash
|
|
2016
|
+
sourceHash,
|
|
2017
|
+
bundleHash: hashString(data.bundle)
|
|
1857
2018
|
});
|
|
1858
2019
|
const onDisk = computeComponentHashes(componentDir);
|
|
1859
2020
|
writeSyncState(componentDir, {
|
|
1860
2021
|
version: data.version,
|
|
1861
2022
|
manifestHash: onDisk.manifestHash,
|
|
1862
|
-
sourceHash: onDisk.sourceHash ?? ""
|
|
2023
|
+
sourceHash: onDisk.sourceHash ?? "",
|
|
2024
|
+
bundleHash: onDisk.bundleHash ?? ""
|
|
1863
2025
|
});
|
|
1864
2026
|
return { name, status: "pulled", version: data.version, wrote };
|
|
1865
2027
|
}
|
|
@@ -2004,10 +2166,13 @@ ${OUTCOME_INDENT}`)
|
|
|
2004
2166
|
};
|
|
2005
2167
|
}
|
|
2006
2168
|
const manifestText = fs9.readFileSync(manifestPath, "utf8");
|
|
2169
|
+
const before = computeComponentHashes(componentDir);
|
|
2170
|
+
const sync = readSyncState(componentDir);
|
|
2171
|
+
const staleBundle = opts.bundlePath === void 0 && sync?.bundleHash !== void 0 && sync.sourceHash !== (before.sourceHash ?? "") && sync.bundleHash === (before.bundleHash ?? "");
|
|
2007
2172
|
if (!force) {
|
|
2008
|
-
const
|
|
2009
|
-
|
|
2010
|
-
|
|
2173
|
+
const unchanged = sync !== null && sync.manifestHash === before.manifestHash && sync.sourceHash === (before.sourceHash ?? "") && // An older sync file has no bundle hash; treat that as "unknown" and
|
|
2174
|
+
// push, rather than assume a bundle we never recorded is current.
|
|
2175
|
+
sync.bundleHash !== void 0 && sync.bundleHash === (before.bundleHash ?? "");
|
|
2011
2176
|
if (unchanged) {
|
|
2012
2177
|
return { name, status: "unchanged" };
|
|
2013
2178
|
}
|
|
@@ -2047,13 +2212,15 @@ ${OUTCOME_INDENT}`)
|
|
|
2047
2212
|
writeSyncState(componentDir, {
|
|
2048
2213
|
version: data.version,
|
|
2049
2214
|
manifestHash: hashes.manifestHash,
|
|
2050
|
-
sourceHash: hashes.sourceHash ?? ""
|
|
2215
|
+
sourceHash: hashes.sourceHash ?? "",
|
|
2216
|
+
bundleHash: hashes.bundleHash ?? ""
|
|
2051
2217
|
});
|
|
2052
2218
|
return {
|
|
2053
2219
|
name,
|
|
2054
2220
|
status: "pushed",
|
|
2055
2221
|
version: data.version,
|
|
2056
|
-
permalink: data.permalink
|
|
2222
|
+
permalink: data.permalink,
|
|
2223
|
+
...staleBundle ? { staleBundle: true } : {}
|
|
2057
2224
|
};
|
|
2058
2225
|
}
|
|
2059
2226
|
function listLocalComponents(componentsDir) {
|
|
@@ -2084,6 +2251,12 @@ function printOutcome2(outcome) {
|
|
|
2084
2251
|
` pushed ${outcome.name} v${outcome.version} \u2192 ${outcome.permalink ?? ""}
|
|
2085
2252
|
`
|
|
2086
2253
|
);
|
|
2254
|
+
if (outcome.staleBundle) {
|
|
2255
|
+
process.stdout.write(
|
|
2256
|
+
`${OUTCOME_INDENT}component.tsx changed but bundle.js did not \u2014 did you forget to build? Run \`gs build ${outcome.name}\` and push again.
|
|
2257
|
+
`
|
|
2258
|
+
);
|
|
2259
|
+
}
|
|
2087
2260
|
return;
|
|
2088
2261
|
case "unchanged":
|
|
2089
2262
|
process.stdout.write(` unchanged ${outcome.name}
|
|
@@ -2309,6 +2482,7 @@ function formatList(list) {
|
|
|
2309
2482
|
// src/commands/configure/set.ts
|
|
2310
2483
|
import * as fs10 from "fs";
|
|
2311
2484
|
import * as path12 from "path";
|
|
2485
|
+
var THEME_FLAG_PREFIX = "theme.";
|
|
2312
2486
|
var TEXT_FIELDS = [
|
|
2313
2487
|
"displayName",
|
|
2314
2488
|
"assistantName",
|
|
@@ -2338,17 +2512,36 @@ async function setConfig(args) {
|
|
|
2338
2512
|
body[field] = entries.length === 0 ? null : entries;
|
|
2339
2513
|
}
|
|
2340
2514
|
const themeFile = flagString(args.flags, "themeFile");
|
|
2515
|
+
const perField = collectThemeFieldFlags(args.flags);
|
|
2516
|
+
const replace = flagBool(args.flags, "replace");
|
|
2341
2517
|
if ("theme" in args.flags && themeFile !== void 0) {
|
|
2342
2518
|
throw new Error("Pass either --theme or --themeFile, not both.");
|
|
2343
2519
|
}
|
|
2520
|
+
if (perField !== null && ("theme" in args.flags || themeFile !== void 0)) {
|
|
2521
|
+
throw new Error(
|
|
2522
|
+
"Pass either --theme.<field> flags or a whole --theme/--themeFile object, not both."
|
|
2523
|
+
);
|
|
2524
|
+
}
|
|
2525
|
+
let themePatch;
|
|
2344
2526
|
if ("theme" in args.flags) {
|
|
2345
2527
|
const v = args.flags["theme"];
|
|
2346
2528
|
if (typeof v !== "string") {
|
|
2347
2529
|
throw new Error('--theme requires a JSON value (use --theme "" to clear).');
|
|
2348
2530
|
}
|
|
2349
|
-
|
|
2531
|
+
themePatch = v === "" ? null : parseThemeJson(v, "--theme");
|
|
2350
2532
|
} else if (themeFile !== void 0) {
|
|
2351
|
-
|
|
2533
|
+
themePatch = parseThemeJson(readTextFile(themeFile, "--themeFile"), "--themeFile");
|
|
2534
|
+
} else if (perField !== null) {
|
|
2535
|
+
themePatch = perField;
|
|
2536
|
+
}
|
|
2537
|
+
if (themePatch !== void 0) {
|
|
2538
|
+
body["theme"] = themePatch === null || replace ? themePatch : { ...await readStoredTheme(slug), ...themePatch };
|
|
2539
|
+
if (body["theme"] !== null) {
|
|
2540
|
+
const merged = body["theme"];
|
|
2541
|
+
for (const [key, value] of Object.entries(merged)) {
|
|
2542
|
+
if (value === "") delete merged[key];
|
|
2543
|
+
}
|
|
2544
|
+
}
|
|
2352
2545
|
}
|
|
2353
2546
|
if (Object.keys(body).length === 0) {
|
|
2354
2547
|
throw new Error(
|
|
@@ -2358,7 +2551,10 @@ async function setConfig(args) {
|
|
|
2358
2551
|
const url = `${adminApiBase(slug)}/configure/save`;
|
|
2359
2552
|
const data = await request(url, {
|
|
2360
2553
|
method: "POST",
|
|
2361
|
-
body
|
|
2554
|
+
body,
|
|
2555
|
+
// Every 400 from this endpoint names the offending field and the values
|
|
2556
|
+
// it accepts — worth far more to the caller than "Request rejected."
|
|
2557
|
+
validationDetail: true
|
|
2362
2558
|
});
|
|
2363
2559
|
if (flagBool(args.flags, "json")) {
|
|
2364
2560
|
process.stdout.write(JSON.stringify(data.config, null, 2) + "\n");
|
|
@@ -2386,6 +2582,59 @@ function parseThemeJson(raw, flag) {
|
|
|
2386
2582
|
}
|
|
2387
2583
|
return parsed;
|
|
2388
2584
|
}
|
|
2585
|
+
async function readStoredTheme(slug) {
|
|
2586
|
+
const url = `${adminApiBase(slug)}/configure/config`;
|
|
2587
|
+
const data = await request(url);
|
|
2588
|
+
return data.brand.theme ?? {};
|
|
2589
|
+
}
|
|
2590
|
+
function collectThemeFieldFlags(flags) {
|
|
2591
|
+
const patch = {};
|
|
2592
|
+
for (const [flag, raw] of Object.entries(flags)) {
|
|
2593
|
+
if (!flag.startsWith(THEME_FLAG_PREFIX)) continue;
|
|
2594
|
+
const name = flag.slice(THEME_FLAG_PREFIX.length);
|
|
2595
|
+
const field = THEME_FIELDS[name];
|
|
2596
|
+
if (!field) {
|
|
2597
|
+
const suggestions = suggestThemeFields(name);
|
|
2598
|
+
throw new Error(
|
|
2599
|
+
`Unknown theme field "${name}".
|
|
2600
|
+
Valid fields: ${Object.keys(THEME_FIELDS).join(", ")}.` + (suggestions.length > 0 ? `
|
|
2601
|
+
Did you mean: ${suggestions.join(", ")}?` : "")
|
|
2602
|
+
);
|
|
2603
|
+
}
|
|
2604
|
+
if (typeof raw !== "string") {
|
|
2605
|
+
if (field.kind === "boolean") {
|
|
2606
|
+
patch[name] = true;
|
|
2607
|
+
continue;
|
|
2608
|
+
}
|
|
2609
|
+
throw new Error(`--${flag} requires a value (use --${flag} "" to clear).`);
|
|
2610
|
+
}
|
|
2611
|
+
patch[name] = coerceThemeValue(flag, name, raw);
|
|
2612
|
+
}
|
|
2613
|
+
return Object.keys(patch).length > 0 ? patch : null;
|
|
2614
|
+
}
|
|
2615
|
+
function coerceThemeValue(flag, name, raw) {
|
|
2616
|
+
const field = THEME_FIELDS[name];
|
|
2617
|
+
if (!field || raw === "") return raw;
|
|
2618
|
+
if (field.values && !field.values.includes(raw)) {
|
|
2619
|
+
throw new Error(
|
|
2620
|
+
`--${flag} must be one of: ${field.values.join(", ")} (got "${raw}").`
|
|
2621
|
+
);
|
|
2622
|
+
}
|
|
2623
|
+
if (field.kind === "boolean") {
|
|
2624
|
+
if (raw !== "true" && raw !== "false") {
|
|
2625
|
+
throw new Error(`--${flag} must be true or false (got "${raw}").`);
|
|
2626
|
+
}
|
|
2627
|
+
return raw === "true";
|
|
2628
|
+
}
|
|
2629
|
+
if (field.kind === "integer") {
|
|
2630
|
+
const n = Number.parseInt(raw, 10);
|
|
2631
|
+
if (!Number.isInteger(n) || String(n) !== raw.trim()) {
|
|
2632
|
+
throw new Error(`--${flag} must be an integer (got "${raw}").`);
|
|
2633
|
+
}
|
|
2634
|
+
return n;
|
|
2635
|
+
}
|
|
2636
|
+
return raw;
|
|
2637
|
+
}
|
|
2389
2638
|
|
|
2390
2639
|
// src/commands/configure/upload.ts
|
|
2391
2640
|
import * as fs11 from "fs";
|
|
@@ -2752,6 +3001,7 @@ var REFRESH_COMMAND = "__refresh-version-cache";
|
|
|
2752
3001
|
var PKG = "@greatstore/cli";
|
|
2753
3002
|
var REGISTRY_URL = `https://registry.npmjs.org/${PKG}/latest`;
|
|
2754
3003
|
var FETCH_TIMEOUT_MS = 5e3;
|
|
3004
|
+
var CACHE_TTL_MS = 10 * 60 * 1e3;
|
|
2755
3005
|
var OutdatedCliError = class extends Error {
|
|
2756
3006
|
constructor(current, latest) {
|
|
2757
3007
|
super(
|
|
@@ -2773,6 +3023,7 @@ async function assertUpToDate(current, opts = {}) {
|
|
|
2773
3023
|
if (cached && compareSemver(cached.latest, current) > 0) {
|
|
2774
3024
|
throw new OutdatedCliError(current, cached.latest);
|
|
2775
3025
|
}
|
|
3026
|
+
if (cached && now() - cached.checkedAt < CACHE_TTL_MS) return;
|
|
2776
3027
|
const fresh = await fetcher();
|
|
2777
3028
|
if (fresh) {
|
|
2778
3029
|
writeCache(home, { latest: fresh, checkedAt: now() });
|
|
@@ -2847,7 +3098,7 @@ function parseVer(v) {
|
|
|
2847
3098
|
}
|
|
2848
3099
|
|
|
2849
3100
|
// src/index.ts
|
|
2850
|
-
var CHANGELOG = true ? "# Changelog\n\nAll notable changes to `@greatstore/cli` are recorded here. The format\nfollows [Keep a Changelog](https://keepachangelog.com/).\n\n## 0.1.3 \u2014 2026-09-12\n\n### Changed\n- `gs skill` prints the steps for installing the GreatStore agent skill\n instead of installing it itself, so any AI coding agent can set it up in\n whichever skills directory it uses \u2014 no `--global` or `--dir` to pick.\n- The installed skill is a link to the copy that ships with the CLI, so\n upgrading `@greatstore/cli` keeps it current with nothing to re-run.\n\n## 0.1.2 \u2014 2026-09-04\n\n### Fixed\n- `gs apps pull` now downloads components that aren't published yet. Pulling\n one used to report that it wasn't found on the server.\n\n## 0.1.1 \u2014 2026-08-20\n\n### Changed\n- Signing in now asks you to authorize the store you picked before the CLI\n gets access to it, and that access can be ended anytime from **Team \u2192 CLI\n access** in the dashboard. Ending it there signs this computer out on its\n next command.\n- For each store, you're signed in on one computer at a time. Signing in to\n that store again from another machine replaces the previous one, which then\n has to sign in again; your other stores are unaffected.\n- This release is required: earlier versions no longer work. Run\n `npm install -g @greatstore/cli` to upgrade.\n\n## 0.1.0 \u2014 2026-08-19\n\n### Changed\n- When a component's `inputSchema` declares fields the component doesn't\n accept, validation now reports them on a single line \u2014 naming the fields\n (capped, with a `(+N more)` count past that) \u2014 instead of one error per\n field. A schema/component mismatch stays readable instead of burying the\n other diagnostics.\n\n## 0.0.48 \u2014 2026-08-19\n\n### Changed\n- Component validation now warns when a component reaches for the page-level\n `window.GreatStore` API. Components should interact with GreatStore through\n the lifecycle props passed into them (`onSendMessage`, `onCallTool`,\n `onGenerateStructuredContent`, \u2026), which are wired to the surface the\n component is mounted in; the warning points you there. It's a nudge, not a\n build failure.\n\n## 0.0.47 \u2014 2026-08-18\n\n### Changed\n- `onGenerateStructuredContent` now takes a required third argument,\n `fallback` \u2014 a schema-shaped object you supply. The component preview\n renders it (there's no live store to generate against there), so a\n generation-driven component previews as it would live. It's validated\n against the schema and throws if the two don't line up.\n\n## 0.0.46 \u2014 2026-08-18\n\n### Added\n- Components now receive an `onGenerateStructuredContent(schema, prompt)`\n prop: ask the store's assistant for content matching a JSON Schema (or a\n Zod schema) and render what it returns, personalized to the shopper. It\n works the same in the conversation on the storefront and every embed.\n Added to the component template, the scaffolded `AGENTS.md` reference, and\n prop validation.\n\n## 0.0.45 \u2014 2026-08-18\n\n### Changed\n- The auto-generated `AGENTS.md` banner now records the CLI version that\n wrote it, so you can tell at a glance when it trails your installed CLI\n and a `gs apps init` refresh is due.\n\n## 0.0.44 \u2014 2026-08-18\n\n### Added\n- New check: a component that still declares `onError` gets a warning\n pointing at the async-component pattern that replaced it, with the\n throw-vs-fallback caveat (a throw asks the assistant to retry, so\n permanent failures should render a fallback rather than throw). Earlier\n this surfaced as the generic \"prop isn't declared in the schema\"\n warning, whose suggested fix was wrong for a former lifecycle callback.\n\n### Changed\n- `gs apps init` now always refreshes `AGENTS.md` (the agent guidance\n file) so it tracks the installed CLI version instead of going stale.\n The file carries a \"do not edit \u2014 auto-generated\" banner; your own\n project files are still left untouched.\n\n## 0.0.43 \u2014 2026-08-18\n\n### Added\n- `gs apps build` and `gs apps push` now check each component before\n building or uploading it. Findings are reported as **errors** (a\n blocker \u2014 the component isn't built or uploaded) or **warnings** (it\n builds and is ready to publish, but something is worth improving),\n and a single run reports everything it found rather than stopping at\n the first problem.\n- New check: a component's props and its `inputSchema.properties` must\n agree. A schema field the component doesn't accept is an error; a prop\n the schema doesn't declare is a warning, since nothing will ever pass\n it. The props GreatStore injects (`onSendMessage`, `onCallTool`,\n `onUpdateModelContext`, `onShowLightbox`, `onClose`, `storeData`,\n `Image`) are exempt.\n\n## 0.0.42 \u2014 2026-08-15\n\n### Changed\n- `gs apps list` now works outside a project. With no `.gsrc` it lists the\n components of the store you're signed in to, instead of erroring. The\n commands that write files or change the store \u2014 `push`, `pull`, `publish`,\n `unpublish`, `delete` \u2014 still require a project.\n\n## 0.0.41 \u2014 2026-08-14\n\n### Changed\n- Internal authentication rework. Re-run `gs login` after updating.\n\n## 0.0.40 \u2014 2026-07-24\n\n### Removed\n- `gs configure set` no longer accepts `--salesGuide` or\n `--salesGuideFile`, and `gs configure show` no longer lists the field.\n\n## 0.0.39 \u2014 2026-07-21\n\n### Added\n- Components now receive an `Image` prop \u2014 a drop-in for `<img>` that\n serves images at the size they're displayed. Render `<Image src=\u2026 />`\n instead of `<img>`; pass `Image={\"img\"}` to preview a component\n outside a store. Scaffolded into `gs apps init` and documented in\n `AGENTS.md`.\n\n## 0.0.38 \u2014 2026-07-13\n\n### Added\n- `gs login --store <slug>` skips the store picker and signs in\n directly to that store \u2014 fails immediately if your account doesn't\n have access to it, instead of falling back to the picker.\n\n## 0.0.37 \u2014 2026-07-10\n\n### Added\n- Signing in now ends by choosing which store to work on \u2014 skipped\n automatically when your account has exactly one. Commands default to\n that store, so `--store` is rarely needed anymore.\n- `gs switch [<slug>]` changes the working store without signing in\n again.\n- `gs apps init` no longer requires `--store` when your sign-in already\n selected a store.\n\n### Changed\n- A `--store` flag or project `.gsrc` that names a different store than\n the one you signed in to is now an error, so work can't accidentally\n target the wrong store. Run `gs switch` to change stores.\n\n## 0.0.33 \u2014 2026-07-10\n\n### Changed\n- `gs apps push` now rejects a component whose `inputSchema` is too\n complex for the assistant to call reliably: union keywords\n (`anyOf`/`oneOf`/`allOf`/`$ref`/`not`), more than 8 KB serialized, or\n more than 50 declared fields. Keep schemas to a small set of flat,\n single-type fields \u2014 one canonical name per concept \u2014 and handle\n aliases or edge cases in component code instead.\n\n## 0.0.32 \u2014 2026-06-18\n\n### Added\n- Chat components can expand an image into a full-screen, on-brand\n lightbox via a new `onShowLightbox({ src, originRect })` prop. Wire it\n to an image's `onClick` \u2014 pass the image URL and, for a smooth zoom,\n the clicked element's `getBoundingClientRect()`. Use it for product\n photos, swatches, or size charts the shopper may want to inspect up\n close, instead of building your own overlay.\n\n## 0.0.31 \u2014 2026-06-18\n\n### Added\n- Components can read a secondary brand font from `--font-secondary`,\n for a second layer of typography. Falls back to the primary font.\n\n### Changed\n- The brand font variable is now `--font-primary` (was `--font-sans`).\n\n## 0.0.30 \u2014 2026-06-17\n\n### Added\n- The agent skill documents a new way to give the assistant background\n context without sending a visible message:\n `window.GreatStore.updateModelContext(text)` on the page, and the\n matching `onUpdateModelContext(text)` prop inside a chat component. Use\n it to keep the assistant aware of what the shopper is doing \u2014 the\n product they're viewing, what's in their cart, the variant they just\n selected \u2014 so its replies stay on point. Each call replaces the previous\n value, and nothing renders in the chat.\n\n## 0.0.29 \u2014 2026-06-12\n\n### Fixed\n- The \"update available\" notice actually fires now. It previously raced\n a 1-second timeout against the npm registry and usually lost, so most\n installs never saw it. The notice is now served instantly from a local\n cache, refreshed in the background after each day's first invocation \u2014\n it can lag one run behind a release, but it no longer adds latency or\n goes silent on slow networks.\n\n## 0.0.28 \u2014 2026-06-12\n\n### Added\n- `gs configure` \u2014 view and edit the store configuration from the CLI:\n display name, assistant name, sales guide, store link, extra origins,\n theme, CSP host lists, and icon/logo uploads. Same fields and\n behaviour as the dashboard's Configure panel.\n- `gs connectors` \u2014 manage the store's MCP connectors: list, add (with\n a discovery probe before saving), remove, enable/disable, toggle the\n Maker MCP, and health-check. Same behaviour as the dashboard's\n Connectors panel.\n- `--store <slug>` on the new admin commands, so they work outside a\n scaffolded component project (a `.gsrc` is still used when present).\n- The agent skill gains a store-administration reference: coding agents\n can read the store's configuration and connectors to ground their\n work, self-serve additive changes like origin allowlists and CSP\n hosts (read-merge-write), and are told which changes need the\n merchant's go-ahead first.\n\n### Changed\n- Component commands now live under `gs apps` (`gs apps push`,\n `gs apps build`, \u2026), matching the dashboard's Apps panel. The old\n top-level forms keep working as aliases, so existing scripts and\n scaffolded projects are unaffected.\n- The skill's structured-content guide now teaches \"point, don't\n paste\": name the SKU/product/collection and let GreatStore research\n the catalog itself instead of inlining fetched specs; validate with\n `gs connectors` that a connector exists for the data a prompt or\n schema depends on (research can't exceed the wired-up connectors);\n and never put shopper data in prompts \u2014 GreatStore already knows the\n shopper, and identified shoppers get per-shopper cached responses.\n\n## 0.0.27 \u2014 2026-06-11\n\n### Changed\n- Skill code samples now carry an explicit reference-only disclaimer:\n coding agents are told to re-express the logic in the host repo's\n framework (React, Vue, Shopify Liquid, Svelte, \u2026) instead of\n retrofitting the framework-free samples as-is.\n\n## 0.0.26 \u2014 2026-06-11\n\n### Added\n- The agent skill gains a \"GreatStore launchers\" recipe: a horizontally\n scrollable row of AI-generated chips, each an engaging first-person\n question about the current page that's sent to the assistant on tap.\n\n### Changed\n- Skill recipes are now one file each under `recipes/`, indexed from\n SKILL.md by a table with description and use-case columns.\n\n## 0.0.25 \u2014 2026-06-11\n\n### Added\n- `gs skill` installs the GreatStore agent skill \u2014 a guide AI coding\n agents use to build with GreatStore: AI content for your own UI, chat\n entry points, page tools, custom in-chat components, push\n notifications, and the store's MCP endpoints. Installs into\n `./.claude/skills/`; use `--global` for `~/.claude/skills/`, or\n `--dir <path>` for agents that read skills from somewhere else. Run\n it again any time to update an installed copy.\n\n## 0.0.24 \u2014 2026-06-03\n\n### Changed\n- `gs init` in an existing project now fills in any scaffold files that\n are missing (for example, the `AGENTS.md` design guide added in\n 0.0.23) and leaves your own files alone. Pass `--force` to refresh\n every scaffold file to the latest version. Your pinned store\n (`.gsrc`) is never rewritten either way.\n\n## 0.0.23 \u2014 2026-06-03\n\n### Added\n- `gs init` now scaffolds an `AGENTS.md` (with `CLAUDE.md` and\n `GEMINI.md` symlinked to it) documenting the design rules every\n component should follow \u2014 use `em` rather than `rem` for sizing, and\n style from the provided brand CSS variables so components match the\n store's theme. It doubles as guidance for AI coding agents.\n\n## 0.0.22 \u2014 2026-06-02\n\n### Added\n- `gs list` now shows a link to each component's page in the dashboard,\n so you can jump straight to a component to preview or publish it. The\n link is also included in `gs list --json`.\n\n## 0.0.21 \u2014 2026-05-31\n\n### Changed\n- The `gs init` component scaffold now shows how to write **async**\n components that load data before they render \u2014 including validating\n inputs up front and signalling a failure by throwing. The scaffolded\n component no longer includes an `onError` prop; throw from an async\n component to report a failure instead.\n\n## 0.0.20 \u2014 2026-05-29\n\n### Added\n- `gs pull`, `gs push`, and `gs publish` now accept several component\n names at once (e.g. `gs publish header footer cart`). Each component\n is reported on its own line and one failure no longer stops the rest.\n\n## 0.0.19 \u2014 2026-05-28\n\n### Fixed\n- `gs login` on Windows no longer opens a sign-in URL with parameters\n stripped, which surfaced as a \"Missing redirect_uri or state\n parameter\" page in the browser.\n\n## 0.0.18 \u2014 2026-05-28\n\n### Changed\n- Push and publish errors now name the specific reason \u2014 including\n every failing field in `manifest.json` \u2014 instead of the previous\n generic message.\n\n## 0.0.17 \u2014 2026-05-28\n\n### Added\n- Each command now prints a one-line upgrade notice when a newer\n `@greatstore/cli` is available on npm.\n\n## 0.0.16 \u2014 2026-05-28\n\n### Changed\n- Simplified error messages.\n\n## 0.0.15 \u2014 2026-05-24\n\n### Added\n- Scaffolded `component.tsx` now declares the four injected lifecycle\n props (`onSendMessage`, `onCallTool`, `onClose`, `onError`) on\n `Props`. Use `onError(message)` to report expected failures (failed\n fetch, host action rejected, invalid host state) so the AI can\n recover on its next turn. Render-time crashes are reported for you.\n\n## 0.0.14 \u2014 2026-05-24\n\n### Changed\n- `gs build` output is now whitespace-minified \u2014 typically ~50% smaller.\n\n## 0.0.13 \u2014 2026-05-24\n\n### Changed\n- `gs build` prints the next-step hint (`gs push`, then `gs publish`).\n\n## 0.0.12 \u2014 2026-05-24\n\n### Fixed\n- `gs build` failing to load Vite in some setups.\n\n## 0.0.11 \u2014 2026-05-24\n\n### Added\n- Multi-component projects. `gs init` (no args) scaffolds the project\n root; `gs init <name>` adds a component under `components/<name>/`.\n- `gs build [<name>]` \u2014 compiles every `components/<name>/bundle.js`.\n- `gs push` (no args) uploads only the components that changed.\n- `gs pull` (no args, or `*`) downloads every component. Locally\n edited components are skipped; pass `--force` to overwrite.\n- Public `CHANGELOG.md`; `gs --version` prints recent entries.\n\n### Changed\n- A project folder ships to exactly one store. Only `gs init` accepts\n `--store`; every other command reads the slug from `.gsrc`. The old\n single-component layout is rejected with a migration hint.\n- `gs init` requires `--store <slug>` for a fresh root, and rejects\n `--store` on an existing root.\n- `gs init` no longer writes `build.mjs` \u2014 scripts call `gs build`.\n\n## 0.0.10 \u2014 2026-05-23\n\n### Changed\n- The sign-in browser tab auto-closes once `gs login` finishes.\n\n## 0.0.9 \u2014 2026-05-23\n\n### Changed\n- Scaffolded manifests include a `displayName` so the admin UI has a\n friendlier label.\n\n## 0.0.8 \u2014 2026-05-23\n\n### Changed\n- `gs push` and `gs publish` print a link to view the component.\n\n## 0.0.6 \u2014 2026-05-23\n\n### Changed\n- `gs --version` reads from the published package version.\n\n## 0.0.4 \u2014 2026-05-23\n\n### Changed\n- Scaffolded projects produce browser-ready bundles out of the box.\n\n## 0.0.3 \u2014 2026-05-23\n\n### Changed\n- Trimmed public README to the essentials.\n\n## 0.0.2 \u2014 2026-05-23\n\n### Fixed\n- Sign-in callback parameter handling.\n" : "";
|
|
3101
|
+
var CHANGELOG = true ? "# Changelog\n\nAll notable changes to `@greatstore/cli` are recorded here. The format\nfollows [Keep a Changelog](https://keepachangelog.com/).\n\n## 0.1.5 \u2014 2026-09-12\n\n### Fixed\n- `gs apps push` says when a component's source changed but its bundle did\n not \u2014 \"did you forget to build?\" \u2014 instead of reporting a successful push\n of code that was never built.\n- A rebuilt bundle is now pushed even when the source is untouched. Such a\n change was reported as \"unchanged\" and never uploaded.\n\n## 0.1.4 \u2014 2026-09-12\n\n### Added\n- Edit one theme field at a time: `gs configure set --theme.fontFamily Manrope\n --theme.radius sharp`. Theme writes merge into the stored theme, so a\n one-field change no longer means retyping the whole object (and no longer\n drops the keys you left out). `--replace` writes a theme outright.\n- `gs configure set --help` prints every field it accepts with its type and\n legal values, and a mistyped field name or value is now rejected with the\n valid list before anything is sent.\n\n### Changed\n- Rejected configuration writes say what was wrong with them \u2014 the field and\n the values it accepts \u2014 instead of \"Request rejected.\"\n- Commands no longer wait on a version check every run, which takes about half\n a second off each one.\n\n## 0.1.3 \u2014 2026-09-12\n\n### Changed\n- `gs skill` prints the steps for installing the GreatStore agent skill\n instead of installing it itself, so any AI coding agent can set it up in\n whichever skills directory it uses \u2014 no `--global` or `--dir` to pick.\n- The installed skill is a link to the copy that ships with the CLI, so\n upgrading `@greatstore/cli` keeps it current with nothing to re-run.\n\n## 0.1.2 \u2014 2026-09-04\n\n### Fixed\n- `gs apps pull` now downloads components that aren't published yet. Pulling\n one used to report that it wasn't found on the server.\n\n## 0.1.1 \u2014 2026-08-20\n\n### Changed\n- Signing in now asks you to authorize the store you picked before the CLI\n gets access to it, and that access can be ended anytime from **Team \u2192 CLI\n access** in the dashboard. Ending it there signs this computer out on its\n next command.\n- For each store, you're signed in on one computer at a time. Signing in to\n that store again from another machine replaces the previous one, which then\n has to sign in again; your other stores are unaffected.\n- This release is required: earlier versions no longer work. Run\n `npm install -g @greatstore/cli` to upgrade.\n\n## 0.1.0 \u2014 2026-08-19\n\n### Changed\n- When a component's `inputSchema` declares fields the component doesn't\n accept, validation now reports them on a single line \u2014 naming the fields\n (capped, with a `(+N more)` count past that) \u2014 instead of one error per\n field. A schema/component mismatch stays readable instead of burying the\n other diagnostics.\n\n## 0.0.48 \u2014 2026-08-19\n\n### Changed\n- Component validation now warns when a component reaches for the page-level\n `window.GreatStore` API. Components should interact with GreatStore through\n the lifecycle props passed into them (`onSendMessage`, `onCallTool`,\n `onGenerateStructuredContent`, \u2026), which are wired to the surface the\n component is mounted in; the warning points you there. It's a nudge, not a\n build failure.\n\n## 0.0.47 \u2014 2026-08-18\n\n### Changed\n- `onGenerateStructuredContent` now takes a required third argument,\n `fallback` \u2014 a schema-shaped object you supply. The component preview\n renders it (there's no live store to generate against there), so a\n generation-driven component previews as it would live. It's validated\n against the schema and throws if the two don't line up.\n\n## 0.0.46 \u2014 2026-08-18\n\n### Added\n- Components now receive an `onGenerateStructuredContent(schema, prompt)`\n prop: ask the store's assistant for content matching a JSON Schema (or a\n Zod schema) and render what it returns, personalized to the shopper. It\n works the same in the conversation on the storefront and every embed.\n Added to the component template, the scaffolded `AGENTS.md` reference, and\n prop validation.\n\n## 0.0.45 \u2014 2026-08-18\n\n### Changed\n- The auto-generated `AGENTS.md` banner now records the CLI version that\n wrote it, so you can tell at a glance when it trails your installed CLI\n and a `gs apps init` refresh is due.\n\n## 0.0.44 \u2014 2026-08-18\n\n### Added\n- New check: a component that still declares `onError` gets a warning\n pointing at the async-component pattern that replaced it, with the\n throw-vs-fallback caveat (a throw asks the assistant to retry, so\n permanent failures should render a fallback rather than throw). Earlier\n this surfaced as the generic \"prop isn't declared in the schema\"\n warning, whose suggested fix was wrong for a former lifecycle callback.\n\n### Changed\n- `gs apps init` now always refreshes `AGENTS.md` (the agent guidance\n file) so it tracks the installed CLI version instead of going stale.\n The file carries a \"do not edit \u2014 auto-generated\" banner; your own\n project files are still left untouched.\n\n## 0.0.43 \u2014 2026-08-18\n\n### Added\n- `gs apps build` and `gs apps push` now check each component before\n building or uploading it. Findings are reported as **errors** (a\n blocker \u2014 the component isn't built or uploaded) or **warnings** (it\n builds and is ready to publish, but something is worth improving),\n and a single run reports everything it found rather than stopping at\n the first problem.\n- New check: a component's props and its `inputSchema.properties` must\n agree. A schema field the component doesn't accept is an error; a prop\n the schema doesn't declare is a warning, since nothing will ever pass\n it. The props GreatStore injects (`onSendMessage`, `onCallTool`,\n `onUpdateModelContext`, `onShowLightbox`, `onClose`, `storeData`,\n `Image`) are exempt.\n\n## 0.0.42 \u2014 2026-08-15\n\n### Changed\n- `gs apps list` now works outside a project. With no `.gsrc` it lists the\n components of the store you're signed in to, instead of erroring. The\n commands that write files or change the store \u2014 `push`, `pull`, `publish`,\n `unpublish`, `delete` \u2014 still require a project.\n\n## 0.0.41 \u2014 2026-08-14\n\n### Changed\n- Internal authentication rework. Re-run `gs login` after updating.\n\n## 0.0.40 \u2014 2026-07-24\n\n### Removed\n- `gs configure set` no longer accepts `--salesGuide` or\n `--salesGuideFile`, and `gs configure show` no longer lists the field.\n\n## 0.0.39 \u2014 2026-07-21\n\n### Added\n- Components now receive an `Image` prop \u2014 a drop-in for `<img>` that\n serves images at the size they're displayed. Render `<Image src=\u2026 />`\n instead of `<img>`; pass `Image={\"img\"}` to preview a component\n outside a store. Scaffolded into `gs apps init` and documented in\n `AGENTS.md`.\n\n## 0.0.38 \u2014 2026-07-13\n\n### Added\n- `gs login --store <slug>` skips the store picker and signs in\n directly to that store \u2014 fails immediately if your account doesn't\n have access to it, instead of falling back to the picker.\n\n## 0.0.37 \u2014 2026-07-10\n\n### Added\n- Signing in now ends by choosing which store to work on \u2014 skipped\n automatically when your account has exactly one. Commands default to\n that store, so `--store` is rarely needed anymore.\n- `gs switch [<slug>]` changes the working store without signing in\n again.\n- `gs apps init` no longer requires `--store` when your sign-in already\n selected a store.\n\n### Changed\n- A `--store` flag or project `.gsrc` that names a different store than\n the one you signed in to is now an error, so work can't accidentally\n target the wrong store. Run `gs switch` to change stores.\n\n## 0.0.33 \u2014 2026-07-10\n\n### Changed\n- `gs apps push` now rejects a component whose `inputSchema` is too\n complex for the assistant to call reliably: union keywords\n (`anyOf`/`oneOf`/`allOf`/`$ref`/`not`), more than 8 KB serialized, or\n more than 50 declared fields. Keep schemas to a small set of flat,\n single-type fields \u2014 one canonical name per concept \u2014 and handle\n aliases or edge cases in component code instead.\n\n## 0.0.32 \u2014 2026-06-18\n\n### Added\n- Chat components can expand an image into a full-screen, on-brand\n lightbox via a new `onShowLightbox({ src, originRect })` prop. Wire it\n to an image's `onClick` \u2014 pass the image URL and, for a smooth zoom,\n the clicked element's `getBoundingClientRect()`. Use it for product\n photos, swatches, or size charts the shopper may want to inspect up\n close, instead of building your own overlay.\n\n## 0.0.31 \u2014 2026-06-18\n\n### Added\n- Components can read a secondary brand font from `--font-secondary`,\n for a second layer of typography. Falls back to the primary font.\n\n### Changed\n- The brand font variable is now `--font-primary` (was `--font-sans`).\n\n## 0.0.30 \u2014 2026-06-17\n\n### Added\n- The agent skill documents a new way to give the assistant background\n context without sending a visible message:\n `window.GreatStore.updateModelContext(text)` on the page, and the\n matching `onUpdateModelContext(text)` prop inside a chat component. Use\n it to keep the assistant aware of what the shopper is doing \u2014 the\n product they're viewing, what's in their cart, the variant they just\n selected \u2014 so its replies stay on point. Each call replaces the previous\n value, and nothing renders in the chat.\n\n## 0.0.29 \u2014 2026-06-12\n\n### Fixed\n- The \"update available\" notice actually fires now. It previously raced\n a 1-second timeout against the npm registry and usually lost, so most\n installs never saw it. The notice is now served instantly from a local\n cache, refreshed in the background after each day's first invocation \u2014\n it can lag one run behind a release, but it no longer adds latency or\n goes silent on slow networks.\n\n## 0.0.28 \u2014 2026-06-12\n\n### Added\n- `gs configure` \u2014 view and edit the store configuration from the CLI:\n display name, assistant name, sales guide, store link, extra origins,\n theme, CSP host lists, and icon/logo uploads. Same fields and\n behaviour as the dashboard's Configure panel.\n- `gs connectors` \u2014 manage the store's MCP connectors: list, add (with\n a discovery probe before saving), remove, enable/disable, toggle the\n Maker MCP, and health-check. Same behaviour as the dashboard's\n Connectors panel.\n- `--store <slug>` on the new admin commands, so they work outside a\n scaffolded component project (a `.gsrc` is still used when present).\n- The agent skill gains a store-administration reference: coding agents\n can read the store's configuration and connectors to ground their\n work, self-serve additive changes like origin allowlists and CSP\n hosts (read-merge-write), and are told which changes need the\n merchant's go-ahead first.\n\n### Changed\n- Component commands now live under `gs apps` (`gs apps push`,\n `gs apps build`, \u2026), matching the dashboard's Apps panel. The old\n top-level forms keep working as aliases, so existing scripts and\n scaffolded projects are unaffected.\n- The skill's structured-content guide now teaches \"point, don't\n paste\": name the SKU/product/collection and let GreatStore research\n the catalog itself instead of inlining fetched specs; validate with\n `gs connectors` that a connector exists for the data a prompt or\n schema depends on (research can't exceed the wired-up connectors);\n and never put shopper data in prompts \u2014 GreatStore already knows the\n shopper, and identified shoppers get per-shopper cached responses.\n\n## 0.0.27 \u2014 2026-06-11\n\n### Changed\n- Skill code samples now carry an explicit reference-only disclaimer:\n coding agents are told to re-express the logic in the host repo's\n framework (React, Vue, Shopify Liquid, Svelte, \u2026) instead of\n retrofitting the framework-free samples as-is.\n\n## 0.0.26 \u2014 2026-06-11\n\n### Added\n- The agent skill gains a \"GreatStore launchers\" recipe: a horizontally\n scrollable row of AI-generated chips, each an engaging first-person\n question about the current page that's sent to the assistant on tap.\n\n### Changed\n- Skill recipes are now one file each under `recipes/`, indexed from\n SKILL.md by a table with description and use-case columns.\n\n## 0.0.25 \u2014 2026-06-11\n\n### Added\n- `gs skill` installs the GreatStore agent skill \u2014 a guide AI coding\n agents use to build with GreatStore: AI content for your own UI, chat\n entry points, page tools, custom in-chat components, push\n notifications, and the store's MCP endpoints. Installs into\n `./.claude/skills/`; use `--global` for `~/.claude/skills/`, or\n `--dir <path>` for agents that read skills from somewhere else. Run\n it again any time to update an installed copy.\n\n## 0.0.24 \u2014 2026-06-03\n\n### Changed\n- `gs init` in an existing project now fills in any scaffold files that\n are missing (for example, the `AGENTS.md` design guide added in\n 0.0.23) and leaves your own files alone. Pass `--force` to refresh\n every scaffold file to the latest version. Your pinned store\n (`.gsrc`) is never rewritten either way.\n\n## 0.0.23 \u2014 2026-06-03\n\n### Added\n- `gs init` now scaffolds an `AGENTS.md` (with `CLAUDE.md` and\n `GEMINI.md` symlinked to it) documenting the design rules every\n component should follow \u2014 use `em` rather than `rem` for sizing, and\n style from the provided brand CSS variables so components match the\n store's theme. It doubles as guidance for AI coding agents.\n\n## 0.0.22 \u2014 2026-06-02\n\n### Added\n- `gs list` now shows a link to each component's page in the dashboard,\n so you can jump straight to a component to preview or publish it. The\n link is also included in `gs list --json`.\n\n## 0.0.21 \u2014 2026-05-31\n\n### Changed\n- The `gs init` component scaffold now shows how to write **async**\n components that load data before they render \u2014 including validating\n inputs up front and signalling a failure by throwing. The scaffolded\n component no longer includes an `onError` prop; throw from an async\n component to report a failure instead.\n\n## 0.0.20 \u2014 2026-05-29\n\n### Added\n- `gs pull`, `gs push`, and `gs publish` now accept several component\n names at once (e.g. `gs publish header footer cart`). Each component\n is reported on its own line and one failure no longer stops the rest.\n\n## 0.0.19 \u2014 2026-05-28\n\n### Fixed\n- `gs login` on Windows no longer opens a sign-in URL with parameters\n stripped, which surfaced as a \"Missing redirect_uri or state\n parameter\" page in the browser.\n\n## 0.0.18 \u2014 2026-05-28\n\n### Changed\n- Push and publish errors now name the specific reason \u2014 including\n every failing field in `manifest.json` \u2014 instead of the previous\n generic message.\n\n## 0.0.17 \u2014 2026-05-28\n\n### Added\n- Each command now prints a one-line upgrade notice when a newer\n `@greatstore/cli` is available on npm.\n\n## 0.0.16 \u2014 2026-05-28\n\n### Changed\n- Simplified error messages.\n\n## 0.0.15 \u2014 2026-05-24\n\n### Added\n- Scaffolded `component.tsx` now declares the four injected lifecycle\n props (`onSendMessage`, `onCallTool`, `onClose`, `onError`) on\n `Props`. Use `onError(message)` to report expected failures (failed\n fetch, host action rejected, invalid host state) so the AI can\n recover on its next turn. Render-time crashes are reported for you.\n\n## 0.0.14 \u2014 2026-05-24\n\n### Changed\n- `gs build` output is now whitespace-minified \u2014 typically ~50% smaller.\n\n## 0.0.13 \u2014 2026-05-24\n\n### Changed\n- `gs build` prints the next-step hint (`gs push`, then `gs publish`).\n\n## 0.0.12 \u2014 2026-05-24\n\n### Fixed\n- `gs build` failing to load Vite in some setups.\n\n## 0.0.11 \u2014 2026-05-24\n\n### Added\n- Multi-component projects. `gs init` (no args) scaffolds the project\n root; `gs init <name>` adds a component under `components/<name>/`.\n- `gs build [<name>]` \u2014 compiles every `components/<name>/bundle.js`.\n- `gs push` (no args) uploads only the components that changed.\n- `gs pull` (no args, or `*`) downloads every component. Locally\n edited components are skipped; pass `--force` to overwrite.\n- Public `CHANGELOG.md`; `gs --version` prints recent entries.\n\n### Changed\n- A project folder ships to exactly one store. Only `gs init` accepts\n `--store`; every other command reads the slug from `.gsrc`. The old\n single-component layout is rejected with a migration hint.\n- `gs init` requires `--store <slug>` for a fresh root, and rejects\n `--store` on an existing root.\n- `gs init` no longer writes `build.mjs` \u2014 scripts call `gs build`.\n\n## 0.0.10 \u2014 2026-05-23\n\n### Changed\n- The sign-in browser tab auto-closes once `gs login` finishes.\n\n## 0.0.9 \u2014 2026-05-23\n\n### Changed\n- Scaffolded manifests include a `displayName` so the admin UI has a\n friendlier label.\n\n## 0.0.8 \u2014 2026-05-23\n\n### Changed\n- `gs push` and `gs publish` print a link to view the component.\n\n## 0.0.6 \u2014 2026-05-23\n\n### Changed\n- `gs --version` reads from the published package version.\n\n## 0.0.4 \u2014 2026-05-23\n\n### Changed\n- Scaffolded projects produce browser-ready bundles out of the box.\n\n## 0.0.3 \u2014 2026-05-23\n\n### Changed\n- Trimmed public README to the essentials.\n\n## 0.0.2 \u2014 2026-05-23\n\n### Fixed\n- Sign-in callback parameter handling.\n" : "";
|
|
2851
3102
|
var HELP = `gs \u2014 GreatStore CLI (v${CLI_VERSION})
|
|
2852
3103
|
|
|
2853
3104
|
Usage:
|
|
@@ -2863,6 +3114,8 @@ Account:
|
|
|
2863
3114
|
Store administration:
|
|
2864
3115
|
configure Show the store configuration.
|
|
2865
3116
|
configure set --<field> <val> Edit it (same fields as the admin Configure panel).
|
|
3117
|
+
\`gs configure set --help\` lists every field,
|
|
3118
|
+
including the theme fields and their values.
|
|
2866
3119
|
configure upload <kind> <file> Upload icon / logoLight / logoDark.
|
|
2867
3120
|
configure clear <kind> Remove an uploaded asset.
|
|
2868
3121
|
connectors List the store's MCP connectors.
|
|
@@ -2928,7 +3181,8 @@ async function main() {
|
|
|
2928
3181
|
return 0;
|
|
2929
3182
|
}
|
|
2930
3183
|
if (flagBool(parsed.flags, "help") || parsed.command === "help" || parsed.command === null) {
|
|
2931
|
-
|
|
3184
|
+
const specific = parsed.command === "configure" ? configureHelp(parsed.positional[0]) : void 0;
|
|
3185
|
+
process.stdout.write(specific ?? HELP);
|
|
2932
3186
|
return 0;
|
|
2933
3187
|
}
|
|
2934
3188
|
if (parsed.command !== null && APPS_ALIASES.has(parsed.command)) {
|
|
@@ -102,9 +102,19 @@ and confirm the result with a read.
|
|
|
102
102
|
gs configure [--json] show configuration
|
|
103
103
|
gs configure set --<field> <value> displayName, assistantName,
|
|
104
104
|
storeLink, extraOrigins a,b,
|
|
105
|
-
theme '<json>' (--themeFile <path>),
|
|
106
105
|
cspScriptHosts a,b, cspConnectHosts a,b
|
|
107
106
|
("" clears a field)
|
|
107
|
+
gs configure set --theme.<field> <value> one theme field, merged into the rest:
|
|
108
|
+
mode auto|light|dark|custom,
|
|
109
|
+
radius sharp|default|rounded,
|
|
110
|
+
panelPosition left|right|middle,
|
|
111
|
+
fontFamily, secondaryFontFamily,
|
|
112
|
+
mobileBottomBar true|false, zIndex,
|
|
113
|
+
brandColor/surfaceColor/textColor and
|
|
114
|
+
the fine-grained color tokens
|
|
115
|
+
gs configure set --theme '<json>' merge a whole object (--themeFile <path>);
|
|
116
|
+
--replace overwrites instead of merging
|
|
117
|
+
gs configure set --help every field, its type and legal values
|
|
108
118
|
gs configure upload <kind> <file> icon | logoLight | logoDark (.png/.jpg/.webp)
|
|
109
119
|
gs configure clear <kind> remove an uploaded asset
|
|
110
120
|
|