@givolt/i3-composer-agent 2.3.2 → 2.3.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 (92) hide show
  1. package/.agents/plugins/marketplace.json +1 -1
  2. package/.claude-plugin/marketplace.json +1 -1
  3. package/.claude-plugin/plugin.json +1 -1
  4. package/.codex-plugin/plugin.json +1 -1
  5. package/README.md +5 -1
  6. package/bin/agent-targets.json +4 -2
  7. package/bin/i3-composer-agent.cjs +44 -8
  8. package/bin/install.cjs +2 -1
  9. package/bin/native-layout.cjs +1 -1
  10. package/bin/tool-selector.cjs +24 -7
  11. package/bin/wizard.cjs +89 -15
  12. package/docs/codebuddy-setup.md +27 -2
  13. package/docs/codex-setup.md +3 -1
  14. package/docs/other-hosts.md +1 -1
  15. package/docs/ui-prototype-native/USAGE.md +4 -2
  16. package/docs/workbuddy-setup.md +3 -1
  17. package/hooks/codebuddy-upstream.cjs +93 -0
  18. package/hooks/i3-prototype.cjs +12 -0
  19. package/hooks/manage.cjs +162 -0
  20. package/package.json +31 -1
  21. package/plugin.json +1 -1
  22. package/scripts/prototype-cache-test.js +55 -0
  23. package/scripts/prototype-generation-entry-test.js +6 -0
  24. package/scripts/prototype-generation-evidence-test.js +10 -0
  25. package/scripts/prototype-generation-native-test.js +78 -0
  26. package/scripts/prototype-generation-test.js +99 -0
  27. package/scripts/prototype-inventory-test.js +43 -0
  28. package/scripts/prototype-locations-test.js +21 -0
  29. package/scripts/prototype-project-test.js +183 -0
  30. package/scripts/ui-prototype-codebuddy-hook-test.js +106 -0
  31. package/scripts/ui-prototype-execution-evidence-test.js +62 -0
  32. package/scripts/ui-prototype-execution-gates-test.js +66 -0
  33. package/scripts/ui-prototype-execution-policy-test.js +42 -0
  34. package/scripts/ui-prototype-execution-runtime-test.js +27 -0
  35. package/scripts/ui-prototype-ide-source-test.js +73 -0
  36. package/scripts/ui-prototype-registration-test.js +53 -0
  37. package/scripts/ui-prototype-transcript-auto-test.js +67 -0
  38. package/skills/i3-frontend-ui-engineering/SKILL.md +1 -1
  39. package/skills/i3-incremental-implementation/SKILL.md +1 -1
  40. package/skills/i3-ui-prototype/SKILL.md +27 -7
  41. package/skills/i3-ui-prototype/assets/capabilities/generation.json +833 -0
  42. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/generation-component-map.json +300 -0
  43. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/src/App.vue +14 -3
  44. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/src/PrototypeShell.vue +59 -0
  45. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/src/config.ts +6 -1
  46. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/src/domain/presentation.ts +29 -0
  47. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/src/style.css +13 -0
  48. package/skills/i3-ui-prototype/assets/frameworks/vue-antdv-next/starter/tests/presentation.test.ts +23 -0
  49. package/skills/i3-ui-prototype/assets/hosts/codebuddy/profile.json +13 -0
  50. package/skills/i3-ui-prototype/assets/optional-skills/host-targets.json +4 -2
  51. package/skills/i3-ui-prototype/assets/templates/catalog.json +2 -1
  52. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/component-inventory.json +707 -0
  53. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/generation.json +49 -0
  54. package/skills/i3-ui-prototype/assets/templates/enterprise-admin/template-inventory.json +28791 -0
  55. package/skills/i3-ui-prototype/assets/templates/gallery/index.html +1 -1
  56. package/skills/i3-ui-prototype/assets/templates/generation-options.js +42 -0
  57. package/skills/i3-ui-prototype/assets/templates/presentation.html +17 -0
  58. package/skills/i3-ui-prototype/references/artifact-contract.md +1 -1
  59. package/skills/i3-ui-prototype/references/content-template.md +9 -4
  60. package/skills/i3-ui-prototype/references/execution-evidence.md +66 -0
  61. package/skills/i3-ui-prototype/references/generation-contract.md +122 -0
  62. package/skills/i3-ui-prototype/references/interaction-acceptance.md +4 -0
  63. package/skills/i3-ui-prototype/references/optional-skills.md +4 -0
  64. package/skills/i3-ui-prototype/references/project-layout.md +92 -0
  65. package/skills/i3-ui-prototype/references/template-adapters.md +6 -0
  66. package/skills/i3-ui-prototype/references/workflow-contract.md +4 -0
  67. package/skills/i3-ui-prototype/scripts/browser-workspace.cjs +72 -0
  68. package/skills/i3-ui-prototype/scripts/codebuddy-context.cjs +75 -0
  69. package/skills/i3-ui-prototype/scripts/codebuddy-hook.cjs +157 -0
  70. package/skills/i3-ui-prototype/scripts/codebuddy-ide-source.cjs +69 -0
  71. package/skills/i3-ui-prototype/scripts/codebuddy-registration.cjs +123 -0
  72. package/skills/i3-ui-prototype/scripts/content-template.cjs +2 -2
  73. package/skills/i3-ui-prototype/scripts/execution-assertions.cjs +43 -0
  74. package/skills/i3-ui-prototype/scripts/execution-evidence.cjs +146 -0
  75. package/skills/i3-ui-prototype/scripts/execution-gates.cjs +147 -0
  76. package/skills/i3-ui-prototype/scripts/execution-policy.cjs +41 -0
  77. package/skills/i3-ui-prototype/scripts/execution-runtime.cjs +60 -0
  78. package/skills/i3-ui-prototype/scripts/generation-assets.cjs +18 -0
  79. package/skills/i3-ui-prototype/scripts/generation-contract.cjs +214 -0
  80. package/skills/i3-ui-prototype/scripts/generation-evidence.cjs +50 -0
  81. package/skills/i3-ui-prototype/scripts/generation-replan.cjs +34 -0
  82. package/skills/i3-ui-prototype/scripts/hosts/codebuddy.cjs +16 -0
  83. package/skills/i3-ui-prototype/scripts/native-delivery.cjs +17 -5
  84. package/skills/i3-ui-prototype/scripts/native-devtools.cjs +1 -0
  85. package/skills/i3-ui-prototype/scripts/native-pilot-lib.cjs +66 -18
  86. package/skills/i3-ui-prototype/scripts/native-pilot.cjs +18 -2
  87. package/skills/i3-ui-prototype/scripts/project-registry.cjs +126 -0
  88. package/skills/i3-ui-prototype/scripts/prototype-hooks.cjs +87 -0
  89. package/skills/i3-ui-prototype/scripts/prototype-lib.cjs +5 -7
  90. package/skills/i3-ui-prototype/scripts/prototype-locations.cjs +5 -1
  91. package/skills/i3-ui-prototype/scripts/template-contract.cjs +11 -2
  92. package/skills/i3-ui-prototype/scripts/template-inventory.cjs +78 -0
@@ -0,0 +1,78 @@
1
+ 'use strict';
2
+ const fs = require('node:fs'), path = require('node:path'), crypto = require('node:crypto'), assert = require('node:assert/strict');
3
+ const digest = value => crypto.createHash('sha256').update(value).digest('hex');
4
+ const ignored = new Set(['template-inventory.json', 'capabilities.generated.json']);
5
+ function files(directory, prefix = '') {
6
+ return fs.readdirSync(path.join(directory, prefix), { withFileTypes: true }).sort((a,b) => a.name.localeCompare(b.name, 'en')).flatMap(entry => {
7
+ const name = prefix ? `${prefix}/${entry.name}` : entry.name;
8
+ assert.ok(!entry.isSymbolicLink(), `Refusing template symlink: ${name}`);
9
+ if (['.git', 'node_modules'].includes(entry.name) || ignored.has(name)) return [];
10
+ return entry.isDirectory() ? files(directory, name) : [name];
11
+ });
12
+ }
13
+ function attributes(text) {
14
+ const value = {};
15
+ for (const match of text.matchAll(/([^\s=<>/'"`]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+)))?/g)) {
16
+ assert.ok(!Object.hasOwn(value, match[1]), `Duplicate HTML attribute: ${match[1]}`);
17
+ value[match[1]] = match[2] ?? match[3] ?? match[4] ?? '';
18
+ }
19
+ return value;
20
+ }
21
+ function scan(directory) {
22
+ directory = fs.realpathSync(directory);
23
+ const sourceFiles = files(directory), hashes = Object.fromEntries(sourceFiles.map(file => [file, digest(fs.readFileSync(path.join(directory, file)))]));
24
+ const html = fs.readFileSync(path.join(directory, 'index.html'), 'utf8');
25
+ const policy = JSON.parse(fs.readFileSync(path.join(directory, 'component-inventory.json'), 'utf8'));
26
+ return scanResources(hashes, html, policy);
27
+ }
28
+ function scanResources(hashes, html, policy) {
29
+ const routesMatch = html.match(/id="prototype-offline-routes">([\s\S]*?)<\/script>/);
30
+ assert.ok(routesMatch, 'Template inventory requires explicit offline routes');
31
+ const routes = JSON.parse(routesMatch[1]);
32
+ assert.equal(policy.schemaVersion, 1, 'Unsupported component inventory classification');
33
+ const fragments = [], components = {}, unknownComponents = new Set(); let eventCount = 0;
34
+ for (const match of html.matchAll(/^<template data-source="([^"]+)">\n([\s\S]*?)^<\/template>/gm)) {
35
+ const file = match[1], content = match[2], nodes = [];
36
+ assert.ok(!fragments.some(fragment => fragment.file === file), `Duplicate HTML fragment: ${file}`);
37
+ const cleaned = content.replace(/<!--[\s\S]*?-->/g, text => ' '.repeat(text.length));
38
+ for (const token of cleaned.matchAll(/<([a-zA-Z][\w:.-]*)(\s(?:[^"'<>]|"[^"]*"|'[^']*')*)?\s*\/?\s*>/g)) {
39
+ const attrs = attributes(token[2] || ''), node = { id: `${file}#${nodes.length + 1}`, tag: token[1], attributes: attrs };
40
+ nodes.push(node);
41
+ eventCount += Object.keys(attrs).filter(key => key.startsWith('data-on-')).length;
42
+ const component = attrs['data-component'];
43
+ if (!component) continue;
44
+ const classification = policy.components?.[component];
45
+ if (!classification) unknownComponents.add(component);
46
+ else {
47
+ assert.ok(['framework', 'business-reference', 'icon', 'router', 'dynamic'].includes(classification.kind), `Unknown classification: ${component}`);
48
+ assert.ok(Array.isArray(classification.capabilities), `Missing semantic classification: ${component}`);
49
+ if (classification.source) assert.ok(fragments.some(item => item.file === classification.source) || html.includes(`<template data-source="${classification.source}">`), `Missing component source: ${component}`);
50
+ }
51
+ components[component] ||= { classification: classification || null, occurrences: [] };
52
+ components[component].occurrences.push(node.id);
53
+ }
54
+ fragments.push({ file, digest: digest(content), nodes });
55
+ }
56
+ assert.ok(fragments.length, 'Template inventory requires editable fragments');
57
+ assert.equal(unknownComponents.size, 0, `Unclassified template components: ${[...unknownComponents].join(', ')}`);
58
+ const pages = [...new Set(routes.map(route => route.component).filter(Boolean))].map(component => {
59
+ const fragment = 'reference/' + component.replace(/^\.\//, '').replace(/\.js$/, '.html');
60
+ assert.ok(fragments.some(item => item.file === fragment), `Route has no editable HTML: ${component}`);
61
+ return { component, fragment, routes: routes.filter(route => route.component === component).map(route => route.path) };
62
+ });
63
+ return { schemaVersion: 1, files: hashes, routes, pages, fragments, components, eventCount, unknownComponents: [] };
64
+ }
65
+ function verify(directory, inventory) {
66
+ assert.deepEqual(scan(directory), inventory, 'Template inventory changed; review every source/component/interaction difference and regenerate the inventory');
67
+ return { status: 'passed', files: Object.keys(inventory.files).length, routes: inventory.routes.length, pages: inventory.pages.length, fragments: inventory.fragments.length, components: Object.keys(inventory.components).length, events: inventory.eventCount };
68
+ }
69
+ function verifySnapshot(snapshot) {
70
+ const resources = new Map(snapshot.files.map(file => [file.path, Buffer.from(file.content, 'base64')]));
71
+ assert.equal(resources.size, snapshot.files.length, 'Duplicate template snapshot resource');
72
+ const hashes = Object.fromEntries([...resources].filter(([file]) => !ignored.has(file)).map(([file, content]) => [file, digest(content)]));
73
+ const expected = JSON.parse(resources.get('template-inventory.json').toString('utf8'));
74
+ const actual = scanResources(hashes, resources.get('index.html').toString('utf8'), JSON.parse(resources.get('component-inventory.json').toString('utf8')));
75
+ assert.deepEqual(actual, expected, 'Template snapshot inventory differs from actual sources/components/events');
76
+ return actual;
77
+ }
78
+ module.exports = { scan, verify, verifySnapshot };