@vibeflow-tools/cli 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -0
- package/dist/chunk-GEQ64RVF.js +7 -0
- package/dist/chunk-IUZWZWMW.js +7 -0
- package/dist/chunk-NRMCK2HM.js +7 -0
- package/dist/chunk-PCPVP4ZD.js +7 -0
- package/dist/chunk-XO547RIH.js +7 -0
- package/dist/cli/chunk-GEQ64RVF.js +7 -0
- package/dist/cli/chunk-IUZWZWMW.js +7 -0
- package/dist/cli/chunk-NRMCK2HM.js +7 -0
- package/dist/cli/chunk-PCPVP4ZD.js +7 -0
- package/dist/cli/chunk-XO547RIH.js +7 -0
- package/dist/cli/files-GOVXPMB5.js +2 -0
- package/dist/cli/files-LTK2TDC2.js +2 -0
- package/dist/cli/files-MEEV7E6V.js +2 -0
- package/dist/cli/files-R6YCYMTI.js +2 -0
- package/dist/cli/files-SUCOSQAO.js +2 -0
- package/dist/cli/index.js +384 -197
- package/dist/client/kanban-browser.js +23 -12
- package/dist/client/kanban.css +1 -1
- package/dist/client/overlay-browser.js +5 -4
- package/dist/files-GOVXPMB5.js +2 -0
- package/dist/files-LTK2TDC2.js +2 -0
- package/dist/files-MEEV7E6V.js +2 -0
- package/dist/files-R6YCYMTI.js +2 -0
- package/dist/files-SUCOSQAO.js +2 -0
- package/dist/index.js +384 -197
- package/package.json +7 -2
- package/dist/chunk-252RNKHM.js +0 -2
- package/dist/chunk-43MUGU6Z.js +0 -67
- package/dist/chunk-4Y62J4KR.js +0 -438
- package/dist/chunk-6ABTC7IA.js +0 -482
- package/dist/chunk-7K2VHAWF.js +0 -569
- package/dist/chunk-BKTZSHJS.js +0 -2
- package/dist/chunk-BQLZVQ4E.js +0 -2
- package/dist/chunk-F57OXWVU.js +0 -33
- package/dist/chunk-I2OSZY66.js +0 -803
- package/dist/chunk-JKC6MUZ4.js +0 -558
- package/dist/chunk-KKBXVPTJ.js +0 -2
- package/dist/chunk-LK3IGDR6.js +0 -438
- package/dist/chunk-MKOKIWTN.js +0 -569
- package/dist/chunk-MW4OS3IK.js +0 -438
- package/dist/chunk-NRPOXSY6.js +0 -568
- package/dist/chunk-NUM3G22J.js +0 -569
- package/dist/chunk-O564QSMS.js +0 -569
- package/dist/chunk-OAGEPYIT.js +0 -535
- package/dist/chunk-PHBHAIHA.js +0 -33
- package/dist/chunk-PK737AKV.js +0 -560
- package/dist/chunk-TWAAPROG.js +0 -822
- package/dist/chunk-XF2CNPE4.js +0 -803
- package/dist/cli/chunk-252RNKHM.js +0 -2
- package/dist/cli/chunk-43MUGU6Z.js +0 -67
- package/dist/cli/chunk-4Y62J4KR.js +0 -438
- package/dist/cli/chunk-6ABTC7IA.js +0 -482
- package/dist/cli/chunk-7K2VHAWF.js +0 -569
- package/dist/cli/chunk-BKTZSHJS.js +0 -2
- package/dist/cli/chunk-BQLZVQ4E.js +0 -2
- package/dist/cli/chunk-F57OXWVU.js +0 -33
- package/dist/cli/chunk-I2OSZY66.js +0 -803
- package/dist/cli/chunk-JKC6MUZ4.js +0 -558
- package/dist/cli/chunk-KKBXVPTJ.js +0 -2
- package/dist/cli/chunk-LK3IGDR6.js +0 -438
- package/dist/cli/chunk-MKOKIWTN.js +0 -569
- package/dist/cli/chunk-MW4OS3IK.js +0 -438
- package/dist/cli/chunk-NRPOXSY6.js +0 -568
- package/dist/cli/chunk-NUM3G22J.js +0 -569
- package/dist/cli/chunk-O564QSMS.js +0 -569
- package/dist/cli/chunk-OAGEPYIT.js +0 -535
- package/dist/cli/chunk-PHBHAIHA.js +0 -33
- package/dist/cli/chunk-PK737AKV.js +0 -560
- package/dist/cli/chunk-TWAAPROG.js +0 -822
- package/dist/cli/chunk-XF2CNPE4.js +0 -803
- package/dist/cli/files-27OYPA7W.js +0 -20
- package/dist/cli/files-2TK74THO.js +0 -22
- package/dist/cli/files-3RDDXUOS.js +0 -2
- package/dist/cli/files-7275M2PW.js +0 -20
- package/dist/cli/files-D3YPV7QT.js +0 -20
- package/dist/cli/files-FER4UZ4X.js +0 -22
- package/dist/cli/files-H4FRDKJV.js +0 -22
- package/dist/cli/files-IJZVMROA.js +0 -22
- package/dist/cli/files-IX5QZQHC.js +0 -2
- package/dist/cli/files-KH3UEFN7.js +0 -20
- package/dist/cli/files-LTDT5ZFT.js +0 -22
- package/dist/cli/files-O4WJLFMU.js +0 -2
- package/dist/cli/files-OYO6A6MZ.js +0 -22
- package/dist/cli/files-R6QHQBH4.js +0 -22
- package/dist/cli/files-UCALOYWZ.js +0 -22
- package/dist/cli/files-UWZP7P6B.js +0 -2
- package/dist/cli/files-VIDLQM7Y.js +0 -20
- package/dist/cli/files-X2RDLF3W.js +0 -22
- package/dist/cli/files-XVDNOAZB.js +0 -22
- package/dist/cli/workspace-NB6BACZA.js +0 -12
- package/dist/cli/workspace-X2NGGGTQ.js +0 -12
- package/dist/cli/workspace-X4QXECQQ.js +0 -12
- package/dist/files-27OYPA7W.js +0 -20
- package/dist/files-2TK74THO.js +0 -22
- package/dist/files-3RDDXUOS.js +0 -2
- package/dist/files-7275M2PW.js +0 -20
- package/dist/files-D3YPV7QT.js +0 -20
- package/dist/files-FER4UZ4X.js +0 -22
- package/dist/files-H4FRDKJV.js +0 -22
- package/dist/files-IJZVMROA.js +0 -22
- package/dist/files-IX5QZQHC.js +0 -2
- package/dist/files-KH3UEFN7.js +0 -20
- package/dist/files-LTDT5ZFT.js +0 -22
- package/dist/files-O4WJLFMU.js +0 -2
- package/dist/files-OYO6A6MZ.js +0 -22
- package/dist/files-R6QHQBH4.js +0 -22
- package/dist/files-UCALOYWZ.js +0 -22
- package/dist/files-UWZP7P6B.js +0 -2
- package/dist/files-VIDLQM7Y.js +0 -20
- package/dist/files-X2RDLF3W.js +0 -22
- package/dist/files-XVDNOAZB.js +0 -22
- package/dist/workspace-NB6BACZA.js +0 -12
- package/dist/workspace-X2NGGGTQ.js +0 -12
- package/dist/workspace-X4QXECQQ.js +0 -12
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibeflow-tools/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Vibeflow CLI for frontend prototyping with LLM assistance — review, annotate, and iterate on HTML prototypes",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
|
-
"author": "Tomislav Zorcec <
|
|
6
|
+
"author": "Tomislav Zorcec <vibeflow.tools@gmail.com>",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"engines": {
|
|
9
9
|
"node": ">=22"
|
|
@@ -34,6 +34,8 @@
|
|
|
34
34
|
"test:coverage": "vitest run --coverage",
|
|
35
35
|
"test:e2e": "vitest run --config vitest.e2e.config.ts",
|
|
36
36
|
"test:browser": "vitest run --config vitest.pw.config.ts",
|
|
37
|
+
"mutation": "stryker run",
|
|
38
|
+
"mutation:ci": "stryker run --thresholds.break 60",
|
|
37
39
|
"lint": "tsc --noEmit",
|
|
38
40
|
"prepublishOnly": "npm run build",
|
|
39
41
|
"serve:designs": "node dist/cli/index.js serve ../../docs/ --port 3701"
|
|
@@ -73,6 +75,9 @@
|
|
|
73
75
|
},
|
|
74
76
|
"devDependencies": {
|
|
75
77
|
"@playwright/test": "^1.58.2",
|
|
78
|
+
"@stryker-mutator/core": "^9.6.1",
|
|
79
|
+
"@stryker-mutator/typescript-checker": "^9.6.1",
|
|
80
|
+
"@stryker-mutator/vitest-runner": "^9.6.1",
|
|
76
81
|
"@types/express": "^5.0.0",
|
|
77
82
|
"@types/node": "^22.0.0",
|
|
78
83
|
"@types/react": "^18.3.28",
|
package/dist/chunk-252RNKHM.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import{readdirSync as H,writeFileSync as K,readFileSync as M,unlinkSync as x,statSync as R,mkdirSync as G,existsSync as c}from"fs";import{join as f,basename as A}from"path";var d=".vibeflow",D="tasks",k="tasks/files",P="tasks/screenshots",Z="config.json";import{existsSync as m,readFileSync as N,writeFileSync as z,mkdirSync as p,readdirSync as y,unlinkSync as v,renameSync as b}from"fs";import{join as l,extname as O}from"path";import{randomBytes as V}from"crypto";var B=["backlog","todo","in-progress","review","done"];function W(){return V(15).toString("hex")}function h(t){return l(t,d,D)}function U(t){let n=l(t,d),e=l(n,"files"),i=l(n,k),s=l(n,"screenshots"),r=l(n,P);if(m(e)){p(i,{recursive:!0});for(let o of y(e)){let a=l(e,o),u=l(i,o);if(!m(u))try{b(a,u)}catch{}}}if(m(s)){p(r,{recursive:!0});for(let o of y(s)){let a=l(s,o),u=l(r,o);if(!m(u))try{b(a,u)}catch{}}}}function rt(t){U(t),p(h(t),{recursive:!0}),p(l(t,d,P),{recursive:!0})}function E(t){return t.slice(0,10)}function j(t,n,e){let i=h(t);return e?l(i,E(e),`${n}.json`):l(i,`${n}.json`)}function T(t,n){let e=h(t);if(!m(e))return null;for(let i of y(e,{withFileTypes:!0}))if(i.isDirectory()){let s=l(e,i.name,`${n}.json`);if(m(s))return s}else if(i.name===`${n}.json`)return l(e,i.name);return null}function J(t){let n=(()=>{if(typeof t.type!="string")return;let e=t.type.trim();if(!(!e||e==="[object Object]"))return e})();return{id:String(t.id??""),title:String(t.title??"Untitled"),description:String(t.description??""),status:B.includes(t.status)?t.status:"todo",url:t.url?String(t.url):void 0,selector:(()=>{let e=String(t.selector??"/");return t.file&&!t.cssSelector&&e.startsWith(String(t.file))?t.url?String(t.url):"/":e})(),cssSelector:t.cssSelector&&String(t.cssSelector)!==String(t.selector??"/")?String(t.cssSelector):void 0,file:t.file?String(t.file):void 0,line:t.line!=null?Number(t.line):void 0,col:t.col!=null?Number(t.col):void 0,component:t.component?String(t.component):void 0,type:n,priority:t.priority?String(t.priority):void 0,...t.reportBack===!0&&{reportBack:!0},agent:t.agent?String(t.agent):void 0,model:t.model?String(t.model):void 0,author:t.author?String(t.author):void 0,commits:Array.isArray(t.commits)?t.commits.map(e=>({sha:String(e.sha??""),message:String(e.message??""),timestamp:String(e.timestamp??new Date().toISOString())})):void 0,created:String(t.created??new Date().toISOString()),updated:t.updated?String(t.updated):void 0,comments:Array.isArray(t.comments)?t.comments.map(e=>({...e,text:e.text??e.content??""})):[],files:Array.isArray(t.files)?t.files.map(e=>typeof e=="string"?{name:e,addedAt:new Date().toISOString()}:{name:String(e.name??""),addedAt:String(e.addedAt??new Date().toISOString()),linkedPath:e.linkedPath?String(e.linkedPath):void 0,mimeType:e.mimeType?String(e.mimeType):void 0}).filter(e=>e.name):[],screenshot:t.screenshot?String(t.screenshot):void 0,annotatedElementText:t.annotatedElementText?String(t.annotatedElementText):void 0,tags:Array.isArray(t.tags)?t.tags.filter(e=>typeof e=="string"&&e.length>0):void 0}}function _(t,n){let e=l(h(t),E(n.created));p(e,{recursive:!0});let i=l(e,`${n.id}.json`),s=i+".tmp";z(s,JSON.stringify(n,null,2),"utf-8"),b(s,i)}function st(t,n){let e=(()=>{let s=(n.priority??"").trim().toLowerCase();return s==="critical"?"Critical":s==="high"?"High":s==="low"?"Low":"Medium"})(),i={...n,priority:e,id:W(),created:new Date().toISOString(),comments:[],files:[]};return _(t,i),i}function S(t){try{let n=N(t,"utf-8");if(t.endsWith(".json")){let e=JSON.parse(n);return!e||typeof e!="object"||!("id"in e)?null:J(e)}return null}catch{return null}}function $(t){let n=h(t);if(!m(n))return[];let e=[];for(let i of y(n,{withFileTypes:!0}))if(i.isDirectory()){let s=l(n,i.name);for(let r of y(s))if(O(r)===".json"){let o=l(s,r),a=S(o);a&&e.push({task:a,filePath:o})}}else if(O(i.name)===".json"){let s=l(n,i.name),r=S(s);r&&e.push({task:r,filePath:s})}return e}function ot(t){return $(t).map(({task:n})=>n)}function at(t){return $(t).map(({task:n,filePath:e})=>({...n,filePath:e}))}function L(t,n,e){let i=T(t,n),s=i?S(i):null;if(!s)return null;let r={...s,...e,updated:new Date().toISOString()};if(_(t,r),i&&i!==j(t,n,r.created))try{v(i)}catch{}return r}function lt(t,n){let e=T(t,n);return e?(v(e),!0):!1}function ut(t,n,e){return{id:t.id,status:t.status,title:t.title,description:t.description,...t.url&&{url:t.url},selector:t.selector,...t.file&&{file:t.file},...t.line!=null&&{line:t.line},...t.col!=null&&{col:t.col},...t.component&&{component:t.component},...t.type&&{type:t.type},...t.priority&&{priority:t.priority},...n&&n.length>0&&{structuredComments:n},...e&&e.length>0&&{linkedFiles:e},...t.reportBack&&{reportBack:!0},created:t.created}}var C=".linked.json";function g(t,n){return f(t,d,k,n)}function q(t,n){G(g(t,n),{recursive:!0})}function Q(t,n){let e=f(g(t,n),C);if(!c(e))return[];try{return JSON.parse(M(e,"utf-8"))}catch{return[]}}function X(t,n){let e=T(t,n),i=e?S(e):null;return!i?.files||i.files.length===0?[]:i.files}function I(t,n,e){L(t,n,{files:e})}function F(t,n){let e=X(t,n),i=f(g(t,n),C);if(!c(i))return e;let s=Q(t,n);if(s.length===0){try{x(i)}catch{}return e}let r=e.slice(),o=!1;for(let a of s)r.find(u=>u.linkedPath===a.path||u.name===a.name&&u.linkedPath)||(r.push({name:a.name,linkedPath:a.path,addedAt:new Date().toISOString()}),o=!0);o&&I(t,n,r);try{x(i)}catch{}return r}function Y(t,n){let e=g(t,n),i=F(t,n),s=new Map;for(let r of i){if(r.linkedPath&&c(r.linkedPath)){let a=R(r.linkedPath);s.set(r.name,{name:r.name,size:a.size,url:`/api/tasks/${n}/files/${encodeURIComponent(r.name)}`,linkedPath:r.linkedPath,createdAt:a.mtime.toISOString()});continue}let o=f(e,r.name);if(c(o)){let a=R(o);s.set(r.name,{name:r.name,size:a.size,url:`/api/tasks/${n}/files/${encodeURIComponent(r.name)}`,createdAt:a.mtime.toISOString()})}}if(c(e))for(let r of H(e,{withFileTypes:!0})){if(!r.isFile()||r.name===C||s.has(r.name))continue;let o=f(e,r.name),a=R(o);s.set(r.name,{name:r.name,size:a.size,url:`/api/tasks/${n}/files/${encodeURIComponent(r.name)}`,createdAt:a.mtime.toISOString()})}return Array.from(s.values())}function yt(t,n,e,i){let s=A(e);q(t,n),K(f(g(t,n),s),i);let r=F(t,n);return r.find(o=>o.name===s&&!o.linkedPath)||(r.push({name:s,addedAt:new Date().toISOString()}),I(t,n,r)),{name:s,size:i.length,url:`/api/tasks/${n}/files/${encodeURIComponent(s)}`}}function St(t,n,e){let i=A(e),s=F(t,n),r=s.findIndex(a=>a.name===i);if(r!==-1){let[a]=s.splice(r,1);if(I(t,n,s),a&&!a.linkedPath){let u=f(g(t,n),i);c(u)&&x(u)}return!0}let o=f(g(t,n),i);return c(o)?(x(o),!0):!1}function ht(t,n,e){let i=A(e),s=F(t,n).find(o=>o.name===i&&o.linkedPath);if(s?.linkedPath&&c(s.linkedPath))return s.linkedPath;let r=f(g(t,n),i);return c(r)?r:null}function kt(t,n){return Y(t,n).length}export{d as a,D as b,P as c,Z as d,W as e,rt as f,j as g,T as h,st as i,S as j,ot as k,at as l,L as m,lt as n,ut as o,g as p,q,Y as r,yt as s,St as t,ht as u,kt as v};
|
package/dist/chunk-43MUGU6Z.js
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
var __create = Object.create;
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
9
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
10
|
-
}) : x)(function(x) {
|
|
11
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
12
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
13
|
-
});
|
|
14
|
-
var __commonJS = (cb, mod) => function __require2() {
|
|
15
|
-
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
16
|
-
};
|
|
17
|
-
var __copyProps = (to, from, except, desc) => {
|
|
18
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
19
|
-
for (let key of __getOwnPropNames(from))
|
|
20
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
21
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
22
|
-
}
|
|
23
|
-
return to;
|
|
24
|
-
};
|
|
25
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
26
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
27
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
28
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
29
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
30
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
31
|
-
mod
|
|
32
|
-
));
|
|
33
|
-
|
|
34
|
-
// src/auth/workspace.ts
|
|
35
|
-
import fs from "fs/promises";
|
|
36
|
-
import os from "os";
|
|
37
|
-
import path from "path";
|
|
38
|
-
var SPOTA_DIR = path.join(os.homedir(), ".spota");
|
|
39
|
-
var WORKSPACE_PATH = path.join(SPOTA_DIR, "workspace");
|
|
40
|
-
async function readWorkspace() {
|
|
41
|
-
try {
|
|
42
|
-
const content = await fs.readFile(WORKSPACE_PATH, "utf8");
|
|
43
|
-
return JSON.parse(content);
|
|
44
|
-
} catch {
|
|
45
|
-
return null;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
async function writeWorkspace(workspace) {
|
|
49
|
-
await fs.mkdir(SPOTA_DIR, { recursive: true });
|
|
50
|
-
await fs.writeFile(WORKSPACE_PATH, JSON.stringify(workspace, null, 2), { mode: 384 });
|
|
51
|
-
}
|
|
52
|
-
async function deleteWorkspace() {
|
|
53
|
-
try {
|
|
54
|
-
await fs.unlink(WORKSPACE_PATH);
|
|
55
|
-
} catch {
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export {
|
|
60
|
-
__require,
|
|
61
|
-
__commonJS,
|
|
62
|
-
__toESM,
|
|
63
|
-
readWorkspace,
|
|
64
|
-
writeWorkspace,
|
|
65
|
-
deleteWorkspace
|
|
66
|
-
};
|
|
67
|
-
//# sourceMappingURL=chunk-43MUGU6Z.js.map
|
package/dist/chunk-4Y62J4KR.js
DELETED
|
@@ -1,438 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// src/core/files.ts
|
|
4
|
-
import {
|
|
5
|
-
readdirSync as readdirSync2,
|
|
6
|
-
writeFileSync as writeFileSync2,
|
|
7
|
-
readFileSync as readFileSync2,
|
|
8
|
-
unlinkSync as unlinkSync2,
|
|
9
|
-
statSync,
|
|
10
|
-
mkdirSync as mkdirSync2,
|
|
11
|
-
existsSync as existsSync2
|
|
12
|
-
} from "fs";
|
|
13
|
-
import { join as join2, basename } from "path";
|
|
14
|
-
|
|
15
|
-
// src/core/types.ts
|
|
16
|
-
var PROTO_DIR = ".vibeflow";
|
|
17
|
-
var TASKS_DIR = "tasks";
|
|
18
|
-
var FILES_DIR = "tasks/files";
|
|
19
|
-
var SCREENSHOTS_DIR = "tasks/screenshots";
|
|
20
|
-
var CONFIG_FILE = "config.json";
|
|
21
|
-
|
|
22
|
-
// src/core/tasks.ts
|
|
23
|
-
import {
|
|
24
|
-
existsSync,
|
|
25
|
-
readFileSync,
|
|
26
|
-
writeFileSync,
|
|
27
|
-
mkdirSync,
|
|
28
|
-
readdirSync,
|
|
29
|
-
unlinkSync,
|
|
30
|
-
renameSync
|
|
31
|
-
} from "fs";
|
|
32
|
-
import { join, extname } from "path";
|
|
33
|
-
import { randomBytes } from "crypto";
|
|
34
|
-
var VALID_STATUSES = ["backlog", "todo", "in-progress", "review", "done"];
|
|
35
|
-
function generateTaskId() {
|
|
36
|
-
return randomBytes(15).toString("hex");
|
|
37
|
-
}
|
|
38
|
-
function getTasksDir(projectDir) {
|
|
39
|
-
return join(projectDir, PROTO_DIR, TASKS_DIR);
|
|
40
|
-
}
|
|
41
|
-
function migrateLegacyTaskAssetFolders(projectDir) {
|
|
42
|
-
const protoRoot = join(projectDir, PROTO_DIR);
|
|
43
|
-
const legacyFilesDir = join(protoRoot, "files");
|
|
44
|
-
const nextFilesDir = join(protoRoot, FILES_DIR);
|
|
45
|
-
const legacyScreenshotsDir = join(protoRoot, "screenshots");
|
|
46
|
-
const nextScreenshotsDir = join(protoRoot, SCREENSHOTS_DIR);
|
|
47
|
-
if (existsSync(legacyFilesDir)) {
|
|
48
|
-
mkdirSync(nextFilesDir, { recursive: true });
|
|
49
|
-
for (const entry of readdirSync(legacyFilesDir)) {
|
|
50
|
-
const from = join(legacyFilesDir, entry);
|
|
51
|
-
const to = join(nextFilesDir, entry);
|
|
52
|
-
if (existsSync(to)) continue;
|
|
53
|
-
try {
|
|
54
|
-
renameSync(from, to);
|
|
55
|
-
} catch {
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
if (existsSync(legacyScreenshotsDir)) {
|
|
60
|
-
mkdirSync(nextScreenshotsDir, { recursive: true });
|
|
61
|
-
for (const entry of readdirSync(legacyScreenshotsDir)) {
|
|
62
|
-
const from = join(legacyScreenshotsDir, entry);
|
|
63
|
-
const to = join(nextScreenshotsDir, entry);
|
|
64
|
-
if (existsSync(to)) continue;
|
|
65
|
-
try {
|
|
66
|
-
renameSync(from, to);
|
|
67
|
-
} catch {
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
function ensureTaskDirs(projectDir) {
|
|
73
|
-
migrateLegacyTaskAssetFolders(projectDir);
|
|
74
|
-
mkdirSync(getTasksDir(projectDir), { recursive: true });
|
|
75
|
-
mkdirSync(join(projectDir, PROTO_DIR, SCREENSHOTS_DIR), { recursive: true });
|
|
76
|
-
}
|
|
77
|
-
function getDateSubdir(isoDate) {
|
|
78
|
-
return isoDate.slice(0, 10);
|
|
79
|
-
}
|
|
80
|
-
function getTaskFilePath(projectDir, taskId, created) {
|
|
81
|
-
const tasksDir = getTasksDir(projectDir);
|
|
82
|
-
if (created) {
|
|
83
|
-
return join(tasksDir, getDateSubdir(created), `${taskId}.json`);
|
|
84
|
-
}
|
|
85
|
-
return join(tasksDir, `${taskId}.json`);
|
|
86
|
-
}
|
|
87
|
-
function findTaskFilePath(projectDir, taskId) {
|
|
88
|
-
const tasksDir = getTasksDir(projectDir);
|
|
89
|
-
if (!existsSync(tasksDir)) return null;
|
|
90
|
-
for (const entry of readdirSync(tasksDir, { withFileTypes: true })) {
|
|
91
|
-
if (entry.isDirectory()) {
|
|
92
|
-
const candidate = join(tasksDir, entry.name, `${taskId}.json`);
|
|
93
|
-
if (existsSync(candidate)) return candidate;
|
|
94
|
-
} else if (entry.name === `${taskId}.json`) {
|
|
95
|
-
return join(tasksDir, entry.name);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
return null;
|
|
99
|
-
}
|
|
100
|
-
function normalizeTask(raw) {
|
|
101
|
-
const normalizedType = (() => {
|
|
102
|
-
if (typeof raw.type !== "string") return void 0;
|
|
103
|
-
const t = raw.type.trim();
|
|
104
|
-
if (!t || t === "[object Object]") return void 0;
|
|
105
|
-
return t;
|
|
106
|
-
})();
|
|
107
|
-
return {
|
|
108
|
-
id: String(raw.id ?? ""),
|
|
109
|
-
title: String(raw.title ?? "Untitled"),
|
|
110
|
-
description: String(raw.description ?? ""),
|
|
111
|
-
status: VALID_STATUSES.includes(raw.status) ? raw.status : "todo",
|
|
112
|
-
url: raw.url ? String(raw.url) : void 0,
|
|
113
|
-
selector: (() => {
|
|
114
|
-
const sel = String(raw.selector ?? "/");
|
|
115
|
-
if (raw.file && !raw.cssSelector && sel.startsWith(String(raw.file))) {
|
|
116
|
-
return raw.url ? String(raw.url) : "/";
|
|
117
|
-
}
|
|
118
|
-
return sel;
|
|
119
|
-
})(),
|
|
120
|
-
cssSelector: raw.cssSelector && String(raw.cssSelector) !== String(raw.selector ?? "/") ? String(raw.cssSelector) : void 0,
|
|
121
|
-
file: raw.file ? String(raw.file) : void 0,
|
|
122
|
-
line: raw.line != null ? Number(raw.line) : void 0,
|
|
123
|
-
col: raw.col != null ? Number(raw.col) : void 0,
|
|
124
|
-
component: raw.component ? String(raw.component) : void 0,
|
|
125
|
-
type: normalizedType,
|
|
126
|
-
priority: raw.priority ? String(raw.priority) : void 0,
|
|
127
|
-
...raw.reportBack === true && { reportBack: true },
|
|
128
|
-
agent: raw.agent ? String(raw.agent) : void 0,
|
|
129
|
-
model: raw.model ? String(raw.model) : void 0,
|
|
130
|
-
author: raw.author ? String(raw.author) : void 0,
|
|
131
|
-
commit: raw.commit ? String(raw.commit) : void 0,
|
|
132
|
-
commits: Array.isArray(raw.commits) ? raw.commits.map((c) => ({
|
|
133
|
-
sha: String(c.sha ?? ""),
|
|
134
|
-
message: String(c.message ?? ""),
|
|
135
|
-
timestamp: String(c.timestamp ?? (/* @__PURE__ */ new Date()).toISOString())
|
|
136
|
-
})) : void 0,
|
|
137
|
-
created: String(raw.created ?? (/* @__PURE__ */ new Date()).toISOString()),
|
|
138
|
-
updated: raw.updated ? String(raw.updated) : void 0,
|
|
139
|
-
comments: Array.isArray(raw.comments) ? raw.comments.map((c) => ({
|
|
140
|
-
...c,
|
|
141
|
-
// Normalize legacy 'content' field → 'text' (some older agent comments used 'content')
|
|
142
|
-
text: c.text ?? c.content ?? ""
|
|
143
|
-
})) : [],
|
|
144
|
-
files: Array.isArray(raw.files) ? raw.files.map((f) => {
|
|
145
|
-
if (typeof f === "string") {
|
|
146
|
-
return { name: f, addedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
147
|
-
}
|
|
148
|
-
return {
|
|
149
|
-
name: String(f.name ?? ""),
|
|
150
|
-
addedAt: String(f.addedAt ?? (/* @__PURE__ */ new Date()).toISOString()),
|
|
151
|
-
linkedPath: f.linkedPath ? String(f.linkedPath) : void 0,
|
|
152
|
-
mimeType: f.mimeType ? String(f.mimeType) : void 0
|
|
153
|
-
};
|
|
154
|
-
}).filter((f) => f.name) : [],
|
|
155
|
-
screenshot: raw.screenshot ? String(raw.screenshot) : void 0,
|
|
156
|
-
annotatedElementText: raw.annotatedElementText ? String(raw.annotatedElementText) : void 0
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
function writeTaskJson(projectDir, task) {
|
|
160
|
-
const dateDir = join(getTasksDir(projectDir), getDateSubdir(task.created));
|
|
161
|
-
mkdirSync(dateDir, { recursive: true });
|
|
162
|
-
const filePath = join(dateDir, `${task.id}.json`);
|
|
163
|
-
writeFileSync(filePath, JSON.stringify(task, null, 2), "utf-8");
|
|
164
|
-
}
|
|
165
|
-
function createTask(projectDir, input) {
|
|
166
|
-
const normalizedPriority = (() => {
|
|
167
|
-
const raw = (input.priority ?? "").trim().toLowerCase();
|
|
168
|
-
if (raw === "critical") return "Critical";
|
|
169
|
-
if (raw === "high") return "High";
|
|
170
|
-
if (raw === "low") return "Low";
|
|
171
|
-
return "Medium";
|
|
172
|
-
})();
|
|
173
|
-
const task = {
|
|
174
|
-
...input,
|
|
175
|
-
priority: normalizedPriority,
|
|
176
|
-
id: generateTaskId(),
|
|
177
|
-
created: (/* @__PURE__ */ new Date()).toISOString(),
|
|
178
|
-
comments: [],
|
|
179
|
-
files: []
|
|
180
|
-
};
|
|
181
|
-
writeTaskJson(projectDir, task);
|
|
182
|
-
return task;
|
|
183
|
-
}
|
|
184
|
-
function readTaskFile(filePath) {
|
|
185
|
-
try {
|
|
186
|
-
const content = readFileSync(filePath, "utf-8");
|
|
187
|
-
if (filePath.endsWith(".json")) {
|
|
188
|
-
const raw = JSON.parse(content);
|
|
189
|
-
if (!raw || typeof raw !== "object" || !("id" in raw)) return null;
|
|
190
|
-
return normalizeTask(raw);
|
|
191
|
-
}
|
|
192
|
-
return null;
|
|
193
|
-
} catch {
|
|
194
|
-
return null;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
function collectTaskFiles(projectDir) {
|
|
198
|
-
const tasksDir = getTasksDir(projectDir);
|
|
199
|
-
if (!existsSync(tasksDir)) return [];
|
|
200
|
-
const results = [];
|
|
201
|
-
for (const entry of readdirSync(tasksDir, { withFileTypes: true })) {
|
|
202
|
-
if (entry.isDirectory()) {
|
|
203
|
-
const dateDir = join(tasksDir, entry.name);
|
|
204
|
-
for (const file of readdirSync(dateDir)) {
|
|
205
|
-
if (extname(file) === ".json") {
|
|
206
|
-
const filePath = join(dateDir, file);
|
|
207
|
-
const task = readTaskFile(filePath);
|
|
208
|
-
if (task) results.push({ task, filePath });
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
} else if (extname(entry.name) === ".json") {
|
|
212
|
-
const filePath = join(tasksDir, entry.name);
|
|
213
|
-
const task = readTaskFile(filePath);
|
|
214
|
-
if (task) results.push({ task, filePath });
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
return results.sort((a, b) => {
|
|
218
|
-
const aDate = a.task.updated ?? a.task.created;
|
|
219
|
-
const bDate = b.task.updated ?? b.task.created;
|
|
220
|
-
return new Date(bDate).getTime() - new Date(aDate).getTime();
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
function listTasks(projectDir) {
|
|
224
|
-
return collectTaskFiles(projectDir).map(({ task }) => task);
|
|
225
|
-
}
|
|
226
|
-
function listTasksWithPaths(projectDir) {
|
|
227
|
-
return collectTaskFiles(projectDir).map(({ task, filePath }) => ({ ...task, filePath }));
|
|
228
|
-
}
|
|
229
|
-
function updateTask(projectDir, taskId, updates) {
|
|
230
|
-
const existingPath = findTaskFilePath(projectDir, taskId);
|
|
231
|
-
const task = existingPath ? readTaskFile(existingPath) : null;
|
|
232
|
-
if (!task) return null;
|
|
233
|
-
const updated = { ...task, ...updates, updated: (/* @__PURE__ */ new Date()).toISOString() };
|
|
234
|
-
writeTaskJson(projectDir, updated);
|
|
235
|
-
if (existingPath && existingPath !== getTaskFilePath(projectDir, taskId, updated.created)) {
|
|
236
|
-
try {
|
|
237
|
-
unlinkSync(existingPath);
|
|
238
|
-
} catch {
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
return updated;
|
|
242
|
-
}
|
|
243
|
-
function deleteTask(projectDir, taskId) {
|
|
244
|
-
const filePath = findTaskFilePath(projectDir, taskId);
|
|
245
|
-
if (!filePath) return false;
|
|
246
|
-
unlinkSync(filePath);
|
|
247
|
-
return true;
|
|
248
|
-
}
|
|
249
|
-
function formatTaskForAgent(task, comments, files) {
|
|
250
|
-
return {
|
|
251
|
-
id: task.id,
|
|
252
|
-
status: task.status,
|
|
253
|
-
title: task.title,
|
|
254
|
-
description: task.description,
|
|
255
|
-
...task.url && { url: task.url },
|
|
256
|
-
selector: task.selector,
|
|
257
|
-
...task.file && { file: task.file },
|
|
258
|
-
...task.line != null && { line: task.line },
|
|
259
|
-
...task.col != null && { col: task.col },
|
|
260
|
-
...task.component && { component: task.component },
|
|
261
|
-
...task.type && { type: task.type },
|
|
262
|
-
...task.priority && { priority: task.priority },
|
|
263
|
-
...comments && comments.length > 0 && { structuredComments: comments },
|
|
264
|
-
...files && files.length > 0 && { linkedFiles: files },
|
|
265
|
-
...task.reportBack && { reportBack: true },
|
|
266
|
-
created: task.created
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// src/core/files.ts
|
|
271
|
-
var LINKED_MANIFEST = ".linked.json";
|
|
272
|
-
function getFilesDir(projectDir, taskId) {
|
|
273
|
-
return join2(projectDir, PROTO_DIR, FILES_DIR, taskId);
|
|
274
|
-
}
|
|
275
|
-
function ensureFilesDir(projectDir, taskId) {
|
|
276
|
-
mkdirSync2(getFilesDir(projectDir, taskId), { recursive: true });
|
|
277
|
-
}
|
|
278
|
-
function readLinked(projectDir, taskId) {
|
|
279
|
-
const manifestPath = join2(getFilesDir(projectDir, taskId), LINKED_MANIFEST);
|
|
280
|
-
if (!existsSync2(manifestPath)) return [];
|
|
281
|
-
try {
|
|
282
|
-
return JSON.parse(readFileSync2(manifestPath, "utf-8"));
|
|
283
|
-
} catch {
|
|
284
|
-
return [];
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
function getTaskFileRefs(projectDir, taskId) {
|
|
288
|
-
const filePath = findTaskFilePath(projectDir, taskId);
|
|
289
|
-
const task = filePath ? readTaskFile(filePath) : null;
|
|
290
|
-
if (!task?.files || task.files.length === 0) return [];
|
|
291
|
-
return task.files;
|
|
292
|
-
}
|
|
293
|
-
function setTaskFileRefs(projectDir, taskId, refs) {
|
|
294
|
-
updateTask(projectDir, taskId, { files: refs });
|
|
295
|
-
}
|
|
296
|
-
function migrateLegacyLinkedRefs(projectDir, taskId) {
|
|
297
|
-
const refs = getTaskFileRefs(projectDir, taskId);
|
|
298
|
-
const manifestPath = join2(getFilesDir(projectDir, taskId), LINKED_MANIFEST);
|
|
299
|
-
if (!existsSync2(manifestPath)) return refs;
|
|
300
|
-
const legacy = readLinked(projectDir, taskId);
|
|
301
|
-
if (legacy.length === 0) {
|
|
302
|
-
try {
|
|
303
|
-
unlinkSync2(manifestPath);
|
|
304
|
-
} catch {
|
|
305
|
-
}
|
|
306
|
-
return refs;
|
|
307
|
-
}
|
|
308
|
-
const next = refs.slice();
|
|
309
|
-
let added = false;
|
|
310
|
-
for (const entry of legacy) {
|
|
311
|
-
if (!next.find((f) => f.linkedPath === entry.path || f.name === entry.name && f.linkedPath)) {
|
|
312
|
-
next.push({
|
|
313
|
-
name: entry.name,
|
|
314
|
-
linkedPath: entry.path,
|
|
315
|
-
addedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
316
|
-
});
|
|
317
|
-
added = true;
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
if (added) {
|
|
321
|
-
setTaskFileRefs(projectDir, taskId, next);
|
|
322
|
-
}
|
|
323
|
-
try {
|
|
324
|
-
unlinkSync2(manifestPath);
|
|
325
|
-
} catch {
|
|
326
|
-
}
|
|
327
|
-
return next;
|
|
328
|
-
}
|
|
329
|
-
function listFiles(projectDir, taskId) {
|
|
330
|
-
const dir = getFilesDir(projectDir, taskId);
|
|
331
|
-
const refs = migrateLegacyLinkedRefs(projectDir, taskId);
|
|
332
|
-
const byName = /* @__PURE__ */ new Map();
|
|
333
|
-
for (const ref of refs) {
|
|
334
|
-
if (ref.linkedPath && existsSync2(ref.linkedPath)) {
|
|
335
|
-
const stat = statSync(ref.linkedPath);
|
|
336
|
-
byName.set(ref.name, {
|
|
337
|
-
name: ref.name,
|
|
338
|
-
size: stat.size,
|
|
339
|
-
url: `/api/tasks/${taskId}/files/${encodeURIComponent(ref.name)}`,
|
|
340
|
-
linkedPath: ref.linkedPath,
|
|
341
|
-
createdAt: stat.mtime.toISOString()
|
|
342
|
-
});
|
|
343
|
-
continue;
|
|
344
|
-
}
|
|
345
|
-
const uploadedPath = join2(dir, ref.name);
|
|
346
|
-
if (existsSync2(uploadedPath)) {
|
|
347
|
-
const stat = statSync(uploadedPath);
|
|
348
|
-
byName.set(ref.name, {
|
|
349
|
-
name: ref.name,
|
|
350
|
-
size: stat.size,
|
|
351
|
-
url: `/api/tasks/${taskId}/files/${encodeURIComponent(ref.name)}`,
|
|
352
|
-
createdAt: stat.mtime.toISOString()
|
|
353
|
-
});
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
if (existsSync2(dir)) {
|
|
357
|
-
for (const entry of readdirSync2(dir, { withFileTypes: true })) {
|
|
358
|
-
if (!entry.isFile() || entry.name === LINKED_MANIFEST || byName.has(entry.name)) continue;
|
|
359
|
-
const fullPath = join2(dir, entry.name);
|
|
360
|
-
const stat = statSync(fullPath);
|
|
361
|
-
byName.set(entry.name, {
|
|
362
|
-
name: entry.name,
|
|
363
|
-
size: stat.size,
|
|
364
|
-
url: `/api/tasks/${taskId}/files/${encodeURIComponent(entry.name)}`,
|
|
365
|
-
createdAt: stat.mtime.toISOString()
|
|
366
|
-
});
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
return Array.from(byName.values());
|
|
370
|
-
}
|
|
371
|
-
function saveFile(projectDir, taskId, filename, data) {
|
|
372
|
-
const safe = basename(filename);
|
|
373
|
-
ensureFilesDir(projectDir, taskId);
|
|
374
|
-
writeFileSync2(join2(getFilesDir(projectDir, taskId), safe), data);
|
|
375
|
-
const refs = migrateLegacyLinkedRefs(projectDir, taskId);
|
|
376
|
-
if (!refs.find((f) => f.name === safe && !f.linkedPath)) {
|
|
377
|
-
refs.push({ name: safe, addedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
378
|
-
setTaskFileRefs(projectDir, taskId, refs);
|
|
379
|
-
}
|
|
380
|
-
return {
|
|
381
|
-
name: safe,
|
|
382
|
-
size: data.length,
|
|
383
|
-
url: `/api/tasks/${taskId}/files/${encodeURIComponent(safe)}`
|
|
384
|
-
};
|
|
385
|
-
}
|
|
386
|
-
function deleteFile(projectDir, taskId, filename) {
|
|
387
|
-
const safe = basename(filename);
|
|
388
|
-
const refs = migrateLegacyLinkedRefs(projectDir, taskId);
|
|
389
|
-
const idx = refs.findIndex((f) => f.name === safe);
|
|
390
|
-
if (idx !== -1) {
|
|
391
|
-
const [removed] = refs.splice(idx, 1);
|
|
392
|
-
setTaskFileRefs(projectDir, taskId, refs);
|
|
393
|
-
if (removed && !removed.linkedPath) {
|
|
394
|
-
const uploadedPath = join2(getFilesDir(projectDir, taskId), safe);
|
|
395
|
-
if (existsSync2(uploadedPath)) unlinkSync2(uploadedPath);
|
|
396
|
-
}
|
|
397
|
-
return true;
|
|
398
|
-
}
|
|
399
|
-
const filePath = join2(getFilesDir(projectDir, taskId), safe);
|
|
400
|
-
if (!existsSync2(filePath)) return false;
|
|
401
|
-
unlinkSync2(filePath);
|
|
402
|
-
return true;
|
|
403
|
-
}
|
|
404
|
-
function getFilePath(projectDir, taskId, filename) {
|
|
405
|
-
const safe = basename(filename);
|
|
406
|
-
const linkedRef = migrateLegacyLinkedRefs(projectDir, taskId).find((f) => f.name === safe && f.linkedPath);
|
|
407
|
-
if (linkedRef?.linkedPath && existsSync2(linkedRef.linkedPath)) return linkedRef.linkedPath;
|
|
408
|
-
const filePath = join2(getFilesDir(projectDir, taskId), safe);
|
|
409
|
-
return existsSync2(filePath) ? filePath : null;
|
|
410
|
-
}
|
|
411
|
-
function getFileCount(projectDir, taskId) {
|
|
412
|
-
return listFiles(projectDir, taskId).length;
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
export {
|
|
416
|
-
PROTO_DIR,
|
|
417
|
-
SCREENSHOTS_DIR,
|
|
418
|
-
CONFIG_FILE,
|
|
419
|
-
generateTaskId,
|
|
420
|
-
ensureTaskDirs,
|
|
421
|
-
getTaskFilePath,
|
|
422
|
-
findTaskFilePath,
|
|
423
|
-
createTask,
|
|
424
|
-
readTaskFile,
|
|
425
|
-
listTasks,
|
|
426
|
-
listTasksWithPaths,
|
|
427
|
-
updateTask,
|
|
428
|
-
deleteTask,
|
|
429
|
-
formatTaskForAgent,
|
|
430
|
-
getFilesDir,
|
|
431
|
-
ensureFilesDir,
|
|
432
|
-
listFiles,
|
|
433
|
-
saveFile,
|
|
434
|
-
deleteFile,
|
|
435
|
-
getFilePath,
|
|
436
|
-
getFileCount
|
|
437
|
-
};
|
|
438
|
-
//# sourceMappingURL=chunk-4Y62J4KR.js.map
|