forge-workflow 0.0.3 → 0.0.5
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/commands/dev.md +340 -314
- package/.claude/commands/plan.md +521 -478
- package/.claude/commands/premerge.md +176 -179
- package/.claude/commands/research.md +42 -42
- package/.claude/commands/review.md +442 -442
- package/.claude/commands/rollback.md +721 -721
- package/.claude/commands/ship.md +164 -134
- package/.claude/commands/sonarcloud.md +152 -152
- package/.claude/commands/status.md +48 -77
- package/.claude/commands/validate.md +282 -237
- package/.claude/commands/verify.md +221 -221
- package/.claude/rules/greptile-review-process.md +285 -285
- package/.claude/rules/workflow.md +105 -105
- package/.claude/scripts/greptile-resolve.sh +526 -526
- package/.claude/scripts/load-env.sh +32 -32
- package/.cline/workflows/dev.md +337 -311
- package/.cline/workflows/plan.md +518 -475
- package/.cline/workflows/premerge.md +173 -176
- package/.cline/workflows/research.md +39 -39
- package/.cline/workflows/review.md +439 -439
- package/.cline/workflows/rollback.md +718 -718
- package/.cline/workflows/ship.md +161 -131
- package/.cline/workflows/sonarcloud.md +146 -146
- package/.cline/workflows/status.md +45 -74
- package/.cline/workflows/validate.md +279 -234
- package/.cline/workflows/verify.md +218 -218
- package/.codex/config.toml +11 -11
- package/.codex/skills/dev/SKILL.md +340 -314
- package/.codex/skills/plan/SKILL.md +521 -478
- package/.codex/skills/premerge/SKILL.md +176 -179
- package/.codex/skills/research/SKILL.md +42 -42
- package/.codex/skills/review/SKILL.md +442 -442
- package/.codex/skills/rollback/SKILL.md +721 -721
- package/.codex/skills/ship/SKILL.md +164 -134
- package/.codex/skills/sonarcloud/SKILL.md +149 -149
- package/.codex/skills/status/SKILL.md +48 -77
- package/.codex/skills/validate/SKILL.md +282 -237
- package/.codex/skills/verify/SKILL.md +221 -221
- package/.cursor/commands/dev.md +337 -311
- package/.cursor/commands/plan.md +518 -475
- package/.cursor/commands/premerge.md +173 -176
- package/.cursor/commands/research.md +39 -39
- package/.cursor/commands/review.md +439 -439
- package/.cursor/commands/rollback.md +718 -718
- package/.cursor/commands/ship.md +161 -131
- package/.cursor/commands/sonarcloud.md +146 -146
- package/.cursor/commands/status.md +45 -74
- package/.cursor/commands/validate.md +279 -234
- package/.cursor/commands/verify.md +218 -218
- package/.cursor/rules/permissions-guidance.mdc +37 -37
- package/.forge/hooks/check-tdd.js +240 -240
- package/.github/PLUGIN_TEMPLATE.json +32 -32
- package/.github/prompts/dev.prompt.md +342 -316
- package/.github/prompts/plan.prompt.md +523 -480
- package/.github/prompts/premerge.prompt.md +178 -181
- package/.github/prompts/research.prompt.md +44 -44
- package/.github/prompts/review.prompt.md +444 -444
- package/.github/prompts/rollback.prompt.md +723 -723
- package/.github/prompts/ship.prompt.md +166 -136
- package/.github/prompts/sonarcloud.prompt.md +151 -151
- package/.github/prompts/status.prompt.md +50 -79
- package/.github/prompts/validate.prompt.md +284 -239
- package/.github/prompts/verify.prompt.md +223 -223
- package/.github/workflows/beads-to-github.yml +56 -0
- package/.github/workflows/github-to-beads.yml +97 -0
- package/.kilocode/workflows/dev.md +341 -315
- package/.kilocode/workflows/plan.md +522 -479
- package/.kilocode/workflows/premerge.md +177 -180
- package/.kilocode/workflows/research.md +43 -43
- package/.kilocode/workflows/review.md +443 -443
- package/.kilocode/workflows/rollback.md +722 -722
- package/.kilocode/workflows/ship.md +165 -135
- package/.kilocode/workflows/sonarcloud.md +150 -150
- package/.kilocode/workflows/status.md +49 -78
- package/.kilocode/workflows/validate.md +283 -238
- package/.kilocode/workflows/verify.md +222 -222
- package/.mcp.json.example +12 -12
- package/.opencode/commands/dev.md +340 -314
- package/.opencode/commands/plan.md +521 -478
- package/.opencode/commands/premerge.md +176 -179
- package/.opencode/commands/research.md +42 -42
- package/.opencode/commands/review.md +442 -442
- package/.opencode/commands/rollback.md +721 -721
- package/.opencode/commands/ship.md +164 -134
- package/.opencode/commands/sonarcloud.md +149 -149
- package/.opencode/commands/status.md +48 -77
- package/.opencode/commands/validate.md +282 -237
- package/.opencode/commands/verify.md +221 -221
- package/.roo/commands/dev.md +341 -315
- package/.roo/commands/plan.md +522 -479
- package/.roo/commands/premerge.md +177 -180
- package/.roo/commands/research.md +43 -43
- package/.roo/commands/review.md +443 -443
- package/.roo/commands/rollback.md +722 -722
- package/.roo/commands/ship.md +165 -135
- package/.roo/commands/sonarcloud.md +150 -150
- package/.roo/commands/status.md +49 -78
- package/.roo/commands/validate.md +283 -238
- package/.roo/commands/verify.md +222 -222
- package/AGENTS.md +175 -169
- package/CLAUDE.md +100 -99
- package/LICENSE +21 -21
- package/README.md +429 -414
- package/bin/forge-cmd.js +313 -313
- package/bin/{forge-validate.js → forge-preflight.js} +309 -303
- package/bin/forge.js +4596 -4232
- package/docs/AGENT_INSTALL_PROMPT.md +342 -342
- package/docs/BEADS_GITHUB_SYNC.md +251 -0
- package/docs/ENHANCED_ONBOARDING.md +602 -602
- package/docs/EXAMPLES.md +482 -482
- package/docs/GREPTILE_SETUP.md +400 -400
- package/docs/MANUAL_REVIEW_GUIDE.md +106 -106
- package/docs/ROADMAP.md +359 -359
- package/docs/SETUP.md +663 -632
- package/docs/TOOLCHAIN.md +630 -630
- package/docs/VALIDATION.md +363 -363
- package/install.sh +40 -1058
- package/lefthook.yml +39 -39
- package/lib/agents/README.md +198 -198
- package/lib/agents/claude.plugin.json +28 -28
- package/lib/agents/cline.plugin.json +22 -22
- package/lib/agents/codex.plugin.json +19 -19
- package/lib/agents/copilot.plugin.json +24 -24
- package/lib/agents/cursor.plugin.json +25 -25
- package/lib/agents/kilocode.plugin.json +22 -22
- package/lib/agents/opencode.plugin.json +20 -20
- package/lib/agents/roo.plugin.json +23 -23
- package/lib/agents-config.js +2112 -2112
- package/lib/beads-health-check.js +143 -0
- package/lib/beads-setup.js +341 -0
- package/lib/beads-sync-scaffold.js +260 -0
- package/lib/commands/dev.js +513 -513
- package/lib/commands/plan.js +692 -692
- package/lib/commands/recommend.js +119 -119
- package/lib/commands/ship.js +377 -377
- package/lib/commands/status.js +378 -378
- package/lib/commands/validate.js +602 -602
- package/lib/context-merge.js +359 -359
- package/lib/dep-guard/analyzer.js +294 -294
- package/lib/dep-guard/behavior-detector.js +98 -98
- package/lib/dep-guard/contract-detector.js +162 -162
- package/lib/dep-guard/import-detector.js +498 -498
- package/lib/dep-guard/path-utils.js +13 -13
- package/lib/dep-guard/rubric.js +120 -120
- package/lib/dep-guard/task-parser.js +318 -318
- package/lib/detect-agent.js +191 -0
- package/lib/detect-worktree.js +47 -0
- package/lib/file-hash.js +26 -0
- package/lib/husky-migration.js +450 -0
- package/lib/lefthook-check.js +65 -0
- package/lib/pat-setup.js +207 -0
- package/lib/plugin-catalog.js +350 -350
- package/lib/plugin-manager.js +166 -166
- package/lib/plugin-recommender.js +141 -141
- package/lib/project-discovery.js +491 -491
- package/lib/setup-action-log.js +139 -0
- package/lib/setup-summary-renderer.js +106 -0
- package/lib/setup-utils.js +96 -0
- package/lib/setup.js +192 -118
- package/lib/smart-merge.js +64 -0
- package/lib/symlink-utils.js +81 -0
- package/lib/workflow-profiles.js +197 -197
- package/package.json +131 -129
- package/scripts/beads-context.sh +291 -0
- package/scripts/beads-context.test.js +563 -0
- package/scripts/behavioral-judge.sh +378 -0
- package/scripts/benchmark.js +85 -0
- package/scripts/branch-protection.js +183 -0
- package/scripts/check-agents.js +172 -0
- package/scripts/commitlint.js +42 -0
- package/scripts/conflict-detect.sh +323 -0
- package/scripts/dep-guard-analyze.js +71 -0
- package/scripts/dep-guard.sh +811 -0
- package/scripts/eval_win.py +249 -0
- package/scripts/file-index.sh +399 -0
- package/scripts/github-beads-sync/comment.mjs +64 -0
- package/scripts/github-beads-sync/config.mjs +148 -0
- package/scripts/github-beads-sync/github-api.mjs +131 -0
- package/scripts/github-beads-sync/index.mjs +332 -0
- package/scripts/github-beads-sync/label-mapper.mjs +54 -0
- package/scripts/github-beads-sync/mapping.mjs +78 -0
- package/scripts/github-beads-sync/reverse-sync-cli.mjs +31 -0
- package/scripts/github-beads-sync/reverse-sync.mjs +138 -0
- package/scripts/github-beads-sync/run-bd.mjs +159 -0
- package/scripts/github-beads-sync/sanitize.mjs +121 -0
- package/scripts/github-beads-sync.config.json +26 -0
- package/scripts/improve-command.js +375 -0
- package/scripts/lib/eval-runner.js +229 -0
- package/scripts/lib/eval-schema.js +135 -0
- package/scripts/lib/eval-storage.js +78 -0
- package/scripts/lib/grading.js +203 -0
- package/scripts/lib/transcript-parser.js +63 -0
- package/scripts/lint.js +47 -0
- package/scripts/migrate-to-bun-test.js +412 -0
- package/scripts/run-command-eval.js +236 -0
- package/scripts/smart-status.sh +782 -0
- package/scripts/sync-commands.js +571 -0
- package/scripts/sync-utils.sh +460 -0
- package/scripts/test-dashboard.js +123 -0
- package/scripts/test.js +44 -0
- package/scripts/validate.sh +94 -0
- package/skills/parallel-deep-research/SKILL.md +108 -108
- package/skills/parallel-deep-research/evals/README.md +27 -27
- package/skills/parallel-deep-research/evals/evals.json +62 -62
- package/skills/sonarcloud-analysis/SKILL.md +171 -171
- package/skills/sonarcloud-analysis/evals/README.md +27 -27
- package/skills/sonarcloud-analysis/evals/evals.json +50 -50
- package/skills/sonarcloud-analysis/references/api-reference.md +466 -466
- package/docs/WORKFLOW.md +0 -400
package/package.json
CHANGED
|
@@ -1,129 +1,131 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "forge-workflow",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "7-stage TDD workflow for ALL AI coding agents (Claude, Cursor, Cline, OpenCode, Copilot, Kilo Code, Roo Code, Codex)",
|
|
5
|
-
"bin": {
|
|
6
|
-
"forge": "bin/forge.js",
|
|
7
|
-
"forge-
|
|
8
|
-
},
|
|
9
|
-
"workspaces": [
|
|
10
|
-
"packages/*"
|
|
11
|
-
],
|
|
12
|
-
"scripts": {
|
|
13
|
-
"test": "bun test",
|
|
14
|
-
"test:setup": "bash test-env/automation/setup-fixtures.sh",
|
|
15
|
-
"test:all": "bun run test:setup && bun test",
|
|
16
|
-
"test:coverage": "c8 --check-coverage bun test",
|
|
17
|
-
"typecheck": "echo 'No TypeScript in project - skipping type check'",
|
|
18
|
-
"lint": "eslint .",
|
|
19
|
-
"check": "bash scripts/validate.sh",
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"test:
|
|
26
|
-
"test:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
"@commitlint/
|
|
39
|
-
"@
|
|
40
|
-
"@eslint
|
|
41
|
-
"@
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
|
|
69
|
-
"
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
"
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
".claude/
|
|
81
|
-
".claude/
|
|
82
|
-
".claude/
|
|
83
|
-
".
|
|
84
|
-
".
|
|
85
|
-
".
|
|
86
|
-
".
|
|
87
|
-
".
|
|
88
|
-
".
|
|
89
|
-
"
|
|
90
|
-
".github/prompts/",
|
|
91
|
-
".github/PLUGIN_TEMPLATE.json",
|
|
92
|
-
".
|
|
93
|
-
"
|
|
94
|
-
"
|
|
95
|
-
"
|
|
96
|
-
"
|
|
97
|
-
"
|
|
98
|
-
".
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
"
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
"
|
|
113
|
-
"
|
|
114
|
-
"
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
"
|
|
118
|
-
"
|
|
119
|
-
"
|
|
120
|
-
".
|
|
121
|
-
"
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
"
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "forge-workflow",
|
|
3
|
+
"version": "0.0.5",
|
|
4
|
+
"description": "7-stage TDD workflow for ALL AI coding agents (Claude, Cursor, Cline, OpenCode, Copilot, Kilo Code, Roo Code, Codex)",
|
|
5
|
+
"bin": {
|
|
6
|
+
"forge": "bin/forge.js",
|
|
7
|
+
"forge-preflight": "bin/forge-preflight.js"
|
|
8
|
+
},
|
|
9
|
+
"workspaces": [
|
|
10
|
+
"packages/*"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"test": "bun test",
|
|
14
|
+
"test:setup": "bash test-env/automation/setup-fixtures.sh",
|
|
15
|
+
"test:all": "bun run test:setup && bun test",
|
|
16
|
+
"test:coverage": "c8 --check-coverage bun test",
|
|
17
|
+
"typecheck": "echo 'No TypeScript in project - skipping type check'",
|
|
18
|
+
"lint": "eslint . --max-warnings 0",
|
|
19
|
+
"check": "bash scripts/validate.sh",
|
|
20
|
+
"prepare": "lefthook install || echo 'Note: lefthook not installed. Git hooks disabled. Run: bun add -d lefthook'",
|
|
21
|
+
"setup": "node ./bin/forge.js setup",
|
|
22
|
+
"help": "node ./bin/forge.js --help",
|
|
23
|
+
"validate:yaml": "find . \\( -name '*.yml' -o -name '*.yaml' \\) | grep -v node_modules | while IFS= read -r file; do echo \"Checking $file...\" && bun x js-yaml \"$file\" > /dev/null || exit 1; done",
|
|
24
|
+
"test:mutation": "npx stryker run",
|
|
25
|
+
"test:benchmark": "node scripts/benchmark.js",
|
|
26
|
+
"test:dashboard": "node scripts/test-dashboard.js"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"lefthook": "^1.0.0"
|
|
30
|
+
},
|
|
31
|
+
"peerDependenciesMeta": {
|
|
32
|
+
"lefthook": {
|
|
33
|
+
"optional": true
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@commitlint/cli": "^20.4.1",
|
|
38
|
+
"@commitlint/config-conventional": "^20.4.1",
|
|
39
|
+
"@eslint/js": "^10.0.1",
|
|
40
|
+
"@microsoft/eslint-formatter-sarif": "^3.1.0",
|
|
41
|
+
"@stryker-mutator/core": "^9.6.0",
|
|
42
|
+
"c8": "^11.0.0",
|
|
43
|
+
"eslint": "^10.0.2",
|
|
44
|
+
"globals": "^17.3.0",
|
|
45
|
+
"js-yaml": "^4.1.1",
|
|
46
|
+
"lefthook": "^1.10.1",
|
|
47
|
+
"yaml": "^2.8.2"
|
|
48
|
+
},
|
|
49
|
+
"keywords": [
|
|
50
|
+
"ai",
|
|
51
|
+
"workflow",
|
|
52
|
+
"tdd",
|
|
53
|
+
"agents-md",
|
|
54
|
+
"claude-code",
|
|
55
|
+
"cursor",
|
|
56
|
+
"kilo-code",
|
|
57
|
+
"opencode",
|
|
58
|
+
"copilot",
|
|
59
|
+
"cline",
|
|
60
|
+
"roo-code",
|
|
61
|
+
"codex",
|
|
62
|
+
"development",
|
|
63
|
+
"testing"
|
|
64
|
+
],
|
|
65
|
+
"author": "Harsha Nandak",
|
|
66
|
+
"license": "MIT",
|
|
67
|
+
"repository": {
|
|
68
|
+
"type": "git",
|
|
69
|
+
"url": "git+https://github.com/harshanandak/forge.git"
|
|
70
|
+
},
|
|
71
|
+
"homepage": "https://github.com/harshanandak/forge#readme",
|
|
72
|
+
"bugs": {
|
|
73
|
+
"url": "https://github.com/harshanandak/forge/issues"
|
|
74
|
+
},
|
|
75
|
+
"files": [
|
|
76
|
+
"bin/",
|
|
77
|
+
"lib/",
|
|
78
|
+
"skills/",
|
|
79
|
+
".claude/commands/",
|
|
80
|
+
".claude/rules/",
|
|
81
|
+
".claude/scripts/",
|
|
82
|
+
".claude/skills/",
|
|
83
|
+
".cursor/",
|
|
84
|
+
".cline/",
|
|
85
|
+
".roo/",
|
|
86
|
+
".codex/",
|
|
87
|
+
".kilocode/",
|
|
88
|
+
".opencode/",
|
|
89
|
+
"scripts/",
|
|
90
|
+
".github/prompts/",
|
|
91
|
+
".github/PLUGIN_TEMPLATE.json",
|
|
92
|
+
".github/workflows/github-to-beads.yml",
|
|
93
|
+
".github/workflows/beads-to-github.yml",
|
|
94
|
+
".forge/hooks/",
|
|
95
|
+
"docs/*.md",
|
|
96
|
+
"install.sh",
|
|
97
|
+
"lefthook.yml",
|
|
98
|
+
"AGENTS.md",
|
|
99
|
+
"CLAUDE.md",
|
|
100
|
+
".mcp.json.example"
|
|
101
|
+
],
|
|
102
|
+
"dependencies": {
|
|
103
|
+
"@babel/parser": "^7.29.2",
|
|
104
|
+
"fastest-levenshtein": "^1.0.16"
|
|
105
|
+
},
|
|
106
|
+
"overrides": {
|
|
107
|
+
"eslint": "^10.0.2",
|
|
108
|
+
"flatted": "3.4.2",
|
|
109
|
+
"minimatch": "10.2.4"
|
|
110
|
+
},
|
|
111
|
+
"c8": {
|
|
112
|
+
"lines": 80,
|
|
113
|
+
"branches": 80,
|
|
114
|
+
"functions": 80,
|
|
115
|
+
"statements": 80,
|
|
116
|
+
"exclude": [
|
|
117
|
+
"test/**",
|
|
118
|
+
"test-env/**",
|
|
119
|
+
"**/*.test.js",
|
|
120
|
+
"**/*.spec.js",
|
|
121
|
+
"coverage/**",
|
|
122
|
+
".forge/hooks/**",
|
|
123
|
+
"bin/forge.js"
|
|
124
|
+
],
|
|
125
|
+
"reporter": [
|
|
126
|
+
"text",
|
|
127
|
+
"lcov",
|
|
128
|
+
"html"
|
|
129
|
+
]
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# beads-context.sh — Helper script to manage Beads issue context
|
|
3
|
+
# for the Forge 7-stage workflow.
|
|
4
|
+
#
|
|
5
|
+
# Subcommands:
|
|
6
|
+
# set-design <issue-id> <task-count> <task-file-path>
|
|
7
|
+
# set-acceptance <issue-id> "<criteria-text>"
|
|
8
|
+
# update-progress <issue-id> <task-num> <total> "<title>" <commit-sha> <test-count> <gate-count>
|
|
9
|
+
# parse-progress <issue-id>
|
|
10
|
+
# stage-transition <issue-id> <completed-stage> <next-stage>
|
|
11
|
+
#
|
|
12
|
+
# Cross-platform: works on Windows (Git Bash), macOS, and Linux.
|
|
13
|
+
# OWASP A03: All variables properly quoted to prevent shell injection.
|
|
14
|
+
|
|
15
|
+
set -euo pipefail
|
|
16
|
+
|
|
17
|
+
# ── Helpers ──────────────────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
usage() {
|
|
20
|
+
cat >&2 <<'EOF'
|
|
21
|
+
Usage: beads-context.sh <subcommand> [args...]
|
|
22
|
+
|
|
23
|
+
Subcommands:
|
|
24
|
+
set-design <issue-id> <task-count> <task-file-path>
|
|
25
|
+
set-acceptance <issue-id> "<criteria-text>"
|
|
26
|
+
update-progress <issue-id> <task-num> <total> "<title>" <commit-sha> <test-count> <gate-count>
|
|
27
|
+
parse-progress <issue-id>
|
|
28
|
+
stage-transition <issue-id> <completed-stage> <next-stage>
|
|
29
|
+
EOF
|
|
30
|
+
exit 1
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
die() {
|
|
34
|
+
echo "Error: $1" >&2
|
|
35
|
+
exit 1
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
# Sanitize a string: strip shell-injection patterns (OWASP A03)
|
|
39
|
+
# Removes: double quotes, $(...), backticks, semicolons, and newlines
|
|
40
|
+
sanitize() {
|
|
41
|
+
local val="$1"
|
|
42
|
+
# Remove double quotes
|
|
43
|
+
val="${val//\"/}"
|
|
44
|
+
# Remove $(...) command substitution patterns (loop handles nested)
|
|
45
|
+
# Use newline-separated commands for BSD sed compatibility (macOS)
|
|
46
|
+
val="$(printf '%s' "$val" | sed -e ':loop' -e 's/\$([^()]*)//g' -e 't loop')"
|
|
47
|
+
# Remove backtick command substitution
|
|
48
|
+
val="${val//\`/}"
|
|
49
|
+
# Remove semicolons (command chaining)
|
|
50
|
+
val="${val//;/}"
|
|
51
|
+
# Replace newlines with spaces
|
|
52
|
+
val="$(printf '%s' "$val" | tr '\n' ' ')"
|
|
53
|
+
printf '%s' "$val"
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
# Run bd update and check for errors in both exit code and output.
|
|
57
|
+
# bd update exits 0 even for non-existent issues, so we check stdout too.
|
|
58
|
+
bd_update() {
|
|
59
|
+
local output
|
|
60
|
+
output="$(bd update "$@" 2>&1)"
|
|
61
|
+
local rc=$?
|
|
62
|
+
|
|
63
|
+
if [[ $rc -ne 0 ]]; then
|
|
64
|
+
echo "$output" >&2
|
|
65
|
+
return 1
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
# bd prints "Error resolving/updating ..." to stdout for non-existent issues
|
|
69
|
+
# Use specific patterns to avoid false positives from data containing "error"
|
|
70
|
+
if printf '%s' "$output" | grep -Eqi '^Error|Error resolving|Error updating'; then
|
|
71
|
+
echo "$output" >&2
|
|
72
|
+
return 1
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
echo "$output"
|
|
76
|
+
return 0
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
# Run bd comments add and check for errors similarly.
|
|
80
|
+
bd_comment() {
|
|
81
|
+
local output
|
|
82
|
+
output="$(bd comments add "$@" 2>&1)"
|
|
83
|
+
local rc=$?
|
|
84
|
+
|
|
85
|
+
if [[ $rc -ne 0 ]]; then
|
|
86
|
+
echo "$output" >&2
|
|
87
|
+
return 1
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
# Use specific error patterns to avoid false positives from data containing "error"
|
|
91
|
+
if printf '%s' "$output" | grep -Eqi '^Error|Error resolving|Error adding'; then
|
|
92
|
+
echo "$output" >&2
|
|
93
|
+
return 1
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
echo "$output"
|
|
97
|
+
return 0
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
# ── Subcommands ──────────────────────────────────────────────────────────
|
|
101
|
+
|
|
102
|
+
cmd_set_design() {
|
|
103
|
+
if [[ $# -lt 3 ]]; then
|
|
104
|
+
echo "Usage: beads-context.sh set-design <issue-id> <task-count> <task-file-path>" >&2
|
|
105
|
+
exit 1
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
local issue_id="$1"
|
|
109
|
+
local task_count
|
|
110
|
+
task_count="$(sanitize "$2")"
|
|
111
|
+
local task_file
|
|
112
|
+
task_file="$(sanitize "$3")"
|
|
113
|
+
|
|
114
|
+
local design_text="${task_count} tasks | ${task_file}"
|
|
115
|
+
|
|
116
|
+
if ! bd_update "$issue_id" --design "$design_text" > /dev/null; then
|
|
117
|
+
die "Failed to set design on issue ${issue_id}"
|
|
118
|
+
fi
|
|
119
|
+
|
|
120
|
+
echo "Design set on ${issue_id}: ${design_text}"
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
cmd_set_acceptance() {
|
|
124
|
+
if [[ $# -lt 2 ]]; then
|
|
125
|
+
echo "Usage: beads-context.sh set-acceptance <issue-id> \"<criteria-text>\"" >&2
|
|
126
|
+
exit 1
|
|
127
|
+
fi
|
|
128
|
+
|
|
129
|
+
local issue_id="$1"
|
|
130
|
+
local criteria
|
|
131
|
+
criteria="$(sanitize "$2")"
|
|
132
|
+
|
|
133
|
+
if ! bd_update "$issue_id" --acceptance "$criteria" > /dev/null; then
|
|
134
|
+
die "Failed to set acceptance on issue ${issue_id}"
|
|
135
|
+
fi
|
|
136
|
+
|
|
137
|
+
echo "Acceptance criteria set on ${issue_id}"
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
cmd_update_progress() {
|
|
141
|
+
if [[ $# -lt 7 ]]; then
|
|
142
|
+
echo "Usage: beads-context.sh update-progress <issue-id> <task-num> <total> \"<title>\" <commit-sha> <test-count> <gate-count>" >&2
|
|
143
|
+
exit 1
|
|
144
|
+
fi
|
|
145
|
+
|
|
146
|
+
local issue_id="$1"
|
|
147
|
+
local task_num
|
|
148
|
+
task_num="$(sanitize "$2")"
|
|
149
|
+
local total
|
|
150
|
+
total="$(sanitize "$3")"
|
|
151
|
+
local title
|
|
152
|
+
title="$(sanitize "$4")"
|
|
153
|
+
local commit_sha
|
|
154
|
+
commit_sha="$(sanitize "$5")"
|
|
155
|
+
local test_count
|
|
156
|
+
test_count="$(sanitize "$6")"
|
|
157
|
+
local gate_count
|
|
158
|
+
gate_count="$(sanitize "$7")"
|
|
159
|
+
|
|
160
|
+
# Strip backslashes from progress fields only — these are read back via
|
|
161
|
+
# printf '%b' in parse-progress, where \n/\t would expand into real escapes.
|
|
162
|
+
# Other commands (set-design, set-acceptance, stage-transition) keep backslashes
|
|
163
|
+
# intact to preserve Windows-style paths like docs\plans\tasks.md.
|
|
164
|
+
task_num="${task_num//\\/}"
|
|
165
|
+
total="${total//\\/}"
|
|
166
|
+
title="${title//\\/}"
|
|
167
|
+
commit_sha="${commit_sha//\\/}"
|
|
168
|
+
test_count="${test_count//\\/}"
|
|
169
|
+
gate_count="${gate_count//\\/}"
|
|
170
|
+
|
|
171
|
+
local note="Task ${task_num}/${total} done: ${title} | ${test_count} tests | ${commit_sha} | ${gate_count} gates"
|
|
172
|
+
|
|
173
|
+
if ! bd_update "$issue_id" --append-notes "$note" > /dev/null; then
|
|
174
|
+
die "Failed to update progress on issue ${issue_id}"
|
|
175
|
+
fi
|
|
176
|
+
|
|
177
|
+
echo "Progress updated on ${issue_id}: Task ${task_num}/${total}"
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
cmd_parse_progress() {
|
|
181
|
+
if [[ $# -lt 1 ]]; then
|
|
182
|
+
echo "Usage: beads-context.sh parse-progress <issue-id>" >&2
|
|
183
|
+
exit 1
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
local issue_id="$1"
|
|
187
|
+
|
|
188
|
+
# Get the issue JSON — detect non-existent issues
|
|
189
|
+
local json
|
|
190
|
+
json="$(bd show "$issue_id" --json 2>&1)" || die "Failed to show issue ${issue_id}"
|
|
191
|
+
|
|
192
|
+
# bd show may exit 0 but print an error for non-existent issues
|
|
193
|
+
# Match specific bd error patterns, not the word "error" in data fields
|
|
194
|
+
if printf '%s' "$json" | grep -Eqi '^Error (fetching|resolving)'; then
|
|
195
|
+
die "Issue not found: ${issue_id}"
|
|
196
|
+
fi
|
|
197
|
+
|
|
198
|
+
# bd show returns "[]" or empty for non-existent issues
|
|
199
|
+
if [[ -z "$json" || "$json" == "[]" || "$json" == "null" ]]; then
|
|
200
|
+
die "Issue not found: ${issue_id}"
|
|
201
|
+
fi
|
|
202
|
+
|
|
203
|
+
# Extract notes field from JSON — prefer jq if available, fall back to grep/sed
|
|
204
|
+
local notes
|
|
205
|
+
if command -v jq &>/dev/null; then
|
|
206
|
+
# Handle both array ([{...}]) and object ({...}) responses from bd show
|
|
207
|
+
notes="$(printf '%s' "$json" | jq -r 'if type == "array" then .[0].notes else .notes end // empty' 2>/dev/null || true)"
|
|
208
|
+
else
|
|
209
|
+
notes="$(printf '%s' "$json" | grep -o '"notes": *"[^"]*"' | head -1 | sed 's/^"notes": *"//;s/"$//' || true)"
|
|
210
|
+
fi
|
|
211
|
+
|
|
212
|
+
if [[ -z "$notes" ]]; then
|
|
213
|
+
echo "No progress data"
|
|
214
|
+
return 0
|
|
215
|
+
fi
|
|
216
|
+
|
|
217
|
+
# Split on literal \n (two chars: backslash + n) and count task lines
|
|
218
|
+
# Use printf to expand the \n into actual newlines for grep (POSIX-compliant)
|
|
219
|
+
local expanded
|
|
220
|
+
expanded="$(printf '%b' "$notes")"
|
|
221
|
+
|
|
222
|
+
local task_lines
|
|
223
|
+
task_lines="$(echo "$expanded" | grep -c 'Task [0-9]*/[0-9]* done:' || true)"
|
|
224
|
+
|
|
225
|
+
if [[ "$task_lines" -eq 0 ]]; then
|
|
226
|
+
echo "No progress data"
|
|
227
|
+
return 0
|
|
228
|
+
fi
|
|
229
|
+
|
|
230
|
+
# Get the last task line
|
|
231
|
+
local last_line
|
|
232
|
+
last_line="$(echo "$expanded" | grep 'Task [0-9]*/[0-9]* done:' | tail -1 || true)"
|
|
233
|
+
|
|
234
|
+
# Extract total (N/M) from last line
|
|
235
|
+
local total
|
|
236
|
+
total="$(echo "$last_line" | grep -o '[0-9]*/[0-9]*' | head -1 | cut -d/ -f2)"
|
|
237
|
+
|
|
238
|
+
# Extract last task title (between "done: " and " |")
|
|
239
|
+
local last_title
|
|
240
|
+
last_title="$(echo "$last_line" | sed 's/.*done: //;s/ |.*//')"
|
|
241
|
+
|
|
242
|
+
# Extract commit sha — 4th pipe-separated field
|
|
243
|
+
# Format: "Task N/M done: <title> | <test_count> tests | <sha> | <gate_count> gates"
|
|
244
|
+
local last_sha
|
|
245
|
+
# Use [|] character class for portable literal pipe matching across gawk and BSD awk
|
|
246
|
+
last_sha="$(echo "$last_line" | awk -F ' [|] ' '{print $3}' | sed 's/^ *//;s/ *$//')"
|
|
247
|
+
|
|
248
|
+
echo "${task_lines}/${total} tasks done | Last: ${last_title} (${last_sha})"
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
cmd_stage_transition() {
|
|
252
|
+
if [[ $# -lt 3 ]]; then
|
|
253
|
+
echo "Usage: beads-context.sh stage-transition <issue-id> <completed-stage> <next-stage>" >&2
|
|
254
|
+
exit 1
|
|
255
|
+
fi
|
|
256
|
+
|
|
257
|
+
local issue_id="$1"
|
|
258
|
+
local completed
|
|
259
|
+
completed="$(sanitize "$2")"
|
|
260
|
+
local next
|
|
261
|
+
next="$(sanitize "$3")"
|
|
262
|
+
|
|
263
|
+
local comment="Stage: ${completed} complete → ready for ${next}"
|
|
264
|
+
|
|
265
|
+
if ! bd_comment "$issue_id" "$comment" > /dev/null; then
|
|
266
|
+
die "Failed to record stage transition on issue ${issue_id}"
|
|
267
|
+
fi
|
|
268
|
+
|
|
269
|
+
echo "Stage transition recorded on ${issue_id}: ${completed} → ${next}"
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
# ── Main dispatcher ──────────────────────────────────────────────────────
|
|
273
|
+
|
|
274
|
+
if [[ $# -lt 1 ]]; then
|
|
275
|
+
usage
|
|
276
|
+
fi
|
|
277
|
+
|
|
278
|
+
subcommand="$1"
|
|
279
|
+
shift
|
|
280
|
+
|
|
281
|
+
case "$subcommand" in
|
|
282
|
+
set-design) cmd_set_design "$@" ;;
|
|
283
|
+
set-acceptance) cmd_set_acceptance "$@" ;;
|
|
284
|
+
update-progress) cmd_update_progress "$@" ;;
|
|
285
|
+
parse-progress) cmd_parse_progress "$@" ;;
|
|
286
|
+
stage-transition) cmd_stage_transition "$@" ;;
|
|
287
|
+
*)
|
|
288
|
+
echo "Error: Unknown subcommand '${subcommand}'" >&2
|
|
289
|
+
usage
|
|
290
|
+
;;
|
|
291
|
+
esac
|