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,230 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @module grounding/context-events
|
|
5
|
+
*
|
|
6
|
+
* The state primitive behind gate.read_first: "this issue's context was loaded"
|
|
7
|
+
* recorded as a durable kernel EVENT, structurally identical to gate.approved
|
|
8
|
+
* (lib/gate-events.js). `forge recap`/`forge show` append a `context.loaded`
|
|
9
|
+
* event to the issue's stream on a successful render; `forge claim` refuses to
|
|
10
|
+
* proceed until such an event exists for the issue this session/window.
|
|
11
|
+
*
|
|
12
|
+
* Mechanism (mirrors gate-events, deliberately): a PURE APPEND via the driver
|
|
13
|
+
* primitives (`insertKernelEvent` + `listKernelEvents`), NOT the guarded
|
|
14
|
+
* issue-mutation pipeline — context.loaded does not mutate the issue, so it must
|
|
15
|
+
* not participate in the issue-revision CAS. Idempotency is enforced by a
|
|
16
|
+
* window-bucketed key (so a re-read inside the freshness window mints no
|
|
17
|
+
* duplicate, but a re-read in the NEXT window mints a fresh event that clears a
|
|
18
|
+
* re-block) plus the unique idempotency index catching a concurrent race.
|
|
19
|
+
*
|
|
20
|
+
* Config-surface note: whether the gate is enabled lives in the runtime graph +
|
|
21
|
+
* `.forge/config.yaml`; this module only records/reads the events.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
const { resolveOwnedKernel, closeIfOwned } = require('../kernel/owned-kernel');
|
|
25
|
+
const { resolveIssueActor } = require('../forge-issues');
|
|
26
|
+
|
|
27
|
+
const CONTEXT_LOADED_EVENT = 'context.loaded';
|
|
28
|
+
const ISSUE_ENTITY_TYPE = 'issue';
|
|
29
|
+
const CONTEXT_EVENT_ORIGIN = 'cli';
|
|
30
|
+
// Tier-2 agnostic freshness floor: a stale-but-loaded issue re-blocks after this
|
|
31
|
+
// window; one `forge recap` clears it. Overridable via
|
|
32
|
+
// `workflow.gates.gate.read_first.window` at the call site (P2).
|
|
33
|
+
const DEFAULT_WINDOW_MS = 24 * 60 * 60 * 1000;
|
|
34
|
+
|
|
35
|
+
// Kernel lifecycle (resolve + close-what-you-built) is shared with gate-events
|
|
36
|
+
// via lib/kernel/owned-kernel; `resolveOwnedKernel`/`closeIfOwned` are imported.
|
|
37
|
+
|
|
38
|
+
/** Coarse window bucket for a timestamp — the roll-over that makes re-reads fresh. */
|
|
39
|
+
function windowBucket(nowMs, windowMs) {
|
|
40
|
+
return Math.floor(nowMs / windowMs);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Idempotency key for a context.loaded event. Scoped to issue + scope
|
|
45
|
+
* (session id when present, else actor) + window bucket so a re-read inside the
|
|
46
|
+
* window is idempotent, while the next window mints a fresh event.
|
|
47
|
+
*/
|
|
48
|
+
function contextLoadedIdempotencyKey(issueId, scope, bucket) {
|
|
49
|
+
return `${CONTEXT_LOADED_EVENT}:${issueId}:${scope}:${bucket}`;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Shape a stored kernel_events row into the context-event view callers consume. */
|
|
53
|
+
function parseContextEvent(row) {
|
|
54
|
+
let payload;
|
|
55
|
+
try {
|
|
56
|
+
payload = row.payload_json ? JSON.parse(row.payload_json) : {};
|
|
57
|
+
} catch {
|
|
58
|
+
payload = {};
|
|
59
|
+
}
|
|
60
|
+
const view = {
|
|
61
|
+
event_type: row.event_type,
|
|
62
|
+
actor: row.actor,
|
|
63
|
+
created_at: row.created_at,
|
|
64
|
+
};
|
|
65
|
+
if (payload.session !== undefined) view.session = payload.session;
|
|
66
|
+
if (payload.cmd !== undefined) view.cmd = payload.cmd;
|
|
67
|
+
if (payload.budget !== undefined) view.budget = payload.budget;
|
|
68
|
+
return view;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function isIdempotencyRace(error) {
|
|
72
|
+
const message = error && error.message ? String(error.message) : '';
|
|
73
|
+
return /UNIQUE constraint failed/i.test(message) && /idempotency_key/i.test(message);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Record that an issue's context was loaded. Idempotent per issue+scope+window.
|
|
78
|
+
* Validates the issue exists (no orphan events).
|
|
79
|
+
*
|
|
80
|
+
* @param {string} projectRoot
|
|
81
|
+
* @param {Object} params
|
|
82
|
+
* @param {string} params.issueId
|
|
83
|
+
* @param {string} [params.cmd] - the command that loaded the context (recap|show).
|
|
84
|
+
* @param {string} [params.session] - harness session id (Tier-1 scoping) when known.
|
|
85
|
+
* @param {number|string} [params.budget]
|
|
86
|
+
* @param {Object} [params.env] - env source for actor resolution.
|
|
87
|
+
* @param {Object} [params.deps] - injected { kernelBroker, kernelDriver }.
|
|
88
|
+
* @param {string} [params.now] - ISO timestamp (defaults to now).
|
|
89
|
+
* @param {number} [params.windowMs] - freshness window (defaults to 24h).
|
|
90
|
+
* @returns {Promise<{ ok: boolean, duplicate?: boolean, issueMissing?: boolean, event?: Object, actor?: string }>}
|
|
91
|
+
*/
|
|
92
|
+
async function recordContextLoaded(projectRoot, params = {}) {
|
|
93
|
+
const { issueId, cmd, session, budget, env, deps, now, windowMs } = params;
|
|
94
|
+
const actor = resolveIssueActor(env || process.env) || 'forge';
|
|
95
|
+
const kernel = await resolveOwnedKernel(projectRoot, deps);
|
|
96
|
+
const { driver, config } = kernel;
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
const entity = await driver.loadKernelEntity(ISSUE_ENTITY_TYPE, issueId, {}, config);
|
|
100
|
+
if (!entity) {
|
|
101
|
+
return { ok: false, issueMissing: true, actor };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const nowIso = now || new Date().toISOString();
|
|
105
|
+
const win = Number.isFinite(windowMs) ? windowMs : DEFAULT_WINDOW_MS;
|
|
106
|
+
const bucket = windowBucket(Date.parse(nowIso), win);
|
|
107
|
+
const scope = session || actor;
|
|
108
|
+
const idempotencyKey = contextLoadedIdempotencyKey(issueId, scope, bucket);
|
|
109
|
+
|
|
110
|
+
const existing = await driver.loadKernelEventByIdempotencyKey(idempotencyKey, {}, config);
|
|
111
|
+
if (existing) {
|
|
112
|
+
return { ok: true, duplicate: true, event: parseContextEvent(existing), actor };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const payload = { actor };
|
|
116
|
+
if (typeof session === 'string' && session.length > 0) payload.session = session;
|
|
117
|
+
if (typeof cmd === 'string' && cmd.length > 0) payload.cmd = cmd;
|
|
118
|
+
if (budget !== undefined) payload.budget = budget;
|
|
119
|
+
|
|
120
|
+
const event = {
|
|
121
|
+
entity_type: ISSUE_ENTITY_TYPE,
|
|
122
|
+
entity_id: issueId,
|
|
123
|
+
event_type: CONTEXT_LOADED_EVENT,
|
|
124
|
+
idempotency_key: idempotencyKey,
|
|
125
|
+
expected_revision: 0,
|
|
126
|
+
actor,
|
|
127
|
+
origin: CONTEXT_EVENT_ORIGIN,
|
|
128
|
+
payload,
|
|
129
|
+
created_at: nowIso,
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
const inserted = await driver.insertKernelEvent(event, {}, config);
|
|
134
|
+
return { ok: true, duplicate: false, event: parseContextEvent(inserted), actor };
|
|
135
|
+
} catch (error) {
|
|
136
|
+
if (isIdempotencyRace(error)) {
|
|
137
|
+
const winner = await driver.loadKernelEventByIdempotencyKey(idempotencyKey, {}, config);
|
|
138
|
+
return { ok: true, duplicate: true, event: winner ? parseContextEvent(winner) : parseContextEvent(event), actor };
|
|
139
|
+
}
|
|
140
|
+
throw error;
|
|
141
|
+
}
|
|
142
|
+
} finally {
|
|
143
|
+
closeIfOwned(kernel);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* List every context.loaded event on an issue, oldest first.
|
|
149
|
+
*
|
|
150
|
+
* @returns {Promise<Array<{ event_type: string, actor: string, created_at: string, session?: string, cmd?: string }>>}
|
|
151
|
+
*/
|
|
152
|
+
async function listContextLoadedEvents(projectRoot, issueId, options = {}) {
|
|
153
|
+
const kernel = await resolveOwnedKernel(projectRoot, options.deps);
|
|
154
|
+
try {
|
|
155
|
+
const rows = await kernel.driver.listKernelEvents(ISSUE_ENTITY_TYPE, issueId, {}, kernel.config);
|
|
156
|
+
return (rows || [])
|
|
157
|
+
.filter(row => row.event_type === CONTEXT_LOADED_EVENT)
|
|
158
|
+
.map(parseContextEvent);
|
|
159
|
+
} finally {
|
|
160
|
+
closeIfOwned(kernel);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* True iff the issue has a context.loaded event that satisfies scoping:
|
|
166
|
+
* - Tier-1 (session given): an event stamped with the SAME session.
|
|
167
|
+
* - Tier-2 (no session): an event newer than the freshness window.
|
|
168
|
+
*
|
|
169
|
+
* @param {string} projectRoot
|
|
170
|
+
* @param {string} issueId
|
|
171
|
+
* @param {{ session?: string, windowMs?: number, now?: string, deps?: Object }} [options]
|
|
172
|
+
* @returns {Promise<boolean>}
|
|
173
|
+
*/
|
|
174
|
+
async function hasFreshContextLoaded(projectRoot, issueId, options = {}) {
|
|
175
|
+
const { session, windowMs, now, deps } = options;
|
|
176
|
+
const events = await listContextLoadedEvents(projectRoot, issueId, { deps });
|
|
177
|
+
return eventsSatisfyFreshness(events, { session, windowMs, now });
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** Shared freshness predicate over an already-listed event set. */
|
|
181
|
+
function eventsSatisfyFreshness(events, { session, windowMs, now } = {}) {
|
|
182
|
+
if (!events || events.length === 0) return false;
|
|
183
|
+
if (typeof session === 'string' && session.length > 0) {
|
|
184
|
+
return events.some(event => event.session === session);
|
|
185
|
+
}
|
|
186
|
+
const nowMs = now ? Date.parse(now) : Date.now();
|
|
187
|
+
const win = Number.isFinite(windowMs) ? windowMs : DEFAULT_WINDOW_MS;
|
|
188
|
+
return events.some(event => {
|
|
189
|
+
const ts = Date.parse(event.created_at);
|
|
190
|
+
return Number.isFinite(ts) && (nowMs - ts) <= win;
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* The gate.read_first verdict for an issue, resolving the kernel ONCE:
|
|
196
|
+
* - 'missing': the issue does not exist in the consulted kernel. The gate is
|
|
197
|
+
* INERT — grounding a phantom issue is meaningless and the real claim will
|
|
198
|
+
* fail on its own; this is also what keeps unit doubles (fake runner, no real
|
|
199
|
+
* store) from being false-blocked. No bypass for a REAL issue: a claim on a
|
|
200
|
+
* non-existent issue fails regardless.
|
|
201
|
+
* - 'loaded': a context.loaded event satisfies session/window scoping -> allow.
|
|
202
|
+
* - 'unread': the issue exists but has no fresh context.loaded event -> BLOCK.
|
|
203
|
+
*
|
|
204
|
+
* @returns {Promise<'missing'|'loaded'|'unread'>}
|
|
205
|
+
*/
|
|
206
|
+
async function readFirstVerdict(projectRoot, issueId, options = {}) {
|
|
207
|
+
const { session, windowMs, now, deps } = options;
|
|
208
|
+
const kernel = await resolveOwnedKernel(projectRoot, deps);
|
|
209
|
+
const { driver, config } = kernel;
|
|
210
|
+
try {
|
|
211
|
+
const entity = await driver.loadKernelEntity(ISSUE_ENTITY_TYPE, issueId, {}, config);
|
|
212
|
+
if (!entity) return 'missing';
|
|
213
|
+
const rows = await driver.listKernelEvents(ISSUE_ENTITY_TYPE, issueId, {}, config);
|
|
214
|
+
const events = (rows || []).filter(row => row.event_type === CONTEXT_LOADED_EVENT).map(parseContextEvent);
|
|
215
|
+
return eventsSatisfyFreshness(events, { session, windowMs, now }) ? 'loaded' : 'unread';
|
|
216
|
+
} finally {
|
|
217
|
+
closeIfOwned(kernel);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
module.exports = {
|
|
222
|
+
CONTEXT_LOADED_EVENT,
|
|
223
|
+
DEFAULT_WINDOW_MS,
|
|
224
|
+
contextLoadedIdempotencyKey,
|
|
225
|
+
parseContextEvent,
|
|
226
|
+
recordContextLoaded,
|
|
227
|
+
listContextLoadedEvents,
|
|
228
|
+
hasFreshContextLoaded,
|
|
229
|
+
readFirstVerdict,
|
|
230
|
+
};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @module grounding/read-first
|
|
5
|
+
*
|
|
6
|
+
* gate.read_first — the first gate that DENIES (fd4c03b3's first real payment):
|
|
7
|
+
* acting on an issue requires having read it. Consulted at the `forge claim`
|
|
8
|
+
* chokepoint (P1) exactly like gate.issue_verify is consulted at the _issue.js
|
|
9
|
+
* boundary (isIssueVerifyEnabled). Fail-closed: no context.loaded event for the
|
|
10
|
+
* issue this session/window -> a block result whose remedy IS the load action
|
|
11
|
+
* (`forge recap <id>`), so the cheapest path through the gate is the correct
|
|
12
|
+
* behavior. Disabling rail.grounding (master) or gate.read_first allows the
|
|
13
|
+
* action (logged), same toggle surface as rail.kernel_tracking.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const { getResolvedRuntimeGraph } = require('../core/runtime-graph');
|
|
17
|
+
const { readFirstVerdict } = require('./context-events');
|
|
18
|
+
|
|
19
|
+
const GROUNDING_RAIL_ID = 'rail.grounding';
|
|
20
|
+
const READ_FIRST_GATE_ID = 'gate.read_first';
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The block message. Contract: exit != 0, remedy is one copy-pastable command,
|
|
24
|
+
* and running that command both satisfies the gate AND injects the context.
|
|
25
|
+
*/
|
|
26
|
+
function buildReadFirstBlockMessage(issueId) {
|
|
27
|
+
return [
|
|
28
|
+
`✗ ${READ_FIRST_GATE_ID}: issue ${issueId} has not been read this session.`,
|
|
29
|
+
` Run: forge recap ${issueId} first`,
|
|
30
|
+
` Then retry. (Override: forge gate disable ${READ_FIRST_GATE_ID} — logged.)`,
|
|
31
|
+
].join('\n');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Resolve whether grounding + read_first are BOTH enabled. Mirrors
|
|
36
|
+
* isIssueVerifyEnabled: an injected opts.resolveRuntimeGraph wins (tests); an
|
|
37
|
+
* unresolvable config (lint errors) yields `unknown` so the caller can fail-open
|
|
38
|
+
* on a broken config rather than bricking claim.
|
|
39
|
+
*
|
|
40
|
+
* @returns {{ enabled: boolean, disabledPrimitive?: string, unknown?: boolean }}
|
|
41
|
+
*/
|
|
42
|
+
function resolveReadFirstEnabled(projectRoot, opts = {}) {
|
|
43
|
+
const resolveGraph = opts.resolveRuntimeGraph || getResolvedRuntimeGraph;
|
|
44
|
+
let graph;
|
|
45
|
+
try {
|
|
46
|
+
graph = resolveGraph({ projectRoot });
|
|
47
|
+
} catch {
|
|
48
|
+
return { enabled: false, unknown: true };
|
|
49
|
+
}
|
|
50
|
+
const rail = (graph.rails || []).find(candidate => candidate.id === GROUNDING_RAIL_ID);
|
|
51
|
+
const gate = (graph.gates || []).find(candidate => candidate.id === READ_FIRST_GATE_ID);
|
|
52
|
+
const railOn = rail ? rail.enabled !== false : true;
|
|
53
|
+
const gateOn = gate ? gate.enabled !== false : true;
|
|
54
|
+
if (!railOn) return { enabled: false, disabledPrimitive: GROUNDING_RAIL_ID };
|
|
55
|
+
if (!gateOn) return { enabled: false, disabledPrimitive: READ_FIRST_GATE_ID };
|
|
56
|
+
return { enabled: true };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Consult gate.read_first for an issue. Returns `null` when the action is
|
|
61
|
+
* allowed (gate off, or a fresh context.loaded event exists), or a block result
|
|
62
|
+
* `{ success:false, error, exitCode }` when the issue has not been read.
|
|
63
|
+
*
|
|
64
|
+
* @param {string} projectRoot
|
|
65
|
+
* @param {string} issueId
|
|
66
|
+
* @param {Object} [opts] - { resolveRuntimeGraph, kernelBroker, kernelDriver, session, windowMs, now }
|
|
67
|
+
* @returns {Promise<null | { success: false, error: string, exitCode: number }>}
|
|
68
|
+
*/
|
|
69
|
+
async function checkReadFirst(projectRoot, issueId, opts = {}) {
|
|
70
|
+
const state = resolveReadFirstEnabled(projectRoot, opts);
|
|
71
|
+
if (!state.enabled) {
|
|
72
|
+
// Disabled (or unresolvable config) -> allow. Log the deliberate skip.
|
|
73
|
+
if (state.disabledPrimitive) {
|
|
74
|
+
console.error(`forge: ${state.disabledPrimitive} disabled — claim on ${issueId} allowed without grounding check.`);
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const deps = (opts.kernelBroker && opts.kernelDriver)
|
|
80
|
+
? { kernelBroker: opts.kernelBroker, kernelDriver: opts.kernelDriver }
|
|
81
|
+
: undefined;
|
|
82
|
+
|
|
83
|
+
let verdict;
|
|
84
|
+
try {
|
|
85
|
+
verdict = await readFirstVerdict(projectRoot, issueId, {
|
|
86
|
+
session: opts.session,
|
|
87
|
+
windowMs: opts.windowMs,
|
|
88
|
+
now: opts.now,
|
|
89
|
+
deps,
|
|
90
|
+
});
|
|
91
|
+
} catch {
|
|
92
|
+
// Kernel unavailable (broken env) -> fail-open, like issue_verify on a
|
|
93
|
+
// config error. In production the project kernel resolves; the enforced
|
|
94
|
+
// path is the normal one.
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// 'missing' -> the issue is not in the consulted kernel; the gate is inert (a
|
|
99
|
+
// real claim on a non-existent issue fails on its own — no grounding bypass).
|
|
100
|
+
// 'loaded' -> a fresh context.loaded event exists. Both allow.
|
|
101
|
+
if (verdict !== 'unread') return null;
|
|
102
|
+
|
|
103
|
+
return { success: false, error: buildReadFirstBlockMessage(issueId), exitCode: 6 };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
module.exports = {
|
|
107
|
+
GROUNDING_RAIL_ID,
|
|
108
|
+
READ_FIRST_GATE_ID,
|
|
109
|
+
buildReadFirstBlockMessage,
|
|
110
|
+
resolveReadFirstEnabled,
|
|
111
|
+
checkReadFirst,
|
|
112
|
+
};
|