@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,774 +1,4 @@
1
1
  #!/bin/bash
2
2
  set -euo pipefail
3
-
4
3
  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
- if REPO_ROOT="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null)"; then
6
- cd "$REPO_ROOT"
7
- elif [[ "$SCRIPT_DIR" == */.ai/harness/scripts ]]; then
8
- cd "$SCRIPT_DIR/../../.."
9
- else
10
- cd "$SCRIPT_DIR/.."
11
- fi
12
-
13
- usage() {
14
- cat <<'USAGE_EOF'
15
- Usage: scripts/plan-to-todo.sh --plan <plan-file>
16
- USAGE_EOF
17
- }
18
-
19
- # Source shared workflow-state library if available (installed via migration).
20
- # This avoids duplicating task-state JSON generation logic.
21
- _WF_LIB=".ai/hooks/lib/workflow-state.sh"
22
- if [[ -f "$_WF_LIB" ]]; then
23
- # shellcheck source=/dev/null
24
- . "$_WF_LIB"
25
- _HAS_WF_LIB=1
26
- else
27
- _HAS_WF_LIB=0
28
- fi
29
-
30
- # Fallback json_escape only when workflow-state.sh is not available
31
- if [[ "$_HAS_WF_LIB" -eq 0 ]]; then
32
- workflow_json_escape() {
33
- local value="$1"
34
- value="${value//\\/\\\\}"
35
- value="${value//\"/\\\"}"
36
- value="${value//$'\n'/\\n}"
37
- value="${value//$'\r'/\\r}"
38
- value="${value//$'\t'/\\t}"
39
- printf '%s' "$value"
40
- }
41
- fi
42
-
43
- extract_status() {
44
- local file="$1"
45
- awk '/\*\*Status\*\*:/ {sub(/^.*\*\*Status\*\*: */, ""); gsub(/\r/, ""); print; exit}' "$file" | xargs
46
- }
47
-
48
- plan_evidence_contract_error() {
49
- local file="$1"
50
- local section=""
51
- local missing=0
52
-
53
- section="$(awk '
54
- BEGIN { in_section = 0 }
55
- /^## Evidence Contract[[:space:]]*$/ { in_section = 1; next }
56
- in_section && /^## / { exit }
57
- in_section { print }
58
- ' "$file")"
59
-
60
- if [[ -z "$(printf '%s' "$section" | tr -d '[:space:]')" ]]; then
61
- echo "missing ## Evidence Contract section"
62
- return 1
63
- fi
64
-
65
- local label line value
66
- for label in "State/progress path" "Verification evidence" "Impact review|Evaluator rubric" "Stop condition" "Rollback surface"; do
67
- line="$(printf '%s\n' "$section" | grep -Ei "^[[:space:]]*-[[:space:]]*(\\*\\*)?${label}(\\*\\*)?[[:space:]]*:" | head -1 || true)"
68
- if [[ -z "$line" ]]; then
69
- echo "missing field: ${label}"
70
- missing=1
71
- continue
72
- fi
73
-
74
- value="${line#*:}"
75
- value="$(printf '%s' "$value" | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//')"
76
- if [[ -z "$value" ]] || printf '%s' "$value" | grep -Eiq '^(tbd|todo|n/a|none|unknown|\.\.\.)$'; then
77
- echo "field has no concrete value: ${label}"
78
- missing=1
79
- fi
80
- done
81
-
82
- [[ "$missing" -eq 0 ]]
83
- }
84
-
85
- extract_capability_id() {
86
- local file="$1"
87
- awk -F': ' '/^\> \*\*Capability ID\*\*:/ {print $2; exit}' "$file" | xargs
88
- }
89
-
90
- get_todo_source_plan() {
91
- awk -F': ' '/^\> \*\*Source Plan\*\*:/ {print $2; exit}' tasks/todos.md 2>/dev/null | xargs
92
- }
93
-
94
- plan_slug_from_path() {
95
- local plan_file="$1"
96
- local base slug
97
- base="$(basename "$plan_file")"
98
- slug="$(printf '%s' "$base" | sed -E 's/^plan-[0-9]{8}-[0-9]{4}-//; s/\.md$//')"
99
- printf '%s' "$slug"
100
- }
101
-
102
- plan_original_artifact_stem_from_path() {
103
- local plan_file="$1"
104
- local base stem
105
- base="$(basename "$plan_file")"
106
- stem="$(printf '%s' "$base" | sed -E 's/^plan-//; s/\.md$//')"
107
- if [[ "$stem" =~ ^[0-9]{8}-[0-9]{4}-.+ ]]; then
108
- printf '%s' "$stem"
109
- else
110
- plan_slug_from_path "$plan_file"
111
- fi
112
- }
113
-
114
- is_transient_plan_slug() {
115
- case "$1" in
116
- think-plan-[0-9]*|codex-plan-[0-9]*|approved-plan-[0-9]*)
117
- return 0
118
- ;;
119
- esac
120
- return 1
121
- }
122
-
123
- plan_title_slug_from_file() {
124
- local plan_file="$1"
125
- local title slug
126
- [[ -f "$plan_file" ]] || return 1
127
- title="$(awk '
128
- /^# Plan:[[:space:]]*/ {
129
- sub(/^# Plan:[[:space:]]*/, "")
130
- print
131
- exit
132
- }
133
- ' "$plan_file" | xargs)"
134
- [[ -n "$title" ]] || return 1
135
- slug="$(printf '%s' "$title" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9]+/-/g; s/^-+//; s/-+$//; s/-{2,}/-/g')"
136
- [[ -n "$slug" ]] || return 1
137
- printf '%s' "$slug"
138
- }
139
-
140
- plan_task_profile_from_file() {
141
- local plan_file="$1"
142
- local profile
143
- profile="$(awk '
144
- /^> \*\*Task Profile\*\*:/ {
145
- sub(/^> \*\*Task Profile\*\*:[[:space:]]*/, "")
146
- gsub(/\r/, "")
147
- print
148
- exit
149
- }
150
- ' "$plan_file" | xargs)"
151
- printf '%s' "${profile:-code-change}"
152
- }
153
-
154
- plan_artifact_stem_from_path() {
155
- local plan_file="$1"
156
- local stem stamp slug title_slug
157
- stem="$(plan_original_artifact_stem_from_path "$plan_file")"
158
- if [[ "$stem" =~ ^[0-9]{8}-[0-9]{4}-.+ ]]; then
159
- stamp="$(printf '%s' "$stem" | sed -E 's/^([0-9]{8}-[0-9]{4})-.+$/\1/')"
160
- slug="$(printf '%s' "$stem" | sed -E 's/^[0-9]{8}-[0-9]{4}-//')"
161
- if is_transient_plan_slug "$slug"; then
162
- title_slug="$(plan_title_slug_from_file "$plan_file" || true)"
163
- if [[ -n "$title_slug" && "$title_slug" != "$slug" ]]; then
164
- printf '%s-%s' "$stamp" "$title_slug"
165
- return 0
166
- fi
167
- fi
168
- printf '%s' "$stem"
169
- else
170
- plan_slug_from_path "$plan_file"
171
- fi
172
- }
173
-
174
- policy_get() {
175
- local jq_path="$1"
176
- local default_value="${2:-}"
177
- local value=""
178
-
179
- if [[ -f ".ai/harness/policy.json" ]] && command -v jq >/dev/null 2>&1; then
180
- value="$(jq -r "$jq_path // empty" ".ai/harness/policy.json" 2>/dev/null || true)"
181
- if [[ -n "$value" ]]; then
182
- printf '%s' "$value"
183
- return 0
184
- fi
185
- fi
186
-
187
- printf '%s' "$default_value"
188
- }
189
-
190
- is_linked_worktree() {
191
- local git_dir
192
- git_dir="$(git rev-parse --git-dir 2>/dev/null || true)"
193
- [[ "$git_dir" == *".git/worktrees/"* ]]
194
- }
195
-
196
- plan_requests_contract_worktree() {
197
- local file="$1"
198
- local auto_for_contract_tasks
199
-
200
- if grep -Eiq '^\> \*\*(Contract Level|Execution Mode|Execution Surface)\*\*:[[:space:]]*(false|primary|inline)[[:space:]]*$' "$file"; then
201
- return 1
202
- fi
203
-
204
- if grep -Eiq '^\> \*\*(Contract Level|Execution Mode|Execution Surface)\*\*:[[:space:]]*(true|worktree|contract-worktree)[[:space:]]*$' "$file"; then
205
- return 0
206
- fi
207
-
208
- auto_for_contract_tasks="$(policy_get '.worktree_strategy.auto_for_contract_tasks' 'false')"
209
- [[ "$auto_for_contract_tasks" == "true" ]]
210
- }
211
-
212
- maybe_start_contract_worktree() {
213
- local file="$1"
214
-
215
- [[ "${FORGE_CONTRACT_WORKTREE:-}" != "1" ]] || return 0
216
- [[ "${FORGE_DISABLE_CONTRACT_WORKTREE:-}" != "1" ]] || return 0
217
- [[ -x "scripts/contract-worktree.sh" ]] || return 0
218
- git rev-parse --is-inside-work-tree >/dev/null 2>&1 || return 0
219
- ! is_linked_worktree || return 0
220
- plan_requests_contract_worktree "$file" || return 0
221
-
222
- bash "scripts/contract-worktree.sh" start --plan "$file"
223
- exit $?
224
- }
225
-
226
- set_plan_status() {
227
- local file="$1"
228
- local status="$2"
229
- local tmp_file
230
- tmp_file="$(mktemp)"
231
- awk -v next_status="$status" '
232
- BEGIN { updated = 0 }
233
- {
234
- if (!updated && $0 ~ /\*\*Status\*\*:/) {
235
- sub(/\*\*Status\*\*: .*/, "**Status**: " next_status)
236
- updated = 1
237
- }
238
- print
239
- }
240
- ' "$file" > "$tmp_file"
241
- mv "$tmp_file" "$file"
242
- }
243
-
244
- unique_archive_path() {
245
- local desired="$1"
246
- if [[ ! -e "$desired" ]]; then
247
- printf '%s' "$desired"
248
- return
249
- fi
250
-
251
- local stem counter candidate
252
- stem="${desired%.md}"
253
- counter=2
254
- candidate="${stem}-v${counter}.md"
255
- while [[ -e "$candidate" ]]; do
256
- counter=$((counter + 1))
257
- candidate="${stem}-v${counter}.md"
258
- done
259
- printf '%s' "$candidate"
260
- }
261
-
262
- rewrite_plan_artifact_references() {
263
- local plan_file="$1"
264
- local from_stem="$2"
265
- local to_stem="$3"
266
- local tmp_file
267
-
268
- [[ -n "$from_stem" && -n "$to_stem" && "$from_stem" != "$to_stem" ]] || return 0
269
-
270
- tmp_file="$(mktemp)"
271
- sed \
272
- -e "s|tasks/contracts/${from_stem}\\.contract\\.md|tasks/contracts/${to_stem}.contract.md|g" \
273
- -e "s|tasks/reviews/${from_stem}\\.review\\.md|tasks/reviews/${to_stem}.review.md|g" \
274
- -e "s|tasks/notes/${from_stem}\\.notes\\.md|tasks/notes/${to_stem}.notes.md|g" \
275
- "$plan_file" > "$tmp_file"
276
- mv "$tmp_file" "$plan_file"
277
- }
278
-
279
- render_contract_file() {
280
- local plan_file="$1"
281
- local contract_file="$2"
282
- local review_file="$3"
283
- local notes_file="$4"
284
- local slug="$5"
285
- local timestamp="$6"
286
- local capability_id="$7"
287
- local owner="${USER:-AI Agent}"
288
- local task_profile
289
- local template_file=".claude/templates/contract.template.md"
290
- local tmp_file
291
-
292
- task_profile="$(plan_task_profile_from_file "$plan_file")"
293
-
294
- if [[ ! -f "$template_file" ]]; then
295
- mkdir -p .claude/templates
296
- cat > "$template_file" <<'CONTRACT_TEMPLATE_EOF'
297
- # Task Contract: {{TASK_SLUG}}
298
-
299
- > **Status**: Pending
300
- > **Plan**: {{PLAN_FILE}}
301
- > **Task Profile**: {{TASK_PROFILE}}
302
- > **Owner**: {{OWNER}}
303
- > **Capability ID**: {{CAPABILITY_ID}}
304
- > **Last Updated**: {{TIMESTAMP}}
305
- > **Review File**: `{{REVIEW_FILE}}`
306
- > **Notes File**: `{{NOTES_FILE}}`
307
-
308
- ## Goal
309
-
310
- Describe the exact outcome this task must deliver.
311
-
312
- ## Scope
313
-
314
- - In scope:
315
- - Out of scope:
316
-
317
- ## Workflow Inventory
318
-
319
- - Source plan: `{{PLAN_FILE}}`
320
- - Deferred-goal ledger: `tasks/todos.md`
321
- - Review file: `{{REVIEW_FILE}}`
322
- - Notes file: `{{NOTES_FILE}}`
323
- - Checks file: `.ai/harness/checks/latest.json`
324
- - Run snapshots: `.ai/harness/runs/`
325
- - Scope gate: edit only paths listed under `allowed_paths`; update this contract before widening scope.
326
- - Completion evidence: `scripts/verify-sprint.sh` reports this contract's direct checks and declared scope. Then perform a fresh semantic impact review.
327
-
328
- ## Allowed Paths
329
-
330
- ```yaml
331
- allowed_paths:
332
- - plans/
333
- - tasks/todos.md
334
- - {{CONTRACT_FILE}}
335
- - {{REVIEW_FILE}}
336
- - {{NOTES_FILE}}
337
- - .ai/context/capabilities.json
338
- - .claude/templates/
339
- - src/
340
- - tests/
341
- ```
342
-
343
- ## Delegation Contract
344
-
345
- ```yaml
346
- delegation:
347
- budget:
348
- tokens: null
349
- tool_calls: null
350
- wall_time_minutes: null
351
- permission_scope:
352
- mode: inherit_allowed_paths
353
- writable_paths: []
354
- network: inherited
355
- roles:
356
- parent:
357
- mode: narrate_and_gatekeep
358
- purpose: approval_checkpoint_owner
359
- explorer:
360
- mode: read_only
361
- purpose: codebase_research
362
- worker:
363
- mode: edit_within_allowed_paths
364
- purpose: implementation
365
- verifier:
366
- mode: read_only
367
- purpose: exit_criteria_review
368
- ```
369
-
370
- ## Exit Criteria (Machine Verifiable)
371
-
372
- ```yaml
373
- exit_criteria:
374
- files_exist:
375
- - src/modules/{{TASK_SLUG}}/index.ts
376
- - {{NOTES_FILE}}
377
- tests_pass:
378
- - path: tests/unit/{{TASK_SLUG}}.test.ts
379
- commands_succeed:
380
- - bun run typecheck
381
- files_contain:
382
- - path: src/modules/{{TASK_SLUG}}/index.ts
383
- pattern: "export"
384
- ```
385
-
386
- ## Acceptance Notes (Human Review)
387
-
388
- - Functional behavior:
389
- - Edge cases:
390
- - Regression risks:
391
-
392
- ## Rollback Point
393
-
394
- - Commit / checkpoint:
395
- - Revert strategy:
396
- CONTRACT_TEMPLATE_EOF
397
- fi
398
-
399
- tmp_file="$(mktemp)"
400
- sed \
401
- -e "s/{{TASK_SLUG}}/${slug}/g" \
402
- -e "s|{{PLAN_FILE}}|${plan_file}|g" \
403
- -e "s|{{TASK_PROFILE}}|${task_profile}|g" \
404
- -e "s|{{CONTRACT_FILE}}|${contract_file}|g" \
405
- -e "s|{{REVIEW_FILE}}|${review_file}|g" \
406
- -e "s|{{NOTES_FILE}}|${notes_file}|g" \
407
- -e "s|{{CAPABILITY_ID}}|${capability_id}|g" \
408
- -e "s/{{OWNER}}/${owner}/g" \
409
- -e "s/{{TIMESTAMP}}/${timestamp}/g" \
410
- "$template_file" \
411
- | sed \
412
- -e "s|tasks/contracts/${slug}\\.contract\\.md|${contract_file}|g" \
413
- -e "s|tasks/reviews/${slug}\\.review\\.md|${review_file}|g" \
414
- -e "s|tasks/notes/${slug}\\.notes\\.md|${notes_file}|g" \
415
- > "$tmp_file"
416
- mv "$tmp_file" "$contract_file"
417
- }
418
-
419
- render_implementation_notes_file() {
420
- local plan_file="$1"
421
- local contract_file="$2"
422
- local review_file="$3"
423
- local notes_file="$4"
424
- local slug="$5"
425
- local timestamp="$6"
426
- local template_file=".claude/templates/implementation-notes.template.md"
427
- local tmp_file
428
-
429
- if [[ ! -f "$template_file" ]]; then
430
- mkdir -p .claude/templates
431
- cat > "$template_file" <<'NOTES_TEMPLATE_EOF'
432
- # Implementation Notes: {{TASK_SLUG}}
433
-
434
- > **Status**: Active
435
- > **Plan**: {{PLAN_FILE}}
436
- > **Contract**: {{CONTRACT_FILE}}
437
- > **Review**: {{REVIEW_FILE}}
438
- > **Last Updated**: {{TIMESTAMP}}
439
- > **Lifecycle**: notes
440
-
441
- ## Design Decisions
442
-
443
- - ...
444
-
445
- ## Deviations From Plan Or Spec
446
-
447
- - None recorded.
448
-
449
- ## Tradeoffs Considered
450
-
451
- | Option | Decision | Reason |
452
- |--------|----------|--------|
453
- | ... | ... | ... |
454
-
455
- ## Open Questions
456
-
457
- - None.
458
-
459
- ## Evidence Links
460
-
461
- - Checks: `.ai/harness/checks/latest.json`
462
- - Run snapshots: `.ai/harness/runs/`
463
-
464
- ## Promotion Candidates
465
-
466
- - Promote to `tasks/lessons.md` only after a repeated correction or failure pattern.
467
- - Promote to `docs/researches/` only when it is durable repo knowledge with evidence.
468
- - Promote to harness asset files only after verification across more than one task or fixture.
469
- NOTES_TEMPLATE_EOF
470
- fi
471
-
472
- tmp_file="$(mktemp)"
473
- sed \
474
- -e "s/{{TASK_SLUG}}/${slug}/g" \
475
- -e "s|{{PLAN_FILE}}|${plan_file}|g" \
476
- -e "s|{{CONTRACT_FILE}}|${contract_file}|g" \
477
- -e "s|{{REVIEW_FILE}}|${review_file}|g" \
478
- -e "s/{{TIMESTAMP}}/${timestamp}/g" \
479
- "$template_file" > "$tmp_file"
480
- mv "$tmp_file" "$notes_file"
481
- }
482
-
483
- # Delegate to workflow-state.sh if available; inline fallback otherwise.
484
- # This ensures a single source of truth for task-state JSON generation.
485
- if [[ "$_HAS_WF_LIB" -eq 0 ]]; then
486
- workflow_sync_task_state_from_todo() {
487
- local todo_file="${1:-tasks/todos.md}"
488
- local state_file="${2:-.claude/.task-state.json}"
489
- local source_plan="${3:-}"
490
- local timestamp
491
- local tmp_state
492
- local total=0
493
- local done=0
494
- local promoted_in_progress=0
495
- local first=1
496
-
497
- mkdir -p "$(dirname "$state_file")"
498
- timestamp="$(date '+%Y-%m-%dT%H:%M:%S%z')"
499
-
500
- {
501
- echo "{"
502
- printf ' "done_tasks": 0,\n'
503
- printf ' "total_tasks": 0,\n'
504
- printf ' "source_plan": "%s",\n' "$(workflow_json_escape "${source_plan:-}")"
505
- printf ' "updated_at": "%s",\n' "$(workflow_json_escape "$timestamp")"
506
- echo ' "tasks": ['
507
-
508
- while IFS= read -r line; do
509
- printf '%s\n' "$line" | grep -Eq '^[[:space:]]*-[[:space:]]\[[ xX]\][[:space:]]+' || continue
510
- total=$((total + 1))
511
- local desc
512
- desc="$(printf '%s' "$line" | sed -E 's/^[[:space:]]*-[[:space:]]\[[ xX]\][[:space:]]+//')"
513
- local status="pending"
514
- local passes="false"
515
-
516
- if [[ "$line" =~ \[[xX]\] ]]; then
517
- status="completed"
518
- passes="true"
519
- done=$((done + 1))
520
- elif [[ "$promoted_in_progress" -eq 0 ]]; then
521
- status="in_progress"
522
- promoted_in_progress=1
523
- fi
524
-
525
- if [[ "$first" -eq 0 ]]; then
526
- echo ","
527
- fi
528
- first=0
529
-
530
- printf ' {"id":"task-%s","desc":"%s","status":"%s","passes":%s,"verification_evidence":[]}' \
531
- "$total" \
532
- "$(workflow_json_escape "$desc")" \
533
- "$status" \
534
- "$passes"
535
- done < "$todo_file"
536
-
537
- echo
538
- echo " ]"
539
- echo "}"
540
- } > "$state_file"
541
-
542
- tmp_state="$(mktemp)"
543
- awk -v done="$done" -v total="$total" '
544
- {
545
- if ($0 ~ /"done_tasks":/) {
546
- printf " \"done_tasks\": %s,\n", done
547
- } else if ($0 ~ /"total_tasks":/) {
548
- printf " \"total_tasks\": %s,\n", total
549
- } else {
550
- print
551
- }
552
- }
553
- ' "$state_file" > "$tmp_state"
554
- mv "$tmp_state" "$state_file"
555
- }
556
- fi
557
-
558
- plan_file=""
559
- while [[ $# -gt 0 ]]; do
560
- case "$1" in
561
- --plan)
562
- [[ -n "${2:-}" ]] || { echo "Error: --plan requires a value" >&2; usage; exit 1; }
563
- plan_file="$2"
564
- shift 2
565
- ;;
566
- --help|-h)
567
- usage
568
- exit 0
569
- ;;
570
- *)
571
- echo "Unknown argument: $1" >&2
572
- usage
573
- exit 1
574
- ;;
575
- esac
576
- done
577
-
578
- if [[ -z "$plan_file" ]]; then
579
- echo "--plan is required" >&2
580
- usage
581
- exit 1
582
- fi
583
-
584
- if [[ ! -f "$plan_file" ]]; then
585
- echo "Plan file not found: $plan_file" >&2
586
- exit 1
587
- fi
588
-
589
- status="$(extract_status "$plan_file")"
590
- if [[ "$status" != "Approved" ]]; then
591
- echo "Plan status must be Approved before extraction (current: ${status:-unknown})." >&2
592
- exit 1
593
- fi
594
-
595
- if ! evidence_error="$(plan_evidence_contract_error "$plan_file")"; then
596
- echo "Plan Evidence Contract is incomplete in $plan_file:" >&2
597
- printf '%s\n' "$evidence_error" >&2
598
- exit 1
599
- fi
600
-
601
- maybe_start_contract_worktree "$plan_file"
602
-
603
- mkdir -p tasks/archive
604
- mkdir -p tasks/contracts
605
- mkdir -p tasks/reviews
606
- mkdir -p tasks/notes
607
- mkdir -p .claude
608
- mkdir -p .ai/context
609
- mkdir -p .ai/harness/checks
610
- mkdir -p .ai/harness/session .ai/harness/controller/packets .ai/harness/projections .ai/harness/transfers
611
- mkdir -p .ai/harness/failures
612
- mkdir -p .ai/harness/planning
613
- mkdir -p .ai/harness/runs
614
-
615
- timestamp="$(date +%Y%m%d-%H%M)"
616
- timestamp_human="$(date '+%Y-%m-%d %H:%M')"
617
- plan_base="$(basename "$plan_file")"
618
- slug="$(plan_slug_from_path "$plan_file")"
619
- original_artifact_stem="$(plan_original_artifact_stem_from_path "$plan_file")"
620
- artifact_stem="$(plan_artifact_stem_from_path "$plan_file")"
621
- contract_file="tasks/contracts/${artifact_stem}.contract.md"
622
- review_file="tasks/reviews/${artifact_stem}.review.md"
623
- notes_file="tasks/notes/${artifact_stem}.notes.md"
624
- previous_source_plan="$(get_todo_source_plan || true)"
625
- parent_run_id="${HOOK_RUN_ID:-${CLAUDE_RUN_ID:-${CODEX_RUN_ID:-run-${timestamp}}}}"
626
- capability_id="$(extract_capability_id "$plan_file")"
627
- capability_id="${capability_id:-root}"
628
-
629
- rewrite_plan_artifact_references "$plan_file" "$original_artifact_stem" "$artifact_stem"
630
-
631
- if [[ -f "tasks/todos.md" ]] \
632
- && grep -q '[^[:space:]]' tasks/todos.md \
633
- && ! grep -Eq '^> \*\*Status\*\*:[[:space:]]*Backlog[[:space:]]*$' tasks/todos.md; then
634
- archive_file="$(unique_archive_path "tasks/archive/todo-${timestamp}-${slug}.md")"
635
- {
636
- echo "> **Archived**: $(date '+%Y-%m-%d %H:%M')"
637
- echo "> **Related Plan**: ${plan_file}"
638
- echo "> **Outcome**: Converted to deferred-goal ledger"
639
- echo "> **Source Plan**: ${previous_source_plan:-"(none)"}"
640
- echo "> **Parent Run ID**: ${parent_run_id}"
641
- echo
642
- cat tasks/todos.md
643
- } > "$archive_file"
644
- fi
645
-
646
- if [[ ! -f "tasks/todos.md" ]] || ! grep -Eq '^> \*\*Status\*\*:[[:space:]]*Backlog[[:space:]]*$' tasks/todos.md; then
647
- {
648
- echo "# Deferred Goal Ledger"
649
- echo
650
- echo "> **Status**: Backlog"
651
- echo "> **Updated**: ${timestamp_human}"
652
- echo "> **Scope**: Medium/long-term goals deferred from active plan execution"
653
- echo
654
- echo "Current plan tasks live in \`${plan_file}\` under \`## Task Breakdown\`."
655
- echo "Do not duplicate that execution checklist here. Record only work intentionally deferred beyond this slice, with the tradeoff and revisit trigger."
656
- echo
657
- echo "## Deferred Goals"
658
- echo
659
- echo "| Goal | Why Deferred | Tradeoff | Revisit Trigger |"
660
- echo "|------|--------------|----------|-----------------|"
661
- echo "| (none) | No deferred medium/long-term goal recorded for this projection. | Keep this sprint bounded. | Add a row when a real follow-up is postponed. |"
662
- } > tasks/todos.md
663
- else
664
- todo_tmp="$(mktemp)"
665
- awk -v timestamp_human="$timestamp_human" -v plan_file="$plan_file" '
666
- /^\> \*\*Updated\*\*:/ {
667
- print "> **Updated**: " timestamp_human
668
- next
669
- }
670
- /^Current plan tasks live in `/ {
671
- print "Current plan tasks live in `" plan_file "` under `## Task Breakdown`."
672
- next
673
- }
674
- { print }
675
- ' tasks/todos.md > "$todo_tmp"
676
- mv "$todo_tmp" tasks/todos.md
677
- fi
678
-
679
- rm -f .claude/.task-state.json
680
-
681
- if [[ -f ".claude/templates/review.template.md" ]]; then
682
- :
683
- else
684
- mkdir -p .claude/templates
685
- cat > .claude/templates/review.template.md <<'REVIEW_TEMPLATE_EOF'
686
- # Task Review: {{TASK_SLUG}}
687
-
688
- > **Status**: Pending
689
- > **Plan**: {{PLAN_FILE}}
690
- > **Contract**: {{CONTRACT_FILE}}
691
- > **Notes File**: {{NOTES_FILE}}
692
- > **Checks File**: {{CHECKS_FILE}}
693
- > **Last Updated**: {{TIMESTAMP}}
694
- > **Summary**:
695
-
696
- ## Semantic Impact Review
697
-
698
- - User intent:
699
- - Affected domains and downstream consumers:
700
- - State transitions and persistence/restart impact:
701
- - Missing impact areas or uncertainty:
702
- - Residual risks and recovery:
703
-
704
- ## Mode Evidence
705
-
706
- - Selected route:
707
- - P1/P2/P3 evidence:
708
- - Root cause or plan evidence:
709
-
710
- ## Verification Evidence
711
-
712
- - Focused/full checks:
713
- - Commands run:
714
- - Manual checks:
715
- - Supporting artifacts:
716
- - Implementation notes reviewed:
717
- - Run snapshot:
718
-
719
- ## Scenario Evidence
720
-
721
- - ...
722
-
723
- ## Residual Risks / Follow-ups
724
-
725
- - ...
726
-
727
- ## Failing Items
728
-
729
- - ...
730
-
731
- ## Retest Steps
732
-
733
- - Re-run:
734
- - Re-check:
735
-
736
- ## Summary
737
-
738
- - ...
739
- REVIEW_TEMPLATE_EOF
740
- fi
741
-
742
- render_contract_file "$plan_file" "$contract_file" "$review_file" "$notes_file" "$slug" "$timestamp_human" "$capability_id"
743
- render_implementation_notes_file "$plan_file" "$contract_file" "$review_file" "$notes_file" "$slug" "$timestamp_human"
744
- sed \
745
- -e "s/{{TASK_SLUG}}/${slug}/g" \
746
- -e "s|{{PLAN_FILE}}|${plan_file}|g" \
747
- -e "s|{{CONTRACT_FILE}}|${contract_file}|g" \
748
- -e "s|{{NOTES_FILE}}|${notes_file}|g" \
749
- -e "s|{{CHECKS_FILE}}|.ai/harness/checks/latest.json|g" \
750
- -e "s/{{TIMESTAMP}}/${timestamp_human}/g" \
751
- .claude/templates/review.template.md > "$review_file"
752
-
753
- if [[ ! -f ".ai/harness/checks/latest.json" ]]; then
754
- echo "{}" > .ai/harness/checks/latest.json
755
- fi
756
-
757
- set_plan_status "$plan_file" "Executing"
758
- if declare -F set_active_plan >/dev/null 2>&1; then
759
- set_active_plan "$plan_file"
760
- else
761
- mkdir -p .ai/harness .claude
762
- printf '%s' "$plan_file" > .ai/harness/active-plan
763
- printf '%s' "$plan_file" > .claude/.active-plan
764
- pwd -P > .ai/harness/active-worktree
765
- fi
766
-
767
- if declare -F workflow_clear_pending_orchestration >/dev/null 2>&1; then
768
- workflow_clear_pending_orchestration
769
- else
770
- rm -f .ai/harness/planning/pending.json
771
- fi
772
-
773
- echo "Prepared sprint artifacts from $plan_file"
774
- echo "Left tasks/todos.md as deferred-goal ledger; execute the plan's own ## Task Breakdown."
4
+ exec "$SCRIPT_DIR/lib/run-forge-helper.sh" "plan-to-todo.sh" "$@"