claude-autopm 2.8.2 → 2.8.4
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/README.md +399 -637
- package/install/install.js +15 -5
- package/package.json +2 -1
- package/packages/plugin-ai/LICENSE +21 -0
- package/packages/plugin-ai/README.md +316 -0
- package/packages/plugin-ai/agents/anthropic-claude-expert.md +579 -0
- package/packages/plugin-ai/agents/azure-openai-expert.md +1411 -0
- package/packages/plugin-ai/agents/gemini-api-expert.md +880 -0
- package/packages/plugin-ai/agents/google-a2a-expert.md +1445 -0
- package/packages/plugin-ai/agents/huggingface-expert.md +2131 -0
- package/packages/plugin-ai/agents/langchain-expert.md +1427 -0
- package/packages/plugin-ai/agents/langgraph-workflow-expert.md +520 -0
- package/packages/plugin-ai/agents/openai-python-expert.md +1087 -0
- package/packages/plugin-ai/commands/a2a-setup.md +886 -0
- package/packages/plugin-ai/commands/ai-model-deployment.md +481 -0
- package/packages/plugin-ai/commands/anthropic-optimize.md +793 -0
- package/packages/plugin-ai/commands/huggingface-deploy.md +789 -0
- package/packages/plugin-ai/commands/langchain-optimize.md +807 -0
- package/packages/plugin-ai/commands/llm-optimize.md +348 -0
- package/packages/plugin-ai/commands/openai-optimize.md +863 -0
- package/packages/plugin-ai/commands/rag-optimize.md +841 -0
- package/packages/plugin-ai/commands/rag-setup-scaffold.md +382 -0
- package/packages/plugin-ai/package.json +66 -0
- package/packages/plugin-ai/plugin.json +519 -0
- package/packages/plugin-ai/rules/ai-model-standards.md +449 -0
- package/packages/plugin-ai/rules/prompt-engineering-standards.md +509 -0
- package/packages/plugin-ai/scripts/examples/huggingface-inference-example.py +145 -0
- package/packages/plugin-ai/scripts/examples/langchain-rag-example.py +366 -0
- package/packages/plugin-ai/scripts/examples/mlflow-tracking-example.py +224 -0
- package/packages/plugin-ai/scripts/examples/openai-chat-example.py +425 -0
- package/packages/plugin-cloud/README.md +268 -0
- package/packages/plugin-cloud/agents/README.md +55 -0
- package/packages/plugin-cloud/agents/aws-cloud-architect.md +521 -0
- package/packages/plugin-cloud/agents/azure-cloud-architect.md +436 -0
- package/packages/plugin-cloud/agents/gcp-cloud-architect.md +385 -0
- package/packages/plugin-cloud/agents/gcp-cloud-functions-engineer.md +306 -0
- package/packages/plugin-cloud/agents/gemini-api-expert.md +880 -0
- package/packages/plugin-cloud/agents/kubernetes-orchestrator.md +566 -0
- package/packages/plugin-cloud/agents/openai-python-expert.md +1087 -0
- package/packages/plugin-cloud/agents/terraform-infrastructure-expert.md +454 -0
- package/packages/plugin-cloud/commands/cloud-cost-optimize.md +243 -0
- package/packages/plugin-cloud/commands/cloud-validate.md +196 -0
- package/packages/plugin-cloud/commands/infra-deploy.md +38 -0
- package/packages/plugin-cloud/commands/k8s-deploy.md +37 -0
- package/packages/plugin-cloud/commands/ssh-security.md +65 -0
- package/packages/plugin-cloud/commands/traefik-setup.md +65 -0
- package/packages/plugin-cloud/hooks/pre-cloud-deploy.js +456 -0
- package/packages/plugin-cloud/package.json +64 -0
- package/packages/plugin-cloud/plugin.json +338 -0
- package/packages/plugin-cloud/rules/cloud-security-compliance.md +313 -0
- package/packages/plugin-cloud/rules/infrastructure-pipeline.md +128 -0
- package/packages/plugin-cloud/scripts/examples/aws-validate.sh +30 -0
- package/packages/plugin-cloud/scripts/examples/azure-setup.sh +33 -0
- package/packages/plugin-cloud/scripts/examples/gcp-setup.sh +39 -0
- package/packages/plugin-cloud/scripts/examples/k8s-validate.sh +40 -0
- package/packages/plugin-cloud/scripts/examples/terraform-init.sh +26 -0
- package/packages/plugin-core/README.md +274 -0
- package/packages/plugin-core/agents/core/agent-manager.md +296 -0
- package/packages/plugin-core/agents/core/code-analyzer.md +131 -0
- package/packages/plugin-core/agents/core/file-analyzer.md +162 -0
- package/packages/plugin-core/agents/core/test-runner.md +200 -0
- package/packages/plugin-core/commands/code-rabbit.md +128 -0
- package/packages/plugin-core/commands/prompt.md +9 -0
- package/packages/plugin-core/commands/re-init.md +9 -0
- package/packages/plugin-core/hooks/context7-reminder.md +29 -0
- package/packages/plugin-core/hooks/enforce-agents.js +125 -0
- package/packages/plugin-core/hooks/enforce-agents.sh +35 -0
- package/packages/plugin-core/hooks/pre-agent-context7.js +224 -0
- package/packages/plugin-core/hooks/pre-command-context7.js +229 -0
- package/packages/plugin-core/hooks/strict-enforce-agents.sh +39 -0
- package/packages/plugin-core/hooks/test-hook.sh +21 -0
- package/packages/plugin-core/hooks/unified-context7-enforcement.sh +38 -0
- package/packages/plugin-core/package.json +45 -0
- package/packages/plugin-core/plugin.json +387 -0
- package/packages/plugin-core/rules/agent-coordination.md +549 -0
- package/packages/plugin-core/rules/agent-mandatory.md +170 -0
- package/packages/plugin-core/rules/ai-integration-patterns.md +219 -0
- package/packages/plugin-core/rules/command-pipelines.md +208 -0
- package/packages/plugin-core/rules/context-optimization.md +176 -0
- package/packages/plugin-core/rules/context7-enforcement.md +327 -0
- package/packages/plugin-core/rules/datetime.md +122 -0
- package/packages/plugin-core/rules/definition-of-done.md +272 -0
- package/packages/plugin-core/rules/development-environments.md +19 -0
- package/packages/plugin-core/rules/development-workflow.md +198 -0
- package/packages/plugin-core/rules/framework-path-rules.md +180 -0
- package/packages/plugin-core/rules/frontmatter-operations.md +64 -0
- package/packages/plugin-core/rules/git-strategy.md +237 -0
- package/packages/plugin-core/rules/golden-rules.md +181 -0
- package/packages/plugin-core/rules/naming-conventions.md +111 -0
- package/packages/plugin-core/rules/no-pr-workflow.md +183 -0
- package/packages/plugin-core/rules/performance-guidelines.md +403 -0
- package/packages/plugin-core/rules/pipeline-mandatory.md +109 -0
- package/packages/plugin-core/rules/security-checklist.md +318 -0
- package/packages/plugin-core/rules/standard-patterns.md +197 -0
- package/packages/plugin-core/rules/strip-frontmatter.md +85 -0
- package/packages/plugin-core/rules/tdd.enforcement.md +103 -0
- package/packages/plugin-core/rules/use-ast-grep.md +113 -0
- package/packages/plugin-core/scripts/lib/datetime-utils.sh +254 -0
- package/packages/plugin-core/scripts/lib/frontmatter-utils.sh +294 -0
- package/packages/plugin-core/scripts/lib/github-utils.sh +221 -0
- package/packages/plugin-core/scripts/lib/logging-utils.sh +199 -0
- package/packages/plugin-core/scripts/lib/validation-utils.sh +339 -0
- package/packages/plugin-core/scripts/mcp/add.sh +7 -0
- package/packages/plugin-core/scripts/mcp/disable.sh +12 -0
- package/packages/plugin-core/scripts/mcp/enable.sh +12 -0
- package/packages/plugin-core/scripts/mcp/list.sh +7 -0
- package/packages/plugin-core/scripts/mcp/sync.sh +8 -0
- package/packages/plugin-data/README.md +315 -0
- package/packages/plugin-data/agents/airflow-orchestration-expert.md +158 -0
- package/packages/plugin-data/agents/kedro-pipeline-expert.md +304 -0
- package/packages/plugin-data/agents/langgraph-workflow-expert.md +530 -0
- package/packages/plugin-data/commands/airflow-dag-scaffold.md +413 -0
- package/packages/plugin-data/commands/kafka-pipeline-scaffold.md +503 -0
- package/packages/plugin-data/package.json +66 -0
- package/packages/plugin-data/plugin.json +294 -0
- package/packages/plugin-data/rules/data-quality-standards.md +373 -0
- package/packages/plugin-data/rules/etl-pipeline-standards.md +255 -0
- package/packages/plugin-data/scripts/examples/airflow-dag-example.py +245 -0
- package/packages/plugin-data/scripts/examples/dbt-transform-example.sql +238 -0
- package/packages/plugin-data/scripts/examples/kafka-streaming-example.py +257 -0
- package/packages/plugin-data/scripts/examples/pandas-etl-example.py +332 -0
- package/packages/plugin-databases/README.md +330 -0
- package/packages/plugin-databases/agents/README.md +50 -0
- package/packages/plugin-databases/agents/bigquery-expert.md +401 -0
- package/packages/plugin-databases/agents/cosmosdb-expert.md +375 -0
- package/packages/plugin-databases/agents/mongodb-expert.md +407 -0
- package/packages/plugin-databases/agents/postgresql-expert.md +329 -0
- package/packages/plugin-databases/agents/redis-expert.md +74 -0
- package/packages/plugin-databases/commands/db-optimize.md +612 -0
- package/packages/plugin-databases/package.json +60 -0
- package/packages/plugin-databases/plugin.json +237 -0
- package/packages/plugin-databases/rules/database-management-strategy.md +146 -0
- package/packages/plugin-databases/rules/database-pipeline.md +316 -0
- package/packages/plugin-databases/scripts/examples/bigquery-cost-analyze.sh +160 -0
- package/packages/plugin-databases/scripts/examples/cosmosdb-ru-optimize.sh +163 -0
- package/packages/plugin-databases/scripts/examples/mongodb-shard-check.sh +120 -0
- package/packages/plugin-databases/scripts/examples/postgres-index-analyze.sh +95 -0
- package/packages/plugin-databases/scripts/examples/redis-cache-stats.sh +121 -0
- package/packages/plugin-devops/README.md +367 -0
- package/packages/plugin-devops/agents/README.md +52 -0
- package/packages/plugin-devops/agents/azure-devops-specialist.md +308 -0
- package/packages/plugin-devops/agents/docker-containerization-expert.md +298 -0
- package/packages/plugin-devops/agents/github-operations-specialist.md +335 -0
- package/packages/plugin-devops/agents/mcp-context-manager.md +319 -0
- package/packages/plugin-devops/agents/observability-engineer.md +574 -0
- package/packages/plugin-devops/agents/ssh-operations-expert.md +1093 -0
- package/packages/plugin-devops/agents/traefik-proxy-expert.md +444 -0
- package/packages/plugin-devops/commands/ci-pipeline-create.md +581 -0
- package/packages/plugin-devops/commands/docker-optimize.md +493 -0
- package/packages/plugin-devops/commands/workflow-create.md +42 -0
- package/packages/plugin-devops/hooks/pre-docker-build.js +472 -0
- package/packages/plugin-devops/package.json +61 -0
- package/packages/plugin-devops/plugin.json +302 -0
- package/packages/plugin-devops/rules/ci-cd-kubernetes-strategy.md +25 -0
- package/packages/plugin-devops/rules/devops-troubleshooting-playbook.md +450 -0
- package/packages/plugin-devops/rules/docker-first-development.md +404 -0
- package/packages/plugin-devops/rules/github-operations.md +92 -0
- package/packages/plugin-devops/scripts/examples/docker-build-multistage.sh +43 -0
- package/packages/plugin-devops/scripts/examples/docker-compose-validate.sh +74 -0
- package/packages/plugin-devops/scripts/examples/github-workflow-validate.sh +48 -0
- package/packages/plugin-devops/scripts/examples/prometheus-health-check.sh +58 -0
- package/packages/plugin-devops/scripts/examples/ssh-key-setup.sh +74 -0
- package/packages/plugin-frameworks/README.md +309 -0
- package/packages/plugin-frameworks/agents/README.md +64 -0
- package/packages/plugin-frameworks/agents/e2e-test-engineer.md +579 -0
- package/packages/plugin-frameworks/agents/nats-messaging-expert.md +254 -0
- package/packages/plugin-frameworks/agents/react-frontend-engineer.md +393 -0
- package/packages/plugin-frameworks/agents/react-ui-expert.md +226 -0
- package/packages/plugin-frameworks/agents/tailwindcss-expert.md +1021 -0
- package/packages/plugin-frameworks/agents/ux-design-expert.md +244 -0
- package/packages/plugin-frameworks/commands/app-scaffold.md +50 -0
- package/packages/plugin-frameworks/commands/nextjs-optimize.md +692 -0
- package/packages/plugin-frameworks/commands/react-optimize.md +583 -0
- package/packages/plugin-frameworks/commands/tailwind-system.md +64 -0
- package/packages/plugin-frameworks/package.json +59 -0
- package/packages/plugin-frameworks/plugin.json +224 -0
- package/packages/plugin-frameworks/rules/performance-guidelines.md +403 -0
- package/packages/plugin-frameworks/rules/ui-development-standards.md +281 -0
- package/packages/plugin-frameworks/rules/ui-framework-rules.md +151 -0
- package/packages/plugin-frameworks/scripts/examples/react-component-perf.sh +34 -0
- package/packages/plugin-frameworks/scripts/examples/tailwind-optimize.sh +44 -0
- package/packages/plugin-frameworks/scripts/examples/vue-composition-check.sh +41 -0
- package/packages/plugin-languages/README.md +333 -0
- package/packages/plugin-languages/agents/README.md +50 -0
- package/packages/plugin-languages/agents/bash-scripting-expert.md +541 -0
- package/packages/plugin-languages/agents/javascript-frontend-engineer.md +197 -0
- package/packages/plugin-languages/agents/nodejs-backend-engineer.md +226 -0
- package/packages/plugin-languages/agents/python-backend-engineer.md +214 -0
- package/packages/plugin-languages/agents/python-backend-expert.md +289 -0
- package/packages/plugin-languages/commands/javascript-optimize.md +636 -0
- package/packages/plugin-languages/commands/nodejs-api-scaffold.md +341 -0
- package/packages/plugin-languages/commands/nodejs-optimize.md +689 -0
- package/packages/plugin-languages/commands/python-api-scaffold.md +261 -0
- package/packages/plugin-languages/commands/python-optimize.md +593 -0
- package/packages/plugin-languages/package.json +65 -0
- package/packages/plugin-languages/plugin.json +265 -0
- package/packages/plugin-languages/rules/code-quality-standards.md +496 -0
- package/packages/plugin-languages/rules/testing-standards.md +768 -0
- package/packages/plugin-languages/scripts/examples/bash-production-script.sh +520 -0
- package/packages/plugin-languages/scripts/examples/javascript-es6-patterns.js +291 -0
- package/packages/plugin-languages/scripts/examples/nodejs-async-iteration.js +360 -0
- package/packages/plugin-languages/scripts/examples/python-async-patterns.py +289 -0
- package/packages/plugin-languages/scripts/examples/typescript-patterns.ts +432 -0
- package/packages/plugin-ml/README.md +430 -0
- package/packages/plugin-ml/agents/automl-expert.md +326 -0
- package/packages/plugin-ml/agents/computer-vision-expert.md +550 -0
- package/packages/plugin-ml/agents/gradient-boosting-expert.md +455 -0
- package/packages/plugin-ml/agents/neural-network-architect.md +1228 -0
- package/packages/plugin-ml/agents/nlp-transformer-expert.md +584 -0
- package/packages/plugin-ml/agents/pytorch-expert.md +412 -0
- package/packages/plugin-ml/agents/reinforcement-learning-expert.md +2088 -0
- package/packages/plugin-ml/agents/scikit-learn-expert.md +228 -0
- package/packages/plugin-ml/agents/tensorflow-keras-expert.md +509 -0
- package/packages/plugin-ml/agents/time-series-expert.md +303 -0
- package/packages/plugin-ml/commands/ml-automl.md +572 -0
- package/packages/plugin-ml/commands/ml-train-optimize.md +657 -0
- package/packages/plugin-ml/package.json +52 -0
- package/packages/plugin-ml/plugin.json +338 -0
- package/packages/plugin-pm/README.md +368 -0
- package/packages/plugin-pm/claudeautopm-plugin-pm-2.0.0.tgz +0 -0
- package/packages/plugin-pm/commands/azure/COMMANDS.md +107 -0
- package/packages/plugin-pm/commands/azure/COMMAND_MAPPING.md +252 -0
- package/packages/plugin-pm/commands/azure/INTEGRATION_FIX.md +103 -0
- package/packages/plugin-pm/commands/azure/README.md +246 -0
- package/packages/plugin-pm/commands/azure/active-work.md +198 -0
- package/packages/plugin-pm/commands/azure/aliases.md +143 -0
- package/packages/plugin-pm/commands/azure/blocked-items.md +287 -0
- package/packages/plugin-pm/commands/azure/clean.md +93 -0
- package/packages/plugin-pm/commands/azure/docs-query.md +48 -0
- package/packages/plugin-pm/commands/azure/feature-decompose.md +380 -0
- package/packages/plugin-pm/commands/azure/feature-list.md +61 -0
- package/packages/plugin-pm/commands/azure/feature-new.md +115 -0
- package/packages/plugin-pm/commands/azure/feature-show.md +205 -0
- package/packages/plugin-pm/commands/azure/feature-start.md +130 -0
- package/packages/plugin-pm/commands/azure/fix-integration-example.md +93 -0
- package/packages/plugin-pm/commands/azure/help.md +150 -0
- package/packages/plugin-pm/commands/azure/import-us.md +269 -0
- package/packages/plugin-pm/commands/azure/init.md +211 -0
- package/packages/plugin-pm/commands/azure/next-task.md +262 -0
- package/packages/plugin-pm/commands/azure/search.md +160 -0
- package/packages/plugin-pm/commands/azure/sprint-status.md +235 -0
- package/packages/plugin-pm/commands/azure/standup.md +260 -0
- package/packages/plugin-pm/commands/azure/sync-all.md +99 -0
- package/packages/plugin-pm/commands/azure/task-analyze.md +186 -0
- package/packages/plugin-pm/commands/azure/task-close.md +329 -0
- package/packages/plugin-pm/commands/azure/task-edit.md +145 -0
- package/packages/plugin-pm/commands/azure/task-list.md +263 -0
- package/packages/plugin-pm/commands/azure/task-new.md +84 -0
- package/packages/plugin-pm/commands/azure/task-reopen.md +79 -0
- package/packages/plugin-pm/commands/azure/task-show.md +126 -0
- package/packages/plugin-pm/commands/azure/task-start.md +301 -0
- package/packages/plugin-pm/commands/azure/task-status.md +65 -0
- package/packages/plugin-pm/commands/azure/task-sync.md +67 -0
- package/packages/plugin-pm/commands/azure/us-edit.md +164 -0
- package/packages/plugin-pm/commands/azure/us-list.md +202 -0
- package/packages/plugin-pm/commands/azure/us-new.md +265 -0
- package/packages/plugin-pm/commands/azure/us-parse.md +253 -0
- package/packages/plugin-pm/commands/azure/us-show.md +188 -0
- package/packages/plugin-pm/commands/azure/us-status.md +320 -0
- package/packages/plugin-pm/commands/azure/validate.md +86 -0
- package/packages/plugin-pm/commands/azure/work-item-sync.md +47 -0
- package/packages/plugin-pm/commands/blocked.md +28 -0
- package/packages/plugin-pm/commands/clean.md +119 -0
- package/packages/plugin-pm/commands/context-create.md +136 -0
- package/packages/plugin-pm/commands/context-prime.md +170 -0
- package/packages/plugin-pm/commands/context-update.md +292 -0
- package/packages/plugin-pm/commands/context.md +28 -0
- package/packages/plugin-pm/commands/epic-close.md +86 -0
- package/packages/plugin-pm/commands/epic-decompose.md +370 -0
- package/packages/plugin-pm/commands/epic-edit.md +83 -0
- package/packages/plugin-pm/commands/epic-list.md +30 -0
- package/packages/plugin-pm/commands/epic-merge.md +222 -0
- package/packages/plugin-pm/commands/epic-oneshot.md +119 -0
- package/packages/plugin-pm/commands/epic-refresh.md +119 -0
- package/packages/plugin-pm/commands/epic-show.md +28 -0
- package/packages/plugin-pm/commands/epic-split.md +120 -0
- package/packages/plugin-pm/commands/epic-start.md +195 -0
- package/packages/plugin-pm/commands/epic-status.md +28 -0
- package/packages/plugin-pm/commands/epic-sync-modular.md +338 -0
- package/packages/plugin-pm/commands/epic-sync-original.md +473 -0
- package/packages/plugin-pm/commands/epic-sync.md +486 -0
- package/packages/plugin-pm/commands/github/workflow-create.md +42 -0
- package/packages/plugin-pm/commands/help.md +28 -0
- package/packages/plugin-pm/commands/import.md +115 -0
- package/packages/plugin-pm/commands/in-progress.md +28 -0
- package/packages/plugin-pm/commands/init.md +28 -0
- package/packages/plugin-pm/commands/issue-analyze.md +202 -0
- package/packages/plugin-pm/commands/issue-close.md +119 -0
- package/packages/plugin-pm/commands/issue-edit.md +93 -0
- package/packages/plugin-pm/commands/issue-reopen.md +87 -0
- package/packages/plugin-pm/commands/issue-show.md +41 -0
- package/packages/plugin-pm/commands/issue-start.md +234 -0
- package/packages/plugin-pm/commands/issue-status.md +95 -0
- package/packages/plugin-pm/commands/issue-sync.md +411 -0
- package/packages/plugin-pm/commands/next.md +28 -0
- package/packages/plugin-pm/commands/prd-edit.md +82 -0
- package/packages/plugin-pm/commands/prd-list.md +28 -0
- package/packages/plugin-pm/commands/prd-new.md +55 -0
- package/packages/plugin-pm/commands/prd-parse.md +42 -0
- package/packages/plugin-pm/commands/prd-status.md +28 -0
- package/packages/plugin-pm/commands/search.md +28 -0
- package/packages/plugin-pm/commands/standup.md +28 -0
- package/packages/plugin-pm/commands/status.md +28 -0
- package/packages/plugin-pm/commands/sync.md +99 -0
- package/packages/plugin-pm/commands/test-reference-update.md +151 -0
- package/packages/plugin-pm/commands/validate.md +28 -0
- package/packages/plugin-pm/commands/what-next.md +28 -0
- package/packages/plugin-pm/package.json +57 -0
- package/packages/plugin-pm/plugin.json +503 -0
- package/packages/plugin-pm/scripts/pm/analytics.js +425 -0
- package/packages/plugin-pm/scripts/pm/blocked.js +164 -0
- package/packages/plugin-pm/scripts/pm/blocked.sh +78 -0
- package/packages/plugin-pm/scripts/pm/clean.js +464 -0
- package/packages/plugin-pm/scripts/pm/context-create.js +216 -0
- package/packages/plugin-pm/scripts/pm/context-prime.js +335 -0
- package/packages/plugin-pm/scripts/pm/context-update.js +344 -0
- package/packages/plugin-pm/scripts/pm/context.js +338 -0
- package/packages/plugin-pm/scripts/pm/epic-close.js +347 -0
- package/packages/plugin-pm/scripts/pm/epic-edit.js +382 -0
- package/packages/plugin-pm/scripts/pm/epic-list.js +273 -0
- package/packages/plugin-pm/scripts/pm/epic-list.sh +109 -0
- package/packages/plugin-pm/scripts/pm/epic-show.js +291 -0
- package/packages/plugin-pm/scripts/pm/epic-show.sh +105 -0
- package/packages/plugin-pm/scripts/pm/epic-split.js +522 -0
- package/packages/plugin-pm/scripts/pm/epic-start/epic-start.js +183 -0
- package/packages/plugin-pm/scripts/pm/epic-start/epic-start.sh +94 -0
- package/packages/plugin-pm/scripts/pm/epic-status.js +291 -0
- package/packages/plugin-pm/scripts/pm/epic-status.sh +104 -0
- package/packages/plugin-pm/scripts/pm/epic-sync/README.md +208 -0
- package/packages/plugin-pm/scripts/pm/epic-sync/create-epic-issue.sh +77 -0
- package/packages/plugin-pm/scripts/pm/epic-sync/create-task-issues.sh +86 -0
- package/packages/plugin-pm/scripts/pm/epic-sync/update-epic-file.sh +79 -0
- package/packages/plugin-pm/scripts/pm/epic-sync/update-references.sh +89 -0
- package/packages/plugin-pm/scripts/pm/epic-sync.sh +137 -0
- package/packages/plugin-pm/scripts/pm/help.js +92 -0
- package/packages/plugin-pm/scripts/pm/help.sh +90 -0
- package/packages/plugin-pm/scripts/pm/in-progress.js +178 -0
- package/packages/plugin-pm/scripts/pm/in-progress.sh +93 -0
- package/packages/plugin-pm/scripts/pm/init.js +321 -0
- package/packages/plugin-pm/scripts/pm/init.sh +178 -0
- package/packages/plugin-pm/scripts/pm/issue-close.js +232 -0
- package/packages/plugin-pm/scripts/pm/issue-edit.js +310 -0
- package/packages/plugin-pm/scripts/pm/issue-show.js +272 -0
- package/packages/plugin-pm/scripts/pm/issue-start.js +181 -0
- package/packages/plugin-pm/scripts/pm/issue-sync/format-comment.sh +468 -0
- package/packages/plugin-pm/scripts/pm/issue-sync/gather-updates.sh +460 -0
- package/packages/plugin-pm/scripts/pm/issue-sync/post-comment.sh +330 -0
- package/packages/plugin-pm/scripts/pm/issue-sync/preflight-validation.sh +348 -0
- package/packages/plugin-pm/scripts/pm/issue-sync/update-frontmatter.sh +387 -0
- package/packages/plugin-pm/scripts/pm/lib/README.md +85 -0
- package/packages/plugin-pm/scripts/pm/lib/epic-discovery.js +119 -0
- package/packages/plugin-pm/scripts/pm/lib/logger.js +78 -0
- package/packages/plugin-pm/scripts/pm/next.js +189 -0
- package/packages/plugin-pm/scripts/pm/next.sh +72 -0
- package/packages/plugin-pm/scripts/pm/optimize.js +407 -0
- package/packages/plugin-pm/scripts/pm/pr-create.js +337 -0
- package/packages/plugin-pm/scripts/pm/pr-list.js +257 -0
- package/packages/plugin-pm/scripts/pm/prd-list.js +242 -0
- package/packages/plugin-pm/scripts/pm/prd-list.sh +103 -0
- package/packages/plugin-pm/scripts/pm/prd-new.js +684 -0
- package/packages/plugin-pm/scripts/pm/prd-parse.js +547 -0
- package/packages/plugin-pm/scripts/pm/prd-status.js +152 -0
- package/packages/plugin-pm/scripts/pm/prd-status.sh +63 -0
- package/packages/plugin-pm/scripts/pm/release.js +460 -0
- package/packages/plugin-pm/scripts/pm/search.js +192 -0
- package/packages/plugin-pm/scripts/pm/search.sh +89 -0
- package/packages/plugin-pm/scripts/pm/standup.js +362 -0
- package/packages/plugin-pm/scripts/pm/standup.sh +95 -0
- package/packages/plugin-pm/scripts/pm/status.js +148 -0
- package/packages/plugin-pm/scripts/pm/status.sh +59 -0
- package/packages/plugin-pm/scripts/pm/sync-batch.js +337 -0
- package/packages/plugin-pm/scripts/pm/sync.js +343 -0
- package/packages/plugin-pm/scripts/pm/template-list.js +141 -0
- package/packages/plugin-pm/scripts/pm/template-new.js +366 -0
- package/packages/plugin-pm/scripts/pm/validate.js +274 -0
- package/packages/plugin-pm/scripts/pm/validate.sh +106 -0
- package/packages/plugin-pm/scripts/pm/what-next.js +660 -0
- package/packages/plugin-testing/README.md +401 -0
- package/packages/plugin-testing/agents/frontend-testing-engineer.md +768 -0
- package/packages/plugin-testing/commands/jest-optimize.md +800 -0
- package/packages/plugin-testing/commands/playwright-optimize.md +887 -0
- package/packages/plugin-testing/commands/test-coverage.md +512 -0
- package/packages/plugin-testing/commands/test-performance.md +1041 -0
- package/packages/plugin-testing/commands/test-setup.md +414 -0
- package/packages/plugin-testing/package.json +40 -0
- package/packages/plugin-testing/plugin.json +197 -0
- package/packages/plugin-testing/rules/test-coverage-requirements.md +581 -0
- package/packages/plugin-testing/rules/testing-standards.md +529 -0
- package/packages/plugin-testing/scripts/examples/react-testing-example.test.jsx +460 -0
- package/packages/plugin-testing/scripts/examples/vitest-config-example.js +352 -0
- package/packages/plugin-testing/scripts/examples/vue-testing-example.test.js +586 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# AST-Grep Integration Protocol for Cursor Agent
|
|
2
|
+
|
|
3
|
+
## When to Use AST-Grep
|
|
4
|
+
|
|
5
|
+
Use `ast-grep` (if installed) instead of plain regex or text search when:
|
|
6
|
+
|
|
7
|
+
- **Structural code patterns** are involved (e.g., finding all function calls, class definitions, or method implementations)
|
|
8
|
+
- **Language-aware refactoring** is required (e.g., renaming variables, updating function signatures, or changing imports)
|
|
9
|
+
- **Complex code analysis** is needed (e.g., finding all usages of a pattern across different syntactic contexts)
|
|
10
|
+
- **Cross-language searches** are necessary (e.g., working with both Ruby and TypeScript in a monorepo)
|
|
11
|
+
- **Semantic code understanding** is important (e.g., finding patterns based on code structure, not just text)
|
|
12
|
+
|
|
13
|
+
## AST-Grep Command Patterns
|
|
14
|
+
|
|
15
|
+
### Basic Search Template
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
ast-grep --pattern '$PATTERN' --lang $LANGUAGE $PATH
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Common Use Cases
|
|
22
|
+
|
|
23
|
+
- **Find function calls:**
|
|
24
|
+
`ast-grep --pattern 'functionName($$$)' --lang javascript .`
|
|
25
|
+
- **Find class definitions:**
|
|
26
|
+
`ast-grep --pattern 'class $NAME { $$$ }' --lang typescript .`
|
|
27
|
+
- **Find variable assignments:**
|
|
28
|
+
`ast-grep --pattern '$VAR = $$$' --lang ruby .`
|
|
29
|
+
- **Find import statements:**
|
|
30
|
+
`ast-grep --pattern 'import { $$$ } from "$MODULE"' --lang javascript .`
|
|
31
|
+
- **Find method calls on objects:**
|
|
32
|
+
`ast-grep --pattern '$OBJ.$METHOD($$$)' --lang typescript .`
|
|
33
|
+
- **Find React hooks:**
|
|
34
|
+
`ast-grep --pattern 'const [$STATE, $SETTER] = useState($$$)' --lang typescript .`
|
|
35
|
+
- **Find Ruby class definitions:**
|
|
36
|
+
`ast-grep --pattern 'class $NAME < $$$; $$$; end' --lang ruby .`
|
|
37
|
+
|
|
38
|
+
## Pattern Syntax Reference
|
|
39
|
+
|
|
40
|
+
- `$VAR` — matches any single node and captures it
|
|
41
|
+
- `$$$` — matches zero or more nodes (wildcard)
|
|
42
|
+
- `$$` — matches one or more nodes
|
|
43
|
+
- Literal code — matches exactly as written
|
|
44
|
+
|
|
45
|
+
## Supported Languages
|
|
46
|
+
|
|
47
|
+
- javascript, typescript, ruby, python, go, rust, java, c, cpp, html, css, yaml, json, and more
|
|
48
|
+
|
|
49
|
+
## Integration Workflow
|
|
50
|
+
|
|
51
|
+
### Before using ast-grep
|
|
52
|
+
|
|
53
|
+
1. **Check if ast-grep is installed:**
|
|
54
|
+
If not, skip and fall back to regex/semantic search.
|
|
55
|
+
|
|
56
|
+
```sh
|
|
57
|
+
command -v ast-grep >/dev/null 2>&1 || echo "ast-grep not installed, skipping AST search"
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
2. **Identify** if the task involves structural code patterns or language-aware refactoring.
|
|
61
|
+
3. **Determine** the appropriate language(s) to search.
|
|
62
|
+
4. **Construct** the pattern using ast-grep syntax.
|
|
63
|
+
5. **Run** ast-grep to gather precise structural information.
|
|
64
|
+
6. **Use** results to inform code edits, refactoring, or further analysis.
|
|
65
|
+
|
|
66
|
+
### Example Workflow
|
|
67
|
+
|
|
68
|
+
When asked to "find all Ruby service objects that call `perform`":
|
|
69
|
+
|
|
70
|
+
1. **Check for ast-grep:**
|
|
71
|
+
|
|
72
|
+
```sh
|
|
73
|
+
command -v ast-grep >/dev/null 2>&1 && ast-grep --pattern 'perform($$$)' --lang ruby app/services/
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
2. **Analyze** results structurally.
|
|
77
|
+
3. **Use** codebase semantic search for additional context if needed.
|
|
78
|
+
4. **Make** informed edits based on structural understanding.
|
|
79
|
+
|
|
80
|
+
### Combine ast-grep with Internal Tools
|
|
81
|
+
|
|
82
|
+
- **codebase_search** for semantic context and documentation
|
|
83
|
+
- **read_file** for examining specific files found by ast-grep
|
|
84
|
+
- **edit_file** for making precise, context-aware code changes
|
|
85
|
+
|
|
86
|
+
### Advanced Usage
|
|
87
|
+
|
|
88
|
+
- **JSON output for programmatic processing:**
|
|
89
|
+
`ast-grep --pattern '$PATTERN' --lang $LANG $PATH --json`
|
|
90
|
+
- **Replace patterns:**
|
|
91
|
+
`ast-grep --pattern '$OLD_PATTERN' --rewrite '$NEW_PATTERN' --lang $LANG $PATH`
|
|
92
|
+
- **Interactive mode:**
|
|
93
|
+
`ast-grep --pattern '$PATTERN' --lang $LANG $PATH --interactive`
|
|
94
|
+
|
|
95
|
+
## Key Benefits Over Regex
|
|
96
|
+
|
|
97
|
+
1. **Language-aware** — understands syntax and semantics
|
|
98
|
+
2. **Structural matching** — finds patterns regardless of formatting
|
|
99
|
+
3. **Cross-language** — works consistently across different languages
|
|
100
|
+
4. **Precise refactoring** — makes structural changes safely
|
|
101
|
+
5. **Context-aware** — understands code hierarchy and scope
|
|
102
|
+
|
|
103
|
+
## Decision Matrix: When to Use Each Tool
|
|
104
|
+
|
|
105
|
+
| Task Type | Tool Choice | Reason |
|
|
106
|
+
|--------------------------|----------------------|-------------------------------|
|
|
107
|
+
| Find text patterns | grep_search | Simple text matching |
|
|
108
|
+
| Find code structures | ast-grep | Syntax-aware search |
|
|
109
|
+
| Understand semantics | codebase_search | AI-powered context |
|
|
110
|
+
| Make edits | edit_file | Precise file editing |
|
|
111
|
+
| Structural refactoring | ast-grep + edit_file | Structure + precision |
|
|
112
|
+
|
|
113
|
+
**Always prefer ast-grep for code structure analysis over regex-based approaches, but only if it is installed and available.**
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# DateTime Utility Library
|
|
3
|
+
# Provides consistent datetime operations across all scripts
|
|
4
|
+
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
# Load dependencies
|
|
8
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
9
|
+
source "${SCRIPT_DIR}/logging-utils.sh"
|
|
10
|
+
|
|
11
|
+
# Get current datetime in ISO 8601 format (UTC)
|
|
12
|
+
get_current_datetime() {
|
|
13
|
+
date -u +"%Y-%m-%dT%H:%M:%SZ"
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
# Get current date only (YYYY-MM-DD)
|
|
17
|
+
get_current_date() {
|
|
18
|
+
date -u +"%Y-%m-%d"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
# Get current timestamp (Unix epoch)
|
|
22
|
+
get_current_timestamp() {
|
|
23
|
+
date +%s
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
# Convert ISO datetime to Unix timestamp
|
|
27
|
+
datetime_to_timestamp() {
|
|
28
|
+
local iso_datetime="$1"
|
|
29
|
+
|
|
30
|
+
log_function_entry "datetime_to_timestamp" "$iso_datetime"
|
|
31
|
+
|
|
32
|
+
local timestamp
|
|
33
|
+
if command -v gdate >/dev/null 2>&1; then
|
|
34
|
+
# macOS with GNU date installed
|
|
35
|
+
timestamp=$(gdate -d "$iso_datetime" +%s 2>/dev/null)
|
|
36
|
+
else
|
|
37
|
+
# Linux date or BSD date
|
|
38
|
+
timestamp=$(date -d "$iso_datetime" +%s 2>/dev/null || date -j -f "%Y-%m-%dT%H:%M:%SZ" "$iso_datetime" +%s 2>/dev/null)
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
if [[ -z "$timestamp" ]]; then
|
|
42
|
+
log_error "Failed to parse datetime: $iso_datetime"
|
|
43
|
+
return 1
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
log_function_exit "datetime_to_timestamp"
|
|
47
|
+
echo "$timestamp"
|
|
48
|
+
return 0
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
# Convert Unix timestamp to ISO datetime
|
|
52
|
+
timestamp_to_datetime() {
|
|
53
|
+
local timestamp="$1"
|
|
54
|
+
|
|
55
|
+
log_function_entry "timestamp_to_datetime" "$timestamp"
|
|
56
|
+
|
|
57
|
+
local iso_datetime
|
|
58
|
+
iso_datetime=$(date -u -d "@$timestamp" +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || date -u -r "$timestamp" +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null)
|
|
59
|
+
|
|
60
|
+
if [[ -z "$iso_datetime" ]]; then
|
|
61
|
+
log_error "Failed to convert timestamp: $timestamp"
|
|
62
|
+
return 1
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
log_function_exit "timestamp_to_datetime"
|
|
66
|
+
echo "$iso_datetime"
|
|
67
|
+
return 0
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
# Calculate time difference in seconds between two ISO datetimes
|
|
71
|
+
datetime_diff_seconds() {
|
|
72
|
+
local datetime1="$1"
|
|
73
|
+
local datetime2="$2"
|
|
74
|
+
|
|
75
|
+
log_function_entry "datetime_diff_seconds" "$datetime1" "$datetime2"
|
|
76
|
+
|
|
77
|
+
local timestamp1 timestamp2
|
|
78
|
+
timestamp1=$(datetime_to_timestamp "$datetime1") || return 1
|
|
79
|
+
timestamp2=$(datetime_to_timestamp "$datetime2") || return 1
|
|
80
|
+
|
|
81
|
+
local diff
|
|
82
|
+
diff=$((timestamp2 - timestamp1))
|
|
83
|
+
|
|
84
|
+
log_function_exit "datetime_diff_seconds"
|
|
85
|
+
echo "$diff"
|
|
86
|
+
return 0
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
# Calculate time difference in minutes
|
|
90
|
+
datetime_diff_minutes() {
|
|
91
|
+
local datetime1="$1"
|
|
92
|
+
local datetime2="$2"
|
|
93
|
+
|
|
94
|
+
local diff_seconds
|
|
95
|
+
diff_seconds=$(datetime_diff_seconds "$datetime1" "$datetime2") || return 1
|
|
96
|
+
|
|
97
|
+
local diff_minutes
|
|
98
|
+
diff_minutes=$((diff_seconds / 60))
|
|
99
|
+
|
|
100
|
+
echo "$diff_minutes"
|
|
101
|
+
return 0
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
# Calculate time difference in hours
|
|
105
|
+
datetime_diff_hours() {
|
|
106
|
+
local datetime1="$1"
|
|
107
|
+
local datetime2="$2"
|
|
108
|
+
|
|
109
|
+
local diff_seconds
|
|
110
|
+
diff_seconds=$(datetime_diff_seconds "$datetime1" "$datetime2") || return 1
|
|
111
|
+
|
|
112
|
+
local diff_hours
|
|
113
|
+
diff_hours=$((diff_seconds / 3600))
|
|
114
|
+
|
|
115
|
+
echo "$diff_hours"
|
|
116
|
+
return 0
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
# Calculate time difference in days
|
|
120
|
+
datetime_diff_days() {
|
|
121
|
+
local datetime1="$1"
|
|
122
|
+
local datetime2="$2"
|
|
123
|
+
|
|
124
|
+
local diff_seconds
|
|
125
|
+
diff_seconds=$(datetime_diff_seconds "$datetime1" "$datetime2") || return 1
|
|
126
|
+
|
|
127
|
+
local diff_days
|
|
128
|
+
diff_days=$((diff_seconds / 86400))
|
|
129
|
+
|
|
130
|
+
echo "$diff_days"
|
|
131
|
+
return 0
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
# Check if datetime1 is before datetime2
|
|
135
|
+
datetime_is_before() {
|
|
136
|
+
local datetime1="$1"
|
|
137
|
+
local datetime2="$2"
|
|
138
|
+
|
|
139
|
+
local diff
|
|
140
|
+
diff=$(datetime_diff_seconds "$datetime1" "$datetime2") || return 1
|
|
141
|
+
|
|
142
|
+
[[ "$diff" -gt 0 ]]
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
# Check if datetime1 is after datetime2
|
|
146
|
+
datetime_is_after() {
|
|
147
|
+
local datetime1="$1"
|
|
148
|
+
local datetime2="$2"
|
|
149
|
+
|
|
150
|
+
local diff
|
|
151
|
+
diff=$(datetime_diff_seconds "$datetime1" "$datetime2") || return 1
|
|
152
|
+
|
|
153
|
+
[[ "$diff" -lt 0 ]]
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
# Format time duration in human-readable format
|
|
157
|
+
format_duration() {
|
|
158
|
+
local seconds="$1"
|
|
159
|
+
|
|
160
|
+
log_function_entry "format_duration" "$seconds"
|
|
161
|
+
|
|
162
|
+
if [[ "$seconds" -lt 60 ]]; then
|
|
163
|
+
echo "${seconds}s"
|
|
164
|
+
elif [[ "$seconds" -lt 3600 ]]; then
|
|
165
|
+
local minutes=$((seconds / 60))
|
|
166
|
+
local remaining_seconds=$((seconds % 60))
|
|
167
|
+
if [[ "$remaining_seconds" -eq 0 ]]; then
|
|
168
|
+
echo "${minutes}m"
|
|
169
|
+
else
|
|
170
|
+
echo "${minutes}m ${remaining_seconds}s"
|
|
171
|
+
fi
|
|
172
|
+
elif [[ "$seconds" -lt 86400 ]]; then
|
|
173
|
+
local hours=$((seconds / 3600))
|
|
174
|
+
local remaining_minutes=$(((seconds % 3600) / 60))
|
|
175
|
+
if [[ "$remaining_minutes" -eq 0 ]]; then
|
|
176
|
+
echo "${hours}h"
|
|
177
|
+
else
|
|
178
|
+
echo "${hours}h ${remaining_minutes}m"
|
|
179
|
+
fi
|
|
180
|
+
else
|
|
181
|
+
local days=$((seconds / 86400))
|
|
182
|
+
local remaining_hours=$(((seconds % 86400) / 3600))
|
|
183
|
+
if [[ "$remaining_hours" -eq 0 ]]; then
|
|
184
|
+
echo "${days}d"
|
|
185
|
+
else
|
|
186
|
+
echo "${days}d ${remaining_hours}h"
|
|
187
|
+
fi
|
|
188
|
+
fi
|
|
189
|
+
|
|
190
|
+
log_function_exit "format_duration"
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
# Get human-readable time ago (e.g., "2 hours ago")
|
|
194
|
+
time_ago() {
|
|
195
|
+
local past_datetime="$1"
|
|
196
|
+
local current_datetime="${2:-$(get_current_datetime)}"
|
|
197
|
+
|
|
198
|
+
log_function_entry "time_ago" "$past_datetime" "$current_datetime"
|
|
199
|
+
|
|
200
|
+
local diff_seconds
|
|
201
|
+
diff_seconds=$(datetime_diff_seconds "$past_datetime" "$current_datetime") || return 1
|
|
202
|
+
|
|
203
|
+
if [[ "$diff_seconds" -lt 0 ]]; then
|
|
204
|
+
echo "in the future"
|
|
205
|
+
return 0
|
|
206
|
+
fi
|
|
207
|
+
|
|
208
|
+
local duration
|
|
209
|
+
duration=$(format_duration "$diff_seconds")
|
|
210
|
+
|
|
211
|
+
echo "$duration ago"
|
|
212
|
+
log_function_exit "time_ago"
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
# Validate ISO datetime format
|
|
216
|
+
validate_datetime() {
|
|
217
|
+
local datetime="$1"
|
|
218
|
+
|
|
219
|
+
log_function_entry "validate_datetime" "$datetime"
|
|
220
|
+
|
|
221
|
+
# Check basic format: YYYY-MM-DDTHH:MM:SSZ
|
|
222
|
+
if [[ ! "$datetime" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$ ]]; then
|
|
223
|
+
log_error "Invalid datetime format: $datetime (expected: YYYY-MM-DDTHH:MM:SSZ)"
|
|
224
|
+
return 1
|
|
225
|
+
fi
|
|
226
|
+
|
|
227
|
+
# Try to parse it to validate
|
|
228
|
+
local timestamp
|
|
229
|
+
timestamp=$(datetime_to_timestamp "$datetime") || return 1
|
|
230
|
+
|
|
231
|
+
log_debug "Datetime validation passed: $datetime"
|
|
232
|
+
log_function_exit "validate_datetime"
|
|
233
|
+
return 0
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
# Get datetime for timezone
|
|
237
|
+
get_datetime_in_timezone() {
|
|
238
|
+
local timezone="$1"
|
|
239
|
+
|
|
240
|
+
log_function_entry "get_datetime_in_timezone" "$timezone"
|
|
241
|
+
|
|
242
|
+
local datetime
|
|
243
|
+
if command -v gdate >/dev/null 2>&1; then
|
|
244
|
+
# macOS with GNU date
|
|
245
|
+
datetime=$(TZ="$timezone" gdate +"%Y-%m-%dT%H:%M:%S%z")
|
|
246
|
+
else
|
|
247
|
+
# Linux date
|
|
248
|
+
datetime=$(TZ="$timezone" date +"%Y-%m-%dT%H:%M:%S%z")
|
|
249
|
+
fi
|
|
250
|
+
|
|
251
|
+
log_function_exit "get_datetime_in_timezone"
|
|
252
|
+
echo "$datetime"
|
|
253
|
+
return 0
|
|
254
|
+
}
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Frontmatter Utility Library
|
|
3
|
+
# Provides functions for YAML frontmatter manipulation in markdown files
|
|
4
|
+
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
# Load dependencies
|
|
8
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
9
|
+
source "${SCRIPT_DIR}/logging-utils.sh"
|
|
10
|
+
source "${SCRIPT_DIR}/datetime-utils.sh"
|
|
11
|
+
|
|
12
|
+
# Escape special characters for use in sed pattern
|
|
13
|
+
sed_escape_pattern() {
|
|
14
|
+
local str="$1"
|
|
15
|
+
# Escape characters that have special meaning in sed patterns: . * [ ] ^ $ \ /
|
|
16
|
+
printf '%s\n' "$str" | sed 's/[]\/$*.^[]/\\&/g'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
# Escape special characters for use in sed replacement
|
|
20
|
+
sed_escape_replacement() {
|
|
21
|
+
local str="$1"
|
|
22
|
+
# Escape backslashes first, then other special characters
|
|
23
|
+
# This prevents double-escaping issues
|
|
24
|
+
printf '%s\n' "$str" | sed 's/\\/\\\\/g; s/&/\\&/g; s/|/\\|/g'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
# Update or add a field in frontmatter
|
|
28
|
+
update_frontmatter_field() {
|
|
29
|
+
local file_path="$1"
|
|
30
|
+
local field_name="$2"
|
|
31
|
+
local field_value="$3"
|
|
32
|
+
|
|
33
|
+
log_function_entry "update_frontmatter_field" "$file_path" "$field_name" "$field_value"
|
|
34
|
+
|
|
35
|
+
if [[ ! -f "$file_path" ]]; then
|
|
36
|
+
log_error "File not found: $file_path"
|
|
37
|
+
return 1
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# Create backup
|
|
41
|
+
cp "$file_path" "${file_path}.bak"
|
|
42
|
+
|
|
43
|
+
# Escape field name and value for safe use in sed
|
|
44
|
+
local escaped_field_name
|
|
45
|
+
local escaped_field_value
|
|
46
|
+
escaped_field_name=$(sed_escape_pattern "$field_name")
|
|
47
|
+
escaped_field_value=$(sed_escape_replacement "$field_value")
|
|
48
|
+
|
|
49
|
+
# Check if field exists
|
|
50
|
+
if grep -q "^${field_name}:" "$file_path"; then
|
|
51
|
+
# Update existing field - delete old line and insert new one
|
|
52
|
+
# This approach avoids sed replacement string escaping issues
|
|
53
|
+
grep -v "^${escaped_field_name}:" "$file_path" > "${file_path}.tmp"
|
|
54
|
+
{
|
|
55
|
+
head -1 "${file_path}.tmp" # First --- line
|
|
56
|
+
printf '%s: %s\n' "$field_name" "$field_value" # New field value
|
|
57
|
+
tail -n +2 "${file_path}.tmp" # Rest of file
|
|
58
|
+
} > "${file_path}.tmp2" && mv "${file_path}.tmp2" "$file_path"
|
|
59
|
+
rm -f "${file_path}.tmp"
|
|
60
|
+
log_debug "Updated existing field: $field_name"
|
|
61
|
+
else
|
|
62
|
+
# Add new field after the first line of frontmatter (after opening ---)
|
|
63
|
+
# Write the new line directly to avoid variable expansion issues
|
|
64
|
+
{
|
|
65
|
+
head -1 "$file_path" # First --- line
|
|
66
|
+
printf '%s: %s\n' "$field_name" "$field_value" # New field (preserves all chars)
|
|
67
|
+
tail -n +2 "$file_path" # Rest of file
|
|
68
|
+
} > "${file_path}.tmp" && mv "${file_path}.tmp" "$file_path"
|
|
69
|
+
log_debug "Added new field: $field_name"
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
# Remove backup if operation successful
|
|
73
|
+
rm -f "${file_path}.bak"
|
|
74
|
+
|
|
75
|
+
log_function_exit "update_frontmatter_field"
|
|
76
|
+
return 0
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# Get a field value from frontmatter
|
|
80
|
+
get_frontmatter_field() {
|
|
81
|
+
local file_path="$1"
|
|
82
|
+
local field_name="$2"
|
|
83
|
+
|
|
84
|
+
log_function_entry "get_frontmatter_field" "$file_path" "$field_name"
|
|
85
|
+
|
|
86
|
+
if [[ ! -f "$file_path" ]]; then
|
|
87
|
+
log_error "File not found: $file_path"
|
|
88
|
+
log_function_exit "get_frontmatter_field" 1
|
|
89
|
+
return 1
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
# Escape field name for safe use in patterns
|
|
93
|
+
local escaped_field_name
|
|
94
|
+
escaped_field_name=$(sed_escape_pattern "$field_name")
|
|
95
|
+
|
|
96
|
+
local field_value
|
|
97
|
+
# Use | delimiter to avoid conflicts with / in values
|
|
98
|
+
# Only remove the field name, colon, and exactly one space (YAML format)
|
|
99
|
+
field_value=$(grep "^${field_name}:" "$file_path" | sed "s|^${escaped_field_name}: ||" | head -1)
|
|
100
|
+
|
|
101
|
+
log_debug "Retrieved field $field_name: '$field_value'"
|
|
102
|
+
log_function_exit "get_frontmatter_field"
|
|
103
|
+
|
|
104
|
+
echo "$field_value"
|
|
105
|
+
return 0
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
# Strip frontmatter from file and output content only
|
|
109
|
+
strip_frontmatter() {
|
|
110
|
+
local input_file="$1"
|
|
111
|
+
local output_file="$2"
|
|
112
|
+
|
|
113
|
+
log_function_entry "strip_frontmatter" "$input_file" "$output_file"
|
|
114
|
+
|
|
115
|
+
if [[ ! -f "$input_file" ]]; then
|
|
116
|
+
log_error "Input file not found: $input_file"
|
|
117
|
+
return 1
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
# Remove frontmatter (everything between first two --- lines)
|
|
121
|
+
sed '1,/^---$/d; 1,/^---$/d' "$input_file" > "$output_file"
|
|
122
|
+
|
|
123
|
+
log_debug "Stripped frontmatter from $input_file to $output_file"
|
|
124
|
+
log_function_exit "strip_frontmatter"
|
|
125
|
+
return 0
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
# Update multiple frontmatter fields with current timestamp
|
|
129
|
+
update_frontmatter_with_timestamp() {
|
|
130
|
+
local file_path="$1"
|
|
131
|
+
shift
|
|
132
|
+
local current_timestamp
|
|
133
|
+
current_timestamp=$(get_current_datetime)
|
|
134
|
+
|
|
135
|
+
log_function_entry "update_frontmatter_with_timestamp" "$file_path" "$*"
|
|
136
|
+
|
|
137
|
+
# Update each field=value pair provided
|
|
138
|
+
while [[ $# -gt 0 ]]; do
|
|
139
|
+
local field_assignment="$1"
|
|
140
|
+
local field_name="${field_assignment%%=*}"
|
|
141
|
+
local field_value="${field_assignment#*=}"
|
|
142
|
+
|
|
143
|
+
# Special handling for timestamp fields
|
|
144
|
+
if [[ "$field_value" == "NOW" ]]; then
|
|
145
|
+
field_value="$current_timestamp"
|
|
146
|
+
fi
|
|
147
|
+
|
|
148
|
+
update_frontmatter_field "$file_path" "$field_name" "$field_value"
|
|
149
|
+
shift
|
|
150
|
+
done
|
|
151
|
+
|
|
152
|
+
# Always update the 'updated' field with current timestamp
|
|
153
|
+
update_frontmatter_field "$file_path" "updated" "$current_timestamp"
|
|
154
|
+
|
|
155
|
+
log_function_exit "update_frontmatter_with_timestamp"
|
|
156
|
+
return 0
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
# Validate frontmatter structure
|
|
160
|
+
validate_frontmatter() {
|
|
161
|
+
local file_path="$1"
|
|
162
|
+
|
|
163
|
+
log_function_entry "validate_frontmatter" "$file_path"
|
|
164
|
+
|
|
165
|
+
if [[ ! -f "$file_path" ]]; then
|
|
166
|
+
log_error "File not found: $file_path"
|
|
167
|
+
return 1
|
|
168
|
+
fi
|
|
169
|
+
|
|
170
|
+
# Check if file starts with frontmatter
|
|
171
|
+
if ! head -1 "$file_path" | grep -q "^---$"; then
|
|
172
|
+
log_error "File does not start with frontmatter: $file_path"
|
|
173
|
+
return 1
|
|
174
|
+
fi
|
|
175
|
+
|
|
176
|
+
# Check if frontmatter is properly closed
|
|
177
|
+
if ! sed -n '2,/^---$/p' "$file_path" | tail -1 | grep -q "^---$"; then
|
|
178
|
+
log_error "Frontmatter not properly closed: $file_path"
|
|
179
|
+
return 1
|
|
180
|
+
fi
|
|
181
|
+
|
|
182
|
+
log_debug "Frontmatter validation passed: $file_path"
|
|
183
|
+
log_function_exit "validate_frontmatter"
|
|
184
|
+
return 0
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
# Extract frontmatter only (without content)
|
|
188
|
+
extract_frontmatter() {
|
|
189
|
+
local input_file="$1"
|
|
190
|
+
local output_file="$2"
|
|
191
|
+
|
|
192
|
+
log_function_entry "extract_frontmatter" "$input_file" "$output_file"
|
|
193
|
+
|
|
194
|
+
if [[ ! -f "$input_file" ]]; then
|
|
195
|
+
log_error "Input file not found: $input_file"
|
|
196
|
+
return 1
|
|
197
|
+
fi
|
|
198
|
+
|
|
199
|
+
# Extract everything from first --- to second ---
|
|
200
|
+
sed -n '1,/^---$/p; /^---$/q' "$input_file" > "$output_file"
|
|
201
|
+
|
|
202
|
+
log_debug "Extracted frontmatter from $input_file to $output_file"
|
|
203
|
+
log_function_exit "extract_frontmatter"
|
|
204
|
+
return 0
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
# Get all frontmatter fields as key=value pairs
|
|
208
|
+
get_all_frontmatter_fields() {
|
|
209
|
+
local file_path="$1"
|
|
210
|
+
|
|
211
|
+
log_function_entry "get_all_frontmatter_fields" "$file_path"
|
|
212
|
+
|
|
213
|
+
if [[ ! -f "$file_path" ]]; then
|
|
214
|
+
log_error "File not found: $file_path"
|
|
215
|
+
return 1
|
|
216
|
+
fi
|
|
217
|
+
|
|
218
|
+
# Extract frontmatter and parse key-value pairs
|
|
219
|
+
sed -n '2,/^---$/p' "$file_path" | sed '/^---$/d' | grep -E "^[^:]+:" | while IFS=': ' read -r key value; do
|
|
220
|
+
echo "${key}=${value}"
|
|
221
|
+
done
|
|
222
|
+
|
|
223
|
+
log_function_exit "get_all_frontmatter_fields"
|
|
224
|
+
return 0
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
# Calculate completion percentage for epic based on task statuses
|
|
228
|
+
calculate_epic_progress() {
|
|
229
|
+
local epic_dir="$1"
|
|
230
|
+
|
|
231
|
+
log_function_entry "calculate_epic_progress" "$epic_dir"
|
|
232
|
+
|
|
233
|
+
if [[ ! -d "$epic_dir" ]]; then
|
|
234
|
+
log_error "Epic directory not found: $epic_dir"
|
|
235
|
+
return 1
|
|
236
|
+
fi
|
|
237
|
+
|
|
238
|
+
local total_tasks=0
|
|
239
|
+
local completed_tasks=0
|
|
240
|
+
|
|
241
|
+
# Count all task files (numbered .md files)
|
|
242
|
+
for task_file in "$epic_dir"/[0-9]*.md; do
|
|
243
|
+
[[ -f "$task_file" ]] || continue
|
|
244
|
+
total_tasks=$((total_tasks + 1))
|
|
245
|
+
|
|
246
|
+
# Check if task is completed
|
|
247
|
+
local status
|
|
248
|
+
status=$(get_frontmatter_field "$task_file" "status" 2>/dev/null || echo "open")
|
|
249
|
+
if [[ "$status" == "closed" || "$status" == "completed" ]]; then
|
|
250
|
+
completed_tasks=$((completed_tasks + 1))
|
|
251
|
+
fi
|
|
252
|
+
done
|
|
253
|
+
|
|
254
|
+
if [[ "$total_tasks" -eq 0 ]]; then
|
|
255
|
+
echo "0"
|
|
256
|
+
log_function_exit "calculate_epic_progress"
|
|
257
|
+
return 0
|
|
258
|
+
fi
|
|
259
|
+
|
|
260
|
+
# Calculate percentage
|
|
261
|
+
local progress
|
|
262
|
+
progress=$(( (completed_tasks * 100) / total_tasks ))
|
|
263
|
+
|
|
264
|
+
log_debug "Epic progress: $completed_tasks/$total_tasks = $progress%"
|
|
265
|
+
log_function_exit "calculate_epic_progress"
|
|
266
|
+
|
|
267
|
+
echo "$progress"
|
|
268
|
+
return 0
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
# Update epic progress based on task completion
|
|
272
|
+
update_epic_progress() {
|
|
273
|
+
local epic_file="$1"
|
|
274
|
+
local epic_dir="$(dirname "$epic_file")"
|
|
275
|
+
|
|
276
|
+
log_function_entry "update_epic_progress" "$epic_file"
|
|
277
|
+
|
|
278
|
+
local current_progress
|
|
279
|
+
current_progress=$(calculate_epic_progress "$epic_dir")
|
|
280
|
+
|
|
281
|
+
# Update epic frontmatter with calculated progress
|
|
282
|
+
update_frontmatter_field "$epic_file" "progress" "${current_progress}%"
|
|
283
|
+
|
|
284
|
+
# Update status based on progress
|
|
285
|
+
if [[ "$current_progress" -eq 100 ]]; then
|
|
286
|
+
update_frontmatter_field "$epic_file" "status" "completed"
|
|
287
|
+
elif [[ "$current_progress" -gt 0 ]]; then
|
|
288
|
+
update_frontmatter_field "$epic_file" "status" "in-progress"
|
|
289
|
+
fi
|
|
290
|
+
|
|
291
|
+
log_success "Updated epic progress to ${current_progress}%"
|
|
292
|
+
log_function_exit "update_epic_progress"
|
|
293
|
+
return 0
|
|
294
|
+
}
|