forge-workflow 0.0.10 → 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 +150 -61
- package/CHANGELOG.md +681 -0
- package/CLAUDE.md +9 -118
- 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 +461 -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 +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/{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 +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 +121 -0
- package/lib/beads-sync-scaffold.js +25 -101
- package/lib/codex-skills.js +51 -1
- package/lib/commands/_issue.js +741 -77
- 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 +17 -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 +0 -1
- 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 +838 -972
- 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 +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 +307 -100
- 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 +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 +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/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 +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/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 +99 -497
- 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 +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 +199 -0
- package/lib/workflow/enforce-stage.js +296 -47
- 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-coordinator.sh +3 -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,247 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* PR-monitor watch loop — the CONSTANT, agent-agnostic push surface. `watchLoop`
|
|
5
|
+
* self-drives a ~60s (jittered) cadence: each tick runs ONE bounded
|
|
6
|
+
* `runMonitorPass` (PR-A: gather → diff → dedup → append → snapshot, all under the
|
|
7
|
+
* cross-process journal lock), then STREAMS every new event as a single NDJSON
|
|
8
|
+
* line to stdout. Any harness (Claude Code background Bash, Codex bg exec, a
|
|
9
|
+
* Cursor per-turn poll, a plain shell) consumes stdout — nothing under `.claude`.
|
|
10
|
+
*
|
|
11
|
+
* Backpressure: `runMonitorPass` only returns events when the snapshot fingerprint
|
|
12
|
+
* moved, so an unchanged tick emits nothing. Terminal: when a tick yields
|
|
13
|
+
* `pr.merged`/`pr.closed` the loop flushes, emits that terminal event LAST, and
|
|
14
|
+
* exits cleanly (stop-on-merge). Flap debounce: a `check.failed` is held one tick
|
|
15
|
+
* and only pushed if the next tick did not recover/green it — the JOURNAL still
|
|
16
|
+
* records everything (authority), so `events --since` replay stays complete.
|
|
17
|
+
*
|
|
18
|
+
* Every external effect is injectable (emit/sleep/rng/now/gather/watcherRunning/
|
|
19
|
+
* writePid/removePid, plus `maxPasses`/`signal`) so tests exercise the loop with a
|
|
20
|
+
* fake clock and fake gh, never touching live GitHub or waiting 60s.
|
|
21
|
+
*
|
|
22
|
+
* @module pr-monitor/watch
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
const { runMonitorPass } = require('./monitor');
|
|
26
|
+
const journal = require('./journal');
|
|
27
|
+
const { EVENT_TYPES: T } = require('./events');
|
|
28
|
+
|
|
29
|
+
const DEFAULT_INTERVAL_MS = 60000;
|
|
30
|
+
const JITTER_RATIO = 0.2;
|
|
31
|
+
const TERMINAL_TYPES = new Set([T.PR_MERGED, T.PR_CLOSED]);
|
|
32
|
+
|
|
33
|
+
// In-process ownership of the watcher slot, keyed by journal dir. The journal
|
|
34
|
+
// PID file serializes claims ACROSS processes, but it cannot make claims within
|
|
35
|
+
// ONE process idempotent: after writePid, `watcherRunning(dir)` returns false
|
|
36
|
+
// because the PID equals process.pid, so a second same-process watchLoop() would
|
|
37
|
+
// also claim, run in parallel, and (on either exit) remove the shared PID while
|
|
38
|
+
// the other is still active. This Set closes that gap for the loop lifetime.
|
|
39
|
+
const ACTIVE_DIRS = new Set();
|
|
40
|
+
|
|
41
|
+
/** Default push sink: one NDJSON line per event to stdout. */
|
|
42
|
+
function defaultEmit(event) {
|
|
43
|
+
process.stdout.write(`${JSON.stringify(event)}\n`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Non-blocking sleep that resolves early when `signal` aborts (Ctrl-C), so a
|
|
48
|
+
* SIGINT never has to wait out a full jittered interval (~72s). The timer and
|
|
49
|
+
* the abort listener are both cleaned up whichever path wins. Overridden in
|
|
50
|
+
* tests by a fake clock.
|
|
51
|
+
*/
|
|
52
|
+
function defaultSleep(ms, signal) {
|
|
53
|
+
return new Promise((resolve) => {
|
|
54
|
+
if (signal?.aborted) { resolve(); return; }
|
|
55
|
+
const finish = () => {
|
|
56
|
+
clearTimeout(timer);
|
|
57
|
+
signal?.removeEventListener?.('abort', finish);
|
|
58
|
+
resolve();
|
|
59
|
+
};
|
|
60
|
+
const timer = setTimeout(finish, ms);
|
|
61
|
+
signal?.addEventListener?.('abort', finish, { once: true });
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** The check name an event refers to (check.failed / check.recovered). */
|
|
66
|
+
function checkName(event) {
|
|
67
|
+
return event.data?.name ?? event.key;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Base interval ± JITTER_RATIO, so many watchers never align their gh calls. */
|
|
71
|
+
function jitter(intervalMs, rng) {
|
|
72
|
+
const spread = intervalMs * JITTER_RATIO;
|
|
73
|
+
return Math.round(intervalMs - spread + rng() * spread * 2);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** True once the caller's abort signal (AbortSignal-like) has fired. */
|
|
77
|
+
function isAborted(signal) {
|
|
78
|
+
return Boolean(signal && signal.aborted);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Atomically claim the watcher slot for this PR. The `watcherRunning` check and
|
|
83
|
+
* the `writePid` write run TOGETHER inside the cross-process journal lock (so two
|
|
84
|
+
* starts in DIFFERENT processes can never both pass), AND the in-process
|
|
85
|
+
* `ACTIVE_DIRS` guard rejects a SECOND concurrent `watchLoop()` in the SAME
|
|
86
|
+
* process (which the PID file alone misses, since our own PID reads as "not
|
|
87
|
+
* running"). Returns true only when the slot was newly claimed; the caller must
|
|
88
|
+
* release with `releaseClaim(dir)` on loop exit. The (possibly injected)
|
|
89
|
+
* `watcherRunning`/`writePid` primitives are honored, so test injection works.
|
|
90
|
+
*/
|
|
91
|
+
function defaultClaim(dir, { watcherRunning, writePid, lockOpts }) {
|
|
92
|
+
return journal.withJournalLock(dir, () => {
|
|
93
|
+
if (ACTIVE_DIRS.has(dir) || watcherRunning(dir)) return false;
|
|
94
|
+
writePid(dir);
|
|
95
|
+
ACTIVE_DIRS.add(dir);
|
|
96
|
+
return true;
|
|
97
|
+
}, lockOpts);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Release the in-process watcher claim for `dir` (idempotent). */
|
|
101
|
+
function releaseClaim(dir) {
|
|
102
|
+
ACTIVE_DIRS.delete(dir);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Split a pass's events into: held-candidate failures (by check name), terminal
|
|
107
|
+
* events (pr.merged/closed), and everything else (emitted immediately).
|
|
108
|
+
*/
|
|
109
|
+
function partition(events) {
|
|
110
|
+
const failures = new Map();
|
|
111
|
+
const terminal = [];
|
|
112
|
+
const others = [];
|
|
113
|
+
for (const e of events) {
|
|
114
|
+
if (e.type === T.CHECK_FAILED) failures.set(checkName(e), e);
|
|
115
|
+
else if (TERMINAL_TYPES.has(e.type)) terminal.push(e);
|
|
116
|
+
else others.push(e);
|
|
117
|
+
}
|
|
118
|
+
return { failures, terminal, others };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Which held failures a pass contradicts: an explicit `checks.green` clears ALL
|
|
123
|
+
* pending failures; a `check.recovered` clears just its own check name.
|
|
124
|
+
*/
|
|
125
|
+
function contradictions(events) {
|
|
126
|
+
let allGreen = false;
|
|
127
|
+
const names = new Set();
|
|
128
|
+
for (const e of events) {
|
|
129
|
+
if (e.type === T.CHECKS_GREEN) allGreen = true;
|
|
130
|
+
else if (e.type === T.CHECK_RECOVERED) names.add(checkName(e));
|
|
131
|
+
}
|
|
132
|
+
return { allGreen, names };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Was a held failure for `name` cleared by this pass? */
|
|
136
|
+
function isContradicted(name, contra) {
|
|
137
|
+
return contra.allGreen || contra.names.has(name);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** Emit the prior tick's held failures that survived (still failing this tick). */
|
|
141
|
+
function confirmHeld(pending, contra, emit) {
|
|
142
|
+
for (const [name, event] of pending) {
|
|
143
|
+
if (!isContradicted(name, contra)) emit(event);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Run ONE watch tick: a bounded monitor pass, then stream its events with the
|
|
149
|
+
* 2-pass flap debounce applied. Mutates `state.pending` (the held failures).
|
|
150
|
+
*
|
|
151
|
+
* @returns {Promise<{ terminal: boolean }>} terminal=true → stop the loop.
|
|
152
|
+
*/
|
|
153
|
+
async function runWatchPass(state, ctx, emit) {
|
|
154
|
+
const { events } = await runMonitorPass({
|
|
155
|
+
dir: ctx.dir, gather: ctx.gather, now: ctx.now, enrich: ctx.enrich, lockOpts: ctx.lockOpts,
|
|
156
|
+
});
|
|
157
|
+
const { failures, terminal, others } = partition(events);
|
|
158
|
+
const contra = contradictions(events);
|
|
159
|
+
const heldNames = new Set(state.pending.keys());
|
|
160
|
+
|
|
161
|
+
confirmHeld(state.pending, contra, emit);
|
|
162
|
+
for (const e of others) {
|
|
163
|
+
// Drop a recovered event that only cancels a failure we held but never pushed.
|
|
164
|
+
if (e.type === T.CHECK_RECOVERED && heldNames.has(checkName(e))) continue;
|
|
165
|
+
emit(e);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (terminal.length) {
|
|
169
|
+
for (const failure of failures.values()) emit(failure);
|
|
170
|
+
for (const t of terminal) emit(t);
|
|
171
|
+
return { terminal: true };
|
|
172
|
+
}
|
|
173
|
+
state.pending = failures;
|
|
174
|
+
return { terminal: false };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Run the constant watch loop over one PR. Long-running by default; self-stops on
|
|
179
|
+
* a terminal event. Returns a summary when the loop ends.
|
|
180
|
+
*
|
|
181
|
+
* @param {object} ctx
|
|
182
|
+
* @param {string} ctx.dir - journal directory (journal.journalDir).
|
|
183
|
+
* @param {() => Promise<object>} ctx.gather - bounded snapshot read.
|
|
184
|
+
* @param {(event: object) => void} [ctx.emit] - push sink (default: stdout NDJSON).
|
|
185
|
+
* @param {(ms: number) => Promise<void>} [ctx.sleep] - cadence sleep (test injection).
|
|
186
|
+
* @param {() => number} [ctx.rng] - jitter source in [0,1) (test injection).
|
|
187
|
+
* @param {() => string} [ctx.now] - timestamp source (test injection).
|
|
188
|
+
* @param {number} [ctx.intervalMs=60000] - base cadence.
|
|
189
|
+
* @param {number} [ctx.maxPasses=Infinity] - bound the loop (tests).
|
|
190
|
+
* @param {{ aborted: boolean }} [ctx.signal] - cooperative interrupt (SIGINT).
|
|
191
|
+
* @param {(records: object[]) => Promise<void>|void} [ctx.enrich] - PR-A enrich hook.
|
|
192
|
+
* @returns {Promise<{ started: boolean, passes: number, stopped: boolean, reason?: string }>}
|
|
193
|
+
*/
|
|
194
|
+
async function watchLoop(ctx) {
|
|
195
|
+
const { dir } = ctx;
|
|
196
|
+
const emit = ctx.emit || defaultEmit;
|
|
197
|
+
const sleep = ctx.sleep || defaultSleep;
|
|
198
|
+
const rng = ctx.rng || Math.random;
|
|
199
|
+
const intervalMs = ctx.intervalMs ?? DEFAULT_INTERVAL_MS;
|
|
200
|
+
const maxPasses = ctx.maxPasses ?? Infinity;
|
|
201
|
+
const watcherRunning = ctx.watcherRunning || journal.watcherRunning;
|
|
202
|
+
const writePid = ctx.writePid || journal.writePid;
|
|
203
|
+
const removePid = ctx.removePid || journal.removePid;
|
|
204
|
+
const claim = ctx.claim || (() => defaultClaim(dir, { watcherRunning, writePid, lockOpts: ctx.lockOpts }));
|
|
205
|
+
|
|
206
|
+
// Atomic idempotent claim: a live OTHER watcher already owns this PR → no-op.
|
|
207
|
+
// The check+write are serialized under the journal lock so concurrent starts
|
|
208
|
+
// cannot both succeed (see defaultClaim).
|
|
209
|
+
const claimed = await claim(dir);
|
|
210
|
+
if (!claimed) {
|
|
211
|
+
return { started: false, passes: 0, stopped: false, reason: 'watcher-already-running' };
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const state = { pending: new Map() };
|
|
215
|
+
let passes = 0;
|
|
216
|
+
let stopped = false;
|
|
217
|
+
try {
|
|
218
|
+
while (passes < maxPasses && !isAborted(ctx.signal)) {
|
|
219
|
+
const result = await runWatchPass(state, ctx, emit);
|
|
220
|
+
passes += 1;
|
|
221
|
+
if (result.terminal) { stopped = true; break; }
|
|
222
|
+
if (passes >= maxPasses || isAborted(ctx.signal)) break;
|
|
223
|
+
await sleep(jitter(intervalMs, rng), ctx.signal);
|
|
224
|
+
}
|
|
225
|
+
} finally {
|
|
226
|
+
// Release BOTH claims: the in-process slot (for a same-process restart) and
|
|
227
|
+
// the cross-process PID file. Ordered so the in-process guard clears first.
|
|
228
|
+
releaseClaim(dir);
|
|
229
|
+
removePid(dir);
|
|
230
|
+
}
|
|
231
|
+
return { started: true, passes, stopped };
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
module.exports = {
|
|
235
|
+
watchLoop,
|
|
236
|
+
runWatchPass,
|
|
237
|
+
defaultSleep,
|
|
238
|
+
defaultClaim,
|
|
239
|
+
releaseClaim,
|
|
240
|
+
jitter,
|
|
241
|
+
partition,
|
|
242
|
+
contradictions,
|
|
243
|
+
isContradicted,
|
|
244
|
+
confirmHeld,
|
|
245
|
+
DEFAULT_INTERVAL_MS,
|
|
246
|
+
TERMINAL_TYPES,
|
|
247
|
+
};
|