@vibeflow-tools/cli 0.4.1 → 0.5.0

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 ADDED
@@ -0,0 +1,158 @@
1
+ # Changelog
2
+
3
+ ## 0.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - `tasks --next` now supports combining with `--type`, `--user`, and `--tag` filters to pick the next available todo task matching specific criteria.
8
+
9
+ ### Patch Changes
10
+
11
+ - 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.
12
+ - Fix kanban drag-and-drop: tasks no longer jump to the top of a column after being dragged.
13
+ - Fix kanban board columns being unequal widths; all columns are now a fixed 280px.
14
+ - 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`.
15
+ - fix: dragging a task to reorder now only updates the dragged task, not all others in the column
16
+
17
+ ## 0.4.2
18
+
19
+ ### Patch Changes
20
+
21
+ - 9cd0d82: Write task files atomically via a .tmp file and renameSync to prevent torn JSON reads during concurrent writes (BUG-09).
22
+ - 9cd0d82: Sanitize boardId before embedding in injected HTML/JS to prevent HTML injection via a malformed workspace ID (BUG-10).
23
+ - 9cd0d82: Fix addComment, updateComment, and deleteComment to read raw task data so soft-deleted comments are preserved instead of silently dropped (B1).
24
+ - 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).
25
+ - 9cd0d82: Fix logout to also delete the stored workspace file so the CLI fully returns to local mode (BUG-03).
26
+ - 9cd0d82: Add status value validation to PATCH /api/tasks/:id to reject unknown status strings (BUG-05).
27
+ - 9cd0d82: Pass projectDir to promptPushLocalTasks so it reads tasks from the correct project root instead of process.cwd() (BUG-07).
28
+ - 9cd0d82: Key remoteCommitCache by projectDir to avoid cross-project SHA collisions when multiple projects are open (BUG-02).
29
+ - 9cd0d82: Remove undeclared commit field from normalizeTask to prevent stale data from persisting in normalized task objects (B2).
30
+ - 9cd0d82: Allowlist known keys in POST /api/settings to prevent writing arbitrary fields to the project settings file (BUG-08).
31
+ - 9cd0d82: Replace hardcoded .vibeflow/tasks path in task watcher with PROTO_DIR and TASKS_DIR constants (BUG-06).
32
+ - 9cd0d82: Escape double-quote characters in renderMarkdown to prevent XSS via attribute injection in link hrefs (BUG-01).
33
+ - 9cd0d82: Use cryptographically random bytes for comment IDs instead of Date.now() to avoid collisions under concurrent writes (I5).
34
+ - 9cd0d82: Replace process.exit(1) calls in login.ts with process.exitCode = 1; return to allow async cleanup handlers to run (I1).
35
+ - 9cd0d82: Remove unused slugify function from tasks.ts; no production code imports it (F11).
36
+ - 9cd0d82: Import PROTO_DIR constant from core/types in settings.ts instead of duplicating the hardcoded string (F13).
37
+ - 9cd0d82: Compute commentCount and fileCount from embedded task arrays instead of reading from disk in the /api/tasks response (P3).
38
+ - 9cd0d82: Write copilot config file with 0o600 permissions to prevent other users from reading the stored token (SEC-04).
39
+ - 9cd0d82: Add file extension allowlist to the CLI file upload endpoint to reject unsupported MIME types (SEC-09).
40
+ - 9cd0d82: Reject POST and DELETE mutation requests from cross-origin pages to prevent unauthorized agent-status and settings writes (SEC-02).
41
+ - 9cd0d82: Validate workspace URL against an allowlist of production domains before using it as the SaaS API base URL, preventing SSRF (SEC-08).
42
+ - 9cd0d82: Serve screenshots through a route handler that validates task ID format instead of an unauthenticated static directory (SEC-05).
43
+ - 9cd0d82: Only trust X-Forwarded-For header for rate limiting when TRUSTED_PROXY=1 env var is set, preventing IP spoofing (SEC-01).
44
+
45
+ ## 0.4.1
46
+
47
+ ### Patch Changes
48
+
49
+ - 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`.
50
+
51
+ ## 0.4.0
52
+
53
+ ### Minor Changes
54
+
55
+ - 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.
56
+ - 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`.
57
+ - 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.
58
+
59
+ ### Patch Changes
60
+
61
+ - 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`.
62
+
63
+ All notable changes to `@vibeflow-tools/cli` are documented here.
64
+
65
+ Format follows [Conventional Commits](https://www.conventionalcommits.org/) → [SemVer](https://semver.org/).
66
+
67
+ ---
68
+
69
+ ## [0.3.2] - 2026-04-24
70
+
71
+ ### Bug Fixes
72
+
73
+ - add comprehensive error handling to board creation endpoints (workspace.create, workspace.createWithBoard) with detailed logging of input, user ID, and root error cause
74
+ - improves debuggability when board creation fails due to database constraints or other issues
75
+
76
+ ---
77
+
78
+ ## [0.3.1] - 2026-04-24
79
+
80
+ ### Bug Fixes
81
+
82
+ - 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)
83
+ - GlobalErrorHandler now gracefully handles minimal errors (e.g., single-character messages) and supplements them with context (stack, line number, error name)
84
+
85
+ ### Tests
86
+
87
+ - add 11 comprehensive unit tests for error extraction logic covering Error objects, strings, objects with message property, null/undefined, and edge cases
88
+
89
+ ---
90
+
91
+ ## [0.3.0] - 2026-04-24
92
+
93
+ ### Features
94
+
95
+ - require `X-Overlay-Api-Key` header on `GET /api/overlay/tasks` — overlay GET endpoint is now authenticated (breaking: clients must include API key)
96
+ - overlay `fetchTasks` now sends `X-Overlay-Api-Key` header when `data-overlay-api-key` is set on the script tag
97
+
98
+ ### Bug Fixes
99
+
100
+ - fix backspace key in header tag search not removing the last active filter tag
101
+ - fix `BETTER_AUTH_SECRET` empty-string bypass (`??` → `||` so empty string correctly falls back to `NEXTAUTH_SECRET`)
102
+
103
+ ### Chores
104
+
105
+ - fix telemetry config path lazy evaluation — improves test isolation when `HOME` env is overridden
106
+
107
+ ---
108
+
109
+ ## [0.2.1] - 2026-04-24
110
+
111
+ ### Bug Fixes
112
+
113
+ - fix telemetry config path to use lazy evaluation so tests correctly isolate `HOME` override
114
+
115
+ ---
116
+
117
+ ## [0.2.0] - 2026-04-24
118
+
119
+ ### Features
120
+
121
+ - 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)
122
+
123
+ ---
124
+
125
+ ## [0.1.2] - 2026-04-24
126
+
127
+ ### Features
128
+
129
+ - add `--tag` filter to `tasks` command — filter tasks by one or more tags
130
+ - add `--next` flag to `tasks` command — select highest-priority next task automatically
131
+ - add `telemetry` command with `--enable`/`--disable`/`--status` options
132
+ - collect CLI usage telemetry via PostHog (EU cloud, opt-out, no PII)
133
+ - add `--host` flag to `serve` and `kanban` commands for LAN sharing (0.0.0.0 binds all interfaces)
134
+
135
+ ### Bug Fixes
136
+
137
+ - fix tag sync in CLI kanban detail panel (tags were lost after WS round-trip)
138
+ - fix tag add failure (missing DB migration for tags column)
139
+
140
+ ---
141
+
142
+ ## [0.1.1] - 2026-04-10
143
+
144
+ ### Features
145
+
146
+ - initial kanban board browser UI
147
+ - overlay script injection for HTML prototypes
148
+ - SaaS API integration (tasks sync, comments, files)
149
+
150
+ ---
151
+
152
+ ## [0.1.0] - 2026-04-01
153
+
154
+ ### Features
155
+
156
+ - initial release: `serve`, `tasks`, `push`, `auth` commands
157
+ - HTML prototype annotation with overlay
158
+ - local task management via `.vibeflow/tasks/`
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{readdirSync as H,writeFileSync as K,readFileSync as M,unlinkSync as x,statSync as R,mkdirSync as G,existsSync as c}from"fs";import{join as f,basename as A}from"path";var d=".vibeflow",D="tasks",k="tasks/files",P="tasks/screenshots",Z="config.json";import{existsSync as m,readFileSync as N,writeFileSync as z,mkdirSync as p,readdirSync as y,unlinkSync as v,renameSync as b}from"fs";import{join as l,extname as O}from"path";import{randomBytes as V}from"crypto";var B=["backlog","todo","in-progress","review","done"];function W(){return V(15).toString("hex")}function h(t){return l(t,d,D)}function U(t){let n=l(t,d),e=l(n,"files"),i=l(n,k),s=l(n,"screenshots"),r=l(n,P);if(m(e)){p(i,{recursive:!0});for(let o of y(e)){let a=l(e,o),u=l(i,o);if(!m(u))try{b(a,u)}catch{}}}if(m(s)){p(r,{recursive:!0});for(let o of y(s)){let a=l(s,o),u=l(r,o);if(!m(u))try{b(a,u)}catch{}}}}function rt(t){U(t),p(h(t),{recursive:!0}),p(l(t,d,P),{recursive:!0})}function E(t){return t.slice(0,10)}function j(t,n,e){let i=h(t);return e?l(i,E(e),`${n}.json`):l(i,`${n}.json`)}function T(t,n){let e=h(t);if(!m(e))return null;for(let i of y(e,{withFileTypes:!0}))if(i.isDirectory()){let s=l(e,i.name,`${n}.json`);if(m(s))return s}else if(i.name===`${n}.json`)return l(e,i.name);return null}function J(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:B.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=l(h(t),E(n.created));p(e,{recursive:!0});let i=l(e,`${n.id}.json`),s=i+".tmp";z(s,JSON.stringify(n,null,2),"utf-8"),b(s,i)}function st(t,n){let e=(()=>{let s=(n.priority??"").trim().toLowerCase();return s==="critical"?"Critical":s==="high"?"High":s==="low"?"Low":"Medium"})(),i={...n,priority:e,id:W(),created:new Date().toISOString(),comments:[],files:[]};return _(t,i),i}function S(t){try{let n=N(t,"utf-8");if(t.endsWith(".json")){let e=JSON.parse(n);return!e||typeof e!="object"||!("id"in e)?null:J(e)}return null}catch{return null}}function $(t){let n=h(t);if(!m(n))return[];let e=[];for(let i of y(n,{withFileTypes:!0}))if(i.isDirectory()){let s=l(n,i.name);for(let r of y(s))if(O(r)===".json"){let o=l(s,r),a=S(o);a&&e.push({task:a,filePath:o})}}else if(O(i.name)===".json"){let s=l(n,i.name),r=S(s);r&&e.push({task:r,filePath:s})}return e}function ot(t){return $(t).map(({task:n})=>n)}function at(t){return $(t).map(({task:n,filePath:e})=>({...n,filePath:e}))}function L(t,n,e){let i=T(t,n),s=i?S(i):null;if(!s)return null;let r={...s,...e,updated:new Date().toISOString()};if(_(t,r),i&&i!==j(t,n,r.created))try{v(i)}catch{}return r}function lt(t,n){let e=T(t,n);return e?(v(e),!0):!1}function ut(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}}var C=".linked.json";function g(t,n){return f(t,d,k,n)}function q(t,n){G(g(t,n),{recursive:!0})}function Q(t,n){let e=f(g(t,n),C);if(!c(e))return[];try{return JSON.parse(M(e,"utf-8"))}catch{return[]}}function X(t,n){let e=T(t,n),i=e?S(e):null;return!i?.files||i.files.length===0?[]:i.files}function I(t,n,e){L(t,n,{files:e})}function F(t,n){let e=X(t,n),i=f(g(t,n),C);if(!c(i))return e;let s=Q(t,n);if(s.length===0){try{x(i)}catch{}return e}let r=e.slice(),o=!1;for(let a of s)r.find(u=>u.linkedPath===a.path||u.name===a.name&&u.linkedPath)||(r.push({name:a.name,linkedPath:a.path,addedAt:new Date().toISOString()}),o=!0);o&&I(t,n,r);try{x(i)}catch{}return r}function Y(t,n){let e=g(t,n),i=F(t,n),s=new Map;for(let r of i){if(r.linkedPath&&c(r.linkedPath)){let a=R(r.linkedPath);s.set(r.name,{name:r.name,size:a.size,url:`/api/tasks/${n}/files/${encodeURIComponent(r.name)}`,linkedPath:r.linkedPath,createdAt:a.mtime.toISOString()});continue}let o=f(e,r.name);if(c(o)){let a=R(o);s.set(r.name,{name:r.name,size:a.size,url:`/api/tasks/${n}/files/${encodeURIComponent(r.name)}`,createdAt:a.mtime.toISOString()})}}if(c(e))for(let r of H(e,{withFileTypes:!0})){if(!r.isFile()||r.name===C||s.has(r.name))continue;let o=f(e,r.name),a=R(o);s.set(r.name,{name:r.name,size:a.size,url:`/api/tasks/${n}/files/${encodeURIComponent(r.name)}`,createdAt:a.mtime.toISOString()})}return Array.from(s.values())}function yt(t,n,e,i){let s=A(e);q(t,n),K(f(g(t,n),s),i);let r=F(t,n);return r.find(o=>o.name===s&&!o.linkedPath)||(r.push({name:s,addedAt:new Date().toISOString()}),I(t,n,r)),{name:s,size:i.length,url:`/api/tasks/${n}/files/${encodeURIComponent(s)}`}}function St(t,n,e){let i=A(e),s=F(t,n),r=s.findIndex(a=>a.name===i);if(r!==-1){let[a]=s.splice(r,1);if(I(t,n,s),a&&!a.linkedPath){let u=f(g(t,n),i);c(u)&&x(u)}return!0}let o=f(g(t,n),i);return c(o)?(x(o),!0):!1}function ht(t,n,e){let i=A(e),s=F(t,n).find(o=>o.name===i&&o.linkedPath);if(s?.linkedPath&&c(s.linkedPath))return s.linkedPath;let r=f(g(t,n),i);return c(r)?r:null}function kt(t,n){return Y(t,n).length}export{d as a,D as b,P as c,Z as d,W as e,rt as f,j as g,T as h,st as i,S as j,ot as k,at as l,L as m,lt as n,ut as o,g as p,q,Y as r,yt as s,St as t,ht as u,kt as v};
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{readdirSync as K,writeFileSync as H,readFileSync as M,unlinkSync as x,statSync as R,mkdirSync as G,existsSync as c}from"fs";import{join as f,basename as A}from"path";var d=".vibeflow",D="tasks",k="tasks/files",P="tasks/screenshots",Z="config.json";import{existsSync as m,readFileSync as N,writeFileSync as z,mkdirSync as p,readdirSync as y,unlinkSync as v,renameSync as b}from"fs";import{join as l,extname as O}from"path";import{randomBytes as V}from"crypto";var B=["backlog","todo","in-progress","review","done"];function W(){return V(15).toString("hex")}function h(t){return l(t,d,D)}function U(t){let n=l(t,d),e=l(n,"files"),i=l(n,k),s=l(n,"screenshots"),r=l(n,P);if(m(e)){p(i,{recursive:!0});for(let o of y(e)){let a=l(e,o),u=l(i,o);if(!m(u))try{b(a,u)}catch{}}}if(m(s)){p(r,{recursive:!0});for(let o of y(s)){let a=l(s,o),u=l(r,o);if(!m(u))try{b(a,u)}catch{}}}}function rt(t){U(t),p(h(t),{recursive:!0}),p(l(t,d,P),{recursive:!0})}function E(t){return t.slice(0,10)}function j(t,n,e){let i=h(t);return e?l(i,E(e),`${n}.json`):l(i,`${n}.json`)}function T(t,n){let e=h(t);if(!m(e))return null;for(let i of y(e,{withFileTypes:!0}))if(i.isDirectory()){let s=l(e,i.name,`${n}.json`);if(m(s))return s}else if(i.name===`${n}.json`)return l(e,i.name);return null}function J(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:B.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=l(h(t),E(n.created));p(e,{recursive:!0});let i=l(e,`${n.id}.json`),s=i+".tmp";z(s,JSON.stringify(n,null,2),"utf-8"),b(s,i)}function st(t,n){let e=(()=>{let s=(n.priority??"").trim().toLowerCase();return s==="critical"?"Critical":s==="high"?"High":s==="low"?"Low":"Medium"})(),i={...n,priority:e,id:W(),created:new Date().toISOString(),comments:[],files:[]};return _(t,i),i}function S(t){try{let n=N(t,"utf-8");if(t.endsWith(".json")){let e=JSON.parse(n);return!e||typeof e!="object"||!("id"in e)?null:J(e)}return null}catch{return null}}function $(t){let n=h(t);if(!m(n))return[];let e=[];for(let i of y(n,{withFileTypes:!0}))if(i.isDirectory()){let s=l(n,i.name);for(let r of y(s))if(O(r)===".json"){let o=l(s,r),a=S(o);a&&e.push({task:a,filePath:o})}}else if(O(i.name)===".json"){let s=l(n,i.name),r=S(s);r&&e.push({task:r,filePath:s})}return e}function ot(t){return $(t).map(({task:n})=>n)}function at(t){return $(t).map(({task:n,filePath:e})=>({...n,filePath:e}))}function L(t,n,e){let i=T(t,n),s=i?S(i):null;if(!s)return null;let r={...s,...e,updated:new Date().toISOString()};if(_(t,r),i&&i!==j(t,n,r.created))try{v(i)}catch{}return r}function lt(t,n){let e=T(t,n);return e?(v(e),!0):!1}function ut(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}}var C=".linked.json";function g(t,n){return f(t,d,k,n)}function q(t,n){G(g(t,n),{recursive:!0})}function Q(t,n){let e=f(g(t,n),C);if(!c(e))return[];try{return JSON.parse(M(e,"utf-8"))}catch{return[]}}function X(t,n){let e=T(t,n),i=e?S(e):null;return!i?.files||i.files.length===0?[]:i.files}function I(t,n,e){L(t,n,{files:e})}function F(t,n){let e=X(t,n),i=f(g(t,n),C);if(!c(i))return e;let s=Q(t,n);if(s.length===0){try{x(i)}catch{}return e}let r=e.slice(),o=!1;for(let a of s)r.find(u=>u.linkedPath===a.path||u.name===a.name&&u.linkedPath)||(r.push({name:a.name,linkedPath:a.path,addedAt:new Date().toISOString()}),o=!0);o&&I(t,n,r);try{x(i)}catch{}return r}function Y(t,n){let e=g(t,n),i=F(t,n),s=new Map;for(let r of i){if(r.linkedPath&&c(r.linkedPath)){let a=R(r.linkedPath);s.set(r.name,{name:r.name,size:a.size,url:`/api/tasks/${n}/files/${encodeURIComponent(r.name)}`,linkedPath:r.linkedPath,createdAt:a.mtime.toISOString()});continue}let o=f(e,r.name);if(c(o)){let a=R(o);s.set(r.name,{name:r.name,size:a.size,url:`/api/tasks/${n}/files/${encodeURIComponent(r.name)}`,createdAt:a.mtime.toISOString()})}}if(c(e))for(let r of K(e,{withFileTypes:!0})){if(!r.isFile()||r.name===C||s.has(r.name))continue;let o=f(e,r.name),a=R(o);s.set(r.name,{name:r.name,size:a.size,url:`/api/tasks/${n}/files/${encodeURIComponent(r.name)}`,createdAt:a.mtime.toISOString()})}return Array.from(s.values())}function yt(t,n,e,i){let s=A(e);q(t,n),H(f(g(t,n),s),i);let r=F(t,n);return r.find(o=>o.name===s&&!o.linkedPath)||(r.push({name:s,addedAt:new Date().toISOString()}),I(t,n,r)),{name:s,size:i.length,url:`/api/tasks/${n}/files/${encodeURIComponent(s)}`}}function St(t,n,e){let i=A(e),s=F(t,n),r=s.findIndex(a=>a.name===i);if(r!==-1){let[a]=s.splice(r,1);if(I(t,n,s),a&&!a.linkedPath){let u=f(g(t,n),i);c(u)&&x(u)}return!0}let o=f(g(t,n),i);return c(o)?(x(o),!0):!1}function ht(t,n,e){let i=A(e),s=F(t,n).find(o=>o.name===i&&o.linkedPath);if(s?.linkedPath&&c(s.linkedPath))return s.linkedPath;let r=f(g(t,n),i);return c(r)?r:null}function kt(t,n){return Y(t,n).length}export{d as a,D as b,P as c,Z as d,W as e,rt as f,j as g,T as h,st as i,S as j,ot as k,at as l,L as m,lt as n,ut as o,g as p,q,Y as r,yt as s,St as t,ht as u,kt as v};
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{readdirSync as H,writeFileSync as K,readFileSync as M,unlinkSync as x,statSync as R,mkdirSync as G,existsSync as c}from"fs";import{join as f,basename as A}from"path";var d=".vibeflow",D="tasks",k="tasks/files",P="tasks/screenshots",Z="config.json";import{existsSync as m,readFileSync as N,writeFileSync as z,mkdirSync as p,readdirSync as y,unlinkSync as v,renameSync as b}from"fs";import{join as l,extname as O}from"path";import{randomBytes as V}from"crypto";var B=["backlog","todo","in-progress","review","done"];function W(){return V(15).toString("hex")}function h(t){return l(t,d,D)}function U(t){let n=l(t,d),e=l(n,"files"),i=l(n,k),s=l(n,"screenshots"),r=l(n,P);if(m(e)){p(i,{recursive:!0});for(let o of y(e)){let a=l(e,o),u=l(i,o);if(!m(u))try{b(a,u)}catch{}}}if(m(s)){p(r,{recursive:!0});for(let o of y(s)){let a=l(s,o),u=l(r,o);if(!m(u))try{b(a,u)}catch{}}}}function rt(t){U(t),p(h(t),{recursive:!0}),p(l(t,d,P),{recursive:!0})}function E(t){return t.slice(0,10)}function j(t,n,e){let i=h(t);return e?l(i,E(e),`${n}.json`):l(i,`${n}.json`)}function T(t,n){let e=h(t);if(!m(e))return null;for(let i of y(e,{withFileTypes:!0}))if(i.isDirectory()){let s=l(e,i.name,`${n}.json`);if(m(s))return s}else if(i.name===`${n}.json`)return l(e,i.name);return null}function J(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:B.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=l(h(t),E(n.created));p(e,{recursive:!0});let i=l(e,`${n.id}.json`),s=i+".tmp";z(s,JSON.stringify(n,null,2),"utf-8"),b(s,i)}function st(t,n){let e=(()=>{let s=(n.priority??"").trim().toLowerCase();return s==="critical"?"Critical":s==="high"?"High":s==="low"?"Low":"Medium"})(),i={...n,priority:e,id:W(),created:new Date().toISOString(),comments:[],files:[]};return _(t,i),i}function S(t){try{let n=N(t,"utf-8");if(t.endsWith(".json")){let e=JSON.parse(n);return!e||typeof e!="object"||!("id"in e)?null:J(e)}return null}catch{return null}}function $(t){let n=h(t);if(!m(n))return[];let e=[];for(let i of y(n,{withFileTypes:!0}))if(i.isDirectory()){let s=l(n,i.name);for(let r of y(s))if(O(r)===".json"){let o=l(s,r),a=S(o);a&&e.push({task:a,filePath:o})}}else if(O(i.name)===".json"){let s=l(n,i.name),r=S(s);r&&e.push({task:r,filePath:s})}return e}function ot(t){return $(t).map(({task:n})=>n)}function at(t){return $(t).map(({task:n,filePath:e})=>({...n,filePath:e}))}function L(t,n,e){let i=T(t,n),s=i?S(i):null;if(!s)return null;let r={...s,...e,updated:new Date().toISOString()};if(_(t,r),i&&i!==j(t,n,r.created))try{v(i)}catch{}return r}function lt(t,n){let e=T(t,n);return e?(v(e),!0):!1}function ut(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}}var C=".linked.json";function g(t,n){return f(t,d,k,n)}function q(t,n){G(g(t,n),{recursive:!0})}function Q(t,n){let e=f(g(t,n),C);if(!c(e))return[];try{return JSON.parse(M(e,"utf-8"))}catch{return[]}}function X(t,n){let e=T(t,n),i=e?S(e):null;return!i?.files||i.files.length===0?[]:i.files}function I(t,n,e){L(t,n,{files:e})}function F(t,n){let e=X(t,n),i=f(g(t,n),C);if(!c(i))return e;let s=Q(t,n);if(s.length===0){try{x(i)}catch{}return e}let r=e.slice(),o=!1;for(let a of s)r.find(u=>u.linkedPath===a.path||u.name===a.name&&u.linkedPath)||(r.push({name:a.name,linkedPath:a.path,addedAt:new Date().toISOString()}),o=!0);o&&I(t,n,r);try{x(i)}catch{}return r}function Y(t,n){let e=g(t,n),i=F(t,n),s=new Map;for(let r of i){if(r.linkedPath&&c(r.linkedPath)){let a=R(r.linkedPath);s.set(r.name,{name:r.name,size:a.size,url:`/api/tasks/${n}/files/${encodeURIComponent(r.name)}`,linkedPath:r.linkedPath,createdAt:a.mtime.toISOString()});continue}let o=f(e,r.name);if(c(o)){let a=R(o);s.set(r.name,{name:r.name,size:a.size,url:`/api/tasks/${n}/files/${encodeURIComponent(r.name)}`,createdAt:a.mtime.toISOString()})}}if(c(e))for(let r of H(e,{withFileTypes:!0})){if(!r.isFile()||r.name===C||s.has(r.name))continue;let o=f(e,r.name),a=R(o);s.set(r.name,{name:r.name,size:a.size,url:`/api/tasks/${n}/files/${encodeURIComponent(r.name)}`,createdAt:a.mtime.toISOString()})}return Array.from(s.values())}function yt(t,n,e,i){let s=A(e);q(t,n),K(f(g(t,n),s),i);let r=F(t,n);return r.find(o=>o.name===s&&!o.linkedPath)||(r.push({name:s,addedAt:new Date().toISOString()}),I(t,n,r)),{name:s,size:i.length,url:`/api/tasks/${n}/files/${encodeURIComponent(s)}`}}function St(t,n,e){let i=A(e),s=F(t,n),r=s.findIndex(a=>a.name===i);if(r!==-1){let[a]=s.splice(r,1);if(I(t,n,s),a&&!a.linkedPath){let u=f(g(t,n),i);c(u)&&x(u)}return!0}let o=f(g(t,n),i);return c(o)?(x(o),!0):!1}function ht(t,n,e){let i=A(e),s=F(t,n).find(o=>o.name===i&&o.linkedPath);if(s?.linkedPath&&c(s.linkedPath))return s.linkedPath;let r=f(g(t,n),i);return c(r)?r:null}function kt(t,n){return Y(t,n).length}export{d as a,D as b,P as c,Z as d,W as e,rt as f,j as g,T as h,st as i,S as j,ot as k,at as l,L as m,lt as n,ut as o,g as p,q,Y as r,yt as s,St as t,ht as u,kt as v};
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{readdirSync as K,writeFileSync as H,readFileSync as M,unlinkSync as x,statSync as R,mkdirSync as G,existsSync as c}from"fs";import{join as f,basename as A}from"path";var d=".vibeflow",D="tasks",k="tasks/files",P="tasks/screenshots",Z="config.json";import{existsSync as m,readFileSync as N,writeFileSync as z,mkdirSync as p,readdirSync as y,unlinkSync as v,renameSync as b}from"fs";import{join as l,extname as O}from"path";import{randomBytes as V}from"crypto";var B=["backlog","todo","in-progress","review","done"];function W(){return V(15).toString("hex")}function h(t){return l(t,d,D)}function U(t){let n=l(t,d),e=l(n,"files"),i=l(n,k),s=l(n,"screenshots"),r=l(n,P);if(m(e)){p(i,{recursive:!0});for(let o of y(e)){let a=l(e,o),u=l(i,o);if(!m(u))try{b(a,u)}catch{}}}if(m(s)){p(r,{recursive:!0});for(let o of y(s)){let a=l(s,o),u=l(r,o);if(!m(u))try{b(a,u)}catch{}}}}function rt(t){U(t),p(h(t),{recursive:!0}),p(l(t,d,P),{recursive:!0})}function E(t){return t.slice(0,10)}function j(t,n,e){let i=h(t);return e?l(i,E(e),`${n}.json`):l(i,`${n}.json`)}function T(t,n){let e=h(t);if(!m(e))return null;for(let i of y(e,{withFileTypes:!0}))if(i.isDirectory()){let s=l(e,i.name,`${n}.json`);if(m(s))return s}else if(i.name===`${n}.json`)return l(e,i.name);return null}function J(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:B.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=l(h(t),E(n.created));p(e,{recursive:!0});let i=l(e,`${n.id}.json`),s=i+".tmp";z(s,JSON.stringify(n,null,2),"utf-8"),b(s,i)}function st(t,n){let e=(()=>{let s=(n.priority??"").trim().toLowerCase();return s==="critical"?"Critical":s==="high"?"High":s==="low"?"Low":"Medium"})(),i={...n,priority:e,id:W(),created:new Date().toISOString(),comments:[],files:[]};return _(t,i),i}function S(t){try{let n=N(t,"utf-8");if(t.endsWith(".json")){let e=JSON.parse(n);return!e||typeof e!="object"||!("id"in e)?null:J(e)}return null}catch{return null}}function $(t){let n=h(t);if(!m(n))return[];let e=[];for(let i of y(n,{withFileTypes:!0}))if(i.isDirectory()){let s=l(n,i.name);for(let r of y(s))if(O(r)===".json"){let o=l(s,r),a=S(o);a&&e.push({task:a,filePath:o})}}else if(O(i.name)===".json"){let s=l(n,i.name),r=S(s);r&&e.push({task:r,filePath:s})}return e}function ot(t){return $(t).map(({task:n})=>n)}function at(t){return $(t).map(({task:n,filePath:e})=>({...n,filePath:e}))}function L(t,n,e){let i=T(t,n),s=i?S(i):null;if(!s)return null;let r={...s,...e,updated:new Date().toISOString()};if(_(t,r),i&&i!==j(t,n,r.created))try{v(i)}catch{}return r}function lt(t,n){let e=T(t,n);return e?(v(e),!0):!1}function ut(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}}var C=".linked.json";function g(t,n){return f(t,d,k,n)}function q(t,n){G(g(t,n),{recursive:!0})}function Q(t,n){let e=f(g(t,n),C);if(!c(e))return[];try{return JSON.parse(M(e,"utf-8"))}catch{return[]}}function X(t,n){let e=T(t,n),i=e?S(e):null;return!i?.files||i.files.length===0?[]:i.files}function I(t,n,e){L(t,n,{files:e})}function F(t,n){let e=X(t,n),i=f(g(t,n),C);if(!c(i))return e;let s=Q(t,n);if(s.length===0){try{x(i)}catch{}return e}let r=e.slice(),o=!1;for(let a of s)r.find(u=>u.linkedPath===a.path||u.name===a.name&&u.linkedPath)||(r.push({name:a.name,linkedPath:a.path,addedAt:new Date().toISOString()}),o=!0);o&&I(t,n,r);try{x(i)}catch{}return r}function Y(t,n){let e=g(t,n),i=F(t,n),s=new Map;for(let r of i){if(r.linkedPath&&c(r.linkedPath)){let a=R(r.linkedPath);s.set(r.name,{name:r.name,size:a.size,url:`/api/tasks/${n}/files/${encodeURIComponent(r.name)}`,linkedPath:r.linkedPath,createdAt:a.mtime.toISOString()});continue}let o=f(e,r.name);if(c(o)){let a=R(o);s.set(r.name,{name:r.name,size:a.size,url:`/api/tasks/${n}/files/${encodeURIComponent(r.name)}`,createdAt:a.mtime.toISOString()})}}if(c(e))for(let r of K(e,{withFileTypes:!0})){if(!r.isFile()||r.name===C||s.has(r.name))continue;let o=f(e,r.name),a=R(o);s.set(r.name,{name:r.name,size:a.size,url:`/api/tasks/${n}/files/${encodeURIComponent(r.name)}`,createdAt:a.mtime.toISOString()})}return Array.from(s.values())}function yt(t,n,e,i){let s=A(e);q(t,n),H(f(g(t,n),s),i);let r=F(t,n);return r.find(o=>o.name===s&&!o.linkedPath)||(r.push({name:s,addedAt:new Date().toISOString()}),I(t,n,r)),{name:s,size:i.length,url:`/api/tasks/${n}/files/${encodeURIComponent(s)}`}}function St(t,n,e){let i=A(e),s=F(t,n),r=s.findIndex(a=>a.name===i);if(r!==-1){let[a]=s.splice(r,1);if(I(t,n,s),a&&!a.linkedPath){let u=f(g(t,n),i);c(u)&&x(u)}return!0}let o=f(g(t,n),i);return c(o)?(x(o),!0):!1}function ht(t,n,e){let i=A(e),s=F(t,n).find(o=>o.name===i&&o.linkedPath);if(s?.linkedPath&&c(s.linkedPath))return s.linkedPath;let r=f(g(t,n),i);return c(r)?r:null}function kt(t,n){return Y(t,n).length}export{d as a,D as b,P as c,Z as d,W as e,rt as f,j as g,T as h,st as i,S as j,ot as k,at as l,L as m,lt as n,ut as o,g as p,q,Y as r,yt as s,St as t,ht as u,kt as v};
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{p as a,q as b,r as c,s as d,t as e,u as f,v as g}from"./chunk-BQLZVQ4E.js";export{e as deleteFile,b as ensureFilesDir,g as getFileCount,f as getFilePath,a as getFilesDir,c as listFiles,d as saveFile};
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{p as a,q as b,r as c,s as d,t as e,u as f,v as g}from"./chunk-252RNKHM.js";export{e as deleteFile,b as ensureFilesDir,g as getFileCount,f as getFilePath,a as getFilesDir,c as listFiles,d as saveFile};