@prmichaelsen/acp-visualizer 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. package/README.md +68 -0
  2. package/agent/commands/acp.clarification-address.md +417 -0
  3. package/agent/commands/acp.clarification-capture.md +386 -0
  4. package/agent/commands/acp.clarification-create.md +437 -0
  5. package/agent/commands/acp.clarifications-research.md +326 -0
  6. package/agent/commands/acp.command-create.md +432 -0
  7. package/agent/commands/acp.design-create.md +286 -0
  8. package/agent/commands/acp.design-reference.md +355 -0
  9. package/agent/commands/acp.handoff.md +270 -0
  10. package/agent/commands/acp.index.md +423 -0
  11. package/agent/commands/acp.init.md +546 -0
  12. package/agent/commands/acp.package-create.md +895 -0
  13. package/agent/commands/acp.package-info.md +212 -0
  14. package/agent/commands/acp.package-install.md +539 -0
  15. package/agent/commands/acp.package-list.md +280 -0
  16. package/agent/commands/acp.package-publish.md +541 -0
  17. package/agent/commands/acp.package-remove.md +293 -0
  18. package/agent/commands/acp.package-search.md +307 -0
  19. package/agent/commands/acp.package-update.md +361 -0
  20. package/agent/commands/acp.package-validate.md +540 -0
  21. package/agent/commands/acp.pattern-create.md +386 -0
  22. package/agent/commands/acp.plan.md +587 -0
  23. package/agent/commands/acp.proceed.md +882 -0
  24. package/agent/commands/acp.project-create.md +675 -0
  25. package/agent/commands/acp.project-info.md +312 -0
  26. package/agent/commands/acp.project-list.md +226 -0
  27. package/agent/commands/acp.project-remove.md +379 -0
  28. package/agent/commands/acp.project-set.md +227 -0
  29. package/agent/commands/acp.project-update.md +307 -0
  30. package/agent/commands/acp.projects-restore.md +228 -0
  31. package/agent/commands/acp.projects-sync.md +347 -0
  32. package/agent/commands/acp.report.md +407 -0
  33. package/agent/commands/acp.resume.md +239 -0
  34. package/agent/commands/acp.sessions.md +301 -0
  35. package/agent/commands/acp.status.md +293 -0
  36. package/agent/commands/acp.sync.md +364 -0
  37. package/agent/commands/acp.task-create.md +500 -0
  38. package/agent/commands/acp.update.md +302 -0
  39. package/agent/commands/acp.validate.md +466 -0
  40. package/agent/commands/acp.version-check-for-updates.md +276 -0
  41. package/agent/commands/acp.version-check.md +191 -0
  42. package/agent/commands/acp.version-update.md +289 -0
  43. package/agent/commands/command.template.md +339 -0
  44. package/agent/commands/git.commit.md +526 -0
  45. package/agent/commands/git.init.md +514 -0
  46. package/agent/commands/tanstack-cloudflare.deploy.md +272 -0
  47. package/agent/commands/tanstack-cloudflare.tail.md +275 -0
  48. package/agent/design/.gitkeep +0 -0
  49. package/agent/design/design.template.md +154 -0
  50. package/agent/design/local.dashboard-layout-routing.md +288 -0
  51. package/agent/design/local.data-model-yaml-parsing.md +310 -0
  52. package/agent/design/local.search-filtering.md +331 -0
  53. package/agent/design/local.server-api-auto-refresh.md +235 -0
  54. package/agent/design/local.table-tree-views.md +299 -0
  55. package/agent/design/local.visualizer-requirements.md +349 -0
  56. package/agent/design/requirements.template.md +387 -0
  57. package/agent/index/.gitkeep +0 -0
  58. package/agent/index/acp.core.yaml +137 -0
  59. package/agent/index/local.main.template.yaml +37 -0
  60. package/agent/manifest.template.yaml +13 -0
  61. package/agent/manifest.yaml +302 -0
  62. package/agent/milestones/.gitkeep +0 -0
  63. package/agent/milestones/milestone-1-project-scaffold-data-pipeline.md +67 -0
  64. package/agent/milestones/milestone-1-{title}.template.md +206 -0
  65. package/agent/milestones/milestone-2-dashboard-views-interaction.md +79 -0
  66. package/agent/package.template.yaml +86 -0
  67. package/agent/patterns/.gitkeep +0 -0
  68. package/agent/patterns/bootstrap.template.md +1237 -0
  69. package/agent/patterns/pattern.template.md +382 -0
  70. package/agent/patterns/tanstack-cloudflare.acl-permissions.md +332 -0
  71. package/agent/patterns/tanstack-cloudflare.action-bar-item.md +416 -0
  72. package/agent/patterns/tanstack-cloudflare.api-route-handlers.md +401 -0
  73. package/agent/patterns/tanstack-cloudflare.auth-session-management.md +387 -0
  74. package/agent/patterns/tanstack-cloudflare.card-and-list.md +271 -0
  75. package/agent/patterns/tanstack-cloudflare.chat-engine.md +353 -0
  76. package/agent/patterns/tanstack-cloudflare.confirmation-tokens.md +346 -0
  77. package/agent/patterns/tanstack-cloudflare.durable-objects-websocket.md +516 -0
  78. package/agent/patterns/tanstack-cloudflare.email-service.md +431 -0
  79. package/agent/patterns/tanstack-cloudflare.expander.md +98 -0
  80. package/agent/patterns/tanstack-cloudflare.fcm-push.md +115 -0
  81. package/agent/patterns/tanstack-cloudflare.firebase-anonymous-sessions.md +441 -0
  82. package/agent/patterns/tanstack-cloudflare.firebase-auth.md +348 -0
  83. package/agent/patterns/tanstack-cloudflare.firebase-firestore.md +550 -0
  84. package/agent/patterns/tanstack-cloudflare.firebase-storage.md +369 -0
  85. package/agent/patterns/tanstack-cloudflare.form-controls.md +145 -0
  86. package/agent/patterns/tanstack-cloudflare.global-search-context.md +93 -0
  87. package/agent/patterns/tanstack-cloudflare.image-carousel.md +126 -0
  88. package/agent/patterns/tanstack-cloudflare.library-services.md +553 -0
  89. package/agent/patterns/tanstack-cloudflare.lightbox.md +169 -0
  90. package/agent/patterns/tanstack-cloudflare.markdown-content.md +115 -0
  91. package/agent/patterns/tanstack-cloudflare.mention-suggestions.md +98 -0
  92. package/agent/patterns/tanstack-cloudflare.modal.md +156 -0
  93. package/agent/patterns/tanstack-cloudflare.nextjs-to-tanstack-routing.md +461 -0
  94. package/agent/patterns/tanstack-cloudflare.notifications-engine.md +151 -0
  95. package/agent/patterns/tanstack-cloudflare.oauth-token-refresh.md +90 -0
  96. package/agent/patterns/tanstack-cloudflare.og-metadata.md +296 -0
  97. package/agent/patterns/tanstack-cloudflare.pagination.md +442 -0
  98. package/agent/patterns/tanstack-cloudflare.pill-input.md +220 -0
  99. package/agent/patterns/tanstack-cloudflare.provider-adapter.md +401 -0
  100. package/agent/patterns/tanstack-cloudflare.rate-limiting.md +323 -0
  101. package/agent/patterns/tanstack-cloudflare.scheduled-tasks.md +338 -0
  102. package/agent/patterns/tanstack-cloudflare.searchable-settings.md +375 -0
  103. package/agent/patterns/tanstack-cloudflare.slide-over.md +129 -0
  104. package/agent/patterns/tanstack-cloudflare.ssr-preload.md +571 -0
  105. package/agent/patterns/tanstack-cloudflare.third-party-api-integration.md +508 -0
  106. package/agent/patterns/tanstack-cloudflare.toast-system.md +142 -0
  107. package/agent/patterns/tanstack-cloudflare.unified-header.md +280 -0
  108. package/agent/patterns/tanstack-cloudflare.user-scoped-collections.md +628 -0
  109. package/agent/patterns/tanstack-cloudflare.websocket-manager.md +237 -0
  110. package/agent/patterns/tanstack-cloudflare.wrangler-configuration.md +358 -0
  111. package/agent/patterns/tanstack-cloudflare.zod-schema-validation.md +336 -0
  112. package/agent/progress.template.yaml +161 -0
  113. package/agent/progress.yaml +145 -0
  114. package/agent/schemas/package.schema.yaml +276 -0
  115. package/agent/scripts/acp.common.sh +1781 -0
  116. package/agent/scripts/acp.install.sh +333 -0
  117. package/agent/scripts/acp.package-create.sh +924 -0
  118. package/agent/scripts/acp.package-info.sh +288 -0
  119. package/agent/scripts/acp.package-install.sh +893 -0
  120. package/agent/scripts/acp.package-list.sh +311 -0
  121. package/agent/scripts/acp.package-publish.sh +420 -0
  122. package/agent/scripts/acp.package-remove.sh +348 -0
  123. package/agent/scripts/acp.package-search.sh +156 -0
  124. package/agent/scripts/acp.package-update.sh +517 -0
  125. package/agent/scripts/acp.package-validate.sh +1018 -0
  126. package/agent/scripts/acp.uninstall.sh +85 -0
  127. package/agent/scripts/acp.version-check-for-updates.sh +98 -0
  128. package/agent/scripts/acp.version-check.sh +47 -0
  129. package/agent/scripts/acp.version-update.sh +176 -0
  130. package/agent/scripts/acp.yaml-parser.sh +985 -0
  131. package/agent/scripts/acp.yaml-validate.sh +205 -0
  132. package/agent/tasks/.gitkeep +0 -0
  133. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-1-initialize-tanstack-start-project.md +210 -0
  134. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-2-implement-data-model-yaml-parser.md +294 -0
  135. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-3-build-server-api-data-loading.md +193 -0
  136. package/agent/tasks/milestone-1-project-scaffold-data-pipeline/task-4-add-auto-refresh-sse.md +262 -0
  137. package/agent/tasks/milestone-2-dashboard-views-interaction/task-10-polish-integration-testing.md +156 -0
  138. package/agent/tasks/milestone-2-dashboard-views-interaction/task-5-build-dashboard-layout-routing.md +178 -0
  139. package/agent/tasks/milestone-2-dashboard-views-interaction/task-6-build-overview-page.md +141 -0
  140. package/agent/tasks/milestone-2-dashboard-views-interaction/task-7-implement-milestone-table-view.md +153 -0
  141. package/agent/tasks/milestone-2-dashboard-views-interaction/task-8-implement-milestone-tree-view.md +174 -0
  142. package/agent/tasks/milestone-2-dashboard-views-interaction/task-9-implement-search-filtering.md +233 -0
  143. package/agent/tasks/task-1-{title}.template.md +244 -0
  144. package/bin/visualize.mjs +84 -0
  145. package/package.json +48 -0
  146. package/src/components/ExtraFieldsBadge.tsx +15 -0
  147. package/src/components/FilterBar.tsx +33 -0
  148. package/src/components/Header.tsx +23 -0
  149. package/src/components/MilestoneTable.tsx +167 -0
  150. package/src/components/MilestoneTree.tsx +84 -0
  151. package/src/components/ProgressBar.tsx +20 -0
  152. package/src/components/SearchInput.tsx +22 -0
  153. package/src/components/Sidebar.tsx +54 -0
  154. package/src/components/StatusBadge.tsx +23 -0
  155. package/src/components/StatusDot.tsx +12 -0
  156. package/src/components/TaskList.tsx +36 -0
  157. package/src/components/ViewToggle.tsx +31 -0
  158. package/src/lib/config.ts +8 -0
  159. package/src/lib/file-watcher.ts +43 -0
  160. package/src/lib/search.ts +48 -0
  161. package/src/lib/types.ts +73 -0
  162. package/src/lib/useAutoRefresh.ts +31 -0
  163. package/src/lib/useCollapse.ts +31 -0
  164. package/src/lib/useFilteredData.ts +55 -0
  165. package/src/lib/yaml-loader-real.spec.ts +47 -0
  166. package/src/lib/yaml-loader.spec.ts +201 -0
  167. package/src/lib/yaml-loader.ts +265 -0
  168. package/src/routeTree.gen.ts +140 -0
  169. package/src/router.tsx +10 -0
  170. package/src/routes/__root.tsx +75 -0
  171. package/src/routes/api/watch.ts +29 -0
  172. package/src/routes/index.tsx +115 -0
  173. package/src/routes/milestones.tsx +50 -0
  174. package/src/routes/search.tsx +84 -0
  175. package/src/routes/tasks.tsx +63 -0
  176. package/src/services/progress-database.service.ts +46 -0
  177. package/src/styles.css +25 -0
  178. package/tsconfig.json +24 -0
  179. package/vite.config.ts +16 -0
  180. package/vitest.config.ts +27 -0
@@ -0,0 +1,288 @@
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
@@ -0,0 +1,310 @@
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