aub-workspace 0.3.0
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/LICENSE +201 -0
- package/README.md +23 -0
- package/bin/aub-workspace.mjs +246 -0
- package/package.json +32 -0
- package/vendor/aub/apps/editor/dist/assets/_commonjs-dynamic-modules-TDtrdbi3.js +1 -0
- package/vendor/aub/apps/editor/dist/assets/angular-importer.lib-dB_jK4mR.js +32 -0
- package/vendor/aub/apps/editor/dist/assets/canvas-tools-CuYC7cA2.js +364 -0
- package/vendor/aub/apps/editor/dist/assets/design-bridge.lib-DJvaK6AX.js +1 -0
- package/vendor/aub/apps/editor/dist/assets/export-agent-prompt.lib-BsP0KNqo.js +2 -0
- package/vendor/aub/apps/editor/dist/assets/export-md.lib-DdmdeWgO.js +3 -0
- package/vendor/aub/apps/editor/dist/assets/handoff-package.lib-DDYpcEma.js +20 -0
- package/vendor/aub/apps/editor/dist/assets/implementation-report.lib-CmsSB_8s.js +1 -0
- package/vendor/aub/apps/editor/dist/assets/index-BCH-ek3h.js +2 -0
- package/vendor/aub/apps/editor/dist/assets/index-lAnc928Q.css +1 -0
- package/vendor/aub/apps/editor/dist/assets/index-vt1nM1M4.js +507 -0
- package/vendor/aub/apps/editor/dist/assets/jszip.min-CRfXyL92.js +12 -0
- package/vendor/aub/apps/editor/dist/assets/react-vendor-ByX9Pqse.js +40 -0
- package/vendor/aub/apps/editor/dist/brand/android-chrome-192x192.png +0 -0
- package/vendor/aub/apps/editor/dist/brand/android-chrome-512x512.png +0 -0
- package/vendor/aub/apps/editor/dist/brand/app-icon-1024.png +0 -0
- package/vendor/aub/apps/editor/dist/brand/app-icon-192.png +0 -0
- package/vendor/aub/apps/editor/dist/brand/app-icon-512.png +0 -0
- package/vendor/aub/apps/editor/dist/brand/apple-touch-icon.png +0 -0
- package/vendor/aub/apps/editor/dist/brand/aub-logo-mark.svg +28 -0
- package/vendor/aub/apps/editor/dist/brand/favicon-16x16.png +0 -0
- package/vendor/aub/apps/editor/dist/brand/favicon-32x32.png +0 -0
- package/vendor/aub/apps/editor/dist/brand/favicon-48x48.png +0 -0
- package/vendor/aub/apps/editor/dist/brand/favicon.ico +0 -0
- package/vendor/aub/apps/editor/dist/brand/favicon.svg +9 -0
- package/vendor/aub/apps/editor/dist/brand/maskable-icon-512.png +0 -0
- package/vendor/aub/apps/editor/dist/brand/mstile-150x150.png +0 -0
- package/vendor/aub/apps/editor/dist/brand/safari-pinned-tab.svg +8 -0
- package/vendor/aub/apps/editor/dist/browserconfig.xml +9 -0
- package/vendor/aub/apps/editor/dist/index.html +22 -0
- package/vendor/aub/apps/editor/dist/manifest.webmanifest +28 -0
- package/vendor/aub/apps/editor/dist/template-previews/admin-table.png +0 -0
- package/vendor/aub/apps/editor/dist/template-previews/booking.png +0 -0
- package/vendor/aub/apps/editor/dist/template-previews/calendar.png +0 -0
- package/vendor/aub/apps/editor/dist/template-previews/catalog.png +0 -0
- package/vendor/aub/apps/editor/dist/template-previews/chat.png +0 -0
- package/vendor/aub/apps/editor/dist/template-previews/checkout.png +0 -0
- package/vendor/aub/apps/editor/dist/template-previews/crm.png +0 -0
- package/vendor/aub/apps/editor/dist/template-previews/dashboard.png +0 -0
- package/vendor/aub/apps/editor/dist/template-previews/feed.png +0 -0
- package/vendor/aub/apps/editor/dist/template-previews/files.png +0 -0
- package/vendor/aub/apps/editor/dist/template-previews/kanban.png +0 -0
- package/vendor/aub/apps/editor/dist/template-previews/landing.png +0 -0
- package/vendor/aub/apps/editor/dist/template-previews/mail.png +0 -0
- package/vendor/aub/apps/editor/dist/template-previews/onboarding.png +0 -0
- package/vendor/aub/apps/editor/dist/template-previews/pricing.png +0 -0
- package/vendor/aub/apps/editor/dist/template-previews/product-detail.png +0 -0
- package/vendor/aub/apps/editor/dist/template-previews/settings.png +0 -0
- package/vendor/aub/apps/editor/dist/template-previews/wiki.png +0 -0
- package/vendor/aub/apps/mcp-server/dist/aub.js +15 -0
- package/vendor/aub/apps/mcp-server/dist/context.js +1 -0
- package/vendor/aub/apps/mcp-server/dist/http.js +123 -0
- package/vendor/aub/apps/mcp-server/dist/index.js +23 -0
- package/vendor/aub/apps/mcp-server/dist/repo.js +17 -0
- package/vendor/aub/apps/mcp-server/dist/schema.js +42 -0
- package/vendor/aub/apps/mcp-server/dist/server.js +80 -0
- package/vendor/aub/apps/mcp-server/dist/tools/approve-component-candidate.js +27 -0
- package/vendor/aub/apps/mcp-server/dist/tools/diff-blueprints.js +27 -0
- package/vendor/aub/apps/mcp-server/dist/tools/export-handoff.js +87 -0
- package/vendor/aub/apps/mcp-server/dist/tools/export-prompt.js +35 -0
- package/vendor/aub/apps/mcp-server/dist/tools/export-template-authoring-prompt.js +13 -0
- package/vendor/aub/apps/mcp-server/dist/tools/generate-template-from-source.js +25 -0
- package/vendor/aub/apps/mcp-server/dist/tools/get-aub-session.js +13 -0
- package/vendor/aub/apps/mcp-server/dist/tools/get-blueprint.js +28 -0
- package/vendor/aub/apps/mcp-server/dist/tools/get-project.js +45 -0
- package/vendor/aub/apps/mcp-server/dist/tools/get-workspace-status.js +10 -0
- package/vendor/aub/apps/mcp-server/dist/tools/import-design-bridge.js +62 -0
- package/vendor/aub/apps/mcp-server/dist/tools/list-blueprints.js +11 -0
- package/vendor/aub/apps/mcp-server/dist/tools/list-projects.js +11 -0
- package/vendor/aub/apps/mcp-server/dist/tools/lock-blueprint.js +33 -0
- package/vendor/aub/apps/mcp-server/dist/tools/migrate-blueprint.js +38 -0
- package/vendor/aub/apps/mcp-server/dist/tools/resolve-component.js +51 -0
- package/vendor/aub/apps/mcp-server/dist/tools/scaffold-blueprint.js +53 -0
- package/vendor/aub/apps/mcp-server/dist/tools/scan-project-ui.js +18 -0
- package/vendor/aub/apps/mcp-server/dist/tools/submit-report.js +48 -0
- package/vendor/aub/apps/mcp-server/dist/tools/update-aub-session.js +14 -0
- package/vendor/aub/apps/mcp-server/dist/tools/validate-blueprint.js +67 -0
- package/vendor/aub/apps/mcp-server/dist/tools/validate-project.js +74 -0
- package/vendor/aub/apps/mcp-server/dist/tools/write-blueprint.js +72 -0
- package/vendor/aub/apps/mcp-server/dist/workspace.js +138 -0
- package/vendor/aub/docs/agent-handoff.md +85 -0
- package/vendor/aub/docs/agent-handoff.zh-Hant.md +85 -0
- package/vendor/aub/docs/template-authoring-agent.md +86 -0
- package/vendor/aub/schema/aub-ci.schema.json +34 -0
- package/vendor/aub/schema/aub.registry.schema.json +118 -0
- package/vendor/aub/schema/design-bridge.schema.json +44 -0
- package/vendor/aub/schema/implementation-report.schema.json +93 -0
- package/vendor/aub/schema/project-types.ts +72 -0
- package/vendor/aub/schema/registry/components.json +118 -0
- package/vendor/aub/schema/types.js +13 -0
- package/vendor/aub/schema/types.ts +348 -0
- package/vendor/aub/schema/ui-blueprint-lock.schema.json +61 -0
- package/vendor/aub/schema/ui-blueprint.schema.json +1339 -0
- package/vendor/aub/schema/ui-project.schema.json +139 -0
- package/vendor/aub/scripts/agent-implementation-benchmark.lib.mjs +125 -0
- package/vendor/aub/scripts/angular-importer.lib.mjs +982 -0
- package/vendor/aub/scripts/check-editor-bundle-budget.mjs +36 -0
- package/vendor/aub/scripts/ci-verify.lib.mjs +256 -0
- package/vendor/aub/scripts/ci-verify.mjs +45 -0
- package/vendor/aub/scripts/create-authoring-kit.mjs +84 -0
- package/vendor/aub/scripts/create-implementation-report.mjs +24 -0
- package/vendor/aub/scripts/design-bridge.lib.d.mts +32 -0
- package/vendor/aub/scripts/design-bridge.lib.mjs +69 -0
- package/vendor/aub/scripts/diff-blueprint.lib.d.mts +18 -0
- package/vendor/aub/scripts/diff-blueprint.lib.mjs +148 -0
- package/vendor/aub/scripts/diff-blueprint.mjs +25 -0
- package/vendor/aub/scripts/export-agent-prompt.lib.d.mts +10 -0
- package/vendor/aub/scripts/export-agent-prompt.lib.mjs +160 -0
- package/vendor/aub/scripts/export-agent-prompt.mjs +79 -0
- package/vendor/aub/scripts/export-md.lib.d.mts +3 -0
- package/vendor/aub/scripts/export-md.lib.mjs +302 -0
- package/vendor/aub/scripts/export-md.mjs +43 -0
- package/vendor/aub/scripts/generate-registry-artifacts.lib.mjs +118 -0
- package/vendor/aub/scripts/generate-registry-artifacts.mjs +65 -0
- package/vendor/aub/scripts/generate-site-locales.mjs +545 -0
- package/vendor/aub/scripts/handoff-package.lib.d.mts +20 -0
- package/vendor/aub/scripts/handoff-package.lib.mjs +111 -0
- package/vendor/aub/scripts/implementation-report.lib.d.mts +21 -0
- package/vendor/aub/scripts/implementation-report.lib.mjs +97 -0
- package/vendor/aub/scripts/import-angular-component.mjs +72 -0
- package/vendor/aub/scripts/import-design-bridge.mjs +59 -0
- package/vendor/aub/scripts/lock-blueprint.lib.d.mts +23 -0
- package/vendor/aub/scripts/lock-blueprint.lib.mjs +58 -0
- package/vendor/aub/scripts/lock-blueprint.mjs +36 -0
- package/vendor/aub/scripts/migrate-blueprint-cli.mjs +28 -0
- package/vendor/aub/scripts/migrate-blueprint.d.mts +5 -0
- package/vendor/aub/scripts/migrate-blueprint.mjs +95 -0
- package/vendor/aub/scripts/package-workspace-cli.mjs +34 -0
- package/vendor/aub/scripts/project.lib.d.mts +44 -0
- package/vendor/aub/scripts/project.lib.mjs +175 -0
- package/vendor/aub/scripts/project.mjs +332 -0
- package/vendor/aub/scripts/registry.lib.d.mts +52 -0
- package/vendor/aub/scripts/registry.lib.mjs +222 -0
- package/vendor/aub/scripts/run-agent-implementation.mjs +423 -0
- package/vendor/aub/scripts/run-agent-readability.mjs +145 -0
- package/vendor/aub/scripts/run-ollama-prompt.mjs +30 -0
- package/vendor/aub/scripts/scaffold-blueprint.lib.d.mts +38 -0
- package/vendor/aub/scripts/scaffold-blueprint.lib.mjs +316 -0
- package/vendor/aub/scripts/scaffold-blueprint.mjs +86 -0
- package/vendor/aub/scripts/score-agent-implementation.mjs +27 -0
- package/vendor/aub/scripts/score-agent-readability.mjs +54 -0
- package/vendor/aub/scripts/sync-brand-assets.mjs +33 -0
- package/vendor/aub/scripts/validate-blueprint.lib.d.mts +14 -0
- package/vendor/aub/scripts/validate-blueprint.lib.mjs +136 -0
- package/vendor/aub/scripts/validate.mjs +128 -0
- package/vendor/aub/scripts/verify-implementation-report.mjs +36 -0
- package/vendor/aub/scripts/workspace-loop.lib.d.mts +17 -0
- package/vendor/aub/scripts/workspace-loop.lib.mjs +674 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { buildKnownTypes, importDesignBridge, validateBlueprintSemantics, } from '../aub.js';
|
|
5
|
+
import { formatAjvErrors } from '../schema.js';
|
|
6
|
+
import { resolveWorkspacePath } from '../workspace.js';
|
|
7
|
+
export const name = 'import_design_bridge';
|
|
8
|
+
const inputSchema = {
|
|
9
|
+
path: z
|
|
10
|
+
.string()
|
|
11
|
+
.optional()
|
|
12
|
+
.describe('Path inside the workspace to a Figma/Penpot .aub.bridge.json document.'),
|
|
13
|
+
bridge: z
|
|
14
|
+
.record(z.any())
|
|
15
|
+
.optional()
|
|
16
|
+
.describe('Inline Design Bridge document instead of a workspace file.'),
|
|
17
|
+
registry: z
|
|
18
|
+
.string()
|
|
19
|
+
.optional()
|
|
20
|
+
.describe('Optional aub.registry.json path for custom component validation.'),
|
|
21
|
+
};
|
|
22
|
+
export const config = {
|
|
23
|
+
title: 'Import Design Bridge',
|
|
24
|
+
description: 'Import a vendor-neutral Figma/Penpot Design Bridge into a validated AUB Blueprint. The bridge must explicitly map every semantic node; this tool does not guess component types.',
|
|
25
|
+
inputSchema,
|
|
26
|
+
};
|
|
27
|
+
export async function run(ctx, args) {
|
|
28
|
+
if (!args.path && !args.bridge)
|
|
29
|
+
throw new Error('Provide either "path" or inline "bridge".');
|
|
30
|
+
if (args.path && args.bridge)
|
|
31
|
+
throw new Error('Provide only one of "path" or "bridge".');
|
|
32
|
+
const bridgePath = args.path ? resolveWorkspacePath(ctx.root, args.path) : null;
|
|
33
|
+
const bridge = bridgePath ? JSON.parse(await readFile(bridgePath, 'utf8')) : args.bridge;
|
|
34
|
+
const bridgeOk = ctx.validators.validateDesignBridge(bridge);
|
|
35
|
+
if (!bridgeOk) {
|
|
36
|
+
throw new Error(`Design Bridge validation failed:\n${formatAjvErrors(ctx.validators.validateDesignBridge)
|
|
37
|
+
.map((item) => `- ${item}`)
|
|
38
|
+
.join('\n')}`);
|
|
39
|
+
}
|
|
40
|
+
const result = importDesignBridge(bridge);
|
|
41
|
+
const schemaOk = ctx.validators.validateBlueprint(result.blueprint);
|
|
42
|
+
const schemaErrors = schemaOk ? [] : formatAjvErrors(ctx.validators.validateBlueprint);
|
|
43
|
+
const knownTypes = await buildKnownTypes({
|
|
44
|
+
extensionPath: args.registry ? resolveWorkspacePath(ctx.root, args.registry) : null,
|
|
45
|
+
startDir: bridgePath ? dirname(bridgePath) : ctx.root,
|
|
46
|
+
});
|
|
47
|
+
const semanticErrors = schemaOk
|
|
48
|
+
? validateBlueprintSemantics(result.blueprint, { knownTypes: knownTypes.knownTypes })
|
|
49
|
+
: [];
|
|
50
|
+
if (!schemaOk || semanticErrors.length > 0) {
|
|
51
|
+
throw new Error(`Imported Blueprint validation failed:\n${[...schemaErrors, ...semanticErrors]
|
|
52
|
+
.map((item) => `- ${item}`)
|
|
53
|
+
.join('\n')}`);
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
source: args.path ?? 'inline',
|
|
57
|
+
designSource: result.source,
|
|
58
|
+
extensionRegistry: knownTypes.extensionPath,
|
|
59
|
+
sourceMap: result.sourceMap,
|
|
60
|
+
blueprint: result.blueprint,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { listBlueprints } from '../workspace.js';
|
|
2
|
+
export const name = 'list_blueprints';
|
|
3
|
+
export const config = {
|
|
4
|
+
title: 'List Blueprints',
|
|
5
|
+
description: 'Scan the AUB workspace root and return every UI Blueprint file (.ui.json / .ui.yaml) with its screen id, name, and version.',
|
|
6
|
+
inputSchema: {},
|
|
7
|
+
};
|
|
8
|
+
export async function run(ctx) {
|
|
9
|
+
const blueprints = await listBlueprints(ctx.root);
|
|
10
|
+
return { root: ctx.root, count: blueprints.length, blueprints };
|
|
11
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { listProjects } from '../workspace.js';
|
|
2
|
+
export const name = 'list_projects';
|
|
3
|
+
export const config = {
|
|
4
|
+
title: 'List Projects',
|
|
5
|
+
description: 'Scan the AUB workspace root and return every multi-screen project file (.aub.project.json / .aub.project.yaml) with its id, name, and screen count.',
|
|
6
|
+
inputSchema: {},
|
|
7
|
+
};
|
|
8
|
+
export async function run(ctx) {
|
|
9
|
+
const projects = await listProjects(ctx.root);
|
|
10
|
+
return { root: ctx.root, count: projects.length, projects };
|
|
11
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { resolveBlueprint } from '../workspace.js';
|
|
3
|
+
import { createBlueprintLock } from '../aub.js';
|
|
4
|
+
export const name = 'lock_blueprint';
|
|
5
|
+
const inputSchema = {
|
|
6
|
+
ref: z.string().optional().describe('Blueprint file path or screen id to lock.'),
|
|
7
|
+
blueprint: z.record(z.any()).optional().describe('Inline Blueprint object to lock.'),
|
|
8
|
+
};
|
|
9
|
+
export const config = {
|
|
10
|
+
title: 'Lock Blueprint',
|
|
11
|
+
description: 'Create a deterministic acceptance lock snapshot with structural SHA-256 hashes. Returns the lock object without writing files.',
|
|
12
|
+
inputSchema,
|
|
13
|
+
};
|
|
14
|
+
export async function run(ctx, args) {
|
|
15
|
+
let blueprint;
|
|
16
|
+
let source;
|
|
17
|
+
if (args.blueprint) {
|
|
18
|
+
blueprint = args.blueprint;
|
|
19
|
+
source = 'inline';
|
|
20
|
+
}
|
|
21
|
+
else if (args.ref) {
|
|
22
|
+
const resolved = await resolveBlueprint(ctx.root, args.ref);
|
|
23
|
+
blueprint = resolved.blueprint;
|
|
24
|
+
source = resolved.entry.path;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
throw new Error('Provide either "ref" or "blueprint".');
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
source,
|
|
31
|
+
lock: createBlueprintLock(blueprint, { sourceFile: source }),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { resolveBlueprint } from '../workspace.js';
|
|
3
|
+
import { migrateBlueprint } from '../aub.js';
|
|
4
|
+
export const name = 'migrate_blueprint';
|
|
5
|
+
const inputSchema = {
|
|
6
|
+
ref: z.string().optional().describe('Blueprint file path or screen id to migrate.'),
|
|
7
|
+
blueprint: z.record(z.any()).optional().describe('Inline Blueprint object to migrate.'),
|
|
8
|
+
};
|
|
9
|
+
export const config = {
|
|
10
|
+
title: 'Migrate Blueprint',
|
|
11
|
+
description: 'Migrate a v0.1 or v0.2 Blueprint to the current schema version. Returns the migrated object without writing files.',
|
|
12
|
+
inputSchema,
|
|
13
|
+
};
|
|
14
|
+
export async function run(ctx, args) {
|
|
15
|
+
let blueprint;
|
|
16
|
+
let source;
|
|
17
|
+
if (args.blueprint) {
|
|
18
|
+
blueprint = args.blueprint;
|
|
19
|
+
source = 'inline';
|
|
20
|
+
}
|
|
21
|
+
else if (args.ref) {
|
|
22
|
+
const resolved = await resolveBlueprint(ctx.root, args.ref);
|
|
23
|
+
blueprint = resolved.blueprint;
|
|
24
|
+
source = resolved.entry.path;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
throw new Error('Provide either "ref" or "blueprint".');
|
|
28
|
+
}
|
|
29
|
+
const fromVersion = blueprint.version ?? '0.1.0';
|
|
30
|
+
const migrated = migrateBlueprint(blueprint);
|
|
31
|
+
return {
|
|
32
|
+
source,
|
|
33
|
+
fromVersion,
|
|
34
|
+
toVersion: migrated.version,
|
|
35
|
+
changed: fromVersion !== migrated.version,
|
|
36
|
+
blueprint: migrated,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { buildKnownTypes } from '../aub.js';
|
|
4
|
+
export const name = 'resolve_component';
|
|
5
|
+
const inputSchema = {
|
|
6
|
+
type: z
|
|
7
|
+
.string()
|
|
8
|
+
.describe('Core or namespaced component type to resolve, for example button or acme:insight_card.'),
|
|
9
|
+
registry: z
|
|
10
|
+
.string()
|
|
11
|
+
.optional()
|
|
12
|
+
.describe('Optional path to aub.registry.json. Defaults to auto-discovery from the workspace root.'),
|
|
13
|
+
implementation: z
|
|
14
|
+
.string()
|
|
15
|
+
.optional()
|
|
16
|
+
.describe('Optional implementation id to select, for example react or angular.'),
|
|
17
|
+
};
|
|
18
|
+
export const config = {
|
|
19
|
+
title: 'Resolve Component',
|
|
20
|
+
description: 'Resolve a semantic component type to its container behavior, description, and production implementation mappings. Use this before creating a bespoke component.',
|
|
21
|
+
inputSchema,
|
|
22
|
+
};
|
|
23
|
+
export async function run(ctx, args) {
|
|
24
|
+
if (!args.type?.trim()) {
|
|
25
|
+
throw new Error('Provide a component "type".');
|
|
26
|
+
}
|
|
27
|
+
const resolved = await buildKnownTypes({
|
|
28
|
+
extensionPath: args.registry ? resolve(ctx.root, args.registry) : null,
|
|
29
|
+
startDir: ctx.root,
|
|
30
|
+
});
|
|
31
|
+
const metadata = resolved.knownTypes.get(args.type);
|
|
32
|
+
if (!metadata) {
|
|
33
|
+
throw new Error(`Unknown component type "${args.type}".`);
|
|
34
|
+
}
|
|
35
|
+
const implementations = metadata.implementations ?? [];
|
|
36
|
+
const selected = args.implementation
|
|
37
|
+
? implementations.find((item) => item.id === args.implementation)
|
|
38
|
+
: undefined;
|
|
39
|
+
if (args.implementation && !selected) {
|
|
40
|
+
throw new Error(`Component "${args.type}" has no implementation "${args.implementation}". Available: ${implementations.map((item) => item.id).join(', ') || 'none'}.`);
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
type: args.type,
|
|
44
|
+
source: metadata.source,
|
|
45
|
+
isContainer: metadata.isContainer,
|
|
46
|
+
description: metadata.description ?? '',
|
|
47
|
+
extensionRegistry: resolved.extensionPath,
|
|
48
|
+
implementations,
|
|
49
|
+
selectedImplementation: selected ?? null,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { resolveBlueprint } from '../workspace.js';
|
|
3
|
+
import { scaffoldBlueprint, SCAFFOLD_SECTIONS } from '../aub.js';
|
|
4
|
+
export const name = 'scaffold_blueprint';
|
|
5
|
+
const inputSchema = {
|
|
6
|
+
ref: z
|
|
7
|
+
.string()
|
|
8
|
+
.optional()
|
|
9
|
+
.describe('Blueprint file path or screen id to load and scaffold.'),
|
|
10
|
+
blueprint: z
|
|
11
|
+
.record(z.any())
|
|
12
|
+
.optional()
|
|
13
|
+
.describe('Inline Blueprint object to scaffold instead of loading from disk.'),
|
|
14
|
+
sections: z
|
|
15
|
+
.array(z.enum(['interactions', 'responsive', 'acceptance']))
|
|
16
|
+
.optional()
|
|
17
|
+
.describe('Which spec sections to scaffold. Defaults to all three.'),
|
|
18
|
+
language: z
|
|
19
|
+
.enum(['en', 'zh-Hant'])
|
|
20
|
+
.optional()
|
|
21
|
+
.describe('Language for generated statements. Defaults to en.'),
|
|
22
|
+
};
|
|
23
|
+
export const config = {
|
|
24
|
+
title: 'Scaffold Blueprint',
|
|
25
|
+
description: 'Deterministically derive missing interactions, responsive rules, and acceptance criteria from the existing node tree and viewports. Non-destructive: existing entries are preserved and only missing items are appended. Returns the scaffolded blueprint and a summary of what was added.',
|
|
26
|
+
inputSchema,
|
|
27
|
+
};
|
|
28
|
+
export async function run(ctx, args) {
|
|
29
|
+
let blueprint;
|
|
30
|
+
let source;
|
|
31
|
+
if (args.blueprint) {
|
|
32
|
+
blueprint = args.blueprint;
|
|
33
|
+
source = 'inline';
|
|
34
|
+
}
|
|
35
|
+
else if (args.ref) {
|
|
36
|
+
const resolved = await resolveBlueprint(ctx.root, args.ref);
|
|
37
|
+
blueprint = resolved.blueprint;
|
|
38
|
+
source = resolved.entry.path;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
throw new Error('Provide either "ref" or "blueprint".');
|
|
42
|
+
}
|
|
43
|
+
const sections = (args.sections ?? SCAFFOLD_SECTIONS);
|
|
44
|
+
const { blueprint: scaffolded, summary } = scaffoldBlueprint(blueprint, {
|
|
45
|
+
sections,
|
|
46
|
+
language: args.language ?? 'en',
|
|
47
|
+
});
|
|
48
|
+
return {
|
|
49
|
+
source,
|
|
50
|
+
summary,
|
|
51
|
+
blueprint: scaffolded,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { scanProjectUi } from '../aub.js';
|
|
3
|
+
export const name = 'scan_project_ui';
|
|
4
|
+
const inputSchema = {
|
|
5
|
+
namespace: z
|
|
6
|
+
.string()
|
|
7
|
+
.optional()
|
|
8
|
+
.describe('Optional namespace for suggested custom types. Defaults to package/app name, or app.'),
|
|
9
|
+
limit: z.number().int().positive().optional().describe('Maximum files to scan. Defaults to 2000.'),
|
|
10
|
+
};
|
|
11
|
+
export const config = {
|
|
12
|
+
title: 'Scan Project UI',
|
|
13
|
+
description: 'Statically scan React/Next, Vue/Nuxt, and Angular project files for routes and reusable UI components. Writes candidates to .aub/component-candidates.json; it never writes aub.registry.json.',
|
|
14
|
+
inputSchema,
|
|
15
|
+
};
|
|
16
|
+
export async function run(ctx, args) {
|
|
17
|
+
return scanProjectUi(ctx.root, args ?? {});
|
|
18
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join, relative, sep } from 'node:path';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { resolveBlueprint } from '../workspace.js';
|
|
5
|
+
import { formatAjvErrors } from '../schema.js';
|
|
6
|
+
import { verifyImplementationReport } from '../aub.js';
|
|
7
|
+
export const name = 'submit_report';
|
|
8
|
+
const inputSchema = {
|
|
9
|
+
ref: z.string().describe('Blueprint file path or screen id the report targets.'),
|
|
10
|
+
report: z.record(z.any()).describe('Implementation report object to verify against the Blueprint.'),
|
|
11
|
+
persist: z
|
|
12
|
+
.boolean()
|
|
13
|
+
.optional()
|
|
14
|
+
.describe('Persist an accepted report under <root>/.aub/reports/. Defaults to true.'),
|
|
15
|
+
};
|
|
16
|
+
export const config = {
|
|
17
|
+
title: 'Submit Implementation Report',
|
|
18
|
+
description: 'Validate an implementation report against the report schema and the Blueprint (node mappings + acceptance evidence). Accepted reports are persisted under the workspace.',
|
|
19
|
+
inputSchema,
|
|
20
|
+
};
|
|
21
|
+
export async function run(ctx, args) {
|
|
22
|
+
const { blueprint, entry } = await resolveBlueprint(ctx.root, args.ref);
|
|
23
|
+
const report = args.report;
|
|
24
|
+
const schemaOk = ctx.validators.validateReport(report);
|
|
25
|
+
const schemaErrors = schemaOk ? [] : formatAjvErrors(ctx.validators.validateReport);
|
|
26
|
+
const verification = schemaOk
|
|
27
|
+
? verifyImplementationReport(blueprint, report)
|
|
28
|
+
: { ready: false, errors: ['Report failed schema validation; skipped semantic verification.'], summary: undefined };
|
|
29
|
+
const accepted = schemaOk && verification.ready;
|
|
30
|
+
let savedPath;
|
|
31
|
+
if (accepted && args.persist !== false) {
|
|
32
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
33
|
+
const screenId = entry.screenId || 'blueprint';
|
|
34
|
+
const dir = join(ctx.root, '.aub', 'reports');
|
|
35
|
+
await mkdir(dir, { recursive: true });
|
|
36
|
+
const absPath = join(dir, `${screenId}-${timestamp}.json`);
|
|
37
|
+
await writeFile(absPath, `${JSON.stringify(report, null, 2)}\n`, 'utf8');
|
|
38
|
+
savedPath = relative(ctx.root, absPath).split(sep).join('/');
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
accepted,
|
|
42
|
+
screenId: entry.screenId,
|
|
43
|
+
schemaErrors,
|
|
44
|
+
errors: verification.errors,
|
|
45
|
+
summary: verification.summary,
|
|
46
|
+
savedPath,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { updateAubSession } from '../aub.js';
|
|
3
|
+
export const name = 'update_aub_session';
|
|
4
|
+
const inputSchema = {
|
|
5
|
+
patch: z.record(z.any()).describe('Partial .aub/session.json content to merge into the current workspace session.'),
|
|
6
|
+
};
|
|
7
|
+
export const config = {
|
|
8
|
+
title: 'Update AUB Session',
|
|
9
|
+
description: 'Merge workspace session state into .aub/session.json. Use after the editor saves a Blueprint or updates preview route metadata.',
|
|
10
|
+
inputSchema,
|
|
11
|
+
};
|
|
12
|
+
export async function run(ctx, args) {
|
|
13
|
+
return updateAubSession(ctx.root, args.patch ?? {});
|
|
14
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { resolveBlueprint } from '../workspace.js';
|
|
4
|
+
import { formatAjvErrors } from '../schema.js';
|
|
5
|
+
import { validateBlueprintSemantics, buildKnownTypes } from '../aub.js';
|
|
6
|
+
export const name = 'validate_blueprint';
|
|
7
|
+
const inputSchema = {
|
|
8
|
+
ref: z
|
|
9
|
+
.string()
|
|
10
|
+
.optional()
|
|
11
|
+
.describe('Blueprint file path or screen id to load and validate.'),
|
|
12
|
+
blueprint: z
|
|
13
|
+
.record(z.any())
|
|
14
|
+
.optional()
|
|
15
|
+
.describe('Inline Blueprint object to validate instead of loading from disk.'),
|
|
16
|
+
registry: z
|
|
17
|
+
.string()
|
|
18
|
+
.optional()
|
|
19
|
+
.describe('Path to an aub.registry.json declaring namespaced (team:component) extension types. Defaults to auto-discovery from the workspace root.'),
|
|
20
|
+
};
|
|
21
|
+
export const config = {
|
|
22
|
+
title: 'Validate Blueprint',
|
|
23
|
+
description: 'Validate a Blueprint against the JSON Schema and the AUB semantic rules. Namespaced extension component types are resolved from a project aub.registry.json (auto-discovered, or pass "registry"). Provide either a ref or an inline blueprint object.',
|
|
24
|
+
inputSchema,
|
|
25
|
+
};
|
|
26
|
+
export async function run(ctx, args) {
|
|
27
|
+
let blueprint;
|
|
28
|
+
let source;
|
|
29
|
+
if (args.blueprint) {
|
|
30
|
+
blueprint = args.blueprint;
|
|
31
|
+
source = 'inline';
|
|
32
|
+
}
|
|
33
|
+
else if (args.ref) {
|
|
34
|
+
const resolved = await resolveBlueprint(ctx.root, args.ref);
|
|
35
|
+
blueprint = resolved.blueprint;
|
|
36
|
+
source = resolved.entry.path;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
throw new Error('Provide either "ref" or "blueprint".');
|
|
40
|
+
}
|
|
41
|
+
const schemaOk = ctx.validators.validateBlueprint(blueprint);
|
|
42
|
+
const schemaErrors = schemaOk ? [] : formatAjvErrors(ctx.validators.validateBlueprint);
|
|
43
|
+
let knownTypes;
|
|
44
|
+
let extensionRegistry = null;
|
|
45
|
+
let registryError = null;
|
|
46
|
+
try {
|
|
47
|
+
const resolved = await buildKnownTypes({
|
|
48
|
+
extensionPath: args.registry ? resolve(ctx.root, args.registry) : null,
|
|
49
|
+
startDir: ctx.root,
|
|
50
|
+
});
|
|
51
|
+
knownTypes = resolved.knownTypes;
|
|
52
|
+
extensionRegistry = resolved.extensionPath;
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
registryError = err instanceof Error ? err.message : String(err);
|
|
56
|
+
}
|
|
57
|
+
const semanticErrors = schemaOk && !registryError ? validateBlueprintSemantics(blueprint, { knownTypes }) : [];
|
|
58
|
+
if (registryError)
|
|
59
|
+
semanticErrors.push(`registry: ${registryError}`);
|
|
60
|
+
return {
|
|
61
|
+
source,
|
|
62
|
+
extensionRegistry,
|
|
63
|
+
valid: schemaOk && !registryError && semanticErrors.length === 0,
|
|
64
|
+
schemaErrors,
|
|
65
|
+
semanticErrors,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { relative, sep } from 'node:path';
|
|
3
|
+
import { resolveProjectRef } from '../workspace.js';
|
|
4
|
+
import { formatAjvErrors } from '../schema.js';
|
|
5
|
+
import { loadProject, validateProjectSemantics, validateBlueprintSemantics, buildKnownTypes } from '../aub.js';
|
|
6
|
+
export const name = 'validate_project';
|
|
7
|
+
const inputSchema = {
|
|
8
|
+
ref: z.string().describe('Project file path or project id to load and validate.'),
|
|
9
|
+
};
|
|
10
|
+
export const config = {
|
|
11
|
+
title: 'Validate Project',
|
|
12
|
+
description: 'Validate a multi-screen project against the JSON Schema and AUB project semantic rules, then validate every member screen Blueprint (schema + semantics). Returns per-screen results and an overall valid flag.',
|
|
13
|
+
inputSchema,
|
|
14
|
+
};
|
|
15
|
+
export async function run(ctx, args) {
|
|
16
|
+
if (!args.ref) {
|
|
17
|
+
throw new Error('Provide a project "ref" (file path or project id).');
|
|
18
|
+
}
|
|
19
|
+
const { projectPath } = await resolveProjectRef(ctx.root, args.ref);
|
|
20
|
+
const loaded = await loadProject(projectPath);
|
|
21
|
+
const source = relative(ctx.root, loaded.projectPath).split(sep).join('/');
|
|
22
|
+
const schemaOk = ctx.validators.validateProject(loaded.project);
|
|
23
|
+
const schemaErrors = schemaOk ? [] : formatAjvErrors(ctx.validators.validateProject);
|
|
24
|
+
const semanticErrors = validateProjectSemantics(loaded.project, {
|
|
25
|
+
screensById: loaded.screensById,
|
|
26
|
+
});
|
|
27
|
+
let knownTypes;
|
|
28
|
+
let registryError = null;
|
|
29
|
+
try {
|
|
30
|
+
const resolved = await buildKnownTypes({ extensionPath: null, startDir: ctx.root });
|
|
31
|
+
knownTypes = resolved.knownTypes;
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
registryError = err instanceof Error ? err.message : String(err);
|
|
35
|
+
}
|
|
36
|
+
const screens = loaded.screens.map((screen) => {
|
|
37
|
+
if (!screen.blueprint) {
|
|
38
|
+
return {
|
|
39
|
+
id: screen.ref?.id ?? '',
|
|
40
|
+
valid: false,
|
|
41
|
+
schemaErrors: [`Member blueprint failed to load: ${screen.path}`],
|
|
42
|
+
semanticErrors: [],
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
const memberSchemaOk = ctx.validators.validateBlueprint(screen.blueprint);
|
|
46
|
+
const memberSchemaErrors = memberSchemaOk
|
|
47
|
+
? []
|
|
48
|
+
: formatAjvErrors(ctx.validators.validateBlueprint);
|
|
49
|
+
const memberSemanticErrors = memberSchemaOk && !registryError
|
|
50
|
+
? validateBlueprintSemantics(screen.blueprint, { knownTypes })
|
|
51
|
+
: [];
|
|
52
|
+
if (registryError)
|
|
53
|
+
memberSemanticErrors.push(`registry: ${registryError}`);
|
|
54
|
+
return {
|
|
55
|
+
id: screen.ref?.id ?? '',
|
|
56
|
+
valid: memberSchemaOk && !registryError && memberSemanticErrors.length === 0,
|
|
57
|
+
schemaErrors: memberSchemaErrors,
|
|
58
|
+
semanticErrors: memberSemanticErrors,
|
|
59
|
+
};
|
|
60
|
+
});
|
|
61
|
+
const valid = schemaOk &&
|
|
62
|
+
schemaErrors.length === 0 &&
|
|
63
|
+
semanticErrors.length === 0 &&
|
|
64
|
+
loaded.errors.length === 0 &&
|
|
65
|
+
screens.every((screen) => screen.valid);
|
|
66
|
+
return {
|
|
67
|
+
source,
|
|
68
|
+
valid,
|
|
69
|
+
schemaErrors,
|
|
70
|
+
semanticErrors,
|
|
71
|
+
screens,
|
|
72
|
+
loadErrors: loaded.errors,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { access, mkdir, rename, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname, extname, relative, sep } from 'node:path';
|
|
3
|
+
import yaml from 'js-yaml';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { buildKnownTypes, validateBlueprintSemantics } from '../aub.js';
|
|
6
|
+
import { formatAjvErrors } from '../schema.js';
|
|
7
|
+
import { resolveWorkspacePath } from '../workspace.js';
|
|
8
|
+
export const name = 'write_blueprint';
|
|
9
|
+
const inputSchema = {
|
|
10
|
+
path: z
|
|
11
|
+
.string()
|
|
12
|
+
.describe('Destination path inside the workspace. Must end in .ui.json, .ui.yaml, or .ui.yml.'),
|
|
13
|
+
blueprint: z.record(z.any()).describe('Complete Blueprint object to validate and write.'),
|
|
14
|
+
registry: z
|
|
15
|
+
.string()
|
|
16
|
+
.optional()
|
|
17
|
+
.describe('Optional aub.registry.json path for custom component validation.'),
|
|
18
|
+
overwrite: z.boolean().optional().describe('Replace an existing file. Defaults to false.'),
|
|
19
|
+
};
|
|
20
|
+
export const config = {
|
|
21
|
+
title: 'Write Blueprint',
|
|
22
|
+
description: 'Validate and atomically write a Blueprint inside the workspace. Existing files are protected unless overwrite is true.',
|
|
23
|
+
inputSchema,
|
|
24
|
+
};
|
|
25
|
+
async function exists(path) {
|
|
26
|
+
try {
|
|
27
|
+
await access(path);
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export async function run(ctx, args) {
|
|
35
|
+
if (!args.path || !/\.ui\.(json|ya?ml)$/i.test(args.path)) {
|
|
36
|
+
throw new Error('Provide a destination "path" ending in .ui.json, .ui.yaml, or .ui.yml.');
|
|
37
|
+
}
|
|
38
|
+
if (!args.blueprint)
|
|
39
|
+
throw new Error('Provide a complete "blueprint" object.');
|
|
40
|
+
const blueprint = args.blueprint;
|
|
41
|
+
const schemaOk = ctx.validators.validateBlueprint(blueprint);
|
|
42
|
+
const schemaErrors = schemaOk ? [] : formatAjvErrors(ctx.validators.validateBlueprint);
|
|
43
|
+
const knownTypes = await buildKnownTypes({
|
|
44
|
+
extensionPath: args.registry ? resolveWorkspacePath(ctx.root, args.registry) : null,
|
|
45
|
+
startDir: ctx.root,
|
|
46
|
+
});
|
|
47
|
+
const semanticErrors = schemaOk
|
|
48
|
+
? validateBlueprintSemantics(blueprint, { knownTypes: knownTypes.knownTypes })
|
|
49
|
+
: [];
|
|
50
|
+
if (!schemaOk || semanticErrors.length > 0) {
|
|
51
|
+
throw new Error(`Blueprint validation failed:\n${[...schemaErrors, ...semanticErrors].map((item) => `- ${item}`).join('\n')}`);
|
|
52
|
+
}
|
|
53
|
+
const outputPath = resolveWorkspacePath(ctx.root, args.path);
|
|
54
|
+
if (!args.overwrite && (await exists(outputPath))) {
|
|
55
|
+
throw new Error(`Refusing to overwrite existing file: ${args.path}`);
|
|
56
|
+
}
|
|
57
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
58
|
+
const ext = extname(outputPath).toLowerCase();
|
|
59
|
+
const content = ext === '.yaml' || ext === '.yml'
|
|
60
|
+
? yaml.dump(blueprint, { noRefs: true, lineWidth: 120 })
|
|
61
|
+
: `${JSON.stringify(blueprint, null, 2)}\n`;
|
|
62
|
+
const tempPath = `${outputPath}.${process.pid}.tmp`;
|
|
63
|
+
await writeFile(tempPath, content, 'utf8');
|
|
64
|
+
await rename(tempPath, outputPath);
|
|
65
|
+
return {
|
|
66
|
+
savedPath: relative(ctx.root, outputPath).split(sep).join('/'),
|
|
67
|
+
screenId: blueprint.screen.id,
|
|
68
|
+
format: ext === '.json' ? 'json' : 'yaml',
|
|
69
|
+
bytes: Buffer.byteLength(content),
|
|
70
|
+
extensionRegistry: knownTypes.extensionPath,
|
|
71
|
+
};
|
|
72
|
+
}
|