@vibeflow-tools/cli 0.5.1 → 0.6.1

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 (109) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/README.md +199 -81
  3. package/dist/chunk-D6KVQU62.js +7 -0
  4. package/dist/{cli/chunk-QULSJOW5.js → chunk-NRMCK2HM.js} +4 -4
  5. package/dist/cli/chunk-D6KVQU62.js +7 -0
  6. package/dist/{chunk-QULSJOW5.js → cli/chunk-NRMCK2HM.js} +4 -4
  7. package/dist/cli/{files-H2UIFEPJ.js → files-GOVXPMB5.js} +1 -1
  8. package/dist/cli/{files-MIDXKOAF.js → files-TKEFFLPI.js} +1 -1
  9. package/dist/cli/index.js +88 -27952
  10. package/dist/client/kanban-browser.js +15 -15
  11. package/dist/client/kanban.css +1 -1
  12. package/dist/{files-H2UIFEPJ.js → files-GOVXPMB5.js} +1 -1
  13. package/dist/{files-MIDXKOAF.js → files-TKEFFLPI.js} +1 -1
  14. package/dist/index.js +88 -27952
  15. package/package.json +8 -3
  16. package/dist/chunk-252RNKHM.js +0 -2
  17. package/dist/chunk-43MUGU6Z.js +0 -67
  18. package/dist/chunk-4Y62J4KR.js +0 -438
  19. package/dist/chunk-6ABTC7IA.js +0 -482
  20. package/dist/chunk-7K2VHAWF.js +0 -569
  21. package/dist/chunk-BKTZSHJS.js +0 -2
  22. package/dist/chunk-BQLZVQ4E.js +0 -2
  23. package/dist/chunk-F57OXWVU.js +0 -33
  24. package/dist/chunk-I2OSZY66.js +0 -803
  25. package/dist/chunk-IZB3AHO6.js +0 -6
  26. package/dist/chunk-JKC6MUZ4.js +0 -558
  27. package/dist/chunk-KKBXVPTJ.js +0 -2
  28. package/dist/chunk-LK3IGDR6.js +0 -438
  29. package/dist/chunk-MKOKIWTN.js +0 -569
  30. package/dist/chunk-MW4OS3IK.js +0 -438
  31. package/dist/chunk-NRPOXSY6.js +0 -568
  32. package/dist/chunk-NUM3G22J.js +0 -569
  33. package/dist/chunk-O564QSMS.js +0 -569
  34. package/dist/chunk-OAGEPYIT.js +0 -535
  35. package/dist/chunk-PHBHAIHA.js +0 -33
  36. package/dist/chunk-PK737AKV.js +0 -560
  37. package/dist/chunk-TPDIOJDI.js +0 -7
  38. package/dist/chunk-TWAAPROG.js +0 -822
  39. package/dist/chunk-XF2CNPE4.js +0 -803
  40. package/dist/cli/chunk-252RNKHM.js +0 -2
  41. package/dist/cli/chunk-43MUGU6Z.js +0 -67
  42. package/dist/cli/chunk-4Y62J4KR.js +0 -438
  43. package/dist/cli/chunk-6ABTC7IA.js +0 -482
  44. package/dist/cli/chunk-7K2VHAWF.js +0 -569
  45. package/dist/cli/chunk-BKTZSHJS.js +0 -2
  46. package/dist/cli/chunk-BQLZVQ4E.js +0 -2
  47. package/dist/cli/chunk-F57OXWVU.js +0 -33
  48. package/dist/cli/chunk-I2OSZY66.js +0 -803
  49. package/dist/cli/chunk-IZB3AHO6.js +0 -6
  50. package/dist/cli/chunk-JKC6MUZ4.js +0 -558
  51. package/dist/cli/chunk-KKBXVPTJ.js +0 -2
  52. package/dist/cli/chunk-LK3IGDR6.js +0 -438
  53. package/dist/cli/chunk-MKOKIWTN.js +0 -569
  54. package/dist/cli/chunk-MW4OS3IK.js +0 -438
  55. package/dist/cli/chunk-NRPOXSY6.js +0 -568
  56. package/dist/cli/chunk-NUM3G22J.js +0 -569
  57. package/dist/cli/chunk-O564QSMS.js +0 -569
  58. package/dist/cli/chunk-OAGEPYIT.js +0 -535
  59. package/dist/cli/chunk-PHBHAIHA.js +0 -33
  60. package/dist/cli/chunk-PK737AKV.js +0 -560
  61. package/dist/cli/chunk-TPDIOJDI.js +0 -7
  62. package/dist/cli/chunk-TWAAPROG.js +0 -822
  63. package/dist/cli/chunk-XF2CNPE4.js +0 -803
  64. package/dist/cli/files-27OYPA7W.js +0 -20
  65. package/dist/cli/files-2TK74THO.js +0 -22
  66. package/dist/cli/files-3RDDXUOS.js +0 -2
  67. package/dist/cli/files-7275M2PW.js +0 -20
  68. package/dist/cli/files-D3YPV7QT.js +0 -20
  69. package/dist/cli/files-FER4UZ4X.js +0 -22
  70. package/dist/cli/files-H4FRDKJV.js +0 -22
  71. package/dist/cli/files-IJZVMROA.js +0 -22
  72. package/dist/cli/files-IX5QZQHC.js +0 -2
  73. package/dist/cli/files-JPVPKRMX.js +0 -2
  74. package/dist/cli/files-KH3UEFN7.js +0 -20
  75. package/dist/cli/files-LTDT5ZFT.js +0 -22
  76. package/dist/cli/files-O4WJLFMU.js +0 -2
  77. package/dist/cli/files-OYO6A6MZ.js +0 -22
  78. package/dist/cli/files-R6QHQBH4.js +0 -22
  79. package/dist/cli/files-UCALOYWZ.js +0 -22
  80. package/dist/cli/files-UWZP7P6B.js +0 -2
  81. package/dist/cli/files-VIDLQM7Y.js +0 -20
  82. package/dist/cli/files-X2RDLF3W.js +0 -22
  83. package/dist/cli/files-XVDNOAZB.js +0 -22
  84. package/dist/cli/workspace-NB6BACZA.js +0 -12
  85. package/dist/cli/workspace-X2NGGGTQ.js +0 -12
  86. package/dist/cli/workspace-X4QXECQQ.js +0 -12
  87. package/dist/files-27OYPA7W.js +0 -20
  88. package/dist/files-2TK74THO.js +0 -22
  89. package/dist/files-3RDDXUOS.js +0 -2
  90. package/dist/files-7275M2PW.js +0 -20
  91. package/dist/files-D3YPV7QT.js +0 -20
  92. package/dist/files-FER4UZ4X.js +0 -22
  93. package/dist/files-H4FRDKJV.js +0 -22
  94. package/dist/files-IJZVMROA.js +0 -22
  95. package/dist/files-IX5QZQHC.js +0 -2
  96. package/dist/files-JPVPKRMX.js +0 -2
  97. package/dist/files-KH3UEFN7.js +0 -20
  98. package/dist/files-LTDT5ZFT.js +0 -22
  99. package/dist/files-O4WJLFMU.js +0 -2
  100. package/dist/files-OYO6A6MZ.js +0 -22
  101. package/dist/files-R6QHQBH4.js +0 -22
  102. package/dist/files-UCALOYWZ.js +0 -22
  103. package/dist/files-UWZP7P6B.js +0 -2
  104. package/dist/files-VIDLQM7Y.js +0 -20
  105. package/dist/files-X2RDLF3W.js +0 -22
  106. package/dist/files-XVDNOAZB.js +0 -22
  107. package/dist/workspace-NB6BACZA.js +0 -12
  108. package/dist/workspace-X2NGGGTQ.js +0 -12
  109. package/dist/workspace-X4QXECQQ.js +0 -12
package/CHANGELOG.md CHANGED
@@ -1,5 +1,58 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 52d796e: Add current git branch name display in kanban header, reorder workflow settings toggles, and fix agent instruction step numbering for createBranch workflow. Also add 'editing' state to collaborative editing event types.
8
+ - 52d796e: Improve CLI README with comprehensive command documentation, browser overlay injection methods, prototype writing guide, API reference, and agent integration details.
9
+
10
+ ## 0.6.0
11
+
12
+ ### Minor Changes
13
+
14
+ - Add agent queue side panel with button in header
15
+ - Fix agent run: use positional message instead of invalid --task flag, add agent picker, list agents/models endpoints, align Run Agent button right, sync model/agent live updates
16
+ - Implement real agent execution: Run Agent button now spawns opencode with task context via server endpoint. Output streams via WebSocket to the UI. Replaced simulated agent runs with actual opencode process spawning.
17
+
18
+ ### Patch Changes
19
+
20
+ - Add agent session metadata display: capture tokens, cost, and duration from opencode JSON output and show in AgentTab footer.
21
+ - Add minimal agent badge to kanban task cards and detail panel.
22
+
23
+ - TaskCard footer now shows a purple "Agent" pill with Bot icon when `task.agent` is set.
24
+ - KanbanListView rows also display the agent badge inline with the title.
25
+ - TaskDetailsTab metadata section includes an "Agent" tile when present.
26
+ - All styles blend with existing badge sizing (font-size 10, compact padding, purple tint).
27
+
28
+ - Parse opencode JSON events into human-readable text in the agent streaming output.
29
+ - Auto-move task to in-progress status when agent run is started
30
+ - Auto-select default model in Agent tab so "Run Agent" works without user interaction.
31
+ - Add `experimentalAgents` feature flag to gate all agent-related UI features. When disabled (default), the agent tab, agent queue, agent status badges, "Run Agents" multi-select toolbar, and agent settings are hidden from the kanban UI. The flag can be toggled in Settings > Agent.
32
+ - Fix agent run: pass full task context, fix model picker dropdown clicks, and sync default model selection between UI and API request.
33
+ - Fix agent run: replace fake model IDs with real opencode models, add integration test with WebSocket event verification.
34
+ - Fix commit hash display in detail panel: show commit tile when commits array is present even if commit string is absent.
35
+ - Fix experimentalAgents flag to properly hide agent UI by default. Changed all gating conditions from `experimentalAgents !== false` (which evaluated to true when undefined) to `experimentalAgents === true`, ensuring agent features are hidden unless explicitly enabled.
36
+ - Fix model picker dropdown closing detail panel when selecting a model
37
+ - Two fixes for model pickers in the kanban UI:
38
+
39
+ 1. **CLI kanban now parses tRPC response correctly** — the `/trpc/models` endpoint returns `{ result: { data: { models: [...] } } }` but the CLI API client was expecting the inner shape directly. Now unwraps the tRPC envelope.
40
+
41
+ 2. **ModelPicker dropdown no longer clipped by modal** — replaced absolute positioning with a `createPortal` that renders the dropdown at `position: fixed` using measured button coordinates. The dropdown now expands upward above the button and escapes any parent overflow clipping.
42
+
43
+ - Fix sortKey not being accepted when creating tasks via POST /api/tasks, enabling multi-select drag-to-reorder to work correctly.
44
+ - Fix web tRPC models endpoint path: `/api/trpc/settings.models` not `/api/trpc/models`
45
+ - Move "Press Ctrl+C to stop" hint to the end of kanban startup output so it appears after the agent prompt block.
46
+ - Kanban web app now loads models dynamically from OpenCode CLI via tRPC `settings.models` endpoint
47
+ - Move agent action buttons from agent tab body to detail panel footer
48
+ - Fix multi-select drag to compute sort keys incrementally, preserving relative order of selected tasks.
49
+ - Add multi-select drag support: dragging a selected task in select mode moves all selected tasks together.
50
+ - Remove AgentQueueBar from kanban UI — the bottom queue bar is no longer shown.
51
+ - Settings modal Agent tab now uses the same searchable ModelPicker as the AgentTab task agent picker
52
+ - Share agent task formatting between CLI --get and server agent-run endpoint via new `renderTaskForAgent` function.
53
+ - Use default model from settings as initial selection in agent tab
54
+ - Use default model from settings in Agent tab when no model is explicitly chosen. Fixed state disconnect where "Run Agent" passed empty string instead of the displayed default model. CLI kanban now passes defaultModel to DetailPanel.
55
+
3
56
  ## 0.5.1
4
57
 
5
58
  ### Patch Changes
package/README.md CHANGED
@@ -1,145 +1,263 @@
1
- # vibeflow
1
+ # Vibeflow
2
2
 
3
- > **Feedback that becomes code.**
3
+ > **Tell your AI agent exactly what to fix — by clicking on it.**
4
4
 
5
- [![npm version](https://img.shields.io/npm/v/%40vibeflow-tools%2Fcli?color=blue)](https://www.npmjs.com/package/@vibeflow-tools/cli)
6
- [![License](https://img.shields.io/badge/license-Apache--2.0-green)](https://www.apache.org/licenses/LICENSE-2.0)
7
- [![Node.js](https://img.shields.io/badge/node-%3E%3D22-brightgreen)](https://nodejs.org)
8
-
9
- Annotate anything in the browser, hand structured context to your AI coding agent, ship. No Slack threads. No tickets nobody reads. No switching context.
5
+ Vibeflow eliminates the back-and-forth of describing UI bugs in words. Click any element on a page to create a task with its exact CSS selector, URL, and source location. Your agent gets precise, actionable context — no "the button in the top right" needed.
10
6
 
11
7
  ```bash
12
- npm install -g vibeflow
13
- npx vibeflow kanban
8
+ npm install -g @vibeflow-tools/cli
9
+ vibeflow kanban
14
10
  ```
15
11
 
16
- ## Website
12
+ ---
13
+
14
+ ## Why It Matters
15
+
16
+ AI agents write code fast, but **understanding what to change is slow**. Describing a UI issue in prose wastes tokens and produces wrong fixes.
17
17
 
18
- - Main website: https://www.vibeflow.tools/
19
- - Tutorials: https://www.vibeflow.tools/tutorials.html
18
+ Vibeflow turns visual feedback into structured tasks:
19
+
20
+ - **Click any element** → instant task with CSS selector, URL, and source file location
21
+ - **Track on a Kanban board** → see everything at a glance, drag between columns
22
+ - **Agents implement with context** → no guessing, no wrong elements, no wasted iterations
23
+
24
+ Perfect for small UI fixes, broken layouts, spacing issues, and anything where pointing is faster than explaining.
20
25
 
21
26
  ---
22
27
 
23
- ## The problem
28
+ ## Quick Start
24
29
 
25
- You review your AI agent's output in the browser. You spot issues. Then the hard part: re-explaining every little thing in plain text, hoping the agent understands where to look and what's wrong.
30
+ ```bash
31
+ # 1. Embed the overlay into your app (bookmarklet, script tag, or devtools)
32
+ # Visit /inject on your running server for ready-to-use snippets
26
33
 
27
- - **"Just sent you a Slack message about it"** — context-switching costs 23 minutes to recover. The fix takes 2 minutes.
28
- - **"Here's a screenshot, the thing on the left"** — screenshots without structure become detective work. Your agent needs selectors, not JPEGs.
29
- - **"I described it to the AI but it got confused"** — prose descriptions lose precision. Agents work best with structured, reproducible context.
34
+ # 2. Open the Kanban board
35
+ vibeflow kanban
30
36
 
31
- **Vibeflow eliminates the guessing loop.**
37
+ # 3. Click elements in your app to annotate, or create tasks on the board
32
38
 
33
- ---
39
+ # 4. Your agent picks the next task with full context executing following command
40
+ vibeflow tasks --next
34
41
 
35
- ## How it works
42
+ ```
36
43
 
37
- Three steps. Zero ceremony.
44
+ ---
38
45
 
39
- ### 1. Serve
46
+ ## Commands
40
47
 
41
- One command starts a local server that injects an annotation overlay into any HTML file or add overlay script to the live app.
48
+ | Command | Description |
49
+ |---------|-------------|
50
+ | `vibeflow kanban [dir]` | Start the server and open the live Kanban board in your browser |
51
+ | `vibeflow serve [target]` | Serve HTML files with live annotation overlay, or run API-only task server for existing apps |
52
+ | `vibeflow tasks` | List, filter, create, edit, and comment on tasks |
53
+ | `vibeflow telemetry` | Manage CLI usage telemetry (opt-out at any time) |
54
+
55
+ ### `vibeflow kanban [dir]`
42
56
 
43
57
  ```bash
44
- vibeflow serve ./my-project
58
+ vibeflow kanban # open Kanban board for current directory
59
+ vibeflow kanban ./my-project # open Kanban for a specific project
45
60
  ```
46
61
 
47
- ### 2. Annotate
62
+ The Kanban board provides a visual task tracker with drag-and-drop columns, agent status display, and file attachments. Create tasks directly on the board or import them from annotated prototypes.
48
63
 
49
- Open the browser. Click any element, write a quick note, set priority. Every annotation becomes a task stored as JSON in `.vibeflow/` versioned in git, visible in the Kanban board.
64
+ ### `vibeflow serve [target]`
50
65
 
51
66
  ```bash
52
- vibeflow kanban # open the Kanban board
67
+ vibeflow serve . # serve all HTML files in current directory
68
+ vibeflow serve dashboard.html # serve a single file
69
+ vibeflow serve -p 4000 . # custom port
70
+ vibeflow serve --no-open . # don't open browser automatically
71
+ vibeflow serve # API-only mode — connects to an existing hosted app
53
72
  ```
54
73
 
55
- ### 3. Hand to your agent
74
+ Serve HTML prototypes with the annotation overlay — click any element to create a task with its CSS selector, URL, and source location.
56
75
 
57
- Give your AI agent one prompt. It claims the next task, implements it, and marks it for review — all through the CLI.
76
+ ### `vibeflow tasks`
77
+
78
+ Full task management from the command line — designed to be agent-friendly.
58
79
 
59
80
  ```bash
60
- vibeflow tasks --next
81
+ # Pick the next task (auto-claims a todo task)
82
+ vibeflow tasks --next # picks highest-priority todo task
83
+ vibeflow tasks --next --type Bug # next bug task only
84
+
85
+ # List tasks
86
+ vibeflow tasks # all tasks (default: 20 most recent)
87
+ vibeflow tasks --limit 0 # show all tasks (no limit)
88
+ vibeflow tasks --json # machine-readable JSON output
89
+
90
+ # Filter
91
+ vibeflow tasks --status todo # by status
92
+ vibeflow tasks --type Bug # by type (Task, Bug, Feature, Enhancement, Research)
93
+ vibeflow tasks --user dev@example.com # by author email
94
+ vibeflow tasks --tag frontend --tag urgent # by tags (AND matching)
95
+
96
+ # Get full details of a single task
97
+ vibeflow tasks --get <id> # supports partial ID prefix
98
+
99
+ # Create a task
100
+ vibeflow tasks --add --title "Fix header" --description "Button overflows on mobile"
101
+
102
+ # Edit a task
103
+ vibeflow tasks --edit <id> --set-status in-progress
104
+ vibeflow tasks --edit <id> --title "Updated title" --description "More detail"
105
+
106
+ # Mark as review (requires implementation report)
107
+ vibeflow tasks --edit <id> --set-status review \
108
+ --commit-message "fix: header layout" \
109
+ --comment "Fixed the alignment issue by adjusting flex-wrap"
61
110
  ```
62
111
 
63
- > **The magic prompt for your agent:**
64
- > *"Get new tasks and implement them, once done check again for new ones:*
65
- > *`npx @vibeflow-tools/cli tasks --next`"*
112
+ **Task types:** Task · Bug · Feature · Enhancement · Research
113
+ **Task statuses:** backlog todo in-progress review done
114
+ **Priorities:** Critical · High · Medium · Low
66
115
 
67
- `--next` atomically claims the highest-priority todo task (sets it in-progress), preventing two agents from picking the same task. Run it again after completing each task to get the next one.
116
+ ### `vibeflow telemetry`
117
+
118
+ ```bash
119
+ vibeflow telemetry # show current status
120
+ vibeflow telemetry --disable # opt out of usage tracking
121
+ vibeflow telemetry --enable # opt back in
122
+ ```
123
+
124
+ No PII is ever collected. User identity is hashed.
68
125
 
69
126
  ---
70
127
 
71
- ## Commands
128
+ ## Browser Overlay
72
129
 
73
- ### Serving
130
+ The overlay is a Shadow DOM panel injected into any page — HTML prototypes or live apps:
74
131
 
75
- | Command | Description |
76
- |---------|-------------|
77
- | `vibeflow serve [target]` | Serve an HTML folder with the annotation overlay injected |
78
- | `vibeflow kanban [dir]` | Start the server and open the Kanban board in your browser |
132
+ - **Click-to-annotate** click any element to open a task form, pre-filled with CSS selector, URL, and source location
133
+ - **Task sidebar** — lists open tasks with status badges; click to jump to the annotated element
134
+ - **Task indicators** numbered markers on annotated elements
135
+ - **Real-time sync** over WebSocket with live file watching
136
+ - **Screenshot capture** — attach screenshots to tasks via the overlay
137
+ - **Dark theme** — polished dark UI, no configuration needed
138
+ - **Keyboard shortcut** — `Alt+A` to toggle annotation mode
139
+ - **CSP-safe injection** — bookmarklet bypasses `script-src` restrictions
79
140
 
80
- ### Tasks
141
+ ### Injection Methods
81
142
 
82
- | Command | Description |
83
- |---------|-------------|
84
- | `vibeflow tasks` | List all tasks |
85
- | `vibeflow tasks --next` | Claim the next todo task (sets in-progress, returns full task details) |
86
- | `vibeflow tasks --status todo` | Filter to open tasks |
87
- | `vibeflow tasks --type Bug` | Filter by type (Task, Bug, Feature, Enhancement, Research) |
88
- | `vibeflow tasks --get <id>` | Full task detail with comments, file attachments, and linked commits |
89
- | `vibeflow tasks --add --title "..." --description "..."` | Create a new task |
90
- | `vibeflow tasks --edit <id> --set-status review --commit-message "..." --comment "..."` | Mark task as review, auto-commit staged files, add report |
91
- | `vibeflow tasks --json` | Machine-readable JSON output |
143
+ The overlay can be injected into any page three ways:
92
144
 
93
- **Task statuses:** backlog todo in-progress → review → done
145
+ | Method | Best for | CSP-safe |
146
+ |--------|----------|----------|
147
+ | **Bookmarklet** (recommended) | Any page, including production apps | Yes |
148
+ | **Script tag** | Pages you control the HTML of | No |
149
+ | **DevTools console** | Quick one-off sessions | Yes |
150
+
151
+ Visit `/inject` on your running server for ready-to-use bookmarklets and snippets.
94
152
 
95
153
  ---
96
154
 
97
- ## Features
155
+ ## How It Works
98
156
 
99
- | Feature | Description |
100
- |---------|-------------|
101
- | **Local-first** | Runs entirely on your machine. Tasks in `.vibeflow/` — committed to git, readable by any tool |
102
- | **Agent-ready** | Works with GitHub Copilot, Claude, Cursor, Windsurf — any tool that accepts a prompt |
103
- | **Click-to-annotate** | Captures exact CSS selector, URL, and source location automatically |
104
- | **Kanban board** | Full task manager with backlog, in-progress, review, done — view in browser or drive from CLI |
105
- | **Screenshots** | Paste a screenshot onto any task, or let the tool capture it automatically |
106
- | **Keyboard shortcut** | `Alt+A` to toggle annotation mode |
107
- | **Error recording** | Captures recent console errors into bug reports |
108
- | **Offline** | Works 100% locally, no account needed |
157
+ ```
158
+ You browse your app → click to annotate → task created with context
159
+ ↑ ↓
160
+ browser reloads ← agent implements ← vibeflow tasks --next
161
+ ```
162
+
163
+ 1. **Overlay** embed the bookmarklet or script into your app, click any element to annotate
164
+ 2. **Kanban** open the board to see all tasks at a glance, create new ones directly
165
+ 3. **Tasks** `vibeflow tasks --next` picks the highest-priority task with full context for your agent
166
+ 4. **Iterate** agent implements, browser reloads, annotate again
109
167
 
110
168
  ---
111
169
 
112
- ## Quick Start
170
+ ## Writing Prototypes
171
+
172
+ Each HTML file is one screen. Use Tailwind CSS, Lucide icons, and Google Fonts via CDN — the annotation contract tells your LLM to use exactly these libraries.
173
+
174
+ **Rules:**
175
+ - One file per screen — name after the route (`login.html`, `dashboard.html`)
176
+ - Every meaningful element gets a `data-vibeflow-id` — kebab-case, globally unique
177
+ - Navigate between pages with relative links: `<a href="./page.html">`
178
+ - Repeat navigation on every page (no shared includes)
179
+
180
+ ```html
181
+ <!DOCTYPE html>
182
+ <html lang="en">
183
+ <head>
184
+ <meta charset="UTF-8">
185
+ <meta name="viewport" content="width=device-width, initial-scale=1">
186
+ <title>App — Dashboard</title>
187
+ <script src="https://cdn.tailwindcss.com"></script>
188
+ <script src="https://unpkg.com/lucide@latest/dist/umd/lucide.min.js"></script>
189
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
190
+ <style>body { font-family: 'Inter', sans-serif; }</style>
191
+ </head>
192
+ <body class="bg-gray-50 text-gray-900 min-h-screen">
193
+ <main data-vibeflow-id="main-content" class="max-w-4xl mx-auto px-6 py-8">
194
+ <h1 data-vibeflow-id="page-title" class="text-2xl font-semibold">Dashboard</h1>
195
+ </main>
196
+ <script>lucide.createIcons();</script>
197
+ </body>
198
+ </html>
199
+ ```
113
200
 
114
- ```bash
115
- # Open the Kanban board
116
- npx vibeflow kanban
201
+ ---
117
202
 
118
- # Tell your agent to implement all open tasks (--next workflow)
119
- npx vibeflow tasks --next
120
- ```
203
+ ## Agent Integration
204
+
205
+ Vibeflow tasks are formatted for AI agents with full context:
206
+
207
+ - **CSS selectors** — exact element targeting, no guesswork
208
+ - **Source locations** — file, line, and column where the element is defined
209
+ - **Screenshots** — visual context attached to tasks
210
+ - **Comments** — threaded discussions on each task
211
+ - **File attachments** — research reports, specs, and reference materials
212
+ - **Git commits** — changes linked back to tasks via `[proto:task-id]` in commit messages
213
+
214
+ Agents can also run directly from the Kanban board via `POST /api/agent/run`, which spawns [opencode](https://github.com/opencode-ai/opencode) with full task context.
121
215
 
122
216
  ---
123
217
 
124
- ## Agent workflow
218
+ ## API
219
+
220
+ A REST API and tRPC router are available at `http://localhost:3700` for integrations and the browser overlay. Key endpoints:
125
221
 
126
- When running `vibeflow tasks`, the CLI prints agent instructions automatically. Key rules:
222
+ - `/kanban` live Kanban board
223
+ - `GET/POST /api/tasks` — list and create tasks
224
+ - `GET/PATCH/DELETE /api/tasks/:id` — manage individual tasks
225
+ - `GET/POST /api/tasks/:id/comments` — task comments
226
+ - `GET/POST/DELETE /api/tasks/:id/files` — file attachments
227
+ - `POST /api/agent/run` — spawn an AI agent for a task
228
+ - `/inject` — overlay injection helper page
127
229
 
128
- 1. **Claim first** set status to `in-progress` before reading or planning
129
- 2. **Never set `done`** — use `review`; only humans mark tasks done
130
- 3. **Never edit `.vibeflow/` files directly** — use CLI commands only
131
- 4. **Research tasks** — attach a `.md` report before marking review; never generate code
132
- 5. **Bug tasks** — include error logs and stack traces in commit comments
230
+ See [src/server/server.ts](https://github.com/zorcec/vibeflow/blob/main/packages/cli/src/server/server.ts) for the full API.
133
231
 
134
232
  ---
135
233
 
136
- ## Requirements
234
+ ## Installation
137
235
 
138
- - **Node.js 22+** — install from [nodejs.org](https://nodejs.org)
139
- - **React in dev mode (recommended)** — for component names, source files, and line numbers. Run in `NODE_ENV=development` (the default for `next dev`).
236
+ ```bash
237
+ npm install -g @vibeflow-tools/cli
238
+ ```
239
+
240
+ Or run without installing:
241
+
242
+ ```bash
243
+ npx @vibeflow-tools/cli kanban
244
+ ```
245
+
246
+ **Requirements:** Node.js >= 22
247
+
248
+ ---
249
+
250
+ ## Contributing
251
+
252
+ ```bash
253
+ pnpm install # install dependencies
254
+ pnpm build:cli # build CLI
255
+ pnpm test # unit tests
256
+ pnpm test:e2e # end-to-end tests
257
+ ```
140
258
 
141
259
  ---
142
260
 
143
261
  ## License
144
262
 
145
- [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0)
263
+ [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0) — see [NOTICE](https://github.com/zorcec/vibeflow/blob/main/NOTICE) for third-party attributions.
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import{readdirSync as W,writeFileSync as J,readFileSync as V,unlinkSync as b,statSync as v,mkdirSync as q,existsSync as c}from"fs";import{join as m,basename as R}from"path";var g=".vibeflow",C="tasks",k="tasks/files",A="tasks/screenshots",Z="config.json";import{existsSync as f,readFileSync as O,writeFileSync as _,mkdirSync as p,readdirSync as h,unlinkSync as D,renameSync as F}from"fs";import{join as u,extname as I}from"path";import{randomBytes as z}from"crypto";var j=["backlog","todo","in-progress","review","done"];function K(){return z(15).toString("hex")}function S(e){return u(e,g,C)}function M(e){let i=u(e,g),n=u(i,"files"),s=u(i,k),r=u(i,"screenshots"),t=u(i,A);if(f(n)){p(s,{recursive:!0});for(let o of h(n)){let a=u(n,o),l=u(s,o);if(!f(l))try{F(a,l)}catch{}}}if(f(r)){p(t,{recursive:!0});for(let o of h(r)){let a=u(r,o),l=u(t,o);if(!f(l))try{F(a,l)}catch{}}}}function re(e){M(e),p(S(e),{recursive:!0}),p(u(e,g,A),{recursive:!0})}function w(e){return e.slice(0,10)}function U(e,i,n){let s=S(e);return n?u(s,w(n),`${i}.json`):u(s,`${i}.json`)}function T(e,i){let n=S(e);if(!f(n))return null;for(let s of h(n,{withFileTypes:!0}))if(s.isDirectory()){let r=u(n,s.name,`${i}.json`);if(f(r))return r}else if(s.name===`${i}.json`)return u(n,s.name);return null}function H(e){let i=(()=>{if(typeof e.type!="string")return;let n=e.type.trim();if(!(!n||n==="[object Object]"))return n})();return{id:String(e.id??""),title:String(e.title??"Untitled"),description:String(e.description??""),status:j.includes(e.status)?e.status:"todo",url:e.url?String(e.url):void 0,selector:(()=>{let n=String(e.selector??"/");return e.file&&!e.cssSelector&&n.startsWith(String(e.file))?e.url?String(e.url):"/":n})(),cssSelector:e.cssSelector&&String(e.cssSelector)!==String(e.selector??"/")?String(e.cssSelector):void 0,file:e.file?String(e.file):void 0,line:e.line!=null?Number(e.line):void 0,col:e.col!=null?Number(e.col):void 0,component:e.component?String(e.component):void 0,type:i,priority:e.priority?String(e.priority):void 0,...e.reportBack===!0&&{reportBack:!0},agent:e.agent?String(e.agent):void 0,model:e.model?String(e.model):void 0,author:e.author?String(e.author):void 0,commits:Array.isArray(e.commits)?e.commits.map(n=>({sha:String(n.sha??""),message:String(n.message??""),timestamp:String(n.timestamp??new Date().toISOString())})):void 0,created:String(e.created??new Date().toISOString()),updated:e.updated?String(e.updated):void 0,comments:Array.isArray(e.comments)?e.comments.map(n=>({...n,text:n.text??n.content??""})):[],files:Array.isArray(e.files)?e.files.map(n=>typeof n=="string"?{name:n,addedAt:new Date().toISOString()}:{name:String(n.name??""),addedAt:String(n.addedAt??new Date().toISOString()),linkedPath:n.linkedPath?String(n.linkedPath):void 0,mimeType:n.mimeType?String(n.mimeType):void 0}).filter(n=>n.name):[],screenshot:e.screenshot?String(e.screenshot):void 0,annotatedElementText:e.annotatedElementText?String(e.annotatedElementText):void 0,tags:Array.isArray(e.tags)?e.tags.filter(n=>typeof n=="string"&&n.length>0):void 0,sortKey:e.sortKey?String(e.sortKey):void 0}}function E(e,i){let n=u(S(e),w(i.created));p(n,{recursive:!0});let s=u(n,`${i.id}.json`),r=s+".tmp";_(r,JSON.stringify(i,null,2),"utf-8"),F(r,s)}function oe(e,i){let n=(()=>{let r=(i.priority??"").trim().toLowerCase();return r==="critical"?"Critical":r==="high"?"High":r==="low"?"Low":"Medium"})(),s={...i,priority:n,id:K(),created:new Date().toISOString(),comments:[],files:[]};return E(e,s),s}function y(e){try{let i=O(e,"utf-8");if(e.endsWith(".json")){let n=JSON.parse(i);return!n||typeof n!="object"||!("id"in n)?null:H(n)}return null}catch{return null}}function L(e){let i=S(e);if(!f(i))return[];let n=[];for(let s of h(i,{withFileTypes:!0}))if(s.isDirectory()){let r=u(i,s.name);for(let t of h(r))if(I(t)===".json"){let o=u(r,t),a=y(o);a&&n.push({task:a,filePath:o})}}else if(I(s.name)===".json"){let r=u(i,s.name),t=y(r);t&&n.push({task:t,filePath:r})}return n}function ae(e){return L(e).map(({task:i})=>i)}function ue(e){return L(e).map(({task:i,filePath:n})=>({...i,filePath:n}))}function N(e,i,n){let s=T(e,i),r=s?y(s):null;if(!r)return null;let t={...r,...n,updated:new Date().toISOString()};if(E(e,t),s&&s!==U(e,i,t.created))try{D(s)}catch{}return t}function le(e,i){let n=T(e,i);return n?(D(n),!0):!1}function ce(e,i,n){return{id:e.id,status:e.status,title:e.title,description:e.description,...e.url&&{url:e.url},selector:e.selector,...e.file&&{file:e.file},...e.line!=null&&{line:e.line},...e.col!=null&&{col:e.col},...e.component&&{component:e.component},...e.type&&{type:e.type},...e.priority&&{priority:e.priority},...i&&i.length>0&&{structuredComments:i},...n&&n.length>0&&{linkedFiles:n},...e.reportBack&&{reportBack:!0},created:e.created}}function me(e,i,n,s,r){let t=[];if(t.push(`[${e.status}] ${e.title}`),t.push(` id: ${e.id}`),t.push(` file: ${i}`),e.file&&t.push(` source: ${e.file}${e.line!=null?`:${e.line}`:""}${e.col!=null?`:${e.col}`:""}`),e.component&&t.push(` component: ${e.component}`),t.push(` selector: ${e.selector??"/"}`),e.cssSelector&&t.push(` css: ${e.cssSelector}`),e.url&&t.push(` url: ${e.url}`),e.commits&&e.commits.length>0)if(e.commits.length===1)t.push(` commit: ${e.commits[0].sha}`);else{t.push(` commits (${e.commits.length}):`);for(let o of e.commits)t.push(` ${o.sha.slice(0,8)} ${o.timestamp} ${o.message.slice(0,60)}`)}if(t.push(` created: ${e.created}`),e.type&&t.push(` type: ${e.type}`),e.priority&&t.push(` priority: ${e.priority}`),e.author&&t.push(` author: ${e.author}`),e.description){t.push(" description:");for(let o of e.description.split(`
3
+ `))t.push(` ${o}`)}if(e.annotatedElementText&&t.push(` element text: ${e.annotatedElementText}`),n.length>0){t.push(` comments (${n.length}):`);for(let o of n){let a=o.updatedAt?` (edited ${o.updatedAt})`:"";t.push(` [${o.author??"user"}] ${o.createdAt}${a}`);for(let l of o.text.split(`
4
+ `))t.push(` ${l}`)}}if(s.length>0){t.push(` linked files (${s.length}):`);for(let o of s){t.push(` - ${o.name} ${o.url}`);let a=o.linkedPath??u(r,".vibeflow","files",e.id,o.name);if(/\.(md|txt)$/i.test(o.name)&&o.size<1e5&&f(a))try{let l=O(a,"utf-8");t.push(" \u250C\u2500\u2500 content \u2500\u2500");for(let B of l.split(`
5
+ `))t.push(` \u2502 ${B}`);t.push(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}catch{}}}return t.join(`
6
+ `)}function fe(e){let{autoCommit:i,autoPush:n,autoComment:s,createBranch:r}=e,t=[];if(t.push("Agent instructions (concise):"),t.push(" Discover: vibeflow tasks --status todo | vibeflow tasks --type Research | vibeflow tasks --user <email> | vibeflow tasks --tag <tag>"),t.push(" Details: vibeflow tasks --get <id> (full task info with comments and files)"),t.push(' Create: vibeflow tasks --add --title "..." --description "..."'),t.push(""),t.push(" Workflow:"),r?(t.push(" \u26A0 Create a branch FIRST, before any implementation:"),t.push(" 1. git checkout -b <short-name> (e.g. fix/annotation-errors, feat/eye-toggle, chore/cleanup-extension)"),t.push(" Branch name rules: lowercase, kebab-case, 2-5 words, prefix fix/feat/chore/docs."),t.push(" Describe the WORK done (not dates). Bad: agent/2026-04-16. Good: fix/bug-errors-visibility."),t.push(" 2. vibeflow tasks --edit <id> --set-status in-progress \u2190 CLAIM TASK"),t.push(" 3. <implement the change>")):(t.push(" \u26A0 IMMEDIATELY set in-progress BEFORE any implementation work:"),t.push(" 1. vibeflow tasks --edit <id> --set-status in-progress \u2190 DO THIS FIRST"),t.push(" 2. <implement the change>")),i){t.push(r?" 4. git add <files> (stage your changes first)":" 3. git add <files> (stage your changes first)");let o=["--set-status review"];i&&o.push('--commit-message "<one-line summary>"'),s&&o.push('--comment "<report>"'),t.push(` ${r?"5":"4"}. vibeflow tasks --edit <id> ${o.join(" ")}`),t.push(" CLI will commit staged changes and link the commit SHA automatically.")}else{t.push(r?' 4. git add <files> && vibeflow tasks --commit --task <id> --message "<one-line summary>"':' 3. git add <files> && vibeflow tasks --commit --task <id> --message "<one-line summary>"');let o=["--set-status review"];s&&o.push('--comment "<report>"'),t.push(` ${r?"5":"4"}. vibeflow tasks --edit <id> ${o.join(" ")}`)}return s&&(t.push(""),t.push(" Comment format (--comment):"),t.push(" \xB7 Plain text for concise one-liners."),t.push(" \xB7 Markdown for multi-section reports. Use **bold**, bullet lists, code fences."),t.push(" \xB7 Must cover: what changed, why, key decisions, anything future agents should know."),t.push(" \xB7 For long reports, attach a .md file and reference it in the comment.")),t.push(""),i&&t.push(" [setting] Auto-commit ON: provide --commit-message when setting status to review; CLI commits."),n&&t.push(" [setting] Auto-push ON: CLI pushes after the commit automatically."),s&&t.push(" [setting] Auto-comment ON: --comment is required when setting status to review."),r&&t.push(" [setting] Create branch ON: all work goes on a dedicated branch created before implementation."),e.hasResearchTasks&&(t.push(" Research tasks: NEVER generate code \u2014 research only."),t.push(" Attach a .md report before marking Research tasks as review."),t.push(" CLI ENFORCES: cannot mark Research as review without an attached .md report."),t.push(" Use --report-file <path> to upload your .md report when marking as review:"),t.push(' vibeflow tasks --edit <id> --set-status review --report-file ./report.md --comment "..."'),t.push(" The file is uploaded to the task and deleted from the local filesystem automatically.")),e.hasBugTasks&&(t.push(" Bug tasks: Include error logs / stack traces in the commit comment."),t.push(" Describe: the symptom, the console error, what triggered it, and how it was fixed.")),t.push(" CRITICAL: NEVER edit .vibeflow/ task files directly."),t.push(" All task operations (status, comments, commits) must go through CLI commands."),t.push(" CRITICAL: Set in-progress BEFORE reading/planning. Other agents may pick the same task."),t.push(" The in-progress transition signals ownership. Skip it and another agent may duplicate your work."),t.push(" Sequence: discover tasks \u2192 pick one \u2192 set in-progress \u2192 THEN read details and implement."),t.push(' CRITICAL: NEVER set a task status to "done".'),t.push(' When your implementation is complete, set the status to "review" \u2014 not "done".'),t.push(" Only humans can mark tasks as done after reviewing the work."),t.push(" The CLI will warn you and still allow the change \u2014 but agents must not use it."),t.push(""),t.join(`
7
+ `)}var P=".linked.json";function d(e,i){return m(e,g,k,i)}function G(e,i){q(d(e,i),{recursive:!0})}function Y(e,i){let n=m(d(e,i),P);if(!c(n))return[];try{return JSON.parse(V(n,"utf-8"))}catch{return[]}}function Q(e,i){let n=T(e,i),s=n?y(n):null;return!s?.files||s.files.length===0?[]:s.files}function $(e,i,n){N(e,i,{files:n})}function x(e,i){let n=Q(e,i),s=m(d(e,i),P);if(!c(s))return n;let r=Y(e,i);if(r.length===0){try{b(s)}catch{}return n}let t=n.slice(),o=!1;for(let a of r)t.find(l=>l.linkedPath===a.path||l.name===a.name&&l.linkedPath)||(t.push({name:a.name,linkedPath:a.path,addedAt:new Date().toISOString()}),o=!0);o&&$(e,i,t);try{b(s)}catch{}return t}function X(e,i){let n=d(e,i),s=x(e,i),r=new Map;for(let t of s){if(t.linkedPath&&c(t.linkedPath)){let a=v(t.linkedPath);r.set(t.name,{name:t.name,size:a.size,url:`/api/tasks/${i}/files/${encodeURIComponent(t.name)}`,linkedPath:t.linkedPath,createdAt:a.mtime.toISOString()});continue}let o=m(n,t.name);if(c(o)){let a=v(o);r.set(t.name,{name:t.name,size:a.size,url:`/api/tasks/${i}/files/${encodeURIComponent(t.name)}`,createdAt:a.mtime.toISOString()})}}if(c(n))for(let t of W(n,{withFileTypes:!0})){if(!t.isFile()||t.name===P||r.has(t.name))continue;let o=m(n,t.name),a=v(o);r.set(t.name,{name:t.name,size:a.size,url:`/api/tasks/${i}/files/${encodeURIComponent(t.name)}`,createdAt:a.mtime.toISOString()})}return Array.from(r.values())}function ke(e,i,n,s){let r=R(n);G(e,i),J(m(d(e,i),r),s);let t=x(e,i);return t.find(o=>o.name===r&&!o.linkedPath)||(t.push({name:r,addedAt:new Date().toISOString()}),$(e,i,t)),{name:r,size:s.length,url:`/api/tasks/${i}/files/${encodeURIComponent(r)}`}}function Te(e,i,n){let s=R(n),r=x(e,i),t=r.findIndex(a=>a.name===s);if(t!==-1){let[a]=r.splice(t,1);if($(e,i,r),a&&!a.linkedPath){let l=m(d(e,i),s);c(l)&&b(l)}return!0}let o=m(d(e,i),s);return c(o)?(b(o),!0):!1}function be(e,i,n){let s=R(n),r=x(e,i).find(o=>o.name===s&&o.linkedPath);if(r?.linkedPath&&c(r.linkedPath))return r.linkedPath;let t=m(d(e,i),s);return c(t)?t:null}function xe(e,i){return X(e,i).length}export{g as a,C as b,A as c,Z as d,K as e,re as f,U as g,T as h,oe as i,y as j,ae as k,ue as l,N as m,le as n,ce as o,me as p,fe as q,d as r,G as s,X as t,ke as u,Te as v,be as w,xe as x};
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import{readdirSync as M,writeFileSync as J,readFileSync as K,unlinkSync as b,statSync as F,mkdirSync as q,existsSync as c}from"fs";import{join as m,basename as v}from"path";var g=".vibeflow",$="tasks",S="tasks/files",R="tasks/screenshots",Z="config.json";import{existsSync as f,readFileSync as O,writeFileSync as _,mkdirSync as p,readdirSync as h,unlinkSync as E,renameSync as A}from"fs";import{join as u,extname as I}from"path";import{randomBytes as z}from"crypto";var V=["backlog","todo","in-progress","review","done"];function W(){return z(15).toString("hex")}function k(e){return u(e,g,$)}function j(e){let s=u(e,g),n=u(s,"files"),i=u(s,S),o=u(s,"screenshots"),t=u(s,R);if(f(n)){p(i,{recursive:!0});for(let r of h(n)){let a=u(n,r),l=u(i,r);if(!f(l))try{A(a,l)}catch{}}}if(f(o)){p(t,{recursive:!0});for(let r of h(o)){let a=u(o,r),l=u(t,r);if(!f(l))try{A(a,l)}catch{}}}}function re(e){j(e),p(k(e),{recursive:!0}),p(u(e,g,R),{recursive:!0})}function D(e){return e.slice(0,10)}function U(e,s,n){let i=k(e);return n?u(i,D(n),`${s}.json`):u(i,`${s}.json`)}function T(e,s){let n=k(e);if(!f(n))return null;for(let i of h(n,{withFileTypes:!0}))if(i.isDirectory()){let o=u(n,i.name,`${s}.json`);if(f(o))return o}else if(i.name===`${s}.json`)return u(n,i.name);return null}function H(e){let s=(()=>{if(typeof e.type!="string")return;let n=e.type.trim();if(!(!n||n==="[object Object]"))return n})();return{id:String(e.id??""),title:String(e.title??"Untitled"),description:String(e.description??""),status:V.includes(e.status)?e.status:"todo",url:e.url?String(e.url):void 0,selector:(()=>{let n=String(e.selector??"/");return e.file&&!e.cssSelector&&n.startsWith(String(e.file))?e.url?String(e.url):"/":n})(),cssSelector:e.cssSelector&&String(e.cssSelector)!==String(e.selector??"/")?String(e.cssSelector):void 0,file:e.file?String(e.file):void 0,line:e.line!=null?Number(e.line):void 0,col:e.col!=null?Number(e.col):void 0,component:e.component?String(e.component):void 0,type:s,priority:e.priority?String(e.priority):void 0,...e.reportBack===!0&&{reportBack:!0},agent:e.agent?String(e.agent):void 0,model:e.model?String(e.model):void 0,author:e.author?String(e.author):void 0,commits:Array.isArray(e.commits)?e.commits.map(n=>({sha:String(n.sha??""),message:String(n.message??""),timestamp:String(n.timestamp??new Date().toISOString())})):void 0,created:String(e.created??new Date().toISOString()),updated:e.updated?String(e.updated):void 0,comments:Array.isArray(e.comments)?e.comments.map(n=>({...n,text:n.text??n.content??""})):[],files:Array.isArray(e.files)?e.files.map(n=>typeof n=="string"?{name:n,addedAt:new Date().toISOString()}:{name:String(n.name??""),addedAt:String(n.addedAt??new Date().toISOString()),linkedPath:n.linkedPath?String(n.linkedPath):void 0,mimeType:n.mimeType?String(n.mimeType):void 0}).filter(n=>n.name):[],screenshot:e.screenshot?String(e.screenshot):void 0,annotatedElementText:e.annotatedElementText?String(e.annotatedElementText):void 0,tags:Array.isArray(e.tags)?e.tags.filter(n=>typeof n=="string"&&n.length>0):void 0}}function w(e,s){let n=u(k(e),D(s.created));p(n,{recursive:!0});let i=u(n,`${s.id}.json`),o=i+".tmp";_(o,JSON.stringify(s,null,2),"utf-8"),A(o,i)}function oe(e,s){let n=(()=>{let o=(s.priority??"").trim().toLowerCase();return o==="critical"?"Critical":o==="high"?"High":o==="low"?"Low":"Medium"})(),i={...s,priority:n,id:W(),created:new Date().toISOString(),comments:[],files:[]};return w(e,i),i}function y(e){try{let s=O(e,"utf-8");if(e.endsWith(".json")){let n=JSON.parse(s);return!n||typeof n!="object"||!("id"in n)?null:H(n)}return null}catch{return null}}function L(e){let s=k(e);if(!f(s))return[];let n=[];for(let i of h(s,{withFileTypes:!0}))if(i.isDirectory()){let o=u(s,i.name);for(let t of h(o))if(I(t)===".json"){let r=u(o,t),a=y(r);a&&n.push({task:a,filePath:r})}}else if(I(i.name)===".json"){let o=u(s,i.name),t=y(o);t&&n.push({task:t,filePath:o})}return n}function ae(e){return L(e).map(({task:s})=>s)}function ue(e){return L(e).map(({task:s,filePath:n})=>({...s,filePath:n}))}function N(e,s,n){let i=T(e,s),o=i?y(i):null;if(!o)return null;let t={...o,...n,updated:new Date().toISOString()};if(w(e,t),i&&i!==U(e,s,t.created))try{E(i)}catch{}return t}function le(e,s){let n=T(e,s);return n?(E(n),!0):!1}function ce(e,s,n){return{id:e.id,status:e.status,title:e.title,description:e.description,...e.url&&{url:e.url},selector:e.selector,...e.file&&{file:e.file},...e.line!=null&&{line:e.line},...e.col!=null&&{col:e.col},...e.component&&{component:e.component},...e.type&&{type:e.type},...e.priority&&{priority:e.priority},...s&&s.length>0&&{structuredComments:s},...n&&n.length>0&&{linkedFiles:n},...e.reportBack&&{reportBack:!0},created:e.created}}function me(e,s,n,i,o){let t=[];if(t.push(`[${e.status}] ${e.title}`),t.push(` id: ${e.id}`),t.push(` file: ${s}`),e.file&&t.push(` source: ${e.file}${e.line!=null?`:${e.line}`:""}${e.col!=null?`:${e.col}`:""}`),e.component&&t.push(` component: ${e.component}`),t.push(` selector: ${e.selector??"/"}`),e.cssSelector&&t.push(` css: ${e.cssSelector}`),e.url&&t.push(` url: ${e.url}`),e.commits&&e.commits.length>0)if(e.commits.length===1)t.push(` commit: ${e.commits[0].sha}`);else{t.push(` commits (${e.commits.length}):`);for(let r of e.commits)t.push(` ${r.sha.slice(0,8)} ${r.timestamp} ${r.message.slice(0,60)}`)}if(t.push(` created: ${e.created}`),e.type&&t.push(` type: ${e.type}`),e.priority&&t.push(` priority: ${e.priority}`),e.author&&t.push(` author: ${e.author}`),e.description){t.push(" description:");for(let r of e.description.split(`
2
+ import{readdirSync as W,writeFileSync as J,readFileSync as V,unlinkSync as x,statSync as v,mkdirSync as q,existsSync as c}from"fs";import{join as m,basename as P}from"path";var g=".vibeflow",C="tasks",k="tasks/files",A="tasks/screenshots",Z="config.json";import{existsSync as f,readFileSync as O,writeFileSync as _,mkdirSync as p,readdirSync as h,unlinkSync as D,renameSync as F}from"fs";import{join as u,extname as I}from"path";import{randomBytes as z}from"crypto";var j=["backlog","todo","in-progress","review","done"];function H(){return z(15).toString("hex")}function S(e){return u(e,g,C)}function K(e){let i=u(e,g),n=u(i,"files"),s=u(i,k),o=u(i,"screenshots"),t=u(i,A);if(f(n)){p(s,{recursive:!0});for(let r of h(n)){let a=u(n,r),l=u(s,r);if(!f(l))try{F(a,l)}catch{}}}if(f(o)){p(t,{recursive:!0});for(let r of h(o)){let a=u(o,r),l=u(t,r);if(!f(l))try{F(a,l)}catch{}}}}function re(e){K(e),p(S(e),{recursive:!0}),p(u(e,g,A),{recursive:!0})}function E(e){return e.slice(0,10)}function U(e,i,n){let s=S(e);return n?u(s,E(n),`${i}.json`):u(s,`${i}.json`)}function T(e,i){let n=S(e);if(!f(n))return null;for(let s of h(n,{withFileTypes:!0}))if(s.isDirectory()){let o=u(n,s.name,`${i}.json`);if(f(o))return o}else if(s.name===`${i}.json`)return u(n,s.name);return null}function M(e){let i=(()=>{if(typeof e.type!="string")return;let n=e.type.trim();if(!(!n||n==="[object Object]"))return n})();return{id:String(e.id??""),title:String(e.title??"Untitled"),description:String(e.description??""),status:j.includes(e.status)?e.status:"todo",url:e.url?String(e.url):void 0,selector:(()=>{let n=String(e.selector??"/");return e.file&&!e.cssSelector&&n.startsWith(String(e.file))?e.url?String(e.url):"/":n})(),cssSelector:e.cssSelector&&String(e.cssSelector)!==String(e.selector??"/")?String(e.cssSelector):void 0,file:e.file?String(e.file):void 0,line:e.line!=null?Number(e.line):void 0,col:e.col!=null?Number(e.col):void 0,component:e.component?String(e.component):void 0,type:i,priority:e.priority?String(e.priority):void 0,...e.reportBack===!0&&{reportBack:!0},agent:e.agent?String(e.agent):void 0,model:e.model?String(e.model):void 0,author:e.author?String(e.author):void 0,commits:Array.isArray(e.commits)?e.commits.map(n=>({sha:String(n.sha??""),message:String(n.message??""),timestamp:String(n.timestamp??new Date().toISOString())})):void 0,created:String(e.created??new Date().toISOString()),updated:e.updated?String(e.updated):void 0,comments:Array.isArray(e.comments)?e.comments.map(n=>({...n,text:n.text??n.content??""})):[],files:Array.isArray(e.files)?e.files.map(n=>typeof n=="string"?{name:n,addedAt:new Date().toISOString()}:{name:String(n.name??""),addedAt:String(n.addedAt??new Date().toISOString()),linkedPath:n.linkedPath?String(n.linkedPath):void 0,mimeType:n.mimeType?String(n.mimeType):void 0}).filter(n=>n.name):[],screenshot:e.screenshot?String(e.screenshot):void 0,annotatedElementText:e.annotatedElementText?String(e.annotatedElementText):void 0,tags:Array.isArray(e.tags)?e.tags.filter(n=>typeof n=="string"&&n.length>0):void 0,sortKey:e.sortKey?String(e.sortKey):void 0}}function w(e,i){let n=u(S(e),E(i.created));p(n,{recursive:!0});let s=u(n,`${i.id}.json`),o=s+".tmp";_(o,JSON.stringify(i,null,2),"utf-8"),F(o,s)}function oe(e,i){let n=(()=>{let o=(i.priority??"").trim().toLowerCase();return o==="critical"?"Critical":o==="high"?"High":o==="low"?"Low":"Medium"})(),s={...i,priority:n,id:H(),created:new Date().toISOString(),comments:[],files:[]};return w(e,s),s}function y(e){try{let i=O(e,"utf-8");if(e.endsWith(".json")){let n=JSON.parse(i);return!n||typeof n!="object"||!("id"in n)?null:M(n)}return null}catch{return null}}function L(e){let i=S(e);if(!f(i))return[];let n=[];for(let s of h(i,{withFileTypes:!0}))if(s.isDirectory()){let o=u(i,s.name);for(let t of h(o))if(I(t)===".json"){let r=u(o,t),a=y(r);a&&n.push({task:a,filePath:r})}}else if(I(s.name)===".json"){let o=u(i,s.name),t=y(o);t&&n.push({task:t,filePath:o})}return n}function ae(e){return L(e).map(({task:i})=>i)}function ue(e){return L(e).map(({task:i,filePath:n})=>({...i,filePath:n}))}function N(e,i,n){let s=T(e,i),o=s?y(s):null;if(!o)return null;let t={...o,...n,updated:new Date().toISOString()};if(w(e,t),s&&s!==U(e,i,t.created))try{D(s)}catch{}return t}function le(e,i){let n=T(e,i);return n?(D(n),!0):!1}function ce(e,i,n){return{id:e.id,status:e.status,title:e.title,description:e.description,...e.url&&{url:e.url},selector:e.selector,...e.file&&{file:e.file},...e.line!=null&&{line:e.line},...e.col!=null&&{col:e.col},...e.component&&{component:e.component},...e.type&&{type:e.type},...e.priority&&{priority:e.priority},...i&&i.length>0&&{structuredComments:i},...n&&n.length>0&&{linkedFiles:n},...e.reportBack&&{reportBack:!0},created:e.created}}function me(e,i,n,s,o){let t=[];if(t.push(`[${e.status}] ${e.title}`),t.push(` id: ${e.id}`),t.push(` file: ${i}`),e.file&&t.push(` source: ${e.file}${e.line!=null?`:${e.line}`:""}${e.col!=null?`:${e.col}`:""}`),e.component&&t.push(` component: ${e.component}`),t.push(` selector: ${e.selector??"/"}`),e.cssSelector&&t.push(` css: ${e.cssSelector}`),e.url&&t.push(` url: ${e.url}`),e.commits&&e.commits.length>0)if(e.commits.length===1)t.push(` commit: ${e.commits[0].sha}`);else{t.push(` commits (${e.commits.length}):`);for(let r of e.commits)t.push(` ${r.sha.slice(0,8)} ${r.timestamp} ${r.message.slice(0,60)}`)}if(t.push(` created: ${e.created}`),e.type&&t.push(` type: ${e.type}`),e.priority&&t.push(` priority: ${e.priority}`),e.author&&t.push(` author: ${e.author}`),e.description){t.push(" description:");for(let r of e.description.split(`
3
3
  `))t.push(` ${r}`)}if(e.annotatedElementText&&t.push(` element text: ${e.annotatedElementText}`),n.length>0){t.push(` comments (${n.length}):`);for(let r of n){let a=r.updatedAt?` (edited ${r.updatedAt})`:"";t.push(` [${r.author??"user"}] ${r.createdAt}${a}`);for(let l of r.text.split(`
4
- `))t.push(` ${l}`)}}if(i.length>0){t.push(` linked files (${i.length}):`);for(let r of i){t.push(` - ${r.name} ${r.url}`);let a=r.linkedPath??u(o,".vibeflow","files",e.id,r.name);if(/\.(md|txt)$/i.test(r.name)&&r.size<1e5&&f(a))try{let l=O(a,"utf-8");t.push(" \u250C\u2500\u2500 content \u2500\u2500");for(let B of l.split(`
4
+ `))t.push(` ${l}`)}}if(s.length>0){t.push(` linked files (${s.length}):`);for(let r of s){t.push(` - ${r.name} ${r.url}`);let a=r.linkedPath??u(o,".vibeflow","files",e.id,r.name);if(/\.(md|txt)$/i.test(r.name)&&r.size<1e5&&f(a))try{let l=O(a,"utf-8");t.push(" \u250C\u2500\u2500 content \u2500\u2500");for(let B of l.split(`
5
5
  `))t.push(` \u2502 ${B}`);t.push(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}catch{}}}return t.join(`
6
- `)}function fe(e){let{autoCommit:s,autoPush:n,autoComment:i,createBranch:o}=e,t=[];if(t.push("Agent instructions (concise):"),t.push(" Discover: vibeflow tasks --status todo | vibeflow tasks --type Research | vibeflow tasks --user <email> | vibeflow tasks --tag <tag>"),t.push(" Details: vibeflow tasks --get <id> (full task info with comments and files)"),t.push(' Create: vibeflow tasks --add --title "..." --description "..."'),t.push(""),t.push(" Workflow:"),t.push(" \u26A0 IMMEDIATELY set in-progress BEFORE any implementation work:"),t.push(" 1. vibeflow tasks --edit <id> --set-status in-progress \u2190 DO THIS FIRST"),t.push(" 2. <implement the change>"),s){t.push(" 3. git add <files> (stage your changes first)");let r=["--set-status review"];s&&r.push('--commit-message "<one-line summary>"'),i&&r.push('--comment "<report>"'),t.push(` 4. vibeflow tasks --edit <id> ${r.join(" ")}`),t.push(" CLI will commit staged changes and link the commit SHA automatically.")}else{t.push(' 3. git add <files> && vibeflow tasks --commit --task <id> --message "<one-line summary>"');let r=["--set-status review"];i&&r.push('--comment "<report>"'),t.push(` 4. vibeflow tasks --edit <id> ${r.join(" ")}`)}return i&&(t.push(""),t.push(" Comment format (--comment):"),t.push(" \xB7 Plain text for concise one-liners."),t.push(" \xB7 Markdown for multi-section reports. Use **bold**, bullet lists, code fences."),t.push(" \xB7 Must cover: what changed, why, key decisions, anything future agents should know."),t.push(" \xB7 For long reports, attach a .md file and reference it in the comment.")),t.push(""),s&&t.push(" [setting] Auto-commit ON: provide --commit-message when setting status to review; CLI commits."),n&&t.push(" [setting] Auto-push ON: CLI pushes after the commit automatically."),i&&t.push(" [setting] Auto-comment ON: --comment is required when setting status to review."),o&&(t.push(" [setting] Create branch ON: after ALL tasks in this session are done, create and push a descriptive branch:"),t.push(" git checkout -b <short-name> (e.g. fix/annotation-errors, feat/eye-toggle, chore/cleanup-extension)"),t.push(" git push -u origin HEAD"),t.push(" Branch name rules: lowercase, kebab-case, 2-5 words, prefix fix/feat/chore/docs."),t.push(" Describe the WORK done (not dates). Bad: agent/2026-04-16. Good: fix/bug-errors-visibility.")),e.hasResearchTasks&&(t.push(" Research tasks: NEVER generate code \u2014 research only."),t.push(" Attach a .md report before marking Research tasks as review."),t.push(" CLI ENFORCES: cannot mark Research as review without an attached .md report."),t.push(" Use --report-file <path> to upload your .md report when marking as review:"),t.push(' vibeflow tasks --edit <id> --set-status review --report-file ./report.md --comment "..."'),t.push(" The file is uploaded to the task and deleted from the local filesystem automatically.")),e.hasBugTasks&&(t.push(" Bug tasks: Include error logs / stack traces in the commit comment."),t.push(" Describe: the symptom, the console error, what triggered it, and how it was fixed.")),t.push(" CRITICAL: NEVER edit .vibeflow/ task files directly."),t.push(" All task operations (status, comments, commits) must go through CLI commands."),t.push(" CRITICAL: Set in-progress BEFORE reading/planning. Other agents may pick the same task."),t.push(" The in-progress transition signals ownership. Skip it and another agent may duplicate your work."),t.push(" Sequence: discover tasks \u2192 pick one \u2192 set in-progress \u2192 THEN read details and implement."),t.push(' CRITICAL: NEVER set a task status to "done".'),t.push(' When your implementation is complete, set the status to "review" \u2014 not "done".'),t.push(" Only humans can mark tasks as done after reviewing the work."),t.push(" The CLI will warn you and still allow the change \u2014 but agents must not use it."),t.push(""),t.join(`
7
- `)}var P=".linked.json";function d(e,s){return m(e,g,S,s)}function G(e,s){q(d(e,s),{recursive:!0})}function Y(e,s){let n=m(d(e,s),P);if(!c(n))return[];try{return JSON.parse(K(n,"utf-8"))}catch{return[]}}function Q(e,s){let n=T(e,s),i=n?y(n):null;return!i?.files||i.files.length===0?[]:i.files}function C(e,s,n){N(e,s,{files:n})}function x(e,s){let n=Q(e,s),i=m(d(e,s),P);if(!c(i))return n;let o=Y(e,s);if(o.length===0){try{b(i)}catch{}return n}let t=n.slice(),r=!1;for(let a of o)t.find(l=>l.linkedPath===a.path||l.name===a.name&&l.linkedPath)||(t.push({name:a.name,linkedPath:a.path,addedAt:new Date().toISOString()}),r=!0);r&&C(e,s,t);try{b(i)}catch{}return t}function X(e,s){let n=d(e,s),i=x(e,s),o=new Map;for(let t of i){if(t.linkedPath&&c(t.linkedPath)){let a=F(t.linkedPath);o.set(t.name,{name:t.name,size:a.size,url:`/api/tasks/${s}/files/${encodeURIComponent(t.name)}`,linkedPath:t.linkedPath,createdAt:a.mtime.toISOString()});continue}let r=m(n,t.name);if(c(r)){let a=F(r);o.set(t.name,{name:t.name,size:a.size,url:`/api/tasks/${s}/files/${encodeURIComponent(t.name)}`,createdAt:a.mtime.toISOString()})}}if(c(n))for(let t of M(n,{withFileTypes:!0})){if(!t.isFile()||t.name===P||o.has(t.name))continue;let r=m(n,t.name),a=F(r);o.set(t.name,{name:t.name,size:a.size,url:`/api/tasks/${s}/files/${encodeURIComponent(t.name)}`,createdAt:a.mtime.toISOString()})}return Array.from(o.values())}function Se(e,s,n,i){let o=v(n);G(e,s),J(m(d(e,s),o),i);let t=x(e,s);return t.find(r=>r.name===o&&!r.linkedPath)||(t.push({name:o,addedAt:new Date().toISOString()}),C(e,s,t)),{name:o,size:i.length,url:`/api/tasks/${s}/files/${encodeURIComponent(o)}`}}function Te(e,s,n){let i=v(n),o=x(e,s),t=o.findIndex(a=>a.name===i);if(t!==-1){let[a]=o.splice(t,1);if(C(e,s,o),a&&!a.linkedPath){let l=m(d(e,s),i);c(l)&&b(l)}return!0}let r=m(d(e,s),i);return c(r)?(b(r),!0):!1}function be(e,s,n){let i=v(n),o=x(e,s).find(r=>r.name===i&&r.linkedPath);if(o?.linkedPath&&c(o.linkedPath))return o.linkedPath;let t=m(d(e,s),i);return c(t)?t:null}function xe(e,s){return X(e,s).length}export{g as a,$ as b,R as c,Z as d,W as e,re as f,U as g,T as h,oe as i,y as j,ae as k,ue as l,N as m,le as n,ce as o,me as p,fe as q,d as r,G as s,X as t,Se as u,Te as v,be as w,xe as x};
6
+ `)}function fe(e){let{autoCommit:i,autoPush:n,autoComment:s,createBranch:o}=e,t=[];if(t.push("Agent instructions (concise):"),t.push(" Discover: vibeflow tasks --status todo | vibeflow tasks --type Research | vibeflow tasks --user <email> | vibeflow tasks --tag <tag>"),t.push(" Details: vibeflow tasks --get <id> (full task info with comments and files)"),t.push(' Create: vibeflow tasks --add --title "..." --description "..."'),t.push(""),t.push(" Workflow:"),t.push(" \u26A0 IMMEDIATELY set in-progress BEFORE any implementation work:"),t.push(" 1. vibeflow tasks --edit <id> --set-status in-progress \u2190 DO THIS FIRST"),t.push(" 2. <implement the change>"),i){t.push(" 3. git add <files> (stage your changes first)");let r=["--set-status review"];i&&r.push('--commit-message "<one-line summary>"'),s&&r.push('--comment "<report>"'),t.push(` 4. vibeflow tasks --edit <id> ${r.join(" ")}`),t.push(" CLI will commit staged changes and link the commit SHA automatically.")}else{t.push(' 3. git add <files> && vibeflow tasks --commit --task <id> --message "<one-line summary>"');let r=["--set-status review"];s&&r.push('--comment "<report>"'),t.push(` 4. vibeflow tasks --edit <id> ${r.join(" ")}`)}return s&&(t.push(""),t.push(" Comment format (--comment):"),t.push(" \xB7 Plain text for concise one-liners."),t.push(" \xB7 Markdown for multi-section reports. Use **bold**, bullet lists, code fences."),t.push(" \xB7 Must cover: what changed, why, key decisions, anything future agents should know."),t.push(" \xB7 For long reports, attach a .md file and reference it in the comment.")),t.push(""),i&&t.push(" [setting] Auto-commit ON: provide --commit-message when setting status to review; CLI commits."),n&&t.push(" [setting] Auto-push ON: CLI pushes after the commit automatically."),s&&t.push(" [setting] Auto-comment ON: --comment is required when setting status to review."),o&&(t.push(" [setting] Create branch ON: after ALL tasks in this session are done, create and push a descriptive branch:"),t.push(" git checkout -b <short-name> (e.g. fix/annotation-errors, feat/eye-toggle, chore/cleanup-extension)"),t.push(" git push -u origin HEAD"),t.push(" Branch name rules: lowercase, kebab-case, 2-5 words, prefix fix/feat/chore/docs."),t.push(" Describe the WORK done (not dates). Bad: agent/2026-04-16. Good: fix/bug-errors-visibility.")),e.hasResearchTasks&&(t.push(" Research tasks: NEVER generate code \u2014 research only."),t.push(" Attach a .md report before marking Research tasks as review."),t.push(" CLI ENFORCES: cannot mark Research as review without an attached .md report."),t.push(" Use --report-file <path> to upload your .md report when marking as review:"),t.push(' vibeflow tasks --edit <id> --set-status review --report-file ./report.md --comment "..."'),t.push(" The file is uploaded to the task and deleted from the local filesystem automatically.")),e.hasBugTasks&&(t.push(" Bug tasks: Include error logs / stack traces in the commit comment."),t.push(" Describe: the symptom, the console error, what triggered it, and how it was fixed.")),t.push(" CRITICAL: NEVER edit .vibeflow/ task files directly."),t.push(" All task operations (status, comments, commits) must go through CLI commands."),t.push(" CRITICAL: Set in-progress BEFORE reading/planning. Other agents may pick the same task."),t.push(" The in-progress transition signals ownership. Skip it and another agent may duplicate your work."),t.push(" Sequence: discover tasks \u2192 pick one \u2192 set in-progress \u2192 THEN read details and implement."),t.push(' CRITICAL: NEVER set a task status to "done".'),t.push(' When your implementation is complete, set the status to "review" \u2014 not "done".'),t.push(" Only humans can mark tasks as done after reviewing the work."),t.push(" The CLI will warn you and still allow the change \u2014 but agents must not use it."),t.push(""),t.join(`
7
+ `)}var R=".linked.json";function d(e,i){return m(e,g,k,i)}function G(e,i){q(d(e,i),{recursive:!0})}function Y(e,i){let n=m(d(e,i),R);if(!c(n))return[];try{return JSON.parse(V(n,"utf-8"))}catch{return[]}}function Q(e,i){let n=T(e,i),s=n?y(n):null;return!s?.files||s.files.length===0?[]:s.files}function $(e,i,n){N(e,i,{files:n})}function b(e,i){let n=Q(e,i),s=m(d(e,i),R);if(!c(s))return n;let o=Y(e,i);if(o.length===0){try{x(s)}catch{}return n}let t=n.slice(),r=!1;for(let a of o)t.find(l=>l.linkedPath===a.path||l.name===a.name&&l.linkedPath)||(t.push({name:a.name,linkedPath:a.path,addedAt:new Date().toISOString()}),r=!0);r&&$(e,i,t);try{x(s)}catch{}return t}function X(e,i){let n=d(e,i),s=b(e,i),o=new Map;for(let t of s){if(t.linkedPath&&c(t.linkedPath)){let a=v(t.linkedPath);o.set(t.name,{name:t.name,size:a.size,url:`/api/tasks/${i}/files/${encodeURIComponent(t.name)}`,linkedPath:t.linkedPath,createdAt:a.mtime.toISOString()});continue}let r=m(n,t.name);if(c(r)){let a=v(r);o.set(t.name,{name:t.name,size:a.size,url:`/api/tasks/${i}/files/${encodeURIComponent(t.name)}`,createdAt:a.mtime.toISOString()})}}if(c(n))for(let t of W(n,{withFileTypes:!0})){if(!t.isFile()||t.name===R||o.has(t.name))continue;let r=m(n,t.name),a=v(r);o.set(t.name,{name:t.name,size:a.size,url:`/api/tasks/${i}/files/${encodeURIComponent(t.name)}`,createdAt:a.mtime.toISOString()})}return Array.from(o.values())}function ke(e,i,n,s){let o=P(n);G(e,i),J(m(d(e,i),o),s);let t=b(e,i);return t.find(r=>r.name===o&&!r.linkedPath)||(t.push({name:o,addedAt:new Date().toISOString()}),$(e,i,t)),{name:o,size:s.length,url:`/api/tasks/${i}/files/${encodeURIComponent(o)}`}}function Te(e,i,n){let s=P(n),o=b(e,i),t=o.findIndex(a=>a.name===s);if(t!==-1){let[a]=o.splice(t,1);if($(e,i,o),a&&!a.linkedPath){let l=m(d(e,i),s);c(l)&&x(l)}return!0}let r=m(d(e,i),s);return c(r)?(x(r),!0):!1}function xe(e,i,n){let s=P(n),o=b(e,i).find(r=>r.name===s&&r.linkedPath);if(o?.linkedPath&&c(o.linkedPath))return o.linkedPath;let t=m(d(e,i),s);return c(t)?t:null}function be(e,i){return X(e,i).length}export{g as a,C as b,A as c,Z as d,H as e,re as f,U as g,T as h,oe as i,y as j,ae as k,ue as l,N as m,le as n,ce as o,me as p,fe as q,d as r,G as s,X as t,ke as u,Te as v,xe as w,be as x};
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import{readdirSync as W,writeFileSync as J,readFileSync as V,unlinkSync as b,statSync as v,mkdirSync as q,existsSync as c}from"fs";import{join as m,basename as R}from"path";var g=".vibeflow",C="tasks",k="tasks/files",A="tasks/screenshots",Z="config.json";import{existsSync as f,readFileSync as O,writeFileSync as _,mkdirSync as p,readdirSync as h,unlinkSync as D,renameSync as F}from"fs";import{join as u,extname as I}from"path";import{randomBytes as z}from"crypto";var j=["backlog","todo","in-progress","review","done"];function K(){return z(15).toString("hex")}function S(e){return u(e,g,C)}function M(e){let i=u(e,g),n=u(i,"files"),s=u(i,k),r=u(i,"screenshots"),t=u(i,A);if(f(n)){p(s,{recursive:!0});for(let o of h(n)){let a=u(n,o),l=u(s,o);if(!f(l))try{F(a,l)}catch{}}}if(f(r)){p(t,{recursive:!0});for(let o of h(r)){let a=u(r,o),l=u(t,o);if(!f(l))try{F(a,l)}catch{}}}}function re(e){M(e),p(S(e),{recursive:!0}),p(u(e,g,A),{recursive:!0})}function w(e){return e.slice(0,10)}function U(e,i,n){let s=S(e);return n?u(s,w(n),`${i}.json`):u(s,`${i}.json`)}function T(e,i){let n=S(e);if(!f(n))return null;for(let s of h(n,{withFileTypes:!0}))if(s.isDirectory()){let r=u(n,s.name,`${i}.json`);if(f(r))return r}else if(s.name===`${i}.json`)return u(n,s.name);return null}function H(e){let i=(()=>{if(typeof e.type!="string")return;let n=e.type.trim();if(!(!n||n==="[object Object]"))return n})();return{id:String(e.id??""),title:String(e.title??"Untitled"),description:String(e.description??""),status:j.includes(e.status)?e.status:"todo",url:e.url?String(e.url):void 0,selector:(()=>{let n=String(e.selector??"/");return e.file&&!e.cssSelector&&n.startsWith(String(e.file))?e.url?String(e.url):"/":n})(),cssSelector:e.cssSelector&&String(e.cssSelector)!==String(e.selector??"/")?String(e.cssSelector):void 0,file:e.file?String(e.file):void 0,line:e.line!=null?Number(e.line):void 0,col:e.col!=null?Number(e.col):void 0,component:e.component?String(e.component):void 0,type:i,priority:e.priority?String(e.priority):void 0,...e.reportBack===!0&&{reportBack:!0},agent:e.agent?String(e.agent):void 0,model:e.model?String(e.model):void 0,author:e.author?String(e.author):void 0,commits:Array.isArray(e.commits)?e.commits.map(n=>({sha:String(n.sha??""),message:String(n.message??""),timestamp:String(n.timestamp??new Date().toISOString())})):void 0,created:String(e.created??new Date().toISOString()),updated:e.updated?String(e.updated):void 0,comments:Array.isArray(e.comments)?e.comments.map(n=>({...n,text:n.text??n.content??""})):[],files:Array.isArray(e.files)?e.files.map(n=>typeof n=="string"?{name:n,addedAt:new Date().toISOString()}:{name:String(n.name??""),addedAt:String(n.addedAt??new Date().toISOString()),linkedPath:n.linkedPath?String(n.linkedPath):void 0,mimeType:n.mimeType?String(n.mimeType):void 0}).filter(n=>n.name):[],screenshot:e.screenshot?String(e.screenshot):void 0,annotatedElementText:e.annotatedElementText?String(e.annotatedElementText):void 0,tags:Array.isArray(e.tags)?e.tags.filter(n=>typeof n=="string"&&n.length>0):void 0,sortKey:e.sortKey?String(e.sortKey):void 0}}function E(e,i){let n=u(S(e),w(i.created));p(n,{recursive:!0});let s=u(n,`${i.id}.json`),r=s+".tmp";_(r,JSON.stringify(i,null,2),"utf-8"),F(r,s)}function oe(e,i){let n=(()=>{let r=(i.priority??"").trim().toLowerCase();return r==="critical"?"Critical":r==="high"?"High":r==="low"?"Low":"Medium"})(),s={...i,priority:n,id:K(),created:new Date().toISOString(),comments:[],files:[]};return E(e,s),s}function y(e){try{let i=O(e,"utf-8");if(e.endsWith(".json")){let n=JSON.parse(i);return!n||typeof n!="object"||!("id"in n)?null:H(n)}return null}catch{return null}}function L(e){let i=S(e);if(!f(i))return[];let n=[];for(let s of h(i,{withFileTypes:!0}))if(s.isDirectory()){let r=u(i,s.name);for(let t of h(r))if(I(t)===".json"){let o=u(r,t),a=y(o);a&&n.push({task:a,filePath:o})}}else if(I(s.name)===".json"){let r=u(i,s.name),t=y(r);t&&n.push({task:t,filePath:r})}return n}function ae(e){return L(e).map(({task:i})=>i)}function ue(e){return L(e).map(({task:i,filePath:n})=>({...i,filePath:n}))}function N(e,i,n){let s=T(e,i),r=s?y(s):null;if(!r)return null;let t={...r,...n,updated:new Date().toISOString()};if(E(e,t),s&&s!==U(e,i,t.created))try{D(s)}catch{}return t}function le(e,i){let n=T(e,i);return n?(D(n),!0):!1}function ce(e,i,n){return{id:e.id,status:e.status,title:e.title,description:e.description,...e.url&&{url:e.url},selector:e.selector,...e.file&&{file:e.file},...e.line!=null&&{line:e.line},...e.col!=null&&{col:e.col},...e.component&&{component:e.component},...e.type&&{type:e.type},...e.priority&&{priority:e.priority},...i&&i.length>0&&{structuredComments:i},...n&&n.length>0&&{linkedFiles:n},...e.reportBack&&{reportBack:!0},created:e.created}}function me(e,i,n,s,r){let t=[];if(t.push(`[${e.status}] ${e.title}`),t.push(` id: ${e.id}`),t.push(` file: ${i}`),e.file&&t.push(` source: ${e.file}${e.line!=null?`:${e.line}`:""}${e.col!=null?`:${e.col}`:""}`),e.component&&t.push(` component: ${e.component}`),t.push(` selector: ${e.selector??"/"}`),e.cssSelector&&t.push(` css: ${e.cssSelector}`),e.url&&t.push(` url: ${e.url}`),e.commits&&e.commits.length>0)if(e.commits.length===1)t.push(` commit: ${e.commits[0].sha}`);else{t.push(` commits (${e.commits.length}):`);for(let o of e.commits)t.push(` ${o.sha.slice(0,8)} ${o.timestamp} ${o.message.slice(0,60)}`)}if(t.push(` created: ${e.created}`),e.type&&t.push(` type: ${e.type}`),e.priority&&t.push(` priority: ${e.priority}`),e.author&&t.push(` author: ${e.author}`),e.description){t.push(" description:");for(let o of e.description.split(`
3
+ `))t.push(` ${o}`)}if(e.annotatedElementText&&t.push(` element text: ${e.annotatedElementText}`),n.length>0){t.push(` comments (${n.length}):`);for(let o of n){let a=o.updatedAt?` (edited ${o.updatedAt})`:"";t.push(` [${o.author??"user"}] ${o.createdAt}${a}`);for(let l of o.text.split(`
4
+ `))t.push(` ${l}`)}}if(s.length>0){t.push(` linked files (${s.length}):`);for(let o of s){t.push(` - ${o.name} ${o.url}`);let a=o.linkedPath??u(r,".vibeflow","files",e.id,o.name);if(/\.(md|txt)$/i.test(o.name)&&o.size<1e5&&f(a))try{let l=O(a,"utf-8");t.push(" \u250C\u2500\u2500 content \u2500\u2500");for(let B of l.split(`
5
+ `))t.push(` \u2502 ${B}`);t.push(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}catch{}}}return t.join(`
6
+ `)}function fe(e){let{autoCommit:i,autoPush:n,autoComment:s,createBranch:r}=e,t=[];if(t.push("Agent instructions (concise):"),t.push(" Discover: vibeflow tasks --status todo | vibeflow tasks --type Research | vibeflow tasks --user <email> | vibeflow tasks --tag <tag>"),t.push(" Details: vibeflow tasks --get <id> (full task info with comments and files)"),t.push(' Create: vibeflow tasks --add --title "..." --description "..."'),t.push(""),t.push(" Workflow:"),r?(t.push(" \u26A0 Create a branch FIRST, before any implementation:"),t.push(" 1. git checkout -b <short-name> (e.g. fix/annotation-errors, feat/eye-toggle, chore/cleanup-extension)"),t.push(" Branch name rules: lowercase, kebab-case, 2-5 words, prefix fix/feat/chore/docs."),t.push(" Describe the WORK done (not dates). Bad: agent/2026-04-16. Good: fix/bug-errors-visibility."),t.push(" 2. vibeflow tasks --edit <id> --set-status in-progress \u2190 CLAIM TASK"),t.push(" 3. <implement the change>")):(t.push(" \u26A0 IMMEDIATELY set in-progress BEFORE any implementation work:"),t.push(" 1. vibeflow tasks --edit <id> --set-status in-progress \u2190 DO THIS FIRST"),t.push(" 2. <implement the change>")),i){t.push(r?" 4. git add <files> (stage your changes first)":" 3. git add <files> (stage your changes first)");let o=["--set-status review"];i&&o.push('--commit-message "<one-line summary>"'),s&&o.push('--comment "<report>"'),t.push(` ${r?"5":"4"}. vibeflow tasks --edit <id> ${o.join(" ")}`),t.push(" CLI will commit staged changes and link the commit SHA automatically.")}else{t.push(r?' 4. git add <files> && vibeflow tasks --commit --task <id> --message "<one-line summary>"':' 3. git add <files> && vibeflow tasks --commit --task <id> --message "<one-line summary>"');let o=["--set-status review"];s&&o.push('--comment "<report>"'),t.push(` ${r?"5":"4"}. vibeflow tasks --edit <id> ${o.join(" ")}`)}return s&&(t.push(""),t.push(" Comment format (--comment):"),t.push(" \xB7 Plain text for concise one-liners."),t.push(" \xB7 Markdown for multi-section reports. Use **bold**, bullet lists, code fences."),t.push(" \xB7 Must cover: what changed, why, key decisions, anything future agents should know."),t.push(" \xB7 For long reports, attach a .md file and reference it in the comment.")),t.push(""),i&&t.push(" [setting] Auto-commit ON: provide --commit-message when setting status to review; CLI commits."),n&&t.push(" [setting] Auto-push ON: CLI pushes after the commit automatically."),s&&t.push(" [setting] Auto-comment ON: --comment is required when setting status to review."),r&&t.push(" [setting] Create branch ON: all work goes on a dedicated branch created before implementation."),e.hasResearchTasks&&(t.push(" Research tasks: NEVER generate code \u2014 research only."),t.push(" Attach a .md report before marking Research tasks as review."),t.push(" CLI ENFORCES: cannot mark Research as review without an attached .md report."),t.push(" Use --report-file <path> to upload your .md report when marking as review:"),t.push(' vibeflow tasks --edit <id> --set-status review --report-file ./report.md --comment "..."'),t.push(" The file is uploaded to the task and deleted from the local filesystem automatically.")),e.hasBugTasks&&(t.push(" Bug tasks: Include error logs / stack traces in the commit comment."),t.push(" Describe: the symptom, the console error, what triggered it, and how it was fixed.")),t.push(" CRITICAL: NEVER edit .vibeflow/ task files directly."),t.push(" All task operations (status, comments, commits) must go through CLI commands."),t.push(" CRITICAL: Set in-progress BEFORE reading/planning. Other agents may pick the same task."),t.push(" The in-progress transition signals ownership. Skip it and another agent may duplicate your work."),t.push(" Sequence: discover tasks \u2192 pick one \u2192 set in-progress \u2192 THEN read details and implement."),t.push(' CRITICAL: NEVER set a task status to "done".'),t.push(' When your implementation is complete, set the status to "review" \u2014 not "done".'),t.push(" Only humans can mark tasks as done after reviewing the work."),t.push(" The CLI will warn you and still allow the change \u2014 but agents must not use it."),t.push(""),t.join(`
7
+ `)}var P=".linked.json";function d(e,i){return m(e,g,k,i)}function G(e,i){q(d(e,i),{recursive:!0})}function Y(e,i){let n=m(d(e,i),P);if(!c(n))return[];try{return JSON.parse(V(n,"utf-8"))}catch{return[]}}function Q(e,i){let n=T(e,i),s=n?y(n):null;return!s?.files||s.files.length===0?[]:s.files}function $(e,i,n){N(e,i,{files:n})}function x(e,i){let n=Q(e,i),s=m(d(e,i),P);if(!c(s))return n;let r=Y(e,i);if(r.length===0){try{b(s)}catch{}return n}let t=n.slice(),o=!1;for(let a of r)t.find(l=>l.linkedPath===a.path||l.name===a.name&&l.linkedPath)||(t.push({name:a.name,linkedPath:a.path,addedAt:new Date().toISOString()}),o=!0);o&&$(e,i,t);try{b(s)}catch{}return t}function X(e,i){let n=d(e,i),s=x(e,i),r=new Map;for(let t of s){if(t.linkedPath&&c(t.linkedPath)){let a=v(t.linkedPath);r.set(t.name,{name:t.name,size:a.size,url:`/api/tasks/${i}/files/${encodeURIComponent(t.name)}`,linkedPath:t.linkedPath,createdAt:a.mtime.toISOString()});continue}let o=m(n,t.name);if(c(o)){let a=v(o);r.set(t.name,{name:t.name,size:a.size,url:`/api/tasks/${i}/files/${encodeURIComponent(t.name)}`,createdAt:a.mtime.toISOString()})}}if(c(n))for(let t of W(n,{withFileTypes:!0})){if(!t.isFile()||t.name===P||r.has(t.name))continue;let o=m(n,t.name),a=v(o);r.set(t.name,{name:t.name,size:a.size,url:`/api/tasks/${i}/files/${encodeURIComponent(t.name)}`,createdAt:a.mtime.toISOString()})}return Array.from(r.values())}function ke(e,i,n,s){let r=R(n);G(e,i),J(m(d(e,i),r),s);let t=x(e,i);return t.find(o=>o.name===r&&!o.linkedPath)||(t.push({name:r,addedAt:new Date().toISOString()}),$(e,i,t)),{name:r,size:s.length,url:`/api/tasks/${i}/files/${encodeURIComponent(r)}`}}function Te(e,i,n){let s=R(n),r=x(e,i),t=r.findIndex(a=>a.name===s);if(t!==-1){let[a]=r.splice(t,1);if($(e,i,r),a&&!a.linkedPath){let l=m(d(e,i),s);c(l)&&b(l)}return!0}let o=m(d(e,i),s);return c(o)?(b(o),!0):!1}function be(e,i,n){let s=R(n),r=x(e,i).find(o=>o.name===s&&o.linkedPath);if(r?.linkedPath&&c(r.linkedPath))return r.linkedPath;let t=m(d(e,i),s);return c(t)?t:null}function xe(e,i){return X(e,i).length}export{g as a,C as b,A as c,Z as d,K as e,re as f,U as g,T as h,oe as i,y as j,ae as k,ue as l,N as m,le as n,ce as o,me as p,fe as q,d as r,G as s,X as t,ke as u,Te as v,be as w,xe as x};