@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,244 +1,4 @@
1
1
  #!/bin/bash
2
2
  set -euo pipefail
3
-
4
- usage() {
5
- cat <<'USAGE_EOF'
6
- Usage:
7
- scripts/archive-architecture-request.sh --request <docs/architecture/requests/file.md> --status <resolved|superseded|rejected|no-change> [--artifact <path>] [--note <text>]
8
-
9
- Archives a handled architecture drift request without making semantic architecture decisions.
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
- request_file=""
18
- status=""
19
- note=""
20
- artifacts=()
21
-
22
- safe_token() {
23
- local value="$1"
24
- value="$(printf '%s' "$value" | tr '[:upper:]' '[:lower:]')"
25
- value="$(printf '%s' "$value" | sed -E 's/[^a-z0-9]+/-/g; s/^-+//; s/-+$//; s/-{2,}/-/g')"
26
- printf '%s' "${value:-request}"
27
- }
28
-
29
- repo_relative_path() {
30
- local value="$1"
31
- value="${value#file://}"
32
- case "$value" in
33
- "$repo"/*)
34
- value="${value#$repo/}"
35
- ;;
36
- /*)
37
- return 1
38
- ;;
39
- ./*)
40
- value="${value#./}"
41
- ;;
42
- esac
43
-
44
- case "$value" in
45
- ""|.|..|../*|*/../*|*$'\n'*|*$'\r'*)
46
- return 1
47
- ;;
48
- esac
49
-
50
- printf '%s' "$value"
51
- }
52
-
53
- canonical_status() {
54
- case "$(safe_token "$1")" in
55
- resolved)
56
- printf 'Resolved'
57
- ;;
58
- superseded)
59
- printf 'Superseded'
60
- ;;
61
- rejected)
62
- printf 'Rejected'
63
- ;;
64
- no-change|no-architecture-change|no-arch-change)
65
- printf 'No architecture change'
66
- ;;
67
- *)
68
- return 1
69
- ;;
70
- esac
71
- }
72
-
73
- clear_contract_pending_request() {
74
- local rel_request="$1"
75
- local short_request="${rel_request#docs/architecture/}"
76
- local file tmp
77
-
78
- find . \
79
- \( -path './.git' -o -path './node_modules' -o -path './_ref' -o -path './_ops' \) -prune -o \
80
- \( -name 'AGENTS.md' -o -name 'CLAUDE.md' \) -type f -print 2>/dev/null |
81
- while IFS= read -r file; do
82
- if ! grep -Fq "Pending architecture request: \`${rel_request}\`" "$file" &&
83
- ! grep -Fq "Pending architecture request: \`${short_request}\`" "$file"; then
84
- continue
85
- fi
86
- tmp="$(mktemp)" || continue
87
- awk -v rel="$rel_request" -v short="$short_request" '
88
- index($0, "Pending architecture request: `" rel "`") > 0 ||
89
- index($0, "Pending architecture request: `" short "`") > 0 {
90
- print "- Pending architecture request: `(none)`"
91
- next
92
- }
93
- { print }
94
- ' "$file" > "$tmp"
95
- mv "$tmp" "$file"
96
- echo "[ArchitectureArchive] Cleared pending architecture request in ${file#./}"
97
- done
98
- }
99
-
100
- while [[ $# -gt 0 ]]; do
101
- case "$1" in
102
- --request)
103
- [[ -n "${2:-}" ]] || { echo "archive-architecture-request: --request requires a value" >&2; exit 2; }
104
- request_file="$2"
105
- shift 2
106
- ;;
107
- --status)
108
- [[ -n "${2:-}" ]] || { echo "archive-architecture-request: --status requires a value" >&2; exit 2; }
109
- status="$2"
110
- shift 2
111
- ;;
112
- --artifact)
113
- [[ -n "${2:-}" ]] || { echo "archive-architecture-request: --artifact requires a value" >&2; exit 2; }
114
- artifacts+=("$2")
115
- shift 2
116
- ;;
117
- --note)
118
- [[ -n "${2:-}" ]] || { echo "archive-architecture-request: --note requires a value" >&2; exit 2; }
119
- note="$2"
120
- shift 2
121
- ;;
122
- --help|-h)
123
- usage
124
- exit 0
125
- ;;
126
- *)
127
- echo "archive-architecture-request: unknown argument: $1" >&2
128
- usage
129
- exit 2
130
- ;;
131
- esac
132
- done
133
-
134
- if [[ -z "$request_file" || -z "$status" ]]; then
135
- usage >&2
136
- exit 2
137
- fi
138
-
139
- rel_request="$(repo_relative_path "$request_file" || true)"
140
- if [[ -z "$rel_request" ]]; then
141
- echo "archive-architecture-request: unsafe request path: $request_file" >&2
142
- exit 2
143
- fi
144
-
145
- case "$rel_request" in
146
- docs/architecture/requests/*.md)
147
- ;;
148
- *)
149
- echo "archive-architecture-request: request must be under docs/architecture/requests/: $rel_request" >&2
150
- exit 2
151
- ;;
152
- esac
153
-
154
- case "$rel_request" in
155
- docs/architecture/requests/archive/*)
156
- echo "archive-architecture-request: request is already archived: $rel_request" >&2
157
- exit 2
158
- ;;
159
- esac
160
-
161
- if [[ ! -f "$rel_request" ]]; then
162
- echo "archive-architecture-request: request not found: $rel_request" >&2
163
- exit 1
164
- fi
165
-
166
- resolved_status="$(canonical_status "$status" || true)"
167
- if [[ -z "$resolved_status" ]]; then
168
- echo "archive-architecture-request: unsupported status: $status" >&2
169
- usage >&2
170
- exit 2
171
- fi
172
-
173
- artifact_lines=()
174
- if [[ "${#artifacts[@]}" -gt 0 ]]; then
175
- for artifact in "${artifacts[@]-}"; do
176
- [[ -n "$artifact" ]] || continue
177
- rel_artifact="$(repo_relative_path "$artifact" || true)"
178
- if [[ -z "$rel_artifact" ]]; then
179
- echo "archive-architecture-request: unsafe artifact path: $artifact" >&2
180
- exit 2
181
- fi
182
- artifact_lines+=("- \`${rel_artifact}\`")
183
- done
184
- fi
185
-
186
- archive_year="$(date '+%Y')"
187
- archive_dir="docs/architecture/requests/archive/${archive_year}"
188
- archive_file="${archive_dir}/$(basename "$rel_request")"
189
- if [[ -e "$archive_file" ]]; then
190
- archive_file="${archive_dir}/$(date '+%Y%m%d-%H%M%S')-$(basename "$rel_request")"
191
- fi
192
-
193
- mkdir -p "$archive_dir"
194
-
195
- tmp_file="$(mktemp)"
196
- awk -v status="$resolved_status" '
197
- BEGIN { replaced = 0 }
198
- /^\> \*\*Status\*\*:/ {
199
- print "> **Status**: " status
200
- replaced = 1
201
- next
202
- }
203
- { print }
204
- END {
205
- if (replaced == 0) {
206
- print ""
207
- print "> **Status**: " status
208
- }
209
- }
210
- ' "$rel_request" > "$tmp_file"
211
-
212
- {
213
- echo ""
214
- echo "## Archive Resolution"
215
- echo ""
216
- echo "- Status: ${resolved_status}"
217
- echo "- Archived: $(date '+%Y-%m-%dT%H:%M:%S%z')"
218
- if [[ "${#artifact_lines[@]}" -gt 0 ]]; then
219
- echo "- Artifacts:"
220
- printf '%s\n' "${artifact_lines[@]}"
221
- else
222
- echo "- Artifacts: (none)"
223
- fi
224
- if [[ -n "$note" ]]; then
225
- echo "- Note: ${note}"
226
- fi
227
- } >> "$tmp_file"
228
-
229
- mv "$tmp_file" "$archive_file"
230
- rm -f "$rel_request"
231
-
232
- index_file="docs/architecture/index.md"
233
- if [[ -f "$index_file" ]]; then
234
- index_tmp="$(mktemp)"
235
- awk -v rel="$rel_request" -v short="${rel_request#docs/architecture/}" '
236
- index($0, rel) == 0 && index($0, short) == 0 { print }
237
- ' "$index_file" > "$index_tmp"
238
- mv "$index_tmp" "$index_file"
239
- fi
240
-
241
- clear_contract_pending_request "$rel_request"
242
-
243
- echo "[ArchitectureArchive] Archived ${rel_request} -> ${archive_file}"
244
- echo "[ArchitectureArchive] status=${resolved_status}"
3
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
4
+ exec "$SCRIPT_DIR/lib/run-forge-helper.sh" "archive-architecture-request.sh" "$@"
@@ -1,294 +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/archive-workflow.sh --plan <plan-file> --outcome <Completed|Abandoned|Superseded>
16
- USAGE_EOF
17
- }
18
-
19
- set_plan_status() {
20
- local file="$1"
21
- local status="$2"
22
- local tmp_file
23
- tmp_file="$(mktemp)"
24
- awk -v next_status="$status" '
25
- BEGIN { updated = 0 }
26
- {
27
- if (!updated && $0 ~ /\*\*Status\*\*:/) {
28
- sub(/\*\*Status\*\*: .*/, "**Status**: " next_status)
29
- updated = 1
30
- }
31
- print
32
- }
33
- ' "$file" > "$tmp_file"
34
- mv "$tmp_file" "$file"
35
- }
36
-
37
- unique_archive_path() {
38
- local desired="$1"
39
- if [[ ! -e "$desired" ]]; then
40
- printf '%s' "$desired"
41
- return
42
- fi
43
-
44
- local stem ext counter candidate
45
- stem="${desired%.md}"
46
- ext=".md"
47
- counter=2
48
- candidate="${stem}-v${counter}${ext}"
49
- while [[ -e "$candidate" ]]; do
50
- counter=$((counter + 1))
51
- candidate="${stem}-v${counter}${ext}"
52
- done
53
- printf '%s' "$candidate"
54
- }
55
-
56
- normalize_slug() {
57
- printf '%s' "$1" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9]+/-/g; s/^-+//; s/-+$//; s/-{2,}/-/g'
58
- }
59
-
60
- is_transient_plan_slug() {
61
- case "$1" in
62
- think-plan-[0-9]*|codex-plan-[0-9]*|approved-plan-[0-9]*)
63
- return 0
64
- ;;
65
- esac
66
- return 1
67
- }
68
-
69
- plan_title_slug_from_file() {
70
- local plan_file="$1"
71
- local title slug
72
- [[ -f "$plan_file" ]] || return 1
73
- title="$(awk '
74
- /^# Plan:[[:space:]]*/ {
75
- sub(/^# Plan:[[:space:]]*/, "")
76
- print
77
- exit
78
- }
79
- ' "$plan_file" | xargs)"
80
- [[ -n "$title" ]] || return 1
81
- slug="$(normalize_slug "$title")"
82
- [[ -n "$slug" ]] || return 1
83
- printf '%s' "$slug"
84
- }
85
-
86
- plan_artifact_stem_from_parts() {
87
- local plan_file="$1"
88
- local original_stem="$2"
89
- local slug="$3"
90
- local stamp title_slug
91
-
92
- if [[ "$original_stem" =~ ^[0-9]{8}-[0-9]{4}-.+ ]]; then
93
- stamp="$(printf '%s' "$original_stem" | sed -E 's/^([0-9]{8}-[0-9]{4})-.+$/\1/')"
94
- if is_transient_plan_slug "$slug"; then
95
- title_slug="$(plan_title_slug_from_file "$plan_file" || true)"
96
- if [[ -n "$title_slug" && "$title_slug" != "$slug" ]]; then
97
- printf '%s-%s' "$stamp" "$title_slug"
98
- return 0
99
- fi
100
- fi
101
- printf '%s' "$original_stem"
102
- else
103
- printf '%s' "$slug"
104
- fi
105
- }
106
-
107
- todo_is_deferred_ledger() {
108
- local file="${1:-tasks/todos.md}"
109
- [[ -f "$file" ]] || return 1
110
- grep -Eq '^# Deferred Goal Ledger[[:space:]]*$' "$file" \
111
- && grep -Eq '^> \*\*Status\*\*:[[:space:]]*Backlog[[:space:]]*$' "$file" \
112
- && grep -Eq '^## Deferred Goals[[:space:]]*$' "$file" \
113
- && grep -Eq '\|[[:space:]]*Goal[[:space:]]*\|[[:space:]]*Why Deferred[[:space:]]*\|[[:space:]]*Tradeoff[[:space:]]*\|[[:space:]]*Revisit Trigger[[:space:]]*\|' "$file"
114
- }
115
-
116
- touch_deferred_ledger_update_marker() {
117
- local file="${1:-tasks/todos.md}"
118
- local tmp_file
119
- tmp_file="$(mktemp)"
120
- awk '
121
- BEGIN { updated = 0 }
122
- !updated && /^> \*\*Updated\*\*:/ {
123
- print "> **Updated**: (archive-workflow)"
124
- updated = 1
125
- next
126
- }
127
- { print }
128
- ' "$file" > "$tmp_file"
129
- mv "$tmp_file" "$file"
130
- }
131
-
132
- write_empty_deferred_ledger() {
133
- cat > tasks/todos.md <<'TODO_EOF'
134
- # Deferred Goal Ledger
135
-
136
- > **Status**: Backlog
137
- > **Updated**: (archive-workflow)
138
- > **Scope**: Medium/long-term goals deferred from active plan execution
139
-
140
- Current plan tasks live in the active plan's `## Task Breakdown`.
141
- Do not duplicate that execution checklist here. Record only work intentionally deferred beyond this slice, with the tradeoff and revisit trigger.
142
-
143
- ## Deferred Goals
144
-
145
- | Goal | Why Deferred | Tradeoff | Revisit Trigger |
146
- |------|--------------|----------|-----------------|
147
- | (none) | Archived workflow did not leave a deferred medium/long-term goal. | Keep the next slice clean. | Add a row when a real follow-up is postponed. |
148
- TODO_EOF
149
- }
150
-
151
- plan_file=""
152
- outcome=""
153
-
154
- while [[ $# -gt 0 ]]; do
155
- case "$1" in
156
- --plan)
157
- [[ -n "${2:-}" ]] || { echo "Error: --plan requires a value" >&2; usage; exit 1; }
158
- plan_file="$2"
159
- shift 2
160
- ;;
161
- --outcome)
162
- [[ -n "${2:-}" ]] || { echo "Error: --outcome requires a value" >&2; usage; exit 1; }
163
- outcome="$2"
164
- shift 2
165
- ;;
166
- --help|-h)
167
- usage
168
- exit 0
169
- ;;
170
- *)
171
- echo "Unknown argument: $1" >&2
172
- usage
173
- exit 1
174
- ;;
175
- esac
176
- done
177
-
178
- if [[ -z "$plan_file" || -z "$outcome" ]]; then
179
- echo "--plan and --outcome are required" >&2
180
- usage
181
- exit 1
182
- fi
183
-
184
- case "$outcome" in
185
- Completed|Abandoned|Superseded)
186
- ;;
187
- *)
188
- echo "Invalid outcome: $outcome" >&2
189
- exit 1
190
- ;;
191
- esac
192
-
193
- if [[ ! -f "$plan_file" ]]; then
194
- echo "Plan file not found: $plan_file" >&2
195
- exit 1
196
- fi
197
-
198
- normalized_plan="${plan_file#./}"
199
- if [[ "$normalized_plan" == plans/archive/* ]]; then
200
- echo "Error: plan is already archived" >&2
201
- exit 1
202
- fi
203
-
204
- mkdir -p plans/archive tasks/archive tasks/notes
205
-
206
- timestamp="$(date +%Y%m%d-%H%M)"
207
- timestamp_human="$(date '+%Y-%m-%d %H:%M')"
208
- plan_base="$(basename "$plan_file")"
209
- slug="$(echo "$plan_base" | sed -E 's/^plan-[0-9]{8}-[0-9]{4}-//; s/\.md$//')"
210
- original_artifact_stem="$(printf '%s' "$plan_base" | sed -E 's/^plan-//; s/\.md$//')"
211
- artifact_stem="$(plan_artifact_stem_from_parts "$plan_file" "$original_artifact_stem" "$slug")"
212
- parent_run_id="${HOOK_RUN_ID:-${CLAUDE_RUN_ID:-${CODEX_RUN_ID:-run-${timestamp}}}}"
213
- todo_source_plan="$(awk -F': ' '/^> \*\*Source Plan\*\*:/ {print $2; exit}' tasks/todos.md 2>/dev/null | xargs)"
214
-
215
- plan_status="Archived"
216
- if [[ "$outcome" == "Abandoned" ]]; then
217
- plan_status="Abandoned"
218
- fi
219
- set_plan_status "$plan_file" "$plan_status"
220
-
221
- archive_plan_path="plans/archive/${plan_base}"
222
- archive_plan_path="$(unique_archive_path "$archive_plan_path")"
223
-
224
- if [[ "$plan_file" != "$archive_plan_path" ]]; then
225
- mv "$plan_file" "$archive_plan_path"
226
- fi
227
-
228
- if [[ -f tasks/todos.md ]] && grep -q '[^[:space:]]' tasks/todos.md; then
229
- archive_todo="tasks/archive/todo-${timestamp}-${slug}.md"
230
- {
231
- echo "> **Archived**: ${timestamp_human}"
232
- echo "> **Related Plan**: ${archive_plan_path}"
233
- echo "> **Outcome**: ${outcome}"
234
- echo "> **Source Plan**: ${todo_source_plan:-"(none)"}"
235
- echo "> **Parent Run ID**: ${parent_run_id}"
236
- echo
237
- cat tasks/todos.md
238
- } > "$archive_todo"
239
- fi
240
-
241
- notes_file="tasks/notes/${artifact_stem}.notes.md"
242
- if [[ ! -f "$notes_file" && -f "tasks/notes/${slug}.notes.md" ]]; then
243
- notes_file="tasks/notes/${slug}.notes.md"
244
- fi
245
- if [[ -f "$notes_file" ]]; then
246
- archive_notes="$(unique_archive_path "tasks/archive/notes-${timestamp}-${slug}.md")"
247
- {
248
- echo "> **Archived**: ${timestamp_human}"
249
- echo "> **Related Plan**: ${archive_plan_path}"
250
- echo "> **Outcome**: ${outcome}"
251
- echo "> **Lifecycle**: notes"
252
- echo "> **Parent Run ID**: ${parent_run_id}"
253
- echo
254
- cat "$notes_file"
255
- } > "$archive_notes"
256
- rm -f "$notes_file"
257
- fi
258
-
259
- if todo_is_deferred_ledger tasks/todos.md; then
260
- touch_deferred_ledger_update_marker tasks/todos.md
261
- else
262
- write_empty_deferred_ledger
263
- fi
264
-
265
- # Clear active-plan markers if they pointed to the archived plan
266
- cleared_active=0
267
- for marker_file in ".ai/harness/active-plan" ".claude/.active-plan"; do
268
- if [[ ! -f "$marker_file" ]]; then
269
- continue
270
- fi
271
- marker_value="$(cat "$marker_file" 2>/dev/null | xargs)"
272
- if [[ "$marker_value" == "$plan_file" || "$marker_value" == "./$plan_file" ]]; then
273
- rm -f "$marker_file"
274
- cleared_active=1
275
- echo "Cleared $marker_file (archived plan was active)"
276
- fi
277
- done
278
- if [[ "$cleared_active" -eq 1 ]]; then
279
- rm -f ".ai/harness/active-worktree"
280
- fi
281
-
282
- # Clean up saved plan state backups
283
- plan_key="$(basename "$plan_file" .md)"
284
- rm -f ".claude/.plan-state/${plan_key}.todo.md.bak"
285
- rm -f ".claude/.plan-state/${plan_key}.task-state.json.bak"
286
-
287
- if [[ -x "scripts/refresh-current-status.sh" ]]; then
288
- bash "scripts/refresh-current-status.sh" --clear --write --reason "archive-workflow" || true
289
- fi
290
-
291
- echo "Archived plan to: $archive_plan_path"
292
- if [[ -f "docs/reference-configs/handoff-protocol.md" ]]; then
293
- echo "Next: refresh or prune long-running workflow rules using docs/reference-configs/handoff-protocol.md"
294
- fi
4
+ exec "$SCRIPT_DIR/lib/run-forge-helper.sh" "archive-workflow.sh" "$@"
File without changes