@astryxdesign/cli 0.6.3-canary.f22695a → 0.6.3

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 (197) hide show
  1. package/README.md +1 -2
  2. package/api/build/build.type.d.mts +2 -2
  3. package/api/build/build.type.mjs +2 -2
  4. package/api/component/component.type.d.mts +6 -6
  5. package/api/component/component.type.mjs +19 -19
  6. package/api/discover/discover.type.d.mts +4 -4
  7. package/api/discover/discover.type.mjs +10 -10
  8. package/api/docs/_adapter.d.mts +24 -37
  9. package/api/docs/_adapter.mjs +83 -169
  10. package/api/docs/detail/detail.mjs +63 -14
  11. package/api/docs/detail/section/section.d.mts +1 -1
  12. package/api/docs/detail/section/section.mjs +20 -44
  13. package/api/docs/detail/section/section.test.mjs +0 -41
  14. package/api/docs/docs.d.mts +2 -7
  15. package/api/docs/docs.doc.mjs +10 -27
  16. package/api/docs/docs.mjs +9 -16
  17. package/api/docs/docs.test.mjs +0 -6
  18. package/api/docs/docs.type.d.mts +3 -40
  19. package/api/docs/docs.type.mjs +8 -36
  20. package/api/docs/integrationDocs.test.mjs +0 -106
  21. package/api/doctor/doctor.d.mts +0 -48
  22. package/api/doctor/doctor.mjs +0 -232
  23. package/api/doctor/doctor.test.mjs +0 -196
  24. package/api/hook/hook.type.d.mts +3 -3
  25. package/api/hook/hook.type.mjs +11 -11
  26. package/api/hook/list/list.d.mts +1 -1
  27. package/api/integration/add-contribution.mjs +3 -5
  28. package/api/integration/add-contribution.test.mjs +4 -4
  29. package/api/integration/integration-authoring.type.d.mts +1 -1
  30. package/api/integration/pack-check.mjs +7 -49
  31. package/api/integration/pack-check.test.mjs +0 -249
  32. package/api/search/search.d.mts +1 -1
  33. package/api/search/search.mjs +5 -5
  34. package/api/search/search.type.d.mts +2 -2
  35. package/api/search/search.type.mjs +1 -1
  36. package/api/swizzle/swizzle.type.d.mts +2 -2
  37. package/api/swizzle/swizzle.type.mjs +2 -2
  38. package/api/template/template.d.mts +1 -1
  39. package/api/template/template.type.d.mts +6 -6
  40. package/api/template/template.type.mjs +12 -12
  41. package/api/theme/build/build.mjs +6 -20
  42. package/api/theme/build/build.test.mjs +0 -127
  43. package/api/theme/palette/generate/generate.mjs +1 -1
  44. package/api/theme/palette/generate/generator.d.mts +13 -10
  45. package/api/theme/palette/generate/generator.mjs +3 -7
  46. package/api/theme/theme.type.d.mts +11 -170
  47. package/api/theme/theme.type.mjs +27 -94
  48. package/api/upgrade/_adapter.mjs +5 -71
  49. package/api/upgrade/upgrade.doc.mjs +3 -4
  50. package/api/upgrade/upgrade.type.d.mts +5 -5
  51. package/api/upgrade/upgrade.type.mjs +11 -11
  52. package/assets/codemods/integration-discovery.mjs +2 -40
  53. package/assets/codemods/integration-discovery.test.mjs +0 -58
  54. package/assets/codemods/transforms/v0.3.0/__tests__/unwrap-authoring-factories.test.mjs +5 -27
  55. package/assets/codemods/transforms/v0.3.0/unwrap-authoring-factories.mjs +5 -20
  56. package/assets/docs/README.md +0 -9
  57. package/assets/docs/cli-integrations.doc.mjs +15 -86
  58. package/assets/docs/styling-libraries.doc.mjs +1 -1
  59. package/assets/docs/working-with-ai.doc.mjs +1 -1
  60. package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.doc.mjs +3 -19
  61. package/assets/templates/blocks/components/Toolbar/ToolbarTableFilter.tsx +65 -383
  62. package/authoring/_shared/contract.ts +0 -22
  63. package/authoring/codemod/codemod.doc.mjs +1 -6
  64. package/authoring/codemod/parse.d.mts +8 -8
  65. package/authoring/codemod/parse.mjs +6 -8
  66. package/authoring/config/parse.d.mts +13 -13
  67. package/authoring/config/parse.mjs +8 -8
  68. package/authoring/config/type.ts +3 -3
  69. package/authoring/debug/parse.d.mts +5 -5
  70. package/authoring/debug/parse.mjs +3 -3
  71. package/authoring/doctypes/_schema.d.mts +23 -788
  72. package/authoring/doctypes/_schema.mjs +39 -492
  73. package/authoring/doctypes/base/type.ts +0 -40
  74. package/authoring/doctypes/command/command.doc.mjs +2 -3
  75. package/authoring/doctypes/command/parse.d.mts +2 -2
  76. package/authoring/doctypes/command/parse.mjs +1 -1
  77. package/authoring/doctypes/command/type.ts +2 -3
  78. package/authoring/doctypes/component/component.doc.mjs +3 -6
  79. package/authoring/doctypes/component/parse.d.mts +2 -2
  80. package/authoring/doctypes/component/parse.mjs +1 -1
  81. package/authoring/doctypes/component/type.ts +3 -4
  82. package/authoring/doctypes/enum/parse.d.mts +2 -2
  83. package/authoring/doctypes/enum/parse.mjs +1 -1
  84. package/authoring/doctypes/enum/type.ts +1 -3
  85. package/authoring/doctypes/function/function.doc.mjs +0 -4
  86. package/authoring/doctypes/function/parse.d.mts +2 -2
  87. package/authoring/doctypes/function/parse.mjs +1 -1
  88. package/authoring/doctypes/function/type.ts +2 -6
  89. package/authoring/doctypes/hook/hook.doc.mjs +0 -4
  90. package/authoring/doctypes/hook/parse.d.mts +2 -2
  91. package/authoring/doctypes/hook/parse.mjs +1 -1
  92. package/authoring/doctypes/hook/type.ts +2 -3
  93. package/authoring/doctypes/legacy.d.mts +6 -8
  94. package/authoring/doctypes/legacy.mjs +4 -5
  95. package/authoring/doctypes/parse.d.mts +18 -20
  96. package/authoring/doctypes/parse.mjs +10 -16
  97. package/authoring/doctypes/parse.test.mjs +3 -77
  98. package/authoring/doctypes/reference/parse.d.mts +2 -2
  99. package/authoring/doctypes/reference/parse.mjs +5 -8
  100. package/authoring/doctypes/reference/reference.doc.mjs +4 -17
  101. package/authoring/doctypes/reference/type.ts +5 -51
  102. package/authoring/doctypes/schema/parse.d.mts +2 -2
  103. package/authoring/doctypes/schema/parse.mjs +1 -1
  104. package/authoring/doctypes/schema/type.ts +2 -3
  105. package/authoring/doctypes/template/parse.d.mts +1 -92
  106. package/authoring/doctypes/template/parse.mjs +2 -36
  107. package/authoring/doctypes/template/parse.test.mjs +2 -8
  108. package/authoring/doctypes/template/template.doc.mjs +0 -4
  109. package/authoring/doctypes/template/type.ts +2 -5
  110. package/authoring/doctypes/types.ts +9 -10
  111. package/authoring/gap-report/parse.d.mts +10 -10
  112. package/authoring/gap-report/parse.mjs +6 -6
  113. package/authoring/gap-report/type.ts +1 -1
  114. package/authoring/index.d.mts +0 -1
  115. package/authoring/index.d.ts +17 -49
  116. package/authoring/index.mjs +0 -1
  117. package/authoring/integration/integration.doc.mjs +6 -13
  118. package/authoring/integration/parse.d.mts +2 -2
  119. package/authoring/integration/parse.mjs +1 -1
  120. package/authoring/integration/parse.test.mjs +1 -10
  121. package/authoring/integration/schema.d.mts +4 -6
  122. package/authoring/integration/schema.mjs +3 -9
  123. package/authoring/integration/type.ts +6 -23
  124. package/authoring/shadcn/receipt.d.mts +6 -6
  125. package/clients/cli/commands/docs.doc.mjs +3 -13
  126. package/clients/cli/commands/docs.mjs +21 -121
  127. package/clients/cli/commands/docs.test.mjs +0 -88
  128. package/clients/cli/commands/integration-authoring.test.mjs +9 -13
  129. package/clients/cli/commands/theme-palette-generate.doc.mjs +4 -8
  130. package/clients/cli/commands/upgrade.doc.mjs +2 -2
  131. package/clients/cli/formatters/index.mjs +1 -162
  132. package/clients/cli/formatters/index.test.mjs +0 -91
  133. package/clients/cli/lib/manifest.mjs +2 -7
  134. package/foundation/config/project.mjs +6 -21
  135. package/foundation/discovery/component-discovery.d.mts +1 -1
  136. package/foundation/discovery/component-discovery.mjs +1 -2
  137. package/foundation/discovery/docs-discovery.d.mts +4 -11
  138. package/foundation/discovery/docs-discovery.mjs +88 -208
  139. package/foundation/discovery/docs-discovery.test.mjs +13 -279
  140. package/foundation/discovery/template-adapter.mjs +1 -2
  141. package/foundation/integrations/autolink.mjs +5 -12
  142. package/foundation/integrations/integration-warnings.mjs +0 -6
  143. package/foundation/integrations/integrations.d.mts +2 -46
  144. package/foundation/integrations/integrations.mjs +8 -167
  145. package/foundation/integrations/integrations.test.mjs +1 -384
  146. package/foundation/integrations/validate-contributions.d.mts +0 -2
  147. package/foundation/integrations/validate-contributions.mjs +0 -10
  148. package/foundation/response/json-contract.test.mjs +17 -46
  149. package/foundation/response/response-types.doc.mjs +1 -6
  150. package/package.json +11 -9
  151. package/api/docs/compiled-topics.test.mjs +0 -78
  152. package/api/docs/index/index.d.mts +0 -18
  153. package/api/docs/index/index.mjs +0 -32
  154. package/api/docs/index/index.test.mjs +0 -62
  155. package/api/upgrade/project-context.test.mjs +0 -272
  156. package/assets/docs/authoring.doc.mjs +0 -14
  157. package/assets/templates/blocks/components/Timer/TimerFormats.doc.mjs +0 -14
  158. package/assets/templates/blocks/components/Timer/TimerFormats.tsx +0 -34
  159. package/assets/templates/blocks/components/Timer/TimerInline.doc.mjs +0 -14
  160. package/assets/templates/blocks/components/Timer/TimerInline.tsx +0 -14
  161. package/assets/templates/blocks/components/Timer/TimerShowcase.doc.mjs +0 -13
  162. package/assets/templates/blocks/components/Timer/TimerShowcase.tsx +0 -47
  163. package/assets/templates/blocks/components/Timer/TimerTypography.doc.mjs +0 -14
  164. package/assets/templates/blocks/components/Timer/TimerTypography.tsx +0 -31
  165. package/authoring/doctypes/base/graph-fields.doc.d.mts +0 -9
  166. package/authoring/doctypes/base/graph-fields.doc.mjs +0 -62
  167. package/authoring/doctypes/load-contract.test.mjs +0 -207
  168. package/authoring/doctypes/namespace/namespace.doc.d.mts +0 -9
  169. package/authoring/doctypes/namespace/namespace.doc.mjs +0 -132
  170. package/authoring/doctypes/namespace/parse.d.mts +0 -12
  171. package/authoring/doctypes/namespace/parse.mjs +0 -25
  172. package/authoring/doctypes/namespace/parse.test.mjs +0 -165
  173. package/authoring/doctypes/namespace/type.ts +0 -71
  174. package/authoring/identity/identity.doc.d.mts +0 -9
  175. package/authoring/identity/identity.doc.mjs +0 -61
  176. package/authoring/identity/type.ts +0 -132
  177. package/foundation/discovery/authoring-self-docs.d.mts +0 -69
  178. package/foundation/discovery/authoring-self-docs.mjs +0 -214
  179. package/foundation/discovery/authoring-self-docs.test.mjs +0 -154
  180. package/foundation/discovery/docs-output-budget.d.mts +0 -28
  181. package/foundation/discovery/docs-output-budget.mjs +0 -50
  182. package/foundation/discovery/docs-section-key.d.mts +0 -98
  183. package/foundation/discovery/docs-section-key.mjs +0 -221
  184. package/foundation/discovery/docs-section-key.test.mjs +0 -224
  185. package/foundation/doc-compiler/compile.d.mts +0 -162
  186. package/foundation/doc-compiler/compile.mjs +0 -262
  187. package/foundation/doc-compiler/doc-compiler.test.mjs +0 -687
  188. package/foundation/doc-compiler/ir.d.mts +0 -9
  189. package/foundation/doc-compiler/ir.mjs +0 -287
  190. package/foundation/doc-compiler/lenses.d.mts +0 -33
  191. package/foundation/doc-compiler/lenses.mjs +0 -127
  192. package/foundation/identity/provider-identity.d.mts +0 -90
  193. package/foundation/identity/provider-identity.mjs +0 -320
  194. package/foundation/identity/provider-identity.test.mjs +0 -254
  195. package/foundation/identity/providers.d.mts +0 -7
  196. package/foundation/identity/providers.mjs +0 -16
  197. package/foundation/integrations/provider-conflicts.test.mjs +0 -125
@@ -6,19 +6,13 @@
6
6
  * Integrations are PACKAGE NAMES listed in astryx.config.{ts,mjs,js}. Each
7
7
  * package declares a single conventional root manifest sibling to its
8
8
  * package.json — astryx.integration.{ts,mjs,js} — which contributes
9
- * components/templates/codemods/docs/themes roots and an optional issuesUrl.
10
- * Stable provider identity and package metadata come from package.json, not the
11
- * manifest.
12
- *
13
- * @input Integration package names, package.json files, and root manifests.
14
- * @output LoadedIntegration records with normalized provider identity and roots.
15
- * @position foundation/integrations — package contribution loading boundary.
9
+ * components/templates/codemods/docs/themes roots and an optional issuesUrl. Identity
10
+ * (name, version) comes from the package's package.json, not the manifest.
16
11
  */
17
12
 
18
13
  import * as fs from 'node:fs';
19
14
  import * as path from 'node:path';
20
15
  import {assertWithin} from '../fs/path-safety.mjs';
21
- import {normalizeProviderId} from '../identity/provider-identity.mjs';
22
16
  // The key census and contribution parsers are internal to the schema module on
23
17
  // purpose: the public parser still validates the complete authored type, while
24
18
  // the loader can isolate an invalid optional contribution from valid roots.
@@ -37,10 +31,6 @@ import {parseGapReportHandler} from '../../authoring/gap-report/parse.mjs';
37
31
  * are internal bookkeeping used by Doctor integration validation and Project.
38
32
  * @typedef {object} LoadedIntegration
39
33
  * @property {string} name
40
- * @property {import('../../authoring/identity/type').ProviderId} [providerId]
41
- * normalized stable provider identity; absent only for a legacy unnamed local
42
- * package. Unique among contributing integrations: a later claimant is kept
43
- * inert with `__providerConflict` (see {@link markProviderConflicts})
44
34
  * @property {string} [version]
45
35
  * @property {string} [components]
46
36
  * @property {string} [templates]
@@ -59,10 +49,6 @@ import {parseGapReportHandler} from '../../authoring/gap-report/parse.mjs';
59
49
  * @property {string} __manifestFile
60
50
  * @property {string} [__loadError] set when the manifest failed to load/validate;
61
51
  * such an integration contributes nothing and is surfaced via Project.issues()
62
- * @property {{providerId: import('../../authoring/identity/type').ProviderId, claimedBy: string, message: string}} [__providerConflict]
63
- * set on a package whose provider ID an earlier-loaded package already
64
- * claims; it contributes nothing and is reported as a `duplicate_provider`
65
- * warning
66
52
  * @property {string[]} [__unknownKeys] manifest keys this CLI does not know —
67
53
  * surfaced as a warning; the rest of the manifest still contributes
68
54
  * @property {boolean} [__autolinked] loaded because the project declares the
@@ -88,137 +74,6 @@ export const MANIFEST_BASENAMES = [
88
74
  'astryx.integration.js',
89
75
  ];
90
76
 
91
- /**
92
- * Normalize a package-owned provider ID without rejecting legacy unnamed local
93
- * packages at this compatibility boundary.
94
- * @param {unknown} name
95
- * @returns {import('../../authoring/identity/type').ProviderId | undefined}
96
- */
97
- function providerIdForPackage(name) {
98
- if (typeof name !== 'string' || name.length === 0) return undefined;
99
- try {
100
- return normalizeProviderId(name);
101
- } catch {
102
- return undefined;
103
- }
104
- }
105
-
106
- /**
107
- * Resolve provider identity across loaded integrations, in precedence order.
108
- *
109
- * Artifact and document IDs are provider-scoped, so two packages cannot both
110
- * contribute under one provider ID. The same package reached twice (an npm
111
- * alias beside the package it aliases, with the same name and version) loads
112
- * once. Any other later claimant, including the same package at another
113
- * version, stays as an inert entry that carries the conflict. The package being
114
- * authored claims its ID before precedence order is considered, because the
115
- * source being edited is authoritative. The winner still contributes; Project
116
- * issues, Doctor, and the per-command warning name the one set aside instead of
117
- * dropping it without a word.
118
- *
119
- * @param {LoadedIntegration[]} integrations in precedence order
120
- * @returns {LoadedIntegration[]}
121
- */
122
- export function markProviderConflicts(integrations) {
123
- /** @type {Map<string, LoadedIntegration>} */
124
- const claims = new Map();
125
- for (const integration of integrations) {
126
- if (integration?.__local && claimsProvider(integration)) {
127
- const providerId = /** @type {string} */ (integration.providerId);
128
- if (!claims.has(providerId)) claims.set(providerId, integration);
129
- }
130
- }
131
- /** @type {LoadedIntegration[]} */
132
- const resolved = [];
133
- for (const integration of integrations) {
134
- if (!claimsProvider(integration)) {
135
- resolved.push(integration);
136
- continue;
137
- }
138
- const providerId = /** @type {string} */ (integration.providerId);
139
- const claimant = claims.get(providerId);
140
- if (claimant == null) {
141
- claims.set(providerId, integration);
142
- resolved.push(integration);
143
- } else if (claimant === integration) {
144
- resolved.push(integration);
145
- } else if (
146
- claimant.name !== integration.name ||
147
- claimant.version !== integration.version
148
- ) {
149
- resolved.push(providerConflict(integration, claimant));
150
- }
151
- }
152
- return resolved;
153
- }
154
-
155
- /**
156
- * Whether an entry contributes under its provider ID: it has one, its manifest
157
- * loaded, and it has not already been set aside.
158
- * @param {LoadedIntegration | undefined} integration
159
- * @returns {boolean}
160
- */
161
- function claimsProvider(integration) {
162
- return (
163
- integration?.providerId != null &&
164
- integration.__loadError == null &&
165
- integration.__providerConflict == null
166
- );
167
- }
168
-
169
- /**
170
- * @param {LoadedIntegration} integration
171
- * @returns {string}
172
- */
173
- function describeIntegration(integration) {
174
- const id = integration.version
175
- ? `${integration.name}@${integration.version}`
176
- : integration.name;
177
- return integration.__spec && integration.__spec !== integration.name
178
- ? `${id} (from "${integration.__spec}")`
179
- : id;
180
- }
181
-
182
- /**
183
- * An inert record for a package whose provider ID is already claimed. It keeps
184
- * the package's identity and location for reporting, and drops every
185
- * contribution root and handler.
186
- * @param {LoadedIntegration} integration
187
- * @param {LoadedIntegration} claimant
188
- * @returns {LoadedIntegration}
189
- */
190
- function providerConflict(integration, claimant) {
191
- const providerId =
192
- /** @type {import('../../authoring/identity/type').ProviderId} */ (
193
- integration.providerId
194
- );
195
- const winner = describeIntegration(claimant);
196
- const setAside = describeIntegration(integration);
197
- const reason = claimant.__local
198
- ? 'is the package being authored, so it is used'
199
- : 'loads first and is used';
200
- return {
201
- name: integration.name,
202
- providerId,
203
- version: integration.version,
204
- __spec: integration.__spec,
205
- __packageDir: integration.__packageDir,
206
- __manifestFile: integration.__manifestFile,
207
- ...(integration.__local ? {__local: true} : {}),
208
- ...(integration.__autolinked
209
- ? {__autolinked: true, __dependencyField: integration.__dependencyField}
210
- : {}),
211
- __providerConflict: {
212
- providerId,
213
- claimedBy: claimant.name,
214
- message:
215
- `${setAside} and ${winner} both claim provider ID "${providerId}". ` +
216
- `${winner} ${reason}; ${setAside} contributes nothing ` +
217
- 'until one package changes its providerId.',
218
- },
219
- };
220
- }
221
-
222
77
  /**
223
78
  * Return the conventional root manifest paths present in `dir`, in
224
79
  * load-precedence order. Unlike {@link resolveManifestPath} this never throws —
@@ -419,7 +274,6 @@ export async function loadLocalIntegration(packageDir, {fresh = false} = {}) {
419
274
  typeof pkg.name === 'string' && pkg.name.length > 0
420
275
  ? pkg.name
421
276
  : '(local integration)';
422
- const packageProviderId = providerIdForPackage(pkg.name);
423
277
  const manifestFile = resolveManifestPath(packageDir, spec);
424
278
 
425
279
  let manifest;
@@ -445,7 +299,6 @@ export async function loadLocalIntegration(packageDir, {fresh = false} = {}) {
445
299
  } catch (err) {
446
300
  return {
447
301
  name: spec,
448
- ...(packageProviderId == null ? {} : {providerId: packageProviderId}),
449
302
  version: pkg.version,
450
303
  __spec: spec,
451
304
  __packageDir: packageDir,
@@ -455,8 +308,6 @@ export async function loadLocalIntegration(packageDir, {fresh = false} = {}) {
455
308
  };
456
309
  }
457
310
 
458
- const providerId = providerIdForPackage(manifest.providerId ?? pkg.name);
459
-
460
311
  /** @param {string | null | undefined} value */
461
312
  const resolveRoot = value => {
462
313
  if (value == null) return undefined;
@@ -469,7 +320,6 @@ export async function loadLocalIntegration(packageDir, {fresh = false} = {}) {
469
320
 
470
321
  return {
471
322
  name: spec,
472
- ...(providerId == null ? {} : {providerId}),
473
323
  version: pkg.version,
474
324
  components: resolveRoot(manifest.components),
475
325
  templates: resolveRoot(manifest.templates),
@@ -495,22 +345,20 @@ export async function loadLocalIntegration(packageDir, {fresh = false} = {}) {
495
345
  * Load configured integrations.
496
346
  *
497
347
  * @param {string[]} [specs] package names
498
- * @param {{cwd?: string, fresh?: boolean, resolveProviders?: boolean}} [options]
499
- * `resolveProviders: false` leaves provider identity to a caller that
500
- * resolves it once over a larger set (Project.load)
348
+ * @param {{cwd?: string, fresh?: boolean}} [options]
501
349
  * @returns {Promise<LoadedIntegration[]>}
502
350
  */
503
351
  export async function loadIntegrations(
504
352
  specs = [],
505
- {cwd = process.cwd(), fresh = false, resolveProviders = true} = {},
353
+ {cwd = process.cwd(), fresh = false} = {},
506
354
  ) {
507
355
  /** @type {LoadedIntegration[]} */
508
356
  const integrations = [];
509
- const seenSpecs = new Set();
357
+ const seen = new Set();
510
358
 
511
359
  for (const spec of specs) {
512
- if (!spec || seenSpecs.has(spec)) continue;
513
- seenSpecs.add(spec);
360
+ if (!spec || seen.has(spec)) continue;
361
+ seen.add(spec);
514
362
 
515
363
  const packageDir = resolvePackageDir(spec, cwd);
516
364
  const pkgPath = path.join(packageDir, 'package.json');
@@ -523,7 +371,6 @@ export async function loadIntegrations(
523
371
  );
524
372
  }
525
373
 
526
- const packageProviderId = providerIdForPackage(pkg.name ?? spec);
527
374
  const manifestFile = resolveManifestPath(packageDir, spec);
528
375
  let manifest;
529
376
  /** @type {string[]} */
@@ -552,7 +399,6 @@ export async function loadIntegrations(
552
399
  // discovery loops naturally skip it (no components/templates/codemods).
553
400
  integrations.push({
554
401
  name: pkg.name ?? spec,
555
- ...(packageProviderId == null ? {} : {providerId: packageProviderId}),
556
402
  version: pkg.version,
557
403
  __spec: spec,
558
404
  __packageDir: packageDir,
@@ -562,10 +408,6 @@ export async function loadIntegrations(
562
408
  continue;
563
409
  }
564
410
 
565
- const providerId = providerIdForPackage(
566
- manifest.providerId ?? pkg.name ?? spec,
567
- );
568
-
569
411
  /** @param {string | null | undefined} value */
570
412
  const resolveRoot = value => {
571
413
  if (value == null) return undefined;
@@ -579,7 +421,6 @@ export async function loadIntegrations(
579
421
 
580
422
  integrations.push({
581
423
  name: pkg.name ?? spec,
582
- ...(providerId == null ? {} : {providerId}),
583
424
  version: pkg.version,
584
425
  components: resolveRoot(manifest.components),
585
426
  templates: resolveRoot(manifest.templates),
@@ -600,5 +441,5 @@ export async function loadIntegrations(
600
441
  });
601
442
  }
602
443
 
603
- return resolveProviders ? markProviderConflicts(integrations) : integrations;
444
+ return integrations;
604
445
  }
@@ -77,7 +77,6 @@ describe('configured integrations', () => {
77
77
  const loaded = project.loadedIntegrations[0];
78
78
  // Identity comes from package.json, not the manifest.
79
79
  expect(loaded.name).toBe('@acme/widgets');
80
- expect(loaded.providerId).toBe('@acme/widgets');
81
80
  expect(loaded.version).toBe('1.2.3');
82
81
  expect(loaded.components).toBe(path.join(pkgDir, 'docs'));
83
82
  expect(loaded.templates).toBe(path.join(pkgDir, 'blocks'));
@@ -85,43 +84,6 @@ describe('configured integrations', () => {
85
84
  expect(loaded.issuesUrl).toBe('https://example.com/issues');
86
85
  });
87
86
 
88
- it('preserves provider identity across an explicit package rename', async () => {
89
- writeManifestPackage(tmpDir, {
90
- body: `export default {providerId: '@acme/legacy-widgets'};\n`,
91
- });
92
-
93
- const [loaded] = await loadIntegrations(['@acme/widgets'], {cwd: tmpDir});
94
- expect(loaded.name).toBe('@acme/widgets');
95
- expect(loaded.providerId).toBe('@acme/legacy-widgets');
96
- expect(loaded.__unknownKeys).toEqual([]);
97
- });
98
-
99
- it('deduplicates package aliases by canonical provider identity', async () => {
100
- writeManifestPackage(tmpDir, {body: `export default {};\n`});
101
- const aliasDir = path.join(
102
- tmpDir,
103
- 'node_modules',
104
- '@acme',
105
- 'widgets-alias',
106
- );
107
- fs.mkdirSync(aliasDir, {recursive: true});
108
- fs.writeFileSync(
109
- path.join(aliasDir, 'package.json'),
110
- JSON.stringify({name: '@acme/widgets', version: '1.2.3'}),
111
- );
112
- fs.writeFileSync(
113
- path.join(aliasDir, 'astryx.integration.mjs'),
114
- `export default {};\n`,
115
- );
116
-
117
- const loaded = await loadIntegrations(
118
- ['@acme/widgets', '@acme/widgets-alias'],
119
- {cwd: tmpDir},
120
- );
121
- expect(loaded).toHaveLength(1);
122
- expect(loaded[0].providerId).toBe('@acme/widgets');
123
- });
124
-
125
87
  it('makes integration components discoverable', async () => {
126
88
  const pkgDir = writeManifestPackage(tmpDir, {
127
89
  body: `export default { components: './docs' };\n`,
@@ -245,347 +207,6 @@ describe('configured integrations', () => {
245
207
  });
246
208
  });
247
209
 
248
- describe('provider identity conflicts', () => {
249
- /**
250
- * Install one integration package that contributes a single component.
251
- * @param {string} dir directory under node_modules
252
- * @param {{name: string, version: string}} pkg package.json identity
253
- * @param {Record<string, unknown>} manifest extra manifest fields
254
- * @param {string} component the component it contributes
255
- */
256
- function installPackage(dir, pkg, manifest, component) {
257
- const pkgDir = path.join(tmpDir, 'node_modules', ...dir.split('/'));
258
- const componentsDir = path.join(pkgDir, 'components');
259
- fs.mkdirSync(componentsDir, {recursive: true});
260
- fs.writeFileSync(path.join(pkgDir, 'package.json'), JSON.stringify(pkg));
261
- fs.writeFileSync(
262
- path.join(pkgDir, 'astryx.integration.mjs'),
263
- `export default ${JSON.stringify({components: './components', ...manifest})};\n`,
264
- );
265
- fs.writeFileSync(
266
- path.join(componentsDir, `${component}.doc.mjs`),
267
- `export default {type: 'component', name: '${component}', props: []};\n`,
268
- );
269
- fs.writeFileSync(
270
- path.join(componentsDir, `${component}.tsx`),
271
- `export function ${component}() { return null; }\n`,
272
- );
273
- }
274
-
275
- /** @param {string[]} integrations */
276
- function configure(integrations) {
277
- fs.writeFileSync(
278
- path.join(tmpDir, 'astryx.config.mjs'),
279
- `export default ${JSON.stringify({integrations})};\n`,
280
- );
281
- }
282
-
283
- /**
284
- * Make the project directory itself the package being authored.
285
- * @param {Record<string, unknown>} pkg package.json fields
286
- * @param {Record<string, unknown>} manifest extra manifest fields
287
- * @param {string} component the component it contributes
288
- */
289
- function writeLocalPackage(pkg, manifest, component) {
290
- const componentsDir = path.join(tmpDir, 'local-components');
291
- fs.mkdirSync(componentsDir, {recursive: true});
292
- fs.writeFileSync(path.join(tmpDir, 'package.json'), JSON.stringify(pkg));
293
- fs.writeFileSync(
294
- path.join(tmpDir, 'astryx.integration.mjs'),
295
- `export default ${JSON.stringify({components: './local-components', ...manifest})};\n`,
296
- );
297
- fs.writeFileSync(
298
- path.join(componentsDir, `${component}.doc.mjs`),
299
- `export default {type: 'component', name: '${component}', props: []};\n`,
300
- );
301
- fs.writeFileSync(
302
- path.join(componentsDir, `${component}.tsx`),
303
- `export function ${component}() { return null; }\n`,
304
- );
305
- }
306
-
307
- /** @param {import('../config/project.mjs').Project} project */
308
- async function conflictIssues(project) {
309
- return (await project.issues()).filter(
310
- issue => issue.code === 'duplicate_provider',
311
- );
312
- }
313
-
314
- it('keeps the first package and reports a different package claiming its ID', async () => {
315
- installPackage(
316
- '@acme/widgets',
317
- {name: '@acme/widgets', version: '1.0.0'},
318
- {},
319
- 'Widget',
320
- );
321
- installPackage(
322
- '@acme/renamed',
323
- {name: '@acme/renamed', version: '2.0.0'},
324
- {providerId: '@acme/widgets'},
325
- 'RenamedWidget',
326
- );
327
- configure(['@acme/widgets', '@acme/renamed']);
328
-
329
- const loaded = await loadIntegrations(['@acme/widgets', '@acme/renamed'], {
330
- cwd: tmpDir,
331
- });
332
- expect(loaded.map(integration => integration.name)).toEqual([
333
- '@acme/widgets',
334
- '@acme/renamed',
335
- ]);
336
- expect(loaded[1]).toMatchObject({
337
- providerId: '@acme/widgets',
338
- __providerConflict: {
339
- providerId: '@acme/widgets',
340
- claimedBy: '@acme/widgets',
341
- },
342
- });
343
- expect(loaded[1].components).toBeUndefined();
344
-
345
- const project = await Project.load(tmpDir, {fresh: true});
346
- const owned = (await project.components()).map(component => [
347
- component.package,
348
- component.name,
349
- ]);
350
- expect(owned).toContainEqual(['@acme/widgets', 'Widget']);
351
- expect(owned.some(([pkg]) => pkg === '@acme/renamed')).toBe(false);
352
- expect(await project.issues()).toContainEqual(
353
- expect.objectContaining({
354
- package: '@acme/renamed@2.0.0',
355
- code: 'duplicate_provider',
356
- severity: 'warning',
357
- message: expect.stringContaining(
358
- '@acme/widgets@1.0.0 loads first and is used',
359
- ),
360
- }),
361
- );
362
- });
363
-
364
- it('reports the same package configured again at another version', async () => {
365
- installPackage(
366
- '@acme/widgets',
367
- {name: '@acme/widgets', version: '1.0.0'},
368
- {},
369
- 'Widget',
370
- );
371
- installPackage(
372
- 'widgets-next',
373
- {name: '@acme/widgets', version: '2.0.0'},
374
- {},
375
- 'NextWidget',
376
- );
377
- configure(['@acme/widgets', 'widgets-next']);
378
-
379
- const project = await Project.load(tmpDir, {fresh: true});
380
- const owned = (await project.components()).map(component => component.name);
381
- expect(owned).toContain('Widget');
382
- expect(owned).not.toContain('NextWidget');
383
- expect(await project.issues()).toContainEqual(
384
- expect.objectContaining({
385
- package: '@acme/widgets@2.0.0',
386
- code: 'duplicate_provider',
387
- severity: 'warning',
388
- message: expect.stringContaining('(from "widgets-next")'),
389
- }),
390
- );
391
- });
392
-
393
- it('reports an autolinked dependency that claims a configured ID', async () => {
394
- installPackage(
395
- '@acme/widgets',
396
- {name: '@acme/widgets', version: '1.0.0'},
397
- {},
398
- 'Widget',
399
- );
400
- installPackage(
401
- '@acme/renamed',
402
- {name: '@acme/renamed', version: '2.0.0'},
403
- {providerId: '@acme/widgets'},
404
- 'RenamedWidget',
405
- );
406
- configure(['@acme/widgets']);
407
- fs.writeFileSync(
408
- path.join(tmpDir, 'package.json'),
409
- JSON.stringify({
410
- name: 'consumer',
411
- dependencies: {'@acme/renamed': '2.0.0'},
412
- }),
413
- );
414
-
415
- const project = await Project.load(tmpDir, {fresh: true});
416
- expect(
417
- project.loadedIntegrations.find(
418
- integration => integration.name === '@acme/renamed',
419
- ),
420
- ).toMatchObject({
421
- __autolinked: true,
422
- __providerConflict: {claimedBy: '@acme/widgets'},
423
- });
424
- expect(await project.issues()).toContainEqual(
425
- expect.objectContaining({
426
- package: '@acme/renamed@2.0.0',
427
- code: 'duplicate_provider',
428
- }),
429
- );
430
- });
431
-
432
- it("reports a set-aside package whose spec is the winner's name", async () => {
433
- installPackage(
434
- 'widgets-old',
435
- {name: '@acme/widgets', version: '1.0.0'},
436
- {},
437
- 'OldWidget',
438
- );
439
- installPackage(
440
- '@acme/widgets',
441
- {name: '@acme/widgets', version: '2.0.0'},
442
- {},
443
- 'NewWidget',
444
- );
445
- configure(['widgets-old', '@acme/widgets']);
446
-
447
- const project = await Project.load(tmpDir, {fresh: true});
448
- const owned = (await project.components()).map(component => component.name);
449
- expect(owned).toContain('OldWidget');
450
- expect(owned).not.toContain('NewWidget');
451
- expect(await conflictIssues(project)).toEqual([
452
- expect.objectContaining({
453
- package: '@acme/widgets@2.0.0',
454
- severity: 'warning',
455
- message: expect.stringContaining(
456
- '@acme/widgets@2.0.0 and @acme/widgets@1.0.0 (from "widgets-old") both claim',
457
- ),
458
- }),
459
- ]);
460
- });
461
-
462
- it('reports an unversioned set-aside package whose spec is the winner\'s name', async () => {
463
- installPackage(
464
- 'widgets-old',
465
- {name: '@acme/widgets', version: '1.0.0'},
466
- {},
467
- 'OldWidget',
468
- );
469
- installPackage('@acme/widgets', {name: '@acme/widgets'}, {}, 'NewWidget');
470
- configure(['widgets-old', '@acme/widgets']);
471
-
472
- const project = await Project.load(tmpDir, {fresh: true});
473
- expect(await conflictIssues(project)).toEqual([
474
- expect.objectContaining({
475
- package: '@acme/widgets',
476
- message: expect.stringContaining(
477
- '@acme/widgets@1.0.0 (from "widgets-old") loads first and is used',
478
- ),
479
- }),
480
- ]);
481
- });
482
-
483
- it('reports an autolinked alias of the same package at another version', async () => {
484
- installPackage(
485
- '@acme/legacy-ui',
486
- {name: '@acme/ui', version: '0.1.22'},
487
- {},
488
- 'LegacyButton',
489
- );
490
- installPackage(
491
- '@acme/ui',
492
- {name: '@acme/ui', version: '1.0.0'},
493
- {},
494
- 'NewButton',
495
- );
496
- fs.rmSync(path.join(tmpDir, 'astryx.config.mjs'));
497
- fs.writeFileSync(
498
- path.join(tmpDir, 'package.json'),
499
- JSON.stringify({
500
- name: 'consumer',
501
- dependencies: {
502
- '@acme/legacy-ui': 'npm:@acme/ui@0.1.22',
503
- '@acme/ui': '1.0.0',
504
- },
505
- }),
506
- );
507
-
508
- const project = await Project.load(tmpDir, {fresh: true});
509
- const owned = (await project.components()).map(component => component.name);
510
- expect(owned).toContain('LegacyButton');
511
- expect(owned).not.toContain('NewButton');
512
- expect(await conflictIssues(project)).toEqual([
513
- expect.objectContaining({
514
- package: '@acme/ui@1.0.0',
515
- message: expect.stringContaining(
516
- '@acme/ui@1.0.0 and @acme/ui@0.1.22 (from "@acme/legacy-ui") both claim',
517
- ),
518
- }),
519
- ]);
520
- });
521
-
522
- it('recomputes conflicts after the authored package replaces its installed copy', async () => {
523
- installPackage(
524
- '@acme/widgets',
525
- {name: '@acme/widgets', version: '1.0.0'},
526
- {},
527
- 'Widget',
528
- );
529
- installPackage(
530
- '@acme/renamed',
531
- {name: '@acme/renamed', version: '2.0.0'},
532
- {providerId: '@acme/widgets'},
533
- 'RenamedWidget',
534
- );
535
- configure(['@acme/widgets', '@acme/renamed']);
536
- writeLocalPackage(
537
- {name: '@acme/widgets', version: '3.0.0-dev'},
538
- {providerId: '@acme/widgets-next'},
539
- 'LocalWidget',
540
- );
541
-
542
- const project = await Project.load(tmpDir, {fresh: true});
543
- expect(
544
- project.loadedIntegrations.some(
545
- integration => integration.__providerConflict,
546
- ),
547
- ).toBe(false);
548
- const owned = (await project.components()).map(component => component.name);
549
- expect(owned).toEqual(
550
- expect.arrayContaining(['LocalWidget', 'RenamedWidget']),
551
- );
552
- expect(owned).not.toContain('Widget');
553
- expect(await conflictIssues(project)).toEqual([]);
554
- });
555
-
556
- it('lets the package being authored win over its installed predecessor', async () => {
557
- installPackage(
558
- '@acme/widgets',
559
- {name: '@acme/widgets', version: '1.0.0'},
560
- {},
561
- 'Widget',
562
- );
563
- fs.rmSync(path.join(tmpDir, 'astryx.config.mjs'));
564
- writeLocalPackage(
565
- {
566
- name: '@acme/renamed',
567
- version: '2.0.0-dev',
568
- devDependencies: {'@acme/widgets': '1.0.0'},
569
- },
570
- {providerId: '@acme/widgets'},
571
- 'RenamedWidget',
572
- );
573
-
574
- const project = await Project.load(tmpDir, {fresh: true});
575
- const owned = (await project.components()).map(component => component.name);
576
- expect(owned).toContain('RenamedWidget');
577
- expect(owned).not.toContain('Widget');
578
- expect(await conflictIssues(project)).toEqual([
579
- expect.objectContaining({
580
- package: '@acme/widgets@1.0.0',
581
- message: expect.stringContaining(
582
- '@acme/renamed@2.0.0-dev is the package being authored, so it is used',
583
- ),
584
- }),
585
- ]);
586
- });
587
- });
588
-
589
210
  describe('local integration self-resolution', () => {
590
211
  it('preserves a valid gapReport named export', async () => {
591
212
  fs.writeFileSync(
@@ -604,11 +225,7 @@ export default {};
604
225
 
605
226
  const loaded = await loadLocalIntegration(tmpDir, {fresh: true});
606
227
 
607
- expect(loaded).toMatchObject({
608
- name: '@acme/local',
609
- providerId: '@acme/local',
610
- __local: true,
611
- });
228
+ expect(loaded).toMatchObject({name: '@acme/local', __local: true});
612
229
  expect(loaded?.__gapReport?.audience).toBe('internal');
613
230
  expect(
614
231
  loaded?.__gapReport?.handle(
@@ -22,7 +22,5 @@ export function validateLoadedIntegration(loaded: LoadedIntegration): Promise<Is
22
22
  */
23
23
  /** Stable issue code for an invalid optional agent-doc contribution. */
24
24
  export const INVALID_AGENT_DOCS: "invalid_agent_docs";
25
- /** Stable issue code for a package whose provider ID is already claimed. */
26
- export const DUPLICATE_PROVIDER: "duplicate_provider";
27
25
  export type Issue = import("./issue").AstryxIntegrationIssue;
28
26
  export type LoadedIntegration = import("./integrations.mjs").LoadedIntegration;