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,567 +0,0 @@
1
- package doctor
2
-
3
- import (
4
- "fmt"
5
- "os"
6
- "path/filepath"
7
- "strconv"
8
- "strings"
9
-
10
- "github.com/opencode/savepoint/internal/data"
11
- "gopkg.in/yaml.v3"
12
- )
13
-
14
- // CheckConfig validates config.yml: exists, valid YAML, required fields present.
15
- func CheckConfig(root string) error {
16
- configPath := filepath.Join(root, "config.yml")
17
- raw, err := os.ReadFile(configPath)
18
- if os.IsNotExist(err) {
19
- return fmt.Errorf("config.yml not found: %w", data.ErrConfigNotFound)
20
- }
21
- if err != nil {
22
- return fmt.Errorf("config.yml unreadable: %w", err)
23
- }
24
-
25
- var fields map[string]any
26
- if err := yaml.Unmarshal(raw, &fields); err != nil {
27
- return fmt.Errorf("config.yml invalid YAML: %w", err)
28
- }
29
-
30
- if _, ok := fields["quality_gates"]; !ok {
31
- return fmt.Errorf("config.yml missing required field: quality_gates")
32
- }
33
- if _, ok := fields["theme"]; !ok {
34
- return fmt.Errorf("config.yml missing required field: theme")
35
- }
36
-
37
- return nil
38
- }
39
-
40
- // CheckRouter validates router.md: valid state name, release/epic directories exist.
41
- // epicFilter, if non-empty, skips directory checks when the router epic doesn't match.
42
- func CheckRouter(root, epicFilter string, overrides ...DoctorDependencies) error {
43
- deps := doctorDependencies(overrides)
44
- routerPath := filepath.Join(root, "router.md")
45
- raw, err := os.ReadFile(routerPath)
46
- if os.IsNotExist(err) {
47
- return fmt.Errorf("router.md not found: %w", data.ErrConfigNotFound)
48
- }
49
- if err != nil {
50
- return fmt.Errorf("router.md unreadable: %w", err)
51
- }
52
-
53
- state, err := deps.RouterReader.ReadState(string(raw))
54
- if err != nil {
55
- return fmt.Errorf("router.md invalid state block: %w", err)
56
- }
57
-
58
- if epicFilter != "" && state.Epic != epicFilter {
59
- return nil
60
- }
61
-
62
- if state.Release != "" && state.Release != "none" {
63
- releasePath := filepath.Join(root, "releases", state.Release)
64
- if _, err := os.Stat(releasePath); os.IsNotExist(err) {
65
- return fmt.Errorf("router.md release %q directory not found", state.Release)
66
- }
67
- }
68
-
69
- if state.Epic != "" && state.Epic != "none" {
70
- if state.Release == "" || state.Release == "none" {
71
- return fmt.Errorf("router.md has epic %q but no release", state.Epic)
72
- }
73
- epicPath := filepath.Join(root, "releases", state.Release, "epics", state.Epic)
74
- if _, err := os.Stat(epicPath); os.IsNotExist(err) {
75
- return fmt.Errorf("router.md epic %q directory not found", state.Epic)
76
- }
77
- }
78
-
79
- return nil
80
- }
81
-
82
- // Problem describes a single issue found during a structure check.
83
- type Problem struct {
84
- File string
85
- Line int
86
- Message string
87
- }
88
-
89
- func (p Problem) Error() string {
90
- if p.Line > 0 {
91
- return fmt.Sprintf("%s:%d: %s", p.File, p.Line, p.Message)
92
- }
93
- if p.File != "" {
94
- return fmt.Sprintf("%s: %s", p.File, p.Message)
95
- }
96
- return p.Message
97
- }
98
-
99
- // CheckStructure validates release/epic/task structure and YAML across the project.
100
- // epicFilter, if non-empty, restricts checks to matching epics.
101
- func CheckStructure(root string, epicFilter string, overrides ...DoctorDependencies) []Problem {
102
- deps := doctorDependencies(overrides)
103
- var problems []Problem
104
-
105
- releasesPath := filepath.Join(root, "releases")
106
- if _, err := os.Stat(releasesPath); os.IsNotExist(err) {
107
- problems = append(problems, Problem{File: releasesPath, Message: "releases directory not found"})
108
- return problems
109
- }
110
-
111
- releases, err := deps.Discoverer.ListReleases(root)
112
- if err != nil {
113
- problems = append(problems, Problem{File: releasesPath, Message: fmt.Sprintf("listing releases: %v", err)})
114
- return problems
115
- }
116
-
117
- if len(releases) == 0 {
118
- problems = append(problems, Problem{File: releasesPath, Message: "no release directories found"})
119
- return problems
120
- }
121
-
122
- for _, release := range releases {
123
- checkReleasePRD(release.Path, release.ID, deps.Parser, &problems)
124
-
125
- epics, err := deps.Discoverer.ListEpics(root, release.ID)
126
- if err != nil {
127
- problems = append(problems, Problem{
128
- File: filepath.Join(release.Path, "epics"),
129
- Message: fmt.Sprintf("listing epics in release %q: %v", release.ID, err),
130
- })
131
- continue
132
- }
133
-
134
- for _, epic := range epics {
135
- if epicFilter != "" && epic.ID != epicFilter && !strings.HasPrefix(epic.ID, epicFilter) {
136
- continue
137
- }
138
-
139
- checkEpicDetail(epic.Path, epic.ID, deps.Parser, &problems)
140
-
141
- tasks, err := deps.Discoverer.ListTasks(root, release.ID, epic.ID)
142
- if err != nil {
143
- problems = append(problems, Problem{
144
- File: filepath.Join(epic.Path, "tasks"),
145
- Message: fmt.Sprintf("listing tasks in epic %q: %v", epic.ID, err),
146
- })
147
- continue
148
- }
149
-
150
- for _, task := range tasks {
151
- checkTaskFile(task.Path, deps.Parser, &problems)
152
- }
153
- }
154
- }
155
-
156
- return problems
157
- }
158
-
159
- func checkReleasePRD(releasePath string, releaseID string, parser taskParser, problems *[]Problem) {
160
- prdPath := filepath.Join(releasePath, releaseID+"-PRD.md")
161
- raw, err := os.ReadFile(prdPath)
162
- if os.IsNotExist(err) {
163
- *problems = append(*problems, Problem{File: prdPath, Message: "release PRD file not found"})
164
- return
165
- }
166
- if err != nil {
167
- *problems = append(*problems, Problem{File: prdPath, Message: fmt.Sprintf("unreadable: %v", err)})
168
- return
169
- }
170
- validateFrontmatter(prdPath, string(raw), parser, problems)
171
- }
172
-
173
- func checkEpicDetail(epicPath string, epicID string, parser taskParser, problems *[]Problem) {
174
- prefix := extractPrefix(epicID)
175
- detailPath := filepath.Join(epicPath, prefix+"-Detail.md")
176
- raw, err := os.ReadFile(detailPath)
177
- if os.IsNotExist(err) {
178
- *problems = append(*problems, Problem{File: detailPath, Message: "epic detail file not found"})
179
- return
180
- }
181
- if err != nil {
182
- *problems = append(*problems, Problem{File: detailPath, Message: fmt.Sprintf("unreadable: %v", err)})
183
- return
184
- }
185
- validateFrontmatter(detailPath, string(raw), parser, problems)
186
- }
187
-
188
- func extractPrefix(epicID string) string {
189
- if idx := strings.IndexByte(epicID, '-'); idx != -1 {
190
- return epicID[:idx]
191
- }
192
- return epicID
193
- }
194
-
195
- func checkTaskFile(path string, parser taskParser, problems *[]Problem) {
196
- raw, err := os.ReadFile(path)
197
- if err != nil {
198
- *problems = append(*problems, Problem{File: path, Message: fmt.Sprintf("unreadable: %v", err)})
199
- return
200
- }
201
-
202
- content := string(raw)
203
- fm, err := parser.ParseFrontmatter(content)
204
- if err != nil {
205
- line := extractYAMLLine(err)
206
- *problems = append(*problems, Problem{File: path, Line: line, Message: fmt.Sprintf("invalid frontmatter: %v", err)})
207
- return
208
- }
209
-
210
- checkRequiredString(fm, path, "id", problems)
211
- checkRequiredString(fm, path, "status", problems)
212
- checkRequiredString(fm, path, "objective", problems)
213
- checkDependsOn(fm, path, problems)
214
-
215
- if !hasAcceptanceCriteria(content) {
216
- *problems = append(*problems, Problem{File: path, Message: "task missing ## Acceptance Criteria section"})
217
- }
218
- }
219
-
220
- func checkRequiredString(fm map[string]any, path, field string, problems *[]Problem) {
221
- val, ok := fm[field]
222
- if !ok {
223
- *problems = append(*problems, Problem{File: path, Message: fmt.Sprintf("task missing required frontmatter field: %s", field)})
224
- return
225
- }
226
- s, ok := val.(string)
227
- if !ok || s == "" {
228
- *problems = append(*problems, Problem{File: path, Message: fmt.Sprintf("task frontmatter field %q must be a non-empty string", field)})
229
- }
230
- }
231
-
232
- func checkDependsOn(fm map[string]any, path string, problems *[]Problem) {
233
- val, ok := fm["depends_on"]
234
- if !ok {
235
- return
236
- }
237
- switch val.(type) {
238
- case []any, []string:
239
- default:
240
- *problems = append(*problems, Problem{File: path, Message: "task frontmatter field depends_on must be a list"})
241
- }
242
- }
243
-
244
- func hasAcceptanceCriteria(content string) bool {
245
- normalized := strings.ReplaceAll(content, "\r\n", "\n")
246
- idx := strings.Index(normalized, "## Acceptance Criteria")
247
- if idx == -1 {
248
- return false
249
- }
250
- section := normalized[idx+len("## Acceptance Criteria"):]
251
- if next := strings.Index(section, "\n## "); next != -1 {
252
- section = section[:next]
253
- }
254
- section = strings.TrimSpace(section)
255
- return section != ""
256
- }
257
-
258
- func validateFrontmatter(path, content string, parser taskParser, problems *[]Problem) {
259
- _, err := parser.ParseFrontmatter(content)
260
- if err != nil {
261
- line := extractYAMLLine(err)
262
- *problems = append(*problems, Problem{File: path, Line: line, Message: fmt.Sprintf("invalid frontmatter: %v", err)})
263
- }
264
- }
265
-
266
- // taskDep describes a parsed task's dependency information.
267
- type taskDep struct {
268
- File string
269
- ID string
270
- DependsOn []string
271
- }
272
-
273
- // CheckDependencies validates task dependency integrity:
274
- // missing deps, duplicate IDs, and dependency cycles.
275
- // epicFilter restricts checks to matching epics if non-empty.
276
- func CheckDependencies(root string, epicFilter string, overrides ...DoctorDependencies) []Problem {
277
- deps := doctorDependencies(overrides)
278
- var problems []Problem
279
-
280
- releases, err := deps.Discoverer.ListReleases(root)
281
- if err != nil {
282
- problems = append(problems, Problem{Message: fmt.Sprintf("listing releases: %v", err)})
283
- return problems
284
- }
285
-
286
- var allTasks []taskDep
287
- idSet := make(map[string]string) // id -> first file seen
288
-
289
- for _, release := range releases {
290
- epics, err := deps.Discoverer.ListEpics(root, release.ID)
291
- if err != nil {
292
- continue
293
- }
294
- for _, epic := range epics {
295
- if epicFilter != "" && epic.ID != epicFilter && !strings.HasPrefix(epic.ID, epicFilter) {
296
- continue
297
- }
298
- tasks, err := deps.Discoverer.ListTasks(root, release.ID, epic.ID)
299
- if err != nil {
300
- continue
301
- }
302
- for _, t := range tasks {
303
- td := parseTaskDep(t.Path, deps.Parser)
304
- if td == nil {
305
- continue
306
- }
307
- allTasks = append(allTasks, *td)
308
- if existing, ok := idSet[td.ID]; ok {
309
- problems = append(problems, Problem{
310
- File: td.File,
311
- Message: fmt.Sprintf("duplicate task ID %q (first seen in %s)", td.ID, existing),
312
- })
313
- } else {
314
- idSet[td.ID] = td.File
315
- }
316
- }
317
- }
318
- }
319
-
320
- // Check for missing dependencies and cycles
321
- graph := make(map[string][]string) // id -> list of dependencies
322
- idToFile := make(map[string]string)
323
-
324
- for _, td := range allTasks {
325
- idToFile[td.ID] = td.File
326
- graph[td.ID] = td.DependsOn
327
- }
328
-
329
- for _, td := range allTasks {
330
- for _, dep := range td.DependsOn {
331
- if _, exists := idSet[dep]; !exists {
332
- problems = append(problems, Problem{
333
- File: td.File,
334
- Message: fmt.Sprintf("depends_on references non-existent task %q", dep),
335
- })
336
- }
337
- }
338
- }
339
-
340
- // Cycle detection using DFS
341
- cycleProblems := detectCycles(graph, idToFile)
342
- problems = append(problems, cycleProblems...)
343
-
344
- return problems
345
- }
346
-
347
- func parseTaskDep(path string, parser taskParser) *taskDep {
348
- raw, err := os.ReadFile(path)
349
- if err != nil {
350
- return nil
351
- }
352
- fm, err := parser.ParseFrontmatter(string(raw))
353
- if err != nil {
354
- return nil
355
- }
356
- id, _ := fm["id"].(string)
357
- if id == "" {
358
- return nil
359
- }
360
- var deps []string
361
- switch v := fm["depends_on"].(type) {
362
- case []any:
363
- for _, d := range v {
364
- if s, ok := d.(string); ok {
365
- deps = append(deps, s)
366
- }
367
- }
368
- case []string:
369
- deps = v
370
- }
371
- return &taskDep{
372
- File: path,
373
- ID: id,
374
- DependsOn: deps,
375
- }
376
- }
377
-
378
- // detectCycles runs DFS on the dependency graph and returns cycle problems.
379
- // Uses a path stack to accurately reconstruct cycle paths (avoids parent-map
380
- // overwrite issues that produced inaccurate paths).
381
- func detectCycles(graph map[string][]string, idToFile map[string]string) []Problem {
382
- const (
383
- white = 0
384
- gray = 1
385
- black = 2
386
- )
387
- color := make(map[string]int)
388
- path := make([]string, 0)
389
-
390
- for id := range graph {
391
- color[id] = white
392
- }
393
-
394
- var problems []Problem
395
-
396
- var dfs func(id string)
397
- dfs = func(id string) {
398
- color[id] = gray
399
- path = append(path, id)
400
- for _, dep := range graph[id] {
401
- switch color[dep] {
402
- case white:
403
- dfs(dep)
404
- case gray:
405
- cycleStart := -1
406
- for i, n := range path {
407
- if n == dep {
408
- cycleStart = i
409
- break
410
- }
411
- }
412
- if cycleStart >= 0 {
413
- cycle := path[cycleStart:]
414
- cyclePath := make([]string, 0, len(cycle))
415
- for _, cid := range cycle {
416
- if f, ok := idToFile[cid]; ok {
417
- cyclePath = append(cyclePath, f)
418
- } else {
419
- cyclePath = append(cyclePath, cid)
420
- }
421
- }
422
- problems = append(problems, Problem{
423
- Message: fmt.Sprintf("dependency cycle detected: %s", strings.Join(cyclePath, " → ")),
424
- })
425
- }
426
- }
427
- }
428
- path = path[:len(path)-1]
429
- color[id] = black
430
- }
431
-
432
- for id := range graph {
433
- if color[id] == white {
434
- dfs(id)
435
- }
436
- }
437
- return problems
438
- }
439
-
440
- // CheckAuditState finds audit proposal files without matching audit-pending state in the router.
441
- func CheckAuditState(root string, overrides ...DoctorDependencies) []Problem {
442
- deps := doctorDependencies(overrides)
443
- var problems []Problem
444
-
445
- routerPath := filepath.Join(root, "router.md")
446
- raw, err := os.ReadFile(routerPath)
447
- if err != nil {
448
- return problems
449
- }
450
-
451
- state, err := deps.RouterReader.ReadState(string(raw))
452
- if err != nil {
453
- return problems
454
- }
455
-
456
- releases, err := deps.Discoverer.ListReleases(root)
457
- if err != nil {
458
- return problems
459
- }
460
-
461
- for _, release := range releases {
462
- epics, err := deps.Discoverer.ListEpics(root, release.ID)
463
- if err != nil {
464
- continue
465
- }
466
- for _, epic := range epics {
467
- prefix := extractPrefix(epic.ID)
468
- auditPath := filepath.Join(epic.Path, prefix+"-Audit.md")
469
- if _, err := os.Stat(auditPath); os.IsNotExist(err) {
470
- continue
471
- }
472
- if state.State != "audit-pending" || state.Epic != epic.ID {
473
- problems = append(problems, Problem{
474
- File: auditPath,
475
- Message: fmt.Sprintf("audit proposal exists but router state is %q (epic: %q) — expected audit-pending for %q", state.State, state.Epic, epic.ID),
476
- })
477
- }
478
- }
479
- }
480
-
481
- return problems
482
- }
483
-
484
- // CheckOrphans finds tasks whose epic prefix in their ID does not match any existing epic directory.
485
- func CheckOrphans(root string, overrides ...DoctorDependencies) []Problem {
486
- deps := doctorDependencies(overrides)
487
- var problems []Problem
488
-
489
- existingEpics := make(map[string]bool)
490
- releasesPath := filepath.Join(root, "releases")
491
- releaseDirs, err := deps.Discoverer.ListRootDirs(releasesPath)
492
- if err != nil {
493
- problems = append(problems, Problem{File: releasesPath, Message: fmt.Sprintf("listing releases: %v", err)})
494
- return problems
495
- }
496
-
497
- for _, release := range releaseDirs {
498
- epicsPath := filepath.Join(releasesPath, release, "epics")
499
- epics, err := deps.Discoverer.ListRootDirs(epicsPath)
500
- if err != nil {
501
- continue
502
- }
503
- for _, epic := range epics {
504
- existingEpics[epic] = true
505
- }
506
- }
507
-
508
- // Collect all tasks and check their epic references
509
- allReleases, err := deps.Discoverer.ListReleases(root)
510
- if err != nil {
511
- return problems
512
- }
513
-
514
- for _, release := range allReleases {
515
- epics, err := deps.Discoverer.ListEpics(root, release.ID)
516
- if err != nil {
517
- continue
518
- }
519
- for _, epic := range epics {
520
- tasks, err := deps.Discoverer.ListTasks(root, release.ID, epic.ID)
521
- if err != nil {
522
- continue
523
- }
524
- for _, t := range tasks {
525
- raw, err := os.ReadFile(t.Path)
526
- if err != nil {
527
- continue
528
- }
529
- fm, err := deps.Parser.ParseFrontmatter(string(raw))
530
- if err != nil {
531
- continue
532
- }
533
- id, _ := fm["id"].(string)
534
- if id == "" {
535
- continue
536
- }
537
- idx := strings.IndexByte(id, '/')
538
- if idx == -1 {
539
- continue
540
- }
541
- taskEpic := id[:idx]
542
- if !existingEpics[taskEpic] {
543
- problems = append(problems, Problem{
544
- File: t.Path,
545
- Message: fmt.Sprintf("orphaned task: epic %q does not exist in any release — consider moving to .savepoint/orphans/", taskEpic),
546
- })
547
- }
548
- }
549
- }
550
- }
551
-
552
- return problems
553
- }
554
-
555
- func extractYAMLLine(err error) int {
556
- s := err.Error()
557
- const prefix = "yaml: line "
558
- if idx := strings.Index(s, prefix); idx != -1 {
559
- rest := s[idx+len(prefix):]
560
- if end := strings.IndexByte(rest, ':'); end != -1 {
561
- if line, err := strconv.Atoi(rest[:end]); err == nil {
562
- return line
563
- }
564
- }
565
- }
566
- return 0
567
- }