forge-workflow 0.0.9 → 0.1.0-beta.2
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/rules/{greptile-review-process.md → review-process.md} +56 -41
- package/.claude/scripts/{greptile-resolve.sh → review-resolve.sh} +13 -3
- package/.cursor/rules/permissions-guidance.mdc +2 -2
- package/.forge/hooks/check-tdd.js +3 -0
- package/.forge/hooks/forge-native-hook.js +245 -0
- package/.forge/protected-paths.yaml +157 -0
- package/AGENTS.md +151 -61
- package/CHANGELOG.md +681 -0
- package/CLAUDE.md +9 -106
- package/QUICKSTART.md +171 -0
- package/README.md +271 -363
- package/bin/forge-cmd.js +120 -9
- package/bin/forge-preflight.js +26 -5
- package/bin/forge.js +466 -489
- package/docs/INDEX.md +93 -0
- package/docs/PROJECT_DESIGN.md +685 -0
- package/docs/architecture/index.md +66 -0
- package/docs/architecture/notes/README.md +35 -0
- package/docs/architecture/subsystems/README.md +46 -0
- package/docs/{TOOLCHAIN.md → forge/TOOLCHAIN.md} +56 -47
- package/docs/forge/VALIDATION.md +82 -0
- package/docs/{AGENT_INSTALL_PROMPT.md → guides/AGENT_INSTALL_PROMPT.md} +3 -3
- package/docs/guides/BEADS_GITHUB_SYNC.md +32 -0
- package/docs/{ENHANCED_ONBOARDING.md → guides/ENHANCED_ONBOARDING.md} +16 -12
- package/docs/guides/GREPTILE_SETUP.md +46 -0
- package/docs/guides/MANUAL_REVIEW_GUIDE.md +58 -0
- package/docs/guides/MIGRATION.md +56 -0
- package/docs/guides/SETUP.md +118 -0
- package/docs/guides/SUPPORT.md +185 -0
- package/docs/guides/WORKFLOW_TEMPLATES.md +74 -0
- package/docs/guides/memory-backends.md +183 -0
- package/docs/reference/ADAPTERS.md +128 -0
- package/docs/reference/AGENT_SKILL_PARITY.md +175 -0
- package/docs/reference/COMMANDS.md +205 -0
- package/docs/reference/DECISION_DRIFT_GUARDS.md +97 -0
- package/docs/{EXAMPLES.md → reference/EXAMPLES.md} +7 -5
- package/docs/reference/FORGE_KERNEL_STORAGE_MODEL.md +135 -0
- package/docs/reference/HERMES_INTEGRATION.md +118 -0
- package/docs/reference/INSIGHTS_RECAP.md +63 -0
- package/docs/reference/INSTALL.md +164 -0
- package/docs/reference/KERNEL_TAXONOMY_VALIDATION.md +161 -0
- package/docs/reference/PROTECTED_PATH_MANIFEST.md +25 -0
- package/docs/reference/RELEASE.md +68 -0
- package/docs/reference/RESEARCH_TEMPLATE.md +292 -0
- package/docs/{ROADMAP.md → reference/ROADMAP.md} +12 -9
- package/docs/reference/SKILLS.md +35 -0
- package/docs/reference/STATUS_BOARD.md +80 -0
- package/docs/reference/TEMPLATES.md +106 -0
- package/docs/reference/TOOLCHAIN.md +658 -0
- package/docs/reference/VALIDATION.md +82 -0
- package/docs/reference/agent-permissions.md +169 -0
- package/docs/reference/beads-to-kernel-migration-ux.md +61 -0
- package/docs/reference/control-plane-guarantees.md +125 -0
- package/docs/reference/dependency-chain.md +331 -0
- package/docs/reference/forge-kernel-issue-command-contract.md +161 -0
- package/docs/reference/forge-kernel-schema.md +72 -0
- package/docs/reference/kernel-conflict-evaluators.md +27 -0
- package/docs/reference/patch-md-format.md +77 -0
- package/docs/reference/protected-state-surfaces.md +59 -0
- package/docs/reference/shepherd.md +115 -0
- package/docs/reference/superpowers-analysis.md +320 -0
- package/docs/reference/superpowers-integration-options.md +404 -0
- package/docs/reference/test-environment.md +519 -0
- package/docs/reference/upgrade-safety.md +59 -0
- package/lefthook.yml +18 -0
- package/lib/adapter-cli.js +307 -0
- package/lib/adapters/beads-issue-adapter.js +127 -0
- package/lib/adapters/beads-kernel-compat.js +1042 -0
- package/lib/adapters/greptile-review-adapter.js +141 -0
- package/lib/adapters/kernel-issue-adapter.js +101 -0
- package/lib/adapters/pr-state-adapter.js +484 -0
- package/lib/adoption-profiles.js +126 -0
- package/lib/agents/README.md +2 -6
- package/lib/agents/claude.plugin.json +3 -8
- package/lib/agents/codex.plugin.json +9 -1
- package/lib/agents/cursor.plugin.json +2 -6
- package/lib/agents/hermes.plugin.json +22 -0
- package/lib/agents-config.js +39 -1236
- package/lib/audit-evidence.js +282 -0
- package/lib/beads-setup.js +225 -28
- package/lib/beads-sync-scaffold.js +36 -107
- package/lib/codex-skills.js +51 -1
- package/lib/commands/_issue.js +744 -70
- package/lib/commands/_manifest.js +91 -0
- package/lib/commands/_registry.js +85 -34
- package/lib/commands/_resolve-command-opts.js +261 -0
- package/lib/commands/_serve-security.js +270 -0
- package/lib/commands/adapter.js +12 -0
- package/lib/commands/add.js +118 -0
- package/lib/commands/audit.js +70 -0
- package/lib/commands/blocked.js +5 -0
- package/lib/commands/board.js +64 -0
- package/lib/commands/claim.js +21 -2
- package/lib/commands/claims.js +7 -0
- package/lib/commands/clean.js +485 -75
- package/lib/commands/close.js +2 -2
- package/lib/commands/comment.js +5 -0
- package/lib/commands/control.js +148 -0
- package/lib/commands/create.js +2 -2
- package/lib/commands/dev.js +185 -7
- package/lib/commands/doc-gate.js +336 -0
- package/lib/commands/doctor.js +156 -0
- package/lib/commands/explain.js +15 -0
- package/lib/commands/export.js +237 -0
- package/lib/commands/gate.js +192 -0
- package/lib/commands/hooks.js +242 -0
- package/lib/commands/inbox.js +118 -0
- package/lib/commands/init.js +598 -0
- package/lib/commands/insights.js +79 -0
- package/lib/commands/issue.js +12 -1
- package/lib/commands/issues.js +66 -0
- package/lib/commands/lint.js +5 -0
- package/lib/commands/list.js +2 -2
- package/lib/commands/merge.js +312 -0
- package/lib/commands/migrate.js +523 -0
- package/lib/commands/new.js +12 -0
- package/lib/commands/options.js +241 -0
- package/lib/commands/orient.js +13 -0
- package/lib/commands/orphans.js +5 -0
- package/lib/commands/patch.js +67 -0
- package/lib/commands/plan.js +436 -24
- package/lib/commands/preflight.js +211 -0
- package/lib/commands/prime.js +13 -0
- package/lib/commands/push.js +69 -2
- package/lib/commands/ready.js +2 -2
- package/lib/commands/recall.js +116 -0
- package/lib/commands/recap.js +61 -0
- package/lib/commands/recommend.js +22 -2
- package/lib/commands/release.js +91 -0
- package/lib/commands/remember.js +74 -0
- package/lib/commands/role.js +99 -0
- package/lib/commands/serve.js +581 -0
- package/lib/commands/setup.js +851 -979
- package/lib/commands/shepherd.js +436 -0
- package/lib/commands/ship.js +23 -1
- package/lib/commands/show.js +2 -2
- package/lib/commands/stage.js +192 -0
- package/lib/commands/stale.js +5 -0
- package/lib/commands/status.js +329 -11
- package/lib/commands/sync.js +34 -46
- package/lib/commands/team.js +15 -2
- package/lib/commands/test.js +58 -7
- package/lib/commands/update.js +2 -2
- package/lib/commands/upgrade.js +47 -0
- package/lib/commands/validate.js +56 -25
- package/lib/commands/worktree.js +308 -128
- package/lib/config-writer.js +202 -0
- package/lib/control-plane.js +236 -0
- package/lib/core/runtime-graph.js +946 -0
- package/lib/dep-guard/keyword-ripple.js +184 -0
- package/lib/deprecated-sync-cleanup.js +362 -0
- package/lib/detect-agent.js +2 -28
- package/lib/detect-worktree.js +42 -17
- package/lib/doc-gate/declaration.js +177 -0
- package/lib/doc-gate/detect.js +289 -0
- package/lib/doc-gate/gate.js +375 -0
- package/lib/doc-gate/okf-config.js +128 -0
- package/lib/doc-gate/okf.js +429 -0
- package/lib/docs-command.js +1161 -6
- package/lib/forge-issues.js +697 -0
- package/lib/forge-lock.js +262 -0
- package/lib/gate-events.js +193 -0
- package/lib/global-flags.js +74 -0
- package/lib/greptile-match.js +7 -63
- package/lib/harness-capability-matrix.js +380 -0
- package/lib/hook-global-installer.js +347 -0
- package/lib/hook-renderer.js +451 -0
- package/lib/inbox.js +391 -0
- package/lib/insights.js +397 -0
- package/lib/issue-adapter.js +156 -0
- package/lib/issue-backend.js +145 -0
- package/lib/issue-render.js +220 -0
- package/lib/issue-sync/authority.js +100 -0
- package/lib/issue-sync/github-pull.js +184 -0
- package/lib/issue-sync/import-primitives.js +98 -0
- package/lib/issue-sync/legacy-link-bridge.js +436 -0
- package/lib/issue-sync/link-store.js +292 -0
- package/lib/issue-sync/project-github.js +123 -0
- package/lib/issue-sync/reconcile.js +195 -0
- package/lib/issue-sync/schema.js +126 -0
- package/lib/kernel/backing-issue.js +305 -0
- package/lib/kernel/broker.js +1218 -0
- package/lib/kernel/cli-broker-factory.js +130 -0
- package/lib/kernel/conflict-signal.js +82 -0
- package/lib/kernel/evaluators.js +195 -0
- package/lib/kernel/fs-class.js +495 -0
- package/lib/kernel/issue-command-contract.js +559 -0
- package/lib/kernel/issue-id-resolver.js +186 -0
- package/lib/kernel/lease-enforcer.js +158 -0
- package/lib/kernel/migrations.js +333 -0
- package/lib/kernel/planning-buckets-schema.js +109 -0
- package/lib/kernel/projection-jsonl-writer.js +450 -0
- package/lib/kernel/readiness-model.js +329 -0
- package/lib/kernel/schema.js +356 -0
- package/lib/kernel/sqlite-driver.js +2504 -0
- package/lib/kernel/taxonomy-validator.js +394 -0
- package/lib/lefthook-check.js +8 -4
- package/lib/lefthook-wiring.js +413 -0
- package/lib/mcp-config-renderer.js +288 -0
- package/lib/memory/graphiti-mcp.js +106 -0
- package/lib/memory/router.js +387 -0
- package/lib/memory/typed-api.js +102 -0
- package/lib/memory-digest.js +195 -0
- package/lib/merge-rules.js +395 -0
- package/lib/migrate-dry-run.js +466 -0
- package/lib/orientation.js +863 -0
- package/lib/package-manager-remediation.js +103 -0
- package/lib/package-root.js +381 -0
- package/lib/patch-intent.js +890 -0
- package/lib/plugin-catalog.js +3 -4
- package/lib/plugin-manager.js +0 -5
- package/lib/pr-bundle.js +186 -0
- package/lib/pr-monitor/differ.js +195 -0
- package/lib/pr-monitor/events.js +0 -0
- package/lib/pr-monitor/gather.js +124 -0
- package/lib/pr-monitor/journal.js +299 -0
- package/lib/pr-monitor/monitor.js +146 -0
- package/lib/pr-monitor/render-sticky.js +157 -0
- package/lib/pr-monitor/watch-lifecycle.js +95 -0
- package/lib/pr-monitor/watch.js +247 -0
- package/lib/pr-pull.js +1273 -0
- package/lib/pr-shepherd.js +494 -0
- package/lib/pr-state-validator.js +59 -0
- package/lib/preflight/gates.js +237 -0
- package/lib/preflight/runner.js +116 -0
- package/lib/project-discovery.js +0 -53
- package/lib/project-memory.js +166 -0
- package/lib/protected-path-manifest.js +281 -0
- package/lib/protected-state-surfaces.js +387 -0
- package/lib/release-readiness.js +2089 -0
- package/lib/reset.js +59 -45
- package/lib/review-adapter.js +68 -0
- package/lib/rules-sync.js +260 -0
- package/lib/runtime-health.js +332 -23
- package/lib/safety-config-renderer.js +268 -0
- package/lib/setup-action-log.js +1 -7
- package/lib/setup.js +27 -65
- package/lib/shell-utils.js +76 -6
- package/lib/skills-sync.js +330 -0
- package/lib/smart-status/conflicts.js +205 -0
- package/lib/smart-status/scoring.js +191 -0
- package/lib/status/beads-snapshot.js +145 -0
- package/lib/status/presenter.js +216 -0
- package/lib/status/snapshot.js +186 -0
- package/lib/sync-backend.js +202 -0
- package/lib/untrusted-content.js +52 -0
- package/lib/upgrade-safety.js +199 -0
- package/lib/workflow/enforce-stage.js +298 -47
- package/lib/workflow/stage-transition.js +115 -0
- package/lib/workflow/stages.js +30 -6
- package/lib/workflow/state-manager.js +159 -14
- package/lib/workflow/state.js +23 -1
- package/lib/workflow-profiles.js +17 -5
- package/package.json +46 -36
- package/rules/documentation.md +19 -0
- package/rules/kernel-tracking.md +26 -0
- package/rules/security.md +22 -0
- package/rules/tdd.md +20 -0
- package/rules/workflow.md +27 -0
- package/scripts/auto-backing-issue.js +47 -0
- package/scripts/beads-context.sh +165 -22
- package/scripts/beads-migrate-to-dolt.sh +7 -0
- package/scripts/beads-upgrade-smoke.sh +284 -0
- package/scripts/behavioral-judge.sh +115 -11
- package/scripts/benchmark.js +349 -63
- package/scripts/bootstrap-windows-tools.sh +78 -0
- package/scripts/branch-protection.js +2 -3
- package/scripts/check-agents.js +34 -137
- package/scripts/commitlint.js +3 -1
- package/scripts/conflict-detect.sh +3 -0
- package/scripts/dep-guard-analyze.js +52 -17
- package/scripts/dep-guard-keyword-ripple.js +29 -0
- package/scripts/dep-guard-render-review.js +86 -0
- package/scripts/dep-guard.sh +64 -232
- package/scripts/file-index.sh +3 -0
- package/scripts/forge-team/lib/claim.sh +34 -18
- package/scripts/forge-team/lib/dashboard.sh +61 -86
- package/scripts/forge-team/lib/epic.sh +99 -263
- package/scripts/forge-team/lib/hooks.sh +26 -28
- package/scripts/forge-team/lib/identity.sh +4 -4
- package/scripts/forge-team/lib/sync-github.sh +144 -47
- package/scripts/forge-team/lib/verify.sh +93 -83
- package/scripts/forge-team/lib/workload.sh +41 -65
- package/scripts/forge-team/tests/claim.test.sh +25 -19
- package/scripts/forge-team/tests/dashboard.test.sh +31 -46
- package/scripts/forge-team/tests/epic.test.sh +52 -71
- package/scripts/forge-team/tests/hooks.test.sh +38 -50
- package/scripts/forge-team/tests/identity.test.sh +3 -3
- package/scripts/forge-team/tests/integration.test.sh +44 -66
- package/scripts/forge-team/tests/sync-github.test.sh +183 -79
- package/scripts/forge-team/tests/verify.test.sh +37 -46
- package/scripts/forge-team/tests/workflow-integration.test.sh +4 -4
- package/scripts/forge-team/tests/workload.test.sh +32 -66
- package/scripts/gen-command-manifest.js +153 -0
- package/scripts/gen-embedded-assets.mjs +129 -0
- package/scripts/install.ps1 +139 -0
- package/scripts/install.sh +268 -0
- package/scripts/lib/beads-migrate-to-dolt.mjs +503 -0
- package/scripts/lib/release-asset.mjs +84 -0
- package/scripts/parity-check.mjs +145 -0
- package/scripts/parity-check.test.mjs +58 -0
- package/scripts/pin-agentic-workflow-images.js +112 -0
- package/scripts/pr-coordinator.sh +3 -0
- package/scripts/preflight-sonar.eslint.config.mjs +44 -0
- package/scripts/preflight.sh +108 -0
- package/scripts/protected-state-check.js +104 -0
- package/scripts/smart-status-score.js +31 -0
- package/scripts/smart-status-sessions.js +51 -0
- package/scripts/smart-status.sh +117 -369
- package/scripts/spikes/config-race-bench.js +111 -0
- package/scripts/spikes/harness-capability-matrix.js +13 -0
- package/scripts/spikes/patch-anchor-stability-bench.js +125 -0
- package/scripts/spikes/protected-path-manifest.js +20 -0
- package/scripts/spikes/skill-auto-invoke-parity.js +292 -0
- package/scripts/sync-agent-skills.js +62 -0
- package/scripts/sync-agentic-workflow.js +48 -0
- package/scripts/sync-utils.sh +3 -0
- package/scripts/test-ci-shard.js +251 -0
- package/scripts/test-dashboard.js +188 -52
- package/scripts/test-full-suite.js +186 -0
- package/scripts/test-profile.js +278 -0
- package/scripts/test.js +302 -28
- package/scripts/validate.js +143 -0
- package/scripts/validate.sh +18 -1
- package/skills/claim-safety/SKILL.md +102 -0
- package/skills/claim-safety/evals/evals.json +46 -0
- package/{.github/prompts/dev.prompt.md → skills/dev/SKILL.md} +46 -52
- package/skills/dev/evals/evals.json +50 -0
- package/skills/hermes-forge/SKILL.md +185 -0
- package/skills/hermes-forge/evals/evals.json +46 -0
- package/skills/issue-basics/SKILL.md +111 -0
- package/skills/issue-basics/evals/evals.json +46 -0
- package/skills/kernel/SKILL.md +166 -0
- package/skills/kernel/evals/evals.json +50 -0
- package/skills/memory/SKILL.md +102 -0
- package/skills/parallel-deep-research/SKILL.md +14 -11
- package/skills/parallel-deep-research/evals/evals.json +11 -27
- package/{.github/prompts/plan.prompt.md → skills/plan/SKILL.md} +134 -159
- package/skills/plan/evals/evals.json +42 -0
- package/skills/research/SKILL.md +195 -0
- package/skills/research/evals/evals.json +42 -0
- package/{.github/prompts/review.prompt.md → skills/review/SKILL.md} +98 -62
- package/skills/review/evals/evals.json +42 -0
- package/skills/rollback/SKILL.md +110 -0
- package/skills/rollback/evals/evals.json +46 -0
- package/skills/rollback/references/methods.md +204 -0
- package/{.cursor/commands/rollback.md → skills/rollback/references/workflow-integration.md} +10 -284
- package/skills/shepherd/SKILL.md +66 -0
- package/skills/shepherd/evals/evals.json +42 -0
- package/skills/ship/SKILL.md +251 -0
- package/skills/ship/evals/evals.json +42 -0
- package/skills/smith/SKILL.md +142 -0
- package/skills/smith/evals/evals.json +46 -0
- package/skills/smith/references/autonomy-and-gates.md +94 -0
- package/{.github/prompts/sonarcloud.prompt.md → skills/sonarcloud/SKILL.md} +14 -3
- package/skills/sonarcloud/evals/evals.json +46 -0
- package/skills/sonarcloud-analysis/SKILL.md +18 -13
- package/skills/sonarcloud-analysis/evals/evals.json +11 -15
- package/skills/status/SKILL.md +102 -0
- package/skills/status/evals/evals.json +50 -0
- package/skills/triage-ready/SKILL.md +121 -0
- package/skills/triage-ready/evals/evals.json +42 -0
- package/{.github/prompts/validate.prompt.md → skills/validate/SKILL.md} +52 -29
- package/skills/validate/evals/evals.json +42 -0
- package/skills/verify/SKILL.md +299 -0
- package/skills/verify/evals/evals.json +50 -0
- package/.claude/commands/dev.md +0 -345
- package/.claude/commands/plan.md +0 -566
- package/.claude/commands/premerge.md +0 -186
- package/.claude/commands/research.md +0 -42
- package/.claude/commands/review.md +0 -451
- package/.claude/commands/rollback.md +0 -721
- package/.claude/commands/ship.md +0 -213
- package/.claude/commands/sonarcloud.md +0 -152
- package/.claude/commands/status.md +0 -90
- package/.claude/commands/validate.md +0 -288
- package/.claude/commands/verify.md +0 -269
- package/.claude/rules/workflow.md +0 -121
- package/.cline/workflows/dev.md +0 -342
- package/.cline/workflows/plan.md +0 -563
- package/.cline/workflows/premerge.md +0 -183
- package/.cline/workflows/research.md +0 -39
- package/.cline/workflows/review.md +0 -448
- package/.cline/workflows/rollback.md +0 -718
- package/.cline/workflows/ship.md +0 -210
- package/.cline/workflows/sonarcloud.md +0 -146
- package/.cline/workflows/status.md +0 -87
- package/.cline/workflows/validate.md +0 -285
- package/.cline/workflows/verify.md +0 -266
- package/.codex/config.toml +0 -11
- package/.codex/skills/dev/SKILL.md +0 -345
- package/.codex/skills/plan/SKILL.md +0 -566
- package/.codex/skills/premerge/SKILL.md +0 -186
- package/.codex/skills/research/SKILL.md +0 -42
- package/.codex/skills/review/SKILL.md +0 -451
- package/.codex/skills/rollback/SKILL.md +0 -721
- package/.codex/skills/ship/SKILL.md +0 -213
- package/.codex/skills/sonarcloud/SKILL.md +0 -149
- package/.codex/skills/status/SKILL.md +0 -90
- package/.codex/skills/validate/SKILL.md +0 -288
- package/.codex/skills/verify/SKILL.md +0 -269
- package/.cursor/commands/dev.md +0 -342
- package/.cursor/commands/plan.md +0 -563
- package/.cursor/commands/premerge.md +0 -183
- package/.cursor/commands/research.md +0 -39
- package/.cursor/commands/review.md +0 -448
- package/.cursor/commands/ship.md +0 -210
- package/.cursor/commands/sonarcloud.md +0 -146
- package/.cursor/commands/status.md +0 -87
- package/.cursor/commands/validate.md +0 -285
- package/.cursor/commands/verify.md +0 -266
- package/.cursorrules +0 -149
- package/.github/prompts/premerge.prompt.md +0 -188
- package/.github/prompts/research.prompt.md +0 -44
- package/.github/prompts/rollback.prompt.md +0 -723
- package/.github/prompts/ship.prompt.md +0 -215
- package/.github/prompts/status.prompt.md +0 -92
- package/.github/prompts/verify.prompt.md +0 -271
- package/.github/workflows/beads-to-github.yml +0 -56
- package/.github/workflows/github-to-beads.yml +0 -97
- package/.kilocode/workflows/dev.md +0 -346
- package/.kilocode/workflows/plan.md +0 -567
- package/.kilocode/workflows/premerge.md +0 -187
- package/.kilocode/workflows/research.md +0 -43
- package/.kilocode/workflows/review.md +0 -452
- package/.kilocode/workflows/rollback.md +0 -722
- package/.kilocode/workflows/ship.md +0 -214
- package/.kilocode/workflows/sonarcloud.md +0 -150
- package/.kilocode/workflows/status.md +0 -91
- package/.kilocode/workflows/validate.md +0 -289
- package/.kilocode/workflows/verify.md +0 -270
- package/.opencode/commands/dev.md +0 -345
- package/.opencode/commands/plan.md +0 -566
- package/.opencode/commands/premerge.md +0 -186
- package/.opencode/commands/research.md +0 -42
- package/.opencode/commands/review.md +0 -451
- package/.opencode/commands/rollback.md +0 -721
- package/.opencode/commands/ship.md +0 -213
- package/.opencode/commands/sonarcloud.md +0 -149
- package/.opencode/commands/status.md +0 -90
- package/.opencode/commands/validate.md +0 -288
- package/.opencode/commands/verify.md +0 -269
- package/.roo/commands/dev.md +0 -346
- package/.roo/commands/plan.md +0 -567
- package/.roo/commands/premerge.md +0 -187
- package/.roo/commands/research.md +0 -43
- package/.roo/commands/review.md +0 -452
- package/.roo/commands/rollback.md +0 -722
- package/.roo/commands/ship.md +0 -214
- package/.roo/commands/sonarcloud.md +0 -150
- package/.roo/commands/status.md +0 -91
- package/.roo/commands/validate.md +0 -289
- package/.roo/commands/verify.md +0 -270
- package/docs/BEADS_GITHUB_SYNC.md +0 -255
- package/docs/GREPTILE_SETUP.md +0 -400
- package/docs/MANUAL_REVIEW_GUIDE.md +0 -106
- package/docs/SETUP.md +0 -663
- package/docs/VALIDATION.md +0 -363
- package/lib/agents/cline.plugin.json +0 -29
- package/lib/agents/copilot.plugin.json +0 -24
- package/lib/agents/kilocode.plugin.json +0 -22
- package/lib/agents/opencode.plugin.json +0 -23
- package/lib/agents/roo.plugin.json +0 -30
- package/lib/beads-health-check.js +0 -143
- package/lib/commands/commands-reset.js +0 -147
- package/opencode.json +0 -67
- package/scripts/beads-context.test.js +0 -567
- package/scripts/github-beads-sync/comment.mjs +0 -64
- package/scripts/github-beads-sync/config.mjs +0 -148
- package/scripts/github-beads-sync/github-api.mjs +0 -131
- package/scripts/github-beads-sync/index.mjs +0 -332
- package/scripts/github-beads-sync/label-mapper.mjs +0 -54
- package/scripts/github-beads-sync/mapping.mjs +0 -78
- package/scripts/github-beads-sync/reverse-sync-cli.mjs +0 -31
- package/scripts/github-beads-sync/reverse-sync.mjs +0 -138
- package/scripts/github-beads-sync/run-bd.mjs +0 -161
- package/scripts/github-beads-sync/sanitize.mjs +0 -121
- package/scripts/github-beads-sync.config.json +0 -26
- package/scripts/sync-commands.js +0 -600
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function roundToTwo(value) {
|
|
4
|
+
return Math.round(value * 100) / 100;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function normalizePriorityNumber(priority) {
|
|
8
|
+
if (priority === undefined || priority === null) {
|
|
9
|
+
return 2;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (typeof priority === 'string') {
|
|
13
|
+
switch (priority) {
|
|
14
|
+
case 'P0':
|
|
15
|
+
return 0;
|
|
16
|
+
case 'P1':
|
|
17
|
+
return 1;
|
|
18
|
+
case 'P2':
|
|
19
|
+
return 2;
|
|
20
|
+
case 'P3':
|
|
21
|
+
return 3;
|
|
22
|
+
case 'P4':
|
|
23
|
+
return 4;
|
|
24
|
+
default:
|
|
25
|
+
return 5;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return priority;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function getPriorityWeight(priority) {
|
|
33
|
+
switch (normalizePriorityNumber(priority)) {
|
|
34
|
+
case 0:
|
|
35
|
+
return 5;
|
|
36
|
+
case 1:
|
|
37
|
+
return 4;
|
|
38
|
+
case 2:
|
|
39
|
+
return 3;
|
|
40
|
+
case 3:
|
|
41
|
+
return 2;
|
|
42
|
+
case 4:
|
|
43
|
+
return 1;
|
|
44
|
+
default:
|
|
45
|
+
return 1;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function getTypeWeight(type = 'task') {
|
|
50
|
+
const normalizedType = type ?? 'task';
|
|
51
|
+
if (normalizedType === 'bug') {
|
|
52
|
+
return 1.2;
|
|
53
|
+
}
|
|
54
|
+
if (normalizedType === 'feature') {
|
|
55
|
+
return 1;
|
|
56
|
+
}
|
|
57
|
+
if (normalizedType === 'task') {
|
|
58
|
+
return 0.8;
|
|
59
|
+
}
|
|
60
|
+
return 1;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function getStatusBoost(status) {
|
|
64
|
+
if (status === 'in_progress') {
|
|
65
|
+
return 1.5;
|
|
66
|
+
}
|
|
67
|
+
if (status === 'open') {
|
|
68
|
+
return 1;
|
|
69
|
+
}
|
|
70
|
+
return 1;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function parseUpdatedAtLikeShell(updatedAt) {
|
|
74
|
+
if (!updatedAt) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const normalized = `${String(updatedAt).slice(0, 19)}Z`;
|
|
79
|
+
const timestamp = Date.parse(normalized);
|
|
80
|
+
return Number.isFinite(timestamp) ? timestamp : null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function getStalenessBoost(updatedAt, now = Date.now()) {
|
|
84
|
+
const timestamp = parseUpdatedAtLikeShell(updatedAt);
|
|
85
|
+
if (timestamp === null) {
|
|
86
|
+
return 1;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const days = (now - timestamp) / 86400000;
|
|
90
|
+
if (days >= 30) {
|
|
91
|
+
return 1.5;
|
|
92
|
+
}
|
|
93
|
+
if (days >= 14) {
|
|
94
|
+
return 1.2;
|
|
95
|
+
}
|
|
96
|
+
if (days >= 7) {
|
|
97
|
+
return 1.1;
|
|
98
|
+
}
|
|
99
|
+
return 1;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function buildDependentsMap(issues) {
|
|
103
|
+
const dependentsMap = new Map();
|
|
104
|
+
|
|
105
|
+
for (const issue of issues) {
|
|
106
|
+
for (const dependency of issue.dependencies ?? []) {
|
|
107
|
+
// The Kernel emits `dependencies` as bare id strings; the legacy shape
|
|
108
|
+
// used `{ depends_on_id }` objects. Accept both so the reverse-graph is
|
|
109
|
+
// reconstructable even when an issue arrives without a `dependents` array.
|
|
110
|
+
const dependencyId = typeof dependency === 'string'
|
|
111
|
+
? dependency
|
|
112
|
+
: dependency?.depends_on_id;
|
|
113
|
+
if (!dependencyId) {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
if (!dependentsMap.has(dependencyId)) {
|
|
117
|
+
dependentsMap.set(dependencyId, []);
|
|
118
|
+
}
|
|
119
|
+
dependentsMap.get(dependencyId).push(issue.id);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return dependentsMap;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function getEpicProximity(issue, epicStats) {
|
|
127
|
+
if (!issue.parent_id || !epicStats?.[issue.parent_id]) {
|
|
128
|
+
return 1;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const stats = epicStats[issue.parent_id];
|
|
132
|
+
if (stats.total <= 0) {
|
|
133
|
+
return 1;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return 1 + ((stats.closed / stats.total) * 0.5);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function scoreIssues(issues, options = {}) {
|
|
140
|
+
const epicStats = options.epicStats ?? {};
|
|
141
|
+
const now = options.now ?? Date.now();
|
|
142
|
+
const dependentsMap = buildDependentsMap(issues);
|
|
143
|
+
|
|
144
|
+
return [...issues]
|
|
145
|
+
.map((issue) => {
|
|
146
|
+
const priorityWeight = getPriorityWeight(issue.priority);
|
|
147
|
+
// Prefer an explicit count, then the Kernel's authoritative `dependents`
|
|
148
|
+
// reverse-graph array, then the locally-reconstructed map (legacy shape).
|
|
149
|
+
const directDependents = issue.dependent_count
|
|
150
|
+
?? (Array.isArray(issue.dependents) ? issue.dependents.length : undefined)
|
|
151
|
+
?? dependentsMap.get(issue.id)?.length
|
|
152
|
+
?? 0;
|
|
153
|
+
const unblockChain = Math.max(directDependents + 1, 1);
|
|
154
|
+
const typeWeight = getTypeWeight(issue.type);
|
|
155
|
+
const statusBoost = getStatusBoost(issue.status);
|
|
156
|
+
const epicProximity = getEpicProximity(issue, epicStats);
|
|
157
|
+
const stalenessBoost = getStalenessBoost(issue.updated_at, now);
|
|
158
|
+
// The Kernel supplies `dependents` directly (reverse graph); fall back to
|
|
159
|
+
// the reconstructed map only for the legacy { depends_on_id } shape.
|
|
160
|
+
const dependents = Array.isArray(issue.dependents)
|
|
161
|
+
? issue.dependents
|
|
162
|
+
: (dependentsMap.get(issue.id) ?? []);
|
|
163
|
+
const score = priorityWeight
|
|
164
|
+
* unblockChain
|
|
165
|
+
* typeWeight
|
|
166
|
+
* statusBoost
|
|
167
|
+
* epicProximity
|
|
168
|
+
* stalenessBoost;
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
...issue,
|
|
172
|
+
score: roundToTwo(score),
|
|
173
|
+
priority_weight: priorityWeight,
|
|
174
|
+
unblock_chain: unblockChain,
|
|
175
|
+
type_weight: typeWeight,
|
|
176
|
+
status_boost: statusBoost,
|
|
177
|
+
epic_proximity: roundToTwo(epicProximity),
|
|
178
|
+
staleness_boost: stalenessBoost,
|
|
179
|
+
dependents,
|
|
180
|
+
};
|
|
181
|
+
})
|
|
182
|
+
.sort((left, right) => right.score - left.score);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
module.exports = {
|
|
186
|
+
getPriorityWeight,
|
|
187
|
+
getStalenessBoost,
|
|
188
|
+
getStatusBoost,
|
|
189
|
+
getTypeWeight,
|
|
190
|
+
scoreIssues,
|
|
191
|
+
};
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const { secureExecFileSync } = require('../shell-utils.js');
|
|
6
|
+
|
|
7
|
+
function getGitConfig(projectRoot, key) {
|
|
8
|
+
try {
|
|
9
|
+
return secureExecFileSync('git', ['config', key], {
|
|
10
|
+
encoding: 'utf8',
|
|
11
|
+
cwd: projectRoot,
|
|
12
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
13
|
+
}).trim();
|
|
14
|
+
} catch (_error) {
|
|
15
|
+
return '';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function getDeveloperIdentity(projectRoot) {
|
|
20
|
+
return {
|
|
21
|
+
email: getGitConfig(projectRoot, 'user.email'),
|
|
22
|
+
name: getGitConfig(projectRoot, 'user.name'),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function normalizeEmail(value) {
|
|
27
|
+
return typeof value === 'string' ? value.trim().toLowerCase() : '';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function readIssues(projectRoot) {
|
|
31
|
+
const issuesPath = path.join(projectRoot, '.beads', 'issues.jsonl');
|
|
32
|
+
if (!fs.existsSync(issuesPath)) {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const raw = fs.readFileSync(issuesPath, 'utf8');
|
|
37
|
+
const latestById = new Map();
|
|
38
|
+
|
|
39
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
40
|
+
if (!line.trim()) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
const issue = JSON.parse(line);
|
|
46
|
+
if (issue && issue.id) {
|
|
47
|
+
latestById.set(issue.id, issue);
|
|
48
|
+
}
|
|
49
|
+
} catch (_error) {
|
|
50
|
+
// Ignore malformed rows so one bad append does not break status.
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return Array.from(latestById.values());
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function isAssignedToDeveloper(issue, developer) {
|
|
58
|
+
if (!issue || !developer) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (issue.owner) {
|
|
63
|
+
const developerEmail = normalizeEmail(developer.email);
|
|
64
|
+
return developerEmail !== '' && normalizeEmail(issue.owner) === developerEmail;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return developer.name !== '' && issue.created_by === developer.name;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const DEFAULT_STALE_AFTER_DAYS = 14;
|
|
71
|
+
|
|
72
|
+
function parseTimestampOrZero(value) {
|
|
73
|
+
if (!value) {
|
|
74
|
+
return 0;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const parsed = Date.parse(value);
|
|
78
|
+
return Number.isNaN(parsed) ? 0 : parsed;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function sortByUpdatedAtDesc(left, right) {
|
|
82
|
+
const leftTime = parseTimestampOrZero(left.updated_at);
|
|
83
|
+
const rightTime = parseTimestampOrZero(right.updated_at);
|
|
84
|
+
return rightTime - leftTime;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function hasUnresolvedDependencies(issue) {
|
|
88
|
+
return Number(issue.dependency_count || 0) > 0;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function isOpenIssue(issue) {
|
|
92
|
+
return issue.status === 'open' || issue.status === 'in_progress';
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function isStale(issue, now, staleAfterDays) {
|
|
96
|
+
if (!isOpenIssue(issue)) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const updatedAt = parseTimestampOrZero(issue.updated_at);
|
|
101
|
+
if (updatedAt === 0) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const staleMs = staleAfterDays * 24 * 60 * 60 * 1000;
|
|
106
|
+
return now.getTime() - updatedAt >= staleMs;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function readBeadsSnapshot(projectRoot, options = {}) {
|
|
110
|
+
const developer = getDeveloperIdentity(projectRoot);
|
|
111
|
+
const issues = readIssues(projectRoot);
|
|
112
|
+
const parsedNow = options.now instanceof Date
|
|
113
|
+
? options.now
|
|
114
|
+
: (typeof options.now === 'string' ? new Date(options.now) : null);
|
|
115
|
+
const now = parsedNow instanceof Date && !Number.isNaN(parsedNow.getTime())
|
|
116
|
+
? parsedNow
|
|
117
|
+
: new Date();
|
|
118
|
+
const parsedStaleAfterDays = Number(options.staleAfterDays);
|
|
119
|
+
const staleAfterDays = Number.isFinite(parsedStaleAfterDays)
|
|
120
|
+
? parsedStaleAfterDays
|
|
121
|
+
: DEFAULT_STALE_AFTER_DAYS;
|
|
122
|
+
|
|
123
|
+
return {
|
|
124
|
+
developer,
|
|
125
|
+
issues,
|
|
126
|
+
active: issues.filter(issue => issue.status === 'in_progress').sort(sortByUpdatedAtDesc),
|
|
127
|
+
activeAssigned: issues.filter(issue => issue.status === 'in_progress' && isAssignedToDeveloper(issue, developer)),
|
|
128
|
+
ready: issues.filter(issue => issue.status === 'open' && !hasUnresolvedDependencies(issue)),
|
|
129
|
+
blocked: issues.filter(issue => isOpenIssue(issue) && hasUnresolvedDependencies(issue)).sort(sortByUpdatedAtDesc),
|
|
130
|
+
stale: issues.filter(issue => isStale(issue, now, staleAfterDays)).sort(sortByUpdatedAtDesc),
|
|
131
|
+
recentCompleted: issues.filter(issue => issue.status === 'closed').sort(sortByUpdatedAtDesc),
|
|
132
|
+
limits: [
|
|
133
|
+
'Uses local Beads issues.jsonl only.',
|
|
134
|
+
'Does not read GitHub review, CI, project, or sync freshness state.',
|
|
135
|
+
],
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
module.exports = {
|
|
140
|
+
getDeveloperIdentity,
|
|
141
|
+
isAssignedToDeveloper,
|
|
142
|
+
readBeadsSnapshot,
|
|
143
|
+
hasUnresolvedDependencies,
|
|
144
|
+
isStale,
|
|
145
|
+
};
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
STAGE_LABELS,
|
|
5
|
+
getStageWorkflow,
|
|
6
|
+
getWorkflowPath,
|
|
7
|
+
} = require('../workflow/stages');
|
|
8
|
+
|
|
9
|
+
const DEFAULT_SECTION_LIMIT = 5;
|
|
10
|
+
|
|
11
|
+
// One-line "why you are at this stage", keyed by the LAST completed stage. Lets the
|
|
12
|
+
// one-glance view answer "why here?" without the agent re-deriving it from raw state.
|
|
13
|
+
const WHY_BY_LAST_COMPLETED = Object.freeze({
|
|
14
|
+
plan: 'planning is done; implementation not started.',
|
|
15
|
+
dev: 'implementation landed; not yet validated.',
|
|
16
|
+
validate: 'validation passed; PR not yet created.',
|
|
17
|
+
ship: 'PR is open; review not yet complete.',
|
|
18
|
+
review: 'review addressed; awaiting merge/verify.',
|
|
19
|
+
verify: 'post-merge verification complete.',
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
function buildSection(title, items, options = {}) {
|
|
23
|
+
const lines = ['', title];
|
|
24
|
+
if (!items || items.length === 0) {
|
|
25
|
+
lines.push(' none', '');
|
|
26
|
+
return lines;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const limit = options.limit ?? null;
|
|
30
|
+
const visibleItems = limit ? items.slice(0, limit) : items;
|
|
31
|
+
lines.push(...visibleItems.map(item => ` ${item}`));
|
|
32
|
+
|
|
33
|
+
if (limit && items.length > limit) {
|
|
34
|
+
lines.push(` ...and ${items.length - limit} more`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
lines.push('');
|
|
38
|
+
return lines;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function toIssueSummary(issue) {
|
|
42
|
+
return {
|
|
43
|
+
id: issue.id,
|
|
44
|
+
title: issue.title || '(untitled)',
|
|
45
|
+
status: issue.status || null,
|
|
46
|
+
owner: issue.owner || null,
|
|
47
|
+
dependency_count: Number(issue.dependency_count || 0),
|
|
48
|
+
updated_at: issue.updated_at || null,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function formatIssue(issue, options = {}) {
|
|
53
|
+
const status = options.includeStatus && issue.status ? ` [${issue.status}]` : '';
|
|
54
|
+
return `${issue.id} ${issue.title || '(untitled)'}${status}`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Shared Run-now / Next-after-this lines. Owned here so BOTH the one-glance
|
|
58
|
+
// "You are here" block and status.js's authoritative stage format render them
|
|
59
|
+
// identically. `noneWhenMissing` prints an explicit "none" for terminal stages
|
|
60
|
+
// (the one-glance view wants it; the authoritative format omits it, as before).
|
|
61
|
+
function formatRunNextLines(workflowResult, { noneWhenMissing = false } = {}) {
|
|
62
|
+
const lines = [`Run now: /${workflowResult.runCommand}`];
|
|
63
|
+
if (workflowResult.nextCommand) {
|
|
64
|
+
lines.push(`Next after this: /${workflowResult.nextCommand}`);
|
|
65
|
+
} else if (noneWhenMissing) {
|
|
66
|
+
lines.push('Next after this: none');
|
|
67
|
+
}
|
|
68
|
+
return lines;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Canonical "Stage N of M — Label (classification workflow)" heading. N/M come from
|
|
72
|
+
// the per-classification path in lib/workflow/stages.js, so non-stages (Research,
|
|
73
|
+
// Merge, pre-merge, "Fresh Start") never get a number.
|
|
74
|
+
function formatStageHeading(workflowResult) {
|
|
75
|
+
const classification = workflowResult.workflowState?.workflowDecisions?.classification || null;
|
|
76
|
+
const stageId = workflowResult.stageId;
|
|
77
|
+
const label = STAGE_LABELS[stageId] || workflowResult.stageName || stageId;
|
|
78
|
+
const workflow = getStageWorkflow(stageId, classification);
|
|
79
|
+
const path = getWorkflowPath(classification);
|
|
80
|
+
|
|
81
|
+
if (workflow && path.length > 0) {
|
|
82
|
+
return `Stage ${workflow.order} of ${path.length} — ${label} (${classification} workflow)`;
|
|
83
|
+
}
|
|
84
|
+
return `Stage — ${label}${classification ? ` (${classification} workflow)` : ''}`;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function deriveWhy(workflowResult) {
|
|
88
|
+
const completed = workflowResult.workflowState?.completedStages || [];
|
|
89
|
+
const last = completed.length > 0 ? completed[completed.length - 1] : null;
|
|
90
|
+
return (last && WHY_BY_LAST_COMPLETED[last]) || 'just getting started.';
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// The "You are here" block: the first thing a user or agent reads. When there is no
|
|
94
|
+
// active workflow, fall back to a STATE-AWARE next step rather than a dead end.
|
|
95
|
+
function buildYouAreHere(workflowResult, snapshot) {
|
|
96
|
+
const lines = ['You are here'];
|
|
97
|
+
|
|
98
|
+
if (!workflowResult) {
|
|
99
|
+
const topReady = (snapshot.ready || [])[0];
|
|
100
|
+
if (topReady) {
|
|
101
|
+
lines.push(` No active workflow. Next: forge claim ${topReady.id}, then /plan (or /dev for a small fix).`);
|
|
102
|
+
} else {
|
|
103
|
+
lines.push(' No active workflow and no ready issues. Next: /plan "<describe the feature>" to start one.');
|
|
104
|
+
}
|
|
105
|
+
return lines;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
lines.push(` ${formatStageHeading(workflowResult)}`);
|
|
109
|
+
for (const line of formatRunNextLines(workflowResult, { noneWhenMissing: true })) {
|
|
110
|
+
lines.push(` ${line}`);
|
|
111
|
+
}
|
|
112
|
+
lines.push(` Why: ${deriveWhy(workflowResult)}`);
|
|
113
|
+
return lines;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Zero-arg `forge status`: a top-down one-glance view. Order matters — orientation
|
|
117
|
+
// first (You are here), then Context, then your work. Blocked/Stale/Recent
|
|
118
|
+
// completions are detail, shown only with `--full`.
|
|
119
|
+
function formatZeroArgStatus({ context, snapshot, workflowResult = null, full = false }) {
|
|
120
|
+
const worktree = context.inWorktree ? 'worktree' : 'main';
|
|
121
|
+
const contextLine = `${context.branch} — ${worktree}, ${context.workingTree.summary}`;
|
|
122
|
+
|
|
123
|
+
const activeIssues = snapshot.activeAssigned || [];
|
|
124
|
+
const readyCount = (snapshot.ready || []).length;
|
|
125
|
+
const workLines = [];
|
|
126
|
+
if (activeIssues.length > 0) {
|
|
127
|
+
for (const issue of activeIssues) {
|
|
128
|
+
workLines.push(`Active: ${formatIssue(issue, { includeStatus: true })}`);
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
workLines.push('Active: none');
|
|
132
|
+
}
|
|
133
|
+
workLines.push(readyCount > 0 ? `Ready: ${readyCount} more (forge issue ready)` : 'Ready: none');
|
|
134
|
+
|
|
135
|
+
const blocks = [
|
|
136
|
+
buildYouAreHere(workflowResult, snapshot).join('\n'),
|
|
137
|
+
['Context', ` ${contextLine}`].join('\n'),
|
|
138
|
+
['Your work', ...workLines.map(line => ` ${line}`)].join('\n'),
|
|
139
|
+
'New here? forge docs setup | forge --help',
|
|
140
|
+
];
|
|
141
|
+
|
|
142
|
+
if (full) {
|
|
143
|
+
blocks.push(
|
|
144
|
+
buildSection('Blocked', (snapshot.blocked || []).map(issue => formatIssue(issue, { includeStatus: true })), { limit: DEFAULT_SECTION_LIMIT }).join('\n').trim(),
|
|
145
|
+
buildSection('Stale', (snapshot.stale || []).map(issue => formatIssue(issue, { includeStatus: true })), { limit: DEFAULT_SECTION_LIMIT }).join('\n').trim(),
|
|
146
|
+
buildSection('Parked', (snapshot.parked || []).map(issue => formatIssue(issue, { includeStatus: true })), { limit: DEFAULT_SECTION_LIMIT }).join('\n').trim(),
|
|
147
|
+
buildSection('Recent Completions', (snapshot.recentCompleted || []).map(issue => formatIssue(issue)), { limit: DEFAULT_SECTION_LIMIT }).join('\n').trim(),
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return blocks.join('\n\n');
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function buildPersonalStatusJson({ context, snapshot, workflowResult = null }) {
|
|
155
|
+
return {
|
|
156
|
+
context,
|
|
157
|
+
personal: {
|
|
158
|
+
activeAssigned: (snapshot.activeAssigned || []).map(toIssueSummary),
|
|
159
|
+
ready: (snapshot.ready || []).map(toIssueSummary),
|
|
160
|
+
blocked: (snapshot.blocked || []).map(toIssueSummary),
|
|
161
|
+
stale: (snapshot.stale || []).map(toIssueSummary),
|
|
162
|
+
parked: (snapshot.parked || []).map(toIssueSummary),
|
|
163
|
+
recentCompleted: (snapshot.recentCompleted || []).map(toIssueSummary),
|
|
164
|
+
},
|
|
165
|
+
workflow: workflowResult ? {
|
|
166
|
+
stageId: workflowResult.stageId,
|
|
167
|
+
stageName: workflowResult.stageName,
|
|
168
|
+
runCommand: workflowResult.runCommand,
|
|
169
|
+
nextCommand: workflowResult.nextCommand,
|
|
170
|
+
nextStages: workflowResult.nextStages,
|
|
171
|
+
} : null,
|
|
172
|
+
limits: snapshot.limits || [],
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function formatBoard({ context, snapshot }) {
|
|
177
|
+
return [
|
|
178
|
+
'',
|
|
179
|
+
'Team Runtime Board',
|
|
180
|
+
`Source: local Beads runtime state`,
|
|
181
|
+
`Branch: ${context.branch}`,
|
|
182
|
+
`Working tree: ${context.workingTree.summary}`,
|
|
183
|
+
'',
|
|
184
|
+
...buildSection('Active', (snapshot.active || []).map(issue => formatIssue(issue, { includeStatus: true })), { limit: DEFAULT_SECTION_LIMIT }),
|
|
185
|
+
...buildSection('Ready', (snapshot.ready || []).map(issue => formatIssue(issue)), { limit: DEFAULT_SECTION_LIMIT }),
|
|
186
|
+
...buildSection('Blocked', (snapshot.blocked || []).map(issue => formatIssue(issue, { includeStatus: true })), { limit: DEFAULT_SECTION_LIMIT }),
|
|
187
|
+
...buildSection('Stale', (snapshot.stale || []).map(issue => formatIssue(issue, { includeStatus: true })), { limit: DEFAULT_SECTION_LIMIT }),
|
|
188
|
+
...buildSection('Parked', (snapshot.parked || []).map(issue => formatIssue(issue, { includeStatus: true })), { limit: DEFAULT_SECTION_LIMIT }),
|
|
189
|
+
...buildSection('Recent Completions', (snapshot.recentCompleted || []).map(issue => formatIssue(issue)), { limit: DEFAULT_SECTION_LIMIT }),
|
|
190
|
+
...buildSection('Limits', snapshot.limits || []),
|
|
191
|
+
].join('\n');
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function buildBoardJson({ context, snapshot }) {
|
|
195
|
+
return {
|
|
196
|
+
context,
|
|
197
|
+
board: {
|
|
198
|
+
active: (snapshot.active || []).map(toIssueSummary),
|
|
199
|
+
ready: (snapshot.ready || []).map(toIssueSummary),
|
|
200
|
+
blocked: (snapshot.blocked || []).map(toIssueSummary),
|
|
201
|
+
stale: (snapshot.stale || []).map(toIssueSummary),
|
|
202
|
+
parked: (snapshot.parked || []).map(toIssueSummary),
|
|
203
|
+
recentCompleted: (snapshot.recentCompleted || []).map(toIssueSummary),
|
|
204
|
+
},
|
|
205
|
+
limits: snapshot.limits || [],
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
module.exports = {
|
|
210
|
+
buildBoardJson,
|
|
211
|
+
buildPersonalStatusJson,
|
|
212
|
+
formatBoard,
|
|
213
|
+
formatRunNextLines,
|
|
214
|
+
formatZeroArgStatus,
|
|
215
|
+
toIssueSummary,
|
|
216
|
+
};
|