savepoint 1.0.4 → 1.0.7

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