forge-workflow 0.0.10 → 0.1.0-beta.3
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 +82 -5
- package/.forge/hooks/forge-native-hook.js +431 -0
- package/.forge/protected-paths.yaml +157 -0
- package/AGENTS.md +151 -61
- package/CHANGELOG.md +709 -0
- package/CLAUDE.md +9 -118
- package/QUICKSTART.md +175 -0
- package/README.md +275 -365
- package/bin/forge-cmd.js +120 -9
- package/bin/forge-preflight.js +26 -5
- package/bin/forge.js +532 -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/forge/TOOLCHAIN.md +670 -0
- 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 +121 -0
- package/docs/guides/SUPPORT.md +190 -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 +214 -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/{TOOLCHAIN.md → reference/TOOLCHAIN.md} +62 -47
- 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 +155 -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/activation/ensure-forge-home.js +135 -0
- package/lib/adapter-cli.js +307 -0
- package/lib/adapters/beads-issue-adapter.js +127 -0
- package/lib/adapters/beads-kernel-compat.js +1109 -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 +139 -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-detect.js +60 -0
- package/lib/beads-nudge.js +91 -0
- package/lib/beads-setup.js +121 -0
- package/lib/beads-sync-scaffold.js +25 -101
- package/lib/codex-skills.js +51 -1
- package/lib/commands/_aliases.js +248 -0
- package/lib/commands/_issue.js +780 -77
- package/lib/commands/_manifest.js +93 -0
- package/lib/commands/_registry.js +99 -34
- package/lib/commands/_resolve-command-opts.js +230 -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 +209 -0
- package/lib/commands/hooks.js +377 -0
- package/lib/commands/inbox.js +118 -0
- package/lib/commands/init.js +604 -0
- package/lib/commands/insights.js +79 -0
- package/lib/commands/issue.js +12 -1
- package/lib/commands/issues.js +17 -0
- package/lib/commands/lint.js +5 -0
- package/lib/commands/list.js +2 -2
- package/lib/commands/memory.js +81 -0
- package/lib/commands/merge.js +312 -0
- package/lib/commands/migrate.js +362 -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 +481 -29
- package/lib/commands/pr.js +88 -0
- package/lib/commands/preflight.js +211 -0
- package/lib/commands/prime.js +13 -0
- package/lib/commands/push.js +135 -2
- package/lib/commands/ready.js +2 -2
- package/lib/commands/recall.js +171 -0
- package/lib/commands/recap.js +75 -0
- package/lib/commands/recommend.js +0 -1
- package/lib/commands/release.js +104 -0
- package/lib/commands/remember.js +140 -0
- package/lib/commands/role.js +99 -0
- package/lib/commands/serve.js +581 -0
- package/lib/commands/setup.js +900 -971
- package/lib/commands/shepherd.js +501 -0
- package/lib/commands/ship.js +59 -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 +158 -21
- package/lib/commands/sync.js +34 -46
- package/lib/commands/team.js +4 -1
- package/lib/commands/test.js +43 -27
- package/lib/commands/update.js +2 -2
- package/lib/commands/upgrade.js +47 -0
- package/lib/commands/validate.js +43 -18
- package/lib/commands/worktree.js +362 -99
- package/lib/config-writer.js +202 -0
- package/lib/control-plane.js +236 -0
- package/lib/core/runtime-graph.js +977 -0
- package/lib/dep-guard/keyword-ripple.js +2 -2
- package/lib/deprecated-sync-cleanup.js +362 -0
- package/lib/detect-agent.js +2 -28
- package/lib/detect-worktree.js +35 -9
- 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 +382 -11
- package/lib/forge-lock.js +262 -0
- package/lib/gate-events.js +192 -0
- package/lib/global-flags.js +104 -0
- package/lib/greptile-match.js +7 -63
- package/lib/grounding/context-events.js +230 -0
- package/lib/grounding/read-first.js +112 -0
- package/lib/harness-capability-matrix.js +380 -0
- package/lib/hook-global-installer.js +347 -0
- package/lib/hook-renderer.js +541 -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/kernel/backing-issue.js +311 -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/owned-kernel.js +43 -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 +2540 -0
- package/lib/kernel/taxonomy-validator.js +394 -0
- package/lib/lefthook-check.js +3 -2
- 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/auto-actions.js +175 -0
- package/lib/pr-monitor/differ.js +195 -0
- package/lib/pr-monitor/digest.js +206 -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 +192 -0
- package/lib/pr-monitor/upsert-sticky.js +169 -0
- package/lib/pr-monitor/watch-lifecycle.js +95 -0
- package/lib/pr-monitor/watch.js +247 -0
- package/lib/pr-pull.js +1314 -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 +99 -497
- package/lib/protected-path-manifest.js +281 -0
- package/lib/protected-state-surfaces.js +387 -0
- package/lib/release-readiness.js +2105 -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 +241 -20
- 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/scoring.js +17 -3
- package/lib/status/beads-snapshot.js +45 -2
- package/lib/status/presenter.js +169 -18
- 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 +251 -0
- package/lib/workflow/enforce-stage.js +351 -45
- package/lib/workflow/stage-transition.js +115 -0
- package/lib/workflow/stages.js +30 -6
- package/lib/workflow/state-manager.js +11 -22
- package/lib/workflow/state.js +23 -1
- package/lib/workflow-profiles.js +17 -5
- package/package.json +37 -35
- 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 +81 -57
- package/scripts/beads-upgrade-smoke.sh +24 -3
- 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.sh +22 -3
- 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 +49 -84
- 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 +50 -83
- 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/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-auto-actions.js +93 -0
- package/scripts/pr-coordinator.sh +3 -0
- package/scripts/pr-verdict-label.js +50 -0
- package/scripts/preflight-sonar.eslint.config.mjs +44 -0
- package/scripts/preflight.sh +21 -94
- package/scripts/protected-state-check.js +104 -0
- package/scripts/smart-status.sh +60 -57
- 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-utils.sh +3 -0
- package/scripts/test-ci-shard.js +13 -6
- package/scripts/test.js +95 -12
- 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} +44 -50
- 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} +132 -157
- 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/{.github/prompts/ship.prompt.md → skills/ship/SKILL.md} +81 -45
- 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/{.github/prompts/status.prompt.md → skills/status/SKILL.md} +20 -10
- 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/verify.prompt.md +0 -271
- package/.github/workflows/beads-to-github.yml +0 -89
- package/.github/workflows/github-to-beads.yml +0 -100
- 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 -281
- 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-bootstrap.js +0 -225
- package/lib/beads-health-check.js +0 -188
- package/lib/commands/commands-reset.js +0 -147
- package/opencode.json +0 -67
- package/scripts/beads-context.test.js +0 -584
- 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 -356
- package/scripts/github-beads-sync/label-mapper.mjs +0 -54
- package/scripts/github-beads-sync/mapping.mjs +0 -132
- package/scripts/github-beads-sync/reverse-sync-cli.mjs +0 -31
- package/scripts/github-beads-sync/reverse-sync.mjs +0 -162
- 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,192 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Forge Stage Command (f61601ab)
|
|
5
|
+
*
|
|
6
|
+
* Records the REAL workflow phase of an issue into the kernel_stage_runs table so
|
|
7
|
+
* the phase is queryable — instead of being guessed from status+claim (a
|
|
8
|
+
* claimed-open issue with a merged PR would otherwise still show "dev"). Mirrors
|
|
9
|
+
* the worktree-linkage registry: direct kernel writes, idempotent per
|
|
10
|
+
* (issue_id, stage).
|
|
11
|
+
*
|
|
12
|
+
* forge stage <issue-id> <stage> --start Open a stage (status=active)
|
|
13
|
+
* forge stage <issue-id> <stage> --complete Close a stage (status=done)
|
|
14
|
+
* forge stage <issue-id> --current Print the current stage
|
|
15
|
+
* forge stage <issue-id> --list Print the full stage history
|
|
16
|
+
*
|
|
17
|
+
* `<stage>` is one of the canonical workflow stages (plan|dev|validate|ship|review|verify).
|
|
18
|
+
* Read the current stage back on `forge show <id>` (data.current_stage).
|
|
19
|
+
*
|
|
20
|
+
* @module commands/stage
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
const { STAGE_IDS, normalizeStageId } = require('../workflow/stages');
|
|
24
|
+
const { resolveIssueId } = require('../kernel/issue-id-resolver');
|
|
25
|
+
|
|
26
|
+
const STAGE_FLAGS = ['--start', '--complete', '--list', '--current', '--json'];
|
|
27
|
+
const VALUE_FLAGS = ['--substage'];
|
|
28
|
+
const USAGE = 'Usage: forge stage <issue-id> <stage> --start|--complete (reads: --current | --list)';
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Parse the stage command's own flags out of the raw args (the global flag parser
|
|
32
|
+
* only recognizes an allowlist, so — like `worktree` — this command extracts its
|
|
33
|
+
* own). Returns { positional, opts } or { error }.
|
|
34
|
+
*/
|
|
35
|
+
function parseStageArgs(args = []) {
|
|
36
|
+
const positional = [];
|
|
37
|
+
const opts = { start: false, complete: false, list: false, current: false, json: false, substage: null };
|
|
38
|
+
|
|
39
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
40
|
+
const arg = args[i];
|
|
41
|
+
if (typeof arg !== 'string') continue;
|
|
42
|
+
|
|
43
|
+
const valueFlag = VALUE_FLAGS.find(flag => arg === flag || arg.startsWith(`${flag}=`));
|
|
44
|
+
if (valueFlag) {
|
|
45
|
+
let value;
|
|
46
|
+
if (arg.startsWith(`${valueFlag}=`)) {
|
|
47
|
+
value = arg.slice(`${valueFlag}=`.length);
|
|
48
|
+
} else {
|
|
49
|
+
value = args[i + 1];
|
|
50
|
+
i += 1;
|
|
51
|
+
}
|
|
52
|
+
if (!value || value.startsWith('--')) {
|
|
53
|
+
return { error: `Missing value for ${valueFlag}. ${USAGE}` };
|
|
54
|
+
}
|
|
55
|
+
opts.substage = value;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (STAGE_FLAGS.includes(arg)) {
|
|
60
|
+
opts[arg.slice(2)] = true;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (arg.startsWith('--')) {
|
|
65
|
+
return { error: `Unknown flag: ${arg}. ${USAGE}` };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
positional.push(arg);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return { positional, opts };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function resolveDriver(projectRoot, opts) {
|
|
75
|
+
if (opts._kernelDriver) return opts._kernelDriver;
|
|
76
|
+
const { buildMigratedKernelIssueDeps } = require('../kernel/cli-broker-factory');
|
|
77
|
+
return (await buildMigratedKernelIssueDeps({ projectRoot })).kernelDriver;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function render(opts, data, humanLines) {
|
|
81
|
+
if (opts.json || process.env.FORGE_JSON === '1') {
|
|
82
|
+
return { success: true, output: JSON.stringify(data, null, 2) };
|
|
83
|
+
}
|
|
84
|
+
return { success: true, output: humanLines.join('\n'), ...data };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
module.exports = {
|
|
88
|
+
name: 'stage',
|
|
89
|
+
description: 'Record or read an issue\'s real workflow stage (stage_runs)',
|
|
90
|
+
usage: USAGE,
|
|
91
|
+
flags: {
|
|
92
|
+
'--start': 'Open a stage run (status=active)',
|
|
93
|
+
'--complete': 'Complete a stage run (status=done)',
|
|
94
|
+
'--substage': 'Optional substage label to record',
|
|
95
|
+
'--current': 'Print the current stage (latest active, else latest completed)',
|
|
96
|
+
'--list': 'Print the full stage-run history for the issue',
|
|
97
|
+
'--json': 'Emit machine-readable JSON',
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* @param {string[]} args - Positional + flag args after `stage`
|
|
102
|
+
* @param {object} _flags - Global parsed flags (unused; this command parses its own)
|
|
103
|
+
* @param {string} projectRoot - Project root path
|
|
104
|
+
* @param {object} [opts] - DI options (may inject `_kernelDriver`)
|
|
105
|
+
* @returns {Promise<object>}
|
|
106
|
+
*/
|
|
107
|
+
handler: async (args, _flags, projectRoot, opts = {}) => {
|
|
108
|
+
const parsed = parseStageArgs(args);
|
|
109
|
+
if (parsed.error) {
|
|
110
|
+
return { success: false, error: parsed.error };
|
|
111
|
+
}
|
|
112
|
+
const { positional, opts: stageOpts } = parsed;
|
|
113
|
+
|
|
114
|
+
const issueRef = positional[0];
|
|
115
|
+
if (!issueRef) {
|
|
116
|
+
return { success: false, error: `Missing issue id. ${USAGE}` };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
let driver;
|
|
120
|
+
try {
|
|
121
|
+
driver = await resolveDriver(projectRoot, opts);
|
|
122
|
+
} catch (error) {
|
|
123
|
+
return { success: false, error: `Kernel unavailable: ${error.message}` };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Resolve prefixes / display handles to a full issue id (same resolver the
|
|
127
|
+
// issue commands use), so `forge stage 1a2b3c4d dev --start` works.
|
|
128
|
+
const resolution = await resolveIssueId(
|
|
129
|
+
issueRef,
|
|
130
|
+
(needle, limit) => driver.findIssueIdsByPrefix(needle, limit, {}, {}),
|
|
131
|
+
);
|
|
132
|
+
if (resolution.error) {
|
|
133
|
+
return { success: false, error: resolution.error };
|
|
134
|
+
}
|
|
135
|
+
const issueId = resolution.id;
|
|
136
|
+
|
|
137
|
+
// Read paths -----------------------------------------------------------
|
|
138
|
+
if (stageOpts.current) {
|
|
139
|
+
const current = driver.getCurrentStage({ issue_id: issueId }, {});
|
|
140
|
+
const data = {
|
|
141
|
+
issue_id: issueId,
|
|
142
|
+
current_stage: current ? current.stage : null,
|
|
143
|
+
current_stage_status: current ? current.status : null,
|
|
144
|
+
};
|
|
145
|
+
const human = current
|
|
146
|
+
? `${issueId}: ${current.stage} (${current.status})`
|
|
147
|
+
: `${issueId}: no stage recorded`;
|
|
148
|
+
return render(stageOpts, data, [human]);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (stageOpts.list) {
|
|
152
|
+
const runs = driver.listStageRuns({ issue_id: issueId }, {});
|
|
153
|
+
const data = { issue_id: issueId, stage_runs: runs };
|
|
154
|
+
const human = runs.length === 0
|
|
155
|
+
? [`${issueId}: no stage runs`]
|
|
156
|
+
: runs.map(run => ` ${run.stage.padEnd(9)} ${run.status.padEnd(7)} started ${run.started_at}${run.completed_at ? ` → completed ${run.completed_at}` : ''}`);
|
|
157
|
+
return render(stageOpts, data, [`${issueId} stage history:`, ...human]);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Write paths ----------------------------------------------------------
|
|
161
|
+
const stage = normalizeStageId(positional[1]);
|
|
162
|
+
if (!stage) {
|
|
163
|
+
return {
|
|
164
|
+
success: false,
|
|
165
|
+
error: `Invalid or missing stage "${positional[1] ?? ''}". Expected one of: ${STAGE_IDS.join(', ')}. ${USAGE}`,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (stageOpts.start && stageOpts.complete) {
|
|
170
|
+
return { success: false, error: `Pass only one of --start or --complete. ${USAGE}` };
|
|
171
|
+
}
|
|
172
|
+
const action = stageOpts.complete ? 'complete' : 'start';
|
|
173
|
+
|
|
174
|
+
let row;
|
|
175
|
+
try {
|
|
176
|
+
row = driver.recordStageRun(
|
|
177
|
+
{ issue_id: issueId, stage, action, substage: stageOpts.substage || null },
|
|
178
|
+
{},
|
|
179
|
+
);
|
|
180
|
+
} catch (error) {
|
|
181
|
+
// A FOREIGN KEY failure means the issue id does not exist in the kernel.
|
|
182
|
+
if (/FOREIGN KEY/i.test(String(error.message))) {
|
|
183
|
+
return { success: false, error: `Issue ${issueId} not found in the kernel.` };
|
|
184
|
+
}
|
|
185
|
+
return { success: false, error: `Failed to record stage: ${error.message}` };
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const data = { issue_id: issueId, action, stage_run: row };
|
|
189
|
+
const verb = action === 'complete' ? 'completed' : 'started';
|
|
190
|
+
return render(stageOpts, data, [`${issueId}: ${verb} stage ${stage} (${row.status})`]);
|
|
191
|
+
},
|
|
192
|
+
};
|
package/lib/commands/status.js
CHANGED
|
@@ -9,8 +9,12 @@ const {
|
|
|
9
9
|
} = require('../workflow/state');
|
|
10
10
|
const { STAGE_IDS } = require('../workflow/stages');
|
|
11
11
|
const { detectWorktree } = require('../detect-worktree');
|
|
12
|
-
const {
|
|
13
|
-
const {
|
|
12
|
+
const { readStatusSnapshot } = require('../status/snapshot');
|
|
13
|
+
const {
|
|
14
|
+
buildPersonalStatusJson,
|
|
15
|
+
formatRunNextLines,
|
|
16
|
+
formatZeroArgStatus,
|
|
17
|
+
} = require('../status/presenter');
|
|
14
18
|
const {
|
|
15
19
|
loadState,
|
|
16
20
|
extractWorkflowStateFromComments,
|
|
@@ -18,6 +22,12 @@ const {
|
|
|
18
22
|
} = require('../workflow/state-manager');
|
|
19
23
|
const { secureExecFileSync } = require('../shell-utils.js');
|
|
20
24
|
|
|
25
|
+
// Lifecycle progression used for status display. Stage 8 'Merge' is the merge
|
|
26
|
+
// EVENT (a human GitHub action — Forge exposes no `merge` command) that lands after
|
|
27
|
+
// the review stage and before post-merge /verify. Pre-merge doc/CI/handoff checks
|
|
28
|
+
// are an embedded gate inside /ship and /review, not a standalone stage, so this
|
|
29
|
+
// ladder never gains a premerge stage. (AUTHORITATIVE_STAGE_NAMES below still maps
|
|
30
|
+
// the legacy 'premerge' id purely so historical workflow state round-trips.)
|
|
21
31
|
const WORKFLOW_STAGES = {
|
|
22
32
|
1: { name: 'Fresh Start', nextCommand: 'research' },
|
|
23
33
|
2: { name: 'Research', nextCommand: 'research' },
|
|
@@ -30,6 +40,10 @@ const WORKFLOW_STAGES = {
|
|
|
30
40
|
9: { name: 'Verification', nextCommand: 'verify' },
|
|
31
41
|
};
|
|
32
42
|
|
|
43
|
+
// Legacy read-path name map. `premerge` is retired as a standalone stage (it is now
|
|
44
|
+
// an embedded gate in /ship and /review) but is intentionally KEPT here so a stored
|
|
45
|
+
// `currentStage: 'premerge'` from a schemaVersion 1 workflow still resolves a name
|
|
46
|
+
// on read — deleting it would break upgraders (see test/status-command.test.js).
|
|
33
47
|
const AUTHORITATIVE_STAGE_NAMES = {
|
|
34
48
|
plan: 'Planning',
|
|
35
49
|
dev: 'Development',
|
|
@@ -329,10 +343,15 @@ function detectStage(context) {
|
|
|
329
343
|
|
|
330
344
|
function parseStatusInputs(args = [], flags = {}) {
|
|
331
345
|
const statusArgs = Array.isArray(args) ? args : [];
|
|
346
|
+
const firstDefined = (...values) => values.find(value => value !== undefined && value !== null);
|
|
332
347
|
const getNextValue = (flagName) => {
|
|
333
348
|
const index = statusArgs.indexOf(flagName);
|
|
334
349
|
if (index !== -1 && index + 1 < statusArgs.length) {
|
|
335
|
-
|
|
350
|
+
const candidate = statusArgs[index + 1];
|
|
351
|
+
if (typeof candidate === 'string' && candidate.startsWith('--')) {
|
|
352
|
+
return null;
|
|
353
|
+
}
|
|
354
|
+
return candidate;
|
|
336
355
|
}
|
|
337
356
|
return null;
|
|
338
357
|
};
|
|
@@ -343,10 +362,23 @@ function parseStatusInputs(args = [], flags = {}) {
|
|
|
343
362
|
};
|
|
344
363
|
|
|
345
364
|
return {
|
|
346
|
-
issueId: flags.issueId
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
365
|
+
issueId: firstDefined(flags.issueId, flags['--issue-id'], getInlineValue('--issue-id'), getNextValue('--issue-id')),
|
|
366
|
+
issueBackend: firstDefined(flags.issueBackend, flags['--issue-backend'], getInlineValue('--issue-backend'), getNextValue('--issue-backend')) || null,
|
|
367
|
+
workflowState: firstDefined(flags.workflowState, flags['--workflow-state'], getInlineValue('--workflow-state'), getNextValue('--workflow-state')),
|
|
368
|
+
bdComments: firstDefined(flags.bdComments, flags['--bd-comments'], getInlineValue('--bd-comments'), getNextValue('--bd-comments')),
|
|
369
|
+
projectRoot: firstDefined(flags.projectRoot, flags['--project-root'], getInlineValue('--project-root'), getNextValue('--project-root')) || null,
|
|
370
|
+
json: flags.json === true || flags['--json'] === true || statusArgs.includes('--json'),
|
|
371
|
+
full: flags.full === true || flags['--full'] === true || statusArgs.includes('--full'),
|
|
372
|
+
now: firstDefined(flags.now, flags['--now'], getInlineValue('--now'), getNextValue('--now')),
|
|
373
|
+
staleAfterDays: firstDefined(
|
|
374
|
+
flags.staleAfterDays,
|
|
375
|
+
flags['--stale-after-days'],
|
|
376
|
+
flags['--staleAfterDays'],
|
|
377
|
+
getInlineValue('--stale-after-days'),
|
|
378
|
+
getInlineValue('--staleAfterDays'),
|
|
379
|
+
getNextValue('--stale-after-days'),
|
|
380
|
+
getNextValue('--staleAfterDays')
|
|
381
|
+
),
|
|
350
382
|
};
|
|
351
383
|
}
|
|
352
384
|
|
|
@@ -408,17 +440,104 @@ function readIssueDetails(issueId, projectRoot = process.cwd()) {
|
|
|
408
440
|
}
|
|
409
441
|
}
|
|
410
442
|
|
|
443
|
+
function stripDatePrefix(value) {
|
|
444
|
+
const datePrefixLength = 11;
|
|
445
|
+
const datePrefix =
|
|
446
|
+
value.length > datePrefixLength &&
|
|
447
|
+
value[4] === '-' &&
|
|
448
|
+
value[7] === '-' &&
|
|
449
|
+
value[10] === '-';
|
|
450
|
+
return datePrefix ? value.slice(datePrefixLength) : value;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function trimTrailingPathPunctuation(value) {
|
|
454
|
+
const trailingPunctuation = '.,;:';
|
|
455
|
+
let end = value.length;
|
|
456
|
+
while (end > 0 && trailingPunctuation.includes(value[end - 1])) {
|
|
457
|
+
end -= 1;
|
|
458
|
+
}
|
|
459
|
+
return value.slice(0, end);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
function stripMarkdownSuffixes(value) {
|
|
463
|
+
let stripped = value.endsWith('.md') ? value.slice(0, -3) : value;
|
|
464
|
+
for (const suffix of ['-design', '-plan', '-tasks', '-decisions']) {
|
|
465
|
+
if (stripped.endsWith(suffix)) {
|
|
466
|
+
stripped = stripped.slice(0, -suffix.length);
|
|
467
|
+
break;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
return stripped;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
function extractSlugFromDesignPath(candidatePath) {
|
|
474
|
+
const parts = trimTrailingPathPunctuation(candidatePath).replaceAll('\\', '/').split('/').filter(Boolean);
|
|
475
|
+
const docsIndex = parts.indexOf('docs');
|
|
476
|
+
if (docsIndex === -1) {
|
|
477
|
+
return '';
|
|
478
|
+
}
|
|
479
|
+
const root = parts[docsIndex + 1];
|
|
480
|
+
|
|
481
|
+
if (root === 'plans') {
|
|
482
|
+
const fileName = parts[docsIndex + 2] || '';
|
|
483
|
+
return stripDatePrefix(stripMarkdownSuffixes(fileName));
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
if (root === 'work') {
|
|
487
|
+
return stripDatePrefix(parts[docsIndex + 2] || '');
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
return '';
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
function isPathCandidateChar(char) {
|
|
494
|
+
return (
|
|
495
|
+
(char >= 'a' && char <= 'z') ||
|
|
496
|
+
(char >= 'A' && char <= 'Z') ||
|
|
497
|
+
(char >= '0' && char <= '9') ||
|
|
498
|
+
char === '/' ||
|
|
499
|
+
char === '\\' ||
|
|
500
|
+
char === '.' ||
|
|
501
|
+
char === '-' ||
|
|
502
|
+
char === '_'
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function extractPathCandidates(text) {
|
|
507
|
+
const candidates = [];
|
|
508
|
+
let index = 0;
|
|
509
|
+
|
|
510
|
+
while (index < text.length) {
|
|
511
|
+
const hasForwardPath = text.startsWith('docs/', index);
|
|
512
|
+
const hasBackwardPath = text.startsWith('docs\\', index);
|
|
513
|
+
|
|
514
|
+
if (!hasForwardPath && !hasBackwardPath) {
|
|
515
|
+
index += 1;
|
|
516
|
+
continue;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
let end = index;
|
|
520
|
+
while (end < text.length && isPathCandidateChar(text[end])) {
|
|
521
|
+
end += 1;
|
|
522
|
+
}
|
|
523
|
+
candidates.push(text.slice(index, end));
|
|
524
|
+
index = end;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
return candidates;
|
|
528
|
+
}
|
|
529
|
+
|
|
411
530
|
function extractDesignSlugs(design) {
|
|
412
531
|
if (typeof design !== 'string' || design.trim() === '') {
|
|
413
532
|
return [];
|
|
414
533
|
}
|
|
415
534
|
|
|
416
535
|
const slugs = new Set();
|
|
417
|
-
const
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
536
|
+
for (const candidate of extractPathCandidates(design)) {
|
|
537
|
+
const slug = extractSlugFromDesignPath(candidate);
|
|
538
|
+
if (slug) {
|
|
539
|
+
slugs.add(slug);
|
|
540
|
+
}
|
|
422
541
|
}
|
|
423
542
|
|
|
424
543
|
return [...slugs];
|
|
@@ -450,7 +569,8 @@ function discoverCurrentIssue(snapshot, context, projectRoot = process.cwd()) {
|
|
|
450
569
|
return hydratedIssues.get(issue.id);
|
|
451
570
|
}
|
|
452
571
|
|
|
453
|
-
const
|
|
572
|
+
const hasSufficientDetails = Boolean(issue.comments) && Boolean(issue.design);
|
|
573
|
+
const details = hasSufficientDetails ? issue : readIssueDetails(issue.id, projectRoot);
|
|
454
574
|
const hydratedIssue = details ? { ...issue, ...details } : issue;
|
|
455
575
|
hydratedIssues.set(issue.id, hydratedIssue);
|
|
456
576
|
return hydratedIssue;
|
|
@@ -578,11 +698,8 @@ function collectCompletedChecks(result) {
|
|
|
578
698
|
function formatAuthoritativeStatus(result) {
|
|
579
699
|
const completedStages = result.workflowState.completedStages.map(stageId => stageId);
|
|
580
700
|
const allowedCommands = result.nextStages.map(stageId => '/' + stageId).join(', ');
|
|
581
|
-
const nextLines =
|
|
701
|
+
const nextLines = formatRunNextLines(result);
|
|
582
702
|
|
|
583
|
-
if (result.nextCommand) {
|
|
584
|
-
nextLines.push(`Next after this: /${result.nextCommand}`);
|
|
585
|
-
}
|
|
586
703
|
if (allowedCommands) {
|
|
587
704
|
nextLines.push(`Allowed after this: ${allowedCommands}`);
|
|
588
705
|
}
|
|
@@ -633,7 +750,12 @@ function formatStatus(result) {
|
|
|
633
750
|
|
|
634
751
|
module.exports = {
|
|
635
752
|
name: 'status',
|
|
636
|
-
description: '
|
|
753
|
+
description: 'One-glance orientation: where you are, what to run next, and your work',
|
|
754
|
+
usage: 'forge status [--full] [--json]',
|
|
755
|
+
flags: {
|
|
756
|
+
'--full': 'Also show blocked, stale, and recently completed issues',
|
|
757
|
+
'--json': 'Emit the machine-readable status envelope',
|
|
758
|
+
},
|
|
637
759
|
handler: async (args, flags, projectRoot) => {
|
|
638
760
|
const inputs = parseStatusInputs(args, flags);
|
|
639
761
|
const isZeroArgStatus = !inputs.issueId && !inputs.workflowState && !inputs.bdComments;
|
|
@@ -647,7 +769,16 @@ module.exports = {
|
|
|
647
769
|
|
|
648
770
|
if (isZeroArgStatus) {
|
|
649
771
|
context = detectRepoContext(effectiveProjectRoot);
|
|
650
|
-
|
|
772
|
+
// Read from the active issue backend (Kernel by default; Beads only when
|
|
773
|
+
// explicitly selected). Previously hard-wired to the retired Beads
|
|
774
|
+
// issues.jsonl, which is empty on a kernel-default repo — so the flagship
|
|
775
|
+
// view showed "Ready: none" despite a populated kernel (bug 40f35797).
|
|
776
|
+
snapshot = await readStatusSnapshot(effectiveProjectRoot, {
|
|
777
|
+
now: inputs.now,
|
|
778
|
+
staleAfterDays: inputs.staleAfterDays,
|
|
779
|
+
issueBackend: inputs.issueBackend,
|
|
780
|
+
env: process.env,
|
|
781
|
+
});
|
|
651
782
|
const discoveredIssue = discoverCurrentIssue(snapshot, context, effectiveProjectRoot);
|
|
652
783
|
if (discoveredIssue) {
|
|
653
784
|
inputs.issueId = discoveredIssue.id;
|
|
@@ -660,23 +791,29 @@ module.exports = {
|
|
|
660
791
|
if (isZeroArgStatus) {
|
|
661
792
|
if (workflowState) {
|
|
662
793
|
const result = buildAuthoritativeStatus(workflowState);
|
|
794
|
+
const output = inputs.json
|
|
795
|
+
? JSON.stringify(buildPersonalStatusJson({ context, snapshot, workflowResult: result }), null, 2)
|
|
796
|
+
: formatZeroArgStatus({ context, snapshot, workflowResult: result, full: inputs.full });
|
|
663
797
|
return {
|
|
664
798
|
success: true,
|
|
665
799
|
context,
|
|
666
800
|
snapshot,
|
|
667
801
|
issueId: inputs.issueId,
|
|
668
|
-
output
|
|
802
|
+
output,
|
|
669
803
|
...result,
|
|
670
804
|
};
|
|
671
805
|
}
|
|
672
806
|
|
|
807
|
+
const output = inputs.json
|
|
808
|
+
? JSON.stringify(buildPersonalStatusJson({ context, snapshot }), null, 2)
|
|
809
|
+
: formatZeroArgStatus({ context, snapshot, full: inputs.full });
|
|
673
810
|
return {
|
|
674
811
|
success: true,
|
|
675
812
|
context,
|
|
676
813
|
snapshot,
|
|
677
814
|
issueId: inputs.issueId,
|
|
678
815
|
missingWorkflowState: true,
|
|
679
|
-
output
|
|
816
|
+
output,
|
|
680
817
|
...(fallbackReason ? { fallbackReason } : {}),
|
|
681
818
|
};
|
|
682
819
|
}
|
package/lib/commands/sync.js
CHANGED
|
@@ -1,73 +1,61 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const {
|
|
4
|
-
|
|
5
|
-
function isRecoverableBeadsSyncError(error) {
|
|
6
|
-
const message = error?.message ?? String(error ?? '');
|
|
7
|
-
return (
|
|
8
|
-
message.includes('failed to open database') ||
|
|
9
|
-
message.includes('database not found') ||
|
|
10
|
-
message.includes('no beads configuration found') ||
|
|
11
|
-
message.includes('remote \'origin\' not found') ||
|
|
12
|
-
message.includes('remote "origin" not found')
|
|
13
|
-
);
|
|
14
|
-
}
|
|
3
|
+
const { createSyncBackend } = require('../sync-backend');
|
|
15
4
|
|
|
16
5
|
/**
|
|
17
6
|
* Forge Sync Command
|
|
18
|
-
* Syncs
|
|
19
|
-
*
|
|
7
|
+
* Syncs Kernel issue state with the configured sync backend.
|
|
8
|
+
*
|
|
9
|
+
* The local kernel is single-machine authority, so the default `local-noop`
|
|
10
|
+
* backend is a graceful no-op that names the model instead of moving data.
|
|
11
|
+
* Selecting `git-jsonl`/`server` (a future swap) is a backend change with zero
|
|
12
|
+
* call-site churn — see docs/work/2026-06-26-sync-authority/plan.md.
|
|
20
13
|
*
|
|
21
14
|
* @module commands/sync
|
|
22
15
|
*/
|
|
23
16
|
module.exports = {
|
|
24
17
|
name: 'sync',
|
|
25
|
-
description: 'Sync
|
|
18
|
+
description: 'Sync Kernel issue state with the configured sync backend (local-noop until a server/remote is configured)',
|
|
26
19
|
usage: 'forge sync',
|
|
27
20
|
flags: {},
|
|
28
21
|
|
|
29
22
|
/**
|
|
30
|
-
*
|
|
23
|
+
* Resolve a SyncBackend (default `local-noop`) and run its one-shot sync.
|
|
31
24
|
* @param {string[]} _args - Positional arguments (unused)
|
|
32
25
|
* @param {object} _flags - CLI flags (unused)
|
|
33
|
-
* @param {string}
|
|
26
|
+
* @param {string} projectRoot - Project root path (used for backend resolution)
|
|
34
27
|
* @param {object} [opts] - Options for dependency injection
|
|
35
|
-
* @param {
|
|
28
|
+
* @param {object} [opts._backend] - Override for the resolved SyncBackend (testing)
|
|
29
|
+
* @param {object} [opts.deps] - Explicit backend selection (precedence over env/config)
|
|
30
|
+
* @param {object} [opts.env] - Environment override (testing)
|
|
36
31
|
* @returns {Promise<{success: boolean, synced: boolean, message?: string, error?: string}>}
|
|
37
32
|
*/
|
|
38
|
-
handler: async (_args, _flags,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
// Step 1: Check if bd binary exists
|
|
33
|
+
handler: async (_args, _flags, projectRoot, opts = {}) => {
|
|
34
|
+
let backend;
|
|
42
35
|
try {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
};
|
|
36
|
+
backend = opts._backend || createSyncBackend({
|
|
37
|
+
projectRoot,
|
|
38
|
+
deps: opts.deps,
|
|
39
|
+
env: opts.env,
|
|
40
|
+
});
|
|
41
|
+
} catch (resolveErr) {
|
|
42
|
+
return { success: false, synced: false, error: resolveErr.message };
|
|
50
43
|
}
|
|
51
44
|
|
|
52
|
-
|
|
45
|
+
let result;
|
|
53
46
|
try {
|
|
54
|
-
|
|
55
|
-
exec('bd', ['dolt', 'push'], { stdio: 'pipe' });
|
|
47
|
+
result = await backend.sync({ ...opts, projectRoot });
|
|
56
48
|
} catch (syncErr) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
success: true,
|
|
60
|
-
synced: false,
|
|
61
|
-
message: 'Beads is installed but not initialized for sync in this worktree — skipping sync',
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
return {
|
|
65
|
-
success: false,
|
|
66
|
-
synced: false,
|
|
67
|
-
error: syncErr.message,
|
|
68
|
-
};
|
|
49
|
+
console.error(`forge sync failed: ${syncErr.message}`);
|
|
50
|
+
return { success: false, synced: false, error: syncErr.message };
|
|
69
51
|
}
|
|
70
|
-
|
|
71
|
-
|
|
52
|
+
// Surface the outcome to the user — otherwise `forge sync` runs silently and
|
|
53
|
+
// a user can't tell whether it synced, no-op'd (local-noop), or failed.
|
|
54
|
+
if (result && result.message) {
|
|
55
|
+
console.log(result.message);
|
|
56
|
+
} else if (result && !result.success && result.error) {
|
|
57
|
+
console.error(`forge sync failed: ${result.error}`);
|
|
58
|
+
}
|
|
59
|
+
return result;
|
|
72
60
|
},
|
|
73
61
|
};
|
package/lib/commands/team.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const { existsSync } = require('node:fs');
|
|
2
2
|
const { execFileSync } = require('node:child_process');
|
|
3
3
|
const path = require('node:path');
|
|
4
|
+
const { getPackageRoot } = require('../package-root');
|
|
4
5
|
|
|
5
6
|
// Resolve bash binary from fixed, known locations only (no PATH search).
|
|
6
7
|
// SonarCloud S4036: PATH must not be searched for OS commands.
|
|
@@ -22,7 +23,9 @@ function _resolveBash() {
|
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
function handleTeam(args) {
|
|
25
|
-
|
|
26
|
+
// Route through the asset root so `forge team` finds the script in BOTH channels:
|
|
27
|
+
// the on-disk package (npm/npx) and a compiled binary (extracted embed dir).
|
|
28
|
+
const scriptPath = path.join(getPackageRoot(), 'scripts', 'forge-team', 'index.sh');
|
|
26
29
|
const bashPath = _resolveBash();
|
|
27
30
|
|
|
28
31
|
try {
|