@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,228 @@
1
+ // GENERATED — DO NOT EDIT. Source: adapter-src/pi/extensions/ask-user-question/view/components/preview/preview-pane.ts
2
+ // Regenerate with: python3 scripts/build-adapters.py
3
+ import { type Component, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
4
+ import type { QuestionData } from "../../../tool/types.js";
5
+ import type { StatefulView } from "../../stateful-view.js";
6
+ import type { OptionListView } from "../option-list-view.js";
7
+ import type { PreviewBlockRenderer } from "./preview-block-renderer.js";
8
+ import {
9
+ bodyWidths,
10
+ columnWidths,
11
+ decideLayout,
12
+ PREVIEW_PADDING_LEFT,
13
+ type PreviewLayoutMode,
14
+ STACKED_GAP_ROWS,
15
+ } from "./preview-layout-decider.js";
16
+
17
+ // ----- Re-exports for test imports — keep `./preview-pane.js` as the public surface -----
18
+ export {
19
+ MAX_PREVIEW_HEIGHT_SIDE_BY_SIDE,
20
+ MAX_PREVIEW_HEIGHT_STACKED,
21
+ NO_PREVIEW_TEXT,
22
+ NOTES_AFFORDANCE_OVERHEAD,
23
+ } from "./markdown-content-cache.js";
24
+ export { NOTES_AFFORDANCE_TEXT, PreviewBlockRenderer } from "./preview-block-renderer.js";
25
+ export {
26
+ BORDER_HORIZONTAL_OVERHEAD,
27
+ BORDER_INNER_PADDING_HORIZONTAL,
28
+ BORDER_VERTICAL_OVERHEAD,
29
+ BOX_MIN_CONTENT_WIDTH,
30
+ renderBorderedBox,
31
+ stripFenceMarkers,
32
+ } from "./preview-box-renderer.js";
33
+ export {
34
+ PREVIEW_COLUMN_GAP,
35
+ PREVIEW_MIN_WIDTH,
36
+ PREVIEW_PADDING_LEFT,
37
+ STACKED_GAP_ROWS,
38
+ } from "./preview-layout-decider.js";
39
+
40
+ /**
41
+ * Per-tick projection of PreviewPane state. Replaces the prior
42
+ * `setNotesVisible(boolean)` sliver-setter and the sibling reads of
43
+ * `optionListView.getSelectedIndex()` / `isFocused()`. The pane now reads
44
+ * `selectedIndex` and `focused` from its own props — both derived from
45
+ * canonical state via `selectPreviewPaneProps`. `OptionListView` and
46
+ * `PreviewPane` see the same source of truth without the cross-component
47
+ * live read.
48
+ */
49
+ export interface PreviewPaneProps {
50
+ notesVisible: boolean;
51
+ selectedIndex: number;
52
+ focused: boolean;
53
+ /**
54
+ * True while the "other" (custom-answer) row is focused and accepting input
55
+ * (`state.inputMode`, set by the reducer via `ROW_INTENT_META.other.activatesInputMode`).
56
+ * Surfaced by `selectPreviewPaneProps` from canonical state; drives the full-width
57
+ * early-returns below so the inline input isn't cramped into the narrow left column.
58
+ */
59
+ inputMode: boolean;
60
+ }
61
+
62
+ export interface PreviewPaneConfig {
63
+ question: QuestionData;
64
+ getTerminalWidth: () => number;
65
+ optionListView: OptionListView;
66
+ previewBlock: PreviewBlockRenderer;
67
+ }
68
+
69
+ /**
70
+ * Thin layout composer. Receives `selectedIndex` / `focused` / `notesVisible`
71
+ * via `setProps` per tick (computed by `selectPreviewPaneProps` from canonical
72
+ * state). Delegates option-side rendering to `OptionListView` (which still
73
+ * owns its render-time state — input buffer, confirmedIndex) and preview-side
74
+ * rendering to `PreviewBlockRenderer` (which owns the markdown cache and
75
+ * bordered-box composition).
76
+ *
77
+ * `naturalHeight` and `maxNaturalHeight` query both children's heights; `render`
78
+ * combines them via `decideLayout` (mode threaded into both calls — never
79
+ * re-derived).
80
+ */
81
+ export class PreviewPane implements StatefulView<PreviewPaneProps>, Component {
82
+ private readonly question: QuestionData;
83
+ private readonly getTerminalWidth: () => number;
84
+ private readonly optionListView: OptionListView;
85
+ private readonly previewBlock: PreviewBlockRenderer;
86
+ private props: PreviewPaneProps;
87
+ /**
88
+ * Cross-tab max left-width getter. Set exactly once by `buildQuestionnaire.injectGlobalLeftWidth`
89
+ * before any render. Initialized to a throwing sentinel so missing injection is a hard fail
90
+ * rather than a silent fallback to a magic constant — render is illegal until injected.
91
+ */
92
+ private globalLeftWidth: (paneWidth: number) => number = () => {
93
+ throw new Error("PreviewPane.setGlobalLeftWidth must be called before render()");
94
+ };
95
+
96
+ constructor(config: PreviewPaneConfig) {
97
+ this.question = config.question;
98
+ this.getTerminalWidth = config.getTerminalWidth;
99
+ this.optionListView = config.optionListView;
100
+ this.previewBlock = config.previewBlock;
101
+ this.props = { notesVisible: false, selectedIndex: 0, focused: false, inputMode: false };
102
+ }
103
+
104
+ setGlobalLeftWidth(getter: (paneWidth: number) => number): void {
105
+ this.globalLeftWidth = getter;
106
+ }
107
+
108
+ private getAdaptiveLeft(paneWidth: number): number {
109
+ return this.globalLeftWidth(paneWidth);
110
+ }
111
+
112
+ setProps(props: PreviewPaneProps): void {
113
+ this.props = props;
114
+ }
115
+
116
+ handleInput(_data: string): void {}
117
+
118
+ invalidate(): void {
119
+ this.previewBlock.invalidate();
120
+ this.optionListView.invalidate();
121
+ }
122
+
123
+ render(width: number): string[] {
124
+ if (this.question.multiSelect === true) return this.optionListView.render(width);
125
+ // Spec: hide the preview pane entirely when no option carries a `preview`.
126
+ if (!this.previewBlock.hasAnyPreview()) return this.optionListView.render(width);
127
+ // `inputMode` (typing on the "other" custom-answer row): the preview is irrelevant —
128
+ // the row sits at index `options.length`, out of bounds for any option's preview — so
129
+ // render the option list at the full pane width instead of the cramped left column.
130
+ // Side-by-side + preview block resume verbatim on nav-away (inputMode clears).
131
+ if (this.props.inputMode) return this.optionListView.render(width);
132
+
133
+ const mode = decideLayout(this.getTerminalWidth(), width);
134
+ if (mode === "side-by-side") return this.renderSideBySide(width, mode);
135
+
136
+ // Stacked: options + blank gap + preview block.
137
+ return [
138
+ ...this.optionListView.render(width),
139
+ ...Array(STACKED_GAP_ROWS).fill(""),
140
+ ...this.previewBlock.renderBlock(
141
+ width,
142
+ this.props.selectedIndex,
143
+ mode,
144
+ this.props.focused,
145
+ this.props.notesVisible,
146
+ ),
147
+ ];
148
+ }
149
+
150
+ focusedItemRowRange(width: number): [number, number] {
151
+ if (this.question.multiSelect === true) return this.optionListView.focusedItemRowRange(width);
152
+ if (!this.previewBlock.hasAnyPreview()) return this.optionListView.focusedItemRowRange(width);
153
+ // `inputMode`: compute the focused row range against the FULL pane width (not the
154
+ // side-by-side leftWidth), mirroring `render`'s full-width option list.
155
+ if (this.props.inputMode) return this.optionListView.focusedItemRowRange(width);
156
+ const mode = decideLayout(this.getTerminalWidth(), width);
157
+ if (mode === "stacked") return this.optionListView.focusedItemRowRange(width);
158
+ const adaptiveLeft = this.getAdaptiveLeft(width);
159
+ const { leftWidth } = columnWidths(width, adaptiveLeft);
160
+ return this.optionListView.focusedItemRowRange(leftWidth);
161
+ }
162
+
163
+ naturalHeight(width: number): number {
164
+ if (this.question.multiSelect === true) return this.optionListView.render(width).length;
165
+ if (!this.previewBlock.hasAnyPreview()) return this.optionListView.render(width).length;
166
+ // `inputMode`: height is the full-width option list only (no preview block) — preserves
167
+ // the `naturalHeight === render.length` parity invariant.
168
+ if (this.props.inputMode) return this.optionListView.render(width).length;
169
+ const mode = decideLayout(this.getTerminalWidth(), width);
170
+ const adaptiveLeft = this.getAdaptiveLeft(width);
171
+ const { optionsWidth, previewWidth } = bodyWidths(width, mode, adaptiveLeft);
172
+ const optionsHeight = this.optionListView.render(optionsWidth).length;
173
+ const previewBlockHeight = this.previewBlock.blockHeight(previewWidth, this.props.selectedIndex, mode);
174
+ if (mode === "side-by-side") return Math.max(optionsHeight, previewBlockHeight);
175
+ return optionsHeight + STACKED_GAP_ROWS + previewBlockHeight;
176
+ }
177
+
178
+ maxNaturalHeight(width: number): number {
179
+ if (this.question.multiSelect === true) return this.optionListView.render(width).length;
180
+ if (!this.previewBlock.hasAnyPreview()) return this.optionListView.render(width).length;
181
+ // `inputMode`: like naturalHeight — full-width option list only, so the
182
+ // `maxNaturalHeight >= naturalHeight` parity invariant holds (both equal the list height).
183
+ if (this.props.inputMode) return this.optionListView.render(width).length;
184
+ const mode = decideLayout(this.getTerminalWidth(), width);
185
+ const adaptiveLeft = this.getAdaptiveLeft(width);
186
+ const { optionsWidth, previewWidth } = bodyWidths(width, mode, adaptiveLeft);
187
+ const optionsHeight = this.optionListView.render(optionsWidth).length;
188
+ let maxPreviewBlock = 0;
189
+ for (let i = 0; i < this.question.options.length; i++) {
190
+ const h = this.previewBlock.blockHeight(previewWidth, i, mode);
191
+ if (h > maxPreviewBlock) maxPreviewBlock = h;
192
+ }
193
+ if (mode === "side-by-side") return Math.max(optionsHeight, maxPreviewBlock);
194
+ return optionsHeight + STACKED_GAP_ROWS + maxPreviewBlock;
195
+ }
196
+
197
+ private renderSideBySide(width: number, mode: PreviewLayoutMode): string[] {
198
+ const adaptiveLeft = this.getAdaptiveLeft(width);
199
+ const { leftWidth, rightWidth, gap } = columnWidths(width, adaptiveLeft);
200
+ const leftLines = this.optionListView.render(leftWidth);
201
+ const rightLines = this.renderPaddedPreviewLines(rightWidth, mode);
202
+ const rows = Math.max(leftLines.length, rightLines.length);
203
+ const gapStr = " ".repeat(gap);
204
+ const out: string[] = [];
205
+ for (let i = 0; i < rows; i++) {
206
+ const leftRaw = leftLines[i] ?? "";
207
+ const rightRaw = rightLines[i] ?? "";
208
+ const leftClamped = truncateToWidth(leftRaw, leftWidth, "");
209
+ const leftPad = " ".repeat(Math.max(0, leftWidth - visibleWidth(leftClamped)));
210
+ const joined = `${leftClamped}${leftPad}${gapStr}${rightRaw}`;
211
+ out.push(truncateToWidth(joined, width, ""));
212
+ }
213
+ return out;
214
+ }
215
+
216
+ private renderPaddedPreviewLines(colWidth: number, mode: PreviewLayoutMode): string[] {
217
+ const inner = Math.max(1, colWidth - PREVIEW_PADDING_LEFT);
218
+ const contentLines = this.previewBlock.renderBlock(
219
+ inner,
220
+ this.props.selectedIndex,
221
+ mode,
222
+ this.props.focused,
223
+ this.props.notesVisible,
224
+ );
225
+ const pad = " ".repeat(PREVIEW_PADDING_LEFT);
226
+ return contentLines.map((l) => (l === "" ? "" : `${pad}${l}`));
227
+ }
228
+ }
@@ -0,0 +1,67 @@
1
+ // GENERATED — DO NOT EDIT. Source: adapter-src/pi/extensions/ask-user-question/view/components/submit-picker.ts
2
+ // Regenerate with: python3 scripts/build-adapters.py
3
+ import type { Theme } from "@earendil-works/pi-coding-agent";
4
+ import { truncateToWidth } from "@earendil-works/pi-tui";
5
+ import { t } from "../../state/i18n-bridge.js";
6
+ import type { StatefulView } from "../stateful-view.js";
7
+
8
+ const ACTIVE_POINTER = "❯ ";
9
+ const INACTIVE_POINTER = " ";
10
+ const NUMBER_SEPARATOR = ". ";
11
+
12
+ export const SUBMIT_LABEL = "Submit answers";
13
+ export const CANCEL_LABEL = "Cancel";
14
+
15
+ /**
16
+ * Per-tick projection of SubmitPicker state. The picker is a fixed 2-row
17
+ * structure (Submit / Cancel) — labels are static, only the active marker
18
+ * varies per tick. `selectSubmitPickerProps` precomputes `active` per row.
19
+ */
20
+ export interface SubmitPickerProps {
21
+ /** Per-row active flag. Length always 2: row 0 = Submit, row 1 = Cancel. */
22
+ rows: ReadonlyArray<{ active: boolean }>;
23
+ }
24
+
25
+ /**
26
+ * Static 2-row picker rendered on the Submit Tab. Row 0 = "Submit answers", Row 1 = "Cancel".
27
+ *
28
+ * - Active pointer (❯) follows `props.rows[i].active` per tick.
29
+ * - Both rows render in normal style at all times — D1 (revised) allows partial submission,
30
+ * so Submit is never dimmed or visually marked as unselectable. The warning header in
31
+ * `buildSubmitContainer` is the sole signal of incompleteness.
32
+ * - `naturalHeight(width)` is state-INDEPENDENT and returns a constant 2, so the
33
+ * chrome-mirror layout in `buildSubmitContainer` can subtract a fixed 2 lines without
34
+ * re-rendering.
35
+ */
36
+ export class SubmitPicker implements StatefulView<SubmitPickerProps> {
37
+ private props: SubmitPickerProps;
38
+
39
+ constructor(private readonly theme: Theme) {
40
+ this.props = { rows: [{ active: false }, { active: false }] };
41
+ }
42
+
43
+ setProps(props: SubmitPickerProps): void {
44
+ this.props = props;
45
+ }
46
+
47
+ handleInput(_data: string): void {}
48
+
49
+ invalidate(): void {}
50
+
51
+ naturalHeight(_width: number): number {
52
+ return 2;
53
+ }
54
+
55
+ render(width: number): string[] {
56
+ const lines: string[] = [];
57
+ for (let i = 0; i < 2; i++) {
58
+ const text = i === 0 ? t("submit.label", SUBMIT_LABEL) : t("submit.cancel", CANCEL_LABEL);
59
+ const active = this.props.rows[i]?.active ?? false;
60
+ const pointer = active ? ACTIVE_POINTER : INACTIVE_POINTER;
61
+ const number = `${i + 1}${NUMBER_SEPARATOR}`;
62
+ const label = active ? this.theme.fg("accent", this.theme.bold(text)) : this.theme.fg("text", text);
63
+ lines.push(truncateToWidth(`${pointer}${number}${label}`, width, ""));
64
+ }
65
+ return lines;
66
+ }
67
+ }
@@ -0,0 +1,59 @@
1
+ // GENERATED — DO NOT EDIT. Source: adapter-src/pi/extensions/ask-user-question/view/components/tab-bar.ts
2
+ // Regenerate with: python3 scripts/build-adapters.py
3
+ import type { Theme } from "@earendil-works/pi-coding-agent";
4
+ import { truncateToWidth } from "@earendil-works/pi-tui";
5
+ import type { StatefulView } from "../stateful-view.js";
6
+
7
+ /**
8
+ * Per-tick projection of TabBar state. The selector
9
+ * (`selectTabBarProps`) hoists every render-time derivation
10
+ * (`allAnswered`, `answered`, `isActive`, `submitActive`) into props so
11
+ * `render()` is pure styling. Replaces the prior `setConfig(TabBarConfig)`
12
+ * snowflake and the inline `+ 1` magic at `props-adapter.ts:127`.
13
+ */
14
+ export interface TabBarProps {
15
+ /** One per author-defined question, in order. */
16
+ tabs: ReadonlyArray<{ label: string; answered: boolean; active: boolean }>;
17
+ /** Submit-tab state. `allAnswered` drives the success/dim color picker. */
18
+ submit: { active: boolean; allAnswered: boolean };
19
+ }
20
+
21
+ export class TabBar implements StatefulView<TabBarProps> {
22
+ private props: TabBarProps;
23
+
24
+ constructor(private readonly theme: Theme) {
25
+ this.props = { tabs: [], submit: { active: false, allAnswered: false } };
26
+ }
27
+
28
+ setProps(props: TabBarProps): void {
29
+ this.props = props;
30
+ }
31
+
32
+ handleInput(_data: string): void {}
33
+
34
+ invalidate(): void {}
35
+
36
+ render(width: number): string[] {
37
+ const pieces: string[] = [" ← "];
38
+
39
+ for (const tab of this.props.tabs) {
40
+ const box = tab.answered ? "■" : "□";
41
+ const rawSeg = ` ${box} ${tab.label} `;
42
+ const styled = tab.active
43
+ ? this.theme.bg("selectedBg", this.theme.fg("text", rawSeg))
44
+ : this.theme.fg(tab.answered ? "success" : "muted", rawSeg);
45
+ pieces.push(styled);
46
+ pieces.push(" ");
47
+ }
48
+
49
+ const submitText = " ✓ Submit ";
50
+ const submitStyled = this.props.submit.active
51
+ ? this.theme.bg("selectedBg", this.theme.fg("text", submitText))
52
+ : this.theme.fg(this.props.submit.allAnswered ? "success" : "dim", submitText);
53
+ pieces.push(submitStyled);
54
+ pieces.push(" →");
55
+
56
+ const tabLine = truncateToWidth(pieces.join(""), width, "");
57
+ return [tabLine, ""];
58
+ }
59
+ }
@@ -0,0 +1,293 @@
1
+ // GENERATED — DO NOT EDIT. Source: adapter-src/pi/extensions/ask-user-question/view/components/wrapping-select.ts
2
+ // Regenerate with: python3 scripts/build-adapters.py
3
+ import type { Component } from "@earendil-works/pi-tui";
4
+ import { visibleWidth, wrapTextWithAnsi } from "@earendil-works/pi-tui";
5
+ import { renderInlineInputRow } from "./inline-input.js";
6
+
7
+ /**
8
+ * Row-intent discriminated union. `kind` is the single discriminator —
9
+ * pre-1.0.3 boolean flags have been removed (see `banned-flags.test.ts`).
10
+ * Modeled after `QuestionnaireAction` (`key-router.ts:13-32`) and `Effect`
11
+ * (`state-reducer.ts:26-32`) — pure literal-tagged variants, no shared base,
12
+ * exhaustive-`switch` enforcement via non-`void` returns.
13
+ *
14
+ * Variant semantics:
15
+ * - `option`: a regular author-defined option row.
16
+ * - `other`: the inline free-text input row appended to every question
17
+ * (label is "Type something."). Renders as inline `Input` when active.
18
+ * - `next`: the explicit commit-and-advance row appended to multi-select questions
19
+ * (label is "Next"). Renders without a number / checkbox.
20
+ */
21
+ export type WrappingSelectItem =
22
+ | { kind: "option"; label: string; description?: string }
23
+ | { kind: "other"; label: string; description?: string }
24
+ | { kind: "next"; label: string; description?: string };
25
+
26
+ export interface WrappingSelectTheme {
27
+ selectedText: (text: string) => string;
28
+ description: (text: string) => string;
29
+ scrollInfo: (text: string) => string;
30
+ }
31
+
32
+ /**
33
+ * Numbering controls.
34
+ *
35
+ * Use `numberStartOffset` + `totalItemsForNumbering` when a list is logically a slice of a
36
+ * larger numbered sequence — e.g. to start numbering at an offset and pad the column as
37
+ * if the list were part of a longer continuous numbered sequence.
38
+ */
39
+ export interface WrappingSelectOptions {
40
+ /** Start numbering at this offset + 1 (default 0 → rows labeled 1, 2, 3 …). */
41
+ numberStartOffset?: number;
42
+ /** Override the total used to pad the number column (useful when items span multiple lists). */
43
+ totalItemsForNumbering?: number;
44
+ }
45
+
46
+ export class WrappingSelect implements Component {
47
+ private static readonly ACTIVE_POINTER = "❯ ";
48
+ private static readonly INACTIVE_POINTER = " ";
49
+ private static readonly NUMBER_SEPARATOR = ". ";
50
+ private static readonly CONFIRMED_MARK = " ✔";
51
+ private static readonly MIN_CONTENT_WIDTH = 1;
52
+
53
+ private readonly items: readonly WrappingSelectItem[];
54
+ private readonly maxVisible: number;
55
+ private readonly theme: WrappingSelectTheme;
56
+ private numberStartOffset: number;
57
+ private totalItemsForNumbering: number;
58
+
59
+ private selectedIndex = 0;
60
+ private focused = true;
61
+ private inputBuffer = "";
62
+ private inputCursorOffset: number | undefined = undefined;
63
+ /**
64
+ * Index of the row that was previously confirmed for this list (e.g. the user's prior
65
+ * answer when re-entering a multi-question tab). Renders `<label> ✔` in the active-row
66
+ * styling but WITHOUT the `❯` pointer — pointer is reserved for the live cursor. When
67
+ * `selectedIndex === confirmedIndex && focused`, the active rendering wins (no double-mark).
68
+ */
69
+ private confirmedIndex: number | undefined = undefined;
70
+ /**
71
+ * When set together with `confirmedIndex`, replaces the row's static label at render time.
72
+ * Used for the `kind: "other"` sentinel — its label is "Type something." but if the user's
73
+ * prior answer was custom text, we render that text instead (e.g. `4. Hello ✔`).
74
+ */
75
+ private confirmedLabelOverride: string | undefined = undefined;
76
+
77
+ constructor(
78
+ items: readonly WrappingSelectItem[],
79
+ maxVisible: number,
80
+ theme: WrappingSelectTheme,
81
+ options: WrappingSelectOptions = {},
82
+ ) {
83
+ this.items = items;
84
+ this.maxVisible = Math.max(1, maxVisible);
85
+ this.theme = theme;
86
+ this.numberStartOffset = options.numberStartOffset ?? 0;
87
+ this.totalItemsForNumbering = options.totalItemsForNumbering ?? items.length;
88
+ }
89
+
90
+ /**
91
+ * Update the numbering offset + total padding width without rebuilding the component.
92
+ * Lets the host realign the number column when the underlying item set changes.
93
+ */
94
+ setNumbering(numberStartOffset: number, totalItemsForNumbering: number): void {
95
+ this.numberStartOffset = numberStartOffset;
96
+ this.totalItemsForNumbering = Math.max(1, totalItemsForNumbering);
97
+ }
98
+
99
+ setSelectedIndex(index: number): void {
100
+ this.selectedIndex = Math.max(0, Math.min(index, this.items.length - 1));
101
+ }
102
+
103
+ setFocused(focused: boolean): void {
104
+ this.focused = focused;
105
+ }
106
+
107
+ /**
108
+ * Mark a previously-confirmed row. Pass `undefined` to clear. `labelOverride` replaces
109
+ * the row's static `item.label` at render time — used for the `kind: "other"` sentinel so
110
+ * the row reads `Hello ✔` instead of `Type something. ✔` when the prior answer was custom
111
+ * text.
112
+ */
113
+ setConfirmedIndex(index: number | undefined, labelOverride?: string): void {
114
+ if (index === undefined) {
115
+ this.confirmedIndex = undefined;
116
+ this.confirmedLabelOverride = undefined;
117
+ return;
118
+ }
119
+ this.confirmedIndex = Math.max(0, Math.min(index, this.items.length - 1));
120
+ this.confirmedLabelOverride = labelOverride;
121
+ }
122
+
123
+ setInputBuffer(text: string): void {
124
+ this.inputBuffer = text;
125
+ }
126
+
127
+ /** Set the cursor offset for the inline input row. `undefined` → end-of-buffer fallback. */
128
+ setInputCursorOffset(offset: number | undefined): void {
129
+ this.inputCursorOffset = offset;
130
+ }
131
+
132
+ /** Intentionally empty — input is routed at the container level. */
133
+ handleInput(_data: string): void {}
134
+
135
+ invalidate(): void {}
136
+
137
+ render(width: number): string[] {
138
+ if (this.items.length === 0) return [];
139
+
140
+ const { startIndex, endIndex } = this.computeVisibleWindow();
141
+ const numberWidth = String(Math.max(1, this.totalItemsForNumbering)).length;
142
+ const lines: string[] = [];
143
+
144
+ for (let i = startIndex; i < endIndex; i++) {
145
+ const item = this.items[i];
146
+ if (!item) continue;
147
+ const isActive = i === this.selectedIndex && this.focused;
148
+ lines.push(...this.renderItem(item, i, isActive, width, numberWidth));
149
+ }
150
+
151
+ if (this.hasItemsOutsideWindow(startIndex, endIndex)) {
152
+ lines.push(this.theme.scrollInfo(` (${this.selectedIndex + 1}/${this.items.length})`));
153
+ }
154
+ return lines;
155
+ }
156
+
157
+ /**
158
+ * Returns the [startRow, endRow) range of the focused (selected) item within
159
+ * the output of `render(width)`. Computed by iterating the visible window and
160
+ * summing per-item row counts — O(maxVisible) per call.
161
+ */
162
+ focusedItemRowRange(width: number): [number, number] {
163
+ if (this.items.length === 0) return [0, 0];
164
+ const { startIndex, endIndex } = this.computeVisibleWindow();
165
+ const numberWidth = String(Math.max(1, this.totalItemsForNumbering)).length;
166
+ let row = 0;
167
+ for (let i = startIndex; i < endIndex; i++) {
168
+ const item = this.items[i];
169
+ if (!item) continue;
170
+ const isActive = i === this.selectedIndex && this.focused;
171
+ const itemRowCount = this.computeItemRowCount(item, i, isActive, width, numberWidth);
172
+ if (i === this.selectedIndex) {
173
+ return [row, row + itemRowCount];
174
+ }
175
+ row += itemRowCount;
176
+ }
177
+ return [0, 1];
178
+ }
179
+
180
+ /**
181
+ * Per-item row count. Delegates to `renderItem().length` so `renderItem` remains
182
+ * the single source of truth for per-item row math — eliminates the prior shadow-copy
183
+ * that risked silent miscounts when new `kind` values branch in `renderItem` but not here.
184
+ */
185
+ private computeItemRowCount(
186
+ item: WrappingSelectItem,
187
+ index: number,
188
+ isActive: boolean,
189
+ width: number,
190
+ numberWidth: number,
191
+ ): number {
192
+ return this.renderItem(item, index, isActive, width, numberWidth).length;
193
+ }
194
+
195
+ private computeVisibleWindow(): { startIndex: number; endIndex: number } {
196
+ const half = Math.floor(this.maxVisible / 2);
197
+ const startIndex = Math.max(0, Math.min(this.selectedIndex - half, this.items.length - this.maxVisible));
198
+ const endIndex = Math.min(startIndex + this.maxVisible, this.items.length);
199
+ return { startIndex, endIndex };
200
+ }
201
+
202
+ private hasItemsOutsideWindow(startIndex: number, endIndex: number): boolean {
203
+ return startIndex > 0 || endIndex < this.items.length;
204
+ }
205
+
206
+ private renderItem(
207
+ item: WrappingSelectItem,
208
+ index: number,
209
+ isActive: boolean,
210
+ width: number,
211
+ numberWidth: number,
212
+ ): string[] {
213
+ const rowPrefix = this.buildRowPrefix(index, isActive, numberWidth);
214
+ const continuationPrefix = " ".repeat(visibleWidth(rowPrefix));
215
+ const contentWidth = Math.max(WrappingSelect.MIN_CONTENT_WIDTH, width - visibleWidth(rowPrefix));
216
+
217
+ if (this.shouldRenderAsInlineInput(item, isActive)) {
218
+ return this.renderInlineInputRow(rowPrefix, continuationPrefix, contentWidth);
219
+ }
220
+
221
+ // Confirmed row gets a trailing ` ✔` and accent+bold styling; pointer is independent
222
+ // (still ❯ when active). When `index === confirmedIndex` AND `isActive`, both `❯` and
223
+ // `✔` appear on the same row — load-bearing for the case where the prior answer was
224
+ // row 0 (cursor resets to 0 on tab-back, so the confirmed row IS the active row).
225
+ // Optional `confirmedLabelOverride` replaces the static label (used for `kind: "other"`
226
+ // + `kind: "custom"` answer); the inline-input branch above still wins for `kind: "other" + isActive`.
227
+ const isConfirmed = index === this.confirmedIndex;
228
+ const label = isConfirmed
229
+ ? `${this.confirmedLabelOverride ?? item.label}${WrappingSelect.CONFIRMED_MARK}`
230
+ : item.label;
231
+ const applySelectedStyle = isActive || isConfirmed;
232
+
233
+ return [
234
+ ...this.renderLabelBlock(label, rowPrefix, continuationPrefix, contentWidth, applySelectedStyle),
235
+ ...this.renderDescriptionBlock(item.description, continuationPrefix, contentWidth),
236
+ ];
237
+ }
238
+
239
+ private buildRowPrefix(index: number, isActive: boolean, numberWidth: number): string {
240
+ const pointer = isActive ? WrappingSelect.ACTIVE_POINTER : WrappingSelect.INACTIVE_POINTER;
241
+ const displayNumber = this.numberStartOffset + index + 1;
242
+ const paddedNumber = String(displayNumber).padStart(numberWidth, " ");
243
+ return `${pointer}${paddedNumber}${WrappingSelect.NUMBER_SEPARATOR}`;
244
+ }
245
+
246
+ private shouldRenderAsInlineInput(item: WrappingSelectItem, isActive: boolean): boolean {
247
+ return item.kind === "other" && isActive;
248
+ }
249
+
250
+ /**
251
+ * Render the inline input row across one or more lines, wrapping at `contentWidth`.
252
+ * Delegates to the shared `renderInlineInputRow` helper (`./inline-input.ts`) so the
253
+ * single-select wrap path and the multi-select single-line path share one cursor-
254
+ * building core. The `multiline: true` path is byte-identical to the pre-extraction
255
+ * output (cursor rationale lives in `inline-input.ts`).
256
+ */
257
+ private renderInlineInputRow(rowPrefix: string, continuationPrefix: string, contentWidth: number): string[] {
258
+ return renderInlineInputRow({
259
+ buffer: this.inputBuffer,
260
+ cursorOffset: this.inputCursorOffset,
261
+ rowPrefix,
262
+ continuationPrefix,
263
+ contentWidth,
264
+ selectedText: this.theme.selectedText,
265
+ multiline: true,
266
+ });
267
+ }
268
+
269
+ private renderLabelBlock(
270
+ label: string,
271
+ rowPrefix: string,
272
+ continuationPrefix: string,
273
+ contentWidth: number,
274
+ applySelectedStyle: boolean,
275
+ ): string[] {
276
+ const wrapped = wrapTextWithAnsi(label, contentWidth);
277
+ return wrapped.map((segment, index) => {
278
+ const prefix = index === 0 ? rowPrefix : continuationPrefix;
279
+ const line = `${prefix}${segment}`;
280
+ return applySelectedStyle ? this.theme.selectedText(line) : line;
281
+ });
282
+ }
283
+
284
+ private renderDescriptionBlock(
285
+ description: string | undefined,
286
+ continuationPrefix: string,
287
+ contentWidth: number,
288
+ ): string[] {
289
+ if (!description) return [];
290
+ const wrapped = wrapTextWithAnsi(description, contentWidth);
291
+ return wrapped.map((segment) => `${continuationPrefix}${this.theme.description(segment)}`);
292
+ }
293
+ }