@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,205 +0,0 @@
1
- #!/bin/bash
2
- # ACP YAML Schema Validator
3
- # Pure bash YAML validation against schema definitions
4
- # Zero external dependencies
5
-
6
- # Source YAML parser (using new generic AST-based parser)
7
- SCRIPT_DIR="$(dirname "$0")"
8
- . "${SCRIPT_DIR}/acp.yaml-parser.sh"
9
- . "${SCRIPT_DIR}/acp.common.sh"
10
-
11
- # Initialize colors
12
- init_colors
13
-
14
- # Validation error tracking
15
- VALIDATION_ERRORS=0
16
- VALIDATION_WARNINGS=0
17
-
18
- # Add validation error
19
- # Usage: add_error "Error message"
20
- add_error() {
21
- echo "${RED}❌ $1${NC}" >&2
22
- VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
23
- }
24
-
25
- # Add validation warning
26
- # Usage: add_warning "Warning message"
27
- add_warning() {
28
- echo "${YELLOW}⚠️ $1${NC}" >&2
29
- VALIDATION_WARNINGS=$((VALIDATION_WARNINGS + 1))
30
- }
31
-
32
- # Validate field exists
33
- # Usage: validate_field_exists "file.yaml" "field.path"
34
- validate_field_exists() {
35
- local yaml_file="$1"
36
- local field_path="$2"
37
-
38
- if ! yaml_has_key "$yaml_file" "$field_path"; then
39
- return 1
40
- fi
41
- return 0
42
- }
43
-
44
- # Validate string pattern (regex)
45
- # Usage: validate_pattern "value" "pattern" "field_name"
46
- validate_pattern() {
47
- local value="$1"
48
- local pattern="$2"
49
- local field_name="$3"
50
-
51
- if ! echo "$value" | grep -qE "$pattern"; then
52
- return 1
53
- fi
54
- return 0
55
- }
56
-
57
- # Validate string length
58
- # Usage: validate_length "value" min max "field_name"
59
- validate_length() {
60
- local value="$1"
61
- local min="$2"
62
- local max="$3"
63
- local field_name="$4"
64
-
65
- local length=${#value}
66
-
67
- if [ -n "$min" ] && [ "$length" -lt "$min" ]; then
68
- add_error "Field '$field_name': Too short (minimum $min characters, got $length)"
69
- return 1
70
- fi
71
-
72
- if [ -n "$max" ] && [ "$length" -gt "$max" ]; then
73
- add_error "Field '$field_name': Too long (maximum $max characters, got $length)"
74
- return 1
75
- fi
76
-
77
- return 0
78
- }
79
-
80
- # Validate package.yaml file
81
- # Usage: validate_package_yaml "package.yaml"
82
- # Returns: 0 if valid, 1 if invalid
83
- validate_package_yaml() {
84
- local yaml_file="$1"
85
-
86
- if [ ! -f "$yaml_file" ]; then
87
- add_error "File not found: $yaml_file"
88
- return 1
89
- fi
90
-
91
- echo "${BLUE}Validating $yaml_file...${NC}"
92
- echo ""
93
-
94
- # Check YAML syntax (try to parse)
95
- if ! yaml_get "$yaml_file" "name" >/dev/null 2>&1; then
96
- add_error "Invalid YAML syntax in $yaml_file"
97
- return 1
98
- fi
99
-
100
- # Validate required fields
101
- local required_fields="name version description author license repository"
102
- for field in $required_fields; do
103
- if ! validate_field_exists "$yaml_file" "$field"; then
104
- add_error "Required field missing: '$field'"
105
- fi
106
- done
107
-
108
- # Validate name field
109
- if validate_field_exists "$yaml_file" "name"; then
110
- local name=$(yaml_get "$yaml_file" "name")
111
- if ! validate_pattern "$name" "^[a-z0-9-]+$" "name"; then
112
- add_error "Field 'name': Must be lowercase letters, numbers, and hyphens only (got: '$name')"
113
- fi
114
-
115
- # Check reserved names
116
- case "$name" in
117
- acp|local|core|system|global)
118
- add_error "Field 'name': '$name' is a reserved package name"
119
- ;;
120
- esac
121
- fi
122
-
123
- # Validate version field
124
- if validate_field_exists "$yaml_file" "version"; then
125
- local version=$(yaml_get "$yaml_file" "version")
126
- if ! validate_pattern "$version" "^[0-9]+\\.[0-9]+\\.[0-9]+$" "version"; then
127
- add_error "Field 'version': Must be semantic version format X.Y.Z (got: '$version')"
128
- fi
129
- fi
130
-
131
- # Validate description field
132
- if validate_field_exists "$yaml_file" "description"; then
133
- local description=$(yaml_get "$yaml_file" "description")
134
- validate_length "$description" 10 200 "description"
135
- fi
136
-
137
- # Validate author field
138
- if validate_field_exists "$yaml_file" "author"; then
139
- local author=$(yaml_get "$yaml_file" "author")
140
- validate_length "$author" 2 "" "author"
141
- fi
142
-
143
- # Validate repository field
144
- if validate_field_exists "$yaml_file" "repository"; then
145
- local repository=$(yaml_get "$yaml_file" "repository")
146
- if ! validate_pattern "$repository" "^https?://.*\\.git$" "repository"; then
147
- add_error "Field 'repository': Must be a git URL ending with .git (got: '$repository')"
148
- fi
149
- fi
150
-
151
- # Validate homepage field (optional)
152
- if validate_field_exists "$yaml_file" "homepage"; then
153
- local homepage=$(yaml_get "$yaml_file" "homepage")
154
- if ! validate_pattern "$homepage" "^https?://.*" "homepage"; then
155
- add_error "Field 'homepage': Must be a valid HTTP/HTTPS URL (got: '$homepage')"
156
- fi
157
- fi
158
-
159
- # Validate contents field (required) - use grep since yaml_has_key may not work for nested objects
160
- if ! grep -q "^contents:" "$yaml_file"; then
161
- add_error "Required field missing: 'contents'"
162
- fi
163
-
164
- # Validate requires.acp field (optional)
165
- if validate_field_exists "$yaml_file" "requires.acp"; then
166
- local acp_version=$(yaml_get "$yaml_file" "requires.acp")
167
- if ! validate_pattern "$acp_version" "^>=?[0-9]+\\.[0-9]+\\.[0-9]+$" "requires.acp"; then
168
- add_error "Field 'requires.acp': Must be version constraint like '>=2.0.0' (got: '$acp_version')"
169
- fi
170
- fi
171
-
172
- # Report results
173
- echo ""
174
- if [ "$VALIDATION_ERRORS" -eq 0 ]; then
175
- echo "${GREEN}✅ Validation passed${NC}"
176
- if [ "$VALIDATION_WARNINGS" -gt 0 ]; then
177
- echo "${YELLOW}⚠️ $VALIDATION_WARNINGS warning(s)${NC}"
178
- fi
179
- return 0
180
- else
181
- echo "${RED}❌ Validation failed${NC}"
182
- echo "${RED} $VALIDATION_ERRORS error(s)${NC}"
183
- if [ "$VALIDATION_WARNINGS" -gt 0 ]; then
184
- echo "${YELLOW} $VALIDATION_WARNINGS warning(s)${NC}"
185
- fi
186
- return 1
187
- fi
188
- }
189
-
190
- # Main function for standalone execution
191
- if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
192
- # Script is being executed directly
193
- if [ $# -eq 0 ]; then
194
- echo "Usage: $0 <yaml-file>"
195
- echo ""
196
- echo "Example:"
197
- echo " $0 package.yaml"
198
- exit 1
199
- fi
200
-
201
- validate_package_yaml "$1"
202
- exit $?
203
- fi
204
-
205
- # Script is being sourced, functions are available
File without changes
@@ -1,210 +0,0 @@
1
- # Task 1: Initialize TanStack Start Project
2
-
3
- **Milestone**: [M1 - Project Scaffold & Data Pipeline](../../milestones/milestone-1-project-scaffold-data-pipeline.md)
4
- **Design Reference**: [Dashboard Layout & Routing](../../design/local.dashboard-layout-routing.md)
5
- **Estimated Time**: 2 hours
6
- **Dependencies**: None
7
- **Status**: Not Started
8
-
9
- ---
10
-
11
- ## Objective
12
-
13
- Scaffold a TanStack Start project with Vite, React, TanStack Router, and Tailwind CSS. Configure design tokens for the admin dashboard theme. This establishes the foundational build toolchain and styling system that all subsequent tasks build upon.
14
-
15
- ---
16
-
17
- ## Context
18
-
19
- The ACP Progress Visualizer is a TanStack Start application that renders progress.yaml data as an interactive admin dashboard. This first task creates the project skeleton with all P0 dependencies installed and Tailwind configured with the project's design token palette (status colors, typography, dark theme). Without this foundation, no UI or data pipeline work can proceed.
20
-
21
- ---
22
-
23
- ## Steps
24
-
25
- ### 1. Scaffold the TanStack Start project
26
-
27
- Run the TanStack Start scaffolding tool or manually initialize the project structure:
28
-
29
- ```bash
30
- npm create @tanstack/start@latest
31
- ```
32
-
33
- If scaffolding manually, create a `package.json` with the project name and set `"type": "module"`.
34
-
35
- ### 2. Install dependencies
36
-
37
- Install all P0 dependencies required for the visualizer:
38
-
39
- ```bash
40
- npm install @tanstack/react-router @tanstack/react-start @tanstack/react-table react react-dom
41
- npm install tailwindcss postcss autoprefixer lucide-react js-yaml fuse.js
42
- npm install -D @types/react @types/react-dom @types/js-yaml typescript vite
43
- ```
44
-
45
- ### 3. Configure Tailwind with custom design tokens
46
-
47
- Initialize Tailwind and configure the theme in `tailwind.config.ts`:
48
-
49
- ```bash
50
- npx tailwindcss init -p --ts
51
- ```
52
-
53
- Add custom design tokens to the Tailwind config:
54
-
55
- ```typescript
56
- // tailwind.config.ts
57
- import type { Config } from "tailwindcss";
58
-
59
- export default {
60
- content: ["./app/**/*.{ts,tsx}"],
61
- darkMode: "class",
62
- theme: {
63
- extend: {
64
- colors: {
65
- status: {
66
- completed: "#22c55e", // green-500
67
- in_progress: "#3b82f6", // blue-500
68
- not_started: "#6b7280", // gray-500
69
- blocked: "#ef4444", // red-500
70
- skipped: "#a855f7", // purple-500
71
- },
72
- },
73
- fontFamily: {
74
- sans: ["Inter", "system-ui", "sans-serif"],
75
- mono: ["JetBrains Mono", "monospace"],
76
- },
77
- },
78
- },
79
- plugins: [],
80
- } satisfies Config;
81
- ```
82
-
83
- ### 4. Create the root layout
84
-
85
- Create `app/routes/__root.tsx` with a minimal root layout that includes the dark theme class and global styles:
86
-
87
- ```typescript
88
- // app/routes/__root.tsx
89
- import { createRootRoute, Outlet } from "@tanstack/react-router";
90
-
91
- export const Route = createRootRoute({
92
- component: RootLayout,
93
- });
94
-
95
- function RootLayout() {
96
- return (
97
- <div className="dark min-h-screen bg-gray-950 text-gray-100">
98
- <Outlet />
99
- </div>
100
- );
101
- }
102
- ```
103
-
104
- ### 5. Create the index route
105
-
106
- Create `app/routes/index.tsx` with placeholder content to verify the app renders:
107
-
108
- ```typescript
109
- // app/routes/index.tsx
110
- import { createFileRoute } from "@tanstack/react-router";
111
-
112
- export const Route = createFileRoute("/")({
113
- component: HomePage,
114
- });
115
-
116
- function HomePage() {
117
- return (
118
- <div className="p-8">
119
- <h1 className="text-2xl font-bold font-sans">
120
- ACP Progress Visualizer
121
- </h1>
122
- <p className="mt-2 text-gray-400 font-mono text-sm">
123
- Dashboard loading...
124
- </p>
125
- </div>
126
- );
127
- }
128
- ```
129
-
130
- ### 6. Create TanStack Start configuration
131
-
132
- Create `app.config.ts` for TanStack Start:
133
-
134
- ```typescript
135
- // app.config.ts
136
- import { defineConfig } from "@tanstack/react-start/config";
137
- import viteTsConfigPaths from "vite-tsconfig-paths";
138
-
139
- export default defineConfig({
140
- vite: {
141
- plugins: [viteTsConfigPaths()],
142
- },
143
- });
144
- ```
145
-
146
- ### 7. Verify dev server starts
147
-
148
- Run the development server and confirm the app loads without errors:
149
-
150
- ```bash
151
- npm run dev
152
- ```
153
-
154
- Open the browser to the local dev URL and verify the placeholder content renders with correct fonts and dark theme styling.
155
-
156
- ---
157
-
158
- ## Verification
159
-
160
- - [ ] `package.json` exists with all P0 dependencies listed
161
- - [ ] `tailwind.config.ts` exists and contains status color tokens (completed, in_progress, not_started, blocked, skipped)
162
- - [ ] `tailwind.config.ts` specifies Inter for sans and JetBrains Mono for mono font families
163
- - [ ] `app/routes/__root.tsx` exists with dark theme wrapper and `<Outlet />`
164
- - [ ] `app/routes/index.tsx` exists with placeholder content
165
- - [ ] `app.config.ts` exists with TanStack Start configuration
166
- - [ ] `npm run dev` starts without errors
167
- - [ ] Root route renders in the browser with dark background and light text
168
-
169
- ---
170
-
171
- ## Expected Output
172
-
173
- **File Structure**:
174
- ```
175
- project-root/
176
- ├── app/
177
- │ ├── routes/
178
- │ │ ├── __root.tsx
179
- │ │ └── index.tsx
180
- │ └── styles/
181
- │ └── globals.css
182
- ├── app.config.ts
183
- ├── tailwind.config.ts
184
- ├── postcss.config.js
185
- ├── tsconfig.json
186
- ├── package.json
187
- └── package-lock.json
188
- ```
189
-
190
- **Key Files Created**:
191
- - `package.json`: Project manifest with all P0 dependencies
192
- - `tailwind.config.ts`: Tailwind configuration with status colors and typography tokens
193
- - `app/routes/__root.tsx`: Root layout with dark theme wrapper
194
- - `app/routes/index.tsx`: Index route with placeholder content
195
- - `app.config.ts`: TanStack Start build configuration
196
-
197
- ---
198
-
199
- ## Notes
200
-
201
- - Dark theme is the default and only theme for this project; no light mode toggle is planned
202
- - The `lucide-react` icon library is installed now but used in later tasks for sidebar and status icons
203
- - `fuse.js` and `@tanstack/react-table` are installed now to avoid dependency churn in later milestones
204
- - If `npm create @tanstack/start@latest` output differs from expected, adjust file locations to match the scaffolding output
205
-
206
- ---
207
-
208
- **Next Task**: [Task 2: Implement Data Model & YAML Parser](./task-2-implement-data-model-yaml-parser.md)
209
- **Related Design Docs**: [Dashboard Layout & Routing](../../design/local.dashboard-layout-routing.md)
210
- **Estimated Completion Date**: TBD
@@ -1,294 +0,0 @@
1
- # Task 2: Implement Data Model & YAML Parser
2
-
3
- **Milestone**: [M1 - Project Scaffold & Data Pipeline](../../milestones/milestone-1-project-scaffold-data-pipeline.md)
4
- **Design Reference**: [Data Model & YAML Parsing](../../design/local.data-model-yaml-parsing.md)
5
- **Estimated Time**: 3 hours
6
- **Dependencies**: Task 1
7
- **Status**: Not Started
8
-
9
- ---
10
-
11
- ## Objective
12
-
13
- Create TypeScript interfaces for progress.yaml data and a lenient YAML parser that handles agent-maintained YAML with drift tolerance. The parser must gracefully handle missing fields, unknown keys, status aliases, and type coercion so the dashboard never crashes on imperfect YAML.
14
-
15
- ---
16
-
17
- ## Context
18
-
19
- The progress.yaml file is maintained by AI agents and tends to drift from a strict schema over time. Fields get renamed, statuses use informal terms ("done" instead of "completed"), single strings appear where arrays are expected, and unknown fields accumulate. The parser must be maximally tolerant: extract what it can, preserve unknown fields in an `extra` bag, normalize statuses and field names, and return safe defaults for anything missing. This approach ensures the dashboard always renders something useful rather than crashing on schema violations.
20
-
21
- ---
22
-
23
- ## Steps
24
-
25
- ### 1. Create TypeScript interfaces
26
-
27
- Create `app/lib/types.ts` with all data model interfaces:
28
-
29
- ```typescript
30
- // app/lib/types.ts
31
-
32
- export type Status = "completed" | "in_progress" | "not_started" | "blocked" | "skipped";
33
-
34
- export interface ExtraFields {
35
- [key: string]: unknown;
36
- }
37
-
38
- export interface ProjectMetadata {
39
- name: string;
40
- description: string;
41
- version: string;
42
- repository: string;
43
- extra: ExtraFields;
44
- }
45
-
46
- export interface WorkEntry {
47
- date: string;
48
- task: string;
49
- hours: number;
50
- notes: string;
51
- extra: ExtraFields;
52
- }
53
-
54
- export interface Task {
55
- id: string;
56
- title: string;
57
- status: Status;
58
- estimated_hours: number;
59
- actual_hours: number;
60
- dependencies: string[];
61
- tags: string[];
62
- notes: string;
63
- extra: ExtraFields;
64
- }
65
-
66
- export interface Milestone {
67
- id: string;
68
- title: string;
69
- status: Status;
70
- target_date: string;
71
- tasks: Task[];
72
- extra: ExtraFields;
73
- }
74
-
75
- export interface DocumentationStats {
76
- design_docs: number;
77
- task_docs: number;
78
- patterns: number;
79
- clarifications: number;
80
- extra: ExtraFields;
81
- }
82
-
83
- export interface ProgressSummary {
84
- total_tasks: number;
85
- completed_tasks: number;
86
- completion_percentage: number;
87
- total_hours_estimated: number;
88
- total_hours_actual: number;
89
- extra: ExtraFields;
90
- }
91
-
92
- export interface ProgressData {
93
- project: ProjectMetadata;
94
- milestones: Milestone[];
95
- work_entries: WorkEntry[];
96
- documentation: DocumentationStats;
97
- progress: ProgressSummary;
98
- extra: ExtraFields;
99
- }
100
- ```
101
-
102
- ### 2. Create the YAML loader module
103
-
104
- Create `app/lib/yaml-loader.ts` with the main `parseProgressYaml` function:
105
-
106
- ```typescript
107
- // app/lib/yaml-loader.ts
108
- import yaml from "js-yaml";
109
- import type { ProgressData } from "./types";
110
-
111
- export function parseProgressYaml(raw: string): ProgressData {
112
- // Implementation in subsequent steps
113
- }
114
- ```
115
-
116
- ### 3. Implement the `extractKnown` helper
117
-
118
- This utility separates known fields from extras, which is the foundation of drift tolerance:
119
-
120
- ```typescript
121
- function extractKnown<T extends Record<string, unknown>>(
122
- obj: Record<string, unknown>,
123
- knownKeys: string[]
124
- ): { known: Partial<T>; extra: Record<string, unknown> } {
125
- const known: Record<string, unknown> = {};
126
- const extra: Record<string, unknown> = {};
127
- for (const [key, value] of Object.entries(obj)) {
128
- if (knownKeys.includes(key)) {
129
- known[key] = value;
130
- } else {
131
- extra[key] = value;
132
- }
133
- }
134
- return { known: known as Partial<T>, extra };
135
- }
136
- ```
137
-
138
- ### 4. Implement `normalizeStatus`
139
-
140
- Map informal status strings to canonical Status values using fuzzy matching:
141
-
142
- ```typescript
143
- function normalizeStatus(raw: unknown): Status {
144
- if (typeof raw !== "string") return "not_started";
145
- const s = raw.toLowerCase().trim().replace(/[\s-]/g, "_");
146
- const aliases: Record<string, Status> = {
147
- done: "completed",
148
- complete: "completed",
149
- completed: "completed",
150
- finished: "completed",
151
- active: "in_progress",
152
- wip: "in_progress",
153
- in_progress: "in_progress",
154
- working: "in_progress",
155
- started: "in_progress",
156
- pending: "not_started",
157
- not_started: "not_started",
158
- todo: "not_started",
159
- queued: "not_started",
160
- blocked: "blocked",
161
- stuck: "blocked",
162
- waiting: "blocked",
163
- skipped: "skipped",
164
- dropped: "skipped",
165
- deferred: "skipped",
166
- };
167
- return aliases[s] ?? "not_started";
168
- }
169
- ```
170
-
171
- ### 5. Implement key alias maps
172
-
173
- Create alias maps so renamed fields still parse correctly:
174
-
175
- ```typescript
176
- const TASK_KEY_ALIASES: Record<string, string> = {
177
- est_hours: "estimated_hours",
178
- estimated: "estimated_hours",
179
- actual: "actual_hours",
180
- act_hours: "actual_hours",
181
- deps: "dependencies",
182
- depends_on: "dependencies",
183
- name: "title",
184
- };
185
-
186
- const MILESTONE_KEY_ALIASES: Record<string, string> = {
187
- name: "title",
188
- target: "target_date",
189
- due_date: "target_date",
190
- deadline: "target_date",
191
- };
192
- ```
193
-
194
- ### 6. Implement `normalizeStringArray`
195
-
196
- Handle cases where a single string appears instead of an array:
197
-
198
- ```typescript
199
- function normalizeStringArray(raw: unknown): string[] {
200
- if (Array.isArray(raw)) return raw.map(String);
201
- if (typeof raw === "string") return [raw];
202
- return [];
203
- }
204
- ```
205
-
206
- ### 7. Implement entity normalizers
207
-
208
- Create normalizer functions for each entity type:
209
-
210
- - `normalizeProject(raw: unknown): ProjectMetadata` — extracts name, description, version, repository with string defaults
211
- - `normalizeMilestones(raw: unknown): Milestone[]` — iterates array, applies key aliases, normalizes status and tasks
212
- - `normalizeTasks(raw: unknown): Task[]` — iterates array, applies key aliases, normalizes status, coerces string arrays for deps/tags
213
- - `normalizeWorkEntries(raw: unknown): WorkEntry[]` — iterates array, coerces hours to number, defaults date/task/notes
214
- - `normalizeDocStats(raw: unknown): DocumentationStats` — extracts numeric counts with 0 defaults
215
- - `normalizeProgress(raw: unknown): ProgressSummary` — extracts numeric summary fields with 0 defaults
216
-
217
- Each normalizer should use `extractKnown` to separate known fields from extras.
218
-
219
- ### 8. Implement top-level parser with fallback
220
-
221
- Wire up `parseProgressYaml`:
222
-
223
- ```typescript
224
- export function parseProgressYaml(raw: string): ProgressData {
225
- try {
226
- const doc = yaml.load(raw) as Record<string, unknown> | null;
227
- if (!doc || typeof doc !== "object") {
228
- return emptyProgressData();
229
- }
230
- return {
231
- project: normalizeProject(doc.project),
232
- milestones: normalizeMilestones(doc.milestones),
233
- work_entries: normalizeWorkEntries(doc.work_entries ?? doc.work_log),
234
- documentation: normalizeDocStats(doc.documentation ?? doc.docs),
235
- progress: normalizeProgress(doc.progress ?? doc.summary),
236
- extra: extractTopLevelExtra(doc),
237
- };
238
- } catch {
239
- return emptyProgressData();
240
- }
241
- }
242
- ```
243
-
244
- ### 9. Write unit tests
245
-
246
- Create `app/lib/__tests__/yaml-loader.test.ts` with tests covering:
247
-
248
- - Complete valid YAML parses correctly
249
- - Missing sections default gracefully (empty arrays, zero counts)
250
- - Unknown fields preserved in `extra`
251
- - Status aliases resolve correctly (`"done"` becomes `"completed"`, `"wip"` becomes `"in_progress"`)
252
- - Single string coerced to array for dependencies and tags
253
- - Key aliases work (`est_hours` becomes `estimated_hours`)
254
- - Completely invalid YAML returns empty ProgressData (no crash)
255
- - Empty string input returns empty ProgressData
256
-
257
- ---
258
-
259
- ## Verification
260
-
261
- - [ ] `app/lib/types.ts` exports all interfaces: Status, ExtraFields, ProgressData, ProjectMetadata, Milestone, Task, WorkEntry, DocumentationStats, ProgressSummary
262
- - [ ] `app/lib/yaml-loader.ts` exports `parseProgressYaml` function
263
- - [ ] Parser handles complete YAML and returns fully populated ProgressData
264
- - [ ] Parser handles incomplete YAML with missing sections (defaults to empty arrays/zero counts)
265
- - [ ] Unknown fields are preserved in `extra` objects at every level
266
- - [ ] Status aliases resolve correctly (done, wip, active, pending, stuck, etc.)
267
- - [ ] Single string values coerced to arrays for dependencies and tags
268
- - [ ] Key aliases resolve correctly (est_hours, deps, name, etc.)
269
- - [ ] Completely invalid YAML returns empty ProgressData without throwing
270
- - [ ] All unit tests pass
271
-
272
- ---
273
-
274
- ## Expected Output
275
-
276
- **Key Files Created**:
277
- - `app/lib/types.ts`: TypeScript interfaces for the entire progress.yaml data model
278
- - `app/lib/yaml-loader.ts`: Lenient YAML parser with drift tolerance
279
- - `app/lib/__tests__/yaml-loader.test.ts`: Unit tests for the parser
280
-
281
- ---
282
-
283
- ## Notes
284
-
285
- - The parser is intentionally lenient; it should never throw. Any error results in a fallback empty ProgressData
286
- - The `extra` field pattern is critical: it allows the dashboard to display fields the schema does not yet know about, which is essential for agent-maintained YAML that evolves over time
287
- - Status normalization covers common agent shorthand; new aliases can be added as they are discovered
288
- - Key alias maps should be extended if agents consistently use non-standard field names
289
-
290
- ---
291
-
292
- **Next Task**: [Task 3: Build Server API & Data Loading](./task-3-build-server-api-data-loading.md)
293
- **Related Design Docs**: [Data Model & YAML Parsing](../../design/local.data-model-yaml-parsing.md)
294
- **Estimated Completion Date**: TBD