@ankhorage/devtools 1.10.12 → 1.10.14
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/dist/tools/skills/assets/zora-designer/SKILL.md +2 -2
- package/dist/tools/skills/assets/zora-designer/references/artifact.md +1 -1
- package/dist/tools/skills/assets/zora-designer/references/audit.md +2 -2
- package/dist/tools/skills/assets/zora-designer/references/screens.md +1 -1
- package/dist/tools/skills/assets/zora-designer/references/workflow.md +2 -2
- package/dist/tools/skills/assets/zora-designer/scripts/{audit.mjs → audit.ts} +280 -49
- package/dist/tools/skills/assets/zora-designer/scripts/{generate-template-catalog.mjs → generate-template-catalog.ts} +15 -7
- package/dist/tools/skills/assets/zora-designer/scripts/{owner-api.mjs → owner-api.ts} +359 -52
- package/dist/tools/skills/assets/zora-designer/scripts/{scaffold-template.mjs → scaffold-template.ts} +27 -21
- package/package.json +1 -1
|
@@ -4,46 +4,52 @@ import { access, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
|
|
|
4
4
|
import { join, relative, resolve, sep } from 'node:path';
|
|
5
5
|
import { pathToFileURL } from 'node:url';
|
|
6
6
|
|
|
7
|
-
import { generateTemplateCatalog } from './generate-template-catalog.
|
|
8
|
-
import { loadOwnerApis } from './owner-api.
|
|
7
|
+
import { generateTemplateCatalog } from './generate-template-catalog.ts';
|
|
8
|
+
import { loadOwnerApis } from './owner-api.ts';
|
|
9
9
|
|
|
10
10
|
/*** Scaffold one complete portable template and refresh filesystem discovery. */
|
|
11
|
-
export async function scaffoldTemplate(input) {
|
|
11
|
+
export async function scaffoldTemplate(input: unknown) {
|
|
12
12
|
assertRecord(input, 'Scaffold input');
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
assertNonEmptyString(input.targetDirectory, 'targetDirectory');
|
|
14
|
+
assertNonEmptyString(input.category, 'category');
|
|
15
|
+
assertNonEmptyString(input.slug, 'slug');
|
|
16
|
+
const { category, slug, targetDirectory: inputTargetDirectory } = input;
|
|
17
|
+
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/u.test(slug)) {
|
|
17
18
|
throw new Error('slug must be a kebab-case identifier.');
|
|
18
19
|
}
|
|
19
20
|
assertRecord(input.manifest, 'manifest');
|
|
21
|
+
const { manifest: inputManifest } = input;
|
|
20
22
|
|
|
21
|
-
const targetDirectory = resolve(
|
|
22
|
-
const packageManifest = JSON.parse(
|
|
23
|
+
const targetDirectory = resolve(inputTargetDirectory);
|
|
24
|
+
const packageManifest: unknown = JSON.parse(
|
|
25
|
+
await readFile(join(targetDirectory, 'package.json'), 'utf8'),
|
|
26
|
+
);
|
|
27
|
+
assertRecord(packageManifest, 'Target package manifest');
|
|
23
28
|
if (packageManifest.name !== '@ankhorage/templates') {
|
|
24
29
|
throw new Error(
|
|
25
30
|
'Template scaffolding is available only in the @ankhorage/templates repository.',
|
|
26
31
|
);
|
|
27
32
|
}
|
|
28
|
-
|
|
33
|
+
assertRecord(inputManifest.metadata, 'manifest.metadata');
|
|
34
|
+
if (inputManifest.metadata.category !== category) {
|
|
29
35
|
throw new Error('Scaffold category must match manifest.metadata.category.');
|
|
30
36
|
}
|
|
31
|
-
if (
|
|
37
|
+
if (inputManifest.metadata.slug !== slug) {
|
|
32
38
|
throw new Error('Scaffold slug must match manifest.metadata.slug.');
|
|
33
39
|
}
|
|
34
40
|
|
|
35
41
|
const owners = await loadOwnerApis(targetDirectory);
|
|
36
|
-
const composition = owners.templates.validateTemplateManifest(
|
|
42
|
+
const composition = owners.templates.validateTemplateManifest(inputManifest, 'release');
|
|
37
43
|
const manifest = owners.templates.assertTemplateManifestReady(composition);
|
|
38
44
|
|
|
39
45
|
const categoryDirectory = resolve(
|
|
40
46
|
targetDirectory,
|
|
41
47
|
'src/templates/categories',
|
|
42
|
-
|
|
48
|
+
category.replaceAll('_', '-'),
|
|
43
49
|
);
|
|
44
50
|
assertInside(targetDirectory, categoryDirectory);
|
|
45
51
|
|
|
46
|
-
const templateDirectory = resolve(categoryDirectory,
|
|
52
|
+
const templateDirectory = resolve(categoryDirectory, slug);
|
|
47
53
|
assertInside(categoryDirectory, templateDirectory);
|
|
48
54
|
if (await pathExists(templateDirectory)) {
|
|
49
55
|
throw new Error(
|
|
@@ -75,7 +81,7 @@ export async function scaffoldTemplate(input) {
|
|
|
75
81
|
}
|
|
76
82
|
|
|
77
83
|
/*** Serialize one complete manifest as the template's canonical default export. */
|
|
78
|
-
function createManifestSource(manifest) {
|
|
84
|
+
function createManifestSource(manifest: Record<string, unknown>): string {
|
|
79
85
|
return `import type { AppManifest } from '@ankhorage/contracts';
|
|
80
86
|
|
|
81
87
|
const manifest = ${JSON.stringify(manifest, null, 2)} satisfies AppManifest;
|
|
@@ -88,7 +94,7 @@ export default function createAppManifest(): AppManifest {
|
|
|
88
94
|
}
|
|
89
95
|
|
|
90
96
|
/*** Assert that a resolved output remains inside its declared owner directory. */
|
|
91
|
-
function assertInside(parentPath, childPath) {
|
|
97
|
+
function assertInside(parentPath: string, childPath: string): void {
|
|
92
98
|
const relativePath = relative(parentPath, childPath);
|
|
93
99
|
if (
|
|
94
100
|
relativePath === '' ||
|
|
@@ -101,7 +107,7 @@ function assertInside(parentPath, childPath) {
|
|
|
101
107
|
}
|
|
102
108
|
|
|
103
109
|
/*** Return whether a filesystem path exists. */
|
|
104
|
-
async function pathExists(filePath) {
|
|
110
|
+
async function pathExists(filePath: string): Promise<boolean> {
|
|
105
111
|
try {
|
|
106
112
|
await access(filePath);
|
|
107
113
|
return true;
|
|
@@ -111,14 +117,14 @@ async function pathExists(filePath) {
|
|
|
111
117
|
}
|
|
112
118
|
|
|
113
119
|
/*** Require a non-array object input. */
|
|
114
|
-
function assertRecord(value, label) {
|
|
120
|
+
function assertRecord(value: unknown, label: string): asserts value is Record<string, unknown> {
|
|
115
121
|
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
116
122
|
throw new Error(`${label} must be an object.`);
|
|
117
123
|
}
|
|
118
124
|
}
|
|
119
125
|
|
|
120
126
|
/*** Require a non-empty string input field. */
|
|
121
|
-
function assertNonEmptyString(value, label) {
|
|
127
|
+
function assertNonEmptyString(value: unknown, label: string): asserts value is string {
|
|
122
128
|
if (typeof value !== 'string' || value.trim() === '') {
|
|
123
129
|
throw new Error(`${label} must be a non-empty string.`);
|
|
124
130
|
}
|
|
@@ -128,9 +134,9 @@ function assertNonEmptyString(value, label) {
|
|
|
128
134
|
async function main() {
|
|
129
135
|
const [inputPath] = process.argv.slice(2);
|
|
130
136
|
if (!inputPath) {
|
|
131
|
-
throw new Error('Usage: scaffold-template.
|
|
137
|
+
throw new Error('Usage: scaffold-template.ts <scaffold-input.json>');
|
|
132
138
|
}
|
|
133
|
-
const input = JSON.parse(await readFile(resolve(inputPath), 'utf8'));
|
|
139
|
+
const input: unknown = JSON.parse(await readFile(resolve(inputPath), 'utf8'));
|
|
134
140
|
console.log(JSON.stringify(await scaffoldTemplate(input), null, 2));
|
|
135
141
|
}
|
|
136
142
|
|
package/package.json
CHANGED