savepoint 1.0.0 → 1.0.1
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.
- package/.claude/settings.local.json +5 -1
- package/.savepoint/Design.md +8 -4
- package/.savepoint/audit/E06-atari-noir-layout/proposals.md +130 -0
- package/.savepoint/audit/E06-atari-noir-layout/snapshot.md +84 -0
- package/.savepoint/config.yml +3 -3
- package/.savepoint/releases/v1/epics/E06-atari-noir-layout/Design.md +24 -6
- package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T007-detail-card-fixes.md +7 -7
- package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T008-checkbox-states.md +10 -8
- package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T009-router-priority-marker.md +16 -9
- package/.savepoint/releases/v1/epics/E06-atari-noir-layout/tasks/T010-auto-refresh-watcher.md +25 -22
- package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/Design.md +10 -4
- package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T001-border-resize-fix.md +2 -1
- package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T002-rename-epic-design-files.md +38 -0
- package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T003-rename-release-prd.md +28 -0
- package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T004-update-instruction-files.md +50 -0
- package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T005-update-cross-references.md +44 -0
- package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T006-column-and-detail-scrolling.md +58 -0
- package/.savepoint/releases/v1.1/epics/E01-tui-optimisation/tasks/T007-next-activity-header.md +55 -0
- package/.savepoint/releases/v1.1/epics/E02-cross-platform-compatibility/Design.md +40 -0
- package/.savepoint/releases/v1.1/epics/E02-cross-platform-compatibility/tasks/T001-fix-makefile.md +34 -0
- package/.savepoint/releases/v1.1/epics/E02-cross-platform-compatibility/tasks/T002-linux-build-target.md +33 -0
- package/.savepoint/releases/v1.1/epics/E02-cross-platform-compatibility/tasks/T003-macos-build-target.md +32 -0
- package/.savepoint/releases/v1.1/epics/E02-cross-platform-compatibility/tasks/T004-smoke-tests-and-artifacts.md +38 -0
- package/.savepoint/router.md +1 -1
- package/.savepoint/visual-identity.md +4 -3
- package/AGENTS.md +3 -3
- package/README.md +1 -1
- package/go.mod +4 -1
- package/go.sum +2 -0
- package/internal/board/board.go +42 -6
- package/internal/board/board_test.go +53 -0
- package/internal/board/card.go +9 -3
- package/internal/board/card_test.go +28 -14
- package/internal/board/column.go +2 -2
- package/internal/board/column_test.go +17 -9
- package/internal/board/detail.go +21 -11
- package/internal/board/detail_test.go +30 -14
- package/internal/board/model.go +7 -1
- package/internal/board/update.go +24 -1
- package/internal/board/view.go +13 -3
- package/internal/board/view_test.go +2 -2
- package/internal/board/watch.go +82 -0
- package/internal/data/parser.go +31 -1
- package/internal/data/parser_test.go +8 -2
- package/internal/data/task.go +12 -2
- package/internal/styles/palette.go +6 -4
- package/internal/styles/styles.go +5 -15
- package/package.json +5 -4
- package/savepoint +0 -0
package/internal/data/parser.go
CHANGED
|
@@ -51,7 +51,7 @@ func (p *Parser) ParseTaskFile(path string, content string) (*Task, error) {
|
|
|
51
51
|
Points: fields.Points,
|
|
52
52
|
Tags: fields.Tags,
|
|
53
53
|
Acceptance: firstList(fields.Acceptance, extractChecklistSection(content, "## Acceptance Criteria")),
|
|
54
|
-
Checklist:
|
|
54
|
+
Checklist: extractChecklistItems(content, "## Implementation Plan"),
|
|
55
55
|
Notes: fields.Notes,
|
|
56
56
|
DependsOn: fields.DependsOn,
|
|
57
57
|
Progress: fields.Progress,
|
|
@@ -162,6 +162,36 @@ func firstList(values ...[]string) []string {
|
|
|
162
162
|
return nil
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
+
func extractChecklistItems(content, heading string) []CheckItem {
|
|
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 := []CheckItem{}
|
|
178
|
+
for _, line := range strings.Split(section, "\n") {
|
|
179
|
+
trimmed := strings.TrimSpace(line)
|
|
180
|
+
if strings.HasPrefix(trimmed, "- [x] ") {
|
|
181
|
+
items = append(items, CheckItem{Text: strings.TrimSpace(trimmed[6:]), Done: true})
|
|
182
|
+
continue
|
|
183
|
+
}
|
|
184
|
+
if strings.HasPrefix(trimmed, "- [ ] ") {
|
|
185
|
+
items = append(items, CheckItem{Text: strings.TrimSpace(trimmed[6:]), Done: false})
|
|
186
|
+
continue
|
|
187
|
+
}
|
|
188
|
+
if strings.HasPrefix(trimmed, "- ") {
|
|
189
|
+
items = append(items, CheckItem{Text: strings.TrimSpace(trimmed[2:]), Done: false})
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return items
|
|
193
|
+
}
|
|
194
|
+
|
|
165
195
|
func extractChecklistSection(content, heading string) []string {
|
|
166
196
|
normalized := strings.ReplaceAll(content, "\r\n", "\n")
|
|
167
197
|
start := strings.Index(normalized, heading)
|
|
@@ -210,7 +210,13 @@ Notes here.`
|
|
|
210
210
|
if len(task.Acceptance) != 2 || task.Acceptance[0] != "First criterion." || task.Acceptance[1] != "Second criterion." {
|
|
211
211
|
t.Errorf("Task.Acceptance = %v, want markdown criteria", task.Acceptance)
|
|
212
212
|
}
|
|
213
|
-
if len(task.Checklist) != 2
|
|
214
|
-
t.
|
|
213
|
+
if len(task.Checklist) != 2 {
|
|
214
|
+
t.Fatalf("Task.Checklist len = %d, want 2", len(task.Checklist))
|
|
215
|
+
}
|
|
216
|
+
if task.Checklist[0].Text != "First checklist item." || task.Checklist[0].Done {
|
|
217
|
+
t.Errorf("Task.Checklist[0] = %+v, want {Text:\"First checklist item.\", Done:false}", task.Checklist[0])
|
|
218
|
+
}
|
|
219
|
+
if task.Checklist[1].Text != "Second checklist item." || !task.Checklist[1].Done {
|
|
220
|
+
t.Errorf("Task.Checklist[1] = %+v, want {Text:\"Second checklist item.\", Done:true}", task.Checklist[1])
|
|
215
221
|
}
|
|
216
222
|
}
|
package/internal/data/task.go
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
package data
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import (
|
|
4
|
+
"fmt"
|
|
5
|
+
"time"
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
type CheckItem struct {
|
|
9
|
+
Text string
|
|
10
|
+
Done bool
|
|
11
|
+
}
|
|
4
12
|
|
|
5
13
|
type ColumnType string
|
|
6
14
|
|
|
@@ -35,10 +43,12 @@ type Task struct {
|
|
|
35
43
|
Points int `yaml:"points,omitempty"`
|
|
36
44
|
Tags []string `yaml:"tags,omitempty"`
|
|
37
45
|
Acceptance []string `yaml:"acceptance,omitempty"`
|
|
38
|
-
Checklist []
|
|
46
|
+
Checklist []CheckItem `yaml:"checklist,omitempty"`
|
|
39
47
|
Notes string `yaml:"notes,omitempty"`
|
|
40
48
|
DependsOn []string `yaml:"depends_on,omitempty"`
|
|
41
49
|
Progress Progress `yaml:"progress,omitempty"`
|
|
50
|
+
Path string `yaml:"-"`
|
|
51
|
+
Mtime time.Time `yaml:"-"`
|
|
42
52
|
}
|
|
43
53
|
|
|
44
54
|
func (t Task) String() string {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
package styles
|
|
2
2
|
|
|
3
|
-
// Truecolor hex constants (Atari-Noir palette)
|
|
3
|
+
// Truecolor hex constants (Atari-Noir palette).
|
|
4
|
+
// Background, Surface, and Surface2 intentionally share one black value so the
|
|
5
|
+
// terminal stays visually flat; hierarchy comes from spacing, dividers, and accents.
|
|
4
6
|
const (
|
|
5
|
-
Background = "#
|
|
6
|
-
Surface = "#
|
|
7
|
-
Surface2 = "#
|
|
7
|
+
Background = "#000000"
|
|
8
|
+
Surface = "#000000"
|
|
9
|
+
Surface2 = "#000000"
|
|
8
10
|
Border = "#1A1A1A"
|
|
9
11
|
BorderSubtle = "#222222"
|
|
10
12
|
PrimaryText = "#F0E6DA"
|
|
@@ -10,8 +10,8 @@ var (
|
|
|
10
10
|
clrOrange = color(AtariOrange, AtariOrange256, AtariOrange16)
|
|
11
11
|
clrText = color(PrimaryText, PrimaryText256, PrimaryText16)
|
|
12
12
|
clrBorder = color(BorderSubtle, BorderSubtle256, BorderSubtle16)
|
|
13
|
-
clrSurface = color(Surface2, Surface2256, Surface216) //
|
|
14
|
-
clrSurfaceDark = color(Surface, Surface256, Surface16) //
|
|
13
|
+
clrSurface = color(Surface2, Surface2256, Surface216) // intentionally black
|
|
14
|
+
clrSurfaceDark = color(Surface, Surface256, Surface16) // intentionally black
|
|
15
15
|
clrGreen = color(NPPGreen, NPPGreen256, NPPGreen16)
|
|
16
16
|
clrPurple = color(VibePurple, VibePurple256, VibePurple16)
|
|
17
17
|
clrDim = color(Dim, Dim256, Dim16)
|
|
@@ -29,18 +29,13 @@ var (
|
|
|
29
29
|
Foreground(clrBorder)
|
|
30
30
|
|
|
31
31
|
HeaderFrame = lipgloss.NewStyle().
|
|
32
|
-
|
|
33
|
-
BorderForeground(clrBorder).
|
|
32
|
+
Background(clrSurfaceDark).
|
|
34
33
|
Padding(1, 1)
|
|
35
34
|
|
|
36
35
|
BoardFrame = lipgloss.NewStyle().
|
|
37
|
-
|
|
38
|
-
BorderForeground(clrBorder).
|
|
39
|
-
Padding(0, 1)
|
|
36
|
+
Background(clrSurfaceDark)
|
|
40
37
|
|
|
41
38
|
Column = lipgloss.NewStyle().
|
|
42
|
-
BorderStyle(lipgloss.RoundedBorder()).
|
|
43
|
-
BorderForeground(clrBorder).
|
|
44
39
|
Background(clrSurfaceDark).
|
|
45
40
|
Padding(0, 1)
|
|
46
41
|
|
|
@@ -65,18 +60,13 @@ var (
|
|
|
65
60
|
Foreground(clrOrange)
|
|
66
61
|
|
|
67
62
|
StatusBar = lipgloss.NewStyle().
|
|
68
|
-
Foreground(clrText)
|
|
69
|
-
Background(clrSurface)
|
|
63
|
+
Foreground(clrText)
|
|
70
64
|
|
|
71
65
|
EpicPanel = lipgloss.NewStyle().
|
|
72
|
-
BorderStyle(lipgloss.RoundedBorder()).
|
|
73
|
-
BorderForeground(clrPurple).
|
|
74
66
|
Background(clrSurface).
|
|
75
67
|
Padding(0, 1)
|
|
76
68
|
|
|
77
69
|
Card = lipgloss.NewStyle().
|
|
78
|
-
BorderStyle(lipgloss.RoundedBorder()).
|
|
79
|
-
BorderForeground(clrBorder).
|
|
80
70
|
Background(clrSurface).
|
|
81
71
|
Padding(0, 1)
|
|
82
72
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "savepoint",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "It’s a simple, file-based state machine and cinematic Terminal UI (TUI) designed to force you—and your agent (Claude, Cursor, Aider, Gemini)—to slow down, write down what you're actually building, and check your work before moving on.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"board",
|
|
@@ -17,9 +17,10 @@
|
|
|
17
17
|
},
|
|
18
18
|
"license": "MIT",
|
|
19
19
|
"author": "anipatke",
|
|
20
|
-
"
|
|
21
|
-
|
|
20
|
+
"bin": {
|
|
21
|
+
"savepoint": "./savepoint"
|
|
22
|
+
},
|
|
22
23
|
"scripts": {
|
|
23
24
|
"test": "savepoint init"
|
|
24
25
|
}
|
|
25
|
-
}
|
|
26
|
+
}
|
package/savepoint
CHANGED
|
Binary file
|