@prmichaelsen/acp-visualizer 0.1.6 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prmichaelsen/acp-visualizer",
3
- "version": "0.1.6",
3
+ "version": "0.1.7",
4
4
  "type": "module",
5
5
  "description": "Browser-based dashboard for visualizing ACP progress.yaml data",
6
6
  "bin": {
@@ -186,6 +186,34 @@ milestones:
186
186
  expect(result.milestones[0].id).toBe('milestone_1')
187
187
  })
188
188
 
189
+ it('maps task keys to milestone IDs when formats differ', () => {
190
+ const yaml = `
191
+ milestones:
192
+ - id: M1
193
+ name: First
194
+ status: completed
195
+ - id: M2
196
+ name: Second
197
+ status: in_progress
198
+
199
+ tasks:
200
+ milestone_1:
201
+ - id: t1
202
+ name: Task A
203
+ status: completed
204
+ milestone_2:
205
+ - id: t2
206
+ name: Task B
207
+ status: in_progress
208
+ `
209
+ const result = parseProgressYaml(yaml)
210
+ // Tasks keyed as milestone_1 should map to milestone ID M1
211
+ expect(result.tasks['M1']).toHaveLength(1)
212
+ expect(result.tasks['M1'][0].name).toBe('Task A')
213
+ expect(result.tasks['M2']).toHaveLength(1)
214
+ expect(result.tasks['M2'][0].name).toBe('Task B')
215
+ })
216
+
189
217
  it('handles null values in dates', () => {
190
218
  const yaml = `
191
219
  milestones:
@@ -35,6 +35,7 @@ const TASK_ALIASES: Record<string, string> = {
35
35
  done_date: 'completed_date',
36
36
  filename: 'file',
37
37
  path: 'file',
38
+ document: 'file',
38
39
  milestone: 'milestone_id',
39
40
  }
40
41
 
@@ -171,12 +172,35 @@ function normalizeTask(raw: unknown, milestoneId: string, index: number): Task {
171
172
  }
172
173
  }
173
174
 
174
- function normalizeTasks(raw: unknown): Record<string, Task[]> {
175
+ function normalizeTasks(raw: unknown, milestones: Milestone[]): Record<string, Task[]> {
175
176
  const result: Record<string, Task[]> = {}
176
177
  const obj = asRecord(raw)
177
- for (const [milestoneId, tasks] of Object.entries(obj)) {
178
+
179
+ // Build a map from task key patterns to milestone IDs.
180
+ // Handles mismatch: tasks keyed as "milestone_1" but milestone.id = "M1"
181
+ const keyToMilestoneId = new Map<string, string>()
182
+ for (let i = 0; i < milestones.length; i++) {
183
+ const m = milestones[i]
184
+ // The task key might be the milestone ID itself, or "milestone_N"
185
+ keyToMilestoneId.set(m.id, m.id)
186
+ keyToMilestoneId.set(m.id.toLowerCase(), m.id)
187
+ keyToMilestoneId.set(`milestone_${i + 1}`, m.id)
188
+ // Also handle "milestone_N" where N matches the numeric part of "MN"
189
+ const numMatch = m.id.match(/(\d+)/)
190
+ if (numMatch) {
191
+ keyToMilestoneId.set(`milestone_${numMatch[1]}`, m.id)
192
+ }
193
+ }
194
+
195
+ for (const [rawKey, tasks] of Object.entries(obj)) {
178
196
  if (Array.isArray(tasks)) {
179
- result[milestoneId] = tasks.map((t, i) => normalizeTask(t, milestoneId, i))
197
+ // Resolve the key to a milestone ID, or keep as-is
198
+ const milestoneId = keyToMilestoneId.get(rawKey) || rawKey
199
+ const existing = result[milestoneId] || []
200
+ result[milestoneId] = [
201
+ ...existing,
202
+ ...tasks.map((t, i) => normalizeTask(t, milestoneId, existing.length + i)),
203
+ ]
180
204
  }
181
205
  }
182
206
  return result
@@ -248,10 +272,12 @@ export function parseProgressYaml(raw: string): ProgressData {
248
272
  }
249
273
  const d = doc as Record<string, unknown>
250
274
 
275
+ const milestones = normalizeMilestones(d.milestones)
276
+
251
277
  return {
252
278
  project: normalizeProject(d.project),
253
- milestones: normalizeMilestones(d.milestones),
254
- tasks: normalizeTasks(d.tasks),
279
+ milestones,
280
+ tasks: normalizeTasks(d.tasks, milestones),
255
281
  recent_work: normalizeWorkEntries(d.recent_work),
256
282
  next_steps: normalizeStringArray(d.next_steps),
257
283
  notes: normalizeStringArray(d.notes),