ai-design-context 0.4.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/AGENTS.md +156 -0
- package/CHANGELOG.md +71 -0
- package/CODE_OF_CONDUCT.md +29 -0
- package/CONTRIBUTING.md +128 -0
- package/LICENSE +21 -0
- package/README.md +283 -0
- package/RELEASE_NOTES_v0.1.0.md +45 -0
- package/RELEASE_NOTES_v0.3.0.md +47 -0
- package/RELEASE_NOTES_v0.4.0.md +29 -0
- package/RELEASE_READINESS.md +107 -0
- package/ROADMAP.md +60 -0
- package/SECURITY.md +40 -0
- package/assets/logo.svg +9 -0
- package/benchmarks/README.md +19 -0
- package/benchmarks/chat.md +37 -0
- package/benchmarks/mobile-home-screen.md +38 -0
- package/benchmarks/notes-app.md +37 -0
- package/benchmarks/settings.md +37 -0
- package/benchmarks/shopping-list.md +37 -0
- package/benchmarks/todo-app.md +144 -0
- package/checklists/DESIGN_QA.md +102 -0
- package/checklists/GENERATED_INDEX.md +7 -0
- package/docs/AGENT_CONTEXT.md +111 -0
- package/docs/BENCHMARK.md +170 -0
- package/docs/DESIGNLINT_READINESS.md +110 -0
- package/docs/DESIGN_SYSTEM.md +23 -0
- package/docs/EVALUATION_RUBRIC.md +154 -0
- package/docs/GITHUB_SETUP.md +28 -0
- package/docs/GLOSSARY.md +45 -0
- package/docs/INDEX.md +109 -0
- package/docs/KNOWLEDGE_ENGINE.md +594 -0
- package/docs/MOBILE_FIRST.md +18 -0
- package/docs/NPM_RELEASE.md +43 -0
- package/docs/PATTERN_SPEC.md +113 -0
- package/docs/PHILOSOPHY.md +25 -0
- package/docs/PRODUCT_THINKING.md +26 -0
- package/docs/STYLE_GUIDE.md +49 -0
- package/docs/TRACEABILITY.md +45 -0
- package/evidence/README.md +64 -0
- package/evidence/TEMPLATE.md +46 -0
- package/evidence/chat/.gitkeep +1 -0
- package/evidence/mobile-home/.gitkeep +1 -0
- package/evidence/notes/.gitkeep +1 -0
- package/evidence/settings/.gitkeep +1 -0
- package/evidence/shopping/.gitkeep +1 -0
- package/evidence/todo/.gitkeep +1 -0
- package/evidence/todo/2026-06-25-codex-gpt-5/EVALUATION.md +66 -0
- package/evidence/todo/2026-06-25-codex-gpt-5/README.md +40 -0
- package/evidence/todo/2026-06-25-codex-gpt-5/ai-design-rules/generated-output.md +163 -0
- package/evidence/todo/2026-06-25-codex-gpt-5/ai-design-rules/metadata.json +38 -0
- package/evidence/todo/2026-06-25-codex-gpt-5/ai-design-rules/notes.md +20 -0
- package/evidence/todo/2026-06-25-codex-gpt-5/ai-design-rules/prompt.md +16 -0
- package/evidence/todo/2026-06-25-codex-gpt-5/ai-design-rules/scores.md +18 -0
- package/evidence/todo/2026-06-25-codex-gpt-5/baseline/generated-output.md +98 -0
- package/evidence/todo/2026-06-25-codex-gpt-5/baseline/metadata.json +19 -0
- package/evidence/todo/2026-06-25-codex-gpt-5/baseline/notes.md +19 -0
- package/evidence/todo/2026-06-25-codex-gpt-5/baseline/prompt.md +9 -0
- package/evidence/todo/2026-06-25-codex-gpt-5/baseline/scores.md +18 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/EVALUATION.md +70 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/README.md +52 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/GENERATION_NOTES.md +133 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/app.js +289 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/context/context-preserving-preview.json +443 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/context/daily-home-surface.json +373 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/context/quick-capture.json +301 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/context/sources-read.txt +36 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/generated-output.md +11 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/index.html +64 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/launch-prompt.md +1 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/metadata.json +55 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/notes.md +15 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/parent-status-message.md +1 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/prompt.md +49 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/runtime-checks.json +776 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/scores.md +20 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/desktop-completed.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/desktop-default.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/desktop-detail-reduced-motion.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/desktop-detail.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/desktop-empty.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/desktop-keyboard-focus.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/desktop-save-error.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/desktop-saved.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/desktop-saving.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/desktop-validation.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/mobile-completed.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/mobile-default.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/mobile-detail-reduced-motion.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/mobile-detail.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/mobile-empty.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/mobile-keyboard-focus.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/mobile-save-error.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/mobile-saved.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/mobile-saving.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/screenshots/mobile-validation.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/source-hashes.json +5 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/ai-design-rules/styles.css +122 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/GENERATION_NOTES.md +86 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/app.js +303 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/generated-output.md +11 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/index.html +71 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/launch-prompt.md +1 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/metadata.json +55 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/notes.md +15 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/parent-status-message.md +1 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/prompt.md +49 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/runtime-checks.json +772 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/scores.md +20 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/desktop-completed.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/desktop-default.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/desktop-detail-reduced-motion.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/desktop-detail.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/desktop-empty.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/desktop-keyboard-focus.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/desktop-save-error.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/desktop-saved.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/desktop-saving.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/desktop-validation.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/mobile-completed.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/mobile-default.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/mobile-detail-reduced-motion.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/mobile-detail.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/mobile-empty.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/mobile-keyboard-focus.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/mobile-save-error.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/mobile-saved.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/mobile-saving.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/screenshots/mobile-validation.png +0 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/source-hashes.json +5 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/baseline/styles.css +9 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/capture-ai-design-rules.js +60 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/capture-baseline.js +60 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/common/brief.md +35 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/common/knowledge-files.json +127 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/common/knowledge.patch +890 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/common/review-context.json +550 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/common/seed.json +86 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/common/setup.json +47 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/common/technical-envelope.md +11 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/layout-metrics.json +133 -0
- package/evidence/todo/2026-09-28-codex-paired-todo/layout-probe.js +15 -0
- package/examples/GENERATED_INDEX.md +8 -0
- package/examples/INDEX.md +16 -0
- package/examples/README.md +15 -0
- package/examples/consequential-action-confirmation-reference.md +83 -0
- package/examples/todo-app-benchmark.md +117 -0
- package/examples/todo-reference/README.md +29 -0
- package/examples/todo-reference/app.js +154 -0
- package/examples/todo-reference/favicon.svg +4 -0
- package/examples/todo-reference/index.html +67 -0
- package/examples/todo-reference/review-evidence/2026-07-15/desktop-default.png +0 -0
- package/examples/todo-reference/review-evidence/2026-07-15/desktop-detail.png +0 -0
- package/examples/todo-reference/review-evidence/2026-07-15/mobile-detail.png +0 -0
- package/examples/todo-reference/review-evidence/2026-07-15/mobile-error.png +0 -0
- package/examples/todo-reference/styles.css +241 -0
- package/graph/GENERATED_GRAPH.md +71 -0
- package/observations/README.md +23 -0
- package/observations/accessibility/reduced-interaction-motion.md +49 -0
- package/observations/accessibility/textual-error-recovery.md +50 -0
- package/observations/accessibility/visible-keyboard-focus.md +49 -0
- package/observations/ai/agent-consequential-action-controls.md +56 -0
- package/observations/ai/agent-work-visibility-and-intervention.md +51 -0
- package/observations/ai/figma-agent-context-and-skills.md +52 -0
- package/observations/finance/high-risk-wallet-recovery-flows.md +55 -0
- package/observations/finance/market-interface-adaptive-trading-surfaces.md +55 -0
- package/observations/interaction/chrome-scoped-view-transitions.md +52 -0
- package/observations/interaction/figma-motion-as-system-capability.md +53 -0
- package/observations/mobile/mobile-bottom-sheet-choice-contracts.md +55 -0
- package/observations/performance/reserved-loading-space.md +51 -0
- package/observations/product-repos/pinned-ai-design-rules-integration.md +49 -0
- package/observations/visual/apple-liquid-glass-functional-layer.md +52 -0
- package/observations/visual/chrome-content-first-adaptive-ui.md +51 -0
- package/observations/visual/material-3-expressive-system.md +52 -0
- package/package.json +65 -0
- package/patterns/GENERATED_INDEX.md +13 -0
- package/patterns/INDEX.md +41 -0
- package/patterns/README.md +5 -0
- package/patterns/consequential-action-confirmation.md +127 -0
- package/patterns/context-preserving-preview.md +145 -0
- package/patterns/daily-home-surface.md +134 -0
- package/patterns/mobile-primary-action.md +110 -0
- package/patterns/object-status-list.md +114 -0
- package/patterns/progressive-detail.md +113 -0
- package/patterns/quick-capture.md +132 -0
- package/prompts/CONSEQUENTIAL_ACTION_REVIEW.md +100 -0
- package/prompts/DESIGN_EVIDENCE_REVIEW.md +49 -0
- package/prompts/GENERATED_INDEX.md +11 -0
- package/prompts/INDEX.md +24 -0
- package/prompts/PROTOTYPE_REVIEW.md +189 -0
- package/prompts/QUICK_CAPTURE_STATE_REVIEW.md +74 -0
- package/prompts/TODO_APP_BENCHMARK.md +88 -0
- package/registry/objects.json +568 -0
- package/registry/relationships.json +972 -0
- package/research/GENERATED_INDEX.md +18 -0
- package/research/INDEX.md +40 -0
- package/research/accessibility/keyboard-focus-and-interaction-motion.md +62 -0
- package/research/accessibility/textual-error-recovery.md +57 -0
- package/research/performance/reserved-loading-space.md +56 -0
- package/research/products/apple-reminders.md +59 -0
- package/research/products/arc.md +61 -0
- package/research/products/linear.md +62 -0
- package/research/products/telegram.md +61 -0
- package/research/products/things-3.md +60 -0
- package/research/ux/contextual-agentic-interface.md +68 -0
- package/research/ux/high-risk-operational-flows.md +89 -0
- package/research/ux/motion-as-state-continuity.md +71 -0
- package/research/visual/expressive-system-ui-2026.md +75 -0
- package/reviews/GENERATED_INDEX.md +9 -0
- package/reviews/README.md +25 -0
- package/reviews/consequential-action-confirmation-review.md +92 -0
- package/reviews/todo-app-benchmark-reference-review.md +86 -0
- package/reviews/todo-reference-fixture-review.md +77 -0
- package/rules/GENERATED_INDEX.md +23 -0
- package/rules/INDEX.md +37 -0
- package/rules/accessibility/A11Y-001.md +58 -0
- package/rules/accessibility/A11Y-002.md +55 -0
- package/rules/accessibility/A11Y-003.md +54 -0
- package/rules/accessibility/A11Y-004.md +54 -0
- package/rules/ia/IA-001.md +60 -0
- package/rules/ia/IA-002.md +61 -0
- package/rules/performance/PERF-001.md +55 -0
- package/rules/product/PRD-001.md +61 -0
- package/rules/product/PRD-002.md +61 -0
- package/rules/ux/UX-001.md +58 -0
- package/rules/ux/UX-002.md +61 -0
- package/rules/ux/UX-003.md +60 -0
- package/rules/ux/UX-004.md +61 -0
- package/rules/ux/UX-005.md +62 -0
- package/rules/ux/UX-006.md +69 -0
- package/rules/visual/VIS-001.md +59 -0
- package/rules/visual/VIS-002.md +59 -0
- package/schema/checklist.schema.json +21 -0
- package/schema/common.schema.json +178 -0
- package/schema/observation.schema.json +21 -0
- package/schema/pattern.schema.json +21 -0
- package/schema/prompt.schema.json +21 -0
- package/schema/reference-project.schema.json +21 -0
- package/schema/research.schema.json +21 -0
- package/schema/review.schema.json +21 -0
- package/schema/rule.schema.json +21 -0
- package/skills/README.md +48 -0
- package/skills/accessibility-reviewer/SKILL.md +101 -0
- package/skills/agent-context/SKILL.md +34 -0
- package/skills/agent-context/agents/openai.yaml +4 -0
- package/skills/design-evidence-researcher/SKILL.md +47 -0
- package/skills/design-evidence-researcher/agents/openai.yaml +4 -0
- package/skills/design-reviewer/SKILL.md +113 -0
- package/skills/design-system-architect/SKILL.md +101 -0
- package/skills/information-architect/SKILL.md +97 -0
- package/skills/interaction-designer/SKILL.md +104 -0
- package/skills/knowledge-graph-architect/SKILL.md +96 -0
- package/skills/mobile-ux-expert/SKILL.md +105 -0
- package/skills/motion-designer/SKILL.md +100 -0
- package/skills/performance-reviewer/SKILL.md +97 -0
- package/skills/product-designer/SKILL.md +104 -0
- package/skills/prompt-architect/SKILL.md +105 -0
- package/skills/reference-driven-design/SKILL.md +119 -0
- package/skills/ux-reviewer/SKILL.md +99 -0
- package/skills/visual-designer/SKILL.md +107 -0
- package/starter-kit/AGENTS.md +37 -0
- package/starter-kit/BOOTSTRAP.md +13 -0
- package/starter-kit/INSTALL_WITH_AGENT.md +133 -0
- package/starter-kit/PROJECT_INTEGRATION.md +60 -0
- package/starter-kit/README.md +41 -0
- package/starter-kit/benchmarks/BENCHMARK_CHECKLIST.md +10 -0
- package/starter-kit/docs/DESIGN_DECISIONS.md +22 -0
- package/starter-kit/docs/INFORMATION_ARCHITECTURE.md +25 -0
- package/starter-kit/docs/PERSONAS.md +14 -0
- package/starter-kit/docs/PRD.md +32 -0
- package/starter-kit/docs/USER_FLOWS.md +19 -0
- package/starter-kit/reviews/DESIGN_REVIEW.md +49 -0
- package/starter-kit/templates/FEATURE_TEMPLATE.md +36 -0
- package/starter-kit/templates/TASK_TEMPLATE.md +22 -0
- package/templates/CHECKLIST_TEMPLATE.md +43 -0
- package/templates/OBSERVATION_TEMPLATE.md +41 -0
- package/templates/PATTERN_TEMPLATE.md +100 -0
- package/templates/PROMPT_TEMPLATE.md +46 -0
- package/templates/PROTOTYPE_REVIEW.md +50 -0
- package/templates/REFERENCE_PROJECT_TEMPLATE.md +49 -0
- package/templates/REVIEW_TEMPLATE.md +55 -0
- package/templates/RULE_TEMPLATE.md +57 -0
- package/tools/cli.mjs +46 -0
- package/tools/context.mjs +342 -0
- package/tools/designlint.mjs +77 -0
- package/tools/generate-indexes.mjs +621 -0
- package/tools/init.mjs +99 -0
- package/tools/validate-benchmark-evidence.mjs +248 -0
- package/tools/validate-knowledge.mjs +481 -0
package/tools/init.mjs
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
const startMarker = '<!-- ai-design-context:start -->';
|
|
5
|
+
const endMarker = '<!-- ai-design-context:end -->';
|
|
6
|
+
const templates = [
|
|
7
|
+
'docs/PRD.md',
|
|
8
|
+
'docs/PERSONAS.md',
|
|
9
|
+
'docs/USER_FLOWS.md',
|
|
10
|
+
'docs/INFORMATION_ARCHITECTURE.md',
|
|
11
|
+
'docs/DESIGN_DECISIONS.md',
|
|
12
|
+
'templates/FEATURE_TEMPLATE.md',
|
|
13
|
+
'templates/TASK_TEMPLATE.md',
|
|
14
|
+
'reviews/DESIGN_REVIEW.md',
|
|
15
|
+
'benchmarks/BENCHMARK_CHECKLIST.md',
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
const instructions = `${startMarker}
|
|
19
|
+
## AI Design Context
|
|
20
|
+
|
|
21
|
+
Use the installed, lockfile-pinned AI Design Context knowledge graph for user-facing product, UX, UI, accessibility, motion, and design-prompt tasks. Existing project instructions, business logic, and the project's design system remain authoritative. Skip graph retrieval for backend-only, infrastructure-only, or unrelated maintenance tasks.
|
|
22
|
+
|
|
23
|
+
Before implementation:
|
|
24
|
+
|
|
25
|
+
\`\`\`bash
|
|
26
|
+
npx --no-install ai-design-context context --task "<task phrase>" --intent implement
|
|
27
|
+
npx --no-install ai-design-context context --task "<task phrase>" --platform mobile --intent implement
|
|
28
|
+
\`\`\`
|
|
29
|
+
|
|
30
|
+
Before review, resolve a known graph object or matching task phrase:
|
|
31
|
+
|
|
32
|
+
\`\`\`bash
|
|
33
|
+
npx --no-install ai-design-context context --review "<object ID, graph path, or matching phrase>" --intent qa
|
|
34
|
+
\`\`\`
|
|
35
|
+
|
|
36
|
+
Read the returned research and rules before making product decisions. Markdown lists absolute reading paths; JSON (\`--format json\`) retains graph-relative \`path\` and adds \`absolutePath\`. Review queries resolve graph context; they do not inspect arbitrary application files. Inspect the implementation separately.
|
|
37
|
+
|
|
38
|
+
Treat \`draft\` and \`seed\` guidance as bounded evidence. Matching is lexical, not translation or semantic search: prefer known slugs or IDs when a phrase does not match. If retrieval fails, record an observation or research need instead of inventing design advice. Report applied rules, patterns, state coverage, mobile assumptions, accessibility checks, and validation limits.
|
|
39
|
+
|
|
40
|
+
Use existing product documentation first. Fill any newly created starter-kit placeholders with actual product context; use \`reviews/DESIGN_REVIEW.md\` for UI review.
|
|
41
|
+
${endMarker}`;
|
|
42
|
+
|
|
43
|
+
function inspectTarget(root, relativePath) {
|
|
44
|
+
const parts = relativePath.split('/');
|
|
45
|
+
let current = root;
|
|
46
|
+
let result;
|
|
47
|
+
for (const [index, part] of parts.entries()) {
|
|
48
|
+
current = path.join(current, part);
|
|
49
|
+
try {
|
|
50
|
+
result = fs.lstatSync(current);
|
|
51
|
+
} catch (error) {
|
|
52
|
+
if (error.code === 'ENOENT') return undefined;
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
if (result.isSymbolicLink()) throw new Error(`Refusing to write through symlink: ${relativePath}`);
|
|
56
|
+
if (index < parts.length - 1 && !result.isDirectory()) {
|
|
57
|
+
throw new Error(`Expected a directory in template path: ${relativePath}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
if (!result.isFile()) throw new Error(`Expected a regular file: ${relativePath}`);
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function initProject(projectRoot, packageRoot) {
|
|
65
|
+
const root = fs.realpathSync(projectRoot);
|
|
66
|
+
const agentsPath = path.join(root, 'AGENTS.md');
|
|
67
|
+
const agentsExists = inspectTarget(root, 'AGENTS.md');
|
|
68
|
+
const original = agentsExists ? fs.readFileSync(agentsPath, 'utf8') : '';
|
|
69
|
+
const starts = original.split(startMarker).length - 1;
|
|
70
|
+
const ends = original.split(endMarker).length - 1;
|
|
71
|
+
if (starts !== ends || starts > 1 || (starts === 1 && original.indexOf(startMarker) > original.indexOf(endMarker))) {
|
|
72
|
+
throw new Error('Invalid AI Design Context markers in AGENTS.md; repair the marked block before running init.');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Preflight all destinations and sources before writing any project files.
|
|
76
|
+
const missing = templates.filter((file) => !inspectTarget(root, file));
|
|
77
|
+
const contents = missing.map((file) => [file, fs.readFileSync(path.join(packageRoot, 'starter-kit', file))]);
|
|
78
|
+
const created = [];
|
|
79
|
+
for (const [file, content] of contents) {
|
|
80
|
+
const target = path.join(root, file);
|
|
81
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
82
|
+
fs.writeFileSync(target, content, { flag: 'wx' });
|
|
83
|
+
created.push(file);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (starts === 0) {
|
|
87
|
+
const newline = original.includes('\r\n') ? '\r\n' : '\n';
|
|
88
|
+
const block = instructions.replaceAll('\n', newline);
|
|
89
|
+
if (agentsExists) {
|
|
90
|
+
const separator = original.endsWith(newline) ? newline : `${newline}${newline}`;
|
|
91
|
+
fs.appendFileSync(agentsPath, `${separator}${block}${newline}`);
|
|
92
|
+
} else {
|
|
93
|
+
fs.writeFileSync(agentsPath, `# Project Agent Instructions${newline}${newline}${block}${newline}`, { flag: 'wx' });
|
|
94
|
+
created.unshift('AGENTS.md');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return { created, instructionsAdded: starts === 0 };
|
|
99
|
+
}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
const root = process.cwd();
|
|
5
|
+
const evidenceRoot = path.join(root, 'evidence');
|
|
6
|
+
const requiredMetadataFields = [
|
|
7
|
+
'scenario',
|
|
8
|
+
'run_type',
|
|
9
|
+
'date',
|
|
10
|
+
'model',
|
|
11
|
+
'provider',
|
|
12
|
+
'generation_surface',
|
|
13
|
+
'temperature',
|
|
14
|
+
'tool_access',
|
|
15
|
+
'implementation_target',
|
|
16
|
+
'evaluator',
|
|
17
|
+
'rubric_version',
|
|
18
|
+
'evidence_level',
|
|
19
|
+
'screenshots',
|
|
20
|
+
'limitation',
|
|
21
|
+
];
|
|
22
|
+
const requiredArtifacts = ['metadata.json', 'prompt.md', 'generated-output.md', 'notes.md', 'scores.md'];
|
|
23
|
+
const rubricCategories = [
|
|
24
|
+
'Product Thinking',
|
|
25
|
+
'UX',
|
|
26
|
+
'Information Architecture',
|
|
27
|
+
'Navigation',
|
|
28
|
+
'Accessibility',
|
|
29
|
+
'Mobile-first',
|
|
30
|
+
'Visual Hierarchy',
|
|
31
|
+
'State Design',
|
|
32
|
+
'Consistency',
|
|
33
|
+
'Performance Awareness',
|
|
34
|
+
'Simplicity',
|
|
35
|
+
'Overall Product Quality',
|
|
36
|
+
];
|
|
37
|
+
const errors = [];
|
|
38
|
+
const warnings = [];
|
|
39
|
+
const runs = [];
|
|
40
|
+
const screenshotExtensions = new Set(['.avif', '.gif', '.jpeg', '.jpg', '.png', '.webp']);
|
|
41
|
+
|
|
42
|
+
function hasSupportedImageSignature(filePath, extension) {
|
|
43
|
+
const bytes = fs.readFileSync(filePath).subarray(0, 16);
|
|
44
|
+
const ascii = bytes.toString('ascii');
|
|
45
|
+
const hex = bytes.toString('hex');
|
|
46
|
+
|
|
47
|
+
switch (extension) {
|
|
48
|
+
case '.png':
|
|
49
|
+
return hex.startsWith('89504e470d0a1a0a');
|
|
50
|
+
case '.jpeg':
|
|
51
|
+
case '.jpg':
|
|
52
|
+
return hex.startsWith('ffd8ff');
|
|
53
|
+
case '.gif':
|
|
54
|
+
return ascii.startsWith('GIF87a') || ascii.startsWith('GIF89a');
|
|
55
|
+
case '.webp':
|
|
56
|
+
return ascii.startsWith('RIFF') && ascii.slice(8, 12) === 'WEBP';
|
|
57
|
+
case '.avif':
|
|
58
|
+
return ascii.slice(4, 8) === 'ftyp' && ['avif', 'avis'].includes(ascii.slice(8, 12));
|
|
59
|
+
default:
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function listDirectories(directory) {
|
|
65
|
+
if (!fs.existsSync(directory)) {
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return fs
|
|
70
|
+
.readdirSync(directory, { withFileTypes: true })
|
|
71
|
+
.filter((entry) => entry.isDirectory() && !entry.name.startsWith('.'))
|
|
72
|
+
.map((entry) => entry.name)
|
|
73
|
+
.sort();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function readMetadata(filePath) {
|
|
77
|
+
try {
|
|
78
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
79
|
+
} catch (error) {
|
|
80
|
+
errors.push(`${path.relative(root, filePath)}: invalid JSON (${error.message})`);
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function validateArtifacts(runPath, runType) {
|
|
86
|
+
for (const artifact of requiredArtifacts) {
|
|
87
|
+
const artifactPath = path.join(runPath, runType, artifact);
|
|
88
|
+
if (!fs.existsSync(artifactPath)) {
|
|
89
|
+
errors.push(`${path.relative(root, runPath)}: missing ${runType}/${artifact}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function validateMetadata(runPath, runType) {
|
|
95
|
+
const metadataPath = path.join(runPath, runType, 'metadata.json');
|
|
96
|
+
if (!fs.existsSync(metadataPath)) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const metadata = readMetadata(metadataPath);
|
|
101
|
+
if (!metadata) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
for (const field of requiredMetadataFields) {
|
|
106
|
+
if (!(field in metadata)) {
|
|
107
|
+
errors.push(`${path.relative(root, metadataPath)}: missing required field ${field}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (metadata.run_type !== runType) {
|
|
112
|
+
errors.push(`${path.relative(root, metadataPath)}: run_type must be ${runType}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (!Array.isArray(metadata.tool_access)) {
|
|
116
|
+
errors.push(`${path.relative(root, metadataPath)}: tool_access must be an array`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (!['directional', 'rendered'].includes(metadata.evidence_level)) {
|
|
120
|
+
errors.push(`${path.relative(root, metadataPath)}: evidence_level must be directional or rendered`);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (metadata.evidence_level === 'rendered') {
|
|
124
|
+
if (!Array.isArray(metadata.screenshots) || metadata.screenshots.length === 0) {
|
|
125
|
+
errors.push(`${path.relative(root, metadataPath)}: rendered evidence requires non-empty screenshots`);
|
|
126
|
+
} else {
|
|
127
|
+
for (const screenshot of metadata.screenshots) {
|
|
128
|
+
if (typeof screenshot !== 'string' || path.isAbsolute(screenshot)) {
|
|
129
|
+
errors.push(`${path.relative(root, metadataPath)}: screenshot paths must be relative strings`);
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const screenshotRoot = path.resolve(runPath, runType);
|
|
134
|
+
const screenshotPath = path.resolve(runPath, screenshot);
|
|
135
|
+
const relativeScreenshotPath = path.relative(screenshotRoot, screenshotPath);
|
|
136
|
+
if (
|
|
137
|
+
relativeScreenshotPath === '' ||
|
|
138
|
+
relativeScreenshotPath.startsWith(`..${path.sep}`) ||
|
|
139
|
+
path.isAbsolute(relativeScreenshotPath)
|
|
140
|
+
) {
|
|
141
|
+
errors.push(
|
|
142
|
+
`${path.relative(root, metadataPath)}: declared screenshot ${screenshot} must stay inside ${runType}/`,
|
|
143
|
+
);
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const extension = path.extname(screenshotPath).toLowerCase();
|
|
148
|
+
if (!screenshotExtensions.has(extension)) {
|
|
149
|
+
errors.push(`${path.relative(root, metadataPath)}: declared screenshot ${screenshot} must be an image file`);
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (!fs.existsSync(screenshotPath)) {
|
|
154
|
+
errors.push(`${path.relative(root, metadataPath)}: declared screenshot ${screenshot} does not exist`);
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (!fs.lstatSync(screenshotPath).isFile()) {
|
|
159
|
+
errors.push(`${path.relative(root, metadataPath)}: declared screenshot ${screenshot} must be a regular file`);
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (!hasSupportedImageSignature(screenshotPath, extension)) {
|
|
164
|
+
errors.push(
|
|
165
|
+
`${path.relative(root, metadataPath)}: declared screenshot ${screenshot} has invalid image data`,
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return metadata;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function validateRun(runPath) {
|
|
176
|
+
const relativeRunPath = path.relative(root, runPath);
|
|
177
|
+
const evaluationPath = path.join(runPath, 'EVALUATION.md');
|
|
178
|
+
if (!fs.existsSync(evaluationPath)) {
|
|
179
|
+
errors.push(`${relativeRunPath}: missing EVALUATION.md`);
|
|
180
|
+
} else {
|
|
181
|
+
const evaluation = fs.readFileSync(evaluationPath, 'utf8');
|
|
182
|
+
for (const category of rubricCategories) {
|
|
183
|
+
if (!evaluation.includes(`| ${category} |`)) {
|
|
184
|
+
errors.push(`${relativeRunPath}/EVALUATION.md: missing rubric category ${category}`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
validateArtifacts(runPath, 'baseline');
|
|
190
|
+
validateArtifacts(runPath, 'ai-design-rules');
|
|
191
|
+
const baseline = validateMetadata(runPath, 'baseline');
|
|
192
|
+
const rules = validateMetadata(runPath, 'ai-design-rules');
|
|
193
|
+
|
|
194
|
+
if (!baseline || !rules) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
for (const field of [
|
|
199
|
+
'scenario',
|
|
200
|
+
'date',
|
|
201
|
+
'model',
|
|
202
|
+
'provider',
|
|
203
|
+
'generation_surface',
|
|
204
|
+
'temperature',
|
|
205
|
+
'tool_access',
|
|
206
|
+
'implementation_target',
|
|
207
|
+
'evaluator',
|
|
208
|
+
'rubric_version',
|
|
209
|
+
'evidence_level',
|
|
210
|
+
]) {
|
|
211
|
+
if (JSON.stringify(baseline[field]) !== JSON.stringify(rules[field])) {
|
|
212
|
+
errors.push(`${relativeRunPath}: baseline and ai-design-rules must use the same ${field}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (baseline.evidence_level === 'directional') {
|
|
217
|
+
warnings.push(`${relativeRunPath}: directional evidence only; no rendered visual proof is asserted`);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
runs.push({ evidenceLevel: baseline.evidence_level, runPath: relativeRunPath });
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
for (const scenario of listDirectories(evidenceRoot)) {
|
|
224
|
+
for (const run of listDirectories(path.join(evidenceRoot, scenario))) {
|
|
225
|
+
validateRun(path.join(evidenceRoot, scenario, run));
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (runs.length === 0) {
|
|
230
|
+
errors.push('evidence/: no benchmark run directories found');
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if (errors.length > 0) {
|
|
234
|
+
console.error(`Benchmark evidence validation failed with ${errors.length} error(s):`);
|
|
235
|
+
for (const error of errors) {
|
|
236
|
+
console.error(`- ${error}`);
|
|
237
|
+
}
|
|
238
|
+
process.exit(1);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const renderedCount = runs.filter((run) => run.evidenceLevel === 'rendered').length;
|
|
242
|
+
const directionalCount = runs.length - renderedCount;
|
|
243
|
+
console.log(
|
|
244
|
+
`Benchmark evidence validation passed: ${runs.length} run(s), ${renderedCount} rendered, ${directionalCount} directional.`,
|
|
245
|
+
);
|
|
246
|
+
for (const warning of warnings) {
|
|
247
|
+
console.warn(`Warning: ${warning}`);
|
|
248
|
+
}
|