forge-workflow 0.0.9 → 0.1.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/rules/{greptile-review-process.md → review-process.md} +56 -41
- package/.claude/scripts/{greptile-resolve.sh → review-resolve.sh} +13 -3
- package/.cursor/rules/permissions-guidance.mdc +2 -2
- package/.forge/hooks/check-tdd.js +3 -0
- package/.forge/hooks/forge-native-hook.js +245 -0
- package/.forge/protected-paths.yaml +157 -0
- package/AGENTS.md +151 -61
- package/CHANGELOG.md +681 -0
- package/CLAUDE.md +9 -106
- package/QUICKSTART.md +171 -0
- package/README.md +271 -363
- package/bin/forge-cmd.js +120 -9
- package/bin/forge-preflight.js +26 -5
- package/bin/forge.js +466 -489
- package/docs/INDEX.md +93 -0
- package/docs/PROJECT_DESIGN.md +685 -0
- package/docs/architecture/index.md +66 -0
- package/docs/architecture/notes/README.md +35 -0
- package/docs/architecture/subsystems/README.md +46 -0
- package/docs/{TOOLCHAIN.md → forge/TOOLCHAIN.md} +56 -47
- package/docs/forge/VALIDATION.md +82 -0
- package/docs/{AGENT_INSTALL_PROMPT.md → guides/AGENT_INSTALL_PROMPT.md} +3 -3
- package/docs/guides/BEADS_GITHUB_SYNC.md +32 -0
- package/docs/{ENHANCED_ONBOARDING.md → guides/ENHANCED_ONBOARDING.md} +16 -12
- package/docs/guides/GREPTILE_SETUP.md +46 -0
- package/docs/guides/MANUAL_REVIEW_GUIDE.md +58 -0
- package/docs/guides/MIGRATION.md +56 -0
- package/docs/guides/SETUP.md +118 -0
- package/docs/guides/SUPPORT.md +185 -0
- package/docs/guides/WORKFLOW_TEMPLATES.md +74 -0
- package/docs/guides/memory-backends.md +183 -0
- package/docs/reference/ADAPTERS.md +128 -0
- package/docs/reference/AGENT_SKILL_PARITY.md +175 -0
- package/docs/reference/COMMANDS.md +205 -0
- package/docs/reference/DECISION_DRIFT_GUARDS.md +97 -0
- package/docs/{EXAMPLES.md → reference/EXAMPLES.md} +7 -5
- package/docs/reference/FORGE_KERNEL_STORAGE_MODEL.md +135 -0
- package/docs/reference/HERMES_INTEGRATION.md +118 -0
- package/docs/reference/INSIGHTS_RECAP.md +63 -0
- package/docs/reference/INSTALL.md +164 -0
- package/docs/reference/KERNEL_TAXONOMY_VALIDATION.md +161 -0
- package/docs/reference/PROTECTED_PATH_MANIFEST.md +25 -0
- package/docs/reference/RELEASE.md +68 -0
- package/docs/reference/RESEARCH_TEMPLATE.md +292 -0
- package/docs/{ROADMAP.md → reference/ROADMAP.md} +12 -9
- package/docs/reference/SKILLS.md +35 -0
- package/docs/reference/STATUS_BOARD.md +80 -0
- package/docs/reference/TEMPLATES.md +106 -0
- package/docs/reference/TOOLCHAIN.md +658 -0
- package/docs/reference/VALIDATION.md +82 -0
- package/docs/reference/agent-permissions.md +169 -0
- package/docs/reference/beads-to-kernel-migration-ux.md +61 -0
- package/docs/reference/control-plane-guarantees.md +125 -0
- package/docs/reference/dependency-chain.md +331 -0
- package/docs/reference/forge-kernel-issue-command-contract.md +161 -0
- package/docs/reference/forge-kernel-schema.md +72 -0
- package/docs/reference/kernel-conflict-evaluators.md +27 -0
- package/docs/reference/patch-md-format.md +77 -0
- package/docs/reference/protected-state-surfaces.md +59 -0
- package/docs/reference/shepherd.md +115 -0
- package/docs/reference/superpowers-analysis.md +320 -0
- package/docs/reference/superpowers-integration-options.md +404 -0
- package/docs/reference/test-environment.md +519 -0
- package/docs/reference/upgrade-safety.md +59 -0
- package/lefthook.yml +18 -0
- package/lib/adapter-cli.js +307 -0
- package/lib/adapters/beads-issue-adapter.js +127 -0
- package/lib/adapters/beads-kernel-compat.js +1042 -0
- package/lib/adapters/greptile-review-adapter.js +141 -0
- package/lib/adapters/kernel-issue-adapter.js +101 -0
- package/lib/adapters/pr-state-adapter.js +484 -0
- package/lib/adoption-profiles.js +126 -0
- package/lib/agents/README.md +2 -6
- package/lib/agents/claude.plugin.json +3 -8
- package/lib/agents/codex.plugin.json +9 -1
- package/lib/agents/cursor.plugin.json +2 -6
- package/lib/agents/hermes.plugin.json +22 -0
- package/lib/agents-config.js +39 -1236
- package/lib/audit-evidence.js +282 -0
- package/lib/beads-setup.js +225 -28
- package/lib/beads-sync-scaffold.js +36 -107
- package/lib/codex-skills.js +51 -1
- package/lib/commands/_issue.js +744 -70
- package/lib/commands/_manifest.js +91 -0
- package/lib/commands/_registry.js +85 -34
- package/lib/commands/_resolve-command-opts.js +261 -0
- package/lib/commands/_serve-security.js +270 -0
- package/lib/commands/adapter.js +12 -0
- package/lib/commands/add.js +118 -0
- package/lib/commands/audit.js +70 -0
- package/lib/commands/blocked.js +5 -0
- package/lib/commands/board.js +64 -0
- package/lib/commands/claim.js +21 -2
- package/lib/commands/claims.js +7 -0
- package/lib/commands/clean.js +485 -75
- package/lib/commands/close.js +2 -2
- package/lib/commands/comment.js +5 -0
- package/lib/commands/control.js +148 -0
- package/lib/commands/create.js +2 -2
- package/lib/commands/dev.js +185 -7
- package/lib/commands/doc-gate.js +336 -0
- package/lib/commands/doctor.js +156 -0
- package/lib/commands/explain.js +15 -0
- package/lib/commands/export.js +237 -0
- package/lib/commands/gate.js +192 -0
- package/lib/commands/hooks.js +242 -0
- package/lib/commands/inbox.js +118 -0
- package/lib/commands/init.js +598 -0
- package/lib/commands/insights.js +79 -0
- package/lib/commands/issue.js +12 -1
- package/lib/commands/issues.js +66 -0
- package/lib/commands/lint.js +5 -0
- package/lib/commands/list.js +2 -2
- package/lib/commands/merge.js +312 -0
- package/lib/commands/migrate.js +523 -0
- package/lib/commands/new.js +12 -0
- package/lib/commands/options.js +241 -0
- package/lib/commands/orient.js +13 -0
- package/lib/commands/orphans.js +5 -0
- package/lib/commands/patch.js +67 -0
- package/lib/commands/plan.js +436 -24
- package/lib/commands/preflight.js +211 -0
- package/lib/commands/prime.js +13 -0
- package/lib/commands/push.js +69 -2
- package/lib/commands/ready.js +2 -2
- package/lib/commands/recall.js +116 -0
- package/lib/commands/recap.js +61 -0
- package/lib/commands/recommend.js +22 -2
- package/lib/commands/release.js +91 -0
- package/lib/commands/remember.js +74 -0
- package/lib/commands/role.js +99 -0
- package/lib/commands/serve.js +581 -0
- package/lib/commands/setup.js +851 -979
- package/lib/commands/shepherd.js +436 -0
- package/lib/commands/ship.js +23 -1
- package/lib/commands/show.js +2 -2
- package/lib/commands/stage.js +192 -0
- package/lib/commands/stale.js +5 -0
- package/lib/commands/status.js +329 -11
- package/lib/commands/sync.js +34 -46
- package/lib/commands/team.js +15 -2
- package/lib/commands/test.js +58 -7
- package/lib/commands/update.js +2 -2
- package/lib/commands/upgrade.js +47 -0
- package/lib/commands/validate.js +56 -25
- package/lib/commands/worktree.js +308 -128
- package/lib/config-writer.js +202 -0
- package/lib/control-plane.js +236 -0
- package/lib/core/runtime-graph.js +946 -0
- package/lib/dep-guard/keyword-ripple.js +184 -0
- package/lib/deprecated-sync-cleanup.js +362 -0
- package/lib/detect-agent.js +2 -28
- package/lib/detect-worktree.js +42 -17
- package/lib/doc-gate/declaration.js +177 -0
- package/lib/doc-gate/detect.js +289 -0
- package/lib/doc-gate/gate.js +375 -0
- package/lib/doc-gate/okf-config.js +128 -0
- package/lib/doc-gate/okf.js +429 -0
- package/lib/docs-command.js +1161 -6
- package/lib/forge-issues.js +697 -0
- package/lib/forge-lock.js +262 -0
- package/lib/gate-events.js +193 -0
- package/lib/global-flags.js +74 -0
- package/lib/greptile-match.js +7 -63
- package/lib/harness-capability-matrix.js +380 -0
- package/lib/hook-global-installer.js +347 -0
- package/lib/hook-renderer.js +451 -0
- package/lib/inbox.js +391 -0
- package/lib/insights.js +397 -0
- package/lib/issue-adapter.js +156 -0
- package/lib/issue-backend.js +145 -0
- package/lib/issue-render.js +220 -0
- package/lib/issue-sync/authority.js +100 -0
- package/lib/issue-sync/github-pull.js +184 -0
- package/lib/issue-sync/import-primitives.js +98 -0
- package/lib/issue-sync/legacy-link-bridge.js +436 -0
- package/lib/issue-sync/link-store.js +292 -0
- package/lib/issue-sync/project-github.js +123 -0
- package/lib/issue-sync/reconcile.js +195 -0
- package/lib/issue-sync/schema.js +126 -0
- package/lib/kernel/backing-issue.js +305 -0
- package/lib/kernel/broker.js +1218 -0
- package/lib/kernel/cli-broker-factory.js +130 -0
- package/lib/kernel/conflict-signal.js +82 -0
- package/lib/kernel/evaluators.js +195 -0
- package/lib/kernel/fs-class.js +495 -0
- package/lib/kernel/issue-command-contract.js +559 -0
- package/lib/kernel/issue-id-resolver.js +186 -0
- package/lib/kernel/lease-enforcer.js +158 -0
- package/lib/kernel/migrations.js +333 -0
- package/lib/kernel/planning-buckets-schema.js +109 -0
- package/lib/kernel/projection-jsonl-writer.js +450 -0
- package/lib/kernel/readiness-model.js +329 -0
- package/lib/kernel/schema.js +356 -0
- package/lib/kernel/sqlite-driver.js +2504 -0
- package/lib/kernel/taxonomy-validator.js +394 -0
- package/lib/lefthook-check.js +8 -4
- package/lib/lefthook-wiring.js +413 -0
- package/lib/mcp-config-renderer.js +288 -0
- package/lib/memory/graphiti-mcp.js +106 -0
- package/lib/memory/router.js +387 -0
- package/lib/memory/typed-api.js +102 -0
- package/lib/memory-digest.js +195 -0
- package/lib/merge-rules.js +395 -0
- package/lib/migrate-dry-run.js +466 -0
- package/lib/orientation.js +863 -0
- package/lib/package-manager-remediation.js +103 -0
- package/lib/package-root.js +381 -0
- package/lib/patch-intent.js +890 -0
- package/lib/plugin-catalog.js +3 -4
- package/lib/plugin-manager.js +0 -5
- package/lib/pr-bundle.js +186 -0
- package/lib/pr-monitor/differ.js +195 -0
- package/lib/pr-monitor/events.js +0 -0
- package/lib/pr-monitor/gather.js +124 -0
- package/lib/pr-monitor/journal.js +299 -0
- package/lib/pr-monitor/monitor.js +146 -0
- package/lib/pr-monitor/render-sticky.js +157 -0
- package/lib/pr-monitor/watch-lifecycle.js +95 -0
- package/lib/pr-monitor/watch.js +247 -0
- package/lib/pr-pull.js +1273 -0
- package/lib/pr-shepherd.js +494 -0
- package/lib/pr-state-validator.js +59 -0
- package/lib/preflight/gates.js +237 -0
- package/lib/preflight/runner.js +116 -0
- package/lib/project-discovery.js +0 -53
- package/lib/project-memory.js +166 -0
- package/lib/protected-path-manifest.js +281 -0
- package/lib/protected-state-surfaces.js +387 -0
- package/lib/release-readiness.js +2089 -0
- package/lib/reset.js +59 -45
- package/lib/review-adapter.js +68 -0
- package/lib/rules-sync.js +260 -0
- package/lib/runtime-health.js +332 -23
- package/lib/safety-config-renderer.js +268 -0
- package/lib/setup-action-log.js +1 -7
- package/lib/setup.js +27 -65
- package/lib/shell-utils.js +76 -6
- package/lib/skills-sync.js +330 -0
- package/lib/smart-status/conflicts.js +205 -0
- package/lib/smart-status/scoring.js +191 -0
- package/lib/status/beads-snapshot.js +145 -0
- package/lib/status/presenter.js +216 -0
- package/lib/status/snapshot.js +186 -0
- package/lib/sync-backend.js +202 -0
- package/lib/untrusted-content.js +52 -0
- package/lib/upgrade-safety.js +199 -0
- package/lib/workflow/enforce-stage.js +298 -47
- package/lib/workflow/stage-transition.js +115 -0
- package/lib/workflow/stages.js +30 -6
- package/lib/workflow/state-manager.js +159 -14
- package/lib/workflow/state.js +23 -1
- package/lib/workflow-profiles.js +17 -5
- package/package.json +46 -36
- package/rules/documentation.md +19 -0
- package/rules/kernel-tracking.md +26 -0
- package/rules/security.md +22 -0
- package/rules/tdd.md +20 -0
- package/rules/workflow.md +27 -0
- package/scripts/auto-backing-issue.js +47 -0
- package/scripts/beads-context.sh +165 -22
- package/scripts/beads-migrate-to-dolt.sh +7 -0
- package/scripts/beads-upgrade-smoke.sh +284 -0
- package/scripts/behavioral-judge.sh +115 -11
- package/scripts/benchmark.js +349 -63
- package/scripts/bootstrap-windows-tools.sh +78 -0
- package/scripts/branch-protection.js +2 -3
- package/scripts/check-agents.js +34 -137
- package/scripts/commitlint.js +3 -1
- package/scripts/conflict-detect.sh +3 -0
- package/scripts/dep-guard-analyze.js +52 -17
- package/scripts/dep-guard-keyword-ripple.js +29 -0
- package/scripts/dep-guard-render-review.js +86 -0
- package/scripts/dep-guard.sh +64 -232
- package/scripts/file-index.sh +3 -0
- package/scripts/forge-team/lib/claim.sh +34 -18
- package/scripts/forge-team/lib/dashboard.sh +61 -86
- package/scripts/forge-team/lib/epic.sh +99 -263
- package/scripts/forge-team/lib/hooks.sh +26 -28
- package/scripts/forge-team/lib/identity.sh +4 -4
- package/scripts/forge-team/lib/sync-github.sh +144 -47
- package/scripts/forge-team/lib/verify.sh +93 -83
- package/scripts/forge-team/lib/workload.sh +41 -65
- package/scripts/forge-team/tests/claim.test.sh +25 -19
- package/scripts/forge-team/tests/dashboard.test.sh +31 -46
- package/scripts/forge-team/tests/epic.test.sh +52 -71
- package/scripts/forge-team/tests/hooks.test.sh +38 -50
- package/scripts/forge-team/tests/identity.test.sh +3 -3
- package/scripts/forge-team/tests/integration.test.sh +44 -66
- package/scripts/forge-team/tests/sync-github.test.sh +183 -79
- package/scripts/forge-team/tests/verify.test.sh +37 -46
- package/scripts/forge-team/tests/workflow-integration.test.sh +4 -4
- package/scripts/forge-team/tests/workload.test.sh +32 -66
- package/scripts/gen-command-manifest.js +153 -0
- package/scripts/gen-embedded-assets.mjs +129 -0
- package/scripts/install.ps1 +139 -0
- package/scripts/install.sh +268 -0
- package/scripts/lib/beads-migrate-to-dolt.mjs +503 -0
- package/scripts/lib/release-asset.mjs +84 -0
- package/scripts/parity-check.mjs +145 -0
- package/scripts/parity-check.test.mjs +58 -0
- package/scripts/pin-agentic-workflow-images.js +112 -0
- package/scripts/pr-coordinator.sh +3 -0
- package/scripts/preflight-sonar.eslint.config.mjs +44 -0
- package/scripts/preflight.sh +108 -0
- package/scripts/protected-state-check.js +104 -0
- package/scripts/smart-status-score.js +31 -0
- package/scripts/smart-status-sessions.js +51 -0
- package/scripts/smart-status.sh +117 -369
- package/scripts/spikes/config-race-bench.js +111 -0
- package/scripts/spikes/harness-capability-matrix.js +13 -0
- package/scripts/spikes/patch-anchor-stability-bench.js +125 -0
- package/scripts/spikes/protected-path-manifest.js +20 -0
- package/scripts/spikes/skill-auto-invoke-parity.js +292 -0
- package/scripts/sync-agent-skills.js +62 -0
- package/scripts/sync-agentic-workflow.js +48 -0
- package/scripts/sync-utils.sh +3 -0
- package/scripts/test-ci-shard.js +251 -0
- package/scripts/test-dashboard.js +188 -52
- package/scripts/test-full-suite.js +186 -0
- package/scripts/test-profile.js +278 -0
- package/scripts/test.js +302 -28
- package/scripts/validate.js +143 -0
- package/scripts/validate.sh +18 -1
- package/skills/claim-safety/SKILL.md +102 -0
- package/skills/claim-safety/evals/evals.json +46 -0
- package/{.github/prompts/dev.prompt.md → skills/dev/SKILL.md} +46 -52
- package/skills/dev/evals/evals.json +50 -0
- package/skills/hermes-forge/SKILL.md +185 -0
- package/skills/hermes-forge/evals/evals.json +46 -0
- package/skills/issue-basics/SKILL.md +111 -0
- package/skills/issue-basics/evals/evals.json +46 -0
- package/skills/kernel/SKILL.md +166 -0
- package/skills/kernel/evals/evals.json +50 -0
- package/skills/memory/SKILL.md +102 -0
- package/skills/parallel-deep-research/SKILL.md +14 -11
- package/skills/parallel-deep-research/evals/evals.json +11 -27
- package/{.github/prompts/plan.prompt.md → skills/plan/SKILL.md} +134 -159
- package/skills/plan/evals/evals.json +42 -0
- package/skills/research/SKILL.md +195 -0
- package/skills/research/evals/evals.json +42 -0
- package/{.github/prompts/review.prompt.md → skills/review/SKILL.md} +98 -62
- package/skills/review/evals/evals.json +42 -0
- package/skills/rollback/SKILL.md +110 -0
- package/skills/rollback/evals/evals.json +46 -0
- package/skills/rollback/references/methods.md +204 -0
- package/{.cursor/commands/rollback.md → skills/rollback/references/workflow-integration.md} +10 -284
- package/skills/shepherd/SKILL.md +66 -0
- package/skills/shepherd/evals/evals.json +42 -0
- package/skills/ship/SKILL.md +251 -0
- package/skills/ship/evals/evals.json +42 -0
- package/skills/smith/SKILL.md +142 -0
- package/skills/smith/evals/evals.json +46 -0
- package/skills/smith/references/autonomy-and-gates.md +94 -0
- package/{.github/prompts/sonarcloud.prompt.md → skills/sonarcloud/SKILL.md} +14 -3
- package/skills/sonarcloud/evals/evals.json +46 -0
- package/skills/sonarcloud-analysis/SKILL.md +18 -13
- package/skills/sonarcloud-analysis/evals/evals.json +11 -15
- package/skills/status/SKILL.md +102 -0
- package/skills/status/evals/evals.json +50 -0
- package/skills/triage-ready/SKILL.md +121 -0
- package/skills/triage-ready/evals/evals.json +42 -0
- package/{.github/prompts/validate.prompt.md → skills/validate/SKILL.md} +52 -29
- package/skills/validate/evals/evals.json +42 -0
- package/skills/verify/SKILL.md +299 -0
- package/skills/verify/evals/evals.json +50 -0
- package/.claude/commands/dev.md +0 -345
- package/.claude/commands/plan.md +0 -566
- package/.claude/commands/premerge.md +0 -186
- package/.claude/commands/research.md +0 -42
- package/.claude/commands/review.md +0 -451
- package/.claude/commands/rollback.md +0 -721
- package/.claude/commands/ship.md +0 -213
- package/.claude/commands/sonarcloud.md +0 -152
- package/.claude/commands/status.md +0 -90
- package/.claude/commands/validate.md +0 -288
- package/.claude/commands/verify.md +0 -269
- package/.claude/rules/workflow.md +0 -121
- package/.cline/workflows/dev.md +0 -342
- package/.cline/workflows/plan.md +0 -563
- package/.cline/workflows/premerge.md +0 -183
- package/.cline/workflows/research.md +0 -39
- package/.cline/workflows/review.md +0 -448
- package/.cline/workflows/rollback.md +0 -718
- package/.cline/workflows/ship.md +0 -210
- package/.cline/workflows/sonarcloud.md +0 -146
- package/.cline/workflows/status.md +0 -87
- package/.cline/workflows/validate.md +0 -285
- package/.cline/workflows/verify.md +0 -266
- package/.codex/config.toml +0 -11
- package/.codex/skills/dev/SKILL.md +0 -345
- package/.codex/skills/plan/SKILL.md +0 -566
- package/.codex/skills/premerge/SKILL.md +0 -186
- package/.codex/skills/research/SKILL.md +0 -42
- package/.codex/skills/review/SKILL.md +0 -451
- package/.codex/skills/rollback/SKILL.md +0 -721
- package/.codex/skills/ship/SKILL.md +0 -213
- package/.codex/skills/sonarcloud/SKILL.md +0 -149
- package/.codex/skills/status/SKILL.md +0 -90
- package/.codex/skills/validate/SKILL.md +0 -288
- package/.codex/skills/verify/SKILL.md +0 -269
- package/.cursor/commands/dev.md +0 -342
- package/.cursor/commands/plan.md +0 -563
- package/.cursor/commands/premerge.md +0 -183
- package/.cursor/commands/research.md +0 -39
- package/.cursor/commands/review.md +0 -448
- package/.cursor/commands/ship.md +0 -210
- package/.cursor/commands/sonarcloud.md +0 -146
- package/.cursor/commands/status.md +0 -87
- package/.cursor/commands/validate.md +0 -285
- package/.cursor/commands/verify.md +0 -266
- package/.cursorrules +0 -149
- package/.github/prompts/premerge.prompt.md +0 -188
- package/.github/prompts/research.prompt.md +0 -44
- package/.github/prompts/rollback.prompt.md +0 -723
- package/.github/prompts/ship.prompt.md +0 -215
- package/.github/prompts/status.prompt.md +0 -92
- package/.github/prompts/verify.prompt.md +0 -271
- package/.github/workflows/beads-to-github.yml +0 -56
- package/.github/workflows/github-to-beads.yml +0 -97
- package/.kilocode/workflows/dev.md +0 -346
- package/.kilocode/workflows/plan.md +0 -567
- package/.kilocode/workflows/premerge.md +0 -187
- package/.kilocode/workflows/research.md +0 -43
- package/.kilocode/workflows/review.md +0 -452
- package/.kilocode/workflows/rollback.md +0 -722
- package/.kilocode/workflows/ship.md +0 -214
- package/.kilocode/workflows/sonarcloud.md +0 -150
- package/.kilocode/workflows/status.md +0 -91
- package/.kilocode/workflows/validate.md +0 -289
- package/.kilocode/workflows/verify.md +0 -270
- package/.opencode/commands/dev.md +0 -345
- package/.opencode/commands/plan.md +0 -566
- package/.opencode/commands/premerge.md +0 -186
- package/.opencode/commands/research.md +0 -42
- package/.opencode/commands/review.md +0 -451
- package/.opencode/commands/rollback.md +0 -721
- package/.opencode/commands/ship.md +0 -213
- package/.opencode/commands/sonarcloud.md +0 -149
- package/.opencode/commands/status.md +0 -90
- package/.opencode/commands/validate.md +0 -288
- package/.opencode/commands/verify.md +0 -269
- package/.roo/commands/dev.md +0 -346
- package/.roo/commands/plan.md +0 -567
- package/.roo/commands/premerge.md +0 -187
- package/.roo/commands/research.md +0 -43
- package/.roo/commands/review.md +0 -452
- package/.roo/commands/rollback.md +0 -722
- package/.roo/commands/ship.md +0 -214
- package/.roo/commands/sonarcloud.md +0 -150
- package/.roo/commands/status.md +0 -91
- package/.roo/commands/validate.md +0 -289
- package/.roo/commands/verify.md +0 -270
- package/docs/BEADS_GITHUB_SYNC.md +0 -255
- package/docs/GREPTILE_SETUP.md +0 -400
- package/docs/MANUAL_REVIEW_GUIDE.md +0 -106
- package/docs/SETUP.md +0 -663
- package/docs/VALIDATION.md +0 -363
- package/lib/agents/cline.plugin.json +0 -29
- package/lib/agents/copilot.plugin.json +0 -24
- package/lib/agents/kilocode.plugin.json +0 -22
- package/lib/agents/opencode.plugin.json +0 -23
- package/lib/agents/roo.plugin.json +0 -30
- package/lib/beads-health-check.js +0 -143
- package/lib/commands/commands-reset.js +0 -147
- package/opencode.json +0 -67
- package/scripts/beads-context.test.js +0 -567
- package/scripts/github-beads-sync/comment.mjs +0 -64
- package/scripts/github-beads-sync/config.mjs +0 -148
- package/scripts/github-beads-sync/github-api.mjs +0 -131
- package/scripts/github-beads-sync/index.mjs +0 -332
- package/scripts/github-beads-sync/label-mapper.mjs +0 -54
- package/scripts/github-beads-sync/mapping.mjs +0 -78
- package/scripts/github-beads-sync/reverse-sync-cli.mjs +0 -31
- package/scripts/github-beads-sync/reverse-sync.mjs +0 -138
- package/scripts/github-beads-sync/run-bd.mjs +0 -161
- package/scripts/github-beads-sync/sanitize.mjs +0 -121
- package/scripts/github-beads-sync.config.json +0 -26
- package/scripts/sync-commands.js +0 -600
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* CLI kernel broker factory.
|
|
5
|
+
*
|
|
6
|
+
* Assembles the kernel issue `deps` the CLI path needs so `createKernelIssueBackend`
|
|
7
|
+
* (lib/forge-issues.js) can construct a working broker:
|
|
8
|
+
*
|
|
9
|
+
* B1 — No real driver on the CLI path. We construct `createBuiltinSQLiteDriver`
|
|
10
|
+
* and inject it as `kernelDriver`, so the broker stops hitting
|
|
11
|
+
* `requireGuardedDriverMethods(undefined)`.
|
|
12
|
+
* B2 — Migrations never run on the runtime path. `ensureKernelMigrated` wraps
|
|
13
|
+
* `broker.initialize()` (pragmas + idempotent migration DDL).
|
|
14
|
+
*
|
|
15
|
+
* The factory does NOT change `createKernelIssueBackend`'s contract — it only
|
|
16
|
+
* supplies the `deps.kernelDriver` / `deps.kernelDatabasePath` it already reads.
|
|
17
|
+
*
|
|
18
|
+
* D19 coordination: the filesystem-doctor (read-only DB-location check) belongs
|
|
19
|
+
* just before the driver opens the file. We expose `resolveKernelDatabasePath`
|
|
20
|
+
* as that seam — D19 hooks the path, this factory does not reimplement it.
|
|
21
|
+
*
|
|
22
|
+
* @module kernel/cli-broker-factory
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
const path = require('node:path');
|
|
26
|
+
const {
|
|
27
|
+
createBuiltinSQLiteDriver,
|
|
28
|
+
selectBuiltinSQLiteRuntime,
|
|
29
|
+
} = require('./sqlite-driver');
|
|
30
|
+
const { resolveGitCommonDir, createLocalBroker } = require('./broker');
|
|
31
|
+
|
|
32
|
+
const KERNEL_DB_FILE = 'kernel.sqlite';
|
|
33
|
+
const KERNEL_DB_SUBDIR = 'forge';
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Resolve the kernel database path. Mirrors `buildLocalBrokerConfig`:
|
|
37
|
+
* explicit `databasePath` wins; otherwise `<gitCommonDir>/forge/kernel.sqlite`,
|
|
38
|
+
* where `gitCommonDir` defaults to the resolved git common dir for `projectRoot`.
|
|
39
|
+
*
|
|
40
|
+
* @param {Object} options
|
|
41
|
+
* @param {string} [options.projectRoot]
|
|
42
|
+
* @param {string} [options.gitCommonDir]
|
|
43
|
+
* @param {string} [options.databasePath]
|
|
44
|
+
* @returns {string}
|
|
45
|
+
*/
|
|
46
|
+
function resolveKernelDatabasePath(options = {}) {
|
|
47
|
+
if (typeof options.databasePath === 'string' && options.databasePath) {
|
|
48
|
+
return options.databasePath;
|
|
49
|
+
}
|
|
50
|
+
const gitCommonDir = options.gitCommonDir
|
|
51
|
+
|| resolveGitCommonDir(options.projectRoot, options);
|
|
52
|
+
return path.join(gitCommonDir, KERNEL_DB_SUBDIR, KERNEL_DB_FILE);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Build the kernel issue deps for the CLI path.
|
|
57
|
+
*
|
|
58
|
+
* @param {Object} options
|
|
59
|
+
* @param {string} [options.projectRoot] - Repo root (used to resolve the git common dir).
|
|
60
|
+
* @param {string} [options.gitCommonDir] - Git common dir (overrides resolution).
|
|
61
|
+
* @param {string} [options.databasePath] - Explicit kernel DB path (overrides default).
|
|
62
|
+
* @param {Object} [options.runtime] - Pre-selected SQLite runtime (tests inject this).
|
|
63
|
+
* @param {Function} [options.requireModule] - Module loader for runtime detection (tests).
|
|
64
|
+
* @returns {{ useKernelBroker: true, kernelDriver: Object, kernelDatabasePath: string, gitCommonDir?: string }}
|
|
65
|
+
* @throws {Error} when no builtin SQLite runtime is available (message names the runtimes).
|
|
66
|
+
*/
|
|
67
|
+
function buildKernelIssueDeps(options = {}) {
|
|
68
|
+
const databasePath = resolveKernelDatabasePath(options);
|
|
69
|
+
const runtime = options.runtime
|
|
70
|
+
|| selectBuiltinSQLiteRuntime({ requireModule: options.requireModule });
|
|
71
|
+
|
|
72
|
+
const kernelDriver = createBuiltinSQLiteDriver({ databasePath, runtime });
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
useKernelBroker: true,
|
|
76
|
+
kernelDriver,
|
|
77
|
+
kernelDatabasePath: databasePath,
|
|
78
|
+
gitCommonDir: options.gitCommonDir,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Run the broker's migrations/pragmas (B2). Idempotent: per-invocation policy —
|
|
84
|
+
* the CLI process is short-lived and `broker.initialize()` swallows
|
|
85
|
+
* duplicate-column DDL, so calling it on every kernel CLI invocation is safe.
|
|
86
|
+
*
|
|
87
|
+
* @param {{ initialize?: Function }} broker
|
|
88
|
+
* @returns {Promise<Object>} the broker.initialize() result.
|
|
89
|
+
* @throws {Error} when the broker cannot be initialized.
|
|
90
|
+
*/
|
|
91
|
+
async function ensureKernelMigrated(broker) {
|
|
92
|
+
if (!broker || typeof broker.initialize !== 'function') {
|
|
93
|
+
throw new Error('Cannot initialize kernel broker: broker is missing initialize().');
|
|
94
|
+
}
|
|
95
|
+
return broker.initialize();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Build the kernel deps AND a migrated broker ready for issue ops. Constructs the
|
|
100
|
+
* driver (B1), builds the broker over it, runs `broker.initialize()` so pragmas +
|
|
101
|
+
* migrations are applied (B2), and returns deps carrying the initialized broker as
|
|
102
|
+
* `kernelBroker` — which `createKernelIssueBackend` (forge-issues.js) uses directly
|
|
103
|
+
* instead of constructing a second broker.
|
|
104
|
+
*
|
|
105
|
+
* @param {Object} options - Same shape as buildKernelIssueDeps.
|
|
106
|
+
* @returns {Promise<{ useKernelBroker: true, kernelBroker: Object, kernelDriver: Object, kernelDatabasePath: string }>}
|
|
107
|
+
*/
|
|
108
|
+
async function buildMigratedKernelIssueDeps(options = {}) {
|
|
109
|
+
const deps = buildKernelIssueDeps(options);
|
|
110
|
+
const broker = createLocalBroker({
|
|
111
|
+
projectRoot: options.projectRoot,
|
|
112
|
+
gitCommonDir: options.gitCommonDir,
|
|
113
|
+
databasePath: deps.kernelDatabasePath,
|
|
114
|
+
driver: deps.kernelDriver,
|
|
115
|
+
});
|
|
116
|
+
await ensureKernelMigrated(broker);
|
|
117
|
+
return {
|
|
118
|
+
useKernelBroker: true,
|
|
119
|
+
kernelBroker: broker,
|
|
120
|
+
kernelDriver: deps.kernelDriver,
|
|
121
|
+
kernelDatabasePath: deps.kernelDatabasePath,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
module.exports = {
|
|
126
|
+
buildKernelIssueDeps,
|
|
127
|
+
buildMigratedKernelIssueDeps,
|
|
128
|
+
ensureKernelMigrated,
|
|
129
|
+
resolveKernelDatabasePath,
|
|
130
|
+
};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// Typed conflict-signal classification (issues 89bf8930 / d4ce47bb).
|
|
4
|
+
//
|
|
5
|
+
// The broker used to classify write conflicts by substring-parsing raw SQLite
|
|
6
|
+
// error text (`/UNIQUE constraint failed/`, `kernel_claims.issue_id`, ...) inline.
|
|
7
|
+
// That coupled the broker to one driver's error dialect and was fragile across
|
|
8
|
+
// SQLite versions/runtimes and future backends (libSQL/Turso/CF).
|
|
9
|
+
//
|
|
10
|
+
// This module is the SINGLE place that owns that driver-boundary knowledge. It
|
|
11
|
+
// maps a raw driver/SQLite error into a stable TYPED code; the broker branches on
|
|
12
|
+
// the code and never parses strings. It mirrors the driver's existing structural
|
|
13
|
+
// signal (`error.kernelRevisionConflict`, set by applyAcceptedIssueMutation's
|
|
14
|
+
// row-level CAS) and generalizes it to every conflict class.
|
|
15
|
+
//
|
|
16
|
+
// When a new backend is added, only classifyConflictSignal changes — the broker's
|
|
17
|
+
// branching stays put. A CI integration test (test/kernel/conflict-signal.test.js)
|
|
18
|
+
// provokes real conflicts against the deployed driver and asserts the mapping,
|
|
19
|
+
// converting the standing "error text" assumption into a build-time contract.
|
|
20
|
+
|
|
21
|
+
const CONFLICT_SIGNAL = Object.freeze({
|
|
22
|
+
// Optimistic-CAS lost update: the row-level revision guard matched 0 rows because
|
|
23
|
+
// the entity's revision moved between the evaluator's out-of-transaction pre-read
|
|
24
|
+
// and the serialized commit. Driver-tagged structurally (never string-derived).
|
|
25
|
+
CAS_STALE: 'CAS_STALE',
|
|
26
|
+
// Duplicate idempotency key — a same-key event replay collided on the events
|
|
27
|
+
// UNIQUE(idempotency_key) index. The broker replays the committed winner.
|
|
28
|
+
UNIQUE_IDEMPOTENCY: 'UNIQUE_IDEMPOTENCY',
|
|
29
|
+
// Two active leases raced on one issue: the partial UNIQUE active-lease index
|
|
30
|
+
// (kernel_claims.issue_id WHERE state='active') rejected the second. The broker
|
|
31
|
+
// quarantines it as a claim_conflict.
|
|
32
|
+
UNIQUE_CLAIM_LEASE: 'UNIQUE_CLAIM_LEASE',
|
|
33
|
+
// Transient lock contention (SQLITE_BUSY / "database is locked"). Part of the
|
|
34
|
+
// typed vocabulary; the broker does not currently branch on it (behavior parity).
|
|
35
|
+
BUSY: 'BUSY',
|
|
36
|
+
// Transient table-level lock (SQLITE_LOCKED). Typed for completeness as above.
|
|
37
|
+
LOCKED: 'LOCKED',
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Map a raw driver/SQLite error → typed conflict code, or null if it is not a
|
|
41
|
+
// recognized conflict. Precedence: an already-typed signal (driver-supplied or a
|
|
42
|
+
// prior classification) wins over any string inspection, so once the driver tags
|
|
43
|
+
// an error at its boundary this never re-parses text.
|
|
44
|
+
function classifyConflictSignal(error) {
|
|
45
|
+
if (!error) return null;
|
|
46
|
+
|
|
47
|
+
// 1. Already-typed, driver-supplied signals take priority over any string parse.
|
|
48
|
+
if (typeof error === 'object') {
|
|
49
|
+
if (error.conflictSignal && isKnownSignal(error.conflictSignal)) {
|
|
50
|
+
return error.conflictSignal;
|
|
51
|
+
}
|
|
52
|
+
// The driver's row-level CAS backstop tags this structurally.
|
|
53
|
+
if (error.kernelRevisionConflict) return CONFLICT_SIGNAL.CAS_STALE;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 2. Fallback for un-tagged native errors: inspect the driver's error surface.
|
|
57
|
+
// This is the ONLY place any error-text/code inspection is permitted.
|
|
58
|
+
const message = String(error && error.message != null ? error.message : error);
|
|
59
|
+
const code = String((error && error.code) || '');
|
|
60
|
+
|
|
61
|
+
if (/UNIQUE constraint failed/i.test(message)) {
|
|
62
|
+
// Match ONLY the active-lease partial index (kernel_claims.issue_id), not the
|
|
63
|
+
// table PK (kernel_claims.id): a duplicate-id violation is a distinct bug.
|
|
64
|
+
if (/kernel_claims\.issue_id/i.test(message)) return CONFLICT_SIGNAL.UNIQUE_CLAIM_LEASE;
|
|
65
|
+
if (/idempotency_key/i.test(message)) return CONFLICT_SIGNAL.UNIQUE_IDEMPOTENCY;
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (/^SQLITE_BUSY/i.test(code) || /database is locked/i.test(message)) return CONFLICT_SIGNAL.BUSY;
|
|
70
|
+
if (/^SQLITE_LOCKED/i.test(code) || /database table is locked/i.test(message)) return CONFLICT_SIGNAL.LOCKED;
|
|
71
|
+
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function isKnownSignal(value) {
|
|
76
|
+
return Object.prototype.hasOwnProperty.call(CONFLICT_SIGNAL, value);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
module.exports = {
|
|
80
|
+
CONFLICT_SIGNAL,
|
|
81
|
+
classifyConflictSignal,
|
|
82
|
+
};
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function stableStringify(value) {
|
|
4
|
+
if (value === undefined) return '{}';
|
|
5
|
+
if (value === null || typeof value !== 'object') {
|
|
6
|
+
return JSON.stringify(value);
|
|
7
|
+
}
|
|
8
|
+
if (Array.isArray(value)) {
|
|
9
|
+
return `[${value.map(stableStringify).join(',')}]`;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return `{${Object.keys(value).sort((left, right) => left.localeCompare(right))
|
|
13
|
+
.map(key => `${JSON.stringify(key)}:${stableStringify(value[key])}`)
|
|
14
|
+
.join(',')}}`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function normalizePayload(event) {
|
|
18
|
+
if (event.payload_json) {
|
|
19
|
+
try {
|
|
20
|
+
return JSON.parse(event.payload_json);
|
|
21
|
+
} catch {
|
|
22
|
+
return event.payload_json;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return event.payload || {};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function payloadJsonFor(event) {
|
|
29
|
+
return stableStringify(normalizePayload(event));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function isForgeProjectionEcho(event, entity = {}) {
|
|
33
|
+
if (event.origin !== 'beads_import') return false;
|
|
34
|
+
|
|
35
|
+
const payload = normalizePayload(event);
|
|
36
|
+
const projectionOrigin = payload.projection_origin;
|
|
37
|
+
if (!projectionOrigin || typeof projectionOrigin !== 'object') return false;
|
|
38
|
+
if (projectionOrigin.source !== 'forge-kernel' || projectionOrigin.target !== 'beads') return false;
|
|
39
|
+
if (projectionOrigin.entity_type !== event.entity_type || projectionOrigin.entity_id !== event.entity_id) return false;
|
|
40
|
+
if (!projectionOrigin.payload_hash || projectionOrigin.payload_hash !== projectionOrigin.imported_payload_hash) return false;
|
|
41
|
+
if (!entity || entity.entity_revision === undefined || entity.entity_revision === null) return false;
|
|
42
|
+
|
|
43
|
+
const actualRevision = Number(entity.entity_revision || 0);
|
|
44
|
+
const projectedRevision = Number(projectionOrigin.entity_revision);
|
|
45
|
+
return Number.isFinite(projectedRevision) && projectedRevision === actualRevision;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function findOriginalIdempotencyEvent(event, priorEvents = []) {
|
|
49
|
+
return priorEvents.find(priorEvent => priorEvent.idempotency_key === event.idempotency_key);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function findEquivalentEvent(event, priorEvents = []) {
|
|
53
|
+
const payloadJson = payloadJsonFor(event);
|
|
54
|
+
return priorEvents.find(priorEvent => (
|
|
55
|
+
priorEvent.idempotency_key !== event.idempotency_key
|
|
56
|
+
&& priorEvent.expected_revision !== undefined
|
|
57
|
+
&& Number(priorEvent.expected_revision) === Number(event.expected_revision || 0)
|
|
58
|
+
&& priorEvent.entity_type === event.entity_type
|
|
59
|
+
&& priorEvent.entity_id === event.entity_id
|
|
60
|
+
&& priorEvent.event_type === event.event_type
|
|
61
|
+
&& payloadJsonFor(priorEvent) === payloadJson
|
|
62
|
+
));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function isBlockingDependency(dependency = {}) {
|
|
66
|
+
return !dependency.dependency_type || dependency.dependency_type === 'blocks';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function dependencyCreatesCycle(payload, dependencies = []) {
|
|
70
|
+
const issueId = payload.issue_id;
|
|
71
|
+
const blocksIssueId = payload.blocks_issue_id;
|
|
72
|
+
if (!issueId || !blocksIssueId) return false;
|
|
73
|
+
if (!isBlockingDependency(payload)) return false;
|
|
74
|
+
|
|
75
|
+
const edges = new Map();
|
|
76
|
+
for (const dependency of [...dependencies, { issue_id: issueId, blocks_issue_id: blocksIssueId }].filter(isBlockingDependency)) {
|
|
77
|
+
if (!edges.has(dependency.issue_id)) edges.set(dependency.issue_id, []);
|
|
78
|
+
edges.get(dependency.issue_id).push(dependency.blocks_issue_id);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const seen = new Set();
|
|
82
|
+
const stack = [blocksIssueId];
|
|
83
|
+
while (stack.length > 0) {
|
|
84
|
+
const candidate = stack.pop();
|
|
85
|
+
if (candidate === issueId) return true;
|
|
86
|
+
if (seen.has(candidate)) continue;
|
|
87
|
+
seen.add(candidate);
|
|
88
|
+
for (const next of edges.get(candidate) || []) {
|
|
89
|
+
stack.push(next);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function buildConflict(event, reason, actualRevision) {
|
|
97
|
+
const payload = normalizePayload(event);
|
|
98
|
+
return {
|
|
99
|
+
entity_type: event.entity_type,
|
|
100
|
+
entity_id: event.entity_id,
|
|
101
|
+
expected_revision: Number(event.expected_revision || 0),
|
|
102
|
+
actual_revision: Number(actualRevision || 0),
|
|
103
|
+
status: 'quarantined',
|
|
104
|
+
reason,
|
|
105
|
+
payload,
|
|
106
|
+
payload_json: stableStringify({
|
|
107
|
+
reason,
|
|
108
|
+
event: {
|
|
109
|
+
entity_type: event.entity_type,
|
|
110
|
+
entity_id: event.entity_id,
|
|
111
|
+
event_type: event.event_type,
|
|
112
|
+
idempotency_key: event.idempotency_key,
|
|
113
|
+
payload,
|
|
114
|
+
},
|
|
115
|
+
}),
|
|
116
|
+
created_at: event.created_at,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function evaluateKernelEvent(input = {}) {
|
|
121
|
+
const event = input.event || {};
|
|
122
|
+
if (!event.entity_type) throw new Error('Kernel event entity_type is required');
|
|
123
|
+
if (!event.entity_id) throw new Error('Kernel event entity_id is required');
|
|
124
|
+
if (!event.event_type) throw new Error('Kernel event event_type is required');
|
|
125
|
+
if (!event.idempotency_key) throw new Error('Kernel event idempotency_key is required');
|
|
126
|
+
|
|
127
|
+
const priorEvents = input.priorEvents || [];
|
|
128
|
+
const originalEvent = findOriginalIdempotencyEvent(event, priorEvents);
|
|
129
|
+
if (originalEvent) {
|
|
130
|
+
return {
|
|
131
|
+
decision: 'duplicate',
|
|
132
|
+
reason: 'idempotency_replay',
|
|
133
|
+
originalEvent,
|
|
134
|
+
projection: false,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const equivalentEvent = findEquivalentEvent(event, priorEvents);
|
|
139
|
+
if (equivalentEvent) {
|
|
140
|
+
return {
|
|
141
|
+
decision: 'dedupe',
|
|
142
|
+
reason: 'equivalent_write',
|
|
143
|
+
originalEvent: equivalentEvent,
|
|
144
|
+
projection: false,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (isForgeProjectionEcho(event, input.entity)) {
|
|
149
|
+
return {
|
|
150
|
+
decision: 'projection_echo',
|
|
151
|
+
reason: 'forge_projection_echo',
|
|
152
|
+
projection: false,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const actualRevision = Number(input.entity?.entity_revision || 0);
|
|
157
|
+
const expectedRevision = Number(event.expected_revision || 0);
|
|
158
|
+
if (expectedRevision !== actualRevision) {
|
|
159
|
+
return {
|
|
160
|
+
decision: 'quarantine',
|
|
161
|
+
reason: 'stale_revision',
|
|
162
|
+
conflict: buildConflict(event, 'stale_revision', actualRevision),
|
|
163
|
+
projection: false,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const payload = normalizePayload(event);
|
|
168
|
+
if (event.event_type === 'dependency.add' && dependencyCreatesCycle(payload, input.dependencies || [])) {
|
|
169
|
+
return {
|
|
170
|
+
decision: 'quarantine',
|
|
171
|
+
reason: 'dependency_cycle',
|
|
172
|
+
conflict: buildConflict(event, 'dependency_cycle', actualRevision),
|
|
173
|
+
projection: false,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return {
|
|
178
|
+
decision: 'accept',
|
|
179
|
+
reason: 'accepted',
|
|
180
|
+
event: {
|
|
181
|
+
...event,
|
|
182
|
+
expected_revision: Number(event.expected_revision || 0),
|
|
183
|
+
payload_json: payloadJsonFor(event),
|
|
184
|
+
},
|
|
185
|
+
projection: true,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
module.exports = {
|
|
190
|
+
buildConflict,
|
|
191
|
+
dependencyCreatesCycle,
|
|
192
|
+
evaluateKernelEvent,
|
|
193
|
+
normalizePayload,
|
|
194
|
+
stableStringify,
|
|
195
|
+
};
|