@moretea-labs/forge 1.7.0 → 1.7.1

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 (175) hide show
  1. package/AGENTS.md +2 -0
  2. package/CHANGELOG.md +13 -0
  3. package/CLAUDE.md +2 -0
  4. package/THIRD_PARTY_NOTICES.md +1 -1
  5. package/agents/openai.yaml +1 -1
  6. package/assets/partials-agents/02-operating-mode.partial.md +2 -0
  7. package/assets/plugin-registry.v1.json +3 -3
  8. package/assets/skill-version.json +2 -2
  9. package/assets/templates/helpers/check-architecture-sync.sh +17 -0
  10. package/assets/templates/helpers/inspect-project-state.ts +8 -6
  11. package/assets/templates/helpers/migrate-workflow-docs.ts +9 -7
  12. package/assets/templates/helpers/workflow-contract.ts +5 -1
  13. package/docs/architecture/CURRENT.md +12 -4
  14. package/docs/forge-plugin-management.md +1 -1
  15. package/docs/operations/controller-performance-and-502.md +19 -0
  16. package/docs/operations/homebrew.md +2 -2
  17. package/package.json +5 -2
  18. package/scripts/architecture-event.ts +2 -820
  19. package/scripts/architecture-queue.sh +2 -645
  20. package/scripts/archive-architecture-request.sh +2 -242
  21. package/scripts/archive-workflow.sh +1 -291
  22. package/scripts/benchmark-work-efficiency.ts +0 -0
  23. package/scripts/capability-config.ts +2 -392
  24. package/scripts/capability-resolver.ts +2 -503
  25. package/scripts/capture-plan.sh +1 -332
  26. package/scripts/check-agent-tooling.sh +2 -1531
  27. package/scripts/check-architecture-sync.sh +2 -302
  28. package/scripts/check-brain-manifest.sh +2 -253
  29. package/scripts/check-context-files.sh +2 -47
  30. package/scripts/check-deploy-sql-order.sh +2 -115
  31. package/scripts/check-runtime-architecture.mjs +243 -16
  32. package/scripts/check-skill-version.ts +3 -191
  33. package/scripts/check-source-duplication.mjs +61 -0
  34. package/scripts/check-stable-baseline.ts +0 -0
  35. package/scripts/check-task-sync.sh +2 -63
  36. package/scripts/check-task-workflow.sh +2 -1000
  37. package/scripts/codex-handoff-resume.sh +2 -267
  38. package/scripts/context-contract-sync.sh +2 -514
  39. package/scripts/contract-run.ts +2 -463
  40. package/scripts/contract-worktree.sh +1 -702
  41. package/scripts/ensure-task-workflow.sh +1 -1192
  42. package/scripts/inspect-project-state.ts +4 -279
  43. package/scripts/lib/project-init-lib.sh +7 -2
  44. package/scripts/lib/run-forge-helper.sh +19 -0
  45. package/scripts/lib/run-forge-helper.ts +26 -0
  46. package/scripts/migrate-project-template.sh +1 -33
  47. package/scripts/migrate-workflow-docs.ts +4 -412
  48. package/scripts/new-plan.sh +1 -180
  49. package/scripts/new-spec.sh +1 -47
  50. package/scripts/new-sprint.sh +1 -46
  51. package/scripts/plan-to-todo.sh +1 -771
  52. package/scripts/prepare-codex-handoff.sh +2 -201
  53. package/scripts/prepare-handoff.sh +1 -78
  54. package/scripts/refresh-current-status.sh +2 -467
  55. package/scripts/run-governed-gate.ts +3 -0
  56. package/scripts/select-agent-context-blocks.sh +2 -64
  57. package/scripts/ship-worktrees.sh +1 -531
  58. package/scripts/sprint-backlog.sh +1 -834
  59. package/scripts/stage-runtime-release.ts +2 -1
  60. package/scripts/summarize-failures.sh +2 -123
  61. package/scripts/switch-plan.sh +1 -150
  62. package/scripts/sync-brain-docs.sh +2 -379
  63. package/scripts/sync-generated-authority.mjs +175 -0
  64. package/scripts/verify-contract.sh +2 -593
  65. package/scripts/verify-sprint.sh +1 -500
  66. package/scripts/workflow-contract.ts +4 -201
  67. package/scripts/workstream-sync.sh +2 -261
  68. package/src/cli/agent-jobs/executor-health.ts +1 -1
  69. package/src/cli/commands/plugin.ts +12 -3
  70. package/src/cli/controller/check-runner.ts +7 -2
  71. package/src/cli/controller/context-pack.ts +46 -21
  72. package/src/cli/github/contracts.ts +16 -0
  73. package/src/cli/github/github.ts +2 -16
  74. package/src/cli/github/session.ts +2 -1
  75. package/src/cli/local-bridge/facade-api.ts +37 -47
  76. package/src/cli/local-bridge/server.ts +2 -2
  77. package/src/cli/mcp/legacy-tool-service.ts +10 -33
  78. package/src/cli/mcp/post-finalize-work-attribution.ts +150 -0
  79. package/src/cli/mcp/repository-tools.ts +85 -89
  80. package/src/cli/mcp/server.ts +57 -13
  81. package/src/cli/mcp/tool-contract.ts +14 -0
  82. package/src/cli/mcp/toolset.ts +2 -2
  83. package/src/cli/mcp/transports/http.ts +23 -0
  84. package/src/cli/repositories/command-classifier.ts +2 -2
  85. package/src/cli/repositories/command-executor.ts +24 -6
  86. package/src/cli/repositories/repository-snapshot.ts +5 -2
  87. package/src/cli/repositories/structured-git.ts +57 -3
  88. package/src/cli/repository/inspector.ts +11 -3
  89. package/src/runtime/context/generic-lsp-provider.ts +1 -1
  90. package/src/runtime/context/semantic-navigation-contract.ts +61 -0
  91. package/src/runtime/context/semantic-navigation.ts +9 -61
  92. package/src/runtime/control-plane/execution/direct-edit-work-completion.ts +18 -25
  93. package/src/runtime/control-plane/execution/repository-work-attribution.ts +106 -0
  94. package/src/runtime/control-plane/execution/retained-work-resume.ts +203 -0
  95. package/src/runtime/control-plane/execution/work-completion-authority.ts +58 -0
  96. package/src/runtime/control-plane/execution/work-evidence-policy.ts +200 -0
  97. package/src/runtime/control-plane/execution/work-execution-support.ts +386 -0
  98. package/src/runtime/control-plane/execution/work-finalization-service.ts +1913 -0
  99. package/src/runtime/control-plane/execution/work-handle-authority.ts +96 -0
  100. package/src/runtime/control-plane/execution/work-handle-store.ts +1 -1
  101. package/src/runtime/control-plane/execution/work-operation-service.ts +468 -0
  102. package/src/runtime/control-plane/execution/work-path-scope.ts +37 -0
  103. package/src/runtime/control-plane/execution/work-preparation-service.ts +479 -0
  104. package/src/runtime/control-plane/execution/work-process-evidence.ts +129 -0
  105. package/src/runtime/control-plane/execution/work-task-receipt.ts +4 -43
  106. package/src/runtime/control-plane/execution/work-terminal-cleanup.ts +13 -3
  107. package/src/runtime/control-plane/execution/work-verification-context.ts +56 -0
  108. package/src/runtime/control-plane/execution/work-verification-service.ts +388 -0
  109. package/src/runtime/control-plane/execution/work-verification-snapshot.ts +5 -1
  110. package/src/runtime/control-plane/facade/controller-round-relay.ts +164 -37
  111. package/src/runtime/control-plane/facade/controller-session-store.ts +183 -24
  112. package/src/runtime/control-plane/facade/goal-workloop-access.ts +15 -1
  113. package/src/runtime/control-plane/facade/goal-workloop.ts +329 -148
  114. package/src/runtime/control-plane/facade/index.ts +2 -0
  115. package/src/runtime/control-plane/facade/plan-contract-store.ts +90 -22
  116. package/src/runtime/control-plane/facade/repository-work-admission.ts +147 -0
  117. package/src/runtime/control-plane/facade/requirement-authority.ts +83 -0
  118. package/src/runtime/control-plane/facade/types.ts +68 -5
  119. package/src/runtime/control-plane/facade/work-contract-store.ts +3 -209
  120. package/src/runtime/control-plane/facade/work-state-machine.ts +250 -0
  121. package/src/runtime/control-plane/global-scheduler/maintenance.ts +14 -7
  122. package/src/runtime/control-plane/global-scheduler/scheduler.ts +5 -1
  123. package/src/runtime/control-plane/launcher/chatgpt-work-binding-store.ts +13 -0
  124. package/src/runtime/control-plane/launcher/chatgpt-work-continuation.ts +15 -6
  125. package/src/runtime/control-plane/launcher/launch-reservation-store.ts +54 -5
  126. package/src/runtime/control-plane/launcher/thin-launcher.ts +56 -7
  127. package/src/runtime/control-plane/persistence/requirement-store.ts +0 -12
  128. package/src/runtime/control-plane/repo-actor/registry.ts +4 -2
  129. package/src/runtime/control-plane/routing/route-policy.ts +18 -6
  130. package/src/runtime/control-plane/routing/workspace-admission.ts +70 -0
  131. package/src/runtime/evidence/process-check-execution.ts +18 -0
  132. package/src/runtime/execution/jobs/child-reference.ts +6 -2
  133. package/src/runtime/execution/process-runtime/check-result.ts +53 -18
  134. package/src/runtime/execution/process-runtime/check-runner-sidecar.ts +7 -1
  135. package/src/runtime/execution/process-runtime/command-facade.ts +39 -17
  136. package/src/runtime/execution/process-runtime/lightweight-managed.ts +20 -3
  137. package/src/runtime/execution/process-runtime/persisted-check.ts +4 -1
  138. package/src/runtime/execution/process-runtime/runtime.ts +10 -0
  139. package/src/runtime/execution/process-runtime/types.ts +2 -12
  140. package/src/runtime/execution/work-activity.ts +21 -0
  141. package/src/runtime/execution/workers/executor.ts +18 -13
  142. package/src/runtime/gateway/mcp/execution-tools.ts +35 -2930
  143. package/src/runtime/gateway/mcp/legacy-ios-tool-adapter.ts +61 -0
  144. package/src/runtime/gateway/mcp/router.ts +2 -2
  145. package/src/runtime/gateway/mcp/runtime-tool-definitions.ts +21 -2
  146. package/src/runtime/gateway/mcp/runtime-tools.ts +805 -1009
  147. package/src/runtime/plugins/app-store-connect-adapter.ts +93 -28
  148. package/src/runtime/plugins/browser-adapter.ts +256 -1083
  149. package/src/runtime/plugins/browser-handoff-host.ts +2 -25
  150. package/src/runtime/plugins/browser-handoff.ts +18 -3
  151. package/src/runtime/plugins/browser-macos-bridge.ts +121 -16
  152. package/src/runtime/plugins/browser-manifest-surface.ts +603 -0
  153. package/src/runtime/plugins/browser-native-session-service.ts +222 -0
  154. package/src/runtime/plugins/browser-runtime-contract.ts +2 -0
  155. package/src/runtime/plugins/browser-runtime.ts +10 -0
  156. package/src/runtime/plugins/browser-session-store.ts +121 -0
  157. package/src/runtime/plugins/browser-session-types.ts +98 -0
  158. package/src/runtime/plugins/desktop-operator-registration.ts +4 -4
  159. package/src/runtime/plugins/external-adapter.ts +92 -58
  160. package/src/runtime/plugins/macos-capability-broker.ts +0 -8
  161. package/src/runtime/plugins/store.ts +66 -9
  162. package/src/runtime/plugins/types.ts +3 -1
  163. package/src/runtime/recovery/maintenance-executor.ts +61 -25
  164. package/src/runtime/root/package-connector-service.ts +46 -4
  165. package/src/runtime/root/package-runtime-release.ts +1 -1
  166. package/src/runtime/root/package-runtime-service.ts +33 -2
  167. package/src/runtime/root/release-manifest.ts +137 -16
  168. package/src/runtime/root/release-materialize.ts +109 -35
  169. package/src/runtime/root/types.ts +10 -0
  170. package/src/runtime/standalone-recovery/core.ts +425 -194
  171. package/src/runtime/standalone-recovery/entry.ts +1 -1
  172. package/src/runtime/standalone-recovery/installer.ts +1 -1
  173. package/src/runtime/workflow/schedules/engine.ts +113 -87
  174. package/src/runtime/workflow/schedules/settlement.ts +26 -23
  175. package/src/runtime/workflow/schedules/store.ts +79 -10
@@ -1,595 +1,4 @@
1
1
  #!/bin/bash
2
2
  set -euo pipefail
3
-
4
- usage() {
5
- cat <<'USAGE_EOF'
6
- Usage: scripts/verify-contract.sh --contract <contract-file> [--strict] [--quiet] [--read-only] [--report-file <path>]
7
-
8
- Options:
9
- --contract <path> Contract markdown file with a YAML exit_criteria block
10
- --strict Exit with code 1 when any criteria fail
11
- --quiet Suppress per-check logs; only print on failure or status change
12
- --read-only Do not rewrite the contract Status header; tests_pass and
13
- commands_succeed still execute for verification
14
- --report-file <path> Write structured JSON results for downstream tooling
15
- USAGE_EOF
16
- }
17
-
18
- strip_quotes() {
19
- local value="$1"
20
- value="$(printf '%s' "$value" | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//')"
21
- if [[ "$value" =~ ^\".*\"$ ]]; then
22
- value="${value:1:${#value}-2}"
23
- elif [[ "$value" =~ ^\'.*\'$ ]]; then
24
- value="${value:1:${#value}-2}"
25
- fi
26
- printf '%s' "$value"
27
- }
28
-
29
- json_escape() {
30
- local value="$1"
31
- value="${value//\\/\\\\}"
32
- value="${value//\"/\\\"}"
33
- value="${value//$'\n'/\\n}"
34
- value="${value//$'\r'/\\r}"
35
- value="${value//$'\t'/\\t}"
36
- printf '%s' "$value"
37
- }
38
-
39
- resolve_bun_bin() {
40
- if [[ -n "${BUN_BIN:-}" ]] && [[ -x "${BUN_BIN}" ]]; then
41
- printf '%s' "$BUN_BIN"
42
- return 0
43
- fi
44
-
45
- if command -v bun >/dev/null 2>&1; then
46
- command -v bun
47
- return 0
48
- fi
49
-
50
- if [[ -x "${HOME}/.bun/bin/bun" ]]; then
51
- printf '%s' "${HOME}/.bun/bin/bun"
52
- return 0
53
- fi
54
-
55
- return 1
56
- }
57
-
58
- resolve_run_id() {
59
- if [[ -n "${HOOK_RUN_ID:-${CLAUDE_RUN_ID:-${CODEX_RUN_ID:-}}}" ]]; then
60
- printf '%s' "${HOOK_RUN_ID:-${CLAUDE_RUN_ID:-${CODEX_RUN_ID:-}}}"
61
- return
62
- fi
63
-
64
- printf 'run-%s-%s' "$(date '+%Y%m%dT%H%M%S')" "$$"
65
- }
66
-
67
- read_contract_status() {
68
- local file="$1"
69
- awk '/^> \*\*Status\*\*:/ {sub(/^.*> \*\*Status\*\*: */, ""); gsub(/\r/, ""); print; exit}' "$file" | xargs
70
- }
71
-
72
- read_contract_task_profile() {
73
- local file="$1"
74
- awk '/^> \*\*Task Profile\*\*:/ {sub(/^.*> \*\*Task Profile\*\*:[[:space:]]*/, ""); gsub(/\r/, ""); print; exit}' "$file" | xargs
75
- }
76
-
77
- contract_allowed_paths() {
78
- local file="$1"
79
- awk '
80
- BEGIN { in_block = 0; block = ""; found = 0 }
81
- /^```yaml[[:space:]]*$/ {
82
- in_block = 1
83
- block = ""
84
- next
85
- }
86
- /^```[[:space:]]*$/ && in_block == 1 {
87
- if (!found && block ~ /(^|[[:space:]])allowed_paths:/) {
88
- printf "%s", block
89
- found = 1
90
- }
91
- in_block = 0
92
- block = ""
93
- next
94
- }
95
- in_block == 1 {
96
- block = block $0 ORS
97
- }
98
- ' "$file" | awk '
99
- function trim(s) {
100
- gsub(/^[[:space:]]+/, "", s)
101
- gsub(/[[:space:]]+$/, "", s)
102
- return s
103
- }
104
- /^[[:space:]]*allowed_paths:[[:space:]]*$/ { in_paths = 1; next }
105
- in_paths && /^[^[:space:]]/ { exit }
106
- in_paths && /^[[:space:]]*-[[:space:]]*/ {
107
- line = $0
108
- sub(/^[[:space:]]*-[[:space:]]*/, "", line)
109
- gsub(/^["'\''`]+|["'\''`]+$/, "", line)
110
- print trim(line)
111
- }
112
- '
113
- }
114
-
115
- update_contract_status() {
116
- local file="$1"
117
- local status="$2"
118
- local tmp_file
119
- tmp_file="$(mktemp)"
120
-
121
- awk -v next_status="$status" '
122
- BEGIN { updated = 0 }
123
- {
124
- if (!updated && $0 ~ /^> \*\*Status\*\*:/) {
125
- print "> **Status**: " next_status
126
- updated = 1
127
- next
128
- }
129
- print
130
- }
131
- END {
132
- if (!updated) {
133
- print ""
134
- print "> **Status**: " next_status
135
- }
136
- }
137
- ' "$file" > "$tmp_file"
138
-
139
- mv "$tmp_file" "$file"
140
- }
141
-
142
- append_result() {
143
- local kind="$1"
144
- local target="$2"
145
- local passed="$3"
146
- local message="$4"
147
- RESULT_KINDS+=("$kind")
148
- RESULT_TARGETS+=("$target")
149
- RESULT_PASSED+=("$passed")
150
- RESULT_MESSAGES+=("$message")
151
- }
152
-
153
- log_check() {
154
- local prefix="$1"
155
- local message="$2"
156
-
157
- if [[ "$quiet" -eq 1 ]]; then
158
- return
159
- fi
160
-
161
- echo "[$prefix] $message"
162
- }
163
-
164
- pass() {
165
- local kind="$1"
166
- local target="$2"
167
- local message="$3"
168
- total=$((total + 1))
169
- append_result "$kind" "$target" "true" "$message"
170
- log_check "PASS" "$message"
171
- }
172
-
173
- fail() {
174
- local kind="$1"
175
- local target="$2"
176
- local message="$3"
177
- total=$((total + 1))
178
- failed=$((failed + 1))
179
- append_result "$kind" "$target" "false" "$message"
180
- log_check "FAIL" "$message"
181
- }
182
-
183
- write_report() {
184
- local report_path="$1"
185
- local idx
186
-
187
- [[ -n "$report_path" ]] || return 0
188
-
189
- mkdir -p "$(dirname "$report_path")"
190
-
191
- {
192
- echo "{"
193
- printf ' "contract": "%s",\n' "$(json_escape "$contract_file")"
194
- printf ' "run_id": "%s",\n' "$(json_escape "$run_id")"
195
- printf ' "previous_status": "%s",\n' "$(json_escape "$previous_status")"
196
- printf ' "next_status": "%s",\n' "$(json_escape "$next_status")"
197
- printf ' "failure_class": "%s",\n' "$(json_escape "$failure_class")"
198
- printf ' "quiet": %s,\n' "$([[ "$quiet" -eq 1 ]] && echo true || echo false)"
199
- printf ' "strict": %s,\n' "$([[ "$strict" -eq 1 ]] && echo true || echo false)"
200
- printf ' "read_only": %s,\n' "$([[ "$read_only" -eq 1 ]] && echo true || echo false)"
201
- printf ' "executes_contract_commands": %s,\n' "$([[ "$executes_contract_commands" -eq 1 ]] && echo true || echo false)"
202
- printf ' "total": %s,\n' "$total"
203
- printf ' "failed": %s,\n' "$failed"
204
- echo ' "results": ['
205
- for idx in "${!RESULT_KINDS[@]}"; do
206
- if [[ "$idx" -gt 0 ]]; then
207
- echo ","
208
- fi
209
- printf ' {"kind":"%s","target":"%s","passed":%s,"message":"%s"}' \
210
- "$(json_escape "${RESULT_KINDS[$idx]}")" \
211
- "$(json_escape "${RESULT_TARGETS[$idx]}")" \
212
- "${RESULT_PASSED[$idx]}" \
213
- "$(json_escape "${RESULT_MESSAGES[$idx]}")"
214
- done
215
- echo
216
- echo " ]"
217
- echo "}"
218
- } > "$report_path"
219
- }
220
-
221
- contract_file=""
222
- strict=0
223
- quiet=0
224
- read_only=0
225
- report_file=""
226
- run_id="$(resolve_run_id)"
227
- failure_class=""
228
- executes_contract_commands=0
229
-
230
- while [[ $# -gt 0 ]]; do
231
- case "$1" in
232
- --contract)
233
- [[ -n "${2:-}" ]] || { echo "Error: --contract requires a value" >&2; usage; exit 2; }
234
- contract_file="$2"
235
- shift 2
236
- ;;
237
- --strict)
238
- strict=1
239
- shift
240
- ;;
241
- --quiet)
242
- quiet=1
243
- shift
244
- ;;
245
- --read-only)
246
- read_only=1
247
- shift
248
- ;;
249
- --report-file)
250
- [[ -n "${2:-}" ]] || { echo "Error: --report-file requires a value" >&2; usage; exit 2; }
251
- report_file="$2"
252
- shift 2
253
- ;;
254
- --help|-h)
255
- usage
256
- exit 0
257
- ;;
258
- *)
259
- echo "Unknown argument: $1" >&2
260
- usage
261
- exit 2
262
- ;;
263
- esac
264
- done
265
-
266
- if [[ -z "$contract_file" ]]; then
267
- echo "Error: --contract is required" >&2
268
- usage
269
- exit 2
270
- fi
271
-
272
- tmp_dir="$(mktemp -d)"
273
- trap 'rm -rf "$tmp_dir"' EXIT
274
-
275
- if [[ ! -f "$contract_file" ]]; then
276
- echo "[ContractVerify] Contract file not found: $contract_file" >&2
277
- exit 2
278
- fi
279
-
280
- previous_status="$(read_contract_status "$contract_file")"
281
- previous_status="${previous_status:-Pending}"
282
-
283
- yaml_block="$(
284
- awk '
285
- BEGIN { in_block = 0; block = ""; found = 0 }
286
- /^```yaml[[:space:]]*$/ {
287
- in_block = 1
288
- block = ""
289
- next
290
- }
291
- /^```[[:space:]]*$/ && in_block == 1 {
292
- if (block ~ /(^|[[:space:]])exit_criteria:/) {
293
- printf "%s", block
294
- found = 1
295
- exit
296
- }
297
- in_block = 0
298
- block = ""
299
- next
300
- }
301
- in_block == 1 {
302
- block = block $0 ORS
303
- }
304
- ' "$contract_file"
305
- )"
306
-
307
- if [[ -z "$yaml_block" ]]; then
308
- next_status="Pending"
309
- if [[ "$read_only" -eq 0 ]]; then
310
- update_contract_status "$contract_file" "$next_status"
311
- fi
312
- total=0
313
- failed=0
314
- failure_class="missing_artifact"
315
- RESULT_KINDS=()
316
- RESULT_TARGETS=()
317
- RESULT_PASSED=()
318
- RESULT_MESSAGES=()
319
- write_report "$report_file"
320
- if [[ "$quiet" -eq 0 ]]; then
321
- echo "[ContractVerify] No YAML exit criteria block found in $contract_file"
322
- elif [[ "$previous_status" != "$next_status" ]]; then
323
- echo "[ContractVerify] status ${previous_status} -> ${next_status}"
324
- fi
325
- if [[ "$strict" -eq 1 ]]; then
326
- exit 1
327
- fi
328
- exit 0
329
- fi
330
-
331
- declare -a files_exist=()
332
- declare -a tests_pass=()
333
- declare -a commands_succeed=()
334
- declare -a artifacts_exist=()
335
- declare -a contain_paths=()
336
- declare -a contain_patterns=()
337
- declare -a files_not_exist=()
338
- declare -a not_contain_paths=()
339
- declare -a not_contain_patterns=()
340
-
341
- section=""
342
- pending_path=""
343
- task_profile="$(read_contract_task_profile "$contract_file" || true)"
344
- declare -a allowed_paths=()
345
- while IFS= read -r allowed_path; do
346
- [[ -n "$allowed_path" ]] && allowed_paths+=("$allowed_path")
347
- done < <(contract_allowed_paths "$contract_file")
348
-
349
- while IFS= read -r raw_line; do
350
- line="$(printf '%s' "$raw_line" | sed -E 's/[[:space:]]+$//')"
351
- trimmed="$(printf '%s' "$line" | sed -E 's/^[[:space:]]+//')"
352
-
353
- [[ -z "$trimmed" ]] && continue
354
- [[ "$trimmed" =~ ^# ]] && continue
355
- [[ "$trimmed" == "exit_criteria:" ]] && continue
356
-
357
- case "$trimmed" in
358
- files_exist:)
359
- section="files_exist"
360
- pending_path=""
361
- continue
362
- ;;
363
- tests_pass:)
364
- section="tests_pass"
365
- pending_path=""
366
- continue
367
- ;;
368
- commands_succeed:)
369
- section="commands_succeed"
370
- pending_path=""
371
- continue
372
- ;;
373
- artifacts_exist:)
374
- section="artifacts_exist"
375
- pending_path=""
376
- continue
377
- ;;
378
- files_contain:)
379
- section="files_contain"
380
- pending_path=""
381
- continue
382
- ;;
383
- files_not_exist:)
384
- section="files_not_exist"
385
- pending_path=""
386
- continue
387
- ;;
388
- files_not_contain:)
389
- section="files_not_contain"
390
- pending_path=""
391
- continue
392
- ;;
393
- esac
394
-
395
- case "$section" in
396
- files_exist|commands_succeed|files_not_exist|artifacts_exist)
397
- if [[ "$trimmed" =~ ^-[[:space:]]*(.+)$ ]]; then
398
- item="$(strip_quotes "${BASH_REMATCH[1]}")"
399
- [[ -n "$item" ]] || continue
400
- if [[ "$section" == "files_exist" ]]; then
401
- files_exist+=("$item")
402
- elif [[ "$section" == "commands_succeed" ]]; then
403
- commands_succeed+=("$item")
404
- elif [[ "$section" == "artifacts_exist" ]]; then
405
- artifacts_exist+=("$item")
406
- else
407
- files_not_exist+=("$item")
408
- fi
409
- fi
410
- ;;
411
- tests_pass)
412
- if [[ "$trimmed" =~ ^-[[:space:]]*path:[[:space:]]*(.+)$ ]]; then
413
- item="$(strip_quotes "${BASH_REMATCH[1]}")"
414
- [[ -n "$item" ]] && tests_pass+=("$item")
415
- fi
416
- ;;
417
- files_contain|files_not_contain)
418
- if [[ "$trimmed" =~ ^-[[:space:]]*path:[[:space:]]*(.+)$ ]]; then
419
- pending_path="$(strip_quotes "${BASH_REMATCH[1]}")"
420
- elif [[ "$trimmed" =~ ^pattern:[[:space:]]*(.+)$ ]]; then
421
- pattern="$(strip_quotes "${BASH_REMATCH[1]}")"
422
- if [[ -n "$pending_path" ]]; then
423
- if [[ "$section" == "files_contain" ]]; then
424
- contain_paths+=("$pending_path")
425
- contain_patterns+=("$pattern")
426
- else
427
- not_contain_paths+=("$pending_path")
428
- not_contain_patterns+=("$pattern")
429
- fi
430
- pending_path=""
431
- fi
432
- fi
433
- ;;
434
- esac
435
- done <<< "$yaml_block"
436
- if ((${#tests_pass[@]} || ${#commands_succeed[@]})); then
437
- executes_contract_commands=1
438
- fi
439
-
440
- total=0
441
- failed=0
442
- RESULT_KINDS=()
443
- RESULT_TARGETS=()
444
- RESULT_PASSED=()
445
- RESULT_MESSAGES=()
446
-
447
- case "$task_profile" in
448
- "")
449
- pass "task_profile" "(legacy)" "task_profile missing: legacy contract accepted"
450
- ;;
451
- code-change|docs-only|ledger-closeout|migration|eval-only|delegated-run)
452
- pass "task_profile" "$task_profile" "task_profile: $task_profile"
453
- ;;
454
- *)
455
- fail "task_profile" "$task_profile" "unsupported task_profile: $task_profile"
456
- ;;
457
- esac
458
-
459
- if [[ -n "$task_profile" ]]; then
460
- for path in "${allowed_paths[@]+"${allowed_paths[@]}"}"; do
461
- case "$task_profile:$path" in
462
- ledger-closeout:src/*|ledger-closeout:src/|ledger-closeout:tests/*|ledger-closeout:tests/|ledger-closeout:.ai/hooks/*|ledger-closeout:.ai/hooks/|ledger-closeout:assets/hooks/*|ledger-closeout:assets/hooks/)
463
- fail "allowed_paths" "$path" "ledger-closeout profile cannot allow runtime code or hook paths by default: $path"
464
- ;;
465
- docs-only:src/*|docs-only:src/|docs-only:tests/*|docs-only:tests/)
466
- fail "allowed_paths" "$path" "docs-only profile cannot allow src/ or tests/ by default: $path"
467
- ;;
468
- eval-only:src/*|eval-only:src/)
469
- fail "allowed_paths" "$path" "eval-only profile cannot allow runtime src/ by default: $path"
470
- ;;
471
- esac
472
- done
473
- fi
474
-
475
- if ((${#files_exist[@]})); then
476
- for path in "${files_exist[@]}"; do
477
- if [[ -e "$path" ]]; then
478
- pass "files_exist" "$path" "files_exist: $path"
479
- else
480
- fail "files_exist" "$path" "files_exist: $path"
481
- fi
482
- done
483
- fi
484
-
485
- if ((${#artifacts_exist[@]})); then
486
- for path in "${artifacts_exist[@]}"; do
487
- if [[ -e "$path" ]]; then
488
- pass "artifacts_exist" "$path" "artifacts_exist: $path"
489
- else
490
- fail "artifacts_exist" "$path" "artifacts_exist: $path"
491
- fi
492
- done
493
- fi
494
-
495
- if ((${#tests_pass[@]})); then
496
- for path in "${tests_pass[@]}"; do
497
- if [[ ! -f "$path" ]]; then
498
- fail "tests_pass" "$path" "tests_pass file missing: $path"
499
- continue
500
- fi
501
-
502
- bun_bin="$(resolve_bun_bin || true)"
503
- if [[ -z "$bun_bin" ]]; then
504
- fail "tests_pass" "$path" "tests_pass cannot run (bun not found): $path"
505
- continue
506
- fi
507
-
508
- if "$bun_bin" test "$path" >"$tmp_dir/contract-test.log" 2>&1; then
509
- pass "tests_pass" "$path" "tests_pass: $path"
510
- else
511
- fail "tests_pass" "$path" "tests_pass: $path"
512
- fi
513
- done
514
- fi
515
-
516
- if ((${#commands_succeed[@]})); then
517
- for cmd in "${commands_succeed[@]}"; do
518
- if env -u BASH_ENV bash --noprofile --norc -c "$cmd" >"$tmp_dir/contract-command.log" 2>&1; then
519
- pass "commands_succeed" "$cmd" "commands_succeed: $cmd"
520
- else
521
- fail "commands_succeed" "$cmd" "commands_succeed: $cmd"
522
- fi
523
- done
524
- fi
525
-
526
- if ((${#contain_paths[@]})); then
527
- for idx in "${!contain_paths[@]}"; do
528
- path="${contain_paths[$idx]}"
529
- pattern="${contain_patterns[$idx]}"
530
-
531
- if [[ ! -f "$path" ]]; then
532
- fail "files_contain" "$path" "files_contain missing file: $path"
533
- continue
534
- fi
535
-
536
- if grep -Eq "$pattern" "$path"; then
537
- pass "files_contain" "$path" "files_contain: $path =~ $pattern"
538
- else
539
- fail "files_contain" "$path" "files_contain: $path !~ $pattern"
540
- fi
541
- done
542
- fi
543
-
544
- if ((${#files_not_exist[@]})); then
545
- for path in "${files_not_exist[@]}"; do
546
- if [[ ! -e "$path" ]]; then
547
- pass "files_not_exist" "$path" "files_not_exist: $path"
548
- else
549
- fail "files_not_exist" "$path" "files_not_exist: $path"
550
- fi
551
- done
552
- fi
553
-
554
- if ((${#not_contain_paths[@]})); then
555
- for idx in "${!not_contain_paths[@]}"; do
556
- path="${not_contain_paths[$idx]}"
557
- pattern="${not_contain_patterns[$idx]}"
558
-
559
- if [[ ! -f "$path" ]]; then
560
- pass "files_not_contain" "$path" "files_not_contain missing file: $path"
561
- continue
562
- fi
563
-
564
- if grep -Eq "$pattern" "$path"; then
565
- fail "files_not_contain" "$path" "files_not_contain: $path =~ $pattern"
566
- else
567
- pass "files_not_contain" "$path" "files_not_contain: $path !~ $pattern"
568
- fi
569
- done
570
- fi
571
-
572
- next_status="Fulfilled"
573
- if [[ "$total" -eq 0 ]]; then
574
- next_status="Pending"
575
- elif [[ "$failed" -gt 0 ]]; then
576
- next_status="Partial"
577
- failure_class="contract_failure"
578
- fi
579
-
580
- if [[ "$read_only" -eq 0 ]]; then
581
- update_contract_status "$contract_file" "$next_status"
582
- fi
583
- write_report "$report_file"
584
-
585
- if [[ "$quiet" -eq 1 ]]; then
586
- if [[ "$failed" -gt 0 || "$previous_status" != "$next_status" ]]; then
587
- echo "[ContractVerify] total=$total failed=$failed status=${previous_status}->${next_status}"
588
- fi
589
- else
590
- echo "[ContractVerify] total=$total failed=$failed status=$next_status"
591
- fi
592
-
593
- if [[ "$strict" -eq 1 && "$failed" -gt 0 ]]; then
594
- exit 1
595
- fi
3
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
4
+ exec "$SCRIPT_DIR/lib/run-forge-helper.sh" "verify-contract.sh" "$@"