@hanzlaa/rcode 2.1.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/AGENTS.md +120 -0
- package/CLAUDE.md +120 -0
- package/CONTRIBUTING.md +298 -0
- package/README.md +436 -0
- package/cli/config.js +142 -0
- package/cli/context.js +213 -0
- package/cli/dashboard.js +38 -0
- package/cli/digest.js +66 -0
- package/cli/doctor.js +283 -0
- package/cli/github-sync.js +1016 -0
- package/cli/index.js +113 -0
- package/cli/install.js +946 -0
- package/cli/lib/config.cjs +334 -0
- package/cli/lib/fsutil.cjs +76 -0
- package/cli/lib/github.cjs +365 -0
- package/cli/lib/manifest.cjs +240 -0
- package/cli/lib/memory-bank.cjs +348 -0
- package/cli/lib/model-profiles.cjs +169 -0
- package/cli/lib/prompts.cjs +355 -0
- package/cli/postinstall.js +32 -0
- package/cli/set-mode.js +94 -0
- package/cli/set-profile.js +80 -0
- package/cli/show-model.js +82 -0
- package/cli/team.js +35 -0
- package/cli/tiers.js +49 -0
- package/cli/uninstall.js +600 -0
- package/cli/update.js +373 -0
- package/package.json +60 -0
- package/rihal/agents/rihal-advisor-researcher.md +116 -0
- package/rihal/agents/rihal-ahmed.md +66 -0
- package/rihal/agents/rihal-architect.md +79 -0
- package/rihal/agents/rihal-assumptions-analyzer.md +117 -0
- package/rihal/agents/rihal-code-fixer.md +74 -0
- package/rihal/agents/rihal-code-reviewer.md +75 -0
- package/rihal/agents/rihal-codebase-mapper.md +170 -0
- package/rihal/agents/rihal-debugger.md +140 -0
- package/rihal/agents/rihal-deviation-analyzer.md +74 -0
- package/rihal/agents/rihal-docs-auditor.md +77 -0
- package/rihal/agents/rihal-edge-case-hunter.md +75 -0
- package/rihal/agents/rihal-executor.md +113 -0
- package/rihal/agents/rihal-fatima.md +68 -0
- package/rihal/agents/rihal-haitham.md +75 -0
- package/rihal/agents/rihal-hanzla.md +59 -0
- package/rihal/agents/rihal-hussain-pm.md +82 -0
- package/rihal/agents/rihal-integration-checker.md +455 -0
- package/rihal/agents/rihal-khalid.md +59 -0
- package/rihal/agents/rihal-layla.md +57 -0
- package/rihal/agents/rihal-mariam.md +58 -0
- package/rihal/agents/rihal-nasser.md +57 -0
- package/rihal/agents/rihal-noor.md +60 -0
- package/rihal/agents/rihal-nyquist-auditor.md +182 -0
- package/rihal/agents/rihal-omar.md +57 -0
- package/rihal/agents/rihal-phase-researcher.md +84 -0
- package/rihal/agents/rihal-planner.md +176 -0
- package/rihal/agents/rihal-profiler.md +74 -0
- package/rihal/agents/rihal-project-researcher.md +80 -0
- package/rihal/agents/rihal-remediation-planner.md +78 -0
- package/rihal/agents/rihal-research-synthesizer.md +253 -0
- package/rihal/agents/rihal-roadmapper.md +73 -0
- package/rihal/agents/rihal-sadiq.md +72 -0
- package/rihal/agents/rihal-security-adversary.md +82 -0
- package/rihal/agents/rihal-security-auditor.md +78 -0
- package/rihal/agents/rihal-sprint-checker.md +124 -0
- package/rihal/agents/rihal-tech-writer.md +80 -0
- package/rihal/agents/rihal-ui-auditor.md +81 -0
- package/rihal/agents/rihal-ui-designer.md +6 -0
- package/rihal/agents/rihal-ux-designer.md +83 -0
- package/rihal/agents/rihal-verifier.md +124 -0
- package/rihal/agents/rihal-waleed.md +60 -0
- package/rihal/agents/rihal-yousef.md +78 -0
- package/rihal/agents/rihal-zahra.md +62 -0
- package/rihal/agents/rihal-zayd.md +78 -0
- package/rihal/agents/rules/codebase-mapper/detailed-guide.md +615 -0
- package/rihal/agents/rules/debugger/checkpoint-recovery.md +272 -0
- package/rihal/agents/rules/debugger/debug-session-state.md +261 -0
- package/rihal/agents/rules/debugger/hypothesis-templates.md +330 -0
- package/rihal/agents/rules/debugger/investigation-protocol.md +298 -0
- package/rihal/agents/rules/debugger/scientific-method.md +317 -0
- package/rihal/agents/rules/executor/authentication-gates.md +202 -0
- package/rihal/agents/rules/executor/deviation-rules.md +191 -0
- package/rihal/agents/rules/executor/execution-flow.md +116 -0
- package/rihal/agents/rules/executor/self-check.md +241 -0
- package/rihal/agents/rules/executor/stub-detection.md +267 -0
- package/rihal/agents/rules/executor/summary-creation.md +76 -0
- package/rihal/agents/rules/executor/task-commit-protocol.md +283 -0
- package/rihal/agents/rules/executor/tdd-flow.md +294 -0
- package/rihal/agents/rules/phase-researcher/detailed-guide.md +628 -0
- package/rihal/agents/rules/planner/common-patterns.md +373 -0
- package/rihal/agents/rules/planner/dependency-analysis.md +195 -0
- package/rihal/agents/rules/planner/goal-backward-thinking.md +220 -0
- package/rihal/agents/rules/planner/sprint-verification.md +202 -0
- package/rihal/agents/rules/planner/task-templates.md +296 -0
- package/rihal/agents/rules/project-researcher/detailed-guide.md +589 -0
- package/rihal/agents/rules/roadmapper/detailed-guide.md +620 -0
- package/rihal/agents/rules/sprint-checker/dimensions.md +414 -0
- package/rihal/agents/rules/sprint-checker/process.md +377 -0
- package/rihal/agents/rules/verifier/anti-patterns.md +94 -0
- package/rihal/agents/rules/verifier/artifact-verification.md +69 -0
- package/rihal/agents/rules/verifier/behavioral-spot-checks.md +49 -0
- package/rihal/agents/rules/verifier/context-loading.md +84 -0
- package/rihal/agents/rules/verifier/data-flow-trace.md +65 -0
- package/rihal/agents/rules/verifier/gap-output.md +51 -0
- package/rihal/agents/rules/verifier/key-links.md +56 -0
- package/rihal/agents/rules/verifier/requirements-coverage.md +28 -0
- package/rihal/agents/rules/verifier/verification-report.md +131 -0
- package/rihal/bin/lib/code-references.cjs +196 -0
- package/rihal/bin/lib/config.cjs +146 -0
- package/rihal/bin/lib/council-panel.cjs +501 -0
- package/rihal/bin/lib/roadmap.cjs +256 -0
- package/rihal/bin/lib/verify.cjs +118 -0
- package/rihal/bin/rihal-hooks.cjs +204 -0
- package/rihal/bin/rihal-tools.cjs +3554 -0
- package/rihal/brain/README.md +38 -0
- package/rihal/brain/best-practices/no-autonomous-bypass.md +37 -0
- package/rihal/brain/best-practices/research-citation-rule.md +39 -0
- package/rihal/brain/best-practices/state-sync-rule.md +43 -0
- package/rihal/brain/sources.yaml +59 -0
- package/rihal/commands/add-phase.md +18 -0
- package/rihal/commands/add-tests.md +18 -0
- package/rihal/commands/add-todo.md +8 -0
- package/rihal/commands/analyze-dependencies.md +11 -0
- package/rihal/commands/audit-fix.md +14 -0
- package/rihal/commands/audit-milestone.md +12 -0
- package/rihal/commands/audit-uat.md +18 -0
- package/rihal/commands/autonomous.md +19 -0
- package/rihal/commands/brainstorm.md +11 -0
- package/rihal/commands/chain.md +8 -0
- package/rihal/commands/check-implementation-readiness.md +8 -0
- package/rihal/commands/check-todos.md +18 -0
- package/rihal/commands/cleanup.md +18 -0
- package/rihal/commands/code-review-fix.md +14 -0
- package/rihal/commands/code-review.md +14 -0
- package/rihal/commands/complete-milestone.md +12 -0
- package/rihal/commands/config.md +8 -0
- package/rihal/commands/correct-course.md +8 -0
- package/rihal/commands/council.md +25 -0
- package/rihal/commands/create-epics-and-stories.md +8 -0
- package/rihal/commands/create-story.md +8 -0
- package/rihal/commands/dashboard.md +10 -0
- package/rihal/commands/debug.md +8 -0
- package/rihal/commands/decisions.md +10 -0
- package/rihal/commands/dev-story.md +8 -0
- package/rihal/commands/diff.md +10 -0
- package/rihal/commands/discuss-phase-power.md +11 -0
- package/rihal/commands/discuss-phase.md +19 -0
- package/rihal/commands/discuss.md +23 -0
- package/rihal/commands/do.md +22 -0
- package/rihal/commands/docs-update.md +14 -0
- package/rihal/commands/document-project.md +8 -0
- package/rihal/commands/enable-hooks.md +11 -0
- package/rihal/commands/execute-sprint.md +13 -0
- package/rihal/commands/execute.md +19 -0
- package/rihal/commands/explore.md +14 -0
- package/rihal/commands/export-to-github.md +11 -0
- package/rihal/commands/forensics.md +11 -0
- package/rihal/commands/from-template.md +11 -0
- package/rihal/commands/health.md +10 -0
- package/rihal/commands/help.md +8 -0
- package/rihal/commands/import.md +12 -0
- package/rihal/commands/inbox.md +12 -0
- package/rihal/commands/init.md +14 -0
- package/rihal/commands/insert-phase.md +11 -0
- package/rihal/commands/install.md +10 -0
- package/rihal/commands/karpathy-audit.md +12 -0
- package/rihal/commands/list-plans.md +11 -0
- package/rihal/commands/list-workspaces.md +10 -0
- package/rihal/commands/map-codebase.md +14 -0
- package/rihal/commands/milestone-summary.md +11 -0
- package/rihal/commands/new-milestone.md +12 -0
- package/rihal/commands/new-project-research.md +11 -0
- package/rihal/commands/new-project-roadmap.md +11 -0
- package/rihal/commands/new-project.md +13 -0
- package/rihal/commands/new-workspace.md +12 -0
- package/rihal/commands/next.md +19 -0
- package/rihal/commands/note.md +12 -0
- package/rihal/commands/notify-test.md +10 -0
- package/rihal/commands/pause-work.md +8 -0
- package/rihal/commands/plan-milestone-gaps.md +18 -0
- package/rihal/commands/plan.md +19 -0
- package/rihal/commands/plant-seed.md +18 -0
- package/rihal/commands/pr-branch.md +18 -0
- package/rihal/commands/profile-user.md +8 -0
- package/rihal/commands/progress.md +19 -0
- package/rihal/commands/quick.md +14 -0
- package/rihal/commands/remove-phase.md +18 -0
- package/rihal/commands/remove-workspace.md +11 -0
- package/rihal/commands/replay.md +11 -0
- package/rihal/commands/report.md +10 -0
- package/rihal/commands/rerun.md +11 -0
- package/rihal/commands/research-phase.md +18 -0
- package/rihal/commands/resume-work.md +8 -0
- package/rihal/commands/review-adversarial.md +8 -0
- package/rihal/commands/review-edge-case-hunter.md +8 -0
- package/rihal/commands/review.md +18 -0
- package/rihal/commands/scan.md +14 -0
- package/rihal/commands/secure-phase.md +14 -0
- package/rihal/commands/session-report.md +10 -0
- package/rihal/commands/settings.md +8 -0
- package/rihal/commands/ship.md +18 -0
- package/rihal/commands/show.md +10 -0
- package/rihal/commands/sprint-planning.md +20 -0
- package/rihal/commands/sprint-status.md +21 -0
- package/rihal/commands/stats.md +10 -0
- package/rihal/commands/status.md +21 -0
- package/rihal/commands/ui-phase.md +8 -0
- package/rihal/commands/ui-review.md +8 -0
- package/rihal/commands/undo.md +14 -0
- package/rihal/commands/update.md +11 -0
- package/rihal/commands/validate-phase.md +18 -0
- package/rihal/commands/verify-phase.md +18 -0
- package/rihal/commands/verify-work.md +19 -0
- package/rihal/commands/why.md +10 -0
- package/rihal/commands/workstream.md +11 -0
- package/rihal/config/model-profiles.json +226 -0
- package/rihal/config/model-profiles.schema.json +36 -0
- package/rihal/config.yaml +39 -0
- package/rihal/digests/README.md +50 -0
- package/rihal/digests/fatima.md +24 -0
- package/rihal/digests/hussain-pm.md +24 -0
- package/rihal/digests/mariam.md +24 -0
- package/rihal/digests/sadiq.md +24 -0
- package/rihal/digests/waleed.md +24 -0
- package/rihal/modules/core.yaml +101 -0
- package/rihal/modules/discovery.yaml +50 -0
- package/rihal/modules/execution.yaml +66 -0
- package/rihal/references/brain-methods.csv +9 -0
- package/rihal/references/checklist-architect.md +146 -0
- package/rihal/references/checklist-change.md +136 -0
- package/rihal/references/checklist-pm.md +154 -0
- package/rihal/references/checklist-po-master.md +100 -0
- package/rihal/references/checklist-story-dod.md +75 -0
- package/rihal/references/checklist-story-draft.md +53 -0
- package/rihal/references/checkpoints-index.md +53 -0
- package/rihal/references/checkpoints.md +778 -0
- package/rihal/references/codebase-grounding.md +76 -0
- package/rihal/references/command-redirect-format.md +62 -0
- package/rihal/references/commit-conventions.md +125 -0
- package/rihal/references/common-bug-patterns-index.md +44 -0
- package/rihal/references/common-bug-patterns.md +621 -0
- package/rihal/references/context-budget.md +104 -0
- package/rihal/references/continuation-format.md +249 -0
- package/rihal/references/council-protocol.md +91 -0
- package/rihal/references/domain-probes.md +213 -0
- package/rihal/references/elicitation-methods.csv +16 -0
- package/rihal/references/execution-protocol.md +155 -0
- package/rihal/references/gate-prompts.md +212 -0
- package/rihal/references/gates.md +127 -0
- package/rihal/references/git-integration.md +159 -0
- package/rihal/references/git-planning-commit.md +185 -0
- package/rihal/references/karpathy-guidelines.md +79 -0
- package/rihal/references/model-profiles.md +90 -0
- package/rihal/references/no-unauthorized-git-ops.md +73 -0
- package/rihal/references/output-format.md +319 -0
- package/rihal/references/output-realism.md +52 -0
- package/rihal/references/project-types.yaml +270 -0
- package/rihal/references/questioning.md +163 -0
- package/rihal/references/response-style.md +81 -0
- package/rihal/references/state-schema.md +366 -0
- package/rihal/references/tdd.md +263 -0
- package/rihal/references/thinking-models-debug.md +126 -0
- package/rihal/references/thinking-models-planning.md +127 -0
- package/rihal/references/ui-brand.md +254 -0
- package/rihal/references/verification-patterns-index.md +76 -0
- package/rihal/references/verification-patterns.md +612 -0
- package/rihal/references/workstream-flag.md +166 -0
- package/rihal/skills/SKILLS_INDEX.md +114 -0
- package/rihal/skills/_shared/no-autonomous-bypass.md +37 -0
- package/rihal/skills/_shared/research-citation-rule.md +39 -0
- package/rihal/skills/_shared/state-sync-rule.md +43 -0
- package/rihal/skills/actions/1-analysis/research/rihal-domain-research/SKILL.md +31 -0
- package/rihal/skills/actions/1-analysis/research/rihal-domain-research/domain-steps/step-01-init.md +137 -0
- package/rihal/skills/actions/1-analysis/research/rihal-domain-research/domain-steps/step-02-domain-analysis.md +229 -0
- package/rihal/skills/actions/1-analysis/research/rihal-domain-research/domain-steps/step-03-competitive-landscape.md +238 -0
- package/rihal/skills/actions/1-analysis/research/rihal-domain-research/domain-steps/step-04-regulatory-focus.md +206 -0
- package/rihal/skills/actions/1-analysis/research/rihal-domain-research/domain-steps/step-05-technical-trends.md +234 -0
- package/rihal/skills/actions/1-analysis/research/rihal-domain-research/domain-steps/step-06-research-synthesis.md +444 -0
- package/rihal/skills/actions/1-analysis/research/rihal-domain-research/research.template.md +29 -0
- package/rihal/skills/actions/1-analysis/research/rihal-domain-research/workflow.md +49 -0
- package/rihal/skills/actions/1-analysis/research/rihal-market-research/SKILL.md +30 -0
- package/rihal/skills/actions/1-analysis/research/rihal-market-research/research.template.md +29 -0
- package/rihal/skills/actions/1-analysis/research/rihal-market-research/steps/step-01-init.md +184 -0
- package/rihal/skills/actions/1-analysis/research/rihal-market-research/steps/step-02-customer-behavior.md +239 -0
- package/rihal/skills/actions/1-analysis/research/rihal-market-research/steps/step-03-customer-pain-points.md +251 -0
- package/rihal/skills/actions/1-analysis/research/rihal-market-research/steps/step-04-customer-decisions.md +261 -0
- package/rihal/skills/actions/1-analysis/research/rihal-market-research/steps/step-05-competitive-analysis.md +173 -0
- package/rihal/skills/actions/1-analysis/research/rihal-market-research/steps/step-06-research-completion.md +478 -0
- package/rihal/skills/actions/1-analysis/research/rihal-market-research/workflow.md +49 -0
- package/rihal/skills/actions/1-analysis/research/rihal-technical-research/SKILL.md +31 -0
- package/rihal/skills/actions/1-analysis/research/rihal-technical-research/research.template.md +29 -0
- package/rihal/skills/actions/1-analysis/research/rihal-technical-research/technical-steps/step-01-init.md +137 -0
- package/rihal/skills/actions/1-analysis/research/rihal-technical-research/technical-steps/step-02-technical-overview.md +239 -0
- package/rihal/skills/actions/1-analysis/research/rihal-technical-research/technical-steps/step-03-integration-patterns.md +248 -0
- package/rihal/skills/actions/1-analysis/research/rihal-technical-research/technical-steps/step-04-architectural-patterns.md +202 -0
- package/rihal/skills/actions/1-analysis/research/rihal-technical-research/technical-steps/step-05-implementation-research.md +233 -0
- package/rihal/skills/actions/1-analysis/research/rihal-technical-research/technical-steps/step-06-research-synthesis.md +487 -0
- package/rihal/skills/actions/1-analysis/research/rihal-technical-research/workflow.md +50 -0
- package/rihal/skills/actions/1-analysis/rihal-document-project/SKILL.md +30 -0
- package/rihal/skills/actions/1-analysis/rihal-document-project/checklist.md +245 -0
- package/rihal/skills/actions/1-analysis/rihal-document-project/documentation-requirements.csv +12 -0
- package/rihal/skills/actions/1-analysis/rihal-document-project/instructions.md +128 -0
- package/rihal/skills/actions/1-analysis/rihal-document-project/templates/deep-dive-template.md +345 -0
- package/rihal/skills/actions/1-analysis/rihal-document-project/templates/index-template.md +169 -0
- package/rihal/skills/actions/1-analysis/rihal-document-project/templates/project-overview-template.md +103 -0
- package/rihal/skills/actions/1-analysis/rihal-document-project/templates/project-scan-report-schema.json +160 -0
- package/rihal/skills/actions/1-analysis/rihal-document-project/templates/source-tree-template.md +135 -0
- package/rihal/skills/actions/1-analysis/rihal-document-project/workflow.md +27 -0
- package/rihal/skills/actions/1-analysis/rihal-document-project/workflows/deep-dive-instructions.md +299 -0
- package/rihal/skills/actions/1-analysis/rihal-document-project/workflows/deep-dive-workflow.md +34 -0
- package/rihal/skills/actions/1-analysis/rihal-document-project/workflows/full-scan-instructions.md +1107 -0
- package/rihal/skills/actions/1-analysis/rihal-document-project/workflows/full-scan-workflow.md +34 -0
- package/rihal/skills/actions/1-analysis/rihal-prfaq/SKILL.md +120 -0
- package/rihal/skills/actions/1-analysis/rihal-prfaq/agents/artifact-analyzer.md +60 -0
- package/rihal/skills/actions/1-analysis/rihal-prfaq/agents/web-researcher.md +49 -0
- package/rihal/skills/actions/1-analysis/rihal-prfaq/assets/prfaq-template.md +62 -0
- package/rihal/skills/actions/1-analysis/rihal-prfaq/references/customer-faq.md +55 -0
- package/rihal/skills/actions/1-analysis/rihal-prfaq/references/internal-faq.md +51 -0
- package/rihal/skills/actions/1-analysis/rihal-prfaq/references/press-release.md +60 -0
- package/rihal/skills/actions/1-analysis/rihal-prfaq/references/verdict.md +79 -0
- package/rihal/skills/actions/1-analysis/rihal-prfaq/rihal-manifest.json +16 -0
- package/rihal/skills/actions/1-analysis/rihal-product-brief/SKILL.md +112 -0
- package/rihal/skills/actions/1-analysis/rihal-product-brief/agents/artifact-analyzer.md +60 -0
- package/rihal/skills/actions/1-analysis/rihal-product-brief/agents/opportunity-reviewer.md +44 -0
- package/rihal/skills/actions/1-analysis/rihal-product-brief/agents/skeptic-reviewer.md +44 -0
- package/rihal/skills/actions/1-analysis/rihal-product-brief/agents/web-researcher.md +49 -0
- package/rihal/skills/actions/1-analysis/rihal-product-brief/prompts/contextual-discovery.md +57 -0
- package/rihal/skills/actions/1-analysis/rihal-product-brief/prompts/draft-and-review.md +86 -0
- package/rihal/skills/actions/1-analysis/rihal-product-brief/prompts/finalize.md +75 -0
- package/rihal/skills/actions/1-analysis/rihal-product-brief/prompts/guided-elicitation.md +70 -0
- package/rihal/skills/actions/1-analysis/rihal-product-brief/resources/brief-template.md +60 -0
- package/rihal/skills/actions/1-analysis/rihal-product-brief/rihal-manifest.json +17 -0
- package/rihal/skills/actions/2-plan/rihal-create-epics-and-stories/SKILL.md +30 -0
- package/rihal/skills/actions/2-plan/rihal-create-epics-and-stories/steps/step-01-validate-prerequisites.md +255 -0
- package/rihal/skills/actions/2-plan/rihal-create-epics-and-stories/steps/step-02-design-epics.md +212 -0
- package/rihal/skills/actions/2-plan/rihal-create-epics-and-stories/steps/step-03-create-stories.md +255 -0
- package/rihal/skills/actions/2-plan/rihal-create-epics-and-stories/steps/step-04-final-validation.md +131 -0
- package/rihal/skills/actions/2-plan/rihal-create-epics-and-stories/templates/epics-template.md +61 -0
- package/rihal/skills/actions/2-plan/rihal-create-epics-and-stories/workflow.md +54 -0
- package/rihal/skills/actions/2-plan/rihal-create-milestone/SKILL.md +39 -0
- package/rihal/skills/actions/2-plan/rihal-create-milestone/steps/README.md +30 -0
- package/rihal/skills/actions/2-plan/rihal-create-milestone/steps/step-01-init.md +62 -0
- package/rihal/skills/actions/2-plan/rihal-create-milestone/steps/step-02-outcomes.md +64 -0
- package/rihal/skills/actions/2-plan/rihal-create-milestone/steps/step-03-sequencing.md +65 -0
- package/rihal/skills/actions/2-plan/rihal-create-milestone/steps/step-04-windows.md +60 -0
- package/rihal/skills/actions/2-plan/rihal-create-milestone/steps/step-05-kill-criteria.md +59 -0
- package/rihal/skills/actions/2-plan/rihal-create-milestone/steps/step-06-phase-stubs.md +56 -0
- package/rihal/skills/actions/2-plan/rihal-create-milestone/steps/step-07-backlog.md +44 -0
- package/rihal/skills/actions/2-plan/rihal-create-milestone/steps/step-08-write-roadmap.md +58 -0
- package/rihal/skills/actions/2-plan/rihal-create-milestone/steps/step-09-state-sync.md +62 -0
- package/rihal/skills/actions/2-plan/rihal-create-milestone/steps/step-10-complete.md +56 -0
- package/rihal/skills/actions/2-plan/rihal-create-milestone/workflow.md +93 -0
- package/rihal/skills/actions/2-plan/rihal-create-prd/SKILL.md +40 -0
- package/rihal/skills/actions/2-plan/rihal-create-prd/data/domain-complexity.csv +15 -0
- package/rihal/skills/actions/2-plan/rihal-create-prd/data/prd-purpose.md +197 -0
- package/rihal/skills/actions/2-plan/rihal-create-prd/data/project-types.csv +11 -0
- package/rihal/skills/actions/2-plan/rihal-create-prd/steps-c/step-01-init.md +178 -0
- package/rihal/skills/actions/2-plan/rihal-create-prd/steps-c/step-01b-continue.md +161 -0
- package/rihal/skills/actions/2-plan/rihal-create-prd/steps-c/step-02-discovery.md +208 -0
- package/rihal/skills/actions/2-plan/rihal-create-prd/steps-c/step-02b-vision.md +142 -0
- package/rihal/skills/actions/2-plan/rihal-create-prd/steps-c/step-02c-executive-summary.md +158 -0
- package/rihal/skills/actions/2-plan/rihal-create-prd/steps-c/step-03-success.md +214 -0
- package/rihal/skills/actions/2-plan/rihal-create-prd/steps-c/step-04-journeys.md +201 -0
- package/rihal/skills/actions/2-plan/rihal-create-prd/steps-c/step-05-domain.md +194 -0
- package/rihal/skills/actions/2-plan/rihal-create-prd/steps-c/step-06-innovation.md +211 -0
- package/rihal/skills/actions/2-plan/rihal-create-prd/steps-c/step-07-project-type.md +222 -0
- package/rihal/skills/actions/2-plan/rihal-create-prd/steps-c/step-08-scoping.md +216 -0
- package/rihal/skills/actions/2-plan/rihal-create-prd/steps-c/step-09-functional.md +219 -0
- package/rihal/skills/actions/2-plan/rihal-create-prd/steps-c/step-10-nonfunctional.md +230 -0
- package/rihal/skills/actions/2-plan/rihal-create-prd/steps-c/step-11-polish.md +221 -0
- package/rihal/skills/actions/2-plan/rihal-create-prd/steps-c/step-12-complete.md +115 -0
- package/rihal/skills/actions/2-plan/rihal-create-prd/templates/prd-template.md +10 -0
- package/rihal/skills/actions/2-plan/rihal-create-prd/workflow.md +64 -0
- package/rihal/skills/actions/2-plan/rihal-create-story/SKILL.md +31 -0
- package/rihal/skills/actions/2-plan/rihal-create-story/checklist.md +357 -0
- package/rihal/skills/actions/2-plan/rihal-create-story/discover-inputs.md +88 -0
- package/rihal/skills/actions/2-plan/rihal-create-story/template.md +49 -0
- package/rihal/skills/actions/2-plan/rihal-create-story/workflow.md +380 -0
- package/rihal/skills/actions/2-plan/rihal-create-ux-design/SKILL.md +31 -0
- package/rihal/skills/actions/2-plan/rihal-create-ux-design/steps/step-01-init.md +135 -0
- package/rihal/skills/actions/2-plan/rihal-create-ux-design/steps/step-01b-continue.md +127 -0
- package/rihal/skills/actions/2-plan/rihal-create-ux-design/steps/step-02-discovery.md +190 -0
- package/rihal/skills/actions/2-plan/rihal-create-ux-design/steps/step-03-core-experience.md +217 -0
- package/rihal/skills/actions/2-plan/rihal-create-ux-design/steps/step-04-emotional-response.md +220 -0
- package/rihal/skills/actions/2-plan/rihal-create-ux-design/steps/step-05-inspiration.md +235 -0
- package/rihal/skills/actions/2-plan/rihal-create-ux-design/steps/step-06-design-system.md +253 -0
- package/rihal/skills/actions/2-plan/rihal-create-ux-design/steps/step-07-defining-experience.md +255 -0
- package/rihal/skills/actions/2-plan/rihal-create-ux-design/steps/step-08-visual-foundation.md +225 -0
- package/rihal/skills/actions/2-plan/rihal-create-ux-design/steps/step-09-design-directions.md +225 -0
- package/rihal/skills/actions/2-plan/rihal-create-ux-design/steps/step-10-user-journeys.md +242 -0
- package/rihal/skills/actions/2-plan/rihal-create-ux-design/steps/step-11-component-strategy.md +249 -0
- package/rihal/skills/actions/2-plan/rihal-create-ux-design/steps/step-12-ux-patterns.md +238 -0
- package/rihal/skills/actions/2-plan/rihal-create-ux-design/steps/step-13-responsive-accessibility.md +265 -0
- package/rihal/skills/actions/2-plan/rihal-create-ux-design/steps/step-14-complete.md +171 -0
- package/rihal/skills/actions/2-plan/rihal-create-ux-design/ux-design-template.md +13 -0
- package/rihal/skills/actions/2-plan/rihal-create-ux-design/workflow.md +36 -0
- package/rihal/skills/actions/2-plan/rihal-edit-prd/SKILL.md +30 -0
- package/rihal/skills/actions/2-plan/rihal-edit-prd/steps-e/step-e-01-discovery.md +242 -0
- package/rihal/skills/actions/2-plan/rihal-edit-prd/steps-e/step-e-01b-legacy-conversion.md +204 -0
- package/rihal/skills/actions/2-plan/rihal-edit-prd/steps-e/step-e-02-review.md +245 -0
- package/rihal/skills/actions/2-plan/rihal-edit-prd/steps-e/step-e-03-edit.md +250 -0
- package/rihal/skills/actions/2-plan/rihal-edit-prd/steps-e/step-e-04-complete.md +165 -0
- package/rihal/skills/actions/2-plan/rihal-edit-prd/workflow.md +63 -0
- package/rihal/skills/actions/2-plan/rihal-frontend-design/SKILL.md +169 -0
- package/rihal/skills/actions/2-plan/rihal-validate-prd/SKILL.md +29 -0
- package/rihal/skills/actions/2-plan/rihal-validate-prd/data/domain-complexity.csv +15 -0
- package/rihal/skills/actions/2-plan/rihal-validate-prd/data/prd-purpose.md +197 -0
- package/rihal/skills/actions/2-plan/rihal-validate-prd/data/project-types.csv +11 -0
- package/rihal/skills/actions/2-plan/rihal-validate-prd/steps-v/step-v-01-discovery.md +221 -0
- package/rihal/skills/actions/2-plan/rihal-validate-prd/steps-v/step-v-02-format-detection.md +188 -0
- package/rihal/skills/actions/2-plan/rihal-validate-prd/steps-v/step-v-02b-parity-check.md +206 -0
- package/rihal/skills/actions/2-plan/rihal-validate-prd/steps-v/step-v-03-density-validation.md +171 -0
- package/rihal/skills/actions/2-plan/rihal-validate-prd/steps-v/step-v-04-brief-coverage-validation.md +211 -0
- package/rihal/skills/actions/2-plan/rihal-validate-prd/steps-v/step-v-05-measurability-validation.md +225 -0
- package/rihal/skills/actions/2-plan/rihal-validate-prd/steps-v/step-v-06-traceability-validation.md +214 -0
- package/rihal/skills/actions/2-plan/rihal-validate-prd/steps-v/step-v-07-implementation-leakage-validation.md +202 -0
- package/rihal/skills/actions/2-plan/rihal-validate-prd/steps-v/step-v-08-domain-compliance-validation.md +240 -0
- package/rihal/skills/actions/2-plan/rihal-validate-prd/steps-v/step-v-09-project-type-validation.md +260 -0
- package/rihal/skills/actions/2-plan/rihal-validate-prd/steps-v/step-v-10-smart-validation.md +206 -0
- package/rihal/skills/actions/2-plan/rihal-validate-prd/steps-v/step-v-11-holistic-quality-validation.md +261 -0
- package/rihal/skills/actions/2-plan/rihal-validate-prd/steps-v/step-v-12-completeness-validation.md +239 -0
- package/rihal/skills/actions/2-plan/rihal-validate-prd/steps-v/step-v-13-report-complete.md +229 -0
- package/rihal/skills/actions/2-plan/rihal-validate-prd/workflow.md +62 -0
- package/rihal/skills/actions/3-solutioning/rihal-check-implementation-readiness/SKILL.md +30 -0
- package/rihal/skills/actions/3-solutioning/rihal-check-implementation-readiness/steps/step-01-document-discovery.md +179 -0
- package/rihal/skills/actions/3-solutioning/rihal-check-implementation-readiness/steps/step-02-prd-analysis.md +168 -0
- package/rihal/skills/actions/3-solutioning/rihal-check-implementation-readiness/steps/step-03-epic-coverage-validation.md +169 -0
- package/rihal/skills/actions/3-solutioning/rihal-check-implementation-readiness/steps/step-04-ux-alignment.md +129 -0
- package/rihal/skills/actions/3-solutioning/rihal-check-implementation-readiness/steps/step-05-epic-quality-review.md +241 -0
- package/rihal/skills/actions/3-solutioning/rihal-check-implementation-readiness/steps/step-06-final-assessment.md +126 -0
- package/rihal/skills/actions/3-solutioning/rihal-check-implementation-readiness/templates/readiness-report-template.md +4 -0
- package/rihal/skills/actions/3-solutioning/rihal-check-implementation-readiness/workflow.md +49 -0
- package/rihal/skills/actions/3-solutioning/rihal-create-architecture/SKILL.md +32 -0
- package/rihal/skills/actions/3-solutioning/rihal-create-architecture/architecture-decision-template.md +12 -0
- package/rihal/skills/actions/3-solutioning/rihal-create-architecture/data/domain-complexity.csv +13 -0
- package/rihal/skills/actions/3-solutioning/rihal-create-architecture/data/project-types.csv +7 -0
- package/rihal/skills/actions/3-solutioning/rihal-create-architecture/steps/step-01-init.md +153 -0
- package/rihal/skills/actions/3-solutioning/rihal-create-architecture/steps/step-01b-continue.md +173 -0
- package/rihal/skills/actions/3-solutioning/rihal-create-architecture/steps/step-02-context.md +224 -0
- package/rihal/skills/actions/3-solutioning/rihal-create-architecture/steps/step-03-starter.md +329 -0
- package/rihal/skills/actions/3-solutioning/rihal-create-architecture/steps/step-04-decisions.md +318 -0
- package/rihal/skills/actions/3-solutioning/rihal-create-architecture/steps/step-05-patterns.md +359 -0
- package/rihal/skills/actions/3-solutioning/rihal-create-architecture/steps/step-06-structure.md +379 -0
- package/rihal/skills/actions/3-solutioning/rihal-create-architecture/steps/step-07-validation.md +359 -0
- package/rihal/skills/actions/3-solutioning/rihal-create-architecture/steps/step-08-complete.md +76 -0
- package/rihal/skills/actions/3-solutioning/rihal-create-architecture/workflow.md +38 -0
- package/rihal/skills/actions/3-solutioning/rihal-generate-project-context/SKILL.md +31 -0
- package/rihal/skills/actions/3-solutioning/rihal-generate-project-context/project-context-template.md +21 -0
- package/rihal/skills/actions/3-solutioning/rihal-generate-project-context/steps/step-01-discover.md +186 -0
- package/rihal/skills/actions/3-solutioning/rihal-generate-project-context/steps/step-02-generate.md +321 -0
- package/rihal/skills/actions/3-solutioning/rihal-generate-project-context/steps/step-03-complete.md +278 -0
- package/rihal/skills/actions/3-solutioning/rihal-generate-project-context/workflow.md +43 -0
- package/rihal/skills/actions/4-implementation/rihal-checkpoint-preview/SKILL.md +48 -0
- package/rihal/skills/actions/4-implementation/rihal-checkpoint-preview/generate-trail.md +38 -0
- package/rihal/skills/actions/4-implementation/rihal-checkpoint-preview/step-01-orientation.md +105 -0
- package/rihal/skills/actions/4-implementation/rihal-checkpoint-preview/step-02-walkthrough.md +89 -0
- package/rihal/skills/actions/4-implementation/rihal-checkpoint-preview/step-03-detail-pass.md +106 -0
- package/rihal/skills/actions/4-implementation/rihal-checkpoint-preview/step-04-testing.md +74 -0
- package/rihal/skills/actions/4-implementation/rihal-checkpoint-preview/step-05-wrapup.md +24 -0
- package/rihal/skills/actions/4-implementation/rihal-code-review/SKILL.md +31 -0
- package/rihal/skills/actions/4-implementation/rihal-code-review/steps/step-01-gather-context.md +62 -0
- package/rihal/skills/actions/4-implementation/rihal-code-review/steps/step-02-review.md +34 -0
- package/rihal/skills/actions/4-implementation/rihal-code-review/steps/step-03-triage.md +49 -0
- package/rihal/skills/actions/4-implementation/rihal-code-review/steps/step-04-present.md +129 -0
- package/rihal/skills/actions/4-implementation/rihal-code-review/workflow.md +55 -0
- package/rihal/skills/actions/4-implementation/rihal-correct-course/SKILL.md +29 -0
- package/rihal/skills/actions/4-implementation/rihal-correct-course/checklist.md +288 -0
- package/rihal/skills/actions/4-implementation/rihal-correct-course/workflow.md +267 -0
- package/rihal/skills/actions/4-implementation/rihal-dev-story/SKILL.md +36 -0
- package/rihal/skills/actions/4-implementation/rihal-dev-story/checklist.md +80 -0
- package/rihal/skills/actions/4-implementation/rihal-dev-story/workflow.md +450 -0
- package/rihal/skills/actions/4-implementation/rihal-qa-generate-e2e-tests/SKILL.md +31 -0
- package/rihal/skills/actions/4-implementation/rihal-qa-generate-e2e-tests/checklist.md +33 -0
- package/rihal/skills/actions/4-implementation/rihal-qa-generate-e2e-tests/workflow.md +136 -0
- package/rihal/skills/actions/4-implementation/rihal-retrospective/SKILL.md +30 -0
- package/rihal/skills/actions/4-implementation/rihal-retrospective/workflow.md +1479 -0
- package/rihal/skills/actions/4-implementation/rihal-scaffold-project/SKILL.md +77 -0
- package/rihal/skills/actions/4-implementation/rihal-scaffold-project/steps/step-01-target.md +17 -0
- package/rihal/skills/actions/4-implementation/rihal-scaffold-project/steps/step-02-safety.md +35 -0
- package/rihal/skills/actions/4-implementation/rihal-scaffold-project/steps/step-03-clone.md +50 -0
- package/rihal/skills/actions/4-implementation/rihal-scaffold-project/steps/step-04-post-setup.md +44 -0
- package/rihal/skills/actions/4-implementation/rihal-sprint-planning/SKILL.md +35 -0
- package/rihal/skills/actions/4-implementation/rihal-sprint-planning/checklist.md +43 -0
- package/rihal/skills/actions/4-implementation/rihal-sprint-planning/sprint-status-template.yaml +56 -0
- package/rihal/skills/actions/4-implementation/rihal-sprint-planning/workflow.md +284 -0
- package/rihal/skills/actions/4-implementation/rihal-sprint-status/SKILL.md +30 -0
- package/rihal/skills/actions/4-implementation/rihal-sprint-status/workflow.md +261 -0
- package/rihal/skills/agents/ahmed-hassani-director/SKILL.md +121 -0
- package/rihal/skills/agents/fatima-qa/SKILL.md +106 -0
- package/rihal/skills/agents/fatima-qa/skill-manifest.yaml +11 -0
- package/rihal/skills/agents/haitham-frontend/SKILL.md +120 -0
- package/rihal/skills/agents/hanzla-engineer/SKILL.md +109 -0
- package/rihal/skills/agents/hanzla-engineer/skill-manifest.yaml +11 -0
- package/rihal/skills/agents/hussain-pm/SKILL.md +107 -0
- package/rihal/skills/agents/hussain-pm/skill-manifest.yaml +11 -0
- package/rihal/skills/agents/hussain-sm/SKILL.md +104 -0
- package/rihal/skills/agents/hussain-sm/skill-manifest.yaml +11 -0
- package/rihal/skills/agents/layla-designer/SKILL.md +96 -0
- package/rihal/skills/agents/layla-designer/skill-manifest.yaml +11 -0
- package/rihal/skills/agents/majlis-council/SKILL.md +179 -0
- package/rihal/skills/agents/mariam-marketing/SKILL.md +133 -0
- package/rihal/skills/agents/nasser-eng-manager/SKILL.md +125 -0
- package/rihal/skills/agents/noor-writer/SKILL.md +104 -0
- package/rihal/skills/agents/noor-writer/explain-concept.md +20 -0
- package/rihal/skills/agents/noor-writer/mermaid-gen.md +20 -0
- package/rihal/skills/agents/noor-writer/skill-manifest.yaml +11 -0
- package/rihal/skills/agents/noor-writer/validate-doc.md +19 -0
- package/rihal/skills/agents/noor-writer/write-document.md +20 -0
- package/rihal/skills/agents/raees-orchestrator/SKILL.md +154 -0
- package/rihal/skills/agents/sadiq-analyst/SKILL.md +106 -0
- package/rihal/skills/agents/sadiq-analyst/skill-manifest.yaml +11 -0
- package/rihal/skills/agents/waleed-architect/SKILL.md +106 -0
- package/rihal/skills/agents/waleed-architect/skill-manifest.yaml +11 -0
- package/rihal/skills/agents/yousef-backend/SKILL.md +136 -0
- package/rihal/skills/agents/zahra-branding/SKILL.md +141 -0
- package/rihal/skills/agents/zayd-ml/SKILL.md +124 -0
- package/rihal/skills/core/module-help.csv +11 -0
- package/rihal/skills/core/module.yaml +25 -0
- package/rihal/skills/core/rihal-advanced-elicitation/SKILL.md +155 -0
- package/rihal/skills/core/rihal-advanced-elicitation/methods.csv +51 -0
- package/rihal/skills/core/rihal-advanced-elicitation/rihal-advanced-elicitation/SKILL.md +148 -0
- package/rihal/skills/core/rihal-advanced-elicitation/rihal-advanced-elicitation/methods.csv +51 -0
- package/rihal/skills/core/rihal-brainstorming/SKILL.md +82 -0
- package/rihal/skills/core/rihal-brainstorming/brain-methods.csv +62 -0
- package/rihal/skills/core/rihal-brainstorming/steps/step-01-session-setup.md +214 -0
- package/rihal/skills/core/rihal-brainstorming/steps/step-01b-continue.md +124 -0
- package/rihal/skills/core/rihal-brainstorming/steps/step-02a-user-selected.md +229 -0
- package/rihal/skills/core/rihal-brainstorming/steps/step-02b-ai-recommended.md +239 -0
- package/rihal/skills/core/rihal-brainstorming/steps/step-02c-random-selection.md +211 -0
- package/rihal/skills/core/rihal-brainstorming/steps/step-02d-progressive-flow.md +266 -0
- package/rihal/skills/core/rihal-brainstorming/steps/step-03-technique-execution.md +401 -0
- package/rihal/skills/core/rihal-brainstorming/steps/step-04-idea-organization.md +305 -0
- package/rihal/skills/core/rihal-brainstorming/template.md +15 -0
- package/rihal/skills/core/rihal-brainstorming/workflow.md +53 -0
- package/rihal/skills/core/rihal-clone-website/SKILL.md +395 -0
- package/rihal/skills/core/rihal-distillator/SKILL.md +205 -0
- package/rihal/skills/core/rihal-distillator/agents/distillate-compressor.md +116 -0
- package/rihal/skills/core/rihal-distillator/agents/round-trip-reconstructor.md +68 -0
- package/rihal/skills/core/rihal-distillator/resources/compression-rules.md +51 -0
- package/rihal/skills/core/rihal-distillator/resources/distillate-format-reference.md +227 -0
- package/rihal/skills/core/rihal-distillator/resources/splitting-strategy.md +78 -0
- package/rihal/skills/core/rihal-distillator/scripts/analyze_sources.py +300 -0
- package/rihal/skills/core/rihal-distillator/scripts/tests/test_analyze_sources.py +204 -0
- package/rihal/skills/core/rihal-editorial-review-prose/SKILL.md +108 -0
- package/rihal/skills/core/rihal-editorial-review-structure/SKILL.md +193 -0
- package/rihal/skills/core/rihal-help/SKILL.md +91 -0
- package/rihal/skills/core/rihal-index-docs/SKILL.md +80 -0
- package/rihal/skills/core/rihal-init/SKILL.md +119 -0
- package/rihal/skills/core/rihal-init/resources/core-module.yaml +25 -0
- package/rihal/skills/core/rihal-init/scripts/rihal_init.py +593 -0
- package/rihal/skills/core/rihal-init/scripts/tests/test_rihal_init.py +329 -0
- package/rihal/skills/core/rihal-party-mode/SKILL.md +77 -0
- package/rihal/skills/core/rihal-party-mode/steps/step-01-agent-loading.md +138 -0
- package/rihal/skills/core/rihal-party-mode/steps/step-02-discussion-orchestration.md +187 -0
- package/rihal/skills/core/rihal-party-mode/steps/step-03-graceful-exit.md +167 -0
- package/rihal/skills/core/rihal-party-mode/workflow.md +190 -0
- package/rihal/skills/core/rihal-review-adversarial-general/SKILL.md +55 -0
- package/rihal/skills/core/rihal-review-edge-case-hunter/SKILL.md +81 -0
- package/rihal/skills/core/rihal-shard-doc/SKILL.md +119 -0
- package/rihal/skills/core/rihal-shard-doc/rihal-shard-doc/SKILL.md +122 -0
- package/rihal/team.yaml +343 -0
- package/rihal/templates/UI-SPEC.md +127 -0
- package/rihal/templates/documentation-requirements.csv +11 -0
- package/rihal/templates/github/bug-template.md +53 -0
- package/rihal/templates/github/epic-template.md +57 -0
- package/rihal/templates/github/feature-template.md +55 -0
- package/rihal/templates/github/task-template.md +52 -0
- package/rihal/templates/milestone.md +147 -0
- package/rihal/templates/projects/api-backend/PROJECT.md +37 -0
- package/rihal/templates/projects/api-backend/REQUIREMENTS.md +38 -0
- package/rihal/templates/projects/api-backend/ROADMAP.md +92 -0
- package/rihal/templates/projects/api-backend/template.yaml +17 -0
- package/rihal/templates/projects/mobile-app/PROJECT.md +37 -0
- package/rihal/templates/projects/mobile-app/REQUIREMENTS.md +32 -0
- package/rihal/templates/projects/mobile-app/ROADMAP.md +93 -0
- package/rihal/templates/projects/mobile-app/template.yaml +17 -0
- package/rihal/templates/projects/saas-b2b/PROJECT.md +40 -0
- package/rihal/templates/projects/saas-b2b/REQUIREMENTS.md +38 -0
- package/rihal/templates/projects/saas-b2b/ROADMAP.md +95 -0
- package/rihal/templates/projects/saas-b2b/template.yaml +18 -0
- package/rihal/templates/settings-hooks.json +36 -0
- package/rihal/templates/sprint.md +70 -0
- package/rihal/workflows/add-phase.md +112 -0
- package/rihal/workflows/add-tests.md +351 -0
- package/rihal/workflows/add-todo.md +181 -0
- package/rihal/workflows/analyze-dependencies.md +138 -0
- package/rihal/workflows/audit-fix.md +190 -0
- package/rihal/workflows/audit-milestone.md +155 -0
- package/rihal/workflows/audit-uat.md +109 -0
- package/rihal/workflows/autonomous.md +992 -0
- package/rihal/workflows/brainstorm.md +203 -0
- package/rihal/workflows/chain.md +188 -0
- package/rihal/workflows/check-implementation-readiness.md +193 -0
- package/rihal/workflows/check-todos.md +177 -0
- package/rihal/workflows/cleanup.md +152 -0
- package/rihal/workflows/code-review-fix.md +529 -0
- package/rihal/workflows/code-review.md +566 -0
- package/rihal/workflows/complete-milestone.md +836 -0
- package/rihal/workflows/config.md +105 -0
- package/rihal/workflows/correct-course.md +190 -0
- package/rihal/workflows/council.md +565 -0
- package/rihal/workflows/create-epics-and-stories.md +373 -0
- package/rihal/workflows/create-story.md +297 -0
- package/rihal/workflows/dashboard.md +102 -0
- package/rihal/workflows/debug.md +256 -0
- package/rihal/workflows/decisions.md +107 -0
- package/rihal/workflows/dev-story.md +432 -0
- package/rihal/workflows/diff.md +74 -0
- package/rihal/workflows/discuss-phase-power.md +325 -0
- package/rihal/workflows/discuss-phase.md +1201 -0
- package/rihal/workflows/discuss.md +227 -0
- package/rihal/workflows/do.md +175 -0
- package/rihal/workflows/docs-update.md +261 -0
- package/rihal/workflows/document-project.md +180 -0
- package/rihal/workflows/enable-hooks.md +102 -0
- package/rihal/workflows/execute-sprint.md +514 -0
- package/rihal/workflows/execute.md +1478 -0
- package/rihal/workflows/explore.md +171 -0
- package/rihal/workflows/export-to-github.md +174 -0
- package/rihal/workflows/forensics.md +201 -0
- package/rihal/workflows/from-template.md +173 -0
- package/rihal/workflows/health.md +194 -0
- package/rihal/workflows/help.md +318 -0
- package/rihal/workflows/import.md +306 -0
- package/rihal/workflows/inbox.md +418 -0
- package/rihal/workflows/init.md +245 -0
- package/rihal/workflows/insert-phase.md +116 -0
- package/rihal/workflows/install.md +85 -0
- package/rihal/workflows/karpathy-audit.md +409 -0
- package/rihal/workflows/list-plans.md +146 -0
- package/rihal/workflows/list-workspaces.md +115 -0
- package/rihal/workflows/map-codebase.md +449 -0
- package/rihal/workflows/milestone-summary.md +206 -0
- package/rihal/workflows/new-milestone.md +616 -0
- package/rihal/workflows/new-project-research.md +262 -0
- package/rihal/workflows/new-project-roadmap.md +446 -0
- package/rihal/workflows/new-project.md +1503 -0
- package/rihal/workflows/new-workspace.md +167 -0
- package/rihal/workflows/next.md +162 -0
- package/rihal/workflows/note.md +156 -0
- package/rihal/workflows/notify-test.md +113 -0
- package/rihal/workflows/pause-work.md +243 -0
- package/rihal/workflows/plan-milestone-gaps.md +273 -0
- package/rihal/workflows/plan.md +1262 -0
- package/rihal/workflows/plant-seed.md +169 -0
- package/rihal/workflows/pr-branch.md +129 -0
- package/rihal/workflows/profile-user.md +162 -0
- package/rihal/workflows/progress.md +184 -0
- package/rihal/workflows/quick.md +105 -0
- package/rihal/workflows/remove-phase.md +155 -0
- package/rihal/workflows/remove-workspace.md +158 -0
- package/rihal/workflows/replay.md +160 -0
- package/rihal/workflows/rerun.md +77 -0
- package/rihal/workflows/research-phase.md +82 -0
- package/rihal/workflows/resume-work.md +326 -0
- package/rihal/workflows/review-adversarial.md +180 -0
- package/rihal/workflows/review-edge-case-hunter.md +214 -0
- package/rihal/workflows/review.md +281 -0
- package/rihal/workflows/scan.md +135 -0
- package/rihal/workflows/secure-phase.md +196 -0
- package/rihal/workflows/session-report.md +187 -0
- package/rihal/workflows/settings.md +185 -0
- package/rihal/workflows/ship.md +237 -0
- package/rihal/workflows/show.md +63 -0
- package/rihal/workflows/sprint-planning.md +166 -0
- package/rihal/workflows/sprint-status.md +124 -0
- package/rihal/workflows/stats.md +141 -0
- package/rihal/workflows/status.md +116 -0
- package/rihal/workflows/ui-phase.md +148 -0
- package/rihal/workflows/ui-review.md +130 -0
- package/rihal/workflows/undo.md +426 -0
- package/rihal/workflows/update.md +185 -0
- package/rihal/workflows/validate-phase.md +174 -0
- package/rihal/workflows/verify-phase.md +375 -0
- package/rihal/workflows/verify-work.md +717 -0
- package/rihal/workflows/why.md +130 -0
- package/rihal/workflows/workstream.md +197 -0
- package/server/dashboard.js +632 -0
|
@@ -0,0 +1,1016 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* rihal-code github-sync ā sync .rihal/ state to GitHub as issues
|
|
3
|
+
*
|
|
4
|
+
* Creates milestones (phases), epics (issues), and stories (issues) with
|
|
5
|
+
* proper parent-child linking via GitHub's native issue references.
|
|
6
|
+
* Labels are NOT created by default ā opt in with --with-labels.
|
|
7
|
+
* Dry-run by default. Mutations always require --execute.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* rihal-code github-sync # dry-run preview
|
|
11
|
+
* rihal-code github-sync --execute # actually create issues
|
|
12
|
+
*
|
|
13
|
+
* Granular targeting (push specific items):
|
|
14
|
+
* --phase=phase-02 push one phase (all its epics + stories)
|
|
15
|
+
* --sprint=sprint-01 push stories belonging to one sprint
|
|
16
|
+
* --epic=epic-1-auth push one epic and its child stories
|
|
17
|
+
* --story=story-1-1-login push one story
|
|
18
|
+
*
|
|
19
|
+
* Options:
|
|
20
|
+
* --repo=owner/name target a specific repo (otherwise auto-detect)
|
|
21
|
+
* --with-labels also create/ensure the Rihal label taxonomy
|
|
22
|
+
* --project also create a Project v2 board
|
|
23
|
+
* --yes skip the confirmation prompt (denied in yolo mode)
|
|
24
|
+
* --force-yolo allow --yes to apply in yolo mode (explicit opt-in)
|
|
25
|
+
*
|
|
26
|
+
* Update opt-outs:
|
|
27
|
+
* --no-update create-only mode ā never touch existing items
|
|
28
|
+
* --no-update-body don't rewrite bodies
|
|
29
|
+
* --no-update-labels don't touch labels
|
|
30
|
+
* --no-close don't close issues when local marks them done
|
|
31
|
+
*
|
|
32
|
+
* Safety:
|
|
33
|
+
* - Mutations always require --execute AND gh auth
|
|
34
|
+
* - In communication_mode=guided: asks to confirm before mutations
|
|
35
|
+
* (skippable with --yes)
|
|
36
|
+
* - In communication_mode=yolo: STILL asks to confirm before GitHub
|
|
37
|
+
* mutations unless BOTH --yes AND --force-yolo are passed
|
|
38
|
+
* - Per AGENTS.md: never auto-pushes, every mutation is explicit
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
const fs = require('fs');
|
|
42
|
+
const path = require('path');
|
|
43
|
+
const crypto = require('crypto');
|
|
44
|
+
const gh = require('./lib/github.cjs');
|
|
45
|
+
const { askText, PromptAbortError } = require('./lib/prompts.cjs');
|
|
46
|
+
const { writeJsonAtomic } = require('./lib/fsutil.cjs');
|
|
47
|
+
const { loadConfig } = require('./lib/config.cjs');
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Hash a string ā used to detect content changes between syncs.
|
|
51
|
+
* Cheap and deterministic; nothing security-sensitive here.
|
|
52
|
+
*/
|
|
53
|
+
function contentHash(str) {
|
|
54
|
+
return crypto.createHash('sha256').update(str || '').digest('hex').slice(0, 12);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ---------- Arg parsing ----------
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Simple flag philosophy:
|
|
61
|
+
* - Default: smart sync ā create missing, update changed, close completed
|
|
62
|
+
* - User only needs to remember: dry-run (default) vs --execute
|
|
63
|
+
* - All narrowing flags are optional escape hatches for advanced users
|
|
64
|
+
*
|
|
65
|
+
* User can think of it as: "sync my project to GitHub" ā that's the whole command.
|
|
66
|
+
*/
|
|
67
|
+
function parseArgs(args) {
|
|
68
|
+
const opts = {
|
|
69
|
+
execute: false,
|
|
70
|
+
dryRun: true,
|
|
71
|
+
repo: null,
|
|
72
|
+
only: null, // narrow the scope (advanced): labels | milestones | epics | stories
|
|
73
|
+
phase: null, // sync only one phase
|
|
74
|
+
sprint: null, // sync only one sprint (filters stories)
|
|
75
|
+
epic: null, // sync only one epic + its child stories
|
|
76
|
+
story: null, // sync only one story
|
|
77
|
+
withLabels: false, // opt-in to label creation (default off per user)
|
|
78
|
+
createProject: false, // also create a Project v2 board
|
|
79
|
+
yes: false, // skip interactive confirmation
|
|
80
|
+
forceYolo: false, // allow --yes to apply in yolo mode
|
|
81
|
+
|
|
82
|
+
// Smart default: enable all update operations.
|
|
83
|
+
// These flags let advanced users OPT OUT, not opt in.
|
|
84
|
+
updateBody: true,
|
|
85
|
+
updateLabels: true,
|
|
86
|
+
updateMilestone: true,
|
|
87
|
+
updateState: true,
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
for (const arg of args) {
|
|
91
|
+
// The two most common flags
|
|
92
|
+
if (arg === '--execute' || arg === '-e') {
|
|
93
|
+
opts.execute = true;
|
|
94
|
+
opts.dryRun = false;
|
|
95
|
+
} else if (arg === '--dry-run') {
|
|
96
|
+
opts.dryRun = true;
|
|
97
|
+
opts.execute = false;
|
|
98
|
+
} else if (arg === '--yes' || arg === '-y') {
|
|
99
|
+
opts.yes = true;
|
|
100
|
+
} else if (arg === '--force-yolo') {
|
|
101
|
+
opts.forceYolo = true;
|
|
102
|
+
} else if (arg === '--with-labels') {
|
|
103
|
+
opts.withLabels = true;
|
|
104
|
+
} else if (arg === '--project') {
|
|
105
|
+
opts.createProject = true;
|
|
106
|
+
}
|
|
107
|
+
// Escape hatches ā disable specific update types
|
|
108
|
+
else if (arg === '--no-update') {
|
|
109
|
+
// Create-only mode (the old default) ā disables ALL updates
|
|
110
|
+
opts.updateBody = false;
|
|
111
|
+
opts.updateLabels = false;
|
|
112
|
+
opts.updateMilestone = false;
|
|
113
|
+
opts.updateState = false;
|
|
114
|
+
} else if (arg === '--no-update-body') {
|
|
115
|
+
opts.updateBody = false;
|
|
116
|
+
} else if (arg === '--no-update-labels') {
|
|
117
|
+
opts.updateLabels = false;
|
|
118
|
+
} else if (arg === '--no-close') {
|
|
119
|
+
opts.updateState = false;
|
|
120
|
+
}
|
|
121
|
+
// Scope narrowing
|
|
122
|
+
else if (arg.startsWith('--repo=')) {
|
|
123
|
+
opts.repo = arg.slice('--repo='.length);
|
|
124
|
+
} else if (arg.startsWith('--only=')) {
|
|
125
|
+
opts.only = arg.slice('--only='.length);
|
|
126
|
+
} else if (arg.startsWith('--phase=')) {
|
|
127
|
+
opts.phase = arg.slice('--phase='.length);
|
|
128
|
+
} else if (arg.startsWith('--sprint=')) {
|
|
129
|
+
opts.sprint = arg.slice('--sprint='.length);
|
|
130
|
+
} else if (arg.startsWith('--epic=')) {
|
|
131
|
+
opts.epic = arg.slice('--epic='.length);
|
|
132
|
+
} else if (arg.startsWith('--story=')) {
|
|
133
|
+
opts.story = arg.slice('--story='.length);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Master switch: updateEnabled is true if ANY update flag is true
|
|
138
|
+
opts.updateEnabled = opts.updateBody || opts.updateLabels || opts.updateMilestone || opts.updateState;
|
|
139
|
+
|
|
140
|
+
return opts;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Parse YAML-ish frontmatter from the top of a markdown file.
|
|
145
|
+
* Used to extract explicit epic/sprint linking from story files.
|
|
146
|
+
* Returns an object of key/value strings, or {} if no frontmatter block.
|
|
147
|
+
*/
|
|
148
|
+
function extractFrontmatter(content) {
|
|
149
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
150
|
+
if (!match) return {};
|
|
151
|
+
const fm = {};
|
|
152
|
+
for (const line of match[1].split(/\r?\n/)) {
|
|
153
|
+
const m = line.match(/^([\w_-]+)\s*:\s*(.*)$/);
|
|
154
|
+
if (m) fm[m[1].trim()] = m[2].trim().replace(/^["']|["']$/g, '');
|
|
155
|
+
}
|
|
156
|
+
return fm;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Parse .rihal/phases/{phase}/sprints.md if present and return a map of
|
|
161
|
+
* sprint-id ā story-ids (based on "- [ ] story-X-Y" list entries under
|
|
162
|
+
* each sprint section). Used by --sprint=ID filtering.
|
|
163
|
+
*
|
|
164
|
+
* Sprint section convention:
|
|
165
|
+
* ## Sprint 1 ā {goal}
|
|
166
|
+
* - [ ] story-1-1-login
|
|
167
|
+
* - [ ] story-1-2-signup
|
|
168
|
+
*/
|
|
169
|
+
function parseSprintsFile(sprintsContent) {
|
|
170
|
+
if (!sprintsContent) return {};
|
|
171
|
+
const sprintMap = {};
|
|
172
|
+
let currentSprint = null;
|
|
173
|
+
for (const line of sprintsContent.split(/\r?\n/)) {
|
|
174
|
+
const header = line.match(/^##\s+Sprint\s+(\S+)/i);
|
|
175
|
+
if (header) {
|
|
176
|
+
currentSprint = `sprint-${header[1].replace(/[^\w-]/g, '')}`;
|
|
177
|
+
sprintMap[currentSprint] = [];
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
if (currentSprint) {
|
|
181
|
+
const item = line.match(/^\s*-\s*\[[ xX]\]\s+(\S+)/);
|
|
182
|
+
if (item) sprintMap[currentSprint].push(item[1]);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return sprintMap;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// ---------- Discover .rihal/ content ----------
|
|
189
|
+
|
|
190
|
+
function loadState(cwd) {
|
|
191
|
+
const statePath = path.join(cwd, '.rihal/state.json');
|
|
192
|
+
if (!fs.existsSync(statePath)) {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
return JSON.parse(fs.readFileSync(statePath, 'utf8'));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function discoverPhases(cwd) {
|
|
199
|
+
const phasesDir = path.join(cwd, '.rihal/phases');
|
|
200
|
+
if (!fs.existsSync(phasesDir)) return [];
|
|
201
|
+
|
|
202
|
+
const phases = [];
|
|
203
|
+
for (const entry of fs.readdirSync(phasesDir, { withFileTypes: true })) {
|
|
204
|
+
if (!entry.isDirectory()) continue;
|
|
205
|
+
const phaseDir = path.join(phasesDir, entry.name);
|
|
206
|
+
const briefPath = path.join(phaseDir, 'brief.md');
|
|
207
|
+
const sprintsPath = path.join(phaseDir, 'sprints.md');
|
|
208
|
+
const storiesDir = path.join(phaseDir, 'stories');
|
|
209
|
+
const tasksDir = path.join(phaseDir, 'tasks');
|
|
210
|
+
|
|
211
|
+
const sprintsContent = fs.existsSync(sprintsPath)
|
|
212
|
+
? fs.readFileSync(sprintsPath, 'utf8')
|
|
213
|
+
: null;
|
|
214
|
+
|
|
215
|
+
const phase = {
|
|
216
|
+
id: entry.name,
|
|
217
|
+
brief: fs.existsSync(briefPath) ? fs.readFileSync(briefPath, 'utf8') : null,
|
|
218
|
+
sprints: sprintsContent,
|
|
219
|
+
sprintMap: parseSprintsFile(sprintsContent),
|
|
220
|
+
stories: [],
|
|
221
|
+
epics: [],
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
if (fs.existsSync(storiesDir)) {
|
|
225
|
+
for (const file of fs.readdirSync(storiesDir)) {
|
|
226
|
+
if (!file.endsWith('.md')) continue;
|
|
227
|
+
const content = fs.readFileSync(path.join(storiesDir, file), 'utf8');
|
|
228
|
+
const fm = extractFrontmatter(content);
|
|
229
|
+
const id = file.replace('.md', '');
|
|
230
|
+
// Figure out which epic this story belongs to: prefer explicit
|
|
231
|
+
// frontmatter, fall back to "story-X-..." ā "epic-X-..." naming
|
|
232
|
+
// convention so existing projects without frontmatter still link.
|
|
233
|
+
let parentEpic = fm.epic || null;
|
|
234
|
+
if (!parentEpic) {
|
|
235
|
+
const m = id.match(/^story-(\d+)/);
|
|
236
|
+
if (m) parentEpic = `epic-${m[1]}`;
|
|
237
|
+
}
|
|
238
|
+
// Figure out which sprint this story belongs to: explicit
|
|
239
|
+
// frontmatter wins, else look it up in the sprint map.
|
|
240
|
+
let sprintId = fm.sprint || null;
|
|
241
|
+
if (!sprintId) {
|
|
242
|
+
for (const [sid, storyList] of Object.entries(phase.sprintMap)) {
|
|
243
|
+
if (storyList.some((s) => s === id || id.startsWith(s))) {
|
|
244
|
+
sprintId = sid;
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
phase.stories.push({
|
|
250
|
+
id,
|
|
251
|
+
file,
|
|
252
|
+
content,
|
|
253
|
+
title: extractTitle(content) || id,
|
|
254
|
+
parentEpic,
|
|
255
|
+
sprintId,
|
|
256
|
+
frontmatter: fm,
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (fs.existsSync(tasksDir)) {
|
|
262
|
+
for (const file of fs.readdirSync(tasksDir)) {
|
|
263
|
+
if (!file.endsWith('.md')) continue;
|
|
264
|
+
const content = fs.readFileSync(path.join(tasksDir, file), 'utf8');
|
|
265
|
+
const fm = extractFrontmatter(content);
|
|
266
|
+
phase.epics.push({
|
|
267
|
+
id: file.replace('.md', ''),
|
|
268
|
+
file,
|
|
269
|
+
content,
|
|
270
|
+
title: extractTitle(content) || file.replace('.md', ''),
|
|
271
|
+
frontmatter: fm,
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
phases.push(phase);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return phases;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Apply granular --sprint/--epic/--story filters to the discovered phases.
|
|
284
|
+
* Mutates a shallow copy ā original discovery result is not touched.
|
|
285
|
+
* Returns a new phases array where only the requested items remain.
|
|
286
|
+
*/
|
|
287
|
+
function applyGranularFilters(phases, opts) {
|
|
288
|
+
// No filters ā return as-is
|
|
289
|
+
if (!opts.sprint && !opts.epic && !opts.story) return phases;
|
|
290
|
+
|
|
291
|
+
const filtered = phases.map((p) => ({
|
|
292
|
+
...p,
|
|
293
|
+
epics: [...p.epics],
|
|
294
|
+
stories: [...p.stories],
|
|
295
|
+
}));
|
|
296
|
+
|
|
297
|
+
if (opts.sprint) {
|
|
298
|
+
for (const p of filtered) {
|
|
299
|
+
// Keep only stories whose sprintId matches
|
|
300
|
+
p.stories = p.stories.filter((s) => s.sprintId === opts.sprint);
|
|
301
|
+
// Keep only epics that have at least one remaining story or whose id
|
|
302
|
+
// the user might also be interested in (conservative: keep all epics
|
|
303
|
+
// in this phase so child stories have a visible parent reference)
|
|
304
|
+
// Actually: if filtering by sprint, user wants the sprint's work ā
|
|
305
|
+
// stories only. Drop epics unless they're referenced by a remaining
|
|
306
|
+
// story.
|
|
307
|
+
const liveEpicIds = new Set(p.stories.map((s) => s.parentEpic).filter(Boolean));
|
|
308
|
+
p.epics = p.epics.filter((e) => liveEpicIds.has(e.id));
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (opts.epic) {
|
|
313
|
+
for (const p of filtered) {
|
|
314
|
+
p.epics = p.epics.filter((e) => e.id === opts.epic);
|
|
315
|
+
// Keep stories whose parentEpic matches
|
|
316
|
+
p.stories = p.stories.filter((s) => s.parentEpic === opts.epic);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (opts.story) {
|
|
321
|
+
for (const p of filtered) {
|
|
322
|
+
p.stories = p.stories.filter((s) => s.id === opts.story);
|
|
323
|
+
// Keep any epic a surviving story points at (so link target exists)
|
|
324
|
+
const parents = new Set(p.stories.map((s) => s.parentEpic).filter(Boolean));
|
|
325
|
+
p.epics = p.epics.filter((e) => parents.has(e.id));
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Drop phases that ended up completely empty after filtering
|
|
330
|
+
return filtered.filter(
|
|
331
|
+
(p) => p.epics.length > 0 || p.stories.length > 0,
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function extractTitle(markdown) {
|
|
336
|
+
const match = markdown.match(/^#\s+(.+)$/m);
|
|
337
|
+
return match ? match[1].trim() : null;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// ---------- Load/save sync map (for idempotency) ----------
|
|
341
|
+
|
|
342
|
+
function loadSyncMap(cwd) {
|
|
343
|
+
const mapPath = path.join(cwd, '.rihal/integrations/github-map.json');
|
|
344
|
+
if (!fs.existsSync(mapPath)) {
|
|
345
|
+
return { phases: {}, epics: {}, stories: {}, project: null, labels: [] };
|
|
346
|
+
}
|
|
347
|
+
return JSON.parse(fs.readFileSync(mapPath, 'utf8'));
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function saveSyncMap(cwd, map) {
|
|
351
|
+
const mapPath = path.join(cwd, '.rihal/integrations/github-map.json');
|
|
352
|
+
// Atomic: partial writes on Ctrl+C would desync our localāremote mapping
|
|
353
|
+
// and orphan issues. writeJsonAtomic ensures the file is either old or new.
|
|
354
|
+
writeJsonAtomic(mapPath, map);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// ---------- Main sync flow ----------
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Detect which fields of an existing issue need updating.
|
|
361
|
+
* Returns an object with only the changed fields set, or null if nothing changed.
|
|
362
|
+
* Never modifies GitHub directly ā this is pure diffing.
|
|
363
|
+
*/
|
|
364
|
+
function diffIssue(existing, desired, opts) {
|
|
365
|
+
const updates = {};
|
|
366
|
+
let hasChanges = false;
|
|
367
|
+
|
|
368
|
+
if (opts.updateBody && desired.body !== undefined && existing.body !== desired.body) {
|
|
369
|
+
updates.body = desired.body;
|
|
370
|
+
hasChanges = true;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (opts.updateLabels && desired.labels) {
|
|
374
|
+
const existingLabelNames = new Set((existing.labels || []).map((l) => l.name));
|
|
375
|
+
const desiredLabelNames = new Set(desired.labels);
|
|
376
|
+
const toAdd = [...desiredLabelNames].filter((l) => !existingLabelNames.has(l));
|
|
377
|
+
const toRemove = [...existingLabelNames].filter(
|
|
378
|
+
(l) => !desiredLabelNames.has(l) && (l.startsWith('status:') || l.startsWith('priority:') || l === 'epic' || l.startsWith('type:')),
|
|
379
|
+
);
|
|
380
|
+
if (toAdd.length > 0) {
|
|
381
|
+
updates.addLabels = toAdd;
|
|
382
|
+
hasChanges = true;
|
|
383
|
+
}
|
|
384
|
+
if (toRemove.length > 0) {
|
|
385
|
+
updates.removeLabels = toRemove;
|
|
386
|
+
hasChanges = true;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
if (opts.updateMilestone && desired.milestone !== undefined) {
|
|
391
|
+
const existingMilestone = existing.milestone ? existing.milestone.number : null;
|
|
392
|
+
if (existingMilestone !== desired.milestone) {
|
|
393
|
+
updates.milestone = desired.milestone;
|
|
394
|
+
hasChanges = true;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
if (opts.updateState && desired.state !== undefined && existing.state !== desired.state) {
|
|
399
|
+
updates.state = desired.state;
|
|
400
|
+
hasChanges = true;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return hasChanges ? updates : null;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
async function main(args) {
|
|
407
|
+
const opts = parseArgs(args);
|
|
408
|
+
const cwd = process.cwd();
|
|
409
|
+
const config = loadConfig(cwd);
|
|
410
|
+
const communicationMode = config.communication_mode || 'guided';
|
|
411
|
+
|
|
412
|
+
console.log(`\nš Rihal Code ā GitHub Sync`);
|
|
413
|
+
console.log(` Mode: ${opts.dryRun ? 'DRY-RUN (preview only, nothing is sent)' : 'EXECUTE'}`);
|
|
414
|
+
console.log(` Comms mode: ${communicationMode}`);
|
|
415
|
+
console.log(` Scope: ${opts.only || 'full (create + update existing)'}`);
|
|
416
|
+
console.log(` Labels: ${opts.withLabels ? 'will create/ensure taxonomy' : 'skipped (pass --with-labels to enable)'}`);
|
|
417
|
+
if (!opts.updateEnabled) console.log(` Note: --no-update passed ā create-only mode`);
|
|
418
|
+
if (opts.phase) console.log(` Phase filter: ${opts.phase}`);
|
|
419
|
+
if (opts.sprint) console.log(` Sprint filter: ${opts.sprint}`);
|
|
420
|
+
if (opts.epic) console.log(` Epic filter: ${opts.epic}`);
|
|
421
|
+
if (opts.story) console.log(` Story filter: ${opts.story}`);
|
|
422
|
+
console.log();
|
|
423
|
+
|
|
424
|
+
// ------ Precondition: gh auth ------
|
|
425
|
+
const auth = gh.checkAuth();
|
|
426
|
+
if (!auth.authenticated) {
|
|
427
|
+
console.error(`ā gh CLI not authenticated.`);
|
|
428
|
+
console.error(` Run: gh auth login`);
|
|
429
|
+
console.error(` Error: ${auth.error || 'unknown'}`);
|
|
430
|
+
process.exit(1);
|
|
431
|
+
}
|
|
432
|
+
console.log(` ā Authenticated as ${auth.account}`);
|
|
433
|
+
|
|
434
|
+
// ------ Precondition: target repo ------
|
|
435
|
+
let repo = opts.repo;
|
|
436
|
+
if (!repo) {
|
|
437
|
+
const detected = gh.detectRepo(cwd);
|
|
438
|
+
if (!detected) {
|
|
439
|
+
console.error(`ā Could not detect GitHub repo. Run from a git repo or pass --repo=owner/name`);
|
|
440
|
+
process.exit(1);
|
|
441
|
+
}
|
|
442
|
+
repo = detected.nameWithOwner;
|
|
443
|
+
}
|
|
444
|
+
console.log(` ā Target repo: ${repo}`);
|
|
445
|
+
|
|
446
|
+
// ------ Precondition: .rihal/ exists ------
|
|
447
|
+
const state = loadState(cwd);
|
|
448
|
+
if (!state) {
|
|
449
|
+
console.error(`ā No .rihal/state.json found. Run 'rihal-code init' first.`);
|
|
450
|
+
process.exit(1);
|
|
451
|
+
}
|
|
452
|
+
console.log(` ā Project: ${state.project_name || '(unnamed)'}`);
|
|
453
|
+
|
|
454
|
+
// ------ Discover phases ------
|
|
455
|
+
let phases = discoverPhases(cwd);
|
|
456
|
+
if (opts.phase) {
|
|
457
|
+
phases = phases.filter((p) => p.id === opts.phase);
|
|
458
|
+
if (phases.length === 0) {
|
|
459
|
+
console.error(`ā Phase '${opts.phase}' not found.`);
|
|
460
|
+
process.exit(1);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// Apply granular filters (sprint/epic/story) AFTER phase filter
|
|
465
|
+
phases = applyGranularFilters(phases, opts);
|
|
466
|
+
|
|
467
|
+
if (phases.length === 0) {
|
|
468
|
+
if (opts.sprint || opts.epic || opts.story) {
|
|
469
|
+
const filter = opts.sprint
|
|
470
|
+
? `sprint '${opts.sprint}'`
|
|
471
|
+
: opts.epic
|
|
472
|
+
? `epic '${opts.epic}'`
|
|
473
|
+
: `story '${opts.story}'`;
|
|
474
|
+
console.error(`ā No items matched ${filter}.`);
|
|
475
|
+
console.error(` Check the filter value or run without filters to see available ids.`);
|
|
476
|
+
process.exit(1);
|
|
477
|
+
}
|
|
478
|
+
console.error(`ā No phases found in .rihal/phases/.`);
|
|
479
|
+
process.exit(1);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
console.log(` ā Phases found: ${phases.length}`);
|
|
483
|
+
for (const p of phases) {
|
|
484
|
+
console.log(` - ${p.id} (${p.epics.length} epics, ${p.stories.length} stories)`);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// ------ Load existing sync map (for idempotency) ------
|
|
488
|
+
const syncMap = loadSyncMap(cwd);
|
|
489
|
+
const alreadySynced = {
|
|
490
|
+
phases: Object.keys(syncMap.phases).length,
|
|
491
|
+
epics: Object.keys(syncMap.epics).length,
|
|
492
|
+
stories: Object.keys(syncMap.stories).length,
|
|
493
|
+
};
|
|
494
|
+
if (alreadySynced.phases + alreadySynced.epics + alreadySynced.stories > 0) {
|
|
495
|
+
console.log(
|
|
496
|
+
` ā¹ Existing sync map: ${alreadySynced.phases} phases, ${alreadySynced.epics} epics, ${alreadySynced.stories} stories`,
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// ------ Build the plan ------
|
|
501
|
+
//
|
|
502
|
+
// Plan has two parts:
|
|
503
|
+
// 1. CREATE ā new items not in the sync map
|
|
504
|
+
// 2. UPDATE ā items already in sync map whose local content has changed
|
|
505
|
+
//
|
|
506
|
+
// The plan diffs local state against what we know was synced before.
|
|
507
|
+
// If updateEnabled is false, the update list stays empty (create-only mode).
|
|
508
|
+
//
|
|
509
|
+
// Label taxonomy follows the Rihal GitHub Standards (4 categories:
|
|
510
|
+
// Type / Priority / Status / Area). It is NOT created or assigned by
|
|
511
|
+
// default ā pass --with-labels to opt in. Without the flag, we focus
|
|
512
|
+
// on clean issue creation with proper parent-child linking and leave
|
|
513
|
+
// labeling to the user or a later explicit run.
|
|
514
|
+
const plan = {
|
|
515
|
+
labels: opts.withLabels ? [
|
|
516
|
+
// Type (what kind of work)
|
|
517
|
+
{ name: 'epic', color: '6f42c1', description: 'Strategic initiative spanning multiple sprints' },
|
|
518
|
+
{ name: 'type:feature', color: '0e8a16', description: 'New functionality' },
|
|
519
|
+
{ name: 'type:task', color: 'c5def5', description: 'Development work' },
|
|
520
|
+
{ name: 'type:bug', color: 'd73a4a', description: 'Something is broken' },
|
|
521
|
+
{ name: 'type:docs', color: '0075ca', description: 'Documentation' },
|
|
522
|
+
|
|
523
|
+
// Priority
|
|
524
|
+
{ name: 'priority:critical', color: 'b60205', description: 'Drop everything' },
|
|
525
|
+
{ name: 'priority:high', color: 'd93f0b', description: 'Important for sprint' },
|
|
526
|
+
{ name: 'priority:medium', color: 'fbca04', description: 'Standard priority' },
|
|
527
|
+
{ name: 'priority:low', color: '0e8a16', description: 'Nice to have' },
|
|
528
|
+
|
|
529
|
+
// Status (flow state)
|
|
530
|
+
{ name: 'status:backlog', color: 'c5def5', description: 'Not started' },
|
|
531
|
+
{ name: 'status:todo', color: '0075ca', description: 'Ready to start' },
|
|
532
|
+
{ name: 'status:in-progress', color: 'fbca04', description: 'Currently working' },
|
|
533
|
+
{ name: 'status:blocked', color: 'd73a4a', description: 'Cannot progress' },
|
|
534
|
+
{ name: 'status:review', color: '6f42c1', description: 'Code review needed' },
|
|
535
|
+
{ name: 'status:done', color: '0e8a16', description: 'Completed' },
|
|
536
|
+
|
|
537
|
+
// Area (team/layer)
|
|
538
|
+
{ name: 'FE', color: '1e3a8a', description: 'Frontend' },
|
|
539
|
+
{ name: 'BE', color: '0e8a16', description: 'Backend' },
|
|
540
|
+
{ name: 'ML', color: '6f42c1', description: 'Machine Learning' },
|
|
541
|
+
{ name: 'API', color: '0075ca', description: 'API / Backend services' },
|
|
542
|
+
{ name: 'Design', color: 'f59e0b', description: 'UI/UX design work' },
|
|
543
|
+
{ name: 'DevOps', color: 'fbca04', description: 'Infrastructure and deployment' },
|
|
544
|
+
{ name: 'QA', color: 'd73a4a', description: 'Quality assurance' },
|
|
545
|
+
{ name: 'Docs', color: 'c5def5', description: 'Documentation' },
|
|
546
|
+
] : [],
|
|
547
|
+
milestones: phases.filter((p) => !syncMap.phases[p.id]),
|
|
548
|
+
epics: phases.flatMap((p) =>
|
|
549
|
+
p.epics.filter((e) => !syncMap.epics[e.id]).map((e) => ({ ...e, phase: p.id })),
|
|
550
|
+
),
|
|
551
|
+
stories: phases.flatMap((p) =>
|
|
552
|
+
p.stories.filter((s) => !syncMap.stories[s.id]).map((s) => ({ ...s, phase: p.id })),
|
|
553
|
+
),
|
|
554
|
+
|
|
555
|
+
// Items that already exist on GitHub ā candidates for update.
|
|
556
|
+
// Only populated when updateEnabled is true.
|
|
557
|
+
updateEpics: opts.updateEnabled
|
|
558
|
+
? phases.flatMap((p) =>
|
|
559
|
+
p.epics.filter((e) => syncMap.epics[e.id]).map((e) => ({
|
|
560
|
+
...e,
|
|
561
|
+
phase: p.id,
|
|
562
|
+
issueNumber: syncMap.epics[e.id].issue_number,
|
|
563
|
+
lastSyncedAt: syncMap.epics[e.id].synced_at,
|
|
564
|
+
lastSyncedContentHash: syncMap.epics[e.id].content_hash,
|
|
565
|
+
})),
|
|
566
|
+
)
|
|
567
|
+
: [],
|
|
568
|
+
updateStories: opts.updateEnabled
|
|
569
|
+
? phases.flatMap((p) =>
|
|
570
|
+
p.stories.filter((s) => syncMap.stories[s.id]).map((s) => ({
|
|
571
|
+
...s,
|
|
572
|
+
phase: p.id,
|
|
573
|
+
issueNumber: syncMap.stories[s.id].issue_number,
|
|
574
|
+
lastSyncedAt: syncMap.stories[s.id].synced_at,
|
|
575
|
+
lastSyncedContentHash: syncMap.stories[s.id].content_hash,
|
|
576
|
+
})),
|
|
577
|
+
)
|
|
578
|
+
: [],
|
|
579
|
+
};
|
|
580
|
+
|
|
581
|
+
console.log(`\nš Plan:`);
|
|
582
|
+
if (opts.withLabels && (!opts.only || opts.only === 'labels')) {
|
|
583
|
+
console.log(` Labels to ensure: ${plan.labels.length}`);
|
|
584
|
+
}
|
|
585
|
+
if (!opts.only || opts.only === 'milestones') console.log(` Milestones to create: ${plan.milestones.length}`);
|
|
586
|
+
if (!opts.only || opts.only === 'epics') console.log(` Epics to create: ${plan.epics.length}`);
|
|
587
|
+
if (!opts.only || opts.only === 'stories') console.log(` Stories to create: ${plan.stories.length}`);
|
|
588
|
+
if (opts.updateEnabled) {
|
|
589
|
+
if (!opts.only || opts.only === 'epics') console.log(` Epics to check: ${plan.updateEpics.length} (existing, will update if changed)`);
|
|
590
|
+
if (!opts.only || opts.only === 'stories') console.log(` Stories to check: ${plan.updateStories.length} (existing, will update if changed)`);
|
|
591
|
+
}
|
|
592
|
+
if (opts.createProject) console.log(` Project v2: will create "${state.project_name || repo}"`);
|
|
593
|
+
console.log();
|
|
594
|
+
|
|
595
|
+
// ------ Permission gate ------
|
|
596
|
+
//
|
|
597
|
+
// Rules:
|
|
598
|
+
// - Execute without --yes ā always prompt (guided behavior)
|
|
599
|
+
// - Execute with --yes in guided mode ā skip prompt (user opted out)
|
|
600
|
+
// - Execute with --yes in yolo mode ā STILL prompt unless --force-yolo
|
|
601
|
+
// is also passed. This is deliberate: github mutations are visible to
|
|
602
|
+
// colleagues and cost rate-limit budget, so YOLO mode does not
|
|
603
|
+
// automatically apply to them. The user has to explicitly opt in.
|
|
604
|
+
//
|
|
605
|
+
const yoloBypassBlocked = communicationMode === 'yolo' && opts.yes && !opts.forceYolo;
|
|
606
|
+
const needsConfirmation = opts.execute && (!opts.yes || yoloBypassBlocked);
|
|
607
|
+
|
|
608
|
+
if (needsConfirmation) {
|
|
609
|
+
if (yoloBypassBlocked) {
|
|
610
|
+
console.log(`ā ļø communication_mode=yolo does not auto-confirm GitHub mutations.`);
|
|
611
|
+
console.log(` Pass --force-yolo to skip this prompt, or answer interactively below.`);
|
|
612
|
+
console.log();
|
|
613
|
+
}
|
|
614
|
+
console.log(`ā ļø This will modify ${repo} on GitHub.`);
|
|
615
|
+
const totalCreate =
|
|
616
|
+
plan.labels.length + plan.milestones.length + plan.epics.length + plan.stories.length;
|
|
617
|
+
console.log(` Items to create: ${totalCreate}`);
|
|
618
|
+
if (opts.sprint || opts.epic || opts.story) {
|
|
619
|
+
console.log(` Granular filter: ${opts.sprint || opts.epic || opts.story}`);
|
|
620
|
+
}
|
|
621
|
+
console.log();
|
|
622
|
+
// Require literal "yes" (not just y) because this mutates remote state.
|
|
623
|
+
const answer = await askText(` Proceed? Type 'yes' to continue: `, {
|
|
624
|
+
default: 'no',
|
|
625
|
+
validate: (v) => {
|
|
626
|
+
const lower = v.toLowerCase();
|
|
627
|
+
if (['yes', 'y', 'no', 'n'].includes(lower)) return true;
|
|
628
|
+
return `Please type 'yes' to confirm, or 'no' to abort.`;
|
|
629
|
+
},
|
|
630
|
+
});
|
|
631
|
+
if (!['yes', 'y'].includes(answer.toLowerCase())) {
|
|
632
|
+
console.log(`\nā Aborted by user. No changes made.`);
|
|
633
|
+
process.exit(0);
|
|
634
|
+
}
|
|
635
|
+
console.log();
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// ------ Execute (or dry-run) ------
|
|
639
|
+
const results = { labels: [], milestones: [], epics: [], stories: [], errors: [] };
|
|
640
|
+
const syncOpts = { execute: opts.execute, dryRun: opts.dryRun, repo };
|
|
641
|
+
|
|
642
|
+
// 1. Labels ā only when explicitly opted in via --with-labels
|
|
643
|
+
if (opts.withLabels && (!opts.only || opts.only === 'labels')) {
|
|
644
|
+
console.log(`\nš·ļø Labels`);
|
|
645
|
+
for (const label of plan.labels) {
|
|
646
|
+
const result = gh.ensureLabel(label.name, label.color, label.description, syncOpts);
|
|
647
|
+
results.labels.push(result);
|
|
648
|
+
if (result.error) {
|
|
649
|
+
results.errors.push(`label ${label.name}: ${result.error}`);
|
|
650
|
+
} else if (!result.dryRun) {
|
|
651
|
+
if (!syncMap.labels.includes(label.name)) syncMap.labels.push(label.name);
|
|
652
|
+
console.log(` ā ${result.existed ? 'exists' : 'created'}: ${label.name}`);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// 2. Milestones (phases)
|
|
658
|
+
if (!opts.only || opts.only === 'milestones') {
|
|
659
|
+
console.log(`\nšÆ Milestones (phases)`);
|
|
660
|
+
for (const phase of plan.milestones) {
|
|
661
|
+
const desc = phase.brief ? phase.brief.split('\n').slice(0, 5).join('\n') : 'Rihal Code phase';
|
|
662
|
+
const result = gh.createMilestone(phase.id, desc, null, syncOpts);
|
|
663
|
+
results.milestones.push({ phase: phase.id, ...result });
|
|
664
|
+
if (result.error) {
|
|
665
|
+
results.errors.push(`milestone ${phase.id}: ${result.error}`);
|
|
666
|
+
} else if (!result.dryRun) {
|
|
667
|
+
syncMap.phases[phase.id] = {
|
|
668
|
+
milestone_number: result.number,
|
|
669
|
+
milestone_id: result.id,
|
|
670
|
+
url: result.url,
|
|
671
|
+
synced_at: new Date().toISOString(),
|
|
672
|
+
};
|
|
673
|
+
console.log(` ā created: ${phase.id} ā milestone #${result.number}`);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
// 3. Epics ā create first so stories can reference their issue numbers
|
|
679
|
+
if (!opts.only || opts.only === 'epics') {
|
|
680
|
+
console.log(`\nš¦ Epics`);
|
|
681
|
+
for (const epic of plan.epics) {
|
|
682
|
+
const body = [
|
|
683
|
+
`## šÆ Epic Vision`,
|
|
684
|
+
``,
|
|
685
|
+
`_Strategic goal this Epic contributes to._`,
|
|
686
|
+
``,
|
|
687
|
+
`## š Source Content`,
|
|
688
|
+
``,
|
|
689
|
+
epic.content.slice(0, 3000),
|
|
690
|
+
``,
|
|
691
|
+
`---`,
|
|
692
|
+
``,
|
|
693
|
+
`## š Meta`,
|
|
694
|
+
``,
|
|
695
|
+
`- **Phase:** \`${epic.phase}\``,
|
|
696
|
+
`- **Source:** \`.rihal/phases/${epic.phase}/tasks/${epic.file}\``,
|
|
697
|
+
`- **Synced by:** Rihal Code github-sync`,
|
|
698
|
+
``,
|
|
699
|
+
`## š Child Stories`,
|
|
700
|
+
``,
|
|
701
|
+
`_Child story issues will be appended here after they are created._`,
|
|
702
|
+
].join('\n');
|
|
703
|
+
|
|
704
|
+
const milestoneNumber =
|
|
705
|
+
syncMap.phases[epic.phase] && syncMap.phases[epic.phase].milestone_number;
|
|
706
|
+
|
|
707
|
+
const result = gh.createIssue(
|
|
708
|
+
{
|
|
709
|
+
title: `[Epic] ${epic.title}`,
|
|
710
|
+
body,
|
|
711
|
+
// Only assign labels if the user opted in ā otherwise GitHub
|
|
712
|
+
// would reject the issue creation on labels that don't exist.
|
|
713
|
+
labels: opts.withLabels ? ['epic', 'priority:medium', 'status:backlog'] : [],
|
|
714
|
+
milestone: milestoneNumber,
|
|
715
|
+
},
|
|
716
|
+
syncOpts,
|
|
717
|
+
);
|
|
718
|
+
results.epics.push({ epic: epic.id, ...result });
|
|
719
|
+
if (result.error) {
|
|
720
|
+
results.errors.push(`epic ${epic.id}: ${result.error}`);
|
|
721
|
+
} else if (!result.dryRun) {
|
|
722
|
+
syncMap.epics[epic.id] = {
|
|
723
|
+
issue_number: result.number,
|
|
724
|
+
url: result.url,
|
|
725
|
+
phase: epic.phase,
|
|
726
|
+
synced_at: new Date().toISOString(),
|
|
727
|
+
content_hash: contentHash(epic.content),
|
|
728
|
+
child_story_issues: [],
|
|
729
|
+
};
|
|
730
|
+
console.log(` ā created: ${epic.id} ā #${result.number}`);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
// 4. Stories ā reference actual parent epic via discovered mapping.
|
|
736
|
+
// Also record child story issue numbers on their parent epic so we can
|
|
737
|
+
// update the epic body with a task list in a second pass below.
|
|
738
|
+
if (!opts.only || opts.only === 'stories') {
|
|
739
|
+
console.log(`\nš Stories`);
|
|
740
|
+
for (const story of plan.stories) {
|
|
741
|
+
// Look up the ACTUAL parent epic by id (from frontmatter or naming
|
|
742
|
+
// convention), not "any epic in this phase" ā that bug led to all
|
|
743
|
+
// stories pointing at the same epic previously.
|
|
744
|
+
const parentEpicEntry = story.parentEpic
|
|
745
|
+
? syncMap.epics[story.parentEpic]
|
|
746
|
+
: null;
|
|
747
|
+
const parentRefLine = parentEpicEntry
|
|
748
|
+
? `- **Parent Epic:** #${parentEpicEntry.issue_number} (Part of this epic)`
|
|
749
|
+
: story.parentEpic
|
|
750
|
+
? `- **Parent Epic:** \`${story.parentEpic}\` (not yet synced to GitHub)`
|
|
751
|
+
: `- **Parent Epic:** (standalone ā no parent epic)`;
|
|
752
|
+
const sprintRefLine = story.sprintId
|
|
753
|
+
? `- **Sprint:** \`${story.sprintId}\``
|
|
754
|
+
: `- **Sprint:** (not assigned to a sprint)`;
|
|
755
|
+
|
|
756
|
+
const body = [
|
|
757
|
+
`## šÆ Problem Statement`,
|
|
758
|
+
``,
|
|
759
|
+
`_Clear explanation of what this story solves._`,
|
|
760
|
+
``,
|
|
761
|
+
`## ā
Acceptance Criteria`,
|
|
762
|
+
``,
|
|
763
|
+
`- [ ] Given/When/Then flows documented in source`,
|
|
764
|
+
`- [ ] Tests written and passing`,
|
|
765
|
+
`- [ ] Code review complete`,
|
|
766
|
+
``,
|
|
767
|
+
`## š Source Content`,
|
|
768
|
+
``,
|
|
769
|
+
story.content.slice(0, 3000),
|
|
770
|
+
``,
|
|
771
|
+
`---`,
|
|
772
|
+
``,
|
|
773
|
+
`## š Meta`,
|
|
774
|
+
``,
|
|
775
|
+
parentRefLine,
|
|
776
|
+
sprintRefLine,
|
|
777
|
+
`- **Phase:** \`${story.phase}\``,
|
|
778
|
+
`- **Source:** \`.rihal/phases/${story.phase}/stories/${story.file}\``,
|
|
779
|
+
`- **Synced by:** Rihal Code github-sync`,
|
|
780
|
+
``,
|
|
781
|
+
`> **Linking:** Reference this story in commits with \`refs #${'{issue}'}\``,
|
|
782
|
+
`> or close it via PR with \`Closes #${'{issue}'}\`.`,
|
|
783
|
+
].join('\n');
|
|
784
|
+
|
|
785
|
+
const milestoneNumber =
|
|
786
|
+
syncMap.phases[story.phase] && syncMap.phases[story.phase].milestone_number;
|
|
787
|
+
|
|
788
|
+
const result = gh.createIssue(
|
|
789
|
+
{
|
|
790
|
+
title: story.title,
|
|
791
|
+
body,
|
|
792
|
+
labels: opts.withLabels ? ['type:feature', 'priority:medium', 'status:backlog'] : [],
|
|
793
|
+
milestone: milestoneNumber,
|
|
794
|
+
},
|
|
795
|
+
syncOpts,
|
|
796
|
+
);
|
|
797
|
+
results.stories.push({ story: story.id, ...result });
|
|
798
|
+
if (result.error) {
|
|
799
|
+
results.errors.push(`story ${story.id}: ${result.error}`);
|
|
800
|
+
} else if (!result.dryRun) {
|
|
801
|
+
syncMap.stories[story.id] = {
|
|
802
|
+
issue_number: result.number,
|
|
803
|
+
url: result.url,
|
|
804
|
+
phase: story.phase,
|
|
805
|
+
parent_epic: story.parentEpic || null,
|
|
806
|
+
sprint_id: story.sprintId || null,
|
|
807
|
+
synced_at: new Date().toISOString(),
|
|
808
|
+
content_hash: contentHash(story.content),
|
|
809
|
+
};
|
|
810
|
+
// Remember this child on the parent epic so we can update the
|
|
811
|
+
// epic body with a task list after all stories have been created.
|
|
812
|
+
if (parentEpicEntry) {
|
|
813
|
+
parentEpicEntry.child_story_issues = parentEpicEntry.child_story_issues || [];
|
|
814
|
+
if (!parentEpicEntry.child_story_issues.includes(result.number)) {
|
|
815
|
+
parentEpicEntry.child_story_issues.push(result.number);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
console.log(` ā created: ${story.id} ā #${result.number}`);
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// 4b. Back-fill epic bodies with a task list of child stories.
|
|
824
|
+
// GitHub renders `- [ ] #N` as a clickable task-list link and shows a
|
|
825
|
+
// progress counter in the parent epic. Only runs if we just created
|
|
826
|
+
// any stories AND their parent epics were also touched in this run.
|
|
827
|
+
if (opts.execute && (!opts.only || opts.only === 'epics' || opts.only === 'stories')) {
|
|
828
|
+
const epicsToBackfill = Object.entries(syncMap.epics).filter(
|
|
829
|
+
([, e]) => e.child_story_issues && e.child_story_issues.length > 0,
|
|
830
|
+
);
|
|
831
|
+
if (epicsToBackfill.length > 0) {
|
|
832
|
+
console.log(`\nš Linking stories ā epics (task lists)`);
|
|
833
|
+
for (const [epicId, epicEntry] of epicsToBackfill) {
|
|
834
|
+
const taskList = epicEntry.child_story_issues
|
|
835
|
+
.sort((a, b) => a - b)
|
|
836
|
+
.map((n) => `- [ ] #${n}`)
|
|
837
|
+
.join('\n');
|
|
838
|
+
|
|
839
|
+
// Fetch current body and append / replace the Child Stories block
|
|
840
|
+
const issue = gh.getIssue(epicEntry.issue_number, { repo });
|
|
841
|
+
if (issue.error) {
|
|
842
|
+
results.errors.push(`link epic #${epicEntry.issue_number}: ${issue.error}`);
|
|
843
|
+
continue;
|
|
844
|
+
}
|
|
845
|
+
const currentBody = issue.body || '';
|
|
846
|
+
// Replace the placeholder block or append one at the end
|
|
847
|
+
let newBody;
|
|
848
|
+
const blockRegex = /## š Child Stories[\s\S]*?(?=\n## |$)/;
|
|
849
|
+
const newBlock = `## š Child Stories\n\n${taskList}\n`;
|
|
850
|
+
if (blockRegex.test(currentBody)) {
|
|
851
|
+
newBody = currentBody.replace(blockRegex, newBlock);
|
|
852
|
+
} else {
|
|
853
|
+
newBody = currentBody.trimEnd() + '\n\n' + newBlock;
|
|
854
|
+
}
|
|
855
|
+
const updateResult = gh.updateIssue(
|
|
856
|
+
epicEntry.issue_number,
|
|
857
|
+
{ body: newBody },
|
|
858
|
+
syncOpts,
|
|
859
|
+
);
|
|
860
|
+
if (updateResult.error) {
|
|
861
|
+
results.errors.push(`update epic #${epicEntry.issue_number}: ${updateResult.error}`);
|
|
862
|
+
} else {
|
|
863
|
+
console.log(
|
|
864
|
+
` ā linked ${epicEntry.child_story_issues.length} stories ā epic #${epicEntry.issue_number}`,
|
|
865
|
+
);
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
// 5. UPDATE existing epics (if changed locally)
|
|
872
|
+
if (opts.updateEnabled && (!opts.only || opts.only === 'epics') && plan.updateEpics.length > 0) {
|
|
873
|
+
console.log(`\nš Update existing epics`);
|
|
874
|
+
for (const epic of plan.updateEpics) {
|
|
875
|
+
const newHash = contentHash(epic.content);
|
|
876
|
+
if (newHash === epic.lastSyncedContentHash) {
|
|
877
|
+
// Nothing changed ā skip silently
|
|
878
|
+
continue;
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
const body = [
|
|
882
|
+
`## šÆ Epic Vision`,
|
|
883
|
+
``,
|
|
884
|
+
`_Strategic goal this Epic contributes to. Fill in from \`.rihal/phases/${epic.phase}/tasks/${epic.file}\`._`,
|
|
885
|
+
``,
|
|
886
|
+
`## š Source Content`,
|
|
887
|
+
``,
|
|
888
|
+
epic.content.slice(0, 3000),
|
|
889
|
+
``,
|
|
890
|
+
`---`,
|
|
891
|
+
``,
|
|
892
|
+
`## š Meta`,
|
|
893
|
+
``,
|
|
894
|
+
`- **Phase:** \`${epic.phase}\``,
|
|
895
|
+
`- **Source:** \`.rihal/phases/${epic.phase}/tasks/${epic.file}\``,
|
|
896
|
+
`- **Last synced:** ${new Date().toISOString()}`,
|
|
897
|
+
].join('\n');
|
|
898
|
+
|
|
899
|
+
const result = gh.updateIssue(
|
|
900
|
+
epic.issueNumber,
|
|
901
|
+
{
|
|
902
|
+
title: opts.updateBody ? `[Epic] ${epic.title}` : undefined,
|
|
903
|
+
body: opts.updateBody ? body : undefined,
|
|
904
|
+
},
|
|
905
|
+
syncOpts,
|
|
906
|
+
);
|
|
907
|
+
if (result.error) {
|
|
908
|
+
results.errors.push(`update epic #${epic.issueNumber}: ${result.error}`);
|
|
909
|
+
} else if (!result.dryRun) {
|
|
910
|
+
syncMap.epics[epic.id].content_hash = newHash;
|
|
911
|
+
syncMap.epics[epic.id].updated_at = new Date().toISOString();
|
|
912
|
+
console.log(` ā updated: #${epic.issueNumber} (${epic.id})`);
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
// 6. UPDATE existing stories (if changed locally)
|
|
918
|
+
if (opts.updateEnabled && (!opts.only || opts.only === 'stories') && plan.updateStories.length > 0) {
|
|
919
|
+
console.log(`\nš Update existing stories`);
|
|
920
|
+
for (const story of plan.updateStories) {
|
|
921
|
+
const newHash = contentHash(story.content);
|
|
922
|
+
if (newHash === story.lastSyncedContentHash) {
|
|
923
|
+
continue;
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
const body = [
|
|
927
|
+
`## šÆ Problem Statement`,
|
|
928
|
+
``,
|
|
929
|
+
`_From \`.rihal/phases/${story.phase}/stories/${story.file}\`._`,
|
|
930
|
+
``,
|
|
931
|
+
`## š Source Content`,
|
|
932
|
+
``,
|
|
933
|
+
story.content.slice(0, 3000),
|
|
934
|
+
``,
|
|
935
|
+
`---`,
|
|
936
|
+
``,
|
|
937
|
+
`## š Meta`,
|
|
938
|
+
``,
|
|
939
|
+
`- **Phase:** \`${story.phase}\``,
|
|
940
|
+
`- **Source:** \`.rihal/phases/${story.phase}/stories/${story.file}\``,
|
|
941
|
+
`- **Last synced:** ${new Date().toISOString()}`,
|
|
942
|
+
].join('\n');
|
|
943
|
+
|
|
944
|
+
const result = gh.updateIssue(
|
|
945
|
+
story.issueNumber,
|
|
946
|
+
{
|
|
947
|
+
title: opts.updateBody ? story.title : undefined,
|
|
948
|
+
body: opts.updateBody ? body : undefined,
|
|
949
|
+
},
|
|
950
|
+
syncOpts,
|
|
951
|
+
);
|
|
952
|
+
if (result.error) {
|
|
953
|
+
results.errors.push(`update story #${story.issueNumber}: ${result.error}`);
|
|
954
|
+
} else if (!result.dryRun) {
|
|
955
|
+
syncMap.stories[story.id].content_hash = newHash;
|
|
956
|
+
syncMap.stories[story.id].updated_at = new Date().toISOString();
|
|
957
|
+
console.log(` ā updated: #${story.issueNumber} (${story.id})`);
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
// 7. Project v2 (optional)
|
|
963
|
+
if (opts.createProject && (!opts.only || opts.only === 'project')) {
|
|
964
|
+
console.log(`\nš Project v2`);
|
|
965
|
+
const owner = repo.split('/')[0];
|
|
966
|
+
const title = state.project_name || repo.split('/')[1];
|
|
967
|
+
const result = gh.createProject(owner, title, syncOpts);
|
|
968
|
+
if (result.error) {
|
|
969
|
+
results.errors.push(`project: ${result.error}`);
|
|
970
|
+
} else if (!result.dryRun) {
|
|
971
|
+
syncMap.project = { number: result.number, url: result.url, synced_at: new Date().toISOString() };
|
|
972
|
+
console.log(` ā created: Project v2 "${title}" ā ${result.url}`);
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
// ------ Save sync map (only if we executed) ------
|
|
977
|
+
if (opts.execute) {
|
|
978
|
+
saveSyncMap(cwd, syncMap);
|
|
979
|
+
console.log(`\nš¾ Sync map saved to .rihal/integrations/github-map.json`);
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
// ------ Summary ------
|
|
983
|
+
console.log(`\nš Summary`);
|
|
984
|
+
console.log(` Labels: ${results.labels.length}`);
|
|
985
|
+
console.log(` Milestones: ${results.milestones.length}`);
|
|
986
|
+
console.log(` Epics: ${results.epics.length} created`);
|
|
987
|
+
console.log(` Stories: ${results.stories.length} created`);
|
|
988
|
+
if (opts.updateEnabled) {
|
|
989
|
+
const epicUpdates = plan.updateEpics.filter((e) => contentHash(e.content) !== e.lastSyncedContentHash).length;
|
|
990
|
+
const storyUpdates = plan.updateStories.filter((s) => contentHash(s.content) !== s.lastSyncedContentHash).length;
|
|
991
|
+
console.log(` Updated: ${epicUpdates} epics, ${storyUpdates} stories (content changed since last sync)`);
|
|
992
|
+
}
|
|
993
|
+
if (results.errors.length > 0) {
|
|
994
|
+
console.log(` Errors: ${results.errors.length}`);
|
|
995
|
+
for (const err of results.errors) console.log(` ā ${err}`);
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
if (opts.dryRun) {
|
|
999
|
+
console.log(`\nā ļø This was a DRY-RUN. No changes were made to GitHub.`);
|
|
1000
|
+
console.log(` To actually apply these changes, run again with: --execute`);
|
|
1001
|
+
} else {
|
|
1002
|
+
console.log(`\nā
Sync complete. View on GitHub: https://github.com/${repo}`);
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
module.exports = function githubSync(args) {
|
|
1007
|
+
main(args).catch((err) => {
|
|
1008
|
+
if (err instanceof PromptAbortError) {
|
|
1009
|
+
console.log(`\nā GitHub sync cancelled ā ${err.message}.`);
|
|
1010
|
+
process.exit(0);
|
|
1011
|
+
}
|
|
1012
|
+
console.error(`\nā GitHub sync failed:`, err.message);
|
|
1013
|
+
if (process.env.DEBUG) console.error(err.stack);
|
|
1014
|
+
process.exit(1);
|
|
1015
|
+
});
|
|
1016
|
+
};
|