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
|
@@ -10,7 +10,7 @@ TEST_TMP=""
|
|
|
10
10
|
setup() {
|
|
11
11
|
mkdir -p /c/tmp/forge-team-integ
|
|
12
12
|
TEST_TMP="$(mktemp -d /c/tmp/forge-team-integ/run.XXXXXX)"
|
|
13
|
-
mkdir -p "$TEST_TMP/.
|
|
13
|
+
mkdir -p "$TEST_TMP/.forge" "$TEST_TMP/mock"
|
|
14
14
|
export TEAM_MAP_ROOT="$TEST_TMP"
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -18,7 +18,7 @@ teardown() {
|
|
|
18
18
|
rm -rf "$TEST_TMP"
|
|
19
19
|
unset TEAM_MAP_ROOT || true
|
|
20
20
|
unset GH_CMD || true
|
|
21
|
-
unset
|
|
21
|
+
unset FORGE_CMD || true
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
assert_exit_code() {
|
|
@@ -64,32 +64,25 @@ esac
|
|
|
64
64
|
MOCK
|
|
65
65
|
chmod +x "$TEST_TMP/mock/gh"
|
|
66
66
|
|
|
67
|
-
cat > "$TEST_TMP/mock/
|
|
67
|
+
cat > "$TEST_TMP/mock/forge" << 'MOCK'
|
|
68
68
|
#!/usr/bin/env bash
|
|
69
69
|
case "$*" in
|
|
70
|
-
*"list
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
echo "◐ forge-t1 · Test Task 1 [● P2 · IN_PROGRESS]"
|
|
75
|
-
echo "Owner: testdev"
|
|
76
|
-
echo "Updated: 2026-03-27T10:00:00Z" ;;
|
|
77
|
-
*"show forge-t2"*)
|
|
78
|
-
echo "○ forge-t2 · Test Task 2 [● P3 · OPEN]"
|
|
79
|
-
echo "Owner: testdev"
|
|
80
|
-
echo "Updated: 2026-03-27T09:00:00Z" ;;
|
|
70
|
+
*"issue list"*"--status=in_progress"*)
|
|
71
|
+
printf '{"data":{"issues":[{"id":"forge-t1","title":"Test Task 1","status":"in_progress","assignee":"testdev","updated_at":"2026-03-27T10:00:00Z","dependencies":[]}]}}\n' ;;
|
|
72
|
+
*"issue list"*"--status=open"*)
|
|
73
|
+
printf '{"data":{"issues":[{"id":"forge-t2","title":"Test Task 2","status":"open","assignee":"testdev","updated_at":"2026-03-27T09:00:00Z","dependencies":[]}]}}\n' ;;
|
|
81
74
|
*) exit 0 ;;
|
|
82
75
|
esac
|
|
83
76
|
MOCK
|
|
84
|
-
chmod +x "$TEST_TMP/mock/
|
|
77
|
+
chmod +x "$TEST_TMP/mock/forge"
|
|
85
78
|
|
|
86
|
-
export GH_CMD="$TEST_TMP/mock/gh"
|
|
79
|
+
export GH_CMD="$TEST_TMP/mock/gh" FORGE_CMD="$TEST_TMP/mock/forge"
|
|
87
80
|
|
|
88
81
|
# Run identity auto-detect in subshell to avoid readonly clashes
|
|
89
82
|
local id_rc
|
|
90
83
|
bash -c '
|
|
91
84
|
set -euo pipefail
|
|
92
|
-
export GH_CMD="'"$TEST_TMP"'/mock/gh"
|
|
85
|
+
export GH_CMD="'"$TEST_TMP"'/mock/gh" FORGE_CMD="'"$TEST_TMP"'/mock/forge" TEAM_MAP_ROOT="'"$TEST_TMP"'"
|
|
93
86
|
source "'"$SCRIPT_DIR"'/lib/identity.sh"
|
|
94
87
|
_GITHUB_USER_CACHE=""
|
|
95
88
|
auto_detect_identity
|
|
@@ -98,7 +91,7 @@ MOCK
|
|
|
98
91
|
|
|
99
92
|
# Check team map has entry
|
|
100
93
|
local map_content
|
|
101
|
-
map_content="$(cat "$TEST_TMP/.
|
|
94
|
+
map_content="$(cat "$TEST_TMP/.forge/team-map.jsonl" 2>/dev/null || echo "")"
|
|
102
95
|
assert_contains "team map has testdev" "testdev" "$map_content"
|
|
103
96
|
|
|
104
97
|
# Workload shows issues
|
|
@@ -125,26 +118,19 @@ esac
|
|
|
125
118
|
MOCK
|
|
126
119
|
chmod +x "$TEST_TMP/mock/gh"
|
|
127
120
|
|
|
128
|
-
cat > "$TEST_TMP/mock/
|
|
121
|
+
cat > "$TEST_TMP/mock/forge" << 'MOCK'
|
|
129
122
|
#!/usr/bin/env bash
|
|
130
123
|
case "$*" in
|
|
131
|
-
*"list
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
echo "◐ forge-aa · Task A [● P2 · IN_PROGRESS]"
|
|
136
|
-
echo "Owner: dev-a"
|
|
137
|
-
echo "Updated: 2026-03-27T10:00:00Z" ;;
|
|
138
|
-
*"show forge-bb"*)
|
|
139
|
-
echo "○ forge-bb · Task B [● P3 · OPEN]"
|
|
140
|
-
echo "Owner: dev-b"
|
|
141
|
-
echo "Updated: 2026-03-27T09:00:00Z" ;;
|
|
124
|
+
*"issue list"*"--status=in_progress"*)
|
|
125
|
+
printf '{"data":{"issues":[{"id":"forge-aa","title":"Task A","status":"in_progress","assignee":"dev-a","updated_at":"2026-03-27T10:00:00Z","dependencies":[]}]}}\n' ;;
|
|
126
|
+
*"issue list"*"--status=open"*)
|
|
127
|
+
printf '{"data":{"issues":[{"id":"forge-bb","title":"Task B","status":"open","assignee":"dev-b","updated_at":"2026-03-27T09:00:00Z","dependencies":[]}]}}\n' ;;
|
|
142
128
|
*) exit 0 ;;
|
|
143
129
|
esac
|
|
144
130
|
MOCK
|
|
145
|
-
chmod +x "$TEST_TMP/mock/
|
|
131
|
+
chmod +x "$TEST_TMP/mock/forge"
|
|
146
132
|
|
|
147
|
-
export GH_CMD="$TEST_TMP/mock/gh"
|
|
133
|
+
export GH_CMD="$TEST_TMP/mock/gh" FORGE_CMD="$TEST_TMP/mock/forge"
|
|
148
134
|
|
|
149
135
|
local output rc
|
|
150
136
|
output="$(bash "$FORGE_TEAM" workload 2>&1)" && rc=$? || rc=$?
|
|
@@ -173,23 +159,24 @@ esac
|
|
|
173
159
|
MOCK
|
|
174
160
|
chmod +x "$TEST_TMP/mock/gh"
|
|
175
161
|
|
|
176
|
-
cat > "$TEST_TMP/mock/
|
|
162
|
+
cat > "$TEST_TMP/mock/forge" << 'MOCK'
|
|
177
163
|
#!/usr/bin/env bash
|
|
178
164
|
case "$*" in
|
|
179
|
-
*"show forge-claimed"*)
|
|
165
|
+
*"issue show forge-claimed"*)
|
|
166
|
+
printf '{"data":{"issue":{"id":"forge-claimed","title":"Claimed","status":"open","labels":["github_issue:42"]}}}\n' ;;
|
|
180
167
|
*) exit 0 ;;
|
|
181
168
|
esac
|
|
182
169
|
MOCK
|
|
183
|
-
chmod +x "$TEST_TMP/mock/
|
|
170
|
+
chmod +x "$TEST_TMP/mock/forge"
|
|
184
171
|
|
|
185
|
-
export GH_CMD="$TEST_TMP/mock/gh"
|
|
172
|
+
export GH_CMD="$TEST_TMP/mock/gh" FORGE_CMD="$TEST_TMP/mock/forge"
|
|
186
173
|
|
|
187
174
|
# Run in subshell to avoid readonly clashes from re-sourcing
|
|
188
175
|
local output rc
|
|
189
176
|
output="$(
|
|
190
177
|
bash -c '
|
|
191
178
|
set -euo pipefail
|
|
192
|
-
export GH_CMD="'"$TEST_TMP"'/mock/gh"
|
|
179
|
+
export GH_CMD="'"$TEST_TMP"'/mock/gh" FORGE_CMD="'"$TEST_TMP"'/mock/forge" TEAM_MAP_ROOT="'"$TEST_TMP"'"
|
|
193
180
|
source "'"$SCRIPT_DIR"'/lib/claim.sh"
|
|
194
181
|
_GITHUB_USER_CACHE=""
|
|
195
182
|
pre_claim_check "forge-claimed" 2>&1
|
|
@@ -217,24 +204,22 @@ esac
|
|
|
217
204
|
MOCK
|
|
218
205
|
chmod +x "$TEST_TMP/mock/gh"
|
|
219
206
|
|
|
220
|
-
cat > "$TEST_TMP/mock/
|
|
207
|
+
cat > "$TEST_TMP/mock/forge" << 'MOCK'
|
|
221
208
|
#!/usr/bin/env bash
|
|
222
209
|
case "$*" in
|
|
223
|
-
*"list
|
|
224
|
-
|
|
225
|
-
*"
|
|
226
|
-
|
|
227
|
-
echo "Owner: testdev"
|
|
228
|
-
echo "Updated: 2026-03-27T10:00:00Z" ;;
|
|
210
|
+
*"issue list"*"--status=open"*)
|
|
211
|
+
printf '{"data":{"issues":[{"id":"forge-orphan","title":"Orphan Task","status":"open","assignee":"testdev","updated_at":"2026-03-27T10:00:00Z","labels":[],"dependencies":[]}]}}\n' ;;
|
|
212
|
+
*"issue list"*"--status=in_progress"*)
|
|
213
|
+
printf '{"data":{"issues":[]}}\n' ;;
|
|
229
214
|
*) exit 0 ;;
|
|
230
215
|
esac
|
|
231
216
|
MOCK
|
|
232
|
-
chmod +x "$TEST_TMP/mock/
|
|
217
|
+
chmod +x "$TEST_TMP/mock/forge"
|
|
233
218
|
|
|
234
|
-
export GH_CMD="$TEST_TMP/mock/gh"
|
|
219
|
+
export GH_CMD="$TEST_TMP/mock/gh" FORGE_CMD="$TEST_TMP/mock/forge"
|
|
235
220
|
|
|
236
221
|
# Seed team map so identity check passes
|
|
237
|
-
echo '{"github":"testdev","display_name":"testdev","updated_at":"2026-03-27T10:00:00Z","is_bot":false}' > "$TEST_TMP/.
|
|
222
|
+
echo '{"github":"testdev","display_name":"testdev","updated_at":"2026-03-27T10:00:00Z","is_bot":false}' > "$TEST_TMP/.forge/team-map.jsonl"
|
|
238
223
|
|
|
239
224
|
local output rc
|
|
240
225
|
output="$(bash "$FORGE_TEAM" verify 2>&1)" && rc=$? || rc=$?
|
|
@@ -261,19 +246,19 @@ esac
|
|
|
261
246
|
MOCK
|
|
262
247
|
chmod +x "$TEST_TMP/mock/gh"
|
|
263
248
|
|
|
264
|
-
cat > "$TEST_TMP/mock/
|
|
249
|
+
cat > "$TEST_TMP/mock/forge" << 'MOCK'
|
|
265
250
|
#!/usr/bin/env bash
|
|
266
251
|
case "$*" in
|
|
267
|
-
*"list"*)
|
|
252
|
+
*"issue list"*) printf '{"data":{"issues":[]}}\n' ;;
|
|
268
253
|
*) exit 0 ;;
|
|
269
254
|
esac
|
|
270
255
|
MOCK
|
|
271
|
-
chmod +x "$TEST_TMP/mock/
|
|
256
|
+
chmod +x "$TEST_TMP/mock/forge"
|
|
272
257
|
|
|
273
|
-
export GH_CMD="$TEST_TMP/mock/gh"
|
|
258
|
+
export GH_CMD="$TEST_TMP/mock/gh" FORGE_CMD="$TEST_TMP/mock/forge"
|
|
274
259
|
|
|
275
260
|
# Seed team map so identity check passes
|
|
276
|
-
echo '{"github":"testdev","display_name":"testdev","updated_at":"2026-03-27T10:00:00Z","is_bot":false}' > "$TEST_TMP/.
|
|
261
|
+
echo '{"github":"testdev","display_name":"testdev","updated_at":"2026-03-27T10:00:00Z","is_bot":false}' > "$TEST_TMP/.forge/team-map.jsonl"
|
|
277
262
|
|
|
278
263
|
# No mapping file — all GitHub issues should be orphans
|
|
279
264
|
local output rc
|
|
@@ -299,26 +284,19 @@ esac
|
|
|
299
284
|
MOCK
|
|
300
285
|
chmod +x "$TEST_TMP/mock/gh"
|
|
301
286
|
|
|
302
|
-
cat > "$TEST_TMP/mock/
|
|
287
|
+
cat > "$TEST_TMP/mock/forge" << 'MOCK'
|
|
303
288
|
#!/usr/bin/env bash
|
|
304
289
|
case "$*" in
|
|
305
|
-
*"list
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
echo "○ forge-bot1 · Bot Task [● P4 · OPEN]"
|
|
310
|
-
echo "Owner: dependabot[bot]"
|
|
311
|
-
echo "Updated: 2026-03-27T10:00:00Z" ;;
|
|
312
|
-
*"show forge-real"*)
|
|
313
|
-
echo "◐ forge-real · Real Task [● P2 · IN_PROGRESS]"
|
|
314
|
-
echo "Owner: testdev"
|
|
315
|
-
echo "Updated: 2026-03-27T10:00:00Z" ;;
|
|
290
|
+
*"issue list"*"--status=in_progress"*)
|
|
291
|
+
printf '{"data":{"issues":[{"id":"forge-real","title":"Real Task","status":"in_progress","assignee":"testdev","updated_at":"2026-03-27T10:00:00Z","dependencies":[]}]}}\n' ;;
|
|
292
|
+
*"issue list"*"--status=open"*)
|
|
293
|
+
printf '{"data":{"issues":[{"id":"forge-bot1","title":"Bot Task","status":"open","assignee":"dependabot[bot]","updated_at":"2026-03-27T10:00:00Z","dependencies":[]}]}}\n' ;;
|
|
316
294
|
*) exit 0 ;;
|
|
317
295
|
esac
|
|
318
296
|
MOCK
|
|
319
|
-
chmod +x "$TEST_TMP/mock/
|
|
297
|
+
chmod +x "$TEST_TMP/mock/forge"
|
|
320
298
|
|
|
321
|
-
export GH_CMD="$TEST_TMP/mock/gh"
|
|
299
|
+
export GH_CMD="$TEST_TMP/mock/gh" FORGE_CMD="$TEST_TMP/mock/forge"
|
|
322
300
|
|
|
323
301
|
local output rc
|
|
324
302
|
output="$(bash "$FORGE_TEAM" workload 2>&1)" && rc=$? || rc=$?
|
|
@@ -29,43 +29,31 @@ exit 1
|
|
|
29
29
|
MOCK
|
|
30
30
|
chmod +x "$mock_dir/gh"
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
# Mock forge: `issue show --json` carries the github_issue:<n> association as a
|
|
33
|
+
# label; `issue update --label` records it. Args are logged for assertions.
|
|
34
|
+
cat > "$mock_dir/forge" << 'MOCK'
|
|
33
35
|
#!/usr/bin/env bash
|
|
34
36
|
echo "$*" >> "$LOG_FILE"
|
|
35
|
-
case "$1" in
|
|
36
|
-
show)
|
|
37
|
-
|
|
38
|
-
cat <<'JSON'
|
|
39
|
-
{"id":"beads-001","github":{"number":42,"nodeId":"I_kwDOForge42","url":"https://github.com/test/repo/issues/42"},"shared":{"title":"Test Issue"}}
|
|
40
|
-
JSON
|
|
41
|
-
else
|
|
42
|
-
echo "o $2 - Test Issue"
|
|
43
|
-
echo "Title: Test Issue"
|
|
44
|
-
fi
|
|
37
|
+
case "$1 $2" in
|
|
38
|
+
"issue show")
|
|
39
|
+
printf '{"data":{"issue":{"id":"beads-001","title":"Test Issue","labels":["github_issue:42"]}}}\n'
|
|
45
40
|
;;
|
|
46
|
-
|
|
41
|
+
"issue update") echo "Updated" ;;
|
|
47
42
|
esac
|
|
48
43
|
MOCK
|
|
49
|
-
chmod +x "$mock_dir/
|
|
44
|
+
chmod +x "$mock_dir/forge"
|
|
50
45
|
|
|
51
|
-
cat > "$mock_dir/
|
|
46
|
+
cat > "$mock_dir/forge-no-gh" << 'MOCK'
|
|
52
47
|
#!/usr/bin/env bash
|
|
53
48
|
echo "$*" >> "$LOG_FILE"
|
|
54
|
-
case "$1" in
|
|
55
|
-
show)
|
|
56
|
-
|
|
57
|
-
cat <<'JSON'
|
|
58
|
-
{"id":"beads-999","shared":{"title":"Test Issue"}}
|
|
59
|
-
JSON
|
|
60
|
-
else
|
|
61
|
-
echo "o $2 - Test Issue"
|
|
62
|
-
echo "Title: Test Issue"
|
|
63
|
-
fi
|
|
49
|
+
case "$1 $2" in
|
|
50
|
+
"issue show")
|
|
51
|
+
printf '{"data":{"issue":{"id":"beads-999","title":"Test Issue","labels":[]}}}\n'
|
|
64
52
|
;;
|
|
65
|
-
|
|
53
|
+
"issue update") echo "Updated" ;;
|
|
66
54
|
esac
|
|
67
55
|
MOCK
|
|
68
|
-
chmod +x "$mock_dir/
|
|
56
|
+
chmod +x "$mock_dir/forge-no-gh"
|
|
69
57
|
|
|
70
58
|
cat > "$portable_bin/grep" << 'MOCK'
|
|
71
59
|
#!/usr/bin/env bash
|
|
@@ -83,7 +71,7 @@ chmod +x "$portable_bin/grep"
|
|
|
83
71
|
|
|
84
72
|
export LOG_FILE="$log_file"
|
|
85
73
|
export GH_CMD="$mock_dir/gh"
|
|
86
|
-
export
|
|
74
|
+
export FORGE_CMD="$mock_dir/forge"
|
|
87
75
|
export TEAM_MAP_ROOT="$TEST_TMP"
|
|
88
76
|
mapping_file="$TEAM_MAP_ROOT/.github/beads-mapping.json"
|
|
89
77
|
|
|
@@ -145,8 +133,8 @@ log_contents="$(cat "$log_file")"
|
|
|
145
133
|
assert_contains "gh issue create called" "issue create" "$log_contents"
|
|
146
134
|
assert_contains "title includes Test Issue" "Test Issue" "$log_contents"
|
|
147
135
|
assert_contains "body includes beads-001" "beads-001" "$log_contents"
|
|
148
|
-
assert_contains "sync create writes
|
|
149
|
-
assert_contains "sync create calls
|
|
136
|
+
assert_contains "sync create writes github_issue label" "github_issue:42" "$log_contents"
|
|
137
|
+
assert_contains "sync create calls issue update for the label" "issue update" "$log_contents"
|
|
150
138
|
assert_contains "sync create persists mapping entry" '"42": "beads-001"' "$(cat "$mapping_file")"
|
|
151
139
|
|
|
152
140
|
echo
|
|
@@ -211,10 +199,10 @@ cat > "$mapping_file" << 'JSON'
|
|
|
211
199
|
"77": "beads-999"
|
|
212
200
|
}
|
|
213
201
|
JSON
|
|
214
|
-
export
|
|
202
|
+
export FORGE_CMD="$mock_dir/forge-no-gh"
|
|
215
203
|
result="$(_get_github_issue_number "beads-999")"
|
|
216
204
|
assert_eq "mapping fallback returns issue number 77" "77" "$result"
|
|
217
|
-
export
|
|
205
|
+
export FORGE_CMD="$mock_dir/forge"
|
|
218
206
|
|
|
219
207
|
echo
|
|
220
208
|
echo "== Test 8: Mapping fallback returns newest issue number =="
|
|
@@ -225,69 +213,54 @@ cat > "$mapping_file" << 'JSON'
|
|
|
225
213
|
"88": "beads-other"
|
|
226
214
|
}
|
|
227
215
|
JSON
|
|
228
|
-
export
|
|
216
|
+
export FORGE_CMD="$mock_dir/forge-no-gh"
|
|
229
217
|
result="$(_get_github_issue_number "beads-999")"
|
|
230
218
|
assert_eq "mapping fallback returns newest matching issue number" "91" "$result"
|
|
231
|
-
export
|
|
219
|
+
export FORGE_CMD="$mock_dir/forge"
|
|
232
220
|
|
|
233
221
|
echo
|
|
234
222
|
echo "== Test 9: Missing canonical GitHub number =="
|
|
235
223
|
rm -f "$mapping_file"
|
|
236
|
-
export
|
|
224
|
+
export FORGE_CMD="$mock_dir/forge-no-gh"
|
|
237
225
|
rc=0
|
|
238
226
|
result="$(_get_github_issue_number "beads-999" 2>/dev/null)" || rc=$?
|
|
239
227
|
assert_exit "returns error when no canonical github number" 1 "$rc"
|
|
240
|
-
export
|
|
228
|
+
export FORGE_CMD="$mock_dir/forge"
|
|
241
229
|
|
|
242
230
|
echo
|
|
243
|
-
echo "== Test 10:
|
|
244
|
-
cat > "$mock_dir/
|
|
231
|
+
echo "== Test 10: github_issue label lookup =="
|
|
232
|
+
cat > "$mock_dir/forge-legacy" << 'MOCK'
|
|
245
233
|
#!/usr/bin/env bash
|
|
246
234
|
echo "$*" >> "$LOG_FILE"
|
|
247
|
-
case "$1" in
|
|
248
|
-
show)
|
|
249
|
-
|
|
250
|
-
cat <<'JSON'
|
|
251
|
-
{"id":"beads-legacy","github_issue":43,"shared":{"title":"Legacy Issue"}}
|
|
252
|
-
JSON
|
|
253
|
-
else
|
|
254
|
-
echo "o $2 - Legacy Issue"
|
|
255
|
-
echo "github_issue:43"
|
|
256
|
-
echo "Title: Legacy Issue"
|
|
257
|
-
fi
|
|
235
|
+
case "$1 $2" in
|
|
236
|
+
"issue show")
|
|
237
|
+
printf '{"data":{"issue":{"id":"beads-legacy","title":"Legacy Issue","labels":["github_issue:43"]}}}\n'
|
|
258
238
|
;;
|
|
259
|
-
|
|
239
|
+
"issue update") echo "Updated" ;;
|
|
260
240
|
esac
|
|
261
241
|
MOCK
|
|
262
|
-
chmod +x "$mock_dir/
|
|
263
|
-
export
|
|
242
|
+
chmod +x "$mock_dir/forge-legacy"
|
|
243
|
+
export FORGE_CMD="$mock_dir/forge-legacy"
|
|
264
244
|
rc=0
|
|
265
245
|
result="$(_get_github_issue_number "beads-legacy" 2>/dev/null)" || rc=$?
|
|
266
246
|
assert_exit "legacy github_issue exits successfully" 0 "$rc"
|
|
267
247
|
assert_eq "legacy github_issue returns number" "43" "$result"
|
|
268
|
-
export
|
|
248
|
+
export FORGE_CMD="$mock_dir/forge"
|
|
269
249
|
|
|
270
250
|
echo
|
|
271
251
|
echo "== Test 11: Injection in title sanitized =="
|
|
272
|
-
cat > "$mock_dir/
|
|
252
|
+
cat > "$mock_dir/forge-inject" << 'MOCK'
|
|
273
253
|
#!/usr/bin/env bash
|
|
274
254
|
echo "$*" >> "$LOG_FILE"
|
|
275
|
-
case "$1" in
|
|
276
|
-
show)
|
|
277
|
-
|
|
278
|
-
cat <<'JSON'
|
|
279
|
-
{"id":"beads-inject","github":{"number":99,"url":"https://github.com/test/repo/issues/99"},"shared":{"title":"Evil $(rm -rf /) Issue"}}
|
|
280
|
-
JSON
|
|
281
|
-
else
|
|
282
|
-
echo 'o beads-inject - Evil $(rm -rf /) Issue'
|
|
283
|
-
echo 'Title: Evil $(rm -rf /) Issue'
|
|
284
|
-
fi
|
|
255
|
+
case "$1 $2" in
|
|
256
|
+
"issue show")
|
|
257
|
+
printf '{"data":{"issue":{"id":"beads-inject","title":"Evil $(rm -rf /) Issue","labels":["github_issue:99"]}}}\n'
|
|
285
258
|
;;
|
|
286
|
-
|
|
259
|
+
"issue update") echo "Updated" ;;
|
|
287
260
|
esac
|
|
288
261
|
MOCK
|
|
289
|
-
chmod +x "$mock_dir/
|
|
290
|
-
export
|
|
262
|
+
chmod +x "$mock_dir/forge-inject"
|
|
263
|
+
export FORGE_CMD="$mock_dir/forge-inject"
|
|
291
264
|
> "$log_file"
|
|
292
265
|
rc=0
|
|
293
266
|
sync_issue_create "beads-inject" || rc=$?
|
|
@@ -300,7 +273,7 @@ else
|
|
|
300
273
|
PASS=$((PASS + 1))
|
|
301
274
|
echo " PASS: injection sanitized - no \$\(rm in gh call"
|
|
302
275
|
fi
|
|
303
|
-
export
|
|
276
|
+
export FORGE_CMD="$mock_dir/forge"
|
|
304
277
|
|
|
305
278
|
echo
|
|
306
279
|
echo "== Test 11: sync_issue_create without grep -P =="
|
|
@@ -314,32 +287,26 @@ assert_contains "gh issue create called without PCRE grep" "issue create" "$log_
|
|
|
314
287
|
export PATH="$ORIGINAL_PATH"
|
|
315
288
|
|
|
316
289
|
echo
|
|
317
|
-
echo "== Test 12: sync_issue_create
|
|
318
|
-
cat > "$mock_dir/
|
|
290
|
+
echo "== Test 12: sync_issue_create reads title from issue show JSON =="
|
|
291
|
+
cat > "$mock_dir/forge-summary-only" << 'MOCK'
|
|
319
292
|
#!/usr/bin/env bash
|
|
320
293
|
echo "$*" >> "$LOG_FILE"
|
|
321
|
-
case "$1" in
|
|
322
|
-
show)
|
|
323
|
-
|
|
324
|
-
cat <<'JSON'
|
|
325
|
-
{"id":"beads-summary","github":{"number":77,"url":"https://github.com/test/repo/issues/77"},"shared":{"title":"Summary Only Title"}}
|
|
326
|
-
JSON
|
|
327
|
-
else
|
|
328
|
-
echo "o $2 - Summary Only Title"
|
|
329
|
-
fi
|
|
294
|
+
case "$1 $2" in
|
|
295
|
+
"issue show")
|
|
296
|
+
printf '{"data":{"issue":{"id":"beads-summary","title":"Summary Only Title","labels":["github_issue:77"]}}}\n'
|
|
330
297
|
;;
|
|
331
|
-
|
|
298
|
+
"issue update") echo "Updated" ;;
|
|
332
299
|
esac
|
|
333
300
|
MOCK
|
|
334
|
-
chmod +x "$mock_dir/
|
|
335
|
-
export
|
|
301
|
+
chmod +x "$mock_dir/forge-summary-only"
|
|
302
|
+
export FORGE_CMD="$mock_dir/forge-summary-only"
|
|
336
303
|
> "$log_file"
|
|
337
304
|
rc=0
|
|
338
305
|
sync_issue_create "beads-summary" || rc=$?
|
|
339
|
-
assert_exit "sync_issue_create works with
|
|
306
|
+
assert_exit "sync_issue_create works with title from issue show JSON" 0 "$rc"
|
|
340
307
|
log_contents="$(cat "$log_file")"
|
|
341
308
|
assert_contains "summary-only title is passed to gh issue create" "Summary Only Title" "$log_contents"
|
|
342
|
-
export
|
|
309
|
+
export FORGE_CMD="$mock_dir/forge"
|
|
343
310
|
|
|
344
311
|
echo
|
|
345
312
|
echo "Results: $PASS passed, $FAIL failed"
|
|
@@ -7,7 +7,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
|
7
7
|
TEST_TMP="$(mktemp -d)"
|
|
8
8
|
trap 'rm -rf "$TEST_TMP"' EXIT
|
|
9
9
|
|
|
10
|
-
# Override TEAM_MAP_ROOT so tests don't touch real .
|
|
10
|
+
# Override TEAM_MAP_ROOT so tests don't touch real .forge/
|
|
11
11
|
export TEAM_MAP_ROOT="$TEST_TMP"
|
|
12
12
|
|
|
13
13
|
# ── Create mock directories ────────────────────────────────────────────
|
|
@@ -66,47 +66,34 @@ exit 1
|
|
|
66
66
|
MOCK
|
|
67
67
|
chmod +x "$mock_dir/gh-noauth"
|
|
68
68
|
|
|
69
|
-
# ── Mock
|
|
70
|
-
|
|
69
|
+
# ── Mock forge (emits Kernel-shaped issue list JSON) ───────────────────
|
|
70
|
+
# The GitHub association lives in each issue's labels as github_issue:<n>.
|
|
71
|
+
# Tests drive which issues appear via FORGE_MOCK_OPEN / FORGE_MOCK_INPROGRESS
|
|
72
|
+
# (JSON arrays, each defaulting to []).
|
|
73
|
+
cat > "$mock_dir/forge" << 'MOCK'
|
|
71
74
|
#!/usr/bin/env bash
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
echo "Owner: devone"
|
|
84
|
-
if [[ -z "${BD_MOCK_NO_GITHUB_AAA:-}" ]]; then
|
|
85
|
-
echo "State: github_issue:10"
|
|
86
|
-
fi
|
|
87
|
-
;;
|
|
88
|
-
forge-bbb)
|
|
89
|
-
echo "○ forge-bbb · Feature B [● P2 · OPEN]"
|
|
90
|
-
echo "Owner: devtwo"
|
|
91
|
-
if [[ -z "${BD_MOCK_NO_GITHUB_BBB:-}" ]]; then
|
|
92
|
-
echo "State: github_issue:20"
|
|
93
|
-
fi
|
|
94
|
-
;;
|
|
95
|
-
forge-ccc)
|
|
96
|
-
echo "◐ forge-ccc · Feature C [● P1 · IN_PROGRESS]"
|
|
97
|
-
echo "Owner: devone"
|
|
98
|
-
# forge-ccc never has github_issue (for orphan tests)
|
|
99
|
-
;;
|
|
100
|
-
esac
|
|
101
|
-
exit 0
|
|
102
|
-
;;
|
|
103
|
-
esac
|
|
75
|
+
args="$*"
|
|
76
|
+
if [[ "$args" == *"issue list"* ]]; then
|
|
77
|
+
if [[ "$args" == *"--status=open"* ]]; then
|
|
78
|
+
printf '{"data":{"issues":%s}}\n' "${FORGE_MOCK_OPEN:-[]}"
|
|
79
|
+
elif [[ "$args" == *"--status=in_progress"* ]]; then
|
|
80
|
+
printf '{"data":{"issues":%s}}\n' "${FORGE_MOCK_INPROGRESS:-[]}"
|
|
81
|
+
else
|
|
82
|
+
printf '{"data":{"issues":[]}}\n'
|
|
83
|
+
fi
|
|
84
|
+
exit 0
|
|
85
|
+
fi
|
|
104
86
|
exit 0
|
|
105
87
|
MOCK
|
|
106
|
-
chmod +x "$mock_dir/
|
|
88
|
+
chmod +x "$mock_dir/forge"
|
|
89
|
+
|
|
90
|
+
# Reusable issue fixtures (synced issues carry a github_issue:<n> label)
|
|
91
|
+
ccc_orphan='{"id":"forge-ccc","title":"Feature C","status":"in_progress","assignee":"devone","labels":[],"dependencies":[]}'
|
|
92
|
+
aaa_synced='{"id":"forge-aaa","title":"Feature A","status":"in_progress","assignee":"devone","labels":["github_issue:10"],"dependencies":[]}'
|
|
93
|
+
bbb_synced='{"id":"forge-bbb","title":"Feature B","status":"open","assignee":"devtwo","labels":["github_issue:20"],"dependencies":[]}'
|
|
107
94
|
|
|
108
95
|
export GH_CMD="$mock_dir/gh"
|
|
109
|
-
export
|
|
96
|
+
export FORGE_CMD="$mock_dir/forge"
|
|
110
97
|
|
|
111
98
|
# Source the library under test
|
|
112
99
|
source "$SCRIPT_DIR/lib/agent-prompt.sh"
|
|
@@ -158,11 +145,12 @@ echo "── Test 1: All clean → exit 0 ──"
|
|
|
158
145
|
# Setup: identity exists in team map
|
|
159
146
|
unset _GITHUB_USER_CACHE
|
|
160
147
|
export GH_CMD="$mock_dir/gh"
|
|
161
|
-
export
|
|
148
|
+
export FORGE_CMD="$mock_dir/forge"
|
|
162
149
|
team_map_add "testuser" "Test User"
|
|
163
150
|
|
|
164
|
-
# No
|
|
165
|
-
export
|
|
151
|
+
# No tracked issues, no github issues
|
|
152
|
+
export FORGE_MOCK_OPEN="[]"
|
|
153
|
+
export FORGE_MOCK_INPROGRESS="[]"
|
|
166
154
|
export GH_MOCK_ISSUES="[]"
|
|
167
155
|
|
|
168
156
|
# Create empty mapping file
|
|
@@ -194,10 +182,11 @@ echo "── Test 3: Orphan Beads issue detected ──"
|
|
|
194
182
|
|
|
195
183
|
unset _GITHUB_USER_CACHE
|
|
196
184
|
export GH_CMD="$mock_dir/gh"
|
|
197
|
-
export
|
|
185
|
+
export FORGE_MOCK_OPEN="[]"
|
|
186
|
+
export FORGE_MOCK_INPROGRESS="[$ccc_orphan]"
|
|
198
187
|
export GH_MOCK_ISSUES="[]"
|
|
199
188
|
|
|
200
|
-
# forge-ccc
|
|
189
|
+
# forge-ccc carries no github_issue label (see fixtures above)
|
|
201
190
|
rc=0
|
|
202
191
|
output="$(cmd_verify 2>&1)" || rc=$?
|
|
203
192
|
assert_exit "orphan beads exits 1" 1 "$rc"
|
|
@@ -210,7 +199,8 @@ echo "── Test 4: Orphan GitHub issue detected ──"
|
|
|
210
199
|
|
|
211
200
|
unset _GITHUB_USER_CACHE
|
|
212
201
|
export GH_CMD="$mock_dir/gh"
|
|
213
|
-
export
|
|
202
|
+
export FORGE_MOCK_OPEN="[]"
|
|
203
|
+
export FORGE_MOCK_INPROGRESS="[]"
|
|
214
204
|
export GH_MOCK_ISSUES='[{"number":42,"title":"Some feature"},{"number":45,"title":"Another feature"}]'
|
|
215
205
|
|
|
216
206
|
# Mapping file has neither #42 nor #45
|
|
@@ -231,8 +221,8 @@ unset _GITHUB_USER_CACHE
|
|
|
231
221
|
export GH_CMD="$mock_dir/gh"
|
|
232
222
|
|
|
233
223
|
# Setup: forge-aaa has github_issue:10, forge-bbb has github_issue:20
|
|
234
|
-
export
|
|
235
|
-
|
|
224
|
+
export FORGE_MOCK_OPEN="[$bbb_synced]"
|
|
225
|
+
export FORGE_MOCK_INPROGRESS="[$aaa_synced]"
|
|
236
226
|
|
|
237
227
|
# Create mapping with both issues
|
|
238
228
|
cat > "$TEST_TMP/.github/beads-mapping.json" << 'EOF'
|
|
@@ -300,7 +290,8 @@ echo "── Test 6: No issues at all → exit 0 ──"
|
|
|
300
290
|
|
|
301
291
|
unset _GITHUB_USER_CACHE
|
|
302
292
|
export GH_CMD="$mock_dir/gh"
|
|
303
|
-
export
|
|
293
|
+
export FORGE_MOCK_OPEN="[]"
|
|
294
|
+
export FORGE_MOCK_INPROGRESS="[]"
|
|
304
295
|
export GH_MOCK_ISSUES="[]"
|
|
305
296
|
echo '{}' > "$TEST_TMP/.github/beads-mapping.json"
|
|
306
297
|
|
|
@@ -31,11 +31,11 @@ assert_contains_file "ship calls sync" "forge-team.*sync" "$SHIP"
|
|
|
31
31
|
assert_contains_file "ship calls verify" "forge-team.*verify" "$SHIP"
|
|
32
32
|
|
|
33
33
|
echo ""
|
|
34
|
-
echo "──
|
|
35
|
-
if
|
|
36
|
-
|
|
34
|
+
echo "── Skill sync check ──"
|
|
35
|
+
if (cd "$SCRIPT_DIR" && node -e "const r=require('./lib/skills-sync').checkSkillsSync({repoRoot:process.cwd()}); process.exit(r.inSync?0:1)"); then
|
|
36
|
+
PASS=$((PASS + 1)); echo " PASS: all agent skill dirs in sync"
|
|
37
37
|
else
|
|
38
|
-
|
|
38
|
+
FAIL=$((FAIL + 1)); echo " FAIL: skill drift detected"
|
|
39
39
|
fi
|
|
40
40
|
|
|
41
41
|
echo ""
|