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,93 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* pr-auto-actions — the pr-monitor workflow's bridge from the `--pull --json`
|
|
6
|
+
* verdict payload to Tier-2 auto-action DECISIONS. Reads the payload file the
|
|
7
|
+
* monitor already wrote (default `pull.json`), asks lib/pr-monitor/auto-actions
|
|
8
|
+
* (the single, unit-tested decision core) what is safe to do, and emits the
|
|
9
|
+
* flags to `$GITHUB_OUTPUT` (or stdout locally) for the workflow's action steps.
|
|
10
|
+
*
|
|
11
|
+
* This script performs NO GitHub writes and takes NO action — it only decides.
|
|
12
|
+
* The workflow owns the visible `gh` calls and the per-head-SHA idempotency
|
|
13
|
+
* markers. Fails CLOSED: an unreadable/malformed payload or any thrown error
|
|
14
|
+
* yields `update_branch=false` / `rerun=false`.
|
|
15
|
+
*
|
|
16
|
+
* Usage: node scripts/pr-auto-actions.js [pull.json] [isFork]
|
|
17
|
+
* isFork: "true" when the PR head is a cross-repository fork (skips update).
|
|
18
|
+
*
|
|
19
|
+
* @module scripts/pr-auto-actions
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const fs = require('node:fs');
|
|
23
|
+
|
|
24
|
+
const { decideAutoActions } = require('../lib/pr-monitor/auto-actions');
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Append `key=value` lines to `$GITHUB_OUTPUT` when set, else print them. Values
|
|
28
|
+
* are single-line (booleans / csv / short reasons) so no multiline escaping is
|
|
29
|
+
* needed; newlines are stripped defensively.
|
|
30
|
+
*
|
|
31
|
+
* @param {Record<string,string>} outputs
|
|
32
|
+
*/
|
|
33
|
+
function emitOutputs(outputs) {
|
|
34
|
+
const target = process.env.GITHUB_OUTPUT;
|
|
35
|
+
const text = Object.entries(outputs)
|
|
36
|
+
.map(([k, val]) => `${k}=${String(val).replace(/[\r\n]+/g, ' ')}`)
|
|
37
|
+
.join('\n') + '\n';
|
|
38
|
+
if (target) fs.appendFileSync(target, text);
|
|
39
|
+
else process.stdout.write(text);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Read + parse the payload file, returning null (fail-closed) on any error. */
|
|
43
|
+
function readPayload(path) {
|
|
44
|
+
try {
|
|
45
|
+
return JSON.parse(fs.readFileSync(path, 'utf8'));
|
|
46
|
+
} catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function main(argv) {
|
|
52
|
+
const path = argv[2] || 'pull.json';
|
|
53
|
+
const isFork = String(argv[3] || '').toLowerCase() === 'true';
|
|
54
|
+
|
|
55
|
+
const payload = readPayload(path);
|
|
56
|
+
if (!payload) {
|
|
57
|
+
// Fail closed: no readable verdict payload → take no action.
|
|
58
|
+
emitOutputs({
|
|
59
|
+
update_branch: 'false', update_reason: `no readable payload at ${path}`,
|
|
60
|
+
rerun: 'false', rerun_run_ids: '', rerun_reason: `no readable payload at ${path}`,
|
|
61
|
+
});
|
|
62
|
+
console.log(`auto-actions: no readable payload at ${path} — no action (fail closed)`);
|
|
63
|
+
return 0;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const { updateBranch, rerunFlaky } = decideAutoActions(payload, { isFork });
|
|
67
|
+
emitOutputs({
|
|
68
|
+
update_branch: updateBranch.should ? 'true' : 'false',
|
|
69
|
+
update_reason: updateBranch.reason,
|
|
70
|
+
rerun: rerunFlaky.should ? 'true' : 'false',
|
|
71
|
+
rerun_run_ids: (rerunFlaky.runIds || []).join(','),
|
|
72
|
+
rerun_reason: rerunFlaky.reason,
|
|
73
|
+
});
|
|
74
|
+
console.log(`auto-actions: update_branch=${updateBranch.should} (${updateBranch.reason})`);
|
|
75
|
+
console.log(`auto-actions: rerun=${rerunFlaky.should} (${rerunFlaky.reason})`);
|
|
76
|
+
return 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (require.main === module) {
|
|
80
|
+
try {
|
|
81
|
+
process.exit(main(process.argv));
|
|
82
|
+
} catch (err) {
|
|
83
|
+
// Absolute fail-closed backstop: never let this script red-X the monitor.
|
|
84
|
+
emitOutputs({
|
|
85
|
+
update_branch: 'false', update_reason: `error: ${(err && err.message) || err}`,
|
|
86
|
+
rerun: 'false', rerun_run_ids: '', rerun_reason: `error: ${(err && err.message) || err}`,
|
|
87
|
+
});
|
|
88
|
+
console.log(`auto-actions: error — no action (fail closed): ${(err && err.message) || err}`);
|
|
89
|
+
process.exit(0);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
module.exports = { emitOutputs, readPayload, main };
|
|
@@ -15,6 +15,9 @@
|
|
|
15
15
|
set -euo pipefail
|
|
16
16
|
|
|
17
17
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
18
|
+
if [[ -f "$SCRIPT_DIR/bootstrap-windows-tools.sh" ]]; then
|
|
19
|
+
source "$SCRIPT_DIR/bootstrap-windows-tools.sh"
|
|
20
|
+
fi
|
|
18
21
|
source "$SCRIPT_DIR/lib/sanitize.sh" || { echo "FATAL: failed to source sanitize.sh" >&2; exit 2; }
|
|
19
22
|
|
|
20
23
|
# Source these but don't fail if missing (tests may not have them)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* pr-verdict label emitter — maps a canonical merge verdict (from
|
|
6
|
+
* `forge shepherd <pr> --pull --json`, lib/pr-pull.js) to its single
|
|
7
|
+
* `pr-verdict:*` label and emits `label` + `all_labels` to `$GITHUB_OUTPUT`
|
|
8
|
+
* (or stdout locally) for the pr-monitor workflow's reconcile step.
|
|
9
|
+
*
|
|
10
|
+
* SINGLE SOURCE: the verdict value and the label vocabulary both come from
|
|
11
|
+
* lib/pr-pull.js — this script computes NO verdict of its own, so the label can
|
|
12
|
+
* never disagree with `--pull`. Fails closed to `unknown` on empty input.
|
|
13
|
+
* Performs NO GitHub writes (the workflow owns the visible `gh` calls).
|
|
14
|
+
*
|
|
15
|
+
* Usage: node scripts/pr-verdict-label.js <VERDICT>
|
|
16
|
+
*
|
|
17
|
+
* @module scripts/pr-verdict-label
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const fs = require('node:fs');
|
|
21
|
+
|
|
22
|
+
const { verdictLabel, VERDICT_LABELS } = require('../lib/pr-pull');
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Append `key=value` lines to `$GITHUB_OUTPUT` when set, else print them.
|
|
26
|
+
*
|
|
27
|
+
* @param {Record<string,string>} outputs
|
|
28
|
+
*/
|
|
29
|
+
function emitOutputs(outputs) {
|
|
30
|
+
const target = process.env.GITHUB_OUTPUT;
|
|
31
|
+
const text = Object.entries(outputs).map(([k, val]) => `${k}=${val}`).join('\n') + '\n';
|
|
32
|
+
if (target) fs.appendFileSync(target, text);
|
|
33
|
+
else process.stdout.write(text);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function main(argv) {
|
|
37
|
+
// Fail closed: a missing/empty verdict arg maps to the `unknown` label rather
|
|
38
|
+
// than erroring — the workflow must still land a label on every pass.
|
|
39
|
+
const verdict = argv[2] || 'UNKNOWN';
|
|
40
|
+
const label = verdictLabel(verdict);
|
|
41
|
+
emitOutputs({ label, all_labels: VERDICT_LABELS.join(',') });
|
|
42
|
+
console.log(`pr-verdict label: ${label} (verdict ${verdict})`);
|
|
43
|
+
return 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (require.main === module) {
|
|
47
|
+
process.exit(main(process.argv));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = { emitOutputs, main };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Isolated ESLint flat config for `forge preflight`'s SonarCloud-parity gate.
|
|
2
|
+
//
|
|
3
|
+
// Run ONLY via `eslint --no-config-lookup --config scripts/preflight-sonar.eslint.config.mjs`
|
|
4
|
+
// on changed files, so these Sonar rules never merge with the repo's main
|
|
5
|
+
// eslint.config.js. The point is deterministic parity with the SonarCloud
|
|
6
|
+
// quality gate WITHOUT the full (slow) Sonar scanner, on the change blast radius.
|
|
7
|
+
//
|
|
8
|
+
// cognitive-complexity is pinned to 15 — the same threshold SonarCloud's default
|
|
9
|
+
// "Cognitive Complexity" (S3776) gate uses, and the most common gate failure.
|
|
10
|
+
//
|
|
11
|
+
// Rule name ↔ Sonar rule ID (eslint-plugin-sonarjs v4):
|
|
12
|
+
// sonarjs/cognitive-complexity S3776 (pinned to 15)
|
|
13
|
+
// sonarjs/void-use S3735 (void should not be used)
|
|
14
|
+
// sonarjs/regex-complexity S5843 (regex too complex)
|
|
15
|
+
//
|
|
16
|
+
// prefer-optional-chain (S6582) is intentionally omitted: sonarjs exposes it
|
|
17
|
+
// only through the TypeScript type-checker path, which this fast JS-only gate
|
|
18
|
+
// does not wire (it would require @typescript-eslint/parser + a project graph
|
|
19
|
+
// and defeats the speed goal). CI's full Sonar scan still enforces it.
|
|
20
|
+
import sonarjs from 'eslint-plugin-sonarjs';
|
|
21
|
+
|
|
22
|
+
const sonarRules = {
|
|
23
|
+
'sonarjs/cognitive-complexity': ['error', 15],
|
|
24
|
+
'sonarjs/void-use': 'error',
|
|
25
|
+
'sonarjs/regex-complexity': 'error',
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export default [
|
|
29
|
+
{
|
|
30
|
+
ignores: ['node_modules/', 'coverage/', 'dist/', 'build/', '**/*.min.js'],
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
files: ['**/*.mjs'],
|
|
34
|
+
languageOptions: { ecmaVersion: 2023, sourceType: 'module' },
|
|
35
|
+
plugins: { sonarjs },
|
|
36
|
+
rules: sonarRules,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
files: ['**/*.js', '**/*.cjs'],
|
|
40
|
+
languageOptions: { ecmaVersion: 2023, sourceType: 'commonjs' },
|
|
41
|
+
plugins: { sonarjs },
|
|
42
|
+
rules: sonarRules,
|
|
43
|
+
},
|
|
44
|
+
];
|
package/scripts/preflight.sh
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
set -u
|
|
3
3
|
|
|
4
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
5
|
+
if [ -f "$SCRIPT_DIR/bootstrap-windows-tools.sh" ]; then
|
|
6
|
+
source "$SCRIPT_DIR/bootstrap-windows-tools.sh"
|
|
7
|
+
fi
|
|
8
|
+
|
|
9
|
+
FORGE_CLI="$SCRIPT_DIR/../bin/forge.js"
|
|
10
|
+
|
|
4
11
|
exit_code=0
|
|
5
|
-
have_bd=0
|
|
6
12
|
have_gh=0
|
|
7
13
|
|
|
8
14
|
ok() {
|
|
@@ -21,62 +27,6 @@ action() {
|
|
|
21
27
|
exit_code=2
|
|
22
28
|
}
|
|
23
29
|
|
|
24
|
-
snapshot_hooks_dir() {
|
|
25
|
-
hooks_dir="$1"
|
|
26
|
-
hooks_snapshot_dir="$(mktemp -d 2>/dev/null || mktemp -d -t forge-preflight-hooks)"
|
|
27
|
-
|
|
28
|
-
if [ -d "$hooks_dir" ]; then
|
|
29
|
-
cp -pR "$hooks_dir"/. "$hooks_snapshot_dir"/
|
|
30
|
-
fi
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
restore_hooks_dir() {
|
|
34
|
-
hooks_dir="$1"
|
|
35
|
-
mkdir -p "$hooks_dir"
|
|
36
|
-
|
|
37
|
-
find "$hooks_dir" -mindepth 1 -maxdepth 1 -exec rm -rf {} +
|
|
38
|
-
|
|
39
|
-
if [ -d "$hooks_snapshot_dir" ]; then
|
|
40
|
-
cp -pR "$hooks_snapshot_dir"/. "$hooks_dir"/
|
|
41
|
-
rm -rf "$hooks_snapshot_dir"
|
|
42
|
-
fi
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
write_beads_config() {
|
|
46
|
-
mkdir -p .beads
|
|
47
|
-
{
|
|
48
|
-
printf '%s\n' 'issue-prefix: forge'
|
|
49
|
-
printf '\n'
|
|
50
|
-
printf '%s\n' 'database:'
|
|
51
|
-
printf '%s\n' ' backend: dolt'
|
|
52
|
-
printf '\n'
|
|
53
|
-
} > .beads/config.yaml
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
write_beads_gitignore() {
|
|
57
|
-
mkdir -p .beads
|
|
58
|
-
{
|
|
59
|
-
printf '%s\n' '# Dolt database files (binary, not suitable for git)'
|
|
60
|
-
printf '%s\n' 'dolt/'
|
|
61
|
-
printf '%s\n' '*.db'
|
|
62
|
-
printf '%s\n' '*.lock'
|
|
63
|
-
printf '\n'
|
|
64
|
-
} > .beads/.gitignore
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
safe_bd_init() {
|
|
68
|
-
hooks_dir="$(git rev-parse --git-path hooks 2>/dev/null || printf '.git/hooks')"
|
|
69
|
-
write_beads_config
|
|
70
|
-
write_beads_gitignore
|
|
71
|
-
snapshot_hooks_dir "$hooks_dir"
|
|
72
|
-
|
|
73
|
-
bd init --database forge --prefix forge >/dev/null 2>&1
|
|
74
|
-
init_status=$?
|
|
75
|
-
|
|
76
|
-
restore_hooks_dir "$hooks_dir"
|
|
77
|
-
return "$init_status"
|
|
78
|
-
}
|
|
79
|
-
|
|
80
30
|
is_windows_shell() {
|
|
81
31
|
case "$(uname -s 2>/dev/null || printf unknown)" in
|
|
82
32
|
MINGW*|MSYS*|CYGWIN*)
|
|
@@ -107,10 +57,7 @@ check_tool() {
|
|
|
107
57
|
}
|
|
108
58
|
|
|
109
59
|
check_tools() {
|
|
110
|
-
|
|
111
|
-
have_bd=1
|
|
112
|
-
fi
|
|
113
|
-
|
|
60
|
+
check_tool "node" "install Node.js (https://nodejs.org)" || true
|
|
114
61
|
check_tool "jq" "winget install jqlang.jq" || true
|
|
115
62
|
|
|
116
63
|
if check_tool "gh" "winget install GitHub.cli"; then
|
|
@@ -131,50 +78,30 @@ check_github_auth() {
|
|
|
131
78
|
action "github-auth" "not logged in; run: gh auth login"
|
|
132
79
|
}
|
|
133
80
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if
|
|
141
|
-
ok "
|
|
142
|
-
init_ok=1
|
|
81
|
+
# Validate the Forge Kernel issue store. The kernel DB is a single-machine
|
|
82
|
+
# SQLite store in the git common dir; any kernel issue command auto-migrates it
|
|
83
|
+
# via broker.initialize(), so the ensure step is just a kernel read. `forge
|
|
84
|
+
# doctor` then reports the filesystem class of that DB path (D19) — it only
|
|
85
|
+
# reports, it does not init, which is why the ensure step runs first.
|
|
86
|
+
check_kernel() {
|
|
87
|
+
if node "$FORGE_CLI" issue list --json >/dev/null 2>&1; then
|
|
88
|
+
ok "kernel-init" "Kernel issue store is readable"
|
|
143
89
|
else
|
|
144
|
-
|
|
145
|
-
fixed "beads-init" "ran hook-preserving bd init --database forge --prefix forge"
|
|
146
|
-
init_ok=1
|
|
147
|
-
else
|
|
148
|
-
action "beads-init" "bd init failed; inspect Beads setup manually"
|
|
149
|
-
fi
|
|
150
|
-
fi
|
|
151
|
-
|
|
152
|
-
if [ "$init_ok" -ne 1 ]; then
|
|
90
|
+
action "kernel-init" "kernel issue store not initializable; inspect: node bin/forge.js doctor"
|
|
153
91
|
return 0
|
|
154
92
|
fi
|
|
155
93
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
if [ "$doctor_status" -eq 0 ]; then
|
|
159
|
-
doctor_output_lower="$(printf '%s' "$doctor_output" | tr '[:upper:]' '[:lower:]')"
|
|
160
|
-
if [ "$exit_code" -eq 1 ] ||
|
|
161
|
-
[[ "$doctor_output_lower" == *fix* ]] ||
|
|
162
|
-
[[ "$doctor_output_lower" == *repair* ]] ||
|
|
163
|
-
[[ "$doctor_output_lower" == *migrat* ]] ||
|
|
164
|
-
[[ "$doctor_output_lower" == *updat* ]]; then
|
|
165
|
-
fixed "beads-doctor" "ran bd doctor --fix --yes after Beads repair"
|
|
166
|
-
else
|
|
167
|
-
ok "beads-doctor" "bd doctor --fix --yes succeeded"
|
|
168
|
-
fi
|
|
94
|
+
if node "$FORGE_CLI" doctor >/dev/null 2>&1; then
|
|
95
|
+
ok "kernel-doctor" "forge doctor reports a healthy filesystem for the kernel database"
|
|
169
96
|
else
|
|
170
|
-
action "
|
|
97
|
+
action "kernel-doctor" "forge doctor reports an unhealthy filesystem; inspect the kernel database path"
|
|
171
98
|
fi
|
|
172
99
|
}
|
|
173
100
|
|
|
174
101
|
main() {
|
|
175
102
|
check_tools
|
|
176
103
|
check_github_auth
|
|
177
|
-
|
|
104
|
+
check_kernel
|
|
178
105
|
exit "$exit_code"
|
|
179
106
|
}
|
|
180
107
|
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { execFileSync } = require('node:child_process');
|
|
4
|
+
const {
|
|
5
|
+
assertProtectedWriteAllowed,
|
|
6
|
+
recordProtectedStateAuditEvent,
|
|
7
|
+
} = require('../lib/protected-state-surfaces');
|
|
8
|
+
|
|
9
|
+
function parseNameStatus(output) {
|
|
10
|
+
const files = [];
|
|
11
|
+
for (const line of output.split(/\r?\n/)) {
|
|
12
|
+
const trimmed = line.trim();
|
|
13
|
+
if (!trimmed) continue;
|
|
14
|
+
const parts = trimmed.split('\t').filter(Boolean);
|
|
15
|
+
const status = parts[0] || '';
|
|
16
|
+
if (/^[RC]/.test(status)) {
|
|
17
|
+
files.push(...parts.slice(1, 3));
|
|
18
|
+
} else {
|
|
19
|
+
files.push(parts[1]);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return [...new Set(files.filter(Boolean))];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getStagedFiles() {
|
|
26
|
+
if (process.env.FORGE_PROTECTED_STATE_STAGED_NAME_STATUS !== undefined) {
|
|
27
|
+
return parseNameStatus(process.env.FORGE_PROTECTED_STATE_STAGED_NAME_STATUS);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (process.env.FORGE_PROTECTED_STATE_STAGED_FILES !== undefined) {
|
|
31
|
+
return process.env.FORGE_PROTECTED_STATE_STAGED_FILES
|
|
32
|
+
.split(/\r?\n/)
|
|
33
|
+
.map(line => line.trim())
|
|
34
|
+
.filter(Boolean);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const output = execFileSync('git', ['diff', '--cached', '--name-status', '--diff-filter=ACMRDT'], {
|
|
38
|
+
encoding: 'utf8',
|
|
39
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
40
|
+
});
|
|
41
|
+
return parseNameStatus(output);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function getAllowedSurfaces() {
|
|
45
|
+
return new Set(
|
|
46
|
+
String(process.env.FORGE_PROTECTED_STATE_ALLOWED_SURFACES || '')
|
|
47
|
+
.split(',')
|
|
48
|
+
.map(surface => surface.trim())
|
|
49
|
+
.filter(Boolean),
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function main() {
|
|
54
|
+
const actor =
|
|
55
|
+
process.env.FORGE_PROTECTED_STATE_ACTOR ||
|
|
56
|
+
process.env.FORGE_ACTOR ||
|
|
57
|
+
process.env.USER ||
|
|
58
|
+
process.env.USERNAME ||
|
|
59
|
+
'unknown';
|
|
60
|
+
const allowedSurfaces = getAllowedSurfaces();
|
|
61
|
+
const decisions = getStagedFiles()
|
|
62
|
+
.map(file => {
|
|
63
|
+
const probe = assertProtectedWriteAllowed(file, { actor, operation: 'staged_edit' });
|
|
64
|
+
if (probe.requiredSurface && allowedSurfaces.has(probe.requiredSurface)) {
|
|
65
|
+
return assertProtectedWriteAllowed(file, {
|
|
66
|
+
actor,
|
|
67
|
+
operation: 'staged_edit',
|
|
68
|
+
viaForgeApi: true,
|
|
69
|
+
surface: probe.requiredSurface,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return probe;
|
|
73
|
+
})
|
|
74
|
+
.filter(decision => !decision.allowed);
|
|
75
|
+
|
|
76
|
+
for (const decision of decisions) {
|
|
77
|
+
const audit = recordProtectedStateAuditEvent(decision, { cwd: process.cwd() });
|
|
78
|
+
if (!audit.success) {
|
|
79
|
+
console.error(`WARN: Failed to record protected-state audit for ${decision.path}: ${audit.error}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (decisions.length === 0) {
|
|
84
|
+
console.log('OK: No protected state edits detected.');
|
|
85
|
+
process.exit(0);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
console.error('ERROR: Protected state edit detected. Direct edits to these paths are blocked:');
|
|
89
|
+
for (const decision of decisions) {
|
|
90
|
+
console.error(` - ${decision.path} [${decision.requiredSurface}]`);
|
|
91
|
+
console.error(` Decision: ${decision.decision}`);
|
|
92
|
+
console.error(` Repair: ${decision.repairHint}`);
|
|
93
|
+
}
|
|
94
|
+
console.error('');
|
|
95
|
+
console.error('Use the owning Forge or Beads API surface, then stage the generated result if that command explicitly owns it.');
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
main();
|
|
101
|
+
} catch (error) {
|
|
102
|
+
console.error(`Protected state check failed: ${error.message}`);
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|