cc-devflow 4.3.0 → 4.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/skills/cc-act/CHANGELOG.md +70 -0
- package/.claude/skills/cc-act/PLAYBOOK.md +212 -0
- package/.claude/skills/cc-act/SKILL.md +330 -0
- package/.claude/skills/cc-act/assets/PR_BRIEF_TEMPLATE.md +68 -0
- package/.claude/skills/cc-act/assets/RELEASE_NOTE_TEMPLATE.md +29 -0
- package/.claude/skills/cc-act/references/closure-contract.md +49 -0
- package/.claude/skills/cc-act/references/git-commit-guidelines.md +83 -0
- package/.claude/skills/cc-act/scripts/archive-requirement.sh +49 -0
- package/.claude/skills/cc-act/scripts/cc-act-common.sh +245 -0
- package/.claude/skills/cc-act/scripts/detect-ship-target.sh +82 -0
- package/.claude/skills/cc-act/scripts/generate-status-report.sh +83 -0
- package/.claude/skills/cc-act/scripts/render-pr-brief.sh +200 -0
- package/.claude/skills/cc-act/scripts/sync-act-docs.sh +328 -0
- package/.claude/skills/cc-act/scripts/verify-act-gate.sh +63 -0
- package/.claude/skills/cc-check/CHANGELOG.md +78 -0
- package/.claude/skills/cc-check/PLAYBOOK.md +153 -0
- package/.claude/skills/cc-check/SKILL.md +353 -0
- package/.claude/skills/cc-check/assets/REPORT_CARD_TEMPLATE.json +53 -0
- package/.claude/skills/cc-check/references/gate-contract.md +29 -0
- package/.claude/skills/cc-check/references/review-contract.md +45 -0
- package/.claude/skills/cc-check/scripts/render-report-card.js +229 -0
- package/.claude/skills/cc-check/scripts/run-quality-gates.sh +86 -0
- package/.claude/skills/cc-check/scripts/verify-gate.sh +57 -0
- package/.claude/skills/cc-do/CHANGELOG.md +54 -0
- package/.claude/skills/cc-do/PLAYBOOK.md +119 -0
- package/.claude/skills/cc-do/SKILL.md +224 -0
- package/.claude/skills/cc-do/references/execution-recovery.md +86 -0
- package/.claude/skills/cc-do/references/parallel-dispatch.md +80 -0
- package/.claude/skills/cc-do/scripts/build-task-context.sh +184 -0
- package/.claude/skills/cc-do/scripts/cc-do-common.sh +79 -0
- package/.claude/skills/cc-do/scripts/check-task-status.sh +92 -0
- package/.claude/skills/cc-do/scripts/detect-file-conflicts.sh +87 -0
- package/.claude/skills/cc-do/scripts/mark-task-complete.sh +119 -0
- package/.claude/skills/cc-do/scripts/record-review-decision.sh +89 -0
- package/.claude/skills/cc-do/scripts/recover-workflow.sh +84 -0
- package/.claude/skills/cc-do/scripts/run-problem-analysis.sh +70 -0
- package/.claude/skills/cc-do/scripts/select-ready-tasks.sh +135 -0
- package/.claude/skills/cc-do/scripts/verify-task-gates.sh +94 -0
- package/.claude/skills/cc-do/scripts/write-task-checkpoint.sh +102 -0
- package/.claude/skills/cc-investigate/CHANGELOG.md +31 -0
- package/.claude/skills/cc-investigate/PLAYBOOK.md +49 -0
- package/.claude/skills/cc-investigate/SKILL.md +229 -0
- package/.claude/skills/cc-investigate/assets/ANALYSIS_TEMPLATE.md +56 -0
- package/.claude/skills/cc-investigate/assets/TASKS_TEMPLATE.md +53 -0
- package/.claude/skills/cc-investigate/assets/TASK_MANIFEST_TEMPLATE.json +106 -0
- package/.claude/skills/cc-investigate/references/investigation-contract.md +28 -0
- package/.claude/skills/cc-investigate/scripts/bootstrap-analysis.sh +38 -0
- package/.claude/skills/cc-plan/CHANGELOG.md +104 -0
- package/.claude/skills/cc-plan/PLAYBOOK.md +106 -0
- package/.claude/skills/cc-plan/SKILL.md +333 -0
- package/.claude/skills/cc-plan/assets/DESIGN_TEMPLATE.md +156 -0
- package/.claude/skills/cc-plan/assets/TASKS_TEMPLATE.md +99 -0
- package/.claude/skills/cc-plan/assets/TASK_MANIFEST_TEMPLATE.json +111 -0
- package/.claude/skills/cc-plan/assets/TINY_DESIGN_TEMPLATE.md +80 -0
- package/.claude/skills/cc-plan/references/planning-contract.md +82 -0
- package/.claude/skills/cc-plan/scripts/bump-skill-version.sh +103 -0
- package/.claude/skills/cc-plan/scripts/parse-task-dependencies.js +75 -0
- package/.claude/skills/cc-plan/scripts/validate-scope.sh +78 -0
- package/.claude/skills/cc-roadmap/CHANGELOG.md +119 -0
- package/.claude/skills/cc-roadmap/PLAYBOOK.md +136 -0
- package/.claude/skills/cc-roadmap/SKILL.md +267 -0
- package/.claude/skills/cc-roadmap/assets/BACKLOG_TEMPLATE.md +46 -0
- package/.claude/skills/cc-roadmap/assets/ROADMAP_TEMPLATE.md +154 -0
- package/.claude/skills/cc-roadmap/assets/TRACKING_TEMPLATE.json +51 -0
- package/.claude/skills/cc-roadmap/references/roadmap-dialogue.md +37 -0
- package/.claude/skills/cc-roadmap/scripts/bump-skill-version.sh +103 -0
- package/.claude/skills/cc-roadmap/scripts/lib/roadmap-tracking/markdown.js +604 -0
- package/.claude/skills/cc-roadmap/scripts/lib/roadmap-tracking/query.js +63 -0
- package/.claude/skills/cc-roadmap/scripts/lib/roadmap-tracking/schema.js +245 -0
- package/.claude/skills/cc-roadmap/scripts/lib/roadmap-tracking/store.js +139 -0
- package/.claude/skills/cc-roadmap/scripts/locate-roadmap-item.sh +109 -0
- package/.claude/skills/cc-roadmap/scripts/roadmap-tracking.js +153 -0
- package/.claude/skills/cc-roadmap/scripts/sync-roadmap-progress.sh +100 -0
- package/.claude/skills/cc-simplify/CHANGELOG.md +10 -0
- package/.claude/skills/cc-simplify/SKILL.md +55 -0
- package/.claude/skills/cc-spec-init/CHANGELOG.md +12 -0
- package/.claude/skills/cc-spec-init/PLAYBOOK.md +55 -0
- package/.claude/skills/cc-spec-init/SKILL.md +135 -0
- package/.claude/skills/cc-spec-init/assets/CAPABILITY_TEMPLATE.md +64 -0
- package/.claude/skills/cc-spec-init/assets/CHANGE_META_TEMPLATE.json +28 -0
- package/.claude/skills/cc-spec-init/assets/INDEX_TEMPLATE.md +35 -0
- package/.claude/skills/cc-spec-init/references/spec-contract.md +22 -0
- package/.claude/skills/cc-spec-init/scripts/bootstrap-specs.sh +31 -0
- package/.claude/skills/cc-spec-init/scripts/validate-spec-links.sh +45 -0
- package/CHANGELOG.md +80 -4
- package/README.md +148 -741
- package/README.zh-CN.md +146 -740
- package/bin/adapt.js +2 -6
- package/bin/cc-devflow-cli.js +287 -166
- package/config/distributable-skills.json +24 -0
- package/config/schema/cc-devflow-config.schema.json +45 -0
- package/config/user-config.template.yml +16 -0
- package/docs/CLAUDE.md +10 -6
- package/docs/commands/README.md +19 -46
- package/docs/commands/README.zh-CN.md +25 -48
- package/docs/examples/BY-ARTIFACT.md +7 -0
- package/docs/examples/README.md +38 -0
- package/docs/examples/START-HERE.md +149 -0
- package/docs/examples/example-bindings.json +38 -0
- package/docs/examples/full-design-blocked/BACKLOG.md +45 -0
- package/docs/examples/full-design-blocked/README.md +55 -0
- package/docs/examples/full-design-blocked/ROADMAP.md +53 -0
- package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/planning/design.md +154 -0
- package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/planning/task-manifest.json +146 -0
- package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/planning/tasks.md +78 -0
- package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/review/report-card.json +52 -0
- package/docs/examples/full-design-blocked/roadmap-tracking.json +50 -0
- package/docs/examples/local-handoff/BACKLOG.md +45 -0
- package/docs/examples/local-handoff/README.md +56 -0
- package/docs/examples/local-handoff/ROADMAP.md +45 -0
- package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/handoff/resume-index.md +39 -0
- package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/handoff/status.md +29 -0
- package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/planning/design.md +71 -0
- package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/planning/task-manifest.json +98 -0
- package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/planning/tasks.md +59 -0
- package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/review/report-card.json +44 -0
- package/docs/examples/local-handoff/roadmap-tracking.json +48 -0
- package/docs/examples/pdca-loop/BACKLOG.md +46 -0
- package/docs/examples/pdca-loop/README.md +58 -0
- package/docs/examples/pdca-loop/ROADMAP.md +133 -0
- package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/handoff/pr-brief.md +72 -0
- package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/handoff/status.md +29 -0
- package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/planning/design.md +72 -0
- package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/planning/task-manifest.json +201 -0
- package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/planning/tasks.md +73 -0
- package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/review/report-card.json +44 -0
- package/docs/examples/pdca-loop/roadmap-tracking.json +114 -0
- package/docs/examples/scripts/check-example-bindings.sh +116 -0
- package/docs/guides/getting-started.md +94 -129
- package/docs/guides/getting-started.zh-CN.md +103 -84
- package/docs/skill-runtime-migration.md +46 -0
- package/docs/v4.3.0-migration-guide.md +60 -225
- package/lib/compiler/CLAUDE.md +55 -84
- package/lib/compiler/__tests__/drift.test.js +1 -1
- package/lib/compiler/__tests__/errors.test.js +0 -1
- package/lib/compiler/__tests__/integration.test.js +49 -3
- package/lib/compiler/__tests__/manifest.test.js +0 -156
- package/lib/compiler/__tests__/parser.test.js +33 -104
- package/lib/compiler/__tests__/schemas.test.js +30 -34
- package/lib/compiler/__tests__/skills-registry.test.js +114 -0
- package/lib/compiler/__tests__/transformer.test.js +5 -9
- package/lib/compiler/emitters/antigravity-emitter.js +5 -213
- package/lib/compiler/emitters/base-emitter.js +3 -298
- package/lib/compiler/emitters/codex-emitter.js +4 -202
- package/lib/compiler/emitters/cursor-emitter.js +3 -287
- package/lib/compiler/emitters/qwen-emitter.js +4 -176
- package/lib/compiler/index.js +65 -345
- package/lib/compiler/manifest.js +6 -68
- package/lib/compiler/parser.js +31 -63
- package/lib/compiler/platforms.js +32 -277
- package/lib/compiler/resource-copier.js +176 -6
- package/lib/compiler/rules-emitters/__tests__/antigravity-rules-emitter.test.js +3 -3
- package/lib/compiler/rules-emitters/__tests__/cursor-rules-emitter.test.js +14 -4
- package/lib/compiler/rules-emitters/__tests__/qwen-rules-emitter.test.js +16 -7
- package/lib/compiler/rules-emitters/antigravity-rules-emitter.js +10 -15
- package/lib/compiler/rules-emitters/base-rules-emitter.js +5 -5
- package/lib/compiler/rules-emitters/cursor-rules-emitter.js +7 -12
- package/lib/compiler/rules-emitters/index.js +6 -3
- package/lib/compiler/rules-emitters/qwen-rules-emitter.js +7 -7
- package/lib/compiler/schemas.js +8 -4
- package/lib/compiler/skills-registry.js +213 -15
- package/lib/compiler/transformer.js +1 -1
- package/lib/skill-runtime/CLAUDE.md +19 -0
- package/lib/skill-runtime/__tests__/autopilot.test.js +210 -0
- package/lib/skill-runtime/__tests__/cli-bootstrap.integration.test.js +291 -0
- package/lib/skill-runtime/__tests__/config.test.js +161 -0
- package/lib/skill-runtime/__tests__/delegation.test.js +97 -0
- package/lib/skill-runtime/__tests__/dispatch.test.js +267 -0
- package/lib/skill-runtime/__tests__/intent.test.js +219 -0
- package/lib/skill-runtime/__tests__/lifecycle.test.js +169 -0
- package/lib/skill-runtime/__tests__/paths.test.js +42 -0
- package/lib/skill-runtime/__tests__/planner.tdd.test.js +250 -0
- package/lib/skill-runtime/__tests__/prepare-pr.test.js +139 -0
- package/lib/skill-runtime/__tests__/query.test.js +284 -0
- package/lib/skill-runtime/__tests__/runtime.integration.test.js +281 -0
- package/lib/skill-runtime/__tests__/schemas.test.js +207 -0
- package/lib/skill-runtime/__tests__/team-state.test.js +51 -0
- package/lib/skill-runtime/__tests__/worker-run.test.js +253 -0
- package/lib/skill-runtime/__tests__/worker.test.js +56 -0
- package/lib/skill-runtime/artifacts.js +93 -0
- package/lib/skill-runtime/config.js +379 -0
- package/lib/skill-runtime/delegation.js +533 -0
- package/lib/skill-runtime/index.js +36 -0
- package/lib/skill-runtime/intent.js +333 -0
- package/lib/skill-runtime/lifecycle.js +294 -0
- package/lib/skill-runtime/operations/CLAUDE.md +19 -0
- package/lib/skill-runtime/operations/approve.js +66 -0
- package/lib/skill-runtime/operations/autopilot-core.js +337 -0
- package/lib/skill-runtime/operations/autopilot-execution.js +307 -0
- package/lib/skill-runtime/operations/autopilot-shared.js +48 -0
- package/lib/skill-runtime/operations/autopilot.js +163 -0
- package/lib/skill-runtime/operations/dispatch.js +454 -0
- package/lib/skill-runtime/operations/init.js +64 -0
- package/lib/{harness → skill-runtime}/operations/janitor.js +9 -6
- package/lib/skill-runtime/operations/plan.js +59 -0
- package/lib/skill-runtime/operations/prepare-pr.js +25 -0
- package/lib/skill-runtime/operations/release.js +96 -0
- package/lib/skill-runtime/operations/resume.js +143 -0
- package/lib/skill-runtime/operations/snapshot.js +45 -0
- package/lib/skill-runtime/operations/verify.js +170 -0
- package/lib/skill-runtime/operations/worker-run.js +529 -0
- package/lib/skill-runtime/operations/worker.js +33 -0
- package/lib/skill-runtime/paths.js +213 -0
- package/lib/skill-runtime/planner.js +519 -0
- package/lib/skill-runtime/query.js +157 -0
- package/lib/skill-runtime/review.js +557 -0
- package/lib/skill-runtime/schemas.js +400 -0
- package/lib/{harness → skill-runtime}/store.js +45 -30
- package/lib/skill-runtime/team-state.js +122 -0
- package/package.json +13 -11
- package/.claude/CLAUDE.md +0 -125
- package/.claude/agents/architecture-designer.md +0 -443
- package/.claude/agents/bug-analyzer.md +0 -381
- package/.claude/agents/checklist-agent.md +0 -175
- package/.claude/agents/clarify-analyst.md +0 -50
- package/.claude/agents/code-quality-reviewer.md +0 -205
- package/.claude/agents/code-reviewer.md +0 -71
- package/.claude/agents/codex-analyzer.md +0 -39
- package/.claude/agents/compatibility-checker.md +0 -579
- package/.claude/agents/consistency-checker.md +0 -532
- package/.claude/agents/dev-implementer.md +0 -195
- package/.claude/agents/flow-researcher.md +0 -132
- package/.claude/agents/impact-analyzer.md +0 -440
- package/.claude/agents/planner.md +0 -230
- package/.claude/agents/prd-writer.md +0 -320
- package/.claude/agents/project-guidelines-generator.md +0 -1329
- package/.claude/agents/qa-tester.md +0 -313
- package/.claude/agents/release-manager.md +0 -295
- package/.claude/agents/security-reviewer.md +0 -314
- package/.claude/agents/spec-reviewer.md +0 -221
- package/.claude/agents/style-guide-generator.md +0 -458
- package/.claude/agents/tech-architect.md +0 -516
- package/.claude/agents/ui-designer.md +0 -485
- package/.claude/commands/core/architecture.md +0 -459
- package/.claude/commands/core/guidelines.md +0 -511
- package/.claude/commands/core/roadmap.md +0 -468
- package/.claude/commands/core/style.md +0 -83
- package/.claude/commands/flow/CLAUDE.md +0 -24
- package/.claude/commands/flow/archive.md +0 -280
- package/.claude/commands/flow/constitution.md +0 -82
- package/.claude/commands/flow/context.md +0 -150
- package/.claude/commands/flow/delta.md +0 -245
- package/.claude/commands/flow/dev.md +0 -40
- package/.claude/commands/flow/fix.md +0 -217
- package/.claude/commands/flow/ideate.md +0 -214
- package/.claude/commands/flow/init.md +0 -38
- package/.claude/commands/flow/release.md +0 -36
- package/.claude/commands/flow/restart.md +0 -97
- package/.claude/commands/flow/spec.md +0 -36
- package/.claude/commands/flow/status.md +0 -64
- package/.claude/commands/flow/update.md +0 -111
- package/.claude/commands/flow/upgrade.md +0 -115
- package/.claude/commands/flow/verify.md +0 -37
- package/.claude/commands/flow/workspace.md +0 -155
- package/.claude/commands/util/cancel-ralph.md +0 -60
- package/.claude/commands/util/code-review.md +0 -58
- package/.claude/commands/util/git-commit.md +0 -422
- package/.claude/commands/util/problem-analyzer.md +0 -60
- package/.claude/config/quality-gates.yml +0 -305
- package/.claude/config/quality-rules.yml +0 -161
- package/.claude/docs/SPEC_KIT_CONSTITUTION_ANALYSIS.md +0 -426
- package/.claude/docs/design/consistency-conflict-detection-algorithms.md +0 -658
- package/.claude/docs/design/intent-driven-input-design.md +0 -380
- package/.claude/docs/design/prd-version-management-design.md +0 -437
- package/.claude/docs/examples/design-inspiration-pool.md +0 -59
- package/.claude/docs/examples/ui-prototype-constitution-checklist.md +0 -75
- package/.claude/docs/guides/INIT_TROUBLESHOOTING.md +0 -117
- package/.claude/docs/guides/NEW_TROUBLESHOOTING.md +0 -99
- package/.claude/docs/guides/ROADMAP_TROUBLESHOOTING.md +0 -188
- package/.claude/docs/guides/TASK_COMPLETION_MARKING.md +0 -338
- package/.claude/docs/guides/TEAM_MODE_GUIDE.md +0 -312
- package/.claude/docs/implementation-summary-v7.md +0 -449
- package/.claude/docs/spec-format-guide.md +0 -349
- package/.claude/docs/state-consolidation-design.md +0 -323
- package/.claude/docs/templates/ARCHITECTURE_TEMPLATE.md +0 -332
- package/.claude/docs/templates/ATTEMPT_TEMPLATE.md +0 -156
- package/.claude/docs/templates/BACKLOG_TEMPLATE.md +0 -261
- package/.claude/docs/templates/BRAINSTORM_TEMPLATE.md +0 -148
- package/.claude/docs/templates/CHECKLIST_TEMPLATE.md +0 -52
- package/.claude/docs/templates/CLARIFICATION_REPORT_TEMPLATE.md +0 -206
- package/.claude/docs/templates/CODE_REVIEW_TEMPLATE.md +0 -71
- package/.claude/docs/templates/DELTA_SPEC_TEMPLATE.md +0 -91
- package/.claude/docs/templates/DESIGN_DECISIONS_TEMPLATE.md +0 -151
- package/.claude/docs/templates/DESIGN_TEMPLATE.md +0 -157
- package/.claude/docs/templates/ERROR_LOG_TEMPLATE.md +0 -80
- package/.claude/docs/templates/INIT_FLOW_TEMPLATE.md +0 -198
- package/.claude/docs/templates/INTENT_CLARIFICATION_TEMPLATE.md +0 -57
- package/.claude/docs/templates/JOURNAL_TEMPLATE.md +0 -75
- package/.claude/docs/templates/NEW_ORCHESTRATION_TEMPLATE.md +0 -76
- package/.claude/docs/templates/PROPOSAL_TEMPLATE.md +0 -91
- package/.claude/docs/templates/RESEARCH_TEMPLATE.md +0 -276
- package/.claude/docs/templates/REVIEW-HIGH.md +0 -57
- package/.claude/docs/templates/ROADMAP_DIALOGUE_TEMPLATE.md +0 -198
- package/.claude/docs/templates/ROADMAP_TEMPLATE.md +0 -310
- package/.claude/docs/templates/SPEC_TEMPLATE_DELTA.md +0 -139
- package/.claude/docs/templates/SPEC_TEMPLATE_PROJECT.md +0 -93
- package/.claude/docs/templates/STYLE_TEMPLATE.md +0 -479
- package/.claude/docs/templates/UI_PROTOTYPE_TEMPLATE.md +0 -373
- package/.claude/docs/templates/_shared/CLAUDE.md +0 -36
- package/.claude/docs/templates/_shared/CONSTITUTION_CHECK.md +0 -125
- package/.claude/docs/templates/_shared/VALIDATION_CHECKLIST.md +0 -187
- package/.claude/docs/templates/_shared/YAML_FRONTMATTER.md +0 -164
- package/.claude/docs/templates/context/dev.jsonl.template +0 -6
- package/.claude/docs/templates/context/epic.jsonl.template +0 -5
- package/.claude/docs/templates/context/prd.jsonl.template +0 -4
- package/.claude/docs/templates/context/research.jsonl.template +0 -4
- package/.claude/docs/templates/context/review.jsonl.template +0 -5
- package/.claude/docs/templates/context/tech.jsonl.template +0 -5
- package/.claude/guides/agent-guides/agent-coordination-guide.md +0 -459
- package/.claude/guides/project-guidelines-system.md +0 -463
- package/.claude/guides/technical-guides/datetime-handling-guide.md +0 -563
- package/.claude/guides/technical-guides/git-github-guide.md +0 -642
- package/.claude/guides/technical-guides/test-execution-guide.md +0 -618
- package/.claude/guides/workflow-guides/bug-fix-orchestrator.md +0 -217
- package/.claude/guides/workflow-guides/flow-orchestrator.md +0 -48
- package/.claude/hooks/CLAUDE.md +0 -342
- package/.claude/hooks/checklist-gate.js +0 -397
- package/.claude/hooks/error-handling-reminder.sh +0 -12
- package/.claude/hooks/error-handling-reminder.ts +0 -459
- package/.claude/hooks/hooks.json +0 -15
- package/.claude/hooks/inject-agent-context.ts +0 -480
- package/.claude/hooks/inject-skill-context.ts +0 -359
- package/.claude/hooks/post-tool-use-tracker.sh +0 -280
- package/.claude/hooks/pre-tool-use-guardrail.sh +0 -36
- package/.claude/hooks/pre-tool-use-guardrail.ts +0 -342
- package/.claude/hooks/ralph-loop.ts +0 -931
- package/.claude/hooks/ralph-stop-hook.sh +0 -190
- package/.claude/hooks/skill-activation-prompt.sh +0 -36
- package/.claude/hooks/skill-activation-prompt.ts +0 -214
- package/.claude/hooks/state/skills-used-test-guard.json +0 -3
- package/.claude/hooks/task-completed-hook.ts +0 -593
- package/.claude/hooks/teammate-idle-hook.ts +0 -690
- package/.claude/hooks/types/team-types.d.ts +0 -238
- package/.claude/rules/devflow-conventions.md +0 -286
- package/.claude/rules/project-constitution.md +0 -1002
- package/.claude/rules/rationalization-library.md +0 -282
- package/.claude/schemas/constitution.schema.json +0 -43
- package/.claude/scripts/.claude/commands/flow/export-openspec.md +0 -221
- package/.claude/scripts/.claude/commands/flow/import-openspec.md +0 -171
- package/.claude/scripts/CLAUDE.md +0 -76
- package/.claude/scripts/__tests__/openspec.test.js +0 -212
- package/.claude/scripts/analyze-upgrade-impact.sh +0 -200
- package/.claude/scripts/archive-requirement.sh +0 -394
- package/.claude/scripts/calculate-checklist-completion.sh +0 -243
- package/.claude/scripts/calculate-quarter.sh +0 -206
- package/.claude/scripts/check-dependencies.sh +0 -409
- package/.claude/scripts/check-prerequisites.sh +0 -232
- package/.claude/scripts/check-task-status.sh +0 -288
- package/.claude/scripts/checklist-errors.sh +0 -131
- package/.claude/scripts/common.sh +0 -1102
- package/.claude/scripts/consolidate-research.sh +0 -182
- package/.claude/scripts/create-requirement.sh +0 -451
- package/.claude/scripts/delta-parser.ts +0 -637
- package/.claude/scripts/detect-file-conflicts.sh +0 -151
- package/.claude/scripts/export-contracts.sh +0 -117
- package/.claude/scripts/export-openspec.js +0 -222
- package/.claude/scripts/extract-data-model.sh +0 -78
- package/.claude/scripts/flow-context-add.sh +0 -134
- package/.claude/scripts/flow-context-init.sh +0 -133
- package/.claude/scripts/flow-context-validate.sh +0 -144
- package/.claude/scripts/flow-delta-apply.sh +0 -297
- package/.claude/scripts/flow-delta-archive.sh +0 -71
- package/.claude/scripts/flow-delta-create.sh +0 -202
- package/.claude/scripts/flow-delta-list.sh +0 -142
- package/.claude/scripts/flow-delta-status.sh +0 -235
- package/.claude/scripts/flow-quality-full.sh +0 -215
- package/.claude/scripts/flow-quality-quick.sh +0 -119
- package/.claude/scripts/flow-workspace-init.sh +0 -117
- package/.claude/scripts/flow-workspace-record.sh +0 -164
- package/.claude/scripts/generate-clarification-questions.sh +0 -377
- package/.claude/scripts/generate-clarification-report.sh +0 -463
- package/.claude/scripts/generate-quickstart.sh +0 -146
- package/.claude/scripts/generate-research-tasks.sh +0 -157
- package/.claude/scripts/generate-status-report.sh +0 -523
- package/.claude/scripts/generate-tech-analysis.sh +0 -46
- package/.claude/scripts/get-workflow-status.sh +0 -415
- package/.claude/scripts/import-openspec.js +0 -272
- package/.claude/scripts/locate-requirement-in-roadmap.sh +0 -233
- package/.claude/scripts/manage-constitution.sh +0 -602
- package/.claude/scripts/mark-task-complete.sh +0 -198
- package/.claude/scripts/parse-task-dependencies.js +0 -334
- package/.claude/scripts/populate-research-tasks.sh +0 -284
- package/.claude/scripts/record-quality-error.sh +0 -165
- package/.claude/scripts/recover-workflow.sh +0 -463
- package/.claude/scripts/run-clarify-scan.sh +0 -601
- package/.claude/scripts/run-high-review.sh +0 -62
- package/.claude/scripts/run-problem-analysis.sh +0 -68
- package/.claude/scripts/run-quality-gates.sh +0 -242
- package/.claude/scripts/setup-epic.sh +0 -173
- package/.claude/scripts/setup-ralph-loop.sh +0 -155
- package/.claude/scripts/sync-roadmap-progress.sh +0 -300
- package/.claude/scripts/sync-task-marks.sh +0 -199
- package/.claude/scripts/team-dev-init.sh +0 -319
- package/.claude/scripts/team-state-recovery.sh +0 -229
- package/.claude/scripts/test-clarify-scan.sh +0 -515
- package/.claude/scripts/update-agent-context.sh +0 -806
- package/.claude/scripts/validate-constitution.sh +0 -567
- package/.claude/scripts/validate-hooks.sh +0 -487
- package/.claude/scripts/validate-research.sh +0 -332
- package/.claude/scripts/validate-scope-boundary.sh +0 -493
- package/.claude/scripts/validate-scope.sh +0 -200
- package/.claude/scripts/verify-gate.sh +0 -269
- package/.claude/scripts/verify-setup.sh +0 -37
- package/.claude/scripts/workflow-status.ts +0 -433
- package/.claude/settings.json +0 -95
- package/.claude/skills/_reference-implementations/README.md +0 -96
- package/.claude/skills/_reference-implementations/backend-express-prisma/SKILL.md +0 -302
- package/.claude/skills/_reference-implementations/backend-express-prisma/resources/architecture-overview.md +0 -451
- package/.claude/skills/_reference-implementations/backend-express-prisma/resources/async-and-errors.md +0 -307
- package/.claude/skills/_reference-implementations/backend-express-prisma/resources/complete-examples.md +0 -638
- package/.claude/skills/_reference-implementations/backend-express-prisma/resources/configuration.md +0 -275
- package/.claude/skills/_reference-implementations/backend-express-prisma/resources/database-patterns.md +0 -224
- package/.claude/skills/_reference-implementations/backend-express-prisma/resources/middleware-guide.md +0 -213
- package/.claude/skills/_reference-implementations/backend-express-prisma/resources/routing-and-controllers.md +0 -756
- package/.claude/skills/_reference-implementations/backend-express-prisma/resources/sentry-and-monitoring.md +0 -336
- package/.claude/skills/_reference-implementations/backend-express-prisma/resources/services-and-repositories.md +0 -789
- package/.claude/skills/_reference-implementations/backend-express-prisma/resources/testing-guide.md +0 -235
- package/.claude/skills/_reference-implementations/backend-express-prisma/resources/validation-patterns.md +0 -754
- package/.claude/skills/_reference-implementations/frontend-react-mui/SKILL.md +0 -399
- package/.claude/skills/_reference-implementations/frontend-react-mui/resources/common-patterns.md +0 -331
- package/.claude/skills/_reference-implementations/frontend-react-mui/resources/complete-examples.md +0 -872
- package/.claude/skills/_reference-implementations/frontend-react-mui/resources/component-patterns.md +0 -502
- package/.claude/skills/_reference-implementations/frontend-react-mui/resources/data-fetching.md +0 -767
- package/.claude/skills/_reference-implementations/frontend-react-mui/resources/file-organization.md +0 -502
- package/.claude/skills/_reference-implementations/frontend-react-mui/resources/loading-and-error-states.md +0 -501
- package/.claude/skills/_reference-implementations/frontend-react-mui/resources/performance.md +0 -406
- package/.claude/skills/_reference-implementations/frontend-react-mui/resources/routing-guide.md +0 -364
- package/.claude/skills/_reference-implementations/frontend-react-mui/resources/styling-guide.md +0 -428
- package/.claude/skills/_reference-implementations/frontend-react-mui/resources/typescript-standards.md +0 -418
- package/.claude/skills/attention-refresh/SKILL.md +0 -170
- package/.claude/skills/brainstorming/SKILL.md +0 -161
- package/.claude/skills/cc-devflow-orchestrator/SKILL.md +0 -169
- package/.claude/skills/constitution-guardian/SKILL.md +0 -306
- package/.claude/skills/constitution-quick-ref/SKILL.md +0 -374
- package/.claude/skills/debugging/SKILL.md +0 -221
- package/.claude/skills/file-standards/SKILL.md +0 -353
- package/.claude/skills/finishing-branch/SKILL.md +0 -189
- package/.claude/skills/flow-dev/CLAUDE.md +0 -16
- package/.claude/skills/flow-dev/SKILL.md +0 -94
- package/.claude/skills/flow-dev/assets/IMPLEMENTATION_PLAN_TEMPLATE.md +0 -71
- package/.claude/skills/flow-dev/context.jsonl +0 -4
- package/.claude/skills/flow-dev/dev-implementer.jsonl +0 -8
- package/.claude/skills/flow-dev/scripts/entry-gate.sh +0 -116
- package/.claude/skills/flow-dev/scripts/exit-gate.sh +0 -101
- package/.claude/skills/flow-dev/scripts/task-orchestrator.sh +0 -106
- package/.claude/skills/flow-fix/SKILL.md +0 -105
- package/.claude/skills/flow-fix/context.jsonl +0 -6
- package/.claude/skills/flow-fix/references/bug-analyzer.md +0 -381
- package/.claude/skills/flow-init/SKILL.md +0 -105
- package/.claude/skills/flow-init/assets/BRAINSTORM_TEMPLATE.md +0 -148
- package/.claude/skills/flow-init/assets/INIT_FLOW_TEMPLATE.md +0 -198
- package/.claude/skills/flow-init/assets/RESEARCH_TEMPLATE.md +0 -276
- package/.claude/skills/flow-init/context.jsonl +0 -5
- package/.claude/skills/flow-init/references/flow-researcher.md +0 -132
- package/.claude/skills/flow-init/scripts/check-prerequisites.sh +0 -240
- package/.claude/skills/flow-init/scripts/consolidate-research.sh +0 -182
- package/.claude/skills/flow-init/scripts/create-requirement.sh +0 -404
- package/.claude/skills/flow-init/scripts/generate-research-tasks.sh +0 -157
- package/.claude/skills/flow-init/scripts/populate-research-tasks.sh +0 -284
- package/.claude/skills/flow-init/scripts/validate-research.sh +0 -340
- package/.claude/skills/flow-quality/SKILL.md +0 -98
- package/.claude/skills/flow-quality/context.jsonl +0 -6
- package/.claude/skills/flow-quality/references/code-quality-reviewer.md +0 -205
- package/.claude/skills/flow-quality/references/qa-tester.md +0 -313
- package/.claude/skills/flow-quality/references/security-reviewer.md +0 -314
- package/.claude/skills/flow-quality/references/spec-reviewer.md +0 -221
- package/.claude/skills/flow-release/SKILL.md +0 -60
- package/.claude/skills/flow-release/context.jsonl +0 -5
- package/.claude/skills/flow-release/references/release-manager.md +0 -295
- package/.claude/skills/flow-spec/CLAUDE.md +0 -17
- package/.claude/skills/flow-spec/SKILL.md +0 -102
- package/.claude/skills/flow-spec/context.jsonl +0 -5
- package/.claude/skills/flow-spec/scripts/entry-gate.sh +0 -194
- package/.claude/skills/flow-spec/scripts/exit-gate.sh +0 -244
- package/.claude/skills/flow-spec/scripts/parallel-orchestrator.sh +0 -205
- package/.claude/skills/flow-spec/scripts/team-communication.sh +0 -353
- package/.claude/skills/flow-spec/scripts/team-init.sh +0 -195
- package/.claude/skills/flow-spec/scripts/test-team-mode.sh +0 -496
- package/.claude/skills/flow-spec/team-config.json +0 -165
- package/.claude/skills/flow-verify/CLAUDE.md +0 -10
- package/.claude/skills/flow-verify/SKILL.md +0 -53
- package/.claude/skills/flow-verify/context.jsonl +0 -5
- package/.claude/skills/fractal-docs/SKILL.md +0 -45
- package/.claude/skills/journey-checker/SKILL.md +0 -199
- package/.claude/skills/journey-checker/pressure-scenarios.md +0 -164
- package/.claude/skills/receiving-review/SKILL.md +0 -153
- package/.claude/skills/skill-creator/LICENSE.txt +0 -202
- package/.claude/skills/skill-creator/SKILL.md +0 -356
- package/.claude/skills/skill-creator/references/output-patterns.md +0 -82
- package/.claude/skills/skill-creator/references/workflows.md +0 -28
- package/.claude/skills/skill-creator/scripts/init_skill.py +0 -303
- package/.claude/skills/skill-creator/scripts/package_skill.py +0 -110
- package/.claude/skills/skill-creator/scripts/quick_validate.py +0 -95
- package/.claude/skills/skill-rules.json +0 -359
- package/.claude/skills/tdd/SKILL.md +0 -218
- package/.claude/skills/tdd-enforcer/SKILL.md +0 -192
- package/.claude/skills/utility/npm-release/CLAUDE.md +0 -55
- package/.claude/skills/utility/npm-release/SKILL.md +0 -379
- package/.claude/skills/utility/npm-release/references/version-decision-guide.md +0 -134
- package/.claude/skills/utility/npm-release/scripts/atomic-version-bump.sh +0 -95
- package/.claude/skills/utility/npm-release/scripts/validate-version-sync.sh +0 -82
- package/.claude/skills/utility/npm-release/scripts/version-decision-tree.sh +0 -44
- package/.claude/skills/verification/SKILL.md +0 -158
- package/.claude/skills/workflow.yaml +0 -219
- package/.claude/tests/README.md +0 -300
- package/.claude/tests/TODO.md +0 -69
- package/.claude/tests/__pycache__/test_analyze_upgrade_impact.cpython-311-pytest-7.2.2.pyc +0 -0
- package/.claude/tests/__pycache__/test_consolidate_research.cpython-311-pytest-7.2.2.pyc +0 -0
- package/.claude/tests/__pycache__/test_export_contracts.cpython-311-pytest-7.2.2.pyc +0 -0
- package/.claude/tests/__pycache__/test_extract_data_model.cpython-311-pytest-7.2.2.pyc +0 -0
- package/.claude/tests/__pycache__/test_generate_quickstart.cpython-311-pytest-7.2.2.pyc +0 -0
- package/.claude/tests/__pycache__/test_generate_research_tasks.cpython-311-pytest-7.2.2.pyc +0 -0
- package/.claude/tests/constitution/run_all_constitution_tests.sh +0 -111
- package/.claude/tests/constitution/test_agent_assignment.sh +0 -207
- package/.claude/tests/constitution/test_article_coverage.sh +0 -201
- package/.claude/tests/constitution/test_template_completeness.sh +0 -150
- package/.claude/tests/constitution/test_version_consistency.sh +0 -120
- package/.claude/tests/fixtures/spec_delta_full.md +0 -16
- package/.claude/tests/fixtures/tasks_progress_sample.md +0 -5
- package/.claude/tests/run-all-tests.sh +0 -229
- package/.claude/tests/scripts/run.sh +0 -30
- package/.claude/tests/scripts/test-framework.sh +0 -128
- package/.claude/tests/scripts/test_check_prerequisites.sh +0 -511
- package/.claude/tests/scripts/test_check_prerequisites.sh.bak +0 -504
- package/.claude/tests/scripts/test_check_prerequisites.sh.bak2 +0 -505
- package/.claude/tests/scripts/test_check_prerequisites.sh.bak3 +0 -506
- package/.claude/tests/scripts/test_check_prerequisites.sh.bak4 +0 -507
- package/.claude/tests/scripts/test_check_prerequisites.sh.bak5 +0 -508
- package/.claude/tests/scripts/test_check_task_status.sh +0 -499
- package/.claude/tests/scripts/test_common.sh +0 -244
- package/.claude/tests/scripts/test_generate_status_report.sh +0 -71
- package/.claude/tests/scripts/test_mark_task_complete.sh +0 -441
- package/.claude/tests/scripts/test_mark_task_complete.sh.backup +0 -410
- package/.claude/tests/scripts/test_recover_workflow.sh +0 -304
- package/.claude/tests/scripts/test_setup_epic.sh +0 -437
- package/.claude/tests/scripts/test_sync_task_marks.sh +0 -196
- package/.claude/tests/scripts/test_validate_constitution.sh +0 -74
- package/.claude/tests/scripts/test_validate_research.sh +0 -462
- package/.claude/tests/slugify.bats +0 -82
- package/.claude/tests/test-framework.sh +0 -732
- package/.claude/tests/test_analyze_upgrade_impact.py +0 -34
- package/.claude/tests/test_consolidate_research.py +0 -48
- package/.claude/tests/test_export_contracts.py +0 -43
- package/.claude/tests/test_extract_data_model.py +0 -33
- package/.claude/tests/test_generate_quickstart.py +0 -50
- package/.claude/tests/test_generate_research_tasks.py +0 -52
- package/.claude/tsc-cache/70d2fc6d-2936-429b-b529-429f1aae8c88/affected-repos.txt +0 -1
- package/.claude/tsc-cache/70d2fc6d-2936-429b-b529-429f1aae8c88/edited-files.log +0 -2
- package/bin/harness.js +0 -22
- package/docs/commands/core-roadmap.md +0 -106
- package/docs/commands/core-roadmap.zh-CN.md +0 -102
- package/docs/commands/core-style.md +0 -53
- package/docs/commands/core-style.zh-CN.md +0 -53
- package/docs/commands/flow-init.md +0 -140
- package/docs/commands/flow-init.zh-CN.md +0 -169
- package/docs/commands/flow-new.md +0 -39
- package/docs/commands/flow-new.zh-CN.md +0 -39
- package/lib/compiler/__tests__/compile-regression.test.js +0 -103
- package/lib/compiler/__tests__/multi-module-emitters.test.js +0 -534
- package/lib/compiler/__tests__/resource-copier.test.js +0 -26
- package/lib/compiler/__tests__/skill-discovery.test.js +0 -72
- package/lib/compiler/context-expander.js +0 -179
- package/lib/compiler/rules-emitters/__tests__/codex-rules-emitter.test.js +0 -109
- package/lib/compiler/rules-emitters/codex-rules-emitter.js +0 -116
- package/lib/compiler/skill-discovery.js +0 -68
- package/lib/harness/CLAUDE.md +0 -22
- package/lib/harness/__tests__/planner.tdd.test.js +0 -125
- package/lib/harness/cli.js +0 -208
- package/lib/harness/index.js +0 -18
- package/lib/harness/operations/dispatch.js +0 -298
- package/lib/harness/operations/init.js +0 -48
- package/lib/harness/operations/pack.js +0 -100
- package/lib/harness/operations/plan.js +0 -83
- package/lib/harness/operations/release.js +0 -170
- package/lib/harness/operations/resume.js +0 -44
- package/lib/harness/operations/verify.js +0 -177
- package/lib/harness/planner.js +0 -272
- package/lib/harness/query.js +0 -126
- package/lib/harness/schemas.js +0 -129
|
@@ -1,1102 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# Common functions and variables for cc-devflow scripts
|
|
3
|
-
# Based on spec-kit principles with cc-devflow enhancements
|
|
4
|
-
|
|
5
|
-
# =============================================================================
|
|
6
|
-
# Beijing Time Functions (统一北京时间格式)
|
|
7
|
-
# =============================================================================
|
|
8
|
-
|
|
9
|
-
# Get current Beijing time in standard format (YYYY-MM-DD HH:MM:SS)
|
|
10
|
-
# Returns: 2025-01-10 14:30:25 (周五)
|
|
11
|
-
get_beijing_time() {
|
|
12
|
-
# Convert UTC to Beijing time (UTC+8)
|
|
13
|
-
TZ='Asia/Shanghai' date '+%Y-%m-%d %H:%M:%S (%a)'
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
# Get Beijing time in ISO format (for JSON/log files)
|
|
17
|
-
# Returns: 2025-01-10T14:30:25+08:00
|
|
18
|
-
get_beijing_time_iso() {
|
|
19
|
-
TZ='Asia/Shanghai' date '+%Y-%m-%dT%H:%M:%S+08:00'
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
# Get Beijing time with Chinese day of week
|
|
23
|
-
# Returns: 2025年1月10日 星期五 14:30:25
|
|
24
|
-
get_beijing_time_full() {
|
|
25
|
-
TZ='Asia/Shanghai' date '+%Y年%m月%d日 星期%u %H:%M:%S' | sed 's/星期1/星期一/' | sed 's/星期2/星期二/' | sed 's/星期3/星期三/' | sed 's/星期4/星期四/' | sed 's/星期5/星期五/' | sed 's/星期6/星期六/' | sed 's/星期7/星期日/'
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
# Get repository root, with fallback for non-git repositories
|
|
29
|
-
get_repo_root() {
|
|
30
|
-
if git rev-parse --show-toplevel >/dev/null 2>&1; then
|
|
31
|
-
git rev-parse --show-toplevel
|
|
32
|
-
else
|
|
33
|
-
# Fall back to script location for non-git repos
|
|
34
|
-
local script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
35
|
-
(cd "$script_dir/../.." && pwd)
|
|
36
|
-
fi
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
# Get current requirement ID from environment, workspace, or directory scan
|
|
40
|
-
# Priority: 1. $DEVFLOW_REQ_ID 2. .current-req file 3. latest requirement dir
|
|
41
|
-
# Returns: REQ-XXX or BUG-XXX format
|
|
42
|
-
get_current_req_id() {
|
|
43
|
-
# Priority 1: Environment variable
|
|
44
|
-
if [[ -n "${DEVFLOW_REQ_ID:-}" ]]; then
|
|
45
|
-
echo "$DEVFLOW_REQ_ID"
|
|
46
|
-
return
|
|
47
|
-
fi
|
|
48
|
-
|
|
49
|
-
# Priority 2: Workspace .current-req file
|
|
50
|
-
local repo_root=$(get_repo_root)
|
|
51
|
-
local current_req_file="$repo_root/devflow/workspace/.current-req"
|
|
52
|
-
if [[ -f "$current_req_file" ]]; then
|
|
53
|
-
local req_from_file
|
|
54
|
-
req_from_file=$(cat "$current_req_file" 2>/dev/null | tr -d '[:space:]')
|
|
55
|
-
if [[ "$req_from_file" =~ ^(REQ|BUG)-[0-9]+(-[0-9]+)?$ ]]; then
|
|
56
|
-
echo "$req_from_file"
|
|
57
|
-
return
|
|
58
|
-
fi
|
|
59
|
-
fi
|
|
60
|
-
|
|
61
|
-
# Priority 3: Latest requirement directory scan
|
|
62
|
-
local req_dir="$repo_root/devflow/requirements"
|
|
63
|
-
|
|
64
|
-
if [[ -d "$req_dir" ]]; then
|
|
65
|
-
local latest_req=""
|
|
66
|
-
local highest=0
|
|
67
|
-
|
|
68
|
-
for dir in "$req_dir"/REQ-* "$req_dir"/BUG-*; do
|
|
69
|
-
if [[ -d "$dir" ]]; then
|
|
70
|
-
local dirname=$(basename "$dir")
|
|
71
|
-
# Match full requirement ID including extended formats like REQ-20251006-001
|
|
72
|
-
if [[ "$dirname" =~ ^(REQ-[0-9]+-[0-9]+|REQ-[0-9]+|BUG-[0-9]+-[0-9]+|BUG-[0-9]+) ]]; then
|
|
73
|
-
local full_id="${BASH_REMATCH[1]}"
|
|
74
|
-
# Extract the first number for comparison
|
|
75
|
-
if [[ "$full_id" =~ (REQ|BUG)-([0-9]+) ]]; then
|
|
76
|
-
local prefix="${BASH_REMATCH[1]}"
|
|
77
|
-
local number="${BASH_REMATCH[2]}"
|
|
78
|
-
number=$((10#$number))
|
|
79
|
-
if [[ "$number" -gt "$highest" ]]; then
|
|
80
|
-
highest=$number
|
|
81
|
-
latest_req="$full_id"
|
|
82
|
-
fi
|
|
83
|
-
fi
|
|
84
|
-
fi
|
|
85
|
-
fi
|
|
86
|
-
done
|
|
87
|
-
|
|
88
|
-
if [[ -n "$latest_req" ]]; then
|
|
89
|
-
echo "$latest_req"
|
|
90
|
-
return
|
|
91
|
-
fi
|
|
92
|
-
fi
|
|
93
|
-
|
|
94
|
-
echo "" # No requirement ID found
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
next_available_req_id() {
|
|
98
|
-
local repo_root="${1:-$(get_repo_root)}"
|
|
99
|
-
ensure_devflow_dir "$repo_root"
|
|
100
|
-
local requirements_dir="$repo_root/devflow/requirements"
|
|
101
|
-
local used_numbers="" width=3 candidate=1
|
|
102
|
-
local nullglob_state
|
|
103
|
-
nullglob_state=$(shopt -p nullglob)
|
|
104
|
-
shopt -s nullglob
|
|
105
|
-
for path in "$requirements_dir"/REQ-*; do
|
|
106
|
-
[[ -d "$path" ]] || continue
|
|
107
|
-
local name=$(basename "$path")
|
|
108
|
-
[[ "$name" =~ ^REQ-([0-9]+)$ ]] || continue
|
|
109
|
-
local value=$((10#${BASH_REMATCH[1]}))
|
|
110
|
-
used_numbers+=" $value"
|
|
111
|
-
done
|
|
112
|
-
eval "$nullglob_state"
|
|
113
|
-
while [[ " $used_numbers " == *" $candidate "* ]]; do
|
|
114
|
-
candidate=$((candidate + 1))
|
|
115
|
-
done
|
|
116
|
-
printf "REQ-%0*d\n" "$width" "$candidate"
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
req_id_in_use() {
|
|
120
|
-
local repo_root="$1"
|
|
121
|
-
local req_id="$2"
|
|
122
|
-
local req_dir
|
|
123
|
-
req_dir=$(get_req_dir "$repo_root" "$req_id")
|
|
124
|
-
[[ -d "$req_dir" ]]
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
# Check if we have git available
|
|
128
|
-
has_git() {
|
|
129
|
-
git rev-parse --show-toplevel >/dev/null 2>&1
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
# Validate requirement ID format
|
|
133
|
-
# Args: $1 - requirement ID to validate
|
|
134
|
-
# Returns: 0 if valid, 1 if invalid
|
|
135
|
-
validate_req_id() {
|
|
136
|
-
local req_id="$1"
|
|
137
|
-
|
|
138
|
-
if [[ -z "$req_id" ]]; then
|
|
139
|
-
echo "ERROR: Requirement ID cannot be empty" >&2
|
|
140
|
-
return 1
|
|
141
|
-
fi
|
|
142
|
-
|
|
143
|
-
# Support both simple (REQ-123) and extended (REQ-20251006-001) formats
|
|
144
|
-
if [[ ! "$req_id" =~ ^(REQ|BUG)-[0-9]+(-[0-9]+)?$ ]]; then
|
|
145
|
-
echo "ERROR: Invalid requirement ID format: $req_id" >&2
|
|
146
|
-
echo "Expected format: REQ-XXX or REQ-YYYYMMDD-XXX (e.g., REQ-123 or REQ-20251006-001)" >&2
|
|
147
|
-
return 1
|
|
148
|
-
fi
|
|
149
|
-
|
|
150
|
-
return 0
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
# Get requirement type from ID
|
|
154
|
-
# Args: $1 - requirement ID
|
|
155
|
-
# Returns: "requirement" or "bug"
|
|
156
|
-
get_req_type() {
|
|
157
|
-
local req_id="$1"
|
|
158
|
-
if [[ "$req_id" =~ ^REQ- ]]; then
|
|
159
|
-
echo "requirement"
|
|
160
|
-
elif [[ "$req_id" =~ ^BUG- ]]; then
|
|
161
|
-
echo "bug"
|
|
162
|
-
else
|
|
163
|
-
echo "unknown"
|
|
164
|
-
fi
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
# Ensure devflow directory structure exists
|
|
168
|
-
# Args: $1 - repo root
|
|
169
|
-
ensure_devflow_dir() {
|
|
170
|
-
local repo_root="$1"
|
|
171
|
-
local devflow_dir="$repo_root/devflow"
|
|
172
|
-
|
|
173
|
-
mkdir -p "$devflow_dir/requirements"
|
|
174
|
-
mkdir -p "$devflow_dir/bugs"
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
# =============================================================================
|
|
178
|
-
# Chinese to Pinyin Conversion (REQ-003)
|
|
179
|
-
# =============================================================================
|
|
180
|
-
|
|
181
|
-
# Internal helper: Convert Chinese characters to pinyin using pypinyin
|
|
182
|
-
# Args: $1 - input string containing Chinese characters
|
|
183
|
-
# Returns: string with Chinese replaced by pinyin, other chars unchanged
|
|
184
|
-
# Side effects: Outputs warning to stderr if pypinyin not installed
|
|
185
|
-
_chinese_to_pinyin() {
|
|
186
|
-
local input="$1"
|
|
187
|
-
|
|
188
|
-
# Check pypinyin availability
|
|
189
|
-
if ! python3 -c "import pypinyin" 2>/dev/null; then
|
|
190
|
-
echo "Warning: pypinyin not installed. Chinese characters cannot be converted." >&2
|
|
191
|
-
echo "Install: pip install pypinyin" >&2
|
|
192
|
-
echo "$input"
|
|
193
|
-
return
|
|
194
|
-
fi
|
|
195
|
-
|
|
196
|
-
# Convert Chinese to pinyin, preserve other characters
|
|
197
|
-
# Use lazy_pinyin on full text for better polyphone handling (phrase-aware)
|
|
198
|
-
python3 -c "
|
|
199
|
-
from pypinyin import lazy_pinyin
|
|
200
|
-
import sys
|
|
201
|
-
import re
|
|
202
|
-
|
|
203
|
-
text = sys.argv[1]
|
|
204
|
-
|
|
205
|
-
# Extract consecutive Chinese chunks and convert them together
|
|
206
|
-
# This allows pypinyin to use phrase dictionary for polyphones
|
|
207
|
-
result = []
|
|
208
|
-
chinese_buffer = ''
|
|
209
|
-
non_chinese_buffer = ''
|
|
210
|
-
|
|
211
|
-
for char in text:
|
|
212
|
-
if re.match(r'[\u4e00-\u9fff]', char):
|
|
213
|
-
if non_chinese_buffer:
|
|
214
|
-
result.append(non_chinese_buffer)
|
|
215
|
-
non_chinese_buffer = ''
|
|
216
|
-
chinese_buffer += char
|
|
217
|
-
else:
|
|
218
|
-
if chinese_buffer:
|
|
219
|
-
# Convert accumulated Chinese as a phrase, space-separated
|
|
220
|
-
pinyin_list = lazy_pinyin(chinese_buffer)
|
|
221
|
-
result.append(' '.join(pinyin_list))
|
|
222
|
-
chinese_buffer = ''
|
|
223
|
-
non_chinese_buffer += char
|
|
224
|
-
|
|
225
|
-
# Flush remaining buffers
|
|
226
|
-
if chinese_buffer:
|
|
227
|
-
pinyin_list = lazy_pinyin(chinese_buffer)
|
|
228
|
-
result.append(' '.join(pinyin_list))
|
|
229
|
-
if non_chinese_buffer:
|
|
230
|
-
result.append(non_chinese_buffer)
|
|
231
|
-
|
|
232
|
-
# Join with space only between Chinese pinyin blocks and other content
|
|
233
|
-
print(' '.join(result))
|
|
234
|
-
" "$input"
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
# Convert arbitrary text to a lowercase slug (branch/task naming helper)
|
|
238
|
-
# Examples:
|
|
239
|
-
# slugify "Add User Login" => "add-user-login"
|
|
240
|
-
# slugify "SAML/OIDC" => "saml-oidc"
|
|
241
|
-
# slugify "用户登录" => "yong-hu-deng-lu" (REQ-003: Chinese to pinyin)
|
|
242
|
-
slugify() {
|
|
243
|
-
local input="$1"
|
|
244
|
-
if [[ -z "$input" ]]; then
|
|
245
|
-
echo ""
|
|
246
|
-
return
|
|
247
|
-
fi
|
|
248
|
-
|
|
249
|
-
local result="$input"
|
|
250
|
-
|
|
251
|
-
# REQ-003: Check for Chinese characters (Unicode range \u4e00-\u9fff)
|
|
252
|
-
# Use Python for cross-platform compatibility (macOS grep lacks -P)
|
|
253
|
-
if python3 -c "import sys,re; sys.exit(0 if re.search(r'[\u4e00-\u9fff]', sys.argv[1]) else 1)" "$input" 2>/dev/null; then
|
|
254
|
-
result=$(_chinese_to_pinyin "$input")
|
|
255
|
-
fi
|
|
256
|
-
|
|
257
|
-
# Convert to lowercase and replace non-alphanumeric characters with hyphen
|
|
258
|
-
local slug
|
|
259
|
-
slug=$(printf '%s' "$result" | tr '[:upper:]' '[:lower:]')
|
|
260
|
-
slug=$(printf '%s' "$slug" | sed 's/[^a-z0-9]/-/g')
|
|
261
|
-
# Collapse repeated hyphens and trim edges
|
|
262
|
-
slug=$(echo "$slug" | sed 's/-\{2,\}/-/g; s/^-//; s/-$//')
|
|
263
|
-
|
|
264
|
-
echo "$slug"
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
# =============================================================================
|
|
268
|
-
# JSON Schema 校验辅助 (轻量实现 draft-07 子集)
|
|
269
|
-
# =============================================================================
|
|
270
|
-
validate_json_schema() {
|
|
271
|
-
local json_path="$1"
|
|
272
|
-
local schema_path="$2"
|
|
273
|
-
|
|
274
|
-
python3 - "$json_path" "$schema_path" <<'PY'
|
|
275
|
-
import json
|
|
276
|
-
import sys
|
|
277
|
-
from pathlib import Path
|
|
278
|
-
|
|
279
|
-
def fail(message: str) -> None:
|
|
280
|
-
print(f"ERROR: {message}", file=sys.stderr)
|
|
281
|
-
sys.exit(1)
|
|
282
|
-
|
|
283
|
-
def ensure_type(target, expected: str, path: str) -> None:
|
|
284
|
-
mapping = {"object": dict, "array": list, "string": str}
|
|
285
|
-
python_type = mapping.get(expected)
|
|
286
|
-
if python_type is None:
|
|
287
|
-
return
|
|
288
|
-
if not isinstance(target, python_type):
|
|
289
|
-
fail(f"{path} must be {expected}")
|
|
290
|
-
|
|
291
|
-
def validate_array(node, schema, path):
|
|
292
|
-
if "minItems" in schema and len(node) < schema["minItems"]:
|
|
293
|
-
fail(f"{path} must contain at least {schema['minItems']} items")
|
|
294
|
-
if schema.get("uniqueItems") and len(set(map(json.dumps, node))) != len(node):
|
|
295
|
-
fail(f"{path} must contain unique items")
|
|
296
|
-
item_schema = schema.get("items")
|
|
297
|
-
if item_schema:
|
|
298
|
-
for idx, item in enumerate(node):
|
|
299
|
-
validate_node(item, item_schema, f"{path}[{idx}]")
|
|
300
|
-
|
|
301
|
-
def validate_object(node, schema, path):
|
|
302
|
-
properties = schema.get("properties", {})
|
|
303
|
-
required = schema.get("required", [])
|
|
304
|
-
additional = schema.get("additionalProperties", True)
|
|
305
|
-
for key in required:
|
|
306
|
-
if key not in node:
|
|
307
|
-
fail(f"{path}.{key} is required")
|
|
308
|
-
for key, value in node.items():
|
|
309
|
-
if key in properties:
|
|
310
|
-
validate_node(value, properties[key], f"{path}.{key}")
|
|
311
|
-
elif additional is False:
|
|
312
|
-
fail(f"{path}.{key} is not allowed")
|
|
313
|
-
|
|
314
|
-
def validate_node(node, schema, path: str) -> None:
|
|
315
|
-
node_type = schema.get("type")
|
|
316
|
-
if node_type:
|
|
317
|
-
ensure_type(node, node_type, path)
|
|
318
|
-
if "enum" in schema and node not in schema["enum"]:
|
|
319
|
-
fail(f"{path} must be one of {schema['enum']}")
|
|
320
|
-
if isinstance(node, str) and "minLength" in schema and len(node) < schema["minLength"]:
|
|
321
|
-
fail(f"{path} length must be >= {schema['minLength']}")
|
|
322
|
-
if isinstance(node, list):
|
|
323
|
-
validate_array(node, schema, path)
|
|
324
|
-
if isinstance(node, dict):
|
|
325
|
-
validate_object(node, schema, path)
|
|
326
|
-
|
|
327
|
-
json_path = Path(sys.argv[1])
|
|
328
|
-
schema_path = Path(sys.argv[2])
|
|
329
|
-
|
|
330
|
-
try:
|
|
331
|
-
data = json.loads(json_path.read_text(encoding="utf-8"))
|
|
332
|
-
except Exception as exc:
|
|
333
|
-
fail(f"Failed to read {json_path}: {exc}")
|
|
334
|
-
|
|
335
|
-
try:
|
|
336
|
-
schema = json.loads(schema_path.read_text(encoding="utf-8"))
|
|
337
|
-
except Exception as exc:
|
|
338
|
-
fail(f"Failed to read schema {schema_path}: {exc}")
|
|
339
|
-
|
|
340
|
-
validate_node(data, schema, "$")
|
|
341
|
-
PY
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
# Get requirement directory path
|
|
345
|
-
# Args: $1 - repo root, $2 - requirement ID
|
|
346
|
-
get_req_dir() {
|
|
347
|
-
local repo_root="$1"
|
|
348
|
-
local req_id="$2"
|
|
349
|
-
local req_type=$(get_req_type "$req_id")
|
|
350
|
-
|
|
351
|
-
# Ensure devflow directory exists
|
|
352
|
-
ensure_devflow_dir "$repo_root"
|
|
353
|
-
|
|
354
|
-
if [[ "$req_type" == "bug" ]]; then
|
|
355
|
-
echo "$repo_root/devflow/bugs/$req_id"
|
|
356
|
-
else
|
|
357
|
-
echo "$repo_root/devflow/requirements/$req_id"
|
|
358
|
-
fi
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
# Get all requirement paths for current context
|
|
362
|
-
# Outputs shell variables for sourcing with eval
|
|
363
|
-
get_requirement_paths() {
|
|
364
|
-
local repo_root=$(get_repo_root)
|
|
365
|
-
local req_id=$(get_current_req_id)
|
|
366
|
-
local has_git_repo="false"
|
|
367
|
-
|
|
368
|
-
if has_git; then
|
|
369
|
-
has_git_repo="true"
|
|
370
|
-
fi
|
|
371
|
-
|
|
372
|
-
local req_dir=$(get_req_dir "$repo_root" "$req_id")
|
|
373
|
-
local req_type=$(get_req_type "$req_id")
|
|
374
|
-
|
|
375
|
-
cat <<EOF
|
|
376
|
-
REPO_ROOT='$repo_root'
|
|
377
|
-
REQ_ID='$req_id'
|
|
378
|
-
REQ_TYPE='$req_type'
|
|
379
|
-
HAS_GIT='$has_git_repo'
|
|
380
|
-
REQ_DIR='$req_dir'
|
|
381
|
-
PRD_FILE='$req_dir/PRD.md'
|
|
382
|
-
EPIC_FILE='$req_dir/EPIC.md'
|
|
383
|
-
TASKS_DIR='$req_dir/tasks'
|
|
384
|
-
TASKS_FILE='$req_dir/TASKS.md'
|
|
385
|
-
RESEARCH_DIR='$req_dir/research'
|
|
386
|
-
TEST_PLAN_FILE='$req_dir/TEST_PLAN.md'
|
|
387
|
-
SECURITY_PLAN_FILE='$req_dir/SECURITY_PLAN.md'
|
|
388
|
-
TEST_REPORT_FILE='$req_dir/TEST_REPORT.md'
|
|
389
|
-
SECURITY_REPORT_FILE='$req_dir/SECURITY_REPORT.md'
|
|
390
|
-
RELEASE_PLAN_FILE='$req_dir/RELEASE_PLAN.md'
|
|
391
|
-
LOG_FILE='$req_dir/EXECUTION_LOG.md'
|
|
392
|
-
STATUS_FILE='$req_dir/orchestration_status.json'
|
|
393
|
-
EOF
|
|
394
|
-
|
|
395
|
-
# Add BUG-specific paths if it's a bug
|
|
396
|
-
if [[ "$req_type" == "bug" ]]; then
|
|
397
|
-
cat <<EOF
|
|
398
|
-
ANALYSIS_FILE='$req_dir/ANALYSIS.md'
|
|
399
|
-
PLAN_FILE='$req_dir/PLAN.md'
|
|
400
|
-
BUG_STATUS_FILE='$req_dir/status.json'
|
|
401
|
-
EOF
|
|
402
|
-
fi
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
# Check if file exists and display status
|
|
406
|
-
# Args: $1 - file path, $2 - display name
|
|
407
|
-
check_file() {
|
|
408
|
-
[[ -f "$1" ]] && echo " ✓ $2" || echo " ✗ $2"
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
# Check if directory exists and is not empty
|
|
412
|
-
# Args: $1 - directory path, $2 - display name
|
|
413
|
-
check_dir() {
|
|
414
|
-
[[ -d "$1" && -n $(ls -A "$1" 2>/dev/null) ]] && echo " ✓ $2" || echo " ✗ $2"
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
# Parse JSON value from key
|
|
418
|
-
# Args: $1 - json string, $2 - key
|
|
419
|
-
# Returns: value for the key
|
|
420
|
-
json_get() {
|
|
421
|
-
local json="$1"
|
|
422
|
-
local key="$2"
|
|
423
|
-
echo "$json" | grep -o "\"$key\":\"[^\"]*\"" | cut -d'"' -f4
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
# Create requirement directory structure
|
|
427
|
-
# Args: $1 - requirement ID
|
|
428
|
-
create_req_structure() {
|
|
429
|
-
local req_id="$1"
|
|
430
|
-
local repo_root=$(get_repo_root)
|
|
431
|
-
local req_dir=$(get_req_dir "$repo_root" "$req_id")
|
|
432
|
-
|
|
433
|
-
mkdir -p "$req_dir"/{research,tasks}
|
|
434
|
-
|
|
435
|
-
# Initialize empty log file
|
|
436
|
-
if [[ ! -f "$req_dir/EXECUTION_LOG.md" ]]; then
|
|
437
|
-
cat > "$req_dir/EXECUTION_LOG.md" <<EOF
|
|
438
|
-
# Execution Log: $req_id
|
|
439
|
-
|
|
440
|
-
## Created
|
|
441
|
-
$(get_beijing_time_full)
|
|
442
|
-
|
|
443
|
-
## Events
|
|
444
|
-
EOF
|
|
445
|
-
fi
|
|
446
|
-
|
|
447
|
-
# Initialize status file
|
|
448
|
-
if [[ ! -f "$req_dir/orchestration_status.json" ]]; then
|
|
449
|
-
cat > "$req_dir/orchestration_status.json" <<EOF
|
|
450
|
-
{
|
|
451
|
-
"reqId": "$req_id",
|
|
452
|
-
"status": "initialized",
|
|
453
|
-
"phase": "planning",
|
|
454
|
-
"createdAt": "$(get_beijing_time_iso)",
|
|
455
|
-
"updatedAt": "$(get_beijing_time_iso)"
|
|
456
|
-
}
|
|
457
|
-
EOF
|
|
458
|
-
fi
|
|
459
|
-
|
|
460
|
-
echo "$req_dir"
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
# Log event to execution log
|
|
464
|
-
# Args: $1 - requirement ID, $2 - event message
|
|
465
|
-
log_event() {
|
|
466
|
-
local req_id="$1"
|
|
467
|
-
local message="$2"
|
|
468
|
-
local repo_root=$(get_repo_root)
|
|
469
|
-
local req_dir=$(get_req_dir "$repo_root" "$req_id")
|
|
470
|
-
local log_file="$req_dir/EXECUTION_LOG.md"
|
|
471
|
-
|
|
472
|
-
if [[ -f "$log_file" ]]; then
|
|
473
|
-
echo "" >> "$log_file"
|
|
474
|
-
echo "### $(get_beijing_time)" >> "$log_file"
|
|
475
|
-
echo "$message" >> "$log_file"
|
|
476
|
-
fi
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
# =============================================================================
|
|
480
|
-
# Archive Functions (归档功能)
|
|
481
|
-
# =============================================================================
|
|
482
|
-
|
|
483
|
-
# Get archive directory path (按年月组织)
|
|
484
|
-
# Args: $1 - repo root, $2 - year-month (YYYY-MM, optional, defaults to current)
|
|
485
|
-
# Returns: archive directory path
|
|
486
|
-
get_archive_dir() {
|
|
487
|
-
local repo_root="$1"
|
|
488
|
-
local year_month="${2:-$(TZ='Asia/Shanghai' date '+%Y-%m')}"
|
|
489
|
-
echo "$repo_root/devflow/archive/$year_month"
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
# Check if requirement is archived
|
|
493
|
-
# Args: $1 - repo root, $2 - requirement ID
|
|
494
|
-
# Returns: 0 if archived, 1 if not
|
|
495
|
-
is_archived() {
|
|
496
|
-
local repo_root="$1"
|
|
497
|
-
local req_id="$2"
|
|
498
|
-
local archive_base="$repo_root/devflow/archive"
|
|
499
|
-
|
|
500
|
-
# 搜索所有归档月份目录
|
|
501
|
-
if [[ -d "$archive_base" ]]; then
|
|
502
|
-
for month_dir in "$archive_base"/*/; do
|
|
503
|
-
if [[ -d "${month_dir}${req_id}" ]]; then
|
|
504
|
-
return 0
|
|
505
|
-
fi
|
|
506
|
-
done
|
|
507
|
-
fi
|
|
508
|
-
return 1
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
# Find archived requirement location
|
|
512
|
-
# Args: $1 - repo root, $2 - requirement ID
|
|
513
|
-
# Returns: full path to archived requirement, or empty if not found
|
|
514
|
-
find_archived_req() {
|
|
515
|
-
local repo_root="$1"
|
|
516
|
-
local req_id="$2"
|
|
517
|
-
local archive_base="$repo_root/devflow/archive"
|
|
518
|
-
|
|
519
|
-
if [[ -d "$archive_base" ]]; then
|
|
520
|
-
for month_dir in "$archive_base"/*/; do
|
|
521
|
-
if [[ -d "${month_dir}${req_id}" ]]; then
|
|
522
|
-
echo "${month_dir}${req_id}"
|
|
523
|
-
return 0
|
|
524
|
-
fi
|
|
525
|
-
done
|
|
526
|
-
fi
|
|
527
|
-
echo ""
|
|
528
|
-
return 1
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
# List all archived requirements
|
|
532
|
-
# Args: $1 - repo root
|
|
533
|
-
# Returns: list of archived requirement IDs with their archive dates
|
|
534
|
-
list_archived_reqs() {
|
|
535
|
-
local repo_root="$1"
|
|
536
|
-
local archive_base="$repo_root/devflow/archive"
|
|
537
|
-
|
|
538
|
-
if [[ ! -d "$archive_base" ]]; then
|
|
539
|
-
echo "No archived requirements found."
|
|
540
|
-
return
|
|
541
|
-
fi
|
|
542
|
-
|
|
543
|
-
local found=false
|
|
544
|
-
for month_dir in "$archive_base"/*/; do
|
|
545
|
-
[[ -d "$month_dir" ]] || continue
|
|
546
|
-
local month=$(basename "$month_dir")
|
|
547
|
-
for req_dir in "$month_dir"*/; do
|
|
548
|
-
[[ -d "$req_dir" ]] || continue
|
|
549
|
-
local req_id=$(basename "$req_dir")
|
|
550
|
-
# 读取归档原因
|
|
551
|
-
local status_file="$req_dir/orchestration_status.json"
|
|
552
|
-
local reason="unknown"
|
|
553
|
-
if [[ -f "$status_file" ]]; then
|
|
554
|
-
reason=$(jq -r '.archivedReason // "completed"' "$status_file" 2>/dev/null)
|
|
555
|
-
fi
|
|
556
|
-
echo "$month | $req_id | $reason"
|
|
557
|
-
found=true
|
|
558
|
-
done
|
|
559
|
-
done
|
|
560
|
-
|
|
561
|
-
if [[ "$found" == "false" ]]; then
|
|
562
|
-
echo "No archived requirements found."
|
|
563
|
-
fi
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
# Get archive summary for a requirement
|
|
567
|
-
# Args: $1 - repo root, $2 - requirement ID
|
|
568
|
-
# Returns: JSON summary of archived requirement
|
|
569
|
-
get_archive_summary() {
|
|
570
|
-
local repo_root="$1"
|
|
571
|
-
local req_id="$2"
|
|
572
|
-
local archived_path=$(find_archived_req "$repo_root" "$req_id")
|
|
573
|
-
|
|
574
|
-
if [[ -z "$archived_path" ]]; then
|
|
575
|
-
echo "{\"error\": \"not_found\"}"
|
|
576
|
-
return 1
|
|
577
|
-
fi
|
|
578
|
-
|
|
579
|
-
local status_file="$archived_path/orchestration_status.json"
|
|
580
|
-
if [[ -f "$status_file" ]]; then
|
|
581
|
-
jq '{
|
|
582
|
-
reqId: .reqId,
|
|
583
|
-
title: .title,
|
|
584
|
-
status: .status,
|
|
585
|
-
archivedReason: .archivedReason,
|
|
586
|
-
archivedAt: .archivedAt,
|
|
587
|
-
archiveLocation: .archiveLocation,
|
|
588
|
-
statusBeforeArchive: .statusBeforeArchive
|
|
589
|
-
}' "$status_file"
|
|
590
|
-
else
|
|
591
|
-
echo "{\"reqId\": \"$req_id\", \"archiveLocation\": \"$archived_path\"}"
|
|
592
|
-
fi
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
# Check if requirement has deltas to archive
|
|
596
|
-
# Args: $1 - requirement directory
|
|
597
|
-
# Returns: 0 if has deltas, 1 if not
|
|
598
|
-
has_deltas_to_archive() {
|
|
599
|
-
local req_dir="$1"
|
|
600
|
-
local deltas_dir="$req_dir/deltas"
|
|
601
|
-
|
|
602
|
-
if [[ -d "$deltas_dir" ]]; then
|
|
603
|
-
local count=$(find "$deltas_dir" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | wc -l)
|
|
604
|
-
[[ $count -gt 0 ]] && return 0
|
|
605
|
-
fi
|
|
606
|
-
return 1
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
# Get delta count for a requirement
|
|
610
|
-
# Args: $1 - requirement directory
|
|
611
|
-
# Returns: number of deltas
|
|
612
|
-
get_delta_count() {
|
|
613
|
-
local req_dir="$1"
|
|
614
|
-
local deltas_dir="$req_dir/deltas"
|
|
615
|
-
|
|
616
|
-
if [[ -d "$deltas_dir" ]]; then
|
|
617
|
-
find "$deltas_dir" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | wc -l | tr -d ' '
|
|
618
|
-
else
|
|
619
|
-
echo "0"
|
|
620
|
-
fi
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
# Color output helpers
|
|
624
|
-
color_red() { echo -e "\033[0;31m$1\033[0m"; }
|
|
625
|
-
color_green() { echo -e "\033[0;32m$1\033[0m"; }
|
|
626
|
-
color_yellow() { echo -e "\033[0;33m$1\033[0m"; }
|
|
627
|
-
color_blue() { echo -e "\033[0;34m$1\033[0m"; }
|
|
628
|
-
color_bold() { echo -e "\033[1m$1\033[0m"; }
|
|
629
|
-
|
|
630
|
-
# =============================================================================
|
|
631
|
-
# Claude Team Functions (v4.7)
|
|
632
|
-
# =============================================================================
|
|
633
|
-
|
|
634
|
-
# Check if Team mode is enabled for a requirement
|
|
635
|
-
# Args: $1 - repo root, $2 - requirement ID
|
|
636
|
-
# Returns: 0 if Team mode enabled, 1 if not
|
|
637
|
-
is_team_mode_enabled() {
|
|
638
|
-
local repo_root="$1"
|
|
639
|
-
local req_id="$2"
|
|
640
|
-
local status_file
|
|
641
|
-
status_file=$(get_req_dir "$repo_root" "$req_id")/orchestration_status.json
|
|
642
|
-
|
|
643
|
-
if [[ -f "$status_file" ]]; then
|
|
644
|
-
local team_mode
|
|
645
|
-
team_mode=$(jq -r '.team.mode // empty' "$status_file" 2>/dev/null)
|
|
646
|
-
[[ -n "$team_mode" ]] && return 0
|
|
647
|
-
fi
|
|
648
|
-
return 1
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
# Initialize Team state in orchestration_status.json
|
|
652
|
-
# Args: $1 - repo root, $2 - requirement ID, $3 - team mode (sequential|parallel), $4 - lead ID
|
|
653
|
-
init_team_state() {
|
|
654
|
-
local repo_root="$1"
|
|
655
|
-
local req_id="$2"
|
|
656
|
-
local mode="${3:-parallel}"
|
|
657
|
-
local lead="${4:-team-lead}"
|
|
658
|
-
local status_file
|
|
659
|
-
status_file=$(get_req_dir "$repo_root" "$req_id")/orchestration_status.json
|
|
660
|
-
|
|
661
|
-
if [[ ! -f "$status_file" ]]; then
|
|
662
|
-
echo "ERROR: orchestration_status.json not found" >&2
|
|
663
|
-
return 1
|
|
664
|
-
fi
|
|
665
|
-
|
|
666
|
-
local now
|
|
667
|
-
now=$(get_beijing_time_iso)
|
|
668
|
-
|
|
669
|
-
# Add team state using jq
|
|
670
|
-
jq --arg mode "$mode" --arg lead "$lead" --arg now "$now" '
|
|
671
|
-
.team = {
|
|
672
|
-
mode: $mode,
|
|
673
|
-
lead: $lead,
|
|
674
|
-
teammates: [],
|
|
675
|
-
taskAssignments: {},
|
|
676
|
-
createdAt: $now,
|
|
677
|
-
updatedAt: $now
|
|
678
|
-
} |
|
|
679
|
-
.ralphLoop = {
|
|
680
|
-
enabled: true,
|
|
681
|
-
teammates: {},
|
|
682
|
-
globalIteration: 0,
|
|
683
|
-
maxIterations: 10,
|
|
684
|
-
startedAt: $now
|
|
685
|
-
}
|
|
686
|
-
' "$status_file" > "${status_file}.tmp" && mv "${status_file}.tmp" "$status_file"
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
# Add a teammate to Team state
|
|
690
|
-
# Args: $1 - repo root, $2 - requirement ID, $3 - teammate ID, $4 - role
|
|
691
|
-
add_teammate() {
|
|
692
|
-
local repo_root="$1"
|
|
693
|
-
local req_id="$2"
|
|
694
|
-
local teammate_id="$3"
|
|
695
|
-
local role="${4:-developer}"
|
|
696
|
-
local status_file
|
|
697
|
-
status_file=$(get_req_dir "$repo_root" "$req_id")/orchestration_status.json
|
|
698
|
-
|
|
699
|
-
if [[ ! -f "$status_file" ]]; then
|
|
700
|
-
echo "ERROR: orchestration_status.json not found" >&2
|
|
701
|
-
return 1
|
|
702
|
-
fi
|
|
703
|
-
|
|
704
|
-
local now
|
|
705
|
-
now=$(get_beijing_time_iso)
|
|
706
|
-
|
|
707
|
-
jq --arg id "$teammate_id" --arg role "$role" --arg now "$now" '
|
|
708
|
-
.team.teammates += [{
|
|
709
|
-
id: $id,
|
|
710
|
-
role: $role,
|
|
711
|
-
status: "idle",
|
|
712
|
-
currentTask: null,
|
|
713
|
-
completedTasks: [],
|
|
714
|
-
lastActiveAt: $now
|
|
715
|
-
}] |
|
|
716
|
-
.team.updatedAt = $now |
|
|
717
|
-
.ralphLoop.teammates[$id] = {
|
|
718
|
-
iteration: 0,
|
|
719
|
-
lastVerifyResult: "skipped"
|
|
720
|
-
}
|
|
721
|
-
' "$status_file" > "${status_file}.tmp" && mv "${status_file}.tmp" "$status_file"
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
# Update teammate status
|
|
725
|
-
# Args: $1 - repo root, $2 - requirement ID, $3 - teammate ID, $4 - status, $5 - current task (optional)
|
|
726
|
-
update_teammate_status() {
|
|
727
|
-
local repo_root="$1"
|
|
728
|
-
local req_id="$2"
|
|
729
|
-
local teammate_id="$3"
|
|
730
|
-
local status="$4"
|
|
731
|
-
local current_task="${5:-null}"
|
|
732
|
-
local status_file
|
|
733
|
-
status_file=$(get_req_dir "$repo_root" "$req_id")/orchestration_status.json
|
|
734
|
-
|
|
735
|
-
if [[ ! -f "$status_file" ]]; then
|
|
736
|
-
echo "ERROR: orchestration_status.json not found" >&2
|
|
737
|
-
return 1
|
|
738
|
-
fi
|
|
739
|
-
|
|
740
|
-
local now
|
|
741
|
-
now=$(get_beijing_time_iso)
|
|
742
|
-
|
|
743
|
-
# Handle null vs string for current_task
|
|
744
|
-
if [[ "$current_task" == "null" ]]; then
|
|
745
|
-
jq --arg id "$teammate_id" --arg status "$status" --arg now "$now" '
|
|
746
|
-
(.team.teammates[] | select(.id == $id)) |= (
|
|
747
|
-
.status = $status |
|
|
748
|
-
.currentTask = null |
|
|
749
|
-
.lastActiveAt = $now
|
|
750
|
-
) |
|
|
751
|
-
.team.updatedAt = $now
|
|
752
|
-
' "$status_file" > "${status_file}.tmp" && mv "${status_file}.tmp" "$status_file"
|
|
753
|
-
else
|
|
754
|
-
jq --arg id "$teammate_id" --arg status "$status" --arg task "$current_task" --arg now "$now" '
|
|
755
|
-
(.team.teammates[] | select(.id == $id)) |= (
|
|
756
|
-
.status = $status |
|
|
757
|
-
.currentTask = $task |
|
|
758
|
-
.lastActiveAt = $now
|
|
759
|
-
) |
|
|
760
|
-
.team.updatedAt = $now
|
|
761
|
-
' "$status_file" > "${status_file}.tmp" && mv "${status_file}.tmp" "$status_file"
|
|
762
|
-
fi
|
|
763
|
-
}
|
|
764
|
-
|
|
765
|
-
# Mark task as completed by teammate
|
|
766
|
-
# Args: $1 - repo root, $2 - requirement ID, $3 - teammate ID, $4 - task ID
|
|
767
|
-
mark_teammate_task_complete() {
|
|
768
|
-
local repo_root="$1"
|
|
769
|
-
local req_id="$2"
|
|
770
|
-
local teammate_id="$3"
|
|
771
|
-
local task_id="$4"
|
|
772
|
-
local status_file
|
|
773
|
-
status_file=$(get_req_dir "$repo_root" "$req_id")/orchestration_status.json
|
|
774
|
-
|
|
775
|
-
if [[ ! -f "$status_file" ]]; then
|
|
776
|
-
echo "ERROR: orchestration_status.json not found" >&2
|
|
777
|
-
return 1
|
|
778
|
-
fi
|
|
779
|
-
|
|
780
|
-
local now
|
|
781
|
-
now=$(get_beijing_time_iso)
|
|
782
|
-
|
|
783
|
-
jq --arg id "$teammate_id" --arg task "$task_id" --arg now "$now" '
|
|
784
|
-
(.team.teammates[] | select(.id == $id)) |= (
|
|
785
|
-
.completedTasks += [$task] |
|
|
786
|
-
.currentTask = null |
|
|
787
|
-
.status = "idle" |
|
|
788
|
-
.lastActiveAt = $now
|
|
789
|
-
) |
|
|
790
|
-
.team.updatedAt = $now
|
|
791
|
-
' "$status_file" > "${status_file}.tmp" && mv "${status_file}.tmp" "$status_file"
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
# Assign task to teammate
|
|
795
|
-
# Args: $1 - repo root, $2 - requirement ID, $3 - task ID, $4 - teammate ID
|
|
796
|
-
assign_task_to_teammate() {
|
|
797
|
-
local repo_root="$1"
|
|
798
|
-
local req_id="$2"
|
|
799
|
-
local task_id="$3"
|
|
800
|
-
local teammate_id="$4"
|
|
801
|
-
local status_file
|
|
802
|
-
status_file=$(get_req_dir "$repo_root" "$req_id")/orchestration_status.json
|
|
803
|
-
|
|
804
|
-
if [[ ! -f "$status_file" ]]; then
|
|
805
|
-
echo "ERROR: orchestration_status.json not found" >&2
|
|
806
|
-
return 1
|
|
807
|
-
fi
|
|
808
|
-
|
|
809
|
-
local now
|
|
810
|
-
now=$(get_beijing_time_iso)
|
|
811
|
-
|
|
812
|
-
jq --arg task "$task_id" --arg id "$teammate_id" --arg now "$now" '
|
|
813
|
-
.team.taskAssignments[$task] = $id |
|
|
814
|
-
(.team.teammates[] | select(.id == $id)) |= (
|
|
815
|
-
.currentTask = $task |
|
|
816
|
-
.status = "working" |
|
|
817
|
-
.lastActiveAt = $now
|
|
818
|
-
) |
|
|
819
|
-
.team.updatedAt = $now
|
|
820
|
-
' "$status_file" > "${status_file}.tmp" && mv "${status_file}.tmp" "$status_file"
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
# Get teammate by ID
|
|
824
|
-
# Args: $1 - repo root, $2 - requirement ID, $3 - teammate ID
|
|
825
|
-
# Returns: JSON object of teammate state
|
|
826
|
-
get_teammate() {
|
|
827
|
-
local repo_root="$1"
|
|
828
|
-
local req_id="$2"
|
|
829
|
-
local teammate_id="$3"
|
|
830
|
-
local status_file
|
|
831
|
-
status_file=$(get_req_dir "$repo_root" "$req_id")/orchestration_status.json
|
|
832
|
-
|
|
833
|
-
if [[ ! -f "$status_file" ]]; then
|
|
834
|
-
echo "{}"
|
|
835
|
-
return 1
|
|
836
|
-
fi
|
|
837
|
-
|
|
838
|
-
jq --arg id "$teammate_id" '.team.teammates[] | select(.id == $id)' "$status_file" 2>/dev/null
|
|
839
|
-
}
|
|
840
|
-
|
|
841
|
-
# List all teammates
|
|
842
|
-
# Args: $1 - repo root, $2 - requirement ID
|
|
843
|
-
# Returns: JSON array of teammates
|
|
844
|
-
list_teammates() {
|
|
845
|
-
local repo_root="$1"
|
|
846
|
-
local req_id="$2"
|
|
847
|
-
local status_file
|
|
848
|
-
status_file=$(get_req_dir "$repo_root" "$req_id")/orchestration_status.json
|
|
849
|
-
|
|
850
|
-
if [[ ! -f "$status_file" ]]; then
|
|
851
|
-
echo "[]"
|
|
852
|
-
return 1
|
|
853
|
-
fi
|
|
854
|
-
|
|
855
|
-
jq '.team.teammates // []' "$status_file" 2>/dev/null
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
# Get unassigned tasks (tasks not in taskAssignments)
|
|
859
|
-
# Args: $1 - repo root, $2 - requirement ID
|
|
860
|
-
# Returns: List of unassigned task IDs
|
|
861
|
-
get_unassigned_tasks() {
|
|
862
|
-
local repo_root="$1"
|
|
863
|
-
local req_id="$2"
|
|
864
|
-
local req_dir
|
|
865
|
-
req_dir=$(get_req_dir "$repo_root" "$req_id")
|
|
866
|
-
local tasks_file="$req_dir/TASKS.md"
|
|
867
|
-
local status_file="$req_dir/orchestration_status.json"
|
|
868
|
-
|
|
869
|
-
if [[ ! -f "$tasks_file" ]] || [[ ! -f "$status_file" ]]; then
|
|
870
|
-
echo ""
|
|
871
|
-
return 1
|
|
872
|
-
fi
|
|
873
|
-
|
|
874
|
-
# Extract task IDs from TASKS.md (format: - [ ] **T001** ...)
|
|
875
|
-
local all_tasks
|
|
876
|
-
all_tasks=$(grep -oE '\*\*T[0-9]+\*\*' "$tasks_file" | sed 's/\*\*//g' | sort -u)
|
|
877
|
-
|
|
878
|
-
# Get assigned tasks from status file
|
|
879
|
-
local assigned_tasks
|
|
880
|
-
assigned_tasks=$(jq -r '.team.taskAssignments | keys[]' "$status_file" 2>/dev/null)
|
|
881
|
-
|
|
882
|
-
# Find unassigned tasks
|
|
883
|
-
for task in $all_tasks; do
|
|
884
|
-
if ! echo "$assigned_tasks" | grep -q "^${task}$"; then
|
|
885
|
-
echo "$task"
|
|
886
|
-
fi
|
|
887
|
-
done
|
|
888
|
-
}
|
|
889
|
-
|
|
890
|
-
# Update Ralph Loop state for teammate
|
|
891
|
-
# Args: $1 - repo root, $2 - requirement ID, $3 - teammate ID, $4 - verify result (passed|failed)
|
|
892
|
-
update_teammate_ralph_state() {
|
|
893
|
-
local repo_root="$1"
|
|
894
|
-
local req_id="$2"
|
|
895
|
-
local teammate_id="$3"
|
|
896
|
-
local verify_result="$4"
|
|
897
|
-
local status_file
|
|
898
|
-
status_file=$(get_req_dir "$repo_root" "$req_id")/orchestration_status.json
|
|
899
|
-
|
|
900
|
-
if [[ ! -f "$status_file" ]]; then
|
|
901
|
-
echo "ERROR: orchestration_status.json not found" >&2
|
|
902
|
-
return 1
|
|
903
|
-
fi
|
|
904
|
-
|
|
905
|
-
local now
|
|
906
|
-
now=$(get_beijing_time_iso)
|
|
907
|
-
|
|
908
|
-
jq --arg id "$teammate_id" --arg result "$verify_result" --arg now "$now" '
|
|
909
|
-
.ralphLoop.teammates[$id].iteration += 1 |
|
|
910
|
-
.ralphLoop.teammates[$id].lastVerifyResult = $result |
|
|
911
|
-
.ralphLoop.teammates[$id].lastVerifyAt = $now |
|
|
912
|
-
.ralphLoop.globalIteration += 1
|
|
913
|
-
' "$status_file" > "${status_file}.tmp" && mv "${status_file}.tmp" "$status_file"
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
# Check if all teammates are idle or completed
|
|
917
|
-
# Args: $1 - repo root, $2 - requirement ID
|
|
918
|
-
# Returns: 0 if all idle/completed, 1 if any working
|
|
919
|
-
all_teammates_idle() {
|
|
920
|
-
local repo_root="$1"
|
|
921
|
-
local req_id="$2"
|
|
922
|
-
local status_file
|
|
923
|
-
status_file=$(get_req_dir "$repo_root" "$req_id")/orchestration_status.json
|
|
924
|
-
|
|
925
|
-
if [[ ! -f "$status_file" ]]; then
|
|
926
|
-
return 1
|
|
927
|
-
fi
|
|
928
|
-
|
|
929
|
-
local working_count
|
|
930
|
-
working_count=$(jq '[.team.teammates[] | select(.status == "working")] | length' "$status_file" 2>/dev/null)
|
|
931
|
-
|
|
932
|
-
[[ "$working_count" == "0" ]] && return 0
|
|
933
|
-
return 1
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
# Clean up Team state
|
|
937
|
-
# Args: $1 - repo root, $2 - requirement ID
|
|
938
|
-
cleanup_team_state() {
|
|
939
|
-
local repo_root="$1"
|
|
940
|
-
local req_id="$2"
|
|
941
|
-
local status_file
|
|
942
|
-
status_file=$(get_req_dir "$repo_root" "$req_id")/orchestration_status.json
|
|
943
|
-
|
|
944
|
-
if [[ ! -f "$status_file" ]]; then
|
|
945
|
-
return 0
|
|
946
|
-
fi
|
|
947
|
-
|
|
948
|
-
local now
|
|
949
|
-
now=$(get_beijing_time_iso)
|
|
950
|
-
|
|
951
|
-
jq --arg now "$now" '
|
|
952
|
-
del(.team) |
|
|
953
|
-
del(.ralphLoop) |
|
|
954
|
-
.updatedAt = $now
|
|
955
|
-
' "$status_file" > "${status_file}.tmp" && mv "${status_file}.tmp" "$status_file"
|
|
956
|
-
}
|
|
957
|
-
|
|
958
|
-
# =============================================================================
|
|
959
|
-
# Team Monitoring Functions (v4.7)
|
|
960
|
-
# =============================================================================
|
|
961
|
-
|
|
962
|
-
# Get Team status summary
|
|
963
|
-
# Args: $1 - repo root, $2 - requirement ID
|
|
964
|
-
# Returns: JSON summary of Team status
|
|
965
|
-
get_team_status_summary() {
|
|
966
|
-
local repo_root="$1"
|
|
967
|
-
local req_id="$2"
|
|
968
|
-
local status_file
|
|
969
|
-
status_file=$(get_req_dir "$repo_root" "$req_id")/orchestration_status.json
|
|
970
|
-
|
|
971
|
-
if [[ ! -f "$status_file" ]]; then
|
|
972
|
-
echo '{"error": "Status file not found"}'
|
|
973
|
-
return 1
|
|
974
|
-
fi
|
|
975
|
-
|
|
976
|
-
jq '{
|
|
977
|
-
mode: .team.mode,
|
|
978
|
-
lead: .team.lead,
|
|
979
|
-
teammateCount: (.team.teammates | length),
|
|
980
|
-
workingCount: ([.team.teammates[] | select(.status == "working")] | length),
|
|
981
|
-
idleCount: ([.team.teammates[] | select(.status == "idle")] | length),
|
|
982
|
-
completedTaskCount: ([.team.teammates[].completedTasks | length] | add),
|
|
983
|
-
assignedTaskCount: (.team.taskAssignments | keys | length),
|
|
984
|
-
ralphLoop: {
|
|
985
|
-
globalIteration: .ralphLoop.globalIteration,
|
|
986
|
-
maxIterations: .ralphLoop.maxIterations
|
|
987
|
-
},
|
|
988
|
-
lastUpdated: .team.updatedAt
|
|
989
|
-
}' "$status_file" 2>/dev/null
|
|
990
|
-
}
|
|
991
|
-
|
|
992
|
-
# Check for timed out teammates
|
|
993
|
-
# Args: $1 - repo root, $2 - requirement ID, $3 - timeout seconds (default 300)
|
|
994
|
-
# Returns: JSON array of timed out teammates
|
|
995
|
-
get_timed_out_teammates() {
|
|
996
|
-
local repo_root="$1"
|
|
997
|
-
local req_id="$2"
|
|
998
|
-
local timeout_seconds="${3:-300}"
|
|
999
|
-
local status_file
|
|
1000
|
-
status_file=$(get_req_dir "$repo_root" "$req_id")/orchestration_status.json
|
|
1001
|
-
|
|
1002
|
-
if [[ ! -f "$status_file" ]]; then
|
|
1003
|
-
echo '[]'
|
|
1004
|
-
return 1
|
|
1005
|
-
fi
|
|
1006
|
-
|
|
1007
|
-
local now_epoch
|
|
1008
|
-
now_epoch=$(date +%s)
|
|
1009
|
-
|
|
1010
|
-
jq --argjson now "$now_epoch" --argjson timeout "$timeout_seconds" '
|
|
1011
|
-
[.team.teammates[] |
|
|
1012
|
-
select(.status == "working") |
|
|
1013
|
-
select(
|
|
1014
|
-
($now - ((.lastActiveAt | sub("\\.[0-9]+"; "") | sub("Z$"; "+00:00") | fromdateiso8601) // 0)) > $timeout
|
|
1015
|
-
)
|
|
1016
|
-
]
|
|
1017
|
-
' "$status_file" 2>/dev/null
|
|
1018
|
-
}
|
|
1019
|
-
|
|
1020
|
-
# Log Team event to EXECUTION_LOG.md
|
|
1021
|
-
# Args: $1 - repo root, $2 - requirement ID, $3 - event type, $4 - message
|
|
1022
|
-
log_team_event() {
|
|
1023
|
-
local repo_root="$1"
|
|
1024
|
-
local req_id="$2"
|
|
1025
|
-
local event_type="$3"
|
|
1026
|
-
local message="$4"
|
|
1027
|
-
local log_file
|
|
1028
|
-
log_file=$(get_req_dir "$repo_root" "$req_id")/EXECUTION_LOG.md
|
|
1029
|
-
|
|
1030
|
-
local timestamp
|
|
1031
|
-
timestamp=$(get_beijing_time_iso)
|
|
1032
|
-
|
|
1033
|
-
local icon
|
|
1034
|
-
case "$event_type" in
|
|
1035
|
-
info) icon="ℹ️" ;;
|
|
1036
|
-
warning) icon="⚠️" ;;
|
|
1037
|
-
error) icon="❌" ;;
|
|
1038
|
-
success) icon="✅" ;;
|
|
1039
|
-
*) icon="📝" ;;
|
|
1040
|
-
esac
|
|
1041
|
-
|
|
1042
|
-
local entry="
|
|
1043
|
-
## [$timestamp] $icon Team Event: $event_type
|
|
1044
|
-
|
|
1045
|
-
$message
|
|
1046
|
-
|
|
1047
|
-
---
|
|
1048
|
-
"
|
|
1049
|
-
|
|
1050
|
-
if [[ -f "$log_file" ]]; then
|
|
1051
|
-
echo "$entry" >> "$log_file"
|
|
1052
|
-
else
|
|
1053
|
-
echo "# Execution Log
|
|
1054
|
-
|
|
1055
|
-
$entry" > "$log_file"
|
|
1056
|
-
fi
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1059
|
-
# Check Team health and log warnings
|
|
1060
|
-
# Args: $1 - repo root, $2 - requirement ID
|
|
1061
|
-
# Returns: 0 if healthy, 1 if issues found
|
|
1062
|
-
check_team_health() {
|
|
1063
|
-
local repo_root="$1"
|
|
1064
|
-
local req_id="$2"
|
|
1065
|
-
local status_file
|
|
1066
|
-
status_file=$(get_req_dir "$repo_root" "$req_id")/orchestration_status.json
|
|
1067
|
-
|
|
1068
|
-
if [[ ! -f "$status_file" ]]; then
|
|
1069
|
-
return 1
|
|
1070
|
-
fi
|
|
1071
|
-
|
|
1072
|
-
local issues=0
|
|
1073
|
-
|
|
1074
|
-
# Check for timed out teammates
|
|
1075
|
-
local timed_out
|
|
1076
|
-
timed_out=$(get_timed_out_teammates "$repo_root" "$req_id")
|
|
1077
|
-
local timed_out_count
|
|
1078
|
-
timed_out_count=$(echo "$timed_out" | jq 'length')
|
|
1079
|
-
|
|
1080
|
-
if [[ "$timed_out_count" -gt 0 ]]; then
|
|
1081
|
-
local teammate_ids
|
|
1082
|
-
teammate_ids=$(echo "$timed_out" | jq -r '.[].id' | tr '\n' ', ' | sed 's/,$//')
|
|
1083
|
-
log_team_event "$repo_root" "$req_id" "warning" "Timed out teammates: $teammate_ids"
|
|
1084
|
-
issues=$((issues + 1))
|
|
1085
|
-
fi
|
|
1086
|
-
|
|
1087
|
-
# Check Ralph Loop iteration limit
|
|
1088
|
-
local global_iter max_iter
|
|
1089
|
-
global_iter=$(jq '.ralphLoop.globalIteration // 0' "$status_file")
|
|
1090
|
-
max_iter=$(jq '.ralphLoop.maxIterations // 10' "$status_file")
|
|
1091
|
-
|
|
1092
|
-
if [[ "$global_iter" -ge "$max_iter" ]]; then
|
|
1093
|
-
log_team_event "$repo_root" "$req_id" "error" "Ralph Loop reached max iterations ($global_iter/$max_iter)"
|
|
1094
|
-
issues=$((issues + 1))
|
|
1095
|
-
elif [[ "$global_iter" -ge $((max_iter * 80 / 100)) ]]; then
|
|
1096
|
-
log_team_event "$repo_root" "$req_id" "warning" "Ralph Loop approaching limit ($global_iter/$max_iter)"
|
|
1097
|
-
fi
|
|
1098
|
-
|
|
1099
|
-
[[ "$issues" -eq 0 ]] && return 0
|
|
1100
|
-
return 1
|
|
1101
|
-
}
|
|
1102
|
-
|