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,773 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bash-scripting
|
|
3
|
+
description: Bash scripting patterns for production-grade shell automation. Covers strict mode, defensive programming, argument parsing, error handling, safe file operations, logging, testing with Bats, ShellCheck linting, portability, and CI/CD integration.
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Bash Scripting Patterns
|
|
8
|
+
|
|
9
|
+
Expert guidance for writing robust, portable, production-grade bash scripts. Covers defensive programming, error handling, safe file operations, testing, linting, and the most common pitfalls that cause scripts to fail silently in production.
|
|
10
|
+
|
|
11
|
+
## When to Use This Skill
|
|
12
|
+
|
|
13
|
+
- Writing automation scripts (deployment, backup, provisioning)
|
|
14
|
+
- Building CI/CD pipeline scripts
|
|
15
|
+
- Creating system administration utilities
|
|
16
|
+
- Developing installer or setup scripts
|
|
17
|
+
- Writing Docker entrypoint scripts
|
|
18
|
+
- Building CLI tools in pure bash
|
|
19
|
+
|
|
20
|
+
## Core Concepts
|
|
21
|
+
|
|
22
|
+
### 1. Strict Mode — Non-Negotiable
|
|
23
|
+
|
|
24
|
+
Every script starts with strict mode. No exceptions.
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
#!/usr/bin/env bash
|
|
28
|
+
set -Eeuo pipefail
|
|
29
|
+
|
|
30
|
+
# Flag breakdown:
|
|
31
|
+
# -E Inherit ERR trap in functions and subshells
|
|
32
|
+
# -e Exit immediately on non-zero return
|
|
33
|
+
# -u Exit on undefined variable reference
|
|
34
|
+
# -o pipefail Pipe fails if ANY command fails, not just the last
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**Additional hardening (Bash 4.4+):**
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
shopt -s inherit_errexit # Subshells inherit -e
|
|
41
|
+
IFS=$'\n\t' # Prevent word splitting on spaces
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 2. Script Boilerplate
|
|
45
|
+
|
|
46
|
+
Every production script follows this structure.
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
#!/usr/bin/env bash
|
|
50
|
+
set -Eeuo pipefail
|
|
51
|
+
|
|
52
|
+
# --- Constants ---
|
|
53
|
+
readonly SCRIPT_NAME="$(basename "${BASH_SOURCE[0]}")"
|
|
54
|
+
readonly SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
|
|
55
|
+
readonly VERSION="1.0.0"
|
|
56
|
+
|
|
57
|
+
# --- Defaults ---
|
|
58
|
+
VERBOSE=false
|
|
59
|
+
DRY_RUN=false
|
|
60
|
+
LOG_LEVEL="info"
|
|
61
|
+
|
|
62
|
+
# --- Cleanup ---
|
|
63
|
+
TMPDIR=""
|
|
64
|
+
cleanup() {
|
|
65
|
+
local exit_code=$?
|
|
66
|
+
if [[ -n "${TMPDIR:-}" && -d "$TMPDIR" ]]; then
|
|
67
|
+
rm -rf -- "$TMPDIR"
|
|
68
|
+
fi
|
|
69
|
+
exit "$exit_code"
|
|
70
|
+
}
|
|
71
|
+
trap cleanup EXIT
|
|
72
|
+
trap 'echo "Error on line $LINENO (exit $?)" >&2' ERR
|
|
73
|
+
|
|
74
|
+
# --- Logging ---
|
|
75
|
+
log() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*" >&2; }
|
|
76
|
+
info() { log "INFO: $*"; }
|
|
77
|
+
warn() { log "WARN: $*"; }
|
|
78
|
+
error() { log "ERROR: $*"; }
|
|
79
|
+
debug() { [[ "$VERBOSE" == true ]] && log "DEBUG: $*" || true; }
|
|
80
|
+
|
|
81
|
+
# --- Usage ---
|
|
82
|
+
usage() {
|
|
83
|
+
cat <<EOF
|
|
84
|
+
Usage: $SCRIPT_NAME [OPTIONS] <argument>
|
|
85
|
+
|
|
86
|
+
Description of what this script does.
|
|
87
|
+
|
|
88
|
+
Options:
|
|
89
|
+
-v, --verbose Enable verbose/debug output
|
|
90
|
+
-d, --dry-run Preview changes without executing
|
|
91
|
+
-h, --help Show this help message
|
|
92
|
+
--version Show version
|
|
93
|
+
|
|
94
|
+
Examples:
|
|
95
|
+
$SCRIPT_NAME -v /path/to/input
|
|
96
|
+
$SCRIPT_NAME --dry-run --verbose /path/to/input
|
|
97
|
+
EOF
|
|
98
|
+
exit "${1:-0}"
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
# --- Argument Parsing ---
|
|
102
|
+
parse_args() {
|
|
103
|
+
while [[ $# -gt 0 ]]; do
|
|
104
|
+
case "$1" in
|
|
105
|
+
-v|--verbose) VERBOSE=true; shift ;;
|
|
106
|
+
-d|--dry-run) DRY_RUN=true; shift ;;
|
|
107
|
+
-h|--help) usage 0 ;;
|
|
108
|
+
--version) echo "$SCRIPT_NAME $VERSION"; exit 0 ;;
|
|
109
|
+
--) shift; break ;;
|
|
110
|
+
-*) error "Unknown option: $1"; usage 1 ;;
|
|
111
|
+
*) break ;;
|
|
112
|
+
esac
|
|
113
|
+
done
|
|
114
|
+
|
|
115
|
+
# Validate required arguments
|
|
116
|
+
if [[ $# -lt 1 ]]; then
|
|
117
|
+
error "Missing required argument"
|
|
118
|
+
usage 1
|
|
119
|
+
fi
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
# --- Main ---
|
|
123
|
+
main() {
|
|
124
|
+
parse_args "$@"
|
|
125
|
+
info "Starting $SCRIPT_NAME v$VERSION"
|
|
126
|
+
|
|
127
|
+
TMPDIR=$(mktemp -d) || { error "Failed to create temp directory"; exit 1; }
|
|
128
|
+
debug "Temp directory: $TMPDIR"
|
|
129
|
+
|
|
130
|
+
# Implementation here
|
|
131
|
+
|
|
132
|
+
info "Completed successfully"
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
main "$@"
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### 3. Variable Safety
|
|
139
|
+
|
|
140
|
+
Quoting is the #1 source of bash bugs. Always quote.
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
# WRONG — word splitting and globbing
|
|
144
|
+
cp $source $dest
|
|
145
|
+
for f in $(ls *.txt); do echo "$f"; done
|
|
146
|
+
|
|
147
|
+
# RIGHT — always quote
|
|
148
|
+
cp "$source" "$dest"
|
|
149
|
+
for f in *.txt; do echo "$f"; done # Shell glob, no ls
|
|
150
|
+
|
|
151
|
+
# Required variables — fail with message if unset
|
|
152
|
+
: "${REQUIRED_VAR:?REQUIRED_VAR is not set}"
|
|
153
|
+
: "${API_KEY:?API_KEY must be set in environment}"
|
|
154
|
+
|
|
155
|
+
# Default values — use if unset
|
|
156
|
+
port="${PORT:-8080}"
|
|
157
|
+
host="${HOST:-localhost}"
|
|
158
|
+
|
|
159
|
+
# Readonly constants
|
|
160
|
+
readonly MAX_RETRIES=3
|
|
161
|
+
readonly CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/myapp"
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
**Never use `eval` on user input:**
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
# WRONG — command injection
|
|
168
|
+
eval "$user_input"
|
|
169
|
+
|
|
170
|
+
# RIGHT — use arrays for dynamic command construction
|
|
171
|
+
declare -a cmd=("curl" "-s" "-o" "$output_file")
|
|
172
|
+
[[ "$VERBOSE" == true ]] && cmd+=("-v")
|
|
173
|
+
"${cmd[@]}" "$url"
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### 4. Array Handling
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
# Declare and iterate safely
|
|
180
|
+
declare -a items=("item 1" "item 2" "item 3")
|
|
181
|
+
for item in "${items[@]}"; do
|
|
182
|
+
echo "Processing: $item"
|
|
183
|
+
done
|
|
184
|
+
|
|
185
|
+
# Read command output into array safely
|
|
186
|
+
mapfile -t lines < <(some_command)
|
|
187
|
+
readarray -t numbers < <(seq 1 10)
|
|
188
|
+
|
|
189
|
+
# NUL-safe file iteration (handles spaces, newlines in filenames)
|
|
190
|
+
while IFS= read -r -d '' file; do
|
|
191
|
+
echo "File: $file"
|
|
192
|
+
done < <(find . -type f -name "*.sh" -print0)
|
|
193
|
+
|
|
194
|
+
# Associative arrays (Bash 4+)
|
|
195
|
+
declare -A config=(
|
|
196
|
+
[host]="localhost"
|
|
197
|
+
[port]="8080"
|
|
198
|
+
[debug]="false"
|
|
199
|
+
)
|
|
200
|
+
echo "${config[host]}:${config[port]}"
|
|
201
|
+
|
|
202
|
+
# Array length and slicing
|
|
203
|
+
echo "Count: ${#items[@]}"
|
|
204
|
+
echo "First: ${items[0]}"
|
|
205
|
+
echo "Last: ${items[-1]}"
|
|
206
|
+
subset=("${items[@]:1:2}") # Slice from index 1, length 2
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### 5. Safe File Operations
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
# Temporary files — always with cleanup trap
|
|
213
|
+
TMPDIR=$(mktemp -d) || exit 1
|
|
214
|
+
trap 'rm -rf -- "$TMPDIR"' EXIT
|
|
215
|
+
|
|
216
|
+
tmp_file="$TMPDIR/work.txt"
|
|
217
|
+
some_command > "$tmp_file"
|
|
218
|
+
|
|
219
|
+
# Safe directory detection
|
|
220
|
+
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)"
|
|
221
|
+
|
|
222
|
+
# Check before operating
|
|
223
|
+
[[ -f "$file" ]] || { error "File not found: $file"; exit 1; }
|
|
224
|
+
[[ -r "$file" ]] || { error "File not readable: $file"; exit 1; }
|
|
225
|
+
[[ -d "$dir" ]] || { error "Directory not found: $dir"; exit 1; }
|
|
226
|
+
[[ -w "$dir" ]] || { error "Directory not writable: $dir"; exit 1; }
|
|
227
|
+
|
|
228
|
+
# Create directories safely
|
|
229
|
+
mkdir -p "$output_dir" || { error "Cannot create $output_dir"; exit 1; }
|
|
230
|
+
|
|
231
|
+
# Restrictive umask for sensitive files
|
|
232
|
+
(umask 077; touch "$secure_file")
|
|
233
|
+
|
|
234
|
+
# End option parsing with -- for safety
|
|
235
|
+
rm -rf -- "$user_provided_path"
|
|
236
|
+
cp -- "$source" "$dest"
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### 6. Error Handling and Traps
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
# Comprehensive trap setup
|
|
243
|
+
cleanup() {
|
|
244
|
+
local exit_code=$?
|
|
245
|
+
# Kill background processes
|
|
246
|
+
jobs -p | xargs -r kill 2>/dev/null || true
|
|
247
|
+
# Remove temp files
|
|
248
|
+
[[ -n "${TMPDIR:-}" ]] && rm -rf -- "$TMPDIR"
|
|
249
|
+
exit "$exit_code"
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
trap cleanup EXIT
|
|
253
|
+
trap 'echo "Error at line $LINENO: exit $?" >&2' ERR
|
|
254
|
+
trap 'echo "Interrupted" >&2; exit 130' INT
|
|
255
|
+
trap 'echo "Terminated" >&2; exit 143' TERM
|
|
256
|
+
|
|
257
|
+
# Retry logic
|
|
258
|
+
retry() {
|
|
259
|
+
local -r max_attempts="${1:?}"
|
|
260
|
+
local -r delay="${2:?}"
|
|
261
|
+
shift 2
|
|
262
|
+
local attempt=1
|
|
263
|
+
|
|
264
|
+
until "$@"; do
|
|
265
|
+
if (( attempt >= max_attempts )); then
|
|
266
|
+
error "Failed after $max_attempts attempts: $*"
|
|
267
|
+
return 1
|
|
268
|
+
fi
|
|
269
|
+
warn "Attempt $attempt failed, retrying in ${delay}s..."
|
|
270
|
+
sleep "$delay"
|
|
271
|
+
(( attempt++ ))
|
|
272
|
+
done
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
# Usage: retry 3 5 curl -sf "$url" -o "$output"
|
|
276
|
+
|
|
277
|
+
# Timeout for external commands
|
|
278
|
+
timeout 30s curl -sf "$url" -o "$output" || {
|
|
279
|
+
error "Download timed out after 30s"
|
|
280
|
+
exit 1
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### 7. Input Validation
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
# Validate numeric input
|
|
288
|
+
validate_integer() {
|
|
289
|
+
local -r value="$1"
|
|
290
|
+
local -r name="${2:-value}"
|
|
291
|
+
if [[ ! "$value" =~ ^[0-9]+$ ]]; then
|
|
292
|
+
error "$name must be a positive integer, got: $value"
|
|
293
|
+
return 1
|
|
294
|
+
fi
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
# Validate file arguments
|
|
298
|
+
validate_input_file() {
|
|
299
|
+
local -r file="$1"
|
|
300
|
+
[[ -f "$file" ]] || { error "Not a file: $file"; return 1; }
|
|
301
|
+
[[ -r "$file" ]] || { error "Not readable: $file"; return 1; }
|
|
302
|
+
[[ -s "$file" ]] || { warn "File is empty: $file"; }
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
# Validate required environment variables
|
|
306
|
+
require_env() {
|
|
307
|
+
local -r var_name="$1"
|
|
308
|
+
if [[ -z "${!var_name:-}" ]]; then
|
|
309
|
+
error "Required environment variable $var_name is not set"
|
|
310
|
+
exit 1
|
|
311
|
+
fi
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
# Check required commands exist
|
|
315
|
+
require_command() {
|
|
316
|
+
for cmd in "$@"; do
|
|
317
|
+
command -v "$cmd" &>/dev/null || {
|
|
318
|
+
error "Required command not found: $cmd"
|
|
319
|
+
error "Install it and try again"
|
|
320
|
+
exit 1
|
|
321
|
+
}
|
|
322
|
+
done
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
# Usage at script start
|
|
326
|
+
require_command curl jq grep sed
|
|
327
|
+
require_env API_KEY
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### 8. Structured Logging
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
# Logging with levels and colors (when TTY)
|
|
334
|
+
declare -A LOG_COLORS=(
|
|
335
|
+
[DEBUG]="\033[0;36m" # Cyan
|
|
336
|
+
[INFO]="\033[0;32m" # Green
|
|
337
|
+
[WARN]="\033[0;33m" # Yellow
|
|
338
|
+
[ERROR]="\033[0;31m" # Red
|
|
339
|
+
)
|
|
340
|
+
readonly RESET="\033[0m"
|
|
341
|
+
|
|
342
|
+
_log() {
|
|
343
|
+
local -r level="$1"; shift
|
|
344
|
+
local -r timestamp="$(date +'%Y-%m-%d %H:%M:%S')"
|
|
345
|
+
|
|
346
|
+
if [[ -t 2 ]]; then
|
|
347
|
+
# TTY — use colors
|
|
348
|
+
printf "${LOG_COLORS[$level]:-}[%s] %-5s %s${RESET}\n" \
|
|
349
|
+
"$timestamp" "$level" "$*" >&2
|
|
350
|
+
else
|
|
351
|
+
# Piped/redirected — plain text
|
|
352
|
+
printf "[%s] %-5s %s\n" "$timestamp" "$level" "$*" >&2
|
|
353
|
+
fi
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
debug() { [[ "$VERBOSE" == true ]] && _log DEBUG "$*" || true; }
|
|
357
|
+
info() { _log INFO "$*"; }
|
|
358
|
+
warn() { _log WARN "$*"; }
|
|
359
|
+
error() { _log ERROR "$*"; }
|
|
360
|
+
|
|
361
|
+
# Log to file
|
|
362
|
+
exec 3>&1 4>&2 # Save stdout/stderr
|
|
363
|
+
exec 1> >(tee -a "$LOG_FILE") 2>&1 # Tee to log file
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### 9. Dry-Run Support
|
|
367
|
+
|
|
368
|
+
```bash
|
|
369
|
+
# Wrap destructive operations
|
|
370
|
+
run() {
|
|
371
|
+
if [[ "$DRY_RUN" == true ]]; then
|
|
372
|
+
info "[DRY RUN] $*"
|
|
373
|
+
else
|
|
374
|
+
debug "Running: $*"
|
|
375
|
+
"$@"
|
|
376
|
+
fi
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
# Usage
|
|
380
|
+
run rm -rf -- "$old_backup"
|
|
381
|
+
run cp -a "$source" "$dest"
|
|
382
|
+
run systemctl restart myservice
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### 10. Portability
|
|
386
|
+
|
|
387
|
+
```bash
|
|
388
|
+
# Detect platform
|
|
389
|
+
case "$(uname -s)" in
|
|
390
|
+
Linux*) PLATFORM="linux" ;;
|
|
391
|
+
Darwin*) PLATFORM="macos" ;;
|
|
392
|
+
MINGW*) PLATFORM="windows" ;;
|
|
393
|
+
*) PLATFORM="unknown" ;;
|
|
394
|
+
esac
|
|
395
|
+
|
|
396
|
+
# Handle GNU vs BSD tool differences
|
|
397
|
+
if [[ "$PLATFORM" == "macos" ]]; then
|
|
398
|
+
# BSD sed requires explicit extension for -i
|
|
399
|
+
sed_inplace() { sed -i '' "$@"; }
|
|
400
|
+
# BSD stat syntax differs
|
|
401
|
+
file_size() { stat -f%z "$1"; }
|
|
402
|
+
# BSD date differs
|
|
403
|
+
epoch() { date -j -f "%Y-%m-%d" "$1" "+%s"; }
|
|
404
|
+
else
|
|
405
|
+
sed_inplace() { sed -i "$@"; }
|
|
406
|
+
file_size() { stat -c%s "$1"; }
|
|
407
|
+
epoch() { date -d "$1" "+%s"; }
|
|
408
|
+
fi
|
|
409
|
+
|
|
410
|
+
# Check bash version for modern features
|
|
411
|
+
check_bash_version() {
|
|
412
|
+
local -r min_major="${1:-4}"
|
|
413
|
+
local -r min_minor="${2:-4}"
|
|
414
|
+
if (( BASH_VERSINFO[0] < min_major ||
|
|
415
|
+
(BASH_VERSINFO[0] == min_major && BASH_VERSINFO[1] < min_minor) )); then
|
|
416
|
+
error "Bash ${min_major}.${min_minor}+ required (found ${BASH_VERSION})"
|
|
417
|
+
exit 1
|
|
418
|
+
fi
|
|
419
|
+
}
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
## Testing with Bats
|
|
423
|
+
|
|
424
|
+
[Bats](https://github.com/bats-core/bats-core) is the standard testing framework for bash scripts.
|
|
425
|
+
|
|
426
|
+
### Test File Structure
|
|
427
|
+
|
|
428
|
+
```bash
|
|
429
|
+
#!/usr/bin/env bats
|
|
430
|
+
# tests/test_myscript.bats
|
|
431
|
+
|
|
432
|
+
setup() {
|
|
433
|
+
# Runs before each test
|
|
434
|
+
TMPDIR="$(mktemp -d)"
|
|
435
|
+
export TMPDIR
|
|
436
|
+
# Source the script's functions (if structured for sourcing)
|
|
437
|
+
source "${BATS_TEST_DIRNAME}/../lib/functions.sh"
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
teardown() {
|
|
441
|
+
# Runs after each test
|
|
442
|
+
rm -rf -- "$TMPDIR"
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
@test "exits with error when no arguments provided" {
|
|
446
|
+
run ./myscript.sh
|
|
447
|
+
[ "$status" -eq 1 ]
|
|
448
|
+
[[ "$output" == *"Missing required argument"* ]]
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
@test "creates output file in specified directory" {
|
|
452
|
+
run ./myscript.sh -o "$TMPDIR/output.txt" input.txt
|
|
453
|
+
[ "$status" -eq 0 ]
|
|
454
|
+
[ -f "$TMPDIR/output.txt" ]
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
@test "dry-run does not modify files" {
|
|
458
|
+
local target="$TMPDIR/existing.txt"
|
|
459
|
+
echo "original" > "$target"
|
|
460
|
+
run ./myscript.sh --dry-run "$target"
|
|
461
|
+
[ "$status" -eq 0 ]
|
|
462
|
+
[ "$(cat "$target")" = "original" ]
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
@test "validates numeric argument" {
|
|
466
|
+
run ./myscript.sh --retries abc
|
|
467
|
+
[ "$status" -eq 1 ]
|
|
468
|
+
[[ "$output" == *"must be a positive integer"* ]]
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
@test "--help shows usage" {
|
|
472
|
+
run ./myscript.sh --help
|
|
473
|
+
[ "$status" -eq 0 ]
|
|
474
|
+
[[ "$output" == *"Usage:"* ]]
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
@test "--version shows version" {
|
|
478
|
+
run ./myscript.sh --version
|
|
479
|
+
[ "$status" -eq 0 ]
|
|
480
|
+
[[ "$output" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]
|
|
481
|
+
}
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
### Running Tests
|
|
485
|
+
|
|
486
|
+
```bash
|
|
487
|
+
# Install Bats
|
|
488
|
+
git clone https://github.com/bats-core/bats-core.git
|
|
489
|
+
./bats-core/install.sh /usr/local
|
|
490
|
+
|
|
491
|
+
# Run tests
|
|
492
|
+
bats tests/
|
|
493
|
+
bats tests/test_myscript.bats --tap # TAP output for CI
|
|
494
|
+
bats tests/ --jobs 4 # Parallel execution
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
## ShellCheck — Mandatory
|
|
498
|
+
|
|
499
|
+
Every script must pass [ShellCheck](https://www.shellcheck.net/) with zero warnings.
|
|
500
|
+
|
|
501
|
+
```bash
|
|
502
|
+
# Lint all scripts
|
|
503
|
+
shellcheck -x *.sh lib/*.sh
|
|
504
|
+
|
|
505
|
+
# With severity filter
|
|
506
|
+
shellcheck --severity=warning *.sh
|
|
507
|
+
|
|
508
|
+
# Inline directives (use sparingly, with justification)
|
|
509
|
+
# shellcheck disable=SC2086 # Word splitting intended here
|
|
510
|
+
command $unquoted_var_intentionally
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
### Common ShellCheck Rules
|
|
514
|
+
|
|
515
|
+
| Code | Issue | Fix |
|
|
516
|
+
|------|-------|-----|
|
|
517
|
+
| SC2086 | Double quote to prevent globbing/splitting | Quote: `"$var"` |
|
|
518
|
+
| SC2046 | Quote to prevent word splitting | `"$(command)"` |
|
|
519
|
+
| SC2034 | Variable appears unused | Prefix with `_` or export |
|
|
520
|
+
| SC2155 | Declare and assign separately | `local var; var=$(cmd)` |
|
|
521
|
+
| SC2164 | Use `cd ... \|\| exit` | `cd "$dir" \|\| exit 1` |
|
|
522
|
+
| SC2128 | Expanding array without index | Use `"${arr[@]}"` |
|
|
523
|
+
| SC2206 | Quote to prevent splitting | `read -ra arr <<< "$line"` |
|
|
524
|
+
|
|
525
|
+
### Formatting with shfmt
|
|
526
|
+
|
|
527
|
+
```bash
|
|
528
|
+
# Install: go install mvdan.cc/sh/v3/cmd/shfmt@latest
|
|
529
|
+
|
|
530
|
+
# Format all scripts (Google style: 2-space indent, switch-case indent)
|
|
531
|
+
shfmt -w -i 2 -ci *.sh
|
|
532
|
+
|
|
533
|
+
# Check formatting (CI mode)
|
|
534
|
+
shfmt -d -i 2 -ci *.sh || { echo "Formatting issues found"; exit 1; }
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
## Common Pitfalls
|
|
538
|
+
|
|
539
|
+
### Word Splitting with `for` Loops
|
|
540
|
+
|
|
541
|
+
```bash
|
|
542
|
+
# WRONG — breaks on spaces in filenames
|
|
543
|
+
for f in $(ls *.txt); do
|
|
544
|
+
echo "$f"
|
|
545
|
+
done
|
|
546
|
+
|
|
547
|
+
# RIGHT — use globbing directly
|
|
548
|
+
for f in *.txt; do
|
|
549
|
+
[[ -f "$f" ]] || continue # Handle no matches
|
|
550
|
+
echo "$f"
|
|
551
|
+
done
|
|
552
|
+
|
|
553
|
+
# RIGHT — use find for recursive/complex matches
|
|
554
|
+
while IFS= read -r -d '' f; do
|
|
555
|
+
echo "$f"
|
|
556
|
+
done < <(find . -name "*.txt" -print0)
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
### Declare and Assign Separately
|
|
560
|
+
|
|
561
|
+
```bash
|
|
562
|
+
# WRONG — masks the exit code of $(command)
|
|
563
|
+
local result=$(some_command)
|
|
564
|
+
|
|
565
|
+
# RIGHT — declare first, then assign
|
|
566
|
+
local result
|
|
567
|
+
result=$(some_command) || { error "Command failed"; return 1; }
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
### Process Substitution vs Pipes
|
|
571
|
+
|
|
572
|
+
```bash
|
|
573
|
+
# WRONG — while loop runs in subshell, variable changes are lost
|
|
574
|
+
cat file.txt | while read -r line; do
|
|
575
|
+
count=$((count + 1)) # Lost after loop!
|
|
576
|
+
done
|
|
577
|
+
|
|
578
|
+
# RIGHT — use process substitution or redirection
|
|
579
|
+
count=0
|
|
580
|
+
while IFS= read -r line; do
|
|
581
|
+
count=$((count + 1))
|
|
582
|
+
done < file.txt
|
|
583
|
+
echo "Lines: $count"
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
### Printf Over Echo
|
|
587
|
+
|
|
588
|
+
```bash
|
|
589
|
+
# WRONG — echo behavior varies across systems
|
|
590
|
+
echo -e "Hello\tWorld" # May or may not interpret escapes
|
|
591
|
+
echo -n "No newline" # Non-portable
|
|
592
|
+
|
|
593
|
+
# RIGHT — printf is consistent everywhere
|
|
594
|
+
printf "Hello\tWorld\n"
|
|
595
|
+
printf "%s" "No newline"
|
|
596
|
+
printf "Name: %s, Age: %d\n" "$name" "$age"
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
## Anti-Patterns
|
|
600
|
+
|
|
601
|
+
| Anti-Pattern | Why It Is Bad | Do This Instead |
|
|
602
|
+
|-------------|--------------|-----------------|
|
|
603
|
+
| `cd dir && ...` without error handling | Silent failure if cd fails | `cd "$dir" \|\| exit 1` |
|
|
604
|
+
| `cat file \| grep pattern` | Useless use of cat | `grep pattern file` |
|
|
605
|
+
| `echo "$password"` in logs | Leaks secrets | Redact or use masked output |
|
|
606
|
+
| `kill -9 $pid` as first resort | Prevents cleanup handlers | `kill -TERM` first, `-9` as fallback |
|
|
607
|
+
| `[ $var = "value" ]` unquoted | Fails on empty or spaced vars | `[[ "$var" == "value" ]]` |
|
|
608
|
+
| `export VAR=$(cmd)` | Masks exit code | `VAR=$(cmd); export VAR` |
|
|
609
|
+
| `ls \| wc -l` for file counting | Breaks on filenames with newlines | `find . -maxdepth 1 -type f \| wc -l` |
|
|
610
|
+
| Inline `if` without `else` | Silent pass on failure | Always handle the else case |
|
|
611
|
+
| `source ./config` unchecked | Fails if file doesn't exist | `[[ -f ./config ]] && source ./config` |
|
|
612
|
+
| `rm -rf $DIR/` unquoted | Deletes `/` if DIR is empty | `rm -rf -- "${DIR:?}/"` |
|
|
613
|
+
|
|
614
|
+
## Modern Bash Features (4.4+)
|
|
615
|
+
|
|
616
|
+
```bash
|
|
617
|
+
# Parameter transformations (Bash 4.4+)
|
|
618
|
+
name="hello world"
|
|
619
|
+
echo "${name@U}" # HELLO WORLD (uppercase, Bash 5.0+)
|
|
620
|
+
echo "${name@L}" # hello world (lowercase, Bash 5.0+)
|
|
621
|
+
echo "${name@Q}" # 'hello world' (shell-quoted)
|
|
622
|
+
|
|
623
|
+
# Nameref variables (Bash 4.3+)
|
|
624
|
+
populate_array() {
|
|
625
|
+
local -n arr_ref="$1"
|
|
626
|
+
arr_ref=("one" "two" "three")
|
|
627
|
+
}
|
|
628
|
+
declare -a my_array
|
|
629
|
+
populate_array my_array
|
|
630
|
+
echo "${my_array[@]}" # one two three
|
|
631
|
+
|
|
632
|
+
# EPOCHSECONDS / EPOCHREALTIME (Bash 5.0+)
|
|
633
|
+
echo "Unix time: $EPOCHSECONDS"
|
|
634
|
+
echo "Microseconds: $EPOCHREALTIME"
|
|
635
|
+
|
|
636
|
+
# wait -n: wait for ANY background job (Bash 4.3+)
|
|
637
|
+
for i in {1..5}; do
|
|
638
|
+
sleep $((RANDOM % 5)) &
|
|
639
|
+
done
|
|
640
|
+
wait -n # Returns when first job finishes
|
|
641
|
+
|
|
642
|
+
# mapfile with custom delimiter (Bash 4.4+)
|
|
643
|
+
mapfile -d ',' -t fields <<< "$csv_line"
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
## Parameter Expansion Reference
|
|
647
|
+
|
|
648
|
+
```bash
|
|
649
|
+
# Default values
|
|
650
|
+
${var:-default} # Use default if unset or empty
|
|
651
|
+
${var:=default} # Set and use default if unset or empty
|
|
652
|
+
${var:+alternate} # Use alternate if set and non-empty
|
|
653
|
+
${var:?error msg} # Exit with error if unset or empty
|
|
654
|
+
|
|
655
|
+
# String manipulation
|
|
656
|
+
${var#pattern} # Remove shortest prefix match
|
|
657
|
+
${var##pattern} # Remove longest prefix match
|
|
658
|
+
${var%pattern} # Remove shortest suffix match
|
|
659
|
+
${var%%pattern} # Remove longest suffix match
|
|
660
|
+
${var/old/new} # Replace first occurrence
|
|
661
|
+
${var//old/new} # Replace all occurrences
|
|
662
|
+
|
|
663
|
+
# Substring
|
|
664
|
+
${var:offset} # Substring from offset
|
|
665
|
+
${var:offset:length} # Substring with length
|
|
666
|
+
${#var} # String length
|
|
667
|
+
|
|
668
|
+
# Common patterns
|
|
669
|
+
filename="${path##*/}" # basename
|
|
670
|
+
extension="${filename##*.}" # file extension
|
|
671
|
+
stem="${filename%.*}" # filename without extension
|
|
672
|
+
directory="${path%/*}" # dirname
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
## CI/CD Integration
|
|
676
|
+
|
|
677
|
+
```bash
|
|
678
|
+
# GitHub Actions workflow
|
|
679
|
+
# .github/workflows/shellcheck.yml
|
|
680
|
+
name: Shell Lint
|
|
681
|
+
on: [push, pull_request]
|
|
682
|
+
jobs:
|
|
683
|
+
lint:
|
|
684
|
+
runs-on: ubuntu-latest
|
|
685
|
+
steps:
|
|
686
|
+
- uses: actions/checkout@v4
|
|
687
|
+
- name: ShellCheck
|
|
688
|
+
uses: ludeeus/action-shellcheck@master
|
|
689
|
+
with:
|
|
690
|
+
severity: warning
|
|
691
|
+
- name: shfmt
|
|
692
|
+
run: |
|
|
693
|
+
go install mvdan.cc/sh/v3/cmd/shfmt@latest
|
|
694
|
+
shfmt -d -i 2 -ci .
|
|
695
|
+
- name: Bats
|
|
696
|
+
run: |
|
|
697
|
+
sudo apt-get install -y bats
|
|
698
|
+
bats tests/
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
## Project Structure
|
|
702
|
+
|
|
703
|
+
```
|
|
704
|
+
my-bash-project/
|
|
705
|
+
bin/
|
|
706
|
+
my-tool # Main executable (no .sh extension for installed tools)
|
|
707
|
+
lib/
|
|
708
|
+
common.sh # Shared functions (sourced, not executed)
|
|
709
|
+
logging.sh # Logging utilities
|
|
710
|
+
validation.sh # Input validation helpers
|
|
711
|
+
tests/
|
|
712
|
+
test_main.bats # Bats test files
|
|
713
|
+
test_validation.bats
|
|
714
|
+
fixtures/ # Test input data
|
|
715
|
+
.shellcheckrc # ShellCheck configuration
|
|
716
|
+
.editorconfig # Editor settings (indent, line endings)
|
|
717
|
+
Makefile # Build/test/install targets
|
|
718
|
+
README.md
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
### .shellcheckrc
|
|
722
|
+
|
|
723
|
+
```bash
|
|
724
|
+
# .shellcheckrc — project-wide ShellCheck settings
|
|
725
|
+
shell=bash
|
|
726
|
+
severity=style
|
|
727
|
+
enable=all
|
|
728
|
+
# Disable specific rules with justification:
|
|
729
|
+
# disable=SC2059 # If using printf format strings from variables intentionally
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
### Makefile
|
|
733
|
+
|
|
734
|
+
```makefile
|
|
735
|
+
.PHONY: lint test fmt check install
|
|
736
|
+
|
|
737
|
+
SCRIPTS := $(shell find bin/ lib/ -name '*.sh' -o -type f -executable)
|
|
738
|
+
|
|
739
|
+
lint:
|
|
740
|
+
shellcheck -x $(SCRIPTS)
|
|
741
|
+
|
|
742
|
+
fmt:
|
|
743
|
+
shfmt -w -i 2 -ci $(SCRIPTS)
|
|
744
|
+
|
|
745
|
+
test:
|
|
746
|
+
bats tests/
|
|
747
|
+
|
|
748
|
+
check: lint test
|
|
749
|
+
|
|
750
|
+
install:
|
|
751
|
+
install -Dm 755 bin/my-tool $(DESTDIR)/usr/local/bin/my-tool
|
|
752
|
+
```
|
|
753
|
+
|
|
754
|
+
## Exit Code Conventions
|
|
755
|
+
|
|
756
|
+
| Code | Meaning |
|
|
757
|
+
|------|---------|
|
|
758
|
+
| `0` | Success |
|
|
759
|
+
| `1` | General error |
|
|
760
|
+
| `2` | Invalid arguments / usage error |
|
|
761
|
+
| `126` | Command found but not executable |
|
|
762
|
+
| `127` | Command not found |
|
|
763
|
+
| `128+N` | Killed by signal N (e.g., 130 = SIGINT, 143 = SIGTERM) |
|
|
764
|
+
|
|
765
|
+
## Resources
|
|
766
|
+
|
|
767
|
+
- **ShellCheck**: https://www.shellcheck.net/
|
|
768
|
+
- **Bats**: https://github.com/bats-core/bats-core
|
|
769
|
+
- **Google Shell Style Guide**: https://google.github.io/styleguide/shellguide.html
|
|
770
|
+
- **shfmt**: https://github.com/mvdan/sh
|
|
771
|
+
- **Bash Reference Manual**: https://www.gnu.org/software/bash/manual/
|
|
772
|
+
- **Pure Bash Bible**: https://github.com/dylanaraps/pure-bash-bible
|
|
773
|
+
- **Bash Pitfalls**: https://mywiki.wooledge.org/BashPitfalls
|