@prmichaelsen/acp-visualizer 0.1.0 → 0.1.2

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 (159) hide show
  1. package/package.json +8 -10
  2. package/src/components/ExtraFieldsBadge.tsx +1 -1
  3. package/src/components/FilterBar.tsx +1 -1
  4. package/src/components/Header.tsx +1 -1
  5. package/src/components/MilestoneTable.tsx +1 -1
  6. package/src/components/MilestoneTree.tsx +2 -2
  7. package/src/components/StatusBadge.tsx +1 -1
  8. package/src/components/StatusDot.tsx +1 -1
  9. package/src/components/TaskList.tsx +1 -1
  10. package/src/routes/__root.tsx +5 -5
  11. package/src/routes/api/watch.ts +1 -1
  12. package/src/routes/index.tsx +2 -2
  13. package/src/routes/milestones.tsx +7 -7
  14. package/src/routes/search.tsx +4 -4
  15. package/src/routes/tasks.tsx +3 -3
  16. package/src/services/progress-database.service.ts +3 -3
  17. package/agent/commands/acp.clarification-address.md +0 -417
  18. package/agent/commands/acp.clarification-capture.md +0 -386
  19. package/agent/commands/acp.clarification-create.md +0 -437
  20. package/agent/commands/acp.clarifications-research.md +0 -326
  21. package/agent/commands/acp.command-create.md +0 -432
  22. package/agent/commands/acp.design-create.md +0 -286
  23. package/agent/commands/acp.design-reference.md +0 -355
  24. package/agent/commands/acp.handoff.md +0 -270
  25. package/agent/commands/acp.index.md +0 -423
  26. package/agent/commands/acp.init.md +0 -546
  27. package/agent/commands/acp.package-create.md +0 -895
  28. package/agent/commands/acp.package-info.md +0 -212
  29. package/agent/commands/acp.package-install.md +0 -539
  30. package/agent/commands/acp.package-list.md +0 -280
  31. package/agent/commands/acp.package-publish.md +0 -541
  32. package/agent/commands/acp.package-remove.md +0 -293
  33. package/agent/commands/acp.package-search.md +0 -307
  34. package/agent/commands/acp.package-update.md +0 -361
  35. package/agent/commands/acp.package-validate.md +0 -540
  36. package/agent/commands/acp.pattern-create.md +0 -386
  37. package/agent/commands/acp.plan.md +0 -587
  38. package/agent/commands/acp.proceed.md +0 -882
  39. package/agent/commands/acp.project-create.md +0 -675
  40. package/agent/commands/acp.project-info.md +0 -312
  41. package/agent/commands/acp.project-list.md +0 -226
  42. package/agent/commands/acp.project-remove.md +0 -379
  43. package/agent/commands/acp.project-set.md +0 -227
  44. package/agent/commands/acp.project-update.md +0 -307
  45. package/agent/commands/acp.projects-restore.md +0 -228
  46. package/agent/commands/acp.projects-sync.md +0 -347
  47. package/agent/commands/acp.report.md +0 -407
  48. package/agent/commands/acp.resume.md +0 -239
  49. package/agent/commands/acp.sessions.md +0 -301
  50. package/agent/commands/acp.status.md +0 -293
  51. package/agent/commands/acp.sync.md +0 -364
  52. package/agent/commands/acp.task-create.md +0 -500
  53. package/agent/commands/acp.update.md +0 -302
  54. package/agent/commands/acp.validate.md +0 -466
  55. package/agent/commands/acp.version-check-for-updates.md +0 -276
  56. package/agent/commands/acp.version-check.md +0 -191
  57. package/agent/commands/acp.version-update.md +0 -289
  58. package/agent/commands/command.template.md +0 -339
  59. package/agent/commands/git.commit.md +0 -526
  60. package/agent/commands/git.init.md +0 -514
  61. package/agent/commands/tanstack-cloudflare.deploy.md +0 -272
  62. package/agent/commands/tanstack-cloudflare.tail.md +0 -275
  63. package/agent/design/.gitkeep +0 -0
  64. package/agent/design/design.template.md +0 -154
  65. package/agent/design/local.dashboard-layout-routing.md +0 -288
  66. package/agent/design/local.data-model-yaml-parsing.md +0 -310
  67. package/agent/design/local.search-filtering.md +0 -331
  68. package/agent/design/local.server-api-auto-refresh.md +0 -235
  69. package/agent/design/local.table-tree-views.md +0 -299
  70. package/agent/design/local.visualizer-requirements.md +0 -349
  71. package/agent/design/requirements.template.md +0 -387
  72. package/agent/index/.gitkeep +0 -0
  73. package/agent/index/acp.core.yaml +0 -137
  74. package/agent/index/local.main.template.yaml +0 -37
  75. package/agent/manifest.template.yaml +0 -13
  76. package/agent/manifest.yaml +0 -302
  77. package/agent/milestones/.gitkeep +0 -0
  78. package/agent/milestones/milestone-1-project-scaffold-data-pipeline.md +0 -67
  79. package/agent/milestones/milestone-1-{title}.template.md +0 -206
  80. package/agent/milestones/milestone-2-dashboard-views-interaction.md +0 -79
  81. package/agent/package.template.yaml +0 -86
  82. package/agent/patterns/.gitkeep +0 -0
  83. package/agent/patterns/bootstrap.template.md +0 -1237
  84. package/agent/patterns/pattern.template.md +0 -382
  85. package/agent/patterns/tanstack-cloudflare.acl-permissions.md +0 -332
  86. package/agent/patterns/tanstack-cloudflare.action-bar-item.md +0 -416
  87. package/agent/patterns/tanstack-cloudflare.api-route-handlers.md +0 -401
  88. package/agent/patterns/tanstack-cloudflare.auth-session-management.md +0 -387
  89. package/agent/patterns/tanstack-cloudflare.card-and-list.md +0 -271
  90. package/agent/patterns/tanstack-cloudflare.chat-engine.md +0 -353
  91. package/agent/patterns/tanstack-cloudflare.confirmation-tokens.md +0 -346
  92. package/agent/patterns/tanstack-cloudflare.durable-objects-websocket.md +0 -516
  93. package/agent/patterns/tanstack-cloudflare.email-service.md +0 -431
  94. package/agent/patterns/tanstack-cloudflare.expander.md +0 -98
  95. package/agent/patterns/tanstack-cloudflare.fcm-push.md +0 -115
  96. package/agent/patterns/tanstack-cloudflare.firebase-anonymous-sessions.md +0 -441
  97. package/agent/patterns/tanstack-cloudflare.firebase-auth.md +0 -348
  98. package/agent/patterns/tanstack-cloudflare.firebase-firestore.md +0 -550
  99. package/agent/patterns/tanstack-cloudflare.firebase-storage.md +0 -369
  100. package/agent/patterns/tanstack-cloudflare.form-controls.md +0 -145
  101. package/agent/patterns/tanstack-cloudflare.global-search-context.md +0 -93
  102. package/agent/patterns/tanstack-cloudflare.image-carousel.md +0 -126
  103. package/agent/patterns/tanstack-cloudflare.library-services.md +0 -553
  104. package/agent/patterns/tanstack-cloudflare.lightbox.md +0 -169
  105. package/agent/patterns/tanstack-cloudflare.markdown-content.md +0 -115
  106. package/agent/patterns/tanstack-cloudflare.mention-suggestions.md +0 -98
  107. package/agent/patterns/tanstack-cloudflare.modal.md +0 -156
  108. package/agent/patterns/tanstack-cloudflare.nextjs-to-tanstack-routing.md +0 -461
  109. package/agent/patterns/tanstack-cloudflare.notifications-engine.md +0 -151
  110. package/agent/patterns/tanstack-cloudflare.oauth-token-refresh.md +0 -90
  111. package/agent/patterns/tanstack-cloudflare.og-metadata.md +0 -296
  112. package/agent/patterns/tanstack-cloudflare.pagination.md +0 -442
  113. package/agent/patterns/tanstack-cloudflare.pill-input.md +0 -220
  114. package/agent/patterns/tanstack-cloudflare.provider-adapter.md +0 -401
  115. package/agent/patterns/tanstack-cloudflare.rate-limiting.md +0 -323
  116. package/agent/patterns/tanstack-cloudflare.scheduled-tasks.md +0 -338
  117. package/agent/patterns/tanstack-cloudflare.searchable-settings.md +0 -375
  118. package/agent/patterns/tanstack-cloudflare.slide-over.md +0 -129
  119. package/agent/patterns/tanstack-cloudflare.ssr-preload.md +0 -571
  120. package/agent/patterns/tanstack-cloudflare.third-party-api-integration.md +0 -508
  121. package/agent/patterns/tanstack-cloudflare.toast-system.md +0 -142
  122. package/agent/patterns/tanstack-cloudflare.unified-header.md +0 -280
  123. package/agent/patterns/tanstack-cloudflare.user-scoped-collections.md +0 -628
  124. package/agent/patterns/tanstack-cloudflare.websocket-manager.md +0 -237
  125. package/agent/patterns/tanstack-cloudflare.wrangler-configuration.md +0 -358
  126. package/agent/patterns/tanstack-cloudflare.zod-schema-validation.md +0 -336
  127. package/agent/progress.template.yaml +0 -161
  128. package/agent/progress.yaml +0 -145
  129. package/agent/schemas/package.schema.yaml +0 -276
  130. package/agent/scripts/acp.common.sh +0 -1781
  131. package/agent/scripts/acp.install.sh +0 -333
  132. package/agent/scripts/acp.package-create.sh +0 -924
  133. package/agent/scripts/acp.package-info.sh +0 -288
  134. package/agent/scripts/acp.package-install.sh +0 -893
  135. package/agent/scripts/acp.package-list.sh +0 -311
  136. package/agent/scripts/acp.package-publish.sh +0 -420
  137. package/agent/scripts/acp.package-remove.sh +0 -348
  138. package/agent/scripts/acp.package-search.sh +0 -156
  139. package/agent/scripts/acp.package-update.sh +0 -517
  140. package/agent/scripts/acp.package-validate.sh +0 -1018
  141. package/agent/scripts/acp.uninstall.sh +0 -85
  142. package/agent/scripts/acp.version-check-for-updates.sh +0 -98
  143. package/agent/scripts/acp.version-check.sh +0 -47
  144. package/agent/scripts/acp.version-update.sh +0 -176
  145. package/agent/scripts/acp.yaml-parser.sh +0 -985
  146. package/agent/scripts/acp.yaml-validate.sh +0 -205
  147. package/agent/tasks/.gitkeep +0 -0
  148. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-1-initialize-tanstack-start-project.md +0 -210
  149. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-2-implement-data-model-yaml-parser.md +0 -294
  150. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-3-build-server-api-data-loading.md +0 -193
  151. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-4-add-auto-refresh-sse.md +0 -262
  152. package/agent/tasks/milestone-2-dashboard-views-interaction/task-10-polish-integration-testing.md +0 -156
  153. package/agent/tasks/milestone-2-dashboard-views-interaction/task-5-build-dashboard-layout-routing.md +0 -178
  154. package/agent/tasks/milestone-2-dashboard-views-interaction/task-6-build-overview-page.md +0 -141
  155. package/agent/tasks/milestone-2-dashboard-views-interaction/task-7-implement-milestone-table-view.md +0 -153
  156. package/agent/tasks/milestone-2-dashboard-views-interaction/task-8-implement-milestone-tree-view.md +0 -174
  157. package/agent/tasks/milestone-2-dashboard-views-interaction/task-9-implement-search-filtering.md +0 -233
  158. package/agent/tasks/task-1-{title}.template.md +0 -244
  159. package/vitest.config.ts +0 -27
@@ -1,288 +0,0 @@
1
- # Dashboard Layout & Routing
2
-
3
- **Concept**: Root layout structure, navigation, routing, and visual design system for the admin dashboard
4
- **Created**: 2026-03-14
5
- **Status**: Design Specification
6
-
7
- ---
8
-
9
- ## Overview
10
-
11
- Defines the application shell — root layout, sidebar navigation, header, routing structure, and the visual design tokens (colors, typography, spacing) that create a cohesive Linear/Vercel-style admin dashboard. This design establishes the container that all view components render within.
12
-
13
- ---
14
-
15
- ## Problem Statement
16
-
17
- The visualizer needs:
18
- - A persistent navigation structure for switching between views (dashboard, milestones, tasks, search)
19
- - Consistent visual language across all pages
20
- - Information-dense layout optimized for desktop developer use
21
- - Clear visual hierarchy for status indicators (completed/in-progress/not-started)
22
-
23
- Without a defined layout system, views would be implemented ad-hoc with inconsistent spacing, typography, and navigation patterns.
24
-
25
- ---
26
-
27
- ## Solution
28
-
29
- A minimal sidebar + content area layout with:
30
- 1. Fixed left sidebar for navigation
31
- 2. Content area with page-specific views
32
- 3. Shared design tokens via Tailwind CSS configuration
33
- 4. TanStack Router file-based routing
34
-
35
- ---
36
-
37
- ## Implementation
38
-
39
- ### Route Structure
40
-
41
- ```
42
- app/routes/
43
- ├── __root.tsx # Root layout (sidebar + content shell)
44
- ├── index.tsx # Dashboard home (project overview + summary)
45
- ├── milestones.tsx # Milestone views (table/tree toggle)
46
- ├── milestones.$id.tsx # Single milestone detail (tasks list)
47
- ├── tasks.tsx # All tasks view
48
- ├── activity.tsx # Recent work timeline (P1)
49
- └── search.tsx # Global search results
50
- ```
51
-
52
- ### Root Layout
53
-
54
- ```tsx
55
- // app/routes/__root.tsx
56
-
57
- export const Route = createRootRoute({
58
- component: RootLayout,
59
- });
60
-
61
- function RootLayout() {
62
- return (
63
- <div className="flex h-screen bg-gray-950 text-gray-100">
64
- <Sidebar />
65
- <main className="flex-1 overflow-auto">
66
- <Header />
67
- <div className="p-6">
68
- <Outlet />
69
- </div>
70
- </main>
71
- </div>
72
- );
73
- }
74
- ```
75
-
76
- ### Sidebar
77
-
78
- ```tsx
79
- // app/components/Sidebar.tsx
80
-
81
- const navItems = [
82
- { to: '/', icon: LayoutDashboard, label: 'Overview' },
83
- { to: '/milestones', icon: Flag, label: 'Milestones' },
84
- { to: '/tasks', icon: CheckSquare, label: 'Tasks' },
85
- { to: '/activity', icon: Clock, label: 'Activity' }, // P1
86
- ];
87
-
88
- function Sidebar() {
89
- return (
90
- <nav className="w-56 border-r border-gray-800 bg-gray-950 flex flex-col">
91
- <div className="p-4 border-b border-gray-800">
92
- <span className="text-sm font-semibold text-gray-300 tracking-wide">
93
- ACP Visualizer
94
- </span>
95
- </div>
96
- <div className="flex-1 py-2">
97
- {navItems.map(item => (
98
- <NavLink key={item.to} {...item} />
99
- ))}
100
- </div>
101
- <div className="p-4 border-t border-gray-800">
102
- <SearchTrigger />
103
- </div>
104
- </nav>
105
- );
106
- }
107
- ```
108
-
109
- ### Header
110
-
111
- Displays current project name, version, status badge, and overall progress:
112
-
113
- ```tsx
114
- // app/components/Header.tsx
115
-
116
- function Header() {
117
- // Project metadata from route loader
118
- return (
119
- <header className="h-14 border-b border-gray-800 flex items-center px-6 gap-4">
120
- <h1 className="text-sm font-medium text-gray-200">{project.name}</h1>
121
- <span className="text-xs text-gray-500">v{project.version}</span>
122
- <StatusBadge status={project.status} />
123
- <div className="ml-auto">
124
- <ProgressBar value={progress.overall} size="sm" />
125
- </div>
126
- </header>
127
- );
128
- }
129
- ```
130
-
131
- ### Design Tokens (Tailwind Config)
132
-
133
- ```typescript
134
- // tailwind.config.ts
135
-
136
- export default {
137
- theme: {
138
- extend: {
139
- colors: {
140
- status: {
141
- completed: '#22c55e', // green-500
142
- in_progress: '#3b82f6', // blue-500
143
- not_started: '#6b7280', // gray-500
144
- },
145
- },
146
- fontFamily: {
147
- mono: ['JetBrains Mono', 'Fira Code', 'monospace'],
148
- sans: ['Inter', 'system-ui', 'sans-serif'],
149
- },
150
- },
151
- },
152
- };
153
- ```
154
-
155
- ### Visual Design Rules
156
-
157
- | Element | Style |
158
- |---------|-------|
159
- | Background | `gray-950` (near-black) |
160
- | Surface/cards | `gray-900` with `gray-800` borders |
161
- | Primary text | `gray-100` |
162
- | Secondary text | `gray-400` |
163
- | Data values | Monospace font (`font-mono`) |
164
- | Status: completed | Green badge/dot |
165
- | Status: in_progress | Blue badge/dot |
166
- | Status: not_started | Gray badge/dot |
167
- | Interactive hover | `gray-800` background |
168
- | Spacing | 4px grid (Tailwind default) |
169
-
170
- ### StatusBadge Component
171
-
172
- ```tsx
173
- // app/components/StatusBadge.tsx
174
-
175
- const statusStyles = {
176
- completed: 'bg-green-500/15 text-green-400 border-green-500/20',
177
- in_progress: 'bg-blue-500/15 text-blue-400 border-blue-500/20',
178
- not_started: 'bg-gray-500/15 text-gray-500 border-gray-500/20',
179
- };
180
-
181
- const statusLabels = {
182
- completed: 'Completed',
183
- in_progress: 'In Progress',
184
- not_started: 'Not Started',
185
- };
186
-
187
- export function StatusBadge({ status }: { status: Status }) {
188
- return (
189
- <span className={`inline-flex items-center px-2 py-0.5 rounded-full text-xs border ${statusStyles[status]}`}>
190
- {statusLabels[status]}
191
- </span>
192
- );
193
- }
194
- ```
195
-
196
- ### ProgressBar Component
197
-
198
- ```tsx
199
- // app/components/ProgressBar.tsx
200
-
201
- export function ProgressBar({ value, size = 'md' }: { value: number; size?: 'sm' | 'md' }) {
202
- const height = size === 'sm' ? 'h-1.5' : 'h-2.5';
203
- return (
204
- <div className={`w-full bg-gray-800 rounded-full ${height} overflow-hidden`}>
205
- <div
206
- className={`${height} rounded-full transition-all duration-300 ${
207
- value === 100 ? 'bg-green-500' : 'bg-blue-500'
208
- }`}
209
- style={{ width: `${Math.min(100, Math.max(0, value))}%` }}
210
- />
211
- </div>
212
- );
213
- }
214
- ```
215
-
216
- ### Dashboard Home (Overview Page)
217
-
218
- The index route shows a single-page summary:
219
- - Project metadata card (name, version, status, dates)
220
- - Overall progress bar
221
- - Milestone summary (compact list with progress bars)
222
- - Next steps list
223
- - Current blockers (if any)
224
-
225
- ---
226
-
227
- ## Benefits
228
-
229
- - **Consistent**: All pages share the same visual language
230
- - **Information-dense**: Compact layout maximizes data visibility
231
- - **Navigable**: Sidebar provides constant orientation
232
- - **Extensible**: Adding new routes/views follows established patterns
233
-
234
- ---
235
-
236
- ## Trade-offs
237
-
238
- - **Desktop-only**: Fixed sidebar layout doesn't collapse for mobile (acceptable per requirements)
239
- - **Dark theme only**: No light mode toggle in P0 (future consideration)
240
- - **Minimal branding**: Intentionally plain — data is the focus
241
-
242
- ---
243
-
244
- ## Applicable Patterns
245
-
246
- | Pattern | How It Applies |
247
- |---------|----------------|
248
- | [`tanstack-cloudflare.unified-header`](../patterns/tanstack-cloudflare.unified-header.md) | Adopt the fixed header + content offset pattern. Use `pt-14` on main content. For view switching (table/tree), use `SubHeaderTabs` rendered as children of the header. Adapt for sidebar layout: the pattern's `max-w-3xl` centering shifts to sidebar + full-width content area, but the fixed positioning, safe-area handling, and tab structure apply directly. |
249
- | [`tanstack-cloudflare.nextjs-to-tanstack-routing`](../patterns/tanstack-cloudflare.nextjs-to-tanstack-routing.md) | Reference for TanStack Router file-based routing conventions: `$id` for dynamic params, `__root.tsx` for layout, `beforeLoad` for data, `meta()` for page metadata. Ensures routes follow established patterns. |
250
- | [`tanstack-cloudflare.card-and-list`](../patterns/tanstack-cloudflare.card-and-list.md) | Adopt consistent card styling for dashboard summary cards: `bg-gray-900/50 backdrop-blur-sm border border-gray-800 rounded-xl p-4`. Text hierarchy: title `text-white font-semibold`, secondary `text-gray-400 text-sm`, meta `text-gray-500 text-xs`. |
251
- | [`tanstack-cloudflare.toast-system`](../patterns/tanstack-cloudflare.toast-system.md) | Use for error feedback (YAML parse errors, file-not-found) and auto-refresh status notifications. `useToast()` for direct calls, `StandaloneToastContainer` at z-60 in root layout. |
252
-
253
- ---
254
-
255
- ## Dependencies
256
-
257
- - Tailwind CSS
258
- - TanStack Router (file-based routing)
259
- - lucide-react for icons (lightweight, tree-shakeable)
260
-
261
- ---
262
-
263
- ## Testing Strategy
264
-
265
- - **Component tests**: Sidebar renders correct nav items, StatusBadge renders correct colors
266
- - **Visual regression**: Screenshot tests for layout at standard viewport sizes
267
- - **Route tests**: Each route resolves and renders without errors
268
-
269
- ---
270
-
271
- ## Migration Path
272
-
273
- N/A — greenfield project.
274
-
275
- ---
276
-
277
- ## Future Considerations
278
-
279
- - **Dark/light mode toggle**: Add theme context and Tailwind dark mode classes
280
- - **Collapsible sidebar**: Icon-only mode for more content space
281
- - **Breadcrumbs**: For nested routes (milestone → task detail)
282
- - **Keyboard navigation**: `Cmd+K` for search, arrow keys for nav
283
-
284
- ---
285
-
286
- **Status**: Design Specification
287
- **Recommendation**: Implement alongside or immediately after server API — provides the shell for all views
288
- **Related Documents**: local.visualizer-requirements.md, tanstack-cloudflare.unified-header, tanstack-cloudflare.nextjs-to-tanstack-routing, tanstack-cloudflare.card-and-list, tanstack-cloudflare.toast-system
@@ -1,310 +0,0 @@
1
- # Data Model & YAML Parsing
2
-
3
- **Concept**: TypeScript data model for progress.yaml and YAML-to-structured-data parsing pipeline
4
- **Created**: 2026-03-14
5
- **Status**: Design Specification
6
-
7
- ---
8
-
9
- ## Overview
10
-
11
- Defines the TypeScript interfaces that represent ACP `progress.yaml` data and the parsing pipeline that converts raw YAML into typed, normalized structures suitable for rendering in the visualizer's views. This is the foundational data layer that all views, search, and filtering depend on.
12
-
13
- ---
14
-
15
- ## Problem Statement
16
-
17
- ACP `progress.yaml` files are large (1800+ lines), loosely structured YAML **maintained by AI agents, not programmatic YAML operations**. This means:
18
- - Fields may be missing, renamed, or added ad-hoc by different agents
19
- - Unexpected/custom properties may appear at any level (e.g., an agent adds `priority: high` to a task)
20
- - Key names may drift slightly (e.g., `estimated_hours` vs `est_hours` vs `hours`)
21
- - Structural variations exist across projects (arrays vs objects, nested vs flat)
22
-
23
- The visualizer needs:
24
- - Strong TypeScript types for compile-time safety across all views
25
- - **Lenient parsing** that extracts known fields without crashing on unknown ones
26
- - **Passthrough of unrecognized properties** so they can be displayed in a "raw data" fallback
27
- - Normalization of optional/missing fields to prevent runtime errors
28
- - Consistent ID generation for entities that don't have explicit IDs in YAML
29
- - Computed fields (e.g., task counts, completion percentages) derived from raw data
30
-
31
- Without a well-defined but flexible data model, the visualizer would either crash on real-world YAML or silently lose agent-added context.
32
-
33
- ---
34
-
35
- ## Solution
36
-
37
- Create a `yaml-loader.ts` module in `app/lib/` that:
38
-
39
- 1. Accepts raw YAML string input
40
- 2. Parses via `js-yaml` into untyped JavaScript objects
41
- 3. Validates and normalizes into strongly-typed TypeScript interfaces
42
- 4. Computes derived fields (progress percentages, task counts)
43
- 5. Returns a single `ProgressData` object consumed by all views
44
-
45
- ---
46
-
47
- ## Implementation
48
-
49
- ### TypeScript Interfaces
50
-
51
- ```typescript
52
- // app/lib/types.ts
53
-
54
- export type Status = 'completed' | 'in_progress' | 'not_started';
55
-
56
- export interface ProgressData {
57
- project: ProjectMetadata;
58
- milestones: Milestone[];
59
- tasks: Record<string, Task[]>; // keyed by milestone_id
60
- recent_work: WorkEntry[];
61
- next_steps: string[];
62
- notes: string[];
63
- current_blockers: string[];
64
- documentation: DocumentationStats;
65
- progress: ProgressSummary;
66
- }
67
-
68
- // Unknown properties from agent-maintained YAML are preserved here
69
- // so views can display them in raw/debug panels without data loss.
70
- export type ExtraFields = Record<string, unknown>;
71
-
72
- export interface ProjectMetadata {
73
- name: string;
74
- version: string;
75
- started: string;
76
- status: Status;
77
- current_milestone?: string;
78
- description: string;
79
- extra: ExtraFields; // any unrecognized project-level fields
80
- }
81
-
82
- export interface Milestone {
83
- id: string;
84
- name: string;
85
- status: Status;
86
- progress: number; // 0-100
87
- started: string | null;
88
- completed: string | null;
89
- estimated_weeks: string;
90
- tasks_completed: number;
91
- tasks_total: number;
92
- notes: string;
93
- extra: ExtraFields;
94
- }
95
-
96
- export interface Task {
97
- id: string;
98
- name: string;
99
- status: Status;
100
- milestone_id: string;
101
- file: string;
102
- estimated_hours: string;
103
- completed_date: string | null;
104
- notes: string;
105
- extra: ExtraFields;
106
- }
107
-
108
- export interface WorkEntry {
109
- date: string;
110
- description: string;
111
- items: string[];
112
- extra: ExtraFields;
113
- }
114
-
115
- export interface DocumentationStats {
116
- design_documents: number;
117
- milestone_documents: number;
118
- pattern_documents: number;
119
- task_documents: number;
120
- }
121
-
122
- export interface ProgressSummary {
123
- planning: number;
124
- implementation: number;
125
- overall: number;
126
- }
127
- ```
128
-
129
- ### YAML Parsing & Normalization
130
-
131
- The parser follows a "extract known, preserve unknown" strategy:
132
-
133
- ```typescript
134
- // app/lib/yaml-loader.ts
135
-
136
- import yaml from 'js-yaml';
137
- import type { ProgressData, Milestone, Task, Status, ExtraFields } from './types';
138
-
139
- export function parseProgressYaml(raw: string): ProgressData {
140
- const doc = yaml.load(raw) as Record<string, unknown>;
141
-
142
- const project = normalizeProject(doc.project);
143
- const milestones = normalizeMilestones(doc.milestones);
144
- const tasks = normalizeTasks(doc.tasks, milestones);
145
-
146
- return {
147
- project,
148
- milestones,
149
- tasks,
150
- recent_work: normalizeWorkEntries(doc.recent_work),
151
- next_steps: normalizeStringArray(doc.next_steps),
152
- notes: normalizeStringArray(doc.notes),
153
- current_blockers: normalizeStringArray(doc.current_blockers),
154
- documentation: normalizeDocStats(doc.documentation),
155
- progress: normalizeProgress(doc.progress),
156
- };
157
- }
158
-
159
- // --- Core extraction helpers ---
160
-
161
- /** Extract known keys from an object, return the rest as ExtraFields */
162
- function extractKnown<T extends Record<string, unknown>>(
163
- obj: Record<string, unknown>,
164
- knownKeys: string[],
165
- ): { known: Partial<T>; extra: ExtraFields } {
166
- const known: Record<string, unknown> = {};
167
- const extra: ExtraFields = {};
168
- for (const [key, value] of Object.entries(obj)) {
169
- if (knownKeys.includes(key)) {
170
- known[key] = value;
171
- } else {
172
- extra[key] = value;
173
- }
174
- }
175
- return { known: known as Partial<T>, extra };
176
- }
177
-
178
- function normalizeStatus(value: unknown): Status {
179
- const s = String(value || 'not_started')
180
- .toLowerCase()
181
- .replace(/[\s-]/g, '_'); // handle "in progress", "in-progress"
182
- if (s === 'completed' || s === 'done' || s === 'complete') return 'completed';
183
- if (s === 'in_progress' || s === 'active' || s === 'wip') return 'in_progress';
184
- return 'not_started';
185
- }
186
-
187
- function normalizeStringArray(value: unknown): string[] {
188
- if (!value) return [];
189
- if (typeof value === 'string') return [value]; // agent wrote a single string instead of array
190
- if (!Array.isArray(value)) return [];
191
- return value.map(String);
192
- }
193
-
194
- function safeString(value: unknown, fallback = ''): string {
195
- if (value == null) return fallback;
196
- return String(value);
197
- }
198
-
199
- function safeNumber(value: unknown, fallback = 0): number {
200
- const n = Number(value);
201
- return Number.isFinite(n) ? n : fallback;
202
- }
203
- ```
204
-
205
- ### Handling Agent-Maintained YAML Drift
206
-
207
- Since progress.yaml files are written and updated by AI agents (not schema-validated tooling), the parser must handle common drift patterns:
208
-
209
- | Drift Pattern | Example | Handling |
210
- |---|---|---|
211
- | Unknown properties | `priority: high` on a task | Preserved in `extra` field, available for display |
212
- | Variant key names | `est_hours` instead of `estimated_hours` | Alias map checked during normalization |
213
- | Status value variants | `"done"`, `"active"`, `"wip"` | Fuzzy-matched to canonical Status enum |
214
- | String-for-array | `notes: "some note"` instead of `notes: ["some note"]` | Wrapped in array automatically |
215
- | Missing sections | No `milestones` key at all | Defaults to empty array |
216
- | Unexpected nesting | Tasks as nested objects vs flat arrays | Both structures accepted |
217
- | Extra top-level keys | `custom_metrics:` section | Ignored gracefully (not in ProgressData but no crash) |
218
-
219
- **Key alias map** (checked in normalizers):
220
- ```typescript
221
- const TASK_ALIASES: Record<string, string> = {
222
- est_hours: 'estimated_hours',
223
- hours: 'estimated_hours',
224
- estimate: 'estimated_hours',
225
- completed: 'completed_date',
226
- done_date: 'completed_date',
227
- filename: 'file',
228
- path: 'file',
229
- };
230
- ```
231
-
232
- ### Computed Fields
233
-
234
- The parser computes:
235
- - `milestone.progress` from task completion ratios when not explicitly set
236
- - `milestone.tasks_completed` / `tasks_total` from the tasks map
237
- - `progress.overall` from milestone-level progress if not set
238
-
239
- ### Error Handling
240
-
241
- - Missing top-level keys default to empty arrays/objects
242
- - Invalid status values fuzzy-match to nearest canonical value, fallback to `'not_started'`
243
- - Missing dates normalize to `null`
244
- - Numeric fields default to `0`
245
- - Unknown properties are preserved in `extra` fields, never discarded silently
246
- - Entire parse is wrapped in try/catch — on total failure, returns a minimal ProgressData with error metadata
247
-
248
- ---
249
-
250
- ## Benefits
251
-
252
- - **Type safety**: All view components get compile-time guarantees
253
- - **Single source of truth**: One parsing function, consistent across all views
254
- - **Defensive**: Gracefully handles incomplete or malformed YAML
255
- - **Testable**: Pure function with no side effects
256
-
257
- ---
258
-
259
- ## Trade-offs
260
-
261
- - **Extra fields add payload**: Preserving unknown properties increases data size, but keeps agent context available for display
262
- - **Alias map maintenance**: New agent drift patterns may require adding aliases over time
263
- - **Upfront parsing cost**: Entire file is parsed on each load (mitigated by small file sizes, typically <100KB)
264
-
265
- ---
266
-
267
- ## Applicable Patterns
268
-
269
- | Pattern | How It Applies |
270
- |---------|----------------|
271
- | [`tanstack-cloudflare.zod-schema-validation`](../patterns/tanstack-cloudflare.zod-schema-validation.md) | Defines how to structure schemas as single source of truth. Use `z.infer<>` for derived types. For this project: Zod schemas could optionally validate known fields via `safeParse` while the `extractKnown` helper preserves extras — a hybrid approach that gets runtime validation on known fields without rejecting agent drift. Place schemas in `app/lib/schemas/`. |
272
- | [`tanstack-cloudflare.library-services`](../patterns/tanstack-cloudflare.library-services.md) | YAML parsing should be encapsulated in a service class (`ProgressDataService`) rather than called directly from components or routes. The service provides `getProgressData()` which handles file reading, parsing, normalization, and error handling. Components never import `yaml-loader.ts` directly. |
273
-
274
- ---
275
-
276
- ## Dependencies
277
-
278
- - `js-yaml` — YAML parsing library
279
- - `zod` — optional runtime validation for known fields (see Applicable Patterns)
280
- - No other external dependencies
281
-
282
- ---
283
-
284
- ## Testing Strategy
285
-
286
- - **Unit tests**: Parse sample progress.yaml files with various completeness levels
287
- - **Drift tests**: YAML with unknown fields, variant key names, status aliases — verify `extra` preservation and alias resolution
288
- - **Edge cases**: Empty milestones array, missing tasks key, null dates, unknown status values, string-for-array, completely empty file
289
- - **Snapshot tests**: Known YAML input → expected ProgressData output
290
- - **Real-world tests**: Parse actual progress.yaml files from ACP core and other projects to catch unexpected structures
291
-
292
- ---
293
-
294
- ## Migration Path
295
-
296
- N/A — greenfield project.
297
-
298
- ---
299
-
300
- ## Future Considerations
301
-
302
- - Zod schema validation for runtime type checking (could replace manual normalization)
303
- - Support for progress.yaml schema versioning if ACP introduces breaking changes
304
- - Streaming parser for extremely large files (unlikely to be needed)
305
-
306
- ---
307
-
308
- **Status**: Design Specification
309
- **Recommendation**: Implement as first task — all other features depend on this
310
- **Related Documents**: local.visualizer-requirements.md, tanstack-cloudflare.zod-schema-validation, tanstack-cloudflare.library-services