savepoint 1.0.0

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 (273) hide show
  1. package/.claude/settings.local.json +20 -0
  2. package/.prettierignore +4 -0
  3. package/.savepoint/Design.md +196 -0
  4. package/.savepoint/PRD.md +58 -0
  5. package/.savepoint/audit/E01-go-setup/proposals.md +166 -0
  6. package/.savepoint/audit/E01-go-setup/snapshot.md +71 -0
  7. package/.savepoint/audit/E01-scaffolding/proposals/AGENTS.md +66 -0
  8. package/.savepoint/audit/E01-scaffolding/proposals/Design.md +210 -0
  9. package/.savepoint/audit/E01-scaffolding/proposals/epic-Design.md +117 -0
  10. package/.savepoint/audit/E01-scaffolding/proposals/quality-review.md +101 -0
  11. package/.savepoint/audit/E01-scaffolding/snapshot.md +54 -0
  12. package/.savepoint/audit/E02-data-model/snapshot.md +128 -0
  13. package/.savepoint/audit/E02-data-readers/proposals.md +123 -0
  14. package/.savepoint/audit/E02-data-readers/snapshot.md +54 -0
  15. package/.savepoint/audit/E03-board-tui-core/proposals.md +146 -0
  16. package/.savepoint/audit/E03-board-tui-core/snapshot.md +57 -0
  17. package/.savepoint/audit/E03-cli-foundation/snapshot.md +106 -0
  18. package/.savepoint/audit/E04-board-components/proposals.md +118 -0
  19. package/.savepoint/audit/E04-board-components/snapshot.md +77 -0
  20. package/.savepoint/audit/E04-templates-and-prompts/snapshot.md +115 -0
  21. package/.savepoint/audit/E05-init-command/snapshot.md +125 -0
  22. package/.savepoint/audit/E05-phase-transitions/proposals.md +83 -0
  23. package/.savepoint/audit/E05-phase-transitions/snapshot.md +36 -0
  24. package/.savepoint/audit/E06-tui-board/snapshot.md +64 -0
  25. package/.savepoint/audit/E07-audit-pipeline/snapshot.md +165 -0
  26. package/.savepoint/audit/E08-board-workflow-cleanup/snapshot.md +65 -0
  27. package/.savepoint/config.yml +27 -0
  28. package/.savepoint/releases/v1/PRD.md +66 -0
  29. package/.savepoint/releases/v1/epics/E01-go-setup/Design.md +39 -0
  30. package/.savepoint/releases/v1/epics/E01-go-setup/tasks/T001-init-module.md +42 -0
  31. package/.savepoint/releases/v1/epics/E01-go-setup/tasks/T002-entrypoint.md +23 -0
  32. package/.savepoint/releases/v1/epics/E01-go-setup/tasks/T003-directory-structure.md +24 -0
  33. package/.savepoint/releases/v1/epics/E01-go-setup/tasks/T004-makefile.md +23 -0
  34. package/.savepoint/releases/v1/epics/E02-data-readers/Design.md +61 -0
  35. package/.savepoint/releases/v1/epics/E02-data-readers/tasks/T001-task-struct.md +29 -0
  36. package/.savepoint/releases/v1/epics/E02-data-readers/tasks/T002-frontmatter-parser.md +30 -0
  37. package/.savepoint/releases/v1/epics/E02-data-readers/tasks/T003-router-reader.md +29 -0
  38. package/.savepoint/releases/v1/epics/E02-data-readers/tasks/T004-config-reader.md +29 -0
  39. package/.savepoint/releases/v1/epics/E02-data-readers/tasks/T005-discovery.md +30 -0
  40. package/.savepoint/releases/v1/epics/E03-board-tui-core/Design.md +38 -0
  41. package/.savepoint/releases/v1/epics/E03-board-tui-core/tasks/T001-model.md +29 -0
  42. package/.savepoint/releases/v1/epics/E03-board-tui-core/tasks/T002-update-loop.md +30 -0
  43. package/.savepoint/releases/v1/epics/E03-board-tui-core/tasks/T003-view.md +34 -0
  44. package/.savepoint/releases/v1/epics/E03-board-tui-core/tasks/T004-styles.md +29 -0
  45. package/.savepoint/releases/v1/epics/E03-board-tui-core/tasks/T005-layout.md +42 -0
  46. package/.savepoint/releases/v1/epics/E04-board-components/Design.md +44 -0
  47. package/.savepoint/releases/v1/epics/E04-board-components/tasks/T001-column.md +34 -0
  48. package/.savepoint/releases/v1/epics/E04-board-components/tasks/T002-card.md +33 -0
  49. package/.savepoint/releases/v1/epics/E04-board-components/tasks/T003-epic-panel.md +49 -0
  50. package/.savepoint/releases/v1/epics/E04-board-components/tasks/T004-detail-overlay.md +40 -0
  51. package/.savepoint/releases/v1/epics/E04-board-components/tasks/T005-release-dropdown.md +33 -0
  52. package/.savepoint/releases/v1/epics/E04-board-components/tasks/T006-help-overlay.md +34 -0
  53. package/.savepoint/releases/v1/epics/E05-phase-transitions/Design.md +38 -0
  54. package/.savepoint/releases/v1/epics/E05-phase-transitions/tasks/T001-phase-stepping.md +29 -0
  55. package/.savepoint/releases/v1/epics/E05-phase-transitions/tasks/T002-gates.md +31 -0
  56. package/.savepoint/releases/v1/epics/E05-phase-transitions/tasks/T003-write-task.md +31 -0
  57. package/.savepoint/releases/v1/epics/E05-phase-transitions/tasks/T004-write-router.md +31 -0
  58. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/Design.md +42 -0
  59. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T001-color-system.md +39 -0
  60. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T002-header-and-dividers.md +52 -0
  61. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T003-footer-status-bar.md +52 -0
  62. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T004-component-refinement.md +53 -0
  63. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T005-restore-nav-hints.md +39 -0
  64. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T007-detail-card-fixes.md +36 -0
  65. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T008-checkbox-states.md +38 -0
  66. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T009-router-priority-marker.md +41 -0
  67. package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T010-auto-refresh-watcher.md +61 -0
  68. package/.savepoint/releases/v1/epics/_archived/E01-archive-and-reset/Design.md +39 -0
  69. package/.savepoint/releases/v1/epics/_archived/E01-archive-and-reset/tasks/T001-archive-epics.md +20 -0
  70. package/.savepoint/releases/v1/epics/_archived/E01-archive-and-reset/tasks/T002-rewrite-prd.md +22 -0
  71. package/.savepoint/releases/v1/epics/_archived/E01-archive-and-reset/tasks/T003-create-epic-stubs.md +24 -0
  72. package/.savepoint/releases/v1/epics/_archived/E01-archive-and-reset/tasks/T004-update-router.md +22 -0
  73. package/.savepoint/releases/v1/epics/_archived/E01-scaffolding/Design.md +118 -0
  74. package/.savepoint/releases/v1/epics/_archived/E01-scaffolding/handoff.md +9 -0
  75. package/.savepoint/releases/v1/epics/_archived/E01-scaffolding/tasks/T001-package-baseline.md +45 -0
  76. package/.savepoint/releases/v1/epics/_archived/E01-scaffolding/tasks/T002-typescript-build.md +48 -0
  77. package/.savepoint/releases/v1/epics/_archived/E01-scaffolding/tasks/T003-vitest-smoke.md +43 -0
  78. package/.savepoint/releases/v1/epics/_archived/E01-scaffolding/tasks/T004-lint-format-gates.md +45 -0
  79. package/.savepoint/releases/v1/epics/_archived/E01-scaffolding/tasks/T005-scaffold-verification.md +40 -0
  80. package/.savepoint/releases/v1/epics/_archived/E02-data-model/Design.md +142 -0
  81. package/.savepoint/releases/v1/epics/_archived/E02-data-model/tasks/T001-domain-ids-status.md +27 -0
  82. package/.savepoint/releases/v1/epics/_archived/E02-data-model/tasks/T002-markdown-frontmatter-boundary.md +28 -0
  83. package/.savepoint/releases/v1/epics/_archived/E02-data-model/tasks/T003-task-documents.md +29 -0
  84. package/.savepoint/releases/v1/epics/_archived/E02-data-model/tasks/T004-release-epic-router-config-readers.md +30 -0
  85. package/.savepoint/releases/v1/epics/_archived/E02-data-model/tasks/T005-dependency-validation.md +29 -0
  86. package/.savepoint/releases/v1/epics/_archived/E02-data-model/tasks/T006-epic-task-set-reader.md +29 -0
  87. package/.savepoint/releases/v1/epics/_archived/E02-data-model/tasks/T007-quality-gates.md +31 -0
  88. package/.savepoint/releases/v1/epics/_archived/E02-domain-phase-model/Design.md +40 -0
  89. package/.savepoint/releases/v1/epics/_archived/E02-domain-phase-model/tasks/T001-phase-types.md +27 -0
  90. package/.savepoint/releases/v1/epics/_archived/E02-domain-phase-model/tasks/T002-phase-frontmatter.md +25 -0
  91. package/.savepoint/releases/v1/epics/_archived/E02-domain-phase-model/tasks/T003-simplify-config.md +26 -0
  92. package/.savepoint/releases/v1/epics/_archived/E02-domain-phase-model/tasks/T004-simplify-router-domain.md +24 -0
  93. package/.savepoint/releases/v1/epics/_archived/E03-cli-foundation/Design.md +122 -0
  94. package/.savepoint/releases/v1/epics/_archived/E03-cli-foundation/tasks/T001-argument-parser-contract.md +28 -0
  95. package/.savepoint/releases/v1/epics/_archived/E03-cli-foundation/tasks/T002-help-text-generation.md +28 -0
  96. package/.savepoint/releases/v1/epics/_archived/E03-cli-foundation/tasks/T003-terminal-environment-detection.md +27 -0
  97. package/.savepoint/releases/v1/epics/_archived/E03-cli-foundation/tasks/T004-command-stub-modules.md +29 -0
  98. package/.savepoint/releases/v1/epics/_archived/E03-cli-foundation/tasks/T005-cli-runner-dispatch.md +34 -0
  99. package/.savepoint/releases/v1/epics/_archived/E03-cli-foundation/tasks/T006-entrypoint-quality-gates.md +32 -0
  100. package/.savepoint/releases/v1/epics/_archived/E03-cli-simplify/Design.md +43 -0
  101. package/.savepoint/releases/v1/epics/_archived/E03-cli-simplify/tasks/T001-strip-args.md +26 -0
  102. package/.savepoint/releases/v1/epics/_archived/E03-cli-simplify/tasks/T002-strip-help.md +23 -0
  103. package/.savepoint/releases/v1/epics/_archived/E03-cli-simplify/tasks/T003-strip-run.md +23 -0
  104. package/.savepoint/releases/v1/epics/_archived/E03-cli-simplify/tasks/T004-delete-commands.md +24 -0
  105. package/.savepoint/releases/v1/epics/_archived/E03-cli-simplify/tasks/T005-update-cli-tests.md +22 -0
  106. package/.savepoint/releases/v1/epics/_archived/E04-board-phase-integration/Design.md +48 -0
  107. package/.savepoint/releases/v1/epics/_archived/E04-board-phase-integration/tasks/T001-board-data-phases.md +26 -0
  108. package/.savepoint/releases/v1/epics/_archived/E04-board-phase-integration/tasks/T002-phase-rendering.md +28 -0
  109. package/.savepoint/releases/v1/epics/_archived/E04-board-phase-integration/tasks/T003-detail-pane-phases.md +27 -0
  110. package/.savepoint/releases/v1/epics/_archived/E04-board-phase-integration/tasks/T004-phase-transitions.md +42 -0
  111. package/.savepoint/releases/v1/epics/_archived/E04-board-phase-integration/tasks/T005-phase-gates.md +24 -0
  112. package/.savepoint/releases/v1/epics/_archived/E04-board-phase-integration/tasks/T006-phase-write-back.md +24 -0
  113. package/.savepoint/releases/v1/epics/_archived/E04-board-phase-integration/tasks/T007-remove-audit-flow.md +27 -0
  114. package/.savepoint/releases/v1/epics/_archived/E04-board-phase-integration/tasks/T008-board-tests.md +25 -0
  115. package/.savepoint/releases/v1/epics/_archived/E04-templates-and-prompts/Design.md +85 -0
  116. package/.savepoint/releases/v1/epics/_archived/E04-templates-and-prompts/tasks/T001-project-template-assets.md +17 -0
  117. package/.savepoint/releases/v1/epics/_archived/E04-templates-and-prompts/tasks/T002-release-and-prompt-assets.md +20 -0
  118. package/.savepoint/releases/v1/epics/_archived/E04-templates-and-prompts/tasks/T003-template-registry-renderer.md +22 -0
  119. package/.savepoint/releases/v1/epics/_archived/E04-templates-and-prompts/tasks/T004-template-integrity-tests.md +17 -0
  120. package/.savepoint/releases/v1/epics/_archived/E04-templates-and-prompts/tasks/T005-template-closeout-quality-gates.md +16 -0
  121. package/.savepoint/releases/v1/epics/_archived/E05-init-command/Design.md +88 -0
  122. package/.savepoint/releases/v1/epics/_archived/E05-init-command/tasks/T001-init-cli-contract.md +22 -0
  123. package/.savepoint/releases/v1/epics/_archived/E05-init-command/tasks/T002-target-validation.md +23 -0
  124. package/.savepoint/releases/v1/epics/_archived/E05-init-command/tasks/T003-scaffold-writer.md +24 -0
  125. package/.savepoint/releases/v1/epics/_archived/E05-init-command/tasks/T004-magic-prompt-and-clipboard.md +23 -0
  126. package/.savepoint/releases/v1/epics/_archived/E05-init-command/tasks/T005-dev-deps-install-option.md +24 -0
  127. package/.savepoint/releases/v1/epics/_archived/E05-init-command/tasks/T006-init-command-integration.md +28 -0
  128. package/.savepoint/releases/v1/epics/_archived/E05-project-cleanup/Design.md +53 -0
  129. package/.savepoint/releases/v1/epics/_archived/E05-project-cleanup/tasks/T001-delete-dead-src.md +23 -0
  130. package/.savepoint/releases/v1/epics/_archived/E05-project-cleanup/tasks/T002-delete-dead-tests.md +26 -0
  131. package/.savepoint/releases/v1/epics/_archived/E05-project-cleanup/tasks/T003-delete-assets.md +25 -0
  132. package/.savepoint/releases/v1/epics/_archived/E05-project-cleanup/tasks/T004-clean-savepoint.md +28 -0
  133. package/.savepoint/releases/v1/epics/_archived/E05-project-cleanup/tasks/T005-rewrite-agents-md.md +28 -0
  134. package/.savepoint/releases/v1/epics/_archived/E05-project-cleanup/tasks/T006-clean-package-json.md +23 -0
  135. package/.savepoint/releases/v1/epics/_archived/E05-project-cleanup/tasks/T007-verify.md +25 -0
  136. package/.savepoint/releases/v1/epics/_archived/E06-tui-board/Design.md +104 -0
  137. package/.savepoint/releases/v1/epics/_archived/E06-tui-board/tasks/T001-board-command-data.md +23 -0
  138. package/.savepoint/releases/v1/epics/_archived/E06-tui-board/tasks/T002-board-view-state.md +24 -0
  139. package/.savepoint/releases/v1/epics/_archived/E06-tui-board/tasks/T003-transition-gates-and-writes.md +25 -0
  140. package/.savepoint/releases/v1/epics/_archived/E06-tui-board/tasks/T004-terminal-theme.md +23 -0
  141. package/.savepoint/releases/v1/epics/_archived/E06-tui-board/tasks/T005-ink-board-ui.md +26 -0
  142. package/.savepoint/releases/v1/epics/_archived/E06-tui-board/tasks/T006-board-integration-audit-entry.md +24 -0
  143. package/.savepoint/releases/v1/epics/_archived/E07-audit-pipeline/Design.md +88 -0
  144. package/.savepoint/releases/v1/epics/_archived/E07-audit-pipeline/tasks/T001-audit-cli-contract.md +23 -0
  145. package/.savepoint/releases/v1/epics/_archived/E07-audit-pipeline/tasks/T002-quality-gate-runner.md +23 -0
  146. package/.savepoint/releases/v1/epics/_archived/E07-audit-pipeline/tasks/T003-snapshot-and-prompt.md +23 -0
  147. package/.savepoint/releases/v1/epics/_archived/E07-audit-pipeline/tasks/T004-audit-orchestration-router.md +27 -0
  148. package/.savepoint/releases/v1/epics/_archived/E07-audit-pipeline/tasks/T005-proposal-validation-apply.md +25 -0
  149. package/.savepoint/releases/v1/epics/_archived/E07-audit-pipeline/tasks/T006-audit-review-state.md +24 -0
  150. package/.savepoint/releases/v1/epics/_archived/E07-audit-pipeline/tasks/T007-audit-review-ui.md +26 -0
  151. package/.savepoint/releases/v1/epics/_archived/E07-audit-pipeline/tasks/T008-audit-pipeline-integration.md +24 -0
  152. package/.savepoint/releases/v1/epics/_archived/E08-board-workflow-cleanup/Design.md +103 -0
  153. package/.savepoint/releases/v1/epics/_archived/E08-board-workflow-cleanup/tasks/T001-acceptance-criteria-model.md +30 -0
  154. package/.savepoint/releases/v1/epics/_archived/E08-board-workflow-cleanup/tasks/T002-release-task-set-reader.md +33 -0
  155. package/.savepoint/releases/v1/epics/_archived/E08-board-workflow-cleanup/tasks/T003-board-data-and-plain-output.md +34 -0
  156. package/.savepoint/releases/v1/epics/_archived/E08-board-workflow-cleanup/tasks/T004-board-selection-state.md +33 -0
  157. package/.savepoint/releases/v1/epics/_archived/E08-board-workflow-cleanup/tasks/T005-ink-board-layout-cleanup.md +37 -0
  158. package/.savepoint/releases/v1/epics/_archived/E08-board-workflow-cleanup/tasks/T006-task-detail-popup.md +36 -0
  159. package/.savepoint/releases/v1/epics/_archived/E08-board-workflow-cleanup/tasks/T007-templates-acceptance-criteria.md +34 -0
  160. package/.savepoint/releases/v1/epics/_archived/E08-board-workflow-cleanup/tasks/T008-board-workflow-integration.md +41 -0
  161. package/.savepoint/releases/v1/epics/_archived/E09-doctor-command/Design.md +70 -0
  162. package/.savepoint/releases/v1/epics/_archived/E10-docs-and-packaging/Design.md +68 -0
  163. package/.savepoint/releases/v1/epics/_archived/E11-release-validation/Design.md +68 -0
  164. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/Design.md +26 -0
  165. package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T001-border-resize-fix.md +35 -0
  166. package/.savepoint/router.md +136 -0
  167. package/.savepoint/visual-identity.md +124 -0
  168. package/AGENTS.md +141 -0
  169. package/CLAUDE.md +1 -0
  170. package/GEMINI.md +1 -0
  171. package/LICENSE +21 -0
  172. package/Makefile +13 -0
  173. package/README.md +78 -0
  174. package/agent-skills/ink-tui-design/SKILL.md +309 -0
  175. package/agent-skills/ink-tui-design/references/component-patterns.md +371 -0
  176. package/agent-skills/ink-tui-design/references/hooks-guide.md +436 -0
  177. package/agent-skills/ink-tui-design/references/ink-gotchas.md +330 -0
  178. package/agent-skills/ink-tui-design/references/testing-patterns.md +384 -0
  179. package/agent-skills/savepoint-audit/SKILL.md +35 -0
  180. package/agent-skills/savepoint-build-task/SKILL.md +39 -0
  181. package/agent-skills/savepoint-create-plan/SKILL.md +28 -0
  182. package/agent-skills/savepoint-create-task/SKILL.md +31 -0
  183. package/agent-skills/savepoint-draft-prd/SKILL.md +32 -0
  184. package/agent-skills/savepoint-system-design/SKILL.md +33 -0
  185. package/agent-skills/superpowers/brainstorming/SKILL.md +165 -0
  186. package/agent-skills/superpowers/brainstorming/visual-companion.md +304 -0
  187. package/agent-skills/superpowers/dispatching-parallel-agents/SKILL.md +193 -0
  188. package/agent-skills/superpowers/executing-plans/SKILL.md +77 -0
  189. package/agent-skills/superpowers/finishing-a-development-branch/SKILL.md +213 -0
  190. package/agent-skills/superpowers/receiving-code-review/SKILL.md +226 -0
  191. package/agent-skills/superpowers/requesting-code-review/SKILL.md +115 -0
  192. package/agent-skills/superpowers/requesting-code-review/code-reviewer.md +160 -0
  193. package/agent-skills/superpowers/subagent-driven-development/SKILL.md +292 -0
  194. package/agent-skills/superpowers/subagent-driven-development/code-quality-reviewer-prompt.md +27 -0
  195. package/agent-skills/superpowers/subagent-driven-development/implementer-prompt.md +113 -0
  196. package/agent-skills/superpowers/subagent-driven-development/spec-reviewer-prompt.md +61 -0
  197. package/agent-skills/superpowers/systematic-debugging/SKILL.md +305 -0
  198. package/agent-skills/superpowers/systematic-debugging/condition-based-waiting.md +122 -0
  199. package/agent-skills/superpowers/systematic-debugging/defense-in-depth.md +130 -0
  200. package/agent-skills/superpowers/systematic-debugging/root-cause-tracing.md +183 -0
  201. package/agent-skills/superpowers/test-driven-development/SKILL.md +389 -0
  202. package/agent-skills/superpowers/test-driven-development/testing-anti-patterns.md +317 -0
  203. package/agent-skills/superpowers/verification-before-completion/SKILL.md +147 -0
  204. package/agent-skills/superpowers/writing-plans/SKILL.md +159 -0
  205. package/agent-skills/superpowers/writing-plans/plan-document-reviewer-prompt.md +49 -0
  206. package/assets/banner.png +0 -0
  207. package/assets/logo.png +0 -0
  208. package/assets/strawman.png +0 -0
  209. package/go.mod +33 -0
  210. package/go.sum +73 -0
  211. package/ink-cli-ui-design.zip +0 -0
  212. package/internal/board/board.go +121 -0
  213. package/internal/board/board_test.go +99 -0
  214. package/internal/board/card.go +72 -0
  215. package/internal/board/card_test.go +111 -0
  216. package/internal/board/column.go +61 -0
  217. package/internal/board/column_test.go +81 -0
  218. package/internal/board/detail.go +140 -0
  219. package/internal/board/detail_test.go +233 -0
  220. package/internal/board/epic_panel.go +69 -0
  221. package/internal/board/epic_panel_test.go +246 -0
  222. package/internal/board/help.go +40 -0
  223. package/internal/board/help_test.go +85 -0
  224. package/internal/board/layout.go +58 -0
  225. package/internal/board/layout_test.go +89 -0
  226. package/internal/board/model.go +151 -0
  227. package/internal/board/model_test.go +67 -0
  228. package/internal/board/release.go +42 -0
  229. package/internal/board/release_test.go +177 -0
  230. package/internal/board/transitions.go +88 -0
  231. package/internal/board/transitions_test.go +141 -0
  232. package/internal/board/update.go +155 -0
  233. package/internal/board/update_test.go +128 -0
  234. package/internal/board/view.go +190 -0
  235. package/internal/board/view_test.go +147 -0
  236. package/internal/data/config.go +87 -0
  237. package/internal/data/config_test.go +73 -0
  238. package/internal/data/discover.go +152 -0
  239. package/internal/data/discover_test.go +106 -0
  240. package/internal/data/errors.go +9 -0
  241. package/internal/data/lifecycle.go +37 -0
  242. package/internal/data/lifecycle_test.go +38 -0
  243. package/internal/data/parser.go +189 -0
  244. package/internal/data/parser_test.go +216 -0
  245. package/internal/data/router.go +52 -0
  246. package/internal/data/router_test.go +35 -0
  247. package/internal/data/task.go +46 -0
  248. package/internal/data/task_test.go +51 -0
  249. package/internal/data/write.go +144 -0
  250. package/internal/data/write_test.go +456 -0
  251. package/internal/styles/palette.go +47 -0
  252. package/internal/styles/styles.go +122 -0
  253. package/main.exe +0 -0
  254. package/main.go +11 -0
  255. package/package.json +25 -0
  256. package/savepoint +0 -0
  257. package/savepoint.exe +0 -0
  258. package/scripts/vitest-preload.cjs +95 -0
  259. package/templates/project/.savepoint/Design.md +47 -0
  260. package/templates/project/.savepoint/PRD.md +34 -0
  261. package/templates/project/.savepoint/config.yml +27 -0
  262. package/templates/project/.savepoint/router.md +152 -0
  263. package/templates/project/.savepoint/visual-identity.md +122 -0
  264. package/templates/project/AGENTS.md +130 -0
  265. package/templates/prompts/audit-reconciliation.prompt.md +67 -0
  266. package/templates/prompts/design.prompt.md +43 -0
  267. package/templates/prompts/epic-design.prompt.md +43 -0
  268. package/templates/prompts/magic-prompt.prompt.md +7 -0
  269. package/templates/prompts/prd.prompt.md +42 -0
  270. package/templates/prompts/task-breakdown.prompt.md +54 -0
  271. package/templates/prompts/task-building.prompt.md +38 -0
  272. package/templates/prompts/task-planning.prompt.md +53 -0
  273. package/templates/release/v1/PRD.md +37 -0
@@ -0,0 +1,189 @@
1
+ package data
2
+
3
+ import (
4
+ "fmt"
5
+ "strings"
6
+
7
+ "gopkg.in/yaml.v3"
8
+ )
9
+
10
+ type Parser struct{}
11
+
12
+ func NewParser() *Parser {
13
+ return &Parser{}
14
+ }
15
+
16
+ func (p *Parser) ParseFrontmatter(content string) (map[string]any, error) {
17
+ frontmatter, err := extractFrontmatter(content)
18
+ if err != nil {
19
+ return nil, err
20
+ }
21
+
22
+ var result map[string]any
23
+ if err := yaml.Unmarshal([]byte(frontmatter), &result); err != nil {
24
+ return nil, fmt.Errorf("failed to parse YAML: %w", err)
25
+ }
26
+
27
+ return result, nil
28
+ }
29
+
30
+ func (p *Parser) ParseTaskFile(path string, content string) (*Task, error) {
31
+ frontmatter, err := extractFrontmatter(content)
32
+ if err != nil {
33
+ return nil, fmt.Errorf("parse error for %s: %w", path, err)
34
+ }
35
+
36
+ var fields taskFrontmatter
37
+ if err := yaml.Unmarshal([]byte(frontmatter), &fields); err != nil {
38
+ return nil, fmt.Errorf("parse error for %s: failed to parse YAML: %w", path, err)
39
+ }
40
+
41
+ rawColumn := firstColumn(fields.Column, fields.Status)
42
+ task := &Task{
43
+ ID: fields.ID,
44
+ Title: firstNonEmpty(fields.Title, fields.Objective),
45
+ Description: fields.Description,
46
+ Epic: firstNonEmpty(fields.Epic, extractEpicFromID(fields.ID)),
47
+ Release: firstNonEmpty(fields.Release, "v1"),
48
+ Column: normalizeColumn(rawColumn),
49
+ Stage: firstStage(fields.Stage, fields.Phase),
50
+ Priority: fields.Priority,
51
+ Points: fields.Points,
52
+ Tags: fields.Tags,
53
+ Acceptance: firstList(fields.Acceptance, extractChecklistSection(content, "## Acceptance Criteria")),
54
+ Checklist: extractChecklistSection(content, "## Implementation Plan"),
55
+ Notes: fields.Notes,
56
+ DependsOn: fields.DependsOn,
57
+ Progress: fields.Progress,
58
+ }
59
+
60
+ if err := validateParsedTaskLifecycle(rawColumn, *task); err != nil {
61
+ return nil, fmt.Errorf("parse error for %s: %w", path, err)
62
+ }
63
+
64
+ return task, nil
65
+ }
66
+
67
+ type taskFrontmatter struct {
68
+ ID string `yaml:"id"`
69
+ Title string `yaml:"title"`
70
+ Objective string `yaml:"objective"`
71
+ Description string `yaml:"description"`
72
+ Epic string `yaml:"epic"`
73
+ Release string `yaml:"release"`
74
+ Status ColumnType `yaml:"status"`
75
+ Column ColumnType `yaml:"column"`
76
+ Phase ProgressStage `yaml:"phase"`
77
+ Stage ProgressStage `yaml:"stage"`
78
+ Priority string `yaml:"priority"`
79
+ Points int `yaml:"points"`
80
+ Tags []string `yaml:"tags"`
81
+ Acceptance []string `yaml:"acceptance"`
82
+ Notes string `yaml:"notes"`
83
+ DependsOn []string `yaml:"depends_on"`
84
+ Progress Progress `yaml:"progress"`
85
+ }
86
+
87
+ func extractFrontmatter(content string) (string, error) {
88
+ normalized := strings.ReplaceAll(content, "\r\n", "\n")
89
+ if !strings.HasPrefix(normalized, "---\n") {
90
+ return "", ErrNoFrontmatter
91
+ }
92
+
93
+ end := strings.Index(normalized[len("---\n"):], "\n---")
94
+ if end == -1 {
95
+ return "", ErrNoClosingFrontmatter
96
+ }
97
+
98
+ return strings.TrimSpace(normalized[len("---\n") : len("---\n")+end]), nil
99
+ }
100
+
101
+ func extractEpicFromID(id string) string {
102
+ parts := strings.Split(id, "/")
103
+ if len(parts) >= 1 {
104
+ return parts[0]
105
+ }
106
+ return ""
107
+ }
108
+
109
+ func firstNonEmpty(values ...string) string {
110
+ for _, value := range values {
111
+ if value != "" {
112
+ return value
113
+ }
114
+ }
115
+ return ""
116
+ }
117
+
118
+ func firstColumn(values ...ColumnType) ColumnType {
119
+ for _, value := range values {
120
+ if value != "" {
121
+ return value
122
+ }
123
+ }
124
+ return ""
125
+ }
126
+
127
+ func normalizeColumn(value ColumnType) ColumnType {
128
+ switch value {
129
+ case "", legacyTodoColumn:
130
+ return ColumnPlanned
131
+ case ColumnPlanned, ColumnInProgress, ColumnDone:
132
+ return value
133
+ default:
134
+ return value
135
+ }
136
+ }
137
+
138
+ const legacyTodoColumn ColumnType = "todo"
139
+
140
+ func validateParsedTaskLifecycle(rawColumn ColumnType, task Task) error {
141
+ if rawColumn != "" && rawColumn != legacyTodoColumn && !IsCanonicalColumn(rawColumn) {
142
+ return fmt.Errorf("invalid task status %q: use planned, in_progress, or done", rawColumn)
143
+ }
144
+ return ValidateTaskLifecycle(task)
145
+ }
146
+
147
+ func firstStage(values ...ProgressStage) ProgressStage {
148
+ for _, value := range values {
149
+ if value != "" {
150
+ return value
151
+ }
152
+ }
153
+ return ""
154
+ }
155
+
156
+ func firstList(values ...[]string) []string {
157
+ for _, value := range values {
158
+ if len(value) > 0 {
159
+ return value
160
+ }
161
+ }
162
+ return nil
163
+ }
164
+
165
+ func extractChecklistSection(content, heading string) []string {
166
+ normalized := strings.ReplaceAll(content, "\r\n", "\n")
167
+ start := strings.Index(normalized, heading)
168
+ if start == -1 {
169
+ return nil
170
+ }
171
+
172
+ section := normalized[start+len(heading):]
173
+ if next := strings.Index(section, "\n## "); next != -1 {
174
+ section = section[:next]
175
+ }
176
+
177
+ items := []string{}
178
+ for _, line := range strings.Split(section, "\n") {
179
+ trimmed := strings.TrimSpace(line)
180
+ if strings.HasPrefix(trimmed, "- [ ] ") || strings.HasPrefix(trimmed, "- [x] ") {
181
+ items = append(items, strings.TrimSpace(trimmed[6:]))
182
+ continue
183
+ }
184
+ if strings.HasPrefix(trimmed, "- ") {
185
+ items = append(items, strings.TrimSpace(trimmed[2:]))
186
+ }
187
+ }
188
+ return items
189
+ }
@@ -0,0 +1,216 @@
1
+ package data
2
+
3
+ import (
4
+ "testing"
5
+ )
6
+
7
+ func TestParseFrontmatter(t *testing.T) {
8
+ p := NewParser()
9
+ content := `---
10
+ id: E01/T001
11
+ status: done
12
+ objective: "Test objective"
13
+ depends_on: []
14
+ ---
15
+
16
+ body content here`
17
+
18
+ result, err := p.ParseFrontmatter(content)
19
+ if err != nil {
20
+ t.Fatalf("ParseFrontmatter() error = %v", err)
21
+ }
22
+
23
+ if result["id"] != "E01/T001" {
24
+ t.Errorf("ParseFrontmatter() id = %v, want E01/T001", result["id"])
25
+ }
26
+ if result["objective"] != "Test objective" {
27
+ t.Errorf("ParseFrontmatter() objective = %v, want Test objective", result["objective"])
28
+ }
29
+ }
30
+
31
+ func TestParseFrontmatterMissing(t *testing.T) {
32
+ p := NewParser()
33
+ content := `# No frontmatter here`
34
+
35
+ _, err := p.ParseFrontmatter(content)
36
+ if err == nil {
37
+ t.Error("ParseFrontmatter() expected error for missing frontmatter")
38
+ }
39
+ }
40
+
41
+ func TestParseFrontmatterMalformedYAML(t *testing.T) {
42
+ p := NewParser()
43
+ content := `---
44
+ id: [broken
45
+ ---
46
+
47
+ # Task description`
48
+
49
+ _, err := p.ParseFrontmatter(content)
50
+ if err == nil {
51
+ t.Fatal("ParseFrontmatter() expected malformed YAML error")
52
+ }
53
+ }
54
+
55
+ func TestParseTaskFile(t *testing.T) {
56
+ p := NewParser()
57
+ content := `---
58
+ id: E02/T001
59
+ status: in_progress
60
+ phase: test
61
+ objective: "Define Task struct"
62
+ description: "Build the task model"
63
+ priority: high
64
+ points: 3
65
+ tags: [data, parser]
66
+ acceptance:
67
+ - parses metadata
68
+ notes: "Keep it small"
69
+ depends_on: [E01/T003]
70
+ ---
71
+
72
+ # Task description`
73
+
74
+ task, err := p.ParseTaskFile("test.md", content)
75
+ if err != nil {
76
+ t.Fatalf("ParseTaskFile() error = %v", err)
77
+ }
78
+
79
+ if task.ID != "E02/T001" {
80
+ t.Errorf("Task.ID = %v, want E02/T001", task.ID)
81
+ }
82
+ if task.Title != "Define Task struct" {
83
+ t.Errorf("Task.Title = %v, want Define Task struct", task.Title)
84
+ }
85
+ if task.Epic != "E02" {
86
+ t.Errorf("Task.Epic = %v, want E02", task.Epic)
87
+ }
88
+ if task.Release != "v1" {
89
+ t.Errorf("Task.Release = %v, want v1", task.Release)
90
+ }
91
+ if task.Column != ColumnInProgress {
92
+ t.Errorf("Task.Column = %v, want %v", task.Column, ColumnInProgress)
93
+ }
94
+ if task.Stage != StageTest {
95
+ t.Errorf("Task.Stage = %v, want %v", task.Stage, StageTest)
96
+ }
97
+ if len(task.DependsOn) != 1 || task.DependsOn[0] != "E01/T003" {
98
+ t.Errorf("Task.DependsOn = %v, want [E01/T003]", task.DependsOn)
99
+ }
100
+ if task.Priority != "high" || task.Points != 3 {
101
+ t.Errorf("Task priority/points = %v/%v, want high/3", task.Priority, task.Points)
102
+ }
103
+ if len(task.Tags) != 2 || task.Tags[0] != "data" || task.Tags[1] != "parser" {
104
+ t.Errorf("Task.Tags = %v, want [data parser]", task.Tags)
105
+ }
106
+ if len(task.Acceptance) != 1 || task.Acceptance[0] != "parses metadata" {
107
+ t.Errorf("Task.Acceptance = %v, want [parses metadata]", task.Acceptance)
108
+ }
109
+ if task.Notes != "Keep it small" {
110
+ t.Errorf("Task.Notes = %v, want Keep it small", task.Notes)
111
+ }
112
+ }
113
+
114
+ func TestParseTaskFile_normalizesLegacyTodoStatusToPlanned(t *testing.T) {
115
+ p := NewParser()
116
+ content := `---
117
+ id: E06/T001
118
+ status: todo
119
+ objective: "Style the board"
120
+ ---
121
+
122
+ # Task`
123
+
124
+ task, err := p.ParseTaskFile("test.md", content)
125
+ if err != nil {
126
+ t.Fatalf("ParseTaskFile() error = %v", err)
127
+ }
128
+ if task.Column != ColumnPlanned {
129
+ t.Errorf("Task.Column = %v, want %v", task.Column, ColumnPlanned)
130
+ }
131
+ }
132
+
133
+ func TestParseTaskFile_rejectsUnknownStatus(t *testing.T) {
134
+ p := NewParser()
135
+ content := `---
136
+ id: E06/T001
137
+ status: review
138
+ objective: "Style the board"
139
+ ---
140
+
141
+ # Task`
142
+
143
+ _, err := p.ParseTaskFile("test.md", content)
144
+ if err == nil {
145
+ t.Fatal("ParseTaskFile() expected unknown status error")
146
+ }
147
+ }
148
+
149
+ func TestParseTaskFile_rejectsPhaseOutsideInProgress(t *testing.T) {
150
+ p := NewParser()
151
+ content := `---
152
+ id: E06/T001
153
+ status: planned
154
+ phase: build
155
+ objective: "Style the board"
156
+ ---
157
+
158
+ # Task`
159
+
160
+ _, err := p.ParseTaskFile("test.md", content)
161
+ if err == nil {
162
+ t.Fatal("ParseTaskFile() expected invalid phase/status error")
163
+ }
164
+ }
165
+
166
+ func TestParseTaskFile_rejectsInProgressWithoutPhase(t *testing.T) {
167
+ p := NewParser()
168
+ content := `---
169
+ id: E06/T001
170
+ status: in_progress
171
+ objective: "Style the board"
172
+ ---
173
+
174
+ # Task`
175
+
176
+ _, err := p.ParseTaskFile("test.md", content)
177
+ if err == nil {
178
+ t.Fatal("ParseTaskFile() expected missing phase error")
179
+ }
180
+ }
181
+
182
+ func TestParseTaskFile_extractsMarkdownAcceptanceAndChecklist(t *testing.T) {
183
+ p := NewParser()
184
+ content := `---
185
+ id: E06/T001
186
+ status: planned
187
+ objective: "Style the board"
188
+ ---
189
+
190
+ # Task
191
+
192
+ ## Acceptance Criteria
193
+
194
+ - First criterion.
195
+ - Second criterion.
196
+
197
+ ## Implementation Plan
198
+
199
+ - [ ] First checklist item.
200
+ - [x] Second checklist item.
201
+
202
+ ## Context Log
203
+
204
+ Notes here.`
205
+
206
+ task, err := p.ParseTaskFile("test.md", content)
207
+ if err != nil {
208
+ t.Fatalf("ParseTaskFile() error = %v", err)
209
+ }
210
+ if len(task.Acceptance) != 2 || task.Acceptance[0] != "First criterion." || task.Acceptance[1] != "Second criterion." {
211
+ t.Errorf("Task.Acceptance = %v, want markdown criteria", task.Acceptance)
212
+ }
213
+ if len(task.Checklist) != 2 || task.Checklist[0] != "First checklist item." || task.Checklist[1] != "Second checklist item." {
214
+ t.Errorf("Task.Checklist = %v, want markdown checklist", task.Checklist)
215
+ }
216
+ }
@@ -0,0 +1,52 @@
1
+ package data
2
+
3
+ import (
4
+ "fmt"
5
+ "strings"
6
+
7
+ "gopkg.in/yaml.v3"
8
+ )
9
+
10
+ const stateBlockStart = "## Current state"
11
+ const stateBlockEnd = "```"
12
+
13
+ type RouterState struct {
14
+ State string `yaml:"state"`
15
+ Release string `yaml:"release"`
16
+ Epic string `yaml:"epic"`
17
+ Task string `yaml:"task"`
18
+ NextAction string `yaml:"next_action"`
19
+ }
20
+
21
+ type RouterReader struct{}
22
+
23
+ func NewRouterReader() *RouterReader {
24
+ return &RouterReader{}
25
+ }
26
+
27
+ func (r *RouterReader) ReadState(content string) (*RouterState, error) {
28
+ startIdx := strings.Index(content, stateBlockStart)
29
+ if startIdx == -1 {
30
+ return nil, fmt.Errorf("no Current state block found")
31
+ }
32
+
33
+ yamlStart := strings.Index(content[startIdx:], "```yaml")
34
+ if yamlStart == -1 {
35
+ return nil, fmt.Errorf("no yaml code block found")
36
+ }
37
+
38
+ yamlStart += startIdx + len("```yaml")
39
+ yamlEnd := strings.Index(content[yamlStart:], "```")
40
+ if yamlEnd == -1 {
41
+ return nil, fmt.Errorf("no closing code block found")
42
+ }
43
+
44
+ yamlContent := strings.TrimSpace(content[yamlStart : yamlStart+yamlEnd])
45
+
46
+ var state RouterState
47
+ if err := yaml.Unmarshal([]byte(yamlContent), &state); err != nil {
48
+ return nil, fmt.Errorf("failed to parse router YAML: %w", err)
49
+ }
50
+
51
+ return &state, nil
52
+ }
@@ -0,0 +1,35 @@
1
+ package data
2
+
3
+ import (
4
+ "testing"
5
+ )
6
+
7
+ func TestRouterReaderReadState(t *testing.T) {
8
+ r := NewRouterReader()
9
+ content := "## Current state\n\n```yaml\nstate: building\nrelease: v1\nepic: E01-go-setup\ntask: E01-go-setup/T002-entrypoint\nnext_action: \"Start T002-entrypoint\"\n```\n"
10
+
11
+ state, err := r.ReadState(content)
12
+ if err != nil {
13
+ t.Fatalf("ReadState() error = %v", err)
14
+ }
15
+
16
+ if state.State != "building" {
17
+ t.Errorf("State = %v, want building", state.State)
18
+ }
19
+ if state.Epic != "E01-go-setup" {
20
+ t.Errorf("Epic = %v, want E01-go-setup", state.Epic)
21
+ }
22
+ if state.Task != "E01-go-setup/T002-entrypoint" {
23
+ t.Errorf("Task = %v, want E01-go-setup/T002-entrypoint", state.Task)
24
+ }
25
+ }
26
+
27
+ func TestRouterReaderMissing(t *testing.T) {
28
+ r := NewRouterReader()
29
+ content := "# No state block here"
30
+
31
+ _, err := r.ReadState(content)
32
+ if err == nil {
33
+ t.Error("ReadState() expected error for missing state block")
34
+ }
35
+ }
@@ -0,0 +1,46 @@
1
+ package data
2
+
3
+ import "fmt"
4
+
5
+ type ColumnType string
6
+
7
+ const (
8
+ ColumnPlanned ColumnType = "planned"
9
+ ColumnInProgress ColumnType = "in_progress"
10
+ ColumnDone ColumnType = "done"
11
+ )
12
+
13
+ type ProgressStage string
14
+
15
+ const (
16
+ StageBuild ProgressStage = "build"
17
+ StageTest ProgressStage = "test"
18
+ StageAudit ProgressStage = "audit"
19
+ )
20
+
21
+ type Progress struct {
22
+ Stage ProgressStage `yaml:"stage"`
23
+ Started bool `yaml:"started"`
24
+ }
25
+
26
+ type Task struct {
27
+ ID string `yaml:"id"`
28
+ Title string `yaml:"title"`
29
+ Description string `yaml:"description,omitempty"`
30
+ Epic string `yaml:"epic"`
31
+ Release string `yaml:"release"`
32
+ Column ColumnType `yaml:"column"`
33
+ Stage ProgressStage `yaml:"stage,omitempty"`
34
+ Priority string `yaml:"priority,omitempty"`
35
+ Points int `yaml:"points,omitempty"`
36
+ Tags []string `yaml:"tags,omitempty"`
37
+ Acceptance []string `yaml:"acceptance,omitempty"`
38
+ Checklist []string `yaml:"checklist,omitempty"`
39
+ Notes string `yaml:"notes,omitempty"`
40
+ DependsOn []string `yaml:"depends_on,omitempty"`
41
+ Progress Progress `yaml:"progress,omitempty"`
42
+ }
43
+
44
+ func (t Task) String() string {
45
+ return fmt.Sprintf("Task(%s)", t.ID)
46
+ }
@@ -0,0 +1,51 @@
1
+ package data
2
+
3
+ import (
4
+ "testing"
5
+ )
6
+
7
+ func TestTaskString(t *testing.T) {
8
+ task := Task{
9
+ ID: "E01/T001",
10
+ Title: "Test Task",
11
+ Column: ColumnPlanned,
12
+ }
13
+ want := "Task(E01/T001)"
14
+ if got := task.String(); got != want {
15
+ t.Errorf("Task.String() = %v, want %v", got, want)
16
+ }
17
+ }
18
+
19
+ func TestColumnTypes(t *testing.T) {
20
+ tests := []struct {
21
+ input ColumnType
22
+ want string
23
+ }{
24
+ {ColumnPlanned, "planned"},
25
+ {ColumnInProgress, "in_progress"},
26
+ {ColumnDone, "done"},
27
+ }
28
+
29
+ for _, tt := range tests {
30
+ if string(tt.input) != tt.want {
31
+ t.Errorf("ColumnType = %v, want %v", tt.input, tt.want)
32
+ }
33
+ }
34
+ }
35
+
36
+ func TestProgressStage(t *testing.T) {
37
+ tests := []struct {
38
+ input ProgressStage
39
+ want string
40
+ }{
41
+ {StageBuild, "build"},
42
+ {StageTest, "test"},
43
+ {StageAudit, "audit"},
44
+ }
45
+
46
+ for _, tt := range tests {
47
+ if string(tt.input) != tt.want {
48
+ t.Errorf("ProgressStage = %v, want %v", tt.input, tt.want)
49
+ }
50
+ }
51
+ }