@ankhorage/devtools 2.0.11 → 2.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
 
4
4
  # @ankhorage/devtools
5
5
 
6
- ![license: MIT](././paradox/badges/license.svg) ![npm: v2.0.11](././paradox/badges/npm.svg) ![runtime: bun](././paradox/badges/runtime.svg) ![typescript: strict](././paradox/badges/typescript.svg) ![eslint: checked](././paradox/badges/eslint.svg) ![prettier: checked](././paradox/badges/prettier.svg) ![build: checked](././paradox/badges/build.svg) ![tests: checked](././paradox/badges/tests.svg) ![paradox: warnings](././paradox/badges/docs.svg)
6
+ ![license: MIT](././paradox/badges/license.svg) ![npm: v2.0.13](././paradox/badges/npm.svg) ![runtime: bun](././paradox/badges/runtime.svg) ![typescript: strict](././paradox/badges/typescript.svg) ![eslint: checked](././paradox/badges/eslint.svg) ![prettier: checked](././paradox/badges/prettier.svg) ![build: checked](././paradox/badges/build.svg) ![tests: checked](././paradox/badges/tests.svg) ![paradox: warnings](././paradox/badges/docs.svg)
7
7
 
8
8
  Shared tooling, repository automation, and agent standards for Ankhorage TypeScript projects
9
9
 
@@ -46,8 +46,9 @@ types, ZORA elements, events, recipes, and version provenance. Never copy owner
46
46
  schemas, token inventories, color algorithms, action types, or manifest implementations into this
47
47
  skill.
48
48
 
49
- The inspection composes metadata-only descriptors from every installed `@ankhorage/zora-*` plugin;
50
- use those plugin elements exactly like ZORA core elements and keep their package provenance.
49
+ The inspection reads the canonical component and authoring metadata directly from released
50
+ `@ankhorage/zora`. Chess, Game, and Tabletop are core ZORA capabilities; do not discover or load
51
+ standalone `@ankhorage/zora-*` packages.
51
52
 
52
53
  For supplied-screen reconstruction, continue through `recognize` and treat the local analyzer's
53
54
  `ScreenSpec`, visual graph, confidence, alternatives, and unresolved diagnostics as the structural
@@ -16,9 +16,9 @@ bun .agents/skills/zora-designer/scripts/owner-api.ts inspect
16
16
  bun .agents/skills/zora-designer/scripts/analyze-screen.ts screen-analysis-input.json
17
17
  ```
18
18
 
19
- The analyzer uses the current composed ZORA metadata, including every installed
20
- `@ankhorage/zora-*` plugin, and delegates image processing to released
21
- `@ankhorage/utility/image`:
19
+ The analyzer uses the current canonical core ZORA metadata from released `@ankhorage/zora` and
20
+ delegates image processing to released `@ankhorage/utility/image`. It does not discover or compose
21
+ standalone ZORA plugin packages:
22
22
 
23
23
  ```text
24
24
  supplied image
@@ -88,7 +88,7 @@ The analyzer returns:
88
88
  - aggregate confidence;
89
89
  - ranked component candidates by region;
90
90
  - unresolved diagnostics;
91
- - the exact composed component names and owner/plugin version provenance used for the pass.
91
+ - the exact core component names and owner version provenance used for the pass.
92
92
 
93
93
  Use the generated `ScreenSpec` as the structural baseline. Do not discard a high-confidence exact
94
94
  metadata match merely because another component looks visually similar.
@@ -18,8 +18,8 @@ navigator types, ZORA elements, or events. Resolve explicit user input before pr
18
18
  existing brief values, category recommendations, and global defaults. Record the origin of every
19
19
  resolved decision.
20
20
 
21
- Installed `@ankhorage/zora-*` packages contribute their metadata-only plugin descriptors to this
22
- same composed element catalog; do not maintain a second plugin list in the skill.
21
+ Use the component catalog reported directly by released core `@ankhorage/zora`. Do not discover,
22
+ compose, or maintain a second catalog from standalone `@ankhorage/zora-*` packages.
23
23
 
24
24
  ## 2. Ask in dependency order
25
25
 
@@ -84,10 +84,6 @@ interface RecipeMetadata extends Record<string, unknown> {
84
84
  }
85
85
 
86
86
  interface ZoraMetadataApi extends Record<string, unknown> {
87
- composeZoraPluginMetadata: (plugins: readonly Record<string, unknown>[]) => {
88
- componentMeta: Record<string, ComponentMetadata | undefined>;
89
- };
90
- ZORA_CORE_PLUGIN_METADATA: Record<string, unknown>;
91
87
  ZORA_COMPONENT_META: Record<string, ComponentMetadata | undefined>;
92
88
  ZORA_THEME_RECIPE_META: Record<string, RecipeMetadata | undefined>;
93
89
  }
@@ -122,8 +118,8 @@ interface LoadedOwnerModule {
122
118
  const OWNER_RELEASES = {
123
119
  colorTheory: { packageName: '@ankhorage/color-theory', minimumVersion: '0.3.1' },
124
120
  contracts: { packageName: '@ankhorage/contracts', minimumVersion: '22.0.2' },
125
- templates: { packageName: '@ankhorage/templates', minimumVersion: '12.0.0' },
126
- zora: { packageName: '@ankhorage/zora', minimumVersion: '20.0.1' },
121
+ templates: { packageName: '@ankhorage/templates', minimumVersion: '12.0.3' },
122
+ zora: { packageName: '@ankhorage/zora', minimumVersion: '21.1.0' },
127
123
  };
128
124
 
129
125
  const OWNER_REQUIREMENTS = {
@@ -159,12 +155,7 @@ const OWNER_REQUIREMENTS = {
159
155
  zoraMetadata: {
160
156
  ...OWNER_RELEASES.zora,
161
157
  specifier: '@ankhorage/zora/metadata',
162
- exports: [
163
- 'composeZoraPluginMetadata',
164
- 'ZORA_COMPONENT_META',
165
- 'ZORA_CORE_PLUGIN_METADATA',
166
- 'ZORA_THEME_RECIPE_META',
167
- ],
158
+ exports: ['ZORA_COMPONENT_META', 'ZORA_THEME_RECIPE_META'],
168
159
  },
169
160
  };
170
161
 
@@ -180,112 +171,27 @@ export async function loadOwnerApis(targetDirectory = process.cwd()) {
180
171
  const templates = await loadOwnerModule(targetDirectory, OWNER_REQUIREMENTS.templates);
181
172
  const zoraTheme = await loadOwnerModule(targetDirectory, OWNER_REQUIREMENTS.zoraTheme);
182
173
  const zoraMetadata = await loadOwnerModule(targetDirectory, OWNER_REQUIREMENTS.zoraMetadata);
183
- const installedPluginMetadata = await loadInstalledZoraPluginMetadata(targetDirectory);
184
174
  assertColorTheoryApi(colorTheory.module);
185
175
  assertContractsApi(contracts.module);
186
176
  assertTemplatesApi(templates.module);
187
177
  assertZoraThemeApi(zoraTheme.module);
188
178
  assertZoraMetadataApi(zoraMetadata.module);
189
- const composedZoraMetadata = zoraMetadata.module.composeZoraPluginMetadata([
190
- zoraMetadata.module.ZORA_CORE_PLUGIN_METADATA,
191
- ...installedPluginMetadata.map((entry) => entry.metadata),
192
- ]);
193
- assertRecord(composedZoraMetadata, 'composed ZORA plugin metadata');
194
- assertRecord(composedZoraMetadata.componentMeta, 'composed ZORA component metadata');
195
179
 
196
180
  return {
197
181
  colorTheory: colorTheory.module,
198
182
  contracts: contracts.module,
199
183
  templates: templates.module,
200
184
  zoraTheme: zoraTheme.module,
201
- zoraMetadata: {
202
- ...zoraMetadata.module,
203
- ZORA_COMPONENT_META: composedZoraMetadata.componentMeta,
204
- },
185
+ zoraMetadata: zoraMetadata.module,
205
186
  versions: {
206
187
  colorTheory: colorTheory.version,
207
188
  contracts: contracts.version,
208
189
  templates: templates.version,
209
190
  zora: zoraTheme.version,
210
- plugins: Object.fromEntries(
211
- installedPluginMetadata.map((entry) => [entry.packageName, entry.version]),
212
- ),
213
191
  },
214
192
  };
215
193
  }
216
194
 
217
- /*** Load metadata-only descriptors for every installed ZORA plugin declared by the target package. */
218
- async function loadInstalledZoraPluginMetadata(
219
- targetDirectory: string,
220
- ): Promise<{ metadata: Record<string, unknown>; packageName: string; version: string }[]> {
221
- const targetManifestPath = join(resolve(targetDirectory), 'package.json');
222
- const targetManifest: unknown = JSON.parse(await readFile(targetManifestPath, 'utf8'));
223
- assertRecord(targetManifest, 'Target package manifest');
224
- const packageNames = new Set<string>();
225
- if (typeof targetManifest.name === 'string') packageNames.add(targetManifest.name);
226
- for (const field of ['dependencies', 'devDependencies', 'peerDependencies']) {
227
- const dependencies = targetManifest[field];
228
- if (!isRecord(dependencies)) continue;
229
- for (const packageName of Object.keys(dependencies)) packageNames.add(packageName);
230
- }
231
-
232
- const loaded: { metadata: Record<string, unknown>; packageName: string; version: string }[] = [];
233
- for (const packageName of [...packageNames].filter(isZoraPluginPackage).sort()) {
234
- const minimumVersion = resolvePluginMinimumVersion(targetManifest, packageName);
235
- const requirement: OwnerRequirement = {
236
- packageName,
237
- minimumVersion,
238
- specifier: `${packageName}/metadata`,
239
- exports: ['ZORA_PLUGIN_METADATA'],
240
- };
241
- const plugin = await loadOwnerModule(targetDirectory, requirement);
242
- const metadata = plugin.module.ZORA_PLUGIN_METADATA;
243
- assertRecord(metadata, `${packageName} ZORA plugin metadata`);
244
- loaded.push({ metadata, packageName, version: plugin.version });
245
- }
246
- return loaded;
247
- }
248
-
249
- function isZoraPluginPackage(packageName: string): boolean {
250
- return packageName.startsWith('@ankhorage/zora-') && packageName !== '@ankhorage/zora';
251
- }
252
-
253
- /*** Resolve one ZORA plugin minimum version from the target package declaration or owner package itself. */
254
- function resolvePluginMinimumVersion(
255
- targetManifest: Record<string, unknown>,
256
- packageName: string,
257
- ): string {
258
- if (targetManifest.name === packageName) {
259
- const { version } = targetManifest;
260
- if (typeof version === 'string' && parseVersion(version)[0] >= 0) return version;
261
- throw new Error(`ZORA plugin owner package ${packageName} must declare a semantic version.`);
262
- }
263
-
264
- for (const field of ['dependencies', 'devDependencies', 'peerDependencies']) {
265
- const dependencies = targetManifest[field];
266
- if (!isRecord(dependencies)) continue;
267
- const specifier = dependencies[packageName];
268
- if (typeof specifier === 'string') {
269
- return readPluginMinimumVersion(packageName, specifier);
270
- }
271
- }
272
-
273
- throw new Error(`ZORA plugin ${packageName} must be declared by the target package.`);
274
- }
275
-
276
- /*** Read the semantic lower bound from one supported published dependency specifier. */
277
- function readPluginMinimumVersion(packageName: string, specifier: string): string {
278
- const normalized = specifier.trim().replace(/^workspace:/u, '');
279
- const match = /^(?:\^|~|>=)?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)$/u.exec(normalized);
280
- const minimumVersion = match?.[1];
281
- if (minimumVersion === undefined) {
282
- throw new Error(
283
- `ZORA plugin ${packageName} must use an exact, caret, tilde, or >= semantic dependency range; found ${specifier}.`,
284
- );
285
- }
286
- return minimumVersion;
287
- }
288
-
289
195
  /*** Load only Contracts for tooling that runs before another owner package has been built. */
290
196
  export async function loadContractsApi(targetDirectory = process.cwd()): Promise<ContractsApi> {
291
197
  const loaded = await loadOwnerModule(targetDirectory, OWNER_REQUIREMENTS.contracts);
@@ -754,10 +660,6 @@ function assertZoraThemeApi(value: Record<string, unknown>): asserts value is Zo
754
660
 
755
661
  /*** Narrow released ZORA metadata into only the fields the orchestration needs. */
756
662
  function assertZoraMetadataApi(value: Record<string, unknown>): asserts value is ZoraMetadataApi {
757
- if (typeof value.composeZoraPluginMetadata !== 'function') {
758
- throw new Error('composeZoraPluginMetadata must be a function.');
759
- }
760
- assertRecord(value.ZORA_CORE_PLUGIN_METADATA, 'ZORA_CORE_PLUGIN_METADATA');
761
663
  assertRecord(value.ZORA_COMPONENT_META, 'ZORA_COMPONENT_META');
762
664
  for (const [name, metadata] of Object.entries(value.ZORA_COMPONENT_META)) {
763
665
  assertComponentMetadata(metadata, name);
@@ -3,4 +3,4 @@ export declare const TEMPLATES_FIXTURE_SOURCE: string;
3
3
  export declare const COLOR_THEORY_FIXTURE_SOURCE = "\nexport const COLOR_HARMONIES = ['monochromatic', 'complementary'];\nexport const COLOR_HARMONY_CATALOG = [\n { id: 'monochromatic', label: 'Monochromatic', description: 'One hue.' },\n { id: 'complementary', label: 'Complementary', description: 'Opposing hues.' },\n];\n";
4
4
  export declare const CONTRACTS_FIXTURE_SOURCE = "\nexport const APP_CATEGORIES = ['business_productivity'];\nexport const NAVIGATOR_TYPES = ['stack', 'tabs', 'drawer'];\n";
5
5
  export declare const ZORA_THEME_FIXTURE_SOURCE = "\nexport const compileZoraTheme = (themeConfig) => ({\n themeConfig,\n light: { surfaceTheme: { mode: 'light' }, diagnostics: [] },\n dark: { surfaceTheme: { mode: 'dark' }, diagnostics: [] },\n diagnostics: [],\n});\n";
6
- export declare const ZORA_METADATA_FIXTURE_SOURCE = "\nexport const ZORA_COMPONENT_META = {\n Screen: {\n name: 'Screen',\n category: 'layout',\n description: 'Screen layout root',\n directManifestNode: true,\n allowedChildren: ['View', 'Box', 'Text', 'MissingElement'],\n props: {},\n },\n View: {\n name: 'View',\n category: 'layout',\n directManifestNode: true,\n allowedChildren: ['Text', 'Box'],\n props: {},\n },\n Box: {\n name: 'Box',\n category: 'foundation',\n directManifestNode: true,\n allowedChildren: [],\n props: {},\n },\n Text: {\n name: 'Text',\n category: 'component',\n directManifestNode: true,\n allowedChildren: [],\n props: { text: { type: 'string' } },\n events: {\n press: {\n eventType: 'text.press',\n label: 'Press',\n description: 'Text was pressed.',\n },\n },\n },\n MissingElement: {\n name: 'MissingElement',\n category: 'pattern',\n directManifestNode: true,\n allowedChildren: [],\n manifestPolicy: { kind: 'unresolved-element', availability: 'draft-only', releaseGate: 'blocked' },\n blueprint: { defaultProps: { requestedCapability: 'Unresolved', reason: 'No exact element.' } },\n props: {\n requestedCapability: { type: 'string' },\n reason: { type: 'string' },\n evidenceId: { type: 'string' },\n },\n },\n};\nexport const ZORA_CORE_PLUGIN_METADATA = {\n packageName: '@ankhorage/zora',\n componentMeta: ZORA_COMPONENT_META,\n extensionHosts: ['Screen', 'View', 'Box'],\n};\nexport const composeZoraPluginMetadata = (plugins) => {\n const componentMeta = {};\n const extensionHosts = new Set();\n for (const plugin of [...plugins].sort((left, right) => left.packageName.localeCompare(right.packageName))) {\n Object.assign(componentMeta, plugin.componentMeta);\n for (const host of plugin.extensionHosts ?? []) extensionHosts.add(host);\n }\n for (const plugin of plugins) {\n for (const placement of plugin.placements ?? []) {\n for (const parent of placement.parents) {\n if (!extensionHosts.has(parent)) throw new Error('Invalid extension host');\n componentMeta[parent] = {\n ...componentMeta[parent],\n allowedChildren: [...componentMeta[parent].allowedChildren, placement.child],\n };\n }\n }\n }\n return { componentMeta };\n};\nexport const ZORA_THEME_RECIPE_META = {\n Card: {\n name: 'Card',\n kind: 'component',\n fields: { variant: { type: 'choice', options: ['filled', 'outlined'] } },\n },\n};\n";
6
+ export declare const ZORA_METADATA_FIXTURE_SOURCE = "\nexport const ZORA_COMPONENT_META = {\n Screen: {\n name: 'Screen',\n category: 'layout',\n description: 'Screen layout root',\n directManifestNode: true,\n allowedChildren: ['View', 'Box', 'Text', 'MissingElement'],\n props: {},\n },\n View: {\n name: 'View',\n category: 'layout',\n directManifestNode: true,\n allowedChildren: ['Text', 'Box'],\n props: {},\n },\n Box: {\n name: 'Box',\n category: 'foundation',\n directManifestNode: true,\n allowedChildren: [],\n props: {},\n },\n Text: {\n name: 'Text',\n category: 'component',\n directManifestNode: true,\n allowedChildren: [],\n props: { text: { type: 'string' } },\n events: {\n press: {\n eventType: 'text.press',\n label: 'Press',\n description: 'Text was pressed.',\n },\n },\n },\n MissingElement: {\n name: 'MissingElement',\n category: 'pattern',\n directManifestNode: true,\n allowedChildren: [],\n manifestPolicy: { kind: 'unresolved-element', availability: 'draft-only', releaseGate: 'blocked' },\n blueprint: { defaultProps: { requestedCapability: 'Unresolved', reason: 'No exact element.' } },\n props: {\n requestedCapability: { type: 'string' },\n reason: { type: 'string' },\n evidenceId: { type: 'string' },\n },\n },\n ChessBoard: {\n name: 'ChessBoard',\n category: 'component',\n directManifestNode: true,\n allowedChildren: [],\n props: {},\n },\n GameField: {\n name: 'GameField',\n category: 'component',\n directManifestNode: true,\n allowedChildren: [],\n props: {},\n },\n TabletopTable: {\n name: 'TabletopTable',\n category: 'component',\n directManifestNode: true,\n allowedChildren: [],\n props: {},\n },\n};\nexport const ZORA_THEME_RECIPE_META = {\n Card: {\n name: 'Card',\n kind: 'component',\n fields: { variant: { type: 'choice', options: ['filled', 'outlined'] } },\n },\n};\n";
@@ -130,31 +130,27 @@ export const ZORA_COMPONENT_META = {
130
130
  evidenceId: { type: 'string' },
131
131
  },
132
132
  },
133
- };
134
- export const ZORA_CORE_PLUGIN_METADATA = {
135
- packageName: '@ankhorage/zora',
136
- componentMeta: ZORA_COMPONENT_META,
137
- extensionHosts: ['Screen', 'View', 'Box'],
138
- };
139
- export const composeZoraPluginMetadata = (plugins) => {
140
- const componentMeta = {};
141
- const extensionHosts = new Set();
142
- for (const plugin of [...plugins].sort((left, right) => left.packageName.localeCompare(right.packageName))) {
143
- Object.assign(componentMeta, plugin.componentMeta);
144
- for (const host of plugin.extensionHosts ?? []) extensionHosts.add(host);
145
- }
146
- for (const plugin of plugins) {
147
- for (const placement of plugin.placements ?? []) {
148
- for (const parent of placement.parents) {
149
- if (!extensionHosts.has(parent)) throw new Error('Invalid extension host');
150
- componentMeta[parent] = {
151
- ...componentMeta[parent],
152
- allowedChildren: [...componentMeta[parent].allowedChildren, placement.child],
153
- };
154
- }
155
- }
156
- }
157
- return { componentMeta };
133
+ ChessBoard: {
134
+ name: 'ChessBoard',
135
+ category: 'component',
136
+ directManifestNode: true,
137
+ allowedChildren: [],
138
+ props: {},
139
+ },
140
+ GameField: {
141
+ name: 'GameField',
142
+ category: 'component',
143
+ directManifestNode: true,
144
+ allowedChildren: [],
145
+ props: {},
146
+ },
147
+ TabletopTable: {
148
+ name: 'TabletopTable',
149
+ category: 'component',
150
+ directManifestNode: true,
151
+ allowedChildren: [],
152
+ props: {},
153
+ },
158
154
  };
159
155
  export const ZORA_THEME_RECIPE_META = {
160
156
  Card: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ankhorage/devtools",
3
- "version": "2.0.11",
3
+ "version": "2.0.13",
4
4
  "description": "Shared tooling, repository automation, and agent standards for Ankhorage TypeScript projects",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/ankhorage/devtools#readme",
@@ -121,7 +121,7 @@
121
121
  "test:standalone": "bun test src/tools/agents/index.test.ts src/tools/shared/managedFiles.test.ts"
122
122
  },
123
123
  "dependencies": {
124
- "@ankhorage/apm": "^0.8.10",
124
+ "@ankhorage/apm": "^0.8.11",
125
125
  "@ankhorage/project-detector": "^0.3.2",
126
126
  "@ankhorage/utility": "^0.5.5",
127
127
  "@changesets/cli": "^3.0.3",
@@ -146,9 +146,9 @@
146
146
  "@ankhorage/policy": "^0.6.0"
147
147
  },
148
148
  "devDependencies": {
149
- "@ankhorage/paradox": "^0.2.6",
149
+ "@ankhorage/paradox": "^0.2.7",
150
150
  "@ankhorage/ankh": "^0.10.4",
151
- "@ankhorage/doctor": "0.11.14",
151
+ "@ankhorage/doctor": "0.11.15",
152
152
  "@techstark/opencv-js": "^5.0.0-release.1",
153
153
  "@types/bun": "^1.4.2",
154
154
  "@types/node": "^26.6.3",