@comfanion/workflow 4.38.1-dev.2 → 4.38.1-dev.3

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": "@comfanion/workflow",
3
- "version": "4.38.1-dev.2",
3
+ "version": "4.38.1-dev.3",
4
4
  "description": "Initialize OpenCode Workflow system for AI-assisted development with semantic code search",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "4.38.1-dev.2",
3
- "buildDate": "2026-01-27T01:09:08.937Z",
2
+ "version": "4.38.1-dev.3",
3
+ "buildDate": "2026-01-27T10:14:50.120Z",
4
4
  "files": [
5
5
  "config.yaml",
6
6
  "FLOW.yaml",
@@ -306,83 +306,39 @@ DO NOT skip this step. DO NOT ask user what to do. Just read these files first.`
306
306
 
307
307
  async function getActiveStory(): Promise<StoryContext | null> {
308
308
  try {
309
- // First, try to find epic state file
309
+ let storyPath: string | null = null
310
+
311
+ // First, try epic state file for story path
310
312
  const epicState = await getActiveEpicState()
311
- if (epicState) {
312
- // Parse epic state to get current story
313
- const storyPathMatch = epicState.content.match(/next_action:\s*["']?Execute\s+(.+?)["']?$/m)
314
- if (storyPathMatch) {
315
- const storyFileName = storyPathMatch[1]
316
- // Find story file
317
- const sprintMatch = epicState.statePath.match(/sprint-(\d+)/)
318
- if (sprintMatch) {
319
- const storyPath = `docs/sprint-artifacts/sprint-${sprintMatch[1]}/stories/${storyFileName}`
320
- const storyContent = await readFile(join(directory, storyPath), "utf-8")
321
-
322
- const titleMatch = storyContent.match(/^#\s+(.+)/m)
323
- const statusMatch = storyContent.match(/\*\*Status:\*\*\s*(\w+)/i)
324
-
325
- const completedTasks: string[] = []
326
- const pendingTasks: string[] = []
327
- let currentTask: string | null = null
328
-
329
- // Parse tasks with more detail
330
- const taskRegex = /- \[([ x])\]\s+\*\*T(\d+)\*\*[:\s]+(.+?)(?=\n|$)/g
331
- let match
332
- while ((match = taskRegex.exec(storyContent)) !== null) {
333
- const [, checked, taskId, taskName] = match
334
- const taskInfo = `T${taskId}: ${taskName.trim()}`
335
- if (checked === "x") {
336
- completedTasks.push(taskInfo)
337
- } else {
338
- if (!currentTask) currentTask = taskInfo
339
- pendingTasks.push(taskInfo)
340
- }
341
- }
342
-
343
- // Parse acceptance criteria
344
- const acceptanceCriteria: string[] = []
345
- const acSection = storyContent.match(/## Acceptance Criteria[\s\S]*?(?=##|$)/i)
346
- if (acSection) {
347
- const acRegex = /- \[([ x])\]\s+(.+?)(?=\n|$)/g
348
- while ((match = acRegex.exec(acSection[0])) !== null) {
349
- const [, checked, criteria] = match
350
- acceptanceCriteria.push(`${checked === "x" ? "✅" : "⬜"} ${criteria.trim()}`)
351
- }
352
- }
313
+ if (epicState?.nextStoryPath) {
314
+ storyPath = epicState.nextStoryPath
315
+ }
353
316
 
354
- return {
355
- path: storyPath,
356
- title: titleMatch?.[1] || "Unknown Story",
357
- status: statusMatch?.[1] || "unknown",
358
- currentTask,
359
- completedTasks,
360
- pendingTasks,
361
- acceptanceCriteria,
362
- fullContent: storyContent
363
- }
317
+ // Fallback: try sprint-status.yaml
318
+ if (!storyPath) {
319
+ try {
320
+ const sprintStatusPath = join(directory, "docs", "sprint-artifacts", "sprint-status.yaml")
321
+ const content = await readFile(sprintStatusPath, "utf-8")
322
+ const inProgressMatch = content.match(/status:\s*in-progress[\s\S]*?path:\s*["']?([^"'\n]+)["']?/i)
323
+ if (inProgressMatch) {
324
+ storyPath = inProgressMatch[1]
364
325
  }
326
+ } catch {
327
+ // No sprint-status.yaml
365
328
  }
366
329
  }
367
-
368
- // Fallback: try old sprint-status.yaml format
369
- const sprintStatusPath = join(directory, "docs", "sprint-artifacts", "sprint-status.yaml")
370
- const content = await readFile(sprintStatusPath, "utf-8")
371
-
372
- const inProgressMatch = content.match(/status:\s*in-progress[\s\S]*?path:\s*["']?([^"'\n]+)["']?/i)
373
- if (!inProgressMatch) return null
374
330
 
375
- const storyPath = inProgressMatch[1]
331
+ if (!storyPath) return null
332
+
333
+ // Parse story file
376
334
  const storyContent = await readFile(join(directory, storyPath), "utf-8")
377
-
378
335
  const titleMatch = storyContent.match(/^#\s+(.+)/m)
379
336
  const statusMatch = storyContent.match(/\*\*Status:\*\*\s*(\w+)/i)
380
-
337
+
381
338
  const completedTasks: string[] = []
382
339
  const pendingTasks: string[] = []
383
340
  let currentTask: string | null = null
384
-
385
- // Parse tasks with more detail
341
+
386
342
  const taskRegex = /- \[([ x])\]\s+\*\*T(\d+)\*\*[:\s]+(.+?)(?=\n|$)/g
387
343
  let match
388
344
  while ((match = taskRegex.exec(storyContent)) !== null) {
@@ -395,8 +351,7 @@ DO NOT skip this step. DO NOT ask user what to do. Just read these files first.`
395
351
  pendingTasks.push(taskInfo)
396
352
  }
397
353
  }
398
-
399
- // Parse acceptance criteria
354
+
400
355
  const acceptanceCriteria: string[] = []
401
356
  const acSection = storyContent.match(/## Acceptance Criteria[\s\S]*?(?=##|$)/i)
402
357
  if (acSection) {