@astryxdesign/cli 0.6.3-canary.db4e378 → 0.6.3-canary.db7b338

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 (276) hide show
  1. package/README.md +22 -1
  2. package/api/blog/blog.doc.mjs +1 -0
  3. package/api/build/build.doc.mjs +1 -0
  4. package/api/component/component.doc.mjs +1 -0
  5. package/api/discover/discover.doc.mjs +1 -0
  6. package/api/docs/_adapter.d.mts +3 -8
  7. package/api/docs/_adapter.mjs +13 -105
  8. package/api/docs/detail/section/section.mjs +9 -15
  9. package/api/docs/detail/section/section.test.mjs +15 -6
  10. package/api/docs/docs.doc.mjs +1 -0
  11. package/api/docs/list/list.mjs +3 -7
  12. package/api/doctor/doctor.d.mts +25 -3
  13. package/api/doctor/doctor.doc.mjs +1 -0
  14. package/api/doctor/doctor.mjs +186 -14
  15. package/api/doctor/doctor.test.mjs +332 -7
  16. package/api/gap-report/gap-report.doc.mjs +1 -0
  17. package/api/hook/_adapter.mjs +19 -5
  18. package/api/hook/hook.doc.mjs +1 -0
  19. package/api/hook/list/list.d.mts +1 -1
  20. package/api/hook/list/list.mjs +69 -17
  21. package/api/init/init.doc.mjs +1 -0
  22. package/api/integration/add-contribution.mjs +7 -7
  23. package/api/integration/add-contribution.test.mjs +37 -3
  24. package/api/integration/add-theme.mjs +34 -64
  25. package/api/integration/add-theme.test.mjs +105 -21
  26. package/api/integration/authoring-checks.test.mjs +8 -4
  27. package/api/integration/integration-block-exports.test.mjs +10 -6
  28. package/api/integration/integrationAdd.doc.mjs +1 -0
  29. package/api/integration/integrationAddAgentDoc.doc.mjs +1 -0
  30. package/api/integration/integrationAddCodemod.doc.mjs +1 -0
  31. package/api/integration/integrationAddComponent.doc.mjs +1 -0
  32. package/api/integration/integrationAddDoc.doc.mjs +1 -0
  33. package/api/integration/integrationAddTemplate.doc.mjs +1 -0
  34. package/api/integration/integrationAddTheme.doc.mjs +6 -5
  35. package/api/integration/integrationComponentConflicts.doc.mjs +1 -0
  36. package/api/integration/integrationDocConflicts.doc.mjs +1 -0
  37. package/api/integration/integrationPackCheck.doc.mjs +1 -0
  38. package/api/integration/integrationTemplateConflicts.doc.mjs +1 -0
  39. package/api/integration/pack-check.test.mjs +17 -47
  40. package/api/integration/summarizeIssues.doc.mjs +1 -0
  41. package/api/integration/validate-integration-fixes.test.mjs +1389 -0
  42. package/api/integration/validate-integration.mjs +50 -102
  43. package/api/integration/validate-integration.test.mjs +85 -23
  44. package/api/integration/validate-unread-theme-folders.test.mjs +110 -0
  45. package/api/integration/validateIntegration.doc.mjs +1 -0
  46. package/api/json/assertResponse.doc.mjs +1 -0
  47. package/api/json/isError.doc.mjs +1 -0
  48. package/api/json/parseResponse.doc.mjs +1 -0
  49. package/api/layout/layoutCheck.doc.mjs +1 -0
  50. package/api/layout/layoutExpand.doc.mjs +1 -0
  51. package/api/layout/layoutGrammar.doc.mjs +1 -0
  52. package/api/search/search.doc.mjs +1 -0
  53. package/api/search/search.mjs +16 -6
  54. package/api/swizzle/swizzle.doc.mjs +1 -0
  55. package/api/template/template-suffix.test.mjs +41 -21
  56. package/api/template/template.doc.mjs +1 -0
  57. package/api/theme/_adapter.d.mts +2 -3
  58. package/api/theme/_adapter.mjs +4 -5
  59. package/api/theme/add/add.binary.test.mjs +10 -17
  60. package/api/theme/add/add.test.mjs +14 -1
  61. package/api/theme/generateTonalPalette.doc.mjs +1 -0
  62. package/api/theme/integration-themes.test.mjs +39 -28
  63. package/api/theme/list/list.test.mjs +19 -20
  64. package/api/theme/listThemes.doc.mjs +6 -5
  65. package/api/theme/themeAdd.doc.mjs +4 -3
  66. package/api/theme/themeBuild.doc.mjs +1 -0
  67. package/api/theme/themeList.doc.mjs +6 -3
  68. package/api/theme/themeListAvailable.doc.mjs +5 -3
  69. package/api/theme/themePaletteGenerate.doc.mjs +1 -0
  70. package/api/theme/themeTargets.doc.mjs +1 -0
  71. package/api/theme/themeTemplate.doc.mjs +1 -0
  72. package/api/upgrade/_adapter.d.mts +32 -5
  73. package/api/upgrade/_adapter.mjs +97 -69
  74. package/api/upgrade/provider-agreement.test.mjs +152 -0
  75. package/api/upgrade/run/run.mjs +356 -59
  76. package/api/upgrade/upgrade.doc.mjs +6 -1
  77. package/api/upgrade/upgrade.type.d.mts +34 -0
  78. package/api/upgrade/upgrade.type.mjs +15 -0
  79. package/assets/codemods/__tests__/runner.test.mjs +330 -8
  80. package/assets/codemods/integration-discovery.mjs +8 -2
  81. package/assets/codemods/integration-discovery.test.mjs +15 -0
  82. package/assets/codemods/integration-runner.mjs +56 -4
  83. package/assets/codemods/integration-runner.protection.test.mjs +153 -0
  84. package/assets/codemods/run-codemod.mjs +177 -34
  85. package/assets/codemods/runner.mjs +350 -102
  86. package/assets/codemods/transforms/next/__tests__/migrate-native-picker-to-presentation.test.mjs +63 -0
  87. package/assets/codemods/transforms/next/__tests__/migrate-theme-catalog-to-descriptors.test.mjs +220 -0
  88. package/assets/codemods/transforms/next/index.mjs +19 -1
  89. package/assets/codemods/transforms/next/migrate-native-picker-to-presentation.mjs +148 -0
  90. package/assets/codemods/transforms/next/migrate-theme-catalog-to-descriptors.mjs +141 -0
  91. package/assets/docs/cli-integrations.doc.mjs +30 -30
  92. package/assets/docs/cli.doc.mjs +15 -0
  93. package/assets/docs/theme.doc.mjs +1 -1
  94. package/assets/templates/blocks/components/DateInput/DateInputDateRange.tsx +1 -1
  95. package/assets/templates/blocks/components/Item/ItemDocumentTabs.doc.mjs +14 -0
  96. package/assets/templates/blocks/components/Item/ItemDocumentTabs.tsx +100 -0
  97. package/assets/templates/blocks/components/TimeInput/TimeInputConstrained.tsx +1 -0
  98. package/assets/templates/themes/butter/butterTheme.doc.mjs +11 -0
  99. package/assets/templates/themes/chocolate/chocolateTheme.doc.mjs +11 -0
  100. package/assets/templates/themes/gothic/gothicTheme.doc.mjs +11 -0
  101. package/assets/templates/themes/matcha/matchaTheme.doc.mjs +11 -0
  102. package/assets/templates/themes/neutral/neutralTheme.doc.mjs +11 -0
  103. package/assets/templates/themes/stone/stoneTheme.doc.mjs +11 -0
  104. package/assets/templates/themes/y2k/y2kTheme.doc.mjs +11 -0
  105. package/authoring/codemod/codemod.doc.mjs +1 -1
  106. package/authoring/codemod/type.ts +12 -0
  107. package/authoring/config/config.doc.mjs +1 -1
  108. package/authoring/debug/debug.doc.d.mts +11 -0
  109. package/authoring/debug/debug.doc.mjs +182 -0
  110. package/authoring/doctypes/_schema.d.mts +71 -141
  111. package/authoring/doctypes/_schema.mjs +29 -2
  112. package/authoring/doctypes/base/graph-fields.doc.mjs +1 -1
  113. package/authoring/doctypes/command/command.doc.mjs +1 -1
  114. package/authoring/doctypes/command/type.ts +1 -1
  115. package/authoring/doctypes/component/type.ts +2 -2
  116. package/authoring/doctypes/doctypes-new.test.mjs +48 -6
  117. package/authoring/doctypes/enum/enum.doc.mjs +1 -1
  118. package/authoring/doctypes/enum/type.ts +1 -1
  119. package/authoring/doctypes/function/function.doc.mjs +1 -1
  120. package/authoring/doctypes/function/type.ts +1 -1
  121. package/authoring/doctypes/hook/type.ts +2 -2
  122. package/authoring/doctypes/load-contract.test.mjs +3 -2
  123. package/authoring/doctypes/namespace/namespace.doc.mjs +2 -2
  124. package/authoring/doctypes/namespace/parse.test.mjs +23 -25
  125. package/authoring/doctypes/namespace/type.ts +5 -2
  126. package/authoring/doctypes/parse.d.mts +4 -2
  127. package/authoring/doctypes/parse.mjs +10 -5
  128. package/authoring/doctypes/reference/reference.doc.mjs +6 -4
  129. package/authoring/doctypes/reference/type.ts +9 -10
  130. package/authoring/doctypes/schema/schema.doc.mjs +1 -1
  131. package/authoring/doctypes/schema/type.ts +1 -2
  132. package/authoring/doctypes/template/template.doc.mjs +3 -3
  133. package/authoring/doctypes/theme/parse.d.mts +35 -0
  134. package/authoring/doctypes/theme/parse.mjs +76 -0
  135. package/authoring/doctypes/theme/theme.doc.d.mts +9 -0
  136. package/authoring/doctypes/theme/theme.doc.mjs +79 -0
  137. package/authoring/doctypes/theme/type.ts +42 -0
  138. package/authoring/doctypes/types.ts +2 -1
  139. package/authoring/gap-report/gap-report.doc.d.mts +12 -0
  140. package/authoring/gap-report/gap-report.doc.mjs +183 -0
  141. package/authoring/index.d.mts +1 -0
  142. package/authoring/index.d.ts +7 -4
  143. package/authoring/index.mjs +2 -1
  144. package/authoring/integration/integration.doc.mjs +2 -2
  145. package/authoring/integration/type.ts +3 -9
  146. package/clients/cli/__tests__/cliManifest.test.ts +27 -29
  147. package/clients/cli/commands/blog.doc.mjs +1 -1
  148. package/clients/cli/commands/build-theme.adaptations.test.mjs +100 -1
  149. package/clients/cli/commands/build-theme.mjs +10 -44
  150. package/clients/cli/commands/build.doc.mjs +1 -1
  151. package/clients/cli/commands/component.doc.mjs +1 -1
  152. package/clients/cli/commands/discover.doc.mjs +1 -1
  153. package/clients/cli/commands/docs.doc.mjs +1 -1
  154. package/clients/cli/commands/docs.mjs +15 -58
  155. package/clients/cli/commands/docs.test.mjs +11 -14
  156. package/clients/cli/commands/doctor-integration-components.doc.mjs +1 -1
  157. package/clients/cli/commands/doctor-integration-docs.doc.mjs +1 -1
  158. package/clients/cli/commands/doctor-integration-templates.doc.mjs +1 -1
  159. package/clients/cli/commands/doctor-integration-validate.doc.mjs +1 -1
  160. package/clients/cli/commands/doctor-integration.doc.mjs +1 -1
  161. package/clients/cli/commands/doctor-integration.test.mjs +15 -7
  162. package/clients/cli/commands/doctor.doc.mjs +1 -1
  163. package/clients/cli/commands/gap-report.doc.mjs +1 -1
  164. package/clients/cli/commands/hook.doc.mjs +1 -1
  165. package/clients/cli/commands/init.doc.mjs +1 -1
  166. package/clients/cli/commands/integration-add.controls.test.mjs +1 -1
  167. package/clients/cli/commands/integration-add.doc.mjs +1 -1
  168. package/clients/cli/commands/integration-pack.doc.mjs +1 -1
  169. package/clients/cli/commands/integration-real-world.test.mjs +3 -9
  170. package/clients/cli/commands/integration.doc.mjs +1 -1
  171. package/clients/cli/commands/layout-check.doc.mjs +1 -1
  172. package/clients/cli/commands/layout-expand.doc.mjs +1 -1
  173. package/clients/cli/commands/layout-grammar.doc.mjs +1 -1
  174. package/clients/cli/commands/layout.doc.mjs +1 -1
  175. package/clients/cli/commands/manifest.doc.mjs +1 -1
  176. package/clients/cli/commands/search.doc.mjs +1 -1
  177. package/clients/cli/commands/swizzle.doc.mjs +1 -1
  178. package/clients/cli/commands/template.doc.mjs +1 -1
  179. package/clients/cli/commands/text-json-parity.test.mjs +718 -0
  180. package/clients/cli/commands/theme-add.doc.mjs +2 -2
  181. package/clients/cli/commands/theme-build.doc.mjs +1 -1
  182. package/clients/cli/commands/theme-list.doc.mjs +2 -2
  183. package/clients/cli/commands/theme-palette-generate.doc.mjs +3 -3
  184. package/clients/cli/commands/theme-palette.doc.mjs +1 -1
  185. package/clients/cli/commands/theme-targets.behavior.test.mjs +4 -3
  186. package/clients/cli/commands/theme-targets.doc.mjs +1 -1
  187. package/clients/cli/commands/theme-template.doc.mjs +1 -1
  188. package/clients/cli/commands/theme.doc.mjs +1 -1
  189. package/clients/cli/commands/upgrade.doc.mjs +3 -2
  190. package/clients/cli/commands/upgrade.file-protection.test.mjs +228 -0
  191. package/clients/cli/commands/upgrade.mjs +29 -7
  192. package/clients/cli/formatters/index.mjs +2 -0
  193. package/clients/cli/formatters/index.test.mjs +6 -0
  194. package/clients/cli/lib/hook-format.mjs +14 -5
  195. package/foundation/config/project-themes.test.mjs +11 -19
  196. package/foundation/config/project.d.mts +8 -0
  197. package/foundation/config/project.mjs +50 -21
  198. package/foundation/config/project.test.mjs +3 -16
  199. package/foundation/discovery/authoring-self-docs.d.mts +6 -0
  200. package/foundation/discovery/authoring-self-docs.mjs +17 -7
  201. package/foundation/discovery/authoring-self-docs.test.mjs +3 -2
  202. package/foundation/discovery/authoring-surface.d.mts +74 -0
  203. package/foundation/discovery/authoring-surface.mjs +525 -0
  204. package/foundation/discovery/authoring-surface.test.mjs +392 -0
  205. package/foundation/discovery/cli-self-docs.d.mts +113 -0
  206. package/foundation/discovery/cli-self-docs.mjs +514 -0
  207. package/foundation/discovery/cli-self-docs.test.mjs +437 -0
  208. package/foundation/discovery/component-loader.d.mts +35 -38
  209. package/foundation/discovery/component-loader.mjs +53 -222
  210. package/foundation/discovery/docs-discovery.d.mts +3 -2
  211. package/foundation/discovery/docs-discovery.mjs +14 -17
  212. package/foundation/discovery/docs-discovery.test.mjs +15 -15
  213. package/foundation/discovery/docs-section-key.d.mts +19 -8
  214. package/foundation/discovery/docs-section-key.mjs +119 -32
  215. package/foundation/discovery/docs-section-key.test.mjs +41 -19
  216. package/foundation/discovery/template-adapter.d.mts +7 -0
  217. package/foundation/discovery/template-adapter.mjs +27 -40
  218. package/foundation/discovery/template-adapter.test.mjs +15 -0
  219. package/foundation/discovery/theme-discovery.d.mts +67 -7
  220. package/foundation/discovery/theme-discovery.mjs +916 -186
  221. package/foundation/discovery/theme-discovery.test.mjs +613 -219
  222. package/foundation/doc-compiler/bundle.d.mts +47 -0
  223. package/foundation/doc-compiler/bundle.mjs +218 -0
  224. package/foundation/doc-compiler/bundle.test.mjs +255 -0
  225. package/foundation/doc-compiler/compile.d.mts +200 -0
  226. package/foundation/doc-compiler/compile.mjs +259 -9
  227. package/foundation/doc-compiler/diagnostics.d.mts +126 -0
  228. package/foundation/doc-compiler/diagnostics.mjs +277 -0
  229. package/foundation/doc-compiler/doc-compiler.test.mjs +28 -1
  230. package/foundation/doc-compiler/doc-loads.test.mjs +1642 -0
  231. package/foundation/doc-compiler/import.d.mts +24 -0
  232. package/foundation/doc-compiler/import.mjs +59 -0
  233. package/foundation/doc-compiler/inputs.d.mts +102 -0
  234. package/foundation/doc-compiler/inputs.mjs +286 -0
  235. package/foundation/doc-compiler/inputs.test.mjs +299 -0
  236. package/foundation/doc-compiler/ir.d.mts +13 -0
  237. package/foundation/doc-compiler/ir.mjs +189 -12
  238. package/foundation/doc-compiler/lower-doc.test.mjs +492 -0
  239. package/foundation/doc-compiler/overlays.d.mts +37 -0
  240. package/foundation/doc-compiler/overlays.mjs +206 -0
  241. package/foundation/doc-compiler/parse-readable.d.mts +9 -0
  242. package/foundation/doc-compiler/parse-readable.mjs +29 -0
  243. package/foundation/doc-compiler/read.d.mts +126 -0
  244. package/foundation/doc-compiler/read.mjs +320 -0
  245. package/foundation/doc-compiler/read.test.mjs +313 -0
  246. package/foundation/doc-compiler/source.d.mts +33 -0
  247. package/foundation/doc-compiler/source.mjs +128 -0
  248. package/foundation/fs/file-protection.d.mts +33 -0
  249. package/foundation/fs/file-protection.mjs +825 -0
  250. package/foundation/fs/file-protection.test.mjs +250 -0
  251. package/foundation/integrations/autolink.d.mts +58 -1
  252. package/foundation/integrations/autolink.mjs +143 -57
  253. package/foundation/integrations/contribution-fixes.d.mts +145 -0
  254. package/foundation/integrations/contribution-fixes.mjs +1284 -0
  255. package/foundation/integrations/contribution-inventory.d.mts +1 -1
  256. package/foundation/integrations/contribution-inventory.mjs +17 -20
  257. package/foundation/integrations/contribution-inventory.test.mjs +67 -27
  258. package/foundation/integrations/integrations.d.mts +3 -0
  259. package/foundation/integrations/integrations.mjs +11 -97
  260. package/foundation/integrations/provider-ledger.test.mjs +275 -0
  261. package/foundation/integrations/provider-resolution.d.mts +152 -0
  262. package/foundation/integrations/provider-resolution.mjs +576 -0
  263. package/foundation/integrations/provider-resolution.test.mjs +369 -0
  264. package/foundation/integrations/theme-descriptor.d.mts +8 -0
  265. package/foundation/integrations/theme-descriptor.mjs +44 -0
  266. package/foundation/integrations/validate-contributions.mjs +104 -10
  267. package/foundation/response/error-codes.d.mts +3 -1
  268. package/foundation/response/error-codes.d.ts +2 -0
  269. package/foundation/response/error-codes.doc.mjs +12 -2
  270. package/foundation/response/error-codes.mjs +7 -1
  271. package/foundation/response/error-codes.test.mjs +55 -11
  272. package/foundation/response/response-types.doc.mjs +1 -1
  273. package/foundation/response/response.doc.mjs +1 -1
  274. package/foundation/text/string-utils.mjs +22 -10
  275. package/package.json +10 -9
  276. package/assets/templates/themes/manifest.json +0 -95
@@ -15,7 +15,10 @@
15
15
  */
16
16
 
17
17
  import {findCoreDir} from '../../foundation/fs/paths.mjs';
18
- import {findHookDoc, getAllHookNames} from '../../foundation/discovery/hook-discovery.mjs';
18
+ import {
19
+ findHookDoc,
20
+ getAllHookNames,
21
+ } from '../../foundation/discovery/hook-discovery.mjs';
19
22
  import {loadDocs} from '../../foundation/discovery/component-loader.mjs';
20
23
  import {levenshteinDistance} from '../../foundation/text/string-utils.mjs';
21
24
  import {AstryxError} from '../error.mjs';
@@ -30,7 +33,11 @@ import {ERROR_CODES} from '../../foundation/response/error-codes.mjs';
30
33
  export function resolveCoreDir(cwd) {
31
34
  const coreDir = findCoreDir(cwd);
32
35
  if (!coreDir) {
33
- throw new AstryxError('Could not find @astryxdesign/core package', undefined, ERROR_CODES.ERR_CORE_NOT_FOUND);
36
+ throw new AstryxError(
37
+ 'Could not find @astryxdesign/core package',
38
+ undefined,
39
+ ERROR_CODES.ERR_CORE_NOT_FOUND,
40
+ );
34
41
  }
35
42
  return coreDir;
36
43
  }
@@ -44,7 +51,11 @@ export function resolveCoreDir(cwd) {
44
51
  * @param {{zh?: boolean, lang?: string|null}} [opts]
45
52
  * @returns {Promise<import('./hook.type.mjs').HookDoc>}
46
53
  */
47
- export async function resolveHookDoc(coreDir, name, {zh = false, lang = null} = {}) {
54
+ export async function resolveHookDoc(
55
+ coreDir,
56
+ name,
57
+ {zh = false, lang = null} = {},
58
+ ) {
48
59
  const docPath = findHookDoc(coreDir, name);
49
60
 
50
61
  if (!docPath) {
@@ -59,7 +70,10 @@ export async function resolveHookDoc(coreDir, name, {zh = false, lang = null} =
59
70
  .filter(m => m.distance <= 5)
60
71
  .sort((a, b) => a.distance - b.distance)
61
72
  .slice(0, 5)
62
- .map(m => ({name: m.name, reason: `similar name (distance ${m.distance})`}));
73
+ .map(m => ({
74
+ name: m.name,
75
+ reason: `similar name (distance ${m.distance})`,
76
+ }));
63
77
 
64
78
  throw new AstryxError(
65
79
  `No hook named "${name}"`,
@@ -68,5 +82,5 @@ export async function resolveHookDoc(coreDir, name, {zh = false, lang = null} =
68
82
  );
69
83
  }
70
84
 
71
- return loadDocs(docPath, /** @type {{zh?: boolean, dense?: boolean, lang?: string}} */ ({zh, lang}));
85
+ return loadDocs(docPath, {zh, lang, root: 'hooks'});
72
86
  }
@@ -11,6 +11,7 @@ export const doc = {
11
11
  type: 'function',
12
12
  kind: 'api',
13
13
  name: 'hook',
14
+ namespace: 'cli/api',
14
15
  displayName: 'hook()',
15
16
  summary:
16
17
  'Resolve a hook by name, or list the catalog, with an optional params-only slice.',
@@ -10,7 +10,7 @@
10
10
  * @param {string|null} [options.lang]
11
11
  * @returns {Promise<import('../hook.type.mjs').HookListResponse>}
12
12
  */
13
- export function list({ cwd, category, detail, zh, lang }?: {
13
+ export function list({ cwd, category, detail, zh, lang, }?: {
14
14
  cwd?: string | undefined;
15
15
  category?: string | undefined;
16
16
  detail?: "compact" | "full" | "names" | "brief" | undefined;
@@ -13,7 +13,10 @@
13
13
  * @position api/hook/list/list.mjs — dispatched from ../hook.mjs
14
14
  */
15
15
 
16
- import {discoverHooks, findHookDoc} from '../../../foundation/discovery/hook-discovery.mjs';
16
+ import {
17
+ discoverHooks,
18
+ findHookDoc,
19
+ } from '../../../foundation/discovery/hook-discovery.mjs';
17
20
  import {loadDocs} from '../../../foundation/discovery/component-loader.mjs';
18
21
  import {AstryxError} from '../../error.mjs';
19
22
  import {ERROR_CODES} from '../../../foundation/response/error-codes.mjs';
@@ -28,7 +31,13 @@ import {resolveCoreDir} from '../_adapter.mjs';
28
31
  * @param {string|null} [options.lang]
29
32
  * @returns {Promise<import('../hook.type.mjs').HookListResponse>}
30
33
  */
31
- export async function list({cwd = process.cwd(), category, detail = 'names', zh = false, lang = null} = {}) {
34
+ export async function list({
35
+ cwd = process.cwd(),
36
+ category,
37
+ detail = 'names',
38
+ zh = false,
39
+ lang = null,
40
+ } = {}) {
32
41
  const coreDir = resolveCoreDir(cwd);
33
42
  const hooks = discoverHooks(coreDir);
34
43
 
@@ -51,20 +60,31 @@ export async function list({cwd = process.cwd(), category, detail = 'names', zh
51
60
  const docPath = findHookDoc(coreDir, hookName);
52
61
  if (docPath) {
53
62
  try {
54
- const docs = await loadDocs(docPath, /** @type {{zh?: boolean, dense?: boolean, lang?: string}} */ ({zh, lang}));
63
+ const docs = await loadDocs(docPath, {zh, lang, root: 'hooks'});
55
64
  entries.push({
56
65
  name: hookName,
57
66
  description: docs.usage?.description || '',
58
67
  import: docs.importPath || '@astryxdesign/core/hooks',
59
68
  });
60
69
  } catch {
61
- entries.push({name: hookName, description: '', import: '@astryxdesign/core/hooks'});
70
+ entries.push({
71
+ name: hookName,
72
+ description: '',
73
+ import: '@astryxdesign/core/hooks',
74
+ });
62
75
  }
63
76
  } else {
64
- entries.push({name: hookName, description: '', import: '@astryxdesign/core/hooks'});
77
+ entries.push({
78
+ name: hookName,
79
+ description: '',
80
+ import: '@astryxdesign/core/hooks',
81
+ });
65
82
  }
66
83
  }
67
- return {type: 'hook.list', data: {detail: 'compact', components: {[match[0]]: entries}}};
84
+ return {
85
+ type: 'hook.list',
86
+ data: {detail: 'compact', components: {[match[0]]: entries}},
87
+ };
68
88
  }
69
89
 
70
90
  if (detail === 'full') {
@@ -74,19 +94,33 @@ export async function list({cwd = process.cwd(), category, detail = 'names', zh
74
94
  const docPath = findHookDoc(coreDir, hookName);
75
95
  if (docPath) {
76
96
  try {
77
- entries.push(await loadDocs(docPath, /** @type {{zh?: boolean, dense?: boolean, lang?: string}} */ ({zh, lang})));
97
+ entries.push(await loadDocs(docPath, {zh, lang, root: 'hooks'}));
78
98
  } catch {
79
- entries.push(/** @type {import('../hook.type.mjs').HookDoc} */ ({name: hookName}));
99
+ entries.push(
100
+ /** @type {import('../hook.type.mjs').HookDoc} */ ({
101
+ name: hookName,
102
+ }),
103
+ );
80
104
  }
81
105
  } else {
82
- entries.push(/** @type {import('../hook.type.mjs').HookDoc} */ ({name: hookName}));
106
+ entries.push(
107
+ /** @type {import('../hook.type.mjs').HookDoc} */ ({
108
+ name: hookName,
109
+ }),
110
+ );
83
111
  }
84
112
  }
85
- return {type: 'hook.list', data: {detail: 'full', components: {[match[0]]: entries}}};
113
+ return {
114
+ type: 'hook.list',
115
+ data: {detail: 'full', components: {[match[0]]: entries}},
116
+ };
86
117
  }
87
118
 
88
119
  // Default: names only
89
- return {type: 'hook.list', data: {detail: 'names', components: {[match[0]]: match[1]}}};
120
+ return {
121
+ type: 'hook.list',
122
+ data: {detail: 'names', components: {[match[0]]: match[1]}},
123
+ };
90
124
  }
91
125
 
92
126
  // All hooks
@@ -99,17 +133,25 @@ export async function list({cwd = process.cwd(), category, detail = 'names', zh
99
133
  const docPath = findHookDoc(coreDir, hookName);
100
134
  if (docPath) {
101
135
  try {
102
- const docs = await loadDocs(docPath, /** @type {{zh?: boolean, dense?: boolean, lang?: string}} */ ({zh, lang}));
136
+ const docs = await loadDocs(docPath, {zh, lang, root: 'hooks'});
103
137
  result[cat].push({
104
138
  name: hookName,
105
139
  description: docs.usage?.description || '',
106
140
  import: docs.importPath || '@astryxdesign/core/hooks',
107
141
  });
108
142
  } catch {
109
- result[cat].push({name: hookName, description: '', import: '@astryxdesign/core/hooks'});
143
+ result[cat].push({
144
+ name: hookName,
145
+ description: '',
146
+ import: '@astryxdesign/core/hooks',
147
+ });
110
148
  }
111
149
  } else {
112
- result[cat].push({name: hookName, description: '', import: '@astryxdesign/core/hooks'});
150
+ result[cat].push({
151
+ name: hookName,
152
+ description: '',
153
+ import: '@astryxdesign/core/hooks',
154
+ });
113
155
  }
114
156
  }
115
157
  }
@@ -125,12 +167,22 @@ export async function list({cwd = process.cwd(), category, detail = 'names', zh
125
167
  const docPath = findHookDoc(coreDir, hookName);
126
168
  if (docPath) {
127
169
  try {
128
- result[cat].push(await loadDocs(docPath, /** @type {{zh?: boolean, dense?: boolean, lang?: string}} */ ({zh, lang})));
170
+ result[cat].push(
171
+ await loadDocs(docPath, {zh, lang, root: 'hooks'}),
172
+ );
129
173
  } catch {
130
- result[cat].push(/** @type {import('../hook.type.mjs').HookDoc} */ ({name: hookName}));
174
+ result[cat].push(
175
+ /** @type {import('../hook.type.mjs').HookDoc} */ ({
176
+ name: hookName,
177
+ }),
178
+ );
131
179
  }
132
180
  } else {
133
- result[cat].push(/** @type {import('../hook.type.mjs').HookDoc} */ ({name: hookName}));
181
+ result[cat].push(
182
+ /** @type {import('../hook.type.mjs').HookDoc} */ ({
183
+ name: hookName,
184
+ }),
185
+ );
134
186
  }
135
187
  }
136
188
  }
@@ -11,6 +11,7 @@ export const doc = {
11
11
  type: 'function',
12
12
  kind: 'api',
13
13
  name: 'init',
14
+ namespace: 'cli/api',
14
15
  displayName: 'init()',
15
16
  summary:
16
17
  'Non-interactive project setup: install agent docs and point at the theme + build workflows.',
@@ -5,8 +5,7 @@
5
5
  * contribution into an integration package.
6
6
  *
7
7
  * Dispatches component, doc, template, codemod, and agent-doc. Theme
8
- * delegates to the existing `integrationAddTheme` (not modified here).
9
- * Every root-based kind shares: first add creates the manifest; one shared
8
+ * delegates to the dedicated same-stem descriptor writer. Every root-based kind shares: first add creates the manifest; one shared
10
9
  * writer; never creates `files`/`exports`; atomic staged writes; no clobber;
11
10
  * dry-run receipt predicts real run; post-write verify through the real
12
11
  * discovery/parser seam.
@@ -263,7 +262,7 @@ async function addComponent(name, options) {
263
262
  const sourcePath = projectPath(path.relative(packageDir, sourceFile));
264
263
  const extensionlessPath = sourcePath.replace(/\.tsx?$/u, '');
265
264
  const importSpecifier = `${owner}/${extensionlessPath}`;
266
- const docContents = `export default {\n type: 'component',\n name: '${name}',\n import: ${JSON.stringify(importSpecifier)},\n description: '${name} component.',\n props: [],\n};\n`;
265
+ const docContents = `/** @type {import('@astryxdesign/cli/authoring').ComponentDoc} */\nexport default {\n type: 'component',\n name: '${name}',\n displayName: '${name}',\n import: ${JSON.stringify(importSpecifier)},\n usage: {description: '${name} component.'},\n props: [],\n};\n`;
267
266
  const sourceContents = `export function ${name}() {\n return <div>${name}</div>;\n}\n`;
268
267
 
269
268
  /** @type {import('./add-helpers.mjs').WritePlan[]} */
@@ -438,7 +437,7 @@ async function addDoc(name, options) {
438
437
  : options.extends
439
438
  ? `\n extends: '${options.extends}',`
440
439
  : '';
441
- const docContents = `export default {\n type: 'generic',\n name: '${name}',\n title: '${title}',\n description: '${title} documentation.',${relationship}\n sections: [\n {\n title: 'Overview',\n content: [\n { type: 'prose', text: '${title} documentation.' },\n ],\n },\n ],\n};\n`;
440
+ const docContents = `/** @type {import('@astryxdesign/cli/authoring').ReferenceDoc} */\nexport default {\n type: 'generic',\n name: '${name}',\n title: '${title}',\n description: '${title} documentation.',${relationship}\n sections: [\n {\n title: 'Overview',\n content: [\n { type: 'prose', text: '${title} documentation.' },\n ],\n },\n ],\n};\n`;
442
441
 
443
442
  /** @type {import('./add-helpers.mjs').WritePlan[]} */
444
443
  const plans = [{path: docFile, contents: docContents, createOnly: true}];
@@ -565,8 +564,8 @@ async function addTemplate(name, options) {
565
564
  throw error;
566
565
  }
567
566
 
568
- const specFile = assertWithin(`${name}.template.mjs`, root, {
569
- label: 'template spec',
567
+ const specFile = assertWithin(`${name}.doc.mjs`, root, {
568
+ label: 'template descriptor',
570
569
  });
571
570
  const sourceFile = assertWithin(`${name}.tsx`, root, {
572
571
  label: 'template source',
@@ -589,7 +588,8 @@ async function addTemplate(name, options) {
589
588
  const pascalName = kebabToPascal(name);
590
589
  const sourcePath = projectPath(path.relative(packageDir, sourceFile));
591
590
  const extensionlessPath = sourcePath.replace(/\.tsx?$/u, '');
592
- const specContents = `export default {\n type: '${templateType}',\n name: '${name}',\n description: '${kebabToTitle(name)} template.',\n};\n`;
591
+ const blockFields = templateType === 'block' ? '\n aspectRatio: 1,' : '';
592
+ const specContents = `/** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */\nexport default {\n type: '${templateType}',\n name: '${name}',\n displayName: '${kebabToTitle(name)}',\n description: '${kebabToTitle(name)} template.',${blockFields}\n};\n`;
593
593
  const sourceContents = `export default function ${pascalName}() {\n return <div>${kebabToTitle(name)}</div>;\n}\n`;
594
594
 
595
595
  /** @type {import('./add-helpers.mjs').WritePlan[]} */
@@ -77,6 +77,7 @@ describe('integrationAdd component', () => {
77
77
  path.join(tmpDir, 'components/MyWidget.doc.mjs'),
78
78
  'utf-8',
79
79
  );
80
+ expect(doc).toContain("@astryxdesign/cli/authoring').ComponentDoc");
80
81
  expect(doc).toContain("type: 'component'");
81
82
  expect(doc).toContain("name: 'MyWidget'");
82
83
  expect(doc).toContain('props: []');
@@ -304,6 +305,7 @@ describe('integrationAdd doc', () => {
304
305
  path.join(tmpDir, 'docs/my-guide.doc.mjs'),
305
306
  'utf-8',
306
307
  );
308
+ expect(doc).toContain("@astryxdesign/cli/authoring').ReferenceDoc");
307
309
  expect(doc).toContain("type: 'generic'");
308
310
  expect(doc).toContain("name: 'my-guide'");
309
311
 
@@ -390,13 +392,14 @@ describe('integrationAdd template', () => {
390
392
  expect(result.data.kind).toBe('template');
391
393
  expect(result.data.name).toBe('my-widget');
392
394
  expect(result.data.root).toEqual({path: './templates', created: true});
393
- expect(result.data.files).toContain('templates/my-widget.template.mjs');
395
+ expect(result.data.files).toContain('templates/my-widget.doc.mjs');
394
396
  expect(result.data.files).toContain('templates/my-widget.tsx');
395
397
 
396
398
  const spec = fs.readFileSync(
397
- path.join(tmpDir, 'templates/my-widget.template.mjs'),
399
+ path.join(tmpDir, 'templates/my-widget.doc.mjs'),
398
400
  'utf-8',
399
401
  );
402
+ expect(spec).toContain("@astryxdesign/cli/authoring').TemplateDoc");
400
403
  expect(spec).toContain("type: 'page'");
401
404
  expect(spec).toContain("name: 'my-widget'");
402
405
 
@@ -432,10 +435,11 @@ describe('integrationAdd template', () => {
432
435
  templateType: 'block',
433
436
  });
434
437
  const spec = fs.readFileSync(
435
- path.join(tmpDir, 'templates/my-card.template.mjs'),
438
+ path.join(tmpDir, 'templates/my-card.doc.mjs'),
436
439
  'utf-8',
437
440
  );
438
441
  expect(spec).toContain("type: 'block'");
442
+ expect(spec).toContain('aspectRatio: 1');
439
443
  });
440
444
 
441
445
  it('rejects an invalid template type', async () => {
@@ -676,6 +680,35 @@ describe('custom root preservation', () => {
676
680
  });
677
681
  });
678
682
 
683
+ describe('typed descriptor conformance', () => {
684
+ it('emits a strongly typed .doc.mjs for every canonical item writer', async () => {
685
+ setup();
686
+ await integrationAdd('component', 'MyWidget', {cwd: tmpDir});
687
+ await integrationAdd('doc', 'my-guide', {cwd: tmpDir});
688
+ await integrationAdd('template', 'my-page', {cwd: tmpDir});
689
+ await integrationAdd('theme', 'ocean', {cwd: tmpDir});
690
+
691
+ // Codemod and agent-doc keep their released formats for compatibility;
692
+ // no new kind may copy those exceptions.
693
+ for (const [relativePath, type] of [
694
+ ['components/MyWidget.doc.mjs', 'ComponentDoc'],
695
+ ['docs/my-guide.doc.mjs', 'ReferenceDoc'],
696
+ ['templates/my-page.doc.mjs', 'TemplateDoc'],
697
+ ['themes/ocean/oceanTheme.doc.mjs', 'ThemeDoc'],
698
+ ]) {
699
+ const source = fs.readFileSync(path.join(tmpDir, relativePath), 'utf-8');
700
+ expect(source).toContain(`@astryxdesign/cli/authoring').${type}`);
701
+ expect(source).toContain('export default {');
702
+ }
703
+ expect(
704
+ fs.existsSync(path.join(tmpDir, 'templates/my-page.template.mjs')),
705
+ ).toBe(false);
706
+ expect(fs.existsSync(path.join(tmpDir, 'themes/manifest.json'))).toBe(
707
+ false,
708
+ );
709
+ });
710
+ });
711
+
679
712
  describe('public per-kind APIs', () => {
680
713
  it('exposes narrow functions for every non-theme contribution kind', async () => {
681
714
  setup();
@@ -711,6 +744,7 @@ describe('public dispatcher', () => {
711
744
  const result = await integrationAdd('theme', 'ocean', {cwd: tmpDir});
712
745
  expect(result.data).toMatchObject({kind: 'theme', name: 'ocean'});
713
746
  expect(result.data.files).toContain('themes/ocean/oceanTheme.ts');
747
+ expect(result.data.files).toContain('themes/ocean/oceanTheme.doc.mjs');
714
748
  });
715
749
 
716
750
  it('refuses a kind-specific option on the wrong kind', async () => {
@@ -1,9 +1,9 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
3
  /**
4
- * @file `astryx integration add theme` — scaffold one valid source theme into
5
- * an integration package, update its theme catalog, and declare the root on
6
- * first use.
4
+ * @file `astryx integration add theme` — scaffold one strongly typed,
5
+ * same-stem source/descriptor pair into an integration package and declare the
6
+ * themes root on first use.
7
7
  */
8
8
 
9
9
  import * as fs from 'node:fs';
@@ -15,16 +15,14 @@ import {
15
15
  PathSafetyError,
16
16
  sanitizeName,
17
17
  } from '../../foundation/fs/path-safety.mjs';
18
- import {
19
- discoverThemeCatalog,
20
- THEME_MANIFEST_BASENAME,
21
- } from '../../foundation/discovery/theme-discovery.mjs';
18
+ import {discoverThemeDirectory} from '../../foundation/discovery/theme-discovery.mjs';
22
19
  import {
23
20
  findLocalIntegrationManifestOrNull,
24
21
  IntegrationRootConflictError,
25
22
  patchIntegrationRoot,
26
23
  } from '../../foundation/integrations/manifest-writer.mjs';
27
24
  import {loadManifestObject} from '../../foundation/integrations/integrations.mjs';
25
+ import {themeDescriptorSource} from '../../foundation/integrations/theme-descriptor.mjs';
28
26
  import {assertContributionVisible} from '../../foundation/integrations/contribution-inventory.mjs';
29
27
  import {
30
28
  applyWrites,
@@ -70,6 +68,7 @@ function themeIdentity(slug) {
70
68
  displayName,
71
69
  exportName: `${identifier}Theme`,
72
70
  entry: `${identifier}Theme.ts`,
71
+ descriptor: `${identifier}Theme.doc.mjs`,
73
72
  };
74
73
  }
75
74
 
@@ -78,9 +77,20 @@ function themeSource(identity) {
78
77
  return `import {defineTheme} from '@astryxdesign/core/theme';\n\nexport const ${identity.exportName} = defineTheme({\n name: '${identity.slug}',\n});\n`;
79
78
  }
80
79
 
80
+ /** @param {{slug: string, displayName: string}} identity */
81
+ function themeDescriptor(identity) {
82
+ return themeDescriptorSource({
83
+ type: 'theme',
84
+ name: identity.slug,
85
+ displayName: identity.displayName,
86
+ description: `${identity.displayName} theme.`,
87
+ maintained: true,
88
+ });
89
+ }
90
+
81
91
  /**
82
- * Read the bytes back through the same integration-theme discovery seam Project
83
- * uses. A write is not successful until the requested slug resolves.
92
+ * Read bytes back through the same discovery seam Project uses. A write is not
93
+ * successful until the requested slug resolves.
84
94
  * @param {string} packageDir
85
95
  * @param {string} manifestFile
86
96
  * @param {string} owner
@@ -176,6 +186,9 @@ export async function integrationAddTheme(name, options = {}) {
176
186
  dryRun: true,
177
187
  createIfMissing: true,
178
188
  });
189
+ if (fs.existsSync(root)) {
190
+ discoverThemeDirectory(root, owner);
191
+ }
179
192
  } catch (error) {
180
193
  if (error instanceof IntegrationRootConflictError) {
181
194
  throw new AstryxError(
@@ -197,72 +210,29 @@ export async function integrationAddTheme(name, options = {}) {
197
210
  const sourceFile = assertWithin(identity.entry, themeDir, {
198
211
  label: 'theme source file',
199
212
  });
200
- if (fs.existsSync(sourceFile)) {
201
- throw new AstryxError(
202
- `Refusing to overwrite existing file ${projectPath(path.relative(packageDir, sourceFile))}.`,
203
- undefined,
204
- ERROR_CODES.ERR_FILE_EXISTS,
205
- );
206
- }
207
-
208
- const catalogFile = assertWithin(THEME_MANIFEST_BASENAME, root, {
209
- label: 'theme catalog manifest',
213
+ const descriptorFile = assertWithin(identity.descriptor, themeDir, {
214
+ label: 'theme descriptor file',
210
215
  });
211
- /** @type {{version: 1, themes: Array<Record<string, unknown>>, [key: string]: unknown}} */
212
- let catalog = {version: 1, themes: []};
213
- /** @type {Buffer|null} */
214
- let catalogOriginal = null;
215
- if (fs.existsSync(catalogFile)) {
216
- try {
217
- catalogOriginal = fs.readFileSync(catalogFile);
218
- catalog = JSON.parse(catalogOriginal.toString('utf-8'));
219
- // The discovery seam is the schema/source-of-truth validator. The write
220
- // plan carries catalogOriginal, so any concurrent change between this read
221
- // and publish is refused rather than overwritten with this snapshot.
222
- discoverThemeCatalog(root, owner);
223
- } catch (error) {
216
+ // An existing folder is filled; only a file this would write is refused.
217
+ for (const file of [sourceFile, descriptorFile]) {
218
+ if (fs.existsSync(file)) {
224
219
  throw new AstryxError(
225
- error instanceof Error ? error.message : String(error),
220
+ `Refusing to overwrite existing file ${projectPath(path.relative(packageDir, file))}.`,
226
221
  undefined,
227
- ERROR_CODES.ERR_THEME_INVALID,
222
+ ERROR_CODES.ERR_FILE_EXISTS,
228
223
  );
229
224
  }
230
225
  }
231
- if (
232
- catalog.themes.some(
233
- theme =>
234
- typeof theme.slug === 'string' &&
235
- theme.slug.toLowerCase() === identity.slug.toLowerCase(),
236
- )
237
- ) {
238
- throw new AstryxError(
239
- `Theme "${identity.slug}" already exists in ${projectPath(path.relative(packageDir, catalogFile))}.`,
240
- undefined,
241
- ERROR_CODES.ERR_FILE_EXISTS,
242
- );
243
- }
244
-
245
- catalog.themes.push({
246
- slug: identity.slug,
247
- displayName: identity.displayName,
248
- description: `${identity.displayName} theme.`,
249
- maintained: true,
250
- entry: identity.entry,
251
- exportName: identity.exportName,
252
- files: [identity.entry],
253
- });
254
226
 
255
227
  /** @type {import('./add-helpers.mjs').WritePlan[]} */
256
- const plans = [];
257
- plans.push(
228
+ const plans = [
258
229
  {path: sourceFile, contents: themeSource(identity), createOnly: true},
259
230
  {
260
- path: catalogFile,
261
- contents: `${JSON.stringify(catalog, null, 2)}\n`,
262
- createOnly: catalogOriginal == null,
263
- expectedOriginal: catalogOriginal ?? undefined,
231
+ path: descriptorFile,
232
+ contents: themeDescriptor(identity),
233
+ createOnly: true,
264
234
  },
265
- );
235
+ ];
266
236
  const packageUpdate = packageJsonUpdate(
267
237
  packageFile,
268
238
  rootPath,