@greatstore/cli 0.0.22 → 0.0.23

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.
Files changed (3) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/cli.js +62 -187
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -3,6 +3,15 @@
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.0.23 — 2026-06-03
7
+
8
+ ### Added
9
+ - `gs init` now scaffolds an `AGENTS.md` (with `CLAUDE.md` and
10
+ `GEMINI.md` symlinked to it) documenting the design rules every
11
+ component should follow — use `em` rather than `rem` for sizing, and
12
+ style from the provided brand CSS variables so components match the
13
+ store's theme. It doubles as guidance for AI coding agents.
14
+
6
15
  ## 0.0.22 — 2026-06-02
7
16
 
8
17
  ### Added
package/dist/cli.js CHANGED
@@ -1111,6 +1111,38 @@ function prompt(question) {
1111
1111
  // src/commands/init.ts
1112
1112
  import * as fs6 from "fs";
1113
1113
  import * as path6 from "path";
1114
+
1115
+ // src/template.ts
1116
+ import { readdirSync as readdirSync2, readFileSync as readFileSync5 } from "fs";
1117
+ import { fileURLToPath } from "url";
1118
+ var cache = null;
1119
+ function loadTemplate() {
1120
+ if (cache) return cache;
1121
+ cache = true ? JSON.parse('{"component/component.tsx":"import React from \\"react\\";\\n\\n// Add your tool args (matching manifest.json#inputSchema.properties)\\n// alongside the GreatStore-injected lifecycle props. See AGENTS.md for\\n// what each lifecycle prop does.\\ninterface Props {\\n onSendMessage: (text: string) => void;\\n onCallTool: (name: string, args: Record<string, unknown>) => void;\\n onClose: () => void;\\n}\\n\\n// See AGENTS.md for the design rules (em-based sizing, brand CSS\\n// variables), the lifecycle props, and how to write an async,\\n// backend-backed component.\\nexport default function __GS_PASCAL__(_props: Props): React.ReactElement {\\n return (\\n <div\\n style={{\\n padding: \\"1em\\",\\n border: \\"1px solid var(--color-border-default)\\",\\n borderRadius: \\"var(--radius-lg)\\",\\n background: \\"var(--color-surface)\\",\\n color: \\"var(--color-foreground)\\",\\n fontFamily: \\"var(--font-sans)\\",\\n }}\\n >\\n <strong>__GS_NAME__</strong> \u2014 hello from your component!\\n </div>\\n );\\n}\\n","component/manifest.json":"{\\n \\"name\\": \\"__GS_NAME__\\",\\n \\"displayName\\": \\"__GS_DISPLAY_NAME__\\",\\n \\"description\\": \\"Renders the __GS_NAME__ widget.\\",\\n \\"displayMode\\": \\"inline\\",\\n \\"inputSchema\\": {\\n \\"type\\": \\"object\\",\\n \\"properties\\": {}\\n }\\n}\\n","root/.gitignore":"node_modules/\\ncomponents/*/bundle.js\\ncomponents/*/.gssync.json\\n*.tsbuildinfo\\n.DS_Store\\n","root/.gsrc":"{\\n \\"store\\": \\"__GS_STORE__\\"\\n}\\n","root/AGENTS.md":"# AGENTS.md\\n\\nGuidance for AI coding agents working on the components in this project.\\n`CLAUDE.md` and `GEMINI.md` are symlinks to this file.\\n\\nThese components render inside arbitrary publisher websites (the embed\\nwidget mounts on a host page) as well as the GreatStore storefront. You\\ncontrol neither the host page\'s base font size nor its color scheme, and\\nthe store owner controls the look from GreatStore theme settings. The\\nrules below keep components portable across both.\\n\\n## Design requirements\\n\\n### Never use `rem` for fonts and sizing \u2014 always use `em`\\n\\n`rem` resolves against the host page\'s root font size, which is\\narbitrary and outside our control. A host that sets `html { font-size:\\n8px }` (or 200%) will shrink or blow up every `rem`-based dimension.\\n`em` resolves against the component\'s own font size, so it stays\\nself-consistent wherever the component is mounted.\\n\\nUse `em` for font sizes, padding, margins, gaps, widths, heights,\\nand any other length. Borders may stay in `px` (hairlines should not\\nscale with text).\\n\\n```tsx\\n// Bad \u2014 breaks on hosts with a non-default root font size\\n<div style={{ padding: \\"1rem\\", fontSize: \\"0.875rem\\" }} />\\n\\n// Good\\n<div style={{ padding: \\"1em\\", fontSize: \\"0.875em\\" }} />\\n```\\n\\n### Don\'t hardcode colors, fonts, or corner radius \u2014 use GreatStore brand variables\\n\\nThe store owner themes the assistant from GreatStore settings. Hardcoded\\nvalues ignore that and make the component clash with the rest of the\\nstore. Read from the CSS variables GreatStore injects on the surface\\ninstead, so the component restyles itself when the theme changes.\\n\\nAvailable variables:\\n\\n| Purpose | Variable |\\n| --- | --- |\\n| Surface background | `--color-surface` |\\n| Secondary surface | `--color-surface-secondary` |\\n| Accent surface | `--color-surface-accent` |\\n| Hover surface | `--color-surface-hover` |\\n| Foreground text | `--color-foreground` |\\n| Secondary text | `--color-foreground-secondary` |\\n| Muted text | `--color-foreground-muted` |\\n| Accent text | `--color-foreground-accent` |\\n| Border | `--color-border-default` |\\n| Focus border | `--color-border-focus` |\\n| Primary / brand | `--color-primary` |\\n| Text on primary | `--color-primary-foreground` |\\n| Primary hover | `--color-primary-hover` |\\n| Primary muted | `--color-primary-muted` |\\n| Text on primary muted | `--color-primary-muted-foreground` |\\n| Primary tint | `--color-primary-tint` |\\n| Link | `--color-link` |\\n| Font family | `--font-sans` |\\n| Corner radius (scale) | `--radius-xs` \u2026 `--radius-4xl`, `--radius-pill` |\\n\\n```tsx\\n// Bad \u2014 hardcoded, ignores the store\'s theme\\n<button style={{ background: \\"#4f46e5\\", borderRadius: 8, fontFamily: \\"Inter\\" }} />\\n\\n// Good\\n<button\\n style={{\\n background: \\"var(--color-primary)\\",\\n color: \\"var(--color-primary-foreground)\\",\\n borderRadius: \\"var(--radius-lg)\\",\\n fontFamily: \\"var(--font-sans)\\",\\n }}\\n/>\\n```\\n\\nProvide a sensible fallback only when a value might be absent, e.g.\\n`var(--color-primary, currentColor)`.\\n\\n## Component props\\n\\nEach component receives its tool args (the fields you declare in\\n`manifest.json#inputSchema.properties`) plus these GreatStore-injected\\nlifecycle props, which are always present:\\n\\n| Prop | What it does |\\n| --- | --- |\\n| `onSendMessage(text)` | Send text into the chat as if the shopper typed it. |\\n| `onCallTool(name, args)` | Chain into another remote-component tool by name. |\\n| `onClose()` | Dismiss the host slot. Over-input clears the overlay, fullscreen reverts the pane, inline is a no-op. |\\n\\n## Async components (backend-backed, render-blocking data)\\n\\nIf a component must load data from a backend/API before it can render\\ncorrectly, make it async \u2014 don\'t render an empty shell and fetch in a\\n`useEffect`. Set `\\"async\\": true` in `manifest.json` and export an async\\ndefault. GreatStore waits for your promise (showing a normal loading\\nstate, so you don\'t render your own placeholder), then renders what it\\nresolves to. Components that render purely from their props stay\\nsynchronous.\\n\\nA thrown error is a **retry signal**: the in-store AI sees it and\\nusually re-calls the tool. So only throw when a *different* call could\\nhelp:\\n\\n1. `await` the backend call, then return the finished JSX.\\n2. Validate the AI-passed props first and throw on bad input \u2014 the AI\\n can fix the args and retry. (Don\'t validate the API\'s *output* and\\n throw: the AI can\'t fix the backend, it\'ll just loop.)\\n3. Broadcast a backend failure ONLY when retrying differently could\\n succeed, and say what to change (e.g. empty search \u2192 \\"try a broader\\n keyword\\"). For idempotent failures (500, timeout, missing record)\\n re-running the same call changes nothing \u2014 render a graceful fallback\\n instead of throwing.\\n\\n```tsx\\nexport default async function Example(props: Props) {\\n if (!props.query?.trim()) throw new Error(\\"missing required prop: query\\");\\n const res = await fetch(`/api/search?q=${encodeURIComponent(props.query)}`);\\n if (res.ok) {\\n const { results } = await res.json();\\n if (results.length === 0)\\n throw new Error(`no results for \\"${props.query}\\" \u2014 try a broader keyword`);\\n return <ul>{/* render results */}</ul>;\\n }\\n return <p>Couldn\'t load results right now.</p>; // idempotent: don\'t throw\\n}\\n```\\n","root/README.md":"# GreatStore components\\n\\nCustom React components published to your GreatStore tenant. Each\\ncomponent lives in its own folder under `components/`.\\n\\n```\\nnpm install\\ngs init <component_name> # add a new component\\ngs build # builds every components/<name>/bundle.js\\ngs push # uploads every changed component as a draft\\ngs publish <component_name> # promote a specific component to live\\n```\\n\\n- `gs push` (no args) hashes each component and only uploads the ones\\n that have changed since the last sync.\\n- `gs pull` (no args) refreshes every remote component into\\n `components/<name>/`. Components with unsaved local edits are skipped\\n with a warning; pass `--force` to overwrite.\\n\\nSee `AGENTS.md` for the design rules every component must follow\\n(em-based sizing, brand CSS variables) \u2014 it doubles as guidance for AI\\ncoding agents (`CLAUDE.md` / `GEMINI.md` symlink to it).\\n","root/package.json":"{\\n \\"name\\": \\"greatstore-components\\",\\n \\"version\\": \\"0.0.1\\",\\n \\"private\\": true,\\n \\"type\\": \\"module\\",\\n \\"scripts\\": {\\n \\"build\\": \\"gs build\\",\\n \\"push\\": \\"gs build && gs push\\"\\n },\\n \\"dependencies\\": {\\n \\"react\\": \\"^19.0.0\\",\\n \\"react-dom\\": \\"^19.0.0\\"\\n },\\n \\"devDependencies\\": {\\n \\"@types/react\\": \\"^19.0.0\\",\\n \\"@types/react-dom\\": \\"^19.0.0\\",\\n \\"@vitejs/plugin-react\\": \\"^4.3.0\\",\\n \\"typescript\\": \\"^5.6.0\\",\\n \\"vite\\": \\"^5.4.0\\"\\n }\\n}\\n","root/tsconfig.json":"{\\n \\"compilerOptions\\": {\\n \\"target\\": \\"ES2022\\",\\n \\"module\\": \\"ESNext\\",\\n \\"moduleResolution\\": \\"Bundler\\",\\n \\"jsx\\": \\"react-jsx\\",\\n \\"lib\\": [\\"ES2022\\", \\"DOM\\"],\\n \\"strict\\": true,\\n \\"esModuleInterop\\": true,\\n \\"skipLibCheck\\": true,\\n \\"isolatedModules\\": true,\\n \\"noEmit\\": true\\n },\\n \\"include\\": [\\"components/**/component.tsx\\", \\"vite.config.ts\\"]\\n}\\n","root/vite.config.ts":"import { defineConfig } from \\"vite\\";\\nimport react from \\"@vitejs/plugin-react\\";\\n\\n// Real builds happen in `gs build` (one Vite invocation per\\n// component, externals + runtime shim paths owned by the CLI). This\\n// file exists only so editors / language servers can resolve the\\n// React plugin when inspecting components/*/component.tsx.\\nexport default defineConfig({\\n plugins: [react()],\\n});\\n"}') : readTemplateFromDisk(new URL("../template/", import.meta.url));
1122
+ return cache;
1123
+ }
1124
+ var TOKENS = {
1125
+ name: "__GS_NAME__",
1126
+ pascalName: "__GS_PASCAL__",
1127
+ displayName: "__GS_DISPLAY_NAME__",
1128
+ store: "__GS_STORE__"
1129
+ };
1130
+ function applyTemplate(content, vars) {
1131
+ let out = content;
1132
+ for (const key of Object.keys(TOKENS)) {
1133
+ const value = vars[key];
1134
+ if (value !== void 0) out = out.split(TOKENS[key]).join(value);
1135
+ }
1136
+ const leftover = out.match(/__GS_[A-Z_]+__/);
1137
+ if (leftover) {
1138
+ throw new Error(
1139
+ `internal: template placeholder ${leftover[0]} was not provided`
1140
+ );
1141
+ }
1142
+ return out;
1143
+ }
1144
+
1145
+ // src/commands/init.ts
1114
1146
  var NAME_REGEX = /^[a-z][a-z0-9_]*$/;
1115
1147
  function initCommand(args) {
1116
1148
  const name = args.positional[0];
@@ -1190,8 +1222,21 @@ function ensureRoot(root, rootExisted, force, opts) {
1190
1222
  fs6.writeFileSync(full, content);
1191
1223
  }
1192
1224
  }
1225
+ for (const link of ["CLAUDE.md", "GEMINI.md"]) {
1226
+ const linkPath = path6.join(root, link);
1227
+ if (force && pathExists(linkPath)) fs6.rmSync(linkPath);
1228
+ if (!pathExists(linkPath)) fs6.symlinkSync("AGENTS.md", linkPath);
1229
+ }
1193
1230
  fs6.mkdirSync(path6.join(root, "components"), { recursive: true });
1194
1231
  }
1232
+ function pathExists(p) {
1233
+ try {
1234
+ fs6.lstatSync(p);
1235
+ return true;
1236
+ } catch {
1237
+ return false;
1238
+ }
1239
+ }
1195
1240
  function ensureComponent(componentDir, name, force) {
1196
1241
  if (fs6.existsSync(componentDir) && !force) {
1197
1242
  const entries = fs6.readdirSync(componentDir);
@@ -1206,40 +1251,25 @@ function ensureComponent(componentDir, name, force) {
1206
1251
  fs6.writeFileSync(path6.join(componentDir, relPath), content);
1207
1252
  }
1208
1253
  }
1254
+ function templateFiles(prefix, vars) {
1255
+ const tree = loadTemplate();
1256
+ return Object.entries(tree).filter(([rel]) => rel.startsWith(prefix)).map(([rel, content]) => [
1257
+ rel.slice(prefix.length),
1258
+ applyTemplate(content, vars)
1259
+ ]);
1260
+ }
1209
1261
  function rootFiles(opts) {
1210
1262
  if (!opts.store) {
1211
1263
  throw new Error("internal: rootFiles called without a store slug");
1212
1264
  }
1213
- return [
1214
- ["package.json", rootPackageJson()],
1215
- ["vite.config.ts", viteEditorConfig()],
1216
- ["tsconfig.json", rootTsconfig()],
1217
- [".gsrc", gsrc(opts.store)],
1218
- [".gitignore", gitignore()],
1219
- ["README.md", rootReadme()]
1220
- ];
1265
+ return templateFiles("root/", { store: opts.store });
1221
1266
  }
1222
1267
  function componentFiles(name) {
1223
- return [
1224
- ["manifest.json", manifest(name)],
1225
- ["component.tsx", component(name)]
1226
- ];
1227
- }
1228
- function manifest(name) {
1229
- return JSON.stringify(
1230
- {
1231
- name,
1232
- displayName: defaultDisplayName(name),
1233
- description: `Renders the ${name} widget.`,
1234
- displayMode: "inline",
1235
- inputSchema: {
1236
- type: "object",
1237
- properties: {}
1238
- }
1239
- },
1240
- null,
1241
- 2
1242
- ) + "\n";
1268
+ return templateFiles("component/", {
1269
+ name,
1270
+ pascalName: pascal(name),
1271
+ displayName: defaultDisplayName(name)
1272
+ });
1243
1273
  }
1244
1274
  function defaultDisplayName(name) {
1245
1275
  const words = name.split("_").filter(Boolean);
@@ -1247,161 +1277,6 @@ function defaultDisplayName(name) {
1247
1277
  const first = words[0];
1248
1278
  return first.charAt(0).toUpperCase() + first.slice(1) + (words.length > 1 ? " " + words.slice(1).join(" ") : "");
1249
1279
  }
1250
- function component(name) {
1251
- return `import React from "react";
1252
-
1253
- interface Props {
1254
- // ---- Your tool args ----
1255
- // Add fields here matching manifest.json#inputSchema.properties.
1256
-
1257
- // ---- GreatStore-injected lifecycle props (always present) ----
1258
- // Send text into the chat as if the shopper typed it.
1259
- onSendMessage: (text: string) => void;
1260
- // Chain into another remote-component tool by name.
1261
- onCallTool: (name: string, args: Record<string, unknown>) => void;
1262
- // Dismiss the host slot (over-input clears the overlay, fullscreen
1263
- // reverts the pane, inline is a no-op).
1264
- onClose: () => void;
1265
- }
1266
-
1267
- export default function ${pascal(name)}(_props: Props): React.ReactElement {
1268
- return (
1269
- <div style={{ padding: "1rem", border: "1px solid #ddd", borderRadius: 8 }}>
1270
- <strong>${name}</strong> \u2014 hello from your component!
1271
- </div>
1272
- );
1273
- }
1274
-
1275
- // ---- Async components (backend-backed, render-blocking data) ----
1276
- // If this component must load data from a backend/API before it can
1277
- // render correctly, make it async \u2014 don't render an empty shell and
1278
- // fetch in a useEffect. Set "async": true in manifest.json and export
1279
- // an async default. GreatStore waits for your promise (showing a normal
1280
- // loading state, so you don't render your own placeholder), then renders
1281
- // what it resolves to.
1282
- //
1283
- // A thrown error is a RETRY SIGNAL: the in-store AI sees it and usually
1284
- // re-calls the tool. So only throw when a *different* call could help.
1285
- // 1. await the backend call, then return the finished JSX.
1286
- // 2. Validate the AI-passed props first and throw on bad input \u2014 the
1287
- // AI can fix the args and retry. (Don't validate the API's output
1288
- // and throw: the AI can't fix the backend, it'll just loop.)
1289
- // 3. Broadcast a backend failure ONLY when retrying differently could
1290
- // succeed, and say what to change (e.g. empty search \u2192 "try a
1291
- // broader keyword"). For idempotent failures (500, timeout, missing
1292
- // record) re-running the same call changes nothing \u2014 render a
1293
- // graceful fallback instead of throwing.
1294
- //
1295
- // export default async function ${pascal(name)}(props: Props) {
1296
- // if (!props.query?.trim()) throw new Error("missing required prop: query");
1297
- // const res = await fetch(\`/api/search?q=\${encodeURIComponent(props.query)}\`);
1298
- // if (res.ok) {
1299
- // const { results } = await res.json();
1300
- // if (results.length === 0)
1301
- // throw new Error(\`no results for "\${props.query}" \u2014 try a broader keyword\`);
1302
- // return <ul>{/* render results */}</ul>;
1303
- // }
1304
- // return <p>Couldn't load results right now.</p>; // idempotent: don't throw
1305
- // }
1306
- //
1307
- // Components that render purely from their props stay synchronous.
1308
- `;
1309
- }
1310
- function viteEditorConfig() {
1311
- return `import { defineConfig } from "vite";
1312
- import react from "@vitejs/plugin-react";
1313
-
1314
- // Real builds happen in \`gs build\` (one Vite invocation per
1315
- // component, externals + runtime shim paths owned by the CLI). This
1316
- // file exists only so editors / language servers can resolve the
1317
- // React plugin when inspecting components/*/component.tsx.
1318
- export default defineConfig({
1319
- plugins: [react()],
1320
- });
1321
- `;
1322
- }
1323
- function rootTsconfig() {
1324
- return JSON.stringify(
1325
- {
1326
- compilerOptions: {
1327
- target: "ES2022",
1328
- module: "ESNext",
1329
- moduleResolution: "Bundler",
1330
- jsx: "react-jsx",
1331
- lib: ["ES2022", "DOM"],
1332
- strict: true,
1333
- esModuleInterop: true,
1334
- skipLibCheck: true,
1335
- isolatedModules: true,
1336
- noEmit: true
1337
- },
1338
- include: ["components/**/component.tsx", "vite.config.ts"]
1339
- },
1340
- null,
1341
- 2
1342
- ) + "\n";
1343
- }
1344
- function rootPackageJson() {
1345
- return JSON.stringify(
1346
- {
1347
- name: "greatstore-components",
1348
- version: "0.0.1",
1349
- private: true,
1350
- type: "module",
1351
- scripts: {
1352
- build: "gs build",
1353
- push: "gs build && gs push"
1354
- },
1355
- dependencies: {
1356
- react: "^19.0.0",
1357
- "react-dom": "^19.0.0"
1358
- },
1359
- devDependencies: {
1360
- "@types/react": "^19.0.0",
1361
- "@types/react-dom": "^19.0.0",
1362
- "@vitejs/plugin-react": "^4.3.0",
1363
- typescript: "^5.6.0",
1364
- vite: "^5.4.0"
1365
- }
1366
- },
1367
- null,
1368
- 2
1369
- ) + "\n";
1370
- }
1371
- function gsrc(store) {
1372
- return JSON.stringify({ store }, null, 2) + "\n";
1373
- }
1374
- function gitignore() {
1375
- return [
1376
- "node_modules/",
1377
- "components/*/bundle.js",
1378
- "components/*/.gssync.json",
1379
- "*.tsbuildinfo",
1380
- ".DS_Store",
1381
- ""
1382
- ].join("\n");
1383
- }
1384
- function rootReadme() {
1385
- return `# GreatStore components
1386
-
1387
- Custom React components published to your GreatStore tenant. Each
1388
- component lives in its own folder under \`components/\`.
1389
-
1390
- \`\`\`
1391
- npm install
1392
- gs init <component_name> # add a new component
1393
- gs build # builds every components/<name>/bundle.js
1394
- gs push # uploads every changed component as a draft
1395
- gs publish <component_name> # promote a specific component to live
1396
- \`\`\`
1397
-
1398
- - \`gs push\` (no args) hashes each component and only uploads the ones
1399
- that have changed since the last sync.
1400
- - \`gs pull\` (no args) refreshes every remote component into
1401
- \`components/<name>/\`. Components with unsaved local edits are skipped
1402
- with a warning; pass \`--force\` to overwrite.
1403
- `;
1404
- }
1405
1280
  function pascal(name) {
1406
1281
  return name.split(/[_-]/).filter(Boolean).map((part) => part[0]?.toUpperCase() + part.slice(1)).join("");
1407
1282
  }
@@ -1677,11 +1552,11 @@ function readCache(home) {
1677
1552
  }
1678
1553
  return null;
1679
1554
  }
1680
- function writeCache(home, cache) {
1555
+ function writeCache(home, cache2) {
1681
1556
  try {
1682
1557
  const file = cachePath(home);
1683
1558
  fs8.mkdirSync(path8.dirname(file), { recursive: true });
1684
- fs8.writeFileSync(file, JSON.stringify(cache));
1559
+ fs8.writeFileSync(file, JSON.stringify(cache2));
1685
1560
  } catch {
1686
1561
  }
1687
1562
  }
@@ -1703,8 +1578,8 @@ function parseVer(v) {
1703
1578
  }
1704
1579
 
1705
1580
  // src/index.ts
1706
- var VERSION = true ? "0.0.22" : "0.0.0-dev";
1707
- 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.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' : "";
1581
+ var VERSION = true ? "0.0.23" : "0.0.0-dev";
1582
+ 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.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" : "";
1708
1583
  var HELP = `gs \u2014 GreatStore CLI (v${VERSION})
1709
1584
 
1710
1585
  Usage:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@greatstore/cli",
3
- "version": "0.0.22",
3
+ "version": "0.0.23",
4
4
  "description": "CLI for authoring and shipping GreatStore custom components.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",