savepoint 1.0.1 → 1.0.3

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 (278) hide show
  1. package/.claude/settings.local.json +15 -1
  2. package/.golangci.yml +11 -0
  3. package/.savepoint/Design.md +52 -46
  4. package/.savepoint/releases/v1/epics/E01-go-setup/tasks/T001-init-module.md +1 -1
  5. package/.savepoint/releases/v1/epics/E03-board-tui-core/tasks/T005-layout.md +1 -1
  6. package/.savepoint/releases/v1/epics/E04-board-components/tasks/T002-card.md +1 -1
  7. package/.savepoint/releases/v1/epics/E04-board-components/tasks/T006-help-overlay.md +1 -1
  8. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/{Design.md → E06-Detail.md} +5 -3
  9. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T002-header-and-dividers.md +1 -1
  10. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T003-footer-status-bar.md +1 -1
  11. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T004-component-refinement.md +1 -1
  12. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T010-auto-refresh-watcher.md +2 -0
  13. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/{Design.md → E01-Detail.md} +9 -1
  14. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/{T007-next-activity-header.md → T001-next-activity-header.md} +13 -12
  15. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T002-rename-epic-design-files.md +9 -9
  16. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T003-rename-release-prd.md +2 -2
  17. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T004-update-instruction-files.md +13 -12
  18. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T005-update-cross-references.md +14 -13
  19. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T006-column-and-detail-scrolling.md +25 -15
  20. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T007-column-focus-border-stability.md +57 -0
  21. package/.savepoint/releases/v1.1/epics/E02-cross-platform-compatibility/E02-Audit.md +124 -0
  22. package/.savepoint/releases/v1.1/epics/E02-cross-platform-compatibility/{Design.md → E02-Detail.md} +12 -3
  23. package/.savepoint/releases/v1.1/epics/E02-cross-platform-compatibility/tasks/T001-fix-makefile.md +11 -8
  24. package/.savepoint/releases/v1.1/epics/E02-cross-platform-compatibility/tasks/T002-linux-build-target.md +12 -7
  25. package/.savepoint/releases/v1.1/epics/E02-cross-platform-compatibility/tasks/T003-macos-build-target.md +9 -5
  26. package/.savepoint/releases/v1.1/epics/E02-cross-platform-compatibility/tasks/T004-smoke-tests-and-artifacts.md +30 -9
  27. package/.savepoint/releases/v1.1/epics/E03-ui-visual-refinement/E03-Audit.md +195 -0
  28. package/.savepoint/releases/v1.1/epics/E03-ui-visual-refinement/E03-Detail.md +45 -0
  29. package/.savepoint/releases/v1.1/epics/E03-ui-visual-refinement/tasks/T001-border-resize-fix.md +40 -0
  30. package/.savepoint/releases/v1.1/epics/E03-ui-visual-refinement/tasks/T002-next-activity-below-header.md +64 -0
  31. package/.savepoint/releases/v1.1/epics/E03-ui-visual-refinement/tasks/T003-checkbox-rendering-fix.md +56 -0
  32. package/.savepoint/releases/v1.1/epics/E03-ui-visual-refinement/tasks/T005-unify-status-glyphs.md +65 -0
  33. package/.savepoint/releases/v1.1/epics/E03-ui-visual-refinement/tasks/T006-forced-256-color-profile.md +36 -0
  34. package/.savepoint/releases/v1.1/epics/E04-epic-navigation/E04-Audit.md +167 -0
  35. package/.savepoint/releases/v1.1/epics/E04-epic-navigation/E04-Detail.md +51 -0
  36. package/.savepoint/releases/v1.1/epics/E04-epic-navigation/tasks/T001-sidebar-focusable-navigation.md +65 -0
  37. package/.savepoint/releases/v1.1/epics/E04-epic-navigation/tasks/T002-epic-detail-overlay.md +73 -0
  38. package/.savepoint/releases/v1.1/epics/E04-epic-navigation/tasks/T003-epic-status-glyphs.md +73 -0
  39. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/E05-Audit.md +237 -0
  40. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/E05-Detail.md +54 -0
  41. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T001-update-agents-md.md +45 -0
  42. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T002-update-router-md.md +40 -0
  43. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T003-update-design-md.md +47 -0
  44. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T004-implement-m-hotkey.md +98 -0
  45. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T005-update-help-overlay.md +33 -0
  46. package/.savepoint/releases/v1.1/epics/E05-tasking-permissions/tasks/T006-tests-and-quality-gates.md +62 -0
  47. package/.savepoint/releases/v1.1/epics/E06-audit-command/E06-Audit.md +56 -0
  48. package/.savepoint/releases/v1.1/epics/E06-audit-command/E06-Detail.md +63 -0
  49. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T005-proposals.md +44 -0
  50. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T007-apply-close.md +35 -0
  51. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T009-integration.md +40 -0
  52. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T010-audit-file-migration.md +45 -0
  53. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T011-model-tab-state.md +26 -0
  54. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T012-epic-audit-render.md +33 -0
  55. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T013-handle-tab-keys.md +34 -0
  56. package/.savepoint/releases/v1.1/epics/E06-audit-command/tasks/T014-tab-indicator.md +33 -0
  57. package/.savepoint/releases/v1.1/epics/E07-init-command/E07-Audit.md +336 -0
  58. package/.savepoint/releases/v1.1/epics/E07-init-command/E07-Detail.md +61 -0
  59. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T001-cli-entrypoint.md +37 -0
  60. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T002-target-validation.md +28 -0
  61. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T003-scaffold-writer.md +46 -0
  62. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T004-atomic-writes.md +27 -0
  63. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T005-magic-prompt.md +25 -0
  64. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T006-clipboard.md +26 -0
  65. package/.savepoint/releases/v1.1/epics/E07-init-command/tasks/T007-integration-test.md +26 -0
  66. package/.savepoint/releases/v1.1/epics/E08-board-command/E08-Audit.md +333 -0
  67. package/.savepoint/releases/v1.1/epics/E08-board-command/E08-Detail.md +68 -0
  68. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T001-cli-entrypoint.md +26 -0
  69. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T002-non-tty-fallback.md +27 -0
  70. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T003-tui-app-shell.md +28 -0
  71. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T004-board-model.md +29 -0
  72. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T005-detail-pane.md +27 -0
  73. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T006-status-transitions.md +29 -0
  74. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T007-theme-fallbacks.md +29 -0
  75. package/.savepoint/releases/v1.1/epics/E08-board-command/tasks/T008-integration-test.md +27 -0
  76. package/.savepoint/releases/v1.1/epics/E09-doctor-command/E09-Audit.md +207 -0
  77. package/.savepoint/releases/v1.1/epics/E09-doctor-command/E09-Detail.md +65 -0
  78. package/.savepoint/releases/v1.1/epics/E09-doctor-command/tasks/T001-cli-entrypoint.md +24 -0
  79. package/.savepoint/releases/v1.1/epics/E09-doctor-command/tasks/T002-config-router-validation.md +28 -0
  80. package/.savepoint/releases/v1.1/epics/E09-doctor-command/tasks/T003-structure-checks.md +29 -0
  81. package/.savepoint/releases/v1.1/epics/E09-doctor-command/tasks/T004-dependency-checks.md +27 -0
  82. package/.savepoint/releases/v1.1/epics/E09-doctor-command/tasks/T005-audit-orphan-checks.md +28 -0
  83. package/.savepoint/releases/v1.1/epics/E09-doctor-command/tasks/T006-quality-gates-report.md +31 -0
  84. package/.savepoint/releases/v1.1/epics/E11-board-refresh-fix/E11-Detail.md +36 -0
  85. package/.savepoint/releases/v1.1/epics/E11-board-refresh-fix/tasks/T001-debug-logging.md +25 -0
  86. package/.savepoint/releases/v1.1/epics/E11-board-refresh-fix/tasks/T002-increase-debounce.md +21 -0
  87. package/.savepoint/releases/v1.1/epics/E11-board-refresh-fix/tasks/T003-error-handling.md +22 -0
  88. package/.savepoint/releases/v1.1/epics/E11-board-refresh-fix/tasks/T004-test-verify.md +29 -0
  89. package/.savepoint/releases/v1.1/epics/E12-validation-fix/E12-Audit.md +444 -0
  90. package/.savepoint/releases/v1.1/epics/E12-validation-fix/E12-Detail.md +45 -0
  91. package/.savepoint/releases/v1.1/epics/E12-validation-fix/tasks/T001-default-phase.md +35 -0
  92. package/.savepoint/releases/v1.1/epics/E12-validation-fix/tasks/T002-default-status.md +19 -0
  93. package/.savepoint/releases/v1.1/epics/E12-validation-fix/tasks/T003-better-errors.md +29 -0
  94. package/.savepoint/releases/v1.1/epics/E12-validation-fix/tasks/T004-validate-on-write.md +25 -0
  95. package/.savepoint/releases/v1.1/epics/E12-validation-fix/tasks/T005-tests.md +37 -0
  96. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/E13-Audit.md +118 -0
  97. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/E13-Detail.md +73 -0
  98. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T001-safe-cleanup.md +66 -0
  99. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T002-bug-fixes.md +35 -0
  100. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T003-centralize-duplication.md +60 -0
  101. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T004-infrastructure.md +33 -0
  102. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T005-decompose-update.md +37 -0
  103. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T006-async-io.md +40 -0
  104. package/.savepoint/releases/v1.1/epics/E13-audit-remediation/tasks/T007-test-coverage.md +37 -0
  105. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/E14-Audit.md +267 -0
  106. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/E14-Detail.md +54 -0
  107. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T001-group-model.md +39 -0
  108. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T002-data-interfaces.md +42 -0
  109. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T003-discover-orphans.md +33 -0
  110. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T004-epic-panel-headings.md +35 -0
  111. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T005-shell-tokenization.md +27 -0
  112. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T006-unify-enums.md +29 -0
  113. package/.savepoint/releases/v1.1/epics/E14-structural-improvements/tasks/T007-testutil-package.md +28 -0
  114. package/.savepoint/releases/v1.1/epics/E15-hardening/E15-Detail.md +43 -0
  115. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T001-benchmarks.md +31 -0
  116. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T002-fuzz-targets.md +28 -0
  117. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T003-debug-flag.md +30 -0
  118. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T004-dist-checksums.md +27 -0
  119. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T005-windows-targets.md +28 -0
  120. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T006-abbreviation-splitting.md +26 -0
  121. package/.savepoint/releases/v1.1/epics/E15-hardening/tasks/T007-root-test-allowlist.md +28 -0
  122. package/.savepoint/releases/v1.1/epics/_archived/T001-cli-entrypoint.md +25 -0
  123. package/.savepoint/releases/v1.1/epics/_archived/T002-quality-gates.md +27 -0
  124. package/.savepoint/releases/v1.1/epics/_archived/T003-snapshot.md +27 -0
  125. package/.savepoint/releases/v1.1/epics/_archived/T004-ai-reconcile.md +29 -0
  126. package/.savepoint/releases/v1.1/epics/_archived/T006-tui-review.md +31 -0
  127. package/.savepoint/releases/v1.1/epics/_archived/T008-skip-handling.md +34 -0
  128. package/.savepoint/releases/v1.1/v1.1-PRD.md +139 -0
  129. package/.savepoint/router.md +29 -108
  130. package/AGENTS.md +69 -111
  131. package/Makefile +19 -3
  132. package/README.md +6 -6
  133. package/agent-skills/savepoint-audit/SKILL.md +87 -35
  134. package/agent-skills/savepoint-build-task/SKILL.md +9 -4
  135. package/agent-skills/savepoint-create-plan/SKILL.md +10 -5
  136. package/agent-skills/savepoint-create-task/SKILL.md +44 -31
  137. package/agent-skills/savepoint-draft-prd/SKILL.md +8 -3
  138. package/agent-skills/savepoint-system-design/SKILL.md +8 -3
  139. package/agent_skills_test.go +91 -0
  140. package/cmd/board.go +59 -0
  141. package/cmd/board_test.go +137 -0
  142. package/cmd/doctor.go +53 -0
  143. package/cmd/doctor_test.go +146 -0
  144. package/cmd/init.go +63 -0
  145. package/cmd/init_test.go +104 -0
  146. package/internal/board/board.go +69 -49
  147. package/internal/board/board_test.go +83 -67
  148. package/internal/board/card.go +71 -20
  149. package/internal/board/card_test.go +141 -12
  150. package/internal/board/column.go +77 -11
  151. package/internal/board/column_test.go +63 -13
  152. package/internal/board/detail.go +107 -72
  153. package/internal/board/detail_test.go +117 -26
  154. package/internal/board/epic_panel.go +211 -18
  155. package/internal/board/epic_panel_test.go +637 -14
  156. package/internal/board/help.go +1 -0
  157. package/internal/board/help_test.go +1 -0
  158. package/internal/board/integration_test.go +266 -0
  159. package/internal/board/interfaces.go +65 -0
  160. package/internal/board/interfaces_test.go +114 -0
  161. package/internal/board/io.go +93 -0
  162. package/internal/board/layout.go +12 -2
  163. package/internal/board/layout_test.go +17 -0
  164. package/internal/board/model.go +130 -52
  165. package/internal/board/plain.go +88 -0
  166. package/internal/board/plain_test.go +117 -0
  167. package/internal/board/release.go +1 -9
  168. package/internal/board/release_test.go +6 -6
  169. package/internal/board/render_policy_test.go +77 -0
  170. package/internal/board/status.go +23 -0
  171. package/internal/board/theme.go +24 -0
  172. package/internal/board/theme_test.go +31 -0
  173. package/internal/board/transitions.go +113 -88
  174. package/internal/board/transitions_test.go +164 -141
  175. package/internal/board/tui.go +32 -0
  176. package/internal/board/update.go +472 -94
  177. package/internal/board/update_test.go +447 -0
  178. package/internal/board/util.go +76 -0
  179. package/internal/board/view.go +139 -22
  180. package/internal/board/view_test.go +171 -3
  181. package/internal/board/watch.go +57 -9
  182. package/internal/buildtool/main.go +211 -0
  183. package/internal/buildtool/main_test.go +46 -0
  184. package/internal/data/config.go +17 -3
  185. package/internal/data/config_test.go +49 -0
  186. package/internal/data/discover.go +26 -0
  187. package/internal/data/discover_test.go +34 -10
  188. package/internal/data/errors.go +4 -0
  189. package/internal/data/lifecycle.go +13 -6
  190. package/internal/data/lifecycle_test.go +14 -11
  191. package/internal/data/parser.go +29 -6
  192. package/internal/data/parser_test.go +66 -7
  193. package/internal/data/task.go +1 -0
  194. package/internal/data/write.go +85 -11
  195. package/internal/data/write_test.go +167 -0
  196. package/internal/doctor/checks.go +567 -0
  197. package/internal/doctor/checks_test.go +716 -0
  198. package/internal/doctor/gates.go +193 -0
  199. package/internal/doctor/gates_test.go +166 -0
  200. package/internal/doctor/interfaces.go +64 -0
  201. package/internal/doctor/interfaces_test.go +104 -0
  202. package/internal/doctor/repairs.go +80 -0
  203. package/internal/doctor/repairs_test.go +81 -0
  204. package/internal/doctor/report.go +157 -0
  205. package/internal/doctor/report_test.go +89 -0
  206. package/internal/init/clipboard.go +146 -0
  207. package/internal/init/clipboard_test.go +74 -0
  208. package/internal/init/install.go +16 -0
  209. package/internal/init/integration_test.go +197 -0
  210. package/internal/init/prompt.go +14 -0
  211. package/internal/init/prompt_test.go +77 -0
  212. package/internal/init/scaffold.go +59 -0
  213. package/internal/init/scaffold_test.go +179 -0
  214. package/internal/init/template_freshness_test.go +56 -0
  215. package/internal/init/validate.go +85 -0
  216. package/internal/init/validate_test.go +141 -0
  217. package/internal/init/write.go +73 -0
  218. package/internal/init/write_test.go +91 -0
  219. package/internal/styles/palette.go +3 -3
  220. package/internal/styles/styles.go +39 -12
  221. package/internal/styles/styles_test.go +133 -0
  222. package/internal/testutil/fixture.go +113 -0
  223. package/internal/testutil/fs.go +26 -0
  224. package/main.go +107 -1
  225. package/package.json +2 -2
  226. package/project-audit/audit_report_glm_5.1.md +411 -0
  227. package/project-audit/audit_report_opus_4.6 +406 -0
  228. package/project-audit/consolidated-audit-report.md +456 -0
  229. package/savepoint +0 -0
  230. package/templates/project/.savepoint/Design.md +2 -2
  231. package/templates/project/.savepoint/router.md +15 -14
  232. package/templates/project/AGENTS.md +56 -98
  233. package/templates/project/agent-skills/savepoint-audit/SKILL.md +87 -0
  234. package/templates/project/agent-skills/savepoint-build-task/SKILL.md +44 -0
  235. package/templates/project/agent-skills/savepoint-create-plan/SKILL.md +33 -0
  236. package/templates/project/agent-skills/savepoint-create-task/SKILL.md +44 -0
  237. package/templates/project/agent-skills/savepoint-draft-prd/SKILL.md +37 -0
  238. package/templates/project/agent-skills/savepoint-system-design/SKILL.md +38 -0
  239. package/templates/prompts/audit-reconciliation.prompt.md +35 -30
  240. package/templates/prompts/design.prompt.md +3 -1
  241. package/templates/prompts/epic-design.prompt.md +3 -3
  242. package/templates/prompts/task-breakdown.prompt.md +1 -1
  243. package/templates/prompts/task-building.prompt.md +1 -1
  244. package/templates/prompts/task-planning.prompt.md +1 -1
  245. package/.savepoint/audit/E01-go-setup/proposals.md +0 -166
  246. package/.savepoint/audit/E01-go-setup/snapshot.md +0 -71
  247. package/.savepoint/audit/E01-scaffolding/proposals/AGENTS.md +0 -66
  248. package/.savepoint/audit/E01-scaffolding/proposals/Design.md +0 -210
  249. package/.savepoint/audit/E01-scaffolding/proposals/epic-Design.md +0 -117
  250. package/.savepoint/audit/E01-scaffolding/proposals/quality-review.md +0 -101
  251. package/.savepoint/audit/E01-scaffolding/snapshot.md +0 -54
  252. package/.savepoint/audit/E02-data-model/snapshot.md +0 -128
  253. package/.savepoint/audit/E02-data-readers/proposals.md +0 -123
  254. package/.savepoint/audit/E02-data-readers/snapshot.md +0 -54
  255. package/.savepoint/audit/E03-board-tui-core/proposals.md +0 -146
  256. package/.savepoint/audit/E03-board-tui-core/snapshot.md +0 -57
  257. package/.savepoint/audit/E03-cli-foundation/snapshot.md +0 -106
  258. package/.savepoint/audit/E04-board-components/proposals.md +0 -118
  259. package/.savepoint/audit/E04-board-components/snapshot.md +0 -77
  260. package/.savepoint/audit/E04-templates-and-prompts/snapshot.md +0 -115
  261. package/.savepoint/audit/E05-init-command/snapshot.md +0 -125
  262. package/.savepoint/audit/E05-phase-transitions/proposals.md +0 -83
  263. package/.savepoint/audit/E05-phase-transitions/snapshot.md +0 -36
  264. package/.savepoint/audit/E06-atari-noir-layout/proposals.md +0 -130
  265. package/.savepoint/audit/E06-atari-noir-layout/snapshot.md +0 -84
  266. package/.savepoint/audit/E06-tui-board/snapshot.md +0 -64
  267. package/.savepoint/audit/E07-audit-pipeline/snapshot.md +0 -165
  268. package/.savepoint/audit/E08-board-workflow-cleanup/snapshot.md +0 -65
  269. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T001-border-resize-fix.md +0 -36
  270. package/ink-cli-ui-design.zip +0 -0
  271. package/main.exe +0 -0
  272. package/savepoint.exe +0 -0
  273. /package/.savepoint/releases/v1/epics/E01-go-setup/{Design.md → E01-Detail.md} +0 -0
  274. /package/.savepoint/releases/v1/epics/E02-data-readers/{Design.md → E02-Detail.md} +0 -0
  275. /package/.savepoint/releases/v1/epics/E03-board-tui-core/{Design.md → E03-Detail.md} +0 -0
  276. /package/.savepoint/releases/v1/epics/E04-board-components/{Design.md → E04-Detail.md} +0 -0
  277. /package/.savepoint/releases/v1/epics/E05-phase-transitions/{Design.md → E05-Detail.md} +0 -0
  278. /package/.savepoint/releases/v1/{PRD.md → v1-PRD.md} +0 -0
@@ -0,0 +1,91 @@
1
+ package init
2
+
3
+ import (
4
+ "os"
5
+ "path/filepath"
6
+ "strings"
7
+ "testing"
8
+
9
+ "github.com/opencode/savepoint/internal/testutil"
10
+ )
11
+
12
+ func TestAtomicWrite_createsFile(t *testing.T) {
13
+ dir := t.TempDir()
14
+ target := filepath.Join(dir, "output.txt")
15
+
16
+ if err := AtomicWrite(target, []byte("hello")); err != nil {
17
+ t.Fatalf("AtomicWrite() error = %v", err)
18
+ }
19
+
20
+ data, err := os.ReadFile(target)
21
+ if err != nil {
22
+ t.Fatal(err)
23
+ }
24
+ if string(data) != "hello" {
25
+ t.Fatalf("got %q, want %q", string(data), "hello")
26
+ }
27
+ }
28
+
29
+ func TestAtomicWrite_replacesExistingFile(t *testing.T) {
30
+ dir := t.TempDir()
31
+ target := filepath.Join(dir, "output.txt")
32
+ testutil.WriteFile(t, target, "old")
33
+
34
+ if err := AtomicWrite(target, []byte("new")); err != nil {
35
+ t.Fatalf("AtomicWrite() error = %v", err)
36
+ }
37
+
38
+ data, err := os.ReadFile(target)
39
+ if err != nil {
40
+ t.Fatal(err)
41
+ }
42
+ if string(data) != "new" {
43
+ t.Fatalf("got %q, want %q", string(data), "new")
44
+ }
45
+
46
+ assertNoWriteArtifacts(t, dir)
47
+ }
48
+
49
+ func TestAtomicWrite_noTempFileLeftBehind(t *testing.T) {
50
+ dir := t.TempDir()
51
+ target := filepath.Join(dir, "output.txt")
52
+
53
+ if err := AtomicWrite(target, []byte("data")); err != nil {
54
+ t.Fatalf("AtomicWrite() error = %v", err)
55
+ }
56
+
57
+ assertNoWriteArtifacts(t, dir)
58
+ }
59
+
60
+ func TestAtomicWrite_handlesNestedDirectories(t *testing.T) {
61
+ dir := t.TempDir()
62
+ target := filepath.Join(dir, "deep", "nested", "output.txt")
63
+
64
+ // Parent directories must exist before calling AtomicWrite
65
+ testutil.MkdirAll(t, filepath.Dir(target))
66
+
67
+ if err := AtomicWrite(target, []byte("nested")); err != nil {
68
+ t.Fatalf("AtomicWrite() error = %v", err)
69
+ }
70
+
71
+ if _, err := os.Stat(target); err != nil {
72
+ t.Errorf("target not created: %v", err)
73
+ }
74
+ }
75
+
76
+ func assertNoWriteArtifacts(t *testing.T, dir string) {
77
+ t.Helper()
78
+
79
+ entries, err := os.ReadDir(dir)
80
+ if err != nil {
81
+ t.Fatal(err)
82
+ }
83
+ for _, e := range entries {
84
+ if strings.HasPrefix(e.Name(), ".tmp-") && strings.HasSuffix(e.Name(), ".write") {
85
+ t.Errorf("temp file %q left behind after successful write", e.Name())
86
+ }
87
+ if strings.HasSuffix(e.Name(), ".savepoint-bak") {
88
+ t.Errorf("backup file %q left behind after successful write", e.Name())
89
+ }
90
+ }
91
+ }
@@ -17,9 +17,9 @@ const (
17
17
 
18
18
  // 256-color (ANSI256) fallbacks — nearest terminal approximations
19
19
  const (
20
- Background256 = "233"
21
- Surface256 = "232"
22
- Surface2256 = "232"
20
+ Background256 = "16"
21
+ Surface256 = "16"
22
+ Surface2256 = "16"
23
23
  Border256 = "234"
24
24
  BorderSubtle256 = "235"
25
25
  PrimaryText256 = "230"
@@ -17,6 +17,8 @@ var (
17
17
  clrDim = color(Dim, Dim256, Dim16)
18
18
  )
19
19
 
20
+ var boxBorder = lipgloss.NormalBorder()
21
+
20
22
  var (
21
23
  HeaderIcon = lipgloss.NewStyle().
22
24
  Foreground(clrOrange).
@@ -29,20 +31,21 @@ var (
29
31
  Foreground(clrBorder)
30
32
 
31
33
  HeaderFrame = lipgloss.NewStyle().
32
- Background(clrSurfaceDark).
33
34
  Padding(1, 1)
34
35
 
35
- BoardFrame = lipgloss.NewStyle().
36
- Background(clrSurfaceDark)
36
+ BoardFrame = lipgloss.NewStyle()
37
37
 
38
38
  Column = lipgloss.NewStyle().
39
- Background(clrSurfaceDark).
40
39
  Padding(0, 1)
41
40
 
41
+ ColumnUnfocused = lipgloss.NewStyle().
42
+ BorderStyle(boxBorder).
43
+ BorderForeground(clrBorder).
44
+ Padding(0, 1)
45
+
42
46
  ColumnFocused = lipgloss.NewStyle().
43
- BorderStyle(lipgloss.RoundedBorder()).
47
+ BorderStyle(boxBorder).
44
48
  BorderForeground(clrOrange).
45
- Background(clrSurfaceDark).
46
49
  Padding(0, 1)
47
50
 
48
51
  ColumnTitle = lipgloss.NewStyle().
@@ -63,30 +66,49 @@ var (
63
66
  Foreground(clrText)
64
67
 
65
68
  EpicPanel = lipgloss.NewStyle().
66
- Background(clrSurface).
69
+ BorderStyle(boxBorder).
70
+ BorderForeground(clrBorder).
67
71
  Padding(0, 1)
68
72
 
73
+ EpicItemFocused = lipgloss.NewStyle().
74
+ Foreground(clrPurple)
75
+
76
+ EpicTitleFocused = lipgloss.NewStyle().
77
+ Foreground(clrPurple).
78
+ Bold(true)
79
+
80
+ EpicPanelFocused = lipgloss.NewStyle().
81
+ BorderStyle(boxBorder).
82
+ BorderForeground(clrPurple).
83
+ Padding(0, 1)
84
+
69
85
  Card = lipgloss.NewStyle().
70
- Background(clrSurface).
71
86
  Padding(0, 1)
72
87
 
73
88
  CardFocused = lipgloss.NewStyle().
74
- BorderStyle(lipgloss.RoundedBorder()).
89
+ BorderStyle(boxBorder).
75
90
  BorderForeground(clrOrange).
76
- Background(clrSurface).
77
91
  Padding(0, 1)
78
92
 
79
- CardMeta = lipgloss.NewStyle().Foreground(clrDim)
93
+ CardMeta = lipgloss.NewStyle().Foreground(clrDim)
94
+ ScrollIndicator = lipgloss.NewStyle().
95
+ Foreground(clrDim).
96
+ Faint(true)
80
97
 
81
98
  GlyphBuild = lipgloss.NewStyle().Foreground(clrOrange)
82
99
  GlyphTest = lipgloss.NewStyle().Foreground(clrGreen)
83
100
  GlyphAudit = lipgloss.NewStyle().Foreground(clrPurple)
84
101
 
85
102
  DetailOverlay = lipgloss.NewStyle().
86
- BorderStyle(lipgloss.RoundedBorder()).
103
+ BorderStyle(boxBorder).
87
104
  BorderForeground(clrOrange).
88
105
  Padding(0, 1)
89
106
 
107
+ EpicDetailOverlay = lipgloss.NewStyle().
108
+ BorderStyle(boxBorder).
109
+ BorderForeground(clrPurple).
110
+ Padding(0, 1)
111
+
90
112
  // Footer phase styles
91
113
  FooterPhasePlan = lipgloss.NewStyle().
92
114
  Foreground(clrPurple).
@@ -106,6 +128,11 @@ var (
106
128
  FooterHints = lipgloss.NewStyle().
107
129
  Foreground(clrDim)
108
130
 
131
+ HeaderRight = lipgloss.NewStyle().
132
+ Foreground(clrDim)
133
+
134
+ RootLine = lipgloss.NewStyle()
135
+
109
136
  // Tag styles for semantic encoding
110
137
  TagDone = lipgloss.NewStyle().Foreground(clrGreen)
111
138
  TagAI = lipgloss.NewStyle().Foreground(clrPurple)
@@ -0,0 +1,133 @@
1
+ package styles
2
+
3
+ import (
4
+ "testing"
5
+
6
+ "github.com/charmbracelet/lipgloss"
7
+ )
8
+
9
+ func TestPaletteConstants_present(t *testing.T) {
10
+ // Truecolor tier
11
+ if Background == "" {
12
+ t.Error("Background constant is empty")
13
+ }
14
+ if Surface == "" {
15
+ t.Error("Surface constant is empty")
16
+ }
17
+ if Surface2 == "" {
18
+ t.Error("Surface2 constant is empty")
19
+ }
20
+ if Border == "" {
21
+ t.Error("Border constant is empty")
22
+ }
23
+ if BorderSubtle == "" {
24
+ t.Error("BorderSubtle constant is empty")
25
+ }
26
+ if PrimaryText == "" {
27
+ t.Error("PrimaryText constant is empty")
28
+ }
29
+ if AtariOrange == "" {
30
+ t.Error("AtariOrange constant is empty")
31
+ }
32
+ if NPPGreen == "" {
33
+ t.Error("NPPGreen constant is empty")
34
+ }
35
+ if VibePurple == "" {
36
+ t.Error("VibePurple constant is empty")
37
+ }
38
+ if Dim == "" {
39
+ t.Error("Dim constant is empty")
40
+ }
41
+ }
42
+
43
+ func TestPaletteConstants_256tier(t *testing.T) {
44
+ if Background256 == "" {
45
+ t.Error("Background256 constant is empty")
46
+ }
47
+ if Surface256 == "" {
48
+ t.Error("Surface256 constant is empty")
49
+ }
50
+ if Surface2256 == "" {
51
+ t.Error("Surface2256 constant is empty")
52
+ }
53
+ if Border256 == "" {
54
+ t.Error("Border256 constant is empty")
55
+ }
56
+ if BorderSubtle256 == "" {
57
+ t.Error("BorderSubtle256 constant is empty")
58
+ }
59
+ if PrimaryText256 == "" {
60
+ t.Error("PrimaryText256 constant is empty")
61
+ }
62
+ if AtariOrange256 == "" {
63
+ t.Error("AtariOrange256 constant is empty")
64
+ }
65
+ if NPPGreen256 == "" {
66
+ t.Error("NPPGreen256 constant is empty")
67
+ }
68
+ if VibePurple256 == "" {
69
+ t.Error("VibePurple256 constant is empty")
70
+ }
71
+ if Dim256 == "" {
72
+ t.Error("Dim256 constant is empty")
73
+ }
74
+ }
75
+
76
+ func TestPaletteConstants_16tier(t *testing.T) {
77
+ if Background16 == "" {
78
+ t.Error("Background16 constant is empty")
79
+ }
80
+ if Surface16 == "" {
81
+ t.Error("Surface16 constant is empty")
82
+ }
83
+ if Surface216 == "" {
84
+ t.Error("Surface216 constant is empty")
85
+ }
86
+ if Border16 == "" {
87
+ t.Error("Border16 constant is empty")
88
+ }
89
+ if BorderSubtle16 == "" {
90
+ t.Error("BorderSubtle16 constant is empty")
91
+ }
92
+ if PrimaryText16 == "" {
93
+ t.Error("PrimaryText16 constant is empty")
94
+ }
95
+ if AtariOrange16 == "" {
96
+ t.Error("AtariOrange16 constant is empty")
97
+ }
98
+ if NPPGreen16 == "" {
99
+ t.Error("NPPGreen16 constant is empty")
100
+ }
101
+ if VibePurple16 == "" {
102
+ t.Error("VibePurple16 constant is empty")
103
+ }
104
+ }
105
+
106
+ func TestColor(t *testing.T) {
107
+ c := color("#FF0000", "196", "9")
108
+ expected := lipgloss.CompleteColor{TrueColor: "#FF0000", ANSI256: "196", ANSI: "9"}
109
+ if c != expected {
110
+ t.Errorf("color() = %+v, want %+v", c, expected)
111
+ }
112
+ }
113
+
114
+ func TestColor_usesPaletteConstants(t *testing.T) {
115
+ c := color(AtariOrange, AtariOrange256, AtariOrange16)
116
+ if c.TrueColor != AtariOrange {
117
+ t.Errorf("color TrueColor = %q, want %q", c.TrueColor, AtariOrange)
118
+ }
119
+ if c.ANSI256 != AtariOrange256 {
120
+ t.Errorf("color ANSI256 = %q, want %q", c.ANSI256, AtariOrange256)
121
+ }
122
+ if c.ANSI != AtariOrange16 {
123
+ t.Errorf("color ANSI = %q, want %q", c.ANSI, AtariOrange16)
124
+ }
125
+ }
126
+
127
+ func TestColor_returnsCompleteColor(t *testing.T) {
128
+ var cc lipgloss.CompleteColor
129
+ cc = color(Background, Background256, Background16)
130
+ if cc.TrueColor != Background {
131
+ t.Errorf("expected TrueColor %q, got %q", Background, cc.TrueColor)
132
+ }
133
+ }
@@ -0,0 +1,113 @@
1
+ package testutil
2
+
3
+ import (
4
+ "fmt"
5
+ "path/filepath"
6
+ "strings"
7
+ "testing"
8
+ )
9
+
10
+ // WriteRouter writes a router.md at root with the given fields.
11
+ // If nextAction is empty, it defaults to "".
12
+ func WriteRouter(t testing.TB, root, state, release, epic, task, nextAction string) {
13
+ t.Helper()
14
+ if nextAction == "" {
15
+ nextAction = `""`
16
+ } else {
17
+ nextAction = `"` + nextAction + `"`
18
+ }
19
+ if task == "" {
20
+ task = `""`
21
+ } else {
22
+ task = `"` + task + `"`
23
+ }
24
+ content := "# Agent State Machine\n\n## Current state\n\n```yaml\nstate: " + state + "\nrelease: " + release + "\nepic: " + epic + "\ntask: " + task + "\nnext_action: " + nextAction + "\n```\n"
25
+ WriteFile(t, filepath.Join(root, "router.md"), content)
26
+ }
27
+
28
+ // WriteReleasePRD writes a minimal release PRD file.
29
+ func WriteReleasePRD(t testing.TB, releasePath string) {
30
+ t.Helper()
31
+ releaseID := filepath.Base(releasePath)
32
+ WriteFile(t, filepath.Join(releasePath, releaseID+"-PRD.md"), "---\ntype: project-prd\nstatus: active\n---\n\n# Release\n")
33
+ }
34
+
35
+ // WriteEpicDetail writes a minimal epic detail file.
36
+ func WriteEpicDetail(t testing.TB, epicPath, prefix string) {
37
+ t.Helper()
38
+ WriteFile(t, filepath.Join(epicPath, prefix+"-Detail.md"), "---\ntype: epic-design\nstatus: planned\n---\n\n# Epic\n")
39
+ }
40
+
41
+ // TaskFixture describes a task file to create.
42
+ type TaskFixture struct {
43
+ Slug string // e.g. "T001-task" — becomes filename
44
+ Release string // optional; omitted if empty
45
+ Status string
46
+ Phase string // optional; omitted if empty
47
+ Objective string
48
+ DependsOn []string // optional; defaults to empty list
49
+ Body string // optional; defaults to minimal body
50
+ Extra map[string]string // optional; extra frontmatter fields
51
+ }
52
+
53
+ // WriteTask writes a task file in the savepoint directory structure.
54
+ func WriteTask(t testing.TB, root, release, epic string, task TaskFixture) {
55
+ t.Helper()
56
+ path := filepath.Join(root, "releases", release, "epics", epic, "tasks", task.Slug+".md")
57
+ id := epic + "/" + task.Slug
58
+
59
+ var b strings.Builder
60
+ b.WriteString("---\n")
61
+ b.WriteString("id: " + id + "\n")
62
+ if task.Release != "" {
63
+ b.WriteString("release: " + task.Release + "\n")
64
+ }
65
+ b.WriteString("status: " + task.Status + "\n")
66
+ if task.Phase != "" {
67
+ b.WriteString("phase: " + task.Phase + "\n")
68
+ }
69
+ b.WriteString("objective: \"" + task.Objective + "\"\n")
70
+
71
+ deps := "[]"
72
+ if len(task.DependsOn) > 0 {
73
+ quoted := make([]string, len(task.DependsOn))
74
+ for i, d := range task.DependsOn {
75
+ quoted[i] = fmt.Sprintf("%q", d)
76
+ }
77
+ deps = "[" + strings.Join(quoted, ", ") + "]"
78
+ }
79
+ b.WriteString("depends_on: " + deps + "\n")
80
+ for k, v := range task.Extra {
81
+ b.WriteString(k + ": " + v + "\n")
82
+ }
83
+ b.WriteString("---\n\n")
84
+
85
+ if task.Body != "" {
86
+ b.WriteString(task.Body)
87
+ } else {
88
+ b.WriteString("# " + task.Slug + "\n\n## Acceptance Criteria\n\n- it works\n")
89
+ }
90
+
91
+ WriteFile(t, path, b.String())
92
+ }
93
+
94
+ // SetupMinimalProject creates a minimal valid savepoint project structure.
95
+ // It creates config.yml, router.md, release PRD, epic detail, and the directory tree.
96
+ func SetupMinimalProject(t testing.TB, root, release, epic string) {
97
+ t.Helper()
98
+ releasePath := filepath.Join(root, "releases", release)
99
+ //nolint:gocritic // assignment to same epicPath variable is fine
100
+ epicPath := filepath.Join(releasePath, "epics", epic)
101
+ tasksPath := filepath.Join(epicPath, "tasks")
102
+ MkdirAll(t, tasksPath)
103
+
104
+ prefix := epic
105
+ if idx := strings.IndexByte(epic, '-'); idx != -1 {
106
+ prefix = epic[:idx]
107
+ }
108
+
109
+ WriteFile(t, filepath.Join(root, "config.yml"), "quality_gates:\n lint: null\n typecheck: null\n test: null\ntheme:\n bg: \"#000\"\n")
110
+ WriteRouter(t, root, "task-building", release, epic, "", "")
111
+ WriteReleasePRD(t, releasePath)
112
+ WriteEpicDetail(t, epicPath, prefix)
113
+ }
@@ -0,0 +1,26 @@
1
+ package testutil
2
+
3
+ import (
4
+ "os"
5
+ "path/filepath"
6
+ "testing"
7
+ )
8
+
9
+ // WriteFile writes content to path, creating parent directories if needed.
10
+ func WriteFile(t testing.TB, path, content string) {
11
+ t.Helper()
12
+ if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
13
+ t.Fatal(err)
14
+ }
15
+ if err := os.WriteFile(path, []byte(content), 0644); err != nil {
16
+ t.Fatal(err)
17
+ }
18
+ }
19
+
20
+ // MkdirAll creates directories with mode 0755, fatal on error.
21
+ func MkdirAll(t testing.TB, path string) {
22
+ t.Helper()
23
+ if err := os.MkdirAll(path, 0755); err != nil {
24
+ t.Fatal(err)
25
+ }
26
+ }
package/main.go CHANGED
@@ -1,11 +1,117 @@
1
1
  package main
2
2
 
3
3
  import (
4
+ "context"
5
+ "embed"
6
+ "fmt"
7
+ "io/fs"
8
+ "os"
9
+
10
+ "github.com/opencode/savepoint/cmd"
4
11
  "github.com/opencode/savepoint/internal/board"
12
+ "github.com/opencode/savepoint/internal/data"
13
+ "github.com/opencode/savepoint/internal/doctor"
14
+ savepointinit "github.com/opencode/savepoint/internal/init"
5
15
  )
6
16
 
17
+ //go:embed templates/project
18
+ //go:embed templates/project/.savepoint
19
+ //go:embed templates/prompts
20
+ var projectTemplates embed.FS
21
+
22
+ var version = "dev"
23
+
7
24
  func main() {
25
+ if len(os.Args) > 1 {
26
+ switch os.Args[1] {
27
+ case "--version":
28
+ fmt.Println(version)
29
+ os.Exit(0)
30
+ case "init":
31
+ if err := cmd.RunInit(context.Background(), os.Args[2:], os.Stdout, initRunner); err != nil {
32
+ fmt.Fprintln(os.Stderr, err)
33
+ os.Exit(1)
34
+ }
35
+ os.Exit(0)
36
+ case "board":
37
+ if err := cmd.RunBoard(context.Background(), os.Args[2:], os.Stdout, func(opts cmd.BoardOptions) error {
38
+ return board.RunWithFilters(opts.Release, opts.Epic)
39
+ }); err != nil {
40
+ fmt.Fprintln(os.Stderr, err)
41
+ os.Exit(1)
42
+ }
43
+ os.Exit(0)
44
+ case "doctor":
45
+ code, err := cmd.RunDoctor(context.Background(), os.Args[2:], os.Stdout, func(opts cmd.DoctorOptions) (int, error) {
46
+ return runDoctorChecks(opts)
47
+ })
48
+ if err != nil {
49
+ fmt.Fprintln(os.Stderr, err)
50
+ }
51
+ os.Exit(code)
52
+ }
53
+ }
8
54
  if err := board.Run(); err != nil {
9
55
  panic(err)
10
56
  }
11
- }
57
+ }
58
+
59
+ func runDoctorChecks(opts cmd.DoctorOptions) (int, error) {
60
+ discover := data.NewDiscover()
61
+ root, err := discover.FindSavepointRoot(".")
62
+ if err != nil {
63
+ return 2, fmt.Errorf("savepoint root not found: %w", err)
64
+ }
65
+
66
+ report := doctor.RunAllChecks(root, opts.Epic)
67
+ fmt.Fprint(os.Stdout, report.Format())
68
+
69
+ if report.HasProblems() {
70
+ return 1, nil
71
+ }
72
+ return 0, nil
73
+ }
74
+
75
+ func initRunner(ctx context.Context, opts cmd.InitOptions) error {
76
+ if err := savepointinit.ValidateTarget(opts.Dir, opts.Force); err != nil {
77
+ return err
78
+ }
79
+
80
+ sub, err := fs.Sub(projectTemplates, "templates/project")
81
+ if err != nil {
82
+ return fmt.Errorf("cannot load templates: %w", err)
83
+ }
84
+
85
+ projectName := savepointinit.ProjectNameFromDir(opts.Dir)
86
+ if err := savepointinit.Scaffold(sub, opts.Dir, projectName, opts.Force); err != nil {
87
+ return err
88
+ }
89
+
90
+ promptSub, err := fs.Sub(projectTemplates, "templates/prompts")
91
+ if err != nil {
92
+ return fmt.Errorf("cannot load prompt templates: %w", err)
93
+ }
94
+
95
+ prompt, err := savepointinit.RenderMagicPrompt(promptSub, projectName)
96
+ if err != nil {
97
+ return fmt.Errorf("render magic prompt: %w", err)
98
+ }
99
+
100
+ fmt.Println(prompt)
101
+
102
+ result := savepointinit.CopyToClipboard(prompt)
103
+ switch result.Status {
104
+ case savepointinit.ClipboardCopied:
105
+ fmt.Fprintf(os.Stderr, "prompt copied to clipboard via %s\n", result.Tool)
106
+ case savepointinit.ClipboardFailed:
107
+ fmt.Fprintf(os.Stderr, "warning: clipboard copy failed: %s\n", result.Message)
108
+ }
109
+
110
+ if opts.Install {
111
+ if err := savepointinit.InstallDependencies(opts.Dir); err != nil {
112
+ return err
113
+ }
114
+ }
115
+
116
+ return nil
117
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "savepoint",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "It’s a simple, file-based state machine and cinematic Terminal UI (TUI) designed to force you—and your agent (Claude, Cursor, Aider, Gemini)—to slow down, write down what you're actually building, and check your work before moving on.",
5
5
  "keywords": [
6
6
  "board",
@@ -21,6 +21,6 @@
21
21
  "savepoint": "./savepoint"
22
22
  },
23
23
  "scripts": {
24
- "test": "savepoint init"
24
+ "test": "echo \"Run 'make test' for Go tests\""
25
25
  }
26
26
  }