@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,147 @@
1
+ // GENERATED — DO NOT EDIT. Source: adapter-src/pi/extensions/ask-user-question/tool/types.ts
2
+ // Regenerate with: python3 scripts/build-adapters.py
3
+ import { type Static, Type } from "typebox";
4
+ import { LABELS_BY_KIND, ROW_INTENT_META } from "../state/row-intent.js";
5
+
6
+ export const MAX_QUESTIONS = 4;
7
+ export const MIN_OPTIONS = 2;
8
+ export const MAX_OPTIONS = 4;
9
+ export const MAX_HEADER_LENGTH = 16;
10
+ export const MAX_LABEL_LENGTH = 60;
11
+
12
+ /**
13
+ * User-facing labels for the three runtime sentinel rows, keyed by their
14
+ * `WrappingSelectItem.kind` discriminator. Sourced from
15
+ * `ROW_INTENT_META` via `LABELS_BY_KIND` (`row-intent.ts`) — single source of
16
+ * truth. Adding a new sentinel requires extending the `WrappingSelectItem`
17
+ * union AND adding an entry to `ROW_INTENT_META`; this map then auto-extends.
18
+ */
19
+ export const SENTINEL_LABELS = LABELS_BY_KIND;
20
+
21
+ export type SentinelKind = keyof typeof SENTINEL_LABELS;
22
+ export type SentinelLabel = (typeof SENTINEL_LABELS)[SentinelKind];
23
+
24
+ /**
25
+ * Labels reserved for Pi-internal sentinels — authoring an option with any
26
+ * of these labels triggers the `reserved_label` runtime guard. Two of the
27
+ * three come from `ROW_INTENT_META` (the runtime kinds); `"Other"` is
28
+ * reserved for CC parity only (the model is conditioned to reach for
29
+ * "Other" in CC; we reject it so the runtime sentinel is the single source
30
+ * of truth) and has no runtime kind.
31
+ *
32
+ * Reserved unconditionally — every question mode rejects these labels, even
33
+ * when a given runtime sentinel is not appended in that mode.
34
+ *
35
+ * Order is pinned by `types.test.ts:292` — keep the explicit
36
+ * `["Other", other, next]` literal so consumers using
37
+ * `RESERVED_LABELS[i]` indexing or `Set` membership see no behavior change.
38
+ */
39
+ export const RESERVED_LABELS = ["Other", ROW_INTENT_META.other.label, ROW_INTENT_META.next.label] as const;
40
+ export type ReservedLabel = (typeof RESERVED_LABELS)[number];
41
+
42
+ export const OptionSchema = Type.Object({
43
+ label: Type.String({
44
+ maxLength: MAX_LABEL_LENGTH,
45
+ description: `MAX ${MAX_LABEL_LENGTH} CHARACTERS — hard limit, requests over the limit are rejected. The display text for this option that the user will see and select. Should be concise (1-5 words) and clearly describe the choice.`,
46
+ }),
47
+ description: Type.String({
48
+ description:
49
+ "Explanation of what this option means or what will happen if chosen. Useful for providing context about trade-offs or implications.",
50
+ }),
51
+ preview: Type.Optional(
52
+ Type.String({
53
+ description:
54
+ "Optional preview content rendered when this option is focused. Use for mockups, code snippets, or visual comparisons that help users compare options. See the tool description for the expected content format.",
55
+ }),
56
+ ),
57
+ });
58
+
59
+ export const QuestionSchema = Type.Object({
60
+ question: Type.String({
61
+ description:
62
+ 'The complete question to ask the user. Should be clear, specific, and end with a question mark. Example: "Which library should we use for date formatting?" If multiSelect is true, phrase it accordingly, e.g. "Which features do you want to enable?"',
63
+ }),
64
+ header: Type.String({
65
+ maxLength: MAX_HEADER_LENGTH,
66
+ description: `MAX ${MAX_HEADER_LENGTH} CHARACTERS — hard limit, requests over the limit are rejected. Very short chip/tag shown next to the question. Examples: "Auth method", "Library", "Approach".`,
67
+ }),
68
+ options: Type.Array(OptionSchema, {
69
+ minItems: MIN_OPTIONS,
70
+ maxItems: MAX_OPTIONS,
71
+ description:
72
+ "The available choices for this question. Must have 2-4 options. Each option should be a distinct, mutually exclusive choice (unless multiSelect is enabled). The 'Type something.' row is appended automatically — do NOT author it.",
73
+ }),
74
+ multiSelect: Type.Optional(
75
+ Type.Boolean({
76
+ default: false,
77
+ description:
78
+ "Set to true to allow the user to select multiple options instead of just one. Use when choices are not mutually exclusive.",
79
+ }),
80
+ ),
81
+ });
82
+
83
+ export const QuestionsSchema = Type.Array(QuestionSchema, {
84
+ minItems: 1,
85
+ maxItems: MAX_QUESTIONS,
86
+ description: "Questions to ask the user (1-4 questions)",
87
+ });
88
+
89
+ export const QuestionParamsSchema = Type.Object({
90
+ questions: QuestionsSchema,
91
+ });
92
+
93
+ export type OptionData = Static<typeof OptionSchema>;
94
+ export type QuestionData = Static<typeof QuestionSchema>;
95
+ export type QuestionParams = Static<typeof QuestionParamsSchema>;
96
+
97
+ /**
98
+ * Answer-intent discriminated union. `kind` is the single discriminator —
99
+ * pre-1.0.3 boolean flags have been removed (see `banned-flags.test.ts`).
100
+ * Mirrors the row-side `WrappingSelectItem.kind` vocabulary where possible;
101
+ * `multi` is the multi-select variant (no row-side analog).
102
+ *
103
+ * Variant semantics:
104
+ * - `option`: user picked one of the author-defined options. `answer` is the option's label.
105
+ * - `custom`: user typed free-text via the "Type something." row. `answer` is the typed text or null.
106
+ * - `multi`: user committed multi-select choices. `selected` carries chosen labels; `answer` is null.
107
+ */
108
+ export interface QuestionAnswer {
109
+ questionIndex: number;
110
+ question: string;
111
+ kind: "option" | "custom" | "multi";
112
+ answer: string | null;
113
+ selected?: string[];
114
+ notes?: string;
115
+ /**
116
+ * Markdown text from the matched option's `preview` field, populated only
117
+ * when the user lands on a single-select option carrying a `preview`.
118
+ * Used by `buildQuestionnaireResponse` to echo `selected preview: <preview>`
119
+ * into the LLM-facing envelope. Undefined for multi-select and custom-text
120
+ * (`kind: "custom"`) answers.
121
+ */
122
+ preview?: string;
123
+ }
124
+
125
+ export type QuestionnaireError =
126
+ | "no_ui"
127
+ | "no_custom_ui"
128
+ | "no_questions"
129
+ | "empty_options"
130
+ | "too_many_questions"
131
+ | "duplicate_question"
132
+ | "duplicate_option_label"
133
+ | "reserved_label"
134
+ | "session_load_failed"
135
+ | "stale_module_cache";
136
+
137
+ export interface QuestionnaireResult {
138
+ answers: QuestionAnswer[];
139
+ cancelled: boolean;
140
+ error?: QuestionnaireError;
141
+ }
142
+
143
+ export function isQuestionnaireResult(value: unknown): value is QuestionnaireResult {
144
+ if (!value || typeof value !== "object") return false;
145
+ const v = value as Record<string, unknown>;
146
+ return Array.isArray(v.answers) && typeof v.cancelled === "boolean";
147
+ }
@@ -0,0 +1,58 @@
1
+ // GENERATED — DO NOT EDIT. Source: adapter-src/pi/extensions/ask-user-question/tool/validate-questionnaire.ts
2
+ // Regenerate with: python3 scripts/build-adapters.py
3
+ import { MAX_QUESTIONS, MIN_OPTIONS, type QuestionnaireError, type QuestionParams, RESERVED_LABELS } from "./types.js";
4
+
5
+ export const ERROR_NO_QUESTIONS = "Error: At least one question is required";
6
+ export const ERROR_TOO_MANY_QUESTIONS = `Error: At most ${MAX_QUESTIONS} questions are allowed per invocation`;
7
+ export const ERROR_DUPLICATE_QUESTION = "Error: Question text must be unique within an invocation";
8
+ export const ERROR_TOO_FEW_OPTIONS = `Error: Each question requires at least ${MIN_OPTIONS} options`;
9
+ export const ERROR_RESERVED_LABEL = `Error: Option label is reserved (${RESERVED_LABELS.join(", ")})`;
10
+ export const ERROR_DUPLICATE_OPTION_LABEL = "Error: Option labels must be unique within a question";
11
+
12
+ const RESERVED_LABEL_SET: ReadonlySet<string> = new Set(RESERVED_LABELS);
13
+
14
+ export type ValidationResult = { ok: true } | { ok: false; error: QuestionnaireError; message: string };
15
+
16
+ /**
17
+ * Pure runtime validator for `QuestionParams`. Covers every guard except
18
+ * `no_ui` (which depends on `ctx.hasUI` and stays inline at the call site).
19
+ * `reserved_label` MUST short-circuit before `duplicate_option_label`.
20
+ */
21
+ export function validateQuestionnaire(typed: QuestionParams): ValidationResult {
22
+ if (typed.questions.length === 0) {
23
+ return { ok: false, error: "no_questions", message: ERROR_NO_QUESTIONS };
24
+ }
25
+ if (typed.questions.length > MAX_QUESTIONS) {
26
+ return { ok: false, error: "too_many_questions", message: ERROR_TOO_MANY_QUESTIONS };
27
+ }
28
+
29
+ const seenQuestions = new Set<string>();
30
+ for (const q of typed.questions) {
31
+ if (seenQuestions.has(q.question)) {
32
+ return { ok: false, error: "duplicate_question", message: ERROR_DUPLICATE_QUESTION };
33
+ }
34
+ seenQuestions.add(q.question);
35
+ }
36
+
37
+ for (const q of typed.questions) {
38
+ if (q.options.length < MIN_OPTIONS) {
39
+ return { ok: false, error: "empty_options", message: ERROR_TOO_FEW_OPTIONS };
40
+ }
41
+ const seenLabels = new Set<string>();
42
+ for (const o of q.options) {
43
+ if (RESERVED_LABEL_SET.has(o.label)) {
44
+ return { ok: false, error: "reserved_label", message: ERROR_RESERVED_LABEL };
45
+ }
46
+ if (seenLabels.has(o.label)) {
47
+ return {
48
+ ok: false,
49
+ error: "duplicate_option_label",
50
+ message: ERROR_DUPLICATE_OPTION_LABEL,
51
+ };
52
+ }
53
+ seenLabels.add(o.label);
54
+ }
55
+ }
56
+
57
+ return { ok: true };
58
+ }
@@ -0,0 +1,65 @@
1
+ // GENERATED — DO NOT EDIT. Source: adapter-src/pi/extensions/ask-user-question/vendor-config-shim.ts
2
+ // Regenerate with: python3 scripts/build-adapters.py
3
+ /**
4
+ * FEATURE-FORGE VENDOR PATCH — local stand-in for `@juicesharp/rpiv-config`.
5
+ *
6
+ * Upstream `config.ts` imports three symbols from `@juicesharp/rpiv-config`
7
+ * (316 LOC, its only hard dependency). Feature-forge vendors this package to
8
+ * keep `adapters/pi/` dependency-free, so those three symbols are supplied
9
+ * here instead:
10
+ *
11
+ * - `GuidanceFields` / `validateGuidanceFields` — copied verbatim from
12
+ * rpiv-config@2.1.0 `config.ts:180-221`.
13
+ * - `loadJsonConfigWithLegacyFallback` — upstream reads user JSON config from
14
+ * `~/.config/rpiv-ask-user-question/config.json` so users can override the
15
+ * tool's LLM-facing guidance. Feature-forge pins its own guidance instead:
16
+ * the skills are written against these exact strings, so a user override
17
+ * would silently change how the pipeline's interview stages behave. This
18
+ * returns the fixed feature-forge config and never touches the filesystem.
19
+ */
20
+
21
+ export interface GuidanceFields {
22
+ promptSnippet?: string;
23
+ promptGuidelines?: string[];
24
+ }
25
+
26
+ /** Verbatim from rpiv-config@2.1.0 (config.ts:207). */
27
+ export function validateGuidanceFields(fields: unknown): GuidanceFields {
28
+ if (!fields || typeof fields !== "object") return {};
29
+ const g = fields as Record<string, unknown>;
30
+ const result: GuidanceFields = {};
31
+ if (typeof g.promptSnippet === "string" && g.promptSnippet.length > 0) {
32
+ result.promptSnippet = g.promptSnippet;
33
+ }
34
+ if (
35
+ Array.isArray(g.promptGuidelines) &&
36
+ g.promptGuidelines.length > 0 &&
37
+ g.promptGuidelines.every((s) => typeof s === "string" && s.length > 0)
38
+ ) {
39
+ result.promptGuidelines = g.promptGuidelines;
40
+ }
41
+ return result;
42
+ }
43
+
44
+ /**
45
+ * Feature-forge's pinned guidance, replacing upstream's user-config load.
46
+ *
47
+ * Carried over from `adapter-src/pi/ask-user-question.ts` with one wording fix:
48
+ * upstream appends a `Type something.` row rather than an `Other` option, and
49
+ * reserves the literal label `Other`, so the guideline names the behaviour
50
+ * rather than the Claude label.
51
+ */
52
+ const FEATURE_FORGE_CONFIG = {
53
+ guidance: {
54
+ promptSnippet: "Ask the user structured multiple-choice questions and return Claude-shaped answers.",
55
+ promptGuidelines: [
56
+ "Use AskUserQuestion only for genuine user decisions or requirements clarification.",
57
+ "AskUserQuestion accepts 1-4 questions with 2-4 options each; the UI appends a custom free-text row automatically — never author an option labelled \"Other\".",
58
+ "Use AskUserQuestion multiSelect only when several options can validly apply together.",
59
+ ],
60
+ },
61
+ };
62
+
63
+ export function loadJsonConfigWithLegacyFallback<T>(_name: string, _file: string = "config.json"): T {
64
+ return FEATURE_FORGE_CONFIG as T;
65
+ }
@@ -0,0 +1,47 @@
1
+ // GENERATED — DO NOT EDIT. Source: adapter-src/pi/extensions/ask-user-question/view/component-binding.ts
2
+ // Regenerate with: python3 scripts/build-adapters.py
3
+ import type {
4
+ BindingContext,
5
+ GlobalSelector,
6
+ PerTabBindingContext,
7
+ PerTabSelector,
8
+ } from "../state/selectors/contract.js";
9
+ import type { QuestionnaireState } from "../state/state.js";
10
+ import type { StatefulView } from "./stateful-view.js";
11
+ import type { TabComponents } from "./tab-components.js";
12
+
13
+ export interface ComponentBinding<P> {
14
+ readonly component: StatefulView<P>;
15
+ readonly select: GlobalSelector<P>;
16
+ }
17
+
18
+ export interface PerTabBinding<P> {
19
+ readonly resolve: (tab: TabComponents) => StatefulView<P> | undefined;
20
+ readonly select: PerTabSelector<P>;
21
+ readonly predicate?: PerTabSelector<boolean>;
22
+ }
23
+
24
+ export interface BoundGlobalBinding {
25
+ apply(state: QuestionnaireState, ctx: BindingContext): void;
26
+ invalidate(): void;
27
+ }
28
+
29
+ export interface BoundPerTabBinding {
30
+ apply(state: QuestionnaireState, ctx: PerTabBindingContext): void;
31
+ }
32
+
33
+ export function globalBinding<P>(spec: ComponentBinding<P>): BoundGlobalBinding {
34
+ return {
35
+ apply: (state, ctx) => spec.component.setProps(spec.select(state, ctx)),
36
+ invalidate: () => spec.component.invalidate(),
37
+ };
38
+ }
39
+
40
+ export function perTabBinding<P>(spec: PerTabBinding<P>): BoundPerTabBinding {
41
+ return {
42
+ apply: (state, ctx) => {
43
+ if (spec.predicate && !spec.predicate(state, ctx)) return;
44
+ spec.resolve(ctx.tab)?.setProps(spec.select(state, ctx));
45
+ },
46
+ };
47
+ }
@@ -0,0 +1,98 @@
1
+ // GENERATED — DO NOT EDIT. Source: adapter-src/pi/extensions/ask-user-question/view/components/inline-input.ts
2
+ // Regenerate with: python3 scripts/build-adapters.py
3
+ import { CURSOR_MARKER, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@earendil-works/pi-tui";
4
+
5
+ // Grapheme-aware extraction at the cursor: pi-tui's Input advances `cursor` by
6
+ // grapheme-cluster code-unit length, so the cursor can land between code units of
7
+ // one cluster (emoji, ZWJ, combining marks). Single-code-unit slicing would split
8
+ // the cluster across the SGR 7/27 boundary. Moved here from wrapping-select.ts so
9
+ // both the single-select (wrap) and multi-select (truncate-to-one-line) inline
10
+ // inputs share one cursor-building core.
11
+ const graphemeSegmenter = new Intl.Segmenter(undefined, { granularity: "grapheme" });
12
+
13
+ export interface RenderInlineInputOptions {
14
+ /** Live inline-input buffer. */
15
+ buffer: string;
16
+ /** Cursor offset; `undefined` / out-of-range → end-of-buffer fallback. */
17
+ cursorOffset: number | undefined;
18
+ /** Prefix for the first emitted line (e.g. `❯ 4. `). */
19
+ rowPrefix: string;
20
+ /** Prefix for continuation lines (whitespace of equal visible width). */
21
+ continuationPrefix: string;
22
+ /** Visible columns available for the buffer content (width − prefix width). */
23
+ contentWidth: number;
24
+ /** Per-line styling (single-select: `theme.selectedText`; multi-select: accent+bold). */
25
+ selectedText: (text: string) => string;
26
+ /**
27
+ * `true` (single-select): wrap across lines at `contentWidth` (byte-identical to the
28
+ * pre-extraction wrapping-select behavior).
29
+ * `false` (multi-select): collapse to ONE line — truncate the plain buffer to
30
+ * `contentWidth` with `…` when the cursor-marked content would overflow, keeping the
31
+ * dialog height state-independent. The cursor is clipped past the visible window
32
+ * (accepted trade): when the cursor-marked content fits it is rendered in full.
33
+ */
34
+ multiline: boolean;
35
+ }
36
+
37
+ /**
38
+ * Resolve the cursor offset, falling back to end-of-buffer for `undefined`/out-of-range.
39
+ * Mirrors the original wrapping-select.resolveOffset exactly.
40
+ */
41
+ function resolveCursorOffset(buffer: string, requested: number | undefined): number {
42
+ if (requested !== undefined && requested >= 0 && requested <= buffer.length) return requested;
43
+ return buffer.length;
44
+ }
45
+
46
+ /**
47
+ * Build the cursor-marked raw string for the whole buffer: `before | CURSOR_MARKER |
48
+ * SGR-7 reverse-video cell | SGR-27 | after`. The cell UNDER the cursor is the single
49
+ * grapheme at the offset (or U+00A0 NBSP at end-of-buffer / on a literal space — NBSP is
50
+ * wrap-safe where a literal space would tokenize as a wrap break). Zero characters shift;
51
+ * the column under the cursor inverts. `CURSOR_MARKER` is zero-width so wrap/truncate math
52
+ * is preserved.
53
+ */
54
+ function buildCursorRaw(buffer: string, offset: number): string {
55
+ const before = buffer.slice(0, offset);
56
+ const [firstGrapheme] = graphemeSegmenter.segment(buffer.slice(offset));
57
+ const rawAt = firstGrapheme ? firstGrapheme.segment : "";
58
+ // NBSP (U+00A0) fallback: visually identical to a space, wrap-safe.
59
+ const atCursor = rawAt === "" || rawAt === " " ? "\xa0" : rawAt;
60
+ const after = buffer.slice(offset + rawAt.length);
61
+ return `${before}${CURSOR_MARKER}\x1b[7m${atCursor}\x1b[27m${after}`;
62
+ }
63
+
64
+ /**
65
+ * Render the inline-input row. `multiline: true` wraps (single-select, byte-identical to
66
+ * the pre-extraction output); `multiline: false` collapses to a single line.
67
+ *
68
+ * Cursor visualization follows the standard TUI input-widget pattern (ECMA-48 SGR 7
69
+ * reverse-video on the cell AT the cursor, not an inserted glyph) — same approach used by
70
+ * pi-tui Input.render, ink-text-input, terkelg/prompts, ratatui's user-input example.
71
+ */
72
+ export function renderInlineInputRow(opts: RenderInlineInputOptions): string[] {
73
+ const { buffer, cursorOffset, rowPrefix, continuationPrefix, contentWidth, selectedText, multiline } = opts;
74
+ const offset = resolveCursorOffset(buffer, cursorOffset);
75
+
76
+ if (multiline) {
77
+ // Single-select: wrap at contentWidth. Byte-identical to the original
78
+ // wrapping-select.renderInlineInputRow output (same raw, same wrapTextWithAnsi,
79
+ // same prefix/selectedText per line).
80
+ const raw = buildCursorRaw(buffer, offset);
81
+ const wrapped = wrapTextWithAnsi(raw, contentWidth);
82
+ return wrapped.map((segment, index) => {
83
+ const prefix = index === 0 ? rowPrefix : continuationPrefix;
84
+ return selectedText(`${prefix}${segment}`);
85
+ });
86
+ }
87
+
88
+ // Multi-select: single line. Build the cursor markup on the full buffer; if it fits
89
+ // contentWidth, emit it as one line. If it overflows, fall back to truncating the PLAIN
90
+ // buffer (ANSI-safe — never cut a CURSOR_MARKER/SGR sequence) with `…` and clip the
91
+ // cursor. This keeps the row at exactly one line so naturalHeight stays state-independent.
92
+ const cursorRaw = buildCursorRaw(buffer, offset);
93
+ if (visibleWidth(cursorRaw) <= contentWidth) {
94
+ return [selectedText(`${rowPrefix}${cursorRaw}`)];
95
+ }
96
+ const clipped = truncateToWidth(buffer, contentWidth, "…");
97
+ return [selectedText(`${rowPrefix}${clipped}`)];
98
+ }
@@ -0,0 +1,193 @@
1
+ // GENERATED — DO NOT EDIT. Source: adapter-src/pi/extensions/ask-user-question/view/components/multi-select-view.ts
2
+ // Regenerate with: python3 scripts/build-adapters.py
3
+ import type { Theme } from "@earendil-works/pi-coding-agent";
4
+ import { truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@earendil-works/pi-tui";
5
+ import { displayLabel } from "../../state/i18n-bridge.js";
6
+ import type { QuestionData } from "../../tool/types.js";
7
+ import type { StatefulView } from "../stateful-view.js";
8
+ import { renderInlineInputRow } from "./inline-input.js";
9
+
10
+ const ACTIVE_POINTER = "❯ ";
11
+ const INACTIVE_POINTER = " ";
12
+ const CHECKED = "[✔]";
13
+ const UNCHECKED = "[ ]";
14
+ const NUMBER_SEPARATOR = ". ";
15
+ const BOX_LABEL_GAP = " ";
16
+ // CC parity: description continuation indents to col 2 (past the pointer slot), NOT to the
17
+ // full prefix column. Wrap width still uses prefixVisibleWidth so naturalHeight matches render.
18
+ const CONTINUATION_INDENT = " ";
19
+
20
+ export const MULTI_SUBMIT_LABEL = "Submit";
21
+
22
+ export interface MultiSelectOtherRowProps {
23
+ /** The "Type something." row is the focused row (optionIndex === options.length). */
24
+ active: boolean;
25
+ /** `state.inputMode` — true once the row has focus and keystrokes append to the buffer. */
26
+ inputMode: boolean;
27
+ /** Live inline-input buffer (read from `runtime.inputBuffer` / `ctx.inputBuffer`). */
28
+ inputBuffer: string;
29
+ inputCursorOffset: number | undefined;
30
+ }
31
+
32
+ export interface MultiSelectViewProps {
33
+ rows: ReadonlyArray<{ checked: boolean; active: boolean }>;
34
+ other: MultiSelectOtherRowProps;
35
+ nextActive: boolean;
36
+ nextLabel: string;
37
+ }
38
+
39
+ /**
40
+ * Renders the multi-select option list (one row per option — pointer + checkbox + label —
41
+ * plus zero or more wrapped continuation lines per description).
42
+ *
43
+ * `naturalHeight(width)` is state-INDEPENDENT (depends only on theme glyph widths,
44
+ * question.options, and width) so the host can compute a stable globalContentHeight
45
+ * without rendering. `naturalHeight(w) === render(w).length` for every props.
46
+ *
47
+ * `setProps(props)` is a pure field reassignment — no render, no invalidate side effects.
48
+ */
49
+ export class MultiSelectView implements StatefulView<MultiSelectViewProps> {
50
+ private props: MultiSelectViewProps;
51
+
52
+ constructor(
53
+ private readonly theme: Theme,
54
+ private readonly question: QuestionData,
55
+ ) {
56
+ this.props = {
57
+ rows: [],
58
+ other: { active: false, inputMode: false, inputBuffer: "", inputCursorOffset: undefined },
59
+ nextActive: false,
60
+ nextLabel: displayLabel("next"),
61
+ };
62
+ }
63
+
64
+ setProps(props: MultiSelectViewProps): void {
65
+ this.props = props;
66
+ }
67
+
68
+ handleInput(_data: string): void {}
69
+
70
+ invalidate(): void {}
71
+
72
+ render(width: number): string[] {
73
+ const lines: string[] = [];
74
+ const prefixWidth = this.prefixVisibleWidth();
75
+ const contentWidth = Math.max(1, width - prefixWidth);
76
+ const numberWidth = String(Math.max(1, this.question.options.length + 1)).length;
77
+ for (let i = 0; i < this.question.options.length; i++) {
78
+ const opt = this.question.options[i];
79
+ const row = this.props.rows[i];
80
+ if (!opt || !row) continue;
81
+ const pointer = row.active ? this.theme.fg("accent", ACTIVE_POINTER) : INACTIVE_POINTER;
82
+ // Checked uses the same `accent` hue as the active-row label so checked rows read
83
+ // as "selected" rather than "success" — matches the visual rhythm of the rest of
84
+ // the dialog (active pointer, label, picker rows are all accent).
85
+ const box = row.checked ? this.theme.fg("accent", CHECKED) : this.theme.fg("muted", UNCHECKED);
86
+ const label = truncateToWidth(opt.label, contentWidth, "…");
87
+ const styledLabel = row.active ? this.theme.fg("accent", this.theme.bold(label)) : label;
88
+ const num = String(i + 1).padStart(numberWidth, " ");
89
+ const line = `${pointer}${num}${NUMBER_SEPARATOR}${box}${BOX_LABEL_GAP}${styledLabel}`;
90
+ lines.push(truncateToWidth(line, width, ""));
91
+ if (opt.description) {
92
+ const wrapped = wrapTextWithAnsi(opt.description, contentWidth);
93
+ for (const segment of wrapped) {
94
+ lines.push(CONTINUATION_INDENT + this.theme.fg("muted", segment));
95
+ }
96
+ }
97
+ }
98
+
99
+ // "Type something." row — numbered N+1, box always [ ] muted UNCHECKED (never checkable).
100
+ // When focused + inputMode, render the label slot via the shared inline-input helper
101
+ // (single-line); otherwise a static localized label truncated to contentWidth with `…`.
102
+ const other = this.props.other;
103
+ const otherPointer = other.active ? this.theme.fg("accent", ACTIVE_POINTER) : INACTIVE_POINTER;
104
+ const otherBox = this.theme.fg("muted", UNCHECKED);
105
+ const otherNum = String(this.question.options.length + 1).padStart(numberWidth, " ");
106
+ let otherLabel: string;
107
+ if (other.active && other.inputMode) {
108
+ const rendered = renderInlineInputRow({
109
+ buffer: other.inputBuffer,
110
+ cursorOffset: other.inputCursorOffset,
111
+ rowPrefix: "",
112
+ continuationPrefix: "",
113
+ contentWidth,
114
+ selectedText: (t) => this.theme.fg("accent", this.theme.bold(t)),
115
+ multiline: false,
116
+ });
117
+ otherLabel = rendered[0] ?? "";
118
+ } else {
119
+ const label = truncateToWidth(displayLabel("other"), contentWidth, "…");
120
+ otherLabel = other.active ? this.theme.fg("accent", this.theme.bold(label)) : label;
121
+ }
122
+ lines.push(
123
+ truncateToWidth(
124
+ `${otherPointer}${otherNum}${NUMBER_SEPARATOR}${otherBox}${BOX_LABEL_GAP}${otherLabel}`,
125
+ width,
126
+ "",
127
+ ),
128
+ );
129
+
130
+ const nextPointer = this.props.nextActive ? this.theme.fg("accent", ACTIVE_POINTER) : INACTIVE_POINTER;
131
+ const nextLabel = this.props.nextActive
132
+ ? this.theme.fg("accent", this.theme.bold(this.props.nextLabel))
133
+ : this.props.nextLabel;
134
+ lines.push(truncateToWidth(`${nextPointer}${nextLabel}`, width, ""));
135
+ return lines;
136
+ }
137
+
138
+ /**
139
+ * Returns the [startRow, endRow) range of the active (focused) row within
140
+ * `render(width)`. Labels are always 1 row (truncated); descriptions wrap.
141
+ */
142
+ focusedItemRowRange(width: number): [number, number] {
143
+ const prefixWidth = this.prefixVisibleWidth();
144
+ const contentWidth = Math.max(1, width - prefixWidth);
145
+ let row = 0;
146
+ for (let i = 0; i < this.question.options.length; i++) {
147
+ const opt = this.question.options[i];
148
+ const r = this.props.rows[i];
149
+ if (!opt || !r) continue;
150
+ const itemHeight = 1 + (opt.description ? wrapTextWithAnsi(opt.description, contentWidth).length : 0);
151
+ if (r.active) {
152
+ return [row, row + itemHeight];
153
+ }
154
+ row += itemHeight;
155
+ }
156
+ // "Type something." row is always exactly 1 line (truncated, no description).
157
+ if (this.props.other.active) {
158
+ return [row, row + 1];
159
+ }
160
+ row += 1;
161
+ if (this.props.nextActive) {
162
+ return [row, row + 1];
163
+ }
164
+ return [0, 0];
165
+ }
166
+
167
+ naturalHeight(width: number): number {
168
+ const contentWidth = Math.max(1, width - this.prefixVisibleWidth());
169
+ let total = 0;
170
+ for (const opt of this.question.options) {
171
+ if (!opt) continue;
172
+ total += 1; // row line
173
+ if (opt.description) {
174
+ total += wrapTextWithAnsi(opt.description, contentWidth).length;
175
+ }
176
+ }
177
+ return total + 2; // "Type something." row + Next sentinel row (neither wraps).
178
+ }
179
+
180
+ private prefixVisibleWidth(): number {
181
+ // Canonical prefix for OPTION rows: INACTIVE_POINTER + numberWidth digits + NUMBER_SEPARATOR
182
+ // + UNCHECKED + BOX_LABEL_GAP. State-independent because ACTIVE/INACTIVE pointer share
183
+ // visibleWidth, CHECKED/UNCHECKED share visibleWidth, and numberWidth is constant per question.
184
+ // The number column fits `options.length + 1` so the "Type something." row's N+1 number
185
+ // is never clipped. The Next sentinel uses a bare `pointer + "Next"` shape — its width
186
+ // never exceeds this prefix at any reasonable terminal width, so it's safe to leave it
187
+ // out of the canonical computation.
188
+ const numberWidth = String(Math.max(1, this.question.options.length + 1)).length;
189
+ return (
190
+ visibleWidth(INACTIVE_POINTER) + numberWidth + visibleWidth(`${NUMBER_SEPARATOR}${UNCHECKED}${BOX_LABEL_GAP}`)
191
+ );
192
+ }
193
+ }
@@ -0,0 +1,70 @@
1
+ // GENERATED — DO NOT EDIT. Source: adapter-src/pi/extensions/ask-user-question/view/components/option-list-view.ts
2
+ // Regenerate with: python3 scripts/build-adapters.py
3
+ import type { StatefulView } from "../stateful-view.js";
4
+ import { WrappingSelect, type WrappingSelectItem, type WrappingSelectTheme } from "./wrapping-select.js";
5
+
6
+ /**
7
+ * Maximum number of option rows visible in the WrappingSelect window. Lifted here from
8
+ * `preview-pane.ts` so the cap travels with the option-list owner.
9
+ */
10
+ export const MAX_VISIBLE_OPTIONS = 10;
11
+
12
+ export interface OptionListViewConfig {
13
+ items: readonly WrappingSelectItem[];
14
+ theme: WrappingSelectTheme;
15
+ }
16
+
17
+ /**
18
+ * Per-tick projection of OptionListView state. After Phase 11b, `inputBuffer`
19
+ * is part of the props bag — the session-owned `inlineInput` (a headless
20
+ * `pi-tui` Input instance) supplies its current `getValue()` here per tick.
21
+ * `OptionListView` is purely props-driven; the imperative buffer surface and
22
+ * read-back getters are gone.
23
+ */
24
+ export interface OptionListViewProps {
25
+ selectedIndex: number;
26
+ focused: boolean;
27
+ inputBuffer: string;
28
+ inputCursorOffset?: number;
29
+ /** Optional previously-confirmed indicator. Omit when no marker should be drawn. */
30
+ confirmed?: { index: number; labelOverride?: string };
31
+ }
32
+
33
+ /**
34
+ * Sole owner of the option list's interactive state. Wraps a single
35
+ * `WrappingSelect`. Implements `StatefulView<OptionListViewProps>`:
36
+ * `setProps` is the only mutator; render output reflects the last props
37
+ * received.
38
+ */
39
+ export class OptionListView implements StatefulView<OptionListViewProps> {
40
+ private readonly select: WrappingSelect;
41
+
42
+ constructor(config: OptionListViewConfig) {
43
+ this.select = new WrappingSelect(config.items, Math.min(config.items.length, MAX_VISIBLE_OPTIONS), config.theme, {
44
+ numberStartOffset: 0,
45
+ totalItemsForNumbering: config.items.length,
46
+ });
47
+ }
48
+
49
+ setProps(props: OptionListViewProps): void {
50
+ this.select.setSelectedIndex(props.selectedIndex);
51
+ this.select.setFocused(props.focused);
52
+ this.select.setConfirmedIndex(props.confirmed?.index, props.confirmed?.labelOverride);
53
+ this.select.setInputBuffer(props.inputBuffer);
54
+ this.select.setInputCursorOffset(props.inputCursorOffset);
55
+ }
56
+
57
+ handleInput(_data: string): void {}
58
+
59
+ invalidate(): void {
60
+ this.select.invalidate();
61
+ }
62
+
63
+ render(width: number): string[] {
64
+ return this.select.render(width);
65
+ }
66
+
67
+ focusedItemRowRange(width: number): [number, number] {
68
+ return this.select.focusedItemRowRange(width);
69
+ }
70
+ }