@design-ai/cli 4.55.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/.claude-plugin/plugin.json +164 -0
- package/AGENTS.ko.md +126 -0
- package/AGENTS.md +182 -0
- package/CHANGELOG.md +6883 -0
- package/CLAUDE.md +39 -0
- package/LICENSE +21 -0
- package/README.ko.md +245 -0
- package/README.md +277 -0
- package/agents/README.md +14 -0
- package/agents/a11y-reviewer.md +121 -0
- package/agents/component-architect.md +57 -0
- package/agents/design-critic.md +46 -0
- package/agents/token-extractor.md +63 -0
- package/cli/bin/design-ai-mcp.mjs +6 -0
- package/cli/bin/design-ai.mjs +40 -0
- package/cli/commands/audit.mjs +111 -0
- package/cli/commands/check.mjs +226 -0
- package/cli/commands/doctor.mjs +141 -0
- package/cli/commands/examples.mjs +58 -0
- package/cli/commands/help.mjs +271 -0
- package/cli/commands/install.mjs +161 -0
- package/cli/commands/learn.mjs +1871 -0
- package/cli/commands/list.mjs +143 -0
- package/cli/commands/mcp.mjs +27 -0
- package/cli/commands/pack.mjs +211 -0
- package/cli/commands/prompt.mjs +199 -0
- package/cli/commands/route.mjs +247 -0
- package/cli/commands/search.mjs +60 -0
- package/cli/commands/show.mjs +52 -0
- package/cli/commands/site.mjs +558 -0
- package/cli/commands/status.mjs +161 -0
- package/cli/commands/uninstall.mjs +119 -0
- package/cli/commands/update.mjs +184 -0
- package/cli/commands/version.mjs +94 -0
- package/cli/commands/workspace.mjs +176 -0
- package/cli/lib/brief.mjs +52 -0
- package/cli/lib/check.mjs +642 -0
- package/cli/lib/dispatch.mjs +109 -0
- package/cli/lib/doctor.mjs +505 -0
- package/cli/lib/examples.mjs +258 -0
- package/cli/lib/exec.mjs +63 -0
- package/cli/lib/help-flags.mjs +5 -0
- package/cli/lib/learn.mjs +3694 -0
- package/cli/lib/log.mjs +47 -0
- package/cli/lib/mcp-server.mjs +426 -0
- package/cli/lib/output.mjs +101 -0
- package/cli/lib/pack.mjs +599 -0
- package/cli/lib/paths.mjs +63 -0
- package/cli/lib/prompt.mjs +603 -0
- package/cli/lib/route.mjs +740 -0
- package/cli/lib/search.mjs +158 -0
- package/cli/lib/show.mjs +161 -0
- package/cli/lib/signals.mjs +2337 -0
- package/cli/lib/site.mjs +6617 -0
- package/cli/lib/skill-proposals.mjs +2046 -0
- package/cli/lib/suggest.mjs +66 -0
- package/cli/lib/workspace.mjs +1056 -0
- package/commands/README.md +25 -0
- package/commands/component-spec.md +34 -0
- package/commands/conversational.md +44 -0
- package/commands/design-from-brief.md +141 -0
- package/commands/design-review.md +62 -0
- package/commands/document-from-brief.md +47 -0
- package/commands/extract-tokens.md +38 -0
- package/commands/game-ui.md +40 -0
- package/commands/illustration.md +37 -0
- package/commands/iterate.md +167 -0
- package/commands/motion-design.md +54 -0
- package/commands/palette-from-brand.md +50 -0
- package/commands/print.md +49 -0
- package/commands/slide-deck.md +46 -0
- package/commands/spatial.md +47 -0
- package/commands/stability-review.md +74 -0
- package/commands/video.md +42 -0
- package/commands/website-improvement.md +77 -0
- package/docs/AGENT-DEVELOPMENT.md +658 -0
- package/docs/AI-LEARNING.md +429 -0
- package/docs/AIDER-INTEGRATION.md +224 -0
- package/docs/ARCHITECTURE.ko.md +183 -0
- package/docs/ARCHITECTURE.md +105 -0
- package/docs/CODEX-INTEGRATION.md +311 -0
- package/docs/COMPANY-WEBSITE-DOGFOOD.ko.md +144 -0
- package/docs/COMPANY-WEBSITE-DOGFOOD.md +150 -0
- package/docs/COMPANY-WEBSITE-INTAKE-TEMPLATE.ko.md +153 -0
- package/docs/COMPANY-WEBSITE-INTAKE-TEMPLATE.md +154 -0
- package/docs/CONTRIBUTING.ko.md +203 -0
- package/docs/CONTRIBUTING.md +242 -0
- package/docs/CURSOR-INTEGRATION.md +220 -0
- package/docs/DISTRIBUTION.ko.md +248 -0
- package/docs/DISTRIBUTION.md +253 -0
- package/docs/DOGFOOD-FINDINGS.md +180 -0
- package/docs/DOGFOOD-V4-FINDINGS.md +139 -0
- package/docs/DOGFOOD-V4-MKDOCS-FINDINGS.md +233 -0
- package/docs/DOGFOOD-V4-NPM-FINDINGS.md +157 -0
- package/docs/DOGFOOD-V4-VSCODE-FINDINGS.md +135 -0
- package/docs/FIGMA-INTEGRATION.md +222 -0
- package/docs/MCP-INTEGRATION.md +243 -0
- package/docs/MIGRATION-v4.md +121 -0
- package/docs/PLUGIN-PACKAGING.md +240 -0
- package/docs/PRODUCT-READINESS.md +66 -0
- package/docs/QUICKSTART.ko.md +178 -0
- package/docs/QUICKSTART.md +179 -0
- package/docs/RELEASE-CHECKLIST.md +292 -0
- package/docs/ROADMAP.md +19495 -0
- package/docs/SESSION-LOG.md +940 -0
- package/docs/TOKEN-SYNC.md +237 -0
- package/docs/USING.ko.md +206 -0
- package/docs/USING.md +218 -0
- package/docs/WEBSITE-IMPROVEMENT.ko.md +75 -0
- package/docs/WEBSITE-IMPROVEMENT.md +89 -0
- package/docs/announcements/README.md +56 -0
- package/docs/announcements/dev-to-korea.md +206 -0
- package/docs/announcements/hashnode-post.ko.md +232 -0
- package/docs/announcements/okky-post.ko.md +158 -0
- package/docs/announcements/press-kit.md +101 -0
- package/docs/announcements/reddit-r-korea.md +196 -0
- package/docs/announcements/show-hn.md +114 -0
- package/docs/announcements/twitter-thread.md +255 -0
- package/docs/external-status.md +34 -0
- package/docs/integrations/aider-walkthrough.ko.md +275 -0
- package/docs/integrations/aider-walkthrough.md +274 -0
- package/docs/integrations/codex-walkthrough.ko.md +297 -0
- package/docs/integrations/codex-walkthrough.md +297 -0
- package/docs/integrations/cursor-walkthrough.ko.md +281 -0
- package/docs/integrations/cursor-walkthrough.md +284 -0
- package/docs/integrations/design-ai-mcp-server.md +169 -0
- package/docs/integrations/figma-mcp.md +149 -0
- package/docs/integrations/github-mcp.md +178 -0
- package/docs/integrations/linear-mcp.md +215 -0
- package/docs/integrations/notion-mcp.md +174 -0
- package/docs/integrations/sdk-walkthrough.ko.md +375 -0
- package/docs/integrations/sdk-walkthrough.md +375 -0
- package/docs/integrations/slack-mcp.md +208 -0
- package/docs/integrations/vscode-walkthrough.ko.md +202 -0
- package/docs/integrations/vscode-walkthrough.md +205 -0
- package/docs/requirements.txt +16 -0
- package/docs/site-overrides/extra.css +83 -0
- package/docs/site-overrides/favicon.svg +4 -0
- package/docs/site-overrides/logo.svg +10 -0
- package/docs/site-overrides/main.html +18 -0
- package/docs/website-console/app.js +2540 -0
- package/docs/website-console/index.html +24 -0
- package/docs/website-console/styles.css +975 -0
- package/examples/README.md +252 -0
- package/examples/cases/dogfood-v4-korean-hr-onboarding.md +356 -0
- package/examples/component-accordion-actions.md +153 -0
- package/examples/component-accordion-details.md +147 -0
- package/examples/component-accordion-summary.md +180 -0
- package/examples/component-accordion.md +229 -0
- package/examples/component-account-card.md +284 -0
- package/examples/component-address-input.md +260 -0
- package/examples/component-affix.md +190 -0
- package/examples/component-alert-dialog.md +210 -0
- package/examples/component-alert-title.md +77 -0
- package/examples/component-alert.md +192 -0
- package/examples/component-amount-input.md +278 -0
- package/examples/component-anchor.md +198 -0
- package/examples/component-app-bar.md +249 -0
- package/examples/component-aspect-ratio.md +156 -0
- package/examples/component-auto-complete.md +199 -0
- package/examples/component-avatar-group.md +170 -0
- package/examples/component-avatar.md +191 -0
- package/examples/component-back-top.md +123 -0
- package/examples/component-backdrop.md +148 -0
- package/examples/component-badge.md +181 -0
- package/examples/component-banner.md +237 -0
- package/examples/component-biometric-gate.md +281 -0
- package/examples/component-blockquote.md +153 -0
- package/examples/component-border-beam.md +207 -0
- package/examples/component-bottom-navigation.md +226 -0
- package/examples/component-box.md +112 -0
- package/examples/component-breadcrumb.md +222 -0
- package/examples/component-button-base.md +190 -0
- package/examples/component-button-group.md +117 -0
- package/examples/component-button.md +213 -0
- package/examples/component-calendar.md +280 -0
- package/examples/component-callout.md +131 -0
- package/examples/component-card-actions.md +101 -0
- package/examples/component-card-content.md +90 -0
- package/examples/component-card-header.md +122 -0
- package/examples/component-card-media.md +79 -0
- package/examples/component-card.md +233 -0
- package/examples/component-carousel.md +266 -0
- package/examples/component-cascader.md +135 -0
- package/examples/component-category-picker.md +271 -0
- package/examples/component-chart.md +237 -0
- package/examples/component-chat-interface.md +399 -0
- package/examples/component-checkbox.md +149 -0
- package/examples/component-click-away-listener.md +87 -0
- package/examples/component-code.md +213 -0
- package/examples/component-collapsible.md +219 -0
- package/examples/component-color-picker.md +110 -0
- package/examples/component-combobox.md +267 -0
- package/examples/component-command.md +299 -0
- package/examples/component-config-provider.md +190 -0
- package/examples/component-context-menu.md +179 -0
- package/examples/component-css-baseline.md +148 -0
- package/examples/component-date-picker.md +249 -0
- package/examples/component-descriptions.md +242 -0
- package/examples/component-dialog-actions.md +111 -0
- package/examples/component-dialog-content-text.md +76 -0
- package/examples/component-dialog-content.md +105 -0
- package/examples/component-dialog-title.md +104 -0
- package/examples/component-dialog.md +176 -0
- package/examples/component-divider.md +182 -0
- package/examples/component-doc-page.md +217 -0
- package/examples/component-drawer.md +257 -0
- package/examples/component-dropdown.md +220 -0
- package/examples/component-email-layout.md +253 -0
- package/examples/component-empty-state.md +269 -0
- package/examples/component-empty.md +172 -0
- package/examples/component-fade.md +87 -0
- package/examples/component-feature-grid.md +201 -0
- package/examples/component-field.md +266 -0
- package/examples/component-filled-input.md +114 -0
- package/examples/component-flex.md +117 -0
- package/examples/component-float-button.md +214 -0
- package/examples/component-form-control-label.md +134 -0
- package/examples/component-form-control.md +113 -0
- package/examples/component-form-controls.md +251 -0
- package/examples/component-form-group.md +86 -0
- package/examples/component-form-helper-text.md +95 -0
- package/examples/component-form-label.md +98 -0
- package/examples/component-form.md +291 -0
- package/examples/component-game-hud.md +362 -0
- package/examples/component-game-menu.md +327 -0
- package/examples/component-grid.md +140 -0
- package/examples/component-grow.md +79 -0
- package/examples/component-hero-block.md +252 -0
- package/examples/component-hover-card.md +211 -0
- package/examples/component-icon-button.md +142 -0
- package/examples/component-icon.md +102 -0
- package/examples/component-illustration.md +280 -0
- package/examples/component-image-list.md +107 -0
- package/examples/component-image.md +282 -0
- package/examples/component-input-adornment.md +101 -0
- package/examples/component-input-base.md +134 -0
- package/examples/component-input-number.md +141 -0
- package/examples/component-input-otp.md +271 -0
- package/examples/component-input.md +213 -0
- package/examples/component-item.md +243 -0
- package/examples/component-kbd.md +197 -0
- package/examples/component-krw-amount.md +219 -0
- package/examples/component-label.md +118 -0
- package/examples/component-layout.md +217 -0
- package/examples/component-link.md +223 -0
- package/examples/component-list-item-avatar.md +72 -0
- package/examples/component-list-item-button.md +139 -0
- package/examples/component-list-item-icon.md +82 -0
- package/examples/component-list-item-text.md +98 -0
- package/examples/component-list-item.md +116 -0
- package/examples/component-list-subheader.md +70 -0
- package/examples/component-list.md +198 -0
- package/examples/component-loading-button.md +125 -0
- package/examples/component-loading-sequence.md +254 -0
- package/examples/component-lottie-player.md +279 -0
- package/examples/component-masonry.md +191 -0
- package/examples/component-mentions.md +189 -0
- package/examples/component-menu-item.md +102 -0
- package/examples/component-menu-list.md +98 -0
- package/examples/component-menu.md +139 -0
- package/examples/component-menubar.md +259 -0
- package/examples/component-message.md +162 -0
- package/examples/component-mobile-stepper.md +155 -0
- package/examples/component-modal.md +220 -0
- package/examples/component-navigation-menu.md +295 -0
- package/examples/component-notification.md +166 -0
- package/examples/component-otp-countdown.md +245 -0
- package/examples/component-outlined-input.md +145 -0
- package/examples/component-page-transition.md +281 -0
- package/examples/component-pagination.md +226 -0
- package/examples/component-paper.md +199 -0
- package/examples/component-pass-auth.md +265 -0
- package/examples/component-payment-brand-button.md +253 -0
- package/examples/component-payment-method-selector.md +272 -0
- package/examples/component-payment-receipt.md +277 -0
- package/examples/component-popconfirm.md +144 -0
- package/examples/component-popover.md +239 -0
- package/examples/component-popper.md +129 -0
- package/examples/component-pricing-cards.md +247 -0
- package/examples/component-progress.md +195 -0
- package/examples/component-qr-code.md +201 -0
- package/examples/component-radio.md +167 -0
- package/examples/component-rate.md +202 -0
- package/examples/component-resizable.md +163 -0
- package/examples/component-result.md +270 -0
- package/examples/component-scroll-area.md +199 -0
- package/examples/component-scroll-reveal.md +320 -0
- package/examples/component-segmented.md +178 -0
- package/examples/component-select.md +258 -0
- package/examples/component-separator.md +177 -0
- package/examples/component-sheet.md +277 -0
- package/examples/component-sidebar.md +257 -0
- package/examples/component-skeleton.md +178 -0
- package/examples/component-slide.md +89 -0
- package/examples/component-slider.md +208 -0
- package/examples/component-snackbar-content.md +92 -0
- package/examples/component-snackbar.md +121 -0
- package/examples/component-sonner.md +165 -0
- package/examples/component-space.md +125 -0
- package/examples/component-spatial-locomotion.md +373 -0
- package/examples/component-spatial-panel.md +330 -0
- package/examples/component-speed-dial-action.md +78 -0
- package/examples/component-speed-dial.md +177 -0
- package/examples/component-spin.md +173 -0
- package/examples/component-spinner.md +204 -0
- package/examples/component-splitter.md +210 -0
- package/examples/component-stack.md +130 -0
- package/examples/component-statistic.md +282 -0
- package/examples/component-step-button.md +157 -0
- package/examples/component-step-connector.md +157 -0
- package/examples/component-step-content.md +121 -0
- package/examples/component-step-icon.md +115 -0
- package/examples/component-step-label.md +101 -0
- package/examples/component-step.md +84 -0
- package/examples/component-steps.md +264 -0
- package/examples/component-stock-chart.md +251 -0
- package/examples/component-swipeable-drawer.md +149 -0
- package/examples/component-switch.md +99 -0
- package/examples/component-tab-scroll-button.md +180 -0
- package/examples/component-tab.md +120 -0
- package/examples/component-table-body.md +82 -0
- package/examples/component-table-cell.md +118 -0
- package/examples/component-table-container.md +75 -0
- package/examples/component-table-footer.md +72 -0
- package/examples/component-table-head.md +78 -0
- package/examples/component-table-pagination.md +137 -0
- package/examples/component-table-row.md +113 -0
- package/examples/component-table-sort-label.md +109 -0
- package/examples/component-table.md +202 -0
- package/examples/component-tabs.md +184 -0
- package/examples/component-tag-badge.md +309 -0
- package/examples/component-tag.md +102 -0
- package/examples/component-testimonial-carousel.md +218 -0
- package/examples/component-textarea-autosize.md +114 -0
- package/examples/component-textarea.md +173 -0
- package/examples/component-time-picker.md +205 -0
- package/examples/component-timeline.md +170 -0
- package/examples/component-toast.md +224 -0
- package/examples/component-toggle-button.md +129 -0
- package/examples/component-toggle.md +220 -0
- package/examples/component-toolbar.md +104 -0
- package/examples/component-tooltip.md +178 -0
- package/examples/component-tour.md +176 -0
- package/examples/component-transaction-list-item.md +243 -0
- package/examples/component-transfer.md +156 -0
- package/examples/component-tree-select.md +202 -0
- package/examples/component-tree.md +297 -0
- package/examples/component-typography.md +215 -0
- package/examples/component-upload.md +295 -0
- package/examples/component-video-hero.md +409 -0
- package/examples/component-video-player.md +340 -0
- package/examples/component-voice-input.md +408 -0
- package/examples/component-watermark.md +217 -0
- package/examples/component-zoom.md +92 -0
- package/examples/doc-explanation-example.md +196 -0
- package/examples/doc-how-to-example.md +205 -0
- package/examples/doc-tutorial-example.md +162 -0
- package/examples/dogfood-korean-fintech-system.md +433 -0
- package/examples/email-transactional-example.md +259 -0
- package/examples/palette-saas-violet.md +235 -0
- package/examples/print-business-card-spec.md +205 -0
- package/examples/print-packaging-spec.md +285 -0
- package/examples/report-example.md +228 -0
- package/examples/slide-deck-example.md +237 -0
- package/examples/website-improvement-report.md +128 -0
- package/examples/website-improvement-workspace.json +126 -0
- package/install.sh +189 -0
- package/knowledge/COVERAGE.md +740 -0
- package/knowledge/PRINCIPLES.md +108 -0
- package/knowledge/a11y/contrast.md +70 -0
- package/knowledge/a11y/keyboard-and-focus.md +108 -0
- package/knowledge/colors/color-theory.md +90 -0
- package/knowledge/colors/mui-palette-structure.md +105 -0
- package/knowledge/colors/palettes-by-product-type.md +876 -0
- package/knowledge/components/INDEX.md +231 -0
- package/knowledge/components/index.json +1470 -0
- package/knowledge/components/shadcn-registry.md +159 -0
- package/knowledge/conversational/ai-chat-interfaces.md +323 -0
- package/knowledge/conversational/chatbot-design.md +312 -0
- package/knowledge/conversational/conversational-ui-fundamentals.md +299 -0
- package/knowledge/conversational/korean-voice-conventions.md +281 -0
- package/knowledge/conversational/voice-ui-patterns.md +297 -0
- package/knowledge/design-tokens/ant-design.md +124 -0
- package/knowledge/design-tokens/material-3.md +235 -0
- package/knowledge/design-tokens/polaris-and-carbon.md +231 -0
- package/knowledge/design-tokens/tailwind-v4.md +284 -0
- package/knowledge/game-ui/game-accessibility.md +317 -0
- package/knowledge/game-ui/game-ui-fundamentals.md +281 -0
- package/knowledge/game-ui/hud-design.md +324 -0
- package/knowledge/game-ui/korean-gaming-conventions.md +312 -0
- package/knowledge/game-ui/menu-systems.md +388 -0
- package/knowledge/i18n/korean-app-store-visual.md +223 -0
- package/knowledge/i18n/korean-document-style.md +301 -0
- package/knowledge/i18n/korean-payments.md +211 -0
- package/knowledge/i18n/korean-product-conventions.md +96 -0
- package/knowledge/i18n/korean-publishing.md +139 -0
- package/knowledge/i18n/korean-typography.md +123 -0
- package/knowledge/icons/curated-sets.md +225 -0
- package/knowledge/illustration/hero-illustrations.md +234 -0
- package/knowledge/illustration/illustration-systems.md +221 -0
- package/knowledge/illustration/mascot-design.md +208 -0
- package/knowledge/illustration/spot-illustrations.md +246 -0
- package/knowledge/illustration/svg-optimization.md +308 -0
- package/knowledge/layout/spacing-and-grid.md +119 -0
- package/knowledge/motion/app-loading-sequences.md +277 -0
- package/knowledge/motion/choreography-depth.md +297 -0
- package/knowledge/motion/marketing-motion.md +223 -0
- package/knowledge/motion/micro-interactions.md +266 -0
- package/knowledge/motion/motion-tools.md +281 -0
- package/knowledge/motion/principles.md +126 -0
- package/knowledge/patterns/auth-flow-design.md +316 -0
- package/knowledge/patterns/b2b-onboarding-flows.md +182 -0
- package/knowledge/patterns/brand-identity.md +238 -0
- package/knowledge/patterns/brand-references.md +97 -0
- package/knowledge/patterns/chart-color-encoding.md +269 -0
- package/knowledge/patterns/chart-types.md +344 -0
- package/knowledge/patterns/dashboard-composition.md +299 -0
- package/knowledge/patterns/design-system-qa.md +356 -0
- package/knowledge/patterns/document-typography.md +248 -0
- package/knowledge/patterns/email-design.md +338 -0
- package/knowledge/patterns/empty-states.md +263 -0
- package/knowledge/patterns/error-states.md +318 -0
- package/knowledge/patterns/form-design.md +237 -0
- package/knowledge/patterns/information-architecture.md +341 -0
- package/knowledge/patterns/landing-hero-design.md +283 -0
- package/knowledge/patterns/landing-page-patterns.md +681 -0
- package/knowledge/patterns/list-and-feed.md +371 -0
- package/knowledge/patterns/mobile-navigation.md +278 -0
- package/knowledge/patterns/money-and-amount.md +301 -0
- package/knowledge/patterns/onboarding.md +300 -0
- package/knowledge/patterns/pricing-page-design.md +261 -0
- package/knowledge/patterns/realtime-data.md +280 -0
- package/knowledge/patterns/report-design.md +330 -0
- package/knowledge/patterns/search-ux.md +373 -0
- package/knowledge/patterns/settings-page.md +325 -0
- package/knowledge/patterns/slide-deck-design.md +316 -0
- package/knowledge/patterns/styles-catalog.md +2599 -0
- package/knowledge/patterns/technical-writing.md +306 -0
- package/knowledge/patterns/ui-reasoning.md +1853 -0
- package/knowledge/patterns/ux-guidelines.md +1454 -0
- package/knowledge/platforms/react-native.md +395 -0
- package/knowledge/print/brochures-and-flyers.md +276 -0
- package/knowledge/print/korean-print-conventions.md +284 -0
- package/knowledge/print/packaging.md +321 -0
- package/knowledge/print/print-fundamentals.md +238 -0
- package/knowledge/print/signage-and-posters.md +235 -0
- package/knowledge/print/stationery.md +262 -0
- package/knowledge/spatial/ar-patterns.md +253 -0
- package/knowledge/spatial/comfort-and-accessibility.md +245 -0
- package/knowledge/spatial/spatial-design-fundamentals.md +346 -0
- package/knowledge/spatial/spatial-ui-elements.md +343 -0
- package/knowledge/spatial/vr-patterns.md +302 -0
- package/knowledge/typography/font-pairings.md +332 -0
- package/knowledge/typography/mui-type-scale.md +57 -0
- package/knowledge/typography/type-scale-fundamentals.md +105 -0
- package/knowledge/video/in-product-video.md +277 -0
- package/knowledge/video/korean-video-conventions.md +247 -0
- package/knowledge/video/marketing-video.md +258 -0
- package/knowledge/video/social-and-short-form.md +257 -0
- package/knowledge/video/video-fundamentals.md +296 -0
- package/package.json +106 -0
- package/skills/README.md +39 -0
- package/skills/color-palette/PLAYBOOK.md +175 -0
- package/skills/color-palette/SKILL.md +6 -0
- package/skills/color-palette/TEMPLATE.md +103 -0
- package/skills/component-spec-writer/PLAYBOOK.md +169 -0
- package/skills/component-spec-writer/SKILL.md +6 -0
- package/skills/component-spec-writer/TEMPLATE.md +115 -0
- package/skills/conversational-ui-designer/PLAYBOOK.md +231 -0
- package/skills/conversational-ui-designer/SKILL.md +6 -0
- package/skills/design-broadcast/PLAYBOOK.md +146 -0
- package/skills/design-broadcast/SKILL.md +6 -0
- package/skills/design-critique/PLAYBOOK.md +137 -0
- package/skills/design-critique/SKILL.md +6 -0
- package/skills/design-pr-review/PLAYBOOK.md +171 -0
- package/skills/design-pr-review/SKILL.md +6 -0
- package/skills/design-system-builder/PLAYBOOK.md +218 -0
- package/skills/design-system-builder/SKILL.md +6 -0
- package/skills/design-system-qa/PLAYBOOK.md +163 -0
- package/skills/design-system-qa/SKILL.md +6 -0
- package/skills/document-author/PLAYBOOK.md +167 -0
- package/skills/document-author/SKILL.md +6 -0
- package/skills/figma-token-sync/PLAYBOOK.md +149 -0
- package/skills/figma-token-sync/SKILL.md +6 -0
- package/skills/game-ui-designer/PLAYBOOK.md +209 -0
- package/skills/game-ui-designer/SKILL.md +6 -0
- package/skills/handoff-spec/PLAYBOOK.md +170 -0
- package/skills/handoff-spec/SKILL.md +6 -0
- package/skills/illustration-designer/PLAYBOOK.md +166 -0
- package/skills/illustration-designer/SKILL.md +6 -0
- package/skills/motion-designer/PLAYBOOK.md +223 -0
- package/skills/motion-designer/SKILL.md +6 -0
- package/skills/print-designer/PLAYBOOK.md +209 -0
- package/skills/print-designer/SKILL.md +6 -0
- package/skills/slide-deck-author/PLAYBOOK.md +198 -0
- package/skills/slide-deck-author/SKILL.md +6 -0
- package/skills/spatial-designer/PLAYBOOK.md +238 -0
- package/skills/spatial-designer/SKILL.md +6 -0
- package/skills/ux-audit/PLAYBOOK.md +142 -0
- package/skills/ux-audit/SKILL.md +6 -0
- package/skills/video-designer/PLAYBOOK.md +240 -0
- package/skills/video-designer/SKILL.md +6 -0
- package/skills/website-improvement/PLAYBOOK.md +118 -0
- package/skills/website-improvement/SKILL.md +6 -0
- package/skills/website-improvement/TEMPLATE.md +103 -0
- package/tools/audit/changelog-generate.py +176 -0
- package/tools/audit/check-coverage.py +483 -0
- package/tools/audit/doctor_assertions.py +256 -0
- package/tools/audit/example-qa.py +108 -0
- package/tools/audit/frontmatter-check.py +199 -0
- package/tools/audit/integration-check.py +95 -0
- package/tools/audit/korean-copy-check.py +161 -0
- package/tools/audit/link-check.py +146 -0
- package/tools/audit/local-ci.py +558 -0
- package/tools/audit/package-contents.py +723 -0
- package/tools/audit/package-smoke.py +22443 -0
- package/tools/audit/raw-hex-check.py +252 -0
- package/tools/audit/registry-smoke.py +8188 -0
- package/tools/audit/release-metadata.py +9832 -0
- package/tools/audit/run-all.py +351 -0
- package/tools/audit/smoke_assertions.py +12742 -0
- package/tools/audit/stability-review.py +332 -0
- package/tools/audit/stale-check.py +156 -0
- package/tools/migrations/add-version-frontmatter.py +132 -0
- package/tools/migrations/bump-last-updated.py +131 -0
- package/tools/migrations/promote-stability.py +172 -0
- package/tools/preview/README.md +58 -0
- package/tools/preview/render-tokens.py +454 -0
|
@@ -0,0 +1,558 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Run the local equivalent of the non-publishing GitHub CI surfaces.
|
|
4
|
+
|
|
5
|
+
This is intentionally broader than `npm run release:check`: it also exercises
|
|
6
|
+
the workflow-only Python syntax check, knowledge size budget, VS Code extension
|
|
7
|
+
compile/unit tests, mkdocs site build, and mkdocs warning policy before a branch
|
|
8
|
+
is pushed for Real-CI verification.
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
python3 tools/audit/local-ci.py
|
|
12
|
+
python3 tools/audit/local-ci.py --docs-only
|
|
13
|
+
"""
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import argparse
|
|
17
|
+
import re
|
|
18
|
+
import subprocess
|
|
19
|
+
import sys
|
|
20
|
+
import tempfile
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
ROOT = Path(__file__).resolve().parents[2]
|
|
24
|
+
KNOWLEDGE_WARN_LINES = 150_000
|
|
25
|
+
KNOWLEDGE_MAX_LINES = 200_000
|
|
26
|
+
PYTHON_COMPILE_DIRS = ("tools/extractors", "tools/audit", "tools/migrations", "tools/preview")
|
|
27
|
+
LINE_BUDGET_DIRS = ("knowledge", "examples", "docs")
|
|
28
|
+
DOCS_WORKFLOW = ROOT / ".github" / "workflows" / "docs.yml"
|
|
29
|
+
DOCS_WORKFLOW_POLICY_COMMAND = "python3 -B tools/audit/local-ci.py --docs-only"
|
|
30
|
+
MKDOCS_REFS_WARNING_BASELINE = 632
|
|
31
|
+
GITHUB_WORKFLOW_FILES = (
|
|
32
|
+
ROOT / ".github" / "workflows" / "audit.yml",
|
|
33
|
+
ROOT / ".github" / "workflows" / "docs.yml",
|
|
34
|
+
ROOT / ".github" / "workflows" / "publish.yml",
|
|
35
|
+
ROOT / ".github" / "workflows" / "release.yml",
|
|
36
|
+
)
|
|
37
|
+
WORKFLOW_REQUIRED_ACTION_REFS = (
|
|
38
|
+
("actions/checkout", "v6"),
|
|
39
|
+
("actions/setup-node", "v6"),
|
|
40
|
+
("actions/setup-python", "v6"),
|
|
41
|
+
("actions/cache", "v5"),
|
|
42
|
+
("actions/upload-pages-artifact", "v5"),
|
|
43
|
+
("actions/deploy-pages", "v5"),
|
|
44
|
+
("softprops/action-gh-release", "v3"),
|
|
45
|
+
)
|
|
46
|
+
WORKFLOW_USES_RE = re.compile(
|
|
47
|
+
r"^\s*-?\s*uses:\s*"
|
|
48
|
+
r"(?P<action>[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+)@(?P<ref>[^\s#]+)"
|
|
49
|
+
)
|
|
50
|
+
DOCS_WORKFLOW_REQUIRED_PATHS = (
|
|
51
|
+
"knowledge/**",
|
|
52
|
+
"examples/**",
|
|
53
|
+
"skills/**",
|
|
54
|
+
"agents/**",
|
|
55
|
+
"commands/**",
|
|
56
|
+
"docs/**",
|
|
57
|
+
"AGENTS.md",
|
|
58
|
+
"AGENTS.ko.md",
|
|
59
|
+
"CLAUDE.md",
|
|
60
|
+
"README.md",
|
|
61
|
+
"README.ko.md",
|
|
62
|
+
"CHANGELOG.md",
|
|
63
|
+
"mkdocs.yml",
|
|
64
|
+
"tools/audit/local-ci.py",
|
|
65
|
+
"tools/build-docs.sh",
|
|
66
|
+
".github/workflows/docs.yml",
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def run(command: list[str], *, cwd: Path = ROOT) -> None:
|
|
71
|
+
print(f"\n$ {' '.join(command)}", flush=True)
|
|
72
|
+
result = subprocess.run(command, cwd=cwd)
|
|
73
|
+
if result.returncode != 0:
|
|
74
|
+
raise SystemExit(result.returncode)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def run_capture(command: list[str], *, cwd: Path = ROOT, echo: bool = True) -> str:
|
|
78
|
+
print(f"\n$ {' '.join(command)}", flush=True)
|
|
79
|
+
result = subprocess.run(
|
|
80
|
+
command,
|
|
81
|
+
cwd=cwd,
|
|
82
|
+
stdout=subprocess.PIPE,
|
|
83
|
+
stderr=subprocess.STDOUT,
|
|
84
|
+
text=True,
|
|
85
|
+
)
|
|
86
|
+
if result.stdout and (echo or result.returncode != 0):
|
|
87
|
+
print(result.stdout, end="", flush=True)
|
|
88
|
+
if result.returncode != 0:
|
|
89
|
+
raise SystemExit(result.returncode)
|
|
90
|
+
return result.stdout
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def run_release_check() -> None:
|
|
94
|
+
run(["npm", "run", "release:check"])
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def python_compile_files(root: Path = ROOT) -> list[str]:
|
|
98
|
+
files: list[str] = []
|
|
99
|
+
for directory in PYTHON_COMPILE_DIRS:
|
|
100
|
+
files.extend(str(path.relative_to(root)) for path in sorted((root / directory).glob("*.py")))
|
|
101
|
+
return files
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def run_python_compile() -> None:
|
|
105
|
+
files = python_compile_files()
|
|
106
|
+
run(["python3", "-m", "py_compile", *files])
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def markdown_line_count(root: Path = ROOT) -> int:
|
|
110
|
+
total = 0
|
|
111
|
+
for directory in LINE_BUDGET_DIRS:
|
|
112
|
+
for path in (root / directory).rglob("*.md"):
|
|
113
|
+
with path.open("r", encoding="utf-8") as handle:
|
|
114
|
+
total += sum(1 for _ in handle)
|
|
115
|
+
return total
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def size_budget_warning(total: int) -> str | None:
|
|
119
|
+
if total > KNOWLEDGE_MAX_LINES:
|
|
120
|
+
raise SystemExit(
|
|
121
|
+
f"knowledge base exceeds hard cap of {KNOWLEDGE_MAX_LINES} lines ({total})"
|
|
122
|
+
)
|
|
123
|
+
if total > KNOWLEDGE_WARN_LINES:
|
|
124
|
+
return f"knowledge base exceeds {KNOWLEDGE_WARN_LINES} lines ({total}); consider pruning"
|
|
125
|
+
return None
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def run_size_budget() -> None:
|
|
129
|
+
total = markdown_line_count()
|
|
130
|
+
print(f"\nKnowledge/docs/examples total: {total} lines", flush=True)
|
|
131
|
+
warning = size_budget_warning(total)
|
|
132
|
+
if warning:
|
|
133
|
+
print(f"warning: {warning}", file=sys.stderr)
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def run_vscode_checks() -> None:
|
|
137
|
+
extension_root = ROOT / "vscode-extension"
|
|
138
|
+
run(["npm", "ci", "--no-audit", "--no-fund"], cwd=extension_root)
|
|
139
|
+
run(["npm", "run", "compile"], cwd=extension_root)
|
|
140
|
+
run(["npm", "run", "test:unit"], cwd=extension_root)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def run_docs_build() -> None:
|
|
144
|
+
try:
|
|
145
|
+
run(["python3", "-m", "mkdocs", "--version"])
|
|
146
|
+
except SystemExit as error:
|
|
147
|
+
if error.code:
|
|
148
|
+
raise SystemExit(
|
|
149
|
+
"mkdocs is not installed; run `python3 -m pip install -r docs/requirements.txt` "
|
|
150
|
+
"before `npm run ci:local`."
|
|
151
|
+
) from error
|
|
152
|
+
raise
|
|
153
|
+
run(["./tools/build-docs.sh"])
|
|
154
|
+
mkdocs_output = run_capture(["python3", "-m", "mkdocs", "build", "--clean"], echo=False)
|
|
155
|
+
assert_mkdocs_warning_policy(mkdocs_output)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def unquote_yaml_scalar(value: str) -> str:
|
|
159
|
+
value = value.strip()
|
|
160
|
+
if len(value) >= 2 and value[0] == value[-1] and value[0] in {"'", '"'}:
|
|
161
|
+
return value[1:-1]
|
|
162
|
+
return value
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def yaml_indent(line: str) -> int:
|
|
166
|
+
return len(line) - len(line.lstrip(" "))
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def workflow_run_commands(text: str) -> list[str]:
|
|
170
|
+
commands: list[str] = []
|
|
171
|
+
for line in text.splitlines():
|
|
172
|
+
stripped = line.strip()
|
|
173
|
+
if stripped.startswith("run:"):
|
|
174
|
+
commands.append(unquote_yaml_scalar(stripped.removeprefix("run:").strip()))
|
|
175
|
+
return commands
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def workflow_path_entries(text: str) -> list[str]:
|
|
179
|
+
entries: list[str] = []
|
|
180
|
+
in_paths = False
|
|
181
|
+
paths_indent = 0
|
|
182
|
+
|
|
183
|
+
for line in text.splitlines():
|
|
184
|
+
stripped = line.strip()
|
|
185
|
+
if not stripped or stripped.startswith("#"):
|
|
186
|
+
continue
|
|
187
|
+
|
|
188
|
+
indent = yaml_indent(line)
|
|
189
|
+
if stripped == "paths:":
|
|
190
|
+
in_paths = True
|
|
191
|
+
paths_indent = indent
|
|
192
|
+
continue
|
|
193
|
+
|
|
194
|
+
if not in_paths:
|
|
195
|
+
continue
|
|
196
|
+
|
|
197
|
+
if indent <= paths_indent and not stripped.startswith("- "):
|
|
198
|
+
in_paths = False
|
|
199
|
+
continue
|
|
200
|
+
|
|
201
|
+
if stripped.startswith("- "):
|
|
202
|
+
entries.append(unquote_yaml_scalar(stripped.removeprefix("- ").strip()))
|
|
203
|
+
|
|
204
|
+
return entries
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def docs_workflow_policy_errors(text: str) -> list[str]:
|
|
208
|
+
errors: list[str] = []
|
|
209
|
+
run_commands = workflow_run_commands(text)
|
|
210
|
+
path_entries = workflow_path_entries(text)
|
|
211
|
+
|
|
212
|
+
if DOCS_WORKFLOW_POLICY_COMMAND not in run_commands:
|
|
213
|
+
errors.append("docs workflow must run local-ci.py --docs-only")
|
|
214
|
+
if any("mkdocs build --clean" in command for command in run_commands):
|
|
215
|
+
errors.append("docs workflow must not call mkdocs build directly")
|
|
216
|
+
for required_path in DOCS_WORKFLOW_REQUIRED_PATHS:
|
|
217
|
+
if required_path not in path_entries:
|
|
218
|
+
errors.append(f"docs workflow path filter missing {required_path}")
|
|
219
|
+
return errors
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def display_workflow_path(path: Path) -> str:
|
|
223
|
+
try:
|
|
224
|
+
return str(path.relative_to(ROOT))
|
|
225
|
+
except ValueError:
|
|
226
|
+
return str(path)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def workflow_action_refs(text: str) -> list[tuple[int, str, str]]:
|
|
230
|
+
refs: list[tuple[int, str, str]] = []
|
|
231
|
+
for line_number, line in enumerate(text.splitlines(), start=1):
|
|
232
|
+
match = WORKFLOW_USES_RE.match(line)
|
|
233
|
+
if match:
|
|
234
|
+
refs.append((line_number, match.group("action"), match.group("ref")))
|
|
235
|
+
return refs
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def workflow_action_ref_errors(
|
|
239
|
+
paths: tuple[Path, ...] = GITHUB_WORKFLOW_FILES,
|
|
240
|
+
expected_refs: tuple[tuple[str, str], ...] = WORKFLOW_REQUIRED_ACTION_REFS,
|
|
241
|
+
) -> list[str]:
|
|
242
|
+
errors: list[str] = []
|
|
243
|
+
expected = dict(expected_refs)
|
|
244
|
+
found: set[str] = set()
|
|
245
|
+
|
|
246
|
+
for path in paths:
|
|
247
|
+
if not path.exists():
|
|
248
|
+
errors.append(f"workflow file is missing: {display_workflow_path(path)}")
|
|
249
|
+
continue
|
|
250
|
+
|
|
251
|
+
text = path.read_text(encoding="utf-8")
|
|
252
|
+
for line_number, action, ref in workflow_action_refs(text):
|
|
253
|
+
expected_ref = expected.get(action)
|
|
254
|
+
if expected_ref is None:
|
|
255
|
+
continue
|
|
256
|
+
found.add(action)
|
|
257
|
+
if ref != expected_ref:
|
|
258
|
+
errors.append(
|
|
259
|
+
f"{display_workflow_path(path)}:{line_number} uses {action}@{ref}; "
|
|
260
|
+
f"expected {action}@{expected_ref}"
|
|
261
|
+
)
|
|
262
|
+
|
|
263
|
+
for action, expected_ref in expected_refs:
|
|
264
|
+
if action not in found:
|
|
265
|
+
errors.append(f"workflow action ref missing: {action}@{expected_ref}")
|
|
266
|
+
|
|
267
|
+
return errors
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def run_workflow_action_ref_check(paths: tuple[Path, ...] = GITHUB_WORKFLOW_FILES) -> None:
|
|
271
|
+
errors = workflow_action_ref_errors(paths)
|
|
272
|
+
if errors:
|
|
273
|
+
raise SystemExit(
|
|
274
|
+
"workflow action ref check failed:\n"
|
|
275
|
+
+ "\n".join(f"- {error}" for error in errors)
|
|
276
|
+
)
|
|
277
|
+
print("\nWorkflow action ref check passed", flush=True)
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def run_docs_workflow_policy_check(path: Path = DOCS_WORKFLOW) -> None:
|
|
281
|
+
errors = docs_workflow_policy_errors(path.read_text(encoding="utf-8"))
|
|
282
|
+
if errors:
|
|
283
|
+
raise SystemExit("docs workflow policy check failed:\n" + "\n".join(f"- {error}" for error in errors))
|
|
284
|
+
print("\nDocs workflow policy check passed", flush=True)
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
def mkdocs_warning_lines(output: str) -> list[str]:
|
|
288
|
+
return [line for line in output.splitlines() if "WARNING" in line]
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def non_refs_mkdocs_warning_lines(output: str) -> list[str]:
|
|
292
|
+
return [line for line in mkdocs_warning_lines(output) if "refs/" not in line]
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
def refs_mkdocs_warning_lines(output: str) -> list[str]:
|
|
296
|
+
return [line for line in mkdocs_warning_lines(output) if "refs/" in line]
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def assert_mkdocs_warning_policy(
|
|
300
|
+
output: str,
|
|
301
|
+
*,
|
|
302
|
+
refs_warning_baseline: int = MKDOCS_REFS_WARNING_BASELINE,
|
|
303
|
+
) -> None:
|
|
304
|
+
unexpected = non_refs_mkdocs_warning_lines(output)
|
|
305
|
+
if unexpected:
|
|
306
|
+
sample = "\n".join(f"- {line}" for line in unexpected[:10])
|
|
307
|
+
raise SystemExit(
|
|
308
|
+
"mkdocs emitted non-refs warning(s); fix docs navigation or update the warning policy.\n"
|
|
309
|
+
f"Unexpected warning count: {len(unexpected)}\n"
|
|
310
|
+
f"{sample}"
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
refs_warnings = refs_mkdocs_warning_lines(output)
|
|
314
|
+
if len(refs_warnings) > refs_warning_baseline:
|
|
315
|
+
sample = "\n".join(f"- {line}" for line in refs_warnings[:10])
|
|
316
|
+
raise SystemExit(
|
|
317
|
+
"mkdocs refs-only warning count exceeded the accepted baseline; normalize new "
|
|
318
|
+
"refs links or update the baseline with a documented policy decision.\n"
|
|
319
|
+
f"Refs warning count: {len(refs_warnings)}\n"
|
|
320
|
+
f"Accepted baseline: {refs_warning_baseline}\n"
|
|
321
|
+
f"{sample}"
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
print(
|
|
325
|
+
"\nMkDocs warning policy passed: "
|
|
326
|
+
f"{len(refs_warnings)}/{refs_warning_baseline} refs-only warning(s)",
|
|
327
|
+
flush=True,
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
def assert_condition(condition: bool, message: str) -> None:
|
|
332
|
+
if not condition:
|
|
333
|
+
raise SystemExit(f"self-test failed: {message}")
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
def run_self_test() -> int:
|
|
337
|
+
with tempfile.TemporaryDirectory() as tmp:
|
|
338
|
+
root = Path(tmp)
|
|
339
|
+
for directory in PYTHON_COMPILE_DIRS:
|
|
340
|
+
(root / directory).mkdir(parents=True)
|
|
341
|
+
|
|
342
|
+
(root / "tools" / "audit" / "b.py").write_text("print('b')\n", encoding="utf-8")
|
|
343
|
+
(root / "tools" / "audit" / "a.py").write_text("print('a')\n", encoding="utf-8")
|
|
344
|
+
(root / "tools" / "preview" / "render.py").write_text("print('p')\n", encoding="utf-8")
|
|
345
|
+
|
|
346
|
+
assert_condition(
|
|
347
|
+
python_compile_files(root) == [
|
|
348
|
+
"tools/audit/a.py",
|
|
349
|
+
"tools/audit/b.py",
|
|
350
|
+
"tools/preview/render.py",
|
|
351
|
+
],
|
|
352
|
+
"python compile file list should be sorted and relative",
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
for directory in LINE_BUDGET_DIRS:
|
|
356
|
+
(root / directory).mkdir(parents=True)
|
|
357
|
+
|
|
358
|
+
(root / "knowledge" / "one.md").write_text("a\nb\n", encoding="utf-8")
|
|
359
|
+
(root / "examples" / "two.md").write_text("c\n", encoding="utf-8")
|
|
360
|
+
(root / "docs" / "nested").mkdir()
|
|
361
|
+
(root / "docs" / "nested" / "three.md").write_text("d\ne\nf\n", encoding="utf-8")
|
|
362
|
+
|
|
363
|
+
assert_condition(markdown_line_count(root) == 6, "markdown line count should include all budget dirs")
|
|
364
|
+
assert_condition(size_budget_warning(42) is None, "small line count should not warn")
|
|
365
|
+
assert_condition(
|
|
366
|
+
"consider pruning" in (size_budget_warning(KNOWLEDGE_WARN_LINES + 1) or ""),
|
|
367
|
+
"warning threshold should return a warning message",
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
try:
|
|
371
|
+
size_budget_warning(KNOWLEDGE_MAX_LINES + 1)
|
|
372
|
+
except SystemExit as error:
|
|
373
|
+
assert_condition("hard cap" in str(error), "hard cap should explain the failure")
|
|
374
|
+
else:
|
|
375
|
+
raise SystemExit("self-test failed: hard cap should raise SystemExit")
|
|
376
|
+
|
|
377
|
+
refs_only_output = "\n".join(
|
|
378
|
+
[
|
|
379
|
+
"INFO - Documentation built",
|
|
380
|
+
"WARNING - Doc file 'examples/component.md' contains a link '../refs/mui/Button.js', but the target 'refs/mui/Button.js' is not found among documentation files.",
|
|
381
|
+
"WARNING - Doc file 'knowledge/components/INDEX.md' contains a link '../../refs/ant-design/button.md', but the target 'refs/ant-design/button.md' is not found among documentation files.",
|
|
382
|
+
]
|
|
383
|
+
)
|
|
384
|
+
assert_condition(
|
|
385
|
+
len(mkdocs_warning_lines(refs_only_output)) == 2,
|
|
386
|
+
"mkdocs warning classifier should count WARNING lines",
|
|
387
|
+
)
|
|
388
|
+
assert_condition(
|
|
389
|
+
non_refs_mkdocs_warning_lines(refs_only_output) == [],
|
|
390
|
+
"refs-only mkdocs warnings should be allowed",
|
|
391
|
+
)
|
|
392
|
+
assert_condition(
|
|
393
|
+
len(refs_mkdocs_warning_lines(refs_only_output)) == 2,
|
|
394
|
+
"refs mkdocs warning classifier should count refs warning lines",
|
|
395
|
+
)
|
|
396
|
+
assert_condition(
|
|
397
|
+
run_capture(["python3", "-c", "print('quiet success')"], echo=False).strip() == "quiet success",
|
|
398
|
+
"quiet command capture should return stdout without echoing on success",
|
|
399
|
+
)
|
|
400
|
+
assert_mkdocs_warning_policy(refs_only_output, refs_warning_baseline=2)
|
|
401
|
+
|
|
402
|
+
refs_baseline_regression_output = refs_only_output + "\n" + (
|
|
403
|
+
"WARNING - Doc file 'examples/extra.md' contains a link '../refs/extra/source.md', "
|
|
404
|
+
"but the target 'refs/extra/source.md' is not found among documentation files."
|
|
405
|
+
)
|
|
406
|
+
try:
|
|
407
|
+
assert_mkdocs_warning_policy(refs_baseline_regression_output, refs_warning_baseline=2)
|
|
408
|
+
except SystemExit as error:
|
|
409
|
+
assert_condition("baseline" in str(error), "refs warning cap failure should explain baseline")
|
|
410
|
+
else:
|
|
411
|
+
raise SystemExit("self-test failed: refs warning cap should raise SystemExit")
|
|
412
|
+
|
|
413
|
+
mixed_output = refs_only_output + "\n" + (
|
|
414
|
+
"WARNING - Doc file 'index.md' contains a link 'skills/', "
|
|
415
|
+
"but the target 'skills/' is not found among documentation files."
|
|
416
|
+
)
|
|
417
|
+
try:
|
|
418
|
+
assert_mkdocs_warning_policy(mixed_output)
|
|
419
|
+
except SystemExit as error:
|
|
420
|
+
assert_condition("non-refs" in str(error), "non-refs warning failure should explain the policy")
|
|
421
|
+
else:
|
|
422
|
+
raise SystemExit("self-test failed: non-refs mkdocs warning should raise SystemExit")
|
|
423
|
+
|
|
424
|
+
passing_workflow = "\n".join(
|
|
425
|
+
[
|
|
426
|
+
" paths:",
|
|
427
|
+
*(f' - "{path}"' for path in DOCS_WORKFLOW_REQUIRED_PATHS),
|
|
428
|
+
" workflow_dispatch:",
|
|
429
|
+
" - name: Build site with warning policy",
|
|
430
|
+
f" run: {DOCS_WORKFLOW_POLICY_COMMAND}",
|
|
431
|
+
]
|
|
432
|
+
)
|
|
433
|
+
assert_condition(
|
|
434
|
+
workflow_path_entries(passing_workflow) == list(DOCS_WORKFLOW_REQUIRED_PATHS),
|
|
435
|
+
"workflow path parser should read quoted path entries",
|
|
436
|
+
)
|
|
437
|
+
assert_condition(
|
|
438
|
+
workflow_run_commands(passing_workflow) == [DOCS_WORKFLOW_POLICY_COMMAND],
|
|
439
|
+
"workflow run parser should read one-line run commands",
|
|
440
|
+
)
|
|
441
|
+
assert_condition(
|
|
442
|
+
docs_workflow_policy_errors(passing_workflow) == [],
|
|
443
|
+
"docs workflow fixture should pass when it uses docs-only policy",
|
|
444
|
+
)
|
|
445
|
+
action_ref_workflow = root / "action-refs.yml"
|
|
446
|
+
action_ref_workflow.write_text(
|
|
447
|
+
"\n".join(
|
|
448
|
+
[
|
|
449
|
+
"name: Action refs",
|
|
450
|
+
"jobs:",
|
|
451
|
+
" fixture:",
|
|
452
|
+
" steps:",
|
|
453
|
+
*(f" - uses: {action}@{ref}" for action, ref in WORKFLOW_REQUIRED_ACTION_REFS),
|
|
454
|
+
]
|
|
455
|
+
),
|
|
456
|
+
encoding="utf-8",
|
|
457
|
+
)
|
|
458
|
+
assert_condition(
|
|
459
|
+
workflow_action_refs(action_ref_workflow.read_text(encoding="utf-8"))[0] == (
|
|
460
|
+
5,
|
|
461
|
+
"actions/checkout",
|
|
462
|
+
"v6",
|
|
463
|
+
),
|
|
464
|
+
"workflow action ref parser should read uses lines with line numbers",
|
|
465
|
+
)
|
|
466
|
+
assert_condition(
|
|
467
|
+
workflow_action_ref_errors((action_ref_workflow,)) == [],
|
|
468
|
+
"workflow action ref fixture should pass when expected refs are present",
|
|
469
|
+
)
|
|
470
|
+
|
|
471
|
+
failing_workflow = "\n".join(
|
|
472
|
+
[
|
|
473
|
+
" - name: Build site",
|
|
474
|
+
" run: mkdocs build --clean",
|
|
475
|
+
]
|
|
476
|
+
)
|
|
477
|
+
workflow_errors = docs_workflow_policy_errors(failing_workflow)
|
|
478
|
+
assert_condition(
|
|
479
|
+
len(workflow_errors) == len(DOCS_WORKFLOW_REQUIRED_PATHS) + 2,
|
|
480
|
+
"docs workflow fixture should fail on direct mkdocs command and missing path filters",
|
|
481
|
+
)
|
|
482
|
+
assert_condition(
|
|
483
|
+
any("--docs-only" in error for error in workflow_errors),
|
|
484
|
+
"docs workflow failure should mention docs-only policy",
|
|
485
|
+
)
|
|
486
|
+
bad_action_ref_workflow = root / "bad-action-refs.yml"
|
|
487
|
+
bad_action_ref_workflow.write_text(
|
|
488
|
+
"\n".join(
|
|
489
|
+
[
|
|
490
|
+
"name: Bad action refs",
|
|
491
|
+
"jobs:",
|
|
492
|
+
" fixture:",
|
|
493
|
+
" steps:",
|
|
494
|
+
" - uses: actions/checkout@v4",
|
|
495
|
+
" - uses: actions/setup-node@v6",
|
|
496
|
+
]
|
|
497
|
+
),
|
|
498
|
+
encoding="utf-8",
|
|
499
|
+
)
|
|
500
|
+
action_ref_errors = workflow_action_ref_errors((bad_action_ref_workflow,))
|
|
501
|
+
assert_condition(
|
|
502
|
+
any("actions/checkout@v4" in error for error in action_ref_errors),
|
|
503
|
+
"workflow action ref failure should report stale action versions",
|
|
504
|
+
)
|
|
505
|
+
assert_condition(
|
|
506
|
+
any("actions/setup-python@v6" in error for error in action_ref_errors),
|
|
507
|
+
"workflow action ref failure should report missing required actions",
|
|
508
|
+
)
|
|
509
|
+
run_workflow_action_ref_check()
|
|
510
|
+
run_docs_workflow_policy_check()
|
|
511
|
+
|
|
512
|
+
print("Local CI self-test passed")
|
|
513
|
+
return 0
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
def main() -> int:
|
|
517
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
518
|
+
parser.add_argument("--self-test", action="store_true", help="Run local fixture checks.")
|
|
519
|
+
parser.add_argument(
|
|
520
|
+
"--docs-only",
|
|
521
|
+
action="store_true",
|
|
522
|
+
help="Run only mkdocs build plus warning policy, matching the docs deployment workflow.",
|
|
523
|
+
)
|
|
524
|
+
parser.add_argument(
|
|
525
|
+
"--skip-release-check",
|
|
526
|
+
action="store_true",
|
|
527
|
+
help="Skip the expensive npm release gate when rerunning workflow-only checks.",
|
|
528
|
+
)
|
|
529
|
+
parser.add_argument("--skip-docs", action="store_true", help="Skip mkdocs site build.")
|
|
530
|
+
parser.add_argument("--skip-vscode", action="store_true", help="Skip VS Code extension checks.")
|
|
531
|
+
args = parser.parse_args()
|
|
532
|
+
|
|
533
|
+
if args.self_test:
|
|
534
|
+
return run_self_test()
|
|
535
|
+
|
|
536
|
+
if args.docs_only:
|
|
537
|
+
run_docs_workflow_policy_check()
|
|
538
|
+
run_docs_build()
|
|
539
|
+
print("\nDocs-only MkDocs policy check passed", flush=True)
|
|
540
|
+
return 0
|
|
541
|
+
|
|
542
|
+
if not args.skip_release_check:
|
|
543
|
+
run_release_check()
|
|
544
|
+
run_python_compile()
|
|
545
|
+
run_size_budget()
|
|
546
|
+
run_workflow_action_ref_check()
|
|
547
|
+
run_docs_workflow_policy_check()
|
|
548
|
+
if not args.skip_vscode:
|
|
549
|
+
run_vscode_checks()
|
|
550
|
+
if not args.skip_docs:
|
|
551
|
+
run_docs_build()
|
|
552
|
+
|
|
553
|
+
print("\nLocal CI parity check passed", flush=True)
|
|
554
|
+
return 0
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
if __name__ == "__main__":
|
|
558
|
+
raise SystemExit(main())
|