@vibeflow-tools/cli 0.4.2 → 0.5.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 +165 -0
- package/dist/chunk-IZB3AHO6.js +6 -0
- package/dist/chunk-QULSJOW5.js +7 -0
- package/dist/chunk-TPDIOJDI.js +7 -0
- package/dist/cli/chunk-IZB3AHO6.js +6 -0
- package/dist/cli/chunk-QULSJOW5.js +7 -0
- package/dist/cli/chunk-TPDIOJDI.js +7 -0
- package/dist/cli/files-H2UIFEPJ.js +2 -0
- package/dist/cli/files-JPVPKRMX.js +2 -0
- package/dist/cli/files-MIDXKOAF.js +2 -0
- package/dist/cli/index.js +337 -150
- package/dist/client/kanban-browser.js +23 -12
- package/dist/client/kanban.css +1 -1
- package/dist/client/overlay-browser.js +5 -4
- package/dist/files-H2UIFEPJ.js +2 -0
- package/dist/files-JPVPKRMX.js +2 -0
- package/dist/files-MIDXKOAF.js +2 -0
- package/dist/index.js +337 -150
- package/package.json +3 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.5.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- de759ff: Include agent workflow instructions in agent run context. Previously, `vibeflow tasks --get` printed CLI instructions but the server agent-run endpoint did not include them in the prompt sent to opencode. Now both entry points share the same `renderAgentInstructions()` formatter, ensuring agents always receive workflow rules, settings flags, and critical constraints.
|
|
8
|
+
- defc6cf: Fix multi-select drag & drop to preserve relative order of selected tasks. Previously, all selected tasks were appended to the column bottom. Now they are inserted at the drop position with correct sort keys computed from the final arrangement. Added e2e Playwright test verifying the behavior.
|
|
9
|
+
|
|
10
|
+
## 0.5.0
|
|
11
|
+
|
|
12
|
+
### Minor Changes
|
|
13
|
+
|
|
14
|
+
- `tasks --next` now supports combining with `--type`, `--user`, and `--tag` filters to pick the next available todo task matching specific criteria.
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- Fix detail panel content being clipped instead of scrollable: TaskDetailsTab wrapper now has `flex-shrink: 0` so long task content (large descriptions, screenshots, annotated element text) overflows the pane and triggers the scroll bar instead of being compressed invisibly. Also adds annotated element text display to the legacy HTML kanban template.
|
|
19
|
+
- Fix kanban drag-and-drop: tasks no longer jump to the top of a column after being dragged.
|
|
20
|
+
- Fix kanban board columns being unequal widths; all columns are now a fixed 280px.
|
|
21
|
+
- f88415f: Fix overlay API/kanban URLs pointing to wrong host when used as bookmarklet on non-CLI pages. Detect server origin from `document.currentScript.src` instead of `window.location.host`.
|
|
22
|
+
- fix: dragging a task to reorder now only updates the dragged task, not all others in the column
|
|
23
|
+
|
|
24
|
+
## 0.4.2
|
|
25
|
+
|
|
26
|
+
### Patch Changes
|
|
27
|
+
|
|
28
|
+
- 9cd0d82: Write task files atomically via a .tmp file and renameSync to prevent torn JSON reads during concurrent writes (BUG-09).
|
|
29
|
+
- 9cd0d82: Sanitize boardId before embedding in injected HTML/JS to prevent HTML injection via a malformed workspace ID (BUG-10).
|
|
30
|
+
- 9cd0d82: Fix addComment, updateComment, and deleteComment to read raw task data so soft-deleted comments are preserved instead of silently dropped (B1).
|
|
31
|
+
- 9cd0d82: Remove 2>/dev/null shell redirect from execSync calls in copilot-auth; it was passed as a literal argument without shell: true (BUG-04).
|
|
32
|
+
- 9cd0d82: Fix logout to also delete the stored workspace file so the CLI fully returns to local mode (BUG-03).
|
|
33
|
+
- 9cd0d82: Add status value validation to PATCH /api/tasks/:id to reject unknown status strings (BUG-05).
|
|
34
|
+
- 9cd0d82: Pass projectDir to promptPushLocalTasks so it reads tasks from the correct project root instead of process.cwd() (BUG-07).
|
|
35
|
+
- 9cd0d82: Key remoteCommitCache by projectDir to avoid cross-project SHA collisions when multiple projects are open (BUG-02).
|
|
36
|
+
- 9cd0d82: Remove undeclared commit field from normalizeTask to prevent stale data from persisting in normalized task objects (B2).
|
|
37
|
+
- 9cd0d82: Allowlist known keys in POST /api/settings to prevent writing arbitrary fields to the project settings file (BUG-08).
|
|
38
|
+
- 9cd0d82: Replace hardcoded .vibeflow/tasks path in task watcher with PROTO_DIR and TASKS_DIR constants (BUG-06).
|
|
39
|
+
- 9cd0d82: Escape double-quote characters in renderMarkdown to prevent XSS via attribute injection in link hrefs (BUG-01).
|
|
40
|
+
- 9cd0d82: Use cryptographically random bytes for comment IDs instead of Date.now() to avoid collisions under concurrent writes (I5).
|
|
41
|
+
- 9cd0d82: Replace process.exit(1) calls in login.ts with process.exitCode = 1; return to allow async cleanup handlers to run (I1).
|
|
42
|
+
- 9cd0d82: Remove unused slugify function from tasks.ts; no production code imports it (F11).
|
|
43
|
+
- 9cd0d82: Import PROTO_DIR constant from core/types in settings.ts instead of duplicating the hardcoded string (F13).
|
|
44
|
+
- 9cd0d82: Compute commentCount and fileCount from embedded task arrays instead of reading from disk in the /api/tasks response (P3).
|
|
45
|
+
- 9cd0d82: Write copilot config file with 0o600 permissions to prevent other users from reading the stored token (SEC-04).
|
|
46
|
+
- 9cd0d82: Add file extension allowlist to the CLI file upload endpoint to reject unsupported MIME types (SEC-09).
|
|
47
|
+
- 9cd0d82: Reject POST and DELETE mutation requests from cross-origin pages to prevent unauthorized agent-status and settings writes (SEC-02).
|
|
48
|
+
- 9cd0d82: Validate workspace URL against an allowlist of production domains before using it as the SaaS API base URL, preventing SSRF (SEC-08).
|
|
49
|
+
- 9cd0d82: Serve screenshots through a route handler that validates task ID format instead of an unauthenticated static directory (SEC-05).
|
|
50
|
+
- 9cd0d82: Only trust X-Forwarded-For header for rate limiting when TRUSTED_PROXY=1 env var is set, preventing IP spoofing (SEC-01).
|
|
51
|
+
|
|
52
|
+
## 0.4.1
|
|
53
|
+
|
|
54
|
+
### Patch Changes
|
|
55
|
+
|
|
56
|
+
- f88415f: Fix overlay API/kanban URLs pointing to wrong host when used as bookmarklet on non-CLI pages. Detect server origin from `document.currentScript.src` instead of `window.location.host`.
|
|
57
|
+
|
|
58
|
+
## 0.4.0
|
|
59
|
+
|
|
60
|
+
### Minor Changes
|
|
61
|
+
|
|
62
|
+
- a2f86f2: Replace manual version:patch/minor/major npm scripts with Changesets CLI (`@changesets/cli`) for versioning and changelog management. Agents now create `.changeset/*.md` files; the publish script runs `pnpm changeset version` to apply all pending changesets before publishing.
|
|
63
|
+
- 44b73b7: Enable tags in the new-task creation form: tags are now editable before saving (previously disabled). Draft tags are stored in panel state and included when the task is created. The task creation API endpoint now also accepts and persists `tags`.
|
|
64
|
+
- 360e8ba: Fix remote serving via `--host 0.0.0.0`: kanban browser code now uses `window.location.origin` and `window.location.host` for all API and WebSocket URLs instead of hardcoded `localhost`. CLI startup output now shows the LAN IP as the primary URL when `--host 0.0.0.0` is specified, with local URL shown as secondary.
|
|
65
|
+
|
|
66
|
+
### Patch Changes
|
|
67
|
+
|
|
68
|
+
- fe9c8fd: Document the `--next` workflow as the primary AI agent workflow: update kanban command prompt suggestion, CLI README step 3, and website hero/how-it-works section to show `tasks --next` instead of `tasks --status todo`.
|
|
69
|
+
|
|
70
|
+
All notable changes to `@vibeflow-tools/cli` are documented here.
|
|
71
|
+
|
|
72
|
+
Format follows [Conventional Commits](https://www.conventionalcommits.org/) → [SemVer](https://semver.org/).
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## [0.3.2] - 2026-04-24
|
|
77
|
+
|
|
78
|
+
### Bug Fixes
|
|
79
|
+
|
|
80
|
+
- add comprehensive error handling to board creation endpoints (workspace.create, workspace.createWithBoard) with detailed logging of input, user ID, and root error cause
|
|
81
|
+
- improves debuggability when board creation fails due to database constraints or other issues
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## [0.3.1] - 2026-04-24
|
|
86
|
+
|
|
87
|
+
### Bug Fixes
|
|
88
|
+
|
|
89
|
+
- improve error logging to capture comprehensive diagnostic details: extract full stack traces, error types, and file locations from any error-like value (Error, string, object, arbitrary values)
|
|
90
|
+
- GlobalErrorHandler now gracefully handles minimal errors (e.g., single-character messages) and supplements them with context (stack, line number, error name)
|
|
91
|
+
|
|
92
|
+
### Tests
|
|
93
|
+
|
|
94
|
+
- add 11 comprehensive unit tests for error extraction logic covering Error objects, strings, objects with message property, null/undefined, and edge cases
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## [0.3.0] - 2026-04-24
|
|
99
|
+
|
|
100
|
+
### Features
|
|
101
|
+
|
|
102
|
+
- require `X-Overlay-Api-Key` header on `GET /api/overlay/tasks` — overlay GET endpoint is now authenticated (breaking: clients must include API key)
|
|
103
|
+
- overlay `fetchTasks` now sends `X-Overlay-Api-Key` header when `data-overlay-api-key` is set on the script tag
|
|
104
|
+
|
|
105
|
+
### Bug Fixes
|
|
106
|
+
|
|
107
|
+
- fix backspace key in header tag search not removing the last active filter tag
|
|
108
|
+
- fix `BETTER_AUTH_SECRET` empty-string bypass (`??` → `||` so empty string correctly falls back to `NEXTAUTH_SECRET`)
|
|
109
|
+
|
|
110
|
+
### Chores
|
|
111
|
+
|
|
112
|
+
- fix telemetry config path lazy evaluation — improves test isolation when `HOME` env is overridden
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## [0.2.1] - 2026-04-24
|
|
117
|
+
|
|
118
|
+
### Bug Fixes
|
|
119
|
+
|
|
120
|
+
- fix telemetry config path to use lazy evaluation so tests correctly isolate `HOME` override
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## [0.2.0] - 2026-04-24
|
|
125
|
+
|
|
126
|
+
### Features
|
|
127
|
+
|
|
128
|
+
- inline token search field with `#tag` picker — type `#` to open tag autocomplete dropdown; active tag chips appear as removable pills inside the search box (Proposals 1 + 3 combined)
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## [0.1.2] - 2026-04-24
|
|
133
|
+
|
|
134
|
+
### Features
|
|
135
|
+
|
|
136
|
+
- add `--tag` filter to `tasks` command — filter tasks by one or more tags
|
|
137
|
+
- add `--next` flag to `tasks` command — select highest-priority next task automatically
|
|
138
|
+
- add `telemetry` command with `--enable`/`--disable`/`--status` options
|
|
139
|
+
- collect CLI usage telemetry via PostHog (EU cloud, opt-out, no PII)
|
|
140
|
+
- add `--host` flag to `serve` and `kanban` commands for LAN sharing (0.0.0.0 binds all interfaces)
|
|
141
|
+
|
|
142
|
+
### Bug Fixes
|
|
143
|
+
|
|
144
|
+
- fix tag sync in CLI kanban detail panel (tags were lost after WS round-trip)
|
|
145
|
+
- fix tag add failure (missing DB migration for tags column)
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## [0.1.1] - 2026-04-10
|
|
150
|
+
|
|
151
|
+
### Features
|
|
152
|
+
|
|
153
|
+
- initial kanban board browser UI
|
|
154
|
+
- overlay script injection for HTML prototypes
|
|
155
|
+
- SaaS API integration (tasks sync, comments, files)
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## [0.1.0] - 2026-04-01
|
|
160
|
+
|
|
161
|
+
### Features
|
|
162
|
+
|
|
163
|
+
- initial release: `serve`, `tasks`, `push`, `auth` commands
|
|
164
|
+
- HTML prototype annotation with overlay
|
|
165
|
+
- local task management via `.vibeflow/tasks/`
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{readdirSync as H,writeFileSync as M,readFileSync as G,unlinkSync as k,statSync as b,mkdirSync as q,existsSync as c}from"fs";import{join as f,basename as A}from"path";var d=".vibeflow",I="tasks",T="tasks/files",P="tasks/screenshots",w="config.json";import{existsSync as m,readFileSync as O,writeFileSync as V,mkdirSync as p,readdirSync as h,unlinkSync as v,renameSync as $}from"fs";import{join as a,extname as D}from"path";import{randomBytes as B}from"crypto";var W=["backlog","todo","in-progress","review","done"];function j(){return B(15).toString("hex")}function S(t){return a(t,d,I)}function U(t){let n=a(t,d),e=a(n,"files"),r=a(n,T),s=a(n,"screenshots"),i=a(n,P);if(m(e)){p(r,{recursive:!0});for(let o of h(e)){let l=a(e,o),u=a(r,o);if(!m(u))try{$(l,u)}catch{}}}if(m(s)){p(i,{recursive:!0});for(let o of h(s)){let l=a(s,o),u=a(i,o);if(!m(u))try{$(l,u)}catch{}}}}function st(t){U(t),p(S(t),{recursive:!0}),p(a(t,d,P),{recursive:!0})}function E(t){return t.slice(0,10)}function J(t,n,e){let r=S(t);return e?a(r,E(e),`${n}.json`):a(r,`${n}.json`)}function x(t,n){let e=S(t);if(!m(e))return null;for(let r of h(e,{withFileTypes:!0}))if(r.isDirectory()){let s=a(e,r.name,`${n}.json`);if(m(s))return s}else if(r.name===`${n}.json`)return a(e,r.name);return null}function K(t){let n=(()=>{if(typeof t.type!="string")return;let e=t.type.trim();if(!(!e||e==="[object Object]"))return e})();return{id:String(t.id??""),title:String(t.title??"Untitled"),description:String(t.description??""),status:W.includes(t.status)?t.status:"todo",url:t.url?String(t.url):void 0,selector:(()=>{let e=String(t.selector??"/");return t.file&&!t.cssSelector&&e.startsWith(String(t.file))?t.url?String(t.url):"/":e})(),cssSelector:t.cssSelector&&String(t.cssSelector)!==String(t.selector??"/")?String(t.cssSelector):void 0,file:t.file?String(t.file):void 0,line:t.line!=null?Number(t.line):void 0,col:t.col!=null?Number(t.col):void 0,component:t.component?String(t.component):void 0,type:n,priority:t.priority?String(t.priority):void 0,...t.reportBack===!0&&{reportBack:!0},agent:t.agent?String(t.agent):void 0,model:t.model?String(t.model):void 0,author:t.author?String(t.author):void 0,commits:Array.isArray(t.commits)?t.commits.map(e=>({sha:String(e.sha??""),message:String(e.message??""),timestamp:String(e.timestamp??new Date().toISOString())})):void 0,created:String(t.created??new Date().toISOString()),updated:t.updated?String(t.updated):void 0,comments:Array.isArray(t.comments)?t.comments.map(e=>({...e,text:e.text??e.content??""})):[],files:Array.isArray(t.files)?t.files.map(e=>typeof e=="string"?{name:e,addedAt:new Date().toISOString()}:{name:String(e.name??""),addedAt:String(e.addedAt??new Date().toISOString()),linkedPath:e.linkedPath?String(e.linkedPath):void 0,mimeType:e.mimeType?String(e.mimeType):void 0}).filter(e=>e.name):[],screenshot:t.screenshot?String(t.screenshot):void 0,annotatedElementText:t.annotatedElementText?String(t.annotatedElementText):void 0,tags:Array.isArray(t.tags)?t.tags.filter(e=>typeof e=="string"&&e.length>0):void 0}}function _(t,n){let e=a(S(t),E(n.created));p(e,{recursive:!0});let r=a(e,`${n.id}.json`),s=r+".tmp";V(s,JSON.stringify(n,null,2),"utf-8"),$(s,r)}function ot(t,n){let e=(()=>{let s=(n.priority??"").trim().toLowerCase();return s==="critical"?"Critical":s==="high"?"High":s==="low"?"Low":"Medium"})(),r={...n,priority:e,id:j(),created:new Date().toISOString(),comments:[],files:[]};return _(t,r),r}function y(t){try{let n=O(t,"utf-8");if(t.endsWith(".json")){let e=JSON.parse(n);return!e||typeof e!="object"||!("id"in e)?null:K(e)}return null}catch{return null}}function z(t){let n=S(t);if(!m(n))return[];let e=[];for(let r of h(n,{withFileTypes:!0}))if(r.isDirectory()){let s=a(n,r.name);for(let i of h(s))if(D(i)===".json"){let o=a(s,i),l=y(o);l&&e.push({task:l,filePath:o})}}else if(D(r.name)===".json"){let s=a(n,r.name),i=y(s);i&&e.push({task:i,filePath:s})}return e}function lt(t){return z(t).map(({task:n})=>n)}function at(t){return z(t).map(({task:n,filePath:e})=>({...n,filePath:e}))}function L(t,n,e){let r=x(t,n),s=r?y(r):null;if(!s)return null;let i={...s,...e,updated:new Date().toISOString()};if(_(t,i),r&&r!==J(t,n,i.created))try{v(r)}catch{}return i}function ut(t,n){let e=x(t,n);return e?(v(e),!0):!1}function ct(t,n,e){return{id:t.id,status:t.status,title:t.title,description:t.description,...t.url&&{url:t.url},selector:t.selector,...t.file&&{file:t.file},...t.line!=null&&{line:t.line},...t.col!=null&&{col:t.col},...t.component&&{component:t.component},...t.type&&{type:t.type},...t.priority&&{priority:t.priority},...n&&n.length>0&&{structuredComments:n},...e&&e.length>0&&{linkedFiles:e},...t.reportBack&&{reportBack:!0},created:t.created}}function ft(t,n,e,r,s){let i=[];if(i.push(`[${t.status}] ${t.title}`),i.push(` id: ${t.id}`),i.push(` file: ${n}`),t.file&&i.push(` source: ${t.file}${t.line!=null?`:${t.line}`:""}${t.col!=null?`:${t.col}`:""}`),t.component&&i.push(` component: ${t.component}`),i.push(` selector: ${t.selector??"/"}`),t.cssSelector&&i.push(` css: ${t.cssSelector}`),t.url&&i.push(` url: ${t.url}`),t.commits&&t.commits.length>0)if(t.commits.length===1)i.push(` commit: ${t.commits[0].sha}`);else{i.push(` commits (${t.commits.length}):`);for(let o of t.commits)i.push(` ${o.sha.slice(0,8)} ${o.timestamp} ${o.message.slice(0,60)}`)}if(i.push(` created: ${t.created}`),t.type&&i.push(` type: ${t.type}`),t.priority&&i.push(` priority: ${t.priority}`),t.author&&i.push(` author: ${t.author}`),t.description){i.push(" description:");for(let o of t.description.split(`
|
|
3
|
+
`))i.push(` ${o}`)}if(t.annotatedElementText&&i.push(` element text: ${t.annotatedElementText}`),e.length>0){i.push(` comments (${e.length}):`);for(let o of e){let l=o.updatedAt?` (edited ${o.updatedAt})`:"";i.push(` [${o.author??"user"}] ${o.createdAt}${l}`);for(let u of o.text.split(`
|
|
4
|
+
`))i.push(` ${u}`)}}if(r.length>0){i.push(` linked files (${r.length}):`);for(let o of r){i.push(` - ${o.name} ${o.url}`);let l=o.linkedPath??a(s,".vibeflow","files",t.id,o.name);if(/\.(md|txt)$/i.test(o.name)&&o.size<1e5&&m(l))try{let u=O(l,"utf-8");i.push(" \u250C\u2500\u2500 content \u2500\u2500");for(let N of u.split(`
|
|
5
|
+
`))i.push(` \u2502 ${N}`);i.push(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}catch{}}}return i.join(`
|
|
6
|
+
`)}var R=".linked.json";function g(t,n){return f(t,d,T,n)}function Q(t,n){q(g(t,n),{recursive:!0})}function X(t,n){let e=f(g(t,n),R);if(!c(e))return[];try{return JSON.parse(G(e,"utf-8"))}catch{return[]}}function Y(t,n){let e=x(t,n),r=e?y(e):null;return!r?.files||r.files.length===0?[]:r.files}function C(t,n,e){L(t,n,{files:e})}function F(t,n){let e=Y(t,n),r=f(g(t,n),R);if(!c(r))return e;let s=X(t,n);if(s.length===0){try{k(r)}catch{}return e}let i=e.slice(),o=!1;for(let l of s)i.find(u=>u.linkedPath===l.path||u.name===l.name&&u.linkedPath)||(i.push({name:l.name,linkedPath:l.path,addedAt:new Date().toISOString()}),o=!0);o&&C(t,n,i);try{k(r)}catch{}return i}function Z(t,n){let e=g(t,n),r=F(t,n),s=new Map;for(let i of r){if(i.linkedPath&&c(i.linkedPath)){let l=b(i.linkedPath);s.set(i.name,{name:i.name,size:l.size,url:`/api/tasks/${n}/files/${encodeURIComponent(i.name)}`,linkedPath:i.linkedPath,createdAt:l.mtime.toISOString()});continue}let o=f(e,i.name);if(c(o)){let l=b(o);s.set(i.name,{name:i.name,size:l.size,url:`/api/tasks/${n}/files/${encodeURIComponent(i.name)}`,createdAt:l.mtime.toISOString()})}}if(c(e))for(let i of H(e,{withFileTypes:!0})){if(!i.isFile()||i.name===R||s.has(i.name))continue;let o=f(e,i.name),l=b(o);s.set(i.name,{name:i.name,size:l.size,url:`/api/tasks/${n}/files/${encodeURIComponent(i.name)}`,createdAt:l.mtime.toISOString()})}return Array.from(s.values())}function St(t,n,e,r){let s=A(e);Q(t,n),M(f(g(t,n),s),r);let i=F(t,n);return i.find(o=>o.name===s&&!o.linkedPath)||(i.push({name:s,addedAt:new Date().toISOString()}),C(t,n,i)),{name:s,size:r.length,url:`/api/tasks/${n}/files/${encodeURIComponent(s)}`}}function Tt(t,n,e){let r=A(e),s=F(t,n),i=s.findIndex(l=>l.name===r);if(i!==-1){let[l]=s.splice(i,1);if(C(t,n,s),l&&!l.linkedPath){let u=f(g(t,n),r);c(u)&&k(u)}return!0}let o=f(g(t,n),r);return c(o)?(k(o),!0):!1}function xt(t,n,e){let r=A(e),s=F(t,n).find(o=>o.name===r&&o.linkedPath);if(s?.linkedPath&&c(s.linkedPath))return s.linkedPath;let i=f(g(t,n),r);return c(i)?i:null}function kt(t,n){return Z(t,n).length}export{d as a,I as b,P as c,w as d,j as e,st as f,J as g,x as h,ot as i,y as j,lt as k,at as l,L as m,ut as n,ct as o,ft as p,g as q,Q as r,Z as s,St as t,Tt as u,xt as v,kt as w};
|
|
@@ -0,0 +1,7 @@
|
|
|
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(`
|
|
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(`
|
|
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};
|
|
@@ -0,0 +1,7 @@
|
|
|
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 m}from"fs";import{join as f,basename as v}from"path";var g=".vibeflow",$="tasks",S="tasks/files",R="tasks/screenshots",Z="config.json";import{existsSync as c,readFileSync as O,writeFileSync as E,mkdirSync as p,readdirSync as h,unlinkSync as D,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(c(n)){p(i,{recursive:!0});for(let r of h(n)){let a=u(n,r),l=u(i,r);if(!c(l))try{A(a,l)}catch{}}}if(c(o)){p(t,{recursive:!0});for(let r of h(o)){let a=u(o,r),l=u(t,r);if(!c(l))try{A(a,l)}catch{}}}}function re(e){j(e),p(k(e),{recursive:!0}),p(u(e,g,R),{recursive:!0});let s=u(e,".opencode"),n=u(s,"opencode.json");c(n)||(p(s,{recursive:!0}),E(n,JSON.stringify({$schema:"https://opencode.ai/config.json",plugin:["opencode-snip@latest"]},null,2),"utf-8"))}function w(e){return e.slice(0,10)}function U(e,s,n){let i=k(e);return n?u(i,w(n),`${s}.json`):u(i,`${s}.json`)}function T(e,s){let n=k(e);if(!c(n))return null;for(let i of h(n,{withFileTypes:!0}))if(i.isDirectory()){let o=u(n,i.name,`${s}.json`);if(c(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 L(e,s){let n=u(k(e),w(s.created));p(n,{recursive:!0});let i=u(n,`${s.id}.json`),o=i+".tmp";E(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 L(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 N(e){let s=k(e);if(!c(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 N(e).map(({task:s})=>s)}function ue(e){return N(e).map(({task:s,filePath:n})=>({...s,filePath:n}))}function B(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(L(e,t),i&&i!==U(e,s,t.created))try{D(i)}catch{}return t}function le(e,s){let n=T(e,s);return n?(D(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(`
|
|
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&&c(a))try{let l=O(a,"utf-8");t.push(" \u250C\u2500\u2500 content \u2500\u2500");for(let _ of l.split(`
|
|
5
|
+
`))t.push(` \u2502 ${_}`);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 f(e,g,S,s)}function G(e,s){q(d(e,s),{recursive:!0})}function Y(e,s){let n=f(d(e,s),P);if(!m(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){B(e,s,{files:n})}function x(e,s){let n=Q(e,s),i=f(d(e,s),P);if(!m(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&&m(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=f(n,t.name);if(m(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(m(n))for(let t of M(n,{withFileTypes:!0})){if(!t.isFile()||t.name===P||o.has(t.name))continue;let r=f(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(f(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=f(d(e,s),i);m(l)&&b(l)}return!0}let r=f(d(e,s),i);return m(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&&m(o.linkedPath))return o.linkedPath;let t=f(d(e,s),i);return m(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,B 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};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{readdirSync as H,writeFileSync as M,readFileSync as G,unlinkSync as k,statSync as b,mkdirSync as q,existsSync as c}from"fs";import{join as f,basename as A}from"path";var d=".vibeflow",I="tasks",T="tasks/files",P="tasks/screenshots",w="config.json";import{existsSync as m,readFileSync as O,writeFileSync as V,mkdirSync as p,readdirSync as h,unlinkSync as v,renameSync as $}from"fs";import{join as a,extname as D}from"path";import{randomBytes as B}from"crypto";var W=["backlog","todo","in-progress","review","done"];function j(){return B(15).toString("hex")}function S(t){return a(t,d,I)}function U(t){let n=a(t,d),e=a(n,"files"),r=a(n,T),s=a(n,"screenshots"),i=a(n,P);if(m(e)){p(r,{recursive:!0});for(let o of h(e)){let l=a(e,o),u=a(r,o);if(!m(u))try{$(l,u)}catch{}}}if(m(s)){p(i,{recursive:!0});for(let o of h(s)){let l=a(s,o),u=a(i,o);if(!m(u))try{$(l,u)}catch{}}}}function st(t){U(t),p(S(t),{recursive:!0}),p(a(t,d,P),{recursive:!0})}function E(t){return t.slice(0,10)}function J(t,n,e){let r=S(t);return e?a(r,E(e),`${n}.json`):a(r,`${n}.json`)}function x(t,n){let e=S(t);if(!m(e))return null;for(let r of h(e,{withFileTypes:!0}))if(r.isDirectory()){let s=a(e,r.name,`${n}.json`);if(m(s))return s}else if(r.name===`${n}.json`)return a(e,r.name);return null}function K(t){let n=(()=>{if(typeof t.type!="string")return;let e=t.type.trim();if(!(!e||e==="[object Object]"))return e})();return{id:String(t.id??""),title:String(t.title??"Untitled"),description:String(t.description??""),status:W.includes(t.status)?t.status:"todo",url:t.url?String(t.url):void 0,selector:(()=>{let e=String(t.selector??"/");return t.file&&!t.cssSelector&&e.startsWith(String(t.file))?t.url?String(t.url):"/":e})(),cssSelector:t.cssSelector&&String(t.cssSelector)!==String(t.selector??"/")?String(t.cssSelector):void 0,file:t.file?String(t.file):void 0,line:t.line!=null?Number(t.line):void 0,col:t.col!=null?Number(t.col):void 0,component:t.component?String(t.component):void 0,type:n,priority:t.priority?String(t.priority):void 0,...t.reportBack===!0&&{reportBack:!0},agent:t.agent?String(t.agent):void 0,model:t.model?String(t.model):void 0,author:t.author?String(t.author):void 0,commits:Array.isArray(t.commits)?t.commits.map(e=>({sha:String(e.sha??""),message:String(e.message??""),timestamp:String(e.timestamp??new Date().toISOString())})):void 0,created:String(t.created??new Date().toISOString()),updated:t.updated?String(t.updated):void 0,comments:Array.isArray(t.comments)?t.comments.map(e=>({...e,text:e.text??e.content??""})):[],files:Array.isArray(t.files)?t.files.map(e=>typeof e=="string"?{name:e,addedAt:new Date().toISOString()}:{name:String(e.name??""),addedAt:String(e.addedAt??new Date().toISOString()),linkedPath:e.linkedPath?String(e.linkedPath):void 0,mimeType:e.mimeType?String(e.mimeType):void 0}).filter(e=>e.name):[],screenshot:t.screenshot?String(t.screenshot):void 0,annotatedElementText:t.annotatedElementText?String(t.annotatedElementText):void 0,tags:Array.isArray(t.tags)?t.tags.filter(e=>typeof e=="string"&&e.length>0):void 0}}function _(t,n){let e=a(S(t),E(n.created));p(e,{recursive:!0});let r=a(e,`${n.id}.json`),s=r+".tmp";V(s,JSON.stringify(n,null,2),"utf-8"),$(s,r)}function ot(t,n){let e=(()=>{let s=(n.priority??"").trim().toLowerCase();return s==="critical"?"Critical":s==="high"?"High":s==="low"?"Low":"Medium"})(),r={...n,priority:e,id:j(),created:new Date().toISOString(),comments:[],files:[]};return _(t,r),r}function y(t){try{let n=O(t,"utf-8");if(t.endsWith(".json")){let e=JSON.parse(n);return!e||typeof e!="object"||!("id"in e)?null:K(e)}return null}catch{return null}}function z(t){let n=S(t);if(!m(n))return[];let e=[];for(let r of h(n,{withFileTypes:!0}))if(r.isDirectory()){let s=a(n,r.name);for(let i of h(s))if(D(i)===".json"){let o=a(s,i),l=y(o);l&&e.push({task:l,filePath:o})}}else if(D(r.name)===".json"){let s=a(n,r.name),i=y(s);i&&e.push({task:i,filePath:s})}return e}function lt(t){return z(t).map(({task:n})=>n)}function at(t){return z(t).map(({task:n,filePath:e})=>({...n,filePath:e}))}function L(t,n,e){let r=x(t,n),s=r?y(r):null;if(!s)return null;let i={...s,...e,updated:new Date().toISOString()};if(_(t,i),r&&r!==J(t,n,i.created))try{v(r)}catch{}return i}function ut(t,n){let e=x(t,n);return e?(v(e),!0):!1}function ct(t,n,e){return{id:t.id,status:t.status,title:t.title,description:t.description,...t.url&&{url:t.url},selector:t.selector,...t.file&&{file:t.file},...t.line!=null&&{line:t.line},...t.col!=null&&{col:t.col},...t.component&&{component:t.component},...t.type&&{type:t.type},...t.priority&&{priority:t.priority},...n&&n.length>0&&{structuredComments:n},...e&&e.length>0&&{linkedFiles:e},...t.reportBack&&{reportBack:!0},created:t.created}}function ft(t,n,e,r,s){let i=[];if(i.push(`[${t.status}] ${t.title}`),i.push(` id: ${t.id}`),i.push(` file: ${n}`),t.file&&i.push(` source: ${t.file}${t.line!=null?`:${t.line}`:""}${t.col!=null?`:${t.col}`:""}`),t.component&&i.push(` component: ${t.component}`),i.push(` selector: ${t.selector??"/"}`),t.cssSelector&&i.push(` css: ${t.cssSelector}`),t.url&&i.push(` url: ${t.url}`),t.commits&&t.commits.length>0)if(t.commits.length===1)i.push(` commit: ${t.commits[0].sha}`);else{i.push(` commits (${t.commits.length}):`);for(let o of t.commits)i.push(` ${o.sha.slice(0,8)} ${o.timestamp} ${o.message.slice(0,60)}`)}if(i.push(` created: ${t.created}`),t.type&&i.push(` type: ${t.type}`),t.priority&&i.push(` priority: ${t.priority}`),t.author&&i.push(` author: ${t.author}`),t.description){i.push(" description:");for(let o of t.description.split(`
|
|
3
|
+
`))i.push(` ${o}`)}if(t.annotatedElementText&&i.push(` element text: ${t.annotatedElementText}`),e.length>0){i.push(` comments (${e.length}):`);for(let o of e){let l=o.updatedAt?` (edited ${o.updatedAt})`:"";i.push(` [${o.author??"user"}] ${o.createdAt}${l}`);for(let u of o.text.split(`
|
|
4
|
+
`))i.push(` ${u}`)}}if(r.length>0){i.push(` linked files (${r.length}):`);for(let o of r){i.push(` - ${o.name} ${o.url}`);let l=o.linkedPath??a(s,".vibeflow","files",t.id,o.name);if(/\.(md|txt)$/i.test(o.name)&&o.size<1e5&&m(l))try{let u=O(l,"utf-8");i.push(" \u250C\u2500\u2500 content \u2500\u2500");for(let N of u.split(`
|
|
5
|
+
`))i.push(` \u2502 ${N}`);i.push(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}catch{}}}return i.join(`
|
|
6
|
+
`)}var R=".linked.json";function g(t,n){return f(t,d,T,n)}function Q(t,n){q(g(t,n),{recursive:!0})}function X(t,n){let e=f(g(t,n),R);if(!c(e))return[];try{return JSON.parse(G(e,"utf-8"))}catch{return[]}}function Y(t,n){let e=x(t,n),r=e?y(e):null;return!r?.files||r.files.length===0?[]:r.files}function C(t,n,e){L(t,n,{files:e})}function F(t,n){let e=Y(t,n),r=f(g(t,n),R);if(!c(r))return e;let s=X(t,n);if(s.length===0){try{k(r)}catch{}return e}let i=e.slice(),o=!1;for(let l of s)i.find(u=>u.linkedPath===l.path||u.name===l.name&&u.linkedPath)||(i.push({name:l.name,linkedPath:l.path,addedAt:new Date().toISOString()}),o=!0);o&&C(t,n,i);try{k(r)}catch{}return i}function Z(t,n){let e=g(t,n),r=F(t,n),s=new Map;for(let i of r){if(i.linkedPath&&c(i.linkedPath)){let l=b(i.linkedPath);s.set(i.name,{name:i.name,size:l.size,url:`/api/tasks/${n}/files/${encodeURIComponent(i.name)}`,linkedPath:i.linkedPath,createdAt:l.mtime.toISOString()});continue}let o=f(e,i.name);if(c(o)){let l=b(o);s.set(i.name,{name:i.name,size:l.size,url:`/api/tasks/${n}/files/${encodeURIComponent(i.name)}`,createdAt:l.mtime.toISOString()})}}if(c(e))for(let i of H(e,{withFileTypes:!0})){if(!i.isFile()||i.name===R||s.has(i.name))continue;let o=f(e,i.name),l=b(o);s.set(i.name,{name:i.name,size:l.size,url:`/api/tasks/${n}/files/${encodeURIComponent(i.name)}`,createdAt:l.mtime.toISOString()})}return Array.from(s.values())}function St(t,n,e,r){let s=A(e);Q(t,n),M(f(g(t,n),s),r);let i=F(t,n);return i.find(o=>o.name===s&&!o.linkedPath)||(i.push({name:s,addedAt:new Date().toISOString()}),C(t,n,i)),{name:s,size:r.length,url:`/api/tasks/${n}/files/${encodeURIComponent(s)}`}}function Tt(t,n,e){let r=A(e),s=F(t,n),i=s.findIndex(l=>l.name===r);if(i!==-1){let[l]=s.splice(i,1);if(C(t,n,s),l&&!l.linkedPath){let u=f(g(t,n),r);c(u)&&k(u)}return!0}let o=f(g(t,n),r);return c(o)?(k(o),!0):!1}function xt(t,n,e){let r=A(e),s=F(t,n).find(o=>o.name===r&&o.linkedPath);if(s?.linkedPath&&c(s.linkedPath))return s.linkedPath;let i=f(g(t,n),r);return c(i)?i:null}function kt(t,n){return Z(t,n).length}export{d as a,I as b,P as c,w as d,j as e,st as f,J as g,x as h,ot as i,y as j,lt as k,at as l,L as m,ut as n,ct as o,ft as p,g as q,Q as r,Z as s,St as t,Tt as u,xt as v,kt as w};
|
|
@@ -0,0 +1,7 @@
|
|
|
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(`
|
|
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(`
|
|
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};
|
|
@@ -0,0 +1,7 @@
|
|
|
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 m}from"fs";import{join as f,basename as v}from"path";var g=".vibeflow",$="tasks",S="tasks/files",R="tasks/screenshots",Z="config.json";import{existsSync as c,readFileSync as O,writeFileSync as E,mkdirSync as p,readdirSync as h,unlinkSync as D,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(c(n)){p(i,{recursive:!0});for(let r of h(n)){let a=u(n,r),l=u(i,r);if(!c(l))try{A(a,l)}catch{}}}if(c(o)){p(t,{recursive:!0});for(let r of h(o)){let a=u(o,r),l=u(t,r);if(!c(l))try{A(a,l)}catch{}}}}function re(e){j(e),p(k(e),{recursive:!0}),p(u(e,g,R),{recursive:!0});let s=u(e,".opencode"),n=u(s,"opencode.json");c(n)||(p(s,{recursive:!0}),E(n,JSON.stringify({$schema:"https://opencode.ai/config.json",plugin:["opencode-snip@latest"]},null,2),"utf-8"))}function w(e){return e.slice(0,10)}function U(e,s,n){let i=k(e);return n?u(i,w(n),`${s}.json`):u(i,`${s}.json`)}function T(e,s){let n=k(e);if(!c(n))return null;for(let i of h(n,{withFileTypes:!0}))if(i.isDirectory()){let o=u(n,i.name,`${s}.json`);if(c(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 L(e,s){let n=u(k(e),w(s.created));p(n,{recursive:!0});let i=u(n,`${s.id}.json`),o=i+".tmp";E(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 L(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 N(e){let s=k(e);if(!c(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 N(e).map(({task:s})=>s)}function ue(e){return N(e).map(({task:s,filePath:n})=>({...s,filePath:n}))}function B(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(L(e,t),i&&i!==U(e,s,t.created))try{D(i)}catch{}return t}function le(e,s){let n=T(e,s);return n?(D(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(`
|
|
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&&c(a))try{let l=O(a,"utf-8");t.push(" \u250C\u2500\u2500 content \u2500\u2500");for(let _ of l.split(`
|
|
5
|
+
`))t.push(` \u2502 ${_}`);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 f(e,g,S,s)}function G(e,s){q(d(e,s),{recursive:!0})}function Y(e,s){let n=f(d(e,s),P);if(!m(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){B(e,s,{files:n})}function x(e,s){let n=Q(e,s),i=f(d(e,s),P);if(!m(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&&m(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=f(n,t.name);if(m(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(m(n))for(let t of M(n,{withFileTypes:!0})){if(!t.isFile()||t.name===P||o.has(t.name))continue;let r=f(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(f(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=f(d(e,s),i);m(l)&&b(l)}return!0}let r=f(d(e,s),i);return m(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&&m(o.linkedPath))return o.linkedPath;let t=f(d(e,s),i);return m(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,B 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};
|