handoff-app 2.0.0-4 → 2.0.0-6

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 (234) hide show
  1. package/AGENTS.md +7 -0
  2. package/CLAUDE.md +7 -0
  3. package/README.md +346 -377
  4. package/dist/app-builder/build.js +11 -4
  5. package/dist/app-builder/client-config.js +1 -0
  6. package/dist/app-builder/nav-shell.js +8 -15
  7. package/dist/app-builder/vercel-output.js +4 -4
  8. package/dist/cli/make.js +2 -2
  9. package/dist/cli.js +38 -6
  10. package/dist/commands/build/app.js +1 -5
  11. package/dist/commands/build/components.js +1 -5
  12. package/dist/commands/build/index.js +1 -5
  13. package/dist/commands/checkout/index.d.ts +15 -12
  14. package/dist/commands/checkout/index.js +15 -54
  15. package/dist/commands/compat/deprecations.d.ts +46 -0
  16. package/dist/commands/compat/deprecations.js +62 -0
  17. package/dist/commands/compat/push-args.d.ts +48 -0
  18. package/dist/commands/compat/push-args.js +73 -0
  19. package/dist/commands/db/migrate.js +1 -5
  20. package/dist/commands/dev/index.js +1 -5
  21. package/dist/commands/eject/config.js +1 -5
  22. package/dist/commands/eject/pages.js +1 -5
  23. package/dist/commands/eject/theme.js +1 -5
  24. package/dist/commands/fetch/index.js +1 -5
  25. package/dist/commands/index.js +4 -0
  26. package/dist/commands/login/index.js +1 -5
  27. package/dist/commands/logout/index.js +1 -5
  28. package/dist/commands/make/component.js +1 -5
  29. package/dist/commands/make/page.js +3 -7
  30. package/dist/commands/make/template.js +1 -5
  31. package/dist/commands/publish/index.d.ts +18 -12
  32. package/dist/commands/publish/index.js +18 -54
  33. package/dist/commands/pull/index.d.ts +13 -0
  34. package/dist/commands/pull/index.js +20 -0
  35. package/dist/commands/push/index.d.ts +23 -0
  36. package/dist/commands/push/index.js +58 -0
  37. package/dist/commands/scaffold/index.js +1 -5
  38. package/dist/commands/start/index.js +1 -5
  39. package/dist/commands/types.d.ts +10 -0
  40. package/dist/commands/utils.d.ts +74 -6
  41. package/dist/commands/utils.js +89 -10
  42. package/dist/commands/validate/components.js +1 -5
  43. package/dist/config/defaults.d.ts +2 -0
  44. package/dist/config/defaults.js +4 -1
  45. package/dist/config/index.d.ts +3 -2
  46. package/dist/config/index.js +3 -1
  47. package/dist/config/loader.d.ts +19 -6
  48. package/dist/config/loader.js +43 -13
  49. package/dist/config/normalizers/page.d.ts +4 -4
  50. package/dist/config/normalizers/page.js +2 -2
  51. package/dist/config/runtime.js +9 -25
  52. package/dist/index.d.ts +69 -22
  53. package/dist/index.js +148 -35
  54. package/dist/nav/resolver.js +3 -1
  55. package/dist/nav/workspace.js +2 -2
  56. package/dist/registry/auth/access-tokens.d.ts +11 -3
  57. package/dist/registry/auth/access-tokens.js +29 -3
  58. package/dist/registry/auth/index.d.ts +4 -3
  59. package/dist/registry/auth/index.js +10 -2
  60. package/dist/registry/auth/sync-secret.d.ts +27 -0
  61. package/dist/registry/auth/sync-secret.js +65 -0
  62. package/dist/registry/auth/types.d.ts +20 -1
  63. package/dist/registry/auth/types.js +3 -1
  64. package/dist/registry/auth/validation.d.ts +11 -0
  65. package/dist/registry/auth/validation.js +18 -1
  66. package/dist/registry/checkout/assets.d.ts +1 -1
  67. package/dist/registry/checkout/assets.js +21 -6
  68. package/dist/registry/checkout/index.d.ts +8 -1
  69. package/dist/registry/checkout/index.js +39 -6
  70. package/dist/registry/checkout/tokens.d.ts +1 -1
  71. package/dist/registry/checkout/tokens.js +12 -5
  72. package/dist/registry/connection.d.ts +10 -0
  73. package/dist/registry/connection.js +52 -7
  74. package/dist/registry/content-kinds.d.ts +27 -0
  75. package/dist/registry/content-kinds.js +33 -0
  76. package/dist/registry/db/client.d.ts +6 -1
  77. package/dist/registry/db/client.js +16 -3
  78. package/dist/registry/db/schema.d.ts +37 -3
  79. package/dist/registry/db/schema.js +9 -7
  80. package/dist/registry/publish/assets.d.ts +2 -2
  81. package/dist/registry/publish/assets.js +46 -35
  82. package/dist/registry/publish/index.d.ts +29 -5
  83. package/dist/registry/publish/index.js +87 -34
  84. package/dist/registry/publish/tokens.d.ts +2 -2
  85. package/dist/registry/publish/tokens.js +30 -24
  86. package/dist/registry/selection.d.ts +12 -0
  87. package/dist/registry/selection.js +22 -0
  88. package/dist/store/registry.d.ts +48 -0
  89. package/dist/store/registry.js +75 -12
  90. package/dist/transformers/preview/types.d.ts +2 -2
  91. package/dist/types/config.d.ts +7 -0
  92. package/dist/utils/markdown.d.ts +10 -0
  93. package/dist/utils/markdown.js +17 -0
  94. package/dist/utils/menu-shell.js +14 -7
  95. package/dist/utils/pages.d.ts +22 -0
  96. package/dist/utils/pages.js +73 -0
  97. package/dist/utils/path.d.ts +5 -0
  98. package/dist/utils/path.js +9 -0
  99. package/docs/api.md +1 -3
  100. package/docs/cli.md +1 -1
  101. package/drizzle/0002_add_pages.sql +5 -3
  102. package/drizzle/meta/0002_snapshot.json +17 -8
  103. package/drizzle/meta/0003_snapshot.json +17 -8
  104. package/drizzle/meta/0004_snapshot.json +17 -8
  105. package/drizzle/meta/0005_snapshot.json +17 -8
  106. package/package.json +4 -2
  107. package/src/app/components/CopyToClipboard.tsx +27 -26
  108. package/src/app/components/Layout/Header.tsx +4 -12
  109. package/src/app/components/Layout/RuntimeModeBadge.tsx +18 -0
  110. package/src/app/components/McpIntegration/McpConfigDialog.tsx +349 -0
  111. package/src/app/components/McpIntegration/McpIcon.tsx +10 -0
  112. package/src/app/components/Navigation/MobileNav.tsx +3 -1
  113. package/src/app/components/ui/dialog.tsx +73 -0
  114. package/src/app/components/util/index.ts +5 -23
  115. package/src/app/lib/docs-api/backend.ts +16 -1
  116. package/src/app/lib/docs-api/errors.ts +8 -7
  117. package/src/app/lib/docs-api/handler.ts +2 -3
  118. package/src/app/lib/docs-api/index.ts +2 -0
  119. package/src/app/lib/docs-api/page-discovery.ts +121 -0
  120. package/src/app/lib/docs-api/page-rendering.ts +37 -0
  121. package/src/app/lib/docs-api/page-search.ts +191 -0
  122. package/src/app/lib/docs-api/records.ts +31 -24
  123. package/src/app/lib/docs-api/registry.ts +92 -11
  124. package/src/app/lib/docs-api/runtime-config.ts +5 -0
  125. package/src/app/lib/docs-api/search.ts +120 -0
  126. package/src/app/lib/mcp/auth.ts +64 -0
  127. package/src/app/lib/mcp/index.ts +2 -0
  128. package/src/app/lib/mcp/server.ts +343 -0
  129. package/src/app/lib/mcp/shape.ts +595 -0
  130. package/src/app/lib/registry-api/allowlist.ts +7 -5
  131. package/src/app/lib/registry-api/asset-transfer.ts +58 -31
  132. package/src/app/lib/registry-api/auth.ts +89 -9
  133. package/src/app/lib/registry-api/entity-routes.ts +17 -7
  134. package/src/app/lib/registry-api/errors.ts +10 -4
  135. package/src/app/lib/registry-api/handler.ts +13 -15
  136. package/src/app/lib/registry-api/meta.ts +4 -0
  137. package/src/app/lib/registry-api/revalidate.ts +31 -12
  138. package/src/app/lib/registry-api/store.ts +89 -26
  139. package/src/app/lib/registry-api/sync-compat.ts +166 -0
  140. package/src/app/lib/registry-api/token-transfer.ts +44 -12
  141. package/src/app/lib/registry-api/transfer-batch.ts +116 -0
  142. package/src/app/lib/registry-api/transfer.ts +62 -35
  143. package/src/app/lib/registry-api/validation.ts +33 -1
  144. package/src/app/lib/registry-connection.ts +1 -1
  145. package/src/app/next.config.mjs +9 -0
  146. package/src/app/pages/[...slug]/index.tsx +52 -51
  147. package/src/app/pages/api/account/tokens/index.ts +4 -13
  148. package/src/app/pages/api/docs/search/pages.json.ts +25 -0
  149. package/src/app/pages/api/mcp.ts +56 -0
  150. package/src/app/pages/api/oauth/revoke.ts +14 -7
  151. package/src/app/pages/api/registry/components/[id]/files/[...filePath].ts +1 -1
  152. package/src/app/pages/api/registry/components/[id].ts +2 -2
  153. package/src/app/pages/api/registry/components/index.ts +1 -1
  154. package/src/app/pages/api/registry/pages/[...id].ts +20 -0
  155. package/src/app/pages/api/registry/pages/index.ts +19 -0
  156. package/src/app/pages/api/registry/patterns/[id]/files/[...filePath].ts +1 -1
  157. package/src/app/pages/api/registry/patterns/[id].ts +2 -2
  158. package/src/app/pages/api/registry/patterns/index.ts +1 -1
  159. package/src/app/pages/api/registry/transfer/assets/blobs/have.ts +2 -2
  160. package/src/app/pages/api/sync/upload.ts +21 -0
  161. package/src/app/pages/index/index.tsx +14 -0
  162. package/src/app/pages/index.tsx +31 -5
  163. package/src/app-builder/build.ts +11 -4
  164. package/src/app-builder/client-config.ts +2 -1
  165. package/src/app-builder/nav-shell.ts +8 -13
  166. package/src/app-builder/vercel-output.ts +4 -4
  167. package/src/cli/make.ts +2 -2
  168. package/src/cli.ts +30 -6
  169. package/src/commands/build/app.ts +2 -3
  170. package/src/commands/build/components.ts +2 -3
  171. package/src/commands/build/index.ts +2 -3
  172. package/src/commands/checkout/index.ts +18 -44
  173. package/src/commands/compat/deprecations.ts +79 -0
  174. package/src/commands/compat/push-args.ts +106 -0
  175. package/src/commands/db/migrate.ts +2 -3
  176. package/src/commands/dev/index.ts +2 -3
  177. package/src/commands/eject/config.ts +2 -3
  178. package/src/commands/eject/pages.ts +2 -3
  179. package/src/commands/eject/theme.ts +2 -3
  180. package/src/commands/fetch/index.ts +2 -3
  181. package/src/commands/index.ts +4 -0
  182. package/src/commands/login/index.ts +2 -3
  183. package/src/commands/logout/index.ts +2 -3
  184. package/src/commands/make/component.ts +2 -3
  185. package/src/commands/make/page.ts +4 -5
  186. package/src/commands/make/template.ts +2 -3
  187. package/src/commands/publish/index.ts +21 -44
  188. package/src/commands/pull/index.ts +32 -0
  189. package/src/commands/push/index.ts +115 -0
  190. package/src/commands/scaffold/index.ts +2 -3
  191. package/src/commands/start/index.ts +2 -3
  192. package/src/commands/types.ts +11 -1
  193. package/src/commands/utils.ts +80 -11
  194. package/src/commands/validate/components.ts +2 -3
  195. package/src/config/defaults.ts +3 -0
  196. package/src/config/index.ts +3 -2
  197. package/src/config/loader.ts +57 -12
  198. package/src/config/normalizers/page.ts +4 -4
  199. package/src/config/runtime.ts +9 -24
  200. package/src/index.ts +183 -42
  201. package/src/nav/resolver.ts +3 -1
  202. package/src/nav/workspace.ts +2 -2
  203. package/src/registry/auth/access-tokens.ts +29 -5
  204. package/src/registry/auth/index.ts +7 -1
  205. package/src/registry/auth/sync-secret.ts +67 -0
  206. package/src/registry/auth/types.ts +24 -1
  207. package/src/registry/auth/validation.ts +18 -0
  208. package/src/registry/checkout/assets.ts +24 -7
  209. package/src/registry/checkout/index.ts +41 -5
  210. package/src/registry/checkout/tokens.ts +12 -6
  211. package/src/registry/connection.ts +53 -5
  212. package/src/registry/content-kinds.ts +39 -0
  213. package/src/registry/db/client.ts +22 -2
  214. package/src/registry/db/schema.ts +9 -7
  215. package/src/registry/publish/assets.ts +47 -37
  216. package/src/registry/publish/index.ts +102 -38
  217. package/src/registry/publish/tokens.ts +35 -26
  218. package/src/registry/selection.ts +19 -0
  219. package/src/store/registry.ts +118 -13
  220. package/src/transformers/preview/types.ts +2 -2
  221. package/src/types/config.ts +7 -0
  222. package/src/utils/README.md +1 -0
  223. package/src/utils/markdown.ts +11 -0
  224. package/src/utils/menu-shell.ts +14 -7
  225. package/src/utils/pages.ts +52 -0
  226. package/src/utils/path.ts +15 -6
  227. package/templates/default/README.md.tpl +10 -0
  228. package/templates/default/handoff.config.js.tpl +6 -3
  229. package/templates/default/handoff.config.ts.tpl +6 -3
  230. package/templates/default/handoff.config.with-examples.js.tpl +6 -3
  231. package/templates/default/handoff.config.with-examples.ts.tpl +6 -3
  232. package/templates/default/package.json.tpl +4 -0
  233. package/config/docs/foundations/logos.md +0 -7
  234. package/src/app/lib/api/redact.ts +0 -46
@@ -40,13 +40,14 @@ const p = __importStar(require("@clack/prompts"));
40
40
  const cross_spawn_1 = __importDefault(require("cross-spawn"));
41
41
  const fs_extra_1 = __importDefault(require("fs-extra"));
42
42
  const path_1 = __importDefault(require("path"));
43
+ const config_1 = require("../config");
43
44
  const components_1 = require("../pipeline/components");
44
45
  const patterns_1 = require("../pipeline/patterns");
46
+ const resolve_1 = require("../registry/asset-storage/resolve");
47
+ const driver_1 = require("../registry/db/driver");
45
48
  const builder_1 = __importDefault(require("../transformers/preview/component/builder"));
46
49
  const css_1 = require("../transformers/preview/component/css");
47
50
  const javascript_1 = require("../transformers/preview/component/javascript");
48
- const driver_1 = require("../registry/db/driver");
49
- const resolve_1 = require("../registry/asset-storage/resolve");
50
51
  const logger_1 = require("../utils/logger");
51
52
  const client_config_1 = require("./client-config");
52
53
  const nav_shell_1 = require("./nav-shell");
@@ -216,6 +217,7 @@ const initializeProjectApp = (handoff_1, ...args_1) => __awaiter(void 0, [handof
216
217
  // Resolved runtime mode + registry connection inputs (names only) baked into the Next bundle so the
217
218
  // deployed registry app resolves its mode/DB env-var name without any build-machine filesystem.
218
219
  const escapedRuntimeMode = escapeForSingleQuotedJsString(runtimeMode);
220
+ const escapedMcpEnabled = escapeForSingleQuotedJsString(String((0, config_1.isMcpEnabled)(handoff.config)));
219
221
  const escapedRegistryDriver = escapeForSingleQuotedJsString((0, driver_1.resolveRegistryDriver)(handoff.config));
220
222
  const escapedDatabaseUrlEnv = escapeForSingleQuotedJsString((0, driver_1.resolveDatabaseUrlEnv)(handoff.config));
221
223
  // Asset storage selection baked (provider + module + env-var names + non-secret options JSON).
@@ -233,6 +235,7 @@ const initializeProjectApp = (handoff_1, ...args_1) => __awaiter(void 0, [handof
233
235
  '%HANDOFF_EXPORT_PATH%': escapedExportPath,
234
236
  '%HANDOFF_WEBSOCKET_PORT%': escapedWebsocketPort,
235
237
  '%HANDOFF_RUNTIME_MODE%': escapedRuntimeMode,
238
+ '%HANDOFF_MCP_ENABLED%': escapedMcpEnabled,
236
239
  '%HANDOFF_REGISTRY_DRIVER%': escapedRegistryDriver,
237
240
  '%HANDOFF_REGISTRY_DATABASE_URL_ENV%': escapedDatabaseUrlEnv,
238
241
  '%HANDOFF_ASSET_STORAGE_ADAPTER%': escapedAssetStorageAdapter,
@@ -426,12 +429,16 @@ containers, custom Node servers, and other non-Vercel hosts.
426
429
  /**
427
430
  * Resolve the set of npm packages the packaged registry app must be able to `require`/`import` at
428
431
  * runtime, given the configured database driver. `next`/`react`/`react-dom` run the server and React
429
- * runtime; `drizzle-orm` backs both the request-time DB client and the migration runner; the driver
430
- * package is driver-specific (the Neon serverless driver also needs `ws` for its Node WebSocket transport).
432
+ * runtime; `drizzle-orm` backs both the request-time DB client and the migration runner; the MCP SDK
433
+ * (and its `zod` peer) is only needed when `/api/mcp/` is enabled; the driver package is
434
+ * driver-specific (the Neon serverless driver also needs `ws` for its Node WebSocket transport).
431
435
  */
432
436
  const getRequiredRegistryRuntimeModules = (handoff) => {
433
437
  var _a;
434
438
  const base = ['next', 'next-auth', 'react', 'react-dom', 'drizzle-orm'];
439
+ if ((0, config_1.isMcpEnabled)(handoff.config)) {
440
+ base.push('@modelcontextprotocol/sdk', 'zod');
441
+ }
435
442
  const driver = (0, driver_1.resolveRegistryDriver)(handoff.config);
436
443
  const driverModules = driver === 'neon' ? ['@neondatabase/serverless', 'ws'] : ['pg'];
437
444
  // Asset-storage SDKs the deployed registry must be able to load at request time. The pre-packaged
@@ -65,6 +65,7 @@ const buildServerRuntimeConfig = (config, modeOverride) => {
65
65
  const assetStorage = (0, resolve_1.resolveAssetStorageFromConfig)(config);
66
66
  return {
67
67
  mode: (_b = modeOverride !== null && modeOverride !== void 0 ? modeOverride : (_a = config === null || config === void 0 ? void 0 : config.runtime) === null || _a === void 0 ? void 0 : _a.mode) !== null && _b !== void 0 ? _b : 'workspace',
68
+ mcp: (0, config_1.isMcpEnabled)(config),
68
69
  registry: {
69
70
  driver: (0, driver_1.resolveRegistryDriver)(config),
70
71
  databaseUrlEnv: (0, driver_1.resolveDatabaseUrlEnv)(config),
@@ -14,10 +14,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.generateNavShell = exports.generateDefaultPages = exports.DEFAULT_PAGES_RELATIVE_PATH = exports.NAV_SHELL_RELATIVE_PATH = void 0;
16
16
  const fs_extra_1 = __importDefault(require("fs-extra"));
17
- const gray_matter_1 = __importDefault(require("gray-matter"));
18
17
  const path_1 = __importDefault(require("path"));
18
+ const markdown_1 = require("../utils/markdown");
19
19
  const menu_shell_1 = require("../utils/menu-shell");
20
20
  const logger_1 = require("../utils/logger");
21
+ const pages_1 = require("../utils/pages");
21
22
  /**
22
23
  * Relative path (within the staged Next app) of the baked navigation shell. The docs read API
23
24
  * (`pages/api/docs/nav.json.ts`) imports this statically so it is bundled into the route chunk and
@@ -27,21 +28,13 @@ const logger_1 = require("../utils/logger");
27
28
  exports.NAV_SHELL_RELATIVE_PATH = path_1.default.join('generated', 'nav-shell.json');
28
29
  /** Baked package-default markdown used as the registry catch-all's runtime fallback. */
29
30
  exports.DEFAULT_PAGES_RELATIVE_PATH = path_1.default.join('generated', 'default-pages.json');
30
- /** Recursively collect package docs (except dedicated index routes) by their catch-all id. */
31
- const collectDefaultPages = (root, relativeParts = []) => {
32
- if (!fs_extra_1.default.existsSync(root))
33
- return {};
31
+ /** Collect package defaults for registry fallbacks, including the dedicated root home page. */
32
+ const collectDefaultPages = (root) => {
34
33
  const pages = {};
35
- for (const entry of fs_extra_1.default.readdirSync(root)) {
36
- const absolutePath = path_1.default.join(root, entry);
37
- if (fs_extra_1.default.lstatSync(absolutePath).isDirectory()) {
38
- Object.assign(pages, collectDefaultPages(absolutePath, [...relativeParts, entry]));
39
- }
40
- else if (entry.endsWith('.md') && entry !== 'index.md') {
41
- const id = [...relativeParts, entry.replace(/\.md$/, '')].join('/');
42
- const { data, content } = (0, gray_matter_1.default)(fs_extra_1.default.readFileSync(absolutePath, 'utf8'));
43
- pages[id] = { metadata: data, content };
44
- }
34
+ for (const segments of (0, pages_1.collectPageSlugSegments)(root, { includeRootIndex: true })) {
35
+ const id = segments.join('/');
36
+ const { data, content } = (0, markdown_1.parseMarkdown)(fs_extra_1.default.readFileSync(path_1.default.resolve(root, `${id}.md`), 'utf8'));
37
+ pages[id] = { metadata: data, content };
45
38
  }
46
39
  return pages;
47
40
  };
@@ -15,6 +15,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.writeRegistryVercelOutput = exports.writeStaticVercelOutput = exports.getVercelOutputPath = void 0;
16
16
  const fs_extra_1 = __importDefault(require("fs-extra"));
17
17
  const path_1 = __importDefault(require("path"));
18
+ const content_kinds_1 = require("../registry/content-kinds");
18
19
  const logger_1 = require("../utils/logger");
19
20
  /**
20
21
  * Vercel Build Output API layout.
@@ -151,9 +152,8 @@ module.exports = async (req, res) => {
151
152
  *
152
153
  * Routes materialized from the mutable docs catch-all also appear in `routes` when package defaults
153
154
  * are prerendered. They are identified by `srcRoute` and deliberately left behind the function so a
154
- * published DB record can override the fallback. Other `fallback:'blocking'` dynamic routes are
155
- * absent and naturally reach the function. Immutable pages — e.g. the header's `<Link href="/">`
156
- * prefetch of `/_next/data/<buildId>/index.json` — are served straight from the CDN.
155
+ * published DB record can override the fallback. The root page is also mutable and stays behind the
156
+ * function. Other `fallback:'blocking'` dynamic routes are absent and naturally reach the function.
157
157
  *
158
158
  * No-op when nothing is prerendered (empty `routes`). Paths are emitted base-path-less, matching the
159
159
  * existing `_next/static` copy and the registry route table.
@@ -173,7 +173,7 @@ const copyPrerenderedStaticPages = (appPath, staticOutDir) => __awaiter(void 0,
173
173
  for (const [route, routeConfig] of Object.entries(routes)) {
174
174
  // A static copy would win at the Build Output API filesystem route and permanently hide a
175
175
  // published override (and its on-demand revalidation) from the registry function.
176
- if (routeConfig.srcRoute === MUTABLE_REGISTRY_PAGE_SRC_ROUTE) {
176
+ if (route === content_kinds_1.HOME_PAGE_PATH || routeConfig.srcRoute === MUTABLE_REGISTRY_PAGE_SRC_ROUTE) {
177
177
  continue;
178
178
  }
179
179
  // `.next/server/pages/<rel>.{html,json}` — `/` maps to `index`, nested routes keep their path.
package/dist/cli/make.js CHANGED
@@ -93,13 +93,13 @@ const makePage = (handoff, name, parent) => __awaiter(void 0, void 0, void 0, fu
93
93
  logger_1.Logger.error(`Page name must be set`);
94
94
  return;
95
95
  }
96
- if (!/^[a-z0-9]+$/i.test(name)) {
96
+ if (!/^[a-z0-9_-]+$/i.test(name)) {
97
97
  logger_1.Logger.error(`Page name must be alphanumeric and may contain dashes or underscores`);
98
98
  return;
99
99
  }
100
100
  let workingPath, sourcePath, templatePath;
101
101
  if (parent) {
102
- if (!/^[a-z0-9]+$/i.test(parent)) {
102
+ if (!/^[a-z0-9_-]+$/i.test(parent)) {
103
103
  logger_1.Logger.error(`Parent name must be alphanumeric and may contain dashes or underscores`);
104
104
  return;
105
105
  }
package/dist/cli.js CHANGED
@@ -1,5 +1,14 @@
1
1
  #! /usr/bin/env node
2
2
  "use strict";
3
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
4
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
5
+ return new (P || (P = Promise))(function (resolve, reject) {
6
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
7
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
8
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
9
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
10
+ });
11
+ };
3
12
  var __importDefault = (this && this.__importDefault) || function (mod) {
4
13
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
14
  };
@@ -7,6 +16,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
16
  const helpers_1 = require("yargs/helpers");
8
17
  const yargs_1 = __importDefault(require("yargs/yargs"));
9
18
  const commands_1 = require("./commands");
19
+ const config_1 = require("./config");
20
+ const logger_1 = require("./utils/logger");
10
21
  class HandoffCliError extends Error {
11
22
  constructor(message) {
12
23
  // 'Error' breaks prototype chain here
@@ -32,18 +43,39 @@ const cliError = function (msg, exitCode = 1) {
32
43
  err.exitCode = exitCode;
33
44
  throw err;
34
45
  };
35
- const run = () => {
46
+ const run = () => __awaiter(void 0, void 0, void 0, function* () {
36
47
  try {
37
48
  const yargsInstance = (0, yargs_1.default)((0, helpers_1.hideBin)(process.argv));
38
49
  commands_1.commands.forEach((command) => {
39
50
  yargsInstance.command(command);
40
51
  });
41
- yargsInstance.help().version(showVersion()).strict().parse();
52
+ yargsInstance.fail((msg, error, instance) => {
53
+ // A bad `-c` is the user's to fix: one actionable line, no usage dump and no stack trace.
54
+ if (error instanceof config_1.HandoffConfigError) {
55
+ logger_1.Logger.error(error.message);
56
+ process.exit(1);
57
+ }
58
+ // Anything else unexpected keeps its stack; usage errors keep yargs' help-then-message output.
59
+ if (error) {
60
+ throw error;
61
+ }
62
+ instance.showHelp();
63
+ logger_1.Logger.error(msg);
64
+ process.exit(1);
65
+ });
66
+ // Awaited so a rejected async handler reaches the failure handling above.
67
+ yield yargsInstance.help().version(showVersion()).strict().parseAsync();
42
68
  }
43
69
  catch (e) {
44
- if (e.message.indexOf('Unknown or unexpected option') === -1)
70
+ const message = e instanceof Error ? e.message : String(e);
71
+ if (message.indexOf('Unknown or unexpected option') === -1)
45
72
  throw e;
46
- return cliError(e.message, 2);
73
+ return cliError(message, 2);
47
74
  }
48
- };
49
- run();
75
+ });
76
+ run().catch((error) => {
77
+ // User-facing failures are already reported above, so anything landing here is unexpected and
78
+ // keeps its stack trace.
79
+ console.error(error);
80
+ process.exit(1);
81
+ });
@@ -8,11 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
11
  Object.defineProperty(exports, "__esModule", { value: true });
15
- const __1 = __importDefault(require("../../"));
16
12
  const utils_1 = require("../utils");
17
13
  const command = {
18
14
  command: 'build:app',
@@ -26,7 +22,7 @@ const command = {
26
22
  },
27
23
  handler: (args) => __awaiter(void 0, void 0, void 0, function* () {
28
24
  var _a;
29
- const handoff = new __1.default(args.debug, args.force);
25
+ const handoff = (0, utils_1.createHandoff)(args);
30
26
  yield handoff.build('static', (_a = args.skipComponents) !== null && _a !== void 0 ? _a : false);
31
27
  }),
32
28
  };
@@ -8,11 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
11
  Object.defineProperty(exports, "__esModule", { value: true });
15
- const __1 = __importDefault(require("../.."));
16
12
  const utils_1 = require("../utils");
17
13
  const command = {
18
14
  command: 'build:components [component]',
@@ -24,7 +20,7 @@ const command = {
24
20
  });
25
21
  },
26
22
  handler: (args) => __awaiter(void 0, void 0, void 0, function* () {
27
- const handoff = new __1.default(args.debug, args.force);
23
+ const handoff = (0, utils_1.createHandoff)(args);
28
24
  yield handoff.component(args.component);
29
25
  }),
30
26
  };
@@ -8,11 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
11
  Object.defineProperty(exports, "__esModule", { value: true });
15
- const __1 = __importDefault(require("../../"));
16
12
  const app_builder_1 = require("../../app-builder");
17
13
  const logger_1 = require("../../utils/logger");
18
14
  const utils_1 = require("../utils");
@@ -47,7 +43,7 @@ const command = {
47
43
  },
48
44
  handler: (args) => __awaiter(void 0, void 0, void 0, function* () {
49
45
  var _a, _b;
50
- const handoff = new __1.default(args.debug, args.force);
46
+ const handoff = (0, utils_1.createHandoff)(args);
51
47
  try {
52
48
  yield handoff.build((_a = args.target) !== null && _a !== void 0 ? _a : app_builder_1.DEFAULT_BUILD_TARGET, (_b = args.skipComponents) !== null && _b !== void 0 ? _b : false, args.package);
53
49
  }
@@ -1,24 +1,27 @@
1
1
  import { CommandModule } from 'yargs';
2
2
  import { SharedArgs } from '../types';
3
- import { RegistryEntityKind } from '../utils';
3
+ import { RegistryTargetKind } from '../utils';
4
4
  export interface CheckoutArgs extends SharedArgs {
5
- type: RegistryEntityKind;
6
- id?: string;
5
+ type: RegistryTargetKind;
6
+ id?: string[];
7
7
  }
8
8
  /**
9
- * `handoff-app checkout <components|patterns|pages> [id]` pulls entities from the connected registry
10
- * into this workspace, writing their source files in standard authoring form and synthesizing local
11
- * declarations. Pass an `id` to pull that one entity, or omit it to pull every published entity of
12
- * that kind.
9
+ * `handoff-app checkout <components|patterns|pages> [id...]` pulls entities from the connected
10
+ * registry into this workspace, writing their source files in standard authoring form and
11
+ * synthesizing local declarations. Pass ids to pull only those entities, or omit them for every
12
+ * published entity of that kind.
13
13
  *
14
- * `handoff-app checkout tokens [setId]` — pull every published token set (or only the named set) into
15
- * this workspace: reconstruct `tokens.json` and restore the generated token files.
14
+ * `handoff-app checkout tokens [setId...]` pulls every published token set, or only the named ones,
15
+ * reconstructing `tokens.json` and restoring the generated token files.
16
+ *
17
+ * `handoff-app checkout assets [collection...]` pulls every published asset collection, or only the
18
+ * named ones, recreating the standard asset files, sprite/manifest and archives.
19
+ *
20
+ * `handoff-app checkout all` runs every kind in the same order publish uses.
16
21
  *
17
- * `handoff-app checkout assets [collection]` pulls every published asset collection (or only the
18
- * named one) into this workspace, recreating the standard asset files, sprite/manifest, and archives.
19
22
  * Available only from a connected workspace (`runtime.mode: workspace` + a configured
20
23
  * `registryConnection`). Overwriting existing local files requires `--force` or an interactive
21
- * confirmation.
24
+ * confirmation; `--dry-run` lists what would be written and changes nothing.
22
25
  */
23
26
  declare const command: CommandModule<{}, CheckoutArgs>;
24
27
  export default command;
@@ -1,67 +1,28 @@
1
1
  "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
2
  Object.defineProperty(exports, "__esModule", { value: true });
15
- const __1 = __importDefault(require("../../"));
16
- const logger_1 = require("../../utils/logger");
17
3
  const utils_1 = require("../utils");
18
4
  /**
19
- * `handoff-app checkout <components|patterns|pages> [id]` pulls entities from the connected registry
20
- * into this workspace, writing their source files in standard authoring form and synthesizing local
21
- * declarations. Pass an `id` to pull that one entity, or omit it to pull every published entity of
22
- * that kind.
5
+ * `handoff-app checkout <components|patterns|pages> [id...]` pulls entities from the connected
6
+ * registry into this workspace, writing their source files in standard authoring form and
7
+ * synthesizing local declarations. Pass ids to pull only those entities, or omit them for every
8
+ * published entity of that kind.
9
+ *
10
+ * `handoff-app checkout tokens [setId...]` pulls every published token set, or only the named ones,
11
+ * reconstructing `tokens.json` and restoring the generated token files.
12
+ *
13
+ * `handoff-app checkout assets [collection...]` pulls every published asset collection, or only the
14
+ * named ones, recreating the standard asset files, sprite/manifest and archives.
23
15
  *
24
- * `handoff-app checkout tokens [setId]` — pull every published token set (or only the named set) into
25
- * this workspace: reconstruct `tokens.json` and restore the generated token files.
16
+ * `handoff-app checkout all` runs every kind in the same order publish uses.
26
17
  *
27
- * `handoff-app checkout assets [collection]` pulls every published asset collection (or only the
28
- * named one) into this workspace, recreating the standard asset files, sprite/manifest, and archives.
29
18
  * Available only from a connected workspace (`runtime.mode: workspace` + a configured
30
19
  * `registryConnection`). Overwriting existing local files requires `--force` or an interactive
31
- * confirmation.
20
+ * confirmation; `--dry-run` lists what would be written and changes nothing.
32
21
  */
33
22
  const command = {
34
- command: 'checkout <type> [id]',
23
+ command: 'checkout <type> [id..]',
35
24
  describe: 'Pull components, patterns, pages, design tokens, or assets from the connected registry into this workspace',
36
- builder: (yargs) => {
37
- return (0, utils_1.getSharedOptions)(yargs)
38
- .positional('type', {
39
- describe: 'The kind of entity to checkout',
40
- choices: utils_1.REGISTRY_ENTITY_KINDS,
41
- type: 'string',
42
- })
43
- .positional('id', {
44
- describe: 'The stable id of the entity (component/pattern/page id, token set id, or asset collection); omit to checkout all of that kind',
45
- type: 'string',
46
- });
47
- },
48
- handler: (args) => __awaiter(void 0, void 0, void 0, function* () {
49
- const handoff = new __1.default(args.debug, args.force);
50
- try {
51
- if (args.type === 'tokens') {
52
- yield handoff.checkoutTokens(args.id);
53
- return;
54
- }
55
- if (args.type === 'assets') {
56
- yield handoff.checkoutAssets(args.id);
57
- return;
58
- }
59
- yield handoff.checkout(utils_1.ENTITY_WIRE_KIND[args.type], args.id);
60
- }
61
- catch (error) {
62
- logger_1.Logger.error(error instanceof Error ? error.message : String(error));
63
- process.exitCode = 1;
64
- }
65
- }),
25
+ builder: (yargs) => (0, utils_1.withTargetPositionals)((0, utils_1.getCheckoutOptions)(yargs), 'checkout'),
26
+ handler: (args) => (0, utils_1.runRegistryCommand)(args, (handoff) => (0, utils_1.runTarget)(handoff, args.type, args.id, 'checkout')),
66
27
  };
67
28
  exports.default = command;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Deprecation notices for the documented-but-superseded CLI surface.
3
+ *
4
+ * Messaging only: no publish, checkout or config behavior lives in this directory. Notices go through
5
+ * {@link Logger.warn} so `HANDOFF_LOG_LEVEL=error` silences them in CI, where the operator has
6
+ * already accepted the older form.
7
+ *
8
+ * Call these from inside `runRegistryCommand`'s callback, never before it. `Logger` reads
9
+ * `HANDOFF_LOG_LEVEL` when the `Handoff` instance is constructed, so a notice emitted earlier prints
10
+ * at the default level and ignores the configured one.
11
+ */
12
+ /** Announce that a command is on its way out and name the canonical form to move to. */
13
+ export declare const warnDeprecatedCommand: (invoked: string, canonical: string) => void;
14
+ /**
15
+ * A documented option we cannot honor, and why. Declared rather than left to `.strict()` so a command
16
+ * copied from the docs runs and explains itself instead of failing with "Unknown argument".
17
+ */
18
+ interface UnsupportedOption {
19
+ /** yargs option key, camelCased as yargs delivers it. */
20
+ key: string;
21
+ /** How the option is written on the command line, for the warning text. */
22
+ flag: string;
23
+ /** yargs value type; only `-m, --message` carries a value. */
24
+ type?: 'boolean' | 'string';
25
+ /** Short flag, where the docs give one. */
26
+ alias?: string;
27
+ reason: string;
28
+ }
29
+ /** Options documented for `push` itself. */
30
+ export declare const UNSUPPORTED_PUSH_OPTIONS: readonly UnsupportedOption[];
31
+ /** Options documented for `push:tokens`. */
32
+ export declare const UNSUPPORTED_PUSH_TOKENS_OPTIONS: readonly UnsupportedOption[];
33
+ /** `push:all` steps documented for subsystems we do not have. */
34
+ export declare const UNSUPPORTED_PUSH_ALL_OPTIONS: readonly UnsupportedOption[];
35
+ /** Declare unsupported options as hidden yargs booleans so `.strict()` accepts them. */
36
+ export declare const hiddenOptions: (options: readonly UnsupportedOption[]) => {
37
+ [k: string]: {
38
+ alias?: string;
39
+ type: "string" | "boolean";
40
+ hidden: boolean;
41
+ describe: string;
42
+ };
43
+ };
44
+ /** Warn about every unsupported option present on the command line, then carry on. */
45
+ export declare const warnUnsupportedOptions: (args: Record<string, unknown>, options: readonly UnsupportedOption[]) => void;
46
+ export {};
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ /**
3
+ * Deprecation notices for the documented-but-superseded CLI surface.
4
+ *
5
+ * Messaging only: no publish, checkout or config behavior lives in this directory. Notices go through
6
+ * {@link Logger.warn} so `HANDOFF_LOG_LEVEL=error` silences them in CI, where the operator has
7
+ * already accepted the older form.
8
+ *
9
+ * Call these from inside `runRegistryCommand`'s callback, never before it. `Logger` reads
10
+ * `HANDOFF_LOG_LEVEL` when the `Handoff` instance is constructed, so a notice emitted earlier prints
11
+ * at the default level and ignores the configured one.
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.warnUnsupportedOptions = exports.hiddenOptions = exports.UNSUPPORTED_PUSH_ALL_OPTIONS = exports.UNSUPPORTED_PUSH_TOKENS_OPTIONS = exports.UNSUPPORTED_PUSH_OPTIONS = exports.warnDeprecatedCommand = void 0;
15
+ const logger_1 = require("../../utils/logger");
16
+ /** Announce that a command is on its way out and name the canonical form to move to. */
17
+ const warnDeprecatedCommand = (invoked, canonical) => {
18
+ logger_1.Logger.warn(`\`handoff-app ${invoked}\` is deprecated and will be removed in a future release; use \`handoff-app ${canonical}\` instead.`);
19
+ };
20
+ exports.warnDeprecatedCommand = warnDeprecatedCommand;
21
+ /** Options documented for `push` itself. */
22
+ exports.UNSUPPORTED_PUSH_OPTIONS = [
23
+ {
24
+ key: 'metadataOnly',
25
+ flag: '--metadata-only',
26
+ reason: 'a publish replaces an entity\'s files and artifacts as one package, so a metadata-only upload would delete them',
27
+ },
28
+ { key: 'message', flag: '-m, --message', type: 'string', alias: 'm', reason: 'there is no change history to annotate' },
29
+ ];
30
+ /** Options documented for `push:tokens`. */
31
+ exports.UNSUPPORTED_PUSH_TOKENS_OPTIONS = [
32
+ { key: 'skipFigma', flag: '--skip-figma', reason: 'rebuilding tokens without a Figma request is not implemented yet' },
33
+ { key: 'skipDtcg', flag: '--skip-dtcg', reason: 'there is no DTCG dist step in this pipeline' },
34
+ ];
35
+ /** `push:all` steps documented for subsystems we do not have. */
36
+ exports.UNSUPPORTED_PUSH_ALL_OPTIONS = [
37
+ { key: 'skipBuild', flag: '--skip-build', reason: 'use --no-build, which applies to the whole run' },
38
+ ...['config', 'theme', 'navigation', 'dtcg', 'icons', 'logos', 'fonts', 'figma-fills', 'image-slots', 'design-md'].map((step) => ({
39
+ key: `skip${step.replace(/(^|-)([a-z])/g, (_match, _dash, letter) => letter.toUpperCase())}`,
40
+ flag: `--skip-${step}`,
41
+ reason: 'this implementation has no such publish step',
42
+ })),
43
+ { key: 'message', flag: '-m, --message', type: 'string', alias: 'm', reason: 'there is no change history to annotate' },
44
+ ];
45
+ /** Declare unsupported options as hidden yargs booleans so `.strict()` accepts them. */
46
+ const hiddenOptions = (options) => Object.fromEntries(options.map((option) => {
47
+ var _a;
48
+ return [
49
+ option.key,
50
+ Object.assign({ type: (_a = option.type) !== null && _a !== void 0 ? _a : 'boolean', hidden: true, describe: option.reason }, (option.alias ? { alias: option.alias } : {})),
51
+ ];
52
+ }));
53
+ exports.hiddenOptions = hiddenOptions;
54
+ /** Warn about every unsupported option present on the command line, then carry on. */
55
+ const warnUnsupportedOptions = (args, options) => {
56
+ for (const option of options) {
57
+ if (args[option.key] !== undefined && args[option.key] !== false) {
58
+ logger_1.Logger.warn(`${option.flag} is ignored: ${option.reason}.`);
59
+ }
60
+ }
61
+ };
62
+ exports.warnUnsupportedOptions = warnUnsupportedOptions;
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Translation from the documented `push` / `pull` argument shape to canonical publish targets.
3
+ *
4
+ * The published CLI reference addresses content with selective flags (`--components <ids>`) and an
5
+ * implied "everything" default, while we address it positionally (`publish <type> [id...]`). These
6
+ * are pure functions that convert one into the other; the publishing itself is done by
7
+ * {@link Handoff.publishAll}, so no orchestration lives here.
8
+ */
9
+ import { type RegistryEntityKind } from '../../registry/content-kinds';
10
+ import type { RegistryTargetKind } from '../utils';
11
+ import type { ContentTarget } from '../../index';
12
+ /** The documented `push` / `pull` arguments read here. */
13
+ export interface CompatTargetArgs {
14
+ type?: RegistryTargetKind;
15
+ id?: string[];
16
+ components?: string[];
17
+ patterns?: string[];
18
+ pages?: string[];
19
+ }
20
+ /** The documented `push:all` skip flags that map onto a real content kind. */
21
+ export interface CompatSkipArgs {
22
+ skipTokens?: boolean;
23
+ skipAssets?: boolean;
24
+ skipComponents?: boolean;
25
+ skipPatterns?: boolean;
26
+ skipPages?: boolean;
27
+ }
28
+ /** The documented `push:assets` skip flags. */
29
+ export interface CompatAssetSkipArgs {
30
+ skipIcons?: boolean;
31
+ skipLogos?: boolean;
32
+ }
33
+ /**
34
+ * Resolve what a documented `push` / `pull` invocation targets, in precedence order:
35
+ *
36
+ * 1. selective flags (`--components a b --pages intro`), the documented way to narrow a run;
37
+ * 2. a positional kind, matching our own `publish <type> [id...]`;
38
+ * 3. nothing, which the docs define as pages plus component and pattern declarations.
39
+ */
40
+ export declare const resolveCompatTargets: (args: CompatTargetArgs) => ContentTarget[];
41
+ /** Resolve the kinds a documented `push:all` should run, honoring its `--skip-<kind>` flags. */
42
+ export declare const resolveCompatAllKinds: (args: CompatSkipArgs) => RegistryEntityKind[];
43
+ /**
44
+ * Resolve the asset collections a documented `push:assets` should publish. Returns `undefined` when
45
+ * nothing is skipped, so the canonical path still discovers collections itself instead of being
46
+ * pinned to the compile-time list.
47
+ */
48
+ export declare const resolveCompatAssetSelection: (args: CompatAssetSkipArgs, collection?: string) => string[] | undefined;
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ /**
3
+ * Translation from the documented `push` / `pull` argument shape to canonical publish targets.
4
+ *
5
+ * The published CLI reference addresses content with selective flags (`--components <ids>`) and an
6
+ * implied "everything" default, while we address it positionally (`publish <type> [id...]`). These
7
+ * are pure functions that convert one into the other; the publishing itself is done by
8
+ * {@link Handoff.publishAll}, so no orchestration lives here.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.resolveCompatAssetSelection = exports.resolveCompatAllKinds = exports.resolveCompatTargets = void 0;
12
+ const sets_1 = require("../../registry/assets/sets");
13
+ const content_kinds_1 = require("../../registry/content-kinds");
14
+ const logger_1 = require("../../utils/logger");
15
+ /** Selective flag → the kind it narrows. Ordered so a mixed request still runs in dependency order. */
16
+ const SELECTIVE_FLAGS = [
17
+ { flag: 'components', kind: 'components' },
18
+ { flag: 'patterns', kind: 'patterns' },
19
+ { flag: 'pages', kind: 'pages' },
20
+ ];
21
+ /** Skip flag → the kind it removes. */
22
+ const SKIP_FLAGS = {
23
+ tokens: 'skipTokens',
24
+ assets: 'skipAssets',
25
+ components: 'skipComponents',
26
+ patterns: 'skipPatterns',
27
+ pages: 'skipPages',
28
+ };
29
+ /**
30
+ * Resolve what a documented `push` / `pull` invocation targets, in precedence order:
31
+ *
32
+ * 1. selective flags (`--components a b --pages intro`), the documented way to narrow a run;
33
+ * 2. a positional kind, matching our own `publish <type> [id...]`;
34
+ * 3. nothing, which the docs define as pages plus component and pattern declarations.
35
+ */
36
+ const resolveCompatTargets = (args) => {
37
+ var _a;
38
+ const selective = SELECTIVE_FLAGS.filter(({ flag }) => { var _a; return (_a = args[flag]) === null || _a === void 0 ? void 0 : _a.length; }).map(({ flag, kind }) => ({
39
+ kind,
40
+ ids: args[flag],
41
+ }));
42
+ if (selective.length > 0) {
43
+ if (args.type) {
44
+ logger_1.Logger.warn(`Ignoring the "${args.type}" argument because selective flags were also given.`);
45
+ }
46
+ return selective;
47
+ }
48
+ // `all` is the canonical every-kind form; expand it here so `push all` behaves like `publish all`.
49
+ if (args.type === 'all') {
50
+ return [...content_kinds_1.ALL_KIND_ORDER];
51
+ }
52
+ if (args.type) {
53
+ return [{ kind: args.type, ids: ((_a = args.id) === null || _a === void 0 ? void 0 : _a.length) ? args.id : undefined }];
54
+ }
55
+ return [...content_kinds_1.ENTITY_KIND_ORDER];
56
+ };
57
+ exports.resolveCompatTargets = resolveCompatTargets;
58
+ /** Resolve the kinds a documented `push:all` should run, honoring its `--skip-<kind>` flags. */
59
+ const resolveCompatAllKinds = (args) => content_kinds_1.ALL_KIND_ORDER.filter((kind) => !args[SKIP_FLAGS[kind]]);
60
+ exports.resolveCompatAllKinds = resolveCompatAllKinds;
61
+ /**
62
+ * Resolve the asset collections a documented `push:assets` should publish. Returns `undefined` when
63
+ * nothing is skipped, so the canonical path still discovers collections itself instead of being
64
+ * pinned to the compile-time list.
65
+ */
66
+ const resolveCompatAssetSelection = (args, collection) => {
67
+ if (collection) {
68
+ return [collection];
69
+ }
70
+ const skipped = new Set([...(args.skipIcons ? ['icons'] : []), ...(args.skipLogos ? ['logos'] : [])]);
71
+ return skipped.size > 0 ? sets_1.ASSET_COLLECTIONS.filter((name) => !skipped.has(name)) : undefined;
72
+ };
73
+ exports.resolveCompatAssetSelection = resolveCompatAssetSelection;