savepoint 1.0.3 → 1.0.6

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 (418) hide show
  1. package/package.json +10 -3
  2. package/{savepoint → savepoint.exe} +0 -0
  3. package/.claude/settings.local.json +0 -38
  4. package/.golangci.yml +0 -11
  5. package/.prettierignore +0 -4
  6. package/.savepoint/Design.md +0 -206
  7. package/.savepoint/PRD.md +0 -58
  8. package/.savepoint/config.yml +0 -27
  9. package/.savepoint/releases/v1/epics/E01-go-setup/E01-Detail.md +0 -39
  10. package/.savepoint/releases/v1/epics/E01-go-setup/tasks/T001-init-module.md +0 -42
  11. package/.savepoint/releases/v1/epics/E01-go-setup/tasks/T002-entrypoint.md +0 -23
  12. package/.savepoint/releases/v1/epics/E01-go-setup/tasks/T003-directory-structure.md +0 -24
  13. package/.savepoint/releases/v1/epics/E01-go-setup/tasks/T004-makefile.md +0 -23
  14. package/.savepoint/releases/v1/epics/E02-data-readers/E02-Detail.md +0 -61
  15. package/.savepoint/releases/v1/epics/E02-data-readers/tasks/T001-task-struct.md +0 -29
  16. package/.savepoint/releases/v1/epics/E02-data-readers/tasks/T002-frontmatter-parser.md +0 -30
  17. package/.savepoint/releases/v1/epics/E02-data-readers/tasks/T003-router-reader.md +0 -29
  18. package/.savepoint/releases/v1/epics/E02-data-readers/tasks/T004-config-reader.md +0 -29
  19. package/.savepoint/releases/v1/epics/E02-data-readers/tasks/T005-discovery.md +0 -30
  20. package/.savepoint/releases/v1/epics/E03-board-tui-core/E03-Detail.md +0 -38
  21. package/.savepoint/releases/v1/epics/E03-board-tui-core/tasks/T001-model.md +0 -29
  22. package/.savepoint/releases/v1/epics/E03-board-tui-core/tasks/T002-update-loop.md +0 -30
  23. package/.savepoint/releases/v1/epics/E03-board-tui-core/tasks/T003-view.md +0 -34
  24. package/.savepoint/releases/v1/epics/E03-board-tui-core/tasks/T004-styles.md +0 -29
  25. package/.savepoint/releases/v1/epics/E03-board-tui-core/tasks/T005-layout.md +0 -42
  26. package/.savepoint/releases/v1/epics/E04-board-components/E04-Detail.md +0 -44
  27. package/.savepoint/releases/v1/epics/E04-board-components/tasks/T001-column.md +0 -34
  28. package/.savepoint/releases/v1/epics/E04-board-components/tasks/T002-card.md +0 -33
  29. package/.savepoint/releases/v1/epics/E04-board-components/tasks/T003-epic-panel.md +0 -49
  30. package/.savepoint/releases/v1/epics/E04-board-components/tasks/T004-detail-overlay.md +0 -40
  31. package/.savepoint/releases/v1/epics/E04-board-components/tasks/T005-release-dropdown.md +0 -33
  32. package/.savepoint/releases/v1/epics/E04-board-components/tasks/T006-help-overlay.md +0 -34
  33. package/.savepoint/releases/v1/epics/E05-phase-transitions/E05-Detail.md +0 -38
  34. package/.savepoint/releases/v1/epics/E05-phase-transitions/tasks/T001-phase-stepping.md +0 -29
  35. package/.savepoint/releases/v1/epics/E05-phase-transitions/tasks/T002-gates.md +0 -31
  36. package/.savepoint/releases/v1/epics/E05-phase-transitions/tasks/T003-write-task.md +0 -31
  37. package/.savepoint/releases/v1/epics/E05-phase-transitions/tasks/T004-write-router.md +0 -31
  38. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/E06-Detail.md +0 -62
  39. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T001-color-system.md +0 -39
  40. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T002-header-and-dividers.md +0 -52
  41. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T003-footer-status-bar.md +0 -52
  42. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T004-component-refinement.md +0 -53
  43. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T005-restore-nav-hints.md +0 -39
  44. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T007-detail-card-fixes.md +0 -36
  45. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T008-checkbox-states.md +0 -40
  46. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T009-router-priority-marker.md +0 -48
  47. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T010-auto-refresh-watcher.md +0 -66
  48. package/.savepoint/releases/v1/epics/_archived/E01-archive-and-reset/Design.md +0 -39
  49. package/.savepoint/releases/v1/epics/_archived/E01-archive-and-reset/tasks/T001-archive-epics.md +0 -20
  50. package/.savepoint/releases/v1/epics/_archived/E01-archive-and-reset/tasks/T002-rewrite-prd.md +0 -22
  51. package/.savepoint/releases/v1/epics/_archived/E01-archive-and-reset/tasks/T003-create-epic-stubs.md +0 -24
  52. package/.savepoint/releases/v1/epics/_archived/E01-archive-and-reset/tasks/T004-update-router.md +0 -22
  53. package/.savepoint/releases/v1/epics/_archived/E01-scaffolding/Design.md +0 -118
  54. package/.savepoint/releases/v1/epics/_archived/E01-scaffolding/handoff.md +0 -9
  55. package/.savepoint/releases/v1/epics/_archived/E01-scaffolding/tasks/T001-package-baseline.md +0 -45
  56. package/.savepoint/releases/v1/epics/_archived/E01-scaffolding/tasks/T002-typescript-build.md +0 -48
  57. package/.savepoint/releases/v1/epics/_archived/E01-scaffolding/tasks/T003-vitest-smoke.md +0 -43
  58. package/.savepoint/releases/v1/epics/_archived/E01-scaffolding/tasks/T004-lint-format-gates.md +0 -45
  59. package/.savepoint/releases/v1/epics/_archived/E01-scaffolding/tasks/T005-scaffold-verification.md +0 -40
  60. package/.savepoint/releases/v1/epics/_archived/E02-data-model/Design.md +0 -142
  61. package/.savepoint/releases/v1/epics/_archived/E02-data-model/tasks/T001-domain-ids-status.md +0 -27
  62. package/.savepoint/releases/v1/epics/_archived/E02-data-model/tasks/T002-markdown-frontmatter-boundary.md +0 -28
  63. package/.savepoint/releases/v1/epics/_archived/E02-data-model/tasks/T003-task-documents.md +0 -29
  64. package/.savepoint/releases/v1/epics/_archived/E02-data-model/tasks/T004-release-epic-router-config-readers.md +0 -30
  65. package/.savepoint/releases/v1/epics/_archived/E02-data-model/tasks/T005-dependency-validation.md +0 -29
  66. package/.savepoint/releases/v1/epics/_archived/E02-data-model/tasks/T006-epic-task-set-reader.md +0 -29
  67. package/.savepoint/releases/v1/epics/_archived/E02-data-model/tasks/T007-quality-gates.md +0 -31
  68. package/.savepoint/releases/v1/epics/_archived/E02-domain-phase-model/Design.md +0 -40
  69. package/.savepoint/releases/v1/epics/_archived/E02-domain-phase-model/tasks/T001-phase-types.md +0 -27
  70. package/.savepoint/releases/v1/epics/_archived/E02-domain-phase-model/tasks/T002-phase-frontmatter.md +0 -25
  71. package/.savepoint/releases/v1/epics/_archived/E02-domain-phase-model/tasks/T003-simplify-config.md +0 -26
  72. package/.savepoint/releases/v1/epics/_archived/E02-domain-phase-model/tasks/T004-simplify-router-domain.md +0 -24
  73. package/.savepoint/releases/v1/epics/_archived/E03-cli-foundation/Design.md +0 -122
  74. package/.savepoint/releases/v1/epics/_archived/E03-cli-foundation/tasks/T001-argument-parser-contract.md +0 -28
  75. package/.savepoint/releases/v1/epics/_archived/E03-cli-foundation/tasks/T002-help-text-generation.md +0 -28
  76. package/.savepoint/releases/v1/epics/_archived/E03-cli-foundation/tasks/T003-terminal-environment-detection.md +0 -27
  77. package/.savepoint/releases/v1/epics/_archived/E03-cli-foundation/tasks/T004-command-stub-modules.md +0 -29
  78. package/.savepoint/releases/v1/epics/_archived/E03-cli-foundation/tasks/T005-cli-runner-dispatch.md +0 -34
  79. package/.savepoint/releases/v1/epics/_archived/E03-cli-foundation/tasks/T006-entrypoint-quality-gates.md +0 -32
  80. package/.savepoint/releases/v1/epics/_archived/E03-cli-simplify/Design.md +0 -43
  81. package/.savepoint/releases/v1/epics/_archived/E03-cli-simplify/tasks/T001-strip-args.md +0 -26
  82. package/.savepoint/releases/v1/epics/_archived/E03-cli-simplify/tasks/T002-strip-help.md +0 -23
  83. package/.savepoint/releases/v1/epics/_archived/E03-cli-simplify/tasks/T003-strip-run.md +0 -23
  84. package/.savepoint/releases/v1/epics/_archived/E03-cli-simplify/tasks/T004-delete-commands.md +0 -24
  85. package/.savepoint/releases/v1/epics/_archived/E03-cli-simplify/tasks/T005-update-cli-tests.md +0 -22
  86. package/.savepoint/releases/v1/epics/_archived/E04-board-phase-integration/Design.md +0 -48
  87. package/.savepoint/releases/v1/epics/_archived/E04-board-phase-integration/tasks/T001-board-data-phases.md +0 -26
  88. package/.savepoint/releases/v1/epics/_archived/E04-board-phase-integration/tasks/T002-phase-rendering.md +0 -28
  89. package/.savepoint/releases/v1/epics/_archived/E04-board-phase-integration/tasks/T003-detail-pane-phases.md +0 -27
  90. package/.savepoint/releases/v1/epics/_archived/E04-board-phase-integration/tasks/T004-phase-transitions.md +0 -42
  91. package/.savepoint/releases/v1/epics/_archived/E04-board-phase-integration/tasks/T005-phase-gates.md +0 -24
  92. package/.savepoint/releases/v1/epics/_archived/E04-board-phase-integration/tasks/T006-phase-write-back.md +0 -24
  93. package/.savepoint/releases/v1/epics/_archived/E04-board-phase-integration/tasks/T007-remove-audit-flow.md +0 -27
  94. package/.savepoint/releases/v1/epics/_archived/E04-board-phase-integration/tasks/T008-board-tests.md +0 -25
  95. package/.savepoint/releases/v1/epics/_archived/E04-templates-and-prompts/Design.md +0 -85
  96. package/.savepoint/releases/v1/epics/_archived/E04-templates-and-prompts/tasks/T001-project-template-assets.md +0 -17
  97. package/.savepoint/releases/v1/epics/_archived/E04-templates-and-prompts/tasks/T002-release-and-prompt-assets.md +0 -20
  98. package/.savepoint/releases/v1/epics/_archived/E04-templates-and-prompts/tasks/T003-template-registry-renderer.md +0 -22
  99. package/.savepoint/releases/v1/epics/_archived/E04-templates-and-prompts/tasks/T004-template-integrity-tests.md +0 -17
  100. package/.savepoint/releases/v1/epics/_archived/E04-templates-and-prompts/tasks/T005-template-closeout-quality-gates.md +0 -16
  101. package/.savepoint/releases/v1/epics/_archived/E05-init-command/Design.md +0 -88
  102. package/.savepoint/releases/v1/epics/_archived/E05-init-command/tasks/T001-init-cli-contract.md +0 -22
  103. package/.savepoint/releases/v1/epics/_archived/E05-init-command/tasks/T002-target-validation.md +0 -23
  104. package/.savepoint/releases/v1/epics/_archived/E05-init-command/tasks/T003-scaffold-writer.md +0 -24
  105. package/.savepoint/releases/v1/epics/_archived/E05-init-command/tasks/T004-magic-prompt-and-clipboard.md +0 -23
  106. package/.savepoint/releases/v1/epics/_archived/E05-init-command/tasks/T005-dev-deps-install-option.md +0 -24
  107. package/.savepoint/releases/v1/epics/_archived/E05-init-command/tasks/T006-init-command-integration.md +0 -28
  108. package/.savepoint/releases/v1/epics/_archived/E05-project-cleanup/Design.md +0 -53
  109. package/.savepoint/releases/v1/epics/_archived/E05-project-cleanup/tasks/T001-delete-dead-src.md +0 -23
  110. package/.savepoint/releases/v1/epics/_archived/E05-project-cleanup/tasks/T002-delete-dead-tests.md +0 -26
  111. package/.savepoint/releases/v1/epics/_archived/E05-project-cleanup/tasks/T003-delete-assets.md +0 -25
  112. package/.savepoint/releases/v1/epics/_archived/E05-project-cleanup/tasks/T004-clean-savepoint.md +0 -28
  113. package/.savepoint/releases/v1/epics/_archived/E05-project-cleanup/tasks/T005-rewrite-agents-md.md +0 -28
  114. package/.savepoint/releases/v1/epics/_archived/E05-project-cleanup/tasks/T006-clean-package-json.md +0 -23
  115. package/.savepoint/releases/v1/epics/_archived/E05-project-cleanup/tasks/T007-verify.md +0 -25
  116. package/.savepoint/releases/v1/epics/_archived/E06-tui-board/Design.md +0 -104
  117. package/.savepoint/releases/v1/epics/_archived/E06-tui-board/tasks/T001-board-command-data.md +0 -23
  118. package/.savepoint/releases/v1/epics/_archived/E06-tui-board/tasks/T002-board-view-state.md +0 -24
  119. package/.savepoint/releases/v1/epics/_archived/E06-tui-board/tasks/T003-transition-gates-and-writes.md +0 -25
  120. package/.savepoint/releases/v1/epics/_archived/E06-tui-board/tasks/T004-terminal-theme.md +0 -23
  121. package/.savepoint/releases/v1/epics/_archived/E06-tui-board/tasks/T005-ink-board-ui.md +0 -26
  122. package/.savepoint/releases/v1/epics/_archived/E06-tui-board/tasks/T006-board-integration-audit-entry.md +0 -24
  123. package/.savepoint/releases/v1/epics/_archived/E07-audit-pipeline/Design.md +0 -88
  124. package/.savepoint/releases/v1/epics/_archived/E07-audit-pipeline/tasks/T001-audit-cli-contract.md +0 -23
  125. package/.savepoint/releases/v1/epics/_archived/E07-audit-pipeline/tasks/T002-quality-gate-runner.md +0 -23
  126. package/.savepoint/releases/v1/epics/_archived/E07-audit-pipeline/tasks/T003-snapshot-and-prompt.md +0 -23
  127. package/.savepoint/releases/v1/epics/_archived/E07-audit-pipeline/tasks/T004-audit-orchestration-router.md +0 -27
  128. package/.savepoint/releases/v1/epics/_archived/E07-audit-pipeline/tasks/T005-proposal-validation-apply.md +0 -25
  129. package/.savepoint/releases/v1/epics/_archived/E07-audit-pipeline/tasks/T006-audit-review-state.md +0 -24
  130. package/.savepoint/releases/v1/epics/_archived/E07-audit-pipeline/tasks/T007-audit-review-ui.md +0 -26
  131. package/.savepoint/releases/v1/epics/_archived/E07-audit-pipeline/tasks/T008-audit-pipeline-integration.md +0 -24
  132. package/.savepoint/releases/v1/epics/_archived/E08-board-workflow-cleanup/Design.md +0 -103
  133. package/.savepoint/releases/v1/epics/_archived/E08-board-workflow-cleanup/tasks/T001-acceptance-criteria-model.md +0 -30
  134. package/.savepoint/releases/v1/epics/_archived/E08-board-workflow-cleanup/tasks/T002-release-task-set-reader.md +0 -33
  135. package/.savepoint/releases/v1/epics/_archived/E08-board-workflow-cleanup/tasks/T003-board-data-and-plain-output.md +0 -34
  136. package/.savepoint/releases/v1/epics/_archived/E08-board-workflow-cleanup/tasks/T004-board-selection-state.md +0 -33
  137. package/.savepoint/releases/v1/epics/_archived/E08-board-workflow-cleanup/tasks/T005-ink-board-layout-cleanup.md +0 -37
  138. package/.savepoint/releases/v1/epics/_archived/E08-board-workflow-cleanup/tasks/T006-task-detail-popup.md +0 -36
  139. package/.savepoint/releases/v1/epics/_archived/E08-board-workflow-cleanup/tasks/T007-templates-acceptance-criteria.md +0 -34
  140. package/.savepoint/releases/v1/epics/_archived/E08-board-workflow-cleanup/tasks/T008-board-workflow-integration.md +0 -41
  141. package/.savepoint/releases/v1/epics/_archived/E09-doctor-command/Design.md +0 -70
  142. package/.savepoint/releases/v1/epics/_archived/E10-docs-and-packaging/Design.md +0 -68
  143. package/.savepoint/releases/v1/epics/_archived/E11-release-validation/Design.md +0 -68
  144. package/.savepoint/releases/v1/v1-PRD.md +0 -66
  145. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/E01-Detail.md +0 -40
  146. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T001-next-activity-header.md +0 -56
  147. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T002-rename-epic-design-files.md +0 -38
  148. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T003-rename-release-prd.md +0 -28
  149. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T004-update-instruction-files.md +0 -51
  150. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T005-update-cross-references.md +0 -45
  151. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T006-column-and-detail-scrolling.md +0 -68
  152. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T007-column-focus-border-stability.md +0 -57
  153. package/.savepoint/releases/v1.1/epics/E02-cross-platform-compatibility/E02-Audit.md +0 -124
  154. package/.savepoint/releases/v1.1/epics/E02-cross-platform-compatibility/E02-Detail.md +0 -49
  155. package/.savepoint/releases/v1.1/epics/E02-cross-platform-compatibility/tasks/T001-fix-makefile.md +0 -37
  156. package/.savepoint/releases/v1.1/epics/E02-cross-platform-compatibility/tasks/T002-linux-build-target.md +0 -38
  157. package/.savepoint/releases/v1.1/epics/E02-cross-platform-compatibility/tasks/T003-macos-build-target.md +0 -36
  158. package/.savepoint/releases/v1.1/epics/E02-cross-platform-compatibility/tasks/T004-smoke-tests-and-artifacts.md +0 -59
  159. package/.savepoint/releases/v1.1/epics/E03-ui-visual-refinement/E03-Audit.md +0 -195
  160. package/.savepoint/releases/v1.1/epics/E03-ui-visual-refinement/E03-Detail.md +0 -45
  161. package/.savepoint/releases/v1.1/epics/E03-ui-visual-refinement/tasks/T001-border-resize-fix.md +0 -40
  162. package/.savepoint/releases/v1.1/epics/E03-ui-visual-refinement/tasks/T002-next-activity-below-header.md +0 -64
  163. package/.savepoint/releases/v1.1/epics/E03-ui-visual-refinement/tasks/T003-checkbox-rendering-fix.md +0 -56
  164. package/.savepoint/releases/v1.1/epics/E03-ui-visual-refinement/tasks/T005-unify-status-glyphs.md +0 -65
  165. package/.savepoint/releases/v1.1/epics/E03-ui-visual-refinement/tasks/T006-forced-256-color-profile.md +0 -36
  166. package/.savepoint/releases/v1.1/epics/E04-epic-navigation/E04-Audit.md +0 -167
  167. package/.savepoint/releases/v1.1/epics/E04-epic-navigation/E04-Detail.md +0 -51
  168. package/.savepoint/releases/v1.1/epics/E04-epic-navigation/tasks/T001-sidebar-focusable-navigation.md +0 -65
  169. package/.savepoint/releases/v1.1/epics/E04-epic-navigation/tasks/T002-epic-detail-overlay.md +0 -73
  170. package/.savepoint/releases/v1.1/epics/E04-epic-navigation/tasks/T003-epic-status-glyphs.md +0 -73
  171. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/E05-Audit.md +0 -237
  172. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/E05-Detail.md +0 -54
  173. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T001-update-agents-md.md +0 -45
  174. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T002-update-router-md.md +0 -40
  175. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T003-update-design-md.md +0 -47
  176. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T004-implement-m-hotkey.md +0 -98
  177. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T005-update-help-overlay.md +0 -33
  178. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T006-tests-and-quality-gates.md +0 -62
  179. package/.savepoint/releases/v1.1/epics/E06-audit-command/E06-Audit.md +0 -56
  180. package/.savepoint/releases/v1.1/epics/E06-audit-command/E06-Detail.md +0 -63
  181. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T005-proposals.md +0 -44
  182. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T007-apply-close.md +0 -35
  183. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T009-integration.md +0 -40
  184. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T010-audit-file-migration.md +0 -45
  185. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T011-model-tab-state.md +0 -26
  186. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T012-epic-audit-render.md +0 -33
  187. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T013-handle-tab-keys.md +0 -34
  188. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T014-tab-indicator.md +0 -33
  189. package/.savepoint/releases/v1.1/epics/E07-init-command/E07-Audit.md +0 -336
  190. package/.savepoint/releases/v1.1/epics/E07-init-command/E07-Detail.md +0 -61
  191. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T001-cli-entrypoint.md +0 -37
  192. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T002-target-validation.md +0 -28
  193. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T003-scaffold-writer.md +0 -46
  194. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T004-atomic-writes.md +0 -27
  195. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T005-magic-prompt.md +0 -25
  196. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T006-clipboard.md +0 -26
  197. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T007-integration-test.md +0 -26
  198. package/.savepoint/releases/v1.1/epics/E08-board-command/E08-Audit.md +0 -333
  199. package/.savepoint/releases/v1.1/epics/E08-board-command/E08-Detail.md +0 -68
  200. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T001-cli-entrypoint.md +0 -26
  201. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T002-non-tty-fallback.md +0 -27
  202. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T003-tui-app-shell.md +0 -28
  203. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T004-board-model.md +0 -29
  204. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T005-detail-pane.md +0 -27
  205. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T006-status-transitions.md +0 -29
  206. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T007-theme-fallbacks.md +0 -29
  207. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T008-integration-test.md +0 -27
  208. package/.savepoint/releases/v1.1/epics/E09-doctor-command/E09-Audit.md +0 -207
  209. package/.savepoint/releases/v1.1/epics/E09-doctor-command/E09-Detail.md +0 -65
  210. package/.savepoint/releases/v1.1/epics/E09-doctor-command/tasks/T001-cli-entrypoint.md +0 -24
  211. package/.savepoint/releases/v1.1/epics/E09-doctor-command/tasks/T002-config-router-validation.md +0 -28
  212. package/.savepoint/releases/v1.1/epics/E09-doctor-command/tasks/T003-structure-checks.md +0 -29
  213. package/.savepoint/releases/v1.1/epics/E09-doctor-command/tasks/T004-dependency-checks.md +0 -27
  214. package/.savepoint/releases/v1.1/epics/E09-doctor-command/tasks/T005-audit-orphan-checks.md +0 -28
  215. package/.savepoint/releases/v1.1/epics/E09-doctor-command/tasks/T006-quality-gates-report.md +0 -31
  216. package/.savepoint/releases/v1.1/epics/E11-board-refresh-fix/E11-Detail.md +0 -36
  217. package/.savepoint/releases/v1.1/epics/E11-board-refresh-fix/tasks/T001-debug-logging.md +0 -25
  218. package/.savepoint/releases/v1.1/epics/E11-board-refresh-fix/tasks/T002-increase-debounce.md +0 -21
  219. package/.savepoint/releases/v1.1/epics/E11-board-refresh-fix/tasks/T003-error-handling.md +0 -22
  220. package/.savepoint/releases/v1.1/epics/E11-board-refresh-fix/tasks/T004-test-verify.md +0 -29
  221. package/.savepoint/releases/v1.1/epics/E12-validation-fix/E12-Audit.md +0 -444
  222. package/.savepoint/releases/v1.1/epics/E12-validation-fix/E12-Detail.md +0 -45
  223. package/.savepoint/releases/v1.1/epics/E12-validation-fix/tasks/T001-default-phase.md +0 -35
  224. package/.savepoint/releases/v1.1/epics/E12-validation-fix/tasks/T002-default-status.md +0 -19
  225. package/.savepoint/releases/v1.1/epics/E12-validation-fix/tasks/T003-better-errors.md +0 -29
  226. package/.savepoint/releases/v1.1/epics/E12-validation-fix/tasks/T004-validate-on-write.md +0 -25
  227. package/.savepoint/releases/v1.1/epics/E12-validation-fix/tasks/T005-tests.md +0 -37
  228. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/E13-Audit.md +0 -118
  229. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/E13-Detail.md +0 -73
  230. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T001-safe-cleanup.md +0 -66
  231. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T002-bug-fixes.md +0 -35
  232. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T003-centralize-duplication.md +0 -60
  233. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T004-infrastructure.md +0 -33
  234. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T005-decompose-update.md +0 -37
  235. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T006-async-io.md +0 -40
  236. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T007-test-coverage.md +0 -37
  237. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/E14-Audit.md +0 -267
  238. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/E14-Detail.md +0 -54
  239. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T001-group-model.md +0 -39
  240. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T002-data-interfaces.md +0 -42
  241. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T003-discover-orphans.md +0 -33
  242. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T004-epic-panel-headings.md +0 -35
  243. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T005-shell-tokenization.md +0 -27
  244. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T006-unify-enums.md +0 -29
  245. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T007-testutil-package.md +0 -28
  246. package/.savepoint/releases/v1.1/epics/E15-hardening/E15-Detail.md +0 -43
  247. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T001-benchmarks.md +0 -31
  248. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T002-fuzz-targets.md +0 -28
  249. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T003-debug-flag.md +0 -30
  250. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T004-dist-checksums.md +0 -27
  251. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T005-windows-targets.md +0 -28
  252. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T006-abbreviation-splitting.md +0 -26
  253. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T007-root-test-allowlist.md +0 -28
  254. package/.savepoint/releases/v1.1/epics/_archived/T001-cli-entrypoint.md +0 -25
  255. package/.savepoint/releases/v1.1/epics/_archived/T002-quality-gates.md +0 -27
  256. package/.savepoint/releases/v1.1/epics/_archived/T003-snapshot.md +0 -27
  257. package/.savepoint/releases/v1.1/epics/_archived/T004-ai-reconcile.md +0 -29
  258. package/.savepoint/releases/v1.1/epics/_archived/T006-tui-review.md +0 -31
  259. package/.savepoint/releases/v1.1/epics/_archived/T008-skip-handling.md +0 -34
  260. package/.savepoint/releases/v1.1/v1.1-PRD.md +0 -139
  261. package/.savepoint/router.md +0 -57
  262. package/.savepoint/visual-identity.md +0 -125
  263. package/AGENTS.md +0 -99
  264. package/CLAUDE.md +0 -1
  265. package/GEMINI.md +0 -1
  266. package/Makefile +0 -29
  267. package/agent-skills/ink-tui-design/SKILL.md +0 -309
  268. package/agent-skills/ink-tui-design/references/component-patterns.md +0 -371
  269. package/agent-skills/ink-tui-design/references/hooks-guide.md +0 -436
  270. package/agent-skills/ink-tui-design/references/ink-gotchas.md +0 -330
  271. package/agent-skills/ink-tui-design/references/testing-patterns.md +0 -384
  272. package/agent-skills/savepoint-audit/SKILL.md +0 -87
  273. package/agent-skills/savepoint-build-task/SKILL.md +0 -44
  274. package/agent-skills/savepoint-create-plan/SKILL.md +0 -33
  275. package/agent-skills/savepoint-create-task/SKILL.md +0 -44
  276. package/agent-skills/savepoint-draft-prd/SKILL.md +0 -37
  277. package/agent-skills/savepoint-system-design/SKILL.md +0 -38
  278. package/agent-skills/superpowers/brainstorming/SKILL.md +0 -165
  279. package/agent-skills/superpowers/brainstorming/visual-companion.md +0 -304
  280. package/agent-skills/superpowers/dispatching-parallel-agents/SKILL.md +0 -193
  281. package/agent-skills/superpowers/executing-plans/SKILL.md +0 -77
  282. package/agent-skills/superpowers/finishing-a-development-branch/SKILL.md +0 -213
  283. package/agent-skills/superpowers/receiving-code-review/SKILL.md +0 -226
  284. package/agent-skills/superpowers/requesting-code-review/SKILL.md +0 -115
  285. package/agent-skills/superpowers/requesting-code-review/code-reviewer.md +0 -160
  286. package/agent-skills/superpowers/subagent-driven-development/SKILL.md +0 -292
  287. package/agent-skills/superpowers/subagent-driven-development/code-quality-reviewer-prompt.md +0 -27
  288. package/agent-skills/superpowers/subagent-driven-development/implementer-prompt.md +0 -113
  289. package/agent-skills/superpowers/subagent-driven-development/spec-reviewer-prompt.md +0 -61
  290. package/agent-skills/superpowers/systematic-debugging/SKILL.md +0 -305
  291. package/agent-skills/superpowers/systematic-debugging/condition-based-waiting.md +0 -122
  292. package/agent-skills/superpowers/systematic-debugging/defense-in-depth.md +0 -130
  293. package/agent-skills/superpowers/systematic-debugging/root-cause-tracing.md +0 -183
  294. package/agent-skills/superpowers/test-driven-development/SKILL.md +0 -389
  295. package/agent-skills/superpowers/test-driven-development/testing-anti-patterns.md +0 -317
  296. package/agent-skills/superpowers/verification-before-completion/SKILL.md +0 -147
  297. package/agent-skills/superpowers/writing-plans/SKILL.md +0 -159
  298. package/agent-skills/superpowers/writing-plans/plan-document-reviewer-prompt.md +0 -49
  299. package/agent_skills_test.go +0 -91
  300. package/assets/banner.png +0 -0
  301. package/assets/logo.png +0 -0
  302. package/assets/strawman.png +0 -0
  303. package/cmd/board.go +0 -59
  304. package/cmd/board_test.go +0 -137
  305. package/cmd/doctor.go +0 -53
  306. package/cmd/doctor_test.go +0 -146
  307. package/cmd/init.go +0 -63
  308. package/cmd/init_test.go +0 -104
  309. package/go.mod +0 -36
  310. package/go.sum +0 -75
  311. package/internal/board/board.go +0 -177
  312. package/internal/board/board_test.go +0 -168
  313. package/internal/board/card.go +0 -129
  314. package/internal/board/card_test.go +0 -254
  315. package/internal/board/column.go +0 -127
  316. package/internal/board/column_test.go +0 -139
  317. package/internal/board/detail.go +0 -185
  318. package/internal/board/detail_test.go +0 -340
  319. package/internal/board/epic_panel.go +0 -262
  320. package/internal/board/epic_panel_test.go +0 -869
  321. package/internal/board/help.go +0 -41
  322. package/internal/board/help_test.go +0 -86
  323. package/internal/board/integration_test.go +0 -266
  324. package/internal/board/interfaces.go +0 -65
  325. package/internal/board/interfaces_test.go +0 -114
  326. package/internal/board/io.go +0 -93
  327. package/internal/board/layout.go +0 -68
  328. package/internal/board/layout_test.go +0 -106
  329. package/internal/board/model.go +0 -235
  330. package/internal/board/model_test.go +0 -67
  331. package/internal/board/plain.go +0 -88
  332. package/internal/board/plain_test.go +0 -117
  333. package/internal/board/release.go +0 -34
  334. package/internal/board/release_test.go +0 -177
  335. package/internal/board/render_policy_test.go +0 -77
  336. package/internal/board/status.go +0 -23
  337. package/internal/board/theme.go +0 -24
  338. package/internal/board/theme_test.go +0 -31
  339. package/internal/board/transitions.go +0 -113
  340. package/internal/board/transitions_test.go +0 -164
  341. package/internal/board/tui.go +0 -32
  342. package/internal/board/update.go +0 -556
  343. package/internal/board/update_test.go +0 -575
  344. package/internal/board/util.go +0 -76
  345. package/internal/board/view.go +0 -317
  346. package/internal/board/view_test.go +0 -315
  347. package/internal/board/watch.go +0 -130
  348. package/internal/buildtool/main.go +0 -211
  349. package/internal/buildtool/main_test.go +0 -46
  350. package/internal/data/config.go +0 -101
  351. package/internal/data/config_test.go +0 -122
  352. package/internal/data/discover.go +0 -178
  353. package/internal/data/discover_test.go +0 -130
  354. package/internal/data/errors.go +0 -13
  355. package/internal/data/lifecycle.go +0 -44
  356. package/internal/data/lifecycle_test.go +0 -41
  357. package/internal/data/parser.go +0 -242
  358. package/internal/data/parser_test.go +0 -281
  359. package/internal/data/router.go +0 -52
  360. package/internal/data/router_test.go +0 -35
  361. package/internal/data/task.go +0 -57
  362. package/internal/data/task_test.go +0 -51
  363. package/internal/data/write.go +0 -218
  364. package/internal/data/write_test.go +0 -623
  365. package/internal/doctor/checks.go +0 -567
  366. package/internal/doctor/checks_test.go +0 -716
  367. package/internal/doctor/gates.go +0 -193
  368. package/internal/doctor/gates_test.go +0 -166
  369. package/internal/doctor/interfaces.go +0 -64
  370. package/internal/doctor/interfaces_test.go +0 -104
  371. package/internal/doctor/repairs.go +0 -80
  372. package/internal/doctor/repairs_test.go +0 -81
  373. package/internal/doctor/report.go +0 -157
  374. package/internal/doctor/report_test.go +0 -89
  375. package/internal/init/clipboard.go +0 -146
  376. package/internal/init/clipboard_test.go +0 -74
  377. package/internal/init/install.go +0 -16
  378. package/internal/init/integration_test.go +0 -197
  379. package/internal/init/prompt.go +0 -14
  380. package/internal/init/prompt_test.go +0 -77
  381. package/internal/init/scaffold.go +0 -59
  382. package/internal/init/scaffold_test.go +0 -179
  383. package/internal/init/template_freshness_test.go +0 -56
  384. package/internal/init/validate.go +0 -85
  385. package/internal/init/validate_test.go +0 -141
  386. package/internal/init/write.go +0 -73
  387. package/internal/init/write_test.go +0 -91
  388. package/internal/styles/palette.go +0 -49
  389. package/internal/styles/styles.go +0 -139
  390. package/internal/styles/styles_test.go +0 -133
  391. package/internal/testutil/fixture.go +0 -113
  392. package/internal/testutil/fs.go +0 -26
  393. package/main.go +0 -117
  394. package/project-audit/audit_report_glm_5.1.md +0 -411
  395. package/project-audit/audit_report_opus_4.6 +0 -406
  396. package/project-audit/consolidated-audit-report.md +0 -456
  397. package/scripts/vitest-preload.cjs +0 -95
  398. package/templates/project/.savepoint/Design.md +0 -47
  399. package/templates/project/.savepoint/PRD.md +0 -34
  400. package/templates/project/.savepoint/config.yml +0 -27
  401. package/templates/project/.savepoint/router.md +0 -153
  402. package/templates/project/.savepoint/visual-identity.md +0 -122
  403. package/templates/project/AGENTS.md +0 -88
  404. package/templates/project/agent-skills/savepoint-audit/SKILL.md +0 -87
  405. package/templates/project/agent-skills/savepoint-build-task/SKILL.md +0 -44
  406. package/templates/project/agent-skills/savepoint-create-plan/SKILL.md +0 -33
  407. package/templates/project/agent-skills/savepoint-create-task/SKILL.md +0 -44
  408. package/templates/project/agent-skills/savepoint-draft-prd/SKILL.md +0 -37
  409. package/templates/project/agent-skills/savepoint-system-design/SKILL.md +0 -38
  410. package/templates/prompts/audit-reconciliation.prompt.md +0 -72
  411. package/templates/prompts/design.prompt.md +0 -45
  412. package/templates/prompts/epic-design.prompt.md +0 -43
  413. package/templates/prompts/magic-prompt.prompt.md +0 -7
  414. package/templates/prompts/prd.prompt.md +0 -42
  415. package/templates/prompts/task-breakdown.prompt.md +0 -54
  416. package/templates/prompts/task-building.prompt.md +0 -38
  417. package/templates/prompts/task-planning.prompt.md +0 -53
  418. package/templates/release/v1/PRD.md +0 -37
@@ -1,254 +0,0 @@
1
- package board
2
-
3
- import (
4
- "strings"
5
- "testing"
6
-
7
- "github.com/opencode/savepoint/internal/data"
8
- "github.com/opencode/savepoint/internal/styles"
9
- )
10
-
11
- func TestRenderCard_containsID(t *testing.T) {
12
- task := data.Task{ID: "E04/T002", Title: "Build card", Stage: data.StageBuild}
13
- got := RenderCard(task, 30, false, nil)
14
- if !strings.Contains(got, "T002") {
15
- t.Error("RenderCard missing short task ID")
16
- }
17
- }
18
-
19
- func TestRenderCard_containsTitle(t *testing.T) {
20
- task := data.Task{ID: "T1", Title: "My title", Stage: data.StageBuild}
21
- got := RenderCard(task, 30, false, nil)
22
- if !strings.Contains(got, "My title") {
23
- t.Error("RenderCard missing task title")
24
- }
25
- }
26
-
27
- func TestRenderCard_containsBuildGlyph(t *testing.T) {
28
- task := data.Task{ID: "T1", Stage: data.StageBuild}
29
- got := RenderCard(task, 30, false, nil)
30
- if !strings.Contains(got, glyphBuild) {
31
- t.Errorf("RenderCard missing build glyph %q", glyphBuild)
32
- }
33
- }
34
-
35
- func TestRenderCard_containsTestGlyph(t *testing.T) {
36
- task := data.Task{ID: "T1", Stage: data.StageTest}
37
- got := RenderCard(task, 30, false, nil)
38
- if !strings.Contains(got, glyphTest) {
39
- t.Errorf("RenderCard missing test glyph %q", glyphTest)
40
- }
41
- }
42
-
43
- func TestRenderCard_containsAuditGlyph(t *testing.T) {
44
- task := data.Task{ID: "T1", Stage: data.StageAudit}
45
- got := RenderCard(task, 30, false, nil)
46
- if !strings.Contains(got, glyphAudit) {
47
- t.Errorf("RenderCard missing audit glyph %q", glyphAudit)
48
- }
49
- }
50
-
51
- func TestRenderCard_focusedDoesNotPanic(t *testing.T) {
52
- task := data.Task{ID: "T1", Title: "hello", Stage: data.StageBuild}
53
- got := RenderCard(task, 30, true, nil)
54
- if got == "" {
55
- t.Error("RenderCard focused returned empty string")
56
- }
57
- }
58
-
59
- func TestRenderCard_titleWraps(t *testing.T) {
60
- long := "This is a very long title that should be wrapped for sure"
61
- task := data.Task{ID: "T1", Title: long, Stage: data.StageBuild}
62
- got := RenderCard(task, 20, false, nil)
63
- // full title as one line does not fit; it must be broken up
64
- if strings.Contains(got, long) {
65
- t.Error("RenderCard should wrap long title, not render it as one line")
66
- }
67
- // words from the title must still appear somewhere in the output
68
- if !strings.Contains(got, "This") {
69
- t.Error("RenderCard wrapped title missing expected content")
70
- }
71
- }
72
-
73
- func TestRenderCard_idTruncated(t *testing.T) {
74
- long := "E04-board-components/T999-very-long-id"
75
- task := data.Task{ID: long, Stage: data.StageBuild}
76
- got := RenderCard(task, 20, false, nil)
77
- if strings.Contains(got, long) {
78
- t.Error("RenderCard should truncate long ID")
79
- }
80
- }
81
-
82
- func TestTruncate_shortString(t *testing.T) {
83
- if truncate("hi", 10) != "hi" {
84
- t.Error("truncate should not clip short string")
85
- }
86
- }
87
-
88
- func TestTruncate_exactLength(t *testing.T) {
89
- if truncate("hello", 5) != "hello" {
90
- t.Error("truncate should not clip string at exact max")
91
- }
92
- }
93
-
94
- func TestTruncate_clipsWithEllipsis(t *testing.T) {
95
- got := truncate("hello", 4)
96
- if got != "hel…" {
97
- t.Errorf("truncate got %q, want %q", got, "hel…")
98
- }
99
- }
100
-
101
- func TestTruncate_maxOne(t *testing.T) {
102
- got := truncate("hello", 1)
103
- if got != "…" {
104
- t.Errorf("truncate(max=1) got %q, want %q", got, "…")
105
- }
106
- }
107
-
108
- func TestRenderCard_defaultStageUsesBuildGlyph(t *testing.T) {
109
- task := data.Task{ID: "T1", Stage: ""}
110
- got := RenderCard(task, 30, false, nil)
111
- if !strings.Contains(got, glyphBuild) {
112
- t.Error("RenderCard with empty stage should use build glyph")
113
- }
114
- }
115
-
116
- func TestRenderCard_routerPriorityUsesGreenGlyph(t *testing.T) {
117
- task := data.Task{ID: "E06/T009", Release: "v1", Epic: "E06", Stage: data.StageTest}
118
- router := &data.RouterState{Release: "v1", Epic: "E06", Task: "E06/T009"}
119
- got := RenderCard(task, 30, false, router)
120
- if !isRouterPriority(task, router) {
121
- t.Error("router priority should match release, epic, and task")
122
- }
123
- if !strings.Contains(got, glyphBuild) {
124
- t.Error("router priority card should use build glyph")
125
- }
126
- nonPriority := RenderCard(task, 30, false, nil)
127
- if !strings.Contains(nonPriority, glyphTest) {
128
- t.Error("non-priority test card should use test glyph")
129
- }
130
- }
131
-
132
- func TestRenderCard_noBackgroundFillEscapes(t *testing.T) {
133
- task := data.Task{ID: "E06/T009", Title: "Router priority", Release: "v1", Epic: "E06", Stage: data.StageTest}
134
- router := &data.RouterState{Release: "v1", Epic: "E06", Task: "E06/T009"}
135
- got := RenderCard(task, 30, false, router)
136
- if strings.Contains(got, "\x1b[48;") || strings.Contains(got, "\x1b[40m") {
137
- t.Fatalf("RenderCard should not emit background fills; got %q", got)
138
- }
139
- }
140
-
141
- func TestRenderCard_routerPriorityMatchesShortID(t *testing.T) {
142
- // Router stores short IDs ("T009"); task ID is full slug — must still match.
143
- task := data.Task{ID: "E06-atari-noir-layout/T009-router-priority", Release: "v1", Epic: "E06-atari-noir-layout", Stage: data.StageTest}
144
- router := &data.RouterState{Release: "v1", Epic: "E06", Task: "T009"}
145
- got := RenderCard(task, 30, false, router)
146
- if !isRouterPriority(task, router) {
147
- t.Error("short router task ID should match full task ID slug")
148
- }
149
- if !strings.Contains(got, glyphBuild) {
150
- t.Error("router priority card should use build glyph")
151
- }
152
- }
153
-
154
- func TestRenderCard_staleRouterTaskNoMatch(t *testing.T) {
155
- // Task moved to a new epic; router still has old epic path — should NOT match a different task number.
156
- task := data.Task{ID: "E03-header-activity/T001-border-resize-fix", Release: "v1", Epic: "E03-header-activity", Stage: data.StageBuild}
157
- router := &data.RouterState{Release: "v1", Epic: "E03", Task: "T002"}
158
- got := RenderCard(task, 30, false, router)
159
- if isRouterPriority(task, router) {
160
- t.Error("stale router pointing to different task number should not show green glyph")
161
- }
162
- if !strings.Contains(got, styles.GlyphBuild.Render(glyphBuild)) {
163
- t.Error("non-priority build task should use orange build glyph")
164
- }
165
- }
166
-
167
- func TestRenderCard_routerSameTaskNumberDifferentEpicNoMatch(t *testing.T) {
168
- task := data.Task{ID: "E03-header-activity/T001-border-resize-fix", Release: "v1", Epic: "E03-header-activity", Stage: data.StageTest}
169
- router := &data.RouterState{Release: "v1", Epic: "E01", Task: "T001"}
170
- got := RenderCard(task, 30, false, router)
171
- if isRouterPriority(task, router) {
172
- t.Error("router priority should not match same task number in a different epic")
173
- }
174
- if !strings.Contains(got, styles.GlyphTest.Render(glyphTest)) {
175
- t.Error("non-priority test task should keep test glyph")
176
- }
177
- }
178
-
179
- func TestRenderCard_doneTaskUsesOrangeBuildGlyph(t *testing.T) {
180
- task := data.Task{ID: "E03/T001", Release: "v1", Epic: "E03", Column: data.ColumnDone, Stage: data.StageTest}
181
- router := &data.RouterState{Release: "v1", Epic: "E03", Task: "T001"}
182
- got := RenderCard(task, 30, false, router)
183
- if !isRouterPriority(task, router) {
184
- t.Error("router state should still identify the matching done task")
185
- }
186
- if !strings.Contains(got, styles.GlyphBuild.Render(glyphBuild)) {
187
- t.Error("done task should use orange build glyph")
188
- }
189
- if strings.Contains(got, glyphTest) {
190
- t.Error("done task should not use test glyph")
191
- }
192
- }
193
-
194
- func TestRenderCard_explicitStatusUsesUnifiedGlyph(t *testing.T) {
195
- tests := []struct {
196
- name string
197
- status string
198
- glyph string
199
- }{
200
- {"planned", string(data.ColumnPlanned), "○"},
201
- {"done", string(data.ColumnDone), "◉"},
202
- {"audited", "audited", "✓"},
203
- }
204
-
205
- for _, tt := range tests {
206
- t.Run(tt.name, func(t *testing.T) {
207
- task := data.Task{ID: "T1", Status: string(tt.status), Stage: data.StageAudit}
208
- got := RenderCard(task, 30, false, nil)
209
- if !strings.Contains(got, tt.glyph) {
210
- t.Errorf("RenderCard with status %q missing glyph %q", tt.status, tt.glyph)
211
- }
212
- if strings.Contains(got, glyphAudit) {
213
- t.Errorf("RenderCard with status %q should not fall back to audit glyph", tt.status)
214
- }
215
- })
216
- }
217
- }
218
-
219
- func TestRenderCard_inProgressShowsPhaseText(t *testing.T) {
220
- tests := []struct {
221
- name string
222
- stage data.ProgressStage
223
- label string
224
- glyph string
225
- }{
226
- {"build", data.StageBuild, "BUILD", glyphBuild},
227
- {"test", data.StageTest, "TEST", glyphTest},
228
- {"audit", data.StageAudit, "AUDIT", glyphAudit},
229
- }
230
-
231
- for _, tt := range tests {
232
- t.Run(tt.name, func(t *testing.T) {
233
- task := data.Task{ID: "T1", Column: data.ColumnInProgress, Status: string(data.ColumnInProgress), Stage: tt.stage}
234
- got := RenderCard(task, 30, false, nil)
235
- if !strings.Contains(got, tt.label) {
236
- t.Errorf("RenderCard missing phase label %q", tt.label)
237
- }
238
- if !strings.Contains(got, tt.glyph) {
239
- t.Errorf("RenderCard missing phase glyph %q", tt.glyph)
240
- }
241
- if strings.Contains(got, "▶") {
242
- t.Error("RenderCard should not use generic in_progress glyph when phase is available")
243
- }
244
- })
245
- }
246
- }
247
-
248
- func TestRenderCard_doneShowsDoneText(t *testing.T) {
249
- task := data.Task{ID: "T1", Column: data.ColumnDone, Status: string(data.ColumnDone)}
250
- got := RenderCard(task, 30, false, nil)
251
- if !strings.Contains(got, "DONE") {
252
- t.Error("RenderCard missing DONE phase label")
253
- }
254
- }
@@ -1,127 +0,0 @@
1
- package board
2
-
3
- import (
4
- "fmt"
5
- "strings"
6
-
7
- "github.com/opencode/savepoint/internal/data"
8
- "github.com/opencode/savepoint/internal/styles"
9
- )
10
-
11
- // RenderColumn renders a board column: header with label+count, task viewport, bordered container.
12
- func RenderColumn(tasks []data.Task, col data.ColumnType, width, maxHeight, offset, focusedTask int, focused bool, routerState *data.RouterState) string {
13
- inner := width - colOverhead
14
- if inner < minColWidth {
15
- inner = minColWidth
16
- }
17
- offset = clampViewportOffset(offset, len(tasks))
18
-
19
- title := columnTitle(col)
20
- header := fmt.Sprintf("%s (%d)", title, len(tasks))
21
- if focused {
22
- header = styles.ColumnTitleFocused.Render(header)
23
- } else {
24
- header = styles.ColumnTitle.Render(header)
25
- }
26
-
27
- lines := []string{header, strings.Repeat("─", inner)}
28
- if len(tasks) == 0 {
29
- lines = append(lines, styles.TaskItem.Render("(empty)"))
30
- } else {
31
- contentBudget := maxHeight - 2
32
- if contentBudget < 1 {
33
- contentBudget = 1
34
- }
35
-
36
- reserveAbove := 0
37
- if offset > 0 {
38
- reserveAbove = 1
39
- }
40
-
41
- type cardEntry struct {
42
- card string
43
- lines int
44
- }
45
- cardEntries := make([]cardEntry, 0, len(tasks)-offset)
46
- for i := offset; i < len(tasks); i++ {
47
- c := RenderCard(tasks[i], inner, focused && i == focusedTask, routerState)
48
- cardEntries = append(cardEntries, cardEntry{card: c, lines: strings.Count(c, "\n") + 1})
49
- }
50
-
51
- usedLines := reserveAbove
52
- endIdx := 0
53
- for endIdx < len(cardEntries) {
54
- needsMore := endIdx < len(cardEntries)-1
55
- bottomReserve := 0
56
- if needsMore {
57
- bottomReserve = 1
58
- }
59
- if usedLines+cardEntries[endIdx].lines+bottomReserve > contentBudget {
60
- break
61
- }
62
- usedLines += cardEntries[endIdx].lines
63
- endIdx++
64
- }
65
-
66
- if endIdx == 0 && len(cardEntries) > 0 {
67
- endIdx = 1
68
- }
69
-
70
- if offset > 0 {
71
- lines = append(lines, renderScrollIndicator("↑", offset, "above"))
72
- }
73
- for i := 0; i < endIdx; i++ {
74
- lines = append(lines, cardEntries[i].card)
75
- }
76
- if endIdx < len(cardEntries) {
77
- remaining := len(tasks) - (offset + endIdx)
78
- lines = append(lines, renderScrollIndicator("↓", remaining, "more"))
79
- }
80
- }
81
-
82
- content := strings.Join(lines, "\n")
83
- st := styles.ColumnUnfocused.Width(width)
84
- if focused {
85
- st = styles.ColumnFocused.Width(width)
86
- }
87
- return st.Render(content)
88
- }
89
-
90
- func visibleColumnTaskLimit(maxHeight int) int {
91
- if maxHeight <= 0 {
92
- return 999999
93
- }
94
- limit := (maxHeight - 2) / 3
95
- if limit < 1 {
96
- return 1
97
- }
98
- return limit
99
- }
100
-
101
- func clampViewportOffset(offset, total int) int {
102
- if offset < 0 || total <= 0 {
103
- return 0
104
- }
105
- if offset >= total {
106
- return total - 1
107
- }
108
- return offset
109
- }
110
-
111
- func renderScrollIndicator(arrow string, count int, suffix string) string {
112
- return styles.ScrollIndicator.Render(fmt.Sprintf("%s %d %s", arrow, count, suffix))
113
- }
114
-
115
- func columnTitle(col data.ColumnType) string {
116
- switch col {
117
- case data.ColumnPlanned:
118
- return "PLANNED"
119
- case data.ColumnInProgress:
120
- return "IN PROGRESS"
121
- case data.ColumnDone:
122
- return "DONE"
123
- default:
124
- return strings.ToUpper(string(col))
125
- }
126
- }
127
-
@@ -1,139 +0,0 @@
1
- package board
2
-
3
- import (
4
- "strings"
5
- "testing"
6
-
7
- "github.com/charmbracelet/lipgloss"
8
- "github.com/opencode/savepoint/internal/data"
9
- )
10
-
11
- func TestRenderColumn_headerContainsLabel(t *testing.T) {
12
- got := RenderColumn(nil, data.ColumnPlanned, 30, 0, 0, 0, false, nil)
13
- if !strings.Contains(got, "PLANNED") {
14
- t.Error("RenderColumn missing PLANNED label")
15
- }
16
- }
17
-
18
- func TestRenderColumn_headerContainsCount(t *testing.T) {
19
- tasks := []data.Task{{ID: "T1", Title: "Task one", Column: data.ColumnPlanned}}
20
- got := RenderColumn(tasks, data.ColumnPlanned, 30, 0, 0, 0, false, nil)
21
- if !strings.Contains(got, "(1)") {
22
- t.Error("RenderColumn missing task count")
23
- }
24
- }
25
-
26
- func TestRenderColumn_emptyShowsPlaceholder(t *testing.T) {
27
- got := RenderColumn(nil, data.ColumnDone, 30, 0, 0, 0, false, nil)
28
- if !strings.Contains(got, "(empty)") {
29
- t.Error("RenderColumn missing (empty) for empty column")
30
- }
31
- }
32
-
33
- func TestRenderColumn_focusedDoesNotPanic(t *testing.T) {
34
- tasks := []data.Task{{ID: "T1", Column: data.ColumnInProgress}}
35
- got := RenderColumn(tasks, data.ColumnInProgress, 30, 0, 0, 0, true, nil)
36
- if got == "" {
37
- t.Error("RenderColumn returned empty string for focused column")
38
- }
39
- }
40
-
41
- func TestRenderColumn_allColumnTitles(t *testing.T) {
42
- cases := []struct {
43
- col data.ColumnType
44
- label string
45
- }{
46
- {data.ColumnPlanned, "PLANNED"},
47
- {data.ColumnInProgress, "IN PROGRESS"},
48
- {data.ColumnDone, "DONE"},
49
- }
50
- for _, tc := range cases {
51
- got := RenderColumn(nil, tc.col, 30, 0, 0, 0, false, nil)
52
- if !strings.Contains(got, tc.label) {
53
- t.Errorf("RenderColumn missing label %q for col %q", tc.label, tc.col)
54
- }
55
- }
56
- }
57
-
58
- func TestRenderColumn_taskTitleRendered(t *testing.T) {
59
- tasks := []data.Task{{ID: "T2", Title: "Build it", Column: data.ColumnPlanned}}
60
- got := RenderColumn(tasks, data.ColumnPlanned, 30, 0, 0, 0, false, nil)
61
- if !strings.Contains(got, "Build it") {
62
- t.Error("RenderColumn missing task title")
63
- }
64
- }
65
-
66
- func TestRenderColumn_rendersTaskCards(t *testing.T) {
67
- tasks := []data.Task{{ID: "T2", Title: "Build it", Column: data.ColumnPlanned, Stage: data.StageAudit}}
68
- got := RenderColumn(tasks, data.ColumnPlanned, 30, 0, 0, 0, true, nil)
69
- if !strings.Contains(got, glyphAudit) {
70
- t.Error("RenderColumn should render task phase glyph from card")
71
- }
72
- if !strings.Contains(got, "┌") {
73
- t.Error("RenderColumn should render focused card border")
74
- }
75
- }
76
-
77
- func TestRenderColumn_focusStatesUseStableBorderDimensions(t *testing.T) {
78
- tasks := []data.Task{{ID: "T2", Title: "Build it", Column: data.ColumnPlanned, Stage: data.StageAudit}}
79
- unfocused := RenderColumn(tasks, data.ColumnPlanned, 30, 0, 0, -1, false, nil)
80
- focused := RenderColumn(tasks, data.ColumnPlanned, 30, 0, 0, -1, true, nil)
81
-
82
- if !strings.Contains(unfocused, "┌") {
83
- t.Error("unfocused column should render a single-line border")
84
- }
85
- if !strings.Contains(focused, "┌") {
86
- t.Error("focused column should render a single-line border")
87
- }
88
-
89
- unfocusedLines := strings.Split(unfocused, "\n")
90
- focusedLines := strings.Split(focused, "\n")
91
- if len(unfocusedLines) != len(focusedLines) {
92
- t.Fatalf("line count changed between focus states: unfocused=%d focused=%d", len(unfocusedLines), len(focusedLines))
93
- }
94
- for i := range unfocusedLines {
95
- if lipgloss.Width(unfocusedLines[i]) != lipgloss.Width(focusedLines[i]) {
96
- t.Fatalf("line %d width changed between focus states: unfocused=%d focused=%d", i, lipgloss.Width(unfocusedLines[i]), lipgloss.Width(focusedLines[i]))
97
- }
98
- }
99
- }
100
-
101
- func TestRenderColumn_emptyCountIsZero(t *testing.T) {
102
- got := RenderColumn(nil, data.ColumnPlanned, 30, 0, 0, 0, false, nil)
103
- if !strings.Contains(got, "(0)") {
104
- t.Error("RenderColumn missing (0) count for empty column")
105
- }
106
- }
107
-
108
- func TestRenderColumn_viewportShowsScrollIndicators(t *testing.T) {
109
- tasks := []data.Task{
110
- {ID: "T1", Title: "Task one", Column: data.ColumnPlanned},
111
- {ID: "T2", Title: "Task two", Column: data.ColumnPlanned},
112
- {ID: "T3", Title: "Task three", Column: data.ColumnPlanned},
113
- {ID: "T4", Title: "Task four", Column: data.ColumnPlanned},
114
- }
115
-
116
- got := RenderColumn(tasks, data.ColumnPlanned, 30, 8, 1, 1, true, nil)
117
-
118
- if !strings.Contains(got, "↑ 1 above") {
119
- t.Error("RenderColumn missing above indicator")
120
- }
121
- if !strings.Contains(got, "↓ 2 more") {
122
- t.Errorf("RenderColumn missing more indicator, got:\n%s", got)
123
- }
124
- if strings.Contains(got, "Task one") {
125
- t.Error("RenderColumn should not render tasks above viewport")
126
- }
127
- if strings.Contains(got, "Task three") {
128
- t.Error("RenderColumn should not render tasks that don't fit budget")
129
- }
130
- if strings.Contains(got, "Task four") {
131
- t.Error("RenderColumn should not render tasks below viewport")
132
- }
133
- }
134
-
135
- func TestVisibleColumnTaskLimitDefaultsToFourAtStandardHeight(t *testing.T) {
136
- if got := visibleColumnTaskLimit(CalculateLayout(100, 24).ContentHeight); got != 4 {
137
- t.Errorf("visibleColumnTaskLimit(standard height) = %d, want 4", got)
138
- }
139
- }
@@ -1,185 +0,0 @@
1
- package board
2
-
3
- import (
4
- "strings"
5
-
6
- "github.com/charmbracelet/lipgloss"
7
- "github.com/opencode/savepoint/internal/data"
8
- "github.com/opencode/savepoint/internal/styles"
9
- )
10
-
11
- const detailBorderPad = 4 // rounded border (2) + padding (2×1)
12
- const detailVerticalOverhead = 4 // overlay border (2) + fixed title/header rows (2)
13
-
14
- // RenderDetail renders a task detail overlay panel at the given display width.
15
- // When router state matches t's release/epic/task, a "(router priority)" label is shown.
16
- func RenderDetail(t data.Task, overlayW int, routerState *data.RouterState, maxHeight, offset int) string {
17
- inner := overlayW - detailBorderPad
18
- if inner < 4 {
19
- inner = 4
20
- }
21
-
22
- lines := []string{
23
- styles.ColumnTitleFocused.Render("TASK DETAIL"),
24
- strings.Repeat("─", inner),
25
- }
26
- body := []string{
27
- detailRow("ID", t.ID, inner),
28
- detailRow("Title", t.Title, inner),
29
- detailRow("Epic", t.Epic, inner),
30
- detailRow("Release", t.Release, inner),
31
- detailRow("Status", string(t.Column), inner),
32
- detailRow("Phase", phaseLabel(t.Stage), inner),
33
- }
34
-
35
- if t.Description != "" {
36
- body = append(body,
37
- "",
38
- styles.ColumnTitle.Render("Description:"),
39
- )
40
- for _, line := range WrapText(t.Description, inner) {
41
- body = append(body, styles.CardMeta.Render(line))
42
- }
43
- }
44
-
45
- if len(t.Checklist) > 0 {
46
- body = append(body, "", styles.ColumnTitle.Render("Implementation Plan:"), "")
47
- for _, item := range t.Checklist {
48
- glyph := "[ ] "
49
- style := styles.CardMeta
50
- if item.Done {
51
- glyph = "[x] "
52
- style = styles.TagDone
53
- }
54
- body = append(body, renderChecklistSentences(item.Text, glyph, inner, style)...)
55
- }
56
- }
57
-
58
- if t.Column != data.ColumnDone && isRouterPriority(t, routerState) {
59
- body = append(body, "", styles.TagDone.Render("(router priority)"))
60
- }
61
- body = append(body, "", styles.CardMeta.Render("esc:close"))
62
- lines = append(lines, visibleDetailLines(body, maxHeight-detailVerticalOverhead, offset)...)
63
-
64
- return styles.DetailOverlay.Width(overlayW).Render(strings.Join(lines, "\n"))
65
- }
66
-
67
- func renderChecklistSentences(text, glyph string, width int, style lipgloss.Style) []string {
68
- textWidth := width - len(glyph)
69
- if textWidth < 4 {
70
- textWidth = 4
71
- }
72
-
73
- lines := []string{}
74
- continuationIndent := strings.Repeat(" ", len(glyph))
75
- for _, sentence := range splitChecklistSentences(text) {
76
- wrapped := WrapText(sentence, textWidth)
77
- for i, line := range wrapped {
78
- if i == 0 {
79
- lines = append(lines, style.Render(glyph+line))
80
- continue
81
- }
82
- lines = append(lines, style.Render(continuationIndent+line))
83
- }
84
- }
85
- return lines
86
- }
87
-
88
- func splitChecklistSentences(text string) []string {
89
- fields := strings.Fields(text)
90
- if len(fields) == 0 {
91
- return nil
92
- }
93
- normalized := strings.Join(fields, " ")
94
-
95
- sentences := []string{}
96
- start := 0
97
- for i, r := range normalized {
98
- if r != '.' && r != '!' && r != '?' {
99
- continue
100
- }
101
- end := i + len(string(r))
102
- if end < len(normalized) && normalized[end] != ' ' {
103
- continue
104
- }
105
- sentence := strings.TrimSpace(normalized[start:end])
106
- if sentence != "" {
107
- sentences = append(sentences, sentence)
108
- }
109
- start = end
110
- }
111
- if tail := strings.TrimSpace(normalized[start:]); tail != "" {
112
- sentences = append(sentences, tail)
113
- }
114
- return sentences
115
- }
116
-
117
- func visibleDetailLines(lines []string, maxBodyHeight, offset int) []string {
118
- total := len(lines)
119
- if maxBodyHeight <= 0 || total <= maxBodyHeight {
120
- return lines
121
- }
122
- offset = clampDetailOffset(offset, total)
123
- available := maxBodyHeight
124
- if offset > 0 {
125
- available--
126
- }
127
- if available < 1 {
128
- available = 1
129
- }
130
- end := min(offset+available, total)
131
- if end < total && available > 1 {
132
- available--
133
- end = min(offset+available, total)
134
- }
135
-
136
- visible := make([]string, 0, available+2)
137
- if offset > 0 {
138
- visible = append(visible, renderScrollIndicator("↑", offset, "above"))
139
- }
140
- visible = append(visible, lines[offset:end]...)
141
- if end < total {
142
- visible = append(visible, renderScrollIndicator("↓", total-end, "more"))
143
- }
144
- return visible
145
- }
146
-
147
- func clampDetailOffset(offset, total int) int {
148
- if offset < 0 || total <= 0 {
149
- return 0
150
- }
151
- if offset >= total {
152
- return total - 1
153
- }
154
- return offset
155
- }
156
-
157
- func detailRow(label, value string, width int) string {
158
- prefix := label + ": "
159
- wrapped := WrapText(value, width-len(prefix))
160
- if len(wrapped) == 0 {
161
- wrapped = []string{""}
162
- }
163
- lines := make([]string, 0, len(wrapped))
164
- for i, line := range wrapped {
165
- if i == 0 {
166
- lines = append(lines, styles.ColumnTitle.Render(prefix)+styles.CardMeta.Render(line))
167
- continue
168
- }
169
- lines = append(lines, strings.Repeat(" ", len(prefix))+styles.CardMeta.Render(line))
170
- }
171
- return strings.Join(lines, "\n")
172
- }
173
-
174
- func phaseLabel(s data.ProgressStage) string {
175
- switch s {
176
- case data.StageTest:
177
- return "test"
178
- case data.StageAudit:
179
- return "audit"
180
- default:
181
- return "build"
182
- }
183
- }
184
-
185
-