@warpgogol/forge 5.2.4 → 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 (568) hide show
  1. package/AGENTS.md +32 -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 +43 -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 +1 -1
  247. package/dist/src/config/forge-config.js +1 -1
  248. package/dist/src/config/forge-config.js.map +1 -1
  249. package/dist/src/knowledge/budgets.js +1 -1
  250. package/dist/src/knowledge/budgets.js.map +1 -1
  251. package/dist/src/knowledge/compact.js +1 -1
  252. package/dist/src/knowledge/compact.js.map +1 -1
  253. package/dist/src/knowledge/parse.js +1 -1
  254. package/dist/src/knowledge/parse.js.map +1 -1
  255. package/dist/src/knowledge/sync.d.ts.map +1 -1
  256. package/dist/src/knowledge/sync.js +3 -5
  257. package/dist/src/knowledge/sync.js.map +1 -1
  258. package/dist/src/migration-adapters/git-utils.js +2 -2
  259. package/dist/src/migration-adapters/git-utils.js.map +1 -1
  260. package/dist/src/migration-adapters/ignored-files.js +2 -2
  261. package/dist/src/migration-adapters/ignored-files.js.map +1 -1
  262. package/dist/src/migration-adapters/node-typescript-pnpm/index.js +1 -1
  263. package/dist/src/migration-adapters/node-typescript-pnpm/index.js.map +1 -1
  264. package/dist/src/migration-adapters/phaser-pnpm/index.js +1 -1
  265. package/dist/src/migration-adapters/phaser-pnpm/index.js.map +1 -1
  266. package/dist/src/onboarding/agents-generate.d.ts.map +1 -1
  267. package/dist/src/onboarding/agents-generate.js +60 -31
  268. package/dist/src/onboarding/agents-generate.js.map +1 -1
  269. package/dist/src/onboarding/create.d.ts.map +1 -1
  270. package/dist/src/onboarding/create.js +10 -10
  271. package/dist/src/onboarding/create.js.map +1 -1
  272. package/dist/src/onboarding/doctor.d.ts.map +1 -1
  273. package/dist/src/onboarding/doctor.js +68 -59
  274. package/dist/src/onboarding/doctor.js.map +1 -1
  275. package/dist/src/onboarding/init.d.ts.map +1 -1
  276. package/dist/src/onboarding/init.js +30 -1
  277. package/dist/src/onboarding/init.js.map +1 -1
  278. package/dist/src/onboarding/invariant-engine.js +1 -1
  279. package/dist/src/onboarding/invariant-engine.js.map +1 -1
  280. package/dist/src/onboarding/memory-compact.d.ts.map +1 -1
  281. package/dist/src/onboarding/memory-compact.js +5 -4
  282. package/dist/src/onboarding/memory-compact.js.map +1 -1
  283. package/dist/src/onboarding/memory-scaffold.js +1 -1
  284. package/dist/src/onboarding/memory-scaffold.js.map +1 -1
  285. package/dist/src/onboarding/nested-agents-generate.d.ts +4 -1
  286. package/dist/src/onboarding/nested-agents-generate.d.ts.map +1 -1
  287. package/dist/src/onboarding/nested-agents-generate.js +34 -5
  288. package/dist/src/onboarding/nested-agents-generate.js.map +1 -1
  289. package/dist/src/onboarding/nested-agents-templates.d.ts.map +1 -1
  290. package/dist/src/onboarding/nested-agents-templates.js +8 -12
  291. package/dist/src/onboarding/nested-agents-templates.js.map +1 -1
  292. package/dist/src/onboarding/npm-token-check.js +2 -2
  293. package/dist/src/onboarding/npm-token-check.js.map +1 -1
  294. package/dist/src/onboarding/prettierignore.d.ts +29 -0
  295. package/dist/src/onboarding/prettierignore.d.ts.map +1 -0
  296. package/dist/src/onboarding/prettierignore.js +231 -0
  297. package/dist/src/onboarding/prettierignore.js.map +1 -0
  298. package/dist/src/onboarding/profile-validate.d.ts.map +1 -1
  299. package/dist/src/onboarding/profile-validate.js +5 -4
  300. package/dist/src/onboarding/profile-validate.js.map +1 -1
  301. package/dist/src/onboarding/scaffold-project.d.ts.map +1 -1
  302. package/dist/src/onboarding/scaffold-project.js +35 -27
  303. package/dist/src/onboarding/scaffold-project.js.map +1 -1
  304. package/dist/src/onboarding/scaffold.js +1 -1
  305. package/dist/src/onboarding/scaffold.js.map +1 -1
  306. package/dist/src/onboarding/skill-markers.d.ts +27 -0
  307. package/dist/src/onboarding/skill-markers.d.ts.map +1 -0
  308. package/dist/src/onboarding/skill-markers.js +131 -0
  309. package/dist/src/onboarding/skill-markers.js.map +1 -0
  310. package/dist/src/onboarding/upgrade.d.ts +10 -0
  311. package/dist/src/onboarding/upgrade.d.ts.map +1 -1
  312. package/dist/src/onboarding/upgrade.js +215 -74
  313. package/dist/src/onboarding/upgrade.js.map +1 -1
  314. package/dist/src/onboarding/workspace-discovery.js +1 -1
  315. package/dist/src/onboarding/workspace-discovery.js.map +1 -1
  316. package/dist/src/pipeline-status.d.ts +6 -5
  317. package/dist/src/pipeline-status.d.ts.map +1 -1
  318. package/dist/src/pipeline-status.js +24 -19
  319. package/dist/src/pipeline-status.js.map +1 -1
  320. package/dist/src/profiles/stack-profile.js +1 -1
  321. package/dist/src/profiles/stack-profile.js.map +1 -1
  322. package/dist/src/registry.d.ts +1 -1
  323. package/dist/src/registry.d.ts.map +1 -1
  324. package/dist/src/registry.js +3 -3
  325. package/dist/src/registry.js.map +1 -1
  326. package/dist/src/skill-schema.d.ts +1 -1
  327. package/dist/src/skill-schema.d.ts.map +1 -1
  328. package/dist/src/skill-schema.js +4 -1
  329. package/dist/src/skill-schema.js.map +1 -1
  330. package/dist/src/types.d.ts +116 -0
  331. package/dist/src/types.d.ts.map +1 -1
  332. package/dist/src/utils/editable-region.d.ts +46 -0
  333. package/dist/src/utils/editable-region.d.ts.map +1 -0
  334. package/dist/src/utils/editable-region.js +125 -0
  335. package/dist/src/utils/editable-region.js.map +1 -0
  336. package/dist/src/utils/fs-idempotent.d.ts +2 -1
  337. package/dist/src/utils/fs-idempotent.d.ts.map +1 -1
  338. package/dist/src/utils/fs-idempotent.js +11 -7
  339. package/dist/src/utils/fs-idempotent.js.map +1 -1
  340. package/dist/src/utils/generated-marker.d.ts +17 -0
  341. package/dist/src/utils/generated-marker.d.ts.map +1 -1
  342. package/dist/src/utils/generated-marker.js +29 -1
  343. package/dist/src/utils/generated-marker.js.map +1 -1
  344. package/dist/src/utils/index.d.ts +3 -1
  345. package/dist/src/utils/index.d.ts.map +1 -1
  346. package/dist/src/utils/index.js +3 -1
  347. package/dist/src/utils/index.js.map +1 -1
  348. package/dist/src/utils/io.d.ts +9 -0
  349. package/dist/src/utils/io.d.ts.map +1 -0
  350. package/dist/src/utils/io.js +130 -0
  351. package/dist/src/utils/io.js.map +1 -0
  352. package/dist/src/utils/markdown-table.d.ts +21 -0
  353. package/dist/src/utils/markdown-table.d.ts.map +1 -0
  354. package/dist/src/utils/markdown-table.js +116 -0
  355. package/dist/src/utils/markdown-table.js.map +1 -0
  356. package/dist/src/utils/sync-fs.d.ts +5 -0
  357. package/dist/src/utils/sync-fs.d.ts.map +1 -0
  358. package/dist/src/utils/sync-fs.js +26 -0
  359. package/dist/src/utils/sync-fs.js.map +1 -0
  360. package/dist/src/validators/note-frontmatter-validate.js +1 -1
  361. package/dist/src/validators/note-frontmatter-validate.js.map +1 -1
  362. package/dist/src/validators/note-link-validate.js +1 -1
  363. package/dist/src/validators/note-link-validate.js.map +1 -1
  364. package/dist/src/validators/note-orphan-detect.js +1 -1
  365. package/dist/src/validators/note-orphan-detect.js.map +1 -1
  366. package/dist/src/validators/port-validate.js +1 -1
  367. package/dist/src/validators/port-validate.js.map +1 -1
  368. package/dist/src/validators/skill-validate.d.ts.map +1 -1
  369. package/dist/src/validators/skill-validate.js +34 -13
  370. package/dist/src/validators/skill-validate.js.map +1 -1
  371. package/os/adr/adr.module.ts +136 -132
  372. package/os/adr/frontmatter-io.ts +5 -5
  373. package/os/adr/handlers/archive.ts +8 -4
  374. package/os/adr/handlers/implement-stamp.ts +14 -9
  375. package/os/adr/handlers/list-create.ts +5 -5
  376. package/os/adr/handlers/validate.ts +1 -1
  377. package/os/audit/audit.module.ts +33 -34
  378. package/os/audit/frontmatter-io.ts +5 -5
  379. package/os/audit/handlers/archive.ts +8 -4
  380. package/os/compass/compass.module.ts +17 -1
  381. package/os/compass/handlers/compass-audit-handler.ts +13 -5
  382. package/os/compass/handlers/compass-change-summary-handler.ts +4 -2
  383. package/os/compass/handlers/compass-inventory-handler.ts +7 -4
  384. package/os/compass/handlers/compass-inventory.ts +11 -8
  385. package/os/compass/handlers/compass-migrate-handler.ts +1 -1
  386. package/os/compass/handlers/compass-migrate.ts +7 -3
  387. package/os/compass/handlers/git-revision.ts +11 -6
  388. package/os/compass/handlers/resolve-scan-root.ts +1 -1
  389. package/os/compass/handlers/summary-record.ts +10 -4
  390. package/os/compass/handlers/tests/compass-audit-plan.test.ts +2 -1
  391. package/os/core/core.module.ts +43 -4
  392. package/os/core/handlers/assets-helpers.ts +7 -3
  393. package/os/core/handlers/build.ts +1 -1
  394. package/os/core/handlers/determinism-check.ts +12 -6
  395. package/os/core/handlers/dev.ts +1 -1
  396. package/os/core/handlers/file-size-lint.ts +16 -9
  397. package/os/core/handlers/forge-autonomy-validate.ts +10 -5
  398. package/os/core/handlers/knowledge-compact.ts +1 -1
  399. package/os/core/handlers/package-health.ts +1 -1
  400. package/os/core/handlers/pinned-check.ts +2 -2
  401. package/os/core/handlers/pinned-init.ts +9 -8
  402. package/os/core/handlers/pinned-validate.ts +3 -3
  403. package/os/core/handlers/profile-resolve.ts +1 -1
  404. package/os/core/handlers/public-surface.ts +1 -1
  405. package/os/core/handlers/release-prepare.ts +11 -6
  406. package/os/core/handlers/release-publish.ts +6 -6
  407. package/os/core/handlers/validate.ts +1 -1
  408. package/os/exploration/exploration.module.ts +1 -0
  409. package/os/exploration/frontmatter-io.ts +4 -4
  410. package/os/exploration/handlers/archive.ts +3 -3
  411. package/os/mission/handlers/archive.ts +27 -19
  412. package/os/mission/mission.module.ts +38 -39
  413. package/os/naming/naming-convention.ts +9 -3
  414. package/os/naming/naming.module.ts +25 -25
  415. package/os/notes/notes.module.ts +87 -85
  416. package/os/plan/frontmatter-io.ts +5 -5
  417. package/os/plan/handlers/archive.ts +8 -4
  418. package/os/plan/plan.module.ts +33 -34
  419. package/os/plugin/plugin.module.ts +8 -6
  420. package/os/program/discovery.ts +2 -2
  421. package/os/program/handlers/complete.ts +1 -1
  422. package/os/program/handlers/lease.ts +1 -1
  423. package/os/program/handlers/seal.ts +1 -1
  424. package/os/program/lease.ts +1 -1
  425. package/os/program/program.module.ts +198 -193
  426. package/os/queue/index.ts +1 -1
  427. package/os/queue/manifest.ts +10 -9
  428. package/os/queue/queue-validate.test.ts +6 -15
  429. package/os/rfc/acceptance.ts +12 -6
  430. package/os/rfc/decision-log.ts +4 -3
  431. package/os/rfc/dna-trace.ts +8 -2
  432. package/os/rfc/frontmatter-io.ts +5 -5
  433. package/os/rfc/handlers/archive.ts +9 -5
  434. package/os/rfc/handlers/check.ts +5 -3
  435. package/os/rfc/handlers/implement-stamp.ts +15 -10
  436. package/os/rfc/handlers/index-graph.ts +3 -3
  437. package/os/rfc/handlers/lifecycle.ts +7 -2
  438. package/os/rfc/handlers/list-create.ts +7 -6
  439. package/os/rfc/handlers/shared.ts +3 -3
  440. package/os/rfc/handlers/supersede-propose.ts +8 -3
  441. package/os/rfc/handlers/validate-rules-rfc1006.test.ts +18 -6
  442. package/os/rfc/handlers/validate-rules.ts +10 -5
  443. package/os/rfc/rfc-create-concurrent.test.ts +11 -3
  444. package/os/rfc/rfc.module.ts +413 -374
  445. package/os/rfc/verification-evidence.ts +11 -5
  446. package/os/rfc/verification-refresh.ts +4 -3
  447. package/os/session/frontmatter-io.ts +14 -14
  448. package/os/session/handlers/archive.ts +8 -4
  449. package/os/session/handlers/metrics-aggregate.ts +34 -13
  450. package/os/session/handlers/metrics-rfc.ts +13 -8
  451. package/os/session/handlers/metrics-session.ts +7 -3
  452. package/os/session/handlers/save.ts +12 -8
  453. package/os/session/session.module.ts +6 -0
  454. package/os/spec/live-spec-list.ts +4 -4
  455. package/os/spec/live-spec-merge.ts +5 -5
  456. package/os/spec/live-spec-show.ts +3 -3
  457. package/os/spec/live-spec-validate.ts +4 -4
  458. package/os/spec/spec-materialize.ts +9 -9
  459. package/os/spec/spec-status.ts +9 -9
  460. package/os/spec/spec-validate.ts +7 -7
  461. package/os/spec/spec.module.ts +8 -0
  462. package/os/werkstatt/handlers/lock.ts +16 -16
  463. package/os/werkstatt/handlers/werkstatt-lock-recover.ts +3 -3
  464. package/os/werkstatt/handlers/werkstatt-operation-validate.ts +4 -2
  465. package/os/werkstatt/werkstatt.module.ts +8 -5
  466. package/os/workflow/handlers.ts +7 -5
  467. package/os/workflow/workflow.module.ts +45 -44
  468. package/package.json +1 -1
  469. package/skills/fo/fo-add-tests/SKILL.md +2 -2
  470. package/skills/fo/fo-architecture/SKILL.md +2 -2
  471. package/skills/fo/fo-compass-annotate/SKILL.md +2 -2
  472. package/skills/fo/fo-design-summit/SKILL.md +2 -2
  473. package/skills/fo/fo-doc-audit/SKILL.md +2 -2
  474. package/skills/fo/fo-explore/SKILL.md +2 -2
  475. package/skills/fo/fo-extract-dna/SKILL.md +2 -2
  476. package/skills/fo/fo-fix/SKILL.md +2 -2
  477. package/skills/fo/fo-handoff/SKILL.md +2 -2
  478. package/skills/fo/fo-harvest/SKILL.md +2 -2
  479. package/skills/fo/fo-idea/SKILL.md +2 -2
  480. package/skills/fo/fo-idea-audit/SKILL.md +2 -2
  481. package/skills/fo/fo-idea-create-adr/SKILL.md +3 -3
  482. package/skills/fo/fo-idea-create-rfc/SKILL.md +3 -3
  483. package/skills/fo/fo-idea-enhance/SKILL.md +2 -2
  484. package/skills/fo/fo-idea-i-just-want-to-see-the-plan/SKILL.md +2 -2
  485. package/skills/fo/fo-idea-i-just-want-to-see-the-result/SKILL.md +1 -1
  486. package/skills/fo/fo-idea-implement/SKILL.md +2 -2
  487. package/skills/fo/fo-idea-plan/SKILL.md +2 -2
  488. package/skills/fo/fo-idea-status/SKILL.md +2 -2
  489. package/skills/fo/fo-knowledge-distill/SKILL.md +2 -2
  490. package/skills/fo/fo-memory-sync/SKILL.md +2 -2
  491. package/skills/fo/fo-qa/SKILL.md +2 -2
  492. package/skills/fo/fo-review/SKILL.md +2 -2
  493. package/skills/fo/fo-session-retro/SKILL.md +2 -2
  494. package/skills/fo/fo-session-save/SKILL.md +2 -2
  495. package/skills/fo/fo-spec-ingest/SKILL.md +2 -2
  496. package/skills/fo/fo-step-commit/SKILL.md +1 -1
  497. package/skills/fo/fo-triage/SKILL.md +2 -2
  498. package/skills/meta/forge-bootstrap/SKILL.md +1 -1
  499. package/skills/meta/port-to-forge/SKILL.md +1 -1
  500. package/skills/meta/skill-create/SKILL.md +1 -1
  501. package/skills/shared/grilling/SKILL.md +1 -1
  502. package/skills/shared/grilling/learned-principles.archive.md +17 -0
  503. package/skills/shared/grilling/learned-principles.md +0 -1
  504. package/skills/shared/knowledge/learned-principles.md +6 -0
  505. package/skills/shared/my-preferences/SKILL.md +1 -1
  506. package/skills/shared/windows-ai-tooling/SKILL.md +1 -1
  507. package/skills/shared/writing-great-skills/SKILL.md +1 -1
  508. package/src/compass/contract-registry.ts +1 -1
  509. package/src/config/forge-config.ts +1 -1
  510. package/src/knowledge/__tests__/sync.test.ts +2 -7
  511. package/src/knowledge/budgets.ts +1 -1
  512. package/src/knowledge/compact.ts +1 -1
  513. package/src/knowledge/parse.ts +1 -1
  514. package/src/knowledge/sync.ts +3 -5
  515. package/src/migration-adapters/git-utils.ts +2 -2
  516. package/src/migration-adapters/ignored-files.ts +2 -2
  517. package/src/migration-adapters/node-typescript-pnpm/index.ts +1 -1
  518. package/src/migration-adapters/phaser-pnpm/index.ts +1 -1
  519. package/src/onboarding/agents-generate.ts +74 -33
  520. package/src/onboarding/create.ts +10 -10
  521. package/src/onboarding/doctor.ts +70 -55
  522. package/src/onboarding/init.ts +38 -1
  523. package/src/onboarding/invariant-engine.ts +1 -1
  524. package/src/onboarding/memory-compact.ts +5 -4
  525. package/src/onboarding/memory-scaffold.ts +1 -1
  526. package/src/onboarding/nested-agents-generate.ts +45 -4
  527. package/src/onboarding/nested-agents-templates.ts +19 -13
  528. package/src/onboarding/npm-token-check.ts +2 -2
  529. package/src/onboarding/prettierignore.ts +263 -0
  530. package/src/onboarding/profile-validate.ts +5 -4
  531. package/src/onboarding/scaffold-project.ts +38 -27
  532. package/src/onboarding/scaffold.ts +1 -1
  533. package/src/onboarding/skill-markers.ts +162 -0
  534. package/src/onboarding/templates/behavioral-layer-core.md +2 -4
  535. package/src/onboarding/upgrade.ts +285 -89
  536. package/src/onboarding/workspace-discovery.ts +1 -1
  537. package/src/pipeline-status.test.ts +1 -4
  538. package/src/pipeline-status.ts +30 -13
  539. package/src/profiles/stack-profile.ts +1 -1
  540. package/src/registry.ts +4 -4
  541. package/src/skill-schema.ts +4 -1
  542. package/src/tests/acceptance-probe-kinds.test.ts +5 -15
  543. package/src/tests/agents-generate.test.ts +6 -4
  544. package/src/tests/contract-registry.test.ts +12 -6
  545. package/src/tests/doctor-fix.test.ts +1 -4
  546. package/src/tests/doctor-nested-agents.test.ts +53 -1
  547. package/src/tests/editable-generated-region.test.ts +231 -0
  548. package/src/tests/file-size-lint.test.ts +8 -12
  549. package/src/tests/fixtures/agents-generate-business-before.txt +54 -54
  550. package/src/tests/markdown-table.test.ts +107 -0
  551. package/src/tests/prettierignore-manage.test.ts +134 -0
  552. package/src/tests/skill-agents-sync.test.ts +168 -0
  553. package/src/tests/skill-sync-marker.test.ts +134 -0
  554. package/src/tests/skill-validate.test.ts +12 -5
  555. package/src/tests/upgrade.test.ts +87 -41
  556. package/src/types.ts +123 -0
  557. package/src/utils/editable-region.ts +156 -0
  558. package/src/utils/fs-idempotent.ts +12 -6
  559. package/src/utils/generated-marker.ts +36 -2
  560. package/src/utils/index.ts +17 -0
  561. package/src/utils/io.ts +143 -0
  562. package/src/utils/markdown-table.ts +121 -0
  563. package/src/utils/sync-fs.ts +43 -0
  564. package/src/validators/note-frontmatter-validate.ts +1 -1
  565. package/src/validators/note-link-validate.ts +1 -1
  566. package/src/validators/note-orphan-detect.ts +1 -1
  567. package/src/validators/port-validate.ts +1 -1
  568. package/src/validators/skill-validate.ts +38 -13
@@ -15,7 +15,7 @@ workspace type (app, service, package) by content markers.</purpose>
15
15
  </CHANGE_SUMMARY>
16
16
  */
17
17
 
18
- import fs from "node:fs";
18
+ import * as fs from "../utils/sync-fs.ts";
19
19
  import path from "node:path";
20
20
  import { hasGeneratedMarker } from "../utils/index.ts";
21
21
  import type { ProfileWorkspaceType } from "../profiles/profile-schema.ts";
@@ -116,10 +116,7 @@ describe("deriveQueueItemStatus — derivation matrix (RFC-1140)", () => {
116
116
 
117
117
  test("audit file only → in-progress/enhance", async () => {
118
118
  await writeRfc("RFC-1107", "status: draft\n");
119
- await fs.writeFile(
120
- path.join(tmpDir, "docs/audits/audit-rfc-1107-test.md"),
121
- "# audit\n",
122
- );
119
+ await fs.writeFile(path.join(tmpDir, "docs/audits/audit-rfc-1107-test.md"), "# audit\n");
123
120
  const r = await deriveQueueItemStatus(tmpDir, "RFC-1107");
124
121
  expect(r?.status).toBe("in-progress");
125
122
  expect(r?.pipelineStep).toBe("enhance");
@@ -25,8 +25,9 @@ Add pipeline-status.test.ts (derivation matrix, order, next selection, ADR, skip
25
25
  </CHANGE_SUMMARY>
26
26
  */
27
27
 
28
- import fs from "node:fs/promises";
29
28
  import path from "node:path";
29
+ import type { WorkspaceIO } from "./types.ts";
30
+ import { resolveIo } from "./utils/io.ts";
30
31
  import YAML from "yaml";
31
32
 
32
33
  // ---------------------------------------------------------------------------
@@ -75,10 +76,12 @@ export function parseFrontmatter(source: string): ParsedDocument {
75
76
  export async function findAuditFile(
76
77
  workspaceRoot: string,
77
78
  docId: string,
79
+ io?: WorkspaceIO,
78
80
  ): Promise<string | undefined> {
81
+ const fio = resolveIo(io);
79
82
  const auditsDir = path.join(workspaceRoot, "docs/audits");
80
83
  try {
81
- const entries = await fs.readdir(auditsDir);
84
+ const entries = (await fio.readdir(auditsDir)).map((e) => e.name);
82
85
  const prefix = `audit-${docId.toLowerCase()}`;
83
86
  const match = entries.find((e) => e.toLowerCase().startsWith(prefix) && e.endsWith(".md"));
84
87
  return match ? path.join("docs/audits", match) : undefined;
@@ -90,10 +93,12 @@ export async function findAuditFile(
90
93
  export async function findPlanFile(
91
94
  workspaceRoot: string,
92
95
  docId: string,
96
+ io?: WorkspaceIO,
93
97
  ): Promise<string | undefined> {
98
+ const fio = resolveIo(io);
94
99
  const plansDir = path.join(workspaceRoot, "docs/plans");
95
100
  try {
96
- const entries = await fs.readdir(plansDir);
101
+ const entries = (await fio.readdir(plansDir)).map((e) => e.name);
97
102
  const prefix = `plan-${docId.toLowerCase()}`;
98
103
  const match = entries.find((e) => e.toLowerCase().startsWith(prefix) && e.endsWith(".md"));
99
104
  return match ? path.join("docs/plans", match) : undefined;
@@ -122,20 +127,26 @@ async function scanForDocument(
122
127
  dirPath: string,
123
128
  relativePrefix: string,
124
129
  idLower: string,
130
+ io: WorkspaceIO,
125
131
  ): Promise<string | undefined> {
126
132
  let entries;
127
133
  try {
128
- entries = await fs.readdir(dirPath, { withFileTypes: true });
134
+ entries = await io.readdir(dirPath);
129
135
  } catch {
130
136
  return undefined;
131
137
  }
132
138
  for (const entry of entries) {
133
139
  const relativePath = relativePrefix ? `${relativePrefix}/${entry.name}` : entry.name;
134
- if (entry.isDirectory()) {
135
- const found = await scanForDocument(path.join(dirPath, entry.name), relativePath, idLower);
140
+ if (entry.isDirectory) {
141
+ const found = await scanForDocument(
142
+ path.join(dirPath, entry.name),
143
+ relativePath,
144
+ idLower,
145
+ io,
146
+ );
136
147
  if (found) return found;
137
148
  } else if (
138
- entry.isFile() &&
149
+ entry.isFile &&
139
150
  entry.name.endsWith(".md") &&
140
151
  entry.name.toLowerCase().startsWith(idLower)
141
152
  ) {
@@ -153,19 +164,21 @@ async function scanForDocument(
153
164
  export async function resolveDocument(
154
165
  workspaceRoot: string,
155
166
  docId: string,
167
+ io?: WorkspaceIO,
156
168
  ): Promise<ResolvedDocument | undefined> {
169
+ const fio = resolveIo(io);
157
170
  const idMatch = DOC_ID_PATTERN.exec(docId.trim());
158
171
  if (!idMatch) return undefined;
159
172
  const kind: QueueDocumentKind = idMatch[1]!.toUpperCase() === "ADR" ? "adr" : "rfc";
160
173
  const baseDir = kind === "adr" ? "docs/adrs" : "docs/rfcs";
161
174
  const idLower = docId.toLowerCase();
162
175
 
163
- const found = await scanForDocument(path.join(workspaceRoot, baseDir), "", idLower);
176
+ const found = await scanForDocument(path.join(workspaceRoot, baseDir), "", idLower, fio);
164
177
  if (!found) return undefined;
165
178
 
166
179
  let source: string;
167
180
  try {
168
- source = await fs.readFile(path.join(workspaceRoot, baseDir, found), "utf-8");
181
+ source = await fio.readFile(path.join(workspaceRoot, baseDir, found));
169
182
  } catch {
170
183
  return undefined;
171
184
  }
@@ -242,8 +255,10 @@ export interface QueueItemReport {
242
255
  export async function deriveQueueItemStatus(
243
256
  workspaceRoot: string,
244
257
  docId: string,
258
+ io?: WorkspaceIO,
245
259
  ): Promise<QueueItemReport | undefined> {
246
- const doc = await resolveDocument(workspaceRoot, docId);
260
+ const fio = resolveIo(io);
261
+ const doc = await resolveDocument(workspaceRoot, docId, fio);
247
262
  if (!doc) return undefined;
248
263
 
249
264
  const fm = doc.frontmatter;
@@ -268,8 +283,8 @@ export async function deriveQueueItemStatus(
268
283
  }
269
284
 
270
285
  const enhancedAt = fm["enhancedAt"] ? String(fm["enhancedAt"]) : undefined;
271
- const auditFile = await findAuditFile(workspaceRoot, doc.id);
272
- const planFile = await findPlanFile(workspaceRoot, doc.id);
286
+ const auditFile = await findAuditFile(workspaceRoot, doc.id, fio);
287
+ const planFile = await findPlanFile(workspaceRoot, doc.id, fio);
273
288
 
274
289
  const stages = computeRfcPipelineStages({
275
290
  status,
@@ -306,10 +321,12 @@ export interface QueueReport {
306
321
  export async function deriveQueueReport(
307
322
  workspaceRoot: string,
308
323
  itemIds: string[],
324
+ io?: WorkspaceIO,
309
325
  ): Promise<QueueReport> {
326
+ const fio = resolveIo(io);
310
327
  const items: QueueItemReport[] = [];
311
328
  for (const id of itemIds) {
312
- const report = await deriveQueueItemStatus(workspaceRoot, id);
329
+ const report = await deriveQueueItemStatus(workspaceRoot, id, fio);
313
330
  // Unresolvable ids are reported by the manifest validator; the resolver
314
331
  // skips them here so a partial report stays usable.
315
332
  if (report) items.push(report);
@@ -20,7 +20,7 @@ Sweep batch 2: real KEY_DECISIONS on 10 files, expanded purposes (CONTRACT-02/PU
20
20
  </CHANGE_SUMMARY>
21
21
  */
22
22
 
23
- import fs from "node:fs";
23
+ import * as fs from "../utils/sync-fs.ts";
24
24
  import path from "node:path";
25
25
  import { z } from "zod";
26
26
  import { parse as parseYaml } from "yaml";
package/src/registry.ts CHANGED
@@ -19,7 +19,7 @@ Sweep batch 2: real KEY_DECISIONS on 10 files, expanded purposes (CONTRACT-02/PU
19
19
  </CHANGE_SUMMARY>
20
20
  */
21
21
 
22
- import fs from "node:fs";
22
+ import * as fs from "./utils/sync-fs.ts";
23
23
  import path from "node:path";
24
24
  import { parse as parseYaml } from "yaml";
25
25
  import type { ForgeConfig } from "./config/forge-config.ts";
@@ -38,7 +38,7 @@ export interface ForgeSkillEntry {
38
38
  dependsOn: string[];
39
39
  path: string;
40
40
  knowledge?: string[];
41
- triggers?: string[];
41
+ triggerPhrases?: string[];
42
42
  }
43
43
 
44
44
  /**
@@ -191,9 +191,9 @@ function discoverForgeSkills(skillsRoot: string): ForgeSkillEntry[] {
191
191
  ),
192
192
  }
193
193
  : {}),
194
- ...(Array.isArray(fm["triggers"])
194
+ ...(Array.isArray(fm["triggerPhrases"])
195
195
  ? {
196
- triggers: (fm["triggers"] as unknown[]).filter(
196
+ triggerPhrases: (fm["triggerPhrases"] as unknown[]).filter(
197
197
  (v): v is string => typeof v === "string",
198
198
  ),
199
199
  }
@@ -31,7 +31,10 @@ export const skillFrontmatterSchema = z.object({
31
31
  })
32
32
  .optional(),
33
33
  knowledge: z.array(z.string()).optional(),
34
- triggers: z.array(z.string().min(5).max(100)).max(5).optional(),
34
+ // Named triggerPhrases, not triggers — agent-IDE skill loaders (Devin CLI,
35
+ // Windsurf) reserve `triggers` for invocation modes (user/model); a list of
36
+ // phrases parses to zero valid modes and the skill is dropped entirely.
37
+ triggerPhrases: z.array(z.string().min(5).max(100)).max(5).optional(),
35
38
  });
36
39
 
37
40
  export type SkillFrontmatter = z.infer<typeof skillFrontmatterSchema>;
@@ -36,17 +36,13 @@ describe("validateAcceptanceShape — test probe", () => {
36
36
  });
37
37
 
38
38
  it("rejects a test probe missing file", () => {
39
- const issues = validateAcceptanceShape([
40
- { probe: "test", expect: { exitCode: 0 } },
41
- ]);
39
+ const issues = validateAcceptanceShape([{ probe: "test", expect: { exitCode: 0 } }]);
42
40
  expect(issues).toHaveLength(1);
43
41
  expect(issues[0].message).toContain('requires a string "file"');
44
42
  });
45
43
 
46
44
  it("rejects a test probe missing expect.exitCode", () => {
47
- const issues = validateAcceptanceShape([
48
- { probe: "test", file: "src/test.ts" },
49
- ]);
45
+ const issues = validateAcceptanceShape([{ probe: "test", file: "src/test.ts" }]);
50
46
  expect(issues).toHaveLength(1);
51
47
  expect(issues[0].message).toContain("requires expect: { exitCode");
52
48
  });
@@ -108,9 +104,7 @@ describe("validateAcceptanceShape — existing probe kinds (regression)", () =>
108
104
  });
109
105
 
110
106
  it("accepts well-formed file-exists probe", () => {
111
- const issues = validateAcceptanceShape([
112
- { probe: "file-exists", path: "src/index.ts" },
113
- ]);
107
+ const issues = validateAcceptanceShape([{ probe: "file-exists", path: "src/index.ts" }]);
114
108
  expect(issues).toEqual([]);
115
109
  });
116
110
 
@@ -122,16 +116,12 @@ describe("validateAcceptanceShape — existing probe kinds (regression)", () =>
122
116
  });
123
117
 
124
118
  it("accepts well-formed command-registered probe", () => {
125
- const issues = validateAcceptanceShape([
126
- { probe: "command-registered", name: "rfc.validate" },
127
- ]);
119
+ const issues = validateAcceptanceShape([{ probe: "command-registered", name: "rfc.validate" }]);
128
120
  expect(issues).toEqual([]);
129
121
  });
130
122
 
131
123
  it("accepts well-formed page probe", () => {
132
- const issues = validateAcceptanceShape([
133
- { probe: "page", path: "/about" },
134
- ]);
124
+ const issues = validateAcceptanceShape([{ probe: "page", path: "/about" }]);
135
125
  expect(issues).toEqual([]);
136
126
  });
137
127
  });
@@ -102,7 +102,8 @@ test("agents-generate includes intent-to-skill routing table", async () => {
102
102
 
103
103
  const agentsMd = await readFile(join(tempDir, "AGENTS.md"), "utf8");
104
104
  expect(agentsMd).toContain("### Intent-to-skill routing");
105
- expect(agentsMd).toContain("| Operator says something like | Skill |");
105
+ // RFC-1154: header cells are padded to column width — match via regex
106
+ expect(agentsMd).toMatch(/\| Operator says something like +\| Skill +\|/);
106
107
  // Should contain at least one skill name from the registry
107
108
  expect(agentsMd).toContain("fo-");
108
109
  });
@@ -427,9 +428,10 @@ test("agents-generate nested renders entry points from exports map", async () =>
427
428
 
428
429
  const nested = await readFile(join(tempDir, "packages", "my-pkg", "AGENTS.md"), "utf8");
429
430
  expect(nested).toContain("## Entry points");
430
- expect(nested).toContain("| `@test/my-pkg` | `./src/index.ts` |");
431
- expect(nested).toContain("| `@test/my-pkg/port` | `./src/port.ts` |");
432
- expect(nested).toContain("| `@test/my-pkg/client` | `./src/client.ts` |");
431
+ // RFC-1154: cells are padded to column width — match via regex
432
+ expect(nested).toMatch(/\| `@test\/my-pkg` +\| `\.\/src\/index\.ts` +\|/);
433
+ expect(nested).toMatch(/\| `@test\/my-pkg\/port` +\| `\.\/src\/port\.ts` +\|/);
434
+ expect(nested).toMatch(/\| `@test\/my-pkg\/client` +\| `\.\/src\/client\.ts` +\|/);
433
435
  });
434
436
 
435
437
  test("agents-generate nested separates workspace and external dependencies", async () => {
@@ -41,11 +41,15 @@ describe("contract-registry (RFC-0943)", () => {
41
41
 
42
42
  describe("fileMatchesGlobs", () => {
43
43
  test("matches a simple glob pattern", () => {
44
- expect(fileMatchesGlobs("packages/my-pack/src/index.ts", ["packages/my-pack/**/*.ts"])).toBe(true);
44
+ expect(fileMatchesGlobs("packages/my-pack/src/index.ts", ["packages/my-pack/**/*.ts"])).toBe(
45
+ true,
46
+ );
45
47
  });
46
48
 
47
49
  test("does not match when glob does not match", () => {
48
- expect(fileMatchesGlobs("packages/other-pack/src/index.ts", ["packages/my-pack/**/*.ts"])).toBe(false);
50
+ expect(
51
+ fileMatchesGlobs("packages/other-pack/src/index.ts", ["packages/my-pack/**/*.ts"]),
52
+ ).toBe(false);
49
53
  });
50
54
 
51
55
  test("matches any of multiple globs", () => {
@@ -58,7 +62,9 @@ describe("contract-registry (RFC-0943)", () => {
58
62
  });
59
63
 
60
64
  test("handles dot files with dot option", () => {
61
- expect(fileMatchesGlobs("packages/my-pack/.env.example", ["packages/**/*.example"])).toBe(true);
65
+ expect(fileMatchesGlobs("packages/my-pack/.env.example", ["packages/**/*.example"])).toBe(
66
+ true,
67
+ );
62
68
  });
63
69
  });
64
70
 
@@ -86,7 +92,7 @@ describe("contract-registry (RFC-0943)", () => {
86
92
  const packDir = join(ws, "my-pack");
87
93
  writeManifest(
88
94
  packDir,
89
- "id: my-pack\nversion: 1.0.0\nextensionPoints:\n compass:\n contract:\n blocks:\n - blockId: api-contract\n requiredFor:\n - \"packages/my-pack/**/*.ts\"\n requiredTags:\n - name: endpoints\n minWords: 5\n",
95
+ 'id: my-pack\nversion: 1.0.0\nextensionPoints:\n compass:\n contract:\n blocks:\n - blockId: api-contract\n requiredFor:\n - "packages/my-pack/**/*.ts"\n requiredTags:\n - name: endpoints\n minWords: 5\n',
90
96
  );
91
97
 
92
98
  const config: ForgeConfig = {
@@ -111,11 +117,11 @@ describe("contract-registry (RFC-0943)", () => {
111
117
  try {
112
118
  writeManifest(
113
119
  join(ws, "pack-a"),
114
- "id: pack-a\nversion: 1.0.0\nextensionPoints:\n compass:\n contract:\n blocks:\n - blockId: shared-block\n requiredFor:\n - \"packages/**/*.ts\"\n",
120
+ 'id: pack-a\nversion: 1.0.0\nextensionPoints:\n compass:\n contract:\n blocks:\n - blockId: shared-block\n requiredFor:\n - "packages/**/*.ts"\n',
115
121
  );
116
122
  writeManifest(
117
123
  join(ws, "pack-b"),
118
- "id: pack-b\nversion: 1.0.0\nextensionPoints:\n compass:\n contract:\n blocks:\n - blockId: shared-block\n requiredFor:\n - \"services/**/*.ts\"\n",
124
+ 'id: pack-b\nversion: 1.0.0\nextensionPoints:\n compass:\n contract:\n blocks:\n - blockId: shared-block\n requiredFor:\n - "services/**/*.ts"\n',
119
125
  );
120
126
 
121
127
  const config: ForgeConfig = {
@@ -83,10 +83,7 @@ test("doctor --fix regenerates stale nested AGENTS.md and subsequent run passes"
83
83
  expect(fixEntry).toBeDefined();
84
84
  expect(fixEntry!.action).toBe("fixed");
85
85
 
86
- const regenerated = await readFile(
87
- join(tempDir, "packages", "my-pkg", "AGENTS.md"),
88
- "utf8",
89
- );
86
+ const regenerated = await readFile(join(tempDir, "packages", "my-pkg", "AGENTS.md"), "utf8");
90
87
  expect(regenerated).toContain("`@test/my-pkg` — Agent Guide");
91
88
  expect(regenerated).not.toContain("Old content");
92
89
 
@@ -9,10 +9,13 @@ workspace discovery exclusions via bindings.workspaces.skipDirs (RFC-1150).</pur
9
9
  */
10
10
 
11
11
  import { test, expect, beforeEach, afterEach } from "vitest";
12
- import { mkdtemp, rm, mkdir, writeFile } from "node:fs/promises";
12
+ import { mkdtemp, rm, mkdir, writeFile, appendFile } from "node:fs/promises";
13
13
  import { tmpdir } from "node:os";
14
14
  import { join } from "node:path";
15
15
  import { runDoctor } from "../onboarding/doctor.ts";
16
+ import { generateNestedAgentsMd } from "../onboarding/nested-agents-generate.ts";
17
+ import { buildGeneratedHeader } from "../utils/index.ts";
18
+ import { loadForgeConfig } from "../config/forge-config.ts";
16
19
  import type { ForgeCommandInput, ForgeRuntimeContext } from "../types.ts";
17
20
 
18
21
  let tempDir: string;
@@ -106,3 +109,52 @@ test("nested-AGENTS.md check reports artifact dir as missing without skipDirs",
106
109
  expect(check).toBeDefined();
107
110
  expect(check!.message).toContain("builds");
108
111
  });
112
+
113
+ // RFC-1153: boundary-aware staleness -----------------------------------------
114
+
115
+ test("AC-8: custom content below the forge:custom boundary reports in-sync, not stale", async () => {
116
+ await writeFile(join(tempDir, "forge.yaml"), forgeYaml([]), "utf8");
117
+ await mkdir(join(tempDir, "packages", "pkg"), { recursive: true });
118
+ await writeFile(join(tempDir, "packages", "pkg", "package.json"), '{"name":"pkg"}', "utf8");
119
+
120
+ const config = loadForgeConfig(tempDir);
121
+ await generateNestedAgentsMd(tempDir, config, false);
122
+
123
+ // Operator appends a custom section below the marker
124
+ await appendFile(
125
+ join(tempDir, "packages", "pkg", "AGENTS.md"),
126
+ "\n## Custom rules\n\n- workspace-specific note\n",
127
+ "utf8",
128
+ );
129
+
130
+ const input: ForgeCommandInput = { argv: [], flags: {} };
131
+ const result = await runDoctor(input, makeContext());
132
+
133
+ const check = result.data!.checks.find((c) => c.name === "nested-AGENTS.md");
134
+ expect(check).toBeDefined();
135
+ expect(
136
+ check!.message,
137
+ "Below-boundary divergence must not count as stale — merge(expected, actual) compares only the head",
138
+ ).not.toContain("stale");
139
+ });
140
+
141
+ test("AC-6: divergent file without a resolvable boundary reports unmapped-customization", async () => {
142
+ await writeFile(join(tempDir, "forge.yaml"), forgeYaml([]), "utf8");
143
+ await mkdir(join(tempDir, "packages", "legacy"), { recursive: true });
144
+ await writeFile(join(tempDir, "packages", "legacy", "package.json"), '{"name":"legacy"}', "utf8");
145
+ // Marker-bearing (isGenerated) file that diverges and lacks footer/forge:custom
146
+ await writeFile(
147
+ join(tempDir, "packages", "legacy", "AGENTS.md"),
148
+ `${buildGeneratedHeader({ filePath: "AGENTS.md", ownerCommand: "forge.agents.generate", editable: true })}\n# Hand-maintained\n\ndivergent body\n`,
149
+ "utf8",
150
+ );
151
+
152
+ const input: ForgeCommandInput = { argv: [], flags: {} };
153
+ const result = await runDoctor(input, makeContext());
154
+
155
+ const check = result.data!.checks.find((c) => c.name === "nested-AGENTS.md");
156
+ expect(check).toBeDefined();
157
+ expect(check!.status).toBe("warn");
158
+ expect(check!.message).toContain("unmapped-customization");
159
+ expect(check!.message).not.toContain("stale");
160
+ });
@@ -0,0 +1,231 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>Unit tests for the RFC-1153 preservation boundary — splitEditableGenerated
4
+ and mergeEditableGenerated (forge:custom marker + canonical-footer fallback),
5
+ plus an integration pass through generateNestedAgentsMd on a temp workspace.</purpose>
6
+ </MODULE_CONTRACT>
7
+ <CHANGE_SUMMARY>
8
+ <item>RFC-1153: initial boundary merge tests — marker, footer fallback, fail-closed, comment styles, CRLF, integration.</item>
9
+ </CHANGE_SUMMARY>
10
+ */
11
+
12
+ import { test, expect, beforeEach, afterEach } from "vitest";
13
+ import { mkdtemp, mkdir, rm, writeFile, readFile, appendFile } from "node:fs/promises";
14
+ import { tmpdir } from "node:os";
15
+ import { join } from "node:path";
16
+ import {
17
+ splitEditableGenerated,
18
+ mergeEditableGenerated,
19
+ canonicalFooterOf,
20
+ } from "../utils/editable-region.ts";
21
+ import {
22
+ CUSTOM_BOUNDARY_HINTS,
23
+ CUSTOM_BOUNDARY_MARKERS,
24
+ buildGeneratedHeader,
25
+ } from "../utils/generated-marker.ts";
26
+ import { generateNestedAgentsMd } from "../onboarding/nested-agents-generate.ts";
27
+ import { loadForgeConfig } from "../config/forge-config.ts";
28
+
29
+ const MD = "AGENTS.md";
30
+ const MD_MARKER = CUSTOM_BOUNDARY_MARKERS["block-html"]; // <!-- forge:custom -->
31
+ const MD_HINT = CUSTOM_BOUNDARY_HINTS["block-html"];
32
+
33
+ const FOOTER = "See the root `AGENTS.md` for project-wide rules, skills, and capabilities.";
34
+
35
+ function render(body: string): string {
36
+ return `${buildGeneratedHeader({ filePath: MD, ownerCommand: "forge.agents.generate", editable: true })}\n${body}\n\n${FOOTER}\n`;
37
+ }
38
+
39
+ test("AC-1: content below the forge:custom marker is preserved byte-identical", () => {
40
+ const tail = "\n## Workspace rules\n\n- always run pnpm test first\n- custom note\n";
41
+ const existing = `${render("old body v1")}${MD_MARKER}\n${MD_HINT}\n${tail}`;
42
+ const merged = mergeEditableGenerated(render("fresh body v2"), existing, MD);
43
+ expect(merged).not.toBeNull();
44
+ // Fresh head regenerated, tail below the marker verbatim
45
+ expect(merged).toContain("fresh body v2");
46
+ expect(merged).not.toContain("old body v1");
47
+ expect(
48
+ merged!.endsWith(tail.trimStart() === tail ? tail : `\n${tail}`) || merged!.includes(tail),
49
+ ).toBe(true);
50
+ expect(merged).toContain(MD_MARKER);
51
+ });
52
+
53
+ test("marker line itself belongs to the generated head — operator-placed marker also merges", () => {
54
+ const tail = "everything below survives\n";
55
+ const existing = `hand-tuned intro\n${MD_MARKER}\n${tail}`;
56
+ const merged = mergeEditableGenerated(render("body"), existing, MD);
57
+ expect(merged).toBe(`${render("body")}${MD_MARKER}\n${MD_HINT}\n${tail}`);
58
+ });
59
+
60
+ test("AC-2: footer fallback preserves text below the canonical template footer", () => {
61
+ const tail = "\noperator-appended rules\n";
62
+ const existing = `${render("stale body")}${tail}`; // marker-less, ends with footer + tail
63
+ const merged = mergeEditableGenerated(render("new body"), existing, MD);
64
+ expect(merged).not.toBeNull();
65
+ expect(merged!.endsWith(tail)).toBe(true);
66
+ });
67
+
68
+ test("AC-3: footer-fallback merge introduces the forge:custom marker as the new boundary", () => {
69
+ const existing = `${render("body")}\ncustom tail\n`;
70
+ const merged = mergeEditableGenerated(render("body"), existing, MD);
71
+ expect(merged).toContain(MD_MARKER);
72
+ expect(merged).toContain(MD_HINT);
73
+ });
74
+
75
+ test("AC-5: footer-less marker-less divergent content returns null — caller must skip", () => {
76
+ const existing = `${buildGeneratedHeader({ filePath: MD, ownerCommand: "forge.agents.generate", editable: true })}\n# Custom\n\ntotally divergent, no footer\n`;
77
+ expect(mergeEditableGenerated(render("body"), existing, MD)).toBeNull();
78
+ });
79
+
80
+ test("identical content is a clean regeneration — marker appended for future runs", () => {
81
+ const r = render("body");
82
+ const merged = mergeEditableGenerated(r, r, MD);
83
+ expect(merged).toBe(`${r}${MD_MARKER}\n${MD_HINT}\n`);
84
+ });
85
+
86
+ test("new file (existing null) gains the boundary marker and hint", () => {
87
+ const merged = mergeEditableGenerated(render("body"), null, MD);
88
+ expect(merged).toBe(`${render("body")}${MD_MARKER}\n${MD_HINT}\n`);
89
+ });
90
+
91
+ test("AC-4: boundary marker is emitted in the comment style of the target file", () => {
92
+ for (const [file, style] of [
93
+ ["AGENTS.md", "block-html"],
94
+ ["config.ts", "line-slash"],
95
+ ["data.yaml", "line-hash"],
96
+ ["styles.css", "block-css"],
97
+ ] as const) {
98
+ const merged = mergeEditableGenerated("content\n", null, file);
99
+ expect(merged, `marker for ${file} must use ${style} comment syntax`).toContain(
100
+ CUSTOM_BOUNDARY_MARKERS[style],
101
+ );
102
+ }
103
+ });
104
+
105
+ test("CRLF input normalizes to LF and still resolves the marker boundary", () => {
106
+ const tail = "preserved tail\n";
107
+ const existing = `a\r\nb\r\n${MD_MARKER}\r\n${tail}`;
108
+ const merged = mergeEditableGenerated("fresh\n", existing, MD);
109
+ expect(merged).toBe(`fresh\n${MD_MARKER}\n${MD_HINT}\n${tail}`);
110
+ expect(merged).not.toContain("\r\n");
111
+ });
112
+
113
+ test("mid-file marker freezes everything below the first occurrence", () => {
114
+ const tail = "mid doc\nfrozen rules\n";
115
+ const existing = `intro\n${MD_MARKER}\n${tail}`;
116
+ const merged = mergeEditableGenerated(render("body"), existing, MD);
117
+ expect(merged!.endsWith(tail)).toBe(true);
118
+ });
119
+
120
+ test("forge:custom token in prose is treated as a boundary (first occurrence wins)", () => {
121
+ const existing = `notes on the forge:custom feature\nkept anyway\n`;
122
+ const split = splitEditableGenerated(existing, MD);
123
+ expect(split.boundary).toBe("marker");
124
+ expect(split.customTail).toBe("kept anyway\n");
125
+ });
126
+
127
+ test("boundary none: split returns whole content as head", () => {
128
+ const split = splitEditableGenerated("plain\nfile\n", MD, FOOTER);
129
+ expect(split.boundary).toBe("none");
130
+ expect(split.customTail).toBeNull();
131
+ });
132
+
133
+ test("canonicalFooterOf returns the last non-empty line", () => {
134
+ expect(canonicalFooterOf("a\nb\n\n\n")).toBe("b");
135
+ expect(canonicalFooterOf("x\n")).toBe("x");
136
+ });
137
+
138
+ // --- Integration through the real write path -----------------------------
139
+
140
+ let tempDir: string;
141
+
142
+ beforeEach(async () => {
143
+ tempDir = await mkdtemp(join(tmpdir(), "editable-region-it-"));
144
+ });
145
+
146
+ afterEach(async () => {
147
+ await rm(tempDir, { recursive: true, force: true });
148
+ });
149
+
150
+ const FORGE_YAML = `schema: "forge/config@1"
151
+ project:
152
+ name: test-project
153
+ stack: []
154
+ packageManager: pnpm
155
+ paths:
156
+ rfcsDir: docs/rfcs
157
+ adrsDir: docs/adrs
158
+ plansDir: docs/plans
159
+ auditsDir: docs/audits
160
+ specsDir: docs/specs
161
+ skillsDir: .agents/skills
162
+ sessionsDir: docs/sessions
163
+ bindings:
164
+ schema: forge/bindings@1
165
+ commands:
166
+ validateRfc: null
167
+ validateAdr: null
168
+ implementStamp: null
169
+ typecheck: null
170
+ test: null
171
+ scopedBuild: null
172
+ specValidate: null
173
+ sessionSave: null
174
+ paths:
175
+ invariantsFile: null
176
+ compassDocs: []
177
+ reviewsDir: null
178
+ handoffsDir: null
179
+ sessionsDir: null
180
+ `;
181
+
182
+ test("generateNestedAgentsMd regenerates the head and preserves the custom tail", async () => {
183
+ await writeFile(join(tempDir, "forge.yaml"), FORGE_YAML, "utf8");
184
+ await mkdir(join(tempDir, "packages", "pkg"), { recursive: true });
185
+ await writeFile(join(tempDir, "packages", "pkg", "package.json"), '{"name":"pkg"}', "utf8");
186
+
187
+ const config = loadForgeConfig(tempDir);
188
+
189
+ // First run — fresh file gains the marker + hint
190
+ const first = await generateNestedAgentsMd(tempDir, config, false);
191
+ expect(first.generated).toContain(join("packages", "pkg", "AGENTS.md"));
192
+ const agentsPath = join(tempDir, "packages", "pkg", "AGENTS.md");
193
+ const initial = await readFile(agentsPath, "utf8");
194
+ expect(initial).toContain(MD_MARKER);
195
+ expect(initial).toContain(MD_HINT);
196
+
197
+ // Operator appends a custom section below the boundary
198
+ await appendFile(agentsPath, "\n## Workspace rules\n\n- never touch dist/\n", "utf8");
199
+
200
+ // Second run — head regenerated, tail preserved verbatim
201
+ const second = await generateNestedAgentsMd(tempDir, config, false);
202
+ expect(second.preserved).toContain(join("packages", "pkg", "AGENTS.md"));
203
+ const merged = await readFile(agentsPath, "utf8");
204
+ expect(merged).toContain("## Workspace rules");
205
+ expect(merged).toContain("- never touch dist/");
206
+ // Boundary sits between generated head and custom tail
207
+ expect(merged.indexOf(MD_MARKER)).toBeLessThan(merged.indexOf("## Workspace rules"));
208
+ });
209
+
210
+ test("generateNestedAgentsMd skips a divergent file without a resolvable boundary", async () => {
211
+ await writeFile(join(tempDir, "forge.yaml"), FORGE_YAML, "utf8");
212
+ await mkdir(join(tempDir, "packages", "legacy"), { recursive: true });
213
+ await writeFile(join(tempDir, "packages", "legacy", "package.json"), '{"name":"legacy"}', "utf8");
214
+ // Marker-bearing (isGenerated) file whose body diverges and lacks the footer
215
+ await writeFile(
216
+ join(tempDir, "packages", "legacy", "AGENTS.md"),
217
+ `${buildGeneratedHeader({ filePath: "AGENTS.md", ownerCommand: "forge.agents.generate", editable: true })}\n# Hand-maintained\n\ndivergent body\n`,
218
+ "utf8",
219
+ );
220
+
221
+ const config = loadForgeConfig(tempDir);
222
+ const result = await generateNestedAgentsMd(tempDir, config, false);
223
+ const skippedEntry = result.skipped.find((s) => s.includes("legacy"));
224
+ expect(
225
+ skippedEntry,
226
+ "Divergent file without forge:custom/footer boundary must be skipped as unmapped-customization",
227
+ ).toContain("unmapped-customization");
228
+ // File untouched
229
+ const content = await readFile(join(tempDir, "packages", "legacy", "AGENTS.md"), "utf8");
230
+ expect(content).toContain("divergent body");
231
+ });