forge-workflow 0.1.0-beta.4 → 0.1.0-beta.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.
Files changed (119) hide show
  1. package/AGENTS.md +14 -7
  2. package/CHANGELOG.md +43 -1
  3. package/README.md +6 -2
  4. package/bin/forge-cmd.js +20 -0
  5. package/bin/forge.js +16 -374
  6. package/docs/INDEX.md +1 -1
  7. package/docs/guides/BEADS_GITHUB_SYNC.md +2 -31
  8. package/docs/guides/MIGRATION.md +4 -4
  9. package/docs/guides/SETUP.md +16 -16
  10. package/docs/reference/COMMANDS.md +8 -5
  11. package/docs/reference/INSIGHTS_RECAP.md +9 -20
  12. package/docs/reference/RELEASE.md +5 -3
  13. package/docs/reference/TOOLCHAIN.md +8 -0
  14. package/docs/reference/protected-state-surfaces.md +4 -4
  15. package/docs/reference/shepherd.md +54 -25
  16. package/lefthook.yml +12 -0
  17. package/lib/activation/ensure-forge-home.js +33 -15
  18. package/lib/adapters/pr-state-adapter.js +344 -142
  19. package/lib/audit-evidence.js +71 -110
  20. package/lib/capped-jsonl-log.js +236 -0
  21. package/lib/commands/_registry.js +2 -2
  22. package/lib/commands/clean.js +196 -32
  23. package/lib/commands/dev.js +4 -33
  24. package/lib/commands/hooks.js +223 -25
  25. package/lib/commands/insights.js +8 -3
  26. package/lib/commands/merge.js +600 -40
  27. package/lib/commands/pr.js +1 -1
  28. package/lib/commands/preflight.js +11 -2
  29. package/lib/commands/prime.js +21 -8
  30. package/lib/commands/push.js +41 -51
  31. package/lib/commands/recall.js +60 -16
  32. package/lib/commands/recap.js +6 -1
  33. package/lib/commands/release.js +17 -2
  34. package/lib/commands/setup.js +191 -94
  35. package/lib/commands/shepherd.js +13 -1
  36. package/lib/commands/ship.js +22 -23
  37. package/lib/commands/skill.js +119 -11
  38. package/lib/commands/status.js +17 -1
  39. package/lib/commands/test.js +24 -34
  40. package/lib/commands/worktree.js +220 -42
  41. package/lib/core/runtime-graph.js +1 -1
  42. package/lib/doc-assertions.js +297 -0
  43. package/lib/existing-tdd-gate.js +253 -0
  44. package/lib/forge-context.js +1 -4
  45. package/lib/forge-issues.js +56 -32
  46. package/lib/git-defaults.js +56 -0
  47. package/lib/harness-capability-matrix.js +3 -3
  48. package/lib/hook-renderer.js +93 -4
  49. package/lib/insights.js +96 -80
  50. package/lib/kernel/backing-issue.js +14 -2
  51. package/lib/kernel/broker.js +16 -0
  52. package/lib/kernel/cli-broker-factory.js +12 -1
  53. package/lib/kernel/close-on-merge.js +154 -0
  54. package/lib/kernel/fs-class.js +42 -25
  55. package/lib/kernel/sqlite-driver.js +153 -29
  56. package/lib/lefthook-wiring.js +21 -1
  57. package/lib/memory/router.js +16 -1
  58. package/lib/memory-digest.js +47 -15
  59. package/lib/memory-recall-events.js +145 -0
  60. package/lib/memory-recall.js +71 -10
  61. package/lib/merge-rules.js +8 -4
  62. package/lib/npm-publish-workflow.js +272 -0
  63. package/lib/orientation.js +68 -43
  64. package/lib/plugin-catalog.js +14 -4
  65. package/lib/pr-bundle.js +5 -6
  66. package/lib/pr-monitor/journal.js +18 -2
  67. package/lib/pr-monitor/reconcile-executor.js +224 -41
  68. package/lib/pr-monitor/render-summary.js +196 -0
  69. package/lib/pr-monitor/shepherd-lease.js +10 -1
  70. package/lib/pr-monitor/watch-lifecycle.js +13 -1
  71. package/lib/pr-pull.js +33 -14
  72. package/lib/pr-shepherd.js +34 -8
  73. package/lib/preflight/gates.js +65 -18
  74. package/lib/preflight/runner.js +5 -0
  75. package/lib/project-memory.js +33 -1
  76. package/lib/protected-state-authority.js +305 -0
  77. package/lib/protected-state-surfaces.js +64 -44
  78. package/lib/release-readiness.js +51 -4
  79. package/lib/shell-utils.js +1 -1
  80. package/lib/skills-sync.js +6 -3
  81. package/lib/smart-merge.js +28 -4
  82. package/lib/symlink-utils.js +74 -26
  83. package/lib/upgrade-safety.js +39 -0
  84. package/lib/using-forge.js +19 -6
  85. package/package.json +6 -7
  86. package/scripts/doc-asserting-tests.js +158 -0
  87. package/scripts/lib/behavioral-eval-runner.js +310 -0
  88. package/scripts/lib/behavioral-eval-runtime.js +456 -0
  89. package/scripts/lib/eval-evidence.js +328 -0
  90. package/scripts/lib/eval-runner.js +81 -41
  91. package/scripts/lib/immutable-eval-corpus.js +309 -0
  92. package/scripts/lib/promotion-evidence-loader.js +94 -0
  93. package/scripts/lib/promotion-scorecard.js +314 -0
  94. package/scripts/npm-release-receipt.js +134 -0
  95. package/scripts/process-tree.js +761 -0
  96. package/scripts/protected-state-check.js +47 -22
  97. package/scripts/run-command-eval.js +29 -1
  98. package/scripts/sync-d20-audit.js +172 -0
  99. package/scripts/test-full-suite.js +249 -37
  100. package/scripts/test.js +176 -43
  101. package/skills/review/SKILL.md +4 -11
  102. package/skills/review/evals/scorecard.json +3 -3
  103. package/skills/rollback/SKILL.md +4 -11
  104. package/skills/rollback/evals/scorecard.json +3 -3
  105. package/skills/shepherd/SKILL.md +20 -14
  106. package/skills/shepherd/evals/scorecard.json +2 -2
  107. package/skills/ship/SKILL.md +4 -12
  108. package/skills/ship/evals/scorecard.json +3 -3
  109. package/skills/worktree/SKILL.md +6 -1
  110. package/skills/worktree/evals/scorecard.json +2 -2
  111. package/lib/beads-setup.js +0 -538
  112. package/lib/beads-sync-scaffold.js +0 -189
  113. package/lib/pat-setup.js +0 -207
  114. package/lib/pr-monitor/render-sticky.js +0 -206
  115. package/lib/pr-monitor/upsert-sticky.js +0 -169
  116. package/scripts/beads-context.sh +0 -577
  117. package/scripts/beads-migrate-to-dolt.sh +0 -7
  118. package/scripts/beads-upgrade-smoke.sh +0 -284
  119. package/scripts/lib/beads-migrate-to-dolt.mjs +0 -503
@@ -1,284 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- _BEADS_UPGRADE_SMOKE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
- if [[ -f "$_BEADS_UPGRADE_SMOKE_DIR/bootstrap-windows-tools.sh" ]]; then
6
- source "$_BEADS_UPGRADE_SMOKE_DIR/bootstrap-windows-tools.sh"
7
- fi
8
-
9
- BD_CMD="${BD_CMD:-bd}"
10
- NODE_CMD="${NODE_CMD:-node}"
11
- PROJECT_ROOT="${PROJECT_ROOT:-$(pwd)}"
12
- ARTIFACT_DIR="${BEADS_UPGRADE_SMOKE_ARTIFACT_DIR:-${PROJECT_ROOT}/.artifacts/beads-upgrade-smoke}"
13
- COMMAND_LOG_PATH="${ARTIFACT_DIR}/commands.jsonl"
14
- SUMMARY_PATH="${ARTIFACT_DIR}/summary.json"
15
- CLEANUP_REASON="Beads upgrade smoke cleanup"
16
- SMOKE_RUN_ID="${BEADS_UPGRADE_SMOKE_RUN_ID:-$(date +%s)-$$}"
17
- PRIMARY_ISSUE_TITLE="Beads upgrade smoke primary (${SMOKE_RUN_ID})"
18
- DEPENDENT_ISSUE_TITLE="Beads upgrade smoke dependent (${SMOKE_RUN_ID})"
19
-
20
- node_fs_path() {
21
- case "$1" in
22
- /[A-Za-z]/*)
23
- _drive="$(printf '%s' "${1:1:1}" | tr '[:lower:]' '[:upper:]')"
24
- printf '%s:/%s\n' "$_drive" "${1:3}"
25
- ;;
26
- *)
27
- if command -v cygpath >/dev/null 2>&1; then
28
- cygpath -m "$1"
29
- else
30
- printf '%s\n' "$1"
31
- fi
32
- ;;
33
- esac
34
- }
35
-
36
- mkdir -p "${ARTIFACT_DIR}"
37
- : > "${COMMAND_LOG_PATH}"
38
-
39
- created_issue_ids=()
40
- closed_issue_ids=()
41
- failed_step=""
42
- failure_message=""
43
-
44
- parse_issue_id() {
45
- local output="$1"
46
- if [[ "${output}" =~ Created[[:space:]]+issue:[[:space:]]*([[:alnum:]-]+) ]]; then
47
- printf '%s' "${BASH_REMATCH[1]}"
48
- return 0
49
- fi
50
- if [[ "${output}" =~ \"id\"[[:space:]]*:[[:space:]]*\"([[:alnum:]-]+)\" ]]; then
51
- printf '%s' "${BASH_REMATCH[1]}"
52
- return 0
53
- fi
54
- return 1
55
- }
56
-
57
- find_issue_id_by_title() {
58
- local issue_title="$1"
59
- local list_output
60
- list_output="$("${BD_CMD}" list --json --limit=50 2>/dev/null)" || return 1
61
-
62
- "${NODE_CMD}" -e '
63
- const fs = require("node:fs");
64
- const [issueTitle] = process.argv.slice(1);
65
- try {
66
- const rows = JSON.parse(fs.readFileSync(0, "utf8"));
67
- if (!Array.isArray(rows)) {
68
- process.exit(1);
69
- }
70
- const match = rows.find((row) => row && row.title === issueTitle && typeof row.id === "string");
71
- if (!match) {
72
- process.exit(1);
73
- }
74
- process.stdout.write(match.id);
75
- } catch {
76
- process.exit(1);
77
- }
78
- ' "${issue_title}" <<< "${list_output}"
79
- }
80
-
81
- append_command() {
82
- local step="$1"
83
- local command_name="$2"
84
- local command_text="$3"
85
- local exit_code="$4"
86
- local stdout_path="$5"
87
- local stderr_path="$6"
88
-
89
- "${NODE_CMD}" -e '
90
- const fs = require("node:fs");
91
- const [logPath, step, commandName, commandText, exitCode, stdoutPath, stderrPath] = process.argv.slice(1);
92
- const entry = {
93
- step,
94
- commandName,
95
- commandText,
96
- exitCode: Number(exitCode),
97
- stdoutPath,
98
- stderrPath,
99
- };
100
- fs.appendFileSync(logPath, JSON.stringify(entry) + "\n");
101
- ' "$(node_fs_path "${COMMAND_LOG_PATH}")" "${step}" "${command_name}" "${command_text}" "${exit_code}" "$(node_fs_path "${stdout_path}")" "$(node_fs_path "${stderr_path}")"
102
- }
103
-
104
- read_output_snippet() {
105
- local file_path="$1"
106
- if [[ ! -f "${file_path}" ]]; then
107
- return 0
108
- fi
109
-
110
- "${NODE_CMD}" -e '
111
- const fs = require("node:fs");
112
- const [filePath] = process.argv.slice(1);
113
- const text = fs.readFileSync(filePath, "utf8");
114
- process.stdout.write(text.slice(0, 4096));
115
- ' "$(node_fs_path "${file_path}")"
116
- }
117
-
118
- write_summary() {
119
- local ok="$1"
120
-
121
- "${NODE_CMD}" -e '
122
- const fs = require("node:fs");
123
- const [
124
- commandLogPath,
125
- summaryPath,
126
- okValue,
127
- failedStep,
128
- failureMessage,
129
- artifactDir,
130
- createdJson,
131
- closedJson,
132
- ] = process.argv.slice(1);
133
- const commands = fs.readFileSync(commandLogPath, "utf8")
134
- .split(/\r?\n/)
135
- .filter(Boolean)
136
- .map((line) => JSON.parse(line));
137
- const summary = {
138
- ok: okValue === "true",
139
- failedStep: failedStep || null,
140
- failureMessage: failureMessage || null,
141
- commands,
142
- cleanup: {
143
- createdIssueIds: JSON.parse(createdJson),
144
- closedIssueIds: JSON.parse(closedJson),
145
- },
146
- failureArtifact: summaryPath,
147
- artifactDir,
148
- };
149
- fs.writeFileSync(summaryPath, JSON.stringify(summary, null, 2) + "\n");
150
- ' "$(node_fs_path "${COMMAND_LOG_PATH}")" "$(node_fs_path "${SUMMARY_PATH}")" "${ok}" "${failed_step}" "${failure_message}" "$(node_fs_path "${ARTIFACT_DIR}")" "$(printf '%s\n' "${created_issue_ids[@]:-}" | "${NODE_CMD}" -e 'const fs=require("node:fs"); const lines=fs.readFileSync(0,"utf8").split(/\r?\n/).filter(Boolean); process.stdout.write(JSON.stringify(lines));')" "$(printf '%s\n' "${closed_issue_ids[@]:-}" | "${NODE_CMD}" -e 'const fs=require("node:fs"); const lines=fs.readFileSync(0,"utf8").split(/\r?\n/).filter(Boolean); process.stdout.write(JSON.stringify(lines));')"
151
- }
152
-
153
- run_bd_step() {
154
- local step="$1"
155
- local command_name="$2"
156
- shift 2
157
-
158
- local stdout_file stderr_file exit_code command_text
159
- stdout_file="${ARTIFACT_DIR}/$(printf '%s' "${step}" | tr '[:upper:]' '[:lower:]').stdout"
160
- stderr_file="${ARTIFACT_DIR}/$(printf '%s' "${step}" | tr '[:upper:]' '[:lower:]').stderr"
161
- command_text="$*"
162
-
163
- if "${BD_CMD}" "$@" >"${stdout_file}" 2>"${stderr_file}"; then
164
- exit_code=0
165
- else
166
- exit_code=$?
167
- fi
168
-
169
- append_command "${step}" "${command_name}" "${command_text}" "${exit_code}" "${stdout_file}" "${stderr_file}"
170
-
171
- if [[ "${exit_code}" -ne 0 ]]; then
172
- failed_step="${command_name}"
173
- local stderr_text stdout_text
174
- stderr_text="$(read_output_snippet "${stderr_file}")"
175
- stdout_text="$(read_output_snippet "${stdout_file}")"
176
- failure_message="${stderr_text:-${stdout_text:-${command_text}}}"
177
- return "${exit_code}"
178
- fi
179
-
180
- cat "${stdout_file}"
181
- }
182
-
183
- is_closed_issue() {
184
- local issue_id="$1"
185
- local existing
186
- for existing in "${closed_issue_ids[@]:-}"; do
187
- if [[ "${existing}" == "${issue_id}" ]]; then
188
- return 0
189
- fi
190
- done
191
- return 1
192
- }
193
-
194
- rollback_unclosed_issues() {
195
- local idx issue_id
196
- for (( idx=${#created_issue_ids[@]} - 1; idx>=0; idx-- )); do
197
- issue_id="${created_issue_ids[idx]}"
198
- if is_closed_issue "${issue_id}"; then
199
- continue
200
- fi
201
- if run_bd_step "rollback-close-${issue_id}" "close" close "${issue_id}" "--reason=${CLEANUP_REASON}" >/dev/null; then
202
- closed_issue_ids+=("${issue_id}")
203
- fi
204
- done
205
- }
206
-
207
- handle_issue_id_parse_failure() {
208
- local issue_title="$1"
209
- local message="$2"
210
- local recovered_issue_id=""
211
-
212
- failed_step="create"
213
- failure_message="${message}"
214
-
215
- recovered_issue_id="$(find_issue_id_by_title "${issue_title}" || true)"
216
- if [[ -n "${recovered_issue_id}" ]]; then
217
- created_issue_ids+=("${recovered_issue_id}")
218
- fi
219
-
220
- rollback_unclosed_issues
221
- write_summary "false"
222
- exit 1
223
- }
224
-
225
- primary_output="$(run_bd_step "create-primary" "create" create --title="${PRIMARY_ISSUE_TITLE}" --type=task --priority=4)" || {
226
- rollback_unclosed_issues
227
- write_summary "false"
228
- exit 1
229
- }
230
- primary_issue_id="$(parse_issue_id "${primary_output}")" || {
231
- handle_issue_id_parse_failure "${PRIMARY_ISSUE_TITLE}" "Could not parse primary smoke issue ID"
232
- }
233
- created_issue_ids+=("${primary_issue_id}")
234
-
235
- dependent_output="$(run_bd_step "create-dependent" "create" create --title="${DEPENDENT_ISSUE_TITLE}" --type=task --priority=4)" || {
236
- rollback_unclosed_issues
237
- write_summary "false"
238
- exit 1
239
- }
240
- dependent_issue_id="$(parse_issue_id "${dependent_output}")" || {
241
- handle_issue_id_parse_failure "${DEPENDENT_ISSUE_TITLE}" "Could not parse dependent smoke issue ID"
242
- }
243
- created_issue_ids+=("${dependent_issue_id}")
244
-
245
- run_bd_step "list" "list" list --json --limit=50 >/dev/null || {
246
- rollback_unclosed_issues
247
- write_summary "false"
248
- exit 1
249
- }
250
-
251
- run_bd_step "show-primary" "show" show "${primary_issue_id}" --json >/dev/null || {
252
- rollback_unclosed_issues
253
- write_summary "false"
254
- exit 1
255
- }
256
-
257
- run_bd_step "dep-add" "dep" dep add "${primary_issue_id}" "${dependent_issue_id}" >/dev/null || {
258
- rollback_unclosed_issues
259
- write_summary "false"
260
- exit 1
261
- }
262
-
263
- run_bd_step "close-dependent" "close" close "${dependent_issue_id}" "--reason=${CLEANUP_REASON}" >/dev/null || {
264
- rollback_unclosed_issues
265
- write_summary "false"
266
- exit 1
267
- }
268
- closed_issue_ids+=("${dependent_issue_id}")
269
-
270
- run_bd_step "close-primary" "close" close "${primary_issue_id}" "--reason=${CLEANUP_REASON}" >/dev/null || {
271
- rollback_unclosed_issues
272
- write_summary "false"
273
- exit 1
274
- }
275
- closed_issue_ids+=("${primary_issue_id}")
276
-
277
- run_bd_step "sync" "sync" sync >/dev/null || {
278
- rollback_unclosed_issues
279
- write_summary "false"
280
- exit 1
281
- }
282
-
283
- write_summary "true"
284
- printf '%s\n' "${SUMMARY_PATH}"