cfsa-antigravity 1.0.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/bin/cli.mjs +324 -0
- package/package.json +34 -0
- package/template/.agent/instructions/commands.md +48 -0
- package/template/.agent/instructions/patterns.md +61 -0
- package/template/.agent/instructions/structure.md +29 -0
- package/template/.agent/instructions/tech-stack.md +43 -0
- package/template/.agent/instructions/workflow.md +41 -0
- package/template/.agent/kit-sync.md +15 -0
- package/template/.agent/rules/boundary-not-placeholder.md +146 -0
- package/template/.agent/rules/completion-checklist.md +48 -0
- package/template/.agent/rules/decision-classification.md +103 -0
- package/template/.agent/rules/extensibility.md +47 -0
- package/template/.agent/rules/question-vs-command.md +81 -0
- package/template/.agent/rules/security-first.md +43 -0
- package/template/.agent/rules/specificity-standards.md +54 -0
- package/template/.agent/rules/tdd-contract-first.md +57 -0
- package/template/.agent/rules/vertical-slices.md +42 -0
- package/template/.agent/skill-library/MANIFEST.md +480 -0
- package/template/.agent/skill-library/README.md +38 -0
- package/template/.agent/skill-library/meta/brand-guidelines/SKILL.md +73 -0
- package/template/.agent/skill-library/meta/claude-code/README.md +9 -0
- package/template/.agent/skill-library/meta/claude-code/agent-development/SKILL.md +415 -0
- package/template/.agent/skill-library/meta/claude-code/hook-development/SKILL.md +712 -0
- package/template/.agent/skill-library/meta/claude-code/plugin-structure/SKILL.md +476 -0
- package/template/.agent/skill-library/meta/git-advanced/SKILL.md +972 -0
- package/template/.agent/skill-library/meta/mcp-builder/SKILL.md +236 -0
- package/template/.agent/skill-library/meta/product-marketing-context/SKILL.md +241 -0
- package/template/.agent/skill-library/meta/regex-patterns/SKILL.md +751 -0
- package/template/.agent/skill-library/meta/tmux-processes/SKILL.md +210 -0
- package/template/.agent/skill-library/meta/using-tmux-for-interactive-commands/SKILL.md +178 -0
- package/template/.agent/skill-library/stack/3d/threejs-pro/SKILL.md +300 -0
- package/template/.agent/skill-library/stack/ai/ai-sdk/SKILL.md +77 -0
- package/template/.agent/skill-library/stack/ai/langchain/SKILL.md +530 -0
- package/template/.agent/skill-library/stack/ai/ollama/SKILL.md +321 -0
- package/template/.agent/skill-library/stack/ai/openai-sdk/SKILL.md +549 -0
- package/template/.agent/skill-library/stack/analytics/google-analytics/SKILL.md +153 -0
- package/template/.agent/skill-library/stack/api/graphql/SKILL.md +1061 -0
- package/template/.agent/skill-library/stack/api/trpc/SKILL.md +576 -0
- package/template/.agent/skill-library/stack/auth/authjs/SKILL.md +569 -0
- package/template/.agent/skill-library/stack/auth/clerk/SKILL.md +590 -0
- package/template/.agent/skill-library/stack/auth/firebase-auth/SKILL.md +734 -0
- package/template/.agent/skill-library/stack/cms/payload-cms/SKILL.md +573 -0
- package/template/.agent/skill-library/stack/cms/shopify/SKILL.md +1193 -0
- package/template/.agent/skill-library/stack/cms/wordpress/SKILL.md +1104 -0
- package/template/.agent/skill-library/stack/css/sass-scss/SKILL.md +1121 -0
- package/template/.agent/skill-library/stack/css/tailwind-css-patterns/SKILL.md +863 -0
- package/template/.agent/skill-library/stack/css/tailwind-design-system/SKILL.md +490 -0
- package/template/.agent/skill-library/stack/css/vanilla-css/SKILL.md +1078 -0
- package/template/.agent/skill-library/stack/databases/clickhouse/SKILL.md +311 -0
- package/template/.agent/skill-library/stack/databases/influxdb/SKILL.md +280 -0
- package/template/.agent/skill-library/stack/databases/lancedb/SKILL.md +415 -0
- package/template/.agent/skill-library/stack/databases/mongodb/SKILL.md +1169 -0
- package/template/.agent/skill-library/stack/databases/neo4j/SKILL.md +839 -0
- package/template/.agent/skill-library/stack/databases/pgvector/SKILL.md +241 -0
- package/template/.agent/skill-library/stack/databases/pinecone/SKILL.md +212 -0
- package/template/.agent/skill-library/stack/databases/postgresql/SKILL.md +658 -0
- package/template/.agent/skill-library/stack/databases/qdrant/SKILL.md +312 -0
- package/template/.agent/skill-library/stack/databases/redis/SKILL.md +1079 -0
- package/template/.agent/skill-library/stack/databases/spacetimedb/SKILL.md +532 -0
- package/template/.agent/skill-library/stack/databases/sqlite/SKILL.md +1132 -0
- package/template/.agent/skill-library/stack/databases/supabase/SKILL.md +640 -0
- package/template/.agent/skill-library/stack/databases/surrealdb-expert/SKILL.md +945 -0
- package/template/.agent/skill-library/stack/databases/timescaledb/SKILL.md +745 -0
- package/template/.agent/skill-library/stack/databases/weaviate/SKILL.md +218 -0
- package/template/.agent/skill-library/stack/devops/github-actions/SKILL.md +554 -0
- package/template/.agent/skill-library/stack/devops/kubernetes/SKILL.md +950 -0
- package/template/.agent/skill-library/stack/devops/nginx/SKILL.md +841 -0
- package/template/.agent/skill-library/stack/devops/terraform/SKILL.md +860 -0
- package/template/.agent/skill-library/stack/email/resend/SKILL.md +391 -0
- package/template/.agent/skill-library/stack/engines/godot/SKILL.md +488 -0
- package/template/.agent/skill-library/stack/extensions/chrome-extension/SKILL.md +375 -0
- package/template/.agent/skill-library/stack/extensions/vscode-extension/SKILL.md +453 -0
- package/template/.agent/skill-library/stack/frameworks/astro-framework/SKILL.md +162 -0
- package/template/.agent/skill-library/stack/frameworks/electron/SKILL.md +1286 -0
- package/template/.agent/skill-library/stack/frameworks/fastapi/SKILL.md +650 -0
- package/template/.agent/skill-library/stack/frameworks/hono/SKILL.md +90 -0
- package/template/.agent/skill-library/stack/frameworks/nestjs/SKILL.md +878 -0
- package/template/.agent/skill-library/stack/frameworks/nextjs/SKILL.md +635 -0
- package/template/.agent/skill-library/stack/frameworks/nuxt/SKILL.md +564 -0
- package/template/.agent/skill-library/stack/frameworks/sveltekit/SKILL.md +614 -0
- package/template/.agent/skill-library/stack/frameworks/tauri/SKILL.md +920 -0
- package/template/.agent/skill-library/stack/gamedev/godot/SKILL.md +1032 -0
- package/template/.agent/skill-library/stack/gamedev/unity/SKILL.md +1175 -0
- package/template/.agent/skill-library/stack/hosting/aws/SKILL.md +467 -0
- package/template/.agent/skill-library/stack/hosting/cloudflare/SKILL.md +201 -0
- package/template/.agent/skill-library/stack/hosting/docker-expert/SKILL.md +409 -0
- package/template/.agent/skill-library/stack/hosting/vercel/SKILL.md +484 -0
- package/template/.agent/skill-library/stack/languages/bash-scripting/SKILL.md +773 -0
- package/template/.agent/skill-library/stack/languages/c-cpp/SKILL.md +712 -0
- package/template/.agent/skill-library/stack/languages/gdscript/SKILL.md +789 -0
- package/template/.agent/skill-library/stack/languages/go/SKILL.md +664 -0
- package/template/.agent/skill-library/stack/languages/java/SKILL.md +778 -0
- package/template/.agent/skill-library/stack/languages/kotlin/SKILL.md +665 -0
- package/template/.agent/skill-library/stack/languages/python/SKILL.md +678 -0
- package/template/.agent/skill-library/stack/languages/rust/SKILL.md +673 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/SKILL.md +141 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/advanced-generics.md +90 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/branded-types.md +57 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/builder-pattern.md +71 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/common-pitfalls.md +135 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/conditional-types.md +27 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/decorators.md +98 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/discriminated-unions.md +62 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/mapped-types.md +53 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/performance-best-practices.md +104 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/template-literal-types.md +49 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/testing-types.md +112 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/type-guards.md +70 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/type-inference.md +101 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/utility-types.md +98 -0
- package/template/.agent/skill-library/stack/languages/vanilla-javascript/SKILL.md +803 -0
- package/template/.agent/skill-library/stack/messaging/kafka/SKILL.md +235 -0
- package/template/.agent/skill-library/stack/mobile/expo-react-native/SKILL.md +665 -0
- package/template/.agent/skill-library/stack/mobile/flutter/SKILL.md +316 -0
- package/template/.agent/skill-library/stack/mobile/react-native/SKILL.md +337 -0
- package/template/.agent/skill-library/stack/monitoring/posthog/SKILL.md +396 -0
- package/template/.agent/skill-library/stack/monitoring/sentry/SKILL.md +509 -0
- package/template/.agent/skill-library/stack/observability/datadog/SKILL.md +179 -0
- package/template/.agent/skill-library/stack/observability/distributed-tracing/SKILL.md +140 -0
- package/template/.agent/skill-library/stack/observability/logging-best-practices/SKILL.md +168 -0
- package/template/.agent/skill-library/stack/observability/opentelemetry/SKILL.md +164 -0
- package/template/.agent/skill-library/stack/observability/prometheus-grafana/SKILL.md +246 -0
- package/template/.agent/skill-library/stack/observability/python-observability/SKILL.md +158 -0
- package/template/.agent/skill-library/stack/orm/drizzle-orm/SKILL.md +613 -0
- package/template/.agent/skill-library/stack/orm/prisma/SKILL.md +744 -0
- package/template/.agent/skill-library/stack/payments/lemonsqueezy/SKILL.md +393 -0
- package/template/.agent/skill-library/stack/payments/stripe-integration/SKILL.md +457 -0
- package/template/.agent/skill-library/stack/queue/bullmq/SKILL.md +385 -0
- package/template/.agent/skill-library/stack/queue/inngest/SKILL.md +438 -0
- package/template/.agent/skill-library/stack/realtime/socketio/SKILL.md +595 -0
- package/template/.agent/skill-library/stack/search/elasticsearch/SKILL.md +248 -0
- package/template/.agent/skill-library/stack/search/meilisearch/SKILL.md +385 -0
- package/template/.agent/skill-library/stack/security/crypto-patterns/SKILL.md +437 -0
- package/template/.agent/skill-library/stack/security/csp-cors-headers/SKILL.md +588 -0
- package/template/.agent/skill-library/stack/security/dependency-auditing/SKILL.md +560 -0
- package/template/.agent/skill-library/stack/security/input-sanitization/SKILL.md +430 -0
- package/template/.agent/skill-library/stack/security/owasp-web-security/SKILL.md +421 -0
- package/template/.agent/skill-library/stack/state/tanstack-query/SKILL.md +637 -0
- package/template/.agent/skill-library/stack/state/zustand/SKILL.md +483 -0
- package/template/.agent/skill-library/stack/storage/aws-s3/SKILL.md +415 -0
- package/template/.agent/skill-library/stack/testing/playwright/SKILL.md +641 -0
- package/template/.agent/skill-library/stack/testing/storybook/SKILL.md +923 -0
- package/template/.agent/skill-library/stack/testing/testing-library/SKILL.md +872 -0
- package/template/.agent/skill-library/stack/testing/vitest/SKILL.md +714 -0
- package/template/.agent/skill-library/stack/ui/react-best-practices/SKILL.md +877 -0
- package/template/.agent/skill-library/stack/ui/react-composition-patterns/SKILL.md +1107 -0
- package/template/.agent/skill-library/stack/ui/react-flow/SKILL.md +425 -0
- package/template/.agent/skill-library/stack/ui/shadcn-ui/SKILL.md +703 -0
- package/template/.agent/skill-library/surface/api/api-caching/SKILL.md +458 -0
- package/template/.agent/skill-library/surface/api/api-documentation-openapi/SKILL.md +697 -0
- package/template/.agent/skill-library/surface/api/api-error-handling/SKILL.md +478 -0
- package/template/.agent/skill-library/surface/api/api-security-checklist/SKILL.md +147 -0
- package/template/.agent/skill-library/surface/api/api-versioning/SKILL.md +420 -0
- package/template/.agent/skill-library/surface/api/email-best-practices/SKILL.md +59 -0
- package/template/.agent/skill-library/surface/api/rate-limiting-abuse-protection/SKILL.md +147 -0
- package/template/.agent/skill-library/surface/api/rest-api-design/SKILL.md +478 -0
- package/template/.agent/skill-library/surface/api/webhook-design/SKILL.md +752 -0
- package/template/.agent/skill-library/surface/cli/cli-configuration-management/SKILL.md +445 -0
- package/template/.agent/skill-library/surface/cli/cli-error-diagnostics/SKILL.md +515 -0
- package/template/.agent/skill-library/surface/cli/cli-shell-integration/SKILL.md +479 -0
- package/template/.agent/skill-library/surface/cli/cli-ux-design/SKILL.md +477 -0
- package/template/.agent/skill-library/surface/desktop/desktop-app-distribution/SKILL.md +416 -0
- package/template/.agent/skill-library/surface/desktop/desktop-security-sandboxing/SKILL.md +407 -0
- package/template/.agent/skill-library/surface/desktop/desktop-ux-conventions/SKILL.md +361 -0
- package/template/.agent/skill-library/surface/desktop/native-os-integration/SKILL.md +563 -0
- package/template/.agent/skill-library/surface/extension/browser-extension-patterns/SKILL.md +482 -0
- package/template/.agent/skill-library/surface/extension/plugin-architecture-design/SKILL.md +632 -0
- package/template/.agent/skill-library/surface/extension/vscode-extension-development/SKILL.md +728 -0
- package/template/.agent/skill-library/surface/mobile/app-store-submission/SKILL.md +304 -0
- package/template/.agent/skill-library/surface/mobile/mobile-offline-sync/SKILL.md +443 -0
- package/template/.agent/skill-library/surface/mobile/mobile-responsive-patterns/SKILL.md +432 -0
- package/template/.agent/skill-library/surface/mobile/push-notifications/SKILL.md +495 -0
- package/template/.agent/skill-library/surface/web/accessibility-compliance/SKILL.md +827 -0
- package/template/.agent/skill-library/surface/web/ai-seo/SKILL.md +398 -0
- package/template/.agent/skill-library/surface/web/ai-seo/references/content-patterns.md +285 -0
- package/template/.agent/skill-library/surface/web/ai-seo/references/platform-ranking-factors.md +152 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/SKILL.md +309 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/event-library.md +260 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/ga4-implementation.md +300 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/gtm-implementation.md +390 -0
- package/template/.agent/skill-library/surface/web/authentication-ui-flows/SKILL.md +530 -0
- package/template/.agent/skill-library/surface/web/dark-mode-theming/SKILL.md +516 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/SKILL.md +105 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/charts.csv +26 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/colors.csv +97 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/landing.csv +31 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/styles.csv +59 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/typography.csv +58 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/ux-guidelines.csv +100 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/core.py +258 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/design_system.py +1067 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/search.py +106 -0
- package/template/.agent/skill-library/surface/web/form-handling-validation/SKILL.md +675 -0
- package/template/.agent/skill-library/surface/web/frontend-design/SKILL.md +1393 -0
- package/template/.agent/skill-library/surface/web/frontend-design/templates/cppn-hero.tsx +299 -0
- package/template/.agent/skill-library/surface/web/frontend-design/templates/wave-hero.tsx +875 -0
- package/template/.agent/skill-library/surface/web/frontend-verification/SKILL.md +111 -0
- package/template/.agent/skill-library/surface/web/frontend-verification/scripts/ux_audit.py +739 -0
- package/template/.agent/skill-library/surface/web/i18n-localization/SKILL.md +154 -0
- package/template/.agent/skill-library/surface/web/offline-first-pwa/SKILL.md +657 -0
- package/template/.agent/skill-library/surface/web/page-cro/SKILL.md +182 -0
- package/template/.agent/skill-library/surface/web/page-cro/references/experiments.md +248 -0
- package/template/.agent/skill-library/surface/web/programmatic-seo/SKILL.md +238 -0
- package/template/.agent/skill-library/surface/web/programmatic-seo/references/playbooks.md +308 -0
- package/template/.agent/skill-library/surface/web/schema-markup/SKILL.md +179 -0
- package/template/.agent/skill-library/surface/web/schema-markup/references/schema-examples.md +398 -0
- package/template/.agent/skill-library/surface/web/seo-audit/SKILL.md +394 -0
- package/template/.agent/skill-library/surface/web/seo-audit/references/ai-writing-detection.md +200 -0
- package/template/.agent/skill-library/surface/web/web-performance-optimization/SKILL.md +646 -0
- package/template/.agent/skill-library/surface/web/web-scraping/SKILL.md +58 -0
- package/template/.agent/skills/accessibility/SKILL.md +522 -0
- package/template/.agent/skills/accessibility/references/WCAG.md +162 -0
- package/template/.agent/skills/adversarial-review/SKILL.md +90 -0
- package/template/.agent/skills/antigravity-workflows/SKILL.md +81 -0
- package/template/.agent/skills/antigravity-workflows/resources/implementation-playbook.md +36 -0
- package/template/.agent/skills/api-design-principles/SKILL.md +37 -0
- package/template/.agent/skills/api-design-principles/assets/api-design-checklist.md +155 -0
- package/template/.agent/skills/api-design-principles/assets/rest-api-template.py +182 -0
- package/template/.agent/skills/api-design-principles/references/graphql-schema-design.md +583 -0
- package/template/.agent/skills/api-design-principles/references/rest-best-practices.md +408 -0
- package/template/.agent/skills/api-design-principles/resources/implementation-playbook.md +513 -0
- package/template/.agent/skills/api-versioning/SKILL.md +420 -0
- package/template/.agent/skills/architecture-mapping/SKILL.md +219 -0
- package/template/.agent/skills/bootstrap-agents/SKILL.md +259 -0
- package/template/.agent/skills/brainstorming/SKILL.md +236 -0
- package/template/.agent/skills/brand-guidelines/SKILL.md +44 -0
- package/template/.agent/skills/clean-code/SKILL.md +94 -0
- package/template/.agent/skills/code-review-pro/SKILL.md +152 -0
- package/template/.agent/skills/concise-planning/SKILL.md +68 -0
- package/template/.agent/skills/cross-layer-consistency/SKILL.md +117 -0
- package/template/.agent/skills/database-schema-design/SKILL.md +429 -0
- package/template/.agent/skills/deployment-procedures/SKILL.md +241 -0
- package/template/.agent/skills/design-anti-cliche/SKILL.md +159 -0
- package/template/.agent/skills/design-direction/SKILL.md +45 -0
- package/template/.agent/skills/error-handling-patterns/SKILL.md +721 -0
- package/template/.agent/skills/find-skills/SKILL.md +145 -0
- package/template/.agent/skills/git-advanced/SKILL.md +972 -0
- package/template/.agent/skills/git-workflow/SKILL.md +420 -0
- package/template/.agent/skills/idea-extraction/SKILL.md +271 -0
- package/template/.agent/skills/logging-best-practices/SKILL.md +851 -0
- package/template/.agent/skills/migration-management/SKILL.md +384 -0
- package/template/.agent/skills/minimalist-surgical-development/SKILL.md +69 -0
- package/template/.agent/skills/parallel-agents/SKILL.md +165 -0
- package/template/.agent/skills/parallel-debugging/SKILL.md +135 -0
- package/template/.agent/skills/parallel-feature-development/SKILL.md +166 -0
- package/template/.agent/skills/performance-budgeting/SKILL.md +144 -0
- package/template/.agent/skills/pipeline-rubrics/SKILL.md +51 -0
- package/template/.agent/skills/pipeline-rubrics/references/architecture-rubric.md +19 -0
- package/template/.agent/skills/pipeline-rubrics/references/be-rubric.md +21 -0
- package/template/.agent/skills/pipeline-rubrics/references/fe-rubric.md +20 -0
- package/template/.agent/skills/pipeline-rubrics/references/ia-rubric.md +19 -0
- package/template/.agent/skills/pipeline-rubrics/references/scoring.md +28 -0
- package/template/.agent/skills/pipeline-rubrics/references/vision-rubric.md +11 -0
- package/template/.agent/skills/prd-templates/SKILL.md +88 -0
- package/template/.agent/skills/prd-templates/references/architecture-design-template.md +88 -0
- package/template/.agent/skills/prd-templates/references/be-spec-template.md +101 -0
- package/template/.agent/skills/prd-templates/references/data-placement-template.md +74 -0
- package/template/.agent/skills/prd-templates/references/decomposition-templates.md +211 -0
- package/template/.agent/skills/prd-templates/references/design-system-decisions.md +198 -0
- package/template/.agent/skills/prd-templates/references/engineering-standards-template.md +124 -0
- package/template/.agent/skills/prd-templates/references/fe-classification-procedures.md +47 -0
- package/template/.agent/skills/prd-templates/references/fe-spec-template.md +84 -0
- package/template/.agent/skills/prd-templates/references/infrastructure-report-template.md +71 -0
- package/template/.agent/skills/prd-templates/references/operational-templates.md +116 -0
- package/template/.agent/skills/prd-templates/references/placeholder-guard-template.md +21 -0
- package/template/.agent/skills/prd-templates/references/surface-model.md +61 -0
- package/template/.agent/skills/prd-templates/references/vision-template.md +66 -0
- package/template/.agent/skills/prompt-engineer/README.md +659 -0
- package/template/.agent/skills/prompt-engineer/SKILL.md +249 -0
- package/template/.agent/skills/regex-patterns/SKILL.md +751 -0
- package/template/.agent/skills/resolve-ambiguity/SKILL.md +278 -0
- package/template/.agent/skills/rest-api-design/SKILL.md +478 -0
- package/template/.agent/skills/security-scanning-security-hardening/SKILL.md +231 -0
- package/template/.agent/skills/session-continuity/SKILL.md +730 -0
- package/template/.agent/skills/session-continuity/protocols/01-session-resumption.md +38 -0
- package/template/.agent/skills/session-continuity/protocols/02-progress-generation.md +85 -0
- package/template/.agent/skills/session-continuity/protocols/03-progress-update.md +70 -0
- package/template/.agent/skills/session-continuity/protocols/04-pattern-extraction.md +60 -0
- package/template/.agent/skills/session-continuity/protocols/05-session-close.md +37 -0
- package/template/.agent/skills/session-continuity/protocols/06-decision-analysis.md +84 -0
- package/template/.agent/skills/session-continuity/protocols/07-spec-pipeline-generation.md +48 -0
- package/template/.agent/skills/session-continuity/protocols/08-spec-pipeline-update.md +43 -0
- package/template/.agent/skills/session-continuity/protocols/09-parallel-claim.md +122 -0
- package/template/.agent/skills/session-continuity/protocols/10-placeholder-verification-gate.md +104 -0
- package/template/.agent/skills/session-continuity/protocols/ambiguity-gates.md +48 -0
- package/template/.agent/skills/skill-creator/LICENSE.txt +202 -0
- package/template/.agent/skills/skill-creator/README.md +270 -0
- package/template/.agent/skills/skill-creator/SKILL.md +590 -0
- package/template/.agent/skills/skill-creator/references/output-patterns.md +82 -0
- package/template/.agent/skills/skill-creator/references/workflows.md +28 -0
- package/template/.agent/skills/skill-creator/scripts/init_skill.py +303 -0
- package/template/.agent/skills/skill-creator/scripts/package_skill.py +110 -0
- package/template/.agent/skills/skill-creator/scripts/quick_validate.py +95 -0
- package/template/.agent/skills/spec-writing/SKILL.md +110 -0
- package/template/.agent/skills/systematic-debugging/CREATION-LOG.md +119 -0
- package/template/.agent/skills/systematic-debugging/SKILL.md +297 -0
- package/template/.agent/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
- package/template/.agent/skills/systematic-debugging/condition-based-waiting.md +115 -0
- package/template/.agent/skills/systematic-debugging/defense-in-depth.md +122 -0
- package/template/.agent/skills/systematic-debugging/find-polluter.sh +63 -0
- package/template/.agent/skills/systematic-debugging/root-cause-tracing.md +169 -0
- package/template/.agent/skills/systematic-debugging/test-academic.md +14 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/template/.agent/skills/tdd-workflow/SKILL.md +409 -0
- package/template/.agent/skills/tech-stack-catalog/SKILL.md +49 -0
- package/template/.agent/skills/tech-stack-catalog/references/constraint-questions.md +21 -0
- package/template/.agent/skills/tech-stack-catalog/references/dev-tooling-decisions.md +37 -0
- package/template/.agent/skills/tech-stack-catalog/references/surface-decision-tables.md +69 -0
- package/template/.agent/skills/technical-writer/SKILL.md +242 -0
- package/template/.agent/skills/testing-strategist/SKILL.md +932 -0
- package/template/.agent/skills/verification-before-completion/SKILL.md +145 -0
- package/template/.agent/skills/workflow-automation/SKILL.md +73 -0
- package/template/.agent/workflows/audit-ambiguity-execute.md +165 -0
- package/template/.agent/workflows/audit-ambiguity-rubrics.md +83 -0
- package/template/.agent/workflows/audit-ambiguity.md +64 -0
- package/template/.agent/workflows/bootstrap-agents-fill.md +201 -0
- package/template/.agent/workflows/bootstrap-agents-provision.md +197 -0
- package/template/.agent/workflows/bootstrap-agents.md +66 -0
- package/template/.agent/workflows/create-prd-architecture.md +119 -0
- package/template/.agent/workflows/create-prd-compile.md +138 -0
- package/template/.agent/workflows/create-prd-design-system.md +135 -0
- package/template/.agent/workflows/create-prd-security.md +113 -0
- package/template/.agent/workflows/create-prd-stack.md +91 -0
- package/template/.agent/workflows/create-prd.md +168 -0
- package/template/.agent/workflows/decompose-architecture-structure.md +82 -0
- package/template/.agent/workflows/decompose-architecture-validate.md +119 -0
- package/template/.agent/workflows/decompose-architecture.md +111 -0
- package/template/.agent/workflows/evolve-contract.md +98 -0
- package/template/.agent/workflows/evolve-feature-cascade.md +140 -0
- package/template/.agent/workflows/evolve-feature-classify.md +116 -0
- package/template/.agent/workflows/evolve-feature.md +56 -0
- package/template/.agent/workflows/ideate-discover.md +144 -0
- package/template/.agent/workflows/ideate-extract.md +129 -0
- package/template/.agent/workflows/ideate-validate.md +117 -0
- package/template/.agent/workflows/ideate.md +113 -0
- package/template/.agent/workflows/implement-slice-setup.md +113 -0
- package/template/.agent/workflows/implement-slice-tdd.md +198 -0
- package/template/.agent/workflows/implement-slice.md +50 -0
- package/template/.agent/workflows/plan-phase.md +202 -0
- package/template/.agent/workflows/propagate-decision-apply.md +135 -0
- package/template/.agent/workflows/propagate-decision-scan.md +147 -0
- package/template/.agent/workflows/propagate-decision.md +56 -0
- package/template/.agent/workflows/remediate-pipeline-assess.md +138 -0
- package/template/.agent/workflows/remediate-pipeline-execute.md +135 -0
- package/template/.agent/workflows/remediate-pipeline.md +55 -0
- package/template/.agent/workflows/resolve-ambiguity.md +82 -0
- package/template/.agent/workflows/sync-kit.md +209 -0
- package/template/.agent/workflows/update-architecture-map.md +74 -0
- package/template/.agent/workflows/validate-phase.md +219 -0
- package/template/.agent/workflows/verify-infrastructure.md +207 -0
- package/template/.agent/workflows/write-architecture-spec-deepen.md +139 -0
- package/template/.agent/workflows/write-architecture-spec-design.md +202 -0
- package/template/.agent/workflows/write-architecture-spec.md +63 -0
- package/template/.agent/workflows/write-be-spec-classify.md +165 -0
- package/template/.agent/workflows/write-be-spec-write.md +98 -0
- package/template/.agent/workflows/write-be-spec.md +76 -0
- package/template/.agent/workflows/write-fe-spec-classify.md +170 -0
- package/template/.agent/workflows/write-fe-spec-write.md +94 -0
- package/template/.agent/workflows/write-fe-spec.md +71 -0
- package/template/AGENTS.md +176 -0
- package/template/GEMINI.md +177 -0
- package/template/docs/README.md +187 -0
- package/template/docs/audits/.gitkeep +0 -0
- package/template/docs/audits/README.md +10 -0
- package/template/docs/plans/.gitkeep +0 -0
- package/template/docs/plans/README.md +21 -0
- package/template/docs/plans/be/.gitkeep +0 -0
- package/template/docs/plans/be/README.md +11 -0
- package/template/docs/plans/fe/.gitkeep +0 -0
- package/template/docs/plans/fe/README.md +11 -0
- package/template/docs/plans/ia/.gitkeep +0 -0
- package/template/docs/plans/ia/README.md +17 -0
- package/template/docs/plans/ia/deep-dives/.gitkeep +0 -0
- package/template/docs/plans/ia/deep-dives/README.md +5 -0
- package/template/docs/plans/phases/.gitkeep +0 -0
- package/template/docs/plans/phases/README.md +11 -0
|
@@ -0,0 +1,632 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: plugin-architecture-design
|
|
3
|
+
description: Plugin and extension system design covering discovery, lifecycle hooks, dependency injection, versioning, sandboxing, configuration schemas, event buses, and marketplace patterns. Use when building applications that need third-party extensibility.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Plugin Architecture Design
|
|
8
|
+
|
|
9
|
+
Design extension systems that allow third-party developers to safely extend your application with discoverable, versioned, and sandboxed plugins.
|
|
10
|
+
|
|
11
|
+
## Plugin Discovery and Loading
|
|
12
|
+
|
|
13
|
+
### Discovery Mechanisms
|
|
14
|
+
|
|
15
|
+
| Mechanism | How It Works | Example |
|
|
16
|
+
|-----------|-------------|---------|
|
|
17
|
+
| Directory scanning | Scan a known directory for plugin manifests | `~/.myapp/plugins/*/plugin.json` |
|
|
18
|
+
| Package manager | Install plugins via npm/cargo/pip | `npm install myapp-plugin-foo` |
|
|
19
|
+
| Registry API | Query a remote plugin registry | `GET /api/plugins?search=foo` |
|
|
20
|
+
| Configuration | User lists plugins in config file | `plugins: ["plugin-a", "plugin-b"]` |
|
|
21
|
+
| Convention-based | Name prefix in node_modules | `myapp-plugin-*` in `node_modules` |
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
// Directory-based plugin discovery
|
|
25
|
+
import fs from 'fs';
|
|
26
|
+
import path from 'path';
|
|
27
|
+
import { z } from 'zod';
|
|
28
|
+
|
|
29
|
+
const PluginManifestSchema = z.object({
|
|
30
|
+
name: z.string().regex(/^[a-z0-9-]+$/),
|
|
31
|
+
version: z.string().regex(/^\d+\.\d+\.\d+$/),
|
|
32
|
+
description: z.string(),
|
|
33
|
+
main: z.string(), // Entry point relative to plugin directory
|
|
34
|
+
engines: z.object({
|
|
35
|
+
myapp: z.string(), // Semver range: ">=1.0.0 <2.0.0"
|
|
36
|
+
}),
|
|
37
|
+
permissions: z.array(z.enum([
|
|
38
|
+
'fs:read', 'fs:write', 'network', 'ui:sidebar', 'ui:statusbar',
|
|
39
|
+
'commands', 'config', 'events',
|
|
40
|
+
])).default([]),
|
|
41
|
+
activationEvents: z.array(z.string()).default(['*']),
|
|
42
|
+
configuration: z.record(z.unknown()).optional(),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
type PluginManifest = z.infer<typeof PluginManifestSchema>;
|
|
46
|
+
|
|
47
|
+
async function discoverPlugins(pluginDirs: string[]): Promise<PluginManifest[]> {
|
|
48
|
+
const manifests: PluginManifest[] = [];
|
|
49
|
+
|
|
50
|
+
for (const dir of pluginDirs) {
|
|
51
|
+
if (!fs.existsSync(dir)) continue;
|
|
52
|
+
|
|
53
|
+
const entries = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
54
|
+
for (const entry of entries) {
|
|
55
|
+
if (!entry.isDirectory()) continue;
|
|
56
|
+
|
|
57
|
+
const manifestPath = path.join(dir, entry.name, 'plugin.json');
|
|
58
|
+
if (!fs.existsSync(manifestPath)) continue;
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
const raw = JSON.parse(await fs.promises.readFile(manifestPath, 'utf-8'));
|
|
62
|
+
const manifest = PluginManifestSchema.parse(raw);
|
|
63
|
+
manifests.push(manifest);
|
|
64
|
+
} catch (error) {
|
|
65
|
+
console.warn(`Invalid plugin manifest at ${manifestPath}: ${(error as Error).message}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return manifests;
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### npm-based Discovery
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
// Discover plugins installed as npm packages
|
|
78
|
+
import { createRequire } from 'module';
|
|
79
|
+
|
|
80
|
+
async function discoverNpmPlugins(prefix: string): Promise<PluginManifest[]> {
|
|
81
|
+
const require = createRequire(import.meta.url);
|
|
82
|
+
const packageJson = require(path.join(process.cwd(), 'package.json'));
|
|
83
|
+
|
|
84
|
+
const pluginDeps = Object.keys({
|
|
85
|
+
...packageJson.dependencies,
|
|
86
|
+
...packageJson.devDependencies,
|
|
87
|
+
}).filter((name) => name.startsWith(prefix));
|
|
88
|
+
|
|
89
|
+
const manifests: PluginManifest[] = [];
|
|
90
|
+
|
|
91
|
+
for (const dep of pluginDeps) {
|
|
92
|
+
try {
|
|
93
|
+
const pluginPkg = require(`${dep}/plugin.json`);
|
|
94
|
+
manifests.push(PluginManifestSchema.parse(pluginPkg));
|
|
95
|
+
} catch {
|
|
96
|
+
// Not a valid plugin package
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return manifests;
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Plugin Lifecycle Hooks
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
// Plugin interface that all plugins must implement
|
|
108
|
+
interface Plugin {
|
|
109
|
+
/** Called when the plugin is first loaded. Set up resources. */
|
|
110
|
+
activate(context: PluginContext): Promise<void>;
|
|
111
|
+
|
|
112
|
+
/** Called when the plugin is disabled or the app shuts down. Clean up. */
|
|
113
|
+
deactivate(): Promise<void>;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Optional lifecycle hooks (implemented via interface extension)
|
|
117
|
+
interface PluginWithConfig extends Plugin {
|
|
118
|
+
/** Called when plugin configuration changes */
|
|
119
|
+
onConfigChanged(newConfig: Record<string, unknown>): Promise<void>;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
interface PluginWithMigration extends Plugin {
|
|
123
|
+
/** Called when the plugin is updated to a new version */
|
|
124
|
+
onUpdate(previousVersion: string, currentVersion: string): Promise<void>;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Plugin context provided by the host
|
|
128
|
+
interface PluginContext {
|
|
129
|
+
/** Plugin's unique identifier */
|
|
130
|
+
pluginId: string;
|
|
131
|
+
|
|
132
|
+
/** Plugin's version */
|
|
133
|
+
version: string;
|
|
134
|
+
|
|
135
|
+
/** Scoped logger */
|
|
136
|
+
logger: PluginLogger;
|
|
137
|
+
|
|
138
|
+
/** Register a command */
|
|
139
|
+
registerCommand(id: string, handler: CommandHandler): Disposable;
|
|
140
|
+
|
|
141
|
+
/** Register a UI contribution */
|
|
142
|
+
registerView(location: ViewLocation, factory: ViewFactory): Disposable;
|
|
143
|
+
|
|
144
|
+
/** Subscribe to events */
|
|
145
|
+
onEvent<T>(eventName: string, handler: (data: T) => void): Disposable;
|
|
146
|
+
|
|
147
|
+
/** Emit events */
|
|
148
|
+
emitEvent<T>(eventName: string, data: T): void;
|
|
149
|
+
|
|
150
|
+
/** Access plugin-scoped storage */
|
|
151
|
+
storage: PluginStorage;
|
|
152
|
+
|
|
153
|
+
/** Access plugin configuration */
|
|
154
|
+
config: PluginConfig;
|
|
155
|
+
|
|
156
|
+
/** Register disposables for automatic cleanup */
|
|
157
|
+
subscriptions: Disposable[];
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Disposable pattern for cleanup
|
|
161
|
+
interface Disposable {
|
|
162
|
+
dispose(): void;
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Lifecycle State Machine
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
┌───────────┐
|
|
170
|
+
│ Discovered│
|
|
171
|
+
└─────┬─────┘
|
|
172
|
+
│ load()
|
|
173
|
+
┌─────▼─────┐
|
|
174
|
+
│ Loaded │ (manifest parsed, dependencies checked)
|
|
175
|
+
└─────┬─────┘
|
|
176
|
+
│ activate()
|
|
177
|
+
┌─────▼─────┐
|
|
178
|
+
┌──→ │ Active │ ←──┐
|
|
179
|
+
│ └─────┬─────┘ │
|
|
180
|
+
│ │ │
|
|
181
|
+
enable() │ deactivate() activate()
|
|
182
|
+
│ │ │
|
|
183
|
+
│ ┌─────▼─────┐ │
|
|
184
|
+
└── │ Inactive │ ──┘
|
|
185
|
+
└─────┬─────┘
|
|
186
|
+
│ uninstall()
|
|
187
|
+
┌─────▼─────┐
|
|
188
|
+
│ Uninstalled│
|
|
189
|
+
└───────────┘
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
// Plugin manager handling lifecycle
|
|
194
|
+
class PluginManager {
|
|
195
|
+
private plugins = new Map<string, PluginInstance>();
|
|
196
|
+
|
|
197
|
+
async loadPlugin(manifest: PluginManifest, pluginDir: string): Promise<void> {
|
|
198
|
+
// Check compatibility
|
|
199
|
+
if (!satisfies(APP_VERSION, manifest.engines.myapp)) {
|
|
200
|
+
throw new Error(
|
|
201
|
+
`Plugin ${manifest.name}@${manifest.version} requires myapp ${manifest.engines.myapp}, ` +
|
|
202
|
+
`but running ${APP_VERSION}`
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Check dependencies
|
|
207
|
+
await this.resolveDependencies(manifest);
|
|
208
|
+
|
|
209
|
+
// Load the plugin module
|
|
210
|
+
const entryPoint = path.join(pluginDir, manifest.main);
|
|
211
|
+
const module = await import(entryPoint);
|
|
212
|
+
const plugin: Plugin = module.default || module;
|
|
213
|
+
|
|
214
|
+
if (typeof plugin.activate !== 'function') {
|
|
215
|
+
throw new Error(`Plugin ${manifest.name} does not export an activate function`);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
this.plugins.set(manifest.name, {
|
|
219
|
+
manifest,
|
|
220
|
+
plugin,
|
|
221
|
+
state: 'loaded',
|
|
222
|
+
context: null,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
async activatePlugin(name: string): Promise<void> {
|
|
227
|
+
const instance = this.plugins.get(name);
|
|
228
|
+
if (!instance) throw new Error(`Plugin ${name} not found`);
|
|
229
|
+
if (instance.state === 'active') return;
|
|
230
|
+
|
|
231
|
+
const context = this.createContext(instance.manifest);
|
|
232
|
+
instance.context = context;
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
await instance.plugin.activate(context);
|
|
236
|
+
instance.state = 'active';
|
|
237
|
+
} catch (error) {
|
|
238
|
+
// Activation failed -- clean up any partial registrations
|
|
239
|
+
for (const sub of context.subscriptions) {
|
|
240
|
+
sub.dispose();
|
|
241
|
+
}
|
|
242
|
+
instance.state = 'error';
|
|
243
|
+
throw error;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
async deactivatePlugin(name: string): Promise<void> {
|
|
248
|
+
const instance = this.plugins.get(name);
|
|
249
|
+
if (!instance || instance.state !== 'active') return;
|
|
250
|
+
|
|
251
|
+
try {
|
|
252
|
+
await instance.plugin.deactivate();
|
|
253
|
+
} finally {
|
|
254
|
+
// Always clean up, even if deactivate throws
|
|
255
|
+
if (instance.context) {
|
|
256
|
+
for (const sub of instance.context.subscriptions) {
|
|
257
|
+
sub.dispose();
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
instance.state = 'inactive';
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
async deactivateAll(): Promise<void> {
|
|
265
|
+
// Deactivate in reverse order of activation
|
|
266
|
+
const active = [...this.plugins.entries()]
|
|
267
|
+
.filter(([, inst]) => inst.state === 'active')
|
|
268
|
+
.reverse();
|
|
269
|
+
|
|
270
|
+
for (const [name] of active) {
|
|
271
|
+
try {
|
|
272
|
+
await this.deactivatePlugin(name);
|
|
273
|
+
} catch (error) {
|
|
274
|
+
console.error(`Failed to deactivate plugin ${name}:`, error);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## Dependency Injection for Plugins
|
|
282
|
+
|
|
283
|
+
```typescript
|
|
284
|
+
// Service registry -- plugins request services by interface, not implementation
|
|
285
|
+
class ServiceRegistry {
|
|
286
|
+
private services = new Map<string, unknown>();
|
|
287
|
+
|
|
288
|
+
register<T>(id: string, service: T): void {
|
|
289
|
+
if (this.services.has(id)) {
|
|
290
|
+
throw new Error(`Service ${id} is already registered`);
|
|
291
|
+
}
|
|
292
|
+
this.services.set(id, service);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
get<T>(id: string): T {
|
|
296
|
+
const service = this.services.get(id);
|
|
297
|
+
if (!service) {
|
|
298
|
+
throw new Error(`Service ${id} not found. Is the providing plugin active?`);
|
|
299
|
+
}
|
|
300
|
+
return service as T;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
has(id: string): boolean {
|
|
304
|
+
return this.services.has(id);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Host registers core services
|
|
309
|
+
const registry = new ServiceRegistry();
|
|
310
|
+
registry.register('storage', storageService);
|
|
311
|
+
registry.register('http', httpService);
|
|
312
|
+
registry.register('ui', uiService);
|
|
313
|
+
|
|
314
|
+
// Plugin accesses services through context
|
|
315
|
+
class PluginContextImpl implements PluginContext {
|
|
316
|
+
constructor(
|
|
317
|
+
private registry: ServiceRegistry,
|
|
318
|
+
private manifest: PluginManifest,
|
|
319
|
+
) {}
|
|
320
|
+
|
|
321
|
+
getService<T>(id: string): T {
|
|
322
|
+
// Check if plugin has permission to access this service
|
|
323
|
+
const requiredPermission = SERVICE_PERMISSIONS[id];
|
|
324
|
+
if (requiredPermission && !this.manifest.permissions.includes(requiredPermission)) {
|
|
325
|
+
throw new Error(
|
|
326
|
+
`Plugin ${this.manifest.name} does not have permission "${requiredPermission}" ` +
|
|
327
|
+
`required to access service "${id}"`
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
return this.registry.get<T>(id);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
## Versioning and Compatibility Contracts
|
|
336
|
+
|
|
337
|
+
```typescript
|
|
338
|
+
// Plugin API versioning with semver
|
|
339
|
+
import { satisfies, valid } from 'semver';
|
|
340
|
+
|
|
341
|
+
// Host declares its API version
|
|
342
|
+
const HOST_API_VERSION = '2.3.0';
|
|
343
|
+
|
|
344
|
+
// Plugin declares compatible range
|
|
345
|
+
// manifest.json: "engines": { "myapp": ">=2.0.0 <3.0.0" }
|
|
346
|
+
|
|
347
|
+
function isPluginCompatible(manifest: PluginManifest): {
|
|
348
|
+
compatible: boolean;
|
|
349
|
+
reason?: string;
|
|
350
|
+
} {
|
|
351
|
+
if (!valid(manifest.version)) {
|
|
352
|
+
return { compatible: false, reason: `Invalid plugin version: ${manifest.version}` };
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
if (!satisfies(HOST_API_VERSION, manifest.engines.myapp)) {
|
|
356
|
+
return {
|
|
357
|
+
compatible: false,
|
|
358
|
+
reason: `Plugin requires myapp ${manifest.engines.myapp}, running ${HOST_API_VERSION}`,
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return { compatible: true };
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// API stability markers
|
|
366
|
+
interface HostAPI {
|
|
367
|
+
/** @stable - Will not change in minor/patch versions */
|
|
368
|
+
registerCommand(id: string, handler: CommandHandler): Disposable;
|
|
369
|
+
|
|
370
|
+
/** @experimental - May change in minor versions */
|
|
371
|
+
registerAIProvider(provider: AIProvider): Disposable;
|
|
372
|
+
|
|
373
|
+
/** @deprecated - Use registerCommand instead. Will be removed in v3.0 */
|
|
374
|
+
addCommand(id: string, handler: CommandHandler): void;
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
## Sandboxing Untrusted Plugins
|
|
379
|
+
|
|
380
|
+
```typescript
|
|
381
|
+
// Node.js vm module for basic sandboxing
|
|
382
|
+
import vm from 'vm';
|
|
383
|
+
|
|
384
|
+
function createSandboxedPlugin(code: string, manifest: PluginManifest): Plugin {
|
|
385
|
+
const sandbox: Record<string, unknown> = {
|
|
386
|
+
console: createScopedConsole(manifest.name),
|
|
387
|
+
setTimeout,
|
|
388
|
+
clearTimeout,
|
|
389
|
+
setInterval,
|
|
390
|
+
clearInterval,
|
|
391
|
+
Promise,
|
|
392
|
+
// Expose only permitted APIs
|
|
393
|
+
...(manifest.permissions.includes('network')
|
|
394
|
+
? { fetch: createScopedFetch(manifest.name) }
|
|
395
|
+
: {}),
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
// Block access to dangerous globals
|
|
399
|
+
// fs, child_process, process.env are NOT in the sandbox
|
|
400
|
+
|
|
401
|
+
const context = vm.createContext(sandbox);
|
|
402
|
+
const script = new vm.Script(code, {
|
|
403
|
+
filename: `plugin:${manifest.name}/main.js`,
|
|
404
|
+
timeout: 5000, // 5 second execution limit
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
script.runInContext(context);
|
|
408
|
+
return sandbox.exports as Plugin;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Worker-based isolation for stronger sandboxing
|
|
412
|
+
import { Worker } from 'worker_threads';
|
|
413
|
+
|
|
414
|
+
function createWorkerPlugin(pluginPath: string, manifest: PluginManifest): PluginProxy {
|
|
415
|
+
const worker = new Worker(pluginPath, {
|
|
416
|
+
workerData: { manifest },
|
|
417
|
+
resourceLimits: {
|
|
418
|
+
maxOldGenerationSizeMb: 64, // Memory limit
|
|
419
|
+
maxYoungGenerationSizeMb: 16,
|
|
420
|
+
codeRangeSizeMb: 16,
|
|
421
|
+
},
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
// Communicate via structured messages
|
|
425
|
+
return new PluginProxy(worker, manifest);
|
|
426
|
+
}
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
## Plugin Configuration Schemas
|
|
430
|
+
|
|
431
|
+
```typescript
|
|
432
|
+
// Plugin declares its configuration schema in the manifest
|
|
433
|
+
// plugin.json
|
|
434
|
+
{
|
|
435
|
+
"name": "my-plugin",
|
|
436
|
+
"version": "1.0.0",
|
|
437
|
+
"configuration": {
|
|
438
|
+
"type": "object",
|
|
439
|
+
"properties": {
|
|
440
|
+
"apiKey": {
|
|
441
|
+
"type": "string",
|
|
442
|
+
"description": "API key for the service",
|
|
443
|
+
"secret": true
|
|
444
|
+
},
|
|
445
|
+
"maxRetries": {
|
|
446
|
+
"type": "number",
|
|
447
|
+
"default": 3,
|
|
448
|
+
"minimum": 1,
|
|
449
|
+
"maximum": 10,
|
|
450
|
+
"description": "Maximum retry attempts"
|
|
451
|
+
},
|
|
452
|
+
"theme": {
|
|
453
|
+
"type": "string",
|
|
454
|
+
"enum": ["light", "dark", "auto"],
|
|
455
|
+
"default": "auto",
|
|
456
|
+
"description": "Plugin UI theme"
|
|
457
|
+
}
|
|
458
|
+
},
|
|
459
|
+
"required": ["apiKey"]
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
```typescript
|
|
465
|
+
// Host validates plugin configuration against its schema
|
|
466
|
+
import Ajv from 'ajv';
|
|
467
|
+
|
|
468
|
+
const ajv = new Ajv({ allErrors: true });
|
|
469
|
+
|
|
470
|
+
function validatePluginConfig(
|
|
471
|
+
manifest: PluginManifest,
|
|
472
|
+
config: Record<string, unknown>
|
|
473
|
+
): { valid: boolean; errors?: string[] } {
|
|
474
|
+
if (!manifest.configuration) return { valid: true };
|
|
475
|
+
|
|
476
|
+
const validate = ajv.compile(manifest.configuration);
|
|
477
|
+
const valid = validate(config);
|
|
478
|
+
|
|
479
|
+
if (!valid) {
|
|
480
|
+
return {
|
|
481
|
+
valid: false,
|
|
482
|
+
errors: validate.errors?.map((e) => `${e.instancePath} ${e.message}`) ?? [],
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
return { valid: true };
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// Plugin reads its configuration through context
|
|
490
|
+
class PluginConfig {
|
|
491
|
+
constructor(
|
|
492
|
+
private pluginId: string,
|
|
493
|
+
private store: ConfigStore,
|
|
494
|
+
private schema: Record<string, unknown>,
|
|
495
|
+
) {}
|
|
496
|
+
|
|
497
|
+
get<T>(key: string): T {
|
|
498
|
+
const value = this.store.get(`plugins.${this.pluginId}.${key}`);
|
|
499
|
+
return value as T ?? this.getDefault(key);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
async set(key: string, value: unknown): Promise<void> {
|
|
503
|
+
// Validate against schema before storing
|
|
504
|
+
const config = { ...this.getAll(), [key]: value };
|
|
505
|
+
const result = validatePluginConfig({ configuration: this.schema } as any, config);
|
|
506
|
+
if (!result.valid) {
|
|
507
|
+
throw new Error(`Invalid config: ${result.errors?.join(', ')}`);
|
|
508
|
+
}
|
|
509
|
+
await this.store.set(`plugins.${this.pluginId}.${key}`, value);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
## Event Bus / Hook System
|
|
515
|
+
|
|
516
|
+
```typescript
|
|
517
|
+
// Typed event bus for plugin communication
|
|
518
|
+
type EventHandler<T = unknown> = (data: T) => void | Promise<void>;
|
|
519
|
+
|
|
520
|
+
class EventBus {
|
|
521
|
+
private handlers = new Map<string, Set<EventHandler>>();
|
|
522
|
+
private interceptors = new Map<string, Set<(data: unknown) => unknown>>();
|
|
523
|
+
|
|
524
|
+
on<T>(event: string, handler: EventHandler<T>): Disposable {
|
|
525
|
+
if (!this.handlers.has(event)) {
|
|
526
|
+
this.handlers.set(event, new Set());
|
|
527
|
+
}
|
|
528
|
+
this.handlers.get(event)!.add(handler as EventHandler);
|
|
529
|
+
|
|
530
|
+
return {
|
|
531
|
+
dispose: () => {
|
|
532
|
+
this.handlers.get(event)?.delete(handler as EventHandler);
|
|
533
|
+
},
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
async emit<T>(event: string, data: T): Promise<void> {
|
|
538
|
+
// Run interceptors first (can modify data)
|
|
539
|
+
let processedData: unknown = data;
|
|
540
|
+
const interceptors = this.interceptors.get(event);
|
|
541
|
+
if (interceptors) {
|
|
542
|
+
for (const interceptor of interceptors) {
|
|
543
|
+
processedData = await interceptor(processedData);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// Notify all handlers
|
|
548
|
+
const handlers = this.handlers.get(event);
|
|
549
|
+
if (!handlers) return;
|
|
550
|
+
|
|
551
|
+
const errors: Error[] = [];
|
|
552
|
+
for (const handler of handlers) {
|
|
553
|
+
try {
|
|
554
|
+
await handler(processedData);
|
|
555
|
+
} catch (error) {
|
|
556
|
+
errors.push(error as Error);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
if (errors.length > 0) {
|
|
561
|
+
console.error(`${errors.length} handler(s) failed for event "${event}":`, errors);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/** Interceptors can modify event data before handlers receive it */
|
|
566
|
+
intercept<T>(event: string, interceptor: (data: T) => T | Promise<T>): Disposable {
|
|
567
|
+
if (!this.interceptors.has(event)) {
|
|
568
|
+
this.interceptors.set(event, new Set());
|
|
569
|
+
}
|
|
570
|
+
this.interceptors.get(event)!.add(interceptor as (data: unknown) => unknown);
|
|
571
|
+
|
|
572
|
+
return {
|
|
573
|
+
dispose: () => {
|
|
574
|
+
this.interceptors.get(event)?.delete(interceptor as (data: unknown) => unknown);
|
|
575
|
+
},
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// Usage in plugins
|
|
581
|
+
async function activate(context: PluginContext) {
|
|
582
|
+
// Listen to host events
|
|
583
|
+
context.subscriptions.push(
|
|
584
|
+
context.onEvent('document:saved', async (doc: Document) => {
|
|
585
|
+
await formatDocument(doc);
|
|
586
|
+
})
|
|
587
|
+
);
|
|
588
|
+
|
|
589
|
+
// Emit custom events for other plugins
|
|
590
|
+
context.emitEvent('my-plugin:analysis-complete', { results });
|
|
591
|
+
}
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
## Documentation for Plugin Authors
|
|
595
|
+
|
|
596
|
+
Every plugin system must provide:
|
|
597
|
+
|
|
598
|
+
| Document | Content |
|
|
599
|
+
|----------|---------|
|
|
600
|
+
| Getting Started Guide | Scaffold a plugin, run in development, install locally |
|
|
601
|
+
| API Reference | Every method, event, and type with examples |
|
|
602
|
+
| Plugin Manifest Reference | Every field in `plugin.json` with validation rules |
|
|
603
|
+
| Permissions Guide | What each permission grants, why it is needed |
|
|
604
|
+
| Publishing Guide | How to submit to the marketplace / registry |
|
|
605
|
+
| Migration Guide | Breaking changes between API versions |
|
|
606
|
+
|
|
607
|
+
## Plugin Marketplace Patterns
|
|
608
|
+
|
|
609
|
+
| Feature | Implementation |
|
|
610
|
+
|---------|---------------|
|
|
611
|
+
| Search | Full-text search on name, description, tags |
|
|
612
|
+
| Categories | Predefined taxonomy (themes, languages, tools, integrations) |
|
|
613
|
+
| Ratings/reviews | User ratings with verified-install badge |
|
|
614
|
+
| Install count | Track unique installs, not downloads |
|
|
615
|
+
| Compatibility | Filter by host version compatibility |
|
|
616
|
+
| Verified publisher | Badge for trusted developers |
|
|
617
|
+
| Security scan | Automated analysis on submission |
|
|
618
|
+
| Auto-update | Host checks for updates periodically |
|
|
619
|
+
|
|
620
|
+
## Output Checklist
|
|
621
|
+
|
|
622
|
+
- [ ] Plugin manifest schema defined and validated with Zod or JSON Schema
|
|
623
|
+
- [ ] Plugin discovery supports at least two mechanisms (directory + package manager)
|
|
624
|
+
- [ ] Lifecycle hooks: activate, deactivate, onConfigChanged, onUpdate
|
|
625
|
+
- [ ] Disposable pattern for automatic cleanup on deactivation
|
|
626
|
+
- [ ] Service registry with permission-gated access
|
|
627
|
+
- [ ] Semver compatibility checking for host/plugin versions
|
|
628
|
+
- [ ] Sandboxing for untrusted plugins (vm or worker threads)
|
|
629
|
+
- [ ] Plugin configuration validated against declared schema
|
|
630
|
+
- [ ] Typed event bus with interceptor support
|
|
631
|
+
- [ ] API stability markers (stable, experimental, deprecated)
|
|
632
|
+
- [ ] Plugin author documentation (getting started, API reference, publishing)
|