@kizenapps/cli 1.10.0 → 1.11.0-3670c77
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/dist/index.js +330 -32
- package/dist/index.js.map +1 -1
- package/dist/viewer/assets/CodeStepsPage-D_kTMpRO.js +1 -0
- package/dist/viewer/assets/{index-Du4zThGL.js → index-BF1Fk_v0.js} +2 -2
- package/dist/viewer/index.html +1 -1
- package/package.json +1 -1
- package/dist/viewer/assets/CodeStepsPage-CvCrJCQn.js +0 -1
package/dist/index.js
CHANGED
|
@@ -1,12 +1,310 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{readFileSync as
|
|
3
|
-
`).map(
|
|
4
|
-
`)?
|
|
2
|
+
import{readFileSync as Ya}from"fs";import{dirname as Xa,join as Za}from"path";import{fileURLToPath as Qa}from"url";import{Command as el}from"commander";import{createElement as ui}from"react";import{render as fi}from"ink";import{useEffect as vr,useState as Me}from"react";import{Box as ze,Text as Re,useApp as ci}from"ink";import{PluginValidationError as di}from"@kizenapps/packager";import{mkdir as zo,writeFile as Ho}from"fs/promises";import{join as Uo}from"path";import{PluginValidationError as Vo,minifyFiles as qo,packagePlugin as Jo,parseManifestFromFiles as Wo,transformDeployablePlugin as Ko,validatePluginApp as Go}from"@kizenapps/packager";import{readdir as Do,readFile as fr}from"fs/promises";import{join as mr,relative as Fo}from"path";var Oo=new Set([".png",".svg"]),jo=new Set([".kzn"]),$o=new Set([".DS_Store"]),tt=new Set(["node_modules",".git",".kizenapp",".github",".claude","__pycache__"]),Lo=8e3;function Mo(e){return e.subarray(0,Lo).includes(0)}async function gr(e,t){let n=await Do(e,{withFileTypes:!0}),o=[];for(let r of n)if(r.isDirectory()){if(tt.has(r.name))continue;o.push(...await gr(mr(e,r.name),t))}else r.isFile()&&($o.has(r.name)||o.push(mr(e,r.name)));return o}async function rt(e,{detectBinaryByContent:t=!1}={}){let n=await gr(e,e);return Promise.all(n.map(async o=>{let r=Fo(e,o).split("\\").join("/"),i=r.lastIndexOf("."),d=i>=0?r.slice(i).toLowerCase():"";if(Oo.has(d)){let g=await fr(o);return{path:r,content:"",base64Image:g.toString("base64")}}let f=await fr(o);return jo.has(d)||t&&Mo(f)?{path:r,content:"",binaryData:f}:{path:r,content:f.toString("utf-8")}}))}var Yo=(e,t)=>({...e,thumbnail:e.thumbnail?Buffer.from(e.thumbnail).toString("base64"):null,kznFile:e.kznFile?Buffer.from(e.kznFile).toString("base64"):null,allReleaseNotes:t});async function nt(e,t,n){await zo(t,{recursive:!0}),n?.("reading-files");let o=await rt(e);n?.("validating");let r=Go(o);if(r.some(x=>x.severity==="error"))throw new Vo(r);n?.("minifying");let i=await qo(o);n?.("packaging");let d=Wo(i),f=Jo(i,d),g=Object.values(f).map(Ko);n?.("writing-bundle");let m=g.map(x=>{let p=x.release_notes_directory?.replace(/\/$/,""),y=p?o.filter(S=>S.path.startsWith(p+"/")&&S.path.endsWith(".md")&&S.content).map(S=>({version:S.path.slice(S.path.lastIndexOf("/")+1,-3),notes:S.content})).sort((S,H)=>H.version.localeCompare(S.version,void 0,{numeric:!0})):[];return Yo(x,y)}),b=JSON.stringify(m,null,2),T=(x,p)=>x==="allReleaseNotes"?void 0:p,P=Buffer.byteLength(JSON.stringify(m,T,2),"utf-8");return await Ho(Uo(t,"bundle.json"),b,"utf-8"),{bundleSize:P}}function $e(e){return e<1024?`${String(e)} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(2)} MB`}import{Box as ei,Text as ti}from"ink";import{Box as Xo,Text as Zo}from"ink";import{jsx as hr}from"react/jsx-runtime";var Qo=[" :::::::: "," :::::: ::::::::::: "," :::::: :::::::::: "," :::::: :::::: ::::::: "," ::::: :::::: ::::::::::::::::: "," ::::: ::::: ::::::::::::::::::: "," ::::: ::::: :::::: ::::: ",":::: ::::: ::: ::::: :: ","::::: :::::: :::::::::: ","::::: :::::: ::::::::::: "," ::::: ::: ::::::: "," ::::::: ::: ::::: "," ::::::::::: :::::: :::::"," :::::::::: :::::: :::::"," :: ::::: ::: ::::: ::::"," ::::: :::::: ::::: ::::: ::: "," ::::::::::::::::::: ::::: ::::: "," ::::::::::::::::: ::::: ::::: "," ::::::::: :::::: :::::: "," :::::::::: :::::: "," ::::::::::: :::::: "," :::::::: "],yr=()=>hr(Xo,{flexDirection:"column",children:Qo.map((e,t)=>hr(Zo,{color:"cyan",children:e},t))});import{Fragment as ri,jsx as jt,jsxs as ni}from"react/jsx-runtime";var q=({marginBottom:e=0})=>ni(ri,{children:[jt(yr,{}),jt(ei,{flexDirection:"column",marginTop:1,marginBottom:e,children:jt(ti,{bold:!0,color:"cyan",children:"Kizen App Development Toolkit"})})]});import{useEffect as oi,useState as ii}from"react";import{Text as si}from"ink";import{jsx as ai}from"react/jsx-runtime";var br=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],me=()=>{let[e,t]=ii(0);return oi(()=>{let n=setInterval(()=>{t(o=>(o+1)%br.length)},80);return()=>{clearInterval(n)}},[]),ai(si,{color:"cyan",children:br[e]??"\u280B"})};import{Box as $t,Text as ot}from"ink";import{jsx as xr,jsxs as Le}from"react/jsx-runtime";var li=e=>{let t=new Map;for(let n of e){let o=n.path??n.pluginApiName??"general",r=t.get(o)??[];r.push(n),t.set(o,r)}return t},it=({issues:e})=>{let t=e.filter(n=>n.severity==="error").length;return Le($t,{flexDirection:"column",marginTop:1,children:[Le(ot,{color:"red",children:["\u2717 ",t," validation ",t===1?"error":"errors"]}),[...li(e)].map(([n,o])=>Le($t,{flexDirection:"column",marginTop:1,children:[xr(ot,{bold:!0,children:n}),o.map((r,i)=>xr($t,{paddingLeft:2,children:Le(ot,{color:r.severity==="error"?"red":"yellow",children:[r.severity==="error"?"\u2717":"\u26A0"," ",r.message," ",Le(ot,{dimColor:!0,children:["(",r.rule,")"]})]})},`${r.rule}-${String(i)}`))]},n))]})};import{Fragment as pi,jsx as ge,jsxs as Ee}from"react/jsx-runtime";var wr=["creating-dir","reading-files","validating","minifying","packaging","writing-bundle"],st={"creating-dir":"Creating .kizenapp directory","reading-files":"Reading plugin files",validating:"Validating plugin app",minifying:"Minifying scripts",packaging:"Packaging plugin","writing-bundle":"Writing bundle.json"},Cr=({outputDir:e,pluginDir:t})=>{let n=ci(),[o,r]=Me("creating-dir"),[i,d]=Me(!1),[f,g]=Me(null),[m,b]=Me(null),[T,P]=Me(null);vr(()=>{nt(t,e,r).then(({bundleSize:y})=>{P(y),r("done")}).catch(y=>{y instanceof di?g(y.issues):b(y instanceof Error?y.message:String(y)),d(!0),process.exitCode=1})},[e,t]),vr(()=>{(o==="done"||i)&&n.exit()},[o,i,n]);let x=wr.indexOf(o),p=o==="done";return Ee(ze,{flexDirection:"column",paddingY:1,paddingX:2,children:[ge(q,{marginBottom:1}),Ee(ze,{flexDirection:"column",gap:0,children:[wr.map((y,S)=>{let H=o===y,O=p||x>S;return ge(ze,{gap:1,children:i&&S===x?Ee(Re,{color:"red",children:["\u2717 ",st[y]]}):O?Ee(Re,{color:"green",children:["\u2713 ",st[y]]}):H?Ee(pi,{children:[ge(me,{}),ge(Re,{children:st[y]})]}):Ee(Re,{dimColor:!0,children:[" ",st[y]]})},y)}),p&&T!==null&&ge(ze,{marginTop:1,gap:1,children:Ee(Re,{color:"green",children:["\u2713 bundle \u2014 ",$e(T)]})}),f!==null&&ge(it,{issues:f}),m!==null&&ge(ze,{marginTop:1,borderStyle:"single",borderColor:"red",paddingX:1,children:ge(Re,{color:"red",children:m})})]})]})};import*as Ae from"fs";import*as Sr from"path";function Ne(e){let t=Sr.join(e,".gitignore"),n=".kizenapp/",o="";if(Ae.existsSync(t)){o=Ae.readFileSync(t,"utf8");let i=o.split(`
|
|
3
|
+
`).map(d=>d.trim());if(i.includes(n)||i.includes(".kizenapp"))return}let r=o.endsWith(`
|
|
4
|
+
`)?n+`
|
|
5
5
|
`:`
|
|
6
|
-
`+
|
|
7
|
-
`;
|
|
8
|
-
`,"utf-8"),await Nt(Ee(e.targetDir,"src"),{recursive:!0}),await Nt(Ee(e.targetDir,"releaseNotes"),{recursive:!0}),Ne(e.targetDir)}var me=["name","apiName","externalLink","description","developerBusinessId"],Rt={name:"Name",apiName:"API name",externalLink:"External link",description:"Description",developerBusinessId:"Business ID"},Dt=["name","apiName"];function gr(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_+|_+$/g,"")}function yr(e){return{name:"",apiName:"",externalLink:"",description:"",developerBusinessId:e}}function hr(e,t){if(Dt.includes(e)&&!t.trim())return`${Rt[e]} is required`}function xr(e,t){return e==="description"?t:t.trim()}import{jsx as B,jsxs as z}from"react/jsx-runtime";var Be=({text:e})=>B(R,{dimColor:!0,children:e}),br=({parentDir:e,defaultBusinessId:t})=>{let o=Bo(),[n,r]=ze({type:"target-select",cursor:0}),[i,p]=ze("in-place"),[u,m]=ze(()=>yr(t)),[g,h]=ze(""),[S,I]=ze(e),v=st((E,b)=>{p(E),h(b.name),r({type:"field-entry",field:0,values:b})},[]),c=st(async E=>{let b=await ur(E);if(b!=="ok"){r({type:"precheck-error",targetDir:E,reason:b});return}I(E),v("in-place",u)},[u,v]),x=st(async E=>{try{let b=await fr(e,E.apiName);I(b),r({type:"confirm",values:E})}catch(b){r({type:"error",message:b instanceof Error?b.message:String(b)})}},[e]),T=st(async(E,b)=>{try{await mr({targetDir:b,name:E.name,apiName:E.apiName,externalLink:E.externalLink,description:E.description,developerBusinessId:E.developerBusinessId}),r({type:"done",targetDir:b})}catch(w){r({type:"error",message:w instanceof Error?w.message:String(w)})}},[]);if(Ro((E,b)=>{if(b.ctrl&&E==="c"){o.exit();return}if(n.type==="target-select"){b.upArrow?r({type:"target-select",cursor:0}):b.downArrow?r({type:"target-select",cursor:1}):b.return?n.cursor===0?c(e):v("sub-dir",u):b.escape&&o.exit();return}if(n.type==="precheck-error"){(b.return||b.escape)&&o.exit();return}if(n.type==="field-entry"){let{field:w,values:P}=n,f=me[w];if(!f)return;if(b.escape){o.exit();return}if(b.backspace||b.delete){h(l=>l.slice(0,-1));return}if(b.upArrow&&w>0){let l={...P,[f]:g},s=w-1,a=me[s];r({type:"field-entry",field:s,values:l}),m(l),h(a?l[a]:"");return}if(b.return||b.tab||b.downArrow){let l=hr(f,g);if(l!==void 0){r({type:"field-entry",field:w,values:P,fieldError:l});return}let s=xr(f,g),a={...P,[f]:s};m(a);let d=w+1;if(d>=me.length)h(""),i==="sub-dir"?(r({type:"resolving-target"}),x(a)):r({type:"confirm",values:a});else{let y=me[d],N=y?a[y]:"",k=y==="apiName"&&!N?gr(a.name):N;r({type:"field-entry",field:d,values:a}),h(k)}return}E&&!b.ctrl&&!b.meta&&h(l=>l+E);return}if(n.type==="confirm"){if(b.escape){let w=me.length-1,P=me[w];r({type:"field-entry",field:w,values:n.values}),h(P?n.values[P]:"");return}b.return&&(r({type:"writing"}),T(n.values,S));return}(n.type==="done"||n.type==="error")&&(b.return||b.escape)&&o.exit()}),n.type==="target-select"){let E=[{label:"Use current directory",desc:e},{label:"Create new sub-directory",desc:`${e}/<inferred from API name>`}];return z(U,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[B(q,{}),z(U,{flexDirection:"column",gap:0,children:[B(R,{bold:!0,children:"Where should the new plugin live?"}),E.map((b,w)=>{let P=n.cursor===w;return z(U,{gap:2,children:[B(R,{...P&&{color:"cyan"},children:P?"\u276F":" "}),B(R,{bold:P,...P&&{color:"cyan"},children:b.label}),B(R,{dimColor:!0,children:b.desc})]},b.label)})]}),B(Be,{text:"\u2191\u2193 to move \xB7 Enter to select \xB7 Esc to cancel"})]})}if(n.type==="precheck-error"){let{targetDir:E,reason:b}=n;return z(U,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[B(q,{}),B(R,{color:"red",bold:!0,children:"Cannot create plugin"}),z(U,{flexDirection:"column",gap:0,children:[z(R,{children:[E," already contains ",B(R,{bold:!0,children:b==="has-manifest"?"kizen.json":".kizenapp/"}),"."]}),B(R,{dimColor:!0,children:"Remove the conflicting file/directory or choose a different target to avoid overwriting an existing plugin."})]}),B(Be,{text:"Enter or Esc to exit"})]})}if(n.type==="field-entry"){let{field:E,fieldError:b}=n,w=i==="sub-dir"?`Target: sub-directory of ${e} (inferred from API name)`:`Target: ${S}`;return z(U,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[B(q,{}),z(U,{flexDirection:"column",gap:0,children:[B(R,{bold:!0,children:"Plugin details"}),B(R,{dimColor:!0,children:w})]}),b!==void 0&&z(R,{color:"red",children:["Error: ",b]}),B(U,{flexDirection:"column",gap:0,children:me.map((P,f)=>{let l=E===f,s=l?g:u[P],a=Dt.includes(P),d=`${Rt[P]}${a?"":" (optional)"}`;return z(U,{gap:2,children:[B(U,{width:24,children:B(R,{bold:l,...l&&{color:"cyan"},children:d})}),B(R,{...l&&{color:"cyan"},children:">"}),B(R,{children:s}),l&&B(R,{color:"cyan",children:"\u2588"})]},P)})}),B(Be,{text:"Enter/Tab/\u2193 next \xB7 \u2191 previous \xB7 Backspace delete \xB7 Esc cancel"})]})}if(n.type==="confirm"){let E=Bt({targetDir:S,name:n.values.name,apiName:n.values.apiName,externalLink:n.values.externalLink,description:n.values.description,developerBusinessId:n.values.developerBusinessId});return z(U,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[B(q,{}),z(U,{flexDirection:"column",gap:0,children:[B(R,{bold:!0,children:"Ready to create"}),z(R,{dimColor:!0,children:["Target: ",S]})]}),z(U,{flexDirection:"column",gap:0,children:[B(R,{bold:!0,children:"kizen.json preview"}),B(R,{children:JSON.stringify(E,null,2)})]}),z(U,{flexDirection:"column",gap:0,children:[B(R,{dimColor:!0,children:"Also creates:"}),z(R,{dimColor:!0,children:[" ",Ft(S,"src/")]}),z(R,{dimColor:!0,children:[" ",Ft(S,"releaseNotes/")]}),z(R,{dimColor:!0,children:[" ",Ft(S,".gitignore")," (adds .kizenapp/)"]})]}),B(Be,{text:"Enter to create \xB7 Esc to go back"})]})}return n.type==="resolving-target"?B(U,{paddingY:1,paddingX:2,children:B(R,{dimColor:!0,children:"Finding available sub-directory\u2026"})}):n.type==="writing"?B(U,{paddingY:1,paddingX:2,children:B(R,{dimColor:!0,children:"Creating plugin\u2026"})}):n.type==="done"?z(U,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[B(q,{}),z(R,{color:"green",bold:!0,children:["Plugin created at ",n.targetDir]}),z(U,{flexDirection:"column",gap:0,children:[B(R,{dimColor:!0,children:"Next steps:"}),z(R,{children:[" ","cd ",n.targetDir]}),z(R,{children:[" ","npx --yes @kizenapps/cli dev"]})]}),B(Be,{text:"Enter or Esc to exit"})]}):z(U,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[B(q,{}),B(R,{color:"red",bold:!0,children:"Failed to create plugin"}),B(R,{children:n.message}),B(Be,{text:"Enter or Esc to exit"})]})};import{mkdir as vr,readFile as Do,readdir as Fo,writeFile as wr}from"fs/promises";import{homedir as Lo}from"os";import{dirname as $o,join as at}from"path";var re=["go","fmo","staging","integration","test1"];var Pe=at(Lo(),".kizenappbuilder"),Re=at(Pe,"credentials.json"),ge="credentials";function Ao(e){return re.includes(e)}function Oo(e){if(typeof e!="object"||e===null)throw new Error("Credentials must be a JSON object");let t=e,o=t.environment;return{apiKey:typeof t.apiKey=="string"?t.apiKey:"",userId:typeof t.userId=="string"?t.userId:"",businessId:typeof t.businessId=="string"?t.businessId:"",environment:Ao(o)?o:"go"}}async function ye(e){let t=await Do(e,"utf-8");return Oo(JSON.parse(t))}async function Y(){try{return await ye(Re)}catch{return null}}async function jo(e){await vr($o(Re),{recursive:!0,mode:448}),await wr(Re,JSON.stringify(e,null,2),{encoding:"utf-8",mode:384})}function Cr(e){return at(Pe,`${e}.json`)}async function ke(){let e=[{name:ge,path:Re,isDefault:!0}];try{let t=await Fo(Pe);for(let o of t){if(!o.endsWith(".json"))continue;let n=o.slice(0,-5);n!==ge&&e.push({name:n,path:at(Pe,o),isDefault:!1})}}catch{}return e}async function Sr(e,t){if(e===ge){await jo(t);return}await vr(Pe,{recursive:!0,mode:448}),await wr(Cr(e),JSON.stringify(t,null,2),{encoding:"utf-8",mode:384})}async function le(e){try{return await ye(Cr(e))}catch{return null}}function Tr(e){e.command("create").description("Scaffold a new Kizen plugin project").action(async()=>{let t=process.cwd(),n=(await Y())?.businessId??"",{waitUntilExit:r}=Mo(zo(br,{parentDir:t,defaultBusinessId:n}),{exitOnCtrlC:!1});await r()})}import{createElement as nn}from"react";import{render as on}from"ink";import{useCallback as De,useEffect as mt,useRef as ce,useState as X}from"react";import{Box as W,Text as D,useInput as $i}from"ink";import{PluginValidationError as Ai}from"@kizenapps/packager";import{watch as Oi}from"fs";import{createServer as ji}from"http";import{join as en}from"path";import{WebSocketServer as zi}from"ws";import{createReadStream as jr,realpathSync as ii}from"fs";import{access as si,readdir as ai,readFile as li,realpath as ci,stat as zr}from"fs/promises";import{dirname as di,extname as Mr,join as Je,resolve as pi,sep as Ut}from"path";import{fileURLToPath as ui}from"url";var Ho=new Set(["set-cookie","strict-transport-security","content-security-policy","content-security-policy-report-only","x-frame-options","content-encoding","content-length"]);function lt(e){let t={};for(let[o,n]of Object.entries(e)){let r=o.toLowerCase();Ho.has(r)||r.startsWith("access-control-")||(t[o]=n)}return t}var Lt=10*1024*1024,Vo=6e4,Uo=200,Me=class extends Error{bytesRead;limit;constructor(t,o){super(`Upstream response exceeded ${String(o)} bytes (read ${String(t)}).`),this.name="ProxyResponseTooLargeError",this.bytesRead=t,this.limit=o}};async function $t(e,t){let o=e.body;if(o===null)return Buffer.alloc(0);let n=[],r=0;for await(let i of o){if(r+=i.length,r>t)throw new Me(r,t);n.push(i)}return Buffer.concat(n)}async function Er(e){let t=lt(Object.fromEntries(e.headers)),o=await $t(e,Lt);return{status:e.status,headers:t,body:o}}function Pr(e={}){let{onChange:t,enabled:o=!0}=e;if(!o)return{async get(p,u){return{response:await Er(await u()),fromCache:!1}},clear(){}};let n=new Map,r=()=>{t?.(n.size)},i=p=>{n.delete(p)&&r()};return{get(p,u){let m=n.get(p);if(m!==void 0){if(Date.now()-m.insertedAt<Vo)return m.promise.then(h=>({response:h,fromCache:!0}));i(p)}if(n.size>=Uo){let h=n.keys().next().value;h!==void 0&&i(h)}let g=u().then(Er).catch(h=>{throw i(p),h});return n.set(p,{insertedAt:Date.now(),promise:g}),r(),g.then(h=>((h.status<200||h.status>=300)&&i(p),{response:h,fromCache:!1}))},clear(){n.clear(),r()}}}var At={".html":"text/html; charset=utf-8",".js":"application/javascript; charset=utf-8",".mjs":"application/javascript; charset=utf-8",".css":"text/css; charset=utf-8",".png":"image/png",".jpg":"image/jpeg",".svg":"image/svg+xml",".ico":"image/x-icon",".json":"application/json; charset=utf-8",".woff":"font/woff",".woff2":"font/woff2",".ttf":"font/ttf",".map":"application/json"};import{mkdir as qo,readFile as Jo,writeFile as Wo}from"fs/promises";import{join as kr}from"path";async function he(e){try{let t=await Jo(kr(e,"config.json"),"utf-8");return JSON.parse(t)}catch{return{}}}async function xe(e,t){await qo(e,{recursive:!0}),await Wo(kr(e,"config.json"),JSON.stringify(t,null,2),"utf-8")}var Ot={prod:"https://plugin-wizard.kizen.com",dev:"https://plugin-wizard.kizen.dev",localDev:"http://localhost:9823"};function He(e){let t=process.env.PLUGIN_WIZARD_URL;return t!==void 0&&t!==""?t:e==="prod"?process.env.PLUGIN_WIZARD_URL_PROD||Ot.prod:process.env.PLUGIN_WIZARD_URL_DEV!==void 0&&process.env.PLUGIN_WIZARD_URL_DEV!==""?process.env.PLUGIN_WIZARD_URL_DEV:process.env.APPBUILDER_LOCAL_DEV!==void 0&&process.env.APPBUILDER_LOCAL_DEV!==""?Ot.localDev:Ot.dev}import{spawn as Ht}from"child_process";import{writeFile as Br,rm as Mt,mkdtemp as Ko,access as Yo}from"fs/promises";import{join as Ue}from"path";import{tmpdir as Xo}from"os";var _r=`awslambdaric
|
|
6
|
+
`+n+`
|
|
7
|
+
`;Ae.writeFileSync(t,o+r)}function Tr(e){e.command("build").description("Bundle the plugin app into .kizenapp directory").action(async()=>{let t=process.cwd(),n=`${t}/.kizenapp`;Ne(t);let{waitUntilExit:o}=fi(ui(Cr,{outputDir:n,pluginDir:t}));await o()})}import{createElement as hs}from"react";import{render as ys}from"ink";import{useCallback as mt,useState as Be}from"react";import{Box as z,Text as I,useApp as rs,useInput as ns}from"ink";import{join as gt}from"path";import{access as Zi,mkdir as lt,writeFile as Ut}from"fs/promises";import{dirname as Qi,join as ce}from"path";var _r=`{
|
|
8
|
+
"name": "Hello Frame",
|
|
9
|
+
"api_name": "hello_frame",
|
|
10
|
+
"title": "Hello Frame",
|
|
11
|
+
"default_position": "bottom-right",
|
|
12
|
+
"minimized_style": "circle",
|
|
13
|
+
"height": 320,
|
|
14
|
+
"width": 280
|
|
15
|
+
}
|
|
16
|
+
`;var Er=`this.outputUI(\`
|
|
17
|
+
<div class="hello-frame">
|
|
18
|
+
<h2 class="hello-frame__title">Hello from a floating frame</h2>
|
|
19
|
+
<p class="hello-frame__body">Edit src/floatingFrames/helloFrame/script.js to change this.</p>
|
|
20
|
+
</div>
|
|
21
|
+
\`);
|
|
22
|
+
`;var kr=`.hello-frame {
|
|
23
|
+
padding: 16px;
|
|
24
|
+
font-family: system-ui, sans-serif;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.hello-frame__title {
|
|
28
|
+
margin: 0 0 8px;
|
|
29
|
+
font-size: 16px;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.hello-frame__body {
|
|
33
|
+
margin: 0;
|
|
34
|
+
color: #555;
|
|
35
|
+
}
|
|
36
|
+
`;var Pr=`{
|
|
37
|
+
"name": "Hello Block",
|
|
38
|
+
"api_name": "hello_block",
|
|
39
|
+
"types": ["dashboards"]
|
|
40
|
+
}
|
|
41
|
+
`;var Ir=`this.outputUI(\`
|
|
42
|
+
<div class="hello-block">
|
|
43
|
+
<h2 class="hello-block__title">Hello from a block</h2>
|
|
44
|
+
<p class="hello-block__body">Edit src/blocks/helloBlock/script.js to change this.</p>
|
|
45
|
+
</div>
|
|
46
|
+
\`);
|
|
47
|
+
`;var Rr=`.hello-block {
|
|
48
|
+
padding: 16px;
|
|
49
|
+
font-family: system-ui, sans-serif;
|
|
50
|
+
background: #f8fafc;
|
|
51
|
+
border-radius: 6px;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.hello-block__title {
|
|
55
|
+
margin: 0 0 8px;
|
|
56
|
+
font-size: 16px;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.hello-block__body {
|
|
60
|
+
margin: 0;
|
|
61
|
+
color: #555;
|
|
62
|
+
}
|
|
63
|
+
`;var Ar=`{
|
|
64
|
+
"icon": "phone",
|
|
65
|
+
"color": "#0ea5e9",
|
|
66
|
+
"tooltip": "Hello adornment",
|
|
67
|
+
"field_type": "phonenumber"
|
|
68
|
+
}
|
|
69
|
+
`;var Nr=`this.showToast('Hello from a data adornment.', { variant: 'success' });
|
|
70
|
+
`;var Br=`{
|
|
71
|
+
"name": "Hello Page",
|
|
72
|
+
"api_name": "hello_page"
|
|
73
|
+
}
|
|
74
|
+
`;var Dr=`this.outputUI(\`
|
|
75
|
+
<div class="hello-page">
|
|
76
|
+
<p class="hello-page__loading">Loading\u2026</p>
|
|
77
|
+
</div>
|
|
78
|
+
\`);
|
|
79
|
+
|
|
80
|
+
this.runEventScript('greet');
|
|
81
|
+
`;var Fr=`.hello-page {
|
|
82
|
+
padding: 24px;
|
|
83
|
+
font-family: system-ui, sans-serif;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.hello-page__title {
|
|
87
|
+
margin: 0 0 8px;
|
|
88
|
+
font-size: 20px;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.hello-page__body {
|
|
92
|
+
margin: 0 0 16px;
|
|
93
|
+
color: #555;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.hello-page__loading {
|
|
97
|
+
margin: 0;
|
|
98
|
+
color: #94a3b8;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.hello-page__actions {
|
|
102
|
+
display: flex;
|
|
103
|
+
gap: 8px;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.hello-page__button {
|
|
107
|
+
padding: 6px 12px;
|
|
108
|
+
font: inherit;
|
|
109
|
+
color: #0f172a;
|
|
110
|
+
background: #e2e8f0;
|
|
111
|
+
border: 0;
|
|
112
|
+
border-radius: 4px;
|
|
113
|
+
cursor: pointer;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.hello-page__button:hover {
|
|
117
|
+
background: #cbd5e1;
|
|
118
|
+
}
|
|
119
|
+
`;var Or=`const tone = this.args?.formData?.tone?.[0] ?? 'plain';
|
|
120
|
+
|
|
121
|
+
const greeting = tone === 'cheer' ? 'Hello, and good to see you!' : 'Hello from a routable page.';
|
|
122
|
+
|
|
123
|
+
this.outputUI(\`
|
|
124
|
+
<div class="hello-page">
|
|
125
|
+
<h1 class="hello-page__title">\${greeting}</h1>
|
|
126
|
+
<p class="hello-page__body">
|
|
127
|
+
This markup came from eventScripts/greet.js. Either button re-runs it and
|
|
128
|
+
repaints the page with a different greeting.
|
|
129
|
+
</p>
|
|
130
|
+
<div class="hello-page__actions">
|
|
131
|
+
<form data-script="greet">
|
|
132
|
+
<input type="hidden" name="tone" value="plain" />
|
|
133
|
+
<button class="hello-page__button" type="submit">Plain</button>
|
|
134
|
+
</form>
|
|
135
|
+
<form data-script="greet">
|
|
136
|
+
<input type="hidden" name="tone" value="cheer" />
|
|
137
|
+
<button class="hello-page__button" type="submit">Cheerful</button>
|
|
138
|
+
</form>
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
\`);
|
|
142
|
+
`;var jr=`{
|
|
143
|
+
"api_name": "hello_toolbar_item",
|
|
144
|
+
"label": "Hello Toolbar Item",
|
|
145
|
+
"icon": "star",
|
|
146
|
+
"color": "#0ea5e9"
|
|
147
|
+
}
|
|
148
|
+
`;var $r=`this.showToast('Hello from a toolbar item.', { variant: 'success' });
|
|
149
|
+
`;var Lr=`{
|
|
150
|
+
"api_name": "hello_object_settings_item",
|
|
151
|
+
"label": "Hello Object Settings"
|
|
152
|
+
}
|
|
153
|
+
`;var Mr=`this.showToast('Hello from an object settings item.', { variant: 'success' });
|
|
154
|
+
`;var zr=`{
|
|
155
|
+
"name": "Hello Action",
|
|
156
|
+
"api_name": "hello_action",
|
|
157
|
+
"hint_object_name": "client_client"
|
|
158
|
+
}
|
|
159
|
+
`;var Hr=`this.showToast('Hello from a JS action.', { variant: 'success' });
|
|
160
|
+
`;var X=["floatingFrame","block","dataAdornment","page","toolbarItem","objectSettingsItem","jsAction"],Lt={floatingFrame:"Floating frame",block:"Block",dataAdornment:"Data adornment",page:"Routable page",toolbarItem:"Toolbar item",objectSettingsItem:"Object settings item",jsAction:"JS action"},Ni={floatingFrame:{directory:"floatingFrames",component:"helloFrame",files:{"config.json":_r,"script.js":Er,"styles.css":kr}},block:{directory:"blocks",component:"helloBlock",files:{"config.json":Pr,"script.js":Ir,"styles.css":Rr}},dataAdornment:{directory:"dataAdornments",component:"helloAdornment",files:{"config.json":Ar,"script.js":Nr}},page:{directory:"pages",component:"helloPage",files:{"config.json":Br,"script.js":Dr,"styles.css":Fr,"eventScripts/greet.js":Or}},toolbarItem:{directory:"toolbarItems",component:"helloToolbarItem",files:{"config.json":jr,"script.js":$r}},objectSettingsItem:{directory:"objectSettingsItems",component:"helloObjectSettingsItem",files:{"config.json":Lr,"script.js":Mr}},jsAction:{directory:"actions",component:"helloAction",files:{"config.json":zr,"script.js":Hr}}};function Bi(e,t="src"){let{directory:n,component:o,files:r}=Ni[e];return Object.entries(r).map(([i,d])=>({path:`${t}/${n}/${o}/${i}`,content:d}))}function Ur(e,t="src"){return[...new Set(e)].flatMap(n=>Bi(n,t))}var Vr='# Copilot review instructions for this Kizen plugin\n\nThis repo is a Kizen plugin app: a `kizen.json` manifest plus the artifacts\nthat `@kizenapps/packager` finds by walking the directory tree under the\nmanifest\'s `entry` (default `src/`). No manifest key lists artifacts. The\ndirectory layout decides what gets packaged.\n\n## Component directories\n\nUnder `entry`, the packager treats these directory names as component types:\n\n- `floatingFrames`\n- `blocks`\n- `dataAdornments`\n- `pages`\n- `views`\n- `toolbarItems`\n- `objectSettingsItems`\n- `actions`\n- `routeScripts`\n- `automationSteps`\n- `calendarSources`\n\nEvery directory under a component type needs a `config.json`. `views/` is the\none exception.\n\n## `api_name` rules\n\n- An `api_name` must match `/^[a-z_][a-z0-9_]+$/`: lowercase letters, digits\n and underscores, starting with a letter or underscore, at least 2 characters.\n- Set `api_name` explicitly in each artifact\'s `config.json`. The fallback\n lowercases and strips the directory name (`myFrame` becomes `myframe`), and\n that result can collide with another artifact\'s explicit `api_name`.\n- Data adornments have no `api_name` field. Flag one that adds it as dead\n configuration.\n- Sibling components in the same directory need unique `api_name`s. `pages/`\n and `views/` go further and share one namespace, so a page and a view with\n the same `api_name` collide even though they live in different directories.\n\n## A green build does not mean a correct artifact\n\nThe packager coerces malformed artifact config instead of rejecting it: an\ninvalid `field_type` on a data adornment becomes `phonenumber`, and an invalid\n`minimized_style` on a floating frame becomes `circle`. It also says nothing\nabout a missing required field. Publishing is the real gate. The publish step\ncreates each artifact with no defaulting, so a field the packager never emitted\nis absent and the publish request 400s. Review each\n`config.json` as if the build will not catch mistakes in it, because for these\ncases it does not.\n\nPublishing an app requires these fields per artifact type. An artifact missing\none builds clean and fails to publish:\n\n| Artifact | Required fields |\n| --- | --- |\n| Floating frame | `api_name`, `name`, `title` |\n| Block | `api_name`, `name` |\n| Data adornment | `field_type` (one of `phonenumber`, `date`, `datetime`) |\n| Routable page | `api_name`, `name` |\n| Toolbar item | `api_name`, `label`, and a non-blank `script.js` |\n| Object settings item | `api_name`, `label`, and a non-blank `script.js` |\n| JS action | `api_name`, `name`, `hint_object_name` (non-blank) |\n\nA floating frame whose `default_position` ends in `-fixed` must set\n`minimized_style: "circle"` or omit `minimized_style`. Any other value fails\nthe build with `structure/fixed-frame-minimized-style`.\n\n## Publishing\n\nPublishing an app requires exactly one `thumbnail.png`, and it must sit inside\nthe `entry` directory (`src/thumbnail.png` by default). The packager never sees\na thumbnail at the repo root, and publishing then fails with "Thumbnail is\nrequired for publishing".\n\n## Scope\n\nThis file covers repo structure and general review. Two path-scoped files\ncover the rest: `.github/instructions/security.instructions.md` for\nsecurity-sensitive patterns and\n`.github/instructions/version-discipline.instructions.md` for manifest version\nbumps.\n';var qr=`---
|
|
161
|
+
applyTo: "src/**/*.js,kizen.json"
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
# Security review rules for plugin scripts
|
|
165
|
+
|
|
166
|
+
These rules mirror the \`security/*\` validation rules in \`@kizenapps/packager\`.
|
|
167
|
+
Flag violations the way the packager would, and also flag the patterns listed
|
|
168
|
+
here that its static scan cannot detect.
|
|
169
|
+
|
|
170
|
+
## \`__dangerouslySkipProxy\`
|
|
171
|
+
|
|
172
|
+
The packager lets \`__dangerouslySkipProxy\` through with the build WARNING
|
|
173
|
+
\`security/dangerously-skip-proxy\`. Flag every occurrence for human review
|
|
174
|
+
anyway, because the request leaves the browser directly instead of passing
|
|
175
|
+
through the Kizen proxy.
|
|
176
|
+
|
|
177
|
+
## Plaintext credentials
|
|
178
|
+
|
|
179
|
+
In \`kizen.json\`, a service's \`auth_credentials.token\`,
|
|
180
|
+
\`auth_credentials.password\` and \`auth_credentials.client_secret\` must each be
|
|
181
|
+
one of:
|
|
182
|
+
|
|
183
|
+
- an encrypted envelope (\`{ "encrypted": true, "value": "..." }\`) that
|
|
184
|
+
\`appbuilder encrypt\` produced
|
|
185
|
+
- a \`{{secret.KEY}}\` reference, with \`KEY\` declared in \`base_config.secrets\`
|
|
186
|
+
- a reference through \`auth_credentials.integration_secret_api_name\`
|
|
187
|
+
|
|
188
|
+
A raw literal in any of those three fields is the build ERROR
|
|
189
|
+
\`security/plaintext-credential\`. Treat a credential that reaches a commit in
|
|
190
|
+
plaintext as compromised and rotate it; deleting the line does not undo the
|
|
191
|
+
exposure.
|
|
192
|
+
|
|
193
|
+
\`client_id\` is excluded from this rule on purpose. Public client ids are not
|
|
194
|
+
sensitive, so do not flag them.
|
|
195
|
+
|
|
196
|
+
## Undeclared secret references
|
|
197
|
+
|
|
198
|
+
A \`{{secret.KEY}}\` reference whose \`KEY\` is missing from \`base_config.secrets\`
|
|
199
|
+
is the build ERROR \`security/undeclared-secret-reference\`, because nothing
|
|
200
|
+
would supply the value at install time.
|
|
201
|
+
|
|
202
|
+
## Dynamic code execution
|
|
203
|
+
|
|
204
|
+
\`eval(...)\`, \`new Function(...)\` or \`Function(...)\`, and a string argument to
|
|
205
|
+
\`setTimeout\` or \`setInterval\` are the build ERROR \`security/dynamic-code\`.
|
|
206
|
+
|
|
207
|
+
This rule catches direct, literal usage only. The packager's scan is
|
|
208
|
+
parser-based, so a call built through a computed property or a reassigned
|
|
209
|
+
reference gets past it. Obfuscated dynamic code stays a human-review concern.
|
|
210
|
+
|
|
211
|
+
## Secret logging and exfiltration
|
|
212
|
+
|
|
213
|
+
The packager has no static check for a secret that gets logged, sent to an
|
|
214
|
+
unexpected endpoint, or otherwise exfiltrated. Review for this by hand: look
|
|
215
|
+
for credentials or decrypted secret values flowing into \`console.log\`, error
|
|
216
|
+
messages, analytics calls, or outbound requests to anything other than the
|
|
217
|
+
service they belong to.
|
|
218
|
+
|
|
219
|
+
## Handling secrets in this repo
|
|
220
|
+
|
|
221
|
+
Encrypt secrets locally with \`appbuilder encrypt\` before committing them. Do
|
|
222
|
+
not commit a plaintext secret value in any form; a comment, a script fixture,
|
|
223
|
+
and a commit you intend to rewrite later all count.
|
|
224
|
+
`;var Jr=`---
|
|
225
|
+
applyTo: "kizen.json"
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
# Version-bump discipline for \`kizen.json\`
|
|
229
|
+
|
|
230
|
+
## What a wrong bump breaks
|
|
231
|
+
|
|
232
|
+
A business that installs this plugin accumulates its own stored state
|
|
233
|
+
(automation runs, config values, references to entities) shaped by what was
|
|
234
|
+
published at the time. Publishing is additive: it never rewrites a business's
|
|
235
|
+
stored rows, and the plugin author has no way to migrate that state for them.
|
|
236
|
+
A change is breaking when it invalidates an assumption the business's existing
|
|
237
|
+
data already depends on.
|
|
238
|
+
|
|
239
|
+
A MINOR or PATCH republish applies at once to a business's running automations
|
|
240
|
+
and installed artifacts. Only a new MAJOR version waits for the business to
|
|
241
|
+
upgrade explicitly. A change that needed MAJOR but shipped as MINOR or PATCH
|
|
242
|
+
therefore breaks the business with no upgrade gate in between.
|
|
243
|
+
|
|
244
|
+
Two kinds of change get MAJOR because they fail without an error:
|
|
245
|
+
|
|
246
|
+
- Renaming a config field, changing its type, or adding a required key. A
|
|
247
|
+
template reference like \`{{config.key}}\` for a key that no longer exists
|
|
248
|
+
resolves to a literal \`null\`, and the artifact renders wrong or does
|
|
249
|
+
nothing.
|
|
250
|
+
- Removing or renaming a JS action. A business's automation and UI
|
|
251
|
+
associations key on the action's \`api_name\` as a plain string, with no
|
|
252
|
+
foreign key. After a rename or removal those associations stop firing.
|
|
253
|
+
|
|
254
|
+
Review every \`kizen.json\` diff against the table below before approving the
|
|
255
|
+
version bump in the same PR.
|
|
256
|
+
|
|
257
|
+
## Bump matrix
|
|
258
|
+
|
|
259
|
+
| Resource | Change | Required bump |
|
|
260
|
+
| --- | --- | --- |
|
|
261
|
+
| Plugin | change \`api_name\` | **HARD-BLOCK**: identity can never change |
|
|
262
|
+
| Service | add | MINOR |
|
|
263
|
+
| Service | remove | MAJOR |
|
|
264
|
+
| Service | change auth type or \`auth_level\` | MAJOR |
|
|
265
|
+
| Service | change \`auth_credentials\` (client id/secret, scopes, authorize/token URLs) | MAJOR |
|
|
266
|
+
| Service | change base URL or other non-auth field | PATCH |
|
|
267
|
+
| Service | rename \`api_name\` | MAJOR |
|
|
268
|
+
| Secret | add | MINOR |
|
|
269
|
+
| Secret | remove | MINOR |
|
|
270
|
+
| Secret | rename key | MAJOR |
|
|
271
|
+
| Secret | re-encrypt value only | PATCH |
|
|
272
|
+
| Automation step | add | MINOR |
|
|
273
|
+
| Automation step | remove entire step | MAJOR |
|
|
274
|
+
| Automation step | remove an input or output | MAJOR |
|
|
275
|
+
| Automation step | change input/output \`data_type\` | MAJOR |
|
|
276
|
+
| Automation step | add required input | MAJOR |
|
|
277
|
+
| Automation step | add optional input | MINOR |
|
|
278
|
+
| Automation step | change python runtime | PATCH |
|
|
279
|
+
| Automation step | edit script body only | PATCH |
|
|
280
|
+
| Artifact (frame, block, adornment, page, route script, toolbar/object-settings item, calendar source) | add | MINOR |
|
|
281
|
+
| Artifact | remove | MINOR |
|
|
282
|
+
| Artifact | rename \`api_name\` | MINOR |
|
|
283
|
+
| Artifact | edit script or behavior | PATCH |
|
|
284
|
+
| JS action | add | MINOR |
|
|
285
|
+
| JS action | remove | MAJOR |
|
|
286
|
+
| JS action | rename \`api_name\` | MAJOR |
|
|
287
|
+
| JS action | change \`hint_object_name\` or script | PATCH |
|
|
288
|
+
| Config field | add optional (with default) | MINOR |
|
|
289
|
+
| Config field | add required (no default) | MAJOR |
|
|
290
|
+
| Config field | remove | MINOR |
|
|
291
|
+
| Config field | rename | MAJOR |
|
|
292
|
+
| Config field | change type | MAJOR |
|
|
293
|
+
| Config field | change default or label | PATCH |
|
|
294
|
+
| \`required_entitlement\` | add gating | MINOR |
|
|
295
|
+
| \`required_entitlement\` | change or remove | PATCH |
|
|
296
|
+
| Manifest metadata (\`name\`, \`description\`, \`entry\`, \`release_branches\`, \`release_environments\`, \`published\`, \`developer_business_id\`) | any change | PATCH |
|
|
297
|
+
`;function Wr(){return[{path:".github/copilot-instructions.md",content:Vr},{path:".github/instructions/security.instructions.md",content:qr},{path:".github/instructions/version-discipline.instructions.md",content:Jr}]}import{deflateSync as ji}from"zlib";var zt=512,$i=150,Li=26,Ht=46,Kr=.6,Mi=Ht*.55,zi=.55,Hi=.47;function Ui(e){let t=2166136261;for(let n=0;n<e.length;n+=1)t^=e.charCodeAt(n),t=t+((t<<1)+(t<<4)+(t<<7)+(t<<8)+(t<<24))>>>0;return t}function Vi(e){let t=Ui(e);return{hue:t%360,quarterTurns:(t>>>16)%4}}function qi(e,t,n){let o=(1-Math.abs(2*n-1))*t,r=e/60,i=o*(1-Math.abs(r%2-1)),d=n-o/2,[f,g,m]=r<1?[o,i,0]:r<2?[i,o,0]:r<3?[0,o,i]:r<4?[0,i,o]:r<5?[i,0,o]:[o,0,i];return[Math.round((f+d)*255),Math.round((g+d)*255),Math.round((m+d)*255)]}function He(e,t,n,o,r){let i=Math.abs(e)-n+r,d=Math.abs(t)-o+r;return Math.hypot(Math.max(i,0),Math.max(d,0))+Math.min(Math.max(i,d),0)-r}function at(e,t,n,o,r){return Math.hypot(e-n,t-o)-r}function Ji(e,t){let n=$i,o=Ht,r=o*Kr,i=Mi,d=He(e,t,n,n,Li),f=Math.min(at(e,t,0,-n-r,o),He(e,t+n+r/2,i,r/2+1,0)),g=Math.min(at(e,t,n+r,0,o),He(e-n-r/2,t,r/2+1,i,0));d=Math.min(d,f,g);let m=Math.min(at(e,t,0,n-r,o),He(e,t-n+r/2,i,r/2+1,0)),b=Math.min(at(e,t,-n+r,0,o),He(e+n-r/2,t,r/2+1,i,0));return Math.max(d,-m,-b)}function Wi(e){let t=zt,n=new Uint8Array(t*t*4),[o,r,i]=qi(e.hue,zi,Hi),d=Ht*(1+Kr),f=(t-1)/2,g=d/2;for(let m=0;m<t;m+=1)for(let b=0;b<t;b+=1){let T=b-f,P=m-f;for(let S=0;S<e.quarterTurns;S+=1)[T,P]=[-P,T];let x=Ji(T+g,P-g),p=Math.min(1,Math.max(0,.5-x));if(p<=0)continue;let y=(m*t+b)*4;n[y]=o,n[y+1]=r,n[y+2]=i,n[y+3]=Math.round(p*255)}return n}var Ki=new Uint32Array(256).map((e,t)=>{let n=t;for(let o=0;o<8;o+=1)n=n&1?3988292384^n>>>1:n>>>1;return n>>>0});function Gi(e){let t=4294967295;for(let n of e)t=(Ki[(t^n)&255]??0)^t>>>8;return(t^4294967295)>>>0}function Mt(e,t){let n=Buffer.from(e,"latin1"),o=Buffer.alloc(4);o.writeUInt32BE(t.length);let r=Buffer.alloc(4);return r.writeUInt32BE(Gi(Buffer.concat([n,t]))),Buffer.concat([o,n,t,r])}var Yi=Buffer.from([137,80,78,71,13,10,26,10]);function Xi(e,t,n){if(n.length!==e*t*4)throw new Error(`encodePng: expected ${String(e*t*4)} bytes of RGBA for ${String(e)}x${String(t)}, got ${String(n.length)}`);let o=Buffer.alloc(13);o.writeUInt32BE(e,0),o.writeUInt32BE(t,4),o[8]=8,o[9]=6;let r=e*4,i=Buffer.alloc((r+1)*t);for(let d=0;d<t;d+=1)i.set(n.subarray(d*r,(d+1)*r),d*(r+1)+1);return Buffer.concat([Yi,Mt("IHDR",o),Mt("IDAT",ji(i,{level:9})),Mt("IEND",new Uint8Array(0))])}function Gr(e){return Xi(zt,zt,Wi(Vi(e)))}var es="src/thumbnail.png",ts=["go","fmo"];async function ct(e){try{return await Zi(e),!0}catch{return!1}}async function dt(e){return await ct(ce(e,"kizen.json"))?"has-manifest":await ct(ce(e,".kizenapp"))?"has-kizenapp":"ok"}async function Xr(e,t){let n=ce(e,t);if(!await ct(n))return n;for(let o=1;o<1e3;o++){let r=ce(e,`${t}-${String(o)}`);if(!await ct(r))return r}throw new Error(`Could not find an available directory name for "${t}"`)}function Vt(e){let t=e.developerBusinessId.trim(),n=t!==""&&!ts.includes(e.developerEnvironment)?[e.developerEnvironment]:["prod"];return{name:e.name,version:"1.0.0",published:!0,api_name:e.apiName,external_link:e.externalLink,description:e.description,entry:"src/",engine:"1.0.0",release_notes_directory:"releaseNotes/",release_environments:n,config_template:{},base_config:{},...t?{developer_business_id:{[e.developerEnvironment]:t}}:{}}}async function Yr(e,t){let n=t.map(r=>({fullPath:ce(e,...r.path.split("/")),content:r.content})),o=new Set(n.map(r=>Qi(r.fullPath)));await Promise.all([...o].map(r=>lt(r,{recursive:!0}))),await Promise.all(n.map(r=>Ut(r.fullPath,r.content,"utf-8")))}async function pt(e){await lt(e.targetDir,{recursive:!0});let t=Vt(e);await Ut(ce(e.targetDir,"kizen.json"),JSON.stringify(t,null,2)+`
|
|
298
|
+
`,"utf-8"),await lt(ce(e.targetDir,"src"),{recursive:!0}),await lt(ce(e.targetDir,"releaseNotes"),{recursive:!0}),await Promise.all([Yr(e.targetDir,Ur(e.artifacts??[])),Yr(e.targetDir,Wr()),Ut(ce(e.targetDir,...es.split("/")),Gr(e.apiName))]),Ne(e.targetDir)}var he=["name","apiName","externalLink","description","developerBusinessId"],ut={name:"Name",apiName:"API name",externalLink:"External link",description:"Description",developerBusinessId:"Business ID"},qt=["name","apiName","description"],Jt=/^[a-z_][a-z0-9_]+$/,Wt="must start with a letter or underscore and contain only lowercase letters, numbers, or underscores (minimum 2 characters)";function ft(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_+|_+$/g,"")}function Zr(e){return{name:"",apiName:"",externalLink:"",description:"",developerBusinessId:e}}function Qr(e,t){let n=t.trim();if(qt.includes(e)&&!n)return`${ut[e]} is required`;if(e==="apiName"&&!Jt.test(n))return`${ut[e]} ${Wt}`}function en(e,t){return e==="description"?t:t.trim()}function tn(e,t){let n=new Set(e);return n.has(t)?n.delete(t):n.add(t),X.filter(o=>n.has(o))}import{jsx as E,jsxs as N}from"react/jsx-runtime";var ke=({text:e})=>E(I,{dimColor:!0,children:e}),rn=({parentDir:e,defaultBusinessId:t,defaultEnvironment:n})=>{let o=rs(),[r,i]=Be({type:"target-select",cursor:0}),[d,f]=Be("in-place"),[g,m]=Be(()=>Zr(t)),[b,T]=Be(()=>[...X]),[P,x]=Be(""),[p,y]=Be(e),S=mt((v,c)=>{f(v),x(c.name),i({type:"field-entry",field:0,values:c})},[]),H=mt(async v=>{let c=await dt(v);if(c!=="ok"){i({type:"precheck-error",targetDir:v,reason:c});return}y(v),S("in-place",g)},[g,S]),O=mt(async(v,c)=>{try{let a=await Xr(e,v.apiName);y(a),i({type:"confirm",values:v,artifacts:c})}catch(a){i({type:"error",message:a instanceof Error?a.message:String(a)})}},[e]),w=mt(async(v,c,a)=>{try{await pt({targetDir:c,name:v.name,apiName:v.apiName,externalLink:v.externalLink,description:v.description,developerBusinessId:v.developerBusinessId,developerEnvironment:n,artifacts:a}),i({type:"done",targetDir:c})}catch(s){i({type:"error",message:s instanceof Error?s.message:String(s)})}},[n]);if(ns((v,c)=>{if(c.ctrl&&v==="c"){o.exit();return}if(r.type==="target-select"){c.upArrow?i({type:"target-select",cursor:0}):c.downArrow?i({type:"target-select",cursor:1}):c.return?r.cursor===0?H(e):S("sub-dir",g):c.escape&&o.exit();return}if(r.type==="precheck-error"){(c.return||c.escape)&&o.exit();return}if(r.type==="field-entry"){let{field:a,values:s}=r,l=he[a];if(!l)return;if(c.escape){o.exit();return}if(c.backspace||c.delete){x(u=>u.slice(0,-1));return}if(c.upArrow&&a>0){let u={...s,[l]:P},h=a-1,k=he[h];i({type:"field-entry",field:h,values:u}),m(u),x(k?u[k]:"");return}if(c.return||c.tab||c.downArrow){let u=Qr(l,P);if(u!==void 0){i({type:"field-entry",field:a,values:s,fieldError:u});return}let h=en(l,P),k={...s,[l]:h};m(k);let _=a+1;if(_>=he.length)x(""),i({type:"artifact-select",values:k,cursor:0,selected:b});else{let A=he[_],M=A?k[A]:"",W=A==="apiName"&&!M?ft(k.name):M;i({type:"field-entry",field:_,values:k}),x(W)}return}v&&!c.ctrl&&!c.meta&&x(u=>u+v);return}if(r.type==="artifact-select"){let{cursor:a,selected:s,values:l}=r;if(c.escape){let u=he.length-1,h=he[u];i({type:"field-entry",field:u,values:l}),x(h?l[h]:"");return}if(c.upArrow){i({...r,cursor:Math.max(0,a-1)});return}if(c.downArrow){i({...r,cursor:Math.min(X.length-1,a+1)});return}if(v===" "){let u=X[a];if(u){let h=tn(s,u);T(h),i({...r,selected:h})}return}if(v==="a"){T([...X]),i({...r,selected:[...X]});return}if(v==="n"){T([]),i({...r,selected:[]});return}c.return&&(d==="sub-dir"?(i({type:"resolving-target"}),O(l,s)):i({type:"confirm",values:l,artifacts:s}));return}if(r.type==="confirm"){if(c.escape){i({type:"artifact-select",values:r.values,cursor:0,selected:r.artifacts});return}c.return&&(i({type:"writing"}),w(r.values,p,r.artifacts));return}(r.type==="done"||r.type==="error")&&(c.return||c.escape)&&o.exit()}),r.type==="target-select"){let v=[{label:"Use current directory",desc:e},{label:"Create new sub-directory",desc:`${e}/<inferred from API name>`}];return N(z,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[E(q,{}),N(z,{flexDirection:"column",gap:0,children:[E(I,{bold:!0,children:"Where should the new plugin live?"}),v.map((c,a)=>{let s=r.cursor===a;return N(z,{gap:2,children:[E(I,{...s&&{color:"cyan"},children:s?"\u276F":" "}),E(I,{bold:s,...s&&{color:"cyan"},children:c.label}),E(I,{dimColor:!0,children:c.desc})]},c.label)})]}),E(ke,{text:"\u2191\u2193 to move \xB7 Enter to select \xB7 Esc to cancel"})]})}if(r.type==="precheck-error"){let{targetDir:v,reason:c}=r;return N(z,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[E(q,{}),E(I,{color:"red",bold:!0,children:"Cannot create plugin"}),N(z,{flexDirection:"column",gap:0,children:[N(I,{children:[v," already contains ",E(I,{bold:!0,children:c==="has-manifest"?"kizen.json":".kizenapp/"}),"."]}),E(I,{dimColor:!0,children:"Remove the conflicting file/directory or choose a different target to avoid overwriting an existing plugin."})]}),E(ke,{text:"Enter or Esc to exit"})]})}if(r.type==="field-entry"){let{field:v,fieldError:c}=r,a=d==="sub-dir"?`Target: sub-directory of ${e} (inferred from API name)`:`Target: ${p}`;return N(z,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[E(q,{}),N(z,{flexDirection:"column",gap:0,children:[E(I,{bold:!0,children:"Plugin details"}),E(I,{dimColor:!0,children:a})]}),c!==void 0&&N(I,{color:"red",children:["Error: ",c]}),E(z,{flexDirection:"column",gap:0,children:he.map((s,l)=>{let u=v===l,h=u?P:g[s],k=qt.includes(s),_=`${ut[s]}${k?"":" (optional)"}`;return N(z,{gap:2,children:[E(z,{width:24,children:E(I,{bold:u,...u&&{color:"cyan"},children:_})}),E(I,{...u&&{color:"cyan"},children:">"}),E(I,{children:h}),u&&E(I,{color:"cyan",children:"\u2588"})]},s)})}),E(ke,{text:"Enter/Tab/\u2193 next \xB7 \u2191 previous \xB7 Backspace delete \xB7 Esc cancel"})]})}if(r.type==="artifact-select"){let{cursor:v,selected:c}=r;return N(z,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[E(q,{}),N(z,{flexDirection:"column",gap:0,children:[E(I,{bold:!0,children:"Which artifacts should we scaffold?"}),E(I,{dimColor:!0,children:"Each one gets a directory with a config.json and a script that runs."})]}),E(z,{flexDirection:"column",gap:0,children:X.map((a,s)=>{let l=v===s,u=c.includes(a);return N(z,{gap:1,children:[E(I,{...l&&{color:"cyan"},children:l?"\u276F":" "}),E(I,{...u&&{color:"green"},children:u?"\u25C9":"\u25EF"}),E(I,{bold:l,...l&&{color:"cyan"},children:Lt[a]})]},a)})}),E(ke,{text:"\u2191\u2193 move \xB7 Space toggle \xB7 a all \xB7 n none \xB7 Enter continue \xB7 Esc back"})]})}if(r.type==="confirm"){let v=Vt({targetDir:p,name:r.values.name,apiName:r.values.apiName,externalLink:r.values.externalLink,description:r.values.description,developerBusinessId:r.values.developerBusinessId,developerEnvironment:n});return N(z,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[E(q,{}),N(z,{flexDirection:"column",gap:0,children:[E(I,{bold:!0,children:"Ready to create"}),N(I,{dimColor:!0,children:["Target: ",p]})]}),N(z,{flexDirection:"column",gap:0,children:[E(I,{bold:!0,children:"kizen.json preview"}),E(I,{children:JSON.stringify(v,null,2)})]}),N(z,{flexDirection:"column",gap:0,children:[E(I,{bold:!0,children:"Artifacts"}),r.artifacts.length===0?N(I,{dimColor:!0,children:[" ","none (src/ will hold only thumbnail.png)"]}):r.artifacts.map(c=>N(I,{dimColor:!0,children:[" ",Lt[c]]},c))]}),N(z,{flexDirection:"column",gap:0,children:[E(I,{dimColor:!0,children:"Also creates:"}),N(I,{dimColor:!0,children:[" ",gt(p,"src/")]}),N(I,{dimColor:!0,children:[" ",gt(p,"src/thumbnail.png")," (generated placeholder)"]}),N(I,{dimColor:!0,children:[" ",gt(p,"releaseNotes/")]}),N(I,{dimColor:!0,children:[" ",gt(p,".gitignore")," (adds .kizenapp/)"]})]}),E(ke,{text:"Enter to create \xB7 Esc to go back"})]})}return r.type==="resolving-target"?E(z,{paddingY:1,paddingX:2,children:E(I,{dimColor:!0,children:"Finding available sub-directory\u2026"})}):r.type==="writing"?E(z,{paddingY:1,paddingX:2,children:E(I,{dimColor:!0,children:"Creating plugin\u2026"})}):r.type==="done"?N(z,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[E(q,{}),N(I,{color:"green",bold:!0,children:["Plugin created at ",r.targetDir]}),N(z,{flexDirection:"column",gap:0,children:[E(I,{dimColor:!0,children:"Next steps:"}),N(I,{children:[" ","cd ",r.targetDir]}),N(I,{children:[" ","npx --yes @kizenapps/cli dev"]}),N(I,{dimColor:!0,children:[" ","Replace src/thumbnail.png with real artwork before publishing."]})]}),E(ke,{text:"Enter or Esc to exit"})]}):N(z,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[E(q,{}),E(I,{color:"red",bold:!0,children:"Failed to create plugin"}),E(I,{children:r.message}),E(ke,{text:"Enter or Esc to exit"})]})};import{mkdir as nn,readFile as os,readdir as is,writeFile as on}from"fs/promises";import{homedir as ss}from"os";import{dirname as as,join as ht}from"path";var Y=["go","fmo","staging","integration","test1"];var Pe=ht(ss(),".kizenappbuilder"),De=ht(Pe,"credentials.json"),ye="credentials";function ls(e){return Y.includes(e)}function cs(e){if(typeof e!="object"||e===null)throw new Error("Credentials must be a JSON object");let t=e,n=t.environment;return{apiKey:typeof t.apiKey=="string"?t.apiKey:"",userId:typeof t.userId=="string"?t.userId:"",businessId:typeof t.businessId=="string"?t.businessId:"",environment:ls(n)?n:"go"}}async function be(e){let t=await os(e,"utf-8");return cs(JSON.parse(t))}async function Z(){try{return await be(De)}catch{return null}}async function ds(e){await nn(as(De),{recursive:!0,mode:448}),await on(De,JSON.stringify(e,null,2),{encoding:"utf-8",mode:384})}function sn(e){return ht(Pe,`${e}.json`)}async function Ie(){let e=[{name:ye,path:De,isDefault:!0}];try{let t=await is(Pe);for(let n of t){if(!n.endsWith(".json"))continue;let o=n.slice(0,-5);o!==ye&&e.push({name:o,path:ht(Pe,n),isDefault:!1})}}catch{}return e}async function an(e,t){if(e===ye){await ds(t);return}await nn(Pe,{recursive:!0,mode:448}),await on(sn(e),JSON.stringify(t,null,2),{encoding:"utf-8",mode:384})}async function de(e){try{return await be(sn(e))}catch{return null}}var ps="A hello-world Kizen plugin.";function us(e){if(e===void 0||e.trim()===""||e.trim()==="all")return[...X];if(e.trim()==="none")return[];let t=e.split(",").map(o=>o.trim()).filter(o=>o!==""),n=t.filter(o=>!X.includes(o));if(n.length>0)throw new Error(`Unknown artifact type(s): ${n.join(", ")}. Valid types: ${X.join(", ")}, or "all" / "none".`);return[...new Set(t)]}function fs(e,t,n){let o=e.name?.trim()??"";if(o==="")throw new Error("--name is required for a non-interactive run.");let r=(e.apiName?.trim()??"")||ft(o);if(!Jt.test(r))throw new Error(`api_name "${r}" is invalid: ${Wt}. Pass --api-name.`);let i=e.description?.trim(),d=e.businessId?.trim()??t.businessId,f=gs(e,t);return{targetDir:n,name:o,apiName:r,externalLink:e.externalLink?.trim()??"",description:i===void 0||i===""?ps:i,developerBusinessId:d,developerEnvironment:f,artifacts:us(e.artifacts)}}function ms(e){return Y.includes(e)}function gs(e,t){let n=e.environment?.trim();if(n!==void 0&&n!==""){if(!ms(n))throw new Error(`Unknown environment "${n}". Valid environments: ${Y.join(", ")}.`);return n}if(e.businessId!==void 0&&t.businessId==="")throw new Error("--environment is required alongside --business-id when no credentials are saved, so the id is keyed to the environment that issued it.");return t.environment}async function ln(e,t,n,o){let r;try{r=fs(e,t,n)}catch(f){o.writeStderr(`Error: ${f instanceof Error?f.message:String(f)}
|
|
299
|
+
`),o.setExitCode(1);return}let i=await o.precheckTargetDir(n);if(i!=="ok"){let f=i==="has-manifest"?"kizen.json":".kizenapp/";o.writeStderr(`Error: ${n} already contains ${f}. Refusing to overwrite an existing plugin.
|
|
300
|
+
`),o.setExitCode(1);return}try{await o.createPlugin(r)}catch(f){o.writeStderr(`Error: ${f instanceof Error?f.message:String(f)}
|
|
301
|
+
`),o.setExitCode(1);return}let d=r.artifacts&&r.artifacts.length>0?r.artifacts.join(", "):"none";o.writeStdout(`Created plugin ${r.apiName} at ${n}
|
|
302
|
+
`),o.writeStdout(`Artifacts: ${d}
|
|
303
|
+
`),o.writeStdout(`Thumbnail: src/thumbnail.png (generated placeholder; replace it before publishing)
|
|
304
|
+
`),r.developerBusinessId.trim()===""&&o.writeStderr(`Warning: no developer_business_id configured, so this plugin cannot be preview-published yet.
|
|
305
|
+
`)}function cn(e){e.command("create").description("Scaffold a new Kizen plugin project").option("-n, --name <name>","plugin display name (implies a non-interactive run)").option("-a, --api-name <name>","plugin api_name (inferred from --name when omitted)").option("-d, --description <text>","plugin description").option("-l, --external-link <url>","external link shown on the plugin listing").option("-b, --business-id <id>","developer business id (defaults to saved credentials)").option("-e, --environment <env>",`environment the business id belongs to: ${Y.join(", ")} (defaults to saved credentials)`).option("--artifacts <list>",`comma-separated artifact types, or "all" / "none" (default: all). Types: ${X.join(", ")}`).action(async t=>{let n=process.cwd(),o=await Z(),r=o?.businessId??"",i=o?.environment??"go",d=Object.values(t).some(m=>m!==void 0);if(!process.stdin.isTTY||!process.stdout.isTTY||d){await ln(t,{businessId:r,environment:i},n,{precheckTargetDir:dt,createPlugin:pt,writeStdout:m=>{process.stdout.write(m)},writeStderr:m=>{process.stderr.write(m)},setExitCode:m=>{process.exitCode=m}});return}let{waitUntilExit:g}=ys(hs(rn,{parentDir:n,defaultBusinessId:r,defaultEnvironment:i}),{exitOnCtrlC:!1});await g()})}import{createElement as Un}from"react";import{render as Vn}from"ink";import{useCallback as Fe,useEffect as St,useRef as pe,useState as Q}from"react";import{Box as K,Text as B,useInput as ma}from"ink";import{PluginValidationError as ga}from"@kizenapps/packager";import{watch as ha}from"fs";import{createServer as ya}from"http";import{join as Mn}from"path";import{WebSocketServer as ba}from"ws";import{createReadStream as _n,realpathSync as js}from"fs";import{access as $s,readdir as Ls,readFile as Ms,realpath as zs,stat as En}from"fs/promises";import{dirname as Hs,extname as kn,join as Ke,resolve as Us,sep as nr}from"path";import{fileURLToPath as Vs}from"url";var bs=new Set(["set-cookie","strict-transport-security","content-security-policy","content-security-policy-report-only","x-frame-options","content-encoding","content-length"]);function yt(e){let t={};for(let[n,o]of Object.entries(e)){let r=n.toLowerCase();bs.has(r)||r.startsWith("access-control-")||(t[n]=o)}return t}var Kt=10*1024*1024,xs=6e4,vs=200,Ue=class extends Error{bytesRead;limit;constructor(t,n){super(`Upstream response exceeded ${String(n)} bytes (read ${String(t)}).`),this.name="ProxyResponseTooLargeError",this.bytesRead=t,this.limit=n}};async function Gt(e,t){let n=e.body;if(n===null)return Buffer.alloc(0);let o=[],r=0;for await(let i of n){if(r+=i.length,r>t)throw new Ue(r,t);o.push(i)}return Buffer.concat(o)}async function dn(e){let t=yt(Object.fromEntries(e.headers)),n=await Gt(e,Kt);return{status:e.status,headers:t,body:n}}function pn(e={}){let{onChange:t,enabled:n=!0}=e;if(!n)return{async get(d,f){return{response:await dn(await f()),fromCache:!1}},clear(){}};let o=new Map,r=()=>{t?.(o.size)},i=d=>{o.delete(d)&&r()};return{get(d,f){let g=o.get(d);if(g!==void 0){if(Date.now()-g.insertedAt<xs)return g.promise.then(b=>({response:b,fromCache:!0}));i(d)}if(o.size>=vs){let b=o.keys().next().value;b!==void 0&&i(b)}let m=f().then(dn).catch(b=>{throw i(d),b});return o.set(d,{insertedAt:Date.now(),promise:m}),r(),m.then(b=>((b.status<200||b.status>=300)&&i(d),{response:b,fromCache:!1}))},clear(){o.clear(),r()}}}var Yt={".html":"text/html; charset=utf-8",".js":"application/javascript; charset=utf-8",".mjs":"application/javascript; charset=utf-8",".css":"text/css; charset=utf-8",".png":"image/png",".jpg":"image/jpeg",".svg":"image/svg+xml",".ico":"image/x-icon",".json":"application/json; charset=utf-8",".woff":"font/woff",".woff2":"font/woff2",".ttf":"font/ttf",".map":"application/json"};import{mkdir as ws,readFile as Cs,writeFile as Ss}from"fs/promises";import{join as un}from"path";async function xe(e){try{let t=await Cs(un(e,"config.json"),"utf-8");return JSON.parse(t)}catch{return{}}}async function ve(e,t){await ws(e,{recursive:!0}),await Ss(un(e,"config.json"),JSON.stringify(t,null,2),"utf-8")}var Xt={prod:"https://plugin-wizard.kizen.com",dev:"https://plugin-wizard.kizen.dev",localDev:"http://localhost:9823"};function Ve(e){let t=process.env.PLUGIN_WIZARD_URL;return t!==void 0&&t!==""?t:e==="prod"?process.env.PLUGIN_WIZARD_URL_PROD||Xt.prod:process.env.PLUGIN_WIZARD_URL_DEV!==void 0&&process.env.PLUGIN_WIZARD_URL_DEV!==""?process.env.PLUGIN_WIZARD_URL_DEV:process.env.APPBUILDER_LOCAL_DEV!==void 0&&process.env.APPBUILDER_LOCAL_DEV!==""?Xt.localDev:Xt.dev}import{spawn as tr}from"child_process";import{writeFile as yn,rm as er,mkdtemp as ks,access as Ps}from"fs/promises";import{join as Je}from"path";import{tmpdir as Is}from"os";var fn=`awslambdaric
|
|
9
306
|
bcrypt
|
|
307
|
+
boto3
|
|
10
308
|
fpdf2
|
|
11
309
|
lxml
|
|
12
310
|
msgpack
|
|
@@ -22,8 +320,8 @@ pytz
|
|
|
22
320
|
requests
|
|
23
321
|
sqlalchemy>=2.0,<2.1
|
|
24
322
|
tzdata
|
|
25
|
-
`;function
|
|
26
|
-
`).map(t=>t.trim().replace(/\s+#.*$/,"")).filter(t=>t.length>0&&!t.startsWith("#"))}function
|
|
323
|
+
`;function mn(e){return e.split(`
|
|
324
|
+
`).map(t=>t.trim().replace(/\s+#.*$/,"")).filter(t=>t.length>0&&!t.startsWith("#"))}function gn(e){let t=/^python-(\d+)[.-](\d+)$/.exec(e),n=t?.[1],o=t?.[2];return n!==void 0&&o!==void 0?`python${n}.${o}`:"python3"}function _s(e){return e==null||e.trim()===""?null:e}function Es(e){return e==null?null:typeof e=="string"?_s(e):typeof e=="number"||typeof e=="boolean"||typeof e=="bigint"?String(e):typeof e=="function"||typeof e=="symbol"?null:JSON.stringify(e)}function hn(e){return e?Object.fromEntries(Object.entries(e).map(([t,n])=>[t,Es(n)])):{}}var Rs=`
|
|
27
325
|
import sys, json, os, traceback
|
|
28
326
|
|
|
29
327
|
# --- Inputs proxy (attribute access) ---
|
|
@@ -183,29 +481,29 @@ sys.stdout.write('\\n__KIZEN_RESULT_START__\\n')
|
|
|
183
481
|
sys.stdout.write(json.dumps(result, ensure_ascii=False))
|
|
184
482
|
sys.stdout.write('\\n__KIZEN_RESULT_END__\\n')
|
|
185
483
|
sys.stdout.flush()
|
|
186
|
-
`.trim(),
|
|
187
|
-
`);for(;
|
|
188
|
-
`)}}),
|
|
189
|
-
`).trim(),h=g.length>0?`: ${g}`:"";r(new Error(`${e} exited with code ${String(m)}${h}`))}})})}var zt=null;function ri(e,t){if(Ve)return t&&zt?.add(t),Ve;let o=new Set;t&&o.add(t),zt=o;let n=i=>{for(let p of o)p(i)},r=Ue(ct,"bin","python");return Ve=(async()=>{try{let i=!1;try{await Yo(r);let p=await $r(r);i=p!==null&&Lr(p)}catch{i=!1}if(!i){await Mt(ct,{recursive:!0,force:!0}).catch(()=>{});let p=await ti(e);await Rr(p,["-m","venv",ct])}return n({kind:"start"}),await Rr(r,["-m","pip","install","--disable-pip-version-check",...Fr],(p,u)=>{n({kind:"log",line:p,stream:u})}),n({kind:"complete"}),r}catch(i){let p=i instanceof Error?i.message:String(i);throw n({kind:"error",message:p}),Ve=null,await Mt(ct,{recursive:!0,force:!0}).catch(()=>{}),i}finally{zt=null}})(),Ve}function ni(e){let t="__KIZEN_RESULT_START__",o="__KIZEN_RESULT_END__",n=e.indexOf(t),r=e.indexOf(o);if(n===-1||r===-1)return{userStdout:e,result:null};let i=e.slice(0,n).trimEnd(),p=e.slice(n+t.length,r).trim();try{let u=JSON.parse(p);return{userStdout:i,result:u}}catch{return{userStdout:e,result:null}}}function oi(e){return{success:!1,outputValues:{},logs:[],stdout:"",stderr:"",error:e,exitCode:1,durationMs:0}}async function Ar(e){let t=e.timeout??Qo;if(!ei(e.scriptRuntime))return oi(`Unsupported runtime "${e.scriptRuntime}". Supported runtimes: ${Dr.join(", ")}. Update the step's config.json "runtime" field (e.g. "python 3.13").`);let o=await ri(e.scriptRuntime,e.onInstallProgress),n=Date.now(),r;try{r=await Ko(Ue(Xo(),"kizen-step-"));let i=Ue(r,"wrapper.py"),p=Ue(r,"script.py");await Promise.all([Br(i,Zo,"utf-8"),Br(p,e.script,"utf-8")]);let u={...process.env,__KIZEN_INPUTS__:JSON.stringify(e.inputs),__KIZEN_SECRETS__:JSON.stringify(e.secrets),__KIZEN_SCRIPT_PATH__:p},{exitCode:m,stdout:g,stderr:h}=await new Promise(x=>{let T=[],E=[],b=!1,w=Ht(o,[i],{env:u,cwd:r,stdio:["ignore","pipe","pipe"]}),P=setTimeout(()=>{w.kill("SIGKILL")},t);w.stdout.on("data",l=>{T.push(l)}),w.stderr.on("data",l=>{E.push(l)});let f=l=>{b||(b=!0,clearTimeout(P),x({exitCode:l??1,stdout:Buffer.concat(T).toString("utf-8"),stderr:Buffer.concat(E).toString("utf-8")}))};w.on("close",f),w.on("error",l=>{b||(b=!0,clearTimeout(P),x({exitCode:1,stdout:"",stderr:l.message}))})}),S=Date.now()-n,{userStdout:I,result:v}=ni(g);if(v){let x={success:v.success,outputValues:v.outputValues,logs:v.logs,stdout:I,stderr:h,exitCode:m,durationMs:S};return v.error!==null&&(x.error=v.error),v.httpRequests&&(x.httpRequests=v.httpRequests),x}let c={success:!1,outputValues:{},logs:[],stdout:I,stderr:h,exitCode:m,durationMs:S};return m!==0&&(c.error=`Process exited with code ${String(m)}`),c}finally{r&&Mt(r,{recursive:!0,force:!0})}}var Or=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".json",".md",".mdx",".yml",".yaml",".toml",".css",".scss",".html",".htm",".xml",".svg",".txt",".sh",".py",".env",".gitignore",".prettierrc",".eslintrc"]);import{CRYPTO_ALG as Hr,CRYPTO_VERSION as Vr,deserializeEnvelope as fi,encrypt as mi,serializeEnvelope as gi}from"@kizenapps/packager";function Vt(e){if(e.kind==="info")return e.message;let t=e.fromCache?" [cache]":"",o=e.upstreamStatus!==void 0?` (upstream ${String(e.upstreamStatus)})`:"";return`${e.method} ${e.url} \u2192 ${String(e.status)}${o}${t}`}var yi=2*1024*1024,hi=new Set([".DS_Store",".gitignore"]);function xi(e){if(e===void 0||e==="")return!1;let t=e.startsWith("[")?e.slice(0,e.indexOf("]")+1):e.split(":")[0]??"";return t==="localhost"||t==="127.0.0.1"||t==="[::1]"}var Wr=["kizen.com","kizen.dev"];function bi(e){let t;try{t=new URL(e)}catch{return!1}let o=t.hostname.toLowerCase();return o==="localhost"||o==="127.0.0.1"||o==="[::1]"?!0:t.protocol!=="https:"?!1:Wr.some(n=>o===n||o.endsWith("."+n))}function vi(e){let t;try{t=new URL(e)}catch{return!1}if(t.protocol!=="https:")return!1;let o=t.hostname.toLowerCase();return Wr.some(n=>o===n||o.endsWith("."+n))}function wi(e){if(e===void 0||e==="")return!1;try{let{hostname:t}=new URL(e);return t==="localhost"||t==="127.0.0.1"||t==="::1"}catch{return!1}}async function Ur(e,t){if(t.includes("\0"))return null;let o=t.replace(/^\/+/,""),n=pi(e,o);if(n!==e&&!n.startsWith(e+Ut))return null;try{let r=await ci(n);return r!==e&&!r.startsWith(e+Ut)?null:r}catch{return null}}function qr(e,t){let o=t===e?"":t.slice(e.length+1);return o===""?!1:o.split(Ut).some(r=>Qe.has(r))}function Gr(){let e=ui(import.meta.url);return Je(di(e),"viewer")}function Jr(e,t,o){if(e.includes("/external-integrations/proxy")&&t["content-type"]?.includes("application/json"))try{let n=JSON.parse(o.toString("utf8"));return typeof n.status_code=="number"?n.status_code:void 0}catch{return}}async function qt(e){try{return await si(e),!0}catch{return!1}}function Kr(e,t,o,n,r,i,p,u,m,g,h){let S=Pr({onChange:u,enabled:h}),I=ii(g);return(v,c)=>{(async()=>{let x=v.url??"/";try{if(!xi(v.headers.host)){c.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Forbidden"}));return}if((v.method==="POST"||v.method==="PATCH"||v.method==="DELETE")&&!wi(v.headers.origin)){c.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Forbidden"}));return}if(t(`Received request: ${x}`),x==="/api/credentials"){c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({credentials:n.current??null,activeProfile:r.current??null}));return}if(x==="/api/credential-profiles"&&v.method==="GET"){let l=await ke();c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({profiles:l,active:r.current}));return}if(x==="/api/credentials/switch"&&v.method==="POST"){let l=[];for await(let y of v)l.push(y);let a=JSON.parse(Buffer.concat(l).toString("utf-8")||"{}").profile,d=a===void 0||a===""?await Y():await le(a);if(d!==null){n.current=d,r.current=a??void 0;let y=r.current,N=await he(i);await xe(i,{...N,credentialMode:"global",...y!==void 0&&{activeCredentialProfile:y}}),p({type:"credentials-updated",credentials:d,activeProfile:r.current??null})}c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({ok:d!==null}));return}if(x==="/api/bundle"){let l=Je(process.cwd(),".kizenapp","bundle.json");try{let s=await li(l,"utf-8");c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(s)}catch{c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end("{}")}return}if(x==="/api/last-path"&&v.method==="POST"){let l=[];for await(let a of v)l.push(a);let s=JSON.parse(Buffer.concat(l).toString("utf-8")||"{}");if(typeof s.path=="string"){m.current=s.path;let a=await he(i);await xe(i,{...a,lastPath:s.path})}c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end('{"ok":true}');return}if(x==="/api/encryption-target"&&v.method==="GET"){let s=(await he(i)).encryptionTarget==="dev"?"dev":"prod";c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({target:s}));return}if(x==="/api/encryption-target"&&v.method==="POST"){let l=[];for await(let y of v)l.push(y);let s=JSON.parse(Buffer.concat(l).toString("utf-8")||"{}"),a=s!==null&&typeof s=="object"?s:{};if(a.target!=="dev"&&a.target!=="prod"){c.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"target must be one of: 'dev', 'prod'"}));return}let d=await he(i);await xe(i,{...d,encryptionTarget:a.target}),c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end('{"ok":true}');return}if(x==="/api/execute-step"&&v.method==="POST"){let l=[];for await(let y of v)l.push(y);let s=JSON.parse(Buffer.concat(l).toString("utf-8")||"{}");if(typeof s.script!="string"){c.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Missing required field: script"}));return}let a={script:s.script,scriptRuntime:s.scriptRuntime??"python-3-13",inputs:s.inputs??{},secrets:s.secrets??{},onInstallProgress:y=>{y.kind==="start"?p({type:"venv-install-start"}):y.kind==="log"?p({type:"venv-install-log",line:y.line,stream:y.stream}):y.kind==="complete"?p({type:"venv-install-complete"}):p({type:"venv-install-error",message:y.message})}};typeof s.timeout=="number"&&s.timeout>0&&(a.timeout=Math.min(s.timeout,300*1e3));let d=await Ar(a);c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify(d));return}if(x==="/api/proxy-cache/clear"){S.clear(),o({kind:"info",message:"Proxy cache cleared"}),c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end('{"ok":true}');return}if(x==="/api/local/encrypt"&&v.method==="POST"){let l=[];for await(let a of v)l.push(a);let s=JSON.parse(Buffer.concat(l).toString("utf-8")||"{}");if(typeof s.publicKeyPem!="string"||typeof s.value!="string"){c.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Missing required fields: publicKeyPem, value"}));return}try{let a=mi(s.value,s.publicKeyPem),d=gi(a);c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify(d))}catch(a){c.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:a.message}))}return}if(x==="/api/local/validate"&&v.method==="POST"){let l=[];for await(let k of v)l.push(k);let s=JSON.parse(Buffer.concat(l).toString("utf-8")||"{}");if(typeof s.value!="string"){c.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Missing required field: value"}));return}let a,d;try{a=fi(s.value)}catch(k){d=k.message}if(d!==void 0||a===void 0){c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({valid:!1,checks:[],error:d}));return}let y=k=>Buffer.from(k,"base64").length,N=[{label:"Version",expected:String(Vr),actual:String(a.v),pass:a.v===Vr},{label:"Algorithm",expected:Hr,actual:a.alg,pass:a.alg===Hr},{label:"Wrapped key",expected:"384 bytes (RSA-3072)",actual:`${String(y(a.k))} bytes`,pass:y(a.k)===384},{label:"IV",expected:"12 bytes",actual:`${String(y(a.iv))} bytes`,pass:y(a.iv)===12},{label:"Auth tag",expected:"16 bytes",actual:`${String(y(a.tag))} bytes`,pass:y(a.tag)===16},{label:"Ciphertext",expected:"\u2265 1 byte",actual:`${String(y(a.ct))} bytes`,pass:y(a.ct)>=1}];c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({valid:N.every(k=>k.pass),checks:N}));return}if(x.startsWith("/api/wizard")){let l=v.headers["x-encryption-target"],a=(Array.isArray(l)?l[0]:l)==="dev"?"dev":"prod",d=He(a);if(!bi(d)){c.writeHead(500,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:`Encryption API host is not allowed: ${d}`}));return}let y=x.slice(11)||"/",N=`${d}${y}`,k=v.method??"GET",A=[];for await(let we of v)A.push(we);let{host:M,"x-encryption-target":K,...Q}=v.headers,ne=A.length>0?Buffer.concat(A):void 0,oe=ne&&ne.length>0?ne:void 0,ee;try{ee=await fetch(N,{method:k,headers:Q,...oe!==void 0&&{body:oe}})}catch(we){let vt=we.code==="ECONNREFUSED"?`plugin-wizard is not running at ${d}`:`Failed to reach plugin-wizard: ${we.message}`;c.writeHead(503,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:vt}));return}let Z=lt(Object.fromEntries(ee.headers)),Fe=await ee.arrayBuffer();c.writeHead(ee.status,Z),c.end(Buffer.from(Fe));return}if(x.startsWith("/api/proxy")){let l=v.headers["x-proxy-target"];if(typeof l!="string"){c.writeHead(400),c.end("Missing x-proxy-target header");return}if(!vi(l)){c.writeHead(400),c.end("Invalid proxy target");return}let s=x.slice(10)||"/",a=`${l}${s}`,d=v.method??"GET",y=[];for await(let ee of v)y.push(ee);let{host:N,"x-proxy-target":k,...A}=v.headers;if(d==="GET"){let ee=`GET::${a}`,{response:Z,fromCache:Fe}=await S.get(ee,()=>fetch(a,{method:"GET",headers:A}));o({kind:"request",method:"GET",status:Z.status,upstreamStatus:Jr(s,Z.headers,Z.body),fromCache:Fe,url:s}),c.writeHead(Z.status,Z.headers),c.end(Z.body);return}let M=y.length>0?Buffer.concat(y):void 0,K=M&&M.length>0?M:void 0,Q=await fetch(a,{method:d,headers:A,...K!==void 0&&{body:K}}),ne=lt(Object.fromEntries(Q.headers)),oe=await $t(Q,Lt);o({kind:"request",method:d,status:Q.status,upstreamStatus:Jr(s,ne,oe),fromCache:!1,url:s}),c.writeHead(Q.status,ne),c.end(oe);return}if(x.startsWith("/api/source/tree")&&v.method==="GET"){let s=new URL(x,"http://localhost").searchParams.get("path")??"",a=await Ur(I,s);if(a===null){c.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Invalid path"}));return}if(qr(I,a)){c.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Path is excluded"}));return}try{let d=await ai(a,{withFileTypes:!0}),y=await Promise.all(d.filter(k=>k.isDirectory()?!Qe.has(k.name):k.isFile()?!hi.has(k.name):!1).map(async k=>{let A=k.isDirectory()?"dir":"file",M={name:k.name,kind:A};if(A==="file")try{let K=await zr(Je(a,k.name));M.size=K.size}catch{}return M}));y.sort((k,A)=>k.kind!==A.kind?k.kind==="dir"?-1:1:k.name.localeCompare(A.name));let N=a===I?"":a.slice(I.length+1);c.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({path:N,entries:y}))}catch(d){let y=d instanceof Error?d.message:String(d);t(`source/tree failed (${s}): ${y}`),c.writeHead(404,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Not found"}))}return}if(x.startsWith("/api/source/file")&&v.method==="GET"){let s=new URL(x,"http://localhost").searchParams.get("path")??"";if(s===""){c.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Missing path"}));return}let a=await Ur(I,s);if(a===null){c.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Invalid path"}));return}if(qr(I,a)){c.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Path is excluded"}));return}try{let d=await zr(a);if(!d.isFile()){c.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Not a file"}));return}if(d.size>yi){c.writeHead(413,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"File too large",size:d.size}));return}let y=Mr(a).toLowerCase(),N=At[y],k=Or.has(y),A=N??(k?"text/plain; charset=utf-8":"application/octet-stream");c.writeHead(200,{"Content-Type":A,"Content-Length":String(d.size)}),jr(a).pipe(c)}catch(d){let y=d instanceof Error?d.message:String(d);t(`source/file failed (${s}): ${y}`),c.writeHead(404,{"Content-Type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:"Not found"}))}return}let b=Je(e,x==="/"?"/index.html":x),w=await qt(b)?b:Je(e,"index.html"),P=Mr(w),f=At[P]??"application/octet-stream";c.writeHead(200,{"Content-Type":f}),jr(w).pipe(c)}catch(T){if(x.startsWith("/api/proxy")){let E=x.slice(10)||"/",b=v.method??"GET";T instanceof Me?o({kind:"info",message:`${b} ${E} \u2192 502 (response exceeded ${String(T.limit)} bytes)`}):o({kind:"request",method:b,status:502,fromCache:!1,url:E})}else o({kind:"info",message:`Error handling ${x}: ${T instanceof Error?T.message:String(T)}`});c.headersSent||(c.writeHead(502),c.end("Bad Gateway"))}})()}}import{launch as Ci}from"chrome-launcher";import{createRequire as Si}from"module";import{mkdirSync as Ti}from"fs";import{readFile as Ei}from"fs/promises";import{dirname as Pi,join as ki}from"path";import{fileURLToPath as _i}from"url";var Yr=Si(import.meta.url)("chrome-remote-interface"),Ii=new Set(["content-security-policy","content-security-policy-report-only","x-frame-options"]),Zr=["kizen.dev","kizen.com"];function Xr(e){try{let{hostname:t}=new URL(e);return Zr.some(o=>t===o||t.endsWith("."+o))}catch{return!1}}async function Ni(e){try{let t=ki(Pi(_i(import.meta.url)),"viewer","icon.png"),o=await Ei(t);await e.Browser.setDockTile({image:o.toString("base64")})}catch{}}async function Qr(e){Ti(e.userDataDir,{recursive:!0});let t=`http://localhost:${String(e.port)}`,o=await Ci({startingUrl:t,chromeFlags:[`--app=${t}`,"--no-first-run","--no-default-browser-check","--disable-extensions","--disable-features=DeviceBoundSessions"],userDataDir:e.userDataDir,handleSIGINT:!1,logLevel:"silent"}),n=o.port,r=null,i=null,p=null,u=null,m=0,g=!1,h=w=>{e.debugLog?.(w)},S=w=>{e.verbose&&e.debugLog?.(w)},I=()=>{i!==null&&(clearInterval(i),i=null)},v=w=>w==="chrome://new-tab-page/"||w==="chrome://newtab/",c=async w=>{I(),p=null,await Ni(w),await w.Fetch.enable({patterns:Zr.flatMap(f=>[{urlPattern:`*://${f}/*`,requestStage:"Response"},{urlPattern:`*://*.${f}/*`,requestStage:"Response"}])}),w.on("Fetch.requestPaused",f=>{(async()=>{let l=f,{requestId:s,request:a,responseHeaders:d,responseStatusCode:y}=l,N=a.url;S(`Fetch ${String(y??"?")} ${N}`);let k=[],A=!1;for(let M of d??[])if(!Ii.has(M.name.toLowerCase()))if(M.name.toLowerCase()==="set-cookie"&&Xr(N)){let K=M.value.split(`
|
|
190
|
-
`).map(
|
|
191
|
-
`);k.push({name:M.name,value:K}),A=!0}else k.push(M);A&&S(` rewrote Set-Cookie SameSite on ${N}`);try{let{body:M,base64Encoded:K}=await w.Fetch.getResponseBody({requestId:s});await w.Fetch.fulfillRequest({requestId:s,responseCode:y??200,responseHeaders:k,body:M,...K&&{base64Encoded:!0}})}catch(M){S(` fulfillRequest failed (${M.message}), falling through`);try{await w.Fetch.continueRequest({requestId:s})}catch(K){S(` continueRequest also failed (${K.message})`)}}})()}),i=setInterval(()=>{(async()=>{try{let{cookies:f}=await w.Network.getAllCookies(),l=0;for(let s of f){if(!Xr(`https://${s.domain??""}`)||s.sameSite==="None")continue;let a=s.domain??"",d=a.startsWith(".")?a.slice(1):a;await w.Network.setCookie({url:`https://${d}`,name:s.name,value:s.value,domain:a,path:s.path??"/",secure:!0,...s.httpOnly!==void 0&&{httpOnly:s.httpOnly},...s.expirationDate!==void 0&&{expires:s.expirationDate},sameSite:"None"}),l++}l>0&&S(`cookie-patch cycle: updated ${String(l)} cookie(s) to SameSite=None`)}catch(f){S(`cookie-patch cycle failed: ${f.message}`)}})()},2e3),await w.Target.setDiscoverTargets({discover:!0});let P=f=>{if(f.type==="page"){if(v(f.url)){h(`closed stray new-tab-page target ${f.targetId}`),p!==null&&w.Target.activateTarget({targetId:p}).catch(()=>{}),w.Target.closeTarget({targetId:f.targetId}).catch(()=>{});return}p===null&&(p=f.targetId,h(`captured main target ${f.targetId} (${f.url})`))}};w.on("Target.targetCreated",f=>{let{targetInfo:l}=f;S(`target +${l.type} ${l.targetId} ${l.url}`),P(l)}),w.on("Target.targetInfoChanged",f=>{let{targetInfo:l}=f;S(`target ~${l.type} ${l.targetId} ${l.url}`),P(l)}),w.on("disconnect",()=>{g||r!==w||(h("CDP disconnected"),r=null,I(),x())})},x=()=>{if(g||u!==null)return;let w=Math.min(1e3*2**m,1e4),P=m+1;m++,h(`CDP reconnect scheduled in ${String(w)}ms (attempt #${String(P)})`),u=setTimeout(()=>{u=null,(async()=>{let f;try{f=await Yr({port:n})}catch{h(`CDP reconnect attempt #${String(P)} failed`),x();return}if(g){try{await f.close()}catch{}return}r=f;try{await c(f),h(`CDP reconnected after ${String(P)} attempt(s)`),m=0}catch{r===f&&(r=null);try{await f.close()}catch{}h(`CDP reconnect attempt #${String(P)} failed during setup`),x()}})()},w)},T=30,E=300;for(let w=0;w<T;w++){await new Promise(P=>setTimeout(P,E)),h(`CDP connect attempt ${String(w+1)}/${String(T)}`);try{let P=await Yr({port:n});r=P,e.path&&P.send("Page.navigate",{url:`${t}${e.path}`});try{await c(P),h("CDP connected")}catch{r===P&&(r=null);try{await P.close()}catch{}h("CDP setup failed after connect")}break}catch{if(w===T-1){let P=`CDP unavailable after ${String(T)} attempts \u2014 viewer running without interception (CSP/cookie rewrites disabled)`;return h(P),e.onWarn?.(P),{kill:()=>{o.kill()}}}}}return r?{kill:()=>{if(h("CDP kill requested \u2014 tearing down"),g=!0,u!==null&&(clearTimeout(u),u=null),I(),r!==null){try{r.close()}catch{}r=null}o.kill()}}:{kill:()=>{o.kill()}}}import{useCallback as Bi,useState as Ri}from"react";function dt(e){let[t,o]=Ri([]),n=Bi(r=>{o(i=>[...i,`${new Date().toLocaleTimeString()}: ${r}`].slice(-e))},[e]);return[t,n]}import{useCallback as pt,useEffect as Jt,useState as ut}from"react";import{Box as V,Text as $,useInput as Di}from"ink";import{jsx as _,jsxs as J}from"react/jsx-runtime";var be=["apiKey","userId","businessId"],Fi={apiKey:"API Key",userId:"User ID",businessId:"Business ID"},We=({text:e})=>_($,{dimColor:!0,children:e}),ft=({initialMode:e,showProfileManager:t,onComplete:o,onCancel:n})=>{let[r,i]=ut(e==="global"&&!t?{type:"loading"}:e==="global"&&t?{type:"profile-loading"}:{type:"mode-select",cursor:0}),[p,u]=ut(""),[m,g]=ut(null),[h,S]=ut(void 0),I=pt(f=>{if(f==="local"){o({mode:"local",credentials:null});return}i({type:"profile-loading"})},[o]),v=pt(async f=>{if(f===null){i({type:"profile-loading"});let a=await ke();i({type:"name-entry",nameBuffer:"",existingProfiles:a});return}S(f.isDefault?void 0:f.name),i({type:"loading"});let l=f.isDefault?await Y():await le(f.name),s=l?Math.max(0,re.indexOf(l.environment)):0;i({type:"creds-entry",field:0,values:l??{},envCursor:s})},[]),c=pt(async(f,l)=>{let s=re[l]??"go",a={apiKey:f.apiKey??"",userId:f.userId??"",businessId:f.businessId??"",environment:s};i({type:"saving"});try{await Sr(h??ge,a),o({mode:"global",credentials:a,...h!==void 0&&{profileName:h}})}catch(d){g(d instanceof Error?d.message:String(d)),i({type:"creds-entry",field:0,values:f,envCursor:l})}},[o,h]);Di((f,l)=>{if(l.ctrl&&f==="c"&&process.exit(0),l.escape){if((r.type==="creds-entry"||r.type==="name-entry")&&e==="global"&&t){i({type:"profile-loading"}),x();return}n?.();return}if(r.type==="mode-select"){if(l.upArrow)i({type:"mode-select",cursor:0});else if(l.downArrow)i({type:"mode-select",cursor:1});else if(l.return){let s=r.cursor===0?"global":"local";I(s)}return}if(r.type==="profile-select"){let{profiles:s,cursor:a}=r,d=s.length,y=s.length+1;if(l.upArrow)i({...r,cursor:(a-1+y)%y});else if(l.downArrow)i({...r,cursor:(a+1)%y});else if(l.return)if(a===d)i({type:"name-entry",nameBuffer:"",existingProfiles:s});else{let N=s[a]??s[0];N&&v(N)}return}if(r.type==="name-entry"){let{nameBuffer:s,existingProfiles:a}=r;if(l.backspace||l.delete)i({type:"name-entry",nameBuffer:s.slice(0,-1),existingProfiles:a});else if(l.return){let d=s.trim();if(!d){i({...r,nameError:"Name cannot be empty"});return}if(d===ge){i({...r,nameError:`"${ge}" is reserved`});return}if(a.some(y=>y.name===d)){i({...r,nameError:`Profile "${d}" already exists`});return}S(d),i({type:"creds-entry",field:0,values:{},envCursor:0}),u("")}else f&&!l.ctrl&&!l.meta&&i({type:"name-entry",nameBuffer:s+f,existingProfiles:a});return}if(r.type==="creds-entry"){let{field:s,values:a,envCursor:d}=r;if(s===be.length){l.leftArrow?i({...r,envCursor:(d-1+re.length)%re.length}):l.rightArrow?i({...r,envCursor:(d+1)%re.length}):l.upArrow?(i({...r,field:s-1}),u(a[be[s-1]]??"")):l.return&&c(a,d);return}let N=be[s];if(!N)return;if(l.backspace||l.delete)u(k=>k.slice(0,-1));else if(l.upArrow&&s>0){let k={...a,[N]:p},A=s-1;i({...r,field:A,values:k}),u(k[be[A]]??"")}else if(l.return||l.tab||l.downArrow){let k={...a,[N]:p},A=s+1;i({...r,field:A,values:k}),A<be.length?u(k[be[A]]??""):u("")}else f&&!l.ctrl&&!l.meta&&u(k=>k+f)}});let x=pt(async()=>{let f=await ke();i({type:"profile-select",profiles:f,cursor:0})},[]);if(Jt(()=>{r.type==="profile-loading"&&x()},[r.type,x]),Jt(()=>{e==="global"&&!t&&(async()=>{let f=await Y(),l=f?Math.max(0,re.indexOf(f.environment)):0;i({type:"creds-entry",field:0,values:f??{},envCursor:l})})()},[]),Jt(()=>{r.type==="creds-entry"&&r.field===0&&u(r.values.apiKey??"")},[r.type]),r.type==="loading"||r.type==="saving"||r.type==="profile-loading"){let f=r.type==="saving"?"Saving credentials\u2026":r.type==="profile-loading"?"Loading profiles\u2026":"Loading credentials\u2026";return _(V,{paddingY:1,paddingX:2,children:_($,{dimColor:!0,children:f})})}if(r.type==="done")return null;if(r.type==="mode-select")return J(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[_(q,{}),J(V,{flexDirection:"column",gap:0,children:[_($,{bold:!0,children:"Credential mode"}),[{label:"Global",desc:"~/.kizenappbuilder/credentials.json",mode:"global"},{label:"Local",desc:"Enter credentials in the browser dev tools",mode:"local"}].map((l,s)=>{let a=r.cursor===s;return J(V,{gap:2,children:[_($,{...a&&{color:"cyan"},children:a?"\u276F":" "}),_($,{bold:a,...a&&{color:"cyan"},children:l.label}),_($,{dimColor:!0,children:l.desc})]},l.mode)})]}),_(We,{text:"\u2191\u2193 to move \xB7 Enter to select \xB7 Ctrl+C to quit"})]});if(r.type==="profile-select"){let{profiles:f,cursor:l}=r,s=f.length;return J(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[_(q,{}),J(V,{flexDirection:"column",gap:0,children:[_($,{bold:!0,children:"Credential profiles"}),f.map((a,d)=>{let y=l===d;return J(V,{gap:2,children:[_($,{...y&&{color:"cyan"},children:y?"\u276F":" "}),_($,{bold:y,...y&&{color:"cyan"},children:a.isDefault?"Default":a.name}),_($,{dimColor:!0,children:a.path})]},a.name)}),J(V,{gap:2,children:[_($,{...l===s&&{color:"cyan"},children:l===s?"\u276F":" "}),_($,{bold:l===s,...l===s&&{color:"cyan"},children:"+ Add new profile"})]})]}),_(We,{text:"\u2191\u2193 to move \xB7 Enter to select \xB7 Esc to cancel"})]})}if(r.type==="name-entry"){let{nameBuffer:f,nameError:l}=r;return J(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[_(q,{}),_(V,{flexDirection:"column",gap:0,children:_($,{bold:!0,children:"New credential profile"})}),l&&J($,{color:"red",children:["Error: ",l]}),J(V,{gap:2,children:[_(V,{width:12,children:_($,{bold:!0,color:"cyan",children:"Profile name"})}),_($,{color:"cyan",children:">"}),_($,{children:f}),_($,{color:"cyan",children:"\u2588"})]}),_(We,{text:"Type a name \xB7 Enter to confirm \xB7 Esc to go back"})]})}let{field:T,values:E,envCursor:b}=r,w=T===be.length,P=h??ge;return J(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[_(q,{}),J(V,{flexDirection:"column",gap:0,children:[_($,{bold:!0,children:h!==void 0?`Profile: ${h}`:"Global credentials"}),J($,{dimColor:!0,children:["Saved to:"," ",h!==void 0?`~/.kizenappbuilder/${h}.json`:Re]})]}),m&&J($,{color:"red",children:["Error: ",m]}),J(V,{flexDirection:"column",gap:0,children:[be.map((f,l)=>{let s=T===l,a=s?p:E[f]??"";return J(V,{gap:2,children:[_(V,{width:12,children:_($,{bold:s,...s&&{color:"cyan"},children:Fi[f]})}),_($,{...s&&{color:"cyan"},children:">"}),_($,{children:a}),s&&_($,{color:"cyan",children:"\u2588"})]},f)}),J(V,{gap:2,children:[_(V,{width:12,children:_($,{bold:w,...w&&{color:"cyan"},children:"Environment"})}),_($,{...w&&{color:"cyan"},children:">"}),_(V,{gap:1,children:re.map((f,l)=>{let s=l===b;return w?_($,{bold:s,...s&&{color:"cyan"},children:s?`[${f}]`:f},f):_($,{dimColor:!s,bold:s,children:f},f)})})]})]}),w?_(We,{text:"\u2190\u2192 to select \xB7 \u2191\u2193 to move \xB7 Enter to save \xB7 Esc to cancel"}):_(We,{text:"\u2191\u2193 to move \xB7 Backspace to delete \xB7 Esc to cancel"}),J($,{dimColor:!0,children:["Profile: ",P]})]})};import{jsx as F,jsxs as H}from"react/jsx-runtime";var Mi=[".kizenapp",".git"],tn=({port:e,pluginDir:t,outputDir:o,credentials:n,credentialMode:r,activeCredentialProfile:i,lastPath:p,debug:u=!1,verbose:m=!1,autoViewer:g=!0,cacheEnabled:h=!0})=>{let S=ce(n),I=ce(i),v=ce(p),[c,x]=X("main"),[T,E]=X(r),[b,w]=X("starting"),[P,f]=X(null),[l,s]=dt(50),[a,d]=dt(50),[y,N]=dt(50),[k,A]=X([]),[M,K]=X("pending"),[Q,ne]=X(null),[oe,ee]=X(null),[Z,Fe]=X(null),[we,vt]=X(null),[wt,Ct]=X(0),[Yt,Mn]=X(0),[Hn,Vn]=X(0),[St,Un]=X(0),Tt=ce(!1),Xt=ce(!1),Ke=ce(null),Le=ce(null),de=ce(new Set),Ye=ce([]),te=De(C=>{let j=JSON.stringify(C);if(de.current.size===0){Ye.current=[...Ye.current,j].slice(-50);return}let pe=!1;for(let ie of de.current)if(ie.readyState===1)try{ie.send(j)}catch{de.current.delete(ie),pe=!0}pe&&Ct(de.current.size)},[]),Xe=s,Et=De(()=>{Ke.current?.kill(),Ke.current=null,Qr({port:e,userDataDir:en(o,".chrome"),broadcast:te,onWarn:C=>{s(`\u26A0 ${C}`)},...v.current!==void 0&&{path:v.current},...u&&{debugLog:N},...m&&{verbose:!0}}).then(C=>{Ke.current=C})},[e,o,te,u,m,N,s]);mt(()=>{let C=()=>{Ke.current?.kill()};return process.on("exit",C),()=>{process.off("exit",C)}},[]),$i((C,j)=>{(C==="q"||j.ctrl&&C==="c")&&process.exit(0),C==="c"&&x("editing"),C==="v"&&Et()},{isActive:c==="main"}),mt(()=>{b!=="running"||Xt.current||!g||(Xt.current=!0,Et())},[b,g,Et]);let qn=De(C=>{S.current=C.credentials,I.current=C.profileName,x("main"),E(C.mode);let j=C.profileName;xe(o,{credentialMode:C.mode,...j!==void 0&&{activeCredentialProfile:j}}),te({type:"credentials-updated",credentials:C.credentials})},[o,te]),Zt=De(C=>{A(j=>[...j,`${new Date().toLocaleTimeString()}: ${Vt(C)}`].slice(-50)),C.kind==="request"&&(C.fromCache?Vn(j=>j+1):Un(j=>j+1)),te({type:"proxy-log",entry:C})},[te]),Ce=De(C=>{d(C),te({type:"log",message:C})},[d,te]),Pt=De(()=>{Tt.current||(Tt.current=!0,K("building"),ne(null),ee(null),Ce("Build started"),tt(t,o).then(({bundleSize:C})=>{Ce(`Build finished \u2014 bundle: ${$e(C)}`),K("done"),Fe(new Date),vt(C),Ce("Notifying viewers to reload"),te({type:"rebuild"})}).catch(C=>{C instanceof Ai?(ee(C.issues),ne(null)):(ne(C instanceof Error?C.message:String(C)),ee(null)),K("error")}).finally(()=>{Tt.current=!1}))},[t,o,Ce,te]);if(mt(()=>{Pt();let C=Oi(t,{recursive:!0},(j,pe)=>{if(!pe)return;let ie=pe.replace(/\\/g,"/");Mi.some(Ze=>ie.startsWith(Ze))||(Ce(`File change detected: ${pe}`),Le.current!==null&&clearTimeout(Le.current),Le.current=setTimeout(Pt,150))});return C.on("error",j=>{Ce(`File watcher error \u2014 rebuilds have stopped: ${j.message}`)}),()=>{C.close(),Le.current!==null&&clearTimeout(Le.current)}},[t,Pt,Ce]),mt(()=>{let C=Gr();qt(en(C,"index.html")).then(j=>{if(!j){f("Viewer not built. Run 'pnpm build:viewer' first."),w("error");return}let pe=Kr(C,Xe,Zt,S,I,o,te,Mn,v,t,h),ie=ji(pe),Ze=new zi({server:ie});return Ze.on("connection",Se=>{for(let Wn of Ye.current)Se.readyState===1&&Se.send(Wn);Ye.current=[],Xe("Viewer connected for live reload"),de.current.add(Se),Ct(de.current.size),Se.on("close",()=>{de.current.delete(Se),Ct(de.current.size)})}),ie.listen(e,"127.0.0.1",()=>{w("running"),Xe(`Server started on 127.0.0.1:${String(e)}`)}),ie.on("error",Se=>{f(Se.message),w("error")}),()=>{Ze.close(),ie.close()}})},[e,Xe,Zt,te,o,t,h]),c==="editing")return F(ft,{...T!==void 0&&{initialMode:T},showProfileManager:T==="global",onComplete:qn,onCancel:()=>{x("main")}});let kt=Z!==null?Math.round((Date.now()-Z.getTime())/1e3):null,Jn=kt===null?"":kt<5?" (just now)":` (${String(kt)}s ago)`,Qt=oe?.filter(C=>C.severity==="error").length??0;return H(W,{flexDirection:"column",paddingY:1,paddingX:2,children:[F(q,{marginBottom:1}),H(W,{flexDirection:"column",children:[H(W,{gap:2,marginBottom:0,children:[F(D,{bold:!0,dimColor:!0,children:"App Build"}),M==="pending"&&F(D,{dimColor:!0,children:"waiting\u2026"}),M==="building"&&H(W,{gap:1,children:[F(ue,{}),F(D,{children:"Building plugin package\u2026"})]}),M==="done"&&H(W,{gap:1,children:[F(D,{color:"green",children:"\u2713 Built"}),Z!==null&&H(D,{dimColor:!0,children:["at ",Z.toLocaleTimeString(),Jn]}),we!==null&&H(D,{dimColor:!0,children:["\xB7 bundle: ",$e(we)]})]}),M==="error"&&(oe!==null?H(D,{color:"red",children:["\u2717 ",Qt," validation ",Qt===1?"error":"errors"]}):H(D,{color:"red",children:["\u2717 ",Q??"unknown error"]}))]}),oe!==null&&F(nt,{issues:oe}),F(W,{flexDirection:"column",height:10,borderStyle:"single",borderColor:"gray",overflow:"hidden",children:a.slice(-8).map((C,j)=>F(D,{dimColor:!0,wrap:"truncate",children:C},j))})]}),H(W,{marginTop:1,flexDirection:"column",children:[H(W,{gap:2,children:[F(D,{bold:!0,dimColor:!0,children:"Web Server"}),b==="starting"&&F(D,{dimColor:!0,children:"starting\u2026"}),b==="running"&&H(W,{gap:2,children:[F(D,{color:"green",children:"\u2713 Running"}),H(D,{dimColor:!0,children:["\u25CF ",wt," viewer",wt!==1?"s":""]})]}),b==="error"&&H(D,{color:"red",children:["\u2717 ",P??"Server error"]})]}),F(W,{flexDirection:"column",height:10,borderStyle:"single",borderColor:"gray",overflow:"hidden",children:l.slice(-8).map((C,j)=>F(D,{dimColor:!0,wrap:"truncate",children:C},j))})]}),H(W,{marginTop:1,flexDirection:"column",children:[H(W,{gap:2,children:[F(D,{bold:!0,dimColor:!0,children:"Network Proxy"}),F(D,{color:"green",children:"\u2713 Active"}),F(D,{dimColor:!0,children:h?`\u25CF ${String(Yt)} key${Yt!==1?"s":""} in the network cache \xB7 ${String(Hn)} hit \xB7 ${String(St)} miss`:`\u25CF network cache disabled \xB7 ${String(St)} request${St!==1?"s":""}`})]}),F(W,{flexDirection:"column",height:10,borderStyle:"single",borderColor:"gray",overflow:"hidden",children:k.length===0?F(D,{dimColor:!0,children:" No requests yet."}):k.slice(-8).map((C,j)=>F(D,{dimColor:!0,wrap:"truncate",children:C},j))})]}),u&&H(W,{marginTop:1,flexDirection:"column",children:[H(W,{gap:2,children:[F(D,{bold:!0,dimColor:!0,children:"CDP Debug"}),H(D,{dimColor:!0,children:["\u25CF ",y.length," event(s)"]})]}),F(W,{flexDirection:"column",height:10,borderStyle:"single",borderColor:"gray",overflow:"hidden",children:y.length===0?F(D,{dimColor:!0,children:" No CDP events yet."}):y.slice(-8).map((C,j)=>F(D,{dimColor:!0,wrap:"truncate",children:C},j))})]}),H(W,{marginTop:1,gap:1,children:[F(D,{dimColor:!0,children:"["}),F(D,{children:"q"}),F(D,{dimColor:!0,children:"] quit ["}),F(D,{children:"c"}),F(D,{dimColor:!0,children:"] credentials ["}),F(D,{children:"v"}),H(D,{dimColor:!0,children:["] ",wt===0?"open viewer":"relaunch viewer"]})]})]})};async function rn(e){return new Promise(t=>{let o=null,n=i=>{o?.(),t(i)},{unmount:r}=on(nn(ft,{...e!==void 0&&{initialMode:e},onComplete:n}),{exitOnCtrlC:!1});o=r})}function sn(e){e.command("dev").description("Start the plugin viewer dev server").option("-p, --port <port>","port to listen on","3121").option("-c, --credentials <path>","path to a credentials JSON file").option("-d, --debug","Enable CDP lifecycle logs in the TUI").option("-v, --verbose","Log every CDP event and handled error (implies --debug)").option("--no-viewer","Don't auto-launch the viewer on startup (press [v] to launch manually)").option("--no-cache","Disable the network proxy cache (always fetch upstream)").action(async t=>{let o=parseInt(t.port,10),n=process.cwd(),r=`${n}/.kizenapp`;Ne(n);let i=null,p,u,{lastPath:m}=await he(r);if(t.credentials)i=await ye(t.credentials);else{let c=await he(r);if(c.credentialMode==="local")p="local";else if(c.credentialMode==="global"){if(p="global",u=c.activeCredentialProfile,u?(i=await le(u),i||(i=await Y(),u=void 0)):i=await Y(),!i){let x=await rn("global");i=x.credentials,u=x.profileName}}else{let x=await rn();i=x.credentials,p=x.mode,u=x.profileName;let T=x.profileName;await xe(r,{credentialMode:x.mode,...T!==void 0&&{activeCredentialProfile:T}})}}let g=t.verbose===!0,h=g||t.debug===!0,S=t.viewer!==!1,I=t.cache!==!1,{waitUntilExit:v}=on(nn(tn,{port:o,pluginDir:n,outputDir:r,credentials:i,...p!==void 0&&{credentialMode:p},...u!==void 0&&{activeCredentialProfile:u},...m!==void 0&&{lastPath:m},debug:h,verbose:g,autoViewer:S,cacheEnabled:I}),{exitOnCtrlC:!1});await v()})}import{createElement as os}from"react";import{render as is}from"ink";import{useCallback as yt,useEffect as un,useState as ht}from"react";import{Box as se,Text as O,useApp as Zi,useInput as Qi}from"ink";import{encrypt as Hi,serializeEnvelope as Vi}from"@kizenapps/packager";function Ui(e){let t=e;return t.code==="ECONNREFUSED"||t.cause?.code==="ECONNREFUSED"}function an(e){return{"Content-Type":"application/json","x-api-key":e.apiKey,"x-user-id":e.userId,"x-business-id":e.businessId,"x-auth-environment":e.environment}}async function ln(e,t,o){try{return await fetch(`${e}${t}`,o)}catch(n){throw new Error(Ui(n)?`Plugin-wizard is not running at ${e}`:`Failed to reach plugin-wizard: ${n.message}`)}}async function cn(e){let t=await e.text();if(t==="")return{};try{let o=JSON.parse(t);return typeof o=="object"&&o!==null?o:{}}catch{return{}}}async function qi(e,t,o){let n=He(e.stage),r=await ln(n,"/get-public-key",{method:"POST",headers:an(t),body:JSON.stringify({api_name:o})}),i=await cn(r);if(!r.ok||typeof i.public_key!="string"){let p=typeof i.error=="string"?i.error:`HTTP ${String(r.status)}`;throw new Error(`Failed to fetch public key: ${p}`)}return i.public_key}function Ji(e,t){let o=Hi(t,e),n=Vi(o);if(typeof n.value!="string")throw new Error("Unexpected serialized envelope shape from @kizenapps/packager");return n.value}async function Wi(e,t,o,n){let r=He(e.stage),i=await ln(r,"/encrypt",{method:"POST",headers:an(t),body:JSON.stringify({api_name:o,value:n})}),p=await cn(i);if(!i.ok||p.encrypted!==!0||typeof p.value!="string"){let u=typeof p.error=="string"?p.error:`HTTP ${String(i.status)}`;throw new Error(`Encryption via plugin-wizard failed: ${u}`)}return p.value}async function gt(e,t,o,n,r){if(e.isRemote)return r?.("encrypting"),Wi(e,t,o,n);r?.("fetching-key");let i=await qi(e,t,o);return r?.("encrypting"),Ji(i,n)}import{spawn as Gi}from"child_process";import{platform as dn}from"process";function Ki(){return dn==="darwin"?[{cmd:"pbcopy",args:[]}]:dn==="win32"?[{cmd:"clip",args:[]}]:[{cmd:"wl-copy",args:[]},{cmd:"xclip",args:["-selection","clipboard"]},{cmd:"xsel",args:["--clipboard","--input"]}]}var Yi=2e3;function Xi(e,{cmd:t,args:o}){return new Promise(n=>{let r;try{r=Gi(t,o,{stdio:["pipe","ignore","ignore"]})}catch{n(!1);return}let i=r,p=!1;function u(g){p||(p=!0,clearTimeout(m),n(g))}let m=setTimeout(()=>{i.kill(),u(!1)},Yi);m.unref(),i.on("error",()=>{u(!1)}),i.on("close",g=>{u(g===0)}),i.stdin.on("error",()=>{u(!1)});try{i.stdin.end(e)}catch{u(!1)}})}async function pn(e){for(let t of Ki())if(await Xi(e,t))return!0;return!1}import{Fragment as xt,jsx as L,jsxs as G}from"react/jsx-runtime";var Wt=({text:e})=>L(O,{dimColor:!0,children:e}),fn=({ctx:e,stageDefaulted:t,credentialsPath:o,initialApiName:n,defaultApiName:r,initialValue:i,onDone:p})=>{let u=Zi(),[m,g]=ht({type:"loading"}),[h,S]=ht(null),[I,v]=ht(n??""),[c,x]=ht(i??""),T=yt(s=>{process.exitCode=1,g({type:"error",message:s instanceof Error?s.message:String(s)})},[]),E=yt(async(s,a,d)=>{try{let y=await gt(e,s,a,d,A=>{g(A==="fetching-key"?{type:"fetching-key"}:{type:"encrypting"})}),N=JSON.stringify({encrypted:!0,value:y},null,2);p?.(y);let k=await pn(N);g({type:"done",envelope:N,copied:k})}catch(y){T(y)}},[e,T,p]),b=yt((s,a,d)=>{if(a.trim()===""){g({type:"api-name-entry",buffer:r??""});return}if(d===""){g({type:"value-entry",buffer:""});return}E(s,a.trim(),d)},[r,E]),w=yt(async s=>{try{g({type:"loading"});let a=s.isDefault?await Y():await le(s.name);if(a===null)throw new Error(`Could not load credential profile: ${s.name}`);S(a),b(a,I,c)}catch(a){T(a)}},[I,c,b,T]);un(()=>{(async()=>{try{if(o!==void 0){let d;try{d=await ye(o)}catch(y){throw new Error(`Could not load credentials from ${o}: ${y instanceof Error?y.message:String(y)}`)}S(d),b(d,I,c);return}let s=await ke();if(s.length===0)throw new Error("No credential profiles found. Create ~/.kizenappbuilder/credentials.json first.");let[a]=s;if(s.length===1&&a!==void 0){let d=a.isDefault?await Y():await le(a.name);if(d===null)throw new Error(`Could not load credential profile: ${a.name}`);S(d),b(d,I,c);return}g({type:"profile-select",profiles:s,cursor:0})}catch(s){T(s)}})()},[]),un(()=>{(m.type==="done"||m.type==="error")&&u.exit()},[m,u]),Qi((s,a)=>{if(a.ctrl&&s==="c"){process.exitCode=130,u.exit();return}if(m.type==="profile-select"){let{profiles:d,cursor:y}=m;if(a.upArrow)g({...m,cursor:(y-1+d.length)%d.length});else if(a.downArrow)g({...m,cursor:(y+1)%d.length});else if(a.return){let N=d[y];N!==void 0&&w(N)}return}if(m.type==="api-name-entry"){let{buffer:d}=m;if(a.backspace||a.delete)g({type:"api-name-entry",buffer:d.slice(0,-1)});else if(a.return){let y=d.trim();if(y===""){g({type:"api-name-entry",buffer:d,error:"api_name cannot be empty"});return}v(y),h?b(h,y,c):T(new Error("Internal error: credentials were not loaded"))}else s&&!a.ctrl&&!a.meta&&g({type:"api-name-entry",buffer:d+s});return}if(m.type==="value-entry"){let{buffer:d}=m;if(a.backspace||a.delete)g({type:"value-entry",buffer:d.slice(0,-1)});else if(a.return){if(d===""){g({type:"value-entry",buffer:d,error:"secret cannot be empty"});return}x(d),h?b(h,I,d):T(new Error("Internal error: credentials were not loaded"))}else s&&!a.ctrl&&!a.meta&&g({type:"value-entry",buffer:d+s});return}});let P=e.isRemote?"remote Kizen API":"on-machine",f=t===!0?`${e.stage} (default)`:e.stage,l=s=>G(se,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[L(q,{}),G(O,{dimColor:!0,children:["Mode: ",P," Stage: ",f]}),s]});if(m.type==="loading")return l(G(se,{gap:1,children:[L(ue,{}),L(O,{dimColor:!0,children:"Loading credentials\u2026"})]}));if(m.type==="profile-select"){let{profiles:s,cursor:a}=m;return l(G(xt,{children:[L(O,{bold:!0,children:"Credential profile"}),L(se,{flexDirection:"column",children:s.map((d,y)=>{let N=a===y;return G(se,{gap:2,children:[L(O,{...N&&{color:"cyan"},children:N?"\u276F":" "}),L(O,{bold:N,...N&&{color:"cyan"},children:d.isDefault?"Default":d.name}),L(O,{dimColor:!0,children:d.path})]},d.name)})}),L(Wt,{text:"\u2191\u2193 to move \xB7 Enter to select \xB7 Ctrl+C to quit"})]}))}return m.type==="api-name-entry"?l(G(xt,{children:[L(O,{bold:!0,children:"Plugin api_name"}),m.error!==void 0&&G(O,{color:"red",children:["Error: ",m.error]}),G(se,{gap:1,children:[L(O,{color:"cyan",children:">"}),L(O,{children:m.buffer}),L(O,{color:"cyan",children:"\u2588"})]}),L(Wt,{text:"Type the api_name \xB7 Enter to confirm \xB7 Ctrl+C to quit"})]})):m.type==="value-entry"?l(G(xt,{children:[L(O,{bold:!0,children:"Secret value"}),m.error!==void 0&&G(O,{color:"red",children:["Error: ",m.error]}),G(se,{gap:1,children:[L(O,{color:"cyan",children:">"}),L(O,{children:"\u2022".repeat(m.buffer.length)}),L(O,{color:"cyan",children:"\u2588"})]}),L(Wt,{text:"Input hidden \xB7 Enter to encrypt \xB7 Ctrl+C to quit"})]})):m.type==="fetching-key"?l(G(se,{gap:1,children:[L(ue,{}),G(O,{children:["Fetching ",e.stage," public key for ",L(O,{bold:!0,children:I}),"\u2026"]})]})):m.type==="encrypting"?l(G(se,{gap:1,children:[L(ue,{}),L(O,{children:"Encrypting\u2026"})]})):m.type==="error"?l(G(se,{gap:1,children:[L(O,{color:"red",children:"\u2717"}),L(O,{color:"red",children:m.message})]})):l(G(xt,{children:[G(se,{gap:1,children:[L(O,{color:"green",children:"\u2713"}),L(O,{bold:!0,children:"Encrypted secret ready"})]}),m.copied?L(O,{color:"green",children:"\u2713 Copied to clipboard \u2014 paste it into the secret value in your kizen.json."}):L(O,{dimColor:!0,children:"Paste this into the secret value in your kizen.json (re-run with --out <path> to save it to a file; selecting it here may capture line wraps):"}),L(O,{children:m.envelope})]}))};import{readFile as es,writeFile as ts}from"fs/promises";import{join as rs}from"path";function mn(e){return{encrypted:!0,value:e}}function gn(e){return JSON.stringify(mn(e))}async function Gt(e,t){await ts(e,`${JSON.stringify(mn(t),null,2)}
|
|
192
|
-
`,"utf-8")}var
|
|
193
|
-
`}async function
|
|
194
|
-
`),
|
|
195
|
-
`),t.out!==void 0)try{await r.writeEnvelopeFile(t.out,
|
|
196
|
-
`)}catch(
|
|
197
|
-
`),r.setExitCode(1)}}function
|
|
198
|
-
`)}catch(
|
|
199
|
-
${
|
|
200
|
-
`)}var
|
|
484
|
+
`.trim(),As=3e4,bt=Je(process.cwd(),".kizenapp","venv"),xn=["python-3-12","python-3-13"];function Ns(e){return xn.includes(e)}var vn=mn(fn);if(vn.length===0)throw new Error("python-requirements.txt bundled no packages \u2014 check the build output");var qe=null,We=[3,10];function wn([e,t]){return e>We[0]||e===We[0]&&t>=We[1]}function Zt(e){return`${String(e[0])}.${String(e[1])}`}function Cn(e){return new Promise(t=>{let n=tr(e,["-c","import sys; print('%d.%d' % sys.version_info[:2])"],{stdio:["ignore","pipe","ignore"]}),o="";n.stdout.on("data",r=>{o+=r.toString("utf-8")}),n.on("error",()=>{t(null)}),n.on("close",r=>{let i=/(\d+)\.(\d+)/.exec(o);if(r!==0||!i){t(null);return}t([Number(i[1]),Number(i[2])])})})}async function Bs(e){let t=gn(e),n=t==="python3"?["python3"]:[t,"python3"],o=[];for(let r of n){let i=await Cn(r);if(!i){o.push(`${r}: not found`);continue}if(wn(i))return r;o.push(`${r}: ${Zt(i)} (too old)`)}throw new Error(`No Python >= ${Zt(We)} found for runtime "${e}". The local runner needs Python ${Zt(We)}+ to install the bundled packages (e.g. psycopg 3.3), matching the remote code-runner (3.12 / 3.13). Tried ${o.join(", ")}. Install Python 3.12 or 3.13 and retry.`)}function bn(e,t,n){return new Promise((o,r)=>{let i=tr(e,t,{stdio:["ignore","pipe","pipe"]}),d=(g,m)=>{let b=[],T="";return g.on("data",P=>{T+=P.toString("utf-8");let x=T.indexOf(`
|
|
485
|
+
`);for(;x>=0;){let p=T.slice(0,x).replace(/\r$/,"");T=T.slice(x+1),b.push(p),n?.(p,m),x=T.indexOf(`
|
|
486
|
+
`)}}),g.on("end",()=>{if(T.length>0){let P=T.replace(/\r$/,"");b.push(P),n?.(P,m)}}),b},f=d(i.stderr,"stderr");d(i.stdout,"stdout"),i.on("error",r),i.on("close",g=>{if(g===0)o();else{let m=f.slice(-10).join(`
|
|
487
|
+
`).trim(),b=m.length>0?`: ${m}`:"";r(new Error(`${e} exited with code ${String(g)}${b}`))}})})}var Qt=null;function Ds(e,t){if(qe)return t&&Qt?.add(t),qe;let n=new Set;t&&n.add(t),Qt=n;let o=i=>{for(let d of n)d(i)},r=Je(bt,"bin","python");return qe=(async()=>{try{let i=!1;try{await Ps(r);let d=await Cn(r);i=d!==null&&wn(d)}catch{i=!1}if(!i){await er(bt,{recursive:!0,force:!0}).catch(()=>{});let d=await Bs(e);await bn(d,["-m","venv",bt])}return o({kind:"start"}),await bn(r,["-m","pip","install","--disable-pip-version-check",...vn],(d,f)=>{o({kind:"log",line:d,stream:f})}),o({kind:"complete"}),r}catch(i){let d=i instanceof Error?i.message:String(i);throw o({kind:"error",message:d}),qe=null,await er(bt,{recursive:!0,force:!0}).catch(()=>{}),i}finally{Qt=null}})(),qe}function Fs(e){let t="__KIZEN_RESULT_START__",n="__KIZEN_RESULT_END__",o=e.indexOf(t),r=e.indexOf(n);if(o===-1||r===-1)return{userStdout:e,result:null};let i=e.slice(0,o).trimEnd(),d=e.slice(o+t.length,r).trim();try{let f=JSON.parse(d);return{userStdout:i,result:f}}catch{return{userStdout:e,result:null}}}function Os(e){return{success:!1,outputValues:{},logs:[],stdout:"",stderr:"",error:e,exitCode:1,durationMs:0}}async function Sn(e){let t=e.timeout??As;if(!Ns(e.scriptRuntime))return Os(`Unsupported runtime "${e.scriptRuntime}". Supported runtimes: ${xn.join(", ")}. Update the step's config.json "runtime" field (e.g. "python 3.13").`);let n=await Ds(e.scriptRuntime,e.onInstallProgress),o=Date.now(),r;try{r=await ks(Je(Is(),"kizen-step-"));let i=Je(r,"wrapper.py"),d=Je(r,"script.py");await Promise.all([yn(i,Rs,"utf-8"),yn(d,e.script,"utf-8")]);let f={...process.env,__KIZEN_INPUTS__:JSON.stringify(e.inputs),__KIZEN_SECRETS__:JSON.stringify(e.secrets),__KIZEN_SCRIPT_PATH__:d},{exitCode:g,stdout:m,stderr:b}=await new Promise(y=>{let S=[],H=[],O=!1,w=tr(n,[i],{env:f,cwd:r,stdio:["ignore","pipe","pipe"]}),v=setTimeout(()=>{w.kill("SIGKILL")},t);w.stdout.on("data",a=>{S.push(a)}),w.stderr.on("data",a=>{H.push(a)});let c=a=>{O||(O=!0,clearTimeout(v),y({exitCode:a??1,stdout:Buffer.concat(S).toString("utf-8"),stderr:Buffer.concat(H).toString("utf-8")}))};w.on("close",c),w.on("error",a=>{O||(O=!0,clearTimeout(v),y({exitCode:1,stdout:"",stderr:a.message}))})}),T=Date.now()-o,{userStdout:P,result:x}=Fs(m);if(x){let y={success:x.success,outputValues:x.outputValues,logs:x.logs,stdout:P,stderr:b,exitCode:g,durationMs:T};return x.error!==null&&(y.error=x.error),x.httpRequests&&(y.httpRequests=x.httpRequests),y}let p={success:!1,outputValues:{},logs:[],stdout:P,stderr:b,exitCode:g,durationMs:T};return g!==0&&(p.error=`Process exited with code ${String(g)}`),p}finally{r&&er(r,{recursive:!0,force:!0})}}var Tn=new Set([".ts",".tsx",".js",".jsx",".mjs",".cjs",".json",".md",".mdx",".yml",".yaml",".toml",".css",".scss",".html",".htm",".xml",".svg",".txt",".sh",".py",".env",".gitignore",".prettierrc",".eslintrc"]);import{CRYPTO_ALG as Pn,CRYPTO_VERSION as In,deserializeEnvelope as qs,encrypt as Js,serializeEnvelope as Ws}from"@kizenapps/packager";function rr(e){if(e.kind==="info")return e.message;let t=e.fromCache?" [cache]":"",n=e.upstreamStatus!==void 0?` (upstream ${String(e.upstreamStatus)})`:"";return`${e.method} ${e.url} \u2192 ${String(e.status)}${n}${t}`}var Ks=2*1024*1024,Gs=new Set([".DS_Store",".gitignore"]);function Ys(e){if(e===void 0||e==="")return!1;let t=e.startsWith("[")?e.slice(0,e.indexOf("]")+1):e.split(":")[0]??"";return t==="localhost"||t==="127.0.0.1"||t==="[::1]"}var Bn=["kizen.com","kizen.dev"];function Xs(e){let t;try{t=new URL(e)}catch{return!1}let n=t.hostname.toLowerCase();return n==="localhost"||n==="127.0.0.1"||n==="[::1]"?!0:t.protocol!=="https:"?!1:Bn.some(o=>n===o||n.endsWith("."+o))}function Zs(e){let t;try{t=new URL(e)}catch{return!1}if(t.protocol!=="https:")return!1;let n=t.hostname.toLowerCase();return Bn.some(o=>n===o||n.endsWith("."+o))}function Qs(e){if(e===void 0||e==="")return!1;try{let{hostname:t}=new URL(e);return t==="localhost"||t==="127.0.0.1"||t==="::1"}catch{return!1}}async function Rn(e,t){if(t.includes("\0"))return null;let n=t.replace(/^\/+/,""),o=Us(e,n);if(o!==e&&!o.startsWith(e+nr))return null;try{let r=await zs(o);return r!==e&&!r.startsWith(e+nr)?null:r}catch{return null}}function An(e,t){let n=t===e?"":t.slice(e.length+1);return n===""?!1:n.split(nr).some(r=>tt.has(r))}function Dn(){let e=Vs(import.meta.url);return Ke(Hs(e),"viewer")}function Nn(e,t,n){if(e.includes("/external-integrations/proxy")&&t["content-type"]?.includes("application/json"))try{let o=JSON.parse(n.toString("utf8"));return typeof o.status_code=="number"?o.status_code:void 0}catch{return}}async function or(e){try{return await $s(e),!0}catch{return!1}}function Fn(e,t,n,o,r,i,d,f,g,m,b){let T=pn({onChange:f,enabled:b}),P=js(m);return(x,p)=>{(async()=>{let y=x.url??"/";try{if(!Ys(x.headers.host)){p.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"Forbidden"}));return}if((x.method==="POST"||x.method==="PATCH"||x.method==="DELETE")&&!Qs(x.headers.origin)){p.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"Forbidden"}));return}if(t(`Received request: ${y}`),y==="/api/credentials"){p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({credentials:o.current??null,activeProfile:r.current??null}));return}if(y==="/api/credential-profiles"&&x.method==="GET"){let a=await Ie();p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({profiles:a,active:r.current}));return}if(y==="/api/credentials/switch"&&x.method==="POST"){let a=[];for await(let h of x)a.push(h);let l=JSON.parse(Buffer.concat(a).toString("utf-8")||"{}").profile,u=l===void 0||l===""?await Z():await de(l);if(u!==null){o.current=u,r.current=l??void 0;let h=r.current,k=await xe(i);await ve(i,{...k,credentialMode:"global",...h!==void 0&&{activeCredentialProfile:h}}),d({type:"credentials-updated",credentials:u,activeProfile:r.current??null})}p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({ok:u!==null}));return}if(y==="/api/bundle"){let a=Ke(process.cwd(),".kizenapp","bundle.json");try{let s=await Ms(a,"utf-8");p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end(s)}catch{p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end("{}")}return}if(y==="/api/last-path"&&x.method==="POST"){let a=[];for await(let l of x)a.push(l);let s=JSON.parse(Buffer.concat(a).toString("utf-8")||"{}");if(typeof s.path=="string"){g.current=s.path;let l=await xe(i);await ve(i,{...l,lastPath:s.path})}p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end('{"ok":true}');return}if(y==="/api/encryption-target"&&x.method==="GET"){let s=(await xe(i)).encryptionTarget==="dev"?"dev":"prod";p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({target:s}));return}if(y==="/api/encryption-target"&&x.method==="POST"){let a=[];for await(let h of x)a.push(h);let s=JSON.parse(Buffer.concat(a).toString("utf-8")||"{}"),l=s!==null&&typeof s=="object"?s:{};if(l.target!=="dev"&&l.target!=="prod"){p.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"target must be one of: 'dev', 'prod'"}));return}let u=await xe(i);await ve(i,{...u,encryptionTarget:l.target}),p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end('{"ok":true}');return}if(y==="/api/execute-step"&&x.method==="POST"){let a=[];for await(let h of x)a.push(h);let s=JSON.parse(Buffer.concat(a).toString("utf-8")||"{}");if(typeof s.script!="string"){p.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"Missing required field: script"}));return}let l={script:s.script,scriptRuntime:s.scriptRuntime??"python-3-13",inputs:hn(s.inputs),secrets:s.secrets??{},onInstallProgress:h=>{h.kind==="start"?d({type:"venv-install-start"}):h.kind==="log"?d({type:"venv-install-log",line:h.line,stream:h.stream}):h.kind==="complete"?d({type:"venv-install-complete"}):d({type:"venv-install-error",message:h.message})}};typeof s.timeout=="number"&&s.timeout>0&&(l.timeout=Math.min(s.timeout,300*1e3));let u=await Sn(l);p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify(u));return}if(y==="/api/proxy-cache/clear"){T.clear(),n({kind:"info",message:"Proxy cache cleared"}),p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end('{"ok":true}');return}if(y==="/api/local/encrypt"&&x.method==="POST"){let a=[];for await(let l of x)a.push(l);let s=JSON.parse(Buffer.concat(a).toString("utf-8")||"{}");if(typeof s.publicKeyPem!="string"||typeof s.value!="string"){p.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"Missing required fields: publicKeyPem, value"}));return}try{let l=Js(s.value,s.publicKeyPem),u=Ws(l);p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify(u))}catch(l){p.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:l.message}))}return}if(y==="/api/local/validate"&&x.method==="POST"){let a=[];for await(let _ of x)a.push(_);let s=JSON.parse(Buffer.concat(a).toString("utf-8")||"{}");if(typeof s.value!="string"){p.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"Missing required field: value"}));return}let l,u;try{l=qs(s.value)}catch(_){u=_.message}if(u!==void 0||l===void 0){p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({valid:!1,checks:[],error:u}));return}let h=_=>Buffer.from(_,"base64").length,k=[{label:"Version",expected:String(In),actual:String(l.v),pass:l.v===In},{label:"Algorithm",expected:Pn,actual:l.alg,pass:l.alg===Pn},{label:"Wrapped key",expected:"384 bytes (RSA-3072)",actual:`${String(h(l.k))} bytes`,pass:h(l.k)===384},{label:"IV",expected:"12 bytes",actual:`${String(h(l.iv))} bytes`,pass:h(l.iv)===12},{label:"Auth tag",expected:"16 bytes",actual:`${String(h(l.tag))} bytes`,pass:h(l.tag)===16},{label:"Ciphertext",expected:"\u2265 1 byte",actual:`${String(h(l.ct))} bytes`,pass:h(l.ct)>=1}];p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({valid:k.every(_=>_.pass),checks:k}));return}if(y.startsWith("/api/wizard")){let a=x.headers["x-encryption-target"],l=(Array.isArray(a)?a[0]:a)==="dev"?"dev":"prod",u=Ve(l);if(!Xs(u)){p.writeHead(500,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:`Encryption API host is not allowed: ${u}`}));return}let h=y.slice(11)||"/",k=`${u}${h}`,_=x.method??"GET",A=[];for await(let Se of x)A.push(Se);let{host:M,"x-encryption-target":W,...te}=x.headers,oe=A.length>0?Buffer.concat(A):void 0,ie=oe&&oe.length>0?oe:void 0,re;try{re=await fetch(k,{method:_,headers:te,...ie!==void 0&&{body:ie}})}catch(Se){let It=Se.code==="ECONNREFUSED"?`plugin-wizard is not running at ${u}`:`Failed to reach plugin-wizard: ${Se.message}`;p.writeHead(503,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:It}));return}let ee=yt(Object.fromEntries(re.headers)),Oe=await re.arrayBuffer();p.writeHead(re.status,ee),p.end(Buffer.from(Oe));return}if(y.startsWith("/api/proxy")){let a=x.headers["x-proxy-target"];if(typeof a!="string"){p.writeHead(400),p.end("Missing x-proxy-target header");return}if(!Zs(a)){p.writeHead(400),p.end("Invalid proxy target");return}let s=y.slice(10)||"/",l=`${a}${s}`,u=x.method??"GET",h=[];for await(let re of x)h.push(re);let{host:k,"x-proxy-target":_,...A}=x.headers;if(u==="GET"){let re=`GET::${l}`,{response:ee,fromCache:Oe}=await T.get(re,()=>fetch(l,{method:"GET",headers:A}));n({kind:"request",method:"GET",status:ee.status,upstreamStatus:Nn(s,ee.headers,ee.body),fromCache:Oe,url:s}),p.writeHead(ee.status,ee.headers),p.end(ee.body);return}let M=h.length>0?Buffer.concat(h):void 0,W=M&&M.length>0?M:void 0,te=await fetch(l,{method:u,headers:A,...W!==void 0&&{body:W}}),oe=yt(Object.fromEntries(te.headers)),ie=await Gt(te,Kt);n({kind:"request",method:u,status:te.status,upstreamStatus:Nn(s,oe,ie),fromCache:!1,url:s}),p.writeHead(te.status,oe),p.end(ie);return}if(y.startsWith("/api/source/tree")&&x.method==="GET"){let s=new URL(y,"http://localhost").searchParams.get("path")??"",l=await Rn(P,s);if(l===null){p.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"Invalid path"}));return}if(An(P,l)){p.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"Path is excluded"}));return}try{let u=await Ls(l,{withFileTypes:!0}),h=await Promise.all(u.filter(_=>_.isDirectory()?!tt.has(_.name):_.isFile()?!Gs.has(_.name):!1).map(async _=>{let A=_.isDirectory()?"dir":"file",M={name:_.name,kind:A};if(A==="file")try{let W=await En(Ke(l,_.name));M.size=W.size}catch{}return M}));h.sort((_,A)=>_.kind!==A.kind?_.kind==="dir"?-1:1:_.name.localeCompare(A.name));let k=l===P?"":l.slice(P.length+1);p.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({path:k,entries:h}))}catch(u){let h=u instanceof Error?u.message:String(u);t(`source/tree failed (${s}): ${h}`),p.writeHead(404,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"Not found"}))}return}if(y.startsWith("/api/source/file")&&x.method==="GET"){let s=new URL(y,"http://localhost").searchParams.get("path")??"";if(s===""){p.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"Missing path"}));return}let l=await Rn(P,s);if(l===null){p.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"Invalid path"}));return}if(An(P,l)){p.writeHead(403,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"Path is excluded"}));return}try{let u=await En(l);if(!u.isFile()){p.writeHead(400,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"Not a file"}));return}if(u.size>Ks){p.writeHead(413,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"File too large",size:u.size}));return}let h=kn(l).toLowerCase(),k=Yt[h],_=Tn.has(h),A=k??(_?"text/plain; charset=utf-8":"application/octet-stream");p.writeHead(200,{"Content-Type":A,"Content-Length":String(u.size)}),_n(l).pipe(p)}catch(u){let h=u instanceof Error?u.message:String(u);t(`source/file failed (${s}): ${h}`),p.writeHead(404,{"Content-Type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:"Not found"}))}return}let O=Ke(e,y==="/"?"/index.html":y),w=await or(O)?O:Ke(e,"index.html"),v=kn(w),c=Yt[v]??"application/octet-stream";p.writeHead(200,{"Content-Type":c}),_n(w).pipe(p)}catch(S){if(y.startsWith("/api/proxy")){let H=y.slice(10)||"/",O=x.method??"GET";S instanceof Ue?n({kind:"info",message:`${O} ${H} \u2192 502 (response exceeded ${String(S.limit)} bytes)`}):n({kind:"request",method:O,status:502,fromCache:!1,url:H})}else n({kind:"info",message:`Error handling ${y}: ${S instanceof Error?S.message:String(S)}`});p.headersSent||(p.writeHead(502),p.end("Bad Gateway"))}})()}}import{launch as ea}from"chrome-launcher";import{createRequire as ta}from"module";import{mkdirSync as ra}from"fs";import{readFile as na}from"fs/promises";import{dirname as oa,join as ia}from"path";import{fileURLToPath as sa}from"url";var On=ta(import.meta.url)("chrome-remote-interface"),aa=new Set(["content-security-policy","content-security-policy-report-only","x-frame-options"]),$n=["kizen.dev","kizen.com"];function jn(e){try{let{hostname:t}=new URL(e);return $n.some(n=>t===n||t.endsWith("."+n))}catch{return!1}}async function la(e){try{let t=ia(oa(sa(import.meta.url)),"viewer","icon.png"),n=await na(t);await e.Browser.setDockTile({image:n.toString("base64")})}catch{}}async function Ln(e){ra(e.userDataDir,{recursive:!0});let t=`http://localhost:${String(e.port)}`,n=await ea({startingUrl:t,chromeFlags:[`--app=${t}`,"--no-first-run","--no-default-browser-check","--disable-extensions","--disable-features=DeviceBoundSessions"],userDataDir:e.userDataDir,handleSIGINT:!1,logLevel:"silent"}),o=n.port,r=null,i=null,d=null,f=null,g=0,m=!1,b=w=>{e.debugLog?.(w)},T=w=>{e.verbose&&e.debugLog?.(w)},P=()=>{i!==null&&(clearInterval(i),i=null)},x=w=>w==="chrome://new-tab-page/"||w==="chrome://newtab/",p=async w=>{P(),d=null,await la(w),await w.Fetch.enable({patterns:$n.flatMap(c=>[{urlPattern:`*://${c}/*`,requestStage:"Response"},{urlPattern:`*://*.${c}/*`,requestStage:"Response"}])}),w.on("Fetch.requestPaused",c=>{(async()=>{let a=c,{requestId:s,request:l,responseHeaders:u,responseStatusCode:h}=a,k=l.url;T(`Fetch ${String(h??"?")} ${k}`);let _=[],A=!1;for(let M of u??[])if(!aa.has(M.name.toLowerCase()))if(M.name.toLowerCase()==="set-cookie"&&jn(k)){let W=M.value.split(`
|
|
488
|
+
`).map(te=>/SameSite=/i.test(te)?te.replace(/SameSite=\w+/i,"SameSite=None"):te+"; SameSite=None; Secure").join(`
|
|
489
|
+
`);_.push({name:M.name,value:W}),A=!0}else _.push(M);A&&T(` rewrote Set-Cookie SameSite on ${k}`);try{let{body:M,base64Encoded:W}=await w.Fetch.getResponseBody({requestId:s});await w.Fetch.fulfillRequest({requestId:s,responseCode:h??200,responseHeaders:_,body:M,...W&&{base64Encoded:!0}})}catch(M){T(` fulfillRequest failed (${M.message}), falling through`);try{await w.Fetch.continueRequest({requestId:s})}catch(W){T(` continueRequest also failed (${W.message})`)}}})()}),i=setInterval(()=>{(async()=>{try{let{cookies:c}=await w.Network.getAllCookies(),a=0;for(let s of c){if(!jn(`https://${s.domain??""}`)||s.sameSite==="None")continue;let l=s.domain??"",u=l.startsWith(".")?l.slice(1):l;await w.Network.setCookie({url:`https://${u}`,name:s.name,value:s.value,domain:l,path:s.path??"/",secure:!0,...s.httpOnly!==void 0&&{httpOnly:s.httpOnly},...s.expirationDate!==void 0&&{expires:s.expirationDate},sameSite:"None"}),a++}a>0&&T(`cookie-patch cycle: updated ${String(a)} cookie(s) to SameSite=None`)}catch(c){T(`cookie-patch cycle failed: ${c.message}`)}})()},2e3),await w.Target.setDiscoverTargets({discover:!0});let v=c=>{if(c.type==="page"){if(x(c.url)){b(`closed stray new-tab-page target ${c.targetId}`),d!==null&&w.Target.activateTarget({targetId:d}).catch(()=>{}),w.Target.closeTarget({targetId:c.targetId}).catch(()=>{});return}d===null&&(d=c.targetId,b(`captured main target ${c.targetId} (${c.url})`))}};w.on("Target.targetCreated",c=>{let{targetInfo:a}=c;T(`target +${a.type} ${a.targetId} ${a.url}`),v(a)}),w.on("Target.targetInfoChanged",c=>{let{targetInfo:a}=c;T(`target ~${a.type} ${a.targetId} ${a.url}`),v(a)}),w.on("disconnect",()=>{m||r!==w||(b("CDP disconnected"),r=null,P(),y())})},y=()=>{if(m||f!==null)return;let w=Math.min(1e3*2**g,1e4),v=g+1;g++,b(`CDP reconnect scheduled in ${String(w)}ms (attempt #${String(v)})`),f=setTimeout(()=>{f=null,(async()=>{let c;try{c=await On({port:o})}catch{b(`CDP reconnect attempt #${String(v)} failed`),y();return}if(m){try{await c.close()}catch{}return}r=c;try{await p(c),b(`CDP reconnected after ${String(v)} attempt(s)`),g=0}catch{r===c&&(r=null);try{await c.close()}catch{}b(`CDP reconnect attempt #${String(v)} failed during setup`),y()}})()},w)},S=30,H=300;for(let w=0;w<S;w++){await new Promise(v=>setTimeout(v,H)),b(`CDP connect attempt ${String(w+1)}/${String(S)}`);try{let v=await On({port:o});r=v,e.path&&v.send("Page.navigate",{url:`${t}${e.path}`});try{await p(v),b("CDP connected")}catch{r===v&&(r=null);try{await v.close()}catch{}b("CDP setup failed after connect")}break}catch{if(w===S-1){let v=`CDP unavailable after ${String(S)} attempts \u2014 viewer running without interception (CSP/cookie rewrites disabled)`;return b(v),e.onWarn?.(v),{kill:()=>{n.kill()}}}}}return r?{kill:()=>{if(b("CDP kill requested \u2014 tearing down"),m=!0,f!==null&&(clearTimeout(f),f=null),P(),r!==null){try{r.close()}catch{}r=null}n.kill()}}:{kill:()=>{n.kill()}}}import{useCallback as ca,useState as da}from"react";function xt(e){let[t,n]=da([]),o=ca(r=>{n(i=>[...i,`${new Date().toLocaleTimeString()}: ${r}`].slice(-e))},[e]);return[t,o]}import{useCallback as vt,useEffect as ir,useState as wt}from"react";import{Box as V,Text as j,useInput as pa}from"ink";import{jsx as R,jsxs as J}from"react/jsx-runtime";var we=["apiKey","userId","businessId"],ua={apiKey:"API Key",userId:"User ID",businessId:"Business ID"},Ge=({text:e})=>R(j,{dimColor:!0,children:e}),Ct=({initialMode:e,showProfileManager:t,onComplete:n,onCancel:o})=>{let[r,i]=wt(e==="global"&&!t?{type:"loading"}:e==="global"&&t?{type:"profile-loading"}:{type:"mode-select",cursor:0}),[d,f]=wt(""),[g,m]=wt(null),[b,T]=wt(void 0),P=vt(c=>{if(c==="local"){n({mode:"local",credentials:null});return}i({type:"profile-loading"})},[n]),x=vt(async c=>{if(c===null){i({type:"profile-loading"});let l=await Ie();i({type:"name-entry",nameBuffer:"",existingProfiles:l});return}T(c.isDefault?void 0:c.name),i({type:"loading"});let a=c.isDefault?await Z():await de(c.name),s=a?Math.max(0,Y.indexOf(a.environment)):0;i({type:"creds-entry",field:0,values:a??{},envCursor:s})},[]),p=vt(async(c,a)=>{let s=Y[a]??"go",l={apiKey:c.apiKey??"",userId:c.userId??"",businessId:c.businessId??"",environment:s};i({type:"saving"});try{await an(b??ye,l),n({mode:"global",credentials:l,...b!==void 0&&{profileName:b}})}catch(u){m(u instanceof Error?u.message:String(u)),i({type:"creds-entry",field:0,values:c,envCursor:a})}},[n,b]);pa((c,a)=>{if(a.ctrl&&c==="c"&&process.exit(0),a.escape){if((r.type==="creds-entry"||r.type==="name-entry")&&e==="global"&&t){i({type:"profile-loading"}),y();return}o?.();return}if(r.type==="mode-select"){if(a.upArrow)i({type:"mode-select",cursor:0});else if(a.downArrow)i({type:"mode-select",cursor:1});else if(a.return){let s=r.cursor===0?"global":"local";P(s)}return}if(r.type==="profile-select"){let{profiles:s,cursor:l}=r,u=s.length,h=s.length+1;if(a.upArrow)i({...r,cursor:(l-1+h)%h});else if(a.downArrow)i({...r,cursor:(l+1)%h});else if(a.return)if(l===u)i({type:"name-entry",nameBuffer:"",existingProfiles:s});else{let k=s[l]??s[0];k&&x(k)}return}if(r.type==="name-entry"){let{nameBuffer:s,existingProfiles:l}=r;if(a.backspace||a.delete)i({type:"name-entry",nameBuffer:s.slice(0,-1),existingProfiles:l});else if(a.return){let u=s.trim();if(!u){i({...r,nameError:"Name cannot be empty"});return}if(u===ye){i({...r,nameError:`"${ye}" is reserved`});return}if(l.some(h=>h.name===u)){i({...r,nameError:`Profile "${u}" already exists`});return}T(u),i({type:"creds-entry",field:0,values:{},envCursor:0}),f("")}else c&&!a.ctrl&&!a.meta&&i({type:"name-entry",nameBuffer:s+c,existingProfiles:l});return}if(r.type==="creds-entry"){let{field:s,values:l,envCursor:u}=r;if(s===we.length){a.leftArrow?i({...r,envCursor:(u-1+Y.length)%Y.length}):a.rightArrow?i({...r,envCursor:(u+1)%Y.length}):a.upArrow?(i({...r,field:s-1}),f(l[we[s-1]]??"")):a.return&&p(l,u);return}let k=we[s];if(!k)return;if(a.backspace||a.delete)f(_=>_.slice(0,-1));else if(a.upArrow&&s>0){let _={...l,[k]:d},A=s-1;i({...r,field:A,values:_}),f(_[we[A]]??"")}else if(a.return||a.tab||a.downArrow){let _={...l,[k]:d},A=s+1;i({...r,field:A,values:_}),A<we.length?f(_[we[A]]??""):f("")}else c&&!a.ctrl&&!a.meta&&f(_=>_+c)}});let y=vt(async()=>{let c=await Ie();i({type:"profile-select",profiles:c,cursor:0})},[]);if(ir(()=>{r.type==="profile-loading"&&y()},[r.type,y]),ir(()=>{e==="global"&&!t&&(async()=>{let c=await Z(),a=c?Math.max(0,Y.indexOf(c.environment)):0;i({type:"creds-entry",field:0,values:c??{},envCursor:a})})()},[]),ir(()=>{r.type==="creds-entry"&&r.field===0&&f(r.values.apiKey??"")},[r.type]),r.type==="loading"||r.type==="saving"||r.type==="profile-loading"){let c=r.type==="saving"?"Saving credentials\u2026":r.type==="profile-loading"?"Loading profiles\u2026":"Loading credentials\u2026";return R(V,{paddingY:1,paddingX:2,children:R(j,{dimColor:!0,children:c})})}if(r.type==="done")return null;if(r.type==="mode-select")return J(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[R(q,{}),J(V,{flexDirection:"column",gap:0,children:[R(j,{bold:!0,children:"Credential mode"}),[{label:"Global",desc:"~/.kizenappbuilder/credentials.json",mode:"global"},{label:"Local",desc:"Enter credentials in the browser dev tools",mode:"local"}].map((a,s)=>{let l=r.cursor===s;return J(V,{gap:2,children:[R(j,{...l&&{color:"cyan"},children:l?"\u276F":" "}),R(j,{bold:l,...l&&{color:"cyan"},children:a.label}),R(j,{dimColor:!0,children:a.desc})]},a.mode)})]}),R(Ge,{text:"\u2191\u2193 to move \xB7 Enter to select \xB7 Ctrl+C to quit"})]});if(r.type==="profile-select"){let{profiles:c,cursor:a}=r,s=c.length;return J(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[R(q,{}),J(V,{flexDirection:"column",gap:0,children:[R(j,{bold:!0,children:"Credential profiles"}),c.map((l,u)=>{let h=a===u;return J(V,{gap:2,children:[R(j,{...h&&{color:"cyan"},children:h?"\u276F":" "}),R(j,{bold:h,...h&&{color:"cyan"},children:l.isDefault?"Default":l.name}),R(j,{dimColor:!0,children:l.path})]},l.name)}),J(V,{gap:2,children:[R(j,{...a===s&&{color:"cyan"},children:a===s?"\u276F":" "}),R(j,{bold:a===s,...a===s&&{color:"cyan"},children:"+ Add new profile"})]})]}),R(Ge,{text:"\u2191\u2193 to move \xB7 Enter to select \xB7 Esc to cancel"})]})}if(r.type==="name-entry"){let{nameBuffer:c,nameError:a}=r;return J(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[R(q,{}),R(V,{flexDirection:"column",gap:0,children:R(j,{bold:!0,children:"New credential profile"})}),a&&J(j,{color:"red",children:["Error: ",a]}),J(V,{gap:2,children:[R(V,{width:12,children:R(j,{bold:!0,color:"cyan",children:"Profile name"})}),R(j,{color:"cyan",children:">"}),R(j,{children:c}),R(j,{color:"cyan",children:"\u2588"})]}),R(Ge,{text:"Type a name \xB7 Enter to confirm \xB7 Esc to go back"})]})}let{field:S,values:H,envCursor:O}=r,w=S===we.length,v=b??ye;return J(V,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[R(q,{}),J(V,{flexDirection:"column",gap:0,children:[R(j,{bold:!0,children:b!==void 0?`Profile: ${b}`:"Global credentials"}),J(j,{dimColor:!0,children:["Saved to:"," ",b!==void 0?`~/.kizenappbuilder/${b}.json`:De]})]}),g&&J(j,{color:"red",children:["Error: ",g]}),J(V,{flexDirection:"column",gap:0,children:[we.map((c,a)=>{let s=S===a,l=s?d:H[c]??"";return J(V,{gap:2,children:[R(V,{width:12,children:R(j,{bold:s,...s&&{color:"cyan"},children:ua[c]})}),R(j,{...s&&{color:"cyan"},children:">"}),R(j,{children:l}),s&&R(j,{color:"cyan",children:"\u2588"})]},c)}),J(V,{gap:2,children:[R(V,{width:12,children:R(j,{bold:w,...w&&{color:"cyan"},children:"Environment"})}),R(j,{...w&&{color:"cyan"},children:">"}),R(V,{gap:1,children:Y.map((c,a)=>{let s=a===O;return w?R(j,{bold:s,...s&&{color:"cyan"},children:s?`[${c}]`:c},c):R(j,{dimColor:!s,bold:s,children:c},c)})})]})]}),w?R(Ge,{text:"\u2190\u2192 to select \xB7 \u2191\u2193 to move \xB7 Enter to save \xB7 Esc to cancel"}):R(Ge,{text:"\u2191\u2193 to move \xB7 Backspace to delete \xB7 Esc to cancel"}),J(j,{dimColor:!0,children:["Profile: ",v]})]})};import{jsx as D,jsxs as U}from"react/jsx-runtime";var xa=[".kizenapp",".git"],zn=({port:e,pluginDir:t,outputDir:n,credentials:o,credentialMode:r,activeCredentialProfile:i,lastPath:d,debug:f=!1,verbose:g=!1,autoViewer:m=!0,cacheEnabled:b=!0})=>{let T=pe(o),P=pe(i),x=pe(d),[p,y]=Q("main"),[S,H]=Q(r),[O,w]=Q("starting"),[v,c]=Q(null),[a,s]=xt(50),[l,u]=xt(50),[h,k]=xt(50),[_,A]=Q([]),[M,W]=Q("pending"),[te,oe]=Q(null),[ie,re]=Q(null),[ee,Oe]=Q(null),[Se,It]=Q(null),[Rt,At]=Q(0),[cr,ko]=Q(0),[Po,Io]=Q(0),[Nt,Ro]=Q(0),Bt=pe(!1),dr=pe(!1),Xe=pe(null),je=pe(null),ue=pe(new Set),Ze=pe([]),ne=Fe(C=>{let L=JSON.stringify(C);if(ue.current.size===0){Ze.current=[...Ze.current,L].slice(-50);return}let fe=!1;for(let se of ue.current)if(se.readyState===1)try{se.send(L)}catch{ue.current.delete(se),fe=!0}fe&&At(ue.current.size)},[]),Qe=s,Dt=Fe(()=>{Xe.current?.kill(),Xe.current=null,Ln({port:e,userDataDir:Mn(n,".chrome"),broadcast:ne,onWarn:C=>{s(`\u26A0 ${C}`)},...x.current!==void 0&&{path:x.current},...f&&{debugLog:k},...g&&{verbose:!0}}).then(C=>{Xe.current=C})},[e,n,ne,f,g,k,s]);St(()=>{let C=()=>{Xe.current?.kill()};return process.on("exit",C),()=>{process.off("exit",C)}},[]),ma((C,L)=>{(C==="q"||L.ctrl&&C==="c")&&process.exit(0),C==="c"&&y("editing"),C==="v"&&Dt()},{isActive:p==="main"}),St(()=>{O!=="running"||dr.current||!m||(dr.current=!0,Dt())},[O,m,Dt]);let Ao=Fe(C=>{T.current=C.credentials,P.current=C.profileName,y("main"),H(C.mode);let L=C.profileName;ve(n,{credentialMode:C.mode,...L!==void 0&&{activeCredentialProfile:L}}),ne({type:"credentials-updated",credentials:C.credentials})},[n,ne]),pr=Fe(C=>{A(L=>[...L,`${new Date().toLocaleTimeString()}: ${rr(C)}`].slice(-50)),C.kind==="request"&&(C.fromCache?Io(L=>L+1):Ro(L=>L+1)),ne({type:"proxy-log",entry:C})},[ne]),Te=Fe(C=>{u(C),ne({type:"log",message:C})},[u,ne]),Ft=Fe(()=>{Bt.current||(Bt.current=!0,W("building"),oe(null),re(null),Te("Build started"),nt(t,n).then(({bundleSize:C})=>{Te(`Build finished \u2014 bundle: ${$e(C)}`),W("done"),Oe(new Date),It(C),Te("Notifying viewers to reload"),ne({type:"rebuild"})}).catch(C=>{C instanceof ga?(re(C.issues),oe(null)):(oe(C instanceof Error?C.message:String(C)),re(null)),W("error")}).finally(()=>{Bt.current=!1}))},[t,n,Te,ne]);if(St(()=>{Ft();let C=ha(t,{recursive:!0},(L,fe)=>{if(!fe)return;let se=fe.replace(/\\/g,"/");xa.some(et=>se.startsWith(et))||(Te(`File change detected: ${fe}`),je.current!==null&&clearTimeout(je.current),je.current=setTimeout(Ft,150))});return C.on("error",L=>{Te(`File watcher error \u2014 rebuilds have stopped: ${L.message}`)}),()=>{C.close(),je.current!==null&&clearTimeout(je.current)}},[t,Ft,Te]),St(()=>{let C=Dn();or(Mn(C,"index.html")).then(L=>{if(!L){c("Viewer not built. Run 'pnpm build:viewer' first."),w("error");return}let fe=Fn(C,Qe,pr,T,P,n,ne,ko,x,t,b),se=ya(fe),et=new ba({server:se});return et.on("connection",_e=>{for(let Bo of Ze.current)_e.readyState===1&&_e.send(Bo);Ze.current=[],Qe("Viewer connected for live reload"),ue.current.add(_e),At(ue.current.size),_e.on("close",()=>{ue.current.delete(_e),At(ue.current.size)})}),se.listen(e,"127.0.0.1",()=>{w("running"),Qe(`Server started on 127.0.0.1:${String(e)}`)}),se.on("error",_e=>{c(_e.message),w("error")}),()=>{et.close(),se.close()}})},[e,Qe,pr,ne,n,t,b]),p==="editing")return D(Ct,{...S!==void 0&&{initialMode:S},showProfileManager:S==="global",onComplete:Ao,onCancel:()=>{y("main")}});let Ot=ee!==null?Math.round((Date.now()-ee.getTime())/1e3):null,No=Ot===null?"":Ot<5?" (just now)":` (${String(Ot)}s ago)`,ur=ie?.filter(C=>C.severity==="error").length??0;return U(K,{flexDirection:"column",paddingY:1,paddingX:2,children:[D(q,{marginBottom:1}),U(K,{flexDirection:"column",children:[U(K,{gap:2,marginBottom:0,children:[D(B,{bold:!0,dimColor:!0,children:"App Build"}),M==="pending"&&D(B,{dimColor:!0,children:"waiting\u2026"}),M==="building"&&U(K,{gap:1,children:[D(me,{}),D(B,{children:"Building plugin package\u2026"})]}),M==="done"&&U(K,{gap:1,children:[D(B,{color:"green",children:"\u2713 Built"}),ee!==null&&U(B,{dimColor:!0,children:["at ",ee.toLocaleTimeString(),No]}),Se!==null&&U(B,{dimColor:!0,children:["\xB7 bundle: ",$e(Se)]})]}),M==="error"&&(ie!==null?U(B,{color:"red",children:["\u2717 ",ur," validation ",ur===1?"error":"errors"]}):U(B,{color:"red",children:["\u2717 ",te??"unknown error"]}))]}),ie!==null&&D(it,{issues:ie}),D(K,{flexDirection:"column",height:10,borderStyle:"single",borderColor:"gray",overflow:"hidden",children:l.slice(-8).map((C,L)=>D(B,{dimColor:!0,wrap:"truncate",children:C},L))})]}),U(K,{marginTop:1,flexDirection:"column",children:[U(K,{gap:2,children:[D(B,{bold:!0,dimColor:!0,children:"Web Server"}),O==="starting"&&D(B,{dimColor:!0,children:"starting\u2026"}),O==="running"&&U(K,{gap:2,children:[D(B,{color:"green",children:"\u2713 Running"}),U(B,{dimColor:!0,children:["\u25CF ",Rt," viewer",Rt!==1?"s":""]})]}),O==="error"&&U(B,{color:"red",children:["\u2717 ",v??"Server error"]})]}),D(K,{flexDirection:"column",height:10,borderStyle:"single",borderColor:"gray",overflow:"hidden",children:a.slice(-8).map((C,L)=>D(B,{dimColor:!0,wrap:"truncate",children:C},L))})]}),U(K,{marginTop:1,flexDirection:"column",children:[U(K,{gap:2,children:[D(B,{bold:!0,dimColor:!0,children:"Network Proxy"}),D(B,{color:"green",children:"\u2713 Active"}),D(B,{dimColor:!0,children:b?`\u25CF ${String(cr)} key${cr!==1?"s":""} in the network cache \xB7 ${String(Po)} hit \xB7 ${String(Nt)} miss`:`\u25CF network cache disabled \xB7 ${String(Nt)} request${Nt!==1?"s":""}`})]}),D(K,{flexDirection:"column",height:10,borderStyle:"single",borderColor:"gray",overflow:"hidden",children:_.length===0?D(B,{dimColor:!0,children:" No requests yet."}):_.slice(-8).map((C,L)=>D(B,{dimColor:!0,wrap:"truncate",children:C},L))})]}),f&&U(K,{marginTop:1,flexDirection:"column",children:[U(K,{gap:2,children:[D(B,{bold:!0,dimColor:!0,children:"CDP Debug"}),U(B,{dimColor:!0,children:["\u25CF ",h.length," event(s)"]})]}),D(K,{flexDirection:"column",height:10,borderStyle:"single",borderColor:"gray",overflow:"hidden",children:h.length===0?D(B,{dimColor:!0,children:" No CDP events yet."}):h.slice(-8).map((C,L)=>D(B,{dimColor:!0,wrap:"truncate",children:C},L))})]}),U(K,{marginTop:1,gap:1,children:[D(B,{dimColor:!0,children:"["}),D(B,{children:"q"}),D(B,{dimColor:!0,children:"] quit ["}),D(B,{children:"c"}),D(B,{dimColor:!0,children:"] credentials ["}),D(B,{children:"v"}),U(B,{dimColor:!0,children:["] ",Rt===0?"open viewer":"relaunch viewer"]})]})]})};async function Hn(e){return new Promise(t=>{let n=null,o=i=>{n?.(),t(i)},{unmount:r}=Vn(Un(Ct,{...e!==void 0&&{initialMode:e},onComplete:o}),{exitOnCtrlC:!1});n=r})}function qn(e){e.command("dev").description("Start the plugin viewer dev server").option("-p, --port <port>","port to listen on","3121").option("-c, --credentials <path>","path to a credentials JSON file").option("-d, --debug","Enable CDP lifecycle logs in the TUI").option("-v, --verbose","Log every CDP event and handled error (implies --debug)").option("--no-viewer","Don't auto-launch the viewer on startup (press [v] to launch manually)").option("--no-cache","Disable the network proxy cache (always fetch upstream)").action(async t=>{let n=parseInt(t.port,10),o=process.cwd(),r=`${o}/.kizenapp`;Ne(o);let i=null,d,f,{lastPath:g}=await xe(r);if(t.credentials)i=await be(t.credentials);else{let p=await xe(r);if(p.credentialMode==="local")d="local";else if(p.credentialMode==="global"){if(d="global",f=p.activeCredentialProfile,f?(i=await de(f),i||(i=await Z(),f=void 0)):i=await Z(),!i){let y=await Hn("global");i=y.credentials,f=y.profileName}}else{let y=await Hn();i=y.credentials,d=y.mode,f=y.profileName;let S=y.profileName;await ve(r,{credentialMode:y.mode,...S!==void 0&&{activeCredentialProfile:S}})}}let m=t.verbose===!0,b=m||t.debug===!0,T=t.viewer!==!1,P=t.cache!==!1,{waitUntilExit:x}=Vn(Un(zn,{port:n,pluginDir:o,outputDir:r,credentials:i,...d!==void 0&&{credentialMode:d},...f!==void 0&&{activeCredentialProfile:f},...g!==void 0&&{lastPath:g},debug:b,verbose:m,autoViewer:T,cacheEnabled:P}),{exitOnCtrlC:!1});await x()})}import{createElement as Oa}from"react";import{render as ja}from"ink";import{useCallback as _t,useEffect as Xn,useState as Et}from"react";import{Box as ae,Text as $,useApp as Ra,useInput as Aa}from"ink";import{encrypt as va,serializeEnvelope as wa}from"@kizenapps/packager";function Ca(e){let t=e;return t.code==="ECONNREFUSED"||t.cause?.code==="ECONNREFUSED"}function Jn(e){return{"Content-Type":"application/json","x-api-key":e.apiKey,"x-user-id":e.userId,"x-business-id":e.businessId,"x-auth-environment":e.environment}}async function Wn(e,t,n){try{return await fetch(`${e}${t}`,n)}catch(o){throw new Error(Ca(o)?`Plugin-wizard is not running at ${e}`:`Failed to reach plugin-wizard: ${o.message}`)}}async function Kn(e){let t=await e.text();if(t==="")return{};try{let n=JSON.parse(t);return typeof n=="object"&&n!==null?n:{}}catch{return{}}}async function Sa(e,t,n){let o=Ve(e.stage),r=await Wn(o,"/get-public-key",{method:"POST",headers:Jn(t),body:JSON.stringify({api_name:n})}),i=await Kn(r);if(!r.ok||typeof i.public_key!="string"){let d=typeof i.error=="string"?i.error:`HTTP ${String(r.status)}`;throw new Error(`Failed to fetch public key: ${d}`)}return i.public_key}function Ta(e,t){let n=va(t,e),o=wa(n);if(typeof o.value!="string")throw new Error("Unexpected serialized envelope shape from @kizenapps/packager");return o.value}async function _a(e,t,n,o){let r=Ve(e.stage),i=await Wn(r,"/encrypt",{method:"POST",headers:Jn(t),body:JSON.stringify({api_name:n,value:o})}),d=await Kn(i);if(!i.ok||d.encrypted!==!0||typeof d.value!="string"){let f=typeof d.error=="string"?d.error:`HTTP ${String(i.status)}`;throw new Error(`Encryption via plugin-wizard failed: ${f}`)}return d.value}async function Tt(e,t,n,o,r){if(e.isRemote)return r?.("encrypting"),_a(e,t,n,o);r?.("fetching-key");let i=await Sa(e,t,n);return r?.("encrypting"),Ta(i,o)}import{spawn as Ea}from"child_process";import{platform as Gn}from"process";function ka(){return Gn==="darwin"?[{cmd:"pbcopy",args:[]}]:Gn==="win32"?[{cmd:"clip",args:[]}]:[{cmd:"wl-copy",args:[]},{cmd:"xclip",args:["-selection","clipboard"]},{cmd:"xsel",args:["--clipboard","--input"]}]}var Pa=2e3;function Ia(e,{cmd:t,args:n}){return new Promise(o=>{let r;try{r=Ea(t,n,{stdio:["pipe","ignore","ignore"]})}catch{o(!1);return}let i=r,d=!1;function f(m){d||(d=!0,clearTimeout(g),o(m))}let g=setTimeout(()=>{i.kill(),f(!1)},Pa);g.unref(),i.on("error",()=>{f(!1)}),i.on("close",m=>{f(m===0)}),i.stdin.on("error",()=>{f(!1)});try{i.stdin.end(e)}catch{f(!1)}})}async function Yn(e){for(let t of ka())if(await Ia(e,t))return!0;return!1}import{Fragment as kt,jsx as F,jsxs as G}from"react/jsx-runtime";var sr=({text:e})=>F($,{dimColor:!0,children:e}),Zn=({ctx:e,stageDefaulted:t,credentialsPath:n,initialApiName:o,defaultApiName:r,initialValue:i,onDone:d})=>{let f=Ra(),[g,m]=Et({type:"loading"}),[b,T]=Et(null),[P,x]=Et(o??""),[p,y]=Et(i??""),S=_t(s=>{process.exitCode=1,m({type:"error",message:s instanceof Error?s.message:String(s)})},[]),H=_t(async(s,l,u)=>{try{let h=await Tt(e,s,l,u,A=>{m(A==="fetching-key"?{type:"fetching-key"}:{type:"encrypting"})}),k=JSON.stringify({encrypted:!0,value:h},null,2);d?.(h);let _=await Yn(k);m({type:"done",envelope:k,copied:_})}catch(h){S(h)}},[e,S,d]),O=_t((s,l,u)=>{if(l.trim()===""){m({type:"api-name-entry",buffer:r??""});return}if(u===""){m({type:"value-entry",buffer:""});return}H(s,l.trim(),u)},[r,H]),w=_t(async s=>{try{m({type:"loading"});let l=s.isDefault?await Z():await de(s.name);if(l===null)throw new Error(`Could not load credential profile: ${s.name}`);T(l),O(l,P,p)}catch(l){S(l)}},[P,p,O,S]);Xn(()=>{(async()=>{try{if(n!==void 0){let u;try{u=await be(n)}catch(h){throw new Error(`Could not load credentials from ${n}: ${h instanceof Error?h.message:String(h)}`)}T(u),O(u,P,p);return}let s=await Ie();if(s.length===0)throw new Error("No credential profiles found. Create ~/.kizenappbuilder/credentials.json first.");let[l]=s;if(s.length===1&&l!==void 0){let u=l.isDefault?await Z():await de(l.name);if(u===null)throw new Error(`Could not load credential profile: ${l.name}`);T(u),O(u,P,p);return}m({type:"profile-select",profiles:s,cursor:0})}catch(s){S(s)}})()},[]),Xn(()=>{(g.type==="done"||g.type==="error")&&f.exit()},[g,f]),Aa((s,l)=>{if(l.ctrl&&s==="c"){process.exitCode=130,f.exit();return}if(g.type==="profile-select"){let{profiles:u,cursor:h}=g;if(l.upArrow)m({...g,cursor:(h-1+u.length)%u.length});else if(l.downArrow)m({...g,cursor:(h+1)%u.length});else if(l.return){let k=u[h];k!==void 0&&w(k)}return}if(g.type==="api-name-entry"){let{buffer:u}=g;if(l.backspace||l.delete)m({type:"api-name-entry",buffer:u.slice(0,-1)});else if(l.return){let h=u.trim();if(h===""){m({type:"api-name-entry",buffer:u,error:"api_name cannot be empty"});return}x(h),b?O(b,h,p):S(new Error("Internal error: credentials were not loaded"))}else s&&!l.ctrl&&!l.meta&&m({type:"api-name-entry",buffer:u+s});return}if(g.type==="value-entry"){let{buffer:u}=g;if(l.backspace||l.delete)m({type:"value-entry",buffer:u.slice(0,-1)});else if(l.return){if(u===""){m({type:"value-entry",buffer:u,error:"secret cannot be empty"});return}y(u),b?O(b,P,u):S(new Error("Internal error: credentials were not loaded"))}else s&&!l.ctrl&&!l.meta&&m({type:"value-entry",buffer:u+s});return}});let v=e.isRemote?"remote Kizen API":"on-machine",c=t===!0?`${e.stage} (default)`:e.stage,a=s=>G(ae,{flexDirection:"column",paddingY:1,paddingX:2,gap:1,children:[F(q,{}),G($,{dimColor:!0,children:["Mode: ",v," Stage: ",c]}),s]});if(g.type==="loading")return a(G(ae,{gap:1,children:[F(me,{}),F($,{dimColor:!0,children:"Loading credentials\u2026"})]}));if(g.type==="profile-select"){let{profiles:s,cursor:l}=g;return a(G(kt,{children:[F($,{bold:!0,children:"Credential profile"}),F(ae,{flexDirection:"column",children:s.map((u,h)=>{let k=l===h;return G(ae,{gap:2,children:[F($,{...k&&{color:"cyan"},children:k?"\u276F":" "}),F($,{bold:k,...k&&{color:"cyan"},children:u.isDefault?"Default":u.name}),F($,{dimColor:!0,children:u.path})]},u.name)})}),F(sr,{text:"\u2191\u2193 to move \xB7 Enter to select \xB7 Ctrl+C to quit"})]}))}return g.type==="api-name-entry"?a(G(kt,{children:[F($,{bold:!0,children:"Plugin api_name"}),g.error!==void 0&&G($,{color:"red",children:["Error: ",g.error]}),G(ae,{gap:1,children:[F($,{color:"cyan",children:">"}),F($,{children:g.buffer}),F($,{color:"cyan",children:"\u2588"})]}),F(sr,{text:"Type the api_name \xB7 Enter to confirm \xB7 Ctrl+C to quit"})]})):g.type==="value-entry"?a(G(kt,{children:[F($,{bold:!0,children:"Secret value"}),g.error!==void 0&&G($,{color:"red",children:["Error: ",g.error]}),G(ae,{gap:1,children:[F($,{color:"cyan",children:">"}),F($,{children:"\u2022".repeat(g.buffer.length)}),F($,{color:"cyan",children:"\u2588"})]}),F(sr,{text:"Input hidden \xB7 Enter to encrypt \xB7 Ctrl+C to quit"})]})):g.type==="fetching-key"?a(G(ae,{gap:1,children:[F(me,{}),G($,{children:["Fetching ",e.stage," public key for ",F($,{bold:!0,children:P}),"\u2026"]})]})):g.type==="encrypting"?a(G(ae,{gap:1,children:[F(me,{}),F($,{children:"Encrypting\u2026"})]})):g.type==="error"?a(G(ae,{gap:1,children:[F($,{color:"red",children:"\u2717"}),F($,{color:"red",children:g.message})]})):a(G(kt,{children:[G(ae,{gap:1,children:[F($,{color:"green",children:"\u2713"}),F($,{bold:!0,children:"Encrypted secret ready"})]}),g.copied?F($,{color:"green",children:"\u2713 Copied to clipboard \u2014 paste it into the secret value in your kizen.json."}):F($,{dimColor:!0,children:"Paste this into the secret value in your kizen.json (re-run with --out <path> to save it to a file; selecting it here may capture line wraps):"}),F($,{children:g.envelope})]}))};import{readFile as Na,writeFile as Ba}from"fs/promises";import{join as Da}from"path";function Qn(e){return{encrypted:!0,value:e}}function eo(e){return JSON.stringify(Qn(e))}async function ar(e,t){await Ba(e,`${JSON.stringify(Qn(t),null,2)}
|
|
490
|
+
`,"utf-8")}var Fa="prod";function to(e){return e==="dev"||e==="prod"}function ro(e){return`Error: --stage must be "dev" or "prod" (got: "${e}")`}function no(e){return{stage:e==="dev"||e==="prod"?e:Fa,wasDefaulted:e===void 0}}function oo(e){return`No --stage given; defaulting to ${e} encryption keys (pass --stage dev to override)
|
|
491
|
+
`}async function io(e=process.cwd()){try{let t=await Na(Da(e,"kizen.json"),"utf-8"),n=JSON.parse(t),o=Array.isArray(n)?n[0]:n,r=typeof o.api_name=="string"&&o.api_name!==""?o.api_name:void 0;return{...r!==void 0&&{apiName:r}}}catch{}return{}}function so(e){return e.replace(/[\r\n]+$/,"")}async function ao(){let e=[];for await(let t of process.stdin)e.push(t);return Buffer.concat(e).toString("utf-8")}async function lo(e,t,n,o,r){let i=t.credentials!==void 0?await r.loadCredentialsFromFile(t.credentials):await r.loadGlobalCredentials();if(i===null)throw new Error("No credentials found. Pass --credentials or create ~/.kizenappbuilder/credentials.json.");let d=t.apiName??n.apiName;if(d===void 0||d.trim()==="")throw new Error("api_name is required in non-interactive mode. Pass --api-name or run inside a plugin directory.");o&&r.writeStderr(oo(e.stage));let f=t.value;if(f===void 0){if(r.stdinIsTTY())throw new Error('No secret provided and stdin is a terminal. Pass --value, or pipe the secret in (e.g. `printf %s "$SECRET" | npx --yes @kizenapps/cli encrypt \u2026`).');r.writeStderr(`Reading secret from stdin (pass --value to skip)\u2026
|
|
492
|
+
`),f=so(await r.readStdin())}if(f==="")throw new Error("A secret value is required. Pass --value or pipe it via stdin.");let g=await r.encryptSecret(e,i,d.trim(),f);if(r.writeStdout(`${eo(g)}
|
|
493
|
+
`),t.out!==void 0)try{await r.writeEnvelopeFile(t.out,g),r.writeStderr(`Wrote encrypted envelope to ${t.out}
|
|
494
|
+
`)}catch(m){r.writeStderr(`Error writing ${t.out}: ${m instanceof Error?m.message:String(m)}
|
|
495
|
+
`),r.setExitCode(1)}}function co(e){e.command("encrypt").description("Encrypt a secret for a plugin against its encryption keys").option("--remote","encrypt via the plugin-wizard's remote API instead of on-machine").option("-c, --credentials <path>","path to a credentials JSON file").option("-a, --api-name <name>","plugin api_name the secret belongs to").option("-v, --value <value>","plaintext secret value to encrypt").option("-s, --stage <stage>","which encryption API to use: dev or prod (default: prod)").option("-o, --out <path>","also write the encrypted envelope to a file").action(async t=>{t.stage!==void 0&&!to(t.stage)&&(console.error(ro(t.stage)),process.exit(1));let o=t.apiName===void 0?await io():{},{stage:r,wasDefaulted:i}=no(t.stage),d={isRemote:t.remote===!0,stage:r};if(!process.stdin.isTTY||!process.stdout.isTTY){try{await lo(d,t,o,i,{loadCredentialsFromFile:be,loadGlobalCredentials:Z,encryptSecret:Tt,readStdin:ao,stdinIsTTY:()=>process.stdin.isTTY,writeStdout:m=>{process.stdout.write(m)},writeStderr:m=>{process.stderr.write(m)},writeEnvelopeFile:ar,setExitCode:m=>{process.exitCode=m}})}catch(m){console.error(`Error: ${m instanceof Error?m.message:String(m)}`),process.exit(1)}return}let f,{waitUntilExit:g}=ja(Oa(Zn,{ctx:d,stageDefaulted:i,onDone:m=>{f=m},...t.credentials!==void 0&&{credentialsPath:t.credentials},...t.apiName!==void 0&&{initialApiName:t.apiName},...o.apiName!==void 0&&{defaultApiName:o.apiName},...t.value!==void 0&&{initialValue:t.value}}),{exitOnCtrlC:!1});if(await g(),f!==void 0&&t.out!==void 0)try{await ar(t.out,f),process.stderr.write(`Wrote encrypted envelope to ${t.out}
|
|
496
|
+
`)}catch(m){console.error(`Error writing ${t.out}: ${m instanceof Error?m.message:String(m)}`),process.exitCode=1}})}var $a=new Set(["phone","envelope","pen-nib","calendar-days","paperclip","file","clipboard","pen","tag","book","print","pen-to-square","folder","folder-open","thumbtack","globe","city","briefcase","compass","address-book","business-time","computer-classic","pen-fancy","badge-check","mug-saucer","landmark","chart-simple","envelopes","diagram-venn","calendar","pencil","phone-volume","copy","table","building","network-wired","address-card","tags","registered","signature","phone-office","projector","sitemap","marker","badge","wallet","copyright","bullseye","calculator","certificate","percent","eraser","file-spreadsheet","glasses","industry","vault","user-tie-hair-long","user-tie-hair","user-hair-mullet","trademark","timeline-arrow","timeline","table-tree","table-rows","table-pivot","table-layout","table-columns","stapler","square-poll-vertical","square-poll-horizontal","square-phone-flip","square-phone","square-pen","square-kanban","square-envelope","socks","slot-machine","signature-slash","signature-lock","shredder","scissors","scanner-image","scale-unbalanced-flip","scale-unbalanced","scale-balanced","router","rectangle-pro","print-slash","print-magnifying-glass","presentation-screen","podium","phone-slash","phone-intercom","phone-flip","person-chalkboard","pen-nib-slash","pen-clip","paste","paperclip-vertical","notebook","note-sticky","money-check-pen","money-check-dollar-pen","magnifying-glass-chart","magnifying-glass-arrow-right","list-tree","list-timeline","list-radio","list-dropdown","list-check","laptop-file","lamp-desk","keynote","industry-windows","inboxes","inbox-full","house-laptop","highlighter","folders","folder-xmark","folder-tree","folder-plus","folder-minus","folder-arrow-up","folder-arrow-down","floppy-disk-circle-xmark","floppy-disk-circle-arrow-right","floppy-disk","file-user","file-lines","file-circle-plus","file-circle-info","file-chart-pie","file-chart-column","fax","envelope-open","envelope-dot","envelope-circle-check","coffee-pot","cloud-word","clipboard-question","chart-user","chart-tree-map","chart-simple-horizontal","chart-pyramid","chart-pie-simple","chart-pie","chart-line-up","chart-line-down","chart-line","cake-candles","cabinet-filing","bullhorn","briefcase-blank","briefcase-arrow-right","brain-arrow-curved-right","boxes-packing","box-archive","book-section","bars-staggered","bars-progress","badge-percent","badge-dollar","arrows-to-eye","arrows-to-dot","arrows-spin","sparkles","megaphone","block-question","lightbulb-slash","comments-dollar","comments","bullseye-pointer","lightbulb","user-group-crown","user-crown","signal-stream-slash","signal-stream","rectangle-ad","ranking-star","person-rays","people-group","messages-dollar","message-dollar","magnifying-glass-location","magnifying-glass-dollar","lightbulb-on","lightbulb-exclamation","lightbulb-dollar","lightbulb-cfl-on","lightbulb-cfl","hundred-points","group-arrows-rotate","gift-card","filter-circle-dollar","envelopes-bulk","envelope-open-text","envelope-open-dollar","comment-dollar","chart-mixed","bullseye-arrow","star","heart","camera-retro","truck-fast","bell","cart-shopping","gift","barcode","bookmark","camera","thumbs-up","thumbs-down","key","truck","balloons","handshake","shop","shirt","bag-shopping","moped","cart-plus","credit-card","store","cash-register","booth-curtain","trophy","receipt","truck-container","truck-clock","truck-bolt","trophy-star","store-slash","store-lock","star-exclamation","shop-slash","shop-lock","rectangle-barcode","person-booth","nfc-trash","nfc-symbol","nfc-slash","nfc-signal","nfc-pen","nfc-magnifying-glass","nfc-lock","nfc","money-check-dollar","money-check","mobile-signal-out","mobile-signal","hexagon-vertical-nft-slanted","hexagon-vertical-nft","hexagon-image","hand-holding-box","gifts","gem","credit-card-front","credit-card-blank","cart-xmark","cart-shopping-fast","cart-minus","cart-circle-xmark","cart-circle-plus","cart-circle-exclamation","cart-circle-check","cart-circle-arrow-up","cart-circle-arrow-down","cart-arrow-up","cart-arrow-down","box-open-full","basket-shopping-simple","basket-shopping","barcode-scan","barcode-read","balloon","bags-shopping","bars","browser","chart-bar","cog","database","calendar-alt","play","kizen-k","add","book-alt","form-entity","arrows-to-circle","question-circle","chevron-down","chevron-up","window-restore","forward"]),La=[...$a].sort(),Ma=new Set(["kizen-k","form-entity"]),po=[...La,...[...Ma].sort()];function uo(e){e.command("icons").description("List all valid icon names accepted by toolbar items, pages, and adornments").action(()=>{for(let t of po)console.log(t)})}import{mkdir as Ka,writeFile as So,readFile as Ga}from"fs/promises";import{join as Pt}from"path";var za=new Set(["developer_business_id"]);function Ha(e){return Array.isArray(e)?e.map(t=>{if(typeof t!="object"||t===null)return t;let n=t;if(typeof n.auth_credentials!="object"||n.auth_credentials===null)return n;let o=Object.fromEntries(Object.keys(n.auth_credentials).map(r=>[r,"*****"]));return{...n,auth_credentials:o}}):e}function mo(e){let t={name:"",children:new Map,isFile:!1,filePath:""};for(let n of e){let o=n.path.split("/"),r=t;o.forEach((i,d)=>{r.children.has(i)||r.children.set(i,{name:i,children:new Map,isFile:d===o.length-1,filePath:o.slice(0,d+1).join("/")});let f=r.children.get(i);f&&(r=f)})}return t}function go(e){return[...e.children.values()].sort((t,n)=>t.isFile!==n.isFile?t.isFile?1:-1:t.name.localeCompare(n.name))}function lr(e){return"file-"+e.replace(/[^a-zA-Z0-9]/g,"-")}function le(e){return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function ho(e){let t=e.lastIndexOf(".");return t>=0?e.slice(t).toLowerCase():""}var Ua={".ts":"typescript",".tsx":"typescript",".js":"javascript",".jsx":"javascript",".mjs":"javascript",".cjs":"javascript",".json":"json",".css":"css",".scss":"scss",".html":"html",".htm":"html",".md":"markdown",".mdx":"markdown",".py":"python",".sh":"bash",".yml":"yaml",".yaml":"yaml",".xml":"xml",".toml":"toml"};function Va(e){return Ua[ho(e)]??""}function fo(e){let t=[...e.matchAll(/`+/g)].reduce((n,o)=>Math.max(n,o[0].length),0);return"`".repeat(Math.max(3,t+1))}function yo(e,t=""){let n=go(e);return n.map((o,r)=>{let i=r===n.length-1,d=i?"\u2514\u2500\u2500 ":"\u251C\u2500\u2500 ",f=i?" ":"\u2502 ";return o.isFile?`${t}${d}${o.name}`:`${t}${d}${o.name}/
|
|
497
|
+
${yo(o,t+f)}`}).join(`
|
|
498
|
+
`)}var qa=/(^|\/)licen[cs]e(\.md|\.txt)?$/i;function bo(e){return e.filter(t=>t.path!=="kizen.json"&&t.path!=="plugin-report.html"&&!qa.test(t.path))}function xo(e){return Object.fromEntries(Object.entries(e).filter(([t])=>!za.has(t)).map(([t,n])=>[t,t==="services"?Ha(n):n]))}var Ja={".png":"image/png",".svg":"image/svg+xml",".jpg":"image/jpeg",".jpeg":"image/jpeg",".gif":"image/gif",".webp":"image/webp"};function vo(e){return`<ul>${go(e).map(o=>o.isFile?`<li class="tf"><a href="#${lr(o.filePath)}" data-id="${lr(o.filePath)}">${le(o.name)}</a></li>`:`<li class="td"><span class="dn">${le(o.name)}/</span>${vo(o)}</li>`).join("")}</ul>`}function Wa(e){let t;return e.base64Image!==void 0?t=`<img src="data:${Ja[ho(e.path)]??"image/png"};base64,${e.base64Image}" alt="${le(e.path)}" style="max-width:100%">`:e.binaryData!==void 0?t=`<p class="bin">[Binary file: ${String(e.binaryData.length)} bytes]</p>`:t=`<pre><code>${le(e.content)}</code></pre>`,`<section id="${lr(e.path)}"><h2 class="fp">${le(e.path)}</h2><div class="fb">${t}</div></section>`}function wo(e,t){let n=xo(e),o=typeof e.name=="string"?e.name:"Plugin",r=typeof e.version=="string"?e.version:"",i=typeof e.description=="string"?e.description:"",d=bo(t),f=[];f.push(`# ${o}${r?` v${r}`:""}`),i&&f.push("",i);let g=JSON.stringify(n,null,2),m=fo(g);f.push("","## Configuration (`kizen.json`)","",`${m}json`,g,m),f.push("","## File Tree","","```",yo(mo(d)),"```"),f.push("","## Files");for(let b of d)if(f.push("",`### \`${b.path}\``,""),b.base64Image!==void 0)f.push(`[Image file: ${b.path}]`);else if(b.binaryData!==void 0)f.push(`[Binary file: ${String(b.binaryData.length)} bytes]`);else{let T=fo(b.content);f.push(`${T}${Va(b.path)}`,b.content,T)}return f.join(`
|
|
201
499
|
`)+`
|
|
202
|
-
`}function
|
|
500
|
+
`}function Co(e,t){let n=xo(e),o=typeof e.name=="string"?e.name:"Plugin",r=typeof e.version=="string"?e.version:"",i=typeof e.description=="string"?e.description:"",d=bo(t),f=vo(mo(d)),g=d.map(Wa).join(`
|
|
203
501
|
`);return`<!DOCTYPE html>
|
|
204
502
|
<html lang="en">
|
|
205
503
|
<head>
|
|
206
504
|
<meta charset="UTF-8">
|
|
207
505
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
208
|
-
<title>${
|
|
506
|
+
<title>${le(o)} \u2014 Plugin Report</title>
|
|
209
507
|
<style>
|
|
210
508
|
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
|
|
211
509
|
:root{
|
|
@@ -242,17 +540,17 @@ img{border:1px solid var(--bd);border-radius:4px}
|
|
|
242
540
|
</head>
|
|
243
541
|
<body>
|
|
244
542
|
<header>
|
|
245
|
-
<h1>${
|
|
246
|
-
${i?`<p>${
|
|
543
|
+
<h1>${le(o)}${r?` <span style="color:var(--mu);font-size:.8em">v${le(r)}</span>`:""}</h1>
|
|
544
|
+
${i?`<p>${le(i)}</p>`:""}
|
|
247
545
|
</header>
|
|
248
546
|
<div class="layout">
|
|
249
547
|
<nav>
|
|
250
548
|
<a href="#config" class="cfg" data-id="config">kizen.json (config)</a>
|
|
251
|
-
${
|
|
549
|
+
${f}
|
|
252
550
|
</nav>
|
|
253
551
|
<main>
|
|
254
|
-
<section id="config"><h2 class="fp">kizen.json \u2014 Plugin Configuration</h2><div class="fb"><pre><code>${
|
|
255
|
-
${
|
|
552
|
+
<section id="config"><h2 class="fp">kizen.json \u2014 Plugin Configuration</h2><div class="fb"><pre><code>${le(JSON.stringify(n,null,2))}</code></pre></div></section>
|
|
553
|
+
${g}
|
|
256
554
|
</main>
|
|
257
555
|
</div>
|
|
258
556
|
<script>
|
|
@@ -265,7 +563,7 @@ ${m}
|
|
|
265
563
|
})();
|
|
266
564
|
</script>
|
|
267
565
|
</body>
|
|
268
|
-
</html>`}var
|
|
566
|
+
</html>`}var To=Pt(Pe,"examples");function _o(e){e.command("report").description("Generate a self-contained HTML report of the plugin").option("-o, --output <path>",`output file path (default: ${To}/<api_name>.html)`).action(async t=>{let n=process.cwd(),o;try{let g=await Ga(Pt(n,"kizen.json"),"utf-8"),m=JSON.parse(g);o=Array.isArray(m)?m[0]:m}catch{console.error("Error: kizen.json not found. Run this command from a plugin directory."),process.exit(1)}let r=typeof o.api_name=="string"?o.api_name:"plugin",i=t.output??Pt(To,`${r}.html`),d=i.replace(/\.html$/,".md"),f=await rt(n,{detectBinaryByContent:!0});await Ka(Pt(i,".."),{recursive:!0}),await Promise.all([So(i,Co(o,f),"utf-8"),So(d,wo(o,f),"utf-8")]),console.log(`Plugin report written to:
|
|
269
567
|
${i}
|
|
270
|
-
${
|
|
568
|
+
${d}`)})}function tl(){let e=Za(Xa(Qa(import.meta.url)),"..","package.json");return JSON.parse(Ya(e,"utf-8")).version}function Eo(){let e=new el;return e.name("appbuilder").description("Kizen plugin app builder").version(tl()),cn(e),Tr(e),qn(e),co(e),_o(e),uo(e),e}Eo().parse();
|
|
271
569
|
//# sourceMappingURL=index.js.map
|