@vibeflow-tools/cli 0.6.0 → 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.
- package/CHANGELOG.md +7 -0
- package/README.md +199 -81
- package/dist/chunk-D6KVQU62.js +7 -0
- package/dist/cli/chunk-D6KVQU62.js +7 -0
- package/dist/cli/{files-LTK2TDC2.js → files-TKEFFLPI.js} +1 -1
- package/dist/cli/index.js +87 -27951
- package/dist/client/kanban-browser.js +15 -15
- package/dist/client/kanban.css +1 -1
- package/dist/{cli/files-MEEV7E6V.js → files-TKEFFLPI.js} +1 -1
- package/dist/index.js +87 -27951
- package/package.json +2 -2
- package/dist/chunk-GEQ64RVF.js +0 -7
- package/dist/chunk-IUZWZWMW.js +0 -7
- package/dist/chunk-PCPVP4ZD.js +0 -7
- package/dist/chunk-XO547RIH.js +0 -7
- package/dist/cli/chunk-GEQ64RVF.js +0 -7
- package/dist/cli/chunk-IUZWZWMW.js +0 -7
- package/dist/cli/chunk-PCPVP4ZD.js +0 -7
- package/dist/cli/chunk-XO547RIH.js +0 -7
- package/dist/cli/files-R6YCYMTI.js +0 -2
- package/dist/cli/files-SUCOSQAO.js +0 -2
- package/dist/files-LTK2TDC2.js +0 -2
- package/dist/files-MEEV7E6V.js +0 -2
- package/dist/files-R6YCYMTI.js +0 -2
- package/dist/files-SUCOSQAO.js +0 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
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
|
+
|
|
3
10
|
## 0.6.0
|
|
4
11
|
|
|
5
12
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -1,145 +1,263 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Vibeflow
|
|
2
2
|
|
|
3
|
-
> **
|
|
3
|
+
> **Tell your AI agent exactly what to fix — by clicking on it.**
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
[](https://www.apache.org/licenses/LICENSE-2.0)
|
|
7
|
-
[](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
|
-
|
|
8
|
+
npm install -g @vibeflow-tools/cli
|
|
9
|
+
vibeflow kanban
|
|
14
10
|
```
|
|
15
11
|
|
|
16
|
-
|
|
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
|
-
|
|
19
|
-
|
|
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
|
-
##
|
|
28
|
+
## Quick Start
|
|
24
29
|
|
|
25
|
-
|
|
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
|
-
|
|
28
|
-
|
|
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
|
-
|
|
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
|
-
|
|
42
|
+
```
|
|
36
43
|
|
|
37
|
-
|
|
44
|
+
---
|
|
38
45
|
|
|
39
|
-
|
|
46
|
+
## Commands
|
|
40
47
|
|
|
41
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
64
|
+
### `vibeflow serve [target]`
|
|
50
65
|
|
|
51
66
|
```bash
|
|
52
|
-
vibeflow
|
|
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
|
-
|
|
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
|
-
|
|
76
|
+
### `vibeflow tasks`
|
|
77
|
+
|
|
78
|
+
Full task management from the command line — designed to be agent-friendly.
|
|
58
79
|
|
|
59
80
|
```bash
|
|
60
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
128
|
+
## Browser Overlay
|
|
72
129
|
|
|
73
|
-
|
|
130
|
+
The overlay is a Shadow DOM panel injected into any page — HTML prototypes or live apps:
|
|
74
131
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
###
|
|
141
|
+
### Injection Methods
|
|
81
142
|
|
|
82
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
155
|
+
## How It Works
|
|
98
156
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
115
|
-
# Open the Kanban board
|
|
116
|
-
npx vibeflow kanban
|
|
201
|
+
---
|
|
117
202
|
|
|
118
|
-
|
|
119
|
-
|
|
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
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
234
|
+
## Installation
|
|
137
235
|
|
|
138
|
-
|
|
139
|
-
|
|
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};
|
|
@@ -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,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{r as a,s as b,t as c,u as d,v as e,w as f,x as g}from"./chunk-
|
|
2
|
+
import{r as a,s as b,t as c,u as d,v as e,w as f,x as g}from"./chunk-D6KVQU62.js";export{e as deleteFile,b as ensureFilesDir,g as getFileCount,f as getFilePath,a as getFilesDir,c as listFiles,d as saveFile};
|