@moretea-labs/forge 1.7.0 → 1.7.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.
Files changed (175) hide show
  1. package/AGENTS.md +2 -0
  2. package/CHANGELOG.md +26 -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 +125 -101
  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 +69 -29
  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 +150 -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 +815 -1015
  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 +3 -2
  166. package/src/runtime/root/package-runtime-service.ts +48 -3
  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,304 +1,4 @@
1
1
  #!/bin/bash
2
2
  set -euo pipefail
3
-
4
- usage() {
5
- cat <<'USAGE_EOF'
6
- Usage: scripts/check-architecture-sync.sh [--mode off|advisory|strict] [--target <branch>] [--changed-files <file>] [--format text|json]
7
-
8
- Checks architecture request index integrity, then gates pending architecture
9
- drift only for capabilities touched by the current branch or working tree.
10
- USAGE_EOF
11
- }
12
-
13
- repo="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
14
- repo="$(cd "$repo" && pwd)"
15
- cd "$repo"
16
-
17
- mode=""
18
- target_branch=""
19
- changed_files_file=""
20
- format="text"
21
-
22
- while [[ $# -gt 0 ]]; do
23
- case "$1" in
24
- --mode)
25
- [[ -n "${2:-}" ]] || { echo "check-architecture-sync: --mode requires a value" >&2; exit 2; }
26
- mode="$2"
27
- shift 2
28
- ;;
29
- --target)
30
- [[ -n "${2:-}" ]] || { echo "check-architecture-sync: --target requires a value" >&2; exit 2; }
31
- target_branch="$2"
32
- shift 2
33
- ;;
34
- --changed-files)
35
- [[ -n "${2:-}" ]] || { echo "check-architecture-sync: --changed-files requires a value" >&2; exit 2; }
36
- changed_files_file="$2"
37
- shift 2
38
- ;;
39
- --format)
40
- [[ -n "${2:-}" ]] || { echo "check-architecture-sync: --format requires a value" >&2; exit 2; }
41
- format="$2"
42
- shift 2
43
- ;;
44
- --help|-h)
45
- usage
46
- exit 0
47
- ;;
48
- *)
49
- echo "check-architecture-sync: unknown argument: $1" >&2
50
- usage >&2
51
- exit 2
52
- ;;
53
- esac
54
- done
55
-
56
- json_escape() {
57
- local value="$1"
58
- value="${value//\\/\\\\}"
59
- value="${value//\"/\\\"}"
60
- value="${value//$'\n'/\\n}"
61
- value="${value//$'\r'/\\r}"
62
- value="${value//$'\t'/\\t}"
63
- printf '%s' "$value"
64
- }
65
-
66
- policy_value() {
67
- local jq_path="$1"
68
- local default_value="$2"
69
- local value=""
70
-
71
- if [[ -f ".ai/harness/policy.json" ]] && command -v jq >/dev/null 2>&1; then
72
- value="$(jq -r "$jq_path // empty" .ai/harness/policy.json 2>/dev/null || true)"
73
- elif [[ -f ".ai/harness/policy.json" ]] && command -v node >/dev/null 2>&1; then
74
- value="$(POLICY_PATH="$jq_path" node -e '
75
- const fs = require("fs");
76
- const path = process.env.POLICY_PATH || "";
77
- try {
78
- const policy = JSON.parse(fs.readFileSync(".ai/harness/policy.json", "utf8"));
79
- const keys = path.replace(/^\./, "").split(".");
80
- let value = policy;
81
- for (const key of keys) value = value && value[key];
82
- if (value === undefined || value === null || value === "") process.exit(1);
83
- process.stdout.write(String(value));
84
- } catch {
85
- process.exit(1);
86
- }
87
- ' 2>/dev/null || true)"
88
- fi
89
-
90
- printf '%s' "${value:-$default_value}"
91
- }
92
-
93
- severity_rank() {
94
- case "$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]')" in
95
- critical) printf '4' ;;
96
- high) printf '3' ;;
97
- medium) printf '2' ;;
98
- low) printf '1' ;;
99
- *) printf '0' ;;
100
- esac
101
- }
102
-
103
- metadata_value() {
104
- local file="$1"
105
- local label="$2"
106
- [[ -f "$file" ]] || return 1
107
- awk -v label="> **${label}**:" '
108
- index($0, label) == 1 {
109
- value = substr($0, length(label) + 1)
110
- gsub(/^[[:space:]]+|[[:space:]]+$/, "", value)
111
- gsub(/^`|`$/, "", value)
112
- print value
113
- exit
114
- }
115
- ' "$file"
116
- }
117
-
118
- normalize_repo_path() {
119
- local value="$1"
120
- value="${value#file://}"
121
- case "$value" in
122
- "$repo"/*) value="${value#$repo/}" ;;
123
- /*) return 1 ;;
124
- ./*) value="${value#./}" ;;
125
- esac
126
- value="${value%/}"
127
- case "$value" in
128
- ""|.|..|../*|*/../*|*$'\n'*|*$'\r'*) return 1 ;;
129
- esac
130
- printf '%s\n' "$value"
131
- }
132
-
133
- collect_changed_files() {
134
- local merge_base=""
135
-
136
- if [[ -n "$changed_files_file" ]]; then
137
- while IFS= read -r path; do
138
- [[ -n "$path" ]] || continue
139
- normalize_repo_path "$path" || true
140
- done < "$changed_files_file"
141
- return 0
142
- fi
143
-
144
- if [[ -n "$target_branch" ]] && git rev-parse --verify --quiet "$target_branch" >/dev/null 2>&1; then
145
- merge_base="$(git merge-base HEAD "$target_branch" 2>/dev/null || true)"
146
- fi
147
-
148
- if [[ -n "$merge_base" ]]; then
149
- git diff --name-only --diff-filter=ACMRTUXB "$merge_base"...HEAD
150
- fi
151
-
152
- git status --porcelain=v1 --untracked-files=all | while IFS= read -r line; do
153
- path="${line:3}"
154
- case "$line" in
155
- R*|C*)
156
- path="${path##* -> }"
157
- ;;
158
- esac
159
- [[ -n "$path" ]] || continue
160
- normalize_repo_path "$path" || true
161
- done
162
- }
163
-
164
- pending_request_files() {
165
- [[ -d "docs/architecture/requests" ]] || return 0
166
- find "docs/architecture/requests" -maxdepth 1 -type f -name '*.md' | sort | while IFS= read -r request; do
167
- [[ "$(metadata_value "$request" "Status" || true)" == "Pending" ]] || continue
168
- printf '%s\n' "$request"
169
- done
170
- }
171
-
172
- pending_requests_for_capabilities() {
173
- local threshold="$1"
174
- local min_rank capability_set="$2"
175
- local request capability severity
176
- min_rank="$(severity_rank "$threshold")"
177
-
178
- while IFS= read -r request; do
179
- capability="$(metadata_value "$request" "Capability ID" || true)"
180
- capability="${capability:-root}"
181
- severity="$(metadata_value "$request" "Severity" || true)"
182
- [[ "$(severity_rank "$severity")" -ge "$min_rank" ]] || continue
183
- if printf '%s\n' "$capability_set" | grep -Fxq "$capability"; then
184
- printf '%s\t%s\t%s\n' "$capability" "$severity" "$request"
185
- fi
186
- done < <(pending_request_files)
187
- }
188
-
189
- mode="${mode:-$(policy_value '.architecture.freshness_gate' 'advisory')}"
190
- target_branch="${target_branch:-$(policy_value '.worktree_strategy.merge_back.target' 'main')}"
191
- threshold="$(policy_value '.architecture.gate_min_severity' 'medium')"
192
-
193
- case "$mode" in
194
- off|advisory|strict) ;;
195
- *)
196
- echo "check-architecture-sync: unknown mode: $mode" >&2
197
- exit 1
198
- ;;
199
- esac
200
-
201
- if [[ ! -x "scripts/architecture-queue.sh" ]]; then
202
- if [[ "$mode" == "strict" ]]; then
203
- echo "[ArchitectureSync] strict gate failed: missing scripts/architecture-queue.sh" >&2
204
- exit 1
205
- fi
206
- echo "[ArchitectureSync] WARN: missing scripts/architecture-queue.sh; skipping advisory freshness gate" >&2
207
- exit 0
208
- fi
209
-
210
- if ! bash scripts/architecture-queue.sh reindex --check >/dev/null; then
211
- echo "[ArchitectureSync] architecture request index is stale; run bash scripts/architecture-queue.sh reindex" >&2
212
- exit 1
213
- fi
214
-
215
- if [[ -f "docs/architecture/current/README.md" ]]; then
216
- if [[ ! -f "docs/architecture/CURRENT.md" ]]; then
217
- echo "[ArchitectureSync] architecture baseline failed: missing required file docs/architecture/CURRENT.md" >&2
218
- exit 1
219
- fi
220
-
221
- if ! grep -Fq "Runtime Authority" "docs/architecture/CURRENT.md"; then
222
- echo "[ArchitectureSync] architecture baseline failed: docs/architecture/CURRENT.md must contain: Runtime Authority" >&2
223
- exit 1
224
- fi
225
-
226
- if ! grep -Fq "Not Runtime Authority" "docs/architecture/current/README.md"; then
227
- echo "[ArchitectureSync] architecture baseline failed: docs/architecture/current/README.md must contain: Not Runtime Authority" >&2
228
- exit 1
229
- fi
230
- fi
231
-
232
- if [[ "$mode" == "off" ]]; then
233
- case "$format" in
234
- json) printf '{"mode":"off","changed_capabilities":0,"blocking":0}\n' ;;
235
- text) echo "[ArchitectureSync] mode=off changed_capabilities=0 blocking=0" ;;
236
- *) echo "check-architecture-sync: unsupported --format: $format" >&2; exit 2 ;;
237
- esac
238
- exit 0
239
- fi
240
-
241
- if ! command -v bun >/dev/null 2>&1 || [[ ! -f "scripts/capability-resolver.ts" ]]; then
242
- if [[ "$mode" == "strict" ]]; then
243
- echo "[ArchitectureSync] strict gate failed: missing bun or scripts/capability-resolver.ts" >&2
244
- exit 1
245
- fi
246
- echo "[ArchitectureSync] WARN: missing bun or scripts/capability-resolver.ts; skipping advisory freshness gate" >&2
247
- exit 0
248
- fi
249
-
250
- changed_files="$(collect_changed_files | sort -u)"
251
- if [[ -z "$changed_files" ]]; then
252
- case "$format" in
253
- json) printf '{"mode":"%s","gate_min_severity":"%s","changed_capabilities":0,"blocking":0}\n' "$(json_escape "$mode")" "$(json_escape "$threshold")" ;;
254
- text) echo "[ArchitectureSync] mode=$mode gate_min_severity=$threshold changed_capabilities=0 blocking=0" ;;
255
- *) echo "check-architecture-sync: unsupported --format: $format" >&2; exit 2 ;;
256
- esac
257
- exit 0
258
- fi
259
-
260
- matches_json="$(printf '%s\n' "$changed_files" | bun scripts/capability-resolver.ts match --paths-from - --format json)"
261
- capabilities="$(
262
- MATCHES_JSON="$matches_json" node -e '
263
- const matches = JSON.parse(process.env.MATCHES_JSON || "[]");
264
- const ids = new Set();
265
- for (const item of matches) ids.add(item.capability_id || "root");
266
- for (const id of [...ids].sort()) console.log(id);
267
- '
268
- )"
269
- changed_count="$(printf '%s\n' "$capabilities" | sed '/^$/d' | wc -l | tr -d ' ')"
270
- blocking_lines="$(pending_requests_for_capabilities "$threshold" "$capabilities")"
271
- blocking_count="$(printf '%s\n' "$blocking_lines" | sed '/^$/d' | wc -l | tr -d ' ')"
272
-
273
- case "$format" in
274
- json)
275
- blocking_json="$(
276
- printf '%s\n' "$blocking_lines" | awk -F '\t' 'NF >= 3 { printf "%s{\"capability_id\":\"%s\",\"severity\":\"%s\",\"request\":\"%s\"}", sep, $1, $2, $3; sep="," }'
277
- )"
278
- printf '{"mode":"%s","gate_min_severity":"%s","changed_capabilities":%s,"blocking":%s,"blocking_requests":[%s]}\n' \
279
- "$(json_escape "$mode")" "$(json_escape "$threshold")" "$changed_count" "$blocking_count" "$blocking_json"
280
- ;;
281
- text)
282
- echo "[ArchitectureSync] mode=$mode gate_min_severity=$threshold changed_capabilities=$changed_count blocking=$blocking_count"
283
- if [[ "$blocking_count" -gt 0 ]]; then
284
- printf '%s\n' "$blocking_lines" | while IFS=$'\t' read -r capability severity request; do
285
- [[ -n "$capability" ]] || continue
286
- echo "[ArchitectureSync] pending $severity $capability -> $request"
287
- done
288
- fi
289
- ;;
290
- *)
291
- echo "check-architecture-sync: unsupported --format: $format" >&2
292
- exit 2
293
- ;;
294
- esac
295
-
296
- if [[ "$blocking_count" -gt 0 ]]; then
297
- if [[ "$mode" == "strict" ]]; then
298
- echo "[ArchitectureSync] strict gate failed: changed capabilities have pending architecture requests" >&2
299
- exit 1
300
- fi
301
- echo "[ArchitectureSync] WARN: changed capabilities have pending architecture requests" >&2
302
- fi
303
-
304
- exit 0
3
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
4
+ exec "$SCRIPT_DIR/lib/run-forge-helper.sh" "check-architecture-sync.sh" "$@"
@@ -1,255 +1,4 @@
1
1
  #!/bin/bash
2
2
  set -euo pipefail
3
-
4
- usage() {
5
- cat <<'USAGE_EOF'
6
- Usage: scripts/check-brain-manifest.sh [--manifest PATH] [--require-vault]
7
-
8
- Validates the repo-local external knowledge manifest and, when the configured
9
- iCloud brain vault is available locally, checks that referenced vault files exist.
10
- USAGE_EOF
11
- }
12
-
13
- manifest_path=".ai/harness/brain-manifest.json"
14
- require_vault=0
15
-
16
- while [[ $# -gt 0 ]]; do
17
- case "$1" in
18
- --manifest)
19
- manifest_path="${2:-}"
20
- shift 2
21
- ;;
22
- --require-vault)
23
- require_vault=1
24
- shift
25
- ;;
26
- --help|-h)
27
- usage
28
- exit 0
29
- ;;
30
- *)
31
- echo "Unknown argument: $1" >&2
32
- usage
33
- exit 1
34
- ;;
35
- esac
36
- done
37
-
38
- resolve_js_runtime() {
39
- if command -v node >/dev/null 2>&1; then
40
- printf 'node'
41
- return 0
42
- fi
43
-
44
- if command -v bun >/dev/null 2>&1; then
45
- printf 'bun'
46
- return 0
47
- fi
48
-
49
- return 1
50
- }
51
-
52
- runtime="$(resolve_js_runtime || true)"
53
- if [[ -z "$runtime" ]]; then
54
- echo "[brain] Missing node or bun to read brain manifest: $manifest_path"
55
- exit 1
56
- fi
57
-
58
- "$runtime" - "$manifest_path" "$require_vault" <<'JS_EOF'
59
- const fs = require("fs");
60
- const path = require("path");
61
- const os = require("os");
62
-
63
- const [, , manifestArg, requireVaultArg] = process.argv;
64
- const requireVault = requireVaultArg === "1";
65
- const repoRoot = process.cwd();
66
- const manifestPath = path.resolve(repoRoot, manifestArg || ".ai/harness/brain-manifest.json");
67
- const policyPath = path.resolve(repoRoot, ".ai/harness/policy.json");
68
- let issues = 0;
69
-
70
- function issue(message) {
71
- console.log(`[brain] ${message}`);
72
- issues += 1;
73
- }
74
-
75
- function warn(message) {
76
- console.log(`[brain] warning: ${message}`);
77
- }
78
-
79
- function readJson(filePath, label) {
80
- try {
81
- return JSON.parse(fs.readFileSync(filePath, "utf8"));
82
- } catch (error) {
83
- issue(`Cannot read ${label}: ${path.relative(repoRoot, filePath) || filePath}`);
84
- return null;
85
- }
86
- }
87
-
88
- function stripWildcard(logicalPath) {
89
- return String(logicalPath || "").replace(/\/\*$/, "/");
90
- }
91
-
92
- const defaultBrainRoot = process.env.FORGE_BRAIN_ROOT ||
93
- path.join(os.homedir(), "Library", "Mobile Documents", "com~apple~CloudDocs", "brain");
94
-
95
- function logicalToLocal(logicalPath) {
96
- const value = String(logicalPath || "");
97
- if (value.startsWith("brain/")) {
98
- return path.join(defaultBrainRoot, value.slice("brain/".length));
99
- }
100
- if (value.startsWith("~/")) {
101
- return path.join(os.homedir(), value.slice(2));
102
- }
103
- return path.resolve(repoRoot, value);
104
- }
105
-
106
- function normalizeRel(filePath) {
107
- return path.relative(repoRoot, path.resolve(repoRoot, filePath)).replaceAll(path.sep, "/");
108
- }
109
-
110
- function fileExistsWithSelfHostFallback(relPath) {
111
- if (!relPath) return false;
112
- if (fs.existsSync(path.resolve(repoRoot, relPath))) return true;
113
- if (relPath.startsWith(".ai/harness/scripts/")) {
114
- const helperName = path.basename(relPath);
115
- return fs.existsSync(path.resolve(repoRoot, "scripts", helperName)) &&
116
- fs.existsSync(path.resolve(repoRoot, "assets", "templates", "helpers", helperName));
117
- }
118
- return false;
119
- }
120
-
121
- function hasDuplicate(values) {
122
- return values.some((value, index) => value && values.indexOf(value) !== index);
123
- }
124
-
125
- if (!fs.existsSync(manifestPath)) {
126
- issue(`Missing brain manifest: ${normalizeRel(manifestPath)}`);
127
- process.exit(1);
128
- }
129
-
130
- const manifest = readJson(manifestPath, "brain manifest");
131
- const policy = fs.existsSync(policyPath) ? readJson(policyPath, "harness policy") : null;
132
-
133
- if (!manifest) {
134
- process.exit(1);
135
- }
136
-
137
- const manifestRel = normalizeRel(manifestPath);
138
- const externalKnowledge = policy?.information_lifecycle?.external_knowledge || {};
139
- const policyManifest = externalKnowledge.manifest_file;
140
- const policyProjectPath = externalKnowledge.project_path;
141
- const policySyncScript = externalKnowledge.sync_script;
142
-
143
- if (policyManifest && policyManifest !== manifestRel) {
144
- issue(`Policy external_knowledge.manifest_file points to ${policyManifest}, expected ${manifestRel}`);
145
- }
146
- if (policySyncScript && !fileExistsWithSelfHostFallback(policySyncScript)) {
147
- issue(`Policy external_knowledge.sync_script is missing: ${policySyncScript}`);
148
- }
149
-
150
- if (!manifest.version) {
151
- issue("Brain manifest is missing version");
152
- }
153
- if (!manifest.project) {
154
- issue("Brain manifest is missing project");
155
- }
156
- if (!manifest.default_brain_path) {
157
- issue("Brain manifest is missing default_brain_path");
158
- }
159
- if (policyProjectPath && manifest.default_brain_path && policyProjectPath !== manifest.default_brain_path) {
160
- issue(`Policy project_path ${policyProjectPath} does not match manifest default_brain_path ${manifest.default_brain_path}`);
161
- }
162
- if (!Array.isArray(manifest.entries)) {
163
- issue("Brain manifest entries must be an array");
164
- }
165
-
166
- const entries = Array.isArray(manifest.entries) ? manifest.entries : [];
167
- const ids = entries.map((entry) => entry.id);
168
- const repoPaths = entries.map((entry) => entry.repo_path);
169
- const brainPaths = entries.map((entry) => entry.brain_path);
170
- const gbrainSlugs = entries.map((entry) => entry.gbrain_slug);
171
-
172
- if (hasDuplicate(ids)) issue("Brain manifest contains duplicate entry ids");
173
- if (hasDuplicate(repoPaths)) issue("Brain manifest contains duplicate repo_path values");
174
- if (hasDuplicate(brainPaths)) issue("Brain manifest contains duplicate brain_path values");
175
- if (hasDuplicate(gbrainSlugs)) issue("Brain manifest contains duplicate gbrain_slug values");
176
-
177
- const defaultPrefix = stripWildcard(manifest.default_brain_path);
178
- const localVaultRoot = logicalToLocal(defaultPrefix);
179
- const shouldCheckVault = requireVault || fs.existsSync(localVaultRoot);
180
- if (entries.length > 0 && !shouldCheckVault) {
181
- warn(`vault root unavailable; skipped external file existence checks: ${localVaultRoot}`);
182
- }
183
-
184
- for (const entry of entries) {
185
- const id = entry.id || "(missing id)";
186
- const repoPath = entry.repo_path;
187
- const assetPath = entry.asset_path;
188
- const brainPath = entry.brain_path;
189
- const gbrainSlug = entry.gbrain_slug;
190
- const maxRepoLines = Number(entry.max_repo_lines || 0);
191
- const syncDirection = entry.sync?.direction || entry.sync_direction || "";
192
- const isRepoToBrainSync = syncDirection === "repo-to-brain";
193
-
194
- if (!entry.id) issue("Entry is missing id");
195
- if (!repoPath) issue(`Entry ${id} is missing repo_path`);
196
- if (!brainPath) issue(`Entry ${id} is missing brain_path`);
197
- if (!gbrainSlug) issue(`Entry ${id} is missing gbrain_slug`);
198
- if (syncDirection && syncDirection !== "repo-to-brain") {
199
- issue(`Entry ${id} has unsupported sync.direction: ${syncDirection}`);
200
- }
201
-
202
- if (brainPath && defaultPrefix && !String(brainPath).startsWith(defaultPrefix)) {
203
- issue(`Entry ${id} brain_path is outside default_brain_path: ${brainPath}`);
204
- }
205
-
206
- if (repoPath) {
207
- const repoFile = path.resolve(repoRoot, repoPath);
208
- if (!fs.existsSync(repoFile)) {
209
- issue(`Entry ${id} repo_path is missing: ${repoPath}`);
210
- } else {
211
- const content = fs.readFileSync(repoFile, "utf8");
212
- if (!isRepoToBrainSync && brainPath && !content.includes(brainPath)) {
213
- issue(`Entry ${id} repo stub does not mention brain_path: ${repoPath}`);
214
- }
215
- if (!isRepoToBrainSync && gbrainSlug && !content.includes(gbrainSlug)) {
216
- issue(`Entry ${id} repo stub does not mention gbrain_slug: ${repoPath}`);
217
- }
218
- if (maxRepoLines > 0) {
219
- const lineCount = content.endsWith("\n") ? content.split("\n").length - 1 : content.split("\n").length;
220
- if (lineCount > maxRepoLines) {
221
- issue(`Entry ${id} repo stub has ${lineCount} lines, max ${maxRepoLines}: ${repoPath}`);
222
- }
223
- }
224
- }
225
- }
226
-
227
- if (repoPath && assetPath) {
228
- const repoFile = path.resolve(repoRoot, repoPath);
229
- const assetFile = path.resolve(repoRoot, assetPath);
230
- if (!fs.existsSync(assetFile)) {
231
- issue(`Entry ${id} asset_path is missing: ${assetPath}`);
232
- } else if (fs.existsSync(repoFile)) {
233
- const repoContent = fs.readFileSync(repoFile, "utf8");
234
- const assetContent = fs.readFileSync(assetFile, "utf8");
235
- if (repoContent !== assetContent) {
236
- issue(`Entry ${id} repo_path and asset_path differ: ${repoPath} != ${assetPath}`);
237
- }
238
- }
239
- }
240
-
241
- if (brainPath && shouldCheckVault) {
242
- const localBrainFile = logicalToLocal(brainPath);
243
- if (!fs.existsSync(localBrainFile)) {
244
- issue(`Entry ${id} brain file is missing: ${brainPath}`);
245
- }
246
- }
247
- }
248
-
249
- if (issues === 0) {
250
- console.log("[brain] OK");
251
- process.exit(0);
252
- }
253
-
254
- process.exit(1);
255
- JS_EOF
3
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
4
+ exec "$SCRIPT_DIR/lib/run-forge-helper.sh" "check-brain-manifest.sh" "$@"
@@ -1,49 +1,4 @@
1
1
  #!/bin/bash
2
2
  set -euo pipefail
3
-
4
- usage() {
5
- cat <<'USAGE_EOF'
6
- Usage: scripts/check-context-files.sh
7
- USAGE_EOF
8
- }
9
-
10
- if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
11
- usage
12
- exit 0
13
- fi
14
-
15
- issues=0
16
- files="$(
17
- find . \
18
- \( -path './.git' -o -path './node_modules' -o -path './_ref' -o -path './_ops' -o -path './.worktrees' \) -prune -o \
19
- -type f \( -name 'AGENTS.md' -o -name 'CLAUDE.md' \) -print \
20
- | sort
21
- )"
22
-
23
- if [[ -z "$files" ]]; then
24
- echo "[ContextScan] No AGENTS.md or CLAUDE.md files found."
25
- exit 0
26
- fi
27
-
28
- scan_pattern() {
29
- local label="$1"
30
- local regex="$2"
31
- local match
32
-
33
- match="$(printf '%s\n' "$files" | xargs grep -Eni "$regex" 2>/dev/null | head -1 || true)"
34
- if [[ -n "$match" ]]; then
35
- echo "[ContextScan] ${label}: ${match}"
36
- issues=$((issues + 1))
37
- fi
38
- }
39
-
40
- scan_pattern "prompt-injection" '(ignore (all|any|previous) instructions|reveal (the )?(system|developer) prompt|bypass (the )?(guard|policy)|override (the )?(policy|guard))'
41
- scan_pattern "secret-exfiltration" '(print|show|copy|upload|send).*(api key|token|secret|credential|\.env)|curl .*https?://|wget .*https?://'
42
- scan_pattern "filesystem-exfiltration" '(read|cat|copy).*(\.env|id_rsa|config\.yaml|secrets?)'
43
-
44
- if [[ "$issues" -gt 0 ]]; then
45
- echo "[ContextScan] FAIL (${issues} suspicious pattern(s))"
46
- exit 1
47
- fi
48
-
49
- echo "[ContextScan] SAFE"
3
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
4
+ exec "$SCRIPT_DIR/lib/run-forge-helper.sh" "check-context-files.sh" "$@"