@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,413 +1,5 @@
1
- import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "fs";
2
- import { dirname, join, resolve } from "path";
1
+ #!/usr/bin/env bun
2
+ export * from "../assets/templates/helpers/migrate-workflow-docs";
3
+ import { runTrackedForgeHelper } from "./lib/run-forge-helper";
3
4
 
4
- type Mode = "dry-run" | "apply";
5
-
6
- type MigrationRecord = {
7
- source: string;
8
- target: string;
9
- action: "archive" | "rewrite" | "append" | "skip";
10
- note: string;
11
- };
12
-
13
- type MigrationSummary = {
14
- repo: string;
15
- mode: Mode;
16
- migrated: MigrationRecord[];
17
- skipped: string[];
18
- manual_followups: string[];
19
- };
20
-
21
- function parseArgs(argv: string[]) {
22
- let repo = process.cwd();
23
- let mode: Mode = "dry-run";
24
- let format: "json" | "text" = "text";
25
-
26
- for (let i = 0; i < argv.length; i += 1) {
27
- const arg = argv[i];
28
- if (arg === "--repo") {
29
- repo = argv[i + 1] ? resolve(argv[i + 1]) : repo;
30
- i += 1;
31
- continue;
32
- }
33
- if (arg === "--apply") {
34
- mode = "apply";
35
- continue;
36
- }
37
- if (arg === "--dry-run") {
38
- mode = "dry-run";
39
- continue;
40
- }
41
- if (arg === "--format") {
42
- format = argv[i + 1] === "json" ? "json" : "text";
43
- i += 1;
44
- }
45
- }
46
-
47
- return { repo, mode, format };
48
- }
49
-
50
- function ensureDir(path: string, mode: Mode) {
51
- if (mode === "apply") {
52
- mkdirSync(path, { recursive: true });
53
- }
54
- }
55
-
56
- function appendIfMissing(target: string, marker: string, block: string, mode: Mode) {
57
- const existing = existsSync(target) ? readFileSync(target, "utf-8") : "";
58
- if (existing.includes(marker)) return false;
59
- if (mode === "apply") {
60
- ensureDir(dirname(target), mode);
61
- const next = existing ? `${existing.trimEnd()}\n\n${block}\n` : `${block}\n`;
62
- writeFileSync(target, next);
63
- }
64
- return true;
65
- }
66
-
67
- function hasCanonicalTodoHeader(content: string): boolean {
68
- return /^# Deferred Goal Ledger\s*$/m.test(content) && /^\> \*\*Status\*\*:\s*Backlog\s*$/m.test(content);
69
- }
70
-
71
- function writeCanonicalTodo(target: string, mode: Mode) {
72
- if (existsSync(target)) return;
73
- const content = [
74
- "# Deferred Goal Ledger",
75
- "",
76
- "> **Status**: Backlog",
77
- "> **Updated**: (migration)",
78
- "> **Scope**: Medium/long-term goals deferred from active plan execution",
79
- "",
80
- "Current plan tasks live in the active plan's `## Task Breakdown`.",
81
- "Do not duplicate that execution checklist here. Record only work intentionally deferred beyond this slice, with the tradeoff and revisit trigger.",
82
- "",
83
- "## Deferred Goals",
84
- "",
85
- "| Goal | Why Deferred | Tradeoff | Revisit Trigger |",
86
- "|------|--------------|----------|-----------------|",
87
- "| (none) | No deferred medium/long-term goal recorded yet. | Keep migrated workflow state bounded. | Add a row when a real follow-up is postponed. |",
88
- ].join("\n");
89
- if (mode === "apply") {
90
- ensureDir(dirname(target), mode);
91
- writeFileSync(target, `${content}\n`);
92
- }
93
- }
94
-
95
- function normalizeLegacyTodo(target: string, archivePath: string, mode: Mode) {
96
- if (!existsSync(target)) return false;
97
-
98
- const existing = readFileSync(target, "utf-8");
99
- if (hasCanonicalTodoHeader(existing)) return false;
100
-
101
- const content = [
102
- "# Deferred Goal Ledger",
103
- "",
104
- "> **Status**: Backlog",
105
- "> **Updated**: (migration)",
106
- "> **Scope**: Medium/long-term goals deferred from active plan execution",
107
- "",
108
- "Current plan tasks live in the active plan's `## Task Breakdown`.",
109
- "Do not duplicate that execution checklist here. Record only work intentionally deferred beyond this slice, with the tradeoff and revisit trigger.",
110
- "",
111
- "## Deferred Goals",
112
- "",
113
- "| Goal | Why Deferred | Tradeoff | Revisit Trigger |",
114
- "|------|--------------|----------|-----------------|",
115
- "| Review archived legacy checklist | Legacy tasks/todos.md contained execution checklist content before migration. | Preserve user-authored task text in tasks/archive instead of guessing which items still matter. | Open the archive and promote real follow-up work into a new plan or a deferred-goal row. |",
116
- ].join("\n");
117
-
118
- if (mode === "apply") {
119
- ensureDir(dirname(target), mode);
120
- ensureDir(dirname(archivePath), mode);
121
- if (!existsSync(archivePath)) {
122
- writeFileSync(archivePath, `${existing.trimEnd()}\n`);
123
- }
124
- writeFileSync(target, `${content}\n`);
125
- }
126
-
127
- return true;
128
- }
129
-
130
- function migrateLegacySingularTodo(source: string, target: string, archivePath: string, mode: Mode) {
131
- if (!existsSync(source)) return false;
132
-
133
- const existing = readFileSync(source, "utf-8");
134
- const content = hasCanonicalTodoHeader(existing)
135
- ? existing.trimEnd()
136
- : [
137
- "# Deferred Goal Ledger",
138
- "",
139
- "> **Status**: Backlog",
140
- "> **Updated**: (migration)",
141
- "> **Scope**: Medium/long-term goals deferred from active plan execution",
142
- "",
143
- "Current plan tasks live in the active plan's `## Task Breakdown`.",
144
- "Do not duplicate that execution checklist here. Record only work intentionally deferred beyond this slice, with the tradeoff and revisit trigger.",
145
- "",
146
- "## Deferred Goals",
147
- "",
148
- "| Goal | Why Deferred | Tradeoff | Revisit Trigger |",
149
- "|------|--------------|----------|-----------------|",
150
- "| Review archived legacy checklist | Legacy tasks/todo.md contained execution checklist content before migration. | Preserve user-authored task text in tasks/archive instead of guessing which items still matter. | Open the archive and promote real follow-up work into a new plan or a deferred-goal row. |",
151
- ].join("\n");
152
-
153
- if (mode === "apply") {
154
- ensureDir(dirname(target), mode);
155
- ensureDir(dirname(archivePath), mode);
156
- if (!existsSync(archivePath)) {
157
- writeFileSync(archivePath, `${existing.trimEnd()}\n`);
158
- }
159
- if (!existsSync(target)) {
160
- writeFileSync(target, `${content}\n`);
161
- }
162
- renameSync(source, `${source}.migrated.bak`);
163
- }
164
-
165
- return true;
166
- }
167
-
168
- function writeResearchReadme(target: string, mode: Mode) {
169
- if (existsSync(target)) return;
170
- const content = [
171
- "# Research Reports",
172
- "",
173
- "Durable research reports live in this directory as dated Markdown files.",
174
- "",
175
- "Use `YYYYMMDD-topic.md` names for new reports. Keep task-local implementation",
176
- "decisions in `tasks/notes/`, and keep repeated correction-derived rules in",
177
- "`tasks/lessons.md`.",
178
- ].join("\n");
179
- if (mode === "apply") {
180
- ensureDir(dirname(target), mode);
181
- writeFileSync(target, `${content}\n`);
182
- }
183
- }
184
-
185
- function migrateLegacyResearch(source: string, archivePath: string, mode: Mode) {
186
- if (!existsSync(source)) return false;
187
-
188
- const existing = readFileSync(source, "utf-8");
189
- if (existing.includes("**Canonical Surface**: `docs/researches/`")) return false;
190
-
191
- const tombstone = [
192
- "# Research Notes Moved",
193
- "",
194
- "> **Status**: Retired tombstone",
195
- "> **Canonical Surface**: `docs/researches/`",
196
- "> **Legacy Archive**: `docs/researches/legacy-research-notes.md`",
197
- "",
198
- "Durable research reports now live under `docs/researches/*.md`. This file is",
199
- "kept only as a transition pointer for older tooling and historical links; do",
200
- "not add new findings here.",
201
- ].join("\n");
202
-
203
- if (mode === "apply") {
204
- ensureDir(dirname(archivePath), mode);
205
- if (!existsSync(archivePath)) {
206
- writeFileSync(archivePath, `${existing.trimEnd()}\n`);
207
- }
208
- writeFileSync(source, `${tombstone}\n`);
209
- }
210
-
211
- return true;
212
- }
213
-
214
- function writeResearchReport(target: string, marker: string, title: string, body: string, mode: Mode) {
215
- const block = [`# ${title}`, "", marker, "", body.trimEnd()].join("\n");
216
- return appendIfMissing(target, marker, block, mode);
217
- }
218
-
219
- export function migrate(repo: string, mode: Mode): MigrationSummary {
220
- const summary: MigrationSummary = {
221
- repo,
222
- mode,
223
- migrated: [],
224
- skipped: [],
225
- manual_followups: [],
226
- };
227
-
228
- const planDoc = join(repo, "docs", "plan.md");
229
- const todoDoc = join(repo, "docs", "TODO.md");
230
- const progressDoc = join(repo, "docs", "PROGRESS.md");
231
- const tasksTodo = join(repo, "tasks", "todos.md");
232
- const legacySingularTasksTodo = join(repo, "tasks", "todo.md");
233
- const tasksResearch = join(repo, "tasks", "research.md");
234
- const researchDir = join(repo, "docs", "researches");
235
- const researchReadme = join(researchDir, "README.md");
236
- const legacyResearchArchive = join(researchDir, "legacy-research-notes.md");
237
- const legacyProgressResearch = join(researchDir, "legacy-progress-import.md");
238
- const plansArchive = join(repo, "plans", "archive");
239
- const tasksArchive = join(repo, "tasks", "archive");
240
- const legacyPlanArchive = join(plansArchive, "legacy-docs-plan.md");
241
- const legacyTodoArchive = join(tasksArchive, "legacy-docs-TODO.md");
242
- const legacyProgressArchive = join(tasksArchive, "legacy-docs-PROGRESS.md");
243
- const legacyTasksTodoArchive = join(tasksArchive, "legacy-tasks-todo.md");
244
- const legacyContractDoc = join(repo, "docs", "contract.md");
245
- const legacyReviewDoc = join(repo, "docs", "review.md");
246
- const legacyHandoffDoc = join(repo, "docs", "handoff.md");
247
- const rootHandoffDoc = join(repo, "HANDOFF.md");
248
-
249
- ensureDir(plansArchive, mode);
250
- ensureDir(tasksArchive, mode);
251
- if (migrateLegacySingularTodo(legacySingularTasksTodo, tasksTodo, legacyTasksTodoArchive, mode)) {
252
- summary.migrated.push({
253
- source: "tasks/todo.md",
254
- target: "tasks/todos.md",
255
- action: "rewrite",
256
- note: "Archived legacy singular todo content and normalized tasks/todos.md to the deferred-goal ledger.",
257
- });
258
- }
259
- writeCanonicalTodo(tasksTodo, mode);
260
- if (normalizeLegacyTodo(tasksTodo, legacyTasksTodoArchive, mode)) {
261
- summary.migrated.push({
262
- source: "tasks/todos.md",
263
- target: "tasks/todos.md",
264
- action: "rewrite",
265
- note: "Archived legacy task checklist content and normalized tasks/todos.md to the deferred-goal ledger.",
266
- });
267
- }
268
- ensureDir(researchDir, mode);
269
- writeResearchReadme(researchReadme, mode);
270
- if (migrateLegacyResearch(tasksResearch, legacyResearchArchive, mode)) {
271
- summary.migrated.push({
272
- source: "tasks/research.md",
273
- target: "docs/researches/legacy-research-notes.md",
274
- action: "archive",
275
- note: "Archived legacy singleton research notes and left a tombstone pointer.",
276
- });
277
- }
278
-
279
- // NOTE: The "<!-- forge: legacy-docs-import ... -->" markers below are
280
- // data markers written into migrated repos and used by appendIfMissing as the
281
- // idempotency key, so renaming them would re-import already-migrated legacy docs.
282
- // Keep the marker string stable.
283
- if (existsSync(planDoc)) {
284
- const content = readFileSync(planDoc, "utf-8");
285
- const archiveBlock = [
286
- "# Legacy Plan Import",
287
- "",
288
- "<!-- forge: legacy-docs-import docs/plan.md -->",
289
- "",
290
- "Original `docs/plan.md` content was archived during migration.",
291
- "",
292
- "## Imported Content",
293
- "",
294
- content.trimEnd(),
295
- ].join("\n");
296
-
297
- if (mode === "apply" && !existsSync(legacyPlanArchive)) {
298
- writeFileSync(legacyPlanArchive, `${archiveBlock}\n`);
299
- }
300
- if (mode === "apply") {
301
- renameSync(planDoc, `${planDoc}.migrated.bak`);
302
- }
303
- summary.migrated.push({
304
- source: "docs/plan.md",
305
- target: "plans/archive/legacy-docs-plan.md",
306
- action: "archive",
307
- note: "Archived uncertain legacy plan content for manual review.",
308
- });
309
- summary.manual_followups.push("Review plans/archive/legacy-docs-plan.md and create a canonical plan if the content is still active.");
310
- }
311
-
312
- if (existsSync(todoDoc)) {
313
- const content = readFileSync(todoDoc, "utf-8").trimEnd();
314
- const hadCanonicalTodo = existsSync(tasksTodo);
315
-
316
- if (!hadCanonicalTodo) {
317
- writeCanonicalTodo(tasksTodo, mode);
318
- }
319
-
320
- if (mode === "apply" && !existsSync(legacyTodoArchive)) {
321
- writeFileSync(legacyTodoArchive, `${content}\n`);
322
- renameSync(todoDoc, `${todoDoc}.migrated.bak`);
323
- }
324
- summary.migrated.push({
325
- source: "docs/TODO.md",
326
- target: "tasks/todos.md",
327
- action: hadCanonicalTodo ? "skip" : "rewrite",
328
- note: hadCanonicalTodo
329
- ? "Archived the legacy todo without rewriting the existing deferred-goal ledger."
330
- : "Created the deferred-goal ledger and archived the legacy todo for manual plan triage.",
331
- });
332
- summary.manual_followups.push(
333
- "Review tasks/archive/legacy-docs-TODO.md and promote any still-relevant work into a new plan instead of rehydrating it into tasks/todos.md."
334
- );
335
- }
336
-
337
- if (existsSync(progressDoc)) {
338
- const content = readFileSync(progressDoc, "utf-8").trimEnd();
339
- if (!readFileSync(progressDoc, "utf-8").includes("milestone checkpoints only")) {
340
- writeResearchReport(
341
- legacyProgressResearch,
342
- "<!-- forge: legacy-docs-import docs/PROGRESS.md -->",
343
- "Legacy Progress Import",
344
- ["Imported from a legacy execution log stored in `docs/PROGRESS.md`.", "", content].join("\n"),
345
- mode
346
- );
347
- }
348
-
349
- if (mode === "apply") {
350
- if (!existsSync(legacyProgressArchive)) {
351
- writeFileSync(legacyProgressArchive, `${content}\n`);
352
- }
353
- renameSync(progressDoc, `${progressDoc}.migrated.bak`);
354
- }
355
- summary.migrated.push({
356
- source: "docs/PROGRESS.md",
357
- target: "tasks/archive/legacy-docs-PROGRESS.md",
358
- action: "archive",
359
- note: "Archived legacy progress notes; docs/PROGRESS.md is no longer a generated workflow surface.",
360
- });
361
- }
362
-
363
- const archiveDoc = (sourcePath: string, archiveName: string, note: string) => {
364
- if (!existsSync(sourcePath)) return;
365
- const target = join(tasksArchive, archiveName);
366
- if (mode === "apply" && !existsSync(target)) {
367
- writeFileSync(target, `${readFileSync(sourcePath, "utf-8").trimEnd()}\n`);
368
- renameSync(sourcePath, `${sourcePath}.migrated.bak`);
369
- }
370
- summary.migrated.push({
371
- source: sourcePath.replace(`${repo}/`, ""),
372
- target: target.replace(`${repo}/`, ""),
373
- action: "archive",
374
- note,
375
- });
376
- summary.manual_followups.push(`Review ${target.replace(`${repo}/`, "")} and re-home any still-relevant content.`);
377
- };
378
-
379
- archiveDoc(legacyContractDoc, "legacy-docs-contract.md", "Archived legacy contract notes for manual triage.");
380
- archiveDoc(legacyReviewDoc, "legacy-docs-review.md", "Archived legacy review notes for manual triage.");
381
- archiveDoc(legacyHandoffDoc, "legacy-docs-handoff.md", "Archived legacy handoff notes for manual triage.");
382
- archiveDoc(rootHandoffDoc, "legacy-root-HANDOFF.md", "Archived root handoff notes for manual triage.");
383
-
384
- return summary;
385
- }
386
-
387
- function renderText(summary: MigrationSummary): string {
388
- const lines = [
389
- `[migrate-docs] repo: ${summary.repo}`,
390
- `[migrate-docs] mode: ${summary.mode}`,
391
- ];
392
-
393
- for (const item of summary.migrated) {
394
- lines.push(`[migrate-docs] ${item.source} -> ${item.target} (${item.action})`);
395
- lines.push(`[migrate-docs] note: ${item.note}`);
396
- }
397
- for (const followup of summary.manual_followups) {
398
- lines.push(`[migrate-docs] follow-up: ${followup}`);
399
- }
400
- if (summary.migrated.length === 0) {
401
- lines.push("[migrate-docs] no legacy documents detected");
402
- }
403
- return lines.join("\n");
404
- }
405
-
406
- const { repo, mode, format } = parseArgs(process.argv.slice(2));
407
- const summary = migrate(repo, mode);
408
-
409
- if (format === "json") {
410
- console.log(JSON.stringify(summary, null, 2));
411
- } else {
412
- console.log(renderText(summary));
413
- }
5
+ if (import.meta.main) runTrackedForgeHelper("migrate-workflow-docs.ts");
@@ -1,183 +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/new-plan.sh --slug <slug> [--title <title>]
16
- USAGE_EOF
17
- }
18
-
19
- normalize_slug() {
20
- printf '%s' "$1" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9]+/-/g; s/^-+//; s/-+$//; s/-{2,}/-/g'
21
- }
22
-
23
- escape_sed_replacement() {
24
- printf '%s' "$1" | sed -e 's/[\/&]/\\&/g'
25
- }
26
-
27
- slug=""
28
- title=""
29
-
30
- while [[ $# -gt 0 ]]; do
31
- case "$1" in
32
- --slug)
33
- [[ -n "${2:-}" ]] || { echo "Error: --slug requires a value" >&2; usage; exit 1; }
34
- slug="$2"
35
- shift 2
36
- ;;
37
- --title)
38
- [[ -n "${2:-}" ]] || { echo "Error: --title requires a value" >&2; usage; exit 1; }
39
- title="$2"
40
- shift 2
41
- ;;
42
- --help|-h)
43
- usage
44
- exit 0
45
- ;;
46
- *)
47
- echo "Unknown argument: $1" >&2
48
- usage
49
- exit 1
50
- ;;
51
- esac
52
- done
53
-
54
- if [[ -z "$slug" ]]; then
55
- echo "--slug is required" >&2
56
- usage
57
- exit 1
58
- fi
59
-
60
- slug="$(normalize_slug "$slug")"
61
- if [[ -z "$slug" ]]; then
62
- echo "Slug is empty after normalization" >&2
63
- exit 1
64
- fi
65
-
66
- if [[ -z "$title" ]]; then
67
- title="$slug"
68
- fi
69
-
70
- timestamp="$(date +%Y%m%d-%H%M)"
71
- mkdir -p plans plans/archive .claude/templates
72
-
73
- template_file=".claude/templates/plan.template.md"
74
- if [[ ! -f "$template_file" ]]; then
75
- cat > "$template_file" <<'PLAN_TEMPLATE_EOF'
76
- # Plan: {{TITLE}}
77
-
78
- > **Status**: Draft
79
- > **Created**: {{TIMESTAMP}}
80
- > **Slug**: {{SLUG}}
81
- > **Spec**: `docs/spec.md`
82
- > **Research**: See `docs/researches/`
83
- > **Task Contract**: `tasks/contracts/{{ARTIFACT_STEM}}.contract.md`
84
- > **Task Review**: `tasks/reviews/{{ARTIFACT_STEM}}.review.md`
85
- > **Implementation Notes**: `tasks/notes/{{ARTIFACT_STEM}}.notes.md`
86
-
87
- ## Agentic Routing
88
- - Selected route:
89
- - Routing reason:
90
- - Due diligence:
91
- - P1 map:
92
- - P2 trace:
93
- - P3 decision rationale:
94
-
95
- ## Workflow Inventory
96
- Complete this inventory before implementation. If any line is unknown, keep the plan in Draft and fill it before projection.
97
-
98
- - Active plan: `{{PLAN_FILE}}`
99
- - Sprint contract: `tasks/contracts/{{ARTIFACT_STEM}}.contract.md`
100
- - Sprint review: `tasks/reviews/{{ARTIFACT_STEM}}.review.md`
101
- - Implementation notes: `tasks/notes/{{ARTIFACT_STEM}}.notes.md`
102
- - Deferred-goal ledger: `tasks/todos.md`
103
- - Current checks: `.ai/harness/checks/latest.json`
104
- - Run snapshots: `.ai/harness/runs/`
105
- - Scope authority: `tasks/contracts/{{ARTIFACT_STEM}}.contract.md` `allowed_paths`
106
- - Concurrency rule: `.ai/harness/active-plan` selects the active plan for this worktree when present; `.ai/harness/active-worktree` records the owning worktree; `.claude/.active-plan` is a legacy fallback during transition. If another worktree already owns active work, open or switch to the matching worktree instead of serializing unrelated plans.
107
- - Execution isolation: approved contract-level work projects through `scripts/plan-to-todo.sh --plan {{PLAN_FILE}}` and may start `scripts/contract-worktree.sh start --plan {{PLAN_FILE}}`.
108
-
109
- ## Approach
110
- ### Strategy
111
- ### Trade-offs
112
- | Option | Pros | Cons | Decision |
113
- |--------|------|------|----------|
114
-
115
- ## Detailed Design
116
- ### File Changes
117
- | File | Action | Description |
118
- |------|--------|-------------|
119
-
120
- ### Code Snippets
121
- ### Data Flow
122
-
123
- ## Risk Assessment
124
- | Risk | Likelihood | Impact | Mitigation |
125
- |------|------------|--------|------------|
126
-
127
- ## Task Contracts
128
- - Contract file: `tasks/contracts/{{ARTIFACT_STEM}}.contract.md`
129
- - Review file: `tasks/reviews/{{ARTIFACT_STEM}}.review.md`
130
- - Implementation notes file: `tasks/notes/{{ARTIFACT_STEM}}.notes.md`
131
- - Template: `.claude/templates/contract.template.md`
132
- - Verification command: `bash scripts/verify-contract.sh --contract tasks/contracts/{{ARTIFACT_STEM}}.contract.md --strict`
133
- - Active plan rule: `.ai/harness/active-plan` is authoritative for this worktree when present; `.ai/harness/active-worktree` records the owning worktree; `.claude/.active-plan` is a legacy fallback during transition. Do not infer active execution from the latest non-archived plan.
134
-
135
- ## Handoff
136
-
137
- - Checks file: `.ai/harness/checks/latest.json`
138
- - Session continuation: `.ai/harness/session/continuation.md`
139
-
140
- ## Evidence Contract
141
-
142
- - **State/progress path**:
143
- - **Verification evidence**:
144
- - **Impact review**:
145
- - **Stop condition**:
146
- - **Rollback surface**:
147
-
148
- ## Annotations
149
- <!-- [NOTE]: prefixed inline. Claude processes all and revises. -->
150
-
151
- ## Task Breakdown
152
- - [ ] ...
153
- PLAN_TEMPLATE_EOF
154
- fi
155
-
156
- base_name="plan-${timestamp}-${slug}.md"
157
- plan_file="plans/${base_name}"
158
- counter=2
159
- while [[ -f "$plan_file" ]]; do
160
- plan_file="plans/plan-${timestamp}-${slug}-v${counter}.md"
161
- counter=$((counter + 1))
162
- done
163
- artifact_stem="$(basename "$plan_file" .md | sed -E 's/^plan-//')"
164
-
165
- slug_esc="$(escape_sed_replacement "$slug")"
166
- artifact_stem_esc="$(escape_sed_replacement "$artifact_stem")"
167
- title_esc="$(escape_sed_replacement "$title")"
168
- timestamp_esc="$(escape_sed_replacement "$timestamp")"
169
-
170
- sed \
171
- -e "s/{{SLUG}}/${slug_esc}/g" \
172
- -e "s/{{ARTIFACT_STEM}}/${artifact_stem_esc}/g" \
173
- -e "s/{{TITLE}}/${title_esc}/g" \
174
- -e "s/{{TIMESTAMP}}/${timestamp_esc}/g" \
175
- -e "s|{{PLAN_FILE}}|${plan_file}|g" \
176
- "$template_file" \
177
- | sed \
178
- -e "s|tasks/contracts/${slug_esc}\\.contract\\.md|tasks/contracts/${artifact_stem_esc}.contract.md|g" \
179
- -e "s|tasks/reviews/${slug_esc}\\.review\\.md|tasks/reviews/${artifact_stem_esc}.review.md|g" \
180
- -e "s|tasks/notes/${slug_esc}\\.notes\\.md|tasks/notes/${artifact_stem_esc}.notes.md|g" \
181
- > "$plan_file"
182
-
183
- echo "Created plan: $plan_file"
4
+ exec "$SCRIPT_DIR/lib/run-forge-helper.sh" "new-plan.sh" "$@"
@@ -1,50 +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
- mkdir -p docs .claude/templates
14
-
15
- template_file=".claude/templates/spec.template.md"
16
- if [[ ! -f "$template_file" ]]; then
17
- cat > "$template_file" <<'SPEC_TEMPLATE_EOF'
18
- # Product Spec: {{PROJECT_NAME}}
19
-
20
- > **Status**: Draft
21
- > **Last Updated**: {{TIMESTAMP}}
22
- > **Owner**: Planner
23
-
24
- ## Product Outcome
25
-
26
- Describe the stable user or operator outcome this repo should deliver.
27
-
28
- ## Success Criteria
29
-
30
- - Primary workflow:
31
- - Quality bar:
32
- - Out of scope:
33
-
34
- ## Constraints
35
-
36
- - Technical:
37
- - Compliance:
38
- - Delivery:
39
- SPEC_TEMPLATE_EOF
40
- fi
41
-
42
- project_name="$(basename "$PWD")"
43
- timestamp="$(date '+%Y-%m-%d %H:%M')"
44
-
45
- sed \
46
- -e "s/{{PROJECT_NAME}}/${project_name}/g" \
47
- -e "s/{{TIMESTAMP}}/${timestamp}/g" \
48
- "$template_file" > docs/spec.md
49
-
50
- echo "Created docs/spec.md"
4
+ exec "$SCRIPT_DIR/lib/run-forge-helper.sh" "new-spec.sh" "$@"