@thierrynakoa/fire-flow 12.2.1 → 13.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CREDITS.md +25 -0
- package/DOMINION-FLOW-OVERVIEW.md +182 -38
- package/README.md +399 -455
- package/TROUBLESHOOTING.md +264 -264
- package/agents/fire-debugger.md +54 -0
- package/agents/fire-executor.md +1610 -1033
- package/agents/fire-fact-checker.md +1 -1
- package/agents/fire-planner.md +85 -17
- package/agents/fire-project-researcher.md +1 -1
- package/agents/fire-researcher.md +4 -22
- package/agents/{fire-phoenix-analyst.md → fire-resurrection-analyst.md} +394 -394
- package/agents/fire-reviewer.md +552 -499
- package/agents/fire-verifier.md +114 -19
- package/bin/cli.js +18 -101
- package/commands/fire-0-orient.md +2 -2
- package/commands/fire-1a-new.md +50 -15
- package/commands/fire-1c-setup.md +33 -5
- package/commands/fire-1d-discuss.md +87 -1
- package/commands/fire-2-plan.md +556 -527
- package/commands/fire-3-execute.md +2046 -1356
- package/commands/fire-4-verify.md +975 -906
- package/commands/fire-5-handoff.md +46 -5
- package/commands/fire-6-resume.md +2 -31
- package/commands/fire-add-new-skill.md +138 -19
- package/commands/fire-autonomous.md +14 -2
- package/commands/fire-complete-milestone.md +1 -1
- package/commands/fire-cost.md +179 -183
- package/commands/fire-debug.md +1 -6
- package/commands/fire-loop-resume.md +2 -2
- package/commands/fire-loop-stop.md +1 -1
- package/commands/fire-loop.md +2 -15
- package/commands/fire-map-codebase.md +1 -1
- package/commands/fire-migrate-database.md +548 -0
- package/commands/fire-new-milestone.md +1 -1
- package/commands/fire-reflect.md +1 -2
- package/commands/fire-research.md +142 -21
- package/commands/{fire-phoenix.md → fire-resurrect.md} +859 -603
- package/commands/fire-scaffold.md +297 -0
- package/commands/fire-search.md +1 -2
- package/commands/fire-security-scan.md +483 -484
- package/commands/fire-setup.md +359 -0
- package/commands/fire-skill.md +770 -0
- package/commands/fire-skills-diff.md +506 -506
- package/commands/fire-skills-history.md +388 -388
- package/commands/fire-skills-rollback.md +7 -7
- package/commands/fire-skills-sync.md +470 -470
- package/commands/fire-test.md +5 -5
- package/commands/fire-todos.md +1 -1
- package/commands/fire-update.md +5 -5
- package/commands/fire-validate-skills.md +282 -0
- package/commands/fire-vuln-scan.md +492 -493
- package/hooks/run-hook.sh +8 -8
- package/hooks/run-session-end.sh +7 -7
- package/hooks/session-end.sh +90 -90
- package/hooks/session-start.sh +1 -1
- package/package.json +4 -24
- package/plugin.json +7 -7
- package/references/autonomy-levels.md +235 -0
- package/references/behavioral-directives.md +95 -3
- package/references/blocker-tracking.md +1 -1
- package/references/circuit-breaker.md +93 -2
- package/references/context-engineering.md +227 -9
- package/references/honesty-protocols.md +70 -1
- package/references/issue-to-pr-pipeline.md +149 -150
- package/references/metrics-and-trends.md +1 -2
- package/references/research-improvements.md +4 -108
- package/references/sdlc-mapping.md +73 -0
- package/references/state-machine.md +151 -0
- package/skills-library/AVAILABLE_TOOLS_REFERENCE.md +333 -0
- package/skills-library/SKILLS-INDEX.md +57 -558
- package/skills-library/SKILLS_LIBRARY_INDEX.md +532 -0
- package/skills-library/_general/api-patterns/api-field-name-mismatch.md +107 -0
- package/skills-library/_general/api-patterns/streaming-command-timeout.md +122 -0
- package/skills-library/_general/api-patterns/streaming-proxy-cors-bypass.md +102 -0
- package/skills-library/_general/automation/settings-gui-generator.md +172 -0
- package/skills-library/_general/database-solutions/data-type-mapping-reference.md +181 -0
- package/skills-library/_general/database-solutions/mysql-limit-offset-string-coercion.md +102 -0
- package/skills-library/_general/database-solutions/mysql-to-pg-migration.md +195 -0
- package/skills-library/_general/database-solutions/orm-schema-portability.md +193 -0
- package/skills-library/_general/database-solutions/persistent-analysis-storage.md +207 -0
- package/skills-library/_general/database-solutions/pg-to-mysql-schema-migration-methodology.md +190 -0
- package/skills-library/_general/database-solutions/sql-dialect-compatibility-matrix.md +306 -0
- package/skills-library/_general/database-solutions/sqlite-to-pg-migration.md +219 -0
- package/skills-library/_general/frontend/canvas-bubble-animation-grouping.md +270 -0
- package/skills-library/_general/frontend/color-token-migration.md +112 -0
- package/skills-library/_general/frontend/framer-motion-layoutid-grouping.md +150 -0
- package/skills-library/_general/frontend/pyqt6-settings-dialog.md +191 -0
- package/skills-library/_general/frontend/react-flow-animated-layout-switching.md +101 -0
- package/skills-library/_general/frontend/react-hooks-order-debugging.md +141 -0
- package/skills-library/_general/frontend/redux-localstorage-auth-desync.md +126 -0
- package/skills-library/_general/frontend/safari-csp-theme-color-debugging.md +124 -0
- package/skills-library/_general/frontend/safari-sw-cache-poisoning.md +138 -0
- package/skills-library/_general/frontend/svg-sparkline-no-charting-library.md +131 -0
- package/skills-library/_general/growth-marketing/oss-daily-growth-intelligence.md +224 -0
- package/skills-library/_general/integrations/claude-code-local-mcp-integration.md +250 -0
- package/skills-library/_general/integrations/mcp-composite-tool-orchestration.md +200 -0
- package/skills-library/_general/methodology/AGENT_SDK_STANDALONE_TOOLING.md +181 -0
- package/skills-library/_general/methodology/AGENT_TEAMS_GUIDE.md +169 -0
- package/skills-library/_general/methodology/ALAS_STATEFUL_EXECUTION.md +207 -0
- package/skills-library/_general/methodology/AUTO_REVIEWER_SUBAGENT.md +211 -0
- package/skills-library/_general/methodology/CONSISTENCY_CHECK_AMBIGUITY_GATE.md +96 -0
- package/skills-library/_general/methodology/DEAD_ENDS_SHELF.md +4 -4
- package/skills-library/_general/methodology/DISTILL_NOT_DUMP.md +108 -0
- package/skills-library/_general/methodology/EXECUTION_PROGRESS_MONITOR.md +157 -0
- package/skills-library/_general/methodology/HIERARCHICAL_REVIEW_MARS.md +122 -0
- package/skills-library/_general/methodology/MCP_INTER_AGENT_BRIDGE.md +207 -0
- package/skills-library/_general/methodology/MERMAID_WIZARD_DIAGRAMS.md +77 -0
- package/skills-library/_general/methodology/MISSING_DIMENSION_DETECTOR.md +89 -0
- package/skills-library/_general/methodology/MULTI_AGENT_COORDINATION.md +397 -0
- package/skills-library/_general/methodology/OBSERVATION_MASKING.md +100 -0
- package/skills-library/_general/methodology/PHOENIX_REBUILD_METHODOLOGY.md +82 -11
- package/skills-library/_general/methodology/REVIEW_BACKTRACK_PANEL.md +140 -0
- package/skills-library/_general/methodology/REVIEW_FIX_LOOP.md +117 -0
- package/skills-library/_general/methodology/VOTING_VERDICT_ARBITRATION.md +155 -0
- package/skills-library/_general/methodology/ZERO_FRICTION_CLI_SETUP.md +2 -2
- package/skills-library/_general/methodology/dead-code-activation.md +123 -0
- package/skills-library/_general/methodology/debug-swarm-researcher-escape-hatch.md +240 -240
- package/skills-library/_general/methodology/shell-autonomous-loop-fixplan.md +1 -1
- package/skills-library/_general/patterns-standards/GOF_DESIGN_PATTERNS_FOR_AI_AGENTS.md +5 -5
- package/skills-library/_general/patterns-standards/cascading-failure-diagnosis.md +119 -0
- package/skills-library/_general/patterns-standards/domain-specific-layout-algorithms.md +209 -0
- package/skills-library/_general/patterns-standards/python-desktop-app-architecture.md +399 -0
- package/skills-library/_general/patterns-standards/realtime-monitoring-dashboard.md +457 -0
- package/skills-library/_general/patterns-standards/togglable-processing-pipeline.md +169 -0
- package/skills-library/_general/performance/liveclock-extraction.md +112 -0
- package/skills-library/_general/performance/ref-based-canvas-animation.md +117 -0
- package/skills-library/_general/performance/use-visible-interval.md +131 -0
- package/skills-library/_general/testing/playwright-firefox-withcredentials-auth-issue.md +104 -0
- package/skills-library/_quarantine/README.md +30 -0
- package/skills-library/api-patterns/BROADCAST_SCHEDULER_SHARED_EXECUTE_FUNCTION.md +150 -0
- package/skills-library/api-patterns/ERROR_RESPONSE_STANDARDS.md +145 -0
- package/skills-library/api-patterns/EXPRESS_ROUTE_ORDERING_MIDDLEWARE_INTERCEPTION.md +326 -0
- package/skills-library/api-patterns/PAGINATION_PATTERNS.md +137 -0
- package/skills-library/api-patterns/PODCAST_PROGRESS_TRACKING_THREE_ROOT_CAUSES.md +277 -0
- package/skills-library/api-patterns/RATE_LIMITING_TOGGLE.md +155 -0
- package/skills-library/api-patterns/graphql-content-queries.md +708 -0
- package/skills-library/appointment-scheduler-design.md +423 -0
- package/skills-library/automation/AUTO_POPULATE_COMPLETE_GUIDE.md +631 -0
- package/skills-library/automation/CC_WORKFLOW_STUDIO.md +83 -0
- package/skills-library/automation/CLAUDE_CODE_SWARM_MODE.md +95 -0
- package/skills-library/automation/DAEMON_TRIGGER_FILE_IPC.md +195 -0
- package/skills-library/automation/scheduled-content-publishing.md +608 -0
- package/skills-library/awesome-workflows/Blogging-Platform-Instructions/view_commands.md +25 -0
- package/skills-library/awesome-workflows/CREDENTIAL-SECURITY-WORKFLOW.md +109 -0
- package/skills-library/awesome-workflows/DEBUGGING-WORKFLOW.md +124 -0
- package/skills-library/awesome-workflows/Design-Review-Workflow/README.md +31 -0
- package/skills-library/awesome-workflows/Design-Review-Workflow/design-principles-example.md +129 -0
- package/skills-library/awesome-workflows/Design-Review-Workflow/design-review-agent.md +107 -0
- package/skills-library/awesome-workflows/Design-Review-Workflow/design-review-claude-md-snippet.md +24 -0
- package/skills-library/awesome-workflows/Design-Review-Workflow/design-review-slash-command.md +38 -0
- package/skills-library/awesome-workflows/PARALLEL-RESEARCH-WORKFLOW.md +89 -0
- package/skills-library/awesome-workflows/PHASE-EXECUTION-WORKFLOW.md +97 -0
- package/skills-library/awesome-workflows/SESSION-HANDOFF-WORKFLOW.md +116 -0
- package/skills-library/cms-patterns/content-branch-preview.md +515 -0
- package/skills-library/cms-patterns/inline-visual-editing.md +666 -0
- package/skills-library/cms-patterns/mdx-component-content.md +649 -0
- package/skills-library/cms-patterns/media-manager-abstraction.md +827 -0
- package/skills-library/cms-patterns/schema-driven-form-generator.md +838 -0
- package/skills-library/complexity-metrics/complexity-divider.md +707 -0
- package/skills-library/complexity-metrics/work-with-complexity.md +193 -0
- package/skills-library/creative-multimedia/animation-stack-guide.md +577 -0
- package/skills-library/creative-multimedia/audio-enhancement-pipeline.md +625 -0
- package/skills-library/creative-multimedia/content-repurposing-pipeline.md +1146 -0
- package/skills-library/creative-multimedia/data-visualization-generator.md +862 -0
- package/skills-library/creative-multimedia/doc-to-podcast-pipeline.md +2184 -0
- package/skills-library/creative-multimedia/ffmpeg-command-generator.md +405 -0
- package/skills-library/creative-multimedia/image-optimization-pipeline.md +605 -0
- package/skills-library/creative-multimedia/multi-format-content-generator.md +1759 -0
- package/skills-library/creative-multimedia/og-image-generator.md +635 -0
- package/skills-library/creative-multimedia/podcast-audio-composition.md +1355 -0
- package/skills-library/creative-multimedia/podcast-quality-evaluation.md +1452 -0
- package/skills-library/creative-multimedia/podcast-script-generation.md +1841 -0
- package/skills-library/creative-multimedia/svg-generation.md +750 -0
- package/skills-library/creative-multimedia/text-to-speech-provider-selector.md +1414 -0
- package/skills-library/creative-multimedia/transcription-pipeline-selector.md +677 -0
- package/skills-library/creative-multimedia/video-streaming-setup.md +559 -0
- package/skills-library/database-solutions/AI_RESPONSE_DATABASE_CACHING.md +520 -0
- package/skills-library/database-solutions/CONDITIONAL_SQL_MIGRATION_PATTERN.md +119 -0
- package/skills-library/database-solutions/DATABASE_COLUMN_NAME_MISMATCH.md +393 -0
- package/skills-library/database-solutions/DATABASE_SCHEMA.md +394 -0
- package/skills-library/database-solutions/DATABASE_SCHEMA_VERIFICATION_GUIDE.md +348 -0
- package/skills-library/database-solutions/DATABASE_STRATEGY.md +71 -0
- package/skills-library/database-solutions/ES_MODULE_SEED_SCRIPT_PATTERN.md +52 -0
- package/skills-library/database-solutions/MIGRATION_GUIDE.md +3 -0
- package/skills-library/database-solutions/PLPGSQL_VARIABLE_CONFLICT_FIX.md +208 -0
- package/skills-library/database-solutions/POSTGRESQL_JSONB_DOUBLE_STRINGIFY_FIX.md +245 -0
- package/skills-library/database-solutions/POSTGRESQL_LICENSE_TABLE_DESIGN.md +393 -0
- package/skills-library/database-solutions/POSTGRESQL_UUID_DOCUMENT_RAG_DUAL_SCOPE.md +732 -0
- package/skills-library/database-solutions/POSTGRES_SQL_TEMPLATE_BINDING_ERROR.md +240 -0
- package/skills-library/database-solutions/PRISMA_DB_PUSH_DATA_LOSS_PREVENTION.md +141 -0
- package/skills-library/database-solutions/PRODUCTION_QUERY_OPTIMIZATION_RESTART_FIX.md +389 -0
- package/skills-library/database-solutions/RLS_SECURITY_GUIDE.md +107 -0
- package/skills-library/database-solutions/SCHEMA_ENHANCEMENTS_GUIDE.md +373 -0
- package/skills-library/database-solutions/SCHEMA_MIGRATION_GUIDE.md +368 -0
- package/skills-library/database-solutions/SCHEMA_VERIFICATION_QUICK_REFERENCE.md +104 -0
- package/skills-library/database-solutions/ai-erd-generator.md +1213 -0
- package/skills-library/database-solutions/content-publishing-states.md +631 -0
- package/skills-library/database-solutions/database-schema-designer.md +522 -0
- package/skills-library/database-solutions/er-diagram-components.md +569 -0
- package/skills-library/database-solutions/er-to-ddl-mapping.md +1405 -0
- package/skills-library/database-solutions/erd-creator-textbook-research.md +433 -0
- package/skills-library/database-solutions/erd-react-flow-architecture.md +1965 -0
- package/skills-library/database-solutions/mariadb-aggregate-function-replacement.md +145 -0
- package/skills-library/database-solutions/normalization-validator.md +778 -0
- package/skills-library/database-solutions/postgres-full-text-search-content.md +494 -0
- package/skills-library/database-solutions/postgresql-to-mysql-runtime-translation.md +286 -0
- package/skills-library/database-solutions/regex-alternation-ordering-sql-types.md +92 -0
- package/skills-library/database-solutions/reserved-word-context-aware-quoting.md +142 -0
- package/skills-library/database-solutions/sql-ddl-generator.md +756 -0
- package/skills-library/database-solutions/supabase-connection-pooler-fix.md +102 -0
- package/skills-library/deployment-security/CPANEL_NODE_DEPLOYMENT.md +166 -0
- package/skills-library/deployment-security/DEPLOYMENT.md +275 -0
- package/skills-library/deployment-security/DEPLOYMENT_CHECKLIST.md +363 -0
- package/skills-library/deployment-security/DEPLOYMENT_PLAN.md +669 -0
- package/skills-library/deployment-security/KNEX_DATABASE_ABSTRACTION.md +444 -0
- package/skills-library/deployment-security/LICENSE_KEY_SYSTEM.md +206 -0
- package/skills-library/deployment-security/NODE18_DEPENDENCY_COMPATIBILITY.md +284 -0
- package/skills-library/deployment-security/PHP_INSTALLER_WIZARD_GUIDE.md +315 -0
- package/skills-library/deployment-security/PM2_ENVIRONMENT_VARIABLE_CACHING.md +256 -0
- package/skills-library/deployment-security/PM2_MEMORY_EXHAUSTION_FIX.md +370 -0
- package/skills-library/deployment-security/PRODUCTION_DEPLOYMENT_GUIDE.md +592 -0
- package/skills-library/deployment-security/PRODUCTION_HARDENING_DOCUMENTATION.md +307 -0
- package/skills-library/deployment-security/PRODUCTION_RECOVERY_CHERRY_PICK_PATTERN.md +202 -0
- package/skills-library/deployment-security/PYINSTALLER_CUDA_WHISPER_BUNDLING.md +236 -0
- package/skills-library/deployment-security/SECURITY.md +41 -0
- package/skills-library/deployment-security/SMTP_SSL_HOSTNAME_MISMATCH_SHARED_HOSTING.md +220 -0
- package/skills-library/deployment-security/SPA_SEO_OPTIMIZATION_CPANEL.md +200 -0
- package/skills-library/deployment-security/SUPABASE_EDGE_FUNCTIONS.md +338 -0
- package/skills-library/deployment-security/VERCEL_GITHUB_DEPLOYMENT_GUIDE.md +858 -0
- package/skills-library/deployment-security/VPS_DEPLOYMENT_READINESS.md +356 -0
- package/skills-library/deployment-security/deployment-changes-not-applying.md +241 -0
- package/skills-library/deployment-security/env-file-management-production-local.md +203 -0
- package/skills-library/deployment-security/express-secure-file-downloads.md +413 -0
- package/skills-library/deployment-security/react-production-deployment-desktop-guide.md +2011 -0
- package/skills-library/deployment-security/self-hosted-supabase-coolify-guide.md +1684 -0
- package/skills-library/deployment-security/unique-features-ai-strategy-plaid-security.md +1613 -0
- package/skills-library/deployment-security/vps-deployment.md +135 -0
- package/skills-library/document-processing/WORD_EXPORT_MARKDOWN_FORMATTING.md +482 -0
- package/skills-library/document-processing/document-ai-landingai-integration.md +677 -0
- package/skills-library/document-processing/express-secure-file-downloads-mern.md +413 -0
- package/skills-library/document-processing/express-secure-file-downloads.md +413 -0
- package/skills-library/document-processing/md-to-word-converter.md +318 -0
- package/skills-library/document-processing/pdf-forms-integration/README.md +101 -0
- package/skills-library/document-processing/pdf-forms-integration/SKILL.md +662 -0
- package/skills-library/ecommerce/ADMIN_PRODUCTS_GUIDE.md +428 -0
- package/skills-library/ecommerce/ECOMMERCE_API_REFERENCE.md +776 -0
- package/skills-library/ecommerce/ECOMMERCE_COMPLETION_SUMMARY.md +673 -0
- package/skills-library/ecommerce/ECOMMERCE_IMPLEMENTATION_GUIDE.md +729 -0
- package/skills-library/ecommerce/ECOMMERCE_QUICK_REFERENCE.md +521 -0
- package/skills-library/ecommerce/ECOMMERCE_TESTING_CHECKLIST.md +565 -0
- package/skills-library/ecommerce/ECOMMERCE_WORKFLOW_GUIDE.md +1059 -0
- package/skills-library/ecommerce/PRODUCT_CREATION_EXPANDED.md +522 -0
- package/skills-library/ecommerce/agentic-commerce-protocol.md +203 -0
- package/skills-library/ecommerce/cart-abandonment-recovery.md +236 -0
- package/skills-library/ecommerce/cart-architecture-patterns.md +300 -0
- package/skills-library/ecommerce/cart-item-count-indicator.md +264 -0
- package/skills-library/ecommerce/checkout-ux-conversion.md +227 -0
- package/skills-library/ecommerce/composable-commerce-selection.md +166 -0
- package/skills-library/ecommerce/ecommerce-analytics-patterns.md +167 -0
- package/skills-library/ecommerce/fraud-detection-patterns.md +179 -0
- package/skills-library/ecommerce/inventory-stock-management.md +270 -0
- package/skills-library/ecommerce/order-saga-state-machine.md +336 -0
- package/skills-library/ecommerce/payment-provider-abstraction.md +245 -0
- package/skills-library/ecommerce/pci-compliance-checklist.md +192 -0
- package/skills-library/ecommerce/refund-chargeback-handling.md +177 -0
- package/skills-library/ecommerce/shipping-carrier-integration.md +218 -0
- package/skills-library/ecommerce/webhook-idempotency-patterns.md +253 -0
- package/skills-library/excalidraw-diagrams/.github/workflows/ci.yml +558 -0
- package/skills-library/excalidraw-diagrams/.github/workflows/prompt-gallery.yml +448 -0
- package/skills-library/excalidraw-diagrams/.github/workflows/release.yml +42 -0
- package/skills-library/excalidraw-diagrams/.github/workflows/test-reusable-ci.yml +25 -0
- package/skills-library/excalidraw-diagrams/CLAUDE.md +57 -0
- package/skills-library/excalidraw-diagrams/LICENSE +21 -0
- package/skills-library/excalidraw-diagrams/README.md +178 -0
- package/skills-library/excalidraw-diagrams/SKILL.md +715 -0
- package/skills-library/form-solutions/BUTTON_TYPE_FORM_SUBMISSION.md +336 -0
- package/skills-library/form-solutions/FILLABLE_PDF_IMPLEMENTATION.md +226 -0
- package/skills-library/form-solutions/SURVEYJS_QUESTIONNAIRE_SYSTEM.md +367 -0
- package/skills-library/form-solutions/tiptap-minimal-setup.md +690 -0
- package/skills-library/frontend/scholarly-classification-bubble-map.md +149 -0
- package/skills-library/infrastructure/ci-cd-pipeline-builder.md +517 -0
- package/skills-library/infrastructure/observability-designer.md +264 -0
- package/skills-library/infrastructure/performance-profiler.md +621 -0
- package/skills-library/installer-wizard-patterns.md +249 -0
- package/skills-library/integrations/CLAUDE_CODE_TOKEN_ANALYTICS.md +160 -0
- package/skills-library/integrations/CONFIGURABLE_AI_PROVIDER_SELECTION.md +728 -0
- package/skills-library/integrations/SOCKET_IO_BROADCAST_ALL_VS_ROOM.md +141 -0
- package/skills-library/integrations/VIRTUAL_MEETINGS_IMPLEMENTATION.md +374 -0
- package/skills-library/integrations/WORDPRESS_LEARNDASH_DATA_RECOVERY.md +53 -0
- package/skills-library/integrations/YOUTUBE_API_SETUP.md +141 -0
- package/skills-library/integrations/YOUTUBE_BOOKMARKING_EXPLANATION.md +252 -0
- package/skills-library/integrations/YOUTUBE_BOOKMARKING_SOLUTION.md +268 -0
- package/skills-library/integrations/YOUTUBE_OAUTH_SETUP_GUIDE.md +200 -0
- package/skills-library/integrations/YOUTUBE_VIDEO_FIX_COMPLETE.md +192 -0
- package/skills-library/integrations/ai-ml/GEMINI_AI_RAG_PIPELINE_COMPLETE_GUIDE.md +195 -0
- package/skills-library/integrations/ai-ml/GEMINI_IMAGE_GENERATION_SETUP.md +64 -0
- package/skills-library/integrations/cloudflare/cloudflare-turnstile-debugging.md +202 -0
- package/skills-library/integrations/cloudflare/cloudflare-turnstile-implementation.md +476 -0
- package/skills-library/integrations/cloudflare-turnstile-debugging.md +202 -0
- package/skills-library/integrations/cloudflare-turnstile-implementation.md +476 -0
- package/skills-library/integrations/ghost-creator-monetization-pattern.md +454 -0
- package/skills-library/integrations/headless-cms-architecture.md +484 -0
- package/skills-library/integrations/headless-cms-stack-selection.md +183 -0
- package/skills-library/integrations/payload-cms-patterns.md +674 -0
- package/skills-library/integrations/realtimestt-openwakeword-cuda-windows.md +229 -0
- package/skills-library/integrations/rss-podcast-integration.md +300 -0
- package/skills-library/integrations/wordpress/WORDPRESS_LEARNDASH_DATA_RECOVERY.md +53 -0
- package/skills-library/integrations/youtube/YOUTUBE_API_SETUP.md +141 -0
- package/skills-library/integrations/youtube/YOUTUBE_BOOKMARKING_EXPLANATION.md +252 -0
- package/skills-library/integrations/youtube/YOUTUBE_BOOKMARKING_SOLUTION.md +268 -0
- package/skills-library/integrations/youtube/YOUTUBE_OAUTH_SETUP_GUIDE.md +200 -0
- package/skills-library/integrations/youtube/YOUTUBE_VIDEO_FIX_COMPLETE.md +192 -0
- package/skills-library/marketing/campaign-analytics.md +97 -0
- package/skills-library/marketing/content-creator.md +105 -0
- package/skills-library/marketing/marketing-strategy-pmm.md +94 -0
- package/skills-library/marketing/social-media-analyzer.md +81 -0
- package/skills-library/methodology/ADVANCED_ORCHESTRATION_PATTERNS.md +401 -0
- package/skills-library/methodology/AGENT_SELF_IMPROVEMENT_LOOP.md +179 -0
- package/skills-library/methodology/BREATH_BASED_PARALLEL_EXECUTION.md +1 -1
- package/skills-library/methodology/CLEANSING_CYCLE.md +358 -0
- package/skills-library/methodology/CONFIDENCE_ANNOTATION_PATTERN.md +143 -0
- package/skills-library/methodology/CRITICAL_PATTERNS_DOCUMENTATION_COMPLETE.md +204 -0
- package/skills-library/methodology/DELIVERABLES_SUMMARY.md +341 -0
- package/skills-library/methodology/DIFFICULTY_AWARE_AGENT_ROUTING.md +252 -0
- package/skills-library/methodology/EVOLUTIONARY_SKILL_SYNTHESIS.md +219 -0
- package/skills-library/methodology/GLOMERULUS_DECISION_GATE.md +223 -0
- package/skills-library/methodology/HIBERNATION_SYSTEM.md +231 -0
- package/skills-library/methodology/INSTRUMENTATION_OVER_RESTRICTION.md +192 -0
- package/skills-library/methodology/MASTER_COMPLETION_SUMMARY.md +444 -0
- package/skills-library/methodology/MASTER_SESSION_COMPLETION.md +743 -0
- package/skills-library/methodology/MERN_QUICK_REFERENCE.md +358 -0
- package/skills-library/methodology/ORGAN_AGENT_MAPPING.md +177 -0
- package/skills-library/methodology/PARALLEL_WAVE_BASED_REFACTORING.md +440 -0
- package/skills-library/methodology/QUICK_REFERENCE.md +358 -0
- package/skills-library/methodology/SDFT_ONPOLICY_SELF_DISTILLATION.md +186 -0
- package/skills-library/methodology/SELF_QUESTIONING_TASK_GENERATION.md +270 -0
- package/skills-library/methodology/SESSION_COMPLETION_SUMMARY.md +304 -0
- package/skills-library/methodology/SESSION_SUMMARY.md +432 -0
- package/skills-library/methodology/WARRIOR_WORKFLOW_DEBUGGING_PROTOCOL.md +252 -0
- package/skills-library/methodology/tech-debt-tracker.md +570 -0
- package/skills-library/parallel-debug/SKILL.md +60 -0
- package/skills-library/patterns-standards/API_PATTERN_FIX_SUMMARY.md +236 -0
- package/skills-library/patterns-standards/BATCH_OPERATIONS_WITH_PROGRESS_MODAL.md +362 -0
- package/skills-library/patterns-standards/CRITICAL_CODING_PATTERNS.md +639 -0
- package/skills-library/patterns-standards/DARK_MODE_MODAL_VISIBILITY.md +258 -0
- package/skills-library/patterns-standards/ERROR_RESILIENCE_IMPLEMENTATION.md +375 -0
- package/skills-library/patterns-standards/ES_MODULE_IMPORT_HOISTING_DOTENV.md +298 -0
- package/skills-library/patterns-standards/NESTED_BACKDROP_FILTER_CSS_ARTIFACT_FIX.md +76 -0
- package/skills-library/patterns-standards/ORDERED_DETECTOR_PIPELINE_GRACEFUL_FALLBACK.md +333 -0
- package/skills-library/patterns-standards/PHASE_IMPORT_ERROR_DEBUGGING.md +271 -0
- package/skills-library/patterns-standards/PYNPUT_GLOBAL_HOTKEY_VK_MATCHING.md +252 -0
- package/skills-library/patterns-standards/REACT_USEEFFECT_CASCADE_RESET_FIX.md +132 -0
- package/skills-library/patterns-standards/SUBMENU_HOVER_DROPDOWN_PATTERN.md +225 -0
- package/skills-library/patterns-standards/TAILWIND_TEXT_VISIBILITY_OVERRIDE.md +322 -0
- package/skills-library/patterns-standards/THEME_AWARE_CSS_VARIABLES_PATTERN.md +209 -0
- package/skills-library/patterns-standards/THEME_USER_OBJECT_PROPERTY_NAMING.md +194 -0
- package/skills-library/patterns-standards/TOOLTIP_BLOCKING_CLICKS_FIX.md +267 -0
- package/skills-library/patterns-standards/claude-code-plugin-structure.md +235 -0
- package/skills-library/patterns-standards/react-i18next-setup.md +429 -0
- package/skills-library/patterns-standards/thesys-c1-generative-ui-integration.md +967 -0
- package/skills-library/plugin-development/CLAUDE_CODE_COMMAND_REGISTRATION_SILENT_FAILURE.md +315 -0
- package/skills-library/plugin-development/plugin-command-namespace-vs-global.md +390 -0
- package/skills-library/plugin-development/plugin-doc-auto-generation.md +172 -0
- package/skills-library/security/GITHUB_REPO_SECURITY_AUDIT.md +115 -0
- package/skills-library/security/admin-deletion-safety.md +396 -0
- package/skills-library/security/application-vuln-patterns.md +477 -0
- package/skills-library/security/env-secrets-manager.md +686 -0
- package/skills-library/security/secure-ai-application-templates.md +347 -0
- package/skills-library/security/sql-injection-prevention-postgresjs.md +151 -0
- package/skills-library/supabase-connection-pooler-fix.md +102 -0
- package/skills-library/system-context/POWERSHELL_BASH_INTEROP.md +82 -0
- package/skills-library/system-context/SERVICE_LIFECYCLE_MANAGEMENT.md +119 -0
- package/skills-library/system-context/SKILL.md +40 -0
- package/skills-library/system-context/WINDOWS_DEV_ENVIRONMENT.md +73 -0
- package/skills-library/testing/E2E_PLAYWRIGHT_PATTERNS.md +99 -0
- package/skills-library/testing/INTEGRATION_TEST_STRATEGY.md +82 -0
- package/skills-library/testing/RED_GREEN_BUGFIX_GATE.md +203 -0
- package/skills-library/testing/TEST_DATA_MANAGEMENT.md +69 -0
- package/skills-library/testing/VITEST_UNIT_TEST_PATTERNS.md +75 -0
- package/skills-library/testing/playwright-api-security-tests.md +202 -0
- package/skills-library/toolbox/SKILL.md +84 -0
- package/skills-library/toolbox/code-graph-and-web-scraping-mcps.md +237 -0
- package/skills-library/ui-ux-pro-max/ACCESSIBILITY_ESSENTIALS.md +115 -0
- package/skills-library/ui-ux-pro-max/DESIGN_SYSTEM_SCAFFOLDING.md +133 -0
- package/skills-library/ui-ux-pro-max/RESPONSIVE_LAYOUT_PATTERNS.md +119 -0
- package/skills-library/ui-ux-pro-max/SKILL.md +386 -0
- package/skills-library/ui-ux-pro-max/data/charts.csv +26 -0
- package/skills-library/ui-ux-pro-max/data/colors.csv +97 -0
- package/skills-library/ui-ux-pro-max/data/icons.csv +101 -0
- package/skills-library/ui-ux-pro-max/data/landing.csv +31 -0
- package/skills-library/ui-ux-pro-max/data/products.csv +97 -0
- package/skills-library/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/skills-library/ui-ux-pro-max/data/stacks/astro.csv +54 -0
- package/skills-library/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/skills-library/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/skills-library/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/skills-library/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/skills-library/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/skills-library/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/skills-library/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/skills-library/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/skills-library/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/skills-library/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/skills-library/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/skills-library/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/skills-library/ui-ux-pro-max/data/styles.csv +68 -0
- package/skills-library/ui-ux-pro-max/data/typography.csv +58 -0
- package/skills-library/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/skills-library/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/skills-library/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/skills-library/wordpress-style-theme-components.md +1526 -0
- package/templates/ASSUMPTIONS.md +1 -1
- package/templates/DECISION_LOG.md +0 -1
- package/templates/phase-prompt.md +1 -1
- package/templates/phoenix-comparison.md +6 -6
- package/templates/skill-api-integration.md +106 -0
- package/templates/skill-architecture-pattern.md +92 -0
- package/templates/skill-debug-pattern.md +98 -0
- package/templates/skill-devops-recipe.md +107 -0
- package/templates/skill-general.md +65 -0
- package/templates/skill-ui-component.md +113 -0
- package/tools/uat-runner.py +179 -0
- package/version.json +7 -3
- package/workflows/handoff-session.md +2 -2
- package/workflows/new-project.md +2 -2
- package/workflows/plan-phase.md +1 -1
- package/.claude-plugin/plugin.json +0 -64
- package/skills-library/_general/methodology/LIVE_BREADCRUMB_PROTOCOL.md +0 -242
- package/skills-library/_general/methodology/llm-judge-memory-crud.md +0 -241
- package/skills-library/methodology/REFLEXION_MEMORY_PATTERN.md +0 -183
- package/skills-library/methodology/RESEARCH_BACKED_WORKFLOW_UPGRADE.md +0 -263
- package/skills-library/methodology/SABBATH_REST_PATTERN.md +0 -267
- package/skills-library/methodology/STONE_AND_SCAFFOLD.md +0 -220
- package/skills-library/specialists/api-architecture/api-designer.md +0 -49
- package/skills-library/specialists/api-architecture/graphql-architect.md +0 -49
- package/skills-library/specialists/api-architecture/mcp-developer.md +0 -51
- package/skills-library/specialists/api-architecture/microservices-architect.md +0 -50
- package/skills-library/specialists/api-architecture/websocket-engineer.md +0 -48
- package/skills-library/specialists/backend/django-expert.md +0 -52
- package/skills-library/specialists/backend/fastapi-expert.md +0 -52
- package/skills-library/specialists/backend/laravel-specialist.md +0 -52
- package/skills-library/specialists/backend/nestjs-expert.md +0 -51
- package/skills-library/specialists/backend/rails-expert.md +0 -53
- package/skills-library/specialists/backend/spring-boot-engineer.md +0 -56
- package/skills-library/specialists/data-ml/fine-tuning-expert.md +0 -48
- package/skills-library/specialists/data-ml/ml-pipeline.md +0 -47
- package/skills-library/specialists/data-ml/pandas-pro.md +0 -47
- package/skills-library/specialists/data-ml/rag-architect.md +0 -51
- package/skills-library/specialists/data-ml/spark-engineer.md +0 -47
- package/skills-library/specialists/frontend/angular-architect.md +0 -52
- package/skills-library/specialists/frontend/flutter-expert.md +0 -51
- package/skills-library/specialists/frontend/nextjs-developer.md +0 -54
- package/skills-library/specialists/frontend/react-native-expert.md +0 -50
- package/skills-library/specialists/frontend/vue-expert.md +0 -51
- package/skills-library/specialists/infrastructure/chaos-engineer.md +0 -74
- package/skills-library/specialists/infrastructure/cloud-architect.md +0 -70
- package/skills-library/specialists/infrastructure/database-optimizer.md +0 -64
- package/skills-library/specialists/infrastructure/devops-engineer.md +0 -70
- package/skills-library/specialists/infrastructure/kubernetes-specialist.md +0 -52
- package/skills-library/specialists/infrastructure/monitoring-expert.md +0 -70
- package/skills-library/specialists/infrastructure/sre-engineer.md +0 -70
- package/skills-library/specialists/infrastructure/terraform-engineer.md +0 -51
- package/skills-library/specialists/languages/cpp-pro.md +0 -74
- package/skills-library/specialists/languages/csharp-developer.md +0 -69
- package/skills-library/specialists/languages/dotnet-core-expert.md +0 -54
- package/skills-library/specialists/languages/golang-pro.md +0 -51
- package/skills-library/specialists/languages/java-architect.md +0 -49
- package/skills-library/specialists/languages/javascript-pro.md +0 -68
- package/skills-library/specialists/languages/kotlin-specialist.md +0 -68
- package/skills-library/specialists/languages/php-pro.md +0 -49
- package/skills-library/specialists/languages/python-pro.md +0 -52
- package/skills-library/specialists/languages/react-expert.md +0 -51
- package/skills-library/specialists/languages/rust-engineer.md +0 -50
- package/skills-library/specialists/languages/sql-pro.md +0 -56
- package/skills-library/specialists/languages/swift-expert.md +0 -69
- package/skills-library/specialists/languages/typescript-pro.md +0 -51
- package/skills-library/specialists/platform/atlassian-mcp.md +0 -52
- package/skills-library/specialists/platform/embedded-systems.md +0 -53
- package/skills-library/specialists/platform/game-developer.md +0 -53
- package/skills-library/specialists/platform/salesforce-developer.md +0 -53
- package/skills-library/specialists/platform/shopify-expert.md +0 -49
- package/skills-library/specialists/platform/wordpress-pro.md +0 -49
- package/skills-library/specialists/quality/code-documenter.md +0 -51
- package/skills-library/specialists/quality/code-reviewer.md +0 -67
- package/skills-library/specialists/quality/debugging-wizard.md +0 -51
- package/skills-library/specialists/quality/fullstack-guardian.md +0 -51
- package/skills-library/specialists/quality/legacy-modernizer.md +0 -50
- package/skills-library/specialists/quality/playwright-expert.md +0 -65
- package/skills-library/specialists/quality/spec-miner.md +0 -56
- package/skills-library/specialists/quality/test-master.md +0 -65
- package/skills-library/specialists/security/secure-code-guardian.md +0 -55
- package/skills-library/specialists/security/security-reviewer.md +0 -53
- package/skills-library/specialists/workflow/architecture-designer.md +0 -53
- package/skills-library/specialists/workflow/cli-developer.md +0 -70
- package/skills-library/specialists/workflow/feature-forge.md +0 -65
- package/skills-library/specialists/workflow/prompt-engineer.md +0 -54
- package/skills-library/specialists/workflow/the-fool.md +0 -62
- /package/skills-library/{performance → _general/performance}/cache-augmented-generation.md +0 -0
- /package/skills-library/{debugging → parallel-debug}/FAILURE_TAXONOMY_CLASSIFICATION.md +0 -0
- /package/skills-library/{debugging → parallel-debug}/THREE_AGENT_HYPOTHESIS_DEBUGGING.md +0 -0
|
@@ -0,0 +1,608 @@
|
|
|
1
|
+
# Scheduled Content Publishing with node-cron
|
|
2
|
+
|
|
3
|
+
> Reliable scheduled publishing system using node-cron: timezone-aware, double-publish-safe, with manual trigger endpoint for testing.
|
|
4
|
+
|
|
5
|
+
**When to use:** Any CMS, blog, or content platform where authors can schedule posts for future publication. Works with the `content-publishing-states.md` state machine.
|
|
6
|
+
**Stack:** Node.js/Express or Bun, node-cron, PostgreSQL, TypeScript
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## node-cron Setup
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install node-cron
|
|
14
|
+
npm install @types/node-cron
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Cron Syntax Reference
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
┌────────────── second (optional, 0-59)
|
|
21
|
+
│ ┌──────────── minute (0-59)
|
|
22
|
+
│ │ ┌────────── hour (0-23)
|
|
23
|
+
│ │ │ ┌──────── day of month (1-31)
|
|
24
|
+
│ │ │ │ ┌────── month (1-12 or JAN-DEC)
|
|
25
|
+
│ │ │ │ │ ┌──── day of week (0-7 or SUN-SAT, 0 and 7 both = Sunday)
|
|
26
|
+
│ │ │ │ │ │
|
|
27
|
+
* * * * * *
|
|
28
|
+
|
|
29
|
+
Common patterns:
|
|
30
|
+
'* * * * *' — every minute
|
|
31
|
+
'*/5 * * * *' — every 5 minutes
|
|
32
|
+
'0 * * * *' — every hour (at minute 0)
|
|
33
|
+
'0 9 * * 1-5' — 9am weekdays
|
|
34
|
+
'0 0 * * *' — midnight daily
|
|
35
|
+
'0 0 1 * *' — midnight first of month
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Core Scheduler: Publish Scheduled Content
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
// schedulers/content-publisher.ts
|
|
44
|
+
import cron from 'node-cron';
|
|
45
|
+
import { Pool } from 'pg';
|
|
46
|
+
import { logStatusChange } from '../lib/audit-log';
|
|
47
|
+
|
|
48
|
+
interface SchedulerConfig {
|
|
49
|
+
db: Pool;
|
|
50
|
+
cronExpression?: string; // default: every minute
|
|
51
|
+
maxBatchSize?: number; // safety limit per run
|
|
52
|
+
onPublishSuccess?: (contentId: string, title: string) => void;
|
|
53
|
+
onPublishFailure?: (contentId: string, error: Error) => void;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function startContentPublisher(config: SchedulerConfig) {
|
|
57
|
+
const {
|
|
58
|
+
db,
|
|
59
|
+
cronExpression = '* * * * *', // every minute
|
|
60
|
+
maxBatchSize = 50,
|
|
61
|
+
onPublishSuccess,
|
|
62
|
+
onPublishFailure,
|
|
63
|
+
} = config;
|
|
64
|
+
|
|
65
|
+
// Validate the cron expression before registering
|
|
66
|
+
if (!cron.validate(cronExpression)) {
|
|
67
|
+
throw new Error(`Invalid cron expression: ${cronExpression}`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const task = cron.schedule(cronExpression, async () => {
|
|
71
|
+
await publishDueContent({ db, maxBatchSize, onPublishSuccess, onPublishFailure });
|
|
72
|
+
}, {
|
|
73
|
+
timezone: 'UTC', // ALWAYS run cron in UTC, convert for display only
|
|
74
|
+
scheduled: true,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
console.log(`[ContentPublisher] Started. Schedule: ${cronExpression} (UTC)`);
|
|
78
|
+
return task;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
interface PublishRunOptions {
|
|
82
|
+
db: Pool;
|
|
83
|
+
maxBatchSize: number;
|
|
84
|
+
systemUserId?: string; // ID of the "system" user for audit logs
|
|
85
|
+
onPublishSuccess?: (contentId: string, title: string) => void;
|
|
86
|
+
onPublishFailure?: (contentId: string, error: Error) => void;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export async function publishDueContent(options: PublishRunOptions): Promise<{
|
|
90
|
+
published: string[];
|
|
91
|
+
failed: string[];
|
|
92
|
+
}> {
|
|
93
|
+
const { db, maxBatchSize, onPublishSuccess, onPublishFailure } = options;
|
|
94
|
+
const published: string[] = [];
|
|
95
|
+
const failed: string[] = [];
|
|
96
|
+
|
|
97
|
+
const client = await db.connect();
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
await client.query('BEGIN');
|
|
101
|
+
|
|
102
|
+
// SELECT FOR UPDATE SKIP LOCKED:
|
|
103
|
+
// - Locks the rows so a second scheduler instance can't pick the same posts
|
|
104
|
+
// - SKIP LOCKED means a concurrent process won't wait — it just skips locked rows
|
|
105
|
+
// - This prevents double-publishing even if two server instances run simultaneously
|
|
106
|
+
const { rows: dueContent } = await client.query<{
|
|
107
|
+
id: string;
|
|
108
|
+
title: string;
|
|
109
|
+
scheduled_at: Date;
|
|
110
|
+
}>(`
|
|
111
|
+
SELECT id, title, scheduled_at
|
|
112
|
+
FROM content
|
|
113
|
+
WHERE
|
|
114
|
+
status = 'scheduled'
|
|
115
|
+
AND scheduled_at <= NOW()
|
|
116
|
+
ORDER BY scheduled_at ASC
|
|
117
|
+
LIMIT $1
|
|
118
|
+
FOR UPDATE SKIP LOCKED
|
|
119
|
+
`, [maxBatchSize]);
|
|
120
|
+
|
|
121
|
+
if (dueContent.length === 0) {
|
|
122
|
+
await client.query('COMMIT');
|
|
123
|
+
return { published, failed };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
console.log(`[ContentPublisher] Found ${dueContent.length} post(s) due for publishing`);
|
|
127
|
+
|
|
128
|
+
// Batch update all due posts to 'published'
|
|
129
|
+
const ids = dueContent.map(r => r.id);
|
|
130
|
+
await client.query(`
|
|
131
|
+
UPDATE content
|
|
132
|
+
SET
|
|
133
|
+
status = 'published',
|
|
134
|
+
published_at = NOW(),
|
|
135
|
+
scheduled_at = NULL,
|
|
136
|
+
updated_at = NOW()
|
|
137
|
+
WHERE id = ANY($1::uuid[])
|
|
138
|
+
`, [ids]);
|
|
139
|
+
|
|
140
|
+
await client.query('COMMIT');
|
|
141
|
+
|
|
142
|
+
// Post-commit: audit logs and notifications (outside transaction)
|
|
143
|
+
for (const post of dueContent) {
|
|
144
|
+
try {
|
|
145
|
+
await logStatusChange(db, {
|
|
146
|
+
contentId: post.id,
|
|
147
|
+
fromStatus: 'scheduled',
|
|
148
|
+
toStatus: 'published',
|
|
149
|
+
changedBy: options.systemUserId ?? '00000000-0000-0000-0000-000000000000',
|
|
150
|
+
notes: `Auto-published at scheduled time: ${post.scheduled_at.toISOString()}`,
|
|
151
|
+
metadata: { trigger: 'cron', scheduled_at: post.scheduled_at },
|
|
152
|
+
});
|
|
153
|
+
published.push(post.id);
|
|
154
|
+
onPublishSuccess?.(post.id, post.title);
|
|
155
|
+
console.log(`[ContentPublisher] Published: "${post.title}" (${post.id})`);
|
|
156
|
+
} catch (auditErr) {
|
|
157
|
+
// Audit log failure doesn't undo the publish — log and move on
|
|
158
|
+
console.error(`[ContentPublisher] Audit log failed for ${post.id}:`, auditErr);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
} catch (err) {
|
|
163
|
+
await client.query('ROLLBACK');
|
|
164
|
+
console.error('[ContentPublisher] Batch publish failed, rolled back:', err);
|
|
165
|
+
|
|
166
|
+
// `failed` is empty here — the batch threw before individual tracking ran.
|
|
167
|
+
// Notify for ALL due items since we don't know which succeeded.
|
|
168
|
+
const allIds = dueContent.map(r => r.id);
|
|
169
|
+
for (const id of allIds) {
|
|
170
|
+
onPublishFailure?.(id, err as Error);
|
|
171
|
+
}
|
|
172
|
+
} finally {
|
|
173
|
+
client.release();
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return { published, failed };
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Registering the Scheduler at App Startup
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
// app.ts or server.ts
|
|
186
|
+
import express from 'express';
|
|
187
|
+
import { Pool } from 'pg';
|
|
188
|
+
import { startContentPublisher } from './schedulers/content-publisher';
|
|
189
|
+
|
|
190
|
+
const app = express();
|
|
191
|
+
const db = new Pool({ connectionString: process.env.DATABASE_URL });
|
|
192
|
+
|
|
193
|
+
// Start the cron job when the server starts
|
|
194
|
+
const publisherTask = startContentPublisher({
|
|
195
|
+
db,
|
|
196
|
+
cronExpression: '* * * * *', // every minute
|
|
197
|
+
maxBatchSize: 50,
|
|
198
|
+
onPublishSuccess: (id, title) => {
|
|
199
|
+
// Trigger a webhook, send a notification, invalidate CDN cache, etc.
|
|
200
|
+
console.log(`Published: ${title}`);
|
|
201
|
+
// Example: invalidateCache(`/posts/${slug}`);
|
|
202
|
+
// Example: sendPublishNotification(authorId, title);
|
|
203
|
+
},
|
|
204
|
+
onPublishFailure: (id, error) => {
|
|
205
|
+
console.error(`Failed to publish ${id}:`, error.message);
|
|
206
|
+
// Example: alertOpsTeam(error);
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// Graceful shutdown
|
|
211
|
+
process.on('SIGTERM', () => {
|
|
212
|
+
publisherTask.stop();
|
|
213
|
+
db.end();
|
|
214
|
+
process.exit(0);
|
|
215
|
+
});
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Timezone Handling
|
|
221
|
+
|
|
222
|
+
**Rule: Store everything in UTC. Convert only for display.**
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
// Correct: when a user schedules for "2026-03-15 09:00 America/New_York"
|
|
226
|
+
// Convert to UTC before storing:
|
|
227
|
+
import { zonedTimeToUtc, utcToZonedTime, format } from 'date-fns-tz';
|
|
228
|
+
|
|
229
|
+
// npm install date-fns date-fns-tz
|
|
230
|
+
|
|
231
|
+
function scheduleContentInUserTimezone(
|
|
232
|
+
isoDateString: string, // e.g. "2026-03-15T09:00" (no timezone)
|
|
233
|
+
userTimezone: string // e.g. "America/New_York"
|
|
234
|
+
): Date {
|
|
235
|
+
// Convert user's local time to UTC for storage
|
|
236
|
+
return zonedTimeToUtc(isoDateString, userTimezone);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function formatScheduledAtForUser(
|
|
240
|
+
utcDate: Date,
|
|
241
|
+
userTimezone: string
|
|
242
|
+
): string {
|
|
243
|
+
const localDate = utcToZonedTime(utcDate, userTimezone);
|
|
244
|
+
return format(localDate, "MMM d, yyyy 'at' h:mm a zzz", { timeZone: userTimezone });
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Usage in route handler:
|
|
248
|
+
router.patch('/content/:id/schedule', async (req, res) => {
|
|
249
|
+
const { scheduled_at_local, timezone } = req.body;
|
|
250
|
+
// scheduled_at_local: "2026-03-15T09:00" (from a datetime-local input)
|
|
251
|
+
// timezone: "America/New_York" (from user profile or request)
|
|
252
|
+
|
|
253
|
+
const scheduledAtUtc = scheduleContentInUserTimezone(scheduled_at_local, timezone);
|
|
254
|
+
|
|
255
|
+
if (scheduledAtUtc <= new Date()) {
|
|
256
|
+
return res.status(400).json({ error: 'Scheduled time must be in the future' });
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
await db.query(
|
|
260
|
+
'UPDATE content SET status = $1, scheduled_at = $2 WHERE id = $3',
|
|
261
|
+
['scheduled', scheduledAtUtc, req.params.id]
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
res.json({
|
|
265
|
+
status: 'scheduled',
|
|
266
|
+
scheduled_at_utc: scheduledAtUtc.toISOString(),
|
|
267
|
+
scheduled_at_display: formatScheduledAtForUser(scheduledAtUtc, timezone),
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**Frontend datetime input handling:**
|
|
273
|
+
|
|
274
|
+
```tsx
|
|
275
|
+
// Use a timezone-aware datetime picker or convert locally:
|
|
276
|
+
function ScheduleForm({ onSchedule }: { onSchedule: (utcDate: string, tz: string) => void }) {
|
|
277
|
+
const userTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
278
|
+
|
|
279
|
+
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
|
280
|
+
e.preventDefault();
|
|
281
|
+
const form = new FormData(e.currentTarget);
|
|
282
|
+
const localDatetime = form.get('scheduled_at') as string; // "2026-03-15T09:00"
|
|
283
|
+
onSchedule(localDatetime, userTimezone);
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
return (
|
|
287
|
+
<form onSubmit={handleSubmit}>
|
|
288
|
+
<label>
|
|
289
|
+
Schedule for (your time: {userTimezone})
|
|
290
|
+
<input type="datetime-local" name="scheduled_at" min={new Date().toISOString().slice(0, 16)} />
|
|
291
|
+
</label>
|
|
292
|
+
<button type="submit">Schedule</button>
|
|
293
|
+
</form>
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
---
|
|
299
|
+
|
|
300
|
+
## Double-Publish Prevention
|
|
301
|
+
|
|
302
|
+
The `SELECT FOR UPDATE SKIP LOCKED` pattern is the correct solution. Here's why it works:
|
|
303
|
+
|
|
304
|
+
```sql
|
|
305
|
+
-- When Instance A runs:
|
|
306
|
+
BEGIN;
|
|
307
|
+
SELECT id, title FROM content
|
|
308
|
+
WHERE status = 'scheduled' AND scheduled_at <= NOW()
|
|
309
|
+
FOR UPDATE SKIP LOCKED;
|
|
310
|
+
-- Instance A holds locks on rows 1, 2, 3
|
|
311
|
+
|
|
312
|
+
-- Simultaneously, Instance B runs:
|
|
313
|
+
BEGIN;
|
|
314
|
+
SELECT id, title FROM content
|
|
315
|
+
WHERE status = 'scheduled' AND scheduled_at <= NOW()
|
|
316
|
+
FOR UPDATE SKIP LOCKED;
|
|
317
|
+
-- Instance B sees rows 1, 2, 3 are locked → SKIPS them
|
|
318
|
+
-- Instance B gets 0 rows → does nothing
|
|
319
|
+
-- No double-publish
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
**Alternative: PostgreSQL Advisory Locks (for simpler use cases)**
|
|
323
|
+
|
|
324
|
+
```typescript
|
|
325
|
+
// Acquire a session-level advisory lock (lock_id is an arbitrary integer)
|
|
326
|
+
const PUBLISHER_LOCK_ID = 123456789;
|
|
327
|
+
|
|
328
|
+
async function withPublisherLock(db: Pool, fn: () => Promise<void>): Promise<void> {
|
|
329
|
+
const client = await db.connect();
|
|
330
|
+
try {
|
|
331
|
+
// Try to acquire lock — returns immediately if already held
|
|
332
|
+
const { rows } = await client.query(
|
|
333
|
+
'SELECT pg_try_advisory_lock($1) AS acquired',
|
|
334
|
+
[PUBLISHER_LOCK_ID]
|
|
335
|
+
);
|
|
336
|
+
|
|
337
|
+
if (!rows[0].acquired) {
|
|
338
|
+
console.log('[ContentPublisher] Another instance is running, skipping');
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
try {
|
|
343
|
+
await fn();
|
|
344
|
+
} finally {
|
|
345
|
+
await client.query('SELECT pg_advisory_unlock($1)', [PUBLISHER_LOCK_ID]);
|
|
346
|
+
}
|
|
347
|
+
} finally {
|
|
348
|
+
client.release();
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// Usage:
|
|
353
|
+
await withPublisherLock(db, () => publishDueContent(options));
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
Use `SELECT FOR UPDATE SKIP LOCKED` for batch row-level locking. Use advisory locks for single-instance "only one cron at a time" protection. In production, use both.
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
## Schedule Route with Validation
|
|
361
|
+
|
|
362
|
+
```typescript
|
|
363
|
+
// routes/content-schedule.ts
|
|
364
|
+
import { Router } from 'express';
|
|
365
|
+
import { zonedTimeToUtc } from 'date-fns-tz';
|
|
366
|
+
|
|
367
|
+
const router = Router();
|
|
368
|
+
|
|
369
|
+
// POST /content/:id/schedule
|
|
370
|
+
router.post('/content/:id/schedule', async (req, res) => {
|
|
371
|
+
const { id } = req.params;
|
|
372
|
+
const { scheduled_at, timezone = 'UTC', notes } = req.body;
|
|
373
|
+
|
|
374
|
+
// Validate
|
|
375
|
+
if (!scheduled_at) {
|
|
376
|
+
return res.status(400).json({ error: 'scheduled_at is required' });
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
let scheduledAtUtc: Date;
|
|
380
|
+
try {
|
|
381
|
+
scheduledAtUtc = timezone === 'UTC'
|
|
382
|
+
? new Date(scheduled_at)
|
|
383
|
+
: zonedTimeToUtc(scheduled_at, timezone);
|
|
384
|
+
} catch {
|
|
385
|
+
return res.status(400).json({ error: 'Invalid date format or timezone' });
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// Must be at least 1 minute in the future (grace period for clock skew)
|
|
389
|
+
const minimumFuture = new Date(Date.now() + 60_000);
|
|
390
|
+
if (scheduledAtUtc < minimumFuture) {
|
|
391
|
+
return res.status(400).json({
|
|
392
|
+
error: 'Scheduled time must be at least 1 minute in the future',
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Check content exists and is in a schedulable state
|
|
397
|
+
const { rows } = await db.query(
|
|
398
|
+
'SELECT id, status, title, slug FROM content WHERE id = $1',
|
|
399
|
+
[id]
|
|
400
|
+
);
|
|
401
|
+
|
|
402
|
+
if (!rows[0]) return res.status(404).json({ error: 'Content not found' });
|
|
403
|
+
|
|
404
|
+
const content = rows[0];
|
|
405
|
+
|
|
406
|
+
if (!['in_review', 'draft'].includes(content.status)) {
|
|
407
|
+
return res.status(422).json({
|
|
408
|
+
error: `Cannot schedule content with status '${content.status}'`,
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (!content.slug) {
|
|
413
|
+
return res.status(422).json({ error: 'Content must have a slug before scheduling' });
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Update
|
|
417
|
+
await db.query(`
|
|
418
|
+
UPDATE content
|
|
419
|
+
SET status = 'scheduled', scheduled_at = $1, updated_at = NOW(), updated_by = $2
|
|
420
|
+
WHERE id = $3
|
|
421
|
+
`, [scheduledAtUtc, req.user.id, id]);
|
|
422
|
+
|
|
423
|
+
res.json({
|
|
424
|
+
status: 'scheduled',
|
|
425
|
+
scheduled_at: scheduledAtUtc.toISOString(),
|
|
426
|
+
});
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
// DELETE /content/:id/schedule — cancel scheduling
|
|
430
|
+
router.delete('/content/:id/schedule', async (req, res) => {
|
|
431
|
+
const { id } = req.params;
|
|
432
|
+
|
|
433
|
+
const { rows } = await db.query('SELECT status FROM content WHERE id = $1', [id]);
|
|
434
|
+
|
|
435
|
+
if (!rows[0]) return res.status(404).json({ error: 'Content not found' });
|
|
436
|
+
if (rows[0].status !== 'scheduled') {
|
|
437
|
+
return res.status(422).json({ error: 'Content is not currently scheduled' });
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
await db.query(`
|
|
441
|
+
UPDATE content
|
|
442
|
+
SET status = 'draft', scheduled_at = NULL, updated_at = NOW(), updated_by = $1
|
|
443
|
+
WHERE id = $2
|
|
444
|
+
`, [req.user.id, id]);
|
|
445
|
+
|
|
446
|
+
res.json({ status: 'draft' });
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
export default router;
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
---
|
|
453
|
+
|
|
454
|
+
## Error Handling: What to Do When Scheduled Publish Fails
|
|
455
|
+
|
|
456
|
+
```typescript
|
|
457
|
+
// In the cron handler — after a publish failure:
|
|
458
|
+
|
|
459
|
+
interface FailedPublish {
|
|
460
|
+
contentId: string;
|
|
461
|
+
failedAt: Date;
|
|
462
|
+
attemptCount: number;
|
|
463
|
+
lastError: string;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// Option 1: Retry table (simple, durable)
|
|
467
|
+
// Add a publish_attempts column to content:
|
|
468
|
+
// ALTER TABLE content ADD COLUMN publish_attempts INT NOT NULL DEFAULT 0;
|
|
469
|
+
// ALTER TABLE content ADD COLUMN last_publish_error TEXT;
|
|
470
|
+
|
|
471
|
+
async function handlePublishFailure(db: Pool, contentId: string, error: Error) {
|
|
472
|
+
await db.query(`
|
|
473
|
+
UPDATE content
|
|
474
|
+
SET
|
|
475
|
+
publish_attempts = publish_attempts + 1,
|
|
476
|
+
last_publish_error = $1
|
|
477
|
+
WHERE id = $2
|
|
478
|
+
`, [error.message, contentId]);
|
|
479
|
+
|
|
480
|
+
// After 3 failures, move to draft and notify author
|
|
481
|
+
const { rows } = await db.query(
|
|
482
|
+
'SELECT publish_attempts, author_id, title FROM content WHERE id = $1',
|
|
483
|
+
[contentId]
|
|
484
|
+
);
|
|
485
|
+
|
|
486
|
+
if (rows[0]?.publish_attempts >= 3) {
|
|
487
|
+
await db.query(`
|
|
488
|
+
UPDATE content
|
|
489
|
+
SET status = 'draft', scheduled_at = NULL
|
|
490
|
+
WHERE id = $1
|
|
491
|
+
`, [contentId]);
|
|
492
|
+
|
|
493
|
+
// Notify author (implement your notification system)
|
|
494
|
+
await notifyAuthor(rows[0].author_id, {
|
|
495
|
+
type: 'publish_failed',
|
|
496
|
+
contentId,
|
|
497
|
+
title: rows[0].title,
|
|
498
|
+
error: error.message,
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
---
|
|
505
|
+
|
|
506
|
+
## Manual Trigger Endpoint for Testing
|
|
507
|
+
|
|
508
|
+
**Never wait for a cron to fire during development.** Add a protected endpoint to trigger the publisher manually:
|
|
509
|
+
|
|
510
|
+
```typescript
|
|
511
|
+
// routes/admin.ts
|
|
512
|
+
import { publishDueContent } from '../schedulers/content-publisher';
|
|
513
|
+
|
|
514
|
+
// POST /admin/trigger-publisher
|
|
515
|
+
// Only accessible to admins — or only in non-production
|
|
516
|
+
router.post('/admin/trigger-publisher', requireRole('admin'), async (req, res) => {
|
|
517
|
+
if (process.env.NODE_ENV === 'production' && !req.user?.isSuperAdmin) {
|
|
518
|
+
return res.status(403).json({ error: 'Manual trigger disabled in production' });
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
console.log('[Admin] Manual publisher trigger initiated');
|
|
522
|
+
|
|
523
|
+
try {
|
|
524
|
+
const result = await publishDueContent({
|
|
525
|
+
db,
|
|
526
|
+
maxBatchSize: 100,
|
|
527
|
+
});
|
|
528
|
+
|
|
529
|
+
res.json({
|
|
530
|
+
published: result.published.length,
|
|
531
|
+
failed: result.failed.length,
|
|
532
|
+
publishedIds: result.published,
|
|
533
|
+
failedIds: result.failed,
|
|
534
|
+
});
|
|
535
|
+
} catch (err) {
|
|
536
|
+
res.status(500).json({ error: (err as Error).message });
|
|
537
|
+
}
|
|
538
|
+
});
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
**Testing with a past-dated schedule:**
|
|
542
|
+
|
|
543
|
+
```bash
|
|
544
|
+
# Set a post to "scheduled" with a past date to test immediately
|
|
545
|
+
curl -X PATCH http://localhost:3000/api/content/123/schedule \
|
|
546
|
+
-H "Authorization: Bearer $JWT" \
|
|
547
|
+
-H "Content-Type: application/json" \
|
|
548
|
+
-d '{"scheduled_at": "2020-01-01T00:00:00Z"}'
|
|
549
|
+
|
|
550
|
+
# Then trigger the publisher manually
|
|
551
|
+
curl -X POST http://localhost:3000/api/admin/trigger-publisher \
|
|
552
|
+
-H "Authorization: Bearer $ADMIN_JWT"
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
---
|
|
556
|
+
|
|
557
|
+
## Monitoring
|
|
558
|
+
|
|
559
|
+
Add basic telemetry to the cron job:
|
|
560
|
+
|
|
561
|
+
```typescript
|
|
562
|
+
// Track last run time and publish counts for a /health endpoint
|
|
563
|
+
const publisherStats = {
|
|
564
|
+
lastRun: null as Date | null,
|
|
565
|
+
lastRunPublished: 0,
|
|
566
|
+
totalPublished: 0,
|
|
567
|
+
totalFailed: 0,
|
|
568
|
+
consecutiveFailures: 0,
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
cron.schedule('* * * * *', async () => {
|
|
572
|
+
const start = Date.now();
|
|
573
|
+
try {
|
|
574
|
+
const result = await publishDueContent({ db, maxBatchSize: 50 });
|
|
575
|
+
publisherStats.lastRun = new Date();
|
|
576
|
+
publisherStats.lastRunPublished = result.published.length;
|
|
577
|
+
publisherStats.totalPublished += result.published.length;
|
|
578
|
+
publisherStats.totalFailed += result.failed.length;
|
|
579
|
+
publisherStats.consecutiveFailures = 0;
|
|
580
|
+
} catch (err) {
|
|
581
|
+
publisherStats.consecutiveFailures++;
|
|
582
|
+
if (publisherStats.consecutiveFailures >= 5) {
|
|
583
|
+
console.error('[ContentPublisher] 5 consecutive failures — alert ops');
|
|
584
|
+
// alertOpsTeam(err);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
console.log(`[ContentPublisher] Run complete in ${Date.now() - start}ms`);
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
// Expose in /health:
|
|
591
|
+
app.get('/health', (req, res) => {
|
|
592
|
+
res.json({
|
|
593
|
+
status: 'ok',
|
|
594
|
+
publisher: publisherStats,
|
|
595
|
+
});
|
|
596
|
+
});
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
---
|
|
600
|
+
|
|
601
|
+
## Common Gotchas
|
|
602
|
+
|
|
603
|
+
1. **Never store scheduled times in local time** — always UTC in the database. Display conversion happens at the UI layer.
|
|
604
|
+
2. **`SKIP LOCKED` requires PostgreSQL 9.5+** — use advisory locks for older PG versions.
|
|
605
|
+
3. **Cron doesn't fire if the server is down** — for critical scheduling, add a startup recovery pass that checks for overdue scheduled posts and publishes them immediately.
|
|
606
|
+
4. **Memory leaks from uncleaned cron tasks** — always call `task.stop()` in shutdown handlers and test suites.
|
|
607
|
+
5. **node-cron runs in server process** — if you scale horizontally (multiple dynos/containers), every instance runs the cron. The `SELECT FOR UPDATE SKIP LOCKED` pattern prevents double-publishing. Advisory locks prevent duplicate processing at the application level.
|
|
608
|
+
6. **1-minute resolution means up to 59s delay** — this is acceptable for blog posts. For time-critical scheduling (newsletters, flash sales), run the cron every 15 or 30 seconds: `'*/30 * * * * *'` (with seconds enabled).
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
Here are all the available project commands, organized by category:
|
|
2
|
+
|
|
3
|
+
## Post Management
|
|
4
|
+
|
|
5
|
+
- `/project:posts:new` - Create a new blog post with proper front matter
|
|
6
|
+
- `/project:posts:check_language` - Check posts for UK English spelling and grammar
|
|
7
|
+
- `/project:posts:check_links` - Verify all links in posts are valid
|
|
8
|
+
- `/project:posts:publish` - Publish a draft post and push changes to GitHub
|
|
9
|
+
- `/project:posts:find_drafts` - List all draft posts with their details
|
|
10
|
+
- `/project:posts:check_images` - Verify all image references exist in the filesystem
|
|
11
|
+
- `/project:posts:recent` - Show the most recent blog posts
|
|
12
|
+
|
|
13
|
+
## Project Management
|
|
14
|
+
|
|
15
|
+
- `/project:projects:new` - Create a new project with proper structure and frontmatter
|
|
16
|
+
- `/project:projects:check_thumbnails` - Verify all project thumbnails exist and have correct dimensions
|
|
17
|
+
|
|
18
|
+
## Site Management
|
|
19
|
+
|
|
20
|
+
- `/project:site:preview` - Generate and serve the site locally
|
|
21
|
+
- `/project:site:check_updates` - Check for updates to Hugo and the Congo theme
|
|
22
|
+
- `/project:site:deploy` - Deploy the site to GitHub Pages
|
|
23
|
+
- `/project:site:find_orphaned_images` - Find unused images in static folder
|
|
24
|
+
|
|
25
|
+
To get more details about a specific command, look at the corresponding Markdown file in the `.claude/commands/` directory.
|