@garygentry/feature-forge 0.2.14 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (486) hide show
  1. package/README.md +6 -3
  2. package/adapters/GENERATION-REPORT.md +20 -0
  3. package/adapters/claude/.feature-forge-bundle.json +1 -1
  4. package/adapters/claude/agents/forge-verifier.md +1 -1
  5. package/adapters/claude/references/forge-config-schema.json +2 -2
  6. package/adapters/claude/references/pipeline-state-schema.json +1 -1
  7. package/adapters/claude/references/shared-conventions.md +62 -12
  8. package/adapters/claude/references/stage-exit-protocol.md +14 -4
  9. package/adapters/claude/references/vendor-construct-inventory.md +1 -1
  10. package/adapters/claude/scripts/epic-manifest.py +49 -6
  11. package/adapters/claude/scripts/forge-root.sh +47 -3
  12. package/adapters/claude/scripts/forge-session.py +1179 -9
  13. package/adapters/claude/scripts/validate-traceability.py +6 -1
  14. package/adapters/claude/skills/forge/SKILL.md +11 -5
  15. package/adapters/claude/skills/forge/references/pipeline-state-schema.json +1 -1
  16. package/adapters/claude/skills/forge/references/shared-conventions.md +62 -12
  17. package/adapters/claude/skills/forge/references/stage-exit-protocol.md +14 -4
  18. package/adapters/claude/skills/forge-0-epic/SKILL.md +1 -1
  19. package/adapters/claude/skills/forge-0-epic/references/pipeline-state-schema.json +1 -1
  20. package/adapters/claude/skills/forge-0-epic/references/shared-conventions.md +62 -12
  21. package/adapters/claude/skills/forge-0-epic/references/stage-exit-protocol.md +14 -4
  22. package/adapters/claude/skills/forge-1-prd/SKILL.md +25 -8
  23. package/adapters/claude/skills/forge-1-prd/references/shared-conventions.md +62 -12
  24. package/adapters/claude/skills/forge-1-prd/references/stage-exit-protocol.md +14 -4
  25. package/adapters/claude/skills/forge-2-tech/SKILL.md +25 -7
  26. package/adapters/claude/skills/forge-2-tech/references/shared-conventions.md +62 -12
  27. package/adapters/claude/skills/forge-2-tech/references/stage-exit-protocol.md +14 -4
  28. package/adapters/claude/skills/forge-3-specs/SKILL.md +24 -7
  29. package/adapters/claude/skills/forge-3-specs/references/shared-conventions.md +62 -12
  30. package/adapters/claude/skills/forge-3-specs/references/stage-exit-protocol.md +14 -4
  31. package/adapters/claude/skills/forge-4-backlog/SKILL.md +23 -7
  32. package/adapters/claude/skills/forge-4-backlog/references/shared-conventions.md +62 -12
  33. package/adapters/claude/skills/forge-4-backlog/references/stage-exit-protocol.md +14 -4
  34. package/adapters/claude/skills/forge-5-loop/SKILL.md +25 -25
  35. package/adapters/claude/skills/forge-5-loop/references/agent-selection.md +116 -0
  36. package/adapters/claude/skills/forge-5-loop/references/runner-contract.md +14 -107
  37. package/adapters/claude/skills/forge-5-loop/references/shared-conventions.md +62 -12
  38. package/adapters/claude/skills/forge-5-loop/references/stage-exit-protocol.md +14 -4
  39. package/adapters/claude/skills/forge-6-docs/SKILL.md +11 -5
  40. package/adapters/claude/skills/forge-6-docs/references/shared-conventions.md +62 -12
  41. package/adapters/claude/skills/forge-fix/references/shared-conventions.md +62 -12
  42. package/adapters/claude/skills/forge-fix/references/stage-exit-protocol.md +14 -4
  43. package/adapters/claude/skills/forge-guide/references/forge-config-schema.json +2 -2
  44. package/adapters/claude/skills/forge-guide/references/shared-conventions.md +62 -12
  45. package/adapters/claude/skills/forge-verify/SKILL.md +22 -12
  46. package/adapters/claude/skills/forge-verify/references/findings-template.md +157 -0
  47. package/adapters/claude/skills/forge-verify/references/pipeline-state-schema.json +1 -1
  48. package/adapters/claude/skills/forge-verify/references/shared-conventions.md +62 -12
  49. package/adapters/claude/skills/forge-verify/references/verification-checklists/backlog.md +97 -0
  50. package/adapters/claude/skills/forge-verify/references/verification-checklists/epic.md +79 -0
  51. package/adapters/claude/skills/forge-verify/references/verification-checklists/impl.md +48 -0
  52. package/adapters/claude/skills/forge-verify/references/verification-checklists/prd.md +31 -0
  53. package/adapters/claude/skills/forge-verify/references/verification-checklists/specs.md +64 -0
  54. package/adapters/claude/skills/forge-verify/references/verification-checklists/tech.md +35 -0
  55. package/adapters/codex/.feature-forge-bundle.json +1 -1
  56. package/adapters/codex/agents/forge-verifier.toml +1 -1
  57. package/adapters/codex/references/forge-config-schema.json +2 -2
  58. package/adapters/codex/references/pipeline-state-schema.json +1 -1
  59. package/adapters/codex/references/shared-conventions.md +62 -12
  60. package/adapters/codex/references/stage-exit-protocol.md +14 -4
  61. package/adapters/codex/references/vendor-construct-inventory.md +1 -1
  62. package/adapters/codex/scripts/epic-manifest.py +49 -6
  63. package/adapters/codex/scripts/forge-root.sh +47 -3
  64. package/adapters/codex/scripts/forge-session.py +1179 -9
  65. package/adapters/codex/scripts/validate-traceability.py +6 -1
  66. package/adapters/codex/skills/forge/SKILL.md +11 -5
  67. package/adapters/codex/skills/forge/references/pipeline-state-schema.json +1 -1
  68. package/adapters/codex/skills/forge/references/shared-conventions.md +62 -12
  69. package/adapters/codex/skills/forge/references/stage-exit-protocol.md +14 -4
  70. package/adapters/codex/skills/forge-0-epic/SKILL.md +1 -1
  71. package/adapters/codex/skills/forge-0-epic/references/pipeline-state-schema.json +1 -1
  72. package/adapters/codex/skills/forge-0-epic/references/shared-conventions.md +62 -12
  73. package/adapters/codex/skills/forge-0-epic/references/stage-exit-protocol.md +14 -4
  74. package/adapters/codex/skills/forge-1-prd/SKILL.md +25 -8
  75. package/adapters/codex/skills/forge-1-prd/references/shared-conventions.md +62 -12
  76. package/adapters/codex/skills/forge-1-prd/references/stage-exit-protocol.md +14 -4
  77. package/adapters/codex/skills/forge-2-tech/SKILL.md +25 -7
  78. package/adapters/codex/skills/forge-2-tech/references/shared-conventions.md +62 -12
  79. package/adapters/codex/skills/forge-2-tech/references/stage-exit-protocol.md +14 -4
  80. package/adapters/codex/skills/forge-3-specs/SKILL.md +24 -7
  81. package/adapters/codex/skills/forge-3-specs/references/shared-conventions.md +62 -12
  82. package/adapters/codex/skills/forge-3-specs/references/stage-exit-protocol.md +14 -4
  83. package/adapters/codex/skills/forge-4-backlog/SKILL.md +23 -7
  84. package/adapters/codex/skills/forge-4-backlog/references/shared-conventions.md +62 -12
  85. package/adapters/codex/skills/forge-4-backlog/references/stage-exit-protocol.md +14 -4
  86. package/adapters/codex/skills/forge-5-loop/SKILL.md +25 -25
  87. package/adapters/codex/skills/forge-5-loop/references/agent-selection.md +116 -0
  88. package/adapters/codex/skills/forge-5-loop/references/runner-contract.md +14 -107
  89. package/adapters/codex/skills/forge-5-loop/references/shared-conventions.md +62 -12
  90. package/adapters/codex/skills/forge-5-loop/references/stage-exit-protocol.md +14 -4
  91. package/adapters/codex/skills/forge-6-docs/SKILL.md +11 -5
  92. package/adapters/codex/skills/forge-6-docs/references/shared-conventions.md +62 -12
  93. package/adapters/codex/skills/forge-fix/references/shared-conventions.md +62 -12
  94. package/adapters/codex/skills/forge-fix/references/stage-exit-protocol.md +14 -4
  95. package/adapters/codex/skills/forge-guide/references/forge-config-schema.json +2 -2
  96. package/adapters/codex/skills/forge-guide/references/shared-conventions.md +62 -12
  97. package/adapters/codex/skills/forge-verify/SKILL.md +22 -12
  98. package/adapters/codex/skills/forge-verify/references/findings-template.md +157 -0
  99. package/adapters/codex/skills/forge-verify/references/pipeline-state-schema.json +1 -1
  100. package/adapters/codex/skills/forge-verify/references/shared-conventions.md +62 -12
  101. package/adapters/codex/skills/forge-verify/references/verification-checklists/backlog.md +97 -0
  102. package/adapters/codex/skills/forge-verify/references/verification-checklists/epic.md +79 -0
  103. package/adapters/codex/skills/forge-verify/references/verification-checklists/impl.md +48 -0
  104. package/adapters/codex/skills/forge-verify/references/verification-checklists/prd.md +31 -0
  105. package/adapters/codex/skills/forge-verify/references/verification-checklists/specs.md +64 -0
  106. package/adapters/codex/skills/forge-verify/references/verification-checklists/tech.md +35 -0
  107. package/adapters/copilot/.feature-forge-bundle.json +1 -1
  108. package/adapters/copilot/agents/forge-verifier.md +1 -1
  109. package/adapters/copilot/references/forge-config-schema.json +2 -2
  110. package/adapters/copilot/references/pipeline-state-schema.json +1 -1
  111. package/adapters/copilot/references/shared-conventions.md +62 -12
  112. package/adapters/copilot/references/stage-exit-protocol.md +14 -4
  113. package/adapters/copilot/references/vendor-construct-inventory.md +1 -1
  114. package/adapters/copilot/scripts/epic-manifest.py +49 -6
  115. package/adapters/copilot/scripts/forge-root.sh +47 -3
  116. package/adapters/copilot/scripts/forge-session.py +1179 -9
  117. package/adapters/copilot/scripts/validate-traceability.py +6 -1
  118. package/adapters/copilot/skills/forge/forge.md +11 -5
  119. package/adapters/copilot/skills/forge/references/pipeline-state-schema.json +1 -1
  120. package/adapters/copilot/skills/forge/references/shared-conventions.md +62 -12
  121. package/adapters/copilot/skills/forge/references/stage-exit-protocol.md +14 -4
  122. package/adapters/copilot/skills/forge-0-epic/forge-0-epic.md +1 -1
  123. package/adapters/copilot/skills/forge-0-epic/references/pipeline-state-schema.json +1 -1
  124. package/adapters/copilot/skills/forge-0-epic/references/shared-conventions.md +62 -12
  125. package/adapters/copilot/skills/forge-0-epic/references/stage-exit-protocol.md +14 -4
  126. package/adapters/copilot/skills/forge-1-prd/forge-1-prd.md +25 -8
  127. package/adapters/copilot/skills/forge-1-prd/references/shared-conventions.md +62 -12
  128. package/adapters/copilot/skills/forge-1-prd/references/stage-exit-protocol.md +14 -4
  129. package/adapters/copilot/skills/forge-2-tech/forge-2-tech.md +25 -7
  130. package/adapters/copilot/skills/forge-2-tech/references/shared-conventions.md +62 -12
  131. package/adapters/copilot/skills/forge-2-tech/references/stage-exit-protocol.md +14 -4
  132. package/adapters/copilot/skills/forge-3-specs/forge-3-specs.md +24 -7
  133. package/adapters/copilot/skills/forge-3-specs/references/shared-conventions.md +62 -12
  134. package/adapters/copilot/skills/forge-3-specs/references/stage-exit-protocol.md +14 -4
  135. package/adapters/copilot/skills/forge-4-backlog/forge-4-backlog.md +23 -7
  136. package/adapters/copilot/skills/forge-4-backlog/references/shared-conventions.md +62 -12
  137. package/adapters/copilot/skills/forge-4-backlog/references/stage-exit-protocol.md +14 -4
  138. package/adapters/copilot/skills/forge-5-loop/forge-5-loop.md +25 -25
  139. package/adapters/copilot/skills/forge-5-loop/references/agent-selection.md +116 -0
  140. package/adapters/copilot/skills/forge-5-loop/references/runner-contract.md +14 -107
  141. package/adapters/copilot/skills/forge-5-loop/references/shared-conventions.md +62 -12
  142. package/adapters/copilot/skills/forge-5-loop/references/stage-exit-protocol.md +14 -4
  143. package/adapters/copilot/skills/forge-6-docs/forge-6-docs.md +11 -5
  144. package/adapters/copilot/skills/forge-6-docs/references/shared-conventions.md +62 -12
  145. package/adapters/copilot/skills/forge-fix/references/shared-conventions.md +62 -12
  146. package/adapters/copilot/skills/forge-fix/references/stage-exit-protocol.md +14 -4
  147. package/adapters/copilot/skills/forge-guide/references/forge-config-schema.json +2 -2
  148. package/adapters/copilot/skills/forge-guide/references/shared-conventions.md +62 -12
  149. package/adapters/copilot/skills/forge-verify/forge-verify.md +22 -12
  150. package/adapters/copilot/skills/forge-verify/references/findings-template.md +157 -0
  151. package/adapters/copilot/skills/forge-verify/references/pipeline-state-schema.json +1 -1
  152. package/adapters/copilot/skills/forge-verify/references/shared-conventions.md +62 -12
  153. package/adapters/copilot/skills/forge-verify/references/verification-checklists/backlog.md +97 -0
  154. package/adapters/copilot/skills/forge-verify/references/verification-checklists/epic.md +79 -0
  155. package/adapters/copilot/skills/forge-verify/references/verification-checklists/impl.md +48 -0
  156. package/adapters/copilot/skills/forge-verify/references/verification-checklists/prd.md +31 -0
  157. package/adapters/copilot/skills/forge-verify/references/verification-checklists/specs.md +64 -0
  158. package/adapters/copilot/skills/forge-verify/references/verification-checklists/tech.md +35 -0
  159. package/adapters/cursor/.feature-forge-bundle.json +1 -1
  160. package/adapters/cursor/agents/forge-verifier.mdc +1 -1
  161. package/adapters/cursor/references/forge-config-schema.json +2 -2
  162. package/adapters/cursor/references/pipeline-state-schema.json +1 -1
  163. package/adapters/cursor/references/shared-conventions.md +62 -12
  164. package/adapters/cursor/references/stage-exit-protocol.md +14 -4
  165. package/adapters/cursor/references/vendor-construct-inventory.md +1 -1
  166. package/adapters/cursor/scripts/epic-manifest.py +49 -6
  167. package/adapters/cursor/scripts/forge-root.sh +47 -3
  168. package/adapters/cursor/scripts/forge-session.py +1179 -9
  169. package/adapters/cursor/scripts/validate-traceability.py +6 -1
  170. package/adapters/cursor/skills/forge/forge.mdc +11 -5
  171. package/adapters/cursor/skills/forge/references/pipeline-state-schema.json +1 -1
  172. package/adapters/cursor/skills/forge/references/shared-conventions.md +62 -12
  173. package/adapters/cursor/skills/forge/references/stage-exit-protocol.md +14 -4
  174. package/adapters/cursor/skills/forge-0-epic/forge-0-epic.mdc +1 -1
  175. package/adapters/cursor/skills/forge-0-epic/references/pipeline-state-schema.json +1 -1
  176. package/adapters/cursor/skills/forge-0-epic/references/shared-conventions.md +62 -12
  177. package/adapters/cursor/skills/forge-0-epic/references/stage-exit-protocol.md +14 -4
  178. package/adapters/cursor/skills/forge-1-prd/forge-1-prd.mdc +25 -8
  179. package/adapters/cursor/skills/forge-1-prd/references/shared-conventions.md +62 -12
  180. package/adapters/cursor/skills/forge-1-prd/references/stage-exit-protocol.md +14 -4
  181. package/adapters/cursor/skills/forge-2-tech/forge-2-tech.mdc +25 -7
  182. package/adapters/cursor/skills/forge-2-tech/references/shared-conventions.md +62 -12
  183. package/adapters/cursor/skills/forge-2-tech/references/stage-exit-protocol.md +14 -4
  184. package/adapters/cursor/skills/forge-3-specs/forge-3-specs.mdc +24 -7
  185. package/adapters/cursor/skills/forge-3-specs/references/shared-conventions.md +62 -12
  186. package/adapters/cursor/skills/forge-3-specs/references/stage-exit-protocol.md +14 -4
  187. package/adapters/cursor/skills/forge-4-backlog/forge-4-backlog.mdc +23 -7
  188. package/adapters/cursor/skills/forge-4-backlog/references/shared-conventions.md +62 -12
  189. package/adapters/cursor/skills/forge-4-backlog/references/stage-exit-protocol.md +14 -4
  190. package/adapters/cursor/skills/forge-5-loop/forge-5-loop.mdc +25 -25
  191. package/adapters/cursor/skills/forge-5-loop/references/agent-selection.md +116 -0
  192. package/adapters/cursor/skills/forge-5-loop/references/runner-contract.md +14 -107
  193. package/adapters/cursor/skills/forge-5-loop/references/shared-conventions.md +62 -12
  194. package/adapters/cursor/skills/forge-5-loop/references/stage-exit-protocol.md +14 -4
  195. package/adapters/cursor/skills/forge-6-docs/forge-6-docs.mdc +11 -5
  196. package/adapters/cursor/skills/forge-6-docs/references/shared-conventions.md +62 -12
  197. package/adapters/cursor/skills/forge-fix/references/shared-conventions.md +62 -12
  198. package/adapters/cursor/skills/forge-fix/references/stage-exit-protocol.md +14 -4
  199. package/adapters/cursor/skills/forge-guide/references/forge-config-schema.json +2 -2
  200. package/adapters/cursor/skills/forge-guide/references/shared-conventions.md +62 -12
  201. package/adapters/cursor/skills/forge-verify/forge-verify.mdc +22 -12
  202. package/adapters/cursor/skills/forge-verify/references/findings-template.md +157 -0
  203. package/adapters/cursor/skills/forge-verify/references/pipeline-state-schema.json +1 -1
  204. package/adapters/cursor/skills/forge-verify/references/shared-conventions.md +62 -12
  205. package/adapters/cursor/skills/forge-verify/references/verification-checklists/backlog.md +97 -0
  206. package/adapters/cursor/skills/forge-verify/references/verification-checklists/epic.md +79 -0
  207. package/adapters/cursor/skills/forge-verify/references/verification-checklists/impl.md +48 -0
  208. package/adapters/cursor/skills/forge-verify/references/verification-checklists/prd.md +31 -0
  209. package/adapters/cursor/skills/forge-verify/references/verification-checklists/specs.md +64 -0
  210. package/adapters/cursor/skills/forge-verify/references/verification-checklists/tech.md +35 -0
  211. package/adapters/gemini/.feature-forge-bundle.json +1 -1
  212. package/adapters/gemini/agents/forge-verifier.md +1 -1
  213. package/adapters/gemini/gemini-extension.json +1 -1
  214. package/adapters/gemini/references/forge-config-schema.json +2 -2
  215. package/adapters/gemini/references/pipeline-state-schema.json +1 -1
  216. package/adapters/gemini/references/shared-conventions.md +62 -12
  217. package/adapters/gemini/references/stage-exit-protocol.md +14 -4
  218. package/adapters/gemini/references/vendor-construct-inventory.md +1 -1
  219. package/adapters/gemini/scripts/epic-manifest.py +49 -6
  220. package/adapters/gemini/scripts/forge-root.sh +47 -3
  221. package/adapters/gemini/scripts/forge-session.py +1179 -9
  222. package/adapters/gemini/scripts/validate-traceability.py +6 -1
  223. package/adapters/gemini/skills/forge/forge.md +11 -5
  224. package/adapters/gemini/skills/forge/references/pipeline-state-schema.json +1 -1
  225. package/adapters/gemini/skills/forge/references/shared-conventions.md +62 -12
  226. package/adapters/gemini/skills/forge/references/stage-exit-protocol.md +14 -4
  227. package/adapters/gemini/skills/forge-0-epic/forge-0-epic.md +1 -1
  228. package/adapters/gemini/skills/forge-0-epic/references/pipeline-state-schema.json +1 -1
  229. package/adapters/gemini/skills/forge-0-epic/references/shared-conventions.md +62 -12
  230. package/adapters/gemini/skills/forge-0-epic/references/stage-exit-protocol.md +14 -4
  231. package/adapters/gemini/skills/forge-1-prd/forge-1-prd.md +25 -8
  232. package/adapters/gemini/skills/forge-1-prd/references/shared-conventions.md +62 -12
  233. package/adapters/gemini/skills/forge-1-prd/references/stage-exit-protocol.md +14 -4
  234. package/adapters/gemini/skills/forge-2-tech/forge-2-tech.md +25 -7
  235. package/adapters/gemini/skills/forge-2-tech/references/shared-conventions.md +62 -12
  236. package/adapters/gemini/skills/forge-2-tech/references/stage-exit-protocol.md +14 -4
  237. package/adapters/gemini/skills/forge-3-specs/forge-3-specs.md +24 -7
  238. package/adapters/gemini/skills/forge-3-specs/references/shared-conventions.md +62 -12
  239. package/adapters/gemini/skills/forge-3-specs/references/stage-exit-protocol.md +14 -4
  240. package/adapters/gemini/skills/forge-4-backlog/forge-4-backlog.md +23 -7
  241. package/adapters/gemini/skills/forge-4-backlog/references/shared-conventions.md +62 -12
  242. package/adapters/gemini/skills/forge-4-backlog/references/stage-exit-protocol.md +14 -4
  243. package/adapters/gemini/skills/forge-5-loop/forge-5-loop.md +25 -25
  244. package/adapters/gemini/skills/forge-5-loop/references/agent-selection.md +116 -0
  245. package/adapters/gemini/skills/forge-5-loop/references/runner-contract.md +14 -107
  246. package/adapters/gemini/skills/forge-5-loop/references/shared-conventions.md +62 -12
  247. package/adapters/gemini/skills/forge-5-loop/references/stage-exit-protocol.md +14 -4
  248. package/adapters/gemini/skills/forge-6-docs/forge-6-docs.md +11 -5
  249. package/adapters/gemini/skills/forge-6-docs/references/shared-conventions.md +62 -12
  250. package/adapters/gemini/skills/forge-fix/references/shared-conventions.md +62 -12
  251. package/adapters/gemini/skills/forge-fix/references/stage-exit-protocol.md +14 -4
  252. package/adapters/gemini/skills/forge-guide/references/forge-config-schema.json +2 -2
  253. package/adapters/gemini/skills/forge-guide/references/shared-conventions.md +62 -12
  254. package/adapters/gemini/skills/forge-verify/forge-verify.md +22 -12
  255. package/adapters/gemini/skills/forge-verify/references/findings-template.md +157 -0
  256. package/adapters/gemini/skills/forge-verify/references/pipeline-state-schema.json +1 -1
  257. package/adapters/gemini/skills/forge-verify/references/shared-conventions.md +62 -12
  258. package/adapters/gemini/skills/forge-verify/references/verification-checklists/backlog.md +97 -0
  259. package/adapters/gemini/skills/forge-verify/references/verification-checklists/epic.md +79 -0
  260. package/adapters/gemini/skills/forge-verify/references/verification-checklists/impl.md +48 -0
  261. package/adapters/gemini/skills/forge-verify/references/verification-checklists/prd.md +31 -0
  262. package/adapters/gemini/skills/forge-verify/references/verification-checklists/specs.md +64 -0
  263. package/adapters/gemini/skills/forge-verify/references/verification-checklists/tech.md +35 -0
  264. package/adapters/pi/.feature-forge-bundle.json +6 -0
  265. package/adapters/pi/agents/forge-researcher.md +139 -0
  266. package/adapters/pi/agents/forge-spec-writer.md +116 -0
  267. package/adapters/pi/agents/forge-verifier.md +126 -0
  268. package/adapters/pi/extensions/ask-user-question/LICENSE +21 -0
  269. package/adapters/pi/extensions/ask-user-question/README.md +91 -0
  270. package/adapters/pi/extensions/ask-user-question/ask-user-question.ts +298 -0
  271. package/adapters/pi/extensions/ask-user-question/config.ts +78 -0
  272. package/adapters/pi/extensions/ask-user-question/events.ts +57 -0
  273. package/adapters/pi/extensions/ask-user-question/index.ts +61 -0
  274. package/adapters/pi/extensions/ask-user-question/locales/de.json +27 -0
  275. package/adapters/pi/extensions/ask-user-question/locales/en.json +27 -0
  276. package/adapters/pi/extensions/ask-user-question/locales/es.json +27 -0
  277. package/adapters/pi/extensions/ask-user-question/locales/fr.json +27 -0
  278. package/adapters/pi/extensions/ask-user-question/locales/pt-BR.json +27 -0
  279. package/adapters/pi/extensions/ask-user-question/locales/pt.json +27 -0
  280. package/adapters/pi/extensions/ask-user-question/locales/ru.json +27 -0
  281. package/adapters/pi/extensions/ask-user-question/locales/uk.json +27 -0
  282. package/adapters/pi/extensions/ask-user-question/locales/zh.json +29 -0
  283. package/adapters/pi/extensions/ask-user-question/reconcile.ts +49 -0
  284. package/adapters/pi/extensions/ask-user-question/rpc-fallback.ts +168 -0
  285. package/adapters/pi/extensions/ask-user-question/state/build-questionnaire.ts +302 -0
  286. package/adapters/pi/extensions/ask-user-question/state/i18n-bridge.ts +53 -0
  287. package/adapters/pi/extensions/ask-user-question/state/key-router.ts +277 -0
  288. package/adapters/pi/extensions/ask-user-question/state/questionnaire-session.ts +234 -0
  289. package/adapters/pi/extensions/ask-user-question/state/row-intent.ts +145 -0
  290. package/adapters/pi/extensions/ask-user-question/state/selectors/contract.ts +26 -0
  291. package/adapters/pi/extensions/ask-user-question/state/selectors/derivations.ts +42 -0
  292. package/adapters/pi/extensions/ask-user-question/state/selectors/focus.ts +19 -0
  293. package/adapters/pi/extensions/ask-user-question/state/selectors/projections.ts +101 -0
  294. package/adapters/pi/extensions/ask-user-question/state/state-reducer.ts +292 -0
  295. package/adapters/pi/extensions/ask-user-question/state/state.ts +55 -0
  296. package/adapters/pi/extensions/ask-user-question/tool/format-answer.ts +31 -0
  297. package/adapters/pi/extensions/ask-user-question/tool/response-envelope.ts +49 -0
  298. package/adapters/pi/extensions/ask-user-question/tool/types.ts +147 -0
  299. package/adapters/pi/extensions/ask-user-question/tool/validate-questionnaire.ts +58 -0
  300. package/adapters/pi/extensions/ask-user-question/vendor-config-shim.ts +65 -0
  301. package/adapters/pi/extensions/ask-user-question/view/component-binding.ts +47 -0
  302. package/adapters/pi/extensions/ask-user-question/view/components/inline-input.ts +98 -0
  303. package/adapters/pi/extensions/ask-user-question/view/components/multi-select-view.ts +193 -0
  304. package/adapters/pi/extensions/ask-user-question/view/components/option-list-view.ts +70 -0
  305. package/adapters/pi/extensions/ask-user-question/view/components/preview/markdown-content-cache.ts +79 -0
  306. package/adapters/pi/extensions/ask-user-question/view/components/preview/preview-block-renderer.ts +111 -0
  307. package/adapters/pi/extensions/ask-user-question/view/components/preview/preview-box-renderer.ts +88 -0
  308. package/adapters/pi/extensions/ask-user-question/view/components/preview/preview-layout-decider.ts +202 -0
  309. package/adapters/pi/extensions/ask-user-question/view/components/preview/preview-pane.ts +228 -0
  310. package/adapters/pi/extensions/ask-user-question/view/components/submit-picker.ts +67 -0
  311. package/adapters/pi/extensions/ask-user-question/view/components/tab-bar.ts +59 -0
  312. package/adapters/pi/extensions/ask-user-question/view/components/wrapping-select.ts +293 -0
  313. package/adapters/pi/extensions/ask-user-question/view/dialog-builder.ts +224 -0
  314. package/adapters/pi/extensions/ask-user-question/view/props-adapter.ts +125 -0
  315. package/adapters/pi/extensions/ask-user-question/view/stateful-view.ts +26 -0
  316. package/adapters/pi/extensions/ask-user-question/view/tab-components.ts +18 -0
  317. package/adapters/pi/extensions/ask-user-question/view/tab-content-strategy.ts +252 -0
  318. package/adapters/pi/package.json +26 -0
  319. package/adapters/pi/references/epic-manifest-schema.json +125 -0
  320. package/adapters/{claude/skills/forge-5-loop → pi}/references/forge-config-schema.json +4 -4
  321. package/adapters/{claude/skills/forge-1-prd → pi}/references/pipeline-state-schema.json +1 -1
  322. package/adapters/pi/references/portable-root.md +71 -0
  323. package/adapters/pi/references/process-overview.md +143 -0
  324. package/adapters/pi/references/ralph-loop-contract.md +221 -0
  325. package/adapters/pi/references/shared-conventions.md +345 -0
  326. package/adapters/pi/references/skill-frontmatter.schema.json +17 -0
  327. package/adapters/pi/references/stack-resolution.md +54 -0
  328. package/adapters/pi/references/stacks/_generic.md +111 -0
  329. package/adapters/pi/references/stacks/go.md +157 -0
  330. package/adapters/pi/references/stacks/python.md +184 -0
  331. package/adapters/pi/references/stacks/rust.md +170 -0
  332. package/adapters/pi/references/stacks/typescript.md +134 -0
  333. package/adapters/pi/references/stage-exit-protocol.md +268 -0
  334. package/adapters/pi/references/templates/specs-hygiene/AGENTS.md +32 -0
  335. package/adapters/pi/references/templates/specs-hygiene/CLAUDE.md +31 -0
  336. package/adapters/pi/references/vendor-construct-inventory.md +50 -0
  337. package/adapters/pi/scripts/epic-manifest.py +1737 -0
  338. package/adapters/pi/scripts/forge-bootstrap.py +1070 -0
  339. package/adapters/pi/scripts/forge-init.sh +58 -0
  340. package/adapters/pi/scripts/forge-root.sh +179 -0
  341. package/adapters/pi/scripts/forge-session.py +3036 -0
  342. package/adapters/pi/scripts/validate-traceability.py +155 -0
  343. package/adapters/pi/skills/forge/SKILL.md +249 -0
  344. package/adapters/{claude/skills/forge-4-backlog → pi/skills/forge}/references/pipeline-state-schema.json +1 -1
  345. package/adapters/pi/skills/forge/references/process-overview.md +143 -0
  346. package/adapters/pi/skills/forge/references/shared-conventions.md +345 -0
  347. package/adapters/pi/skills/forge/references/stage-exit-protocol.md +268 -0
  348. package/adapters/pi/skills/forge-0-epic/SKILL.md +308 -0
  349. package/adapters/pi/skills/forge-0-epic/references/edit-mode.md +266 -0
  350. package/adapters/pi/skills/forge-0-epic/references/epic-manifest-subcommands.md +75 -0
  351. package/adapters/{claude/skills/forge-2-tech → pi/skills/forge-0-epic}/references/pipeline-state-schema.json +1 -1
  352. package/adapters/pi/skills/forge-0-epic/references/portable-root.md +71 -0
  353. package/adapters/pi/skills/forge-0-epic/references/shared-conventions.md +345 -0
  354. package/adapters/pi/skills/forge-0-epic/references/stage-exit-protocol.md +268 -0
  355. package/adapters/pi/skills/forge-1-prd/SKILL.md +181 -0
  356. package/adapters/pi/skills/forge-1-prd/references/prd-template.md +106 -0
  357. package/adapters/pi/skills/forge-1-prd/references/shared-conventions.md +345 -0
  358. package/adapters/pi/skills/forge-1-prd/references/stage-exit-protocol.md +268 -0
  359. package/adapters/pi/skills/forge-2-tech/SKILL.md +243 -0
  360. package/adapters/pi/skills/forge-2-tech/references/shared-conventions.md +345 -0
  361. package/adapters/pi/skills/forge-2-tech/references/stack-discovery-checklist.md +95 -0
  362. package/adapters/pi/skills/forge-2-tech/references/stack-resolution.md +54 -0
  363. package/adapters/pi/skills/forge-2-tech/references/stacks/_generic.md +111 -0
  364. package/adapters/pi/skills/forge-2-tech/references/stacks/go.md +157 -0
  365. package/adapters/pi/skills/forge-2-tech/references/stacks/python.md +184 -0
  366. package/adapters/pi/skills/forge-2-tech/references/stacks/rust.md +170 -0
  367. package/adapters/pi/skills/forge-2-tech/references/stacks/typescript.md +134 -0
  368. package/adapters/pi/skills/forge-2-tech/references/stage-exit-protocol.md +268 -0
  369. package/adapters/pi/skills/forge-3-specs/SKILL.md +195 -0
  370. package/adapters/pi/skills/forge-3-specs/references/shared-conventions.md +345 -0
  371. package/adapters/pi/skills/forge-3-specs/references/spec-archetypes.md +106 -0
  372. package/adapters/pi/skills/forge-3-specs/references/spec-examples.md +71 -0
  373. package/adapters/pi/skills/forge-3-specs/references/stacks/_generic.md +111 -0
  374. package/adapters/pi/skills/forge-3-specs/references/stacks/go.md +157 -0
  375. package/adapters/pi/skills/forge-3-specs/references/stacks/python.md +184 -0
  376. package/adapters/pi/skills/forge-3-specs/references/stacks/rust.md +170 -0
  377. package/adapters/pi/skills/forge-3-specs/references/stacks/typescript.md +134 -0
  378. package/adapters/pi/skills/forge-3-specs/references/stage-exit-protocol.md +268 -0
  379. package/adapters/pi/skills/forge-4-backlog/SKILL.md +191 -0
  380. package/adapters/pi/skills/forge-4-backlog/references/shared-conventions.md +345 -0
  381. package/adapters/pi/skills/forge-4-backlog/references/stage-exit-protocol.md +268 -0
  382. package/adapters/pi/skills/forge-5-loop/SKILL.md +314 -0
  383. package/adapters/pi/skills/forge-5-loop/references/agent-selection.md +116 -0
  384. package/adapters/pi/skills/forge-5-loop/references/ralph-loop-contract.md +221 -0
  385. package/adapters/pi/skills/forge-5-loop/references/result-reporting.md +85 -0
  386. package/adapters/pi/skills/forge-5-loop/references/runner-contract.md +248 -0
  387. package/adapters/pi/skills/forge-5-loop/references/shared-conventions.md +345 -0
  388. package/adapters/pi/skills/forge-5-loop/references/stage-exit-protocol.md +268 -0
  389. package/adapters/pi/skills/forge-6-docs/SKILL.md +208 -0
  390. package/adapters/pi/skills/forge-6-docs/references/doc-conventions.md +126 -0
  391. package/adapters/pi/skills/forge-6-docs/references/shared-conventions.md +345 -0
  392. package/adapters/pi/skills/forge-bootstrap/SKILL.md +250 -0
  393. package/adapters/pi/skills/forge-bootstrap/references/templates/ci/github-actions.yml +12 -0
  394. package/adapters/pi/skills/forge-bootstrap/references/templates/generic/run.sh +3 -0
  395. package/adapters/pi/skills/forge-bootstrap/references/templates/generic/test.sh +13 -0
  396. package/adapters/pi/skills/forge-bootstrap/references/templates/go/go.mod +3 -0
  397. package/adapters/pi/skills/forge-bootstrap/references/templates/go/main.go +12 -0
  398. package/adapters/pi/skills/forge-bootstrap/references/templates/go/main_test.go +11 -0
  399. package/adapters/pi/skills/forge-bootstrap/references/templates/hygiene/AGENTS.md +35 -0
  400. package/adapters/pi/skills/forge-bootstrap/references/templates/hygiene/CLAUDE.md +36 -0
  401. package/adapters/pi/skills/forge-bootstrap/references/templates/hygiene/README.md +11 -0
  402. package/adapters/pi/skills/forge-bootstrap/references/templates/licenses/Apache-2.0/LICENSE +198 -0
  403. package/adapters/pi/skills/forge-bootstrap/references/templates/licenses/MIT/LICENSE +21 -0
  404. package/adapters/pi/skills/forge-bootstrap/references/templates/python/pyproject.toml +24 -0
  405. package/adapters/pi/skills/forge-bootstrap/references/templates/python/src/{{PKG}}/__init__.py +5 -0
  406. package/adapters/pi/skills/forge-bootstrap/references/templates/python/src/{{PKG}}/main.py +13 -0
  407. package/adapters/pi/skills/forge-bootstrap/references/templates/python/tests/test_smoke.py +8 -0
  408. package/adapters/pi/skills/forge-bootstrap/references/templates/rust/Cargo.toml +15 -0
  409. package/adapters/pi/skills/forge-bootstrap/references/templates/rust/src/lib.rs +7 -0
  410. package/adapters/pi/skills/forge-bootstrap/references/templates/rust/src/main.rs +5 -0
  411. package/adapters/pi/skills/forge-bootstrap/references/templates/rust/tests/smoke.rs +6 -0
  412. package/adapters/pi/skills/forge-bootstrap/references/templates/typescript/package.json +15 -0
  413. package/adapters/pi/skills/forge-bootstrap/references/templates/typescript/src/index.ts +4 -0
  414. package/adapters/pi/skills/forge-bootstrap/references/templates/typescript/test/smoke.test.ts +6 -0
  415. package/adapters/pi/skills/forge-bootstrap/references/templates/typescript/tsconfig.json +14 -0
  416. package/adapters/pi/skills/forge-fix/SKILL.md +98 -0
  417. package/adapters/pi/skills/forge-fix/references/shared-conventions.md +345 -0
  418. package/adapters/pi/skills/forge-fix/references/stage-exit-protocol.md +268 -0
  419. package/adapters/pi/skills/forge-guide/SKILL.md +192 -0
  420. package/adapters/{codex/skills/forge-4-backlog → pi/skills/forge-guide}/references/forge-config-schema.json +4 -4
  421. package/adapters/pi/skills/forge-guide/references/process-overview.md +143 -0
  422. package/adapters/pi/skills/forge-guide/references/ralph-loop-contract.md +221 -0
  423. package/adapters/pi/skills/forge-guide/references/shared-conventions.md +345 -0
  424. package/adapters/pi/skills/forge-guide/references/stack-resolution.md +54 -0
  425. package/adapters/pi/skills/forge-guide/references/stacks/_generic.md +111 -0
  426. package/adapters/pi/skills/forge-guide/references/stacks/go.md +157 -0
  427. package/adapters/pi/skills/forge-guide/references/stacks/python.md +184 -0
  428. package/adapters/pi/skills/forge-guide/references/stacks/rust.md +170 -0
  429. package/adapters/pi/skills/forge-guide/references/stacks/typescript.md +134 -0
  430. package/adapters/pi/skills/forge-init/SKILL.md +72 -0
  431. package/adapters/pi/skills/forge-verify/SKILL.md +283 -0
  432. package/adapters/pi/skills/forge-verify/references/findings-template.md +157 -0
  433. package/adapters/{claude/skills/forge-3-specs → pi/skills/forge-verify}/references/pipeline-state-schema.json +1 -1
  434. package/adapters/pi/skills/forge-verify/references/shared-conventions.md +345 -0
  435. package/adapters/pi/skills/forge-verify/references/verification-checklists/backlog.md +97 -0
  436. package/adapters/pi/skills/forge-verify/references/verification-checklists/epic.md +79 -0
  437. package/adapters/pi/skills/forge-verify/references/verification-checklists/impl.md +48 -0
  438. package/adapters/pi/skills/forge-verify/references/verification-checklists/prd.md +31 -0
  439. package/adapters/pi/skills/forge-verify/references/verification-checklists/specs.md +64 -0
  440. package/adapters/pi/skills/forge-verify/references/verification-checklists/tech.md +35 -0
  441. package/dist/agent-targets.d.ts +1 -1
  442. package/dist/agent-targets.js +23 -3
  443. package/dist/detect.d.ts +1 -1
  444. package/dist/detect.js +2 -1
  445. package/dist/manifest.d.ts +1 -1
  446. package/dist/manifest.js +2 -2
  447. package/dist/placements.js +5 -1
  448. package/dist/rauf.d.ts +4 -4
  449. package/dist/rauf.js +3 -3
  450. package/dist/types.d.ts +31 -6
  451. package/dist/types.js +6 -3
  452. package/package.json +14 -3
  453. package/adapters/claude/skills/forge-4-backlog/references/forge-config-schema.json +0 -236
  454. package/adapters/claude/skills/forge-6-docs/references/pipeline-state-schema.json +0 -191
  455. package/adapters/claude/skills/forge-verify/references/verification-checklists.md +0 -477
  456. package/adapters/codex/skills/forge-1-prd/references/pipeline-state-schema.json +0 -191
  457. package/adapters/codex/skills/forge-2-tech/references/pipeline-state-schema.json +0 -191
  458. package/adapters/codex/skills/forge-3-specs/references/pipeline-state-schema.json +0 -191
  459. package/adapters/codex/skills/forge-4-backlog/references/pipeline-state-schema.json +0 -191
  460. package/adapters/codex/skills/forge-5-loop/references/forge-config-schema.json +0 -236
  461. package/adapters/codex/skills/forge-6-docs/references/pipeline-state-schema.json +0 -191
  462. package/adapters/codex/skills/forge-verify/references/verification-checklists.md +0 -477
  463. package/adapters/copilot/skills/forge-1-prd/references/pipeline-state-schema.json +0 -191
  464. package/adapters/copilot/skills/forge-2-tech/references/pipeline-state-schema.json +0 -191
  465. package/adapters/copilot/skills/forge-3-specs/references/pipeline-state-schema.json +0 -191
  466. package/adapters/copilot/skills/forge-4-backlog/references/forge-config-schema.json +0 -236
  467. package/adapters/copilot/skills/forge-4-backlog/references/pipeline-state-schema.json +0 -191
  468. package/adapters/copilot/skills/forge-5-loop/references/forge-config-schema.json +0 -236
  469. package/adapters/copilot/skills/forge-6-docs/references/pipeline-state-schema.json +0 -191
  470. package/adapters/copilot/skills/forge-verify/references/verification-checklists.md +0 -477
  471. package/adapters/cursor/skills/forge-1-prd/references/pipeline-state-schema.json +0 -191
  472. package/adapters/cursor/skills/forge-2-tech/references/pipeline-state-schema.json +0 -191
  473. package/adapters/cursor/skills/forge-3-specs/references/pipeline-state-schema.json +0 -191
  474. package/adapters/cursor/skills/forge-4-backlog/references/forge-config-schema.json +0 -236
  475. package/adapters/cursor/skills/forge-4-backlog/references/pipeline-state-schema.json +0 -191
  476. package/adapters/cursor/skills/forge-5-loop/references/forge-config-schema.json +0 -236
  477. package/adapters/cursor/skills/forge-6-docs/references/pipeline-state-schema.json +0 -191
  478. package/adapters/cursor/skills/forge-verify/references/verification-checklists.md +0 -477
  479. package/adapters/gemini/skills/forge-1-prd/references/pipeline-state-schema.json +0 -191
  480. package/adapters/gemini/skills/forge-2-tech/references/pipeline-state-schema.json +0 -191
  481. package/adapters/gemini/skills/forge-3-specs/references/pipeline-state-schema.json +0 -191
  482. package/adapters/gemini/skills/forge-4-backlog/references/forge-config-schema.json +0 -236
  483. package/adapters/gemini/skills/forge-4-backlog/references/pipeline-state-schema.json +0 -191
  484. package/adapters/gemini/skills/forge-5-loop/references/forge-config-schema.json +0 -236
  485. package/adapters/gemini/skills/forge-6-docs/references/pipeline-state-schema.json +0 -191
  486. package/adapters/gemini/skills/forge-verify/references/verification-checklists.md +0 -477
@@ -0,0 +1,79 @@
1
+ // GENERATED — DO NOT EDIT. Source: adapter-src/pi/extensions/ask-user-question/view/components/preview/markdown-content-cache.ts
2
+ // Regenerate with: python3 scripts/build-adapters.py
3
+ import type { Theme } from "@earendil-works/pi-coding-agent";
4
+ import { Markdown, type MarkdownTheme, visibleWidth } from "@earendil-works/pi-tui";
5
+ import { t } from "../../../state/i18n-bridge.js";
6
+ import type { QuestionData } from "../../../tool/types.js";
7
+ import { stripFenceMarkers } from "./preview-box-renderer.js";
8
+
9
+ /** CC parity in side-by-side layout. */
10
+ export const MAX_PREVIEW_HEIGHT_SIDE_BY_SIDE = 20;
11
+ /** Preserves narrow-terminal protection in stacked layout. */
12
+ export const MAX_PREVIEW_HEIGHT_STACKED = 15;
13
+ export const NO_PREVIEW_TEXT = "No preview available";
14
+ /** 1 blank separator + 1 affordance text row reserved when `hasAnyPreview` (height stability of the affordance row's offset relative to the box). */
15
+ export const NOTES_AFFORDANCE_OVERHEAD = 2;
16
+
17
+ /**
18
+ * Per-question cache for rendered markdown previews. Width-keyed: switching the
19
+ * inner width invalidates every cached `Markdown`'s render output (pi-tui's
20
+ * `Markdown.render(width)` re-wraps when width changes).
21
+ *
22
+ * Replaces the inline `previewTexts`, `markdownCache`, `cachedWidth` triple from
23
+ * the previous monolithic `preview-pane.ts`. One Markdown per option, lazy on
24
+ * first request, never re-constructed — count semantics frozen by tests.
25
+ */
26
+ export class MarkdownContentCache {
27
+ private readonly previewTexts: Map<number, string>;
28
+ private readonly markdownCache: Map<number, Markdown>;
29
+ private cachedWidth: number | undefined;
30
+ private readonly theme: Theme;
31
+ private readonly markdownTheme: MarkdownTheme;
32
+
33
+ constructor(question: QuestionData, theme: Theme, markdownTheme: MarkdownTheme) {
34
+ this.theme = theme;
35
+ this.markdownTheme = markdownTheme;
36
+ this.previewTexts = new Map();
37
+ for (let i = 0; i < question.options.length; i++) {
38
+ const raw = question.options[i]?.preview;
39
+ if (raw && raw.length > 0) this.previewTexts.set(i, raw);
40
+ }
41
+ this.markdownCache = new Map();
42
+ }
43
+
44
+ hasAnyPreview(): boolean {
45
+ return this.previewTexts.size > 0;
46
+ }
47
+
48
+ has(optionIndex: number): boolean {
49
+ return this.previewTexts.has(optionIndex);
50
+ }
51
+
52
+ /**
53
+ * Compute the body lines for a given option at a given inner width. Width changes
54
+ * invalidate the per-Markdown render cache.
55
+ */
56
+ bodyFor(optionIndex: number, innerWidth: number): string[] {
57
+ if (this.cachedWidth !== innerWidth) {
58
+ for (const md of this.markdownCache.values()) md.invalidate();
59
+ this.cachedWidth = innerWidth;
60
+ }
61
+ const text = this.previewTexts.get(optionIndex);
62
+ if (!text) {
63
+ const placeholder = this.theme.fg("dim", t("preview.no_preview", NO_PREVIEW_TEXT));
64
+ const pad = Math.max(0, innerWidth - visibleWidth(placeholder));
65
+ return [placeholder + " ".repeat(pad)];
66
+ }
67
+ let md = this.markdownCache.get(optionIndex);
68
+ if (!md) {
69
+ md = new Markdown(text, 0, 0, this.markdownTheme);
70
+ this.markdownCache.set(optionIndex, md);
71
+ }
72
+ return stripFenceMarkers(md.render(innerWidth));
73
+ }
74
+
75
+ invalidate(): void {
76
+ for (const md of this.markdownCache.values()) md.invalidate();
77
+ this.cachedWidth = undefined;
78
+ }
79
+ }
@@ -0,0 +1,111 @@
1
+ // GENERATED — DO NOT EDIT. Source: adapter-src/pi/extensions/ask-user-question/view/components/preview/preview-block-renderer.ts
2
+ // Regenerate with: python3 scripts/build-adapters.py
3
+ import type { Theme } from "@earendil-works/pi-coding-agent";
4
+ import type { MarkdownTheme } from "@earendil-works/pi-tui";
5
+ import { t } from "../../../state/i18n-bridge.js";
6
+ import type { QuestionData } from "../../../tool/types.js";
7
+ import {
8
+ MAX_PREVIEW_HEIGHT_SIDE_BY_SIDE,
9
+ MAX_PREVIEW_HEIGHT_STACKED,
10
+ MarkdownContentCache,
11
+ NOTES_AFFORDANCE_OVERHEAD,
12
+ } from "./markdown-content-cache.js";
13
+ import {
14
+ BORDER_HORIZONTAL_OVERHEAD,
15
+ BORDER_INNER_PADDING_HORIZONTAL,
16
+ BORDER_VERTICAL_OVERHEAD,
17
+ computeBoxDimensions,
18
+ renderBorderedBox,
19
+ } from "./preview-box-renderer.js";
20
+ import type { PreviewLayoutMode } from "./preview-layout-decider.js";
21
+
22
+ /**
23
+ * Affordance text shown below the bordered preview when focused on a preview-bearing option.
24
+ * Re-exported by `preview-pane.ts` for the existing test surface.
25
+ */
26
+ export const NOTES_AFFORDANCE_TEXT = "Notes: press n to add notes";
27
+
28
+ export interface PreviewBlockRendererConfig {
29
+ question: QuestionData;
30
+ theme: Theme;
31
+ markdownTheme: MarkdownTheme;
32
+ }
33
+
34
+ /**
35
+ * Renders the bordered markdown preview block for a single question (one block per render call,
36
+ * for the option at `optionIndex`). Owns a per-question `MarkdownContentCache`.
37
+ *
38
+ * NOT a `Component` — pure render-and-measure helper consumed by `PreviewPane`. The layout mode
39
+ * is threaded as an explicit param (never re-derived from column width post-split).
40
+ *
41
+ * The affordance row is always emitted (visually empty when gated) so the preview block's row
42
+ * count is height-stable across affordance-state transitions.
43
+ */
44
+ export class PreviewBlockRenderer {
45
+ private readonly theme: Theme;
46
+ private readonly cache: MarkdownContentCache;
47
+
48
+ constructor(config: PreviewBlockRendererConfig) {
49
+ this.theme = config.theme;
50
+ this.cache = new MarkdownContentCache(config.question, config.theme, config.markdownTheme);
51
+ }
52
+
53
+ hasAnyPreview(): boolean {
54
+ return this.cache.hasAnyPreview();
55
+ }
56
+
57
+ has(optionIndex: number): boolean {
58
+ return this.cache.has(optionIndex);
59
+ }
60
+
61
+ invalidate(): void {
62
+ this.cache.invalidate();
63
+ }
64
+
65
+ /**
66
+ * Height contribution of the preview block: `BORDER_VERTICAL_OVERHEAD + contentRows +
67
+ * NOTES_AFFORDANCE_OVERHEAD`. Always returns the same value as `renderBlock(...).length`
68
+ * — the affordance overhead is constant, not gated by `focused`/`notesVisible`.
69
+ */
70
+ blockHeight(width: number, optionIndex: number, mode: PreviewLayoutMode): number {
71
+ const cap = mode === "side-by-side" ? MAX_PREVIEW_HEIGHT_SIDE_BY_SIDE : MAX_PREVIEW_HEIGHT_STACKED;
72
+ const contentBudget = Math.max(1, cap - BORDER_VERTICAL_OVERHEAD - NOTES_AFFORDANCE_OVERHEAD);
73
+ const innerWidth = Math.max(1, width - BORDER_HORIZONTAL_OVERHEAD - 2 * BORDER_INNER_PADDING_HORIZONTAL);
74
+ const rawRows = this.cache.bodyFor(optionIndex, innerWidth).length;
75
+ const contentRows = Math.min(rawRows, contentBudget);
76
+ return BORDER_VERTICAL_OVERHEAD + contentRows + NOTES_AFFORDANCE_OVERHEAD;
77
+ }
78
+
79
+ /**
80
+ * Render the full preview block at `width`: bordered box + blank separator + affordance row.
81
+ * `focused` and `notesVisible` together gate the affordance text (visible only when the
82
+ * focused option carries a preview AND notes mode is inactive). The affordance row is ALWAYS
83
+ * emitted (as an empty string when gated) so the row count is invariant.
84
+ */
85
+ renderBlock(
86
+ width: number,
87
+ optionIndex: number,
88
+ mode: PreviewLayoutMode,
89
+ focused: boolean,
90
+ notesVisible: boolean,
91
+ ): string[] {
92
+ const cap = mode === "side-by-side" ? MAX_PREVIEW_HEIGHT_SIDE_BY_SIDE : MAX_PREVIEW_HEIGHT_STACKED;
93
+ const contentBudget = Math.max(1, cap - BORDER_VERTICAL_OVERHEAD - NOTES_AFFORDANCE_OVERHEAD);
94
+ const maxInnerWidth = Math.max(1, width - BORDER_HORIZONTAL_OVERHEAD - 2 * BORDER_INNER_PADDING_HORIZONTAL);
95
+
96
+ const raw = this.cache.bodyFor(optionIndex, maxInnerWidth);
97
+ const truncated = raw.length > contentBudget;
98
+ const hidden = truncated ? raw.length - contentBudget : 0;
99
+ const contentLines = truncated ? raw.slice(0, contentBudget) : raw;
100
+
101
+ const { boxWidth } = computeBoxDimensions(contentLines, maxInnerWidth);
102
+ const colorFn = (s: string) => this.theme.fg("accent", s);
103
+ const boxedLines = renderBorderedBox(contentLines, boxWidth, colorFn, hidden);
104
+
105
+ const showAffordance = focused && !notesVisible && this.cache.has(optionIndex);
106
+ const affordance = showAffordance
107
+ ? this.theme.fg("muted", t("preview.notes_affordance", NOTES_AFFORDANCE_TEXT))
108
+ : "";
109
+ return [...boxedLines, "", affordance];
110
+ }
111
+ }
@@ -0,0 +1,88 @@
1
+ // GENERATED — DO NOT EDIT. Source: adapter-src/pi/extensions/ask-user-question/view/components/preview/preview-box-renderer.ts
2
+ // Regenerate with: python3 scripts/build-adapters.py
3
+ import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
4
+
5
+ const ANSI_SGR_RE = /\x1b\[[0-9;]*m/g;
6
+ const ANSI_OSC8_RE = /\x1b\]8;[^\x07\x1b]*(?:\x07|\x1b\\)/g;
7
+ const FENCE_MARKER_RE = /^`{3}/;
8
+
9
+ /** Top + bottom border rows consumed by `renderBorderedBox`. */
10
+ export const BORDER_VERTICAL_OVERHEAD = 2;
11
+ /** Left + right vertical bar columns (`│ ... │`) consumed by `renderBorderedBox`. */
12
+ export const BORDER_HORIZONTAL_OVERHEAD = 2;
13
+ /** Inner horizontal padding (1 col) between each border bar and content area. */
14
+ export const BORDER_INNER_PADDING_HORIZONTAL = 1;
15
+ /** Floor for the preview box's inner content width — CC parity (`PreviewBox.minWidth`). */
16
+ export const BOX_MIN_CONTENT_WIDTH = 40;
17
+
18
+ /**
19
+ * Drops fenced-code-block marker lines (` ``` ` opener/closer) from rendered markdown.
20
+ * pi-tui's Markdown emits literal opening ` ```lang ` and closing ` ``` ` lines around
21
+ * code blocks; this strip leaves only the highlighted code body. Inline code
22
+ * (`codespan`) is unaffected — pi-tui already renders it without backticks.
23
+ */
24
+ export function stripFenceMarkers(lines: readonly string[]): string[] {
25
+ return lines.filter((line) => {
26
+ const clean = line.replace(ANSI_SGR_RE, "").replace(ANSI_OSC8_RE, "");
27
+ return !FENCE_MARKER_RE.test(clean);
28
+ });
29
+ }
30
+
31
+ /**
32
+ * Wraps `lines` in a 4-sided ASCII border with 1 col of inner horizontal padding.
33
+ * Layout per content row: `│` + ` ` + content padded to `contentInner` + ` ` + `│`,
34
+ * where `contentInner = width - BORDER_HORIZONTAL_OVERHEAD - 2 * BORDER_INNER_PADDING_HORIZONTAL`.
35
+ * Top/bottom dash runs span corner-to-corner (`width - BORDER_HORIZONTAL_OVERHEAD`). When
36
+ * `hidden > 0`, the bottom-row dash run is replaced with ` ✂ ── N lines hidden ── ` (corners stay).
37
+ */
38
+ export function renderBorderedBox(
39
+ lines: readonly string[],
40
+ width: number,
41
+ colorFn: (s: string) => string,
42
+ hidden = 0,
43
+ ): string[] {
44
+ const dashSpan = Math.max(1, width - BORDER_HORIZONTAL_OVERHEAD);
45
+ const contentInner = Math.max(1, dashSpan - 2 * BORDER_INNER_PADDING_HORIZONTAL);
46
+ const pad = " ".repeat(BORDER_INNER_PADDING_HORIZONTAL);
47
+ const top = colorFn(`┌${"─".repeat(dashSpan)}┐`);
48
+ const out: string[] = [top];
49
+ for (const line of lines) {
50
+ const padded = truncateToWidth(line, contentInner, "", true);
51
+ out.push(`${colorFn("│")}${pad}${padded}${pad}${colorFn("│")}`);
52
+ }
53
+ if (hidden > 0) {
54
+ const indicator = ` ✂ ── ${hidden} lines hidden ── `;
55
+ const space = dashSpan - indicator.length;
56
+ const leftFill = "─".repeat(Math.max(0, Math.floor(space / 2)));
57
+ const rightFill = "─".repeat(Math.max(0, dashSpan - leftFill.length - indicator.length));
58
+ out.push(colorFn(`└${leftFill}${indicator}${rightFill}┘`));
59
+ } else {
60
+ out.push(colorFn(`└${"─".repeat(dashSpan)}┘`));
61
+ }
62
+ return out;
63
+ }
64
+
65
+ /**
66
+ * Compute box dimensions from content lines. Pure of args.
67
+ *
68
+ * CC parity:
69
+ * contentWidth = max(minWidth, widestRenderedLine)
70
+ * boxWidth = min(contentWidth + 4, effectiveMaxWidth)
71
+ *
72
+ * Trailing whitespace is stripped before measuring because pi-tui's
73
+ * `Markdown.render(width)` pads every line to `width`, which would otherwise force
74
+ * the box to fill the whole column allocation.
75
+ */
76
+ export function computeBoxDimensions(
77
+ contentLines: readonly string[],
78
+ maxInnerWidth: number,
79
+ ): { innerWidth: number; boxWidth: number } {
80
+ let widest = Math.min(BOX_MIN_CONTENT_WIDTH, maxInnerWidth);
81
+ for (const line of contentLines) {
82
+ const w = visibleWidth(line.replace(/\s+$/, ""));
83
+ if (w > widest) widest = w;
84
+ }
85
+ const innerWidth = Math.min(widest, maxInnerWidth);
86
+ const boxWidth = innerWidth + BORDER_HORIZONTAL_OVERHEAD + 2 * BORDER_INNER_PADDING_HORIZONTAL;
87
+ return { innerWidth, boxWidth };
88
+ }
@@ -0,0 +1,202 @@
1
+ // GENERATED — DO NOT EDIT. Source: adapter-src/pi/extensions/ask-user-question/view/components/preview/preview-layout-decider.ts
2
+ // Regenerate with: python3 scripts/build-adapters.py
3
+ import { visibleWidth } from "@earendil-works/pi-tui";
4
+ import type { QuestionData } from "../../../tool/types.js";
5
+ import type { WrappingSelectItem } from "../wrapping-select.js";
6
+ import { BORDER_HORIZONTAL_OVERHEAD, BORDER_INNER_PADDING_HORIZONTAL } from "./preview-box-renderer.js";
7
+
8
+ /** Min terminal/pane width for the side-by-side layout to engage. */
9
+ export const PREVIEW_MIN_WIDTH = 100;
10
+ /** Visual gap between options column and preview column in side-by-side. */
11
+ export const PREVIEW_COLUMN_GAP = 2;
12
+ /** 1 col padding inside the preview column (between gap and `│`). */
13
+ export const PREVIEW_PADDING_LEFT = 1;
14
+ /** Empty rows between options and preview blocks in stacked (narrow) layout. */
15
+ export const STACKED_GAP_ROWS = 1;
16
+
17
+ /** Floor for the adaptive left column width — prevents collapse on short labels. */
18
+ export const MIN_LEFT = 30;
19
+ /** Ceiling ratio: left column never exceeds this fraction of pane width. */
20
+ export const MAX_LEFT_RATIO = 0.5;
21
+ /** Floor for the preview column width — prevents right-side collapse on narrow terminals. */
22
+ export const MIN_PREVIEW_WIDTH = 45;
23
+ /** visibleWidth(" ✔") = 2 (space + ✔ codepoint). Reserved on the longest-label measurement
24
+ * so a confirmed row never gets truncated when MIN_LEFT clamps the column. */
25
+ export const CONFIRMED_OVERHEAD = 2;
26
+
27
+ export type PreviewLayoutMode = "side-by-side" | "stacked";
28
+
29
+ /**
30
+ * Decide layout mode from terminal + pane widths. Pure of inputs.
31
+ *
32
+ * The terminal-width gate is the AND check from the previous `preview-pane.ts` —
33
+ * lifted here so the decision is computed ONCE per render and threaded explicitly
34
+ * through `previewBlockHeight`. Removes the bug class where `previewBlockHeight`
35
+ * re-derived `sideBySide` from a column width (already < pane width post-split),
36
+ * capping height too short.
37
+ */
38
+ export function decideLayout(terminalWidth: number, paneWidth: number): PreviewLayoutMode {
39
+ return terminalWidth >= PREVIEW_MIN_WIDTH && paneWidth >= PREVIEW_MIN_WIDTH ? "side-by-side" : "stacked";
40
+ }
41
+
42
+ /**
43
+ * Compute the adaptive left column width from option labels.
44
+ * Pure function — deterministic for a given (items, totalForNumbering, paneWidth).
45
+ *
46
+ * Pipeline:
47
+ * 1. Measure: longest visible label width + prefix overhead + confirmed-mark overhead
48
+ * 2. Clamp: floor MIN_LEFT, ceiling paneWidth * MAX_LEFT_RATIO
49
+ * 3. Safety net: never exceed available = paneWidth - GAP - MIN_PREVIEW_WIDTH
50
+ */
51
+ export function adaptiveLeftWidth(
52
+ items: readonly WrappingSelectItem[],
53
+ totalForNumbering: number,
54
+ paneWidth: number,
55
+ ): number {
56
+ const prefixW = String(Math.max(1, totalForNumbering)).length + 4; // digits + "❯ " + ". "
57
+ const confirmedOverhead = CONFIRMED_OVERHEAD; // visibleWidth(" ✔") = 2 (space + ✔ codepoint)
58
+ let maxLabel = 0;
59
+ for (const item of items) {
60
+ const w = visibleWidth(item.label);
61
+ if (w > maxLabel) maxLabel = w;
62
+ }
63
+ const desired = maxLabel + prefixW + confirmedOverhead;
64
+ const ratioCapped = Math.min(desired, Math.floor(paneWidth * MAX_LEFT_RATIO));
65
+ const available = paneWidth - PREVIEW_COLUMN_GAP - MIN_PREVIEW_WIDTH;
66
+ return Math.max(MIN_LEFT, Math.min(ratioCapped, Math.max(1, available)));
67
+ }
68
+
69
+ /**
70
+ * Cross-tab maximum left-column width. Aggregates `adaptiveLeftWidth` over every tab
71
+ * and returns the widest result, so the options column stays stable on tab switch.
72
+ *
73
+ * Pure function — `tabs.length` MUST equal `itemsByTab.length`. Numbering uses
74
+ * `items.length` for every tab (the chat row slot that once added +1 on single-select
75
+ * has been removed).
76
+ * Floor is `MIN_LEFT` so an all-empty input still produces a usable column.
77
+ */
78
+ export function crossTabMaxLeftWidth(
79
+ tabs: ReadonlyArray<{ multiSelect?: boolean }>,
80
+ itemsByTab: ReadonlyArray<readonly WrappingSelectItem[]>,
81
+ paneWidth: number,
82
+ ): number {
83
+ let max = MIN_LEFT;
84
+ for (let i = 0; i < tabs.length; i++) {
85
+ const items = itemsByTab[i] ?? [];
86
+ const totalForNumbering = items.length;
87
+ const tabWidth = adaptiveLeftWidth(items, totalForNumbering, paneWidth);
88
+ if (tabWidth > max) max = tabWidth;
89
+ }
90
+ return max;
91
+ }
92
+
93
+ /**
94
+ * Source-line probe: measures the widest source line across all options' previews.
95
+ * Returns 0 when no option carries a preview.
96
+ *
97
+ * V1 heuristic — works well for tree/table/heading/list content where source-line
98
+ * width ≈ rendered width. Paragraphs overstate (source width "wants" the full pane);
99
+ * the worst case is "donation does nothing useful" — fallback to the label-driven path.
100
+ * Upgrade path: replace with a render-width probe that invokes Markdown at a probe width.
101
+ *
102
+ * Pure function — O(total chars) per question; no Markdown invocation, no cache interaction.
103
+ */
104
+ export function previewSourceWidth(question: QuestionData): number {
105
+ let max = 0;
106
+ for (const option of question.options) {
107
+ const text = option.preview;
108
+ if (!text) continue;
109
+ for (const line of text.split("\n")) {
110
+ const w = visibleWidth(line);
111
+ if (w > max) max = w;
112
+ }
113
+ }
114
+ return max;
115
+ }
116
+
117
+ /**
118
+ * Cross-tab/cross-option preview budget. Iterates all questions, computes each question's
119
+ * preview appetite via `previewSourceWidth`, adds box + padding overhead (5 cols), and
120
+ * returns the widest result. Floor is `MIN_PREVIEW_WIDTH` so a previewless question still
121
+ * reserves a usable column. Ceiling ensures the left column retains its `MIN_LEFT` floor.
122
+ *
123
+ * Pure function — same cross-tab max pattern as `crossTabMaxLeftWidth`.
124
+ */
125
+ export function crossTabPreviewBudget(questions: readonly QuestionData[], paneWidth: number): number {
126
+ let max = MIN_PREVIEW_WIDTH;
127
+ for (const question of questions) {
128
+ const rawWidth = previewSourceWidth(question);
129
+ const capped = Math.min(rawWidth, paneWidth - PREVIEW_COLUMN_GAP - MIN_LEFT);
130
+ const budget = capped + BORDER_HORIZONTAL_OVERHEAD + 2 * BORDER_INNER_PADDING_HORIZONTAL + PREVIEW_PADDING_LEFT;
131
+ if (budget > max) max = budget;
132
+ }
133
+ return max;
134
+ }
135
+
136
+ /**
137
+ * Cross-tab left-column width with slack donation. Combines the label-driven width
138
+ * (from `crossTabMaxLeftWidth`) with the slack donated by narrow previews.
139
+ *
140
+ * Pipeline:
141
+ * 1. `labelDriven` = `crossTabMaxLeftWidth(tabs, itemsByTab, paneWidth)`
142
+ * 2. `previewBudget` = `crossTabPreviewBudget(questions, paneWidth)`
143
+ * 3. `slackDonation` = `paneWidth − GAP − previewBudget`
144
+ * 4. Return `min(max(labelDriven, slackDonation), ceiling)` where `ceiling = paneWidth − GAP − MIN_PREVIEW_WIDTH`
145
+ *
146
+ * Invariants:
147
+ * - Floor: result ≥ MIN_LEFT (labelDriven ≥ MIN_LEFT)
148
+ * - Preview floor: right column ≥ MIN_PREVIEW_WIDTH (ceiling enforces this)
149
+ * - Cross-tab stability: both reductions are tab-independent
150
+ * - Determinism: pure of (questions, itemsByTab, paneWidth)
151
+ *
152
+ * `crossTabMaxLeftWidth` is NOT replaced — it continues to exist as the primitive.
153
+ * `MAX_LEFT_RATIO` caps the label-driven path inside `adaptiveLeftWidth`; donation
154
+ * operates above the cap when preview slack is available.
155
+ */
156
+ export function crossTabLeftWidthWithDonation(
157
+ tabs: ReadonlyArray<{ multiSelect?: boolean }>,
158
+ itemsByTab: ReadonlyArray<readonly WrappingSelectItem[]>,
159
+ questions: readonly QuestionData[],
160
+ paneWidth: number,
161
+ ): number {
162
+ const labelDriven = crossTabMaxLeftWidth(tabs, itemsByTab, paneWidth);
163
+ // Compact-content guard: labels at MIN_LEFT fit below the floor, so widening
164
+ // the column would only inject dead space between the option list and the
165
+ // preview box. Skip donation and preserve the compact intent.
166
+ if (labelDriven <= MIN_LEFT) return labelDriven;
167
+ const previewBudget = crossTabPreviewBudget(questions, paneWidth);
168
+ const slackDonation = paneWidth - PREVIEW_COLUMN_GAP - previewBudget;
169
+ const ceiling = paneWidth - PREVIEW_COLUMN_GAP - MIN_PREVIEW_WIDTH;
170
+ return Math.min(Math.max(labelDriven, slackDonation), Math.max(1, ceiling));
171
+ }
172
+
173
+ /**
174
+ * Width allocation for side-by-side mode.
175
+ * `adaptiveLeft` is the pre-computed left column width (from `adaptiveLeftWidth`,
176
+ * cross-tab aggregated). The Math.max(1, ...) calls keep both columns >= 1 col on
177
+ * extreme inputs.
178
+ */
179
+ export function columnWidths(
180
+ paneWidth: number,
181
+ adaptiveLeft: number,
182
+ ): { leftWidth: number; rightWidth: number; gap: number } {
183
+ const gap = PREVIEW_COLUMN_GAP;
184
+ const leftWidth = Math.min(adaptiveLeft, Math.max(1, paneWidth - gap - 1));
185
+ const rightWidth = Math.max(1, paneWidth - leftWidth - gap);
186
+ return { leftWidth, rightWidth, gap };
187
+ }
188
+
189
+ /**
190
+ * Returns the widths actually passed to `options.render` and `previewLines` inside
191
+ * `render()`. Stacked uses the full pane width for both; side-by-side splits via
192
+ * `columnWidths`, with the preview column offset by `PREVIEW_PADDING_LEFT`.
193
+ */
194
+ export function bodyWidths(
195
+ paneWidth: number,
196
+ mode: PreviewLayoutMode,
197
+ adaptiveLeft: number,
198
+ ): { optionsWidth: number; previewWidth: number } {
199
+ if (mode === "stacked") return { optionsWidth: paneWidth, previewWidth: paneWidth };
200
+ const { leftWidth, rightWidth } = columnWidths(paneWidth, adaptiveLeft);
201
+ return { optionsWidth: leftWidth, previewWidth: Math.max(1, rightWidth - PREVIEW_PADDING_LEFT) };
202
+ }