buildanything 1.8.0 → 2.1.1
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/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +17 -3
- package/CHANGELOG.md +57 -0
- package/README.md +57 -61
- package/agents/a11y-architect.md +168 -0
- package/agents/briefing-officer.md +172 -0
- package/agents/business-model.md +82 -29
- package/agents/code-architect.md +80 -0
- package/agents/code-reviewer.md +256 -0
- package/agents/code-simplifier.md +72 -0
- package/agents/design-brand-guardian.md +312 -53
- package/agents/design-critic.md +144 -0
- package/agents/design-inclusive-visuals-specialist.md +8 -19
- package/agents/design-ui-designer.md +352 -56
- package/agents/design-ux-architect.md +418 -55
- package/agents/design-ux-researcher.md +359 -49
- package/agents/engineering-ai-engineer.md +28 -36
- package/agents/engineering-backend-architect.md +187 -36
- package/agents/engineering-data-engineer.md +227 -43
- package/agents/engineering-devops-automator.md +229 -74
- package/agents/engineering-frontend-developer.md +223 -34
- package/agents/engineering-mobile-app-builder.md +8 -1
- package/agents/engineering-rapid-prototyper.md +45 -11
- package/agents/engineering-security-engineer.md +265 -61
- package/agents/engineering-senior-developer.md +141 -19
- package/agents/engineering-sre.md +86 -0
- package/agents/engineering-technical-writer.md +287 -41
- package/agents/feature-intel.md +111 -0
- package/agents/ios-app-review-guardian.md +21 -2
- package/agents/ios-foundation-models-specialist.md +22 -2
- package/agents/ios-product-reality-auditor.md +292 -0
- package/agents/ios-storekit-specialist.md +11 -2
- package/agents/ios-swift-architect.md +29 -1
- package/agents/ios-swift-search.md +9 -1
- package/agents/ios-swift-ui-design.md +40 -5
- package/agents/marketing-app-store-optimizer.md +248 -64
- package/agents/planner.md +221 -0
- package/agents/pr-test-analyzer.md +64 -0
- package/agents/product-feedback-synthesizer.md +70 -2
- package/agents/product-owner.md +163 -0
- package/agents/product-reality-auditor.md +216 -0
- package/agents/product-spec-writer.md +176 -0
- package/agents/refactor-cleaner.md +110 -0
- package/agents/security-reviewer.md +129 -0
- package/agents/silent-failure-hunter.md +55 -0
- package/agents/swift-build-resolver.md +121 -0
- package/agents/swift-reviewer.md +113 -0
- package/agents/tech-feasibility.md +26 -4
- package/agents/testing-api-tester.md +238 -59
- package/agents/testing-evidence-collector.md +50 -1
- package/agents/testing-performance-benchmarker.md +23 -1
- package/agents/testing-reality-checker.md +7 -1
- package/agents/visual-research.md +118 -0
- package/bin/adapters/cycle-counter-tool.ts +155 -0
- package/bin/adapters/scribe-tool.ts +73 -0
- package/bin/adapters/state-save-tool.ts +130 -0
- package/bin/adapters/write-lease-tool.ts +127 -0
- package/bin/buildanything-runtime.js +15 -0
- package/bin/buildanything-runtime.ts +241 -0
- package/bin/graph-index.js +24 -0
- package/bin/graph-index.ts +340 -0
- package/bin/mcp-servers/graph-mcp.js +26 -0
- package/bin/mcp-servers/graph-mcp.ts +481 -0
- package/bin/mcp-servers/orchestrator-mcp.js +26 -0
- package/bin/mcp-servers/orchestrator-mcp.ts +361 -0
- package/bin/setup.js +312 -76
- package/commands/add-feature.md +2 -0
- package/commands/build.md +994 -265
- package/commands/fix.md +1 -1
- package/commands/idea-sweep.md +2 -2
- package/commands/self-check.md +121 -0
- package/commands/setup.md +61 -9
- package/commands/ux-review.md +5 -5
- package/commands/verify.md +9 -9
- package/docs/migration/agents.yaml +729 -0
- package/docs/migration/phase-graph.yaml +1504 -0
- package/docs/migration/sdk-host-compat.md +18 -0
- package/hooks/compile-writer-owner-cache.ts +171 -0
- package/hooks/design-md-lint +4 -0
- package/hooks/design-md-lint.ts +295 -0
- package/hooks/hooks.json +36 -0
- package/hooks/pre-tool-use +19 -0
- package/hooks/pre-tool-use.ts +807 -0
- package/hooks/record-mode-transitions.ts +235 -0
- package/hooks/session-start +71 -1
- package/hooks/subagent-start +17 -0
- package/hooks/subagent-start.ts +472 -0
- package/hooks/subagent-stop +17 -0
- package/hooks/subagent-stop.ts +153 -0
- package/package.json +26 -4
- package/protocols/agent-prompt-authoring.md +165 -0
- package/protocols/architecture-schema.md +178 -0
- package/protocols/cleanup.md +4 -0
- package/protocols/decision-log.md +135 -0
- package/protocols/design-md-authoring.md +520 -0
- package/protocols/design-md-spec.md +362 -0
- package/protocols/fake-data-detector.md +1 -1
- package/protocols/ios-context.md +10 -11
- package/protocols/ios-fake-data-detector.md +65 -0
- package/protocols/ios-phase-branches.md +299 -39
- package/protocols/launch-readiness.md +262 -0
- package/protocols/metric-loop.md +62 -2
- package/protocols/page-spec-schema.md +234 -0
- package/protocols/product-spec-schema.md +354 -0
- package/protocols/smoke-test.md +9 -1
- package/protocols/sprint-tasks-schema.md +53 -0
- package/protocols/state-schema.json +423 -0
- package/protocols/state-schema.md +202 -0
- package/protocols/verify.md +91 -3
- package/protocols/web-phase-branches.md +395 -75
- package/skills/ios/_VENDORED.md +2 -0
- package/skills/ios/app-store-connect-metadata/SKILL.md +148 -0
- package/skills/ios/asc-privacy-manifest/SKILL.md +350 -0
- package/skills/ios/hig-components-content/SKILL.md +86 -0
- package/skills/ios/hig-components-content/references/activity-views.md +79 -0
- package/skills/ios/hig-components-content/references/charts.md +180 -0
- package/skills/ios/hig-components-content/references/collections.md +48 -0
- package/skills/ios/hig-components-content/references/color-wells.md +42 -0
- package/skills/ios/hig-components-content/references/image-views.md +82 -0
- package/skills/ios/hig-components-content/references/image-wells.md +34 -0
- package/skills/ios/hig-components-content/references/lockups.md +78 -0
- package/skills/ios/hig-components-content/references/web-views.md +36 -0
- package/skills/ios/hig-components-controls/SKILL.md +88 -0
- package/skills/ios/hig-components-controls/references/combo-boxes.md +40 -0
- package/skills/ios/hig-components-controls/references/controls.md +112 -0
- package/skills/ios/hig-components-controls/references/gauges.md +74 -0
- package/skills/ios/hig-components-controls/references/labels.md +92 -0
- package/skills/ios/hig-components-controls/references/pickers.md +128 -0
- package/skills/ios/hig-components-controls/references/rating-indicators.md +38 -0
- package/skills/ios/hig-components-controls/references/segmented-controls.md +94 -0
- package/skills/ios/hig-components-controls/references/sliders.md +92 -0
- package/skills/ios/hig-components-controls/references/steppers.md +40 -0
- package/skills/ios/hig-components-controls/references/text-fields.md +88 -0
- package/skills/ios/hig-components-controls/references/text-views.md +56 -0
- package/skills/ios/hig-components-controls/references/toggles.md +127 -0
- package/skills/ios/hig-components-controls/references/token-fields.md +48 -0
- package/skills/ios/hig-components-controls/references/virtual-keyboards.md +156 -0
- package/skills/ios/hig-components-dialogs/SKILL.md +76 -0
- package/skills/ios/hig-components-dialogs/references/action-sheets.md +74 -0
- package/skills/ios/hig-components-dialogs/references/alerts.md +158 -0
- package/skills/ios/hig-components-dialogs/references/digit-entry-views.md +32 -0
- package/skills/ios/hig-components-dialogs/references/popovers.md +81 -0
- package/skills/ios/hig-components-dialogs/references/sheets.md +157 -0
- package/skills/ios/hig-components-layout/SKILL.md +99 -0
- package/skills/ios/hig-components-layout/references/boxes.md +48 -0
- package/skills/ios/hig-components-layout/references/column-views.md +44 -0
- package/skills/ios/hig-components-layout/references/lists-and-tables.md +99 -0
- package/skills/ios/hig-components-layout/references/ornaments.md +56 -0
- package/skills/ios/hig-components-layout/references/outline-views.md +64 -0
- package/skills/ios/hig-components-layout/references/panels.md +75 -0
- package/skills/ios/hig-components-layout/references/scroll-views.md +123 -0
- package/skills/ios/hig-components-layout/references/sidebars.md +109 -0
- package/skills/ios/hig-components-layout/references/split-views.md +110 -0
- package/skills/ios/hig-components-layout/references/tab-bars.md +173 -0
- package/skills/ios/hig-components-layout/references/tab-views.md +68 -0
- package/skills/ios/hig-components-layout/references/windows.md +188 -0
- package/skills/ios/hig-components-menus/SKILL.md +81 -0
- package/skills/ios/hig-components-menus/references/action-button.md +61 -0
- package/skills/ios/hig-components-menus/references/buttons.md +261 -0
- package/skills/ios/hig-components-menus/references/context-menus.md +105 -0
- package/skills/ios/hig-components-menus/references/disclosure-controls.md +84 -0
- package/skills/ios/hig-components-menus/references/dock-menus.md +40 -0
- package/skills/ios/hig-components-menus/references/edit-menus.md +88 -0
- package/skills/ios/hig-components-menus/references/menus.md +171 -0
- package/skills/ios/hig-components-menus/references/pop-up-buttons.md +70 -0
- package/skills/ios/hig-components-menus/references/pull-down-buttons.md +77 -0
- package/skills/ios/hig-components-menus/references/the-menu-bar.md +303 -0
- package/skills/ios/hig-components-menus/references/toolbars.md +256 -0
- package/skills/ios/hig-components-search/SKILL.md +68 -0
- package/skills/ios/hig-components-search/references/page-controls.md +120 -0
- package/skills/ios/hig-components-search/references/path-controls.md +40 -0
- package/skills/ios/hig-components-search/references/search-fields.md +189 -0
- package/skills/ios/hig-components-status/SKILL.md +80 -0
- package/skills/ios/hig-components-status/references/activity-rings.md +105 -0
- package/skills/ios/hig-components-status/references/progress-indicators.md +116 -0
- package/skills/ios/hig-components-status/references/status-bars.md +38 -0
- package/skills/ios/hig-components-system/SKILL.md +88 -0
- package/skills/ios/hig-components-system/references/app-clips.md +387 -0
- package/skills/ios/hig-components-system/references/app-shortcuts.md +114 -0
- package/skills/ios/hig-components-system/references/complications.md +425 -0
- package/skills/ios/hig-components-system/references/home-screen-quick-actions.md +42 -0
- package/skills/ios/hig-components-system/references/live-activities.md +442 -0
- package/skills/ios/hig-components-system/references/notifications.md +153 -0
- package/skills/ios/hig-components-system/references/top-shelf.md +135 -0
- package/skills/ios/hig-components-system/references/watch-faces.md +40 -0
- package/skills/ios/hig-components-system/references/widgets.md +517 -0
- package/skills/ios/hig-foundations/SKILL.md +98 -0
- package/skills/ios/hig-foundations/references/accessibility.md +291 -0
- package/skills/ios/hig-foundations/references/app-icons.md +210 -0
- package/skills/ios/hig-foundations/references/branding.md +44 -0
- package/skills/ios/hig-foundations/references/color.md +274 -0
- package/skills/ios/hig-foundations/references/dark-mode.md +116 -0
- package/skills/ios/hig-foundations/references/icons.md +263 -0
- package/skills/ios/hig-foundations/references/images.md +176 -0
- package/skills/ios/hig-foundations/references/immersive-experiences.md +174 -0
- package/skills/ios/hig-foundations/references/inclusion.md +189 -0
- package/skills/ios/hig-foundations/references/layout.md +425 -0
- package/skills/ios/hig-foundations/references/materials.md +238 -0
- package/skills/ios/hig-foundations/references/motion.md +103 -0
- package/skills/ios/hig-foundations/references/privacy.md +231 -0
- package/skills/ios/hig-foundations/references/right-to-left.md +206 -0
- package/skills/ios/hig-foundations/references/sf-symbols.md +310 -0
- package/skills/ios/hig-foundations/references/spatial-layout.md +142 -0
- package/skills/ios/hig-foundations/references/typography.md +1146 -0
- package/skills/ios/hig-foundations/references/writing.md +91 -0
- package/skills/ios/hig-inputs/SKILL.md +94 -0
- package/skills/ios/hig-inputs/references/apple-pencil-and-scribble.md +148 -0
- package/skills/ios/hig-inputs/references/camera-control.md +107 -0
- package/skills/ios/hig-inputs/references/digital-crown.md +83 -0
- package/skills/ios/hig-inputs/references/eyes.md +120 -0
- package/skills/ios/hig-inputs/references/focus-and-selection.md +120 -0
- package/skills/ios/hig-inputs/references/game-controls.md +156 -0
- package/skills/ios/hig-inputs/references/gestures.md +208 -0
- package/skills/ios/hig-inputs/references/gyro-and-accelerometer.md +40 -0
- package/skills/ios/hig-inputs/references/keyboards.md +234 -0
- package/skills/ios/hig-inputs/references/nearby-interactions.md +70 -0
- package/skills/ios/hig-inputs/references/pointing-devices.md +237 -0
- package/skills/ios/hig-inputs/references/remotes.md +67 -0
- package/skills/ios/hig-inputs/references/spatial-interactions.md +70 -0
- package/skills/ios/hig-patterns/SKILL.md +104 -0
- package/skills/ios/hig-patterns/references/charting-data.md +81 -0
- package/skills/ios/hig-patterns/references/collaboration-and-sharing.md +86 -0
- package/skills/ios/hig-patterns/references/drag-and-drop.md +134 -0
- package/skills/ios/hig-patterns/references/entering-data.md +69 -0
- package/skills/ios/hig-patterns/references/feedback.md +67 -0
- package/skills/ios/hig-patterns/references/file-management.md +135 -0
- package/skills/ios/hig-patterns/references/going-full-screen.md +79 -0
- package/skills/ios/hig-patterns/references/launching.md +81 -0
- package/skills/ios/hig-patterns/references/live-viewing-apps.md +79 -0
- package/skills/ios/hig-patterns/references/loading.md +59 -0
- package/skills/ios/hig-patterns/references/managing-accounts.md +107 -0
- package/skills/ios/hig-patterns/references/managing-notifications.md +99 -0
- package/skills/ios/hig-patterns/references/modality.md +82 -0
- package/skills/ios/hig-patterns/references/multitasking.md +131 -0
- package/skills/ios/hig-patterns/references/offering-help.md +117 -0
- package/skills/ios/hig-patterns/references/onboarding.md +69 -0
- package/skills/ios/hig-patterns/references/playing-audio.md +124 -0
- package/skills/ios/hig-patterns/references/playing-haptics.md +280 -0
- package/skills/ios/hig-patterns/references/playing-video.md +180 -0
- package/skills/ios/hig-patterns/references/printing.md +50 -0
- package/skills/ios/hig-patterns/references/ratings-and-reviews.md +48 -0
- package/skills/ios/hig-patterns/references/searching.md +70 -0
- package/skills/ios/hig-patterns/references/settings.md +84 -0
- package/skills/ios/hig-patterns/references/undo-and-redo.md +58 -0
- package/skills/ios/hig-patterns/references/workouts.md +76 -0
- package/skills/ios/hig-platforms/SKILL.md +84 -0
- package/skills/ios/hig-platforms/references/designing-for-games.md +159 -0
- package/skills/ios/hig-platforms/references/designing-for-ios.md +66 -0
- package/skills/ios/hig-platforms/references/designing-for-ipados.md +64 -0
- package/skills/ios/hig-platforms/references/designing-for-macos.md +70 -0
- package/skills/ios/hig-platforms/references/designing-for-tvos.md +68 -0
- package/skills/ios/hig-platforms/references/designing-for-visionos.md +85 -0
- package/skills/ios/hig-platforms/references/designing-for-watchos.md +74 -0
- package/skills/ios/hig-project-context/SKILL.md +133 -0
- package/skills/ios/hig-technologies/SKILL.md +107 -0
- package/skills/ios/hig-technologies/references/airplay.md +125 -0
- package/skills/ios/hig-technologies/references/always-on.md +62 -0
- package/skills/ios/hig-technologies/references/apple-pay.md +441 -0
- package/skills/ios/hig-technologies/references/augmented-reality.md +247 -0
- package/skills/ios/hig-technologies/references/carekit.md +224 -0
- package/skills/ios/hig-technologies/references/carplay.md +119 -0
- package/skills/ios/hig-technologies/references/game-center.md +343 -0
- package/skills/ios/hig-technologies/references/generative-ai.md +110 -0
- package/skills/ios/hig-technologies/references/healthkit.md +120 -0
- package/skills/ios/hig-technologies/references/homekit.md +343 -0
- package/skills/ios/hig-technologies/references/icloud.md +52 -0
- package/skills/ios/hig-technologies/references/id-verifier.md +73 -0
- package/skills/ios/hig-technologies/references/imessage-apps-and-stickers.md +105 -0
- package/skills/ios/hig-technologies/references/in-app-purchase.md +263 -0
- package/skills/ios/hig-technologies/references/live-photos.md +54 -0
- package/skills/ios/hig-technologies/references/mac-catalyst.md +216 -0
- package/skills/ios/hig-technologies/references/machine-learning.md +394 -0
- package/skills/ios/hig-technologies/references/maps.md +221 -0
- package/skills/ios/hig-technologies/references/nfc.md +51 -0
- package/skills/ios/hig-technologies/references/photo-editing.md +40 -0
- package/skills/ios/hig-technologies/references/researchkit.md +134 -0
- package/skills/ios/hig-technologies/references/shareplay.md +142 -0
- package/skills/ios/hig-technologies/references/shazamkit.md +47 -0
- package/skills/ios/hig-technologies/references/sign-in-with-apple.md +288 -0
- package/skills/ios/hig-technologies/references/siri.md +523 -0
- package/skills/ios/hig-technologies/references/tap-to-pay-on-iphone.md +208 -0
- package/skills/ios/hig-technologies/references/voiceover.md +90 -0
- package/skills/ios/hig-technologies/references/wallet.md +420 -0
- package/skills/ios/ios-bootstrap/SKILL.md +17 -8
- package/skills/ios/swift-actor-persistence/SKILL.md +143 -0
- package/skills/ios/swift-concurrency-6-2/SKILL.md +216 -0
- package/skills/ios/swift-protocol-di-testing/SKILL.md +190 -0
- package/skills/ios/swiftui-design-tokens/SKILL.md +475 -0
- package/skills/ios/writing-for-interfaces/SKILL.md +75 -0
- package/skills/web/accessibility/SKILL.md +146 -0
- package/skills/web/aceternity-ui/SKILL.md +719 -0
- package/skills/web/aceternity-ui/metadata.json +10 -0
- package/skills/web/api-design/SKILL.md +523 -0
- package/skills/web/chart-accessibility/SKILL.md +332 -0
- package/skills/web/composition-patterns/AGENTS.md +946 -0
- package/skills/web/composition-patterns/README.md +60 -0
- package/skills/web/composition-patterns/SKILL.md +89 -0
- package/skills/web/composition-patterns/metadata.json +11 -0
- package/skills/web/composition-patterns/rules/_sections.md +29 -0
- package/skills/web/composition-patterns/rules/_template.md +24 -0
- package/skills/web/composition-patterns/rules/architecture-avoid-boolean-props.md +100 -0
- package/skills/web/composition-patterns/rules/architecture-compound-components.md +112 -0
- package/skills/web/composition-patterns/rules/patterns-children-over-render-props.md +87 -0
- package/skills/web/composition-patterns/rules/patterns-explicit-variants.md +100 -0
- package/skills/web/composition-patterns/rules/react19-no-forwardref.md +42 -0
- package/skills/web/composition-patterns/rules/state-context-interface.md +191 -0
- package/skills/web/composition-patterns/rules/state-decouple-implementation.md +113 -0
- package/skills/web/composition-patterns/rules/state-lift-state.md +125 -0
- package/skills/web/cost-aware-llm-pipeline/SKILL.md +183 -0
- package/skills/web/database-migrations/SKILL.md +429 -0
- package/skills/web/deployment-patterns/SKILL.md +427 -0
- package/skills/web/docker-patterns/SKILL.md +364 -0
- package/skills/web/e2e-testing/SKILL.md +326 -0
- package/skills/web/lighthouse-ci/SKILL.md +361 -0
- package/skills/web/mcp-server-patterns/SKILL.md +69 -0
- package/skills/web/next-best-practices/SKILL.md +153 -0
- package/skills/web/next-best-practices/async-patterns.md +87 -0
- package/skills/web/next-best-practices/bundling.md +180 -0
- package/skills/web/next-best-practices/data-patterns.md +297 -0
- package/skills/web/next-best-practices/debug-tricks.md +105 -0
- package/skills/web/next-best-practices/directives.md +73 -0
- package/skills/web/next-best-practices/error-handling.md +227 -0
- package/skills/web/next-best-practices/file-conventions.md +140 -0
- package/skills/web/next-best-practices/font.md +245 -0
- package/skills/web/next-best-practices/functions.md +108 -0
- package/skills/web/next-best-practices/hydration-error.md +91 -0
- package/skills/web/next-best-practices/image.md +173 -0
- package/skills/web/next-best-practices/metadata.md +301 -0
- package/skills/web/next-best-practices/parallel-routes.md +287 -0
- package/skills/web/next-best-practices/route-handlers.md +146 -0
- package/skills/web/next-best-practices/rsc-boundaries.md +159 -0
- package/skills/web/next-best-practices/runtime-selection.md +39 -0
- package/skills/web/next-best-practices/scripts.md +141 -0
- package/skills/web/next-best-practices/self-hosting.md +371 -0
- package/skills/web/next-best-practices/suspense-boundaries.md +67 -0
- package/skills/web/next-cache-components/SKILL.md +411 -0
- package/skills/web/postgres-best-practices/SKILL.md +14 -0
- package/skills/web/postgres-best-practices/references/schema-design.md +9 -0
- package/skills/web/react-best-practices/AGENTS.md +3810 -0
- package/skills/web/react-best-practices/README.md +123 -0
- package/skills/web/react-best-practices/SKILL.md +149 -0
- package/skills/web/react-best-practices/metadata.json +15 -0
- package/skills/web/react-best-practices/rules/_sections.md +46 -0
- package/skills/web/react-best-practices/rules/_template.md +28 -0
- package/skills/web/react-best-practices/rules/advanced-effect-event-deps.md +56 -0
- package/skills/web/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/skills/web/react-best-practices/rules/advanced-init-once.md +42 -0
- package/skills/web/react-best-practices/rules/advanced-use-latest.md +39 -0
- package/skills/web/react-best-practices/rules/async-api-routes.md +38 -0
- package/skills/web/react-best-practices/rules/async-cheap-condition-before-await.md +37 -0
- package/skills/web/react-best-practices/rules/async-defer-await.md +82 -0
- package/skills/web/react-best-practices/rules/async-dependencies.md +51 -0
- package/skills/web/react-best-practices/rules/async-parallel.md +28 -0
- package/skills/web/react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/skills/web/react-best-practices/rules/bundle-analyzable-paths.md +63 -0
- package/skills/web/react-best-practices/rules/bundle-barrel-imports.md +60 -0
- package/skills/web/react-best-practices/rules/bundle-conditional.md +31 -0
- package/skills/web/react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/skills/web/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/skills/web/react-best-practices/rules/bundle-preload.md +50 -0
- package/skills/web/react-best-practices/rules/client-event-listeners.md +74 -0
- package/skills/web/react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/skills/web/react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/skills/web/react-best-practices/rules/client-swr-dedup.md +56 -0
- package/skills/web/react-best-practices/rules/js-batch-dom-css.md +107 -0
- package/skills/web/react-best-practices/rules/js-cache-function-results.md +80 -0
- package/skills/web/react-best-practices/rules/js-cache-property-access.md +28 -0
- package/skills/web/react-best-practices/rules/js-cache-storage.md +70 -0
- package/skills/web/react-best-practices/rules/js-combine-iterations.md +32 -0
- package/skills/web/react-best-practices/rules/js-early-exit.md +50 -0
- package/skills/web/react-best-practices/rules/js-flatmap-filter.md +60 -0
- package/skills/web/react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/skills/web/react-best-practices/rules/js-index-maps.md +37 -0
- package/skills/web/react-best-practices/rules/js-length-check-first.md +49 -0
- package/skills/web/react-best-practices/rules/js-min-max-loop.md +82 -0
- package/skills/web/react-best-practices/rules/js-request-idle-callback.md +105 -0
- package/skills/web/react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/skills/web/react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/skills/web/react-best-practices/rules/rendering-activity.md +26 -0
- package/skills/web/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/skills/web/react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/skills/web/react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/skills/web/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/skills/web/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/skills/web/react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
- package/skills/web/react-best-practices/rules/rendering-resource-hints.md +85 -0
- package/skills/web/react-best-practices/rules/rendering-script-defer-async.md +68 -0
- package/skills/web/react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/skills/web/react-best-practices/rules/rendering-usetransition-loading.md +75 -0
- package/skills/web/react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/skills/web/react-best-practices/rules/rerender-dependencies.md +45 -0
- package/skills/web/react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
- package/skills/web/react-best-practices/rules/rerender-derived-state.md +29 -0
- package/skills/web/react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/skills/web/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/skills/web/react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
- package/skills/web/react-best-practices/rules/rerender-memo.md +44 -0
- package/skills/web/react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
- package/skills/web/react-best-practices/rules/rerender-no-inline-components.md +82 -0
- package/skills/web/react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
- package/skills/web/react-best-practices/rules/rerender-split-combined-hooks.md +64 -0
- package/skills/web/react-best-practices/rules/rerender-transitions.md +40 -0
- package/skills/web/react-best-practices/rules/rerender-use-deferred-value.md +59 -0
- package/skills/web/react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
- package/skills/web/react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/skills/web/react-best-practices/rules/server-auth-actions.md +96 -0
- package/skills/web/react-best-practices/rules/server-cache-lru.md +41 -0
- package/skills/web/react-best-practices/rules/server-cache-react.md +76 -0
- package/skills/web/react-best-practices/rules/server-dedup-props.md +65 -0
- package/skills/web/react-best-practices/rules/server-hoist-static-io.md +149 -0
- package/skills/web/react-best-practices/rules/server-no-shared-module-state.md +50 -0
- package/skills/web/react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/skills/web/react-best-practices/rules/server-parallel-nested-fetching.md +34 -0
- package/skills/web/react-best-practices/rules/server-serialization.md +38 -0
- package/skills/web/seo/SKILL.md +154 -0
- package/skills/web/web-design-guidelines/SKILL.md +39 -0
- package/skills/web/zap-scan-config/SKILL.md +444 -0
- package/skills/web/zap-scan-config/assets/.gitkeep +9 -0
- package/skills/web/zap-scan-config/assets/github_action.yml +207 -0
- package/skills/web/zap-scan-config/assets/gitlab_ci.yml +226 -0
- package/skills/web/zap-scan-config/assets/zap_automation.yaml +196 -0
- package/skills/web/zap-scan-config/assets/zap_context.xml +192 -0
- package/skills/web/zap-scan-config/references/EXAMPLE.md +40 -0
- package/skills/web/zap-scan-config/references/api_testing_guide.md +475 -0
- package/skills/web/zap-scan-config/references/authentication_guide.md +431 -0
- package/skills/web/zap-scan-config/references/false_positive_handling.md +427 -0
- package/skills/web/zap-scan-config/references/owasp_mapping.md +255 -0
- package/src/graph/ids.ts +86 -0
- package/src/graph/index.ts +32 -0
- package/src/graph/parser/architecture.ts +603 -0
- package/src/graph/parser/component-manifest.ts +268 -0
- package/src/graph/parser/decisions-jsonl.ts +407 -0
- package/src/graph/parser/design-md-pass2.ts +253 -0
- package/src/graph/parser/design-md.ts +477 -0
- package/src/graph/parser/page-spec.ts +496 -0
- package/src/graph/parser/product-spec.ts +930 -0
- package/src/graph/parser/screenshot.ts +342 -0
- package/src/graph/parser/sprint-tasks.ts +317 -0
- package/src/graph/storage/index.ts +1154 -0
- package/src/graph/types.ts +432 -0
- package/src/graph/util/dhash.ts +84 -0
- package/src/lrr/aggregator.ts +175 -0
- package/src/orchestrator/hooks/context-header.ts +119 -0
- package/src/orchestrator/hooks/token-accounting-emitter.ts +77 -0
- package/src/orchestrator/hooks/token-accounting.ts +112 -0
- package/src/orchestrator/mcp/cycle-counter.ts +130 -0
- package/src/orchestrator/mcp/scribe.ts +294 -0
- package/src/orchestrator/mcp/state-save.ts +149 -0
- package/src/orchestrator/mcp/write-lease.ts +184 -0
- package/src/orchestrator/phase4-shared-context.ts +57 -0
- package/src/orchestrator/schemas/backward-edge.ts +46 -0
- package/agents/agentic-identity-trust.md +0 -121
- package/agents/data-consolidation-agent.md +0 -39
- package/agents/design-image-prompt-engineer.md +0 -105
- package/agents/design-visual-storyteller.md +0 -147
- package/agents/design-whimsy-injector.md +0 -89
- package/agents/engineering-autonomous-optimization-architect.md +0 -105
- package/agents/market-intel.md +0 -35
- package/agents/marketing-instagram-curator.md +0 -111
- package/agents/marketing-reddit-community-builder.md +0 -121
- package/agents/marketing-social-media-strategist.md +0 -74
- package/agents/marketing-tiktok-strategist.md +0 -123
- package/agents/marketing-twitter-engager.md +0 -124
- package/agents/marketing-wechat-official-account.md +0 -143
- package/agents/marketing-xiaohongshu-specialist.md +0 -136
- package/agents/marketing-zhihu-strategist.md +0 -160
- package/agents/product-behavioral-nudge-engine.md +0 -78
- package/agents/project-management-experiment-tracker.md +0 -102
- package/agents/report-distribution-agent.md +0 -43
- package/agents/risk-analysis.md +0 -45
- package/agents/sales-data-extraction-agent.md +0 -46
- package/agents/specialized-cultural-intelligence-strategist.md +0 -65
- package/agents/specialized-developer-advocate.md +0 -146
- package/agents/support-analytics-reporter.md +0 -133
- package/agents/support-executive-summary-generator.md +0 -64
- package/agents/support-finance-tracker.md +0 -145
- package/agents/support-legal-compliance-checker.md +0 -129
- package/agents/support-support-responder.md +0 -91
- package/agents/testing-accessibility-auditor.md +0 -110
- package/agents/testing-test-results-analyzer.md +0 -97
- package/agents/testing-tool-evaluator.md +0 -76
- package/agents/testing-workflow-optimizer.md +0 -99
- package/agents/user-research.md +0 -40
- package/protocols/brainstorm.md +0 -99
- package/protocols/design.md +0 -269
- package/protocols/planning.md +0 -87
- package/skills/ios/ios-hig/SKILL.md +0 -41
- package/skills/ios/ios-hig/references/accessibility.md +0 -81
- package/skills/ios/ios-hig/references/content.md +0 -142
- package/skills/ios/ios-hig/references/feedback.md +0 -123
- package/skills/ios/ios-hig/references/interaction.md +0 -199
- package/skills/ios/ios-hig/references/performance-platform.md +0 -129
- package/skills/ios/ios-hig/references/privacy-permissions.md +0 -181
- package/skills/ios/ios-hig/references/visual-design.md +0 -84
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# SDK / Host Compatibility Matrix
|
|
2
|
+
|
|
3
|
+
Tracks validated Claude Code host version ranges for each SDK pin version.
|
|
4
|
+
Used to gate SDK features and ensure runtime compatibility across migration stages.
|
|
5
|
+
|
|
6
|
+
## Compatibility Table
|
|
7
|
+
|
|
8
|
+
| SDK Version | Host Range (semver) | Validated Date | Notes |
|
|
9
|
+
|-------------|---------------------|----------------|-------|
|
|
10
|
+
| `0.1.0` | `>=1.5.0 <3.0.0` | 2026-04-18 | Initial pin — Stage 1 bootstrap |
|
|
11
|
+
|
|
12
|
+
## Update Policy
|
|
13
|
+
|
|
14
|
+
Updated per Stage release. Each row represents a tested SDK pin version with its validated Claude Code host range. The `claudeCodeHostRange` field in `.claude-plugin/plugin.json` must match the latest row.
|
|
15
|
+
|
|
16
|
+
## Degradation Behavior
|
|
17
|
+
|
|
18
|
+
If the host does not expose `CLAUDE_CODE_VERSION`, the version probe no-ops (logged, not errored). Fallback: markdown mode with user-visible warning.
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/*
|
|
3
|
+
* buildanything: compile writer-owner cache (tasks 2.1.2, 2.1.3).
|
|
4
|
+
*
|
|
5
|
+
* Called from hooks/session-start once per session. Reads the plugin's
|
|
6
|
+
* docs/migration/phase-graph.yaml, flattens the artifacts table into a
|
|
7
|
+
* JSON cache the PreToolUse handler can read without parsing YAML on every
|
|
8
|
+
* tool call.
|
|
9
|
+
*
|
|
10
|
+
* Task 2.1.3 additive: also encodes `phase_internal_scratch.path_glob` as
|
|
11
|
+
* `scratch_globs` so the handler can exempt scratch paths from default-deny
|
|
12
|
+
* without re-parsing YAML. Still version 1 — new field is additive.
|
|
13
|
+
*
|
|
14
|
+
* Usage: tsx hooks/compile-writer-owner-cache.ts <source-yaml> <output-json>
|
|
15
|
+
*
|
|
16
|
+
* Exits 0 on success. Exits 1 (with stderr) on any failure so session-start
|
|
17
|
+
* can log a warning and continue — the handler falls back to live YAML parse.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { createHash } from "node:crypto";
|
|
21
|
+
import { mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
22
|
+
import { dirname, resolve } from "node:path";
|
|
23
|
+
import process from "node:process";
|
|
24
|
+
import { parse as parseYaml } from "yaml";
|
|
25
|
+
|
|
26
|
+
interface RawArtifact {
|
|
27
|
+
path: string;
|
|
28
|
+
writer?: string;
|
|
29
|
+
writers?: string[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface RawScratch {
|
|
33
|
+
path_glob?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface PhaseGraph {
|
|
37
|
+
artifacts?: RawArtifact[];
|
|
38
|
+
phase_internal_scratch?: RawScratch;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface CompiledArtifact {
|
|
42
|
+
path: string;
|
|
43
|
+
writers: string[];
|
|
44
|
+
is_glob: boolean;
|
|
45
|
+
regex?: string;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
interface CompiledScratchGlob {
|
|
49
|
+
glob: string;
|
|
50
|
+
regex: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
interface Cache {
|
|
54
|
+
version: 1;
|
|
55
|
+
source_sha: string;
|
|
56
|
+
source_mtime: number;
|
|
57
|
+
compiled_at: string;
|
|
58
|
+
artifacts: CompiledArtifact[];
|
|
59
|
+
// Additive v1 field (task 2.1.3): globs from `phase_internal_scratch` that
|
|
60
|
+
// must be exempt from default-deny. Writers: any phase.
|
|
61
|
+
scratch_globs: CompiledScratchGlob[];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const CACHE_VERSION = 1;
|
|
65
|
+
|
|
66
|
+
function globToRegex(pattern: string): string {
|
|
67
|
+
let out = "";
|
|
68
|
+
for (let i = 0; i < pattern.length; i += 1) {
|
|
69
|
+
const ch = pattern[i];
|
|
70
|
+
if (ch === "*") {
|
|
71
|
+
if (pattern[i + 1] === "*") {
|
|
72
|
+
out += ".*";
|
|
73
|
+
i += 1;
|
|
74
|
+
} else {
|
|
75
|
+
out += "[^/]*";
|
|
76
|
+
}
|
|
77
|
+
} else if (ch === "{") {
|
|
78
|
+
// Brace expansion: {md,json} -> (md|json). Flat alternation only (no nesting).
|
|
79
|
+
const close = pattern.indexOf("}", i);
|
|
80
|
+
if (close === -1) {
|
|
81
|
+
out += "\\{";
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const parts = pattern.slice(i + 1, close).split(",").map((p) =>
|
|
85
|
+
p.replace(/[.+?^${}()|[\]\\]/g, (m) => `\\${m}`),
|
|
86
|
+
);
|
|
87
|
+
out += `(?:${parts.join("|")})`;
|
|
88
|
+
i = close;
|
|
89
|
+
} else if (/[.+?^${}()|[\]\\]/.test(ch)) {
|
|
90
|
+
out += `\\${ch}`;
|
|
91
|
+
} else {
|
|
92
|
+
out += ch;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return `^${out}$`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function compile(sourcePath: string): Cache {
|
|
99
|
+
const text = readFileSync(sourcePath, "utf8");
|
|
100
|
+
const stat = statSync(sourcePath);
|
|
101
|
+
const sha = createHash("sha256").update(text).digest("hex");
|
|
102
|
+
const doc = parseYaml(text) as PhaseGraph;
|
|
103
|
+
const rawArtifacts = Array.isArray(doc?.artifacts) ? doc.artifacts : [];
|
|
104
|
+
|
|
105
|
+
const compiled: CompiledArtifact[] = rawArtifacts.map((a) => {
|
|
106
|
+
const writers: string[] = [];
|
|
107
|
+
if (a.writer) writers.push(String(a.writer).trim());
|
|
108
|
+
if (Array.isArray(a.writers)) {
|
|
109
|
+
for (const w of a.writers) writers.push(String(w).trim());
|
|
110
|
+
}
|
|
111
|
+
const hasGlobChar = a.path.includes("*");
|
|
112
|
+
const hasBracketPlaceholder = /\[[^\]]+\]/.test(a.path);
|
|
113
|
+
const is_glob = hasGlobChar || hasBracketPlaceholder;
|
|
114
|
+
const entry: CompiledArtifact = {
|
|
115
|
+
path: a.path,
|
|
116
|
+
writers: writers.filter(Boolean),
|
|
117
|
+
is_glob,
|
|
118
|
+
};
|
|
119
|
+
if (is_glob) {
|
|
120
|
+
const normalized = a.path.replace(/\[[^\]]+\]/g, "*");
|
|
121
|
+
entry.regex = globToRegex(normalized);
|
|
122
|
+
}
|
|
123
|
+
return entry;
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const scratchGlobs: CompiledScratchGlob[] = [];
|
|
127
|
+
const scratchGlob = doc?.phase_internal_scratch?.path_glob;
|
|
128
|
+
if (typeof scratchGlob === "string" && scratchGlob.trim()) {
|
|
129
|
+
scratchGlobs.push({ glob: scratchGlob, regex: globToRegex(scratchGlob) });
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
version: CACHE_VERSION,
|
|
134
|
+
source_sha: sha,
|
|
135
|
+
source_mtime: Math.floor(stat.mtimeMs),
|
|
136
|
+
compiled_at: new Date().toISOString(),
|
|
137
|
+
artifacts: compiled,
|
|
138
|
+
scratch_globs: scratchGlobs,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function main(): number {
|
|
143
|
+
const [sourceArg, outputArg] = process.argv.slice(2);
|
|
144
|
+
if (!sourceArg || !outputArg) {
|
|
145
|
+
process.stderr.write(
|
|
146
|
+
"compile-writer-owner-cache: usage: <source-yaml> <output-json>\n",
|
|
147
|
+
);
|
|
148
|
+
return 1;
|
|
149
|
+
}
|
|
150
|
+
const source = resolve(sourceArg);
|
|
151
|
+
const output = resolve(outputArg);
|
|
152
|
+
let cache: Cache;
|
|
153
|
+
try {
|
|
154
|
+
cache = compile(source);
|
|
155
|
+
} catch (err) {
|
|
156
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
157
|
+
process.stderr.write(`compile-writer-owner-cache: ${msg}\n`);
|
|
158
|
+
return 1;
|
|
159
|
+
}
|
|
160
|
+
try {
|
|
161
|
+
mkdirSync(dirname(output), { recursive: true });
|
|
162
|
+
writeFileSync(output, `${JSON.stringify(cache, null, 2)}\n`, "utf8");
|
|
163
|
+
} catch (err) {
|
|
164
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
165
|
+
process.stderr.write(`compile-writer-owner-cache: write failed: ${msg}\n`);
|
|
166
|
+
return 1;
|
|
167
|
+
}
|
|
168
|
+
return 0;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
process.exit(main());
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/*
|
|
3
|
+
* buildanything: DESIGN.md lint runner (Phase 3 Step 3.8 gate).
|
|
4
|
+
*
|
|
5
|
+
* Runs the pinned @google/design.md linter (devDependency in package.json) via
|
|
6
|
+
* `npx --no-install` against the DESIGN.md at the current working directory.
|
|
7
|
+
* Auto-installs the pinned version on first use if the package is listed in
|
|
8
|
+
* package.json devDependencies but not yet in node_modules — runs plain
|
|
9
|
+
* `npm install` (no args) so package.json is not mutated. Classifies findings
|
|
10
|
+
* (broken-ref => error, everything else => warning per
|
|
11
|
+
* protocols/design-md-authoring.md §8),
|
|
12
|
+
* writes a JSON summary to .buildanything/graph/lint-status.json (consumed by
|
|
13
|
+
* src/graph/storage/index.ts queryDna lint_status field), and appends a
|
|
14
|
+
* one-line summary to docs/plans/build-log.md under
|
|
15
|
+
* `## Phase 3 Step 3.8 — DESIGN.md Lint`.
|
|
16
|
+
*
|
|
17
|
+
* Exit codes:
|
|
18
|
+
* 0 — pass (broken-refs == 0; warnings allowed)
|
|
19
|
+
* 2 — fail (broken-refs > 0; orchestrator routes back to Step 3.4)
|
|
20
|
+
* 3 — DESIGN.md missing
|
|
21
|
+
*
|
|
22
|
+
* Invocation:
|
|
23
|
+
* npx tsx hooks/design-md-lint.ts # run inside project root
|
|
24
|
+
* hooks/design-md-lint # via bash wrapper
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { spawnSync } from "node:child_process";
|
|
28
|
+
import { createHash } from "node:crypto";
|
|
29
|
+
import { existsSync, mkdirSync, readFileSync, appendFileSync, writeFileSync, renameSync } from "node:fs";
|
|
30
|
+
import { dirname, resolve } from "node:path";
|
|
31
|
+
import process from "node:process";
|
|
32
|
+
import YAML from "yaml";
|
|
33
|
+
|
|
34
|
+
interface LintFinding {
|
|
35
|
+
rule: string;
|
|
36
|
+
severity: "error" | "warning" | "info";
|
|
37
|
+
message: string;
|
|
38
|
+
line?: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
interface LintSummary {
|
|
42
|
+
file_hash: string;
|
|
43
|
+
broken_refs: number;
|
|
44
|
+
warnings: LintFinding[];
|
|
45
|
+
errors: LintFinding[];
|
|
46
|
+
ran_at: string;
|
|
47
|
+
exit_code: number;
|
|
48
|
+
raw_stdout: string;
|
|
49
|
+
raw_stderr: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const BROKEN_REF_RULES = new Set(["broken-ref"]);
|
|
53
|
+
|
|
54
|
+
function sha256(content: string): string {
|
|
55
|
+
return createHash("sha256").update(content).digest("hex");
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function ensureDir(filePath: string): void {
|
|
59
|
+
const dir = dirname(filePath);
|
|
60
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Atomic write — tmp + rename so a crash mid-write never leaves a partial
|
|
64
|
+
// JSON that graph/storage queryDna would fail to parse.
|
|
65
|
+
function atomicWrite(path: string, content: string): void {
|
|
66
|
+
ensureDir(path);
|
|
67
|
+
const tmp = `${path}.tmp`;
|
|
68
|
+
writeFileSync(tmp, content);
|
|
69
|
+
renameSync(tmp, path);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function parseFindings(stdout: string): LintFinding[] {
|
|
73
|
+
const findings: LintFinding[] = [];
|
|
74
|
+
for (const raw of stdout.split(/\r?\n/)) {
|
|
75
|
+
const line = raw.trim();
|
|
76
|
+
if (!line) continue;
|
|
77
|
+
const m = line.match(/^DESIGN\.md(?::(\d+))?\s+(error|warn|warning|info)\s+([\w-]+)\s+(.+)$/i);
|
|
78
|
+
if (!m) continue;
|
|
79
|
+
const sev = m[2].toLowerCase();
|
|
80
|
+
const severity: LintFinding["severity"] =
|
|
81
|
+
sev === "error" ? "error" : sev === "info" ? "info" : "warning";
|
|
82
|
+
findings.push({
|
|
83
|
+
rule: m[3],
|
|
84
|
+
severity,
|
|
85
|
+
message: m[4],
|
|
86
|
+
line: m[1] ? Number(m[1]) : undefined,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
return findings;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
interface PackageJson {
|
|
93
|
+
devDependencies?: Record<string, string>;
|
|
94
|
+
dependencies?: Record<string, string>;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Returns true if @google/design.md is pinned in package.json devDependencies
|
|
99
|
+
* (or dependencies) but is NOT installed under node_modules. This is the
|
|
100
|
+
* narrow window where auto-install is safe — the package is "ours" to install.
|
|
101
|
+
* Returns false in any other state (missing package.json, missing pin,
|
|
102
|
+
* already installed, parse error) so the caller falls through to existing
|
|
103
|
+
* behavior.
|
|
104
|
+
*/
|
|
105
|
+
function shouldAutoInstall(cwd: string): boolean {
|
|
106
|
+
const pkgPath = resolve(cwd, "package.json");
|
|
107
|
+
if (!existsSync(pkgPath)) return false;
|
|
108
|
+
let pkg: PackageJson;
|
|
109
|
+
try {
|
|
110
|
+
pkg = JSON.parse(readFileSync(pkgPath, "utf8")) as PackageJson;
|
|
111
|
+
} catch {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
const pinned =
|
|
115
|
+
pkg.devDependencies?.["@google/design.md"] ??
|
|
116
|
+
pkg.dependencies?.["@google/design.md"];
|
|
117
|
+
if (!pinned) return false;
|
|
118
|
+
// Installed if the package directory exists. We don't validate the
|
|
119
|
+
// version range here — npm install will reconcile against package-lock.
|
|
120
|
+
const installedPath = resolve(cwd, "node_modules", "@google", "design.md");
|
|
121
|
+
return !existsSync(installedPath);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function main(): number {
|
|
125
|
+
const cwd = process.cwd();
|
|
126
|
+
const designMd = resolve(cwd, "DESIGN.md");
|
|
127
|
+
if (!existsSync(designMd)) {
|
|
128
|
+
process.stderr.write(`design-md-lint: DESIGN.md not found at ${designMd}\n`);
|
|
129
|
+
return 3;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const fileContent = readFileSync(designMd, "utf8");
|
|
133
|
+
const fileHash = sha256(fileContent);
|
|
134
|
+
|
|
135
|
+
// First attempt: --no-install ensures we use the pinned version from
|
|
136
|
+
// package.json (devDependency). If the package isn't installed locally,
|
|
137
|
+
// we auto-install once below rather than silently fetching latest from
|
|
138
|
+
// npm — that's the whole point of pinning.
|
|
139
|
+
const runLint = () =>
|
|
140
|
+
spawnSync("npx", ["--no-install", "@google/design.md", "lint", "DESIGN.md"], {
|
|
141
|
+
cwd,
|
|
142
|
+
encoding: "utf8",
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
let lint = runLint();
|
|
146
|
+
|
|
147
|
+
// Auto-install fallback: only fires when the package is pinned in
|
|
148
|
+
// package.json but missing from node_modules. We run plain `npm install`
|
|
149
|
+
// (no args, no --save-dev) — that installs from the existing devDeps
|
|
150
|
+
// block and does NOT mutate package.json or package-lock.json beyond
|
|
151
|
+
// what npm already does for normal install resolution.
|
|
152
|
+
const linterNotInstalled = lint.error || (lint.status !== null && lint.status !== 0 && /could not determine|could not find/i.test(lint.stderr ?? ""));
|
|
153
|
+
if (linterNotInstalled && shouldAutoInstall(cwd)) {
|
|
154
|
+
process.stdout.write("design-md-lint: pinned linter not installed; running 'npm install' once (~5-15s)...\n");
|
|
155
|
+
const install = spawnSync("npm", ["install", "--silent"], {
|
|
156
|
+
cwd,
|
|
157
|
+
encoding: "utf8",
|
|
158
|
+
});
|
|
159
|
+
if (install.status === 0) {
|
|
160
|
+
lint = runLint();
|
|
161
|
+
} else {
|
|
162
|
+
process.stderr.write(`design-md-lint: auto-install failed (exit ${install.status}). Run 'npm install' from the plugin root manually.\n`);
|
|
163
|
+
if (install.stderr) process.stderr.write(install.stderr);
|
|
164
|
+
return 2;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const stdout = lint.stdout ?? "";
|
|
169
|
+
const stderr = lint.stderr ?? "";
|
|
170
|
+
|
|
171
|
+
if (lint.error) {
|
|
172
|
+
process.stderr.write(`design-md-lint: linter spawn failed: ${lint.error.message}\n`);
|
|
173
|
+
process.stderr.write(`design-md-lint: install pinned version with: npm install --save-dev @google/design.md\n`);
|
|
174
|
+
process.stderr.write(stderr);
|
|
175
|
+
return 2;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const findings = parseFindings(stdout);
|
|
179
|
+
const errors = findings.filter((f) => f.severity === "error" && BROKEN_REF_RULES.has(f.rule));
|
|
180
|
+
const warnings = findings.filter((f) => f.severity === "warning" || (f.severity === "error" && !BROKEN_REF_RULES.has(f.rule)));
|
|
181
|
+
const infos: LintFinding[] = [];
|
|
182
|
+
|
|
183
|
+
// §9.5 iOS-specific post-process checks (gated on project_type=ios).
|
|
184
|
+
const buildStatePath = resolve(cwd, "docs/plans/.build-state.json");
|
|
185
|
+
if (existsSync(buildStatePath)) {
|
|
186
|
+
try {
|
|
187
|
+
const bs = JSON.parse(readFileSync(buildStatePath, "utf8")) as Record<string, unknown>;
|
|
188
|
+
if (bs.project_type === "ios") {
|
|
189
|
+
// Parse YAML frontmatter for token inspection.
|
|
190
|
+
const fmMatch = fileContent.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
191
|
+
const fmYaml = fmMatch ? fmMatch[1] : "";
|
|
192
|
+
let fm: Record<string, unknown> = {};
|
|
193
|
+
try { fm = YAML.parse(fmYaml) ?? {}; } catch { /* skip if unparseable */ }
|
|
194
|
+
|
|
195
|
+
const colors = (typeof fm.colors === "object" && fm.colors !== null) ? fm.colors as Record<string, unknown> : {};
|
|
196
|
+
const typography = (typeof fm.typography === "object" && fm.typography !== null) ? fm.typography as Record<string, unknown> : {};
|
|
197
|
+
const components = (typeof fm.components === "object" && fm.components !== null) ? fm.components as Record<string, unknown> : {};
|
|
198
|
+
|
|
199
|
+
// 1. Dark-pair rule: every color token needs a -dark counterpart.
|
|
200
|
+
const colorKeys = Object.keys(colors);
|
|
201
|
+
for (const ck of colorKeys) {
|
|
202
|
+
if (ck.endsWith("-dark")) continue;
|
|
203
|
+
if (!colorKeys.includes(`${ck}-dark`)) {
|
|
204
|
+
warnings.push({ rule: "ios-dark-pair", severity: "warning", message: `colors.${ck} has no -dark pair for dark mode` });
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// 2. Dynamic Type role check: typography tokens should match iOS roles.
|
|
209
|
+
const DYNAMIC_TYPE_ROLES = new Set(["largeTitle", "title", "title2", "title3", "headline", "body", "callout", "subheadline", "footnote", "caption", "caption2"]);
|
|
210
|
+
for (const tk of Object.keys(typography)) {
|
|
211
|
+
if (!DYNAMIC_TYPE_ROLES.has(tk)) {
|
|
212
|
+
warnings.push({ rule: "ios-dynamic-type", severity: "warning", message: `typography.${tk} is not a Dynamic Type role — fixed-size Font, breaks accessibility scaling` });
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// 3. iOS 26 gating: Glassy material + iOS 26 → require card-glass/button-tinted.
|
|
217
|
+
const dnaMatch = fileContent.match(/###\s*Brand DNA[\s\S]*?(?=###|\n##\s|$)/);
|
|
218
|
+
const dnaBlock = dnaMatch ? dnaMatch[0] : "";
|
|
219
|
+
const materialMatch = dnaBlock.match(/Material\s*:\s*(.+)/i);
|
|
220
|
+
const material = materialMatch ? materialMatch[1].trim() : "";
|
|
221
|
+
const iosFeatures = Array.isArray(bs.ios_features) ? bs.ios_features as string[] : [];
|
|
222
|
+
const targetsIos26 = iosFeatures.some((f) => /ios\s*26|26\s*sdk/i.test(String(f)));
|
|
223
|
+
const isGlassy = /glassy/i.test(material);
|
|
224
|
+
const compKeys = Object.keys(components);
|
|
225
|
+
|
|
226
|
+
if (isGlassy && targetsIos26) {
|
|
227
|
+
if (!compKeys.includes("card-glass")) infos.push({ rule: "ios26-glassy-gate", severity: "info", message: "Material=Glassy + iOS 26 target but components.card-glass is missing" });
|
|
228
|
+
if (!compKeys.includes("button-tinted")) infos.push({ rule: "ios26-glassy-gate", severity: "info", message: "Material=Glassy + iOS 26 target but components.button-tinted is missing" });
|
|
229
|
+
} else if (!isGlassy) {
|
|
230
|
+
if (compKeys.includes("card-glass")) infos.push({ rule: "ios26-glassy-gate", severity: "info", message: "Material is not Glassy but components.card-glass is present — remove it" });
|
|
231
|
+
if (compKeys.includes("button-tinted")) infos.push({ rule: "ios26-glassy-gate", severity: "info", message: "Material is not Glassy but components.button-tinted is present — remove it" });
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
} catch { /* build-state unreadable — skip iOS checks */ }
|
|
235
|
+
}
|
|
236
|
+
const brokenRefs = errors.length;
|
|
237
|
+
const exitCode = brokenRefs > 0 ? 2 : 0;
|
|
238
|
+
|
|
239
|
+
const ranAt = new Date().toISOString();
|
|
240
|
+
const status: "pass" | "warn" | "fail" =
|
|
241
|
+
brokenRefs > 0 ? "fail" : (warnings.length > 0 || infos.length > 0) ? "warn" : "pass";
|
|
242
|
+
|
|
243
|
+
// Storage layer (src/graph/storage/index.ts queryDna) reads
|
|
244
|
+
// .buildanything/graph/lint-status.json and only consumes the `status`
|
|
245
|
+
// field. Extra diagnostic fields (broken_refs, warnings, errors, raw_*)
|
|
246
|
+
// are preserved here for human/tool inspection and are ignored by storage.
|
|
247
|
+
const summary: LintSummary & { status: "pass" | "warn" | "fail"; at: string; source: string } = {
|
|
248
|
+
status,
|
|
249
|
+
at: ranAt,
|
|
250
|
+
source: "DESIGN.md",
|
|
251
|
+
file_hash: fileHash,
|
|
252
|
+
broken_refs: brokenRefs,
|
|
253
|
+
warnings,
|
|
254
|
+
errors,
|
|
255
|
+
ran_at: ranAt,
|
|
256
|
+
exit_code: exitCode,
|
|
257
|
+
raw_stdout: stdout.slice(0, 8000),
|
|
258
|
+
raw_stderr: stderr.slice(0, 2000),
|
|
259
|
+
...(infos.length > 0 ? { infos } : {}),
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const summaryPath = resolve(cwd, ".buildanything/graph/lint-status.json");
|
|
263
|
+
atomicWrite(summaryPath, JSON.stringify(summary, null, 2));
|
|
264
|
+
|
|
265
|
+
const buildLogPath = resolve(cwd, "docs/plans/build-log.md");
|
|
266
|
+
if (existsSync(buildLogPath)) {
|
|
267
|
+
const shortHash = fileHash.slice(0, 12);
|
|
268
|
+
const oneLine = `${summary.ran_at} | broken-refs: ${brokenRefs} | warnings: ${warnings.length} | hash: ${shortHash}\n`;
|
|
269
|
+
let existing = readFileSync(buildLogPath, "utf8");
|
|
270
|
+
if (!/## Phase 3 Step 3\.8 — DESIGN\.md Lint/.test(existing)) {
|
|
271
|
+
existing += `\n## Phase 3 Step 3.8 — DESIGN.md Lint\n\n`;
|
|
272
|
+
writeFileSync(buildLogPath, existing);
|
|
273
|
+
}
|
|
274
|
+
appendFileSync(buildLogPath, oneLine);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (brokenRefs > 0) {
|
|
278
|
+
process.stderr.write(`design-md-lint: ${brokenRefs} broken-ref error(s) — Phase 3.8 routes back to Step 3.4\n`);
|
|
279
|
+
for (const e of errors) {
|
|
280
|
+
process.stderr.write(` ${e.rule}${e.line ? ` (line ${e.line})` : ""}: ${e.message}\n`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
if (warnings.length > 0) {
|
|
284
|
+
process.stdout.write(`design-md-lint: ${warnings.length} warning(s) (logged, non-blocking)\n`);
|
|
285
|
+
}
|
|
286
|
+
if (infos.length > 0) {
|
|
287
|
+
process.stdout.write(`design-md-lint: ${infos.length} info(s) (logged, non-blocking)\n`);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return exitCode;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (process.argv[1]?.endsWith("design-md-lint.ts") || process.argv[1]?.endsWith("design-md-lint")) {
|
|
294
|
+
process.exit(main());
|
|
295
|
+
}
|
package/hooks/hooks.json
CHANGED
|
@@ -12,6 +12,42 @@
|
|
|
12
12
|
]
|
|
13
13
|
}
|
|
14
14
|
],
|
|
15
|
+
"PreToolUse": [
|
|
16
|
+
{
|
|
17
|
+
"matcher": "Write|Edit",
|
|
18
|
+
"hooks": [
|
|
19
|
+
{
|
|
20
|
+
"type": "command",
|
|
21
|
+
"command": "'${CLAUDE_PLUGIN_ROOT}/hooks/pre-tool-use'",
|
|
22
|
+
"async": false
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"SubagentStart": [
|
|
28
|
+
{
|
|
29
|
+
"matcher": ".*",
|
|
30
|
+
"hooks": [
|
|
31
|
+
{
|
|
32
|
+
"type": "command",
|
|
33
|
+
"command": "'${CLAUDE_PLUGIN_ROOT}/hooks/subagent-start'",
|
|
34
|
+
"async": false
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
"SubagentStop": [
|
|
40
|
+
{
|
|
41
|
+
"matcher": ".*",
|
|
42
|
+
"hooks": [
|
|
43
|
+
{
|
|
44
|
+
"type": "command",
|
|
45
|
+
"command": "'${CLAUDE_PLUGIN_ROOT}/hooks/subagent-stop'",
|
|
46
|
+
"async": false
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
],
|
|
15
51
|
"PreCompact": [
|
|
16
52
|
{
|
|
17
53
|
"matcher": ".*",
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# buildanything: PreToolUse writer-owner hook (task 2.1.1)
|
|
3
|
+
# Enforces the writer-owner table from docs/migration/phase-graph.yaml on
|
|
4
|
+
# Write|Edit|MultiEdit tool calls. Shim delegates to Node via tsx.
|
|
5
|
+
#
|
|
6
|
+
# Claude Code hook protocol: exit 2 with stderr = deny. Exit 0 = allow.
|
|
7
|
+
# Rollback: BUILDANYTHING_ENFORCE_WRITER_OWNER=false degrades deny to warn.
|
|
8
|
+
|
|
9
|
+
set -u
|
|
10
|
+
|
|
11
|
+
HANDLER="${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}/hooks/pre-tool-use.ts"
|
|
12
|
+
|
|
13
|
+
if [ ! -f "$HANDLER" ]; then
|
|
14
|
+
# Handler missing — fail open so the hook never bricks the session.
|
|
15
|
+
echo "buildanything: pre-tool-use handler missing at $HANDLER — allowing" >&2
|
|
16
|
+
exit 0
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
exec npx --no-install tsx "$HANDLER"
|