@vibeflow-tools/cli 0.11.0 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/chunk-22ZK3AD6.js +6 -0
  3. package/dist/chunk-2CI62NHU.js +8 -0
  4. package/dist/chunk-2FTOVVDE.js +10 -0
  5. package/dist/chunk-2HKRXAUP.js +10 -0
  6. package/dist/chunk-32Z32W7T.js +2 -0
  7. package/dist/chunk-3V7HLRIS.js +6 -0
  8. package/dist/chunk-4KWRHSXU.js +10 -0
  9. package/dist/chunk-ACDVAO4P.js +6 -0
  10. package/dist/chunk-BBIA4IIO.js +2 -0
  11. package/dist/chunk-BOPGIKZN.js +8 -0
  12. package/dist/chunk-BUQI2W5H.js +2 -0
  13. package/dist/chunk-BZDBSBRV.js +2 -0
  14. package/dist/chunk-CKNX42Z3.js +10 -0
  15. package/dist/chunk-CQ524DVH.js +2 -0
  16. package/dist/chunk-EAYTSVCN.js +2 -0
  17. package/dist/chunk-EDJNSJXJ.js +10 -0
  18. package/dist/chunk-EZX6HYC3.js +8 -0
  19. package/dist/chunk-FYRJDWDC.js +2 -0
  20. package/dist/chunk-GN436FFO.js +10 -0
  21. package/dist/chunk-GQQIUROY.js +2 -0
  22. package/dist/chunk-GTZDS3U3.js +6 -0
  23. package/dist/chunk-ICO6AZHJ.js +10 -0
  24. package/dist/chunk-IJ67OEKX.js +2 -0
  25. package/dist/chunk-ILUMCOF2.js +2 -0
  26. package/dist/chunk-JAWQQLJC.js +8 -0
  27. package/dist/chunk-JQTURVVN.js +2 -0
  28. package/dist/chunk-KZZ4ADHY.js +6 -0
  29. package/dist/chunk-L6EJ7QTO.js +6 -0
  30. package/dist/chunk-LYJHU4LP.js +10 -0
  31. package/dist/chunk-N5PXJMOU.js +6 -0
  32. package/dist/chunk-NHVKGOSV.js +10 -0
  33. package/dist/chunk-O4LGEPMQ.js +8 -0
  34. package/dist/chunk-P63ZVL36.js +2 -0
  35. package/dist/chunk-PFOVGF7M.js +10 -0
  36. package/dist/chunk-PGGJRQCO.js +2 -0
  37. package/dist/chunk-PN5C7EHL.js +8 -0
  38. package/dist/chunk-PWP474PZ.js +2 -0
  39. package/dist/chunk-Q7MEW67Z.js +8 -0
  40. package/dist/chunk-QJMBWTAZ.js +8 -0
  41. package/dist/chunk-R5NQALFI.js +2 -0
  42. package/dist/chunk-RBBUTBE3.js +6 -0
  43. package/dist/chunk-RRQ5P63N.js +2 -0
  44. package/dist/chunk-SQPWTIQO.js +2 -0
  45. package/dist/chunk-TTWEWSD3.js +6 -0
  46. package/dist/chunk-WARORREB.js +2 -0
  47. package/dist/chunk-WHXU37AT.js +10 -0
  48. package/dist/chunk-WKEMBLJR.js +2 -0
  49. package/dist/chunk-WVRMKUU5.js +6 -0
  50. package/dist/chunk-WZ2QQDYW.js +2 -0
  51. package/dist/chunk-X3VLCXWS.js +6 -0
  52. package/dist/chunk-X4CQRMD4.js +6 -0
  53. package/dist/chunk-X4RGF6JJ.js +2 -0
  54. package/dist/chunk-XHZXHACL.js +2 -0
  55. package/dist/chunk-XJ35INCK.js +10 -0
  56. package/dist/chunk-YMBPKWZ4.js +2 -0
  57. package/dist/chunk-ZHA4Y2KB.js +8 -0
  58. package/dist/cli/chunk-22ZK3AD6.js +6 -0
  59. package/dist/cli/chunk-2CI62NHU.js +8 -0
  60. package/dist/cli/chunk-2FTOVVDE.js +10 -0
  61. package/dist/cli/chunk-2HKRXAUP.js +10 -0
  62. package/dist/cli/chunk-32Z32W7T.js +2 -0
  63. package/dist/cli/chunk-3V7HLRIS.js +6 -0
  64. package/dist/cli/chunk-4KWRHSXU.js +10 -0
  65. package/dist/cli/chunk-ACDVAO4P.js +6 -0
  66. package/dist/cli/chunk-BBIA4IIO.js +2 -0
  67. package/dist/cli/chunk-BOPGIKZN.js +8 -0
  68. package/dist/cli/chunk-BUQI2W5H.js +2 -0
  69. package/dist/cli/chunk-BZDBSBRV.js +2 -0
  70. package/dist/cli/chunk-CKNX42Z3.js +10 -0
  71. package/dist/cli/chunk-CQ524DVH.js +2 -0
  72. package/dist/cli/chunk-EAYTSVCN.js +2 -0
  73. package/dist/cli/chunk-EDJNSJXJ.js +10 -0
  74. package/dist/cli/chunk-EZX6HYC3.js +8 -0
  75. package/dist/cli/chunk-FYRJDWDC.js +2 -0
  76. package/dist/cli/chunk-GN436FFO.js +10 -0
  77. package/dist/cli/chunk-GQQIUROY.js +2 -0
  78. package/dist/cli/chunk-GTZDS3U3.js +6 -0
  79. package/dist/cli/chunk-ICO6AZHJ.js +10 -0
  80. package/dist/cli/chunk-IJ67OEKX.js +2 -0
  81. package/dist/cli/chunk-ILUMCOF2.js +2 -0
  82. package/dist/cli/chunk-JAWQQLJC.js +8 -0
  83. package/dist/cli/chunk-JQTURVVN.js +2 -0
  84. package/dist/cli/chunk-KZZ4ADHY.js +6 -0
  85. package/dist/cli/chunk-L6EJ7QTO.js +6 -0
  86. package/dist/cli/chunk-LYJHU4LP.js +10 -0
  87. package/dist/cli/chunk-N5PXJMOU.js +6 -0
  88. package/dist/cli/chunk-NHVKGOSV.js +10 -0
  89. package/dist/cli/chunk-O4LGEPMQ.js +8 -0
  90. package/dist/cli/chunk-P63ZVL36.js +2 -0
  91. package/dist/cli/chunk-PFOVGF7M.js +10 -0
  92. package/dist/cli/chunk-PGGJRQCO.js +2 -0
  93. package/dist/cli/chunk-PN5C7EHL.js +8 -0
  94. package/dist/cli/chunk-PWP474PZ.js +2 -0
  95. package/dist/cli/chunk-Q7MEW67Z.js +8 -0
  96. package/dist/cli/chunk-QJMBWTAZ.js +8 -0
  97. package/dist/cli/chunk-R5NQALFI.js +2 -0
  98. package/dist/cli/chunk-RBBUTBE3.js +6 -0
  99. package/dist/cli/chunk-RRQ5P63N.js +2 -0
  100. package/dist/cli/chunk-SQPWTIQO.js +2 -0
  101. package/dist/cli/chunk-TTWEWSD3.js +6 -0
  102. package/dist/cli/chunk-WARORREB.js +2 -0
  103. package/dist/cli/chunk-WHXU37AT.js +10 -0
  104. package/dist/cli/chunk-WKEMBLJR.js +2 -0
  105. package/dist/cli/chunk-WVRMKUU5.js +6 -0
  106. package/dist/cli/chunk-WZ2QQDYW.js +2 -0
  107. package/dist/cli/chunk-X3VLCXWS.js +6 -0
  108. package/dist/cli/chunk-X4CQRMD4.js +6 -0
  109. package/dist/cli/chunk-X4RGF6JJ.js +2 -0
  110. package/dist/cli/chunk-XHZXHACL.js +2 -0
  111. package/dist/cli/chunk-XJ35INCK.js +10 -0
  112. package/dist/cli/chunk-YMBPKWZ4.js +2 -0
  113. package/dist/cli/chunk-ZHA4Y2KB.js +8 -0
  114. package/dist/cli/comments-5LRGOYLT.js +2 -0
  115. package/dist/cli/comments-D3SKM2F4.js +2 -0
  116. package/dist/cli/comments-GGE2X2EE.js +2 -0
  117. package/dist/cli/comments-GZ6HQMHL.js +2 -0
  118. package/dist/cli/comments-LHSMBKJ3.js +2 -0
  119. package/dist/cli/comments-M5HDNHXR.js +2 -0
  120. package/dist/cli/comments-MJP5KLEE.js +2 -0
  121. package/dist/cli/comments-TQHWMRB4.js +2 -0
  122. package/dist/cli/comments-VSWJW47E.js +2 -0
  123. package/dist/cli/files-3GGL6AHA.js +2 -0
  124. package/dist/cli/files-4M7AX2IR.js +2 -0
  125. package/dist/cli/files-7GFBKISD.js +2 -0
  126. package/dist/cli/files-7H73XU4Z.js +2 -0
  127. package/dist/cli/files-FL23FKMK.js +2 -0
  128. package/dist/cli/files-GQPP5SSP.js +2 -0
  129. package/dist/cli/files-QO35EIJI.js +2 -0
  130. package/dist/cli/files-R6BRCQQX.js +2 -0
  131. package/dist/cli/files-WH4W5IPG.js +2 -0
  132. package/dist/cli/files-XKVCQQMI.js +2 -0
  133. package/dist/cli/git-NH6PGXOM.js +2 -0
  134. package/dist/cli/index.js +63 -71
  135. package/dist/cli/push-25YMX4RZ.js +2 -0
  136. package/dist/cli/push-26JSGYHL.js +2 -0
  137. package/dist/cli/push-5NNA77B2.js +2 -0
  138. package/dist/cli/push-7M34G4OW.js +2 -0
  139. package/dist/cli/push-AARMGHSL.js +2 -0
  140. package/dist/cli/push-EVBLKP53.js +2 -0
  141. package/dist/cli/push-HG6EPV6P.js +2 -0
  142. package/dist/cli/push-RFYHMZBR.js +2 -0
  143. package/dist/cli/push-RQJQM7U7.js +2 -0
  144. package/dist/cli/push-S4G36KHW.js +2 -0
  145. package/dist/cli/push-S5XSREE5.js +2 -0
  146. package/dist/cli/push-SWN2KN2R.js +2 -0
  147. package/dist/cli/review-gate-MGMU7CIR.js +2 -0
  148. package/dist/cli/review-gate-QR2E4REN.js +2 -0
  149. package/dist/cli/settings-KKHPB344.js +2 -0
  150. package/dist/cli/settings-PYRZJJ4H.js +2 -0
  151. package/dist/cli/tasks-3HXDHCPS.js +2 -0
  152. package/dist/cli/tasks-5X5AAK2N.js +2 -0
  153. package/dist/cli/tasks-MUL5SYJQ.js +2 -0
  154. package/dist/cli/tasks-N3AEGAEB.js +2 -0
  155. package/dist/cli/tasks-NSLXFEXZ.js +2 -0
  156. package/dist/cli/tasks-OJTUAWAN.js +2 -0
  157. package/dist/cli/tasks-SV7ZVS7W.js +2 -0
  158. package/dist/cli/tasks-VCU3JVNJ.js +2 -0
  159. package/dist/cli/verify-44MRXSPT.js +2 -0
  160. package/dist/cli/verify-AXMQ27UT.js +2 -0
  161. package/dist/cli/verify-BJ62CQI3.js +2 -0
  162. package/dist/cli/verify-DEG2BZOB.js +2 -0
  163. package/dist/cli/verify-DGL7A4WD.js +2 -0
  164. package/dist/cli/verify-GP427VCE.js +2 -0
  165. package/dist/cli/verify-QUCASFYP.js +2 -0
  166. package/dist/cli/verify-RY7B6C2P.js +2 -0
  167. package/dist/cli/verify-TTAW3GG6.js +2 -0
  168. package/dist/cli/verify-VLVCMBBW.js +2 -0
  169. package/dist/cli/verify-XL7JI7LN.js +2 -0
  170. package/dist/cli/verify-ZOAIUNRD.js +2 -0
  171. package/dist/cli/workspace-AJAVENKA.js +2 -0
  172. package/dist/client/kanban-browser.js +16 -15
  173. package/dist/client/overlay-browser.js +4 -4
  174. package/dist/files-3GGL6AHA.js +2 -0
  175. package/dist/files-4M7AX2IR.js +2 -0
  176. package/dist/files-7GFBKISD.js +2 -0
  177. package/dist/files-7H73XU4Z.js +2 -0
  178. package/dist/files-FL23FKMK.js +2 -0
  179. package/dist/files-GQPP5SSP.js +2 -0
  180. package/dist/files-QO35EIJI.js +2 -0
  181. package/dist/files-R6BRCQQX.js +2 -0
  182. package/dist/files-WH4W5IPG.js +2 -0
  183. package/dist/files-XKVCQQMI.js +2 -0
  184. package/dist/index.js +63 -71
  185. package/dist/workspace-AJAVENKA.js +2 -0
  186. package/package.json +2 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.12.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 6881de6: Fix verify gate: skip enforcement when no baseline.json exists
8
+
9
+ Auto-created log-cluster tasks have selector+url but no baseline screenshot. The verify gate now checks baseline.json existence before blocking review.
10
+
11
+ ## 0.12.0
12
+
13
+ ### Minor Changes
14
+
15
+ > ⚠️ The `MCP server` is experimental and may change without notice.
16
+
17
+ - 405b3f8: MCP server: streamable HTTP endpoint at `/api/mcp` exposing 10 task tools (list_tasks, get_task, create_task, update_task, claim_next_task, add_comment, attach_file, export_prompt, verify_task, push_tasks). Manifest-driven — new CLI commands are auto-discovered. Auth: loopback-only locally, Bearer token for SaaS. Session management with 30-min TTL.
18
+ - 148cd3c: Kanban: new Compact view mode (Board | Compact | List). Compact shows one-line rows across all lanes — no tags, no comment/file counts. Done lane fits cards to screen height with "+N more" indicator. Overlay: add-task dialog now has an Advanced section with tag chips and priority selector.
19
+ - c57b423: Verify gate: optional enforcement in Settings > Enforcement. When ON, agents must run `vibeflow verify` before setting status to review. Auto-skips for non-UI tasks. `--skip-verify` flag available as bypass.
20
+
21
+ ### Patch Changes
22
+
23
+ - ef67d56: Comment edits now broadcast to live UI. File uploads reject reserved filenames (.env, .git\*, .linked.json). Task schema limits enforced (titles 500 chars, descriptions 10K, URLs 2K).
24
+ - 7f96921: File upload validation hardened: rejects filenames with leading dots, enforces max length (255 chars), and validates extensions against an allowlist. 24 new tests.
25
+ - 074e376: Concurrent task writes now safely serialized via cross-process lock. GET endpoints are side-effect-free. Unified priority sorting across CLI and API.
26
+ - 16112b3: Atomic task claim: `--next` now re-checks status inside a lock, preventing double-claims under concurrent access.
27
+ - 803ca05: Review gate shared between CLI and REST. PATCH route now filters unexpected fields. Comment and verify requirements enforced.
28
+ - cf9dc82: Push dry-run mode, orphan task cleanup, verify cancellation via AbortSignal, serve deduplication.
29
+ - 1c3385d: Schema validation now enforces max lengths on task titles, descriptions, URLs, and selectors. Oversized fields are rejected with a clear error instead of being silently stored.
30
+ - 405b3f8: Fix file count badge display and changelog button styling in the kanban UI.
31
+
3
32
  ## 0.11.0
4
33
 
5
34
  ### Minor Changes
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ import{a as w}from"./chunk-BZDBSBRV.js";import{a as B,d as U}from"./chunk-32Z32W7T.js";import{c as P,d as E,u as N}from"./chunk-ZHA4Y2KB.js";import{a as A,b as _}from"./chunk-KJ5LYG6A.js";import g from"chalk";import{unlinkSync as ye,readFileSync as ke,existsSync as we}from"fs";import{resolve as Se,join as $e}from"path";import I from"fs/promises";import oe from"os";import F from"path";var re=F.join(oe.homedir(),".vibeflow"),T=F.join(re,"token");async function b(){try{return(await I.readFile(T,"utf8")).trim()||null}catch{return null}}async function j(e){await I.mkdir(F.dirname(T),{recursive:!0}),await I.writeFile(T,e,{mode:384})}async function Ae(){try{await I.unlink(T)}catch{}}import i from"chalk";import ie from"open";import V from"readline";import ae from"@inquirer/select";import{existsSync as L,readFileSync as D,writeFileSync as W,mkdirSync as M,renameSync as z}from"fs";import{join as x}from"path";import G from"os";var ne="settings.json";function H(){return x(G.homedir(),".vibeflow","settings.json")}function J(e){return x(e,P,ne)}function O(){try{return JSON.parse(D(H(),"utf-8"))}catch{return{}}}function q(e){let r=x(G.homedir(),".vibeflow");L(r)||M(r,{recursive:!0});let o=H(),n=o+".tmp";W(n,JSON.stringify(e,null,2),"utf-8"),z(n,o)}function se(e){let r=O(),o=J(e);if(!L(o))return r;try{let n=JSON.parse(D(o,"utf-8"));return{...r,...n}}catch{return r}}function Ne(e,r){let o=x(e,P);L(o)||M(o,{recursive:!0});let n=J(e),c={...se(e),...r},p=n+".tmp";return W(p,JSON.stringify(c,null,2),"utf-8"),z(p,n),c}import{existsSync as ce,readdirSync as K,readFileSync as le}from"fs";import{join as R,resolve as de}from"path";var pe="https://app.vibeflow.tools",fe=300*1e3;function Y(){return process.env.VIBEFLOW_API_URL??pe}async function ue(e){return new Promise(r=>setTimeout(r,e))}async function ge(e){return e.length===1?(console.log(i.dim(` Using board: ${e[0].icon??""} ${e[0].name}`)),e[0]):await ae({message:"Select a board to use:",choices:e.map(o=>({name:`${o.icon??""} ${o.name}`,value:o}))})}async function Q(e,r){try{let o=await fetch(`${e}/api/cli/settings`,{headers:{Authorization:`Bearer ${r}`}});if(!o.ok)return;let n=await o.json();n.settings&&Object.keys(n.settings).length>0&&q({...n.settings,_settingsRefreshedAt:Date.now()})}catch{}}async function Ve(){try{let e=await b();if(!e)return;let o=O()._settingsRefreshedAt??0;if(Date.now()-o<fe)return;let n=Y();Q(n,e)}catch{}}async function me(e,r){try{let[o,n]=await Promise.all([fetch(`${e}/api/cli/workspaces`,{headers:{Authorization:`Bearer ${r}`}}),fetch(`${e}/api/cli/profile`,{headers:{Authorization:`Bearer ${r}`}})]);if(!o.ok)return;let a=await o.json();if(!a.workspaces?.length){console.log(i.yellow(" No boards found. Create a board in the web app first."));return}let c=n.ok?await n.json():null,p=await ge(a.workspaces);await _({...p,email:c?.email??null}),console.log(i.green(` Board set: ${p.icon??""} ${p.name}`)),console.log(i.dim(` Open at: ${p.url}`))}catch{}}async function he(e,r,o,n){let a=R(e,P,E);if(!ce(a))return;let c=[];try{for(let s of K(a,{withFileTypes:!0}))if(s.isDirectory()){let f=R(a,s.name);for(let m of K(f).filter(d=>d.endsWith(".json")))c.push(R(f,m))}else s.isFile()&&s.name.endsWith(".json")&&c.push(R(a,s.name))}catch{return}if(c.length===0)return;let p=c.flatMap(s=>{try{return[JSON.parse(le(s,"utf-8"))]}catch{return[]}}),y=new Set;try{let s=await fetch(`${r}/api/cli/tasks?boardId=${n.id}`,{headers:{Authorization:`Bearer ${o}`}}).catch(()=>null);if(s?.ok){let f=await s.json();y=new Set((f.tasks??[]).flatMap(m=>[m.id,...m.cliId?[m.cliId]:[]]))}}catch{}let l=p.filter(s=>!y.has(s.id));if(l.length===0)return;console.log(),console.log(i.bold(` ${l.length} local task${l.length!==1?"s are":" is"} not yet synced to the board:`));let h=l.slice(0,10);for(let s of h){let f=s.status?i.dim(` [${s.status}]`):"";console.log(i.dim(` \u2022 ${s.title??s.id}${f}`))}return l.length>10&&console.log(i.dim(` \u2026 and ${l.length-10} more`)),new Promise(s=>{let f=V.createInterface({input:process.stdin,output:process.stdout});f.question(i.cyan(`
3
+ Push them to your board now? [Y/n]: `),async m=>{if(f.close(),m.trim().toLowerCase()==="n"){console.log(i.dim(" Skipped. You can push later with: vibeflow push")),s();return}let d=V.createInterface({input:process.stdin,output:process.stdout});d.question(i.cyan(" Delete local task files after push? [y/N]: "),async k=>{d.close();let S=k.trim().toLowerCase()!=="y";try{let t=await fetch(`${r}/api/cli/import`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},body:JSON.stringify({boardId:n.id,tasks:l,keepLocalFiles:S})}),u={};try{u=await t.json()}catch{}t.ok?(console.log(i.green(` \u2713 Pushed ${u.imported??0} task${(u.imported??0)!==1?"s":""} to ${n.name}`)),(u.skipped??0)>0&&console.log(i.dim(` (${u.skipped} already existed and were skipped)`))):console.log(i.red(` Push failed: ${u.error??`HTTP ${t.status}`}`))}catch(t){console.log(i.red(` Push failed: ${t instanceof Error?t.message:"Network error"}`))}s()})})})}async function X(e=de(".")){let r=Y();console.log(i.cyan(" Initiating device login flow..."));let o;try{o=await fetch(`${r}/api/cli/auth/device-init`,{method:"POST",headers:{"Content-Type":"application/json"}})}catch(h){console.error(i.red(` Failed to connect to login server: ${h instanceof Error?h.message:"Network error"}`)),process.exitCode=w.AUTH;return}if(!o.ok){console.error(i.red(` Failed to initiate login: ${o.status} ${o.statusText}`)),process.exitCode=w.AUTH;return}let{deviceCode:n,userCode:a,verificationUrl:c,expiresIn:p}=await o.json();console.log(),console.log(i.bold(" Open this URL in your browser to authorize:")),console.log(i.underline(` ${c}`)),console.log();try{await ie(c),console.log(i.dim(" (Browser opened automatically)"))}catch{}let y=Date.now()+p*1e3,l=3e3;for(;Date.now()<y;){await ue(l);let h=null;try{h=await fetch(`${r}/api/cli/auth/device-poll`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({deviceCode:n})})}catch{console.error(i.red(" Poll request failed (network error). Retrying..."));continue}if(!h.ok){console.error(i.red(" Poll request failed. Retrying..."));continue}let s=await h.json();if("token"in s){await j(s.token),console.log(),console.log(i.green(" Logged in successfully. Now operating in SaaS mode.")),await Promise.all([me(r,s.token),Q(r,s.token)]);let{readWorkspace:f}=await import("./workspace-AJAVENKA.js"),m=await f();m&&await he(e,r,s.token,m);return}if("expired"in s){console.error(i.red(" Device code expired. Please try again.")),process.exitCode=w.AUTH;return}process.stdout.write(i.dim("."))}console.error(i.red(`
4
+ Login timed out. Please try again.`)),process.exitCode=w.AUTH}var Pe="https://app.vibeflow.tools";function be(){return process.env.VIBEFLOW_API_URL??Pe}function Ie(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}function Z(e,r,o=24){let n=Math.round(e/r*o);return`[${"\u2588".repeat(n)+"\u2591".repeat(o-n)}]`}async function Te(e,r,o,n){let a=[];for(let{localId:d,remoteId:k}of n){let S=U(o,d);for(let t of S){let u=t.linkedPath??$e(B(o,d),t.name);we(u)&&a.push({remoteId:k,name:t.name,filePath:u,size:t.size})}}if(a.length===0)return{uploaded:0,failed:0,failedFiles:[]};let c=a.length,p=a.reduce((d,k)=>d+k.size,0);console.log(g.cyan(`
5
+ Uploading ${c} file(s) (${Ie(p)})...`));let y=0,l=0,h=0,s=Date.now(),f=[];for(let d of a){let k=Math.round(y/c*100),S=Z(y,c),t=(Date.now()-s)/1e3,u=h/Math.max(t,.01),ee=p-h,v=u>0?Math.ceil(ee/u):0,te=v>60?`${Math.ceil(v/60)}m`:`${v}s`;process.stdout.write(`\r ${S} ${k}% ${d.name.slice(0,28)} ETA: ${te} `);try{let $=ke(d.filePath),C=await fetch(`${e}/api/tasks/${encodeURIComponent(d.remoteId)}/files`,{method:"POST",headers:{Authorization:`Bearer ${r}`,"Content-Type":"application/octet-stream","x-filename":encodeURIComponent(d.name)},body:$});C.ok?(y++,h+=d.size):(l++,f.push({name:d.name,reason:`HTTP ${C.status}`}))}catch($){l++,f.push({name:d.name,reason:$ instanceof Error?$.message:String($)})}}let m=Z(c,c);return process.stdout.write(`\r ${m} 100% Done${" ".repeat(40)}
6
+ `),{uploaded:y,failed:l,failedFiles:f}}async function it(e,r){let o=Se(e),n=await b();if(!n&&(console.log(g.yellow(" Not logged in. Starting login flow...")),await X(),n=await b(),!n)){console.error(g.red(" Login failed. Please run `vibeflow login` and try again.")),process.exitCode=w.AUTH;return}let a=N(o);if(a.length===0){console.log(g.dim(" No local tasks found. Nothing to push."));return}console.log(g.cyan(` Found ${a.length} local task(s). Pushing to SaaS...`));let c=be(),p=r.workspace;if(!p){let t=await A();t&&(p=t.id,console.log(g.dim(` Using board: ${t.icon??""} ${t.name}`)))}let y={tasks:a};p&&(y.workspaceId=p);let l;try{let t=await fetch(`${c}/api/cli/import`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`},body:JSON.stringify(y)});if(!t.ok){let u=await t.json().catch(()=>({}));console.error(g.red(` Import failed: ${t.status} ${u.error??t.statusText}`)),process.exitCode=w.GENERAL;return}l=await t.json()}catch(t){let u=t instanceof Error?t.message:String(t);console.error(g.red(` Network error: ${u}`)),process.exitCode=w.GENERAL;return}console.log(g.green(` \u2713 Pushed ${l.imported} task(s) to SaaS`)),l.skipped&&l.skipped>0&&console.log(g.dim(` Skipped ${l.skipped} already-imported task(s).`));let h=(await A())?.name??l.workspaceId;console.log(g.dim(` Board: ${h}`));let s=l.idMap??{},f=a.filter(t=>t.id&&s[t.id]).map(t=>({localId:t.id,remoteId:s[t.id]})),{uploaded:m,failed:d,failedFiles:k}=await Te(c,n,o,f);if(m>0&&console.log(g.green(` \u2713 Uploaded ${m} file(s) to storage`)),d>0){console.log(g.yellow(` \u26A0 ${d} file(s) failed to upload`));for(let t of k)console.log(g.dim(` - ${t.name}: ${t.reason}`))}if(r.keepLocalFiles){console.log(g.dim(" Local task files kept (--keep-local-files)."));return}let S=0;for(let t of a)try{ye(t.filePath),S++}catch{}console.log(g.dim(` Deleted ${S} local task file(s).`))}export{b as a,Ae as b,se as c,Ne as d,Ve as e,X as f,Ie as g,Z as h,it as i};
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ import{a as B}from"./chunk-X4RGF6JJ.js";import{existsSync as l,readFileSync as I,writeFileSync as F,mkdirSync as d,readdirSync as f,unlinkSync as h,renameSync as k,openSync as H,statSync as J}from"fs";import{join as u,extname as S}from"path";import{randomBytes as V}from"crypto";var b=["backlog","todo","in-progress","review","done"];function v(e){let i=(e??"Medium").trim().toLowerCase();return i==="critical"?0:i==="high"?1:i==="low"?3:2}function Y(e,i){let n=v(e.priority),s=v(i.priority);return n!==s?n-s:new Date(e.created).getTime()-new Date(i.created).getTime()}var m=".vibeflow",w="tasks",x="tasks/files",y="tasks/screenshots",Q="config.json";import{openSync as j,statSync as _,unlinkSync as D,mkdirSync as E,existsSync as M}from"fs";import{join as A}from"path";var $=new Map;function R(e,i){let n=A(e,m,"tasks",".locks");try{M(n)||E(n,{recursive:!0})}catch{}return A(n,`${i}.lock`)}function K(e,i,n){let s=Date.now()+i,{dirname:r}=B("path");for(;;)try{j(e,"wx");return}catch(t){if(t.code==="ENOENT"){try{E(r(e),{recursive:!0})}catch{}continue}if(t.code!=="EEXIST")throw t;try{let c=_(e);if(Date.now()-c.mtimeMs>n){try{D(e)}catch{}continue}}catch{continue}if(Date.now()>=s)throw new Error(`Failed to acquire lock ${e} within ${i}ms`);if(s-Date.now()<=0)throw new Error(`Failed to acquire lock ${e} within ${i}ms`);let a=Date.now()+Math.min(10,s-Date.now());for(;Date.now()<a;);}}function q(e){try{D(e)}catch{}}async function ie(e,i,n){let s=n?.timeoutMs??5e3,r=n?.staleMs??1e4,o=($.get(e)??Promise.resolve()).then(async()=>{K(e,s,r);try{return await i()}finally{q(e)}});return $.set(e,o.catch(()=>{})),o}function W(){return V(15).toString("hex")}function p(e){return u(e,m,w)}function z(e){let i=u(e,m),n=u(i,"files"),s=u(i,x),r=u(i,"screenshots"),t=u(i,y);if(l(n)){d(s,{recursive:!0});for(let o of f(n)){let a=u(n,o),c=u(s,o);if(!l(c))try{k(a,c)}catch{}}}if(l(r)){d(t,{recursive:!0});for(let o of f(r)){let a=u(r,o),c=u(t,o);if(!l(c))try{k(a,c)}catch{}}}}function le(e){z(e),d(p(e),{recursive:!0}),d(u(e,m,y),{recursive:!0})}function T(e){return e.slice(0,10)}function U(e,i,n){let s=p(e);return n?u(s,T(n),`${i}.json`):u(s,`${i}.json`)}function O(e,i){let n=p(e);if(!l(n))return null;for(let s of f(n,{withFileTypes:!0}))if(s.isDirectory()){let r=u(n,s.name,`${i}.json`);if(l(r))return r}else if(s.name===`${i}.json`)return u(n,s.name);return null}function G(e){return{...e,text:e.text??e.content??""}}function X(e){let i=(()=>{if(typeof e.type!="string")return;let n=e.type.trim();if(!(!n||n==="[object Object]"))return n})();return{id:String(e.id??""),title:String(e.title??"Untitled"),description:String(e.description??""),status:b.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?void 0:Number(e.line),col:e.col==null?void 0:Number(e.col),component:e.component?String(e.component):void 0,type:i,priority:e.priority?String(e.priority):void 0,...e.reportBack===!0&&{reportBack:!0},agent:e.agent?String(e.agent):void 0,model:e.model?String(e.model):void 0,author:e.author?String(e.author):void 0,commits:Array.isArray(e.commits)?e.commits.map(n=>({sha:String(n.sha??""),message:String(n.message??""),timestamp:String(n.timestamp??new Date().toISOString())})):void 0,created:String(e.created??new Date().toISOString()),updated:e.updated?String(e.updated):void 0,comments:Array.isArray(e.comments)?e.comments.map(n=>G(n)):[],files:Array.isArray(e.files)?e.files.map(n=>typeof n=="string"?{name:n,addedAt:new Date().toISOString()}:{name:String(n.name??""),addedAt:String(n.addedAt??new Date().toISOString()),linkedPath:n.linkedPath?String(n.linkedPath):void 0,mimeType:n.mimeType?String(n.mimeType):void 0}).filter(n=>n.name):[],screenshot:e.screenshot?String(e.screenshot):void 0,annotatedElementText:e.annotatedElementText?String(e.annotatedElementText):void 0,tags:Array.isArray(e.tags)?e.tags.filter(n=>typeof n=="string"&&n.length>0):void 0,sortKey:e.sortKey?String(e.sortKey):void 0,verified:e.verified===!0,branchName:e.branchName?String(e.branchName):void 0,baseline:e.baseline&&typeof e.baseline=="object"?e.baseline:void 0,authStateEnc:e.authStateEnc?String(e.authStateEnc):void 0}}function N(e,i){let n=u(p(e),T(i.created));d(n,{recursive:!0});let s=u(n,`${i.id}.json`),r=s+".tmp";F(r,JSON.stringify(i,null,2),"utf-8"),k(r,s)}function C(e){return e.replace(/\\(n|t|r|\\)/g,(i,n)=>{switch(n){case"n":return`
3
+ `;case"t":return" ";case"r":return"\r";case"\\":return"\\";default:return n}})}function me(e,i){let n=(()=>{let r=(i.priority??"").trim().toLowerCase();return r==="critical"?"Critical":r==="high"?"High":r==="low"?"Low":"Medium"})(),s={...i,title:C(i.title??"").trim(),description:C(i.description??"").trim(),priority:n,id:W(),created:new Date().toISOString(),comments:[],files:[]};return N(e,s),s}function g(e){try{let i=I(e,"utf-8");if(e.endsWith(".json")){let n=JSON.parse(i);return!n||typeof n!="object"||!("id"in n)?null:X(n)}return null}catch{return null}}function P(e){let i=p(e);if(!l(i))return[];let n=[];for(let s of f(i,{withFileTypes:!0}))if(s.isDirectory()){let r=u(i,s.name);for(let t of f(r))if(S(t)===".json"){let o=u(r,t),a=g(o);a&&n.push({task:a,filePath:o})}}else if(S(s.name)===".json"){let r=u(i,s.name),t=g(r);t&&n.push({task:t,filePath:r})}return n}function de(e){return P(e).map(({task:i})=>i)}function fe(e){return P(e).map(({task:i,filePath:n})=>({...i,filePath:n}))}function pe(e,i,n){let s=R(e,i),r=null,t=Date.now()+5e3;for(;Date.now()<t;)try{H(s,"wx");break}catch(o){if(o.code!=="EEXIST")throw o;try{let c=J(s);if(Date.now()-c.mtimeMs>1e4){try{h(s)}catch{}continue}}catch{continue}let a=Date.now();for(;Date.now()-a<10&&Date.now()<t;);}try{let o=O(e,i),a=o?g(o):null;if(!a)return null;let c={...a,...n,updated:new Date().toISOString()};if(N(e,c),o&&o!==U(e,i,c.created))try{h(o)}catch{}r=c}finally{try{h(s)}catch{}}return r}function he(e,i){let n=O(e,i);return n?(h(n),!0):!1}function ge(e,i,n){return{id:e.id,status:e.status,title:e.title,description:e.description,...e.url&&{url:e.url},selector:e.selector,...e.file&&{file:e.file},...e.line!=null&&{line:e.line},...e.col!=null&&{col:e.col},...e.component&&{component:e.component},...e.type&&{type:e.type},...e.priority&&{priority:e.priority},...i&&i.length>0&&{structuredComments:i},...n&&n.length>0&&{linkedFiles:n},...e.reportBack&&{reportBack:!0},created:e.created}}function ye(e,i,n,s,r){let t=[];if(t.push(`[${e.status}] ${e.title}`),t.push(` id: ${e.id}`),t.push(` file: ${i}`),e.file&&t.push(` source: ${e.file}${e.line==null?"":`:${e.line}`}${e.col==null?"":`:${e.col}`}`),e.component&&t.push(` component: ${e.component}`),t.push(` selector: ${e.selector??"/"}`),e.cssSelector&&t.push(` css: ${e.cssSelector}`),e.url&&t.push(` url: ${e.url}`),e.commits&&e.commits.length>0)if(e.commits.length===1)t.push(` commit: ${e.commits[0].sha}`);else{t.push(` commits (${e.commits.length}):`);for(let o of e.commits)t.push(` ${o.sha.slice(0,8)} ${o.timestamp} ${o.message.slice(0,60)}`)}if(t.push(` created: ${e.created}`),e.type&&t.push(` type: ${e.type}`),e.priority&&t.push(` priority: ${e.priority}`),e.author&&t.push(` author: ${e.author}`),e.description){t.push(" description:");for(let o of e.description.split(`
4
+ `))t.push(` ${o}`)}if(e.annotatedElementText&&t.push(` element text: ${e.annotatedElementText}`),n.length>0){t.push(` comments (${n.length}):`);for(let o of n){let a=o.updatedAt?` (edited ${o.updatedAt})`:"";t.push(` [${o.author??"user"}] ${o.createdAt}${a}`);for(let c of o.text.split(`
5
+ `))t.push(` ${c}`)}}if(s.length>0){t.push(` linked files (${s.length}):`);for(let o of s){t.push(` - ${o.name} ${o.url}`);let a=o.linkedPath??u(r,".vibeflow","files",e.id,o.name);if(/\.(md|txt)$/i.test(o.name)&&o.size<1e5&&l(a))try{let c=I(a,"utf-8");t.push(" \u250C\u2500\u2500 content \u2500\u2500");for(let L of c.split(`
6
+ `))t.push(` \u2502 ${L}`);t.push(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}catch{}}}return t.join(`
7
+ `)}function ke(e){let{autoCommit:i,autoPush:n,autoComment:s,createBranch:r}=e,t=[];if(t.push("Agent instructions (concise):"),t.push(" Discover: vibeflow tasks --status todo | vibeflow tasks --type Research | vibeflow tasks --user <email> | vibeflow tasks --tag <tag>"),t.push(" Auto-claim: vibeflow tasks --next (picks highest-priority todo task and sets it in-progress automatically)"),t.push(" Details: vibeflow tasks --get <id> (full task info with comments and files)"),t.push(' Create: vibeflow tasks --add --title "..." --description "..."'),t.push(""),t.push(" Workflow:"),r?(t.push(" \u26A0 Create a branch FIRST, before any implementation:"),t.push(" 1. git checkout -b <short-name> (e.g. fix/annotation-errors, feat/eye-toggle, chore/cleanup-extension)"),t.push(" Branch name rules: lowercase, kebab-case, 2-5 words, prefix fix/feat/chore/docs."),t.push(" Describe the WORK done (not dates). Bad: agent/2026-04-16. Good: fix/bug-errors-visibility."),t.push(" 2. vibeflow tasks --edit <id> --set-status in-progress \u2190 CLAIM TASK"),t.push(" 3. <implement the change>")):(t.push(" \u26A0 IMMEDIATELY set in-progress BEFORE any implementation work:"),t.push(" 1. vibeflow tasks --edit <id> --set-status in-progress \u2190 DO THIS FIRST"),t.push(" (if you used --next: task is already in-progress \u2014 skip to step 2)"),t.push(" 2. <implement the change>")),e.requireVerifyBeforeReview)if(i){t.push(r?" 4. git add <files> (stage your changes first)":" 3. git add <files> (stage your changes first)"),t.push(` ${r?"5":"4"}. vibeflow verify <id> (verify the fix \u2014 check the evidences it produces)`),t.push(" If verification fails, set task back to in-progress and fix.");let a=["--set-status review"];i&&a.push('--commit-message "<one-line summary>"'),s&&a.push('--comment "<report>"'),t.push(` ${r?"6":"5"}. vibeflow tasks --edit <id> ${a.join(" ")}`),t.push(" CLI will commit staged changes and link the commit SHA automatically.")}else{t.push(r?' 4. git add <files> && vibeflow tasks --commit --task <id> --message "<one-line summary>"':' 3. git add <files> && vibeflow tasks --commit --task <id> --message "<one-line summary>"'),t.push(` ${r?"5":"4"}. vibeflow verify <id> (verify the fix \u2014 check the evidences it produces)`),t.push(" If verification fails, set task back to in-progress and fix.");let a=["--set-status review"];s&&a.push('--comment "<report>"'),t.push(` ${r?"6":"5"}. vibeflow tasks --edit <id> ${a.join(" ")}`)}else{if(i){t.push(r?" 4. git add <files> (stage your changes first)":" 3. git add <files> (stage your changes first)");let c=["--set-status review"];i&&c.push('--commit-message "<one-line summary>"'),s&&c.push('--comment "<report>"'),t.push(` ${r?"5":"4"}. vibeflow tasks --edit <id> ${c.join(" ")}`),t.push(" CLI will commit staged changes and link the commit SHA automatically.")}else{t.push(r?' 4. git add <files> && vibeflow tasks --commit --task <id> --message "<one-line summary>"':' 3. git add <files> && vibeflow tasks --commit --task <id> --message "<one-line summary>"');let c=["--set-status review"];s&&c.push('--comment "<report>"'),t.push(` ${r?"5":"4"}. vibeflow tasks --edit <id> ${c.join(" ")}`)}let a=r?"6":"5";t.push(` ${a}. vibeflow verify <id> (verify the fix \u2014 check the evidences it produces)`),t.push(" If verification fails, set task back to in-progress and fix.")}return s&&(t.push(""),t.push(" Comment format (--comment):"),t.push(" \xB7 Plain text for concise one-liners."),t.push(" \xB7 Markdown for multi-section reports. Use **bold**, bullet lists, code fences."),t.push(" \xB7 Must cover: what changed, why, key decisions, anything future agents should know."),t.push(" \xB7 For long reports, attach a .md file and reference it in the comment.")),t.push(""),i&&t.push(" [setting] Auto-commit ON: provide --commit-message when setting status to review; CLI commits."),n&&t.push(" [setting] Auto-push ON: CLI pushes after the commit automatically."),s&&t.push(" [setting] Auto-comment ON: --comment is required when setting status to review."),r&&t.push(" [setting] Create branch ON: all work goes on a dedicated branch created before implementation."),e.requireVerifyBeforeReview&&t.push(" [setting] Verify gate ON: run vibeflow verify before setting status to review (skipped for tasks without URL/selector)."),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(" Create the report file locally first, then upload when marking as review:"),t.push(' vibeflow tasks --edit <id> --set-status review --report-file ./report.md --comment "..."'),t.push(" The file is saved next to the task and deleted from the original path automatically."),t.push(" Report must include: findings, options considered (with pros/cons), recommendation, sources.")),e.hasBugTasks&&(t.push(" Bug tasks: Reproduce the bug first, then include in the comment:"),t.push(" \xB7 Symptom: what the user sees"),t.push(" \xB7 Trigger: exact steps to reproduce"),t.push(" \xB7 Root cause: the specific code/logic that caused it"),t.push(" \xB7 Fix: what was changed and why it works"),t.push(" \xB7 Evidence: paste the relevant error message or stack trace")),t.push(" BLOCKED? If a task is unclear or missing context:"),t.push(' vibeflow tasks --edit <id> --comment "Blocked: <reason>. Need: <what is needed>."'),t.push(" Then pick the next task: vibeflow tasks --next"),t.push(" Do not guess at unclear requirements \u2014 leave a comment and move on."),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(`
8
+ `)}function Se(e){let i=p(e);if(!l(i))return 0;let n=0;for(let s of f(i,{withFileTypes:!0})){if(s.isDirectory()||S(s.name)!==".json")continue;let r=u(i,s.name),t=g(r);if(!t)continue;let o=u(i,T(t.created)),a=u(o,s.name);r!==a&&(d(o,{recursive:!0}),F(a,JSON.stringify(t,null,2),"utf-8"),h(r),n++)}return n}export{b as a,v as b,Y as c,m as d,w as e,x as f,y as g,Q as h,R as i,ie as j,W as k,p as l,le as m,U as n,O as o,N as p,C as q,me as r,g as s,de as t,fe as u,pe as v,he as w,ge as x,ye as y,ke as z,Se as A};
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ import{c as st}from"./chunk-SQPWTIQO.js";import{a as U}from"./chunk-BZDBSBRV.js";import{a as b,e as R,g as I}from"./chunk-GQQIUROY.js";import{c as tt,g as et,n as ot,r as nt,u as rt}from"./chunk-QJMBWTAZ.js";import c from"chalk";import{resolve as wt,join as N}from"path";import{readFileSync as z}from"fs";import{statSync as Nt,readdirSync as Tt,unlinkSync as At}from"fs";import M from"crypto";var vt="vibeflow-auth-v1",xt=1440*60*1e3;function it(t){return M.scryptSync(t,vt,32)}function jt(t,e){let o=it(e),n=M.randomBytes(16),r=M.createCipheriv("aes-256-gcm",o,n),s=JSON.stringify(t),i=Buffer.concat([r.update(s),r.final()]),y=r.getAuthTag();return{version:1,createdAt:new Date().toISOString(),expiresAt:new Date(Date.now()+xt).toISOString(),iv:n.toString("hex"),tag:y.toString("hex"),data:i.toString("hex")}}function at(t,e){if(new Date(t.expiresAt)<new Date)return null;try{let o=it(e),n=M.createDecipheriv("aes-256-gcm",o,Buffer.from(t.iv,"hex"));n.setAuthTag(Buffer.from(t.tag,"hex"));let r=Buffer.concat([n.update(Buffer.from(t.data,"hex")),n.final()]);return JSON.parse(r.toString())}catch{return null}}function bt(t,e){return Math.abs(t.x-e.x)>2||Math.abs(t.y-e.y)>2||Math.abs(t.width-e.width)>2||Math.abs(t.height-e.height)>2}function H(t,e){let o=!!e.outerHTML,n=t.outerHTML!==e.outerHTML,r={},s=new Set([...Object.keys(t.computedStyles),...Object.keys(e.computedStyles)]);for(let l of s){let E=t.computedStyles[l],x=e.computedStyles[l];E!==x&&(r[l]=[E??"",x??""])}let i=bt(t.position.boundingBox,e.position.boundingBox),y=new Set(t.consoleErrors),g=e.consoleErrors.filter(l=>!y.has(l));return{selectorResolves:o,htmlChanged:n,stylesChanged:r,positionChanged:i,newConsoleErrors:g}}function ct(t,e){let o=[];if(t.selectorResolves){t.htmlChanged&&o.push("HTML changed");let n=Object.keys(t.stylesChanged).length;if(n>0){let r=Object.keys(t.stylesChanged).slice(0,5).join(", "),s=n>5?` (+${n-5} more)`:"";o.push(`${n} style property change(s): ${r}${s}`)}t.positionChanged&&o.push("position shifted"),t.newConsoleErrors.length>0&&o.push(`${t.newConsoleErrors.length} new console error(s)`),o.length===0&&o.push("no structural changes detected")}else o.push(`Selector "${e}" no longer resolves`);return o.join("; ")}import{readFileSync as lt,writeFileSync as Ht,mkdirSync as Jt,existsSync as ft}from"fs";import{join as gt,basename as Rt}from"path";import{execSync as Ct}from"child_process";var G={port:3700};function Ot(t){return gt(t,tt,et)}function ut(t){let e=Ot(t);if(!ft(e))return{...G};let o=lt(e,"utf-8"),n;try{n=JSON.parse(o)}catch{return{...G}}return{...G,...n}}function Wt(t){let e=gt(t,"package.json");if(ft(e))try{let o=JSON.parse(lt(e,"utf-8"));if(o.name)return o.name}catch{}return Rt(t)}function zt(t){try{return Ct("git branch --show-current",{cwd:t,encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()||null}catch{return null}}var W=["display","visibility","opacity","position","overflow","overflow-x","overflow-y","width","min-width","max-width","height","min-height","max-height","margin","margin-top","margin-right","margin-bottom","margin-left","padding","padding-top","padding-right","padding-bottom","padding-left","border","border-width","border-style","border-color","border-radius","background-color","background-image","color","font-size","font-weight","font-style","font-family","line-height","letter-spacing","text-align","text-decoration","text-overflow","white-space","flex-direction","flex-wrap","flex","justify-content","align-items","gap","row-gap","column-gap","grid-template-columns","grid-template-rows","z-index","box-shadow","transform","transition","cursor","user-select","pointer-events","top","left","right","bottom"];function dt(t){let e=[],o=t;for(;o&&o!==document.documentElement;){let n=o.parentElement;if(!n)break;let r=Array.from(n.children).indexOf(o);e.unshift(r),o=n}return e.join("/")}function ht(t){let e=t.tagName.toLowerCase(),o=t.getAttribute("data-task-id");if(o)return`${e}.task-card[data-task-id=${o}]`;let n=t.getAttribute("data-status");if(n&&t.classList.contains("column-scroll"))return`${e}.column-scroll[data-status=${n}]`;let r=t.getAttribute("data-column-id");if(r)return`${e}[data-column-id=${r}]`;let s=Array.from(t.classList).slice(0,2),i=e;s.length&&(i+="."+s.join("."));let y=t.parentElement;if(y){let g=Array.from(y.children).filter(l=>l.tagName===t.tagName);if(g.length>1){let l=g.indexOf(t)+1;i+=`:nth-of-type(${l})`}}return i}function mt(t,e=W){let o=window.getComputedStyle(t),n={};for(let r of e)n[r]=o.getPropertyValue(r);return n}function pt(t,e=200){return t.replace(/\s+/g," ").trim().slice(0,e)}function yt(t){let e=new Map;for(let o of t){let n=o.tagName.toLowerCase(),r=Array.from(o.classList).slice(0,2).join("."),s=r?`${n}.${r}`:n;e.set(s,(e.get(s)||0)+1)}return Array.from(e.entries()).map(([o,n])=>`${o} \xD7${n}`).slice(0,10)}var p=class extends Error{constructor(o,n,r){super(n);this.code=o;this.suggestion=r;this.name="VerifyError"}code;suggestion};async function Pt(){try{return await import("playwright")}catch{throw new p("E_PLAYWRIGHT_MISSING","Playwright is not installed.","Run: npx playwright install chromium")}}async function kt(t,e,o={}){let n=wt(t),r=ot(n,e);if(!r)throw new p("E_NOT_FOUND",`Task not found: ${e}`,"Run 'vibeflow tasks' to see available task IDs.");let s=nt(r);if(!s)throw new p("E_NOT_FOUND",`Task not found: ${e}`);let i,y=s.baselineElementFile||"baseline-element.json",g=I(n,e,y);if(g)try{i=JSON.parse(z(g,"utf-8"))}catch{}if(!i&&s.baseline&&(i=s.baseline),!i)throw new p("E_NO_BASELINE","Task has no baseline. Re-annotate to capture one.");let l=[],E={},x={};if(s.authStateEnc&&s.author)try{let m=JSON.parse(s.authStateEnc),f=at(m,s.author);if(!f)throw new p("E_AUTH_EXPIRED","Auth state expired. Re-annotate to capture fresh cookies.");l=f.cookies,E=f.localStorage,x=f.sessionStorage}catch(m){throw m instanceof p?m:new p("E_AUTH_CORRUPT","Auth state corrupted. Re-annotate.")}let v=o.url??s.url;if(!v)throw new p("E_NO_URL","Task has no URL. Cannot verify without a target URL.","Re-annotate the element with a URL, or use --url to override.");let C=ut(n).port??3700,A=v.startsWith("http")?v:`http://localhost:${C}${v.startsWith("/")?v:"/"+v}`,S=s.cssSelector??s.selector;if(!S||S==="/")throw new p("E_NO_SELECTOR","Task has no CSS selector. Cannot verify without a selector.");let j=await Pt(),$;try{$=await j.chromium.launch({headless:!0})}catch(m){let f=m instanceof Error?m.message:String(m);throw f.includes("not found")||f.includes("not installed")||f.includes("Executable doesn't exist")?new p("E_PLAYWRIGHT_MISSING","Chromium is not installed.","Run: npx playwright install chromium"):new p("E_PLAYWRIGHT_CRASH",`Verification failed: ${f}`,"Try again.")}let k;try{let m=i.position?.viewport;k=await $.newContext({viewport:m?{width:m.width,height:m.height}:void 0,deviceScaleFactor:m?.dpr,userAgent:i.browser||void 0}),l.length>0&&await k.addCookies(l.map(a=>({name:a.name,value:a.value,domain:a.domain,path:a.path,expires:a.expires,httpOnly:a.httpOnly,secure:a.secure,sameSite:a.sameSite})));let f=await k.newPage(),T=[];f.on("console",a=>{a.type()==="error"&&T.push(a.text())}),f.on("pageerror",a=>{T.push(a.message)});try{await f.goto(A,{waitUntil:"networkidle",timeout:15e3})}catch(a){let u=a instanceof Error?a.message:String(a);throw u.includes("ERR_CONNECTION_REFUSED")||u.includes("ECONNREFUSED")?new p("E_APP_NOT_RUNNING",`Cannot connect to ${A}. Is the dev server running?`):new p("E_NAVIGATION_FAILED",`Failed to navigate to ${A}: ${u}`)}try{Object.keys(E).length>0&&await f.evaluate(a=>{for(let[u,d]of Object.entries(a))window.localStorage.setItem(u,d)},E),Object.keys(x).length>0&&await f.evaluate(a=>{for(let[u,d]of Object.entries(a))window.sessionStorage.setItem(u,d)},x)}catch{}let P=0;try{await f.waitForSelector(S,{timeout:1e4}),P=await f.locator(S).count()}catch{let a={outerHTML:"",computedStyles:{},selector:S,position:i.position,browser:i.browser,consoleErrors:T,capturedAt:new Date().toISOString()},u=H(i,a);return K(s.id,s.description,i,a,u,[],S)}if(P>1){let a={outerHTML:"",computedStyles:{},selector:S,position:i.position,browser:i.browser,consoleErrors:T,capturedAt:new Date().toISOString()},u=H(i,a),d=`Selector matches ${P} elements. The selector may need to be more specific.`;return K(s.id,s.description,i,a,u,[],S,d)}let L=await Lt(f,S,i,T),_=null,B=s.baselineFile||"baseline-page.json",F=I(n,e,B);if(F)try{_=JSON.parse(z(F,"utf-8"))}catch{}let h=H(i,L),O=await _t(n,e,i,L,h,T,f,S);if(_&&_.elements){let a=I(n,e,"verify-all-styles.json");if(a)try{let u=JSON.parse(z(a,"utf-8"));if(u&&u.elements){let d={},St=Object.entries(u.elements);for(let[Y,X]of St){let J=_.elements[Y]?.after;if(J){X.baseline=J;let V={};for(let[q,Q]of Object.entries(X.after)){let Z=J[q];Z!==Q&&(V[q]=[Z,Q])}Object.keys(V).length>0&&(d[Y]=V)}}R(n,e,"verify-all-styles.json",Buffer.from(JSON.stringify(u,null,2)));let Et=JSON.stringify({totalChanged:Object.keys(d).length,elements:d},null,2);R(n,e,"verify-page-diff.json",Buffer.from(Et)),O.push(N(b(n,e),"verify-page-diff.json"))}}catch{}}let D=K(s.id,s.description,i,L,h,O,S);return rt(n,e,{verified:D.ok}),D}finally{await k?.close(),await $?.close()}}async function Lt(t,e,o,n){let r=t.locator(e).first(),s=await r.evaluate(l=>l.outerHTML).catch(()=>""),i=await r.evaluate(l=>{let E=window.getComputedStyle(l),x={};for(let v=0;v<E.length;v++){let w=E[v];x[w]=E.getPropertyValue(w)}return x}).catch(()=>({})),g={boundingBox:await r.boundingBox().catch(()=>null)??o.position.boundingBox,scrollPosition:await t.evaluate(()=>({x:window.scrollX,y:window.scrollY})),viewport:await t.evaluate(()=>({width:window.innerWidth,height:window.innerHeight,dpr:window.devicePixelRatio})),stackingContext:o.position.stackingContext};return{outerHTML:s,computedStyles:i,selector:e,position:g,browser:o.browser,consoleErrors:n,capturedAt:new Date().toISOString()}}async function _t(t,e,o,n,r,s,i,y){let g=[],l=b(t,e);try{let w=Tt(l);for(let C of w)(C.startsWith("verify-")||C==="baseline.json")&&At(N(l,C))}catch{}let E=JSON.stringify(n,null,2);R(t,e,"verify-after.json",Buffer.from(E)),g.push(N(b(t,e),"verify-after.json"));let x=JSON.stringify(r,null,2);R(t,e,"verify-diff.json",Buffer.from(x)),g.push(N(b(t,e),"verify-diff.json"));let v=s.length>0?s.join(`
3
+ `):"(no console errors)";if(R(t,e,"verify-console.txt",Buffer.from(v)),g.push(N(b(t,e),"verify-console.txt")),i){try{let w=await i.content();R(t,e,"verify-page.html",Buffer.from(w)),g.push(N(b(t,e),"verify-page.html"))}catch{}try{let C=await i.evaluate(({buildKeyFn:A,buildSelectorFn:S,filterStylesFn:j,childSignatureFn:$,normalizeTextFn:k,styles:m,maxElements:f})=>{let T={},P=0,L=!1,_=document.createTreeWalker(document.body,NodeFilter.SHOW_ELEMENT,{acceptNode(h){if(P>=f)return NodeFilter.FILTER_REJECT;let O=h;return O.classList.length>0||O.hasAttribute("data-task-id")||O.hasAttribute("data-status")||O.hasAttribute("data-column-id")?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP}}),B=[],F;for(;F=_.nextNode();)B.push(F);for(let h of B){if(P>=f){L=!0;break}let O=A(h),D=Array.from(h.children),a={};for(let d of Array.from(h.attributes))d.name.startsWith("data-")&&(a[d.name.slice(5)]=d.value);let u={x:0,y:0,width:0,height:0};try{let d=h.getBoundingClientRect();u={x:Math.round(d.x),y:Math.round(d.y),width:Math.round(d.width),height:Math.round(d.height)}}catch{}T[O]={key:O,selector:S(h),tag:h.tagName.toLowerCase(),classes:Array.from(h.classList),dataAttrs:a,parentKey:h.parentElement?A(h.parentElement):"",childCount:D.length,childSignature:$(D),text:k(h.textContent??""),position:u,baseline:j(h,m),after:j(h,m)},P++}return{version:1,capturedAt:new Date().toISOString(),truncated:L,elements:T}},{buildKeyFn:dt,buildSelectorFn:ht,filterStylesFn:mt,childSignatureFn:yt,normalizeTextFn:pt,styles:W,maxElements:1e3});if(C){let A=JSON.stringify(C,null,2);R(t,e,"verify-all-styles.json",Buffer.from(A)),g.push(N(b(t,e),"verify-all-styles.json"))}}catch{}try{let w=await i.screenshot({fullPage:!1});R(t,e,"verify-screenshot.png",w),g.push(N(b(t,e),"verify-screenshot.png"))}catch{}if(y)try{let w=await i.locator(y).first().evaluate(C=>C.outerHTML);R(t,e,"verify-element.html",Buffer.from(w)),g.push(N(b(t,e),"verify-element.html"))}catch{}}if(o){let w=JSON.stringify(o,null,2);R(t,e,"baseline.json",Buffer.from(w)),g.push(N(b(t,e),"baseline.json"))}return g}function K(t,e,o,n,r,s,i,y){let g=r.selectorResolves&&r.newConsoleErrors.length===0,l=y??ct(r,i);return{taskId:t,ok:g,taskDescription:e,baseline:{selector:o.selector,url:"",capturedAt:o.capturedAt,snapshot:o},after:{snapshot:n,consoleErrors:n.consoleErrors},diff:r,evidenceFiles:s,verdict:l}}async function ce(t,e,o){let n=wt(t);try{let r=await kt(n,e,o);await $t(n,e,r),o.json?console.log(JSON.stringify(r,null,2)):Ft(r)}catch(r){if(r instanceof p)o.json?process.stderr.write(JSON.stringify({ok:!1,error:{code:r.code,message:r.message,suggestion:r.suggestion}})+`
4
+ `):(process.stderr.write(c.red(`\u2717 ${r.message}
5
+ `)),r.suggestion&&process.stderr.write(c.dim(` ${r.suggestion}
6
+ `))),process.exitCode=U.GENERAL;else{let s=r instanceof Error?r.message:String(r);o.json?process.stderr.write(JSON.stringify({ok:!1,error:{code:"E_UNKNOWN",message:s}})+`
7
+ `):process.stderr.write(c.red(`\u2717 Verification failed: ${s}
8
+ `)),process.exitCode=U.GENERAL}}}async function $t(t,e,o){let n=`**Verification ${o.ok?"\u2705 passed":"\u26A0\uFE0F issues detected"}**
9
+
10
+ ${o.verdict}`;st(t,e,"agent",n,void 0,"system")}function Ft(t){let e=t.ok?c.green("\u2705"):c.yellow("\u26A0\uFE0F");console.log(),console.log(` ${e} Evidences collected for task ${t.taskId}`),console.log(c.dim("\u2500".repeat(60))),console.log(c.dim(` Verdict: ${t.verdict}`)),console.log();let o=t.diff;if(o.selectorResolves){o.htmlChanged?console.log(c.cyan(" \u2713 HTML changed")):console.log(c.dim(" \xB7 HTML unchanged"));let n=Object.keys(o.stylesChanged).length;if(n>0){console.log(c.cyan(` \u2713 ${n} style property change(s):`));for(let[r,[s,i]]of Object.entries(o.stylesChanged).slice(0,8))console.log(c.dim(` ${r}: ${s} \u2192 ${i}`));n>8&&console.log(c.dim(` ... and ${n-8} more`))}if(o.positionChanged&&console.log(c.cyan(" \u2713 Position shifted")),o.newConsoleErrors.length>0){console.log(c.yellow(` \u26A0 ${o.newConsoleErrors.length} new console error(s):`));for(let r of o.newConsoleErrors.slice(0,3))console.log(c.dim(` ${r.slice(0,120)}`))}}else console.log(c.red(" \u26A0 Target element not found \u2014 the fix may have renamed/removed it."));if(t.evidenceFiles.length>0){console.log(c.cyan(` Evidence files (${t.evidenceFiles.length}):`));for(let n of t.evidenceFiles){let r=n.split("/").pop()??n;try{let i=(Nt(n).size/1024).toFixed(1);console.log(c.dim(` ${r} (${i} KB)`))}catch{console.log(c.dim(` ${r}`))}}}console.log(),console.log(c.cyan(" Explore evidence (agent tools):")),console.log(c.dim(` vibeflow verify style_query ${t.taskId} <property>`)),console.log(c.dim(` vibeflow verify style_diff ${t.taskId} [--filter <pattern>]`)),console.log(c.dim(` vibeflow verify element_info ${t.taskId}`)),console.log(c.dim(` vibeflow verify html_diff ${t.taskId}`)),console.log(),console.log(c.cyan(" Review evidences:")),console.log(c.dim(" 1. Check if the fix is confirmed (styles match expectations)")),console.log(c.dim(` 2. If confirmed \u2192 vibeflow tasks --edit ${t.taskId} --set-status review --comment "Verified: <what you confirmed>"`)),console.log(c.dim(" 3. If not sure \u2192 leave a comment explaining uncertainty")),console.log(c.dim(` 4. If wrong \u2192 vibeflow tasks --edit ${t.taskId} --set-status in-progress`)),console.log(),t.ok||(console.log(c.yellow(" \u26A0 Verification failed \u2014 move to in-progress and fix:")),console.log(c.dim(` vibeflow tasks --edit ${t.taskId} --set-status in-progress`)))}export{jt as a,ut as b,Wt as c,zt as d,p as e,kt as f,ce as g,$t as h};
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ import{c as st}from"./chunk-CQ524DVH.js";import{a as U}from"./chunk-BZDBSBRV.js";import{g as b,k as R,m as I}from"./chunk-IJ67OEKX.js";import{c as tt,g as et,n as ot,s as nt,v as rt}from"./chunk-PN5C7EHL.js";import c from"chalk";import{resolve as wt,join as N}from"path";import{readFileSync as z}from"fs";import{statSync as Nt,readdirSync as Tt,unlinkSync as At}from"fs";import M from"crypto";var vt="vibeflow-auth-v1",xt=1440*60*1e3;function it(t){return M.scryptSync(t,vt,32)}function jt(t,e){let o=it(e),n=M.randomBytes(16),r=M.createCipheriv("aes-256-gcm",o,n),s=JSON.stringify(t),i=Buffer.concat([r.update(s),r.final()]),y=r.getAuthTag();return{version:1,createdAt:new Date().toISOString(),expiresAt:new Date(Date.now()+xt).toISOString(),iv:n.toString("hex"),tag:y.toString("hex"),data:i.toString("hex")}}function at(t,e){if(new Date(t.expiresAt)<new Date)return null;try{let o=it(e),n=M.createDecipheriv("aes-256-gcm",o,Buffer.from(t.iv,"hex"));n.setAuthTag(Buffer.from(t.tag,"hex"));let r=Buffer.concat([n.update(Buffer.from(t.data,"hex")),n.final()]);return JSON.parse(r.toString())}catch{return null}}function bt(t,e){return Math.abs(t.x-e.x)>2||Math.abs(t.y-e.y)>2||Math.abs(t.width-e.width)>2||Math.abs(t.height-e.height)>2}function H(t,e){let o=!!e.outerHTML,n=t.outerHTML!==e.outerHTML,r={},s=new Set([...Object.keys(t.computedStyles),...Object.keys(e.computedStyles)]);for(let l of s){let E=t.computedStyles[l],x=e.computedStyles[l];E!==x&&(r[l]=[E??"",x??""])}let i=bt(t.position.boundingBox,e.position.boundingBox),y=new Set(t.consoleErrors),g=e.consoleErrors.filter(l=>!y.has(l));return{selectorResolves:o,htmlChanged:n,stylesChanged:r,positionChanged:i,newConsoleErrors:g}}function ct(t,e){let o=[];if(t.selectorResolves){t.htmlChanged&&o.push("HTML changed");let n=Object.keys(t.stylesChanged).length;if(n>0){let r=Object.keys(t.stylesChanged).slice(0,5).join(", "),s=n>5?` (+${n-5} more)`:"";o.push(`${n} style property change(s): ${r}${s}`)}t.positionChanged&&o.push("position shifted"),t.newConsoleErrors.length>0&&o.push(`${t.newConsoleErrors.length} new console error(s)`),o.length===0&&o.push("no structural changes detected")}else o.push(`Selector "${e}" no longer resolves`);return o.join("; ")}import{readFileSync as lt,writeFileSync as Ht,mkdirSync as Jt,existsSync as ft}from"fs";import{join as gt,basename as Rt}from"path";import{execSync as Ct}from"child_process";var G={port:3700};function Ot(t){return gt(t,tt,et)}function ut(t){let e=Ot(t);if(!ft(e))return{...G};let o=lt(e,"utf-8"),n;try{n=JSON.parse(o)}catch{return{...G}}return{...G,...n}}function Wt(t){let e=gt(t,"package.json");if(ft(e))try{let o=JSON.parse(lt(e,"utf-8"));if(o.name)return o.name}catch{}return Rt(t)}function zt(t){try{return Ct("git branch --show-current",{cwd:t,encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()||null}catch{return null}}var W=["display","visibility","opacity","position","overflow","overflow-x","overflow-y","width","min-width","max-width","height","min-height","max-height","margin","margin-top","margin-right","margin-bottom","margin-left","padding","padding-top","padding-right","padding-bottom","padding-left","border","border-width","border-style","border-color","border-radius","background-color","background-image","color","font-size","font-weight","font-style","font-family","line-height","letter-spacing","text-align","text-decoration","text-overflow","white-space","flex-direction","flex-wrap","flex","justify-content","align-items","gap","row-gap","column-gap","grid-template-columns","grid-template-rows","z-index","box-shadow","transform","transition","cursor","user-select","pointer-events","top","left","right","bottom"];function dt(t){let e=[],o=t;for(;o&&o!==document.documentElement;){let n=o.parentElement;if(!n)break;let r=Array.from(n.children).indexOf(o);e.unshift(r),o=n}return e.join("/")}function ht(t){let e=t.tagName.toLowerCase(),o=t.getAttribute("data-task-id");if(o)return`${e}.task-card[data-task-id=${o}]`;let n=t.getAttribute("data-status");if(n&&t.classList.contains("column-scroll"))return`${e}.column-scroll[data-status=${n}]`;let r=t.getAttribute("data-column-id");if(r)return`${e}[data-column-id=${r}]`;let s=Array.from(t.classList).slice(0,2),i=e;s.length&&(i+="."+s.join("."));let y=t.parentElement;if(y){let g=Array.from(y.children).filter(l=>l.tagName===t.tagName);if(g.length>1){let l=g.indexOf(t)+1;i+=`:nth-of-type(${l})`}}return i}function mt(t,e=W){let o=window.getComputedStyle(t),n={};for(let r of e)n[r]=o.getPropertyValue(r);return n}function pt(t,e=200){return t.replace(/\s+/g," ").trim().slice(0,e)}function yt(t){let e=new Map;for(let o of t){let n=o.tagName.toLowerCase(),r=Array.from(o.classList).slice(0,2).join("."),s=r?`${n}.${r}`:n;e.set(s,(e.get(s)||0)+1)}return Array.from(e.entries()).map(([o,n])=>`${o} \xD7${n}`).slice(0,10)}var p=class extends Error{constructor(o,n,r){super(n);this.code=o;this.suggestion=r;this.name="VerifyError"}code;suggestion};async function Pt(){try{return await import("playwright")}catch{throw new p("E_PLAYWRIGHT_MISSING","Playwright is not installed.","Run: npx playwright install chromium")}}async function kt(t,e,o={}){let n=wt(t),r=ot(n,e);if(!r)throw new p("E_NOT_FOUND",`Task not found: ${e}`,"Run 'vibeflow tasks' to see available task IDs.");let s=nt(r);if(!s)throw new p("E_NOT_FOUND",`Task not found: ${e}`);let i,y=s.baselineElementFile||"baseline-element.json",g=I(n,e,y);if(g)try{i=JSON.parse(z(g,"utf-8"))}catch{}if(!i&&s.baseline&&(i=s.baseline),!i)throw new p("E_NO_BASELINE","Task has no baseline. Re-annotate to capture one.");let l=[],E={},x={};if(s.authStateEnc&&s.author)try{let m=JSON.parse(s.authStateEnc),f=at(m,s.author);if(!f)throw new p("E_AUTH_EXPIRED","Auth state expired. Re-annotate to capture fresh cookies.");l=f.cookies,E=f.localStorage,x=f.sessionStorage}catch(m){throw m instanceof p?m:new p("E_AUTH_CORRUPT","Auth state corrupted. Re-annotate.")}let v=o.url??s.url;if(!v)throw new p("E_NO_URL","Task has no URL. Cannot verify without a target URL.","Re-annotate the element with a URL, or use --url to override.");let C=ut(n).port??3700,A=v.startsWith("http")?v:`http://localhost:${C}${v.startsWith("/")?v:"/"+v}`,S=s.cssSelector??s.selector;if(!S||S==="/")throw new p("E_NO_SELECTOR","Task has no CSS selector. Cannot verify without a selector.");let j=await Pt(),$;try{$=await j.chromium.launch({headless:!0})}catch(m){let f=m instanceof Error?m.message:String(m);throw f.includes("not found")||f.includes("not installed")||f.includes("Executable doesn't exist")?new p("E_PLAYWRIGHT_MISSING","Chromium is not installed.","Run: npx playwright install chromium"):new p("E_PLAYWRIGHT_CRASH",`Verification failed: ${f}`,"Try again.")}let k;try{let m=i.position?.viewport;k=await $.newContext({viewport:m?{width:m.width,height:m.height}:void 0,deviceScaleFactor:m?.dpr,userAgent:i.browser||void 0}),l.length>0&&await k.addCookies(l.map(a=>({name:a.name,value:a.value,domain:a.domain,path:a.path,expires:a.expires,httpOnly:a.httpOnly,secure:a.secure,sameSite:a.sameSite})));let f=await k.newPage(),T=[];f.on("console",a=>{a.type()==="error"&&T.push(a.text())}),f.on("pageerror",a=>{T.push(a.message)});try{await f.goto(A,{waitUntil:"networkidle",timeout:15e3})}catch(a){let u=a instanceof Error?a.message:String(a);throw u.includes("ERR_CONNECTION_REFUSED")||u.includes("ECONNREFUSED")?new p("E_APP_NOT_RUNNING",`Cannot connect to ${A}. Is the dev server running?`):new p("E_NAVIGATION_FAILED",`Failed to navigate to ${A}: ${u}`)}try{Object.keys(E).length>0&&await f.evaluate(a=>{for(let[u,d]of Object.entries(a))window.localStorage.setItem(u,d)},E),Object.keys(x).length>0&&await f.evaluate(a=>{for(let[u,d]of Object.entries(a))window.sessionStorage.setItem(u,d)},x)}catch{}let P=0;try{await f.waitForSelector(S,{timeout:1e4}),P=await f.locator(S).count()}catch{let a={outerHTML:"",computedStyles:{},selector:S,position:i.position,browser:i.browser,consoleErrors:T,capturedAt:new Date().toISOString()},u=H(i,a);return K(s.id,s.description,i,a,u,[],S)}if(P>1){let a={outerHTML:"",computedStyles:{},selector:S,position:i.position,browser:i.browser,consoleErrors:T,capturedAt:new Date().toISOString()},u=H(i,a),d=`Selector matches ${P} elements. The selector may need to be more specific.`;return K(s.id,s.description,i,a,u,[],S,d)}let L=await Lt(f,S,i,T),_=null,B=s.baselineFile||"baseline-page.json",F=I(n,e,B);if(F)try{_=JSON.parse(z(F,"utf-8"))}catch{}let h=H(i,L),O=await _t(n,e,i,L,h,T,f,S);if(_&&_.elements){let a=I(n,e,"verify-all-styles.json");if(a)try{let u=JSON.parse(z(a,"utf-8"));if(u&&u.elements){let d={},St=Object.entries(u.elements);for(let[Y,X]of St){let J=_.elements[Y]?.after;if(J){X.baseline=J;let V={};for(let[q,Q]of Object.entries(X.after)){let Z=J[q];Z!==Q&&(V[q]=[Z,Q])}Object.keys(V).length>0&&(d[Y]=V)}}R(n,e,"verify-all-styles.json",Buffer.from(JSON.stringify(u,null,2)));let Et=JSON.stringify({totalChanged:Object.keys(d).length,elements:d},null,2);R(n,e,"verify-page-diff.json",Buffer.from(Et)),O.push(N(b(n,e),"verify-page-diff.json"))}}catch{}}let D=K(s.id,s.description,i,L,h,O,S);return rt(n,e,{verified:D.ok}),D}finally{await k?.close(),await $?.close()}}async function Lt(t,e,o,n){let r=t.locator(e).first(),s=await r.evaluate(l=>l.outerHTML).catch(()=>""),i=await r.evaluate(l=>{let E=window.getComputedStyle(l),x={};for(let v=0;v<E.length;v++){let w=E[v];x[w]=E.getPropertyValue(w)}return x}).catch(()=>({})),g={boundingBox:await r.boundingBox().catch(()=>null)??o.position.boundingBox,scrollPosition:await t.evaluate(()=>({x:window.scrollX,y:window.scrollY})),viewport:await t.evaluate(()=>({width:window.innerWidth,height:window.innerHeight,dpr:window.devicePixelRatio})),stackingContext:o.position.stackingContext};return{outerHTML:s,computedStyles:i,selector:e,position:g,browser:o.browser,consoleErrors:n,capturedAt:new Date().toISOString()}}async function _t(t,e,o,n,r,s,i,y){let g=[],l=b(t,e);try{let w=Tt(l);for(let C of w)(C.startsWith("verify-")||C==="baseline.json")&&At(N(l,C))}catch{}let E=JSON.stringify(n,null,2);R(t,e,"verify-after.json",Buffer.from(E)),g.push(N(b(t,e),"verify-after.json"));let x=JSON.stringify(r,null,2);R(t,e,"verify-diff.json",Buffer.from(x)),g.push(N(b(t,e),"verify-diff.json"));let v=s.length>0?s.join(`
3
+ `):"(no console errors)";if(R(t,e,"verify-console.txt",Buffer.from(v)),g.push(N(b(t,e),"verify-console.txt")),i){try{let w=await i.content();R(t,e,"verify-page.html",Buffer.from(w)),g.push(N(b(t,e),"verify-page.html"))}catch{}try{let C=await i.evaluate(({buildKeyFn:A,buildSelectorFn:S,filterStylesFn:j,childSignatureFn:$,normalizeTextFn:k,styles:m,maxElements:f})=>{let T={},P=0,L=!1,_=document.createTreeWalker(document.body,NodeFilter.SHOW_ELEMENT,{acceptNode(h){if(P>=f)return NodeFilter.FILTER_REJECT;let O=h;return O.classList.length>0||O.hasAttribute("data-task-id")||O.hasAttribute("data-status")||O.hasAttribute("data-column-id")?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP}}),B=[],F;for(;F=_.nextNode();)B.push(F);for(let h of B){if(P>=f){L=!0;break}let O=A(h),D=Array.from(h.children),a={};for(let d of Array.from(h.attributes))d.name.startsWith("data-")&&(a[d.name.slice(5)]=d.value);let u={x:0,y:0,width:0,height:0};try{let d=h.getBoundingClientRect();u={x:Math.round(d.x),y:Math.round(d.y),width:Math.round(d.width),height:Math.round(d.height)}}catch{}T[O]={key:O,selector:S(h),tag:h.tagName.toLowerCase(),classes:Array.from(h.classList),dataAttrs:a,parentKey:h.parentElement?A(h.parentElement):"",childCount:D.length,childSignature:$(D),text:k(h.textContent??""),position:u,baseline:j(h,m),after:j(h,m)},P++}return{version:1,capturedAt:new Date().toISOString(),truncated:L,elements:T}},{buildKeyFn:dt,buildSelectorFn:ht,filterStylesFn:mt,childSignatureFn:yt,normalizeTextFn:pt,styles:W,maxElements:1e3});if(C){let A=JSON.stringify(C,null,2);R(t,e,"verify-all-styles.json",Buffer.from(A)),g.push(N(b(t,e),"verify-all-styles.json"))}}catch{}try{let w=await i.screenshot({fullPage:!1});R(t,e,"verify-screenshot.png",w),g.push(N(b(t,e),"verify-screenshot.png"))}catch{}if(y)try{let w=await i.locator(y).first().evaluate(C=>C.outerHTML);R(t,e,"verify-element.html",Buffer.from(w)),g.push(N(b(t,e),"verify-element.html"))}catch{}}if(o){let w=JSON.stringify(o,null,2);R(t,e,"baseline.json",Buffer.from(w)),g.push(N(b(t,e),"baseline.json"))}return g}function K(t,e,o,n,r,s,i,y){let g=r.selectorResolves&&r.newConsoleErrors.length===0,l=y??ct(r,i);return{taskId:t,ok:g,taskDescription:e,baseline:{selector:o.selector,url:"",capturedAt:o.capturedAt,snapshot:o},after:{snapshot:n,consoleErrors:n.consoleErrors},diff:r,evidenceFiles:s,verdict:l}}async function ce(t,e,o){let n=wt(t);try{let r=await kt(n,e,o);await $t(n,e,r),o.json?console.log(JSON.stringify(r,null,2)):Ft(r)}catch(r){if(r instanceof p)o.json?process.stderr.write(JSON.stringify({ok:!1,error:{code:r.code,message:r.message,suggestion:r.suggestion}})+`
4
+ `):(process.stderr.write(c.red(`\u2717 ${r.message}
5
+ `)),r.suggestion&&process.stderr.write(c.dim(` ${r.suggestion}
6
+ `))),process.exitCode=U.GENERAL;else{let s=r instanceof Error?r.message:String(r);o.json?process.stderr.write(JSON.stringify({ok:!1,error:{code:"E_UNKNOWN",message:s}})+`
7
+ `):process.stderr.write(c.red(`\u2717 Verification failed: ${s}
8
+ `)),process.exitCode=U.GENERAL}}}async function $t(t,e,o){let n=`**Verification ${o.ok?"\u2705 passed":"\u26A0\uFE0F issues detected"}**
9
+
10
+ ${o.verdict}`;st(t,e,"agent",n,void 0,"system")}function Ft(t){let e=t.ok?c.green("\u2705"):c.yellow("\u26A0\uFE0F");console.log(),console.log(` ${e} Evidences collected for task ${t.taskId}`),console.log(c.dim("\u2500".repeat(60))),console.log(c.dim(` Verdict: ${t.verdict}`)),console.log();let o=t.diff;if(o.selectorResolves){o.htmlChanged?console.log(c.cyan(" \u2713 HTML changed")):console.log(c.dim(" \xB7 HTML unchanged"));let n=Object.keys(o.stylesChanged).length;if(n>0){console.log(c.cyan(` \u2713 ${n} style property change(s):`));for(let[r,[s,i]]of Object.entries(o.stylesChanged).slice(0,8))console.log(c.dim(` ${r}: ${s} \u2192 ${i}`));n>8&&console.log(c.dim(` ... and ${n-8} more`))}if(o.positionChanged&&console.log(c.cyan(" \u2713 Position shifted")),o.newConsoleErrors.length>0){console.log(c.yellow(` \u26A0 ${o.newConsoleErrors.length} new console error(s):`));for(let r of o.newConsoleErrors.slice(0,3))console.log(c.dim(` ${r.slice(0,120)}`))}}else console.log(c.red(" \u26A0 Target element not found \u2014 the fix may have renamed/removed it."));if(t.evidenceFiles.length>0){console.log(c.cyan(` Evidence files (${t.evidenceFiles.length}):`));for(let n of t.evidenceFiles){let r=n.split("/").pop()??n;try{let i=(Nt(n).size/1024).toFixed(1);console.log(c.dim(` ${r} (${i} KB)`))}catch{console.log(c.dim(` ${r}`))}}}console.log(),console.log(c.cyan(" Explore evidence (agent tools):")),console.log(c.dim(` vibeflow verify style_query ${t.taskId} <property>`)),console.log(c.dim(` vibeflow verify style_diff ${t.taskId} [--filter <pattern>]`)),console.log(c.dim(` vibeflow verify element_info ${t.taskId}`)),console.log(c.dim(` vibeflow verify html_diff ${t.taskId}`)),console.log(),console.log(c.cyan(" Review evidences:")),console.log(c.dim(" 1. Check if the fix is confirmed (styles match expectations)")),console.log(c.dim(` 2. If confirmed \u2192 vibeflow tasks --edit ${t.taskId} --set-status review --comment "Verified: <what you confirmed>"`)),console.log(c.dim(" 3. If not sure \u2192 leave a comment explaining uncertainty")),console.log(c.dim(` 4. If wrong \u2192 vibeflow tasks --edit ${t.taskId} --set-status in-progress`)),console.log(),t.ok||(console.log(c.yellow(" \u26A0 Verification failed \u2014 move to in-progress and fix:")),console.log(c.dim(` vibeflow tasks --edit ${t.taskId} --set-status in-progress`)))}export{jt as a,ut as b,Wt as c,zt as d,p as e,kt as f,ce as g,$t as h};
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{c as y,e as S,n as R,s as T,v as x}from"./chunk-ZHA4Y2KB.js";import{readdirSync as A,writeFileSync as z,readFileSync as O,unlinkSync as m,statSync as g,mkdirSync as $,existsSync as f}from"fs";import{join as l,basename as d}from"path";var h=".linked.json";function c(e,n){return l(e,y,S,n)}function b(e,n){$(c(e,n),{recursive:!0})}function L(e,n){let s=l(c(e,n),h);if(!f(s))return[];try{return JSON.parse(O(s,"utf-8"))}catch{return[]}}function F(e,n){let s=R(e,n),r=s?T(s):null;return!r?.files||r.files.length===0?[]:r.files}function P(e,n){return F(e,n)}function k(e,n,s){x(e,n,{files:s})}function p(e,n){let s=F(e,n),r=l(c(e,n),h);if(!f(r))return s;let i=L(e,n);if(i.length===0){try{m(r)}catch{}return s}let t=s.slice(),o=!1;for(let a of i)t.find(u=>u.linkedPath===a.path||u.name===a.name&&u.linkedPath)||(t.push({name:a.name,linkedPath:a.path,addedAt:new Date().toISOString()}),o=!0);o&&k(e,n,t);try{m(r)}catch{}return t}function v(e,n){let s=c(e,n),r=P(e,n),i=new Map;for(let t of r){if(t.linkedPath&&f(t.linkedPath)){let a=g(t.linkedPath);i.set(t.name,{name:t.name,size:a.size,url:`/api/tasks/${n}/files/${encodeURIComponent(t.name)}`,linkedPath:t.linkedPath,createdAt:a.mtime.toISOString()});continue}let o=l(s,t.name);if(f(o)){let a=g(o);i.set(t.name,{name:t.name,size:a.size,url:`/api/tasks/${n}/files/${encodeURIComponent(t.name)}`,createdAt:a.mtime.toISOString()})}}if(f(s))for(let t of A(s,{withFileTypes:!0})){if(!t.isFile()||t.name===h||i.has(t.name))continue;let o=l(s,t.name),a=g(o);i.set(t.name,{name:t.name,size:a.size,url:`/api/tasks/${n}/files/${encodeURIComponent(t.name)}`,createdAt:a.mtime.toISOString()})}return Array.from(i.values())}function U(e,n,s,r){let i=d(s);b(e,n),z(l(c(e,n),i),r);let t=p(e,n);return t.find(o=>o.name===i&&!o.linkedPath)||(t.push({name:i,addedAt:new Date().toISOString()}),k(e,n,t)),{name:i,size:r.length,url:`/api/tasks/${n}/files/${encodeURIComponent(i)}`}}function E(e,n,s){let r=d(s),i=p(e,n),t=i.findIndex(a=>a.name===r);if(t!==-1){let[a]=i.splice(t,1);if(k(e,n,i),a&&!a.linkedPath){let u=l(c(e,n),r);f(u)&&m(u)}return!0}let o=l(c(e,n),r);return f(o)?(m(o),!0):!1}function _(e,n,s){let r=d(s),i=P(e,n).find(o=>o.name===r&&o.linkedPath);if(i?.linkedPath&&f(i.linkedPath))return i.linkedPath;let t=l(c(e,n),r);return f(t)?t:null}function M(e,n){return v(e,n).length}async function B(e){let{listTasks:n}=await import("./tasks-N3AEGAEB.js"),s=n(e),r=0;for(let i of s)try{let t=P(e,i.id);p(e,i.id),F(e,i.id).length!==t.length&&r++}catch{}return r}export{c as a,b,P as c,v as d,U as e,E as f,_ as g,M as h,B as i};
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ import{a as C,b as M}from"./chunk-KJ5LYG6A.js";import{a as _,b as W}from"./chunk-FYRJDWDC.js";import{a as P}from"./chunk-BZDBSBRV.js";import{g as F,j as L}from"./chunk-BBIA4IIO.js";import{n as N}from"./chunk-Q7MEW67Z.js";import{d as T,e as j,g as B}from"./chunk-XHZXHACL.js";import u from"chalk";import{unlinkSync as K,readFileSync as de,existsSync as E}from"fs";import{resolve as pe,join as O}from"path";import A from"fs/promises";import Q from"os";import D from"path";var X=D.join(Q.homedir(),".vibeflow"),x=D.join(X,"token");async function R(){try{return(await A.readFile(x,"utf8")).trim()||null}catch{return null}}async function z(t){await A.mkdir(D.dirname(x),{recursive:!0}),await A.writeFile(x,t,{mode:384})}async function we(){try{await A.unlink(x)}catch{}}import n from"chalk";import Z from"open";import H from"readline";import ee from"@inquirer/select";import{existsSync as te,readdirSync as q,readFileSync as oe}from"fs";import{join as v,resolve as re}from"path";var se="https://app.vibeflow.tools",ne=300*1e3;function G(){return process.env.VIBEFLOW_API_URL??se}async function ie(t){return new Promise(i=>setTimeout(i,t))}async function ae(t){return t.length===1?(console.log(n.dim(` Using board: ${t[0].icon??""} ${t[0].name}`)),t[0]):await ee({message:"Select a board to use:",choices:t.map(o=>({name:`${o.icon??""} ${o.name}`,value:o}))})}async function J(t,i){try{let o=await fetch(`${t}/api/cli/settings`,{headers:{Authorization:`Bearer ${i}`}});if(!o.ok)return;let s=await o.json();s.settings&&Object.keys(s.settings).length>0&&W({...s.settings,_settingsRefreshedAt:Date.now()})}catch{}}async function Ce(){try{let t=await R();if(!t)return;let o=_()._settingsRefreshedAt??0;if(Date.now()-o<ne)return;let s=G();J(s,t)}catch{}}async function le(t,i){try{let[o,s]=await Promise.all([fetch(`${t}/api/cli/workspaces`,{headers:{Authorization:`Bearer ${i}`}}),fetch(`${t}/api/cli/profile`,{headers:{Authorization:`Bearer ${i}`}})]);if(!o.ok)return;let l=await o.json();if(!l.workspaces?.length){console.log(n.yellow(" No boards found. Create a board in the web app first."));return}let a=s.ok?await s.json():null,m=await ae(l.workspaces);await M({...m,email:a?.email??null}),console.log(n.green(` Board set: ${m.icon??""} ${m.name}`)),console.log(n.dim(` Open at: ${m.url}`))}catch{}}async function ce(t,i,o,s){let l=v(t,T,j);if(!te(l))return;let a=[];try{for(let e of q(l,{withFileTypes:!0}))if(e.isDirectory()){let d=v(l,e.name);for(let k of q(d).filter(c=>c.endsWith(".json")))a.push(v(d,k))}else e.isFile()&&e.name.endsWith(".json")&&a.push(v(l,e.name))}catch{return}if(a.length===0)return;let m=a.flatMap(e=>{try{return[JSON.parse(oe(e,"utf-8"))]}catch{return[]}}),h=new Set;try{let e=await fetch(`${i}/api/cli/tasks?boardId=${s.id}`,{headers:{Authorization:`Bearer ${o}`}}).catch(()=>null);if(e?.ok){let d=await e.json();h=new Set((d.tasks??[]).flatMap(k=>[k.id,...k.cliId?[k.cliId]:[]]))}}catch{}let g=m.filter(e=>!h.has(e.id));if(g.length===0)return;console.log(),console.log(n.bold(` ${g.length} local task${g.length!==1?"s are":" is"} not yet synced to the board:`));let y=g.slice(0,10);for(let e of y){let d=e.status?n.dim(` [${e.status}]`):"";console.log(n.dim(` \u2022 ${e.title??e.id}${d}`))}return g.length>10&&console.log(n.dim(` \u2026 and ${g.length-10} more`)),new Promise(e=>{let d=H.createInterface({input:process.stdin,output:process.stdout});d.question(n.cyan(`
3
+ Push them to your board now? [Y/n]: `),async k=>{if(d.close(),k.trim().toLowerCase()==="n"){console.log(n.dim(" Skipped. You can push later with: vibeflow push")),e();return}let c=H.createInterface({input:process.stdin,output:process.stdout});c.question(n.cyan(" Delete local task files after push? [y/N]: "),async $=>{c.close();let b=$.trim().toLowerCase()!=="y";try{let p=await fetch(`${i}/api/cli/import`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},body:JSON.stringify({boardId:s.id,tasks:g,keepLocalFiles:b})}),f={};try{f=await p.json()}catch{}p.ok?(console.log(n.green(` \u2713 Pushed ${f.imported??0} task${(f.imported??0)!==1?"s":""} to ${s.name}`)),(f.skipped??0)>0&&console.log(n.dim(` (${f.skipped} already existed and were skipped)`))):console.log(n.red(` Push failed: ${f.error??`HTTP ${p.status}`}`))}catch(p){console.log(n.red(` Push failed: ${p instanceof Error?p.message:"Network error"}`))}e()})})})}async function V(t=re(".")){let i=G();console.log(n.cyan(" Initiating device login flow..."));let o;try{o=await fetch(`${i}/api/cli/auth/device-init`,{method:"POST",headers:{"Content-Type":"application/json"}})}catch(y){console.error(n.red(` Failed to connect to login server: ${y instanceof Error?y.message:"Network error"}`)),process.exitCode=P.AUTH;return}if(!o.ok){console.error(n.red(` Failed to initiate login: ${o.status} ${o.statusText}`)),process.exitCode=P.AUTH;return}let{deviceCode:s,userCode:l,verificationUrl:a,expiresIn:m}=await o.json();console.log(),console.log(n.bold(" Open this URL in your browser to authorize:")),console.log(n.underline(` ${a}`)),console.log();try{await Z(a),console.log(n.dim(" (Browser opened automatically)"))}catch{}let h=Date.now()+m*1e3,g=3e3;for(;Date.now()<h;){await ie(g);let y=null;try{y=await fetch(`${i}/api/cli/auth/device-poll`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({deviceCode:s})})}catch{console.error(n.red(" Poll request failed (network error). Retrying..."));continue}if(!y.ok){console.error(n.red(" Poll request failed. Retrying..."));continue}let e=await y.json();if("token"in e){await z(e.token),console.log(),console.log(n.green(" Logged in successfully. Now operating in SaaS mode.")),await Promise.all([le(i,e.token),J(i,e.token)]);let{readWorkspace:d}=await import("./workspace-KGOQ67YV.js"),k=await d();k&&await ce(t,i,e.token,k);return}if("expired"in e){console.error(n.red(" Device code expired. Please try again.")),process.exitCode=P.AUTH;return}process.stdout.write(n.dim("."))}console.error(n.red(`
4
+ Login timed out. Please try again.`)),process.exitCode=P.AUTH}var fe="https://app.vibeflow.tools";function ue(){return process.env.VIBEFLOW_API_URL??fe}function me(t){return t<1024?`${t} B`:t<1024*1024?`${(t/1024).toFixed(1)} KB`:`${(t/(1024*1024)).toFixed(1)} MB`}function Y(t,i,o=24){let s=Math.round(t/i*o);return`[${"\u2588".repeat(s)+"\u2591".repeat(o-s)}]`}async function ge(t,i,o,s){let l=[];for(let{localId:c,remoteId:$}of s){let b=L(o,c);for(let p of b){let f=p.linkedPath??O(F(o,c),p.name);E(f)&&l.push({remoteId:$,name:p.name,filePath:f,size:p.size})}}if(l.length===0)return{uploaded:0,failed:0,failedFiles:[]};let a=l.length,m=l.reduce((c,$)=>c+$.size,0);console.log(u.cyan(`
5
+ Uploading ${a} file(s) (${me(m)})...`));let h=0,g=0,y=0,e=Date.now(),d=[];for(let c of l){let $=Math.round(h/a*100),b=Y(h,a),p=(Date.now()-e)/1e3,f=y/Math.max(p,.01),r=m-y,w=f>0?Math.ceil(r/f):0,I=w>60?`${Math.ceil(w/60)}m`:`${w}s`;process.stdout.write(`\r ${b} ${$}% ${c.name.slice(0,28)} ETA: ${I} `);try{let S=de(c.filePath),U=await fetch(`${t}/api/tasks/${encodeURIComponent(c.remoteId)}/files`,{method:"POST",headers:{Authorization:`Bearer ${i}`,"Content-Type":"application/octet-stream","x-filename":encodeURIComponent(c.name)},body:S});U.ok?(h++,y+=c.size):(g++,d.push({name:c.name,reason:`HTTP ${U.status}`}))}catch(S){g++,d.push({name:c.name,reason:S instanceof Error?S.message:String(S)})}}let k=Y(a,a);return process.stdout.write(`\r ${k} 100% Done${" ".repeat(40)}
6
+ `),{uploaded:h,failed:g,failedFiles:d}}async function He(t,i){let o=pe(t),s=N(o);if(s.length===0)return console.log(u.dim(" No local tasks found. Nothing to push.")),{dryRun:!!i.dryRun,tasks:0,files:0,steps:["No tasks"]};let l=0;for(let r of s){let w=L(o,r.id);l+=w.length}let a=i.workspace;if(!a){let r=await C().catch(()=>null);r&&(a=r.id)}let m=a?(await C().catch(()=>null))?.name??a:"(no board selected)";if(i.dryRun)return console.log(u.cyan(` Dry run: ${s.length} task(s), ${l} file(s), board: ${m}`)),{dryRun:!0,tasks:s.length,files:l,board:m,steps:["Dry run: no changes made"]};let h=await R();if(!h&&(console.log(u.yellow(" Not logged in. Starting login flow...")),await V(),h=await R(),!h)){console.error(u.red(" Login failed. Please run `vibeflow login` and try again.")),process.exitCode=P.AUTH;return}console.log(u.cyan(` Found ${s.length} local task(s). Pushing to SaaS...`));let g=ue(),y={tasks:s};a&&(y.workspaceId=a);let e;try{let r=await fetch(`${g}/api/cli/import`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${h}`},body:JSON.stringify(y)});if(!r.ok){let w=await r.json().catch(()=>({}));console.error(u.red(` Import failed: ${r.status} ${w.error??r.statusText}`)),process.exitCode=P.GENERAL;return}e=await r.json()}catch(r){let w=r instanceof Error?r.message:String(r);console.error(u.red(` Network error: ${w}`)),process.exitCode=P.GENERAL;return}console.log(u.green(` \u2713 Pushed ${e.imported} task(s) to SaaS`)),e.skipped&&e.skipped>0&&console.log(u.dim(` Skipped ${e.skipped} already-imported task(s).`)),console.log(u.dim(` Board: ${m}`));let d=e.idMap??{},k=s.filter(r=>r.id&&d[r.id]).map(r=>({localId:r.id,remoteId:d[r.id]})),{uploaded:c,failed:$,failedFiles:b}=await ge(g,h,o,k);if(c>0&&console.log(u.green(` \u2713 Uploaded ${c} file(s) to storage`)),$>0){console.log(u.yellow(` \u26A0 ${$} file(s) failed to upload`));for(let r of b)console.log(u.dim(` - ${r.name}: ${r.reason}`))}if(i.keepLocalFiles){console.log(u.dim(" Local task files kept (--keep-local-files)."));return}let p=0,f=0;for(let r of s){try{K(r.filePath),p++}catch{}try{let w=F(o,r.id);if(E(w)){let{rmSync:I}=await import("fs");I(w,{recursive:!0,force:!0}),f++}}catch{}try{let w=O(o,T,B),I=O(w,`${r.id}.png`);E(I)&&(K(I),f++)}catch{}}return console.log(u.dim(` Deleted ${p} local task file(s).`)),f>0&&console.log(u.dim(` Cleaned ${f} orphaned asset dir(s).`)),{dryRun:!1,tasks:p,files:l,board:m,steps:["Push completed"]}}export{R as a,we as b,Ce as c,V as d,me as e,Y as f,He as g};
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ import{c as st}from"./chunk-EAYTSVCN.js";import{a as U}from"./chunk-BZDBSBRV.js";import{a as b,e as R,g as I}from"./chunk-PWP474PZ.js";import{d as tt,h as et,o as ot,s as nt,v as rt}from"./chunk-2CI62NHU.js";import c from"chalk";import{resolve as wt,join as N}from"path";import{readFileSync as z}from"fs";import{statSync as Nt,readdirSync as Tt,unlinkSync as At}from"fs";import M from"crypto";var vt="vibeflow-auth-v1",xt=1440*60*1e3;function it(t){return M.scryptSync(t,vt,32)}function jt(t,e){let o=it(e),n=M.randomBytes(16),r=M.createCipheriv("aes-256-gcm",o,n),s=JSON.stringify(t),i=Buffer.concat([r.update(s),r.final()]),y=r.getAuthTag();return{version:1,createdAt:new Date().toISOString(),expiresAt:new Date(Date.now()+xt).toISOString(),iv:n.toString("hex"),tag:y.toString("hex"),data:i.toString("hex")}}function at(t,e){if(new Date(t.expiresAt)<new Date)return null;try{let o=it(e),n=M.createDecipheriv("aes-256-gcm",o,Buffer.from(t.iv,"hex"));n.setAuthTag(Buffer.from(t.tag,"hex"));let r=Buffer.concat([n.update(Buffer.from(t.data,"hex")),n.final()]);return JSON.parse(r.toString())}catch{return null}}function bt(t,e){return Math.abs(t.x-e.x)>2||Math.abs(t.y-e.y)>2||Math.abs(t.width-e.width)>2||Math.abs(t.height-e.height)>2}function H(t,e){let o=!!e.outerHTML,n=t.outerHTML!==e.outerHTML,r={},s=new Set([...Object.keys(t.computedStyles),...Object.keys(e.computedStyles)]);for(let l of s){let E=t.computedStyles[l],x=e.computedStyles[l];E!==x&&(r[l]=[E??"",x??""])}let i=bt(t.position.boundingBox,e.position.boundingBox),y=new Set(t.consoleErrors),g=e.consoleErrors.filter(l=>!y.has(l));return{selectorResolves:o,htmlChanged:n,stylesChanged:r,positionChanged:i,newConsoleErrors:g}}function ct(t,e){let o=[];if(t.selectorResolves){t.htmlChanged&&o.push("HTML changed");let n=Object.keys(t.stylesChanged).length;if(n>0){let r=Object.keys(t.stylesChanged).slice(0,5).join(", "),s=n>5?` (+${n-5} more)`:"";o.push(`${n} style property change(s): ${r}${s}`)}t.positionChanged&&o.push("position shifted"),t.newConsoleErrors.length>0&&o.push(`${t.newConsoleErrors.length} new console error(s)`),o.length===0&&o.push("no structural changes detected")}else o.push(`Selector "${e}" no longer resolves`);return o.join("; ")}import{readFileSync as lt,writeFileSync as Ht,mkdirSync as Jt,existsSync as ft}from"fs";import{join as gt,basename as Rt}from"path";import{execSync as Ct}from"child_process";var G={port:3700};function Ot(t){return gt(t,tt,et)}function ut(t){let e=Ot(t);if(!ft(e))return{...G};let o=lt(e,"utf-8"),n;try{n=JSON.parse(o)}catch{return{...G}}return{...G,...n}}function Wt(t){let e=gt(t,"package.json");if(ft(e))try{let o=JSON.parse(lt(e,"utf-8"));if(o.name)return o.name}catch{}return Rt(t)}function zt(t){try{return Ct("git branch --show-current",{cwd:t,encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()||null}catch{return null}}var W=["display","visibility","opacity","position","overflow","overflow-x","overflow-y","width","min-width","max-width","height","min-height","max-height","margin","margin-top","margin-right","margin-bottom","margin-left","padding","padding-top","padding-right","padding-bottom","padding-left","border","border-width","border-style","border-color","border-radius","background-color","background-image","color","font-size","font-weight","font-style","font-family","line-height","letter-spacing","text-align","text-decoration","text-overflow","white-space","flex-direction","flex-wrap","flex","justify-content","align-items","gap","row-gap","column-gap","grid-template-columns","grid-template-rows","z-index","box-shadow","transform","transition","cursor","user-select","pointer-events","top","left","right","bottom"];function dt(t){let e=[],o=t;for(;o&&o!==document.documentElement;){let n=o.parentElement;if(!n)break;let r=Array.from(n.children).indexOf(o);e.unshift(r),o=n}return e.join("/")}function ht(t){let e=t.tagName.toLowerCase(),o=t.getAttribute("data-task-id");if(o)return`${e}.task-card[data-task-id=${o}]`;let n=t.getAttribute("data-status");if(n&&t.classList.contains("column-scroll"))return`${e}.column-scroll[data-status=${n}]`;let r=t.getAttribute("data-column-id");if(r)return`${e}[data-column-id=${r}]`;let s=Array.from(t.classList).slice(0,2),i=e;s.length&&(i+="."+s.join("."));let y=t.parentElement;if(y){let g=Array.from(y.children).filter(l=>l.tagName===t.tagName);if(g.length>1){let l=g.indexOf(t)+1;i+=`:nth-of-type(${l})`}}return i}function mt(t,e=W){let o=window.getComputedStyle(t),n={};for(let r of e)n[r]=o.getPropertyValue(r);return n}function pt(t,e=200){return t.replace(/\s+/g," ").trim().slice(0,e)}function yt(t){let e=new Map;for(let o of t){let n=o.tagName.toLowerCase(),r=Array.from(o.classList).slice(0,2).join("."),s=r?`${n}.${r}`:n;e.set(s,(e.get(s)||0)+1)}return Array.from(e.entries()).map(([o,n])=>`${o} \xD7${n}`).slice(0,10)}var p=class extends Error{constructor(o,n,r){super(n);this.code=o;this.suggestion=r;this.name="VerifyError"}code;suggestion};async function Pt(){try{return await import("playwright")}catch{throw new p("E_PLAYWRIGHT_MISSING","Playwright is not installed.","Run: npx playwright install chromium")}}async function kt(t,e,o={}){let n=wt(t),r=ot(n,e);if(!r)throw new p("E_NOT_FOUND",`Task not found: ${e}`,"Run 'vibeflow tasks' to see available task IDs.");let s=nt(r);if(!s)throw new p("E_NOT_FOUND",`Task not found: ${e}`);let i,y=s.baselineElementFile||"baseline-element.json",g=I(n,e,y);if(g)try{i=JSON.parse(z(g,"utf-8"))}catch{}if(!i&&s.baseline&&(i=s.baseline),!i)throw new p("E_NO_BASELINE","Task has no baseline. Re-annotate to capture one.");let l=[],E={},x={};if(s.authStateEnc&&s.author)try{let m=JSON.parse(s.authStateEnc),f=at(m,s.author);if(!f)throw new p("E_AUTH_EXPIRED","Auth state expired. Re-annotate to capture fresh cookies.");l=f.cookies,E=f.localStorage,x=f.sessionStorage}catch(m){throw m instanceof p?m:new p("E_AUTH_CORRUPT","Auth state corrupted. Re-annotate.")}let v=o.url??s.url;if(!v)throw new p("E_NO_URL","Task has no URL. Cannot verify without a target URL.","Re-annotate the element with a URL, or use --url to override.");let C=ut(n).port??3700,A=v.startsWith("http")?v:`http://localhost:${C}${v.startsWith("/")?v:"/"+v}`,S=s.cssSelector??s.selector;if(!S||S==="/")throw new p("E_NO_SELECTOR","Task has no CSS selector. Cannot verify without a selector.");let j=await Pt(),$;try{$=await j.chromium.launch({headless:!0})}catch(m){let f=m instanceof Error?m.message:String(m);throw f.includes("not found")||f.includes("not installed")||f.includes("Executable doesn't exist")?new p("E_PLAYWRIGHT_MISSING","Chromium is not installed.","Run: npx playwright install chromium"):new p("E_PLAYWRIGHT_CRASH",`Verification failed: ${f}`,"Try again.")}let k;try{let m=i.position?.viewport;k=await $.newContext({viewport:m?{width:m.width,height:m.height}:void 0,deviceScaleFactor:m?.dpr,userAgent:i.browser||void 0}),l.length>0&&await k.addCookies(l.map(a=>({name:a.name,value:a.value,domain:a.domain,path:a.path,expires:a.expires,httpOnly:a.httpOnly,secure:a.secure,sameSite:a.sameSite})));let f=await k.newPage(),T=[];f.on("console",a=>{a.type()==="error"&&T.push(a.text())}),f.on("pageerror",a=>{T.push(a.message)});try{await f.goto(A,{waitUntil:"networkidle",timeout:15e3})}catch(a){let u=a instanceof Error?a.message:String(a);throw u.includes("ERR_CONNECTION_REFUSED")||u.includes("ECONNREFUSED")?new p("E_APP_NOT_RUNNING",`Cannot connect to ${A}. Is the dev server running?`):new p("E_NAVIGATION_FAILED",`Failed to navigate to ${A}: ${u}`)}try{Object.keys(E).length>0&&await f.evaluate(a=>{for(let[u,d]of Object.entries(a))window.localStorage.setItem(u,d)},E),Object.keys(x).length>0&&await f.evaluate(a=>{for(let[u,d]of Object.entries(a))window.sessionStorage.setItem(u,d)},x)}catch{}let P=0;try{await f.waitForSelector(S,{timeout:1e4}),P=await f.locator(S).count()}catch{let a={outerHTML:"",computedStyles:{},selector:S,position:i.position,browser:i.browser,consoleErrors:T,capturedAt:new Date().toISOString()},u=H(i,a);return K(s.id,s.description,i,a,u,[],S)}if(P>1){let a={outerHTML:"",computedStyles:{},selector:S,position:i.position,browser:i.browser,consoleErrors:T,capturedAt:new Date().toISOString()},u=H(i,a),d=`Selector matches ${P} elements. The selector may need to be more specific.`;return K(s.id,s.description,i,a,u,[],S,d)}let L=await Lt(f,S,i,T),_=null,B=s.baselineFile||"baseline-page.json",F=I(n,e,B);if(F)try{_=JSON.parse(z(F,"utf-8"))}catch{}let h=H(i,L),O=await _t(n,e,i,L,h,T,f,S);if(_&&_.elements){let a=I(n,e,"verify-all-styles.json");if(a)try{let u=JSON.parse(z(a,"utf-8"));if(u&&u.elements){let d={},St=Object.entries(u.elements);for(let[Y,X]of St){let J=_.elements[Y]?.after;if(J){X.baseline=J;let V={};for(let[q,Q]of Object.entries(X.after)){let Z=J[q];Z!==Q&&(V[q]=[Z,Q])}Object.keys(V).length>0&&(d[Y]=V)}}R(n,e,"verify-all-styles.json",Buffer.from(JSON.stringify(u,null,2)));let Et=JSON.stringify({totalChanged:Object.keys(d).length,elements:d},null,2);R(n,e,"verify-page-diff.json",Buffer.from(Et)),O.push(N(b(n,e),"verify-page-diff.json"))}}catch{}}let D=K(s.id,s.description,i,L,h,O,S);return rt(n,e,{verified:D.ok}),D}finally{await k?.close(),await $?.close()}}async function Lt(t,e,o,n){let r=t.locator(e).first(),s=await r.evaluate(l=>l.outerHTML).catch(()=>""),i=await r.evaluate(l=>{let E=window.getComputedStyle(l),x={};for(let v=0;v<E.length;v++){let w=E[v];x[w]=E.getPropertyValue(w)}return x}).catch(()=>({})),g={boundingBox:await r.boundingBox().catch(()=>null)??o.position.boundingBox,scrollPosition:await t.evaluate(()=>({x:window.scrollX,y:window.scrollY})),viewport:await t.evaluate(()=>({width:window.innerWidth,height:window.innerHeight,dpr:window.devicePixelRatio})),stackingContext:o.position.stackingContext};return{outerHTML:s,computedStyles:i,selector:e,position:g,browser:o.browser,consoleErrors:n,capturedAt:new Date().toISOString()}}async function _t(t,e,o,n,r,s,i,y){let g=[],l=b(t,e);try{let w=Tt(l);for(let C of w)(C.startsWith("verify-")||C==="baseline.json")&&At(N(l,C))}catch{}let E=JSON.stringify(n,null,2);R(t,e,"verify-after.json",Buffer.from(E)),g.push(N(b(t,e),"verify-after.json"));let x=JSON.stringify(r,null,2);R(t,e,"verify-diff.json",Buffer.from(x)),g.push(N(b(t,e),"verify-diff.json"));let v=s.length>0?s.join(`
3
+ `):"(no console errors)";if(R(t,e,"verify-console.txt",Buffer.from(v)),g.push(N(b(t,e),"verify-console.txt")),i){try{let w=await i.content();R(t,e,"verify-page.html",Buffer.from(w)),g.push(N(b(t,e),"verify-page.html"))}catch{}try{let C=await i.evaluate(({buildKeyFn:A,buildSelectorFn:S,filterStylesFn:j,childSignatureFn:$,normalizeTextFn:k,styles:m,maxElements:f})=>{let T={},P=0,L=!1,_=document.createTreeWalker(document.body,NodeFilter.SHOW_ELEMENT,{acceptNode(h){if(P>=f)return NodeFilter.FILTER_REJECT;let O=h;return O.classList.length>0||O.hasAttribute("data-task-id")||O.hasAttribute("data-status")||O.hasAttribute("data-column-id")?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP}}),B=[],F;for(;F=_.nextNode();)B.push(F);for(let h of B){if(P>=f){L=!0;break}let O=A(h),D=Array.from(h.children),a={};for(let d of Array.from(h.attributes))d.name.startsWith("data-")&&(a[d.name.slice(5)]=d.value);let u={x:0,y:0,width:0,height:0};try{let d=h.getBoundingClientRect();u={x:Math.round(d.x),y:Math.round(d.y),width:Math.round(d.width),height:Math.round(d.height)}}catch{}T[O]={key:O,selector:S(h),tag:h.tagName.toLowerCase(),classes:Array.from(h.classList),dataAttrs:a,parentKey:h.parentElement?A(h.parentElement):"",childCount:D.length,childSignature:$(D),text:k(h.textContent??""),position:u,baseline:j(h,m),after:j(h,m)},P++}return{version:1,capturedAt:new Date().toISOString(),truncated:L,elements:T}},{buildKeyFn:dt,buildSelectorFn:ht,filterStylesFn:mt,childSignatureFn:yt,normalizeTextFn:pt,styles:W,maxElements:1e3});if(C){let A=JSON.stringify(C,null,2);R(t,e,"verify-all-styles.json",Buffer.from(A)),g.push(N(b(t,e),"verify-all-styles.json"))}}catch{}try{let w=await i.screenshot({fullPage:!1});R(t,e,"verify-screenshot.png",w),g.push(N(b(t,e),"verify-screenshot.png"))}catch{}if(y)try{let w=await i.locator(y).first().evaluate(C=>C.outerHTML);R(t,e,"verify-element.html",Buffer.from(w)),g.push(N(b(t,e),"verify-element.html"))}catch{}}if(o){let w=JSON.stringify(o,null,2);R(t,e,"baseline.json",Buffer.from(w)),g.push(N(b(t,e),"baseline.json"))}return g}function K(t,e,o,n,r,s,i,y){let g=r.selectorResolves&&r.newConsoleErrors.length===0,l=y??ct(r,i);return{taskId:t,ok:g,taskDescription:e,baseline:{selector:o.selector,url:"",capturedAt:o.capturedAt,snapshot:o},after:{snapshot:n,consoleErrors:n.consoleErrors},diff:r,evidenceFiles:s,verdict:l}}async function ce(t,e,o){let n=wt(t);try{let r=await kt(n,e,o);await $t(n,e,r),o.json?console.log(JSON.stringify(r,null,2)):Ft(r)}catch(r){if(r instanceof p)o.json?process.stderr.write(JSON.stringify({ok:!1,error:{code:r.code,message:r.message,suggestion:r.suggestion}})+`
4
+ `):(process.stderr.write(c.red(`\u2717 ${r.message}
5
+ `)),r.suggestion&&process.stderr.write(c.dim(` ${r.suggestion}
6
+ `))),process.exitCode=U.GENERAL;else{let s=r instanceof Error?r.message:String(r);o.json?process.stderr.write(JSON.stringify({ok:!1,error:{code:"E_UNKNOWN",message:s}})+`
7
+ `):process.stderr.write(c.red(`\u2717 Verification failed: ${s}
8
+ `)),process.exitCode=U.GENERAL}}}async function $t(t,e,o){let n=`**Verification ${o.ok?"\u2705 passed":"\u26A0\uFE0F issues detected"}**
9
+
10
+ ${o.verdict}`;st(t,e,"agent",n,void 0,"system")}function Ft(t){let e=t.ok?c.green("\u2705"):c.yellow("\u26A0\uFE0F");console.log(),console.log(` ${e} Evidences collected for task ${t.taskId}`),console.log(c.dim("\u2500".repeat(60))),console.log(c.dim(` Verdict: ${t.verdict}`)),console.log();let o=t.diff;if(o.selectorResolves){o.htmlChanged?console.log(c.cyan(" \u2713 HTML changed")):console.log(c.dim(" \xB7 HTML unchanged"));let n=Object.keys(o.stylesChanged).length;if(n>0){console.log(c.cyan(` \u2713 ${n} style property change(s):`));for(let[r,[s,i]]of Object.entries(o.stylesChanged).slice(0,8))console.log(c.dim(` ${r}: ${s} \u2192 ${i}`));n>8&&console.log(c.dim(` ... and ${n-8} more`))}if(o.positionChanged&&console.log(c.cyan(" \u2713 Position shifted")),o.newConsoleErrors.length>0){console.log(c.yellow(` \u26A0 ${o.newConsoleErrors.length} new console error(s):`));for(let r of o.newConsoleErrors.slice(0,3))console.log(c.dim(` ${r.slice(0,120)}`))}}else console.log(c.red(" \u26A0 Target element not found \u2014 the fix may have renamed/removed it."));if(t.evidenceFiles.length>0){console.log(c.cyan(` Evidence files (${t.evidenceFiles.length}):`));for(let n of t.evidenceFiles){let r=n.split("/").pop()??n;try{let i=(Nt(n).size/1024).toFixed(1);console.log(c.dim(` ${r} (${i} KB)`))}catch{console.log(c.dim(` ${r}`))}}}console.log(),console.log(c.cyan(" Explore evidence (agent tools):")),console.log(c.dim(` vibeflow verify style_query ${t.taskId} <property>`)),console.log(c.dim(` vibeflow verify style_diff ${t.taskId} [--filter <pattern>]`)),console.log(c.dim(` vibeflow verify element_info ${t.taskId}`)),console.log(c.dim(` vibeflow verify html_diff ${t.taskId}`)),console.log(),console.log(c.cyan(" Review evidences:")),console.log(c.dim(" 1. Check if the fix is confirmed (styles match expectations)")),console.log(c.dim(` 2. If confirmed \u2192 vibeflow tasks --edit ${t.taskId} --set-status review --comment "Verified: <what you confirmed>"`)),console.log(c.dim(" 3. If not sure \u2192 leave a comment explaining uncertainty")),console.log(c.dim(` 4. If wrong \u2192 vibeflow tasks --edit ${t.taskId} --set-status in-progress`)),console.log(),t.ok||(console.log(c.yellow(" \u26A0 Verification failed \u2014 move to in-progress and fix:")),console.log(c.dim(` vibeflow tasks --edit ${t.taskId} --set-status in-progress`)))}export{jt as a,ut as b,Wt as c,zt as d,p as e,kt as f,ce as g,$t as h};
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ import{a as w}from"./chunk-BZDBSBRV.js";import{a as B,d as U}from"./chunk-PWP474PZ.js";import{d as P,e as E,u as N}from"./chunk-2CI62NHU.js";import{a as A,b as _}from"./chunk-KJ5LYG6A.js";import g from"chalk";import{unlinkSync as ye,readFileSync as ke,existsSync as we}from"fs";import{resolve as Se,join as $e}from"path";import I from"fs/promises";import oe from"os";import F from"path";var re=F.join(oe.homedir(),".vibeflow"),T=F.join(re,"token");async function b(){try{return(await I.readFile(T,"utf8")).trim()||null}catch{return null}}async function j(e){await I.mkdir(F.dirname(T),{recursive:!0}),await I.writeFile(T,e,{mode:384})}async function Ae(){try{await I.unlink(T)}catch{}}import i from"chalk";import ie from"open";import V from"readline";import ae from"@inquirer/select";import{existsSync as L,readFileSync as D,writeFileSync as W,mkdirSync as M,renameSync as z}from"fs";import{join as x}from"path";import G from"os";var ne="settings.json";function H(){return x(G.homedir(),".vibeflow","settings.json")}function J(e){return x(e,P,ne)}function O(){try{return JSON.parse(D(H(),"utf-8"))}catch{return{}}}function q(e){let r=x(G.homedir(),".vibeflow");L(r)||M(r,{recursive:!0});let o=H(),n=o+".tmp";W(n,JSON.stringify(e,null,2),"utf-8"),z(n,o)}function se(e){let r=O(),o=J(e);if(!L(o))return r;try{let n=JSON.parse(D(o,"utf-8"));return{...r,...n}}catch{return r}}function Ne(e,r){let o=x(e,P);L(o)||M(o,{recursive:!0});let n=J(e),c={...se(e),...r},p=n+".tmp";return W(p,JSON.stringify(c,null,2),"utf-8"),z(p,n),c}import{existsSync as ce,readdirSync as K,readFileSync as le}from"fs";import{join as R,resolve as de}from"path";var pe="https://app.vibeflow.tools",fe=300*1e3;function Y(){return process.env.VIBEFLOW_API_URL??pe}async function ue(e){return new Promise(r=>setTimeout(r,e))}async function ge(e){return e.length===1?(console.log(i.dim(` Using board: ${e[0].icon??""} ${e[0].name}`)),e[0]):await ae({message:"Select a board to use:",choices:e.map(o=>({name:`${o.icon??""} ${o.name}`,value:o}))})}async function Q(e,r){try{let o=await fetch(`${e}/api/cli/settings`,{headers:{Authorization:`Bearer ${r}`}});if(!o.ok)return;let n=await o.json();n.settings&&Object.keys(n.settings).length>0&&q({...n.settings,_settingsRefreshedAt:Date.now()})}catch{}}async function Ve(){try{let e=await b();if(!e)return;let o=O()._settingsRefreshedAt??0;if(Date.now()-o<fe)return;let n=Y();Q(n,e)}catch{}}async function me(e,r){try{let[o,n]=await Promise.all([fetch(`${e}/api/cli/workspaces`,{headers:{Authorization:`Bearer ${r}`}}),fetch(`${e}/api/cli/profile`,{headers:{Authorization:`Bearer ${r}`}})]);if(!o.ok)return;let a=await o.json();if(!a.workspaces?.length){console.log(i.yellow(" No boards found. Create a board in the web app first."));return}let c=n.ok?await n.json():null,p=await ge(a.workspaces);await _({...p,email:c?.email??null}),console.log(i.green(` Board set: ${p.icon??""} ${p.name}`)),console.log(i.dim(` Open at: ${p.url}`))}catch{}}async function he(e,r,o,n){let a=R(e,P,E);if(!ce(a))return;let c=[];try{for(let s of K(a,{withFileTypes:!0}))if(s.isDirectory()){let f=R(a,s.name);for(let m of K(f).filter(d=>d.endsWith(".json")))c.push(R(f,m))}else s.isFile()&&s.name.endsWith(".json")&&c.push(R(a,s.name))}catch{return}if(c.length===0)return;let p=c.flatMap(s=>{try{return[JSON.parse(le(s,"utf-8"))]}catch{return[]}}),y=new Set;try{let s=await fetch(`${r}/api/cli/tasks?boardId=${n.id}`,{headers:{Authorization:`Bearer ${o}`}}).catch(()=>null);if(s?.ok){let f=await s.json();y=new Set((f.tasks??[]).flatMap(m=>[m.id,...m.cliId?[m.cliId]:[]]))}}catch{}let l=p.filter(s=>!y.has(s.id));if(l.length===0)return;console.log(),console.log(i.bold(` ${l.length} local task${l.length!==1?"s are":" is"} not yet synced to the board:`));let h=l.slice(0,10);for(let s of h){let f=s.status?i.dim(` [${s.status}]`):"";console.log(i.dim(` \u2022 ${s.title??s.id}${f}`))}return l.length>10&&console.log(i.dim(` \u2026 and ${l.length-10} more`)),new Promise(s=>{let f=V.createInterface({input:process.stdin,output:process.stdout});f.question(i.cyan(`
3
+ Push them to your board now? [Y/n]: `),async m=>{if(f.close(),m.trim().toLowerCase()==="n"){console.log(i.dim(" Skipped. You can push later with: vibeflow push")),s();return}let d=V.createInterface({input:process.stdin,output:process.stdout});d.question(i.cyan(" Delete local task files after push? [y/N]: "),async k=>{d.close();let S=k.trim().toLowerCase()!=="y";try{let t=await fetch(`${r}/api/cli/import`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${o}`},body:JSON.stringify({boardId:n.id,tasks:l,keepLocalFiles:S})}),u={};try{u=await t.json()}catch{}t.ok?(console.log(i.green(` \u2713 Pushed ${u.imported??0} task${(u.imported??0)!==1?"s":""} to ${n.name}`)),(u.skipped??0)>0&&console.log(i.dim(` (${u.skipped} already existed and were skipped)`))):console.log(i.red(` Push failed: ${u.error??`HTTP ${t.status}`}`))}catch(t){console.log(i.red(` Push failed: ${t instanceof Error?t.message:"Network error"}`))}s()})})})}async function X(e=de(".")){let r=Y();console.log(i.cyan(" Initiating device login flow..."));let o;try{o=await fetch(`${r}/api/cli/auth/device-init`,{method:"POST",headers:{"Content-Type":"application/json"}})}catch(h){console.error(i.red(` Failed to connect to login server: ${h instanceof Error?h.message:"Network error"}`)),process.exitCode=w.AUTH;return}if(!o.ok){console.error(i.red(` Failed to initiate login: ${o.status} ${o.statusText}`)),process.exitCode=w.AUTH;return}let{deviceCode:n,userCode:a,verificationUrl:c,expiresIn:p}=await o.json();console.log(),console.log(i.bold(" Open this URL in your browser to authorize:")),console.log(i.underline(` ${c}`)),console.log();try{await ie(c),console.log(i.dim(" (Browser opened automatically)"))}catch{}let y=Date.now()+p*1e3,l=3e3;for(;Date.now()<y;){await ue(l);let h=null;try{h=await fetch(`${r}/api/cli/auth/device-poll`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({deviceCode:n})})}catch{console.error(i.red(" Poll request failed (network error). Retrying..."));continue}if(!h.ok){console.error(i.red(" Poll request failed. Retrying..."));continue}let s=await h.json();if("token"in s){await j(s.token),console.log(),console.log(i.green(" Logged in successfully. Now operating in SaaS mode.")),await Promise.all([me(r,s.token),Q(r,s.token)]);let{readWorkspace:f}=await import("./workspace-AJAVENKA.js"),m=await f();m&&await he(e,r,s.token,m);return}if("expired"in s){console.error(i.red(" Device code expired. Please try again.")),process.exitCode=w.AUTH;return}process.stdout.write(i.dim("."))}console.error(i.red(`
4
+ Login timed out. Please try again.`)),process.exitCode=w.AUTH}var Pe="https://app.vibeflow.tools";function be(){return process.env.VIBEFLOW_API_URL??Pe}function Ie(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}function Z(e,r,o=24){let n=Math.round(e/r*o);return`[${"\u2588".repeat(n)+"\u2591".repeat(o-n)}]`}async function Te(e,r,o,n){let a=[];for(let{localId:d,remoteId:k}of n){let S=U(o,d);for(let t of S){let u=t.linkedPath??$e(B(o,d),t.name);we(u)&&a.push({remoteId:k,name:t.name,filePath:u,size:t.size})}}if(a.length===0)return{uploaded:0,failed:0,failedFiles:[]};let c=a.length,p=a.reduce((d,k)=>d+k.size,0);console.log(g.cyan(`
5
+ Uploading ${c} file(s) (${Ie(p)})...`));let y=0,l=0,h=0,s=Date.now(),f=[];for(let d of a){let k=Math.round(y/c*100),S=Z(y,c),t=(Date.now()-s)/1e3,u=h/Math.max(t,.01),ee=p-h,v=u>0?Math.ceil(ee/u):0,te=v>60?`${Math.ceil(v/60)}m`:`${v}s`;process.stdout.write(`\r ${S} ${k}% ${d.name.slice(0,28)} ETA: ${te} `);try{let $=ke(d.filePath),C=await fetch(`${e}/api/tasks/${encodeURIComponent(d.remoteId)}/files`,{method:"POST",headers:{Authorization:`Bearer ${r}`,"Content-Type":"application/octet-stream","x-filename":encodeURIComponent(d.name)},body:$});C.ok?(y++,h+=d.size):(l++,f.push({name:d.name,reason:`HTTP ${C.status}`}))}catch($){l++,f.push({name:d.name,reason:$ instanceof Error?$.message:String($)})}}let m=Z(c,c);return process.stdout.write(`\r ${m} 100% Done${" ".repeat(40)}
6
+ `),{uploaded:y,failed:l,failedFiles:f}}async function it(e,r){let o=Se(e),n=await b();if(!n&&(console.log(g.yellow(" Not logged in. Starting login flow...")),await X(),n=await b(),!n)){console.error(g.red(" Login failed. Please run `vibeflow login` and try again.")),process.exitCode=w.AUTH;return}let a=N(o);if(a.length===0){console.log(g.dim(" No local tasks found. Nothing to push."));return}console.log(g.cyan(` Found ${a.length} local task(s). Pushing to SaaS...`));let c=be(),p=r.workspace;if(!p){let t=await A();t&&(p=t.id,console.log(g.dim(` Using board: ${t.icon??""} ${t.name}`)))}let y={tasks:a};p&&(y.workspaceId=p);let l;try{let t=await fetch(`${c}/api/cli/import`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${n}`},body:JSON.stringify(y)});if(!t.ok){let u=await t.json().catch(()=>({}));console.error(g.red(` Import failed: ${t.status} ${u.error??t.statusText}`)),process.exitCode=w.GENERAL;return}l=await t.json()}catch(t){let u=t instanceof Error?t.message:String(t);console.error(g.red(` Network error: ${u}`)),process.exitCode=w.GENERAL;return}console.log(g.green(` \u2713 Pushed ${l.imported} task(s) to SaaS`)),l.skipped&&l.skipped>0&&console.log(g.dim(` Skipped ${l.skipped} already-imported task(s).`));let h=(await A())?.name??l.workspaceId;console.log(g.dim(` Board: ${h}`));let s=l.idMap??{},f=a.filter(t=>t.id&&s[t.id]).map(t=>({localId:t.id,remoteId:s[t.id]})),{uploaded:m,failed:d,failedFiles:k}=await Te(c,n,o,f);if(m>0&&console.log(g.green(` \u2713 Uploaded ${m} file(s) to storage`)),d>0){console.log(g.yellow(` \u26A0 ${d} file(s) failed to upload`));for(let t of k)console.log(g.dim(` - ${t.name}: ${t.reason}`))}if(r.keepLocalFiles){console.log(g.dim(" Local task files kept (--keep-local-files)."));return}let S=0;for(let t of a)try{ye(t.filePath),S++}catch{}console.log(g.dim(` Deleted ${S} local task file(s).`))}export{b as a,Ae as b,se as c,Ne as d,Ve as e,X as f,Ie as g,Z as h,it as i};
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{g as S,l as A,o as R}from"./chunk-Q7MEW67Z.js";import{d as y,f as k}from"./chunk-XHZXHACL.js";import{readdirSync as I,writeFileSync as $,readFileSync as w,unlinkSync as g,statSync as d,mkdirSync as C,existsSync as l}from"fs";import{join as f,basename as m,extname as L}from"path";var E=255,T=50*1024*1024,v=new Set([".png",".jpg",".jpeg",".gif",".webp",".pdf",".txt",".md",".json",".csv",".svg",".mp4",".mov",".zip"]);function N(e){if(!e||e.length===0||e.length>E||e.startsWith(".")||e.includes("/")||e.includes("\\")||e==="."||e===".."||e.includes("..")||e.includes("\0"))return!1;for(let t=0;t<e.length;t++)if(e.charCodeAt(t)<32)return!1;return!0}function O(e){let t=L(e).toLowerCase();return v.has(t)}function W(e,t){return N(e)?O(e)?t!==void 0&&t>T?{valid:!1,errorCode:"VALIDATION",errorMessage:`File too large: ${t} bytes (max ${T})`}:{valid:!0}:{valid:!1,errorCode:"UNSUPPORTED_FILE_TYPE",errorMessage:`Unsupported file type "${L(e).toLowerCase()}". Allowed: ${[...v].join(", ")}`}:{valid:!1,errorCode:"INVALID_FILENAME",errorMessage:`Invalid filename: empty, too long (>${E} chars), path separator, control character, or hidden file`}}var h=".linked.json";function u(e,t){return f(e,y,k,t)}function _(e,t){C(u(e,t),{recursive:!0})}function b(e,t){let r=f(u(e,t),h);if(!l(r))return[];try{return JSON.parse(w(r,"utf-8"))}catch{return[]}}function p(e,t){let r=S(e,t),s=r?A(r):null;return!s?.files||s.files.length===0?[]:s.files}function F(e,t){return p(e,t)}function P(e,t,r){R(e,t,{files:r})}function x(e,t){let r=p(e,t),s=f(u(e,t),h);if(!l(s))return r;let i=b(e,t);if(i.length===0){try{g(s)}catch{}return r}let n=r.slice(),a=!1;for(let o of i)n.find(c=>c.linkedPath===o.path||c.name===o.name&&c.linkedPath)||(n.push({name:o.name,linkedPath:o.path,addedAt:new Date().toISOString()}),a=!0);a&&P(e,t,n);try{g(s)}catch{}return n}function M(e,t){let r=u(e,t),s=F(e,t),i=new Map;for(let n of s){if(n.linkedPath&&l(n.linkedPath)){let o=d(n.linkedPath);i.set(n.name,{name:n.name,size:o.size,url:`/api/tasks/${t}/files/${encodeURIComponent(n.name)}`,linkedPath:n.linkedPath,createdAt:o.mtime.toISOString()});continue}let a=f(r,n.name);if(l(a)){let o=d(a);i.set(n.name,{name:n.name,size:o.size,url:`/api/tasks/${t}/files/${encodeURIComponent(n.name)}`,createdAt:o.mtime.toISOString()})}}if(l(r))for(let n of I(r,{withFileTypes:!0})){if(!n.isFile()||n.name===h||i.has(n.name))continue;let a=f(r,n.name),o=d(a);i.set(n.name,{name:n.name,size:o.size,url:`/api/tasks/${t}/files/${encodeURIComponent(n.name)}`,createdAt:o.mtime.toISOString()})}return Array.from(i.values())}function B(e,t,r,s){let i=m(r);_(e,t),$(f(u(e,t),i),s);let n=x(e,t);return n.find(a=>a.name===i&&!a.linkedPath)||(n.push({name:i,addedAt:new Date().toISOString()}),P(e,t,n)),{name:i,size:s.length,url:`/api/tasks/${t}/files/${encodeURIComponent(i)}`}}function G(e,t,r){let s=m(r),i=x(e,t),n=i.findIndex(o=>o.name===s);if(n!==-1){let[o]=i.splice(n,1);if(P(e,t,i),o&&!o.linkedPath){let c=f(u(e,t),s);l(c)&&g(c)}return!0}let a=f(u(e,t),s);return l(a)?(g(a),!0):!1}function H(e,t,r){let s=m(r),i=F(e,t).find(a=>a.name===s&&a.linkedPath);if(i?.linkedPath&&l(i.linkedPath))return i.linkedPath;let n=f(u(e,t),s);return l(n)?n:null}function J(e,t){return M(e,t).length}async function K(e){let{listTasks:t}=await import("./tasks-5X5AAK2N.js"),r=t(e),s=0;for(let i of r)try{let n=F(e,i.id);x(e,i.id),p(e,i.id).length!==n.length&&s++}catch{}return s}export{E as a,T as b,v as c,N as d,O as e,W as f,u as g,_ as h,F as i,M as j,B as k,G as l,H as m,J as n,K as o};
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ import{readdirSync as W,writeFileSync as J,readFileSync as G,unlinkSync as v,statSync as R,mkdirSync as Y,existsSync as l}from"fs";import{join as f,basename as F}from"path";var g=".vibeflow",C="tasks",S="tasks/files",x="tasks/screenshots",te="config.json";import{existsSync as m,readFileSync as O,writeFileSync as j,mkdirSync as p,readdirSync as h,unlinkSync as E,renameSync as A}from"fs";import{join as c,extname as P}from"path";import{randomBytes as z}from"crypto";var K=["backlog","todo","in-progress","review","done"];function H(){return z(15).toString("hex")}function k(e){return c(e,g,C)}function M(e){let i=c(e,g),n=c(i,"files"),r=c(i,S),s=c(i,"screenshots"),t=c(i,x);if(m(n)){p(r,{recursive:!0});for(let o of h(n)){let a=c(n,o),u=c(r,o);if(!m(u))try{A(a,u)}catch{}}}if(m(s)){p(t,{recursive:!0});for(let o of h(s)){let a=c(s,o),u=c(t,o);if(!m(u))try{A(a,u)}catch{}}}}function ae(e){M(e),p(k(e),{recursive:!0}),p(c(e,g,x),{recursive:!0})}function D(e){return e.slice(0,10)}function U(e,i,n){let r=k(e);return n?c(r,D(n),`${i}.json`):c(r,`${i}.json`)}function T(e,i){let n=k(e);if(!m(n))return null;for(let r of h(n,{withFileTypes:!0}))if(r.isDirectory()){let s=c(n,r.name,`${i}.json`);if(m(s))return s}else if(r.name===`${i}.json`)return c(n,r.name);return null}function V(e){return{...e,text:e.text??e.content??""}}function q(e){let i=(()=>{if(typeof e.type!="string")return;let n=e.type.trim();if(!(!n||n==="[object Object]"))return n})();return{id:String(e.id??""),title:String(e.title??"Untitled"),description:String(e.description??""),status:K.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?void 0:Number(e.line),col:e.col==null?void 0:Number(e.col),component:e.component?String(e.component):void 0,type:i,priority:e.priority?String(e.priority):void 0,...e.reportBack===!0&&{reportBack:!0},agent:e.agent?String(e.agent):void 0,model:e.model?String(e.model):void 0,author:e.author?String(e.author):void 0,commits:Array.isArray(e.commits)?e.commits.map(n=>({sha:String(n.sha??""),message:String(n.message??""),timestamp:String(n.timestamp??new Date().toISOString())})):void 0,created:String(e.created??new Date().toISOString()),updated:e.updated?String(e.updated):void 0,comments:Array.isArray(e.comments)?e.comments.map(n=>V(n)):[],files:Array.isArray(e.files)?e.files.map(n=>typeof n=="string"?{name:n,addedAt:new Date().toISOString()}:{name:String(n.name??""),addedAt:String(n.addedAt??new Date().toISOString()),linkedPath:n.linkedPath?String(n.linkedPath):void 0,mimeType:n.mimeType?String(n.mimeType):void 0}).filter(n=>n.name):[],screenshot:e.screenshot?String(e.screenshot):void 0,annotatedElementText:e.annotatedElementText?String(e.annotatedElementText):void 0,tags:Array.isArray(e.tags)?e.tags.filter(n=>typeof n=="string"&&n.length>0):void 0,sortKey:e.sortKey?String(e.sortKey):void 0,verified:e.verified===!0,branchName:e.branchName?String(e.branchName):void 0,baseline:e.baseline&&typeof e.baseline=="object"?e.baseline:void 0,authStateEnc:e.authStateEnc?String(e.authStateEnc):void 0}}function N(e,i){let n=c(k(e),D(i.created));p(n,{recursive:!0});let r=c(n,`${i.id}.json`),s=r+".tmp";j(s,JSON.stringify(i,null,2),"utf-8"),A(s,r)}function I(e){return e.replace(/\\(n|t|r|\\)/g,(i,n)=>{switch(n){case"n":return`
3
+ `;case"t":return" ";case"r":return"\r";case"\\":return"\\";default:return n}})}function ue(e,i){let n=(()=>{let s=(i.priority??"").trim().toLowerCase();return s==="critical"?"Critical":s==="high"?"High":s==="low"?"Low":"Medium"})(),r={...i,title:I(i.title??"").trim(),description:I(i.description??"").trim(),priority:n,id:H(),created:new Date().toISOString(),comments:[],files:[]};return N(e,r),r}function y(e){try{let i=O(e,"utf-8");if(e.endsWith(".json")){let n=JSON.parse(i);return!n||typeof n!="object"||!("id"in n)?null:q(n)}return null}catch{return null}}function L(e){let i=k(e);if(!m(i))return[];let n=[];for(let r of h(i,{withFileTypes:!0}))if(r.isDirectory()){let s=c(i,r.name);for(let t of h(s))if(P(t)===".json"){let o=c(s,t),a=y(o);a&&n.push({task:a,filePath:o})}}else if(P(r.name)===".json"){let s=c(i,r.name),t=y(s);t&&n.push({task:t,filePath:s})}return n}function ce(e){return L(e).map(({task:i})=>i)}function le(e){return L(e).map(({task:i,filePath:n})=>({...i,filePath:n}))}function B(e,i,n){let r=T(e,i),s=r?y(r):null;if(!s)return null;let t={...s,...n,updated:new Date().toISOString()};if(N(e,t),r&&r!==U(e,i,t.created))try{E(r)}catch{}return t}function fe(e,i){let n=T(e,i);return n?(E(n),!0):!1}function me(e,i,n){return{id:e.id,status:e.status,title:e.title,description:e.description,...e.url&&{url:e.url},selector:e.selector,...e.file&&{file:e.file},...e.line!=null&&{line:e.line},...e.col!=null&&{col:e.col},...e.component&&{component:e.component},...e.type&&{type:e.type},...e.priority&&{priority:e.priority},...i&&i.length>0&&{structuredComments:i},...n&&n.length>0&&{linkedFiles:n},...e.reportBack&&{reportBack:!0},created:e.created}}function de(e,i,n,r,s){let t=[];if(t.push(`[${e.status}] ${e.title}`),t.push(` id: ${e.id}`),t.push(` file: ${i}`),e.file&&t.push(` source: ${e.file}${e.line==null?"":`:${e.line}`}${e.col==null?"":`:${e.col}`}`),e.component&&t.push(` component: ${e.component}`),t.push(` selector: ${e.selector??"/"}`),e.cssSelector&&t.push(` css: ${e.cssSelector}`),e.url&&t.push(` url: ${e.url}`),e.commits&&e.commits.length>0)if(e.commits.length===1)t.push(` commit: ${e.commits[0].sha}`);else{t.push(` commits (${e.commits.length}):`);for(let o of e.commits)t.push(` ${o.sha.slice(0,8)} ${o.timestamp} ${o.message.slice(0,60)}`)}if(t.push(` created: ${e.created}`),e.type&&t.push(` type: ${e.type}`),e.priority&&t.push(` priority: ${e.priority}`),e.author&&t.push(` author: ${e.author}`),e.description){t.push(" description:");for(let o of e.description.split(`
4
+ `))t.push(` ${o}`)}if(e.annotatedElementText&&t.push(` element text: ${e.annotatedElementText}`),n.length>0){t.push(` comments (${n.length}):`);for(let o of n){let a=o.updatedAt?` (edited ${o.updatedAt})`:"";t.push(` [${o.author??"user"}] ${o.createdAt}${a}`);for(let u of o.text.split(`
5
+ `))t.push(` ${u}`)}}if(r.length>0){t.push(` linked files (${r.length}):`);for(let o of r){t.push(` - ${o.name} ${o.url}`);let a=o.linkedPath??c(s,".vibeflow","files",e.id,o.name);if(/\.(md|txt)$/i.test(o.name)&&o.size<1e5&&m(a))try{let u=O(a,"utf-8");t.push(" \u250C\u2500\u2500 content \u2500\u2500");for(let _ of u.split(`
6
+ `))t.push(` \u2502 ${_}`);t.push(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}catch{}}}return t.join(`
7
+ `)}function ge(e){let{autoCommit:i,autoPush:n,autoComment:r,createBranch:s}=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(" Auto-claim: vibeflow tasks --next (picks highest-priority todo task and sets it in-progress automatically)"),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:"),s?(t.push(" \u26A0 Create a branch FIRST, before any implementation:"),t.push(" 1. git checkout -b <short-name> (e.g. fix/annotation-errors, feat/eye-toggle, chore/cleanup-extension)"),t.push(" Branch name rules: lowercase, kebab-case, 2-5 words, prefix fix/feat/chore/docs."),t.push(" Describe the WORK done (not dates). Bad: agent/2026-04-16. Good: fix/bug-errors-visibility."),t.push(" 2. vibeflow tasks --edit <id> --set-status in-progress \u2190 CLAIM TASK"),t.push(" 3. <implement the change>")):(t.push(" \u26A0 IMMEDIATELY set in-progress BEFORE any implementation work:"),t.push(" 1. vibeflow tasks --edit <id> --set-status in-progress \u2190 DO THIS FIRST"),t.push(" (if you used --next: task is already in-progress \u2014 skip to step 2)"),t.push(" 2. <implement the change>")),e.requireVerifyBeforeReview)if(i){t.push(s?" 4. git add <files> (stage your changes first)":" 3. git add <files> (stage your changes first)"),t.push(` ${s?"5":"4"}. vibeflow verify <id> (verify the fix \u2014 check the evidences it produces)`),t.push(" If verification fails, set task back to in-progress and fix.");let a=["--set-status review"];i&&a.push('--commit-message "<one-line summary>"'),r&&a.push('--comment "<report>"'),t.push(` ${s?"6":"5"}. vibeflow tasks --edit <id> ${a.join(" ")}`),t.push(" CLI will commit staged changes and link the commit SHA automatically.")}else{t.push(s?' 4. git add <files> && vibeflow tasks --commit --task <id> --message "<one-line summary>"':' 3. git add <files> && vibeflow tasks --commit --task <id> --message "<one-line summary>"'),t.push(` ${s?"5":"4"}. vibeflow verify <id> (verify the fix \u2014 check the evidences it produces)`),t.push(" If verification fails, set task back to in-progress and fix.");let a=["--set-status review"];r&&a.push('--comment "<report>"'),t.push(` ${s?"6":"5"}. vibeflow tasks --edit <id> ${a.join(" ")}`)}else{if(i){t.push(s?" 4. git add <files> (stage your changes first)":" 3. git add <files> (stage your changes first)");let u=["--set-status review"];i&&u.push('--commit-message "<one-line summary>"'),r&&u.push('--comment "<report>"'),t.push(` ${s?"5":"4"}. vibeflow tasks --edit <id> ${u.join(" ")}`),t.push(" CLI will commit staged changes and link the commit SHA automatically.")}else{t.push(s?' 4. git add <files> && vibeflow tasks --commit --task <id> --message "<one-line summary>"':' 3. git add <files> && vibeflow tasks --commit --task <id> --message "<one-line summary>"');let u=["--set-status review"];r&&u.push('--comment "<report>"'),t.push(` ${s?"5":"4"}. vibeflow tasks --edit <id> ${u.join(" ")}`)}let a=s?"6":"5";t.push(` ${a}. vibeflow verify <id> (verify the fix \u2014 check the evidences it produces)`),t.push(" If verification fails, set task back to in-progress and fix.")}return r&&(t.push(""),t.push(" Comment format (--comment):"),t.push(" \xB7 Plain text for concise one-liners."),t.push(" \xB7 Markdown for multi-section reports. Use **bold**, bullet lists, code fences."),t.push(" \xB7 Must cover: what changed, why, key decisions, anything future agents should know."),t.push(" \xB7 For long reports, attach a .md file and reference it in the comment.")),t.push(""),i&&t.push(" [setting] Auto-commit ON: provide --commit-message when setting status to review; CLI commits."),n&&t.push(" [setting] Auto-push ON: CLI pushes after the commit automatically."),r&&t.push(" [setting] Auto-comment ON: --comment is required when setting status to review."),s&&t.push(" [setting] Create branch ON: all work goes on a dedicated branch created before implementation."),e.requireVerifyBeforeReview&&t.push(" [setting] Verify gate ON: run vibeflow verify before setting status to review (skipped for tasks without URL/selector)."),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(" Create the report file locally first, then upload when marking as review:"),t.push(' vibeflow tasks --edit <id> --set-status review --report-file ./report.md --comment "..."'),t.push(" The file is saved next to the task and deleted from the original path automatically."),t.push(" Report must include: findings, options considered (with pros/cons), recommendation, sources.")),e.hasBugTasks&&(t.push(" Bug tasks: Reproduce the bug first, then include in the comment:"),t.push(" \xB7 Symptom: what the user sees"),t.push(" \xB7 Trigger: exact steps to reproduce"),t.push(" \xB7 Root cause: the specific code/logic that caused it"),t.push(" \xB7 Fix: what was changed and why it works"),t.push(" \xB7 Evidence: paste the relevant error message or stack trace")),t.push(" BLOCKED? If a task is unclear or missing context:"),t.push(' vibeflow tasks --edit <id> --comment "Blocked: <reason>. Need: <what is needed>."'),t.push(" Then pick the next task: vibeflow tasks --next"),t.push(" Do not guess at unclear requirements \u2014 leave a comment and move on."),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(`
8
+ `)}var $=".linked.json";function d(e,i){return f(e,g,S,i)}function Q(e,i){Y(d(e,i),{recursive:!0})}function X(e,i){let n=f(d(e,i),$);if(!l(n))return[];try{return JSON.parse(G(n,"utf-8"))}catch{return[]}}function Z(e,i){let n=T(e,i),r=n?y(n):null;return!r?.files||r.files.length===0?[]:r.files}function w(e,i,n){B(e,i,{files:n})}function b(e,i){let n=Z(e,i),r=f(d(e,i),$);if(!l(r))return n;let s=X(e,i);if(s.length===0){try{v(r)}catch{}return n}let t=n.slice(),o=!1;for(let a of s)t.find(u=>u.linkedPath===a.path||u.name===a.name&&u.linkedPath)||(t.push({name:a.name,linkedPath:a.path,addedAt:new Date().toISOString()}),o=!0);o&&w(e,i,t);try{v(r)}catch{}return t}function ee(e,i){let n=d(e,i),r=b(e,i),s=new Map;for(let t of r){if(t.linkedPath&&l(t.linkedPath)){let a=R(t.linkedPath);s.set(t.name,{name:t.name,size:a.size,url:`/api/tasks/${i}/files/${encodeURIComponent(t.name)}`,linkedPath:t.linkedPath,createdAt:a.mtime.toISOString()});continue}let o=f(n,t.name);if(l(o)){let a=R(o);s.set(t.name,{name:t.name,size:a.size,url:`/api/tasks/${i}/files/${encodeURIComponent(t.name)}`,createdAt:a.mtime.toISOString()})}}if(l(n))for(let t of W(n,{withFileTypes:!0})){if(!t.isFile()||t.name===$||s.has(t.name))continue;let o=f(n,t.name),a=R(o);s.set(t.name,{name:t.name,size:a.size,url:`/api/tasks/${i}/files/${encodeURIComponent(t.name)}`,createdAt:a.mtime.toISOString()})}return Array.from(s.values())}function ve(e,i,n,r){let s=F(n);Q(e,i),J(f(d(e,i),s),r);let t=b(e,i);return t.find(o=>o.name===s&&!o.linkedPath)||(t.push({name:s,addedAt:new Date().toISOString()}),w(e,i,t)),{name:s,size:r.length,url:`/api/tasks/${i}/files/${encodeURIComponent(s)}`}}function be(e,i,n){let r=F(n),s=b(e,i),t=s.findIndex(a=>a.name===r);if(t!==-1){let[a]=s.splice(t,1);if(w(e,i,s),a&&!a.linkedPath){let u=f(d(e,i),r);l(u)&&v(u)}return!0}let o=f(d(e,i),r);return l(o)?(v(o),!0):!1}function xe(e,i,n){let r=F(n),s=b(e,i).find(o=>o.name===r&&o.linkedPath);if(s?.linkedPath&&l(s.linkedPath))return s.linkedPath;let t=f(d(e,i),r);return l(t)?t:null}function Ae(e,i){return ee(e,i).length}export{g as a,C as b,x as c,te as d,H as e,ae as f,U as g,T as h,I as i,ue as j,y as k,ce as l,le as m,B as n,fe as o,me as p,de as q,ge as r,d as s,Q as t,ee as u,ve as v,be as w,xe as x,Ae as y};
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{d as y,f as S,o as R,s as T,v as x}from"./chunk-O4LGEPMQ.js";import{readdirSync as A,writeFileSync as z,readFileSync as O,unlinkSync as m,statSync as g,mkdirSync as $,existsSync as f}from"fs";import{join as l,basename as d}from"path";var h=".linked.json";function c(e,n){return l(e,y,S,n)}function b(e,n){$(c(e,n),{recursive:!0})}function L(e,n){let s=l(c(e,n),h);if(!f(s))return[];try{return JSON.parse(O(s,"utf-8"))}catch{return[]}}function F(e,n){let s=R(e,n),r=s?T(s):null;return!r?.files||r.files.length===0?[]:r.files}function P(e,n){return F(e,n)}function k(e,n,s){x(e,n,{files:s})}function p(e,n){let s=F(e,n),r=l(c(e,n),h);if(!f(r))return s;let i=L(e,n);if(i.length===0){try{m(r)}catch{}return s}let t=s.slice(),o=!1;for(let a of i)t.find(u=>u.linkedPath===a.path||u.name===a.name&&u.linkedPath)||(t.push({name:a.name,linkedPath:a.path,addedAt:new Date().toISOString()}),o=!0);o&&k(e,n,t);try{m(r)}catch{}return t}function v(e,n){let s=c(e,n),r=P(e,n),i=new Map;for(let t of r){if(t.linkedPath&&f(t.linkedPath)){let a=g(t.linkedPath);i.set(t.name,{name:t.name,size:a.size,url:`/api/tasks/${n}/files/${encodeURIComponent(t.name)}`,linkedPath:t.linkedPath,createdAt:a.mtime.toISOString()});continue}let o=l(s,t.name);if(f(o)){let a=g(o);i.set(t.name,{name:t.name,size:a.size,url:`/api/tasks/${n}/files/${encodeURIComponent(t.name)}`,createdAt:a.mtime.toISOString()})}}if(f(s))for(let t of A(s,{withFileTypes:!0})){if(!t.isFile()||t.name===h||i.has(t.name))continue;let o=l(s,t.name),a=g(o);i.set(t.name,{name:t.name,size:a.size,url:`/api/tasks/${n}/files/${encodeURIComponent(t.name)}`,createdAt:a.mtime.toISOString()})}return Array.from(i.values())}function U(e,n,s,r){let i=d(s);b(e,n),z(l(c(e,n),i),r);let t=p(e,n);return t.find(o=>o.name===i&&!o.linkedPath)||(t.push({name:i,addedAt:new Date().toISOString()}),k(e,n,t)),{name:i,size:r.length,url:`/api/tasks/${n}/files/${encodeURIComponent(i)}`}}function E(e,n,s){let r=d(s),i=p(e,n),t=i.findIndex(a=>a.name===r);if(t!==-1){let[a]=i.splice(t,1);if(k(e,n,i),a&&!a.linkedPath){let u=l(c(e,n),r);f(u)&&m(u)}return!0}let o=l(c(e,n),r);return f(o)?(m(o),!0):!1}function _(e,n,s){let r=d(s),i=P(e,n).find(o=>o.name===r&&o.linkedPath);if(i?.linkedPath&&f(i.linkedPath))return i.linkedPath;let t=l(c(e,n),r);return f(t)?t:null}function M(e,n){return v(e,n).length}async function B(e){let{listTasks:n}=await import("./tasks-SV7ZVS7W.js"),s=n(e),r=0;for(let i of s)try{let t=P(e,i.id);p(e,i.id),F(e,i.id).length!==t.length&&r++}catch{}return r}export{c as a,b,P as c,v as d,U as e,E as f,_ as g,M as h,B as i};
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ var e={SUCCESS:0,GENERAL:1,USAGE:2,NOT_FOUND:3,AUTH:4,CONFLICT:5};export{e as a};
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ import{c as st}from"./chunk-RRQ5P63N.js";import{a as U}from"./chunk-BZDBSBRV.js";import{a as b,e as R,g as I}from"./chunk-BUQI2W5H.js";import{d as tt,h as et,o as ot,s as nt,v as rt}from"./chunk-O4LGEPMQ.js";import c from"chalk";import{resolve as wt,join as N}from"path";import{readFileSync as z}from"fs";import{statSync as Nt,readdirSync as Tt,unlinkSync as At}from"fs";import M from"crypto";var vt="vibeflow-auth-v1",xt=1440*60*1e3;function it(t){return M.scryptSync(t,vt,32)}function jt(t,e){let o=it(e),n=M.randomBytes(16),r=M.createCipheriv("aes-256-gcm",o,n),s=JSON.stringify(t),i=Buffer.concat([r.update(s),r.final()]),y=r.getAuthTag();return{version:1,createdAt:new Date().toISOString(),expiresAt:new Date(Date.now()+xt).toISOString(),iv:n.toString("hex"),tag:y.toString("hex"),data:i.toString("hex")}}function at(t,e){if(new Date(t.expiresAt)<new Date)return null;try{let o=it(e),n=M.createDecipheriv("aes-256-gcm",o,Buffer.from(t.iv,"hex"));n.setAuthTag(Buffer.from(t.tag,"hex"));let r=Buffer.concat([n.update(Buffer.from(t.data,"hex")),n.final()]);return JSON.parse(r.toString())}catch{return null}}function bt(t,e){return Math.abs(t.x-e.x)>2||Math.abs(t.y-e.y)>2||Math.abs(t.width-e.width)>2||Math.abs(t.height-e.height)>2}function H(t,e){let o=!!e.outerHTML,n=t.outerHTML!==e.outerHTML,r={},s=new Set([...Object.keys(t.computedStyles),...Object.keys(e.computedStyles)]);for(let l of s){let E=t.computedStyles[l],x=e.computedStyles[l];E!==x&&(r[l]=[E??"",x??""])}let i=bt(t.position.boundingBox,e.position.boundingBox),y=new Set(t.consoleErrors),g=e.consoleErrors.filter(l=>!y.has(l));return{selectorResolves:o,htmlChanged:n,stylesChanged:r,positionChanged:i,newConsoleErrors:g}}function ct(t,e){let o=[];if(t.selectorResolves){t.htmlChanged&&o.push("HTML changed");let n=Object.keys(t.stylesChanged).length;if(n>0){let r=Object.keys(t.stylesChanged).slice(0,5).join(", "),s=n>5?` (+${n-5} more)`:"";o.push(`${n} style property change(s): ${r}${s}`)}t.positionChanged&&o.push("position shifted"),t.newConsoleErrors.length>0&&o.push(`${t.newConsoleErrors.length} new console error(s)`),o.length===0&&o.push("no structural changes detected")}else o.push(`Selector "${e}" no longer resolves`);return o.join("; ")}import{readFileSync as lt,writeFileSync as Ht,mkdirSync as Jt,existsSync as ft}from"fs";import{join as gt,basename as Rt}from"path";import{execSync as Ct}from"child_process";var G={port:3700};function Ot(t){return gt(t,tt,et)}function ut(t){let e=Ot(t);if(!ft(e))return{...G};let o=lt(e,"utf-8"),n;try{n=JSON.parse(o)}catch{return{...G}}return{...G,...n}}function Wt(t){let e=gt(t,"package.json");if(ft(e))try{let o=JSON.parse(lt(e,"utf-8"));if(o.name)return o.name}catch{}return Rt(t)}function zt(t){try{return Ct("git branch --show-current",{cwd:t,encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()||null}catch{return null}}var W=["display","visibility","opacity","position","overflow","overflow-x","overflow-y","width","min-width","max-width","height","min-height","max-height","margin","margin-top","margin-right","margin-bottom","margin-left","padding","padding-top","padding-right","padding-bottom","padding-left","border","border-width","border-style","border-color","border-radius","background-color","background-image","color","font-size","font-weight","font-style","font-family","line-height","letter-spacing","text-align","text-decoration","text-overflow","white-space","flex-direction","flex-wrap","flex","justify-content","align-items","gap","row-gap","column-gap","grid-template-columns","grid-template-rows","z-index","box-shadow","transform","transition","cursor","user-select","pointer-events","top","left","right","bottom"];function dt(t){let e=[],o=t;for(;o&&o!==document.documentElement;){let n=o.parentElement;if(!n)break;let r=Array.from(n.children).indexOf(o);e.unshift(r),o=n}return e.join("/")}function ht(t){let e=t.tagName.toLowerCase(),o=t.getAttribute("data-task-id");if(o)return`${e}.task-card[data-task-id=${o}]`;let n=t.getAttribute("data-status");if(n&&t.classList.contains("column-scroll"))return`${e}.column-scroll[data-status=${n}]`;let r=t.getAttribute("data-column-id");if(r)return`${e}[data-column-id=${r}]`;let s=Array.from(t.classList).slice(0,2),i=e;s.length&&(i+="."+s.join("."));let y=t.parentElement;if(y){let g=Array.from(y.children).filter(l=>l.tagName===t.tagName);if(g.length>1){let l=g.indexOf(t)+1;i+=`:nth-of-type(${l})`}}return i}function mt(t,e=W){let o=window.getComputedStyle(t),n={};for(let r of e)n[r]=o.getPropertyValue(r);return n}function pt(t,e=200){return t.replace(/\s+/g," ").trim().slice(0,e)}function yt(t){let e=new Map;for(let o of t){let n=o.tagName.toLowerCase(),r=Array.from(o.classList).slice(0,2).join("."),s=r?`${n}.${r}`:n;e.set(s,(e.get(s)||0)+1)}return Array.from(e.entries()).map(([o,n])=>`${o} \xD7${n}`).slice(0,10)}var p=class extends Error{constructor(o,n,r){super(n);this.code=o;this.suggestion=r;this.name="VerifyError"}code;suggestion};async function Pt(){try{return await import("playwright")}catch{throw new p("E_PLAYWRIGHT_MISSING","Playwright is not installed.","Run: npx playwright install chromium")}}async function kt(t,e,o={}){let n=wt(t),r=ot(n,e);if(!r)throw new p("E_NOT_FOUND",`Task not found: ${e}`,"Run 'vibeflow tasks' to see available task IDs.");let s=nt(r);if(!s)throw new p("E_NOT_FOUND",`Task not found: ${e}`);let i,y=s.baselineElementFile||"baseline-element.json",g=I(n,e,y);if(g)try{i=JSON.parse(z(g,"utf-8"))}catch{}if(!i&&s.baseline&&(i=s.baseline),!i)throw new p("E_NO_BASELINE","Task has no baseline. Re-annotate to capture one.");let l=[],E={},x={};if(s.authStateEnc&&s.author)try{let m=JSON.parse(s.authStateEnc),f=at(m,s.author);if(!f)throw new p("E_AUTH_EXPIRED","Auth state expired. Re-annotate to capture fresh cookies.");l=f.cookies,E=f.localStorage,x=f.sessionStorage}catch(m){throw m instanceof p?m:new p("E_AUTH_CORRUPT","Auth state corrupted. Re-annotate.")}let v=o.url??s.url;if(!v)throw new p("E_NO_URL","Task has no URL. Cannot verify without a target URL.","Re-annotate the element with a URL, or use --url to override.");let C=ut(n).port??3700,A=v.startsWith("http")?v:`http://localhost:${C}${v.startsWith("/")?v:"/"+v}`,S=s.cssSelector??s.selector;if(!S||S==="/")throw new p("E_NO_SELECTOR","Task has no CSS selector. Cannot verify without a selector.");let j=await Pt(),$;try{$=await j.chromium.launch({headless:!0})}catch(m){let f=m instanceof Error?m.message:String(m);throw f.includes("not found")||f.includes("not installed")||f.includes("Executable doesn't exist")?new p("E_PLAYWRIGHT_MISSING","Chromium is not installed.","Run: npx playwright install chromium"):new p("E_PLAYWRIGHT_CRASH",`Verification failed: ${f}`,"Try again.")}let k;try{let m=i.position?.viewport;k=await $.newContext({viewport:m?{width:m.width,height:m.height}:void 0,deviceScaleFactor:m?.dpr,userAgent:i.browser||void 0}),l.length>0&&await k.addCookies(l.map(a=>({name:a.name,value:a.value,domain:a.domain,path:a.path,expires:a.expires,httpOnly:a.httpOnly,secure:a.secure,sameSite:a.sameSite})));let f=await k.newPage(),T=[];f.on("console",a=>{a.type()==="error"&&T.push(a.text())}),f.on("pageerror",a=>{T.push(a.message)});try{await f.goto(A,{waitUntil:"networkidle",timeout:15e3})}catch(a){let u=a instanceof Error?a.message:String(a);throw u.includes("ERR_CONNECTION_REFUSED")||u.includes("ECONNREFUSED")?new p("E_APP_NOT_RUNNING",`Cannot connect to ${A}. Is the dev server running?`):new p("E_NAVIGATION_FAILED",`Failed to navigate to ${A}: ${u}`)}try{Object.keys(E).length>0&&await f.evaluate(a=>{for(let[u,d]of Object.entries(a))window.localStorage.setItem(u,d)},E),Object.keys(x).length>0&&await f.evaluate(a=>{for(let[u,d]of Object.entries(a))window.sessionStorage.setItem(u,d)},x)}catch{}let P=0;try{await f.waitForSelector(S,{timeout:1e4}),P=await f.locator(S).count()}catch{let a={outerHTML:"",computedStyles:{},selector:S,position:i.position,browser:i.browser,consoleErrors:T,capturedAt:new Date().toISOString()},u=H(i,a);return K(s.id,s.description,i,a,u,[],S)}if(P>1){let a={outerHTML:"",computedStyles:{},selector:S,position:i.position,browser:i.browser,consoleErrors:T,capturedAt:new Date().toISOString()},u=H(i,a),d=`Selector matches ${P} elements. The selector may need to be more specific.`;return K(s.id,s.description,i,a,u,[],S,d)}let L=await Lt(f,S,i,T),_=null,B=s.baselineFile||"baseline-page.json",F=I(n,e,B);if(F)try{_=JSON.parse(z(F,"utf-8"))}catch{}let h=H(i,L),O=await _t(n,e,i,L,h,T,f,S);if(_&&_.elements){let a=I(n,e,"verify-all-styles.json");if(a)try{let u=JSON.parse(z(a,"utf-8"));if(u&&u.elements){let d={},St=Object.entries(u.elements);for(let[Y,X]of St){let J=_.elements[Y]?.after;if(J){X.baseline=J;let V={};for(let[q,Q]of Object.entries(X.after)){let Z=J[q];Z!==Q&&(V[q]=[Z,Q])}Object.keys(V).length>0&&(d[Y]=V)}}R(n,e,"verify-all-styles.json",Buffer.from(JSON.stringify(u,null,2)));let Et=JSON.stringify({totalChanged:Object.keys(d).length,elements:d},null,2);R(n,e,"verify-page-diff.json",Buffer.from(Et)),O.push(N(b(n,e),"verify-page-diff.json"))}}catch{}}let D=K(s.id,s.description,i,L,h,O,S);return rt(n,e,{verified:D.ok}),D}finally{await k?.close(),await $?.close()}}async function Lt(t,e,o,n){let r=t.locator(e).first(),s=await r.evaluate(l=>l.outerHTML).catch(()=>""),i=await r.evaluate(l=>{let E=window.getComputedStyle(l),x={};for(let v=0;v<E.length;v++){let w=E[v];x[w]=E.getPropertyValue(w)}return x}).catch(()=>({})),g={boundingBox:await r.boundingBox().catch(()=>null)??o.position.boundingBox,scrollPosition:await t.evaluate(()=>({x:window.scrollX,y:window.scrollY})),viewport:await t.evaluate(()=>({width:window.innerWidth,height:window.innerHeight,dpr:window.devicePixelRatio})),stackingContext:o.position.stackingContext};return{outerHTML:s,computedStyles:i,selector:e,position:g,browser:o.browser,consoleErrors:n,capturedAt:new Date().toISOString()}}async function _t(t,e,o,n,r,s,i,y){let g=[],l=b(t,e);try{let w=Tt(l);for(let C of w)(C.startsWith("verify-")||C==="baseline.json")&&At(N(l,C))}catch{}let E=JSON.stringify(n,null,2);R(t,e,"verify-after.json",Buffer.from(E)),g.push(N(b(t,e),"verify-after.json"));let x=JSON.stringify(r,null,2);R(t,e,"verify-diff.json",Buffer.from(x)),g.push(N(b(t,e),"verify-diff.json"));let v=s.length>0?s.join(`
3
+ `):"(no console errors)";if(R(t,e,"verify-console.txt",Buffer.from(v)),g.push(N(b(t,e),"verify-console.txt")),i){try{let w=await i.content();R(t,e,"verify-page.html",Buffer.from(w)),g.push(N(b(t,e),"verify-page.html"))}catch{}try{let C=await i.evaluate(({buildKeyFn:A,buildSelectorFn:S,filterStylesFn:j,childSignatureFn:$,normalizeTextFn:k,styles:m,maxElements:f})=>{let T={},P=0,L=!1,_=document.createTreeWalker(document.body,NodeFilter.SHOW_ELEMENT,{acceptNode(h){if(P>=f)return NodeFilter.FILTER_REJECT;let O=h;return O.classList.length>0||O.hasAttribute("data-task-id")||O.hasAttribute("data-status")||O.hasAttribute("data-column-id")?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP}}),B=[],F;for(;F=_.nextNode();)B.push(F);for(let h of B){if(P>=f){L=!0;break}let O=A(h),D=Array.from(h.children),a={};for(let d of Array.from(h.attributes))d.name.startsWith("data-")&&(a[d.name.slice(5)]=d.value);let u={x:0,y:0,width:0,height:0};try{let d=h.getBoundingClientRect();u={x:Math.round(d.x),y:Math.round(d.y),width:Math.round(d.width),height:Math.round(d.height)}}catch{}T[O]={key:O,selector:S(h),tag:h.tagName.toLowerCase(),classes:Array.from(h.classList),dataAttrs:a,parentKey:h.parentElement?A(h.parentElement):"",childCount:D.length,childSignature:$(D),text:k(h.textContent??""),position:u,baseline:j(h,m),after:j(h,m)},P++}return{version:1,capturedAt:new Date().toISOString(),truncated:L,elements:T}},{buildKeyFn:dt,buildSelectorFn:ht,filterStylesFn:mt,childSignatureFn:yt,normalizeTextFn:pt,styles:W,maxElements:1e3});if(C){let A=JSON.stringify(C,null,2);R(t,e,"verify-all-styles.json",Buffer.from(A)),g.push(N(b(t,e),"verify-all-styles.json"))}}catch{}try{let w=await i.screenshot({fullPage:!1});R(t,e,"verify-screenshot.png",w),g.push(N(b(t,e),"verify-screenshot.png"))}catch{}if(y)try{let w=await i.locator(y).first().evaluate(C=>C.outerHTML);R(t,e,"verify-element.html",Buffer.from(w)),g.push(N(b(t,e),"verify-element.html"))}catch{}}if(o){let w=JSON.stringify(o,null,2);R(t,e,"baseline.json",Buffer.from(w)),g.push(N(b(t,e),"baseline.json"))}return g}function K(t,e,o,n,r,s,i,y){let g=r.selectorResolves&&r.newConsoleErrors.length===0,l=y??ct(r,i);return{taskId:t,ok:g,taskDescription:e,baseline:{selector:o.selector,url:"",capturedAt:o.capturedAt,snapshot:o},after:{snapshot:n,consoleErrors:n.consoleErrors},diff:r,evidenceFiles:s,verdict:l}}async function ce(t,e,o){let n=wt(t);try{let r=await kt(n,e,o);await $t(n,e,r),o.json?console.log(JSON.stringify(r,null,2)):Ft(r)}catch(r){if(r instanceof p)o.json?process.stderr.write(JSON.stringify({ok:!1,error:{code:r.code,message:r.message,suggestion:r.suggestion}})+`
4
+ `):(process.stderr.write(c.red(`\u2717 ${r.message}
5
+ `)),r.suggestion&&process.stderr.write(c.dim(` ${r.suggestion}
6
+ `))),process.exitCode=U.GENERAL;else{let s=r instanceof Error?r.message:String(r);o.json?process.stderr.write(JSON.stringify({ok:!1,error:{code:"E_UNKNOWN",message:s}})+`
7
+ `):process.stderr.write(c.red(`\u2717 Verification failed: ${s}
8
+ `)),process.exitCode=U.GENERAL}}}async function $t(t,e,o){let n=`**Verification ${o.ok?"\u2705 passed":"\u26A0\uFE0F issues detected"}**
9
+
10
+ ${o.verdict}`;st(t,e,"agent",n,void 0,"system")}function Ft(t){let e=t.ok?c.green("\u2705"):c.yellow("\u26A0\uFE0F");console.log(),console.log(` ${e} Evidences collected for task ${t.taskId}`),console.log(c.dim("\u2500".repeat(60))),console.log(c.dim(` Verdict: ${t.verdict}`)),console.log();let o=t.diff;if(o.selectorResolves){o.htmlChanged?console.log(c.cyan(" \u2713 HTML changed")):console.log(c.dim(" \xB7 HTML unchanged"));let n=Object.keys(o.stylesChanged).length;if(n>0){console.log(c.cyan(` \u2713 ${n} style property change(s):`));for(let[r,[s,i]]of Object.entries(o.stylesChanged).slice(0,8))console.log(c.dim(` ${r}: ${s} \u2192 ${i}`));n>8&&console.log(c.dim(` ... and ${n-8} more`))}if(o.positionChanged&&console.log(c.cyan(" \u2713 Position shifted")),o.newConsoleErrors.length>0){console.log(c.yellow(` \u26A0 ${o.newConsoleErrors.length} new console error(s):`));for(let r of o.newConsoleErrors.slice(0,3))console.log(c.dim(` ${r.slice(0,120)}`))}}else console.log(c.red(" \u26A0 Target element not found \u2014 the fix may have renamed/removed it."));if(t.evidenceFiles.length>0){console.log(c.cyan(` Evidence files (${t.evidenceFiles.length}):`));for(let n of t.evidenceFiles){let r=n.split("/").pop()??n;try{let i=(Nt(n).size/1024).toFixed(1);console.log(c.dim(` ${r} (${i} KB)`))}catch{console.log(c.dim(` ${r}`))}}}console.log(),console.log(c.cyan(" Explore evidence (agent tools):")),console.log(c.dim(` vibeflow verify style_query ${t.taskId} <property>`)),console.log(c.dim(` vibeflow verify style_diff ${t.taskId} [--filter <pattern>]`)),console.log(c.dim(` vibeflow verify element_info ${t.taskId}`)),console.log(c.dim(` vibeflow verify html_diff ${t.taskId}`)),console.log(),console.log(c.cyan(" Review evidences:")),console.log(c.dim(" 1. Check if the fix is confirmed (styles match expectations)")),console.log(c.dim(` 2. If confirmed \u2192 vibeflow tasks --edit ${t.taskId} --set-status review --comment "Verified: <what you confirmed>"`)),console.log(c.dim(" 3. If not sure \u2192 leave a comment explaining uncertainty")),console.log(c.dim(` 4. If wrong \u2192 vibeflow tasks --edit ${t.taskId} --set-status in-progress`)),console.log(),t.ok||(console.log(c.yellow(" \u26A0 Verification failed \u2014 move to in-progress and fix:")),console.log(c.dim(` vibeflow tasks --edit ${t.taskId} --set-status in-progress`)))}export{jt as a,ut as b,Wt as c,zt as d,p as e,kt as f,ce as g,$t as h};
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{h as d,i as f,m as S,n as c,o as g,q as p,s as u}from"./chunk-PN5C7EHL.js";import{mkdirSync as w,writeFileSync as O,renameSync as F}from"fs";import{dirname as b}from"path";import{randomBytes as z}from"crypto";function P(t){let n=t;return{...t,text:t.text||n.body||"",author:t.author??"agent"}}function B(t,n){let r=c(t,n);return((r?u(r):null)?.comments??[]).filter(e=>!e.deleted).map(P)}function x(t){return p(t)}async function E(t,n,r,i,e,o,m){i=x(i);let a=d(t,n);return f(a,()=>{let s=c(t,n),l=s?u(s):null,y=l?.comments??[],C={id:z(8).toString("hex"),author:r,text:i,...e&&e.length>0?{files:e}:{},...o&&o!=="comment"?{type:o}:{},createdAt:new Date().toISOString(),source:m??"cli"},T=[...y,C];if(l)g(t,{...l,comments:T});else{let k=S(t,n,new Date().toISOString());w(b(k),{recursive:!0});let h=k+".tmp";O(h,JSON.stringify({id:n,comments:T},null,2),"utf-8"),F(h,k)}return C})}async function N(t,n,r,i){let e=d(t,n);return f(e,()=>{let o=c(t,n),m=o?u(o):null,a=m?.comments??[],s=a.find(l=>l.id===r&&!l.deleted);return s?(s.text=x(i),s.updatedAt=new Date().toISOString(),m&&g(t,{...m,comments:a}),P(s)):null})}async function G(t,n,r){let i=d(t,n);return f(i,()=>{let e=c(t,n),o=e?u(e):null,m=o?.comments??[],a=m.findIndex(s=>s.id===r&&!s.deleted);return a===-1?!1:(m[a]={...m[a],deleted:!0,text:"[Comment deleted]",updatedAt:new Date().toISOString()},o&&g(t,{...o,comments:m}),!0)})}export{B as a,x as b,E as c,N as d,G as e};
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import{i as d,j as f,n as S,o as c,p as g,q as p,s as u}from"./chunk-2CI62NHU.js";import{mkdirSync as w,writeFileSync as O,renameSync as F}from"fs";import{dirname as b}from"path";import{randomBytes as z}from"crypto";function P(t){let n=t;return{...t,text:t.text||n.body||"",author:t.author??"agent"}}function B(t,n){let r=c(t,n);return((r?u(r):null)?.comments??[]).filter(e=>!e.deleted).map(P)}function x(t){return p(t)}async function E(t,n,r,i,e,o,m){i=x(i);let a=d(t,n);return f(a,()=>{let s=c(t,n),l=s?u(s):null,y=l?.comments??[],C={id:z(8).toString("hex"),author:r,text:i,...e&&e.length>0?{files:e}:{},...o&&o!=="comment"?{type:o}:{},createdAt:new Date().toISOString(),source:m??"cli"},T=[...y,C];if(l)g(t,{...l,comments:T});else{let k=S(t,n,new Date().toISOString());w(b(k),{recursive:!0});let h=k+".tmp";O(h,JSON.stringify({id:n,comments:T},null,2),"utf-8"),F(h,k)}return C})}async function N(t,n,r,i){let e=d(t,n);return f(e,()=>{let o=c(t,n),m=o?u(o):null,a=m?.comments??[],s=a.find(l=>l.id===r&&!l.deleted);return s?(s.text=x(i),s.updatedAt=new Date().toISOString(),m&&g(t,{...m,comments:a}),P(s)):null})}async function G(t,n,r){let i=d(t,n);return f(i,()=>{let e=c(t,n),o=e?u(e):null,m=o?.comments??[],a=m.findIndex(s=>s.id===r&&!s.deleted);return a===-1?!1:(m[a]={...m[a],deleted:!0,text:"[Comment deleted]",updatedAt:new Date().toISOString()},o&&g(t,{...o,comments:m}),!0)})}export{B as a,x as b,E as c,N as d,G as e};
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ import{c as st}from"./chunk-WZ2QQDYW.js";import{a as U}from"./chunk-BZDBSBRV.js";import{a as b,e as R,g as I}from"./chunk-32Z32W7T.js";import{c as tt,g as et,n as ot,s as nt,v as rt}from"./chunk-ZHA4Y2KB.js";import c from"chalk";import{resolve as wt,join as N}from"path";import{readFileSync as z}from"fs";import{statSync as Nt,readdirSync as Tt,unlinkSync as At}from"fs";import M from"crypto";var vt="vibeflow-auth-v1",xt=1440*60*1e3;function it(t){return M.scryptSync(t,vt,32)}function jt(t,e){let o=it(e),n=M.randomBytes(16),r=M.createCipheriv("aes-256-gcm",o,n),s=JSON.stringify(t),i=Buffer.concat([r.update(s),r.final()]),y=r.getAuthTag();return{version:1,createdAt:new Date().toISOString(),expiresAt:new Date(Date.now()+xt).toISOString(),iv:n.toString("hex"),tag:y.toString("hex"),data:i.toString("hex")}}function at(t,e){if(new Date(t.expiresAt)<new Date)return null;try{let o=it(e),n=M.createDecipheriv("aes-256-gcm",o,Buffer.from(t.iv,"hex"));n.setAuthTag(Buffer.from(t.tag,"hex"));let r=Buffer.concat([n.update(Buffer.from(t.data,"hex")),n.final()]);return JSON.parse(r.toString())}catch{return null}}function bt(t,e){return Math.abs(t.x-e.x)>2||Math.abs(t.y-e.y)>2||Math.abs(t.width-e.width)>2||Math.abs(t.height-e.height)>2}function H(t,e){let o=!!e.outerHTML,n=t.outerHTML!==e.outerHTML,r={},s=new Set([...Object.keys(t.computedStyles),...Object.keys(e.computedStyles)]);for(let l of s){let E=t.computedStyles[l],x=e.computedStyles[l];E!==x&&(r[l]=[E??"",x??""])}let i=bt(t.position.boundingBox,e.position.boundingBox),y=new Set(t.consoleErrors),g=e.consoleErrors.filter(l=>!y.has(l));return{selectorResolves:o,htmlChanged:n,stylesChanged:r,positionChanged:i,newConsoleErrors:g}}function ct(t,e){let o=[];if(t.selectorResolves){t.htmlChanged&&o.push("HTML changed");let n=Object.keys(t.stylesChanged).length;if(n>0){let r=Object.keys(t.stylesChanged).slice(0,5).join(", "),s=n>5?` (+${n-5} more)`:"";o.push(`${n} style property change(s): ${r}${s}`)}t.positionChanged&&o.push("position shifted"),t.newConsoleErrors.length>0&&o.push(`${t.newConsoleErrors.length} new console error(s)`),o.length===0&&o.push("no structural changes detected")}else o.push(`Selector "${e}" no longer resolves`);return o.join("; ")}import{readFileSync as lt,writeFileSync as Ht,mkdirSync as Jt,existsSync as ft}from"fs";import{join as gt,basename as Rt}from"path";import{execSync as Ct}from"child_process";var G={port:3700};function Ot(t){return gt(t,tt,et)}function ut(t){let e=Ot(t);if(!ft(e))return{...G};let o=lt(e,"utf-8"),n;try{n=JSON.parse(o)}catch{return{...G}}return{...G,...n}}function Wt(t){let e=gt(t,"package.json");if(ft(e))try{let o=JSON.parse(lt(e,"utf-8"));if(o.name)return o.name}catch{}return Rt(t)}function zt(t){try{return Ct("git branch --show-current",{cwd:t,encoding:"utf-8",stdio:["pipe","pipe","pipe"]}).trim()||null}catch{return null}}var W=["display","visibility","opacity","position","overflow","overflow-x","overflow-y","width","min-width","max-width","height","min-height","max-height","margin","margin-top","margin-right","margin-bottom","margin-left","padding","padding-top","padding-right","padding-bottom","padding-left","border","border-width","border-style","border-color","border-radius","background-color","background-image","color","font-size","font-weight","font-style","font-family","line-height","letter-spacing","text-align","text-decoration","text-overflow","white-space","flex-direction","flex-wrap","flex","justify-content","align-items","gap","row-gap","column-gap","grid-template-columns","grid-template-rows","z-index","box-shadow","transform","transition","cursor","user-select","pointer-events","top","left","right","bottom"];function dt(t){let e=[],o=t;for(;o&&o!==document.documentElement;){let n=o.parentElement;if(!n)break;let r=Array.from(n.children).indexOf(o);e.unshift(r),o=n}return e.join("/")}function ht(t){let e=t.tagName.toLowerCase(),o=t.getAttribute("data-task-id");if(o)return`${e}.task-card[data-task-id=${o}]`;let n=t.getAttribute("data-status");if(n&&t.classList.contains("column-scroll"))return`${e}.column-scroll[data-status=${n}]`;let r=t.getAttribute("data-column-id");if(r)return`${e}[data-column-id=${r}]`;let s=Array.from(t.classList).slice(0,2),i=e;s.length&&(i+="."+s.join("."));let y=t.parentElement;if(y){let g=Array.from(y.children).filter(l=>l.tagName===t.tagName);if(g.length>1){let l=g.indexOf(t)+1;i+=`:nth-of-type(${l})`}}return i}function mt(t,e=W){let o=window.getComputedStyle(t),n={};for(let r of e)n[r]=o.getPropertyValue(r);return n}function pt(t,e=200){return t.replace(/\s+/g," ").trim().slice(0,e)}function yt(t){let e=new Map;for(let o of t){let n=o.tagName.toLowerCase(),r=Array.from(o.classList).slice(0,2).join("."),s=r?`${n}.${r}`:n;e.set(s,(e.get(s)||0)+1)}return Array.from(e.entries()).map(([o,n])=>`${o} \xD7${n}`).slice(0,10)}var p=class extends Error{constructor(o,n,r){super(n);this.code=o;this.suggestion=r;this.name="VerifyError"}code;suggestion};async function Pt(){try{return await import("playwright")}catch{throw new p("E_PLAYWRIGHT_MISSING","Playwright is not installed.","Run: npx playwright install chromium")}}async function kt(t,e,o={}){let n=wt(t),r=ot(n,e);if(!r)throw new p("E_NOT_FOUND",`Task not found: ${e}`,"Run 'vibeflow tasks' to see available task IDs.");let s=nt(r);if(!s)throw new p("E_NOT_FOUND",`Task not found: ${e}`);let i,y=s.baselineElementFile||"baseline-element.json",g=I(n,e,y);if(g)try{i=JSON.parse(z(g,"utf-8"))}catch{}if(!i&&s.baseline&&(i=s.baseline),!i)throw new p("E_NO_BASELINE","Task has no baseline. Re-annotate to capture one.");let l=[],E={},x={};if(s.authStateEnc&&s.author)try{let m=JSON.parse(s.authStateEnc),f=at(m,s.author);if(!f)throw new p("E_AUTH_EXPIRED","Auth state expired. Re-annotate to capture fresh cookies.");l=f.cookies,E=f.localStorage,x=f.sessionStorage}catch(m){throw m instanceof p?m:new p("E_AUTH_CORRUPT","Auth state corrupted. Re-annotate.")}let v=o.url??s.url;if(!v)throw new p("E_NO_URL","Task has no URL. Cannot verify without a target URL.","Re-annotate the element with a URL, or use --url to override.");let C=ut(n).port??3700,A=v.startsWith("http")?v:`http://localhost:${C}${v.startsWith("/")?v:"/"+v}`,S=s.cssSelector??s.selector;if(!S||S==="/")throw new p("E_NO_SELECTOR","Task has no CSS selector. Cannot verify without a selector.");let j=await Pt(),$;try{$=await j.chromium.launch({headless:!0})}catch(m){let f=m instanceof Error?m.message:String(m);throw f.includes("not found")||f.includes("not installed")||f.includes("Executable doesn't exist")?new p("E_PLAYWRIGHT_MISSING","Chromium is not installed.","Run: npx playwright install chromium"):new p("E_PLAYWRIGHT_CRASH",`Verification failed: ${f}`,"Try again.")}let k;try{let m=i.position?.viewport;k=await $.newContext({viewport:m?{width:m.width,height:m.height}:void 0,deviceScaleFactor:m?.dpr,userAgent:i.browser||void 0}),l.length>0&&await k.addCookies(l.map(a=>({name:a.name,value:a.value,domain:a.domain,path:a.path,expires:a.expires,httpOnly:a.httpOnly,secure:a.secure,sameSite:a.sameSite})));let f=await k.newPage(),T=[];f.on("console",a=>{a.type()==="error"&&T.push(a.text())}),f.on("pageerror",a=>{T.push(a.message)});try{await f.goto(A,{waitUntil:"networkidle",timeout:15e3})}catch(a){let u=a instanceof Error?a.message:String(a);throw u.includes("ERR_CONNECTION_REFUSED")||u.includes("ECONNREFUSED")?new p("E_APP_NOT_RUNNING",`Cannot connect to ${A}. Is the dev server running?`):new p("E_NAVIGATION_FAILED",`Failed to navigate to ${A}: ${u}`)}try{Object.keys(E).length>0&&await f.evaluate(a=>{for(let[u,d]of Object.entries(a))window.localStorage.setItem(u,d)},E),Object.keys(x).length>0&&await f.evaluate(a=>{for(let[u,d]of Object.entries(a))window.sessionStorage.setItem(u,d)},x)}catch{}let P=0;try{await f.waitForSelector(S,{timeout:1e4}),P=await f.locator(S).count()}catch{let a={outerHTML:"",computedStyles:{},selector:S,position:i.position,browser:i.browser,consoleErrors:T,capturedAt:new Date().toISOString()},u=H(i,a);return K(s.id,s.description,i,a,u,[],S)}if(P>1){let a={outerHTML:"",computedStyles:{},selector:S,position:i.position,browser:i.browser,consoleErrors:T,capturedAt:new Date().toISOString()},u=H(i,a),d=`Selector matches ${P} elements. The selector may need to be more specific.`;return K(s.id,s.description,i,a,u,[],S,d)}let L=await Lt(f,S,i,T),_=null,B=s.baselineFile||"baseline-page.json",F=I(n,e,B);if(F)try{_=JSON.parse(z(F,"utf-8"))}catch{}let h=H(i,L),O=await _t(n,e,i,L,h,T,f,S);if(_&&_.elements){let a=I(n,e,"verify-all-styles.json");if(a)try{let u=JSON.parse(z(a,"utf-8"));if(u&&u.elements){let d={},St=Object.entries(u.elements);for(let[Y,X]of St){let J=_.elements[Y]?.after;if(J){X.baseline=J;let V={};for(let[q,Q]of Object.entries(X.after)){let Z=J[q];Z!==Q&&(V[q]=[Z,Q])}Object.keys(V).length>0&&(d[Y]=V)}}R(n,e,"verify-all-styles.json",Buffer.from(JSON.stringify(u,null,2)));let Et=JSON.stringify({totalChanged:Object.keys(d).length,elements:d},null,2);R(n,e,"verify-page-diff.json",Buffer.from(Et)),O.push(N(b(n,e),"verify-page-diff.json"))}}catch{}}let D=K(s.id,s.description,i,L,h,O,S);return rt(n,e,{verified:D.ok}),D}finally{await k?.close(),await $?.close()}}async function Lt(t,e,o,n){let r=t.locator(e).first(),s=await r.evaluate(l=>l.outerHTML).catch(()=>""),i=await r.evaluate(l=>{let E=window.getComputedStyle(l),x={};for(let v=0;v<E.length;v++){let w=E[v];x[w]=E.getPropertyValue(w)}return x}).catch(()=>({})),g={boundingBox:await r.boundingBox().catch(()=>null)??o.position.boundingBox,scrollPosition:await t.evaluate(()=>({x:window.scrollX,y:window.scrollY})),viewport:await t.evaluate(()=>({width:window.innerWidth,height:window.innerHeight,dpr:window.devicePixelRatio})),stackingContext:o.position.stackingContext};return{outerHTML:s,computedStyles:i,selector:e,position:g,browser:o.browser,consoleErrors:n,capturedAt:new Date().toISOString()}}async function _t(t,e,o,n,r,s,i,y){let g=[],l=b(t,e);try{let w=Tt(l);for(let C of w)(C.startsWith("verify-")||C==="baseline.json")&&At(N(l,C))}catch{}let E=JSON.stringify(n,null,2);R(t,e,"verify-after.json",Buffer.from(E)),g.push(N(b(t,e),"verify-after.json"));let x=JSON.stringify(r,null,2);R(t,e,"verify-diff.json",Buffer.from(x)),g.push(N(b(t,e),"verify-diff.json"));let v=s.length>0?s.join(`
3
+ `):"(no console errors)";if(R(t,e,"verify-console.txt",Buffer.from(v)),g.push(N(b(t,e),"verify-console.txt")),i){try{let w=await i.content();R(t,e,"verify-page.html",Buffer.from(w)),g.push(N(b(t,e),"verify-page.html"))}catch{}try{let C=await i.evaluate(({buildKeyFn:A,buildSelectorFn:S,filterStylesFn:j,childSignatureFn:$,normalizeTextFn:k,styles:m,maxElements:f})=>{let T={},P=0,L=!1,_=document.createTreeWalker(document.body,NodeFilter.SHOW_ELEMENT,{acceptNode(h){if(P>=f)return NodeFilter.FILTER_REJECT;let O=h;return O.classList.length>0||O.hasAttribute("data-task-id")||O.hasAttribute("data-status")||O.hasAttribute("data-column-id")?NodeFilter.FILTER_ACCEPT:NodeFilter.FILTER_SKIP}}),B=[],F;for(;F=_.nextNode();)B.push(F);for(let h of B){if(P>=f){L=!0;break}let O=A(h),D=Array.from(h.children),a={};for(let d of Array.from(h.attributes))d.name.startsWith("data-")&&(a[d.name.slice(5)]=d.value);let u={x:0,y:0,width:0,height:0};try{let d=h.getBoundingClientRect();u={x:Math.round(d.x),y:Math.round(d.y),width:Math.round(d.width),height:Math.round(d.height)}}catch{}T[O]={key:O,selector:S(h),tag:h.tagName.toLowerCase(),classes:Array.from(h.classList),dataAttrs:a,parentKey:h.parentElement?A(h.parentElement):"",childCount:D.length,childSignature:$(D),text:k(h.textContent??""),position:u,baseline:j(h,m),after:j(h,m)},P++}return{version:1,capturedAt:new Date().toISOString(),truncated:L,elements:T}},{buildKeyFn:dt,buildSelectorFn:ht,filterStylesFn:mt,childSignatureFn:yt,normalizeTextFn:pt,styles:W,maxElements:1e3});if(C){let A=JSON.stringify(C,null,2);R(t,e,"verify-all-styles.json",Buffer.from(A)),g.push(N(b(t,e),"verify-all-styles.json"))}}catch{}try{let w=await i.screenshot({fullPage:!1});R(t,e,"verify-screenshot.png",w),g.push(N(b(t,e),"verify-screenshot.png"))}catch{}if(y)try{let w=await i.locator(y).first().evaluate(C=>C.outerHTML);R(t,e,"verify-element.html",Buffer.from(w)),g.push(N(b(t,e),"verify-element.html"))}catch{}}if(o){let w=JSON.stringify(o,null,2);R(t,e,"baseline.json",Buffer.from(w)),g.push(N(b(t,e),"baseline.json"))}return g}function K(t,e,o,n,r,s,i,y){let g=r.selectorResolves&&r.newConsoleErrors.length===0,l=y??ct(r,i);return{taskId:t,ok:g,taskDescription:e,baseline:{selector:o.selector,url:"",capturedAt:o.capturedAt,snapshot:o},after:{snapshot:n,consoleErrors:n.consoleErrors},diff:r,evidenceFiles:s,verdict:l}}async function ce(t,e,o){let n=wt(t);try{let r=await kt(n,e,o);await $t(n,e,r),o.json?console.log(JSON.stringify(r,null,2)):Ft(r)}catch(r){if(r instanceof p)o.json?process.stderr.write(JSON.stringify({ok:!1,error:{code:r.code,message:r.message,suggestion:r.suggestion}})+`
4
+ `):(process.stderr.write(c.red(`\u2717 ${r.message}
5
+ `)),r.suggestion&&process.stderr.write(c.dim(` ${r.suggestion}
6
+ `))),process.exitCode=U.GENERAL;else{let s=r instanceof Error?r.message:String(r);o.json?process.stderr.write(JSON.stringify({ok:!1,error:{code:"E_UNKNOWN",message:s}})+`
7
+ `):process.stderr.write(c.red(`\u2717 Verification failed: ${s}
8
+ `)),process.exitCode=U.GENERAL}}}async function $t(t,e,o){let n=`**Verification ${o.ok?"\u2705 passed":"\u26A0\uFE0F issues detected"}**
9
+
10
+ ${o.verdict}`;st(t,e,"agent",n,void 0,"system")}function Ft(t){let e=t.ok?c.green("\u2705"):c.yellow("\u26A0\uFE0F");console.log(),console.log(` ${e} Evidences collected for task ${t.taskId}`),console.log(c.dim("\u2500".repeat(60))),console.log(c.dim(` Verdict: ${t.verdict}`)),console.log();let o=t.diff;if(o.selectorResolves){o.htmlChanged?console.log(c.cyan(" \u2713 HTML changed")):console.log(c.dim(" \xB7 HTML unchanged"));let n=Object.keys(o.stylesChanged).length;if(n>0){console.log(c.cyan(` \u2713 ${n} style property change(s):`));for(let[r,[s,i]]of Object.entries(o.stylesChanged).slice(0,8))console.log(c.dim(` ${r}: ${s} \u2192 ${i}`));n>8&&console.log(c.dim(` ... and ${n-8} more`))}if(o.positionChanged&&console.log(c.cyan(" \u2713 Position shifted")),o.newConsoleErrors.length>0){console.log(c.yellow(` \u26A0 ${o.newConsoleErrors.length} new console error(s):`));for(let r of o.newConsoleErrors.slice(0,3))console.log(c.dim(` ${r.slice(0,120)}`))}}else console.log(c.red(" \u26A0 Target element not found \u2014 the fix may have renamed/removed it."));if(t.evidenceFiles.length>0){console.log(c.cyan(` Evidence files (${t.evidenceFiles.length}):`));for(let n of t.evidenceFiles){let r=n.split("/").pop()??n;try{let i=(Nt(n).size/1024).toFixed(1);console.log(c.dim(` ${r} (${i} KB)`))}catch{console.log(c.dim(` ${r}`))}}}console.log(),console.log(c.cyan(" Explore evidence (agent tools):")),console.log(c.dim(` vibeflow verify style_query ${t.taskId} <property>`)),console.log(c.dim(` vibeflow verify style_diff ${t.taskId} [--filter <pattern>]`)),console.log(c.dim(` vibeflow verify element_info ${t.taskId}`)),console.log(c.dim(` vibeflow verify html_diff ${t.taskId}`)),console.log(),console.log(c.cyan(" Review evidences:")),console.log(c.dim(" 1. Check if the fix is confirmed (styles match expectations)")),console.log(c.dim(` 2. If confirmed \u2192 vibeflow tasks --edit ${t.taskId} --set-status review --comment "Verified: <what you confirmed>"`)),console.log(c.dim(" 3. If not sure \u2192 leave a comment explaining uncertainty")),console.log(c.dim(` 4. If wrong \u2192 vibeflow tasks --edit ${t.taskId} --set-status in-progress`)),console.log(),t.ok||(console.log(c.yellow(" \u26A0 Verification failed \u2014 move to in-progress and fix:")),console.log(c.dim(` vibeflow tasks --edit ${t.taskId} --set-status in-progress`)))}export{jt as a,ut as b,Wt as c,zt as d,p as e,kt as f,ce as g,$t as h};
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ import{existsSync as l,readFileSync as A,writeFileSync as $,mkdirSync as m,readdirSync as d,unlinkSync as S,renameSync as y}from"fs";import{join as a,extname as k}from"path";import{randomBytes as D}from"crypto";var p=".vibeflow",v="tasks",b="tasks/files",h="tasks/screenshots",j="config.json";var E=["backlog","todo","in-progress","review","done"];function F(){return D(15).toString("hex")}function f(e){return a(e,p,v)}function O(e){let s=a(e,p),n=a(s,"files"),i=a(s,b),r=a(s,"screenshots"),t=a(s,h);if(l(n)){m(i,{recursive:!0});for(let o of d(n)){let u=a(n,o),c=a(i,o);if(!l(c))try{y(u,c)}catch{}}}if(l(r)){m(t,{recursive:!0});for(let o of d(r)){let u=a(r,o),c=a(t,o);if(!l(c))try{y(u,c)}catch{}}}}function q(e){O(e),m(f(e),{recursive:!0}),m(a(e,p,h),{recursive:!0})}function T(e){return e.slice(0,10)}function P(e,s,n){let i=f(e);return n?a(i,T(n),`${s}.json`):a(i,`${s}.json`)}function w(e,s){let n=f(e);if(!l(n))return null;for(let i of d(n,{withFileTypes:!0}))if(i.isDirectory()){let r=a(n,i.name,`${s}.json`);if(l(r))return r}else if(i.name===`${s}.json`)return a(n,i.name);return null}function B(e){return{...e,text:e.text??e.content??""}}function N(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:E.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?void 0:Number(e.line),col:e.col==null?void 0:Number(e.col),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=>B(n)):[],files:Array.isArray(e.files)?e.files.map(n=>typeof n=="string"?{name:n,addedAt:new Date().toISOString()}:{name:String(n.name??""),addedAt:String(n.addedAt??new Date().toISOString()),linkedPath:n.linkedPath?String(n.linkedPath):void 0,mimeType:n.mimeType?String(n.mimeType):void 0}).filter(n=>n.name):[],screenshot:e.screenshot?String(e.screenshot):void 0,annotatedElementText:e.annotatedElementText?String(e.annotatedElementText):void 0,tags:Array.isArray(e.tags)?e.tags.filter(n=>typeof n=="string"&&n.length>0):void 0,sortKey:e.sortKey?String(e.sortKey):void 0,verified:e.verified===!0,branchName:e.branchName?String(e.branchName):void 0,baseline:e.baseline&&typeof e.baseline=="object"?e.baseline:void 0,authStateEnc:e.authStateEnc?String(e.authStateEnc):void 0}}function C(e,s){let n=a(f(e),T(s.created));m(n,{recursive:!0});let i=a(n,`${s.id}.json`),r=i+".tmp";$(r,JSON.stringify(s,null,2),"utf-8"),y(r,i)}function x(e){return e.replace(/\\(n|t|r|\\)/g,(s,n)=>{switch(n){case"n":return`
3
+ `;case"t":return" ";case"r":return"\r";case"\\":return"\\";default:return n}})}function W(e,s){let n=(()=>{let r=(s.priority??"").trim().toLowerCase();return r==="critical"?"Critical":r==="high"?"High":r==="low"?"Low":"Medium"})(),i={...s,title:x(s.title??"").trim(),description:x(s.description??"").trim(),priority:n,id:F(),created:new Date().toISOString(),comments:[],files:[]};return C(e,i),i}function g(e){try{let s=A(e,"utf-8");if(e.endsWith(".json")){let n=JSON.parse(s);return!n||typeof n!="object"||!("id"in n)?null:N(n)}return null}catch{return null}}function R(e){let s=f(e);if(!l(s))return[];let n=[];for(let i of d(s,{withFileTypes:!0}))if(i.isDirectory()){let r=a(s,i.name);for(let t of d(r))if(k(t)===".json"){let o=a(r,t),u=g(o);u&&n.push({task:u,filePath:o})}}else if(k(i.name)===".json"){let r=a(s,i.name),t=g(r);t&&n.push({task:t,filePath:r})}return n}function z(e){return R(e).map(({task:s})=>s)}function M(e){return R(e).map(({task:s,filePath:n})=>({...s,filePath:n}))}function J(e,s,n){let i=w(e,s),r=i?g(i):null;if(!r)return null;let t={...r,...n,updated:new Date().toISOString()};if(C(e,t),i&&i!==P(e,s,t.created))try{S(i)}catch{}return t}function U(e,s){let n=w(e,s);return n?(S(n),!0):!1}function G(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 Y(e,s,n,i,r){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 o of e.commits)t.push(` ${o.sha.slice(0,8)} ${o.timestamp} ${o.message.slice(0,60)}`)}if(t.push(` created: ${e.created}`),e.type&&t.push(` type: ${e.type}`),e.priority&&t.push(` priority: ${e.priority}`),e.author&&t.push(` author: ${e.author}`),e.description){t.push(" description:");for(let o of e.description.split(`
4
+ `))t.push(` ${o}`)}if(e.annotatedElementText&&t.push(` element text: ${e.annotatedElementText}`),n.length>0){t.push(` comments (${n.length}):`);for(let o of n){let u=o.updatedAt?` (edited ${o.updatedAt})`:"";t.push(` [${o.author??"user"}] ${o.createdAt}${u}`);for(let c of o.text.split(`
5
+ `))t.push(` ${c}`)}}if(i.length>0){t.push(` linked files (${i.length}):`);for(let o of i){t.push(` - ${o.name} ${o.url}`);let u=o.linkedPath??a(r,".vibeflow","files",e.id,o.name);if(/\.(md|txt)$/i.test(o.name)&&o.size<1e5&&l(u))try{let c=A(u,"utf-8");t.push(" \u250C\u2500\u2500 content \u2500\u2500");for(let I of c.split(`
6
+ `))t.push(` \u2502 ${I}`);t.push(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")}catch{}}}return t.join(`
7
+ `)}function Q(e){let{autoCommit:s,autoPush:n,autoComment:i,createBranch:r}=e,t=[];if(t.push("Agent instructions (concise):"),t.push(" Discover: vibeflow tasks --status todo | vibeflow tasks --type Research | vibeflow tasks --user <email> | vibeflow tasks --tag <tag>"),t.push(" Auto-claim: vibeflow tasks --next (picks highest-priority todo task and sets it in-progress automatically)"),t.push(" Details: vibeflow tasks --get <id> (full task info with comments and files)"),t.push(' Create: vibeflow tasks --add --title "..." --description "..."'),t.push(""),t.push(" Workflow:"),r?(t.push(" \u26A0 Create a branch FIRST, before any implementation:"),t.push(" 1. git checkout -b <short-name> (e.g. fix/annotation-errors, feat/eye-toggle, chore/cleanup-extension)"),t.push(" Branch name rules: lowercase, kebab-case, 2-5 words, prefix fix/feat/chore/docs."),t.push(" Describe the WORK done (not dates). Bad: agent/2026-04-16. Good: fix/bug-errors-visibility."),t.push(" 2. vibeflow tasks --edit <id> --set-status in-progress \u2190 CLAIM TASK"),t.push(" 3. <implement the change>")):(t.push(" \u26A0 IMMEDIATELY set in-progress BEFORE any implementation work:"),t.push(" 1. vibeflow tasks --edit <id> --set-status in-progress \u2190 DO THIS FIRST"),t.push(" (if you used --next: task is already in-progress \u2014 skip to step 2)"),t.push(" 2. <implement the change>")),e.requireVerifyBeforeReview)if(s){t.push(r?" 4. git add <files> (stage your changes first)":" 3. git add <files> (stage your changes first)"),t.push(` ${r?"5":"4"}. vibeflow verify <id> (verify the fix \u2014 check the evidences it produces)`),t.push(" If verification fails, set task back to in-progress and fix.");let u=["--set-status review"];s&&u.push('--commit-message "<one-line summary>"'),i&&u.push('--comment "<report>"'),t.push(` ${r?"6":"5"}. vibeflow tasks --edit <id> ${u.join(" ")}`),t.push(" CLI will commit staged changes and link the commit SHA automatically.")}else{t.push(r?' 4. git add <files> && vibeflow tasks --commit --task <id> --message "<one-line summary>"':' 3. git add <files> && vibeflow tasks --commit --task <id> --message "<one-line summary>"'),t.push(` ${r?"5":"4"}. vibeflow verify <id> (verify the fix \u2014 check the evidences it produces)`),t.push(" If verification fails, set task back to in-progress and fix.");let u=["--set-status review"];i&&u.push('--comment "<report>"'),t.push(` ${r?"6":"5"}. vibeflow tasks --edit <id> ${u.join(" ")}`)}else{if(s){t.push(r?" 4. git add <files> (stage your changes first)":" 3. git add <files> (stage your changes first)");let c=["--set-status review"];s&&c.push('--commit-message "<one-line summary>"'),i&&c.push('--comment "<report>"'),t.push(` ${r?"5":"4"}. vibeflow tasks --edit <id> ${c.join(" ")}`),t.push(" CLI will commit staged changes and link the commit SHA automatically.")}else{t.push(r?' 4. git add <files> && vibeflow tasks --commit --task <id> --message "<one-line summary>"':' 3. git add <files> && vibeflow tasks --commit --task <id> --message "<one-line summary>"');let c=["--set-status review"];i&&c.push('--comment "<report>"'),t.push(` ${r?"5":"4"}. vibeflow tasks --edit <id> ${c.join(" ")}`)}let u=r?"6":"5";t.push(` ${u}. vibeflow verify <id> (verify the fix \u2014 check the evidences it produces)`),t.push(" If verification fails, set task back to in-progress and fix.")}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."),r&&t.push(" [setting] Create branch ON: all work goes on a dedicated branch created before implementation."),e.requireVerifyBeforeReview&&t.push(" [setting] Verify gate ON: run vibeflow verify before setting status to review (skipped for tasks without URL/selector)."),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(" Create the report file locally first, then upload when marking as review:"),t.push(' vibeflow tasks --edit <id> --set-status review --report-file ./report.md --comment "..."'),t.push(" The file is saved next to the task and deleted from the original path automatically."),t.push(" Report must include: findings, options considered (with pros/cons), recommendation, sources.")),e.hasBugTasks&&(t.push(" Bug tasks: Reproduce the bug first, then include in the comment:"),t.push(" \xB7 Symptom: what the user sees"),t.push(" \xB7 Trigger: exact steps to reproduce"),t.push(" \xB7 Root cause: the specific code/logic that caused it"),t.push(" \xB7 Fix: what was changed and why it works"),t.push(" \xB7 Evidence: paste the relevant error message or stack trace")),t.push(" BLOCKED? If a task is unclear or missing context:"),t.push(' vibeflow tasks --edit <id> --comment "Blocked: <reason>. Need: <what is needed>."'),t.push(" Then pick the next task: vibeflow tasks --next"),t.push(" Do not guess at unclear requirements \u2014 leave a comment and move on."),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(`
8
+ `)}function X(e){let s=f(e);if(!l(s))return 0;let n=0;for(let i of d(s,{withFileTypes:!0})){if(i.isDirectory()||k(i.name)!==".json")continue;let r=a(s,i.name),t=g(r);if(!t)continue;let o=a(s,T(t.created)),u=a(o,i.name);r!==u&&(m(o,{recursive:!0}),$(u,JSON.stringify(t,null,2),"utf-8"),S(r),n++)}return n}export{p as a,v as b,b as c,h as d,j as e,F as f,f as g,q as h,P as i,w as j,x as k,W as l,g as m,z as n,M as o,J as p,U as q,G as r,Y as s,Q as t,X as u};