@warpgogol/forge 5.2.3 → 5.3.0

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 (584) hide show
  1. package/AGENTS.md +34 -2
  2. package/README.md +1 -1
  3. package/README.uk.md +8 -8
  4. package/bin/cli.ts +1 -0
  5. package/dist/bin/cli.js +1 -0
  6. package/dist/bin/cli.js.map +1 -1
  7. package/dist/os/adr/adr.module.d.ts.map +1 -1
  8. package/dist/os/adr/adr.module.js +8 -3
  9. package/dist/os/adr/adr.module.js.map +1 -1
  10. package/dist/os/adr/frontmatter-io.js +5 -5
  11. package/dist/os/adr/frontmatter-io.js.map +1 -1
  12. package/dist/os/adr/handlers/archive.d.ts.map +1 -1
  13. package/dist/os/adr/handlers/archive.js +10 -4
  14. package/dist/os/adr/handlers/archive.js.map +1 -1
  15. package/dist/os/adr/handlers/implement-stamp.d.ts.map +1 -1
  16. package/dist/os/adr/handlers/implement-stamp.js +10 -9
  17. package/dist/os/adr/handlers/implement-stamp.js.map +1 -1
  18. package/dist/os/adr/handlers/list-create.js +5 -5
  19. package/dist/os/adr/handlers/list-create.js.map +1 -1
  20. package/dist/os/adr/handlers/validate.js +1 -1
  21. package/dist/os/adr/handlers/validate.js.map +1 -1
  22. package/dist/os/audit/audit.module.js +3 -3
  23. package/dist/os/audit/audit.module.js.map +1 -1
  24. package/dist/os/audit/frontmatter-io.js +5 -5
  25. package/dist/os/audit/frontmatter-io.js.map +1 -1
  26. package/dist/os/audit/handlers/archive.d.ts.map +1 -1
  27. package/dist/os/audit/handlers/archive.js +10 -4
  28. package/dist/os/audit/handlers/archive.js.map +1 -1
  29. package/dist/os/compass/compass.module.d.ts.map +1 -1
  30. package/dist/os/compass/compass.module.js +17 -1
  31. package/dist/os/compass/compass.module.js.map +1 -1
  32. package/dist/os/compass/handlers/compass-audit-handler.d.ts.map +1 -1
  33. package/dist/os/compass/handlers/compass-audit-handler.js +12 -5
  34. package/dist/os/compass/handlers/compass-audit-handler.js.map +1 -1
  35. package/dist/os/compass/handlers/compass-change-summary-handler.d.ts.map +1 -1
  36. package/dist/os/compass/handlers/compass-change-summary-handler.js +3 -2
  37. package/dist/os/compass/handlers/compass-change-summary-handler.js.map +1 -1
  38. package/dist/os/compass/handlers/compass-inventory-handler.d.ts.map +1 -1
  39. package/dist/os/compass/handlers/compass-inventory-handler.js +6 -4
  40. package/dist/os/compass/handlers/compass-inventory-handler.js.map +1 -1
  41. package/dist/os/compass/handlers/compass-inventory.d.ts.map +1 -1
  42. package/dist/os/compass/handlers/compass-inventory.js +10 -8
  43. package/dist/os/compass/handlers/compass-inventory.js.map +1 -1
  44. package/dist/os/compass/handlers/compass-migrate-handler.js +1 -1
  45. package/dist/os/compass/handlers/compass-migrate-handler.js.map +1 -1
  46. package/dist/os/compass/handlers/compass-migrate.d.ts.map +1 -1
  47. package/dist/os/compass/handlers/compass-migrate.js +6 -3
  48. package/dist/os/compass/handlers/compass-migrate.js.map +1 -1
  49. package/dist/os/compass/handlers/git-revision.d.ts.map +1 -1
  50. package/dist/os/compass/handlers/git-revision.js +9 -6
  51. package/dist/os/compass/handlers/git-revision.js.map +1 -1
  52. package/dist/os/compass/handlers/resolve-scan-root.js +1 -1
  53. package/dist/os/compass/handlers/resolve-scan-root.js.map +1 -1
  54. package/dist/os/compass/handlers/summary-record.d.ts.map +1 -1
  55. package/dist/os/compass/handlers/summary-record.js +8 -4
  56. package/dist/os/compass/handlers/summary-record.js.map +1 -1
  57. package/dist/os/core/core.module.d.ts.map +1 -1
  58. package/dist/os/core/core.module.js +57 -4
  59. package/dist/os/core/core.module.js.map +1 -1
  60. package/dist/os/core/handlers/assets-helpers.d.ts.map +1 -1
  61. package/dist/os/core/handlers/assets-helpers.js +6 -3
  62. package/dist/os/core/handlers/assets-helpers.js.map +1 -1
  63. package/dist/os/core/handlers/build.js +1 -1
  64. package/dist/os/core/handlers/build.js.map +1 -1
  65. package/dist/os/core/handlers/determinism-check.d.ts.map +1 -1
  66. package/dist/os/core/handlers/determinism-check.js +10 -6
  67. package/dist/os/core/handlers/determinism-check.js.map +1 -1
  68. package/dist/os/core/handlers/dev.js +1 -1
  69. package/dist/os/core/handlers/dev.js.map +1 -1
  70. package/dist/os/core/handlers/file-size-lint.d.ts.map +1 -1
  71. package/dist/os/core/handlers/file-size-lint.js +11 -7
  72. package/dist/os/core/handlers/file-size-lint.js.map +1 -1
  73. package/dist/os/core/handlers/forge-autonomy-validate.d.ts.map +1 -1
  74. package/dist/os/core/handlers/forge-autonomy-validate.js +9 -5
  75. package/dist/os/core/handlers/forge-autonomy-validate.js.map +1 -1
  76. package/dist/os/core/handlers/knowledge-compact.js +1 -1
  77. package/dist/os/core/handlers/knowledge-compact.js.map +1 -1
  78. package/dist/os/core/handlers/package-health.js +1 -1
  79. package/dist/os/core/handlers/package-health.js.map +1 -1
  80. package/dist/os/core/handlers/pinned-check.js +2 -2
  81. package/dist/os/core/handlers/pinned-check.js.map +1 -1
  82. package/dist/os/core/handlers/pinned-init.d.ts.map +1 -1
  83. package/dist/os/core/handlers/pinned-init.js +9 -8
  84. package/dist/os/core/handlers/pinned-init.js.map +1 -1
  85. package/dist/os/core/handlers/pinned-validate.js +3 -3
  86. package/dist/os/core/handlers/pinned-validate.js.map +1 -1
  87. package/dist/os/core/handlers/profile-resolve.js +1 -1
  88. package/dist/os/core/handlers/profile-resolve.js.map +1 -1
  89. package/dist/os/core/handlers/public-surface.js +1 -1
  90. package/dist/os/core/handlers/public-surface.js.map +1 -1
  91. package/dist/os/core/handlers/release-prepare.d.ts.map +1 -1
  92. package/dist/os/core/handlers/release-prepare.js +10 -6
  93. package/dist/os/core/handlers/release-prepare.js.map +1 -1
  94. package/dist/os/core/handlers/release-publish.js +6 -6
  95. package/dist/os/core/handlers/release-publish.js.map +1 -1
  96. package/dist/os/core/handlers/validate.js +1 -1
  97. package/dist/os/core/handlers/validate.js.map +1 -1
  98. package/dist/os/exploration/exploration.module.d.ts.map +1 -1
  99. package/dist/os/exploration/exploration.module.js +1 -0
  100. package/dist/os/exploration/exploration.module.js.map +1 -1
  101. package/dist/os/exploration/frontmatter-io.js +4 -4
  102. package/dist/os/exploration/frontmatter-io.js.map +1 -1
  103. package/dist/os/exploration/handlers/archive.js +3 -3
  104. package/dist/os/exploration/handlers/archive.js.map +1 -1
  105. package/dist/os/mission/handlers/archive.d.ts.map +1 -1
  106. package/dist/os/mission/handlers/archive.js +22 -19
  107. package/dist/os/mission/handlers/archive.js.map +1 -1
  108. package/dist/os/mission/mission.module.js +3 -3
  109. package/dist/os/mission/mission.module.js.map +1 -1
  110. package/dist/os/naming/naming-convention.d.ts.map +1 -1
  111. package/dist/os/naming/naming-convention.js +7 -3
  112. package/dist/os/naming/naming-convention.js.map +1 -1
  113. package/dist/os/naming/naming.module.d.ts.map +1 -1
  114. package/dist/os/naming/naming.module.js +4 -3
  115. package/dist/os/naming/naming.module.js.map +1 -1
  116. package/dist/os/notes/notes.module.d.ts.map +1 -1
  117. package/dist/os/notes/notes.module.js +6 -3
  118. package/dist/os/notes/notes.module.js.map +1 -1
  119. package/dist/os/plan/frontmatter-io.js +5 -5
  120. package/dist/os/plan/frontmatter-io.js.map +1 -1
  121. package/dist/os/plan/handlers/archive.d.ts.map +1 -1
  122. package/dist/os/plan/handlers/archive.js +10 -4
  123. package/dist/os/plan/handlers/archive.js.map +1 -1
  124. package/dist/os/plan/plan.module.js +3 -3
  125. package/dist/os/plan/plan.module.js.map +1 -1
  126. package/dist/os/plugin/plugin.module.d.ts.map +1 -1
  127. package/dist/os/plugin/plugin.module.js +6 -3
  128. package/dist/os/plugin/plugin.module.js.map +1 -1
  129. package/dist/os/program/discovery.js +2 -2
  130. package/dist/os/program/discovery.js.map +1 -1
  131. package/dist/os/program/handlers/complete.js +1 -1
  132. package/dist/os/program/handlers/complete.js.map +1 -1
  133. package/dist/os/program/handlers/lease.js +1 -1
  134. package/dist/os/program/handlers/lease.js.map +1 -1
  135. package/dist/os/program/handlers/seal.js +1 -1
  136. package/dist/os/program/handlers/seal.js.map +1 -1
  137. package/dist/os/program/lease.js +1 -1
  138. package/dist/os/program/lease.js.map +1 -1
  139. package/dist/os/program/program.module.d.ts.map +1 -1
  140. package/dist/os/program/program.module.js +9 -3
  141. package/dist/os/program/program.module.js.map +1 -1
  142. package/dist/os/queue/index.js +1 -1
  143. package/dist/os/queue/manifest.d.ts.map +1 -1
  144. package/dist/os/queue/manifest.js +4 -8
  145. package/dist/os/queue/manifest.js.map +1 -1
  146. package/dist/os/rfc/acceptance.d.ts.map +1 -1
  147. package/dist/os/rfc/acceptance.js +10 -6
  148. package/dist/os/rfc/acceptance.js.map +1 -1
  149. package/dist/os/rfc/decision-log.d.ts.map +1 -1
  150. package/dist/os/rfc/decision-log.js +4 -3
  151. package/dist/os/rfc/decision-log.js.map +1 -1
  152. package/dist/os/rfc/dna-trace.d.ts.map +1 -1
  153. package/dist/os/rfc/dna-trace.js +7 -2
  154. package/dist/os/rfc/dna-trace.js.map +1 -1
  155. package/dist/os/rfc/frontmatter-io.js +5 -5
  156. package/dist/os/rfc/frontmatter-io.js.map +1 -1
  157. package/dist/os/rfc/handlers/archive.d.ts.map +1 -1
  158. package/dist/os/rfc/handlers/archive.js +11 -5
  159. package/dist/os/rfc/handlers/archive.js.map +1 -1
  160. package/dist/os/rfc/handlers/check.d.ts.map +1 -1
  161. package/dist/os/rfc/handlers/check.js +6 -3
  162. package/dist/os/rfc/handlers/check.js.map +1 -1
  163. package/dist/os/rfc/handlers/implement-stamp.d.ts.map +1 -1
  164. package/dist/os/rfc/handlers/implement-stamp.js +11 -10
  165. package/dist/os/rfc/handlers/implement-stamp.js.map +1 -1
  166. package/dist/os/rfc/handlers/index-graph.js +3 -3
  167. package/dist/os/rfc/handlers/index-graph.js.map +1 -1
  168. package/dist/os/rfc/handlers/lifecycle.d.ts.map +1 -1
  169. package/dist/os/rfc/handlers/lifecycle.js +6 -2
  170. package/dist/os/rfc/handlers/lifecycle.js.map +1 -1
  171. package/dist/os/rfc/handlers/list-create.d.ts.map +1 -1
  172. package/dist/os/rfc/handlers/list-create.js +7 -6
  173. package/dist/os/rfc/handlers/list-create.js.map +1 -1
  174. package/dist/os/rfc/handlers/shared.js +3 -3
  175. package/dist/os/rfc/handlers/shared.js.map +1 -1
  176. package/dist/os/rfc/handlers/supersede-propose.d.ts.map +1 -1
  177. package/dist/os/rfc/handlers/supersede-propose.js +7 -3
  178. package/dist/os/rfc/handlers/supersede-propose.js.map +1 -1
  179. package/dist/os/rfc/handlers/validate-rules.d.ts.map +1 -1
  180. package/dist/os/rfc/handlers/validate-rules.js +8 -5
  181. package/dist/os/rfc/handlers/validate-rules.js.map +1 -1
  182. package/dist/os/rfc/rfc.module.d.ts.map +1 -1
  183. package/dist/os/rfc/rfc.module.js +44 -4
  184. package/dist/os/rfc/rfc.module.js.map +1 -1
  185. package/dist/os/rfc/verification-evidence.d.ts.map +1 -1
  186. package/dist/os/rfc/verification-evidence.js +9 -5
  187. package/dist/os/rfc/verification-evidence.js.map +1 -1
  188. package/dist/os/rfc/verification-refresh.d.ts.map +1 -1
  189. package/dist/os/rfc/verification-refresh.js +4 -3
  190. package/dist/os/rfc/verification-refresh.js.map +1 -1
  191. package/dist/os/session/frontmatter-io.js +12 -12
  192. package/dist/os/session/frontmatter-io.js.map +1 -1
  193. package/dist/os/session/handlers/archive.d.ts.map +1 -1
  194. package/dist/os/session/handlers/archive.js +10 -4
  195. package/dist/os/session/handlers/archive.js.map +1 -1
  196. package/dist/os/session/handlers/metrics-aggregate.d.ts.map +1 -1
  197. package/dist/os/session/handlers/metrics-aggregate.js +9 -5
  198. package/dist/os/session/handlers/metrics-aggregate.js.map +1 -1
  199. package/dist/os/session/handlers/metrics-rfc.d.ts.map +1 -1
  200. package/dist/os/session/handlers/metrics-rfc.js +11 -8
  201. package/dist/os/session/handlers/metrics-rfc.js.map +1 -1
  202. package/dist/os/session/handlers/metrics-session.d.ts.map +1 -1
  203. package/dist/os/session/handlers/metrics-session.js +6 -3
  204. package/dist/os/session/handlers/metrics-session.js.map +1 -1
  205. package/dist/os/session/handlers/save.d.ts.map +1 -1
  206. package/dist/os/session/handlers/save.js +14 -8
  207. package/dist/os/session/handlers/save.js.map +1 -1
  208. package/dist/os/session/session.module.d.ts.map +1 -1
  209. package/dist/os/session/session.module.js +6 -0
  210. package/dist/os/session/session.module.js.map +1 -1
  211. package/dist/os/spec/live-spec-list.js +4 -4
  212. package/dist/os/spec/live-spec-list.js.map +1 -1
  213. package/dist/os/spec/live-spec-merge.js +5 -5
  214. package/dist/os/spec/live-spec-merge.js.map +1 -1
  215. package/dist/os/spec/live-spec-show.js +3 -3
  216. package/dist/os/spec/live-spec-show.js.map +1 -1
  217. package/dist/os/spec/live-spec-validate.js +4 -4
  218. package/dist/os/spec/live-spec-validate.js.map +1 -1
  219. package/dist/os/spec/spec-materialize.js +9 -9
  220. package/dist/os/spec/spec-materialize.js.map +1 -1
  221. package/dist/os/spec/spec-status.js +9 -9
  222. package/dist/os/spec/spec-status.js.map +1 -1
  223. package/dist/os/spec/spec-validate.js +7 -7
  224. package/dist/os/spec/spec-validate.js.map +1 -1
  225. package/dist/os/spec/spec.module.d.ts.map +1 -1
  226. package/dist/os/spec/spec.module.js +8 -0
  227. package/dist/os/spec/spec.module.js.map +1 -1
  228. package/dist/os/werkstatt/handlers/lock.js +16 -16
  229. package/dist/os/werkstatt/handlers/lock.js.map +1 -1
  230. package/dist/os/werkstatt/handlers/werkstatt-lock-recover.js +3 -3
  231. package/dist/os/werkstatt/handlers/werkstatt-lock-recover.js.map +1 -1
  232. package/dist/os/werkstatt/handlers/werkstatt-operation-validate.d.ts.map +1 -1
  233. package/dist/os/werkstatt/handlers/werkstatt-operation-validate.js +3 -2
  234. package/dist/os/werkstatt/handlers/werkstatt-operation-validate.js.map +1 -1
  235. package/dist/os/werkstatt/werkstatt.module.d.ts.map +1 -1
  236. package/dist/os/werkstatt/werkstatt.module.js +6 -2
  237. package/dist/os/werkstatt/werkstatt.module.js.map +1 -1
  238. package/dist/os/workflow/handlers.d.ts.map +1 -1
  239. package/dist/os/workflow/handlers.js +8 -5
  240. package/dist/os/workflow/handlers.js.map +1 -1
  241. package/dist/os/workflow/workflow.module.d.ts.map +1 -1
  242. package/dist/os/workflow/workflow.module.js +6 -3
  243. package/dist/os/workflow/workflow.module.js.map +1 -1
  244. package/dist/src/compass/contract-registry.js +1 -1
  245. package/dist/src/compass/contract-registry.js.map +1 -1
  246. package/dist/src/config/forge-config.d.ts +10 -1
  247. package/dist/src/config/forge-config.d.ts.map +1 -1
  248. package/dist/src/config/forge-config.js +8 -1
  249. package/dist/src/config/forge-config.js.map +1 -1
  250. package/dist/src/knowledge/budgets.js +1 -1
  251. package/dist/src/knowledge/budgets.js.map +1 -1
  252. package/dist/src/knowledge/compact.js +1 -1
  253. package/dist/src/knowledge/compact.js.map +1 -1
  254. package/dist/src/knowledge/parse.js +1 -1
  255. package/dist/src/knowledge/parse.js.map +1 -1
  256. package/dist/src/knowledge/sync.d.ts.map +1 -1
  257. package/dist/src/knowledge/sync.js +3 -5
  258. package/dist/src/knowledge/sync.js.map +1 -1
  259. package/dist/src/migration-adapters/git-utils.js +2 -2
  260. package/dist/src/migration-adapters/git-utils.js.map +1 -1
  261. package/dist/src/migration-adapters/ignored-files.js +2 -2
  262. package/dist/src/migration-adapters/ignored-files.js.map +1 -1
  263. package/dist/src/migration-adapters/node-typescript-pnpm/index.js +1 -1
  264. package/dist/src/migration-adapters/node-typescript-pnpm/index.js.map +1 -1
  265. package/dist/src/migration-adapters/phaser-pnpm/index.js +1 -1
  266. package/dist/src/migration-adapters/phaser-pnpm/index.js.map +1 -1
  267. package/dist/src/onboarding/agents-generate.d.ts +2 -0
  268. package/dist/src/onboarding/agents-generate.d.ts.map +1 -1
  269. package/dist/src/onboarding/agents-generate.js +73 -48
  270. package/dist/src/onboarding/agents-generate.js.map +1 -1
  271. package/dist/src/onboarding/create.d.ts.map +1 -1
  272. package/dist/src/onboarding/create.js +10 -10
  273. package/dist/src/onboarding/create.js.map +1 -1
  274. package/dist/src/onboarding/doctor.d.ts +6 -0
  275. package/dist/src/onboarding/doctor.d.ts.map +1 -1
  276. package/dist/src/onboarding/doctor.js +179 -61
  277. package/dist/src/onboarding/doctor.js.map +1 -1
  278. package/dist/src/onboarding/init.d.ts.map +1 -1
  279. package/dist/src/onboarding/init.js +30 -1
  280. package/dist/src/onboarding/init.js.map +1 -1
  281. package/dist/src/onboarding/invariant-engine.js +1 -1
  282. package/dist/src/onboarding/invariant-engine.js.map +1 -1
  283. package/dist/src/onboarding/memory-compact.d.ts +22 -0
  284. package/dist/src/onboarding/memory-compact.d.ts.map +1 -0
  285. package/dist/src/onboarding/memory-compact.js +148 -0
  286. package/dist/src/onboarding/memory-compact.js.map +1 -0
  287. package/dist/src/onboarding/memory-scaffold.d.ts +1 -0
  288. package/dist/src/onboarding/memory-scaffold.d.ts.map +1 -1
  289. package/dist/src/onboarding/memory-scaffold.js +2 -2
  290. package/dist/src/onboarding/memory-scaffold.js.map +1 -1
  291. package/dist/src/onboarding/nested-agents-generate.d.ts +4 -1
  292. package/dist/src/onboarding/nested-agents-generate.d.ts.map +1 -1
  293. package/dist/src/onboarding/nested-agents-generate.js +35 -6
  294. package/dist/src/onboarding/nested-agents-generate.js.map +1 -1
  295. package/dist/src/onboarding/nested-agents-templates.d.ts.map +1 -1
  296. package/dist/src/onboarding/nested-agents-templates.js +8 -12
  297. package/dist/src/onboarding/nested-agents-templates.js.map +1 -1
  298. package/dist/src/onboarding/npm-token-check.js +2 -2
  299. package/dist/src/onboarding/npm-token-check.js.map +1 -1
  300. package/dist/src/onboarding/prettierignore.d.ts +29 -0
  301. package/dist/src/onboarding/prettierignore.d.ts.map +1 -0
  302. package/dist/src/onboarding/prettierignore.js +231 -0
  303. package/dist/src/onboarding/prettierignore.js.map +1 -0
  304. package/dist/src/onboarding/profile-validate.d.ts.map +1 -1
  305. package/dist/src/onboarding/profile-validate.js +5 -4
  306. package/dist/src/onboarding/profile-validate.js.map +1 -1
  307. package/dist/src/onboarding/scaffold-project.d.ts.map +1 -1
  308. package/dist/src/onboarding/scaffold-project.js +35 -27
  309. package/dist/src/onboarding/scaffold-project.js.map +1 -1
  310. package/dist/src/onboarding/scaffold.js +1 -1
  311. package/dist/src/onboarding/scaffold.js.map +1 -1
  312. package/dist/src/onboarding/skill-markers.d.ts +27 -0
  313. package/dist/src/onboarding/skill-markers.d.ts.map +1 -0
  314. package/dist/src/onboarding/skill-markers.js +131 -0
  315. package/dist/src/onboarding/skill-markers.js.map +1 -0
  316. package/dist/src/onboarding/upgrade.d.ts +10 -0
  317. package/dist/src/onboarding/upgrade.d.ts.map +1 -1
  318. package/dist/src/onboarding/upgrade.js +215 -74
  319. package/dist/src/onboarding/upgrade.js.map +1 -1
  320. package/dist/src/onboarding/workspace-discovery.d.ts +1 -1
  321. package/dist/src/onboarding/workspace-discovery.d.ts.map +1 -1
  322. package/dist/src/onboarding/workspace-discovery.js +15 -3
  323. package/dist/src/onboarding/workspace-discovery.js.map +1 -1
  324. package/dist/src/pipeline-status.d.ts +6 -5
  325. package/dist/src/pipeline-status.d.ts.map +1 -1
  326. package/dist/src/pipeline-status.js +24 -19
  327. package/dist/src/pipeline-status.js.map +1 -1
  328. package/dist/src/profiles/stack-profile.js +1 -1
  329. package/dist/src/profiles/stack-profile.js.map +1 -1
  330. package/dist/src/registry.d.ts +1 -1
  331. package/dist/src/registry.d.ts.map +1 -1
  332. package/dist/src/registry.js +3 -3
  333. package/dist/src/registry.js.map +1 -1
  334. package/dist/src/skill-schema.d.ts +1 -1
  335. package/dist/src/skill-schema.d.ts.map +1 -1
  336. package/dist/src/skill-schema.js +4 -1
  337. package/dist/src/skill-schema.js.map +1 -1
  338. package/dist/src/types.d.ts +116 -0
  339. package/dist/src/types.d.ts.map +1 -1
  340. package/dist/src/utils/editable-region.d.ts +46 -0
  341. package/dist/src/utils/editable-region.d.ts.map +1 -0
  342. package/dist/src/utils/editable-region.js +125 -0
  343. package/dist/src/utils/editable-region.js.map +1 -0
  344. package/dist/src/utils/fs-idempotent.d.ts +2 -1
  345. package/dist/src/utils/fs-idempotent.d.ts.map +1 -1
  346. package/dist/src/utils/fs-idempotent.js +11 -7
  347. package/dist/src/utils/fs-idempotent.js.map +1 -1
  348. package/dist/src/utils/generated-marker.d.ts +17 -0
  349. package/dist/src/utils/generated-marker.d.ts.map +1 -1
  350. package/dist/src/utils/generated-marker.js +29 -1
  351. package/dist/src/utils/generated-marker.js.map +1 -1
  352. package/dist/src/utils/index.d.ts +3 -1
  353. package/dist/src/utils/index.d.ts.map +1 -1
  354. package/dist/src/utils/index.js +3 -1
  355. package/dist/src/utils/index.js.map +1 -1
  356. package/dist/src/utils/io.d.ts +9 -0
  357. package/dist/src/utils/io.d.ts.map +1 -0
  358. package/dist/src/utils/io.js +130 -0
  359. package/dist/src/utils/io.js.map +1 -0
  360. package/dist/src/utils/markdown-table.d.ts +21 -0
  361. package/dist/src/utils/markdown-table.d.ts.map +1 -0
  362. package/dist/src/utils/markdown-table.js +116 -0
  363. package/dist/src/utils/markdown-table.js.map +1 -0
  364. package/dist/src/utils/sync-fs.d.ts +5 -0
  365. package/dist/src/utils/sync-fs.d.ts.map +1 -0
  366. package/dist/src/utils/sync-fs.js +26 -0
  367. package/dist/src/utils/sync-fs.js.map +1 -0
  368. package/dist/src/validators/note-frontmatter-validate.js +1 -1
  369. package/dist/src/validators/note-frontmatter-validate.js.map +1 -1
  370. package/dist/src/validators/note-link-validate.js +1 -1
  371. package/dist/src/validators/note-link-validate.js.map +1 -1
  372. package/dist/src/validators/note-orphan-detect.js +1 -1
  373. package/dist/src/validators/note-orphan-detect.js.map +1 -1
  374. package/dist/src/validators/port-validate.js +1 -1
  375. package/dist/src/validators/port-validate.js.map +1 -1
  376. package/dist/src/validators/skill-validate.d.ts.map +1 -1
  377. package/dist/src/validators/skill-validate.js +34 -13
  378. package/dist/src/validators/skill-validate.js.map +1 -1
  379. package/docs/reference/forge-yaml.md +12 -0
  380. package/os/adr/adr.module.ts +136 -132
  381. package/os/adr/frontmatter-io.ts +5 -5
  382. package/os/adr/handlers/archive.ts +8 -4
  383. package/os/adr/handlers/implement-stamp.ts +14 -9
  384. package/os/adr/handlers/list-create.ts +5 -5
  385. package/os/adr/handlers/validate.ts +1 -1
  386. package/os/audit/audit.module.ts +33 -34
  387. package/os/audit/frontmatter-io.ts +5 -5
  388. package/os/audit/handlers/archive.ts +8 -4
  389. package/os/compass/compass.module.ts +17 -1
  390. package/os/compass/handlers/compass-audit-handler.ts +13 -5
  391. package/os/compass/handlers/compass-change-summary-handler.ts +4 -2
  392. package/os/compass/handlers/compass-inventory-handler.ts +7 -4
  393. package/os/compass/handlers/compass-inventory.ts +11 -8
  394. package/os/compass/handlers/compass-migrate-handler.ts +1 -1
  395. package/os/compass/handlers/compass-migrate.ts +7 -3
  396. package/os/compass/handlers/git-revision.ts +11 -6
  397. package/os/compass/handlers/resolve-scan-root.ts +1 -1
  398. package/os/compass/handlers/summary-record.ts +10 -4
  399. package/os/compass/handlers/tests/compass-audit-plan.test.ts +2 -1
  400. package/os/core/core.module.ts +58 -4
  401. package/os/core/handlers/assets-helpers.ts +7 -3
  402. package/os/core/handlers/build.ts +1 -1
  403. package/os/core/handlers/determinism-check.ts +12 -6
  404. package/os/core/handlers/dev.ts +1 -1
  405. package/os/core/handlers/file-size-lint.ts +16 -9
  406. package/os/core/handlers/forge-autonomy-validate.ts +10 -5
  407. package/os/core/handlers/knowledge-compact.ts +1 -1
  408. package/os/core/handlers/package-health.ts +1 -1
  409. package/os/core/handlers/pinned-check.ts +2 -2
  410. package/os/core/handlers/pinned-init.ts +9 -8
  411. package/os/core/handlers/pinned-validate.ts +3 -3
  412. package/os/core/handlers/profile-resolve.ts +1 -1
  413. package/os/core/handlers/public-surface.ts +1 -1
  414. package/os/core/handlers/release-prepare.ts +11 -6
  415. package/os/core/handlers/release-publish.ts +6 -6
  416. package/os/core/handlers/validate.ts +1 -1
  417. package/os/exploration/exploration.module.ts +1 -0
  418. package/os/exploration/frontmatter-io.ts +4 -4
  419. package/os/exploration/handlers/archive.ts +3 -3
  420. package/os/mission/handlers/archive.ts +27 -19
  421. package/os/mission/mission.module.ts +38 -39
  422. package/os/naming/naming-convention.ts +9 -3
  423. package/os/naming/naming.module.ts +25 -25
  424. package/os/notes/notes.module.ts +87 -85
  425. package/os/plan/frontmatter-io.ts +5 -5
  426. package/os/plan/handlers/archive.ts +8 -4
  427. package/os/plan/plan.module.ts +33 -34
  428. package/os/plugin/plugin.module.ts +8 -6
  429. package/os/program/discovery.ts +2 -2
  430. package/os/program/handlers/complete.ts +1 -1
  431. package/os/program/handlers/lease.ts +1 -1
  432. package/os/program/handlers/seal.ts +1 -1
  433. package/os/program/lease.ts +1 -1
  434. package/os/program/program.module.ts +198 -193
  435. package/os/queue/index.ts +1 -1
  436. package/os/queue/manifest.ts +10 -9
  437. package/os/queue/queue-validate.test.ts +6 -15
  438. package/os/rfc/acceptance.ts +12 -6
  439. package/os/rfc/decision-log.ts +4 -3
  440. package/os/rfc/dna-trace.ts +8 -2
  441. package/os/rfc/frontmatter-io.ts +5 -5
  442. package/os/rfc/handlers/archive.ts +9 -5
  443. package/os/rfc/handlers/check.ts +5 -3
  444. package/os/rfc/handlers/implement-stamp.ts +15 -10
  445. package/os/rfc/handlers/index-graph.ts +3 -3
  446. package/os/rfc/handlers/lifecycle.ts +7 -2
  447. package/os/rfc/handlers/list-create.ts +7 -6
  448. package/os/rfc/handlers/shared.ts +3 -3
  449. package/os/rfc/handlers/supersede-propose.ts +8 -3
  450. package/os/rfc/handlers/validate-rules-rfc1006.test.ts +18 -6
  451. package/os/rfc/handlers/validate-rules.ts +10 -5
  452. package/os/rfc/rfc-create-concurrent.test.ts +11 -3
  453. package/os/rfc/rfc.module.ts +413 -374
  454. package/os/rfc/verification-evidence.ts +11 -5
  455. package/os/rfc/verification-refresh.ts +4 -3
  456. package/os/session/frontmatter-io.ts +14 -14
  457. package/os/session/handlers/archive.ts +8 -4
  458. package/os/session/handlers/metrics-aggregate.ts +34 -13
  459. package/os/session/handlers/metrics-rfc.ts +13 -8
  460. package/os/session/handlers/metrics-session.ts +7 -3
  461. package/os/session/handlers/save.ts +12 -8
  462. package/os/session/session.module.ts +6 -0
  463. package/os/spec/live-spec-list.ts +4 -4
  464. package/os/spec/live-spec-merge.ts +5 -5
  465. package/os/spec/live-spec-show.ts +3 -3
  466. package/os/spec/live-spec-validate.ts +4 -4
  467. package/os/spec/spec-materialize.ts +9 -9
  468. package/os/spec/spec-status.ts +9 -9
  469. package/os/spec/spec-validate.ts +7 -7
  470. package/os/spec/spec.module.ts +8 -0
  471. package/os/werkstatt/handlers/lock.ts +16 -16
  472. package/os/werkstatt/handlers/werkstatt-lock-recover.ts +3 -3
  473. package/os/werkstatt/handlers/werkstatt-operation-validate.ts +4 -2
  474. package/os/werkstatt/werkstatt.module.ts +8 -5
  475. package/os/workflow/handlers.ts +7 -5
  476. package/os/workflow/workflow.module.ts +45 -44
  477. package/package.json +1 -1
  478. package/profiles/forge-shell.yaml +3 -0
  479. package/profiles/godot-game.yaml +3 -0
  480. package/profiles/phaser-game.yaml +3 -0
  481. package/profiles/site-workshop.yaml +567 -564
  482. package/skills/fo/fo-add-tests/SKILL.md +2 -2
  483. package/skills/fo/fo-architecture/SKILL.md +2 -2
  484. package/skills/fo/fo-compass-annotate/SKILL.md +2 -2
  485. package/skills/fo/fo-design-summit/SKILL.md +2 -2
  486. package/skills/fo/fo-doc-audit/SKILL.md +2 -2
  487. package/skills/fo/fo-explore/SKILL.md +2 -2
  488. package/skills/fo/fo-extract-dna/SKILL.md +2 -2
  489. package/skills/fo/fo-fix/SKILL.md +2 -2
  490. package/skills/fo/fo-handoff/SKILL.md +2 -2
  491. package/skills/fo/fo-harvest/SKILL.md +2 -2
  492. package/skills/fo/fo-idea/SKILL.md +2 -2
  493. package/skills/fo/fo-idea-audit/SKILL.md +2 -2
  494. package/skills/fo/fo-idea-create-adr/SKILL.md +3 -3
  495. package/skills/fo/fo-idea-create-rfc/SKILL.md +3 -3
  496. package/skills/fo/fo-idea-enhance/SKILL.md +2 -2
  497. package/skills/fo/fo-idea-i-just-want-to-see-the-plan/SKILL.md +2 -2
  498. package/skills/fo/fo-idea-i-just-want-to-see-the-result/SKILL.md +1 -1
  499. package/skills/fo/fo-idea-implement/SKILL.md +2 -2
  500. package/skills/fo/fo-idea-plan/SKILL.md +2 -2
  501. package/skills/fo/fo-idea-status/SKILL.md +2 -2
  502. package/skills/fo/fo-knowledge-distill/SKILL.md +2 -2
  503. package/skills/fo/fo-memory-sync/SKILL.md +2 -2
  504. package/skills/fo/fo-qa/SKILL.md +2 -2
  505. package/skills/fo/fo-review/SKILL.md +2 -2
  506. package/skills/fo/fo-session-retro/SKILL.md +2 -2
  507. package/skills/fo/fo-session-save/SKILL.md +2 -2
  508. package/skills/fo/fo-spec-ingest/SKILL.md +2 -2
  509. package/skills/fo/fo-step-commit/SKILL.md +1 -1
  510. package/skills/fo/fo-triage/SKILL.md +2 -2
  511. package/skills/meta/forge-bootstrap/SKILL.md +1 -1
  512. package/skills/meta/port-to-forge/SKILL.md +1 -1
  513. package/skills/meta/skill-create/SKILL.md +1 -1
  514. package/skills/shared/grilling/SKILL.md +1 -1
  515. package/skills/shared/grilling/learned-principles.archive.md +17 -0
  516. package/skills/shared/grilling/learned-principles.md +0 -1
  517. package/skills/shared/knowledge/learned-principles.md +6 -0
  518. package/skills/shared/my-preferences/SKILL.md +1 -1
  519. package/skills/shared/windows-ai-tooling/SKILL.md +1 -1
  520. package/skills/shared/writing-great-skills/SKILL.md +1 -1
  521. package/src/compass/contract-registry.ts +1 -1
  522. package/src/config/forge-config.ts +12 -1
  523. package/src/knowledge/__tests__/sync.test.ts +2 -7
  524. package/src/knowledge/budgets.ts +1 -1
  525. package/src/knowledge/compact.ts +1 -1
  526. package/src/knowledge/parse.ts +1 -1
  527. package/src/knowledge/sync.ts +3 -5
  528. package/src/migration-adapters/git-utils.ts +2 -2
  529. package/src/migration-adapters/ignored-files.ts +2 -2
  530. package/src/migration-adapters/node-typescript-pnpm/index.ts +1 -1
  531. package/src/migration-adapters/phaser-pnpm/index.ts +1 -1
  532. package/src/onboarding/agents-generate.ts +91 -50
  533. package/src/onboarding/create.ts +10 -10
  534. package/src/onboarding/doctor.ts +199 -59
  535. package/src/onboarding/init.ts +38 -1
  536. package/src/onboarding/invariant-engine.ts +1 -1
  537. package/src/onboarding/memory-compact.ts +189 -0
  538. package/src/onboarding/memory-scaffold.ts +2 -2
  539. package/src/onboarding/nested-agents-generate.ts +50 -5
  540. package/src/onboarding/nested-agents-templates.ts +19 -13
  541. package/src/onboarding/npm-token-check.ts +2 -2
  542. package/src/onboarding/prettierignore.ts +263 -0
  543. package/src/onboarding/profile-validate.ts +5 -4
  544. package/src/onboarding/scaffold-project.ts +38 -27
  545. package/src/onboarding/scaffold.ts +1 -1
  546. package/src/onboarding/skill-markers.ts +162 -0
  547. package/src/onboarding/templates/behavioral-layer-core.md +2 -4
  548. package/src/onboarding/upgrade.ts +285 -89
  549. package/src/onboarding/workspace-discovery.ts +16 -2
  550. package/src/pipeline-status.test.ts +1 -4
  551. package/src/pipeline-status.ts +30 -13
  552. package/src/profiles/stack-profile.ts +1 -1
  553. package/src/registry.ts +4 -4
  554. package/src/skill-schema.ts +4 -1
  555. package/src/tests/acceptance-probe-kinds.test.ts +5 -15
  556. package/src/tests/agents-generate.test.ts +32 -7
  557. package/src/tests/contract-registry.test.ts +12 -6
  558. package/src/tests/doctor-dist-freshness.test.ts +110 -0
  559. package/src/tests/doctor-fix.test.ts +142 -0
  560. package/src/tests/doctor-nested-agents.test.ts +160 -0
  561. package/src/tests/editable-generated-region.test.ts +231 -0
  562. package/src/tests/file-size-lint.test.ts +8 -12
  563. package/src/tests/fixtures/agents-generate-business-before.txt +54 -54
  564. package/src/tests/markdown-table.test.ts +107 -0
  565. package/src/tests/memory-compact.test.ts +143 -0
  566. package/src/tests/prettierignore-manage.test.ts +134 -0
  567. package/src/tests/skill-agents-sync.test.ts +168 -0
  568. package/src/tests/skill-sync-marker.test.ts +134 -0
  569. package/src/tests/skill-validate.test.ts +12 -5
  570. package/src/tests/upgrade.test.ts +87 -41
  571. package/src/tests/workspace-discovery.test.ts +28 -0
  572. package/src/types.ts +123 -0
  573. package/src/utils/editable-region.ts +156 -0
  574. package/src/utils/fs-idempotent.ts +12 -6
  575. package/src/utils/generated-marker.ts +36 -2
  576. package/src/utils/index.ts +17 -0
  577. package/src/utils/io.ts +143 -0
  578. package/src/utils/markdown-table.ts +121 -0
  579. package/src/utils/sync-fs.ts +43 -0
  580. package/src/validators/note-frontmatter-validate.ts +1 -1
  581. package/src/validators/note-link-validate.ts +1 -1
  582. package/src/validators/note-orphan-detect.ts +1 -1
  583. package/src/validators/port-validate.ts +1 -1
  584. package/src/validators/skill-validate.ts +38 -13
@@ -0,0 +1,189 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>forge memory.compact — mechanically enforce the MEMORY.md character budget
4
+ (RFC-0664) by removing oldest Environment notes bullets until the file fits.
5
+ Invoked standalone and by forge doctor --fix for the memory-layer check (RFC-1151).</purpose>
6
+ <non-goals>
7
+ <item>Never touch "## Current focus" or "## Decisions in flight" — those need editorial judgment.</item>
8
+ <item>No semantic rewriting — bullets are removed whole, never edited or merged.</item>
9
+ <item>No archiving into daily/ logs — removed content is recoverable via git history.</item>
10
+ </non-goals>
11
+ </MODULE_CONTRACT>
12
+ <CHANGE_SUMMARY>
13
+ <item>RFC-1151: initial memory.compact — oldest-first Environment notes truncation.</item>
14
+ </CHANGE_SUMMARY>
15
+ */
16
+
17
+ import { resolveIo } from "../utils/io.ts";
18
+ import path from "node:path";
19
+ import type { ForgeCommandInput, ForgeCommandResult, ForgeRuntimeContext } from "../types.ts";
20
+ import { resolveMemoryBudget } from "./memory-scaffold.ts";
21
+
22
+ const MEMORY_MD_PATH = path.join(".agents", "memory", "MEMORY.md");
23
+ const COMPACT_SECTION = "## Environment notes";
24
+ const PROTECTED_SECTIONS = new Set(["## Current focus", "## Decisions in flight"]);
25
+
26
+ export interface MemoryCompactResult {
27
+ command: "forge.memory.compact";
28
+ status: "pass" | "fail";
29
+ removed: number;
30
+ remainingChars: number;
31
+ budget: number;
32
+ removedLines?: string[];
33
+ errors: string[];
34
+ }
35
+
36
+ interface Section {
37
+ header: string;
38
+ start: number; // line index of the "## ..." header
39
+ end: number; // line index one past the section's last line
40
+ }
41
+
42
+ function parseSections(lines: string[]): Section[] {
43
+ const sections: Section[] = [];
44
+ for (let i = 0; i < lines.length; i++) {
45
+ if (lines[i].startsWith("## ")) {
46
+ if (sections.length > 0) sections[sections.length - 1].end = i;
47
+ sections.push({ header: lines[i].trim(), start: i, end: lines.length });
48
+ }
49
+ }
50
+ return sections;
51
+ }
52
+
53
+ function isBullet(line: string): boolean {
54
+ return /^\s*-\s+/.test(line);
55
+ }
56
+
57
+ /**
58
+ * Remove oldest bullets from `## Environment notes` until the file fits the
59
+ * budget. Returns the new line list and the removed bullet lines.
60
+ * Exported for reuse by `forge doctor --fix` (RFC-1151).
61
+ */
62
+ export function compactMemoryMd(
63
+ content: string,
64
+ budget: number,
65
+ ): { lines: string[]; removedLines: string[]; fitsBudget: boolean } {
66
+ if (content.length <= budget) {
67
+ return { lines: content.split("\n"), removedLines: [], fitsBudget: true };
68
+ }
69
+
70
+ const lines = content.split("\n");
71
+ const sections = parseSections(lines);
72
+ const target = sections.find((s) => s.header === COMPACT_SECTION);
73
+
74
+ const removedLines: string[] = [];
75
+ if (target) {
76
+ // Sanity: never remove from protected sections even if headers drift.
77
+ if (PROTECTED_SECTIONS.has(target.header)) {
78
+ return { lines, removedLines, fitsBudget: false };
79
+ }
80
+ // Remove bullet lines oldest-first (document order) within the section.
81
+ let i = target.start + 1;
82
+ while (i < target.end && lines.join("\n").length > budget) {
83
+ if (isBullet(lines[i])) {
84
+ removedLines.push(lines[i]);
85
+ lines.splice(i, 1);
86
+ target.end--;
87
+ // Recompute section ends after splice — only the target shrinks.
88
+ } else {
89
+ i++;
90
+ }
91
+ }
92
+ }
93
+
94
+ const fitsBudget = lines.join("\n").length <= budget;
95
+ return { lines, removedLines, fitsBudget };
96
+ }
97
+
98
+ export async function runMemoryCompact(
99
+ _input: ForgeCommandInput,
100
+ context: ForgeRuntimeContext,
101
+ ): Promise<ForgeCommandResult<MemoryCompactResult>> {
102
+ const { workspaceRoot, logger, outputFormat, dryRun } = context;
103
+ const fio = resolveIo(context.io);
104
+ const memoryPath = path.join(workspaceRoot, MEMORY_MD_PATH);
105
+ const budget = resolveMemoryBudget(workspaceRoot);
106
+
107
+ const fail = (msg: string): ForgeCommandResult<MemoryCompactResult> => ({
108
+ data: {
109
+ command: "forge.memory.compact",
110
+ status: "fail",
111
+ removed: 0,
112
+ remainingChars: 0,
113
+ budget,
114
+ errors: [msg],
115
+ },
116
+ exitCode: 1,
117
+ summary: `forge.memory.compact: failed — ${msg}`,
118
+ });
119
+
120
+ if (!(await fio.exists(memoryPath))) {
121
+ return {
122
+ data: {
123
+ command: "forge.memory.compact",
124
+ status: "pass",
125
+ removed: 0,
126
+ remainingChars: 0,
127
+ budget,
128
+ errors: [],
129
+ },
130
+ exitCode: 0,
131
+ summary: "forge.memory.compact: OK — MEMORY.md absent, nothing to compact",
132
+ };
133
+ }
134
+
135
+ const content = await fio.readFile(memoryPath);
136
+ if (content.length <= budget) {
137
+ return {
138
+ data: {
139
+ command: "forge.memory.compact",
140
+ status: "pass",
141
+ removed: 0,
142
+ remainingChars: content.length,
143
+ budget,
144
+ errors: [],
145
+ },
146
+ exitCode: 0,
147
+ summary: `forge.memory.compact: OK — already within budget (${content.length}/${budget} chars)`,
148
+ };
149
+ }
150
+
151
+ const { lines, removedLines, fitsBudget } = compactMemoryMd(content, budget);
152
+ const remainingChars = lines.join("\n").length;
153
+
154
+ if (!fitsBudget) {
155
+ return fail(
156
+ `still over budget after removing ${removedLines.length} Environment notes bullet(s) ` +
157
+ `(${remainingChars}/${budget} chars) — manual editorial compaction required`,
158
+ );
159
+ }
160
+
161
+ if (!dryRun) {
162
+ await fio.writeFile(memoryPath, lines.join("\n"));
163
+ }
164
+
165
+ if (outputFormat === "pretty") {
166
+ for (const line of removedLines) {
167
+ logger.info(`removed: ${line.slice(0, 80)}`);
168
+ }
169
+ logger.success(
170
+ `${dryRun ? "[dry-run] would remove" : "removed"} ${removedLines.length} bullet(s) — ${remainingChars}/${budget} chars`,
171
+ );
172
+ }
173
+
174
+ return {
175
+ data: {
176
+ command: "forge.memory.compact",
177
+ status: "pass",
178
+ removed: removedLines.length,
179
+ remainingChars,
180
+ budget,
181
+ removedLines: dryRun ? removedLines : undefined,
182
+ errors: [],
183
+ },
184
+ exitCode: 0,
185
+ summary: dryRun
186
+ ? `forge.memory.compact: [dry-run] would remove ${removedLines.length} bullet(s) — ${remainingChars}/${budget} chars`
187
+ : `forge.memory.compact: OK — removed ${removedLines.length} bullet(s), ${remainingChars}/${budget} chars`,
188
+ };
189
+ }
@@ -12,7 +12,7 @@
12
12
  </CHANGE_SUMMARY>
13
13
  */
14
14
 
15
- import fs from "node:fs";
15
+ import * as fs from "../utils/sync-fs.ts";
16
16
  import path from "node:path";
17
17
  import { loadForgeConfig } from "../config/forge-config.ts";
18
18
 
@@ -138,7 +138,7 @@ export function scaffoldMemoryLayer(workspaceRoot: string): MemoryScaffoldResult
138
138
  // Health check
139
139
  // ---------------------------------------------------------------------------
140
140
 
141
- function resolveMemoryBudget(workspaceRoot: string): number {
141
+ export function resolveMemoryBudget(workspaceRoot: string): number {
142
142
  try {
143
143
  const config = loadForgeConfig(workspaceRoot);
144
144
  if (config.bindings?.memory?.budget !== undefined && config.bindings?.memory?.budget !== null) {
@@ -23,19 +23,29 @@ Sweep batch 4: 73 Compass headers on headerless engine files (certification, com
23
23
  </CHANGE_SUMMARY>
24
24
  */
25
25
 
26
- import fs from "node:fs";
26
+ import * as fs from "../utils/sync-fs.ts";
27
27
  import path from "node:path";
28
- import { writeFileIfChanged } from "../utils/index.ts";
28
+ import {
29
+ canonicalFooterOf,
30
+ hasEditableGeneratedMarker,
31
+ mergeEditableGenerated,
32
+ splitEditableGenerated,
33
+ writeFileIfChanged,
34
+ } from "../utils/index.ts";
35
+ import { resolveIo } from "../utils/io.ts";
29
36
  import { discoverWorkspaces } from "./workspace-discovery.ts";
30
37
  import { buildNestedAgentsMd, selectNestedTemplate, type PackageInfo } from "./nested-agents-templates.ts";
31
38
  import type { ForgeConfig } from "../config/forge-config.ts";
32
39
  import type { ProfileWorkspaceType } from "../profiles/profile-schema.ts";
33
40
  import type { StackProfile } from "../profiles/stack-profile.ts";
41
+ import type { WorkspaceIO } from "../types.ts";
34
42
  import { resolveAllTerminology } from "../profiles/terminology-utils.ts";
35
43
 
36
44
  export interface NestedGenerateResult {
37
45
  generated: string[];
38
46
  skipped: string[];
47
+ /** RFC-1153: files merged with a carried custom tail below the boundary. */
48
+ preserved: string[];
39
49
  renderedFiles: { [relPath: string]: string };
40
50
  workspaceTypeMap?: { [relPath: string]: string };
41
51
  }
@@ -55,11 +65,18 @@ export async function generateNestedAgentsMd(
55
65
  config: ForgeConfig,
56
66
  dryRun: boolean,
57
67
  workspaceTypes?: ProfileWorkspaceType[],
68
+ io?: WorkspaceIO,
58
69
  ): Promise<NestedGenerateResult> {
59
- const workspaces = discoverWorkspaces(workspaceRoot, workspaceTypes);
70
+ const workspaces = discoverWorkspaces(
71
+ workspaceRoot,
72
+ workspaceTypes,
73
+ config.bindings?.workspaces?.skipDirs,
74
+ );
60
75
  const generated: string[] = [];
61
76
  const skipped: string[] = [];
77
+ const preserved: string[] = [];
62
78
  const renderedFiles: { [relPath: string]: string } = {};
79
+ const fio = resolveIo(io);
63
80
  const workspaceTypeMap: { [relPath: string]: string } = {};
64
81
 
65
82
  // RFC-0643: resolve terminology from config + profile for nested template substitution
@@ -86,12 +103,40 @@ export async function generateNestedAgentsMd(
86
103
  continue;
87
104
  }
88
105
 
89
- await writeFileIfChanged(agentsMdPath, content);
106
+ // RFC-1153: merge instead of overwrite — the `forge:custom` boundary marks
107
+ // the split between the generator-owned head and the preserved custom tail.
108
+ let existing: string | null = null;
109
+ if (ws.hasAgentsMd) {
110
+ try {
111
+ existing = await fio.readFile(agentsMdPath);
112
+ } catch {
113
+ // Unreadable — treat as absent; merge will emit a fresh file.
114
+ }
115
+ }
116
+ let merged = mergeEditableGenerated(content, existing, relPath);
117
+ if (merged === null && existing !== null && !hasEditableGeneratedMarker(existing)) {
118
+ // RFC-0081/RFC-1153: restrictive-marker file is fully generator-owned —
119
+ // upgrade it to the editable boundary contract (fresh render + marker).
120
+ merged = mergeEditableGenerated(content, null, relPath);
121
+ }
122
+ if (merged === null) {
123
+ skipped.push(`${relPath} (unmapped-customization)`);
124
+ continue;
125
+ }
126
+
127
+ await writeFileIfChanged(agentsMdPath, merged, fio);
90
128
  generated.push(relPath);
91
129
  workspaceTypeMap[relPath] = ws.type;
130
+ const footer = canonicalFooterOf(content);
131
+ if (
132
+ existing !== null &&
133
+ splitEditableGenerated(existing, relPath, footer ?? undefined).customTail !== null
134
+ ) {
135
+ preserved.push(relPath);
136
+ }
92
137
  }
93
138
 
94
- return { generated, skipped, renderedFiles, workspaceTypeMap };
139
+ return { generated, skipped, preserved, renderedFiles, workspaceTypeMap };
95
140
  }
96
141
 
97
142
  export { discoverWorkspaces, type WorkspaceDir, type WorkspaceType } from "./workspace-discovery.ts";
@@ -19,13 +19,13 @@ Sweep batch 4: 73 Compass headers on headerless engine files (certification, com
19
19
  </CHANGE_SUMMARY>
20
20
  */
21
21
 
22
- import { buildGeneratedHeader } from "../utils/index.ts";
22
+ import { alignMarkdownTable, buildGeneratedHeader } from "../utils/index.ts";
23
23
  import { resolveForgePackageRoot } from "../config/forge-config.ts";
24
24
  import type { ForgeConfig } from "../config/forge-config.ts";
25
25
  import type { WorkspaceDir, WorkspaceType } from "./workspace-discovery.ts";
26
26
  import type { ProfileWorkspaceType } from "../profiles/profile-schema.ts";
27
27
  import type { StackProfile } from "../profiles/stack-profile.ts";
28
- import fs from "node:fs";
28
+ import * as fs from "../utils/sync-fs.ts";
29
29
  import path from "node:path";
30
30
 
31
31
  export interface PackageInfo {
@@ -99,11 +99,13 @@ function buildScriptsTable(scripts: Record<string, string> | undefined): string[
99
99
  const lines: string[] = [];
100
100
  lines.push("## Scripts");
101
101
  lines.push("");
102
- lines.push("| Script | Command |");
103
- lines.push("| --- | --- |");
104
- for (const [name, cmd] of Object.entries(scripts)) {
105
- lines.push(`| \`${name}\` | \`${cmd}\` |`);
106
- }
102
+ // RFC-1154: emitted prettier-normal via alignMarkdownTable
103
+ lines.push(
104
+ alignMarkdownTable(
105
+ ["Script", "Command"],
106
+ Object.entries(scripts).map(([name, cmd]) => [`\`${name}\``, `\`${cmd}\``]),
107
+ ),
108
+ );
107
109
  lines.push("");
108
110
  return lines;
109
111
  }
@@ -222,12 +224,16 @@ export function buildNestedAgentsMd(
222
224
  if (entryPoints.length > 0) {
223
225
  lines.push("## Entry points");
224
226
  lines.push("");
225
- lines.push("| Entry point | Module |");
226
- lines.push("| --- | --- |");
227
- for (const ep of entryPoints) {
228
- const suffix = ep.name === "." ? "" : ep.name.replace(/^\.\//, "/");
229
- lines.push(`| \`${displayName}${suffix}\` | \`${ep.module}\` |`);
230
- }
227
+ // RFC-1154: emitted prettier-normal via alignMarkdownTable
228
+ lines.push(
229
+ alignMarkdownTable(
230
+ ["Entry point", "Module"],
231
+ entryPoints.map((ep) => {
232
+ const suffix = ep.name === "." ? "" : ep.name.replace(/^\.\//, "/");
233
+ return [`\`${displayName}${suffix}\``, `\`${ep.module}\``];
234
+ }),
235
+ ),
236
+ );
231
237
  lines.push("");
232
238
  }
233
239
  }
@@ -11,8 +11,8 @@
11
11
  </CHANGE_SUMMARY>
12
12
  */
13
13
 
14
- import { execSync } from "node:child_process";
15
- import fs from "node:fs";
14
+ import { execSync } from "../utils/sync-fs.ts";
15
+ import * as fs from "../utils/sync-fs.ts";
16
16
  import path from "node:path";
17
17
 
18
18
  /** Result of the npm-token probe (RFC-1125). */
@@ -0,0 +1,263 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>
4
+ RFC-1154: managed `.prettierignore` block for forge-owned generated paths.
5
+ planPrettierignore detects whether a consumer project uses prettier (root
6
+ config file, package.json key, or existing .prettierignore) and computes the
7
+ delimited block entries — forge-synced skill dirs plus generated-artifact
8
+ globs. applyPrettierignore reconciles the block idempotently via
9
+ writeFileIfChanged; everything outside the delimited markers stays
10
+ operator-owned.
11
+ </purpose>
12
+ <non-goals>
13
+ <item>Do not detect prettier outside the project root — nested-only configs are out of scope (documented limitation).</item>
14
+ <item>Do not touch consumer entries outside the delimited block — the rest of the file is operator-owned.</item>
15
+ <item>Do not list unmarked skill dirs — .agents/skills entries come from .forge-managed markers only (AC-9).</item>
16
+ </non-goals>
17
+ <KEY_DECISIONS>
18
+ <item>Skill entries enumerate dirs carrying a .forge-managed marker — block membership equals the forge-owned set.</item>
19
+ <item>Unbalanced markers treat the file as operator-owned; a fresh block is appended, never merged.</item>
20
+ </KEY_DECISIONS>
21
+ </MODULE_CONTRACT>
22
+ <CHANGE_SUMMARY>
23
+ <item>RFC-1154: initial implementation — plan/apply + delimited-block reconcile.</item>
24
+ </CHANGE_SUMMARY>
25
+ */
26
+
27
+ import path from "node:path";
28
+ import type { WorkspaceIO } from "../types.ts";
29
+ import { resolveIo } from "../utils/io.ts";
30
+ import { writeFileIfChanged } from "../utils/fs-idempotent.ts";
31
+ import { fileExists } from "../utils/fs.ts";
32
+ import * as sfs from "../utils/sync-fs.ts";
33
+ import { SKILL_MARKER_FILE } from "./skill-markers.ts";
34
+
35
+ export const PRETTIERIGNORE_BLOCK_BEGIN = "# forge-managed generated paths (RFC-1154)";
36
+ export const PRETTIERIGNORE_BLOCK_END = "# end forge-managed";
37
+
38
+ /** Prettier config files probed at the project root (root-only detection). */
39
+ const PRETTIER_CONFIG_NAMES = [
40
+ ".prettierrc",
41
+ ".prettierrc.json",
42
+ ".prettierrc.yml",
43
+ ".prettierrc.yaml",
44
+ ".prettierrc.js",
45
+ ".prettierrc.cjs",
46
+ ".prettierrc.mjs",
47
+ ".prettierrc.toml",
48
+ "prettier.config.js",
49
+ "prettier.config.cjs",
50
+ "prettier.config.mjs",
51
+ "prettier.config.ts",
52
+ ];
53
+
54
+ /** Non-skill generated-artifact entries, in stable order. */
55
+ const FIXED_ENTRIES = [
56
+ "**/*.generated.yaml",
57
+ "docs/sessions/",
58
+ "docs/metrics/",
59
+ "docs/queues/session-*.yaml",
60
+ ];
61
+
62
+ export interface PrettierignorePlan {
63
+ applies: boolean; // consumer uses prettier
64
+ entries: string[]; // resolved ignore entries for this workspace
65
+ fileExists: boolean;
66
+ }
67
+
68
+ export type PrettierignoreResult = "written" | "updated" | "unchanged" | "skipped";
69
+
70
+ function packageJsonUsesPrettier(pkg: Record<string, unknown>): boolean {
71
+ if (typeof pkg["prettier"] !== "undefined") return true;
72
+ for (const depKey of ["dependencies", "devDependencies"]) {
73
+ const deps = pkg[depKey];
74
+ if (deps && typeof deps === "object" && "prettier" in deps) return true;
75
+ }
76
+ return false;
77
+ }
78
+
79
+ async function detectPrettier(workspaceRoot: string, io: WorkspaceIO): Promise<boolean> {
80
+ for (const name of PRETTIER_CONFIG_NAMES) {
81
+ if (await io.exists(path.join(workspaceRoot, name))) return true;
82
+ }
83
+ const pkgPath = path.join(workspaceRoot, "package.json");
84
+ if (await io.exists(pkgPath)) {
85
+ try {
86
+ if (packageJsonUsesPrettier(JSON.parse(await io.readFile(pkgPath)))) return true;
87
+ } catch {
88
+ // Unreadable package.json — other probes still apply
89
+ }
90
+ }
91
+ return fileExists(path.join(workspaceRoot, ".prettierignore"));
92
+ }
93
+
94
+ // Sync twin for runInit (sync call path — no WorkspaceIO).
95
+ function detectPrettierSync(workspaceRoot: string): boolean {
96
+ for (const name of PRETTIER_CONFIG_NAMES) {
97
+ if (sfs.existsSync(path.join(workspaceRoot, name))) return true;
98
+ }
99
+ const pkgPath = path.join(workspaceRoot, "package.json");
100
+ if (sfs.existsSync(pkgPath)) {
101
+ try {
102
+ if (packageJsonUsesPrettier(JSON.parse(sfs.readFileSync(pkgPath, "utf8")))) return true;
103
+ } catch {
104
+ // Unreadable package.json — other probes still apply
105
+ }
106
+ }
107
+ return sfs.existsSync(path.join(workspaceRoot, ".prettierignore"));
108
+ }
109
+
110
+ /**
111
+ * Skill-dir entries derive from `.forge-managed` markers under
112
+ * `agentsSkillsDir` — marker presence is the forge-ownership proof (AC-9:
113
+ * unmarked dirs are consumer-owned and never listed).
114
+ */
115
+ async function listManagedSkillEntries(
116
+ workspaceRoot: string,
117
+ skillsDirRel: string,
118
+ io: WorkspaceIO,
119
+ ): Promise<string[]> {
120
+ const entries: string[] = [];
121
+ const absDir = path.join(workspaceRoot, skillsDirRel);
122
+ let children;
123
+ try {
124
+ children = await io.readdir(absDir);
125
+ } catch {
126
+ return entries;
127
+ }
128
+ for (const child of children) {
129
+ if (!child.isDirectory) continue;
130
+ if (await io.exists(path.join(absDir, child.name, SKILL_MARKER_FILE))) {
131
+ entries.push(`${skillsDirRel.replace(/\/+$/, "")}/${child.name}/`);
132
+ }
133
+ }
134
+ return entries.sort();
135
+ }
136
+
137
+ // Sync twin for runInit.
138
+ function listManagedSkillEntriesSync(workspaceRoot: string, skillsDirRel: string): string[] {
139
+ const entries: string[] = [];
140
+ const absDir = path.join(workspaceRoot, skillsDirRel);
141
+ let children;
142
+ try {
143
+ children = sfs.readdirSync(absDir, { withFileTypes: true });
144
+ } catch {
145
+ return entries;
146
+ }
147
+ for (const child of children) {
148
+ if (!child.isDirectory()) continue;
149
+ if (sfs.existsSync(path.join(absDir, child.name, SKILL_MARKER_FILE))) {
150
+ entries.push(`${skillsDirRel.replace(/\/+$/, "")}/${child.name}/`);
151
+ }
152
+ }
153
+ return entries.sort();
154
+ }
155
+
156
+ export async function planPrettierignore(
157
+ workspaceRoot: string,
158
+ skillsDirRel = ".agents/skills",
159
+ io?: WorkspaceIO,
160
+ ): Promise<PrettierignorePlan> {
161
+ const fio = resolveIo(io);
162
+ const applies = await detectPrettier(workspaceRoot, fio);
163
+ const skillEntries = applies
164
+ ? await listManagedSkillEntries(workspaceRoot, skillsDirRel, fio)
165
+ : [];
166
+ return {
167
+ applies,
168
+ entries: [...skillEntries, ...FIXED_ENTRIES],
169
+ fileExists: await fileExists(path.join(workspaceRoot, ".prettierignore")),
170
+ };
171
+ }
172
+
173
+ // Sync twin for runInit.
174
+ export function planPrettierignoreSync(
175
+ workspaceRoot: string,
176
+ skillsDirRel = ".agents/skills",
177
+ ): PrettierignorePlan {
178
+ const applies = detectPrettierSync(workspaceRoot);
179
+ const skillEntries = applies ? listManagedSkillEntriesSync(workspaceRoot, skillsDirRel) : [];
180
+ return {
181
+ applies,
182
+ entries: [...skillEntries, ...FIXED_ENTRIES],
183
+ fileExists: sfs.existsSync(path.join(workspaceRoot, ".prettierignore")),
184
+ };
185
+ }
186
+
187
+ function renderBlock(entries: string[]): string {
188
+ return [PRETTIERIGNORE_BLOCK_BEGIN, ...entries, PRETTIERIGNORE_BLOCK_END].join("\n");
189
+ }
190
+
191
+ /**
192
+ * Pure reconcile: compute the next `.prettierignore` content from existing
193
+ * content + managed entries. Content outside the delimited block is preserved
194
+ * verbatim; unbalanced markers cause the whole file to be treated as
195
+ * operator-owned (fresh block appended).
196
+ */
197
+ export function reconcilePrettierignoreContent(
198
+ existing: string,
199
+ entries: string[],
200
+ ): { next: string; changed: Exclude<PrettierignoreResult, "skipped"> } {
201
+ const block = renderBlock(entries);
202
+ if (existing === "") {
203
+ return { next: block + "\n", changed: "written" };
204
+ }
205
+
206
+ const beginIdx = existing.indexOf(PRETTIERIGNORE_BLOCK_BEGIN);
207
+ const endIdx = existing.indexOf(PRETTIERIGNORE_BLOCK_END);
208
+ const balanced = beginIdx !== -1 && endIdx !== -1 && endIdx > beginIdx;
209
+ if (balanced) {
210
+ const before = existing.slice(0, beginIdx);
211
+ const after = existing.slice(endIdx + PRETTIERIGNORE_BLOCK_END.length).replace(/^\r?\n/, "");
212
+ let next = before + block + (after ? "\n" + after : "");
213
+ if (!next.endsWith("\n")) next += "\n";
214
+ return { next, changed: next === existing ? "unchanged" : "updated" };
215
+ }
216
+
217
+ const next = existing.endsWith("\n")
218
+ ? existing + "\n" + block + "\n"
219
+ : existing + "\n\n" + block + "\n";
220
+ return { next, changed: "updated" };
221
+ }
222
+
223
+ /**
224
+ * Reconcile the managed block in `.prettierignore` (async/io path — used by
225
+ * forge upgrade and kernel-driven callers).
226
+ */
227
+ export async function applyPrettierignore(
228
+ workspaceRoot: string,
229
+ plan: PrettierignorePlan,
230
+ io?: WorkspaceIO,
231
+ ): Promise<PrettierignoreResult> {
232
+ if (!plan.applies) return "skipped";
233
+
234
+ const fio = resolveIo(io);
235
+ const filePath = path.join(workspaceRoot, ".prettierignore");
236
+
237
+ let existing = "";
238
+ try {
239
+ existing = await fio.readFile(filePath);
240
+ } catch {
241
+ // File absent — create containing only the managed block
242
+ }
243
+
244
+ const { next, changed } = reconcilePrettierignoreContent(existing, plan.entries);
245
+ if (changed === "unchanged") return "unchanged";
246
+ const writeResult = await writeFileIfChanged(filePath, next, fio);
247
+ return writeResult === "unchanged" ? "unchanged" : changed;
248
+ }
249
+
250
+ /** Sync twin for runInit — same contract via sync-fs. */
251
+ export function applyPrettierignoreSync(
252
+ workspaceRoot: string,
253
+ plan: PrettierignorePlan,
254
+ ): PrettierignoreResult {
255
+ if (!plan.applies) return "skipped";
256
+
257
+ const filePath = path.join(workspaceRoot, ".prettierignore");
258
+ const existing = sfs.existsSync(filePath) ? sfs.readFileSync(filePath, "utf8") : "";
259
+ const { next, changed } = reconcilePrettierignoreContent(existing, plan.entries);
260
+ if (changed === "unchanged") return "unchanged";
261
+ sfs.writeFileSync(filePath, next, "utf8");
262
+ return changed;
263
+ }
@@ -11,7 +11,7 @@
11
11
  </CHANGE_SUMMARY>
12
12
  */
13
13
 
14
- import fs from "node:fs";
14
+ import { resolveIo } from "../utils/io.ts";
15
15
  import path from "node:path";
16
16
  import { parse as parseYaml } from "yaml";
17
17
  import { stackProfileSchema } from "../profiles/stack-profile.ts";
@@ -37,6 +37,7 @@ export async function runProfileValidate(
37
37
  context: ForgeRuntimeContext,
38
38
  ): Promise<ForgeCommandResult<ProfileValidateResult>> {
39
39
  const { workspaceRoot, logger, outputFormat } = context;
40
+ const fio = resolveIo(context.io);
40
41
  const filterId = input.flags["id"] as string | undefined;
41
42
 
42
43
  const forgeRoot = context.forgeRoot ?? path.join(workspaceRoot, "packages", "forge");
@@ -44,7 +45,7 @@ export async function runProfileValidate(
44
45
 
45
46
  const profileResults: ProfileValidateResult["profiles"] = [];
46
47
 
47
- if (!fs.existsSync(profilesDir)) {
48
+ if (!(await fio.exists(profilesDir))) {
48
49
  const result: ProfileValidateResult = {
49
50
  command: "forge.profile.validate",
50
51
  valid: true,
@@ -60,12 +61,12 @@ export async function runProfileValidate(
60
61
  };
61
62
  }
62
63
 
63
- const entries = fs.readdirSync(profilesDir);
64
+ const entries = (await fio.readdir(profilesDir)).map((e) => e.name);
64
65
  for (const entry of entries) {
65
66
  if (!entry.endsWith(".yaml") || entry.startsWith(".")) continue;
66
67
 
67
68
  const profilePath = path.join(profilesDir, entry);
68
- const raw = fs.readFileSync(profilePath, "utf8");
69
+ const raw = await fio.readFile(profilePath);
69
70
 
70
71
  let parsed: unknown;
71
72
  let parseError: string | null = null;